From 993f983ec3ce747da730aa73e6ecea25f226ca7f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 01:43:02 +0000 Subject: [PATCH 01/24] i18n: string-extraction codemod, literal ratchet and en-XA pseudo-locale audit - scripts/i18n-literals.ts: shared scanner for user-visible literals, a per-file ratchet (i18n/literal-baseline.json) wired into i18n:check, and report/update commands; exemptions via i18n/literal-allowlist.json or an i18n-ignore comment - scripts/i18n-codemod.ts: rewrites JSX text, UI props, conditional and template copy and notification payloads into i18n._ descriptors with the usePascalI18n hook; module-level and server copy is listed for a person - en-XA pseudo-locale compiled from English, registered by the app outside production, plus a Playwright audit that screenshots surfaces and lists copy that bypassed the catalog - i18n:check accepts AI drafts flagged fuzzy + Review: required (they are never compiled into packs); check --reviewed keeps the sign-off gate --- .gitignore | 1 + CONTRIBUTING.md | 16 + apps/editor/app/client-bootstrap.tsx | 2 + apps/editor/app/layout.tsx | 2 + bun.lock | 5 +- i18n/README.md | 85 ++- i18n/literal-allowlist.json | 43 ++ i18n/literal-baseline.json | 198 ++++++ i18n/pseudo-surfaces.ts | 47 ++ package.json | 5 +- packages/editor/package.json | 1 + .../editor/src/i18n/locales/en-XA/messages.ts | 1 + packages/editor/src/i18n/pseudo-locale.ts | 17 + scripts/i18n-codemod.ts | 462 ++++++++++++++ scripts/i18n-literals.test.ts | 168 +++++ scripts/i18n-literals.ts | 595 ++++++++++++++++++ scripts/i18n-pseudo-audit.ts | 144 +++++ scripts/i18n.ts | 274 +++++--- 18 files changed, 1980 insertions(+), 86 deletions(-) create mode 100644 i18n/literal-allowlist.json create mode 100644 i18n/literal-baseline.json create mode 100644 i18n/pseudo-surfaces.ts create mode 100644 packages/editor/src/i18n/locales/en-XA/messages.ts create mode 100644 packages/editor/src/i18n/pseudo-locale.ts create mode 100644 scripts/i18n-codemod.ts create mode 100644 scripts/i18n-literals.test.ts create mode 100644 scripts/i18n-literals.ts create mode 100644 scripts/i18n-pseudo-audit.ts diff --git a/.gitignore b/.gitignore index e41ddbb868..8d9dbf9930 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,4 @@ og-test .claude/launch.json .claude/settings.local.json .vscode/launch.json +.i18n-audit/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5f928dbb3..b438dba567 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,6 +60,22 @@ and reports inflated counts. `bun run test` goes through Turborepo, which builds workspace dependencies first (several packages import theirs from `dist/`) and runs each package's own scoped test script. +### User-visible text + +Every string a person reads in the editor (labels, tooltips, `aria-label`, +`title`, placeholders, menus, dialogs, errors) goes through the i18n catalog: + +```tsx +const i18n = usePascalI18n() + ) } function WallModeToggle() { + const i18n = usePascalI18n() const wallMode = useViewer((state) => state.wallMode) const setWallMode = useViewer((state) => state.setWallMode) const config = wallModeConfig[wallMode] ?? wallModeConfig.cutaway! @@ -215,7 +325,13 @@ function WallModeToggle() { } return ( - + ) @@ -238,14 +354,33 @@ function WallModeToggle() { // camera projection, units, render mode, edges and scene theme. const EDGE_OPTIONS = [ - { id: 'off', name: 'Off', detail: 'No edge lines' }, - { id: 'soft', name: 'Soft', detail: 'Faint outline of major creases' }, - { id: 'strong', name: 'Strong', detail: 'Crisp, opaque edge lines' }, -] as const satisfies readonly { id: EdgeMode; name: string; detail: string }[] + { + id: 'off', + name: /* i18n */ { id: 'app.viewerToolbar.off', message: 'Off' }, + detail: /* i18n */ { id: 'app.viewerToolbar.noEdgeLines', message: 'No edge lines' }, + }, + { + id: 'soft', + name: /* i18n */ { id: 'app.viewerToolbar.soft', message: 'Soft' }, + detail: /* i18n */ { + id: 'app.viewerToolbar.faintOutlineOfMajorCreases', + message: 'Faint outline of major creases', + }, + }, + { + id: 'strong', + name: /* i18n */ { id: 'app.viewerToolbar.strong', message: 'Strong' }, + detail: /* i18n */ { + id: 'app.viewerToolbar.crispOpaqueEdgeLines', + message: 'Crisp, opaque edge lines', + }, + }, +] as const satisfies readonly { id: EdgeMode; name: MessageDescriptor; detail: MessageDescriptor }[] const SUBMENU_CONTENT_CLASS = 'min-w-56 rounded-xl border-border/45 bg-popover/95 backdrop-blur-xl' function DisplayMenu() { + const i18n = usePascalI18n() const scene = useEditor(visibleScene) const showGrid = useViewer((state) => state.showGrid) const setShowGrid = useViewer((state) => state.setShowGrid) @@ -291,27 +426,34 @@ function DisplayMenu() { return ( - + keepOpen(e, () => setShowGrid(!showGrid))}> - Grid + {i18n._({ id: 'app.viewerToolbar.grid', message: 'Grid' })} {showGrid ? ( ) : ( @@ -323,7 +465,11 @@ function DisplayMenu() { onSelect={(e) => keepOpen(e, () => setShowMeasurements(!showMeasurements))} > - {scene === 'split' ? '3D measurements' : 'Measurements'} + + {scene === 'split' + ? i18n._({ id: 'app.viewerToolbar.n3dMeasurements', message: '3D measurements' }) + : i18n._({ id: 'app.viewerToolbar.measurements', message: 'Measurements' })} + {showMeasurements ? ( ) : ( @@ -336,17 +482,21 @@ function DisplayMenu() { - Floor plan mode + + {i18n._({ id: 'app.viewerToolbar.floorPlanMode', message: 'Floor plan mode' })} + - {floorplanMode === 'default' ? 'Default' : 'Expert'} + {floorplanMode === 'default' + ? i18n._({ id: 'app.viewerToolbar.default', message: 'Default' }) + : i18n._({ id: 'app.viewerToolbar.expert', message: 'Expert' })} {FLOORPLAN_MODE_OPTIONS.map((option) => ( setFloorplanMode(option.id)}>
- {option.name} - {option.detail} + {i18n._(option.name)} + {i18n._(option.detail)}
{floorplanMode === option.id ? ( @@ -360,7 +510,12 @@ function DisplayMenu() { - Floor plan annotations + + {i18n._({ + id: 'app.viewerToolbar.floorPlanAnnotations', + message: 'Floor plan annotations', + })} + {FLOORPLAN_ANNOTATION_OPTIONS.map((option) => { @@ -374,7 +529,7 @@ function DisplayMenu() { } > - {option.name} + {i18n._(option.name)} {visible ? ( ) : ( @@ -388,13 +543,20 @@ function DisplayMenu() { - Wall dimensions + + {i18n._({ + id: 'app.viewerToolbar.wallDimensions', + message: 'Wall dimensions', + })} + - { - FLOORPLAN_WALL_DIMENSION_REFERENCE_OPTIONS.find( - (option) => option.id === wallDimensionReference, - )?.name - } + {i18n._( + ( + FLOORPLAN_WALL_DIMENSION_REFERENCE_OPTIONS.find( + (option) => option.id === wallDimensionReference, + ) ?? FLOORPLAN_WALL_DIMENSION_REFERENCE_OPTIONS[0] + ).name, + )} @@ -406,8 +568,10 @@ function DisplayMenu() { } >
- {option.name} - {option.detail} + {i18n._(option.name)} + + {i18n._(option.detail)} +
{wallDimensionReference === option.id ? ( @@ -422,15 +586,21 @@ function DisplayMenu() { ) : null} keepOpen(e, () => setMagneticSnap(!magneticSnap))}> - Magnetic snap + {i18n._({ id: 'app.viewerToolbar.magneticSnap', message: 'Magnetic snap' })} - {magneticSnap ? 'On' : 'Off'} + {magneticSnap + ? i18n._({ id: 'app.viewerToolbar.on', message: 'On' }) + : i18n._({ id: 'app.viewerToolbar.off', message: 'Off' })} keepOpen(e, () => setShadows(!shadows))}> - Shadows - {shadows ? 'On' : 'Off'} + {i18n._({ id: 'app.viewerToolbar.shadows', message: 'Shadows' })} + + {shadows + ? i18n._({ id: 'app.viewerToolbar.on', message: 'On' }) + : i18n._({ id: 'app.viewerToolbar.off', message: 'Off' })} + @@ -444,9 +614,11 @@ function DisplayMenu() { icon={cameraMode === 'perspective' ? 'icon-park-outline:perspective' : 'vaadin:grid'} width={16} /> - Camera + {i18n._({ id: 'app.viewerToolbar.camera', message: 'Camera' })} - {cameraMode === 'perspective' ? 'Perspective' : 'Orthographic'} + {cameraMode === 'perspective' + ? i18n._({ id: 'app.viewerToolbar.perspective', message: 'Perspective' }) + : i18n._({ id: 'app.viewerToolbar.orthographic', message: 'Orthographic' })} @@ -454,13 +626,13 @@ function DisplayMenu() { {unit === 'imperial' ? 'ft' : metricNotation === 'millimeters' ? 'mm' : 'm'} - Units + {i18n._({ id: 'app.viewerToolbar.units', message: 'Units' })} {unit === 'imperial' - ? 'Feet & inches' + ? i18n._({ id: 'app.viewerToolbar.feetInches', message: 'Feet & inches' }) : metricNotation === 'millimeters' - ? 'Millimeters' - : 'Meters'} + ? i18n._({ id: 'app.viewerToolbar.millimeters', message: 'Millimeters' }) + : i18n._({ id: 'app.viewerToolbar.meters', message: 'Meters' })} @@ -468,7 +640,7 @@ function DisplayMenu() { m - Meters + {i18n._({ id: 'app.viewerToolbar.meters', message: 'Meters' })} {unit === 'metric' && metricNotation === 'meters' ? ( ) : null} @@ -477,7 +649,7 @@ function DisplayMenu() { mm - Millimeters + {i18n._({ id: 'app.viewerToolbar.millimeters', message: 'Millimeters' })} {unit === 'metric' && metricNotation === 'millimeters' ? ( ) : null} @@ -486,7 +658,9 @@ function DisplayMenu() { ft - Feet & inches + + {i18n._({ id: 'app.viewerToolbar.feetInches', message: 'Feet & inches' })} + {unit === 'imperial' ? : null}
@@ -497,8 +671,10 @@ function DisplayMenu() { - Render - {activeShading.name} + {i18n._({ id: 'app.viewerToolbar.render', message: 'Render' })} + + {i18n._(activeShading.name)} + {SHADING_OPTIONS.map((option) => { @@ -507,8 +683,8 @@ function DisplayMenu() { setShading(option.id)}>
- {option.name} - {option.detail} + {i18n._(option.name)} + {i18n._(option.detail)}
{shading === option.id ? ( @@ -522,15 +698,17 @@ function DisplayMenu() { - Edges - {activeEdges.name} + {i18n._({ id: 'app.viewerToolbar.edges', message: 'Edges' })} + + {i18n._(activeEdges.name)} + {EDGE_OPTIONS.map((option) => ( setEdges(option.id)}>
- {option.name} - {option.detail} + {i18n._(option.name)} + {i18n._(option.detail)}
{edges === option.id ? : null}
@@ -541,9 +719,9 @@ function DisplayMenu() { - Scene theme + {i18n._({ id: 'app.viewerToolbar.sceneTheme', message: 'Scene theme' })} - {activeTheme.name} + {sceneThemeName(activeTheme.id, activeTheme.name, i18n)} @@ -561,7 +739,9 @@ function DisplayMenu() { ))} - {theme.name} + + {sceneThemeName(theme.id, theme.name, i18n)} + {sceneTheme === theme.id ? ( ) : null} @@ -576,6 +756,7 @@ function DisplayMenu() { } function WalkthroughButton() { + const i18n = usePascalI18n() const isFirstPersonMode = useEditor((state) => state.isFirstPersonMode) const setFirstPersonMode = useEditor((state) => state.setFirstPersonMode) const handleClick = useCallback(() => { @@ -589,7 +770,7 @@ function WalkthroughButton() { }, [isFirstPersonMode, setFirstPersonMode]) return ( - + ) @@ -662,7 +846,7 @@ export function EditorViewerToolbarRight({ vrButton, vrActive = false, vrDisabled = false, - vrLabel = vrActive ? 'Exit VR' : 'Enter VR', + vrLabel, }: { onVRToggle?: () => void vrButton?: ReactNode @@ -670,6 +854,12 @@ export function EditorViewerToolbarRight({ vrDisabled?: boolean vrLabel?: string }) { + const i18n = usePascalI18n() + const label = + vrLabel ?? + (vrActive + ? i18n._({ id: 'app.viewerToolbar.exitVr', message: 'Exit VR' }) + : i18n._({ id: 'app.viewerToolbar.enterVr', message: 'Enter VR' })) return (
@@ -681,12 +871,7 @@ export function EditorViewerToolbarRight({ {onVRToggle || vrButton ? (vrButton ?? (onVRToggle ? ( - + ) : null)) : null} diff --git a/packages/editor/src/components/viewer/viewer-controls-bar.tsx b/packages/editor/src/components/viewer/viewer-controls-bar.tsx index 9129e7521f..10f6e20f87 100644 --- a/packages/editor/src/components/viewer/viewer-controls-bar.tsx +++ b/packages/editor/src/components/viewer/viewer-controls-bar.tsx @@ -26,6 +26,7 @@ import { Square, SwatchBook, } from 'lucide-react' +import { sceneThemeName } from '../../i18n/scene-theme-name' import { cn } from '../../lib/utils' import { ActionButton } from '../ui/action-menu/action-button' import { FollowPascalToggle } from '../ui/action-menu/follow-pascal-toggle' @@ -69,20 +70,6 @@ function wallModeLabel(mode: keyof typeof wallModeConfig, i18n: PascalI18n): str return i18n._({ id: 'viewer.walls.cutaway', message: 'Cutaway' }) } -function sceneThemeName(id: string, fallback: string, i18n: PascalI18n): string { - if (id === 'studio') return i18n._({ id: 'viewer.theme.studio', message: 'Studio' }) - if (id === 'paper') return i18n._({ id: 'viewer.theme.paper', message: 'Paper' }) - if (id === 'sunset') return i18n._({ id: 'viewer.theme.sunset', message: 'Sunset' }) - if (id === 'overcast') return i18n._({ id: 'viewer.theme.overcast', message: 'Overcast' }) - if (id === 'blueprint') return i18n._({ id: 'viewer.theme.blueprint', message: 'Blueprint' }) - if (id === 'mediterranean') - return i18n._({ id: 'viewer.theme.mediterranean', message: 'Mediterranean' }) - if (id === 'twilight') return i18n._({ id: 'viewer.theme.twilight', message: 'Twilight' }) - if (id === 'night') return i18n._({ id: 'viewer.theme.night', message: 'Night' }) - if (id === 'verdant') return i18n._({ id: 'viewer.theme.verdant', message: 'Verdant' }) - return fallback -} - // Keep the dropdown open when flipping an in-place toggle row. const keepOpen = (event: Event, fn: () => void) => { event.preventDefault() diff --git a/packages/editor/src/i18n/scene-theme-name.ts b/packages/editor/src/i18n/scene-theme-name.ts new file mode 100644 index 0000000000..2d9001c154 --- /dev/null +++ b/packages/editor/src/i18n/scene-theme-name.ts @@ -0,0 +1,16 @@ +import type { PascalI18n } from '@pascal-app/core' + +/** Display name of a built-in scene theme; unknown (plugin) themes keep their own name. */ +export function sceneThemeName(id: string, fallback: string, i18n: PascalI18n): string { + if (id === 'studio') return i18n._({ id: 'viewer.theme.studio', message: 'Studio' }) + if (id === 'paper') return i18n._({ id: 'viewer.theme.paper', message: 'Paper' }) + if (id === 'sunset') return i18n._({ id: 'viewer.theme.sunset', message: 'Sunset' }) + if (id === 'overcast') return i18n._({ id: 'viewer.theme.overcast', message: 'Overcast' }) + if (id === 'blueprint') return i18n._({ id: 'viewer.theme.blueprint', message: 'Blueprint' }) + if (id === 'mediterranean') + return i18n._({ id: 'viewer.theme.mediterranean', message: 'Mediterranean' }) + if (id === 'twilight') return i18n._({ id: 'viewer.theme.twilight', message: 'Twilight' }) + if (id === 'night') return i18n._({ id: 'viewer.theme.night', message: 'Night' }) + if (id === 'verdant') return i18n._({ id: 'viewer.theme.verdant', message: 'Verdant' }) + return fallback +} diff --git a/scripts/i18n-git.ts b/scripts/i18n-git.ts new file mode 100644 index 0000000000..5159f86b76 --- /dev/null +++ b/scripts/i18n-git.ts @@ -0,0 +1,35 @@ +import { dirname, relative, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..') + +function git(args: string[]): string | undefined { + const result = Bun.spawnSync(['git', ...args], { cwd: ROOT, stdout: 'pipe', stderr: 'ignore' }) + return result.exitCode === 0 ? result.stdout.toString() : undefined +} + +/** + * The revision a change is compared with. In a pull_request CI run the + * checkout is GitHub's merge commit, whose first parent is the base tip; + * locally it is the merge base with origin/main. `I18N_BASE_REF` overrides. + */ +export function baseRevision(): string | undefined { + const requested = + process.env.I18N_BASE_REF ?? + (process.env.GITHUB_EVENT_NAME === 'pull_request' + ? 'HEAD^1' + : git(['merge-base', 'HEAD', 'origin/main'])?.trim()) + if (!requested) return undefined + const revision = git(['rev-parse', '--verify', '--quiet', `${requested}^{commit}`])?.trim() + if (!revision) { + if (process.env.GITHUB_EVENT_NAME === 'pull_request') { + throw new Error(`Base revision ${requested} is not available; fetch it before i18n:check`) + } + return undefined + } + return revision === git(['rev-parse', 'HEAD'])?.trim() ? undefined : revision +} + +export function readAtRevision(revision: string, path: string): string | undefined { + return git(['show', `${revision}:${relative(ROOT, path)}`]) +} diff --git a/scripts/i18n.ts b/scripts/i18n.ts index 5a5e0f5b51..440ffd27ae 100644 --- a/scripts/i18n.ts +++ b/scripts/i18n.ts @@ -6,7 +6,8 @@ import { createCompiledCatalog, getCatalogs } from '@lingui/cli/api' import { getConfig } from '@lingui/conf' import { compileMessageOrThrow } from '@lingui/message-utils/compileMessage' import { type PoFile, type PoItem, parsePo, stringifyPo } from 'pofile-ts' -import { checkLiterals } from './i18n-literals' +import { baseRevision, readAtRevision } from './i18n-git' +import { checkRepositoryLiterals } from './i18n-literals' export type SourceMessage = { id: string @@ -515,7 +516,12 @@ function compiledCatalog(locale: string, sources: SourceMessage[]) { function writeCompiledCatalogs(strict = false): void { const sources = readSourceMessages() if (strict) { - const errors = checkCatalogMessages(sources, readJson(GLOSSARY_PATH), {}) + const errors = checkTranslationEntries( + sources, + readLocaleEntries((path) => readFileSync(path, 'utf8')), + readJson(GLOSSARY_PATH), + {}, + ) if (errors.length > 0) throw new Error(errors.join('\n')) } const compiled = ALL_LOCALES.map((locale) => [locale, compiledCatalog(locale, sources)] as const) @@ -735,8 +741,21 @@ export function pendingReview(sources: SourceMessage[]): Record ) } -function checkCatalogMessages( +export type LocaleEntries = Record> + +function readLocaleEntries(read: (path: string) => string | undefined): LocaleEntries { + const entries: LocaleEntries = {} + for (const locale of TARGET_LOCALES) { + const text = read(catalogPath(locale)) + if (text !== undefined) entries[locale] = readTranslationState(parsePo(text)) + } + return entries +} + +/** Pure completeness/validity/review rules for the bundled target catalogs. */ +export function checkTranslationEntries( sources: SourceMessage[], + entriesByLocale: LocaleEntries, glossary: Glossary, options: CatalogCheckOptions = { requireReviewed: true }, ): string[] { @@ -747,8 +766,7 @@ function checkCatalogMessages( } for (const locale of TARGET_LOCALES) { - const po = parsePo(readFileSync(catalogPath(locale), 'utf8')) - const entries = readTranslationState(po) + const entries = entriesByLocale[locale] ?? {} for (const source of sources) { const entry = entries[source.id] if (!entry?.translation) { @@ -782,6 +800,59 @@ function checkCatalogMessages( return errors } +/** + * A translation a person approved on the base branch stays approved while its + * English is unchanged: a PR may edit it (still `Review: human`) but never + * send it back to draft, which would silently drop it from the shipped pack. + */ +export function reviewRegressions( + sources: SourceMessage[], + current: LocaleEntries, + base: LocaleEntries, +): string[] { + const errors: string[] = [] + for (const locale of TARGET_LOCALES) { + for (const source of sources) { + const before = base[locale]?.[source.id] + if ( + !before?.translation || + before.fuzzy || + before.review !== 'human' || + before.sourceHash !== hashSource(source.message) + ) { + continue + } + const after = current[locale]?.[source.id] + if (!after?.translation || after.fuzzy || after.review !== 'human') { + errors.push( + `${locale}: "${source.id}" is reviewed on the base branch with the same English and must stay reviewed`, + ) + } + } + } + return errors +} + +function checkCatalogMessages( + sources: SourceMessage[], + glossary: Glossary, + options: CatalogCheckOptions = { requireReviewed: true }, +): string[] { + const current = readLocaleEntries((path) => readFileSync(path, 'utf8')) + const errors = checkTranslationEntries(sources, current, glossary, options) + const base = baseRevision() + if (base) { + errors.push( + ...reviewRegressions( + sources, + current, + readLocaleEntries((path) => readAtRevision(base, path)), + ), + ) + } + return errors +} + function checkEnglishCatalog( extractedSources: SourceMessage[], catalogSources: SourceMessage[], @@ -850,7 +921,7 @@ async function main(): Promise { if (command === 'check') { const requireReviewed = process.argv.includes('--reviewed') const errors = await checkCatalogs({ requireReviewed }) - const literals = checkLiterals() + const literals = checkRepositoryLiterals() errors.push(...literals.errors.map((error) => `literal guard: ${error}`)) if (errors.length > 0) { console.error(errors.map((error) => `[i18n] ${error}`).join('\n')) From 184a2ae3a1f7d88e327ea87ab7f4c2a0b3bf758c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 02:42:21 +0000 Subject: [PATCH 07/24] Literal guard: per-text baseline that may only shrink, stricter scanner The baseline lists each file's legacy copy by text, so new or swapped copy fails, and CI fails when the baseline gains entries relative to the base. i18n-ignore needs a reason; hyphenated labels and string constants rendered in JSX are copy; toast descriptions count once. The codemod keeps one-line bodies valid and converts explicitly named .ts modules. Enter, Space, Tab and Del leave the allowlist. --- i18n/literal-allowlist.json | 4 - scripts/i18n-codemod.ts | 23 +++++- scripts/i18n-literals.ts | 151 ++++++++++++++++++++++++++++++------ 3 files changed, 149 insertions(+), 29 deletions(-) diff --git a/i18n/literal-allowlist.json b/i18n/literal-allowlist.json index 584e6af02c..354688c61a 100644 --- a/i18n/literal-allowlist.json +++ b/i18n/literal-allowlist.json @@ -30,10 +30,6 @@ "Alt", "Shift", "Esc", - "Tab", - "Enter", - "Del", - "Space", "OK" ], "paths": { diff --git a/scripts/i18n-codemod.ts b/scripts/i18n-codemod.ts index 2dfa9db88b..9142c80772 100644 --- a/scripts/i18n-codemod.ts +++ b/scripts/i18n-codemod.ts @@ -206,7 +206,9 @@ function hookEdits(source: ts.SourceFile, component: ts.FunctionLikeDeclaration) if (!body) return [] if (ts.isBlock(body)) { const at = body.getStart(source) + 1 - return [{ start: at, end: at, text: `\n const i18n = ${HOOK}()` }] + // Keep the body's own first statement on a line of its own. + const separator = /^[ \t]*\r?\n/.test(source.text.slice(at)) ? '' : '\n' + return [{ start: at, end: at, text: `\n const i18n = ${HOOK}()${separator}` }] } return [ { @@ -341,6 +343,7 @@ export function convertSource( registry: IdRegistry, allow: Set, targets: DescriptorTargets = {}, + allKinds = path.endsWith('.tsx'), ): { output: string; planned: Planned[] } { const source = parseSource(path, text) const planned: Planned[] = [] @@ -435,6 +438,14 @@ export function convertSource( text: directAttribute ? `{${call}}` : call, }) }, + constant(node, value) { + planned.push({ + path, + line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1, + message: value, + manual: `string constant ${node.text}: make it a descriptor or translate at the use`, + }) + }, template(node) { const names = node.templateSpans.map((span) => placeholderName(span.expression)) const preview = [ @@ -475,6 +486,7 @@ export function convertSource( }, }, allow, + allKinds, ) if (edits.length === 0) return { output: text, planned } @@ -520,7 +532,14 @@ export async function convertFiles(args: string[]): Promise { ]) for (const path of [...files].sort()) { const text = readFileSync(join(ROOT, path), 'utf8') - const { output, planned } = convertSource(path, text, registry, allow, targets) + const { output, planned } = convertSource( + path, + text, + registry, + allow, + targets, + path.endsWith('.tsx') || explicit.includes(path), + ) for (const item of planned) { if (item.manual) manual += 1 else converted += 1 diff --git a/scripts/i18n-literals.ts b/scripts/i18n-literals.ts index 9410c61968..512c251c8b 100644 --- a/scripts/i18n-literals.ts +++ b/scripts/i18n-literals.ts @@ -2,6 +2,7 @@ import { readFileSync, writeFileSync } from 'node:fs' import { dirname, join, relative, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import ts from 'typescript' +import { baseRevision, readAtRevision } from './i18n-git' /** * User-visible literal scanner shared by the one-time codemod (`convert`) and @@ -108,7 +109,8 @@ type Allowlist = { paths: Record } -type Baseline = { version: 1; files: Record } +/** Legacy candidates per file, by text (a multiset: repeated copy appears once per use). */ +export type Baseline = { version: 2; files: Record } function readAllowlist(): Allowlist { return JSON.parse(readFileSync(ALLOWLIST_PATH, 'utf8')) as Allowlist @@ -132,8 +134,8 @@ function looksTranslatable(text: string, allow: Set): boolean { const trimmed = text.trim() if (!/\p{L}{2}/u.test(trimmed)) return false if (allow.has(trimmed)) return false - // Identifiers, icon names, CSS classes, paths and URLs. - if (/^[a-z0-9]+(?:[-_:./#][a-z0-9]+)+$/i.test(trimmed) && !/\s/.test(trimmed)) return false + // Icon names, snake_case keys, paths and URLs. Hyphenated words ("Read-only", "zoom-in") are copy. + if (/^[a-z0-9-]+(?:[_:./#][a-z0-9-]+)+$/i.test(trimmed)) return false if (/^(?:https?:|mailto:|\/|#|\.)/.test(trimmed)) return false if (/^[a-z][a-zA-Z0-9]*$/.test(trimmed) && /[A-Z]/.test(trimmed)) return false return true @@ -152,7 +154,7 @@ function isIgnored(source: ts.SourceFile, node: ts.Node): boolean { previousLineStart, text.indexOf('\n', start) === -1 ? text.length : text.indexOf('\n', start), ) - return window.includes('i18n-ignore') + return /i18n-ignore:\s*\S/.test(window) } function isTranslationCall(node: ts.Node): boolean { @@ -288,11 +290,55 @@ export type Visitor = { sentence(element: ts.JsxElement, children: SentenceChild[], text: string): void literal(node: ts.StringLiteral | ts.NoSubstitutionTemplateLiteral, kind: CandidateKind): void template(node: ts.TemplateExpression, kind: CandidateKind): void + /** A `const` holding copy, rendered by name in JSX or a UI prop. */ + constant(node: ts.Identifier, text: string, kind: CandidateKind): void +} + +/** `const NAME = 'Copy'` declarations anywhere in the file, by name. */ +function stringConstants( + source: ts.SourceFile, +): Map { + const constants = new Map() + const visit = (node: ts.Node): void => { + if (ts.isVariableDeclarationList(node) && (node.flags & ts.NodeFlags.Const) !== 0) { + for (const declaration of node.declarations) { + const value = declaration.initializer + if ( + ts.isIdentifier(declaration.name) && + value && + (ts.isStringLiteral(value) || ts.isNoSubstitutionTemplateLiteral(value)) + ) { + constants.set(declaration.name.text, value) + } + } + } + ts.forEachChild(node, visit) + } + visit(source) + return constants +} + +function isNotifyOptions(node: ts.Node): boolean { + const call = node.parent + return ( + ts.isObjectLiteralExpression(node) && + !!call && + ts.isCallExpression(call) && + call.arguments[1] === node && + notifyCallee(call) !== undefined + ) } /** Walks every user-visible literal in one file. */ -export function visitUiLiterals(source: ts.SourceFile, visitor: Visitor, allow: Set): void { - const notifyOnly = !source.fileName.endsWith('.tsx') +export function visitUiLiterals( + source: ts.SourceFile, + visitor: Visitor, + allow: Set, + /** Plain modules are scanned for notifications only unless the codemod was pointed at them. */ + allKinds = source.fileName.endsWith('.tsx'), +): void { + const notifyOnly = !allKinds + const constants = stringConstants(source) const literalSink = (expression: ts.Expression | undefined, kind: CandidateKind): void => { if (!expression || (notifyOnly && kind !== 'notify')) return if (ts.isParenthesizedExpression(expression)) { @@ -316,6 +362,18 @@ export function visitUiLiterals(source: ts.SourceFile, visitor: Visitor, allow: literalSink(expression.right, kind) return } + if (ts.isIdentifier(expression)) { + const value = constants.get(expression.text) + if ( + value && + looksTranslatable(value.text, allow) && + !isIgnored(source, value) && + !isIgnored(source, expression) + ) { + visitor.constant(expression, value.text, kind) + } + return + } if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) { if (looksTranslatable(expression.text, allow) && !isIgnored(source, expression)) { visitor.literal(expression, kind) @@ -376,7 +434,8 @@ export function visitUiLiterals(source: ts.SourceFile, visitor: Visitor, allow: ts.isPropertyAssignment(node) && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name)) && UI_PROPERTIES.has(node.name.text) && - !insideTranslationCall(node) + !insideTranslationCall(node) && + !isNotifyOptions(node.parent) ) { literalSink(node.initializer, 'property') } @@ -451,6 +510,8 @@ export function scanSource( names.includes(undefined) ? 'complex template interpolation' : undefined, ) }, + constant: (node, value, kind) => + add(node, kind, value, 'string constant: make it a descriptor or translate at the use'), }, allow, ) @@ -480,29 +541,56 @@ export function scanRepository(): Map { return result } +export function parseBaseline(text: string | undefined): Baseline | undefined { + if (!text) return undefined + const parsed = JSON.parse(text) as { version?: number; files?: Record } + return parsed.version === 2 ? (parsed as Baseline) : undefined +} + function readBaseline(): Baseline { - return JSON.parse(readFileSync(BASELINE_PATH, 'utf8')) as Baseline + return parseBaseline(readFileSync(BASELINE_PATH, 'utf8')) ?? { version: 2, files: {} } +} + +/** The base branch's baseline, when the base has one (see `baseRevision`). */ +function readBaseBaseline(): Baseline | undefined { + const revision = baseRevision() + return revision ? parseBaseline(readAtRevision(revision, BASELINE_PATH)) : undefined } function writeBaseline(scan: Map): void { const files = Object.fromEntries( [...scan.entries()] .sort(([a], [b]) => a.localeCompare(b)) - .map(([path, list]) => [path, list.length]), + .map(([path, list]) => [path, list.map((candidate) => candidate.text).sort()]), ) writeFileSync( BASELINE_PATH, - `${JSON.stringify({ version: 1, files } satisfies Baseline, null, 2)}\n`, + `${JSON.stringify({ version: 2, files } satisfies Baseline, null, 2)}\n`, ) } +/** Items of `values` left after removing one occurrence per item of `allowed`. */ +function beyond(values: readonly string[], allowed: readonly string[]): string[] { + const remaining = new Map() + for (const value of allowed) remaining.set(value, (remaining.get(value) ?? 0) + 1) + return values.filter((value) => { + const left = remaining.get(value) ?? 0 + if (left === 0) return true + remaining.set(value, left - 1) + return false + }) +} + /** - * The ratchet: a file may never gain hardcoded copy. Files absent from the - * baseline (every new file) must have none. + * The ratchet: a file may only keep copy its baseline already lists, so new + * or swapped copy fails, and a file absent from the baseline must have none. + * The baseline itself may only shrink relative to the base branch; exempting + * copy goes through `i18n/literal-allowlist.json` or an `i18n-ignore: `. */ export function checkLiterals( scan = scanRepository(), baseline = readBaseline(), + base?: Baseline, ): { errors: string[] improvable: string[] @@ -513,23 +601,40 @@ export function checkLiterals( let total = 0 for (const [path, candidates] of scan) { total += candidates.length - const allowed = baseline.files[path] ?? 0 - if (candidates.length > allowed) { - const listed = candidates.map( - (candidate) => ` ${path}:${candidate.line} ${JSON.stringify(candidate.text)}`, - ) + const unknown = new Set( + beyond( + candidates.map((candidate) => candidate.text), + baseline.files[path] ?? [], + ), + ) + if (unknown.size === 0) continue + const listed = candidates + .filter((candidate) => unknown.has(candidate.text)) + .map((candidate) => ` ${path}:${candidate.line} ${JSON.stringify(candidate.text)}`) + errors.push( + `${path}: untranslated user-visible literals not in the baseline. Wrap them with i18n._({ id, message }) or add an "i18n-ignore: " comment.\n${listed.join('\n')}`, + ) + } + for (const [path, allowed] of Object.entries(baseline.files)) { + const left = beyond( + allowed, + (scan.get(path) ?? []).map((candidate) => candidate.text), + ) + if (left.length > 0) improvable.push(`${path}: ${left.length} fewer`) + const added = base ? beyond(allowed, base.files[path] ?? []) : [] + if (added.length > 0) { errors.push( - `${path}: ${candidates.length} untranslated user-visible literals (baseline ${allowed}). Wrap new copy with i18n._({ id, message }) or add an "i18n-ignore: " comment.\n${listed.join('\n')}`, + `${path}: i18n/literal-baseline.json adds ${added.map((text) => JSON.stringify(text)).join(', ')} relative to the base branch; the baseline may only shrink`, ) } } - for (const [path, allowed] of Object.entries(baseline.files)) { - const current = scan.get(path)?.length ?? 0 - if (current < allowed) improvable.push(`${path}: ${current} < ${allowed}`) - } return { errors, improvable, total } } +export function checkRepositoryLiterals() { + return checkLiterals(scanRepository(), readBaseline(), readBaseBaseline()) +} + function report(scan: Map): void { const byArea = new Map() for (const [path, candidates] of scan) { @@ -547,7 +652,7 @@ function report(scan: Map): void { async function main(): Promise { const [command, ...args] = process.argv.slice(2) if (command === 'check') { - const { errors, improvable, total } = checkLiterals() + const { errors, improvable, total } = checkRepositoryLiterals() if (improvable.length > 0) { console.log( `[i18n literals] ${improvable.length} files are below their baseline; run bun run i18n:literals -- update to lock in the progress`, From 2e08651431578e5c9e3ebfaebb3729330422c0a3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 02:42:22 +0000 Subject: [PATCH 08/24] Pseudo-locale: dev/test builds only; audit allowlist matches whole words; playwright-core 1.64.1 --- apps/editor/app/client-bootstrap.tsx | 4 ++-- apps/editor/app/layout.tsx | 4 ++-- apps/editor/lib/dev-locales.ts | 11 +++++++++++ bun.lock | 6 ++---- package.json | 2 +- scripts/i18n-pseudo-audit.ts | 5 ++++- 6 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 apps/editor/lib/dev-locales.ts diff --git a/apps/editor/app/client-bootstrap.tsx b/apps/editor/app/client-bootstrap.tsx index 982e2815ad..ac33b9f387 100644 --- a/apps/editor/app/client-bootstrap.tsx +++ b/apps/editor/app/client-bootstrap.tsx @@ -11,11 +11,11 @@ import '../lib/bootstrap' import { createI18n, defaultI18n, PascalI18nProvider } from '@pascal-app/core' import { registerBundledLocales } from '@pascal-app/editor/locales' -import { registerPseudoLocale } from '@pascal-app/editor/locales/pseudo' import { type ReactNode, useEffect, useMemo } from 'react' +import { registerDevLocales } from '@/lib/dev-locales' registerBundledLocales() -if (process.env.NODE_ENV !== 'production') registerPseudoLocale() +registerDevLocales() export function ClientBootstrap({ children, diff --git a/apps/editor/app/layout.tsx b/apps/editor/app/layout.tsx index 576960860c..6af66b7ac6 100644 --- a/apps/editor/app/layout.tsx +++ b/apps/editor/app/layout.tsx @@ -1,16 +1,16 @@ import { registerBundledLocales } from '@pascal-app/editor/locales' -import { registerPseudoLocale } from '@pascal-app/editor/locales/pseudo' import { Agentation } from 'agentation' import { GeistPixelSquare } from 'geist/font/pixel' import { Barlow } from 'next/font/google' import localFont from 'next/font/local' import { headers } from 'next/headers' +import { registerDevLocales } from '@/lib/dev-locales' import { PASCAL_LOCALE_HEADER, resolveUiLocale } from '@/lib/ui-locale' import { ClientBootstrap } from './client-bootstrap' import './globals.css' registerBundledLocales() -if (process.env.NODE_ENV !== 'production') registerPseudoLocale() +registerDevLocales() const geistSans = localFont({ src: './fonts/GeistVF.woff', diff --git a/apps/editor/lib/dev-locales.ts b/apps/editor/lib/dev-locales.ts new file mode 100644 index 0000000000..10fe9716c9 --- /dev/null +++ b/apps/editor/lib/dev-locales.ts @@ -0,0 +1,11 @@ +/** + * `en-XA` is a test locale. The require sits inside a `NODE_ENV` branch that + * bundlers drop from production builds, so its catalog never ships. + */ +export function registerDevLocales(): void { + if (process.env.NODE_ENV !== 'production') { + const { registerPseudoLocale } = + require('@pascal-app/editor/locales/pseudo') as typeof import('@pascal-app/editor/locales/pseudo') + registerPseudoLocale() + } +} diff --git a/bun.lock b/bun.lock index 5d535efd91..5b96f8f300 100644 --- a/bun.lock +++ b/bun.lock @@ -17,7 +17,7 @@ "ai": "^7.0.154", "dotenv-cli": "^11.0.0", "fast-xml-parser": "^5.11.2", - "playwright-core": "1.58.0", + "playwright-core": "1.64.1", "pofile-ts": "^4.0.3", "turbo": "^2.11.10", "typescript": "npm:@typescript/typescript6@6.0.2", @@ -1947,7 +1947,7 @@ "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], - "playwright-core": ["playwright-core@1.58.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw=="], + "playwright-core": ["playwright-core@1.64.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ=="], "png-js": ["png-js@2.0.0", "", { "dependencies": { "fflate": "^0.8.2" } }, "sha512-GdzJuUMc6ZSpxFJWVxtOH1bzYHym+TOnveqUjb+VJIbZWbZzyiRGFiKhbiielfpYbgMlhHVhsJ0FTazfuRFkMA=="], @@ -2423,8 +2423,6 @@ "react-doctor/agent-install": ["agent-install@0.0.5", "", { "dependencies": { "@iarna/toml": "^2.2.5", "commander": "^14.0.0", "jsonc-parser": "^3.3.1", "picocolors": "^1.1.1", "prompts": "^2.4.2", "yaml": "^2.8.3" }, "bin": { "agent-install": "bin/agent-install.mjs" } }, "sha512-nHlms9BkP8ZiY79HrwCGiA2DcNaXrAaJrCM/BEqQ7MEsSKyCk+2A76xPGylIfASZSZE0SaU3T0bNSg4rBPIJAQ=="], - "react-doctor/playwright-core": ["playwright-core@1.64.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ=="], - "react-doctor/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "react-scan/bippy": ["bippy@0.5.41", "", { "peerDependencies": { "react": ">=17.0.1" } }, "sha512-jCP2pXXLhXqPrAN+iSEFZmLI4uUM4fjSqajh0K+TmM062VehfDT3ZJNkrTGyN701Z5XMejs9qAudSqkMGhSMKg=="], diff --git a/package.json b/package.json index f6a1dc2b70..b09604c572 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "ai": "^7.0.154", "dotenv-cli": "^11.0.0", "fast-xml-parser": "^5.11.2", - "playwright-core": "1.58.0", + "playwright-core": "1.64.1", "pofile-ts": "^4.0.3", "turbo": "^2.11.10", "typescript": "npm:@typescript/typescript6@6.0.2", diff --git a/scripts/i18n-pseudo-audit.ts b/scripts/i18n-pseudo-audit.ts index 345cfd780b..9b029f631f 100644 --- a/scripts/i18n-pseudo-audit.ts +++ b/scripts/i18n-pseudo-audit.ts @@ -33,7 +33,10 @@ function argument(name: string): string | undefined { export function untranslatedWords(text: string, allowed: readonly string[]): string[] { let rest = text for (const value of [...allowed].sort((a, b) => b.length - a.length)) { - if (value) rest = rest.split(value).join(' ') + if (!value) continue + // Whole words only: allowing the unit "in" must not hide "Find" or "Pin". + const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + rest = rest.replace(new RegExp(`(? Date: Tue, 27 Oct 2026 02:42:22 +0000 Subject: [PATCH 09/24] i18n: migrate the viewer toolbar so the literal baseline only shrinks Scene theme names move to a shared helper used by both toolbars. 64 new messages; zh-CN/fr/es/ja drafts are fuzzy and await human review. --- i18n/literal-baseline.json | 3465 ++++++++++++++++- .../editor/src/i18n/locales/en-XA/messages.ts | 2 +- .../editor/src/i18n/locales/en/messages.po | 274 +- .../editor/src/i18n/locales/en/messages.ts | 2 +- .../editor/src/i18n/locales/es/messages.po | 658 +++- .../editor/src/i18n/locales/fr/messages.po | 658 +++- .../editor/src/i18n/locales/ja/messages.po | 658 +++- .../editor/src/i18n/locales/zh-CN/messages.po | 658 +++- packages/editor/src/index.tsx | 1 + 9 files changed, 6135 insertions(+), 241 deletions(-) diff --git a/i18n/literal-baseline.json b/i18n/literal-baseline.json index e67993f029..351cd92278 100644 --- a/i18n/literal-baseline.json +++ b/i18n/literal-baseline.json @@ -1,198 +1,3275 @@ { - "version": 1, + "version": 2, "files": { - "apps/editor/app/embed/[id]/page.tsx": 1, - "apps/editor/app/import/import-client.tsx": 8, - "apps/editor/app/import/page.tsx": 4, - "apps/editor/app/login/login-form.tsx": 6, - "apps/editor/app/login/page.tsx": 3, - "apps/editor/app/page.tsx": 4, - "apps/editor/app/project/[id]/page.tsx": 4, - "apps/editor/app/settings/page.tsx": 23, - "apps/editor/app/setup/page.tsx": 3, - "apps/editor/components/app-shell.tsx": 1, - "apps/editor/components/build-tab.tsx": 37, - "apps/editor/components/create-project-button.tsx": 4, - "apps/editor/components/editor-navbar.tsx": 6, - "apps/editor/components/embed-viewer.tsx": 2, - "apps/editor/components/kitchen-browser.tsx": 8, - "apps/editor/components/scene-card.tsx": 20, - "apps/editor/components/scene-loader.tsx": 9, - "apps/editor/components/share-panel.tsx": 15, - "apps/editor/components/viewer-toolbar.tsx": 53, - "packages/editor/src/components/editor-2d/floorplan-measurement-tool-layer.tsx": 4, - "packages/editor/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx": 2, - "packages/editor/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx": 1, - "packages/editor/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx": 1, - "packages/editor/src/components/editor/capture-level-picker.tsx": 2, - "packages/editor/src/components/editor/delete-confirmation-dialog.tsx": 21, - "packages/editor/src/components/editor/first-person-controls.tsx": 7, - "packages/editor/src/components/editor/floating-action-menu.tsx": 9, - "packages/editor/src/components/editor/floorplan-mode-coordinator.tsx": 2, - "packages/editor/src/components/editor/floorplan-panel.tsx": 23, - "packages/editor/src/components/editor/footprint-height-handle.tsx": 2, - "packages/editor/src/components/editor/index.tsx": 12, - "packages/editor/src/components/editor/join-walls-pill.tsx": 1, - "packages/editor/src/components/editor/node-action-menu.tsx": 10, - "packages/editor/src/components/editor/open-wall-ends-3d-layer.tsx": 1, - "packages/editor/src/components/editor/open-wall-ends-hint.tsx": 1, - "packages/editor/src/components/editor/quick-measurement-card.tsx": 5, - "packages/editor/src/components/editor/riser-diagram-panel.tsx": 6, - "packages/editor/src/components/editor/room-controls.tsx": 2, - "packages/editor/src/components/editor/room-handles-2d.tsx": 3, - "packages/editor/src/components/editor/room-handles.tsx": 1, - "packages/editor/src/components/editor/snapshot-capture-overlay.tsx": 24, - "packages/editor/src/components/editor/views/host-view.tsx": 3, - "packages/editor/src/components/editor/views/plugins-view.tsx": 38, - "packages/editor/src/components/editor/views/view-bar.tsx": 19, - "packages/editor/src/components/point-ask/bubble.tsx": 12, - "packages/editor/src/components/point-ask/hover-chip.tsx": 2, - "packages/editor/src/components/point-ask/mode-pill.tsx": 3, - "packages/editor/src/components/point-ask/pins.tsx": 15, - "packages/editor/src/components/procedural-items/inspector.tsx": 11, - "packages/editor/src/components/tools/distribution/distribution-run-tool.tsx": 3, - "packages/editor/src/components/ui/action-menu/camera-actions.tsx": 6, - "packages/editor/src/components/ui/action-menu/control-modes.tsx": 2, - "packages/editor/src/components/ui/action-menu/follow-pascal-pill.tsx": 1, - "packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx": 1, - "packages/editor/src/components/ui/action-menu/furnish-tools.tsx": 5, - "packages/editor/src/components/ui/action-menu/measurement-control.tsx": 20, - "packages/editor/src/components/ui/action-menu/point-ask-button.tsx": 3, - "packages/editor/src/components/ui/action-menu/structure-tools.tsx": 22, - "packages/editor/src/components/ui/action-menu/view-toggles.tsx": 39, - "packages/editor/src/components/ui/command-palette/editor-commands.tsx": 29, - "packages/editor/src/components/ui/command-palette/index.tsx": 14, - "packages/editor/src/components/ui/controls/finish-swatch.tsx": 2, - "packages/editor/src/components/ui/controls/material-paint-panel.tsx": 13, - "packages/editor/src/components/ui/controls/material-picker.tsx": 1, - "packages/editor/src/components/ui/controls/material-properties-editor.tsx": 8, - "packages/editor/src/components/ui/controls/scene-material-list.tsx": 11, - "packages/editor/src/components/ui/controls/slider-control.tsx": 1, - "packages/editor/src/components/ui/controls/terrain-sculpt-panel.tsx": 16, - "packages/editor/src/components/ui/floating-level-selector.tsx": 31, - "packages/editor/src/components/ui/helpers/building-helper.tsx": 3, - "packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx": 22, - "packages/editor/src/components/ui/helpers/helper-manager.tsx": 51, - "packages/editor/src/components/ui/helpers/item-helper.tsx": 4, - "packages/editor/src/components/ui/helpers/registered-tool-helper.tsx": 1, - "packages/editor/src/components/ui/item-catalog/catalog-items.tsx": 3, - "packages/editor/src/components/ui/level-duplicate-dialog.tsx": 12, - "packages/editor/src/components/ui/panels/collections/collections-popover.tsx": 9, - "packages/editor/src/components/ui/panels/floor-foundation-panel.tsx": 20, - "packages/editor/src/components/ui/panels/floor-opening-panel.tsx": 11, - "packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx": 1, - "packages/editor/src/components/ui/panels/mobile-selection-bar.tsx": 5, - "packages/editor/src/components/ui/panels/multi-height-mode.tsx": 5, - "packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx": 1, - "packages/editor/src/components/ui/panels/multi-selection-panel.tsx": 15, - "packages/editor/src/components/ui/panels/panel-manager.tsx": 1, - "packages/editor/src/components/ui/panels/panel-wrapper.tsx": 7, - "packages/editor/src/components/ui/panels/parametric-field-control.tsx": 1, - "packages/editor/src/components/ui/panels/parametric-inspector.tsx": 5, - "packages/editor/src/components/ui/panels/reference-panel.tsx": 38, - "packages/editor/src/components/ui/panels/room-construction-rows.tsx": 33, - "packages/editor/src/components/ui/panels/room-openings-field.tsx": 8, - "packages/editor/src/components/ui/panels/room-panel.tsx": 43, - "packages/editor/src/components/ui/panels/shape-choice.tsx": 2, - "packages/editor/src/components/ui/panels/wall-region-list.tsx": 3, - "packages/editor/src/components/ui/primitives/dialog.tsx": 1, - "packages/editor/src/components/ui/primitives/error-boundary.tsx": 2, - "packages/editor/src/components/ui/primitives/opacity-control.tsx": 1, - "packages/editor/src/components/ui/primitives/sheet.tsx": 1, - "packages/editor/src/components/ui/primitives/shortcut-token.tsx": 5, - "packages/editor/src/components/ui/primitives/sidebar.tsx": 5, - "packages/editor/src/components/ui/scene-loader.tsx": 3, - "packages/editor/src/components/ui/sidebar/icon-rail.tsx": 2, - "packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx": 6, - "packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx": 6, - "packages/editor/src/components/ui/sidebar/panels/settings-panel/animation-speed-setting.tsx": 6, - "packages/editor/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx": 8, - "packages/editor/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx": 10, - "packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx": 83, - "packages/editor/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx": 10, - "packages/editor/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx": 26, - "packages/editor/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx": 3, - "packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx": 2, - "packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx": 3, - "packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx": 59, - "packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx": 7, - "packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-drag.tsx": 1, - "packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx": 5, - "packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx": 1, - "packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx": 12, - "packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx": 4, - "packages/editor/src/components/ui/slider-demo.tsx": 2, - "packages/editor/src/components/walkthrough-hud.tsx": 6, - "packages/nodes/src/block/panel.tsx": 14, - "packages/nodes/src/block/selection.tsx": 33, - "packages/nodes/src/box-vent/panel.tsx": 24, - "packages/nodes/src/cabinet/compartment-card.tsx": 48, - "packages/nodes/src/cabinet/essential-controls.tsx": 17, - "packages/nodes/src/cabinet/kitchen-collection.tsx": 4, - "packages/nodes/src/cabinet/kitchen-module-actions.tsx": 18, - "packages/nodes/src/cabinet/panel.tsx": 74, - "packages/nodes/src/cabinet/run-panel.tsx": 68, - "packages/nodes/src/ceiling/panel.tsx": 28, - "packages/nodes/src/chimney/panel.tsx": 61, - "packages/nodes/src/column/panel.tsx": 81, - "packages/nodes/src/construction-dimension/panel.tsx": 49, - "packages/nodes/src/cupola/panel.tsx": 16, - "packages/nodes/src/door/panel.tsx": 88, - "packages/nodes/src/dormer/panel-actions-section.tsx": 4, - "packages/nodes/src/dormer/panel-position-section.tsx": 2, - "packages/nodes/src/dormer/panel-windows-section.tsx": 11, - "packages/nodes/src/dormer/panel.tsx": 21, - "packages/nodes/src/downspout/inspector-editors.tsx": 1, - "packages/nodes/src/duct-fitting/inspector-editors.tsx": 2, - "packages/nodes/src/duct-fitting/tool.tsx": 5, - "packages/nodes/src/duct-terminal/tool.tsx": 4, - "packages/nodes/src/elevator/panel.tsx": 45, - "packages/nodes/src/eyebrow-vent/panel.tsx": 15, - "packages/nodes/src/fence-feature/actions.tsx": 2, - "packages/nodes/src/fence-feature/inspector.tsx": 29, - "packages/nodes/src/fence/inspector-editors.tsx": 24, - "packages/nodes/src/fence/move-endpoint-tool.tsx": 2, - "packages/nodes/src/gutter/downspouts-panel.tsx": 4, - "packages/nodes/src/hvac-equipment/tool.tsx": 1, - "packages/nodes/src/item/authored-params.tsx": 7, - "packages/nodes/src/item/panel.tsx": 20, - "packages/nodes/src/liquid-line/tool.tsx": 2, - "packages/nodes/src/measurement/selection.tsx": 1, - "packages/nodes/src/measurement/tool.tsx": 3, - "packages/nodes/src/pipe-fitting/tool.tsx": 3, - "packages/nodes/src/pipe-trap/tool.tsx": 2, - "packages/nodes/src/ridge-vent/panel.tsx": 17, - "packages/nodes/src/roof-segment/panel.tsx": 59, - "packages/nodes/src/roof/barrel-panel.tsx": 4, - "packages/nodes/src/roof/glazing-controls.tsx": 17, - "packages/nodes/src/roof/glazing-panel-editor.tsx": 14, - "packages/nodes/src/roof/glazing-panel.tsx": 28, - "packages/nodes/src/roof/panel.tsx": 47, - "packages/nodes/src/shared/item-interaction-actions.tsx": 2, - "packages/nodes/src/shared/run-hanger-inspector.tsx": 12, - "packages/nodes/src/shared/system-check-panel.tsx": 26, - "packages/nodes/src/site/panel.tsx": 37, - "packages/nodes/src/skylight/panel.tsx": 33, - "packages/nodes/src/slab/panel.tsx": 34, - "packages/nodes/src/solar-panel/panel.tsx": 22, - "packages/nodes/src/spawn/panel.tsx": 7, - "packages/nodes/src/stair-segment/panel.tsx": 32, - "packages/nodes/src/stair/construction-controls.tsx": 16, - "packages/nodes/src/stair/panel.tsx": 89, - "packages/nodes/src/stair/railing-controls.tsx": 15, - "packages/nodes/src/turbine-vent/panel.tsx": 19, - "packages/nodes/src/unit/unit-panel.tsx": 15, - "packages/nodes/src/wall/actions.tsx": 4, - "packages/nodes/src/wall/curtain-wall-panel.tsx": 70, - "packages/nodes/src/wall/move-endpoint-tool.tsx": 2, - "packages/nodes/src/wall/panel.tsx": 86, - "packages/nodes/src/window/panel.tsx": 66, - "packages/nodes/src/zone/quantities-panel.tsx": 14, - "packages/ui/src/button.tsx": 1, - "packages/ui/src/card.tsx": 1, - "packages/viewer/src/components/viewer/glb-scene.tsx": 2, - "packages/viewer/src/components/viewer/perf-panel.tsx": 21, - "packages/viewer/src/components/viewer/unsupported-gpu-fallback.tsx": 2, - "packages/viewer/src/systems/interactive/control-widget.tsx": 2 + "apps/editor/app/embed/[id]/page.tsx": [ + "{name} · Pascal" + ], + "apps/editor/app/import/import-client.tsx": [ + " · {?} m² of floor", + "Contents", + "Creating the scene…", + "Fetching the scene…", + "Import as a new scene", + "Scene name", + "Try again", + "node" + ], + "apps/editor/app/import/page.tsx": [ + "Home", + "Import", + "Import a scene", + "Review the file before it becomes a scene. Nothing is created until you confirm." + ], + "apps/editor/app/login/login-form.tsx": [ + "Could not reach the editor.", + "Password", + "Sign in", + "Signing in…", + "That password is not right.", + "Too many attempts. Try again in a minute." + ], + "apps/editor/app/login/page.tsx": [ + "Enter the admin password set for this instance.", + "Sign in to this editor", + "Sign in · Pascal" + ], + "apps/editor/app/page.tsx": [ + "Projects", + "Settings", + "Settings", + "Your projects live here. Start one to begin designing." + ], + "apps/editor/app/project/[id]/page.tsx": [ + "All projects", + "Project not found", + "There is no project with id", + "on this editor." + ], + "apps/editor/app/settings/page.tsx": [ + "About", + "Account", + "Agent token", + "Agents and scripts send the PASCAL_SCENE_API_TOKEN value in an Authorization: Bearer header.", + "All projects", + "Configured", + "Connect an agent", + "Data directory", + "Documentation", + "Instance", + "Not configured", + "Public URL", + "Scene API", + "Set PASCAL_SCENE_API_TOKEN on this instance, then send it in an Authorization: Bearer header from agents and scripts.", + "Settings", + "Settings · Pascal", + "Sign out", + "Signed in as the instance admin.", + "Source code", + "Version", + "development", + "{publicUrl}/api/scenes", + "~/.pascal/data" + ], + "apps/editor/app/setup/page.tsx": [ + "Set an admin password in the environment and restart. Until then, nothing is served from this address.", + "Set up · Pascal", + "This editor is reachable but not protected yet" + ], + "apps/editor/components/app-shell.tsx": [ + "Pascal home" + ], + "apps/editor/components/build-tab.tsx": [ + "Add Gate", + "Add Open Passage", + "Add to rooms", + "Choose Gate or Open Passage, then click its position on any fence. Find placed gates and openings under their fence in the scene graph.", + "Click a lineset to lay the line beside it.", + "Double gate", + "Features & extensions", + "Fence features", + "Follow lineset", + "Gate", + "Gate style", + "Horizontal boards", + "Hover a fence to preview. Click to place. Esc cancels. Leave room between openings.", + "Leaves", + "Liquid Line", + "MEP", + "Match fence style", + "Match fence style", + "Match fence style", + "Off", + "On", + "Open rails", + "Opening", + "Opening width (m)", + "Outdoor", + "Picket", + "Roof type", + "Rooms already create their floor and ceiling. Use these for platforms and one-off structure.", + "Search build tools and kitchen items", + "Search tools, fridge, sink…", + "Select a curved wall to match its radius and arc.", + "Single gate", + "Slab, ceiling, column…", + "Solid privacy", + "Trace a line alongside an existing lineset (F).", + "Vertical slats", + "← All build tools" + ], + "apps/editor/components/create-project-button.tsx": [ + "Creating…", + "Failed to create project", + "Failed to create project ({status})", + "New project" + ], + "apps/editor/components/editor-navbar.tsx": [ + "All projects", + "All projects", + "Preview", + "Project name", + "Rename project", + "Share" + ], + "apps/editor/components/embed-viewer.tsx": [ + "Made with Pascal", + "This project could not be shown in 3D here. Try a browser with hardware acceleration turned on." + ], + "apps/editor/components/kitchen-browser.tsx": [ + "Add to kitchen", + "Add {label}", + "Choose an item, then click to place it. Appliances include their cabinetry.", + "Find in this project · {length}", + "Find {?}", + "Kitchen cabinet", + "No matching kitchen items placed yet.", + "Select and show in scene" + ], + "apps/editor/components/scene-card.tsx": [ + "Actions for {name}", + "Cancel", + "Cancel", + "Could not reach the editor.", + "Could not reach the editor.", + "Delete", + "Delete", + "Delete failed ({status})", + "Delete project?", + "Deleting…", + "Project name", + "Rename", + "Rename failed ({status})", + "Rename project", + "Save", + "Saving…", + "This project changed since the page loaded. Reload and try again.", + "This project changed since the page loaded. Reload and try again.", + "node", + "nodes", + "· Updated", + "“{name}” will be removed from this editor, along with everything in it." + ], + "apps/editor/components/scene-loader.tsx": [ + "Another session saved first — refresh?", + "Build", + "Dismiss", + "Items", + "Paint", + "Reload", + "Scene", + "Settings", + "Your changes haven't been saved. Reload to pick up the latest version." + ], + "apps/editor/components/share-panel.tsx": [ + "Anyone with the link can view this project. They cannot edit it.", + "Copied", + "Copy", + "Could not read the sharing state.", + "Could not turn off the public link.", + "Could not turn on the public link.", + "Embed code", + "Embed code", + "Embed link", + "Hide controls", + "Link", + "Only the 3D view, no header or toolbar.", + "Open", + "Public link", + "Share project" + ], + "packages/editor/src/components/editor-2d/floorplan-measurement-tool-layer.tsx": [ + "ALIGN ", + "Create", + "Extrusion height", + "Extrusion height" + ], + "packages/editor/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx": [ + "Wall end not joined", + "{?}{opacity:0.4}" + ], + "packages/editor/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx": [ + "Cannot read \"{?}\"" + ], + "packages/editor/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx": [ + "override" + ], + "packages/editor/src/components/editor/capture-level-picker.tsx": [ + "Levels in the shot", + "Whole building" + ], + "packages/editor/src/components/editor/delete-confirmation-dialog.tsx": [ + "Add walls", + "Add walls to {room}?", + "Adds {?} · the room loses {?} m² of floor.", + "Cancel", + "Delete", + "Delete", + "Delete all", + "Delete items", + "Delete {?}?", + "Delete {?}?", + "Remove", + "Remove", + "Remove all", + "Remove the ceiling from {room}?", + "Remove the floor from {room}?", + "Remove walls", + "Remove walls from {room}?", + "Removes the ceiling.", + "Removes the floor.", + "This removes every selected element. You can undo the deletion while it remains in the editor history.", + "{hosted} {?} on it. Keep {it} at {its} height, or delete {it} too." + ], + "packages/editor/src/components/editor/first-person-controls.tsx": [ + "Lights", + "Place a spawn point from the Build tab to control where walkthrough starts.", + "door", + "door button", + "elevator button", + "item", + "window" + ], + "packages/editor/src/components/editor/floating-action-menu.tsx": [ + "Axis", + "R/T rotate", + "System", + "register", + "registers", + "run", + "runs", + "⌥ axis", + "⚠ no equipment" + ], + "packages/editor/src/components/editor/floorplan-mode-coordinator.tsx": [ + "Dismiss", + "Switch to Expert" + ], + "packages/editor/src/components/editor/floorplan-panel.tsx": [ + "Any decimal works. Use the known real length, not the drawn value.", + "Cancel", + "Centimeters", + "Click one end of a distance you know — e.g. a dimension printed on the plan", + "Click the other end of that distance", + "Drawn line", + "Enter a length greater than 0.", + "Enter the real-world length of the line you just drew. The image will resize to match it.", + "Feet", + "Image will scale {?}x from the first point.", + "Inches", + "Meters", + "Real length", + "Ref {?}", + "Save Scale", + "Set overlay scale", + "Switch to a building level to view and edit the floorplan.", + "ctrl", + "e.g. 3.5, 180cm or 5'11\"", + "panel", + "resize", + "rotate", + "set scale" + ], + "packages/editor/src/components/editor/footprint-height-handle.tsx": [ + "Floor top", + "Foundation", + "footprint-height" + ], + "packages/editor/src/components/editor/index.tsx": [ + "Back to home", + "Camera controls hint", + "Dismiss", + "Dismiss camera controls hint", + "Expand sidebar", + "Left click", + "Middle click", + "Reload editor", + "Right click", + "Scroll wheel", + "Space", + "The editor scene failed to render", + "You can retry the scene or return home without reloading the whole app shell." + ], + "packages/editor/src/components/editor/join-walls-pill.tsx": [ + "Join walls" + ], + "packages/editor/src/components/editor/node-action-menu.tsx": [ + "Curve", + "Cut out", + "Duplicate", + "Edit mesh", + "Find in catalog", + "Group selection", + "Move", + "Rotate left", + "Rotate right", + "Ungroup selection" + ], + "packages/editor/src/components/editor/open-wall-ends-3d-layer.tsx": [ + "Wall end not joined" + ], + "packages/editor/src/components/editor/open-wall-ends-hint.tsx": [ + "Show" + ], + "packages/editor/src/components/editor/quick-measurement-card.tsx": [ + "Click another surface to replace", + "Click surface to pin", + "Live lens", + "Pinned", + "{?} {?} measurements" + ], + "packages/editor/src/components/editor/riser-diagram-panel.tsx": [ + "DWV plumbing isometric", + "DWV riser diagram", + "No drain, waste, or vent pipes yet. Draw plumbing to see the riser diagram.", + "Riser Diagram", + "Vent", + "Waste" + ], + "packages/editor/src/components/editor/room-controls.tsx": [ + "Add stairs", + "Divide room" + ], + "packages/editor/src/components/editor/room-handles-2d.tsx": [ + "Floor height", + "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", + "Capture", + "Capture", + "Capturing…", + "Close capture mode", + "Crop", + "Drag the area you want to capture", + "Drone", + "Esc to cancel", + "Field of view", + "Format", + "Lens", + "Orbit", + "Preset · square", + "Reset field of view", + "Saved", + "Standard", + "Switch back to orbit to drag a capture area", + "Take snapshot", + "Take snapshot", + "Viewport", + "Walk", + "snapshot" + ], + "packages/editor/src/components/editor/views/host-view.tsx": [ + "\"{label}\" crashed", + "Loading…", + "This view isn't available" + ], + "packages/editor/src/components/editor/views/plugins-view.tsx": [ + "About", + "Add focused tools and content to", + "Adds a new tool panel to the editor.", + "Adds a new tool panel to the editor.", + "All plugins", + "All plugins", + "Browse", + "By", + "By {name}", + "Can access", + "Category", + "Close details", + "Create a Pascal plugin", + "Credits", + "Doesn't use credits", + "Install", + "Install", + "Install in {projectName}", + "Installed", + "Installed in {projectName}", + "Manage", + "No plugins here yet.", + "No plugins match “{?}”{?}.", + "Not installed", + "Open {label}", + "Plugin categories", + "Plugins", + "Runs in the editor. No Pascal services, no outside accounts.", + "Search plugins", + "Search plugins", + "Undo", + "Uninstall", + "Uses this project's credits", + "View plugin", + "installed", + "this project", + "uninstalled", + "{label} details" + ], + "packages/editor/src/components/editor/views/view-bar.tsx": [ + "Auto", + "Browse plugins", + "Close split (\\)", + "Close {label}", + "Ground", + "Keep the ground solid", + "More views", + "Pane {?} views", + "Pin to the view bar", + "Pin {label}", + "Solid", + "Split", + "Split (\\)", + "Swap panes", + "Swap panes", + "Unpin from the view bar", + "Unpin {label}", + "Veil the ground over a level below grade", + "Views" + ], + "packages/editor/src/components/point-ask/bubble.tsx": [ + "Ask Pascal", + "Ask Pascal", + "Dictate", + "Drag to move it aside", + "No picture", + "Queue", + "Queue", + "Remove the area", + "Remove {name}", + "Send", + "Stop dictating", + "What Pascal will see" + ], + "packages/editor/src/components/point-ask/hover-chip.tsx": [ + "Pascal is working on this", + "⌥ the wall" + ], + "packages/editor/src/components/point-ask/mode-pill.tsx": [ + "Before", + "Point at anything to ask Pascal", + "· Esc to leave" + ], + "packages/editor/src/components/point-ask/pins.tsx": [ + "After", + "After", + "Change more", + "Hold to see before", + "Keep", + "Open in chat", + "Open in chat", + "Redo", + "See why", + "Sent to Pascal", + "Showing before", + "Try again", + "Undo", + "Undo anyway", + "You've changed the scene since. Undoing also removes those changes." + ], + "packages/editor/src/components/procedural-items/inspector.tsx": [ + "Adjust design", + "Back", + "Edit parts", + "Invalid attachment", + "Invalid edit", + "Invalid placement", + "Invalid position", + "Invalid reset", + "Position", + "Reset this part", + "pos" + ], + "packages/editor/src/components/tools/distribution/distribution-run-tool.tsx": [ + "Length:", + "Tab: direction", + "type a length" + ], + "packages/editor/src/components/ui/action-menu/camera-actions.tsx": [ + "Orbit Left", + "Orbit Left", + "Orbit Right", + "Orbit Right", + "Top View", + "Top View" + ], + "packages/editor/src/components/ui/action-menu/control-modes.tsx": [ + "Delete", + "Select" + ], + "packages/editor/src/components/ui/action-menu/follow-pascal-pill.tsx": [ + "Resume following" + ], + "packages/editor/src/components/ui/action-menu/follow-pascal-toggle.tsx": [ + "Follow Pascal: {?}" + ], + "packages/editor/src/components/ui/action-menu/furnish-tools.tsx": [ + "Appliance", + "Bathroom", + "Furniture", + "Kitchen", + "Outdoor" + ], + "packages/editor/src/components/ui/action-menu/measurement-control.tsx": [ + "Angle", + "Angular dimension", + "Arc length", + "Area", + "Center mark", + "Chord dimension", + "Continuous dimension", + "Coordinate dimensions", + "Diameter dimension", + "Distance", + "Floor plan", + "Linear dimension", + "Measure: {selectedLabel}", + "Measure: {selectedLabel}", + "Measurement options", + "Measurement type", + "Perimeter", + "Radius dimension", + "Smart", + "Volume" + ], + "packages/editor/src/components/ui/action-menu/point-ask-button.tsx": [ + "Point and ask", + "Point and ask (C)", + "Point and ask works in the 3D view" + ], + "packages/editor/src/components/ui/action-menu/structure-tools.tsx": [ + "Ceiling", + "Column", + "DWV Pipe", + "Door", + "Duct", + "Duct Fitting", + "Elevator", + "Fence", + "Gable Roof", + "HVAC Unit", + "Lineset", + "Liquid Line", + "Pipe Fitting", + "Register", + "Shelf", + "Slab", + "Spawn Point", + "Stairs", + "Trap", + "Wall", + "Window", + "Zone" + ], + "packages/editor/src/components/ui/action-menu/view-toggles.tsx": [ + "Delete guide image", + "Delete scan", + "Delete {noun}", + "Guide image settings", + "Guide image {?}", + "Guide images", + "Guide images", + "Guides", + "Guides: {?}", + "Hide reference floor", + "Hide {?}", + "No lower floor available.", + "Opacity", + "Opacity", + "Opacity", + "Opacity", + "Reference floor", + "Reference floor", + "Reference floor settings", + "Reference floor: {selectedLevelName}", + "Reference settings", + "References", + "References: {?}", + "Riser diagram", + "Scan settings", + "Scan {?}", + "Scans", + "Scans", + "Scans", + "Scans: {?}", + "Show reference floor", + "Show {?}", + "Upload GLB meshes as scan references or blueprint images as guide references.", + "Upload GLB meshes as scan references or blueprint images as guide references.", + "Upload GLB meshes as scan references or blueprint images as guide references.", + "Upload GLB meshes as scan references or blueprint images as guide references.", + "Upload scan or guide image", + "below", + "guide image", + "on this level", + "on this level", + "on this level", + "scan" + ], + "packages/editor/src/components/ui/command-palette/editor-commands.tsx": [ + "Add Level", + "Ceiling Tool", + "Copy Share Link", + "Delete Level", + "Delete Selection", + "Door Tool", + "Exit unit focus", + "Export 3D Model (GLB)", + "Export Scene (JSON)", + "Focus unit: {?}", + "Go to Level", + "Item Tool", + "Material Paint", + "New unit", + "Redo", + "Rename Level", + "Sculpt Terrain", + "Slab Tool", + "Stair Tool", + "Switch to Rendered", + "Switch to Solid", + "Take Screenshot", + "Take Snapshot", + "Toggle Fullscreen", + "Undo", + "Wall Mode", + "Wall Tool", + "Window Tool", + "Zone Tool" + ], + "packages/editor/src/components/ui/command-palette/index.tsx": [ + "Command Palette", + "Filter options…", + "Go to Level", + "No commands found.", + "Rename Level", + "Rename to", + "Search actions…", + "Type a new name above…", + "Type a new name…", + "Wall Mode", + "back", + "close", + "navigate", + "select" + ], + "packages/editor/src/components/ui/controls/finish-swatch.tsx": [ + "Default", + "Default" + ], + "packages/editor/src/components/ui/controls/material-paint-panel.tsx": [ + "Add material", + "Add material", + "Click a painted part of a wall, floor or ceiling to remove it, or a painted surface to reset it to its default.", + "Erase", + "Erase: click a painted part to remove it, or a painted surface to reset it", + "No custom materials yet — add one with +.", + "Paint", + "Pick material", + "Pick: click a surface to paint with its material (or hold Alt / Option)", + "Polygon: click the points of a shape on a floor or ceiling", + "Rectangle: press anywhere on a wall, floor or ceiling, drag to the opposite corner", + "Scene materials", + "Whole surface: a click paints the surface under it" + ], + "packages/editor/src/components/ui/controls/material-picker.tsx": [ + "New material" + ], + "packages/editor/src/components/ui/controls/material-properties-editor.tsx": [ + "Back", + "Color", + "Double", + "Front", + "Metalness", + "Opacity", + "Roughness", + "Side" + ], + "packages/editor/src/components/ui/controls/scene-material-list.tsx": [ + "Delete", + "Delete", + "Duplicate", + "Duplicate", + "Edit", + "Edit", + "Paint with", + "Paint with", + "Used by", + "part", + "parts" + ], + "packages/editor/src/components/ui/controls/slider-control.tsx": [ + "Mixed" + ], + "packages/editor/src/components/ui/controls/terrain-sculpt-panel.tsx": [ + "Clear terrain", + "Click the ground to pick its height as the target.", + "Every flatten stroke levels toward this height.", + "Flatten", + "Level lot", + "Lower", + "No target yet — the first click samples the ground under it.", + "Pick target height from the ground", + "Raise", + "Round", + "Size", + "Smooth", + "Softness", + "Square", + "Strength", + "Target" + ], + "packages/editor/src/components/ui/floating-level-selector.tsx": [ + "10 ft", + "8 ft", + "9 ft", + "? All walls, floors, and objects on this level will be permanently removed.", + "Add a floor under the roof", + "Add level above", + "Add level below", + "Are you sure you want to delete", + "Cancel", + "Delete", + "Delete level", + "Delete level", + "Delete level", + "Drag to reorder", + "Duplicate level", + "Duplicate with options...", + "Exit unit focus", + "Exit unit focus", + "Focused unit has zones here", + "Ground line: the levels under it are below grade", + "Insert level here", + "Level height", + "Level height", + "Paste copied selection", + "Reorder {levelName}", + "Seat the building so this floor stands at grade; the floors under it are below grade", + "Set as ground floor", + "The ground floor stands {?} {displayUnit} {?} grade. Seat the ground floor 8 in over grade", + "The ground level cannot be deleted", + "This floor stands at grade", + "Unit" + ], + "packages/editor/src/components/ui/helpers/building-helper.tsx": [ + "Cancel", + "Place building", + "Rotate" + ], + "packages/editor/src/components/ui/helpers/contextual-helper-panel.tsx": [ + "Cancel placement", + "Continuation — click or press C to cycle", + "Drag to draw fence", + "Fence type — click or press T to switch between straight, curved and freehand", + "Fewer shortcuts", + "Finish curve (or double-click)", + "Grid step — click or tap Ctrl to cycle", + "Grid: {?} m", + "Hover a painted surface to erase", + "Hover a surface to paint", + "Hover a surface to pick its material", + "More shortcuts", + "Place gate on a fence", + "Place passage on a fence", + "Select a material to paint", + "Snapping mode — click or press Shift to cycle", + "Snapping: {?}", + "Straight continuation is unavailable for curved or freehand fences", + "Straight fence continuation — click or press C to toggle", + "Straight: Continuous", + "Straight: Single", + "{verb} scope — click or press Shift to cycle" + ], + "packages/editor/src/components/ui/helpers/helper-manager.tsx": [ + "Add point", + "Add point · click the first to close", + "Add point · click the first to close", + "Add point · click the first to close", + "Brush size", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel", + "Cancel picking", + "Cancel stroke", + "Done", + "Done", + "Draw the mezzanine", + "Draw the opening", + "Draw the terrace", + "Exit smart measure", + "Finish", + "Finish", + "Finish at the edge", + "Free move", + "Free move · slide doors and windows", + "Hold to pick a material", + "Inspect surface dimensions", + "Paint with this material", + "Pick target height", + "Pin measurement lens", + "Place", + "Place inside the room", + "Press anywhere, drag to the opposite corner", + "Raise or lower", + "Remove a painted part, or reset a surface", + "Remove last point", + "Remove last point", + "Remove last point", + "Remove last point", + "Resize", + "Resize", + "Rotate the selection ±45°", + "Rotate ±45°", + "Rotate ±45°", + "Set one corner, then the opposite", + "Set one corner, then the opposite" + ], + "packages/editor/src/components/ui/helpers/item-helper.tsx": [ + "Cancel", + "Force place", + "Place", + "Rotate" + ], + "packages/editor/src/components/ui/helpers/registered-tool-helper.tsx": [ + "Guided constraints bypassed" + ], + "packages/editor/src/components/ui/item-catalog/catalog-items.tsx": [ + "Intensity", + "Intensity", + "Intensity" + ], + "packages/editor/src/components/ui/level-duplicate-dialog.tsx": [ + "Cancel", + "Choose what to copy from", + "Duplicate", + "Duplicate Level", + "Everything", + "Structure + furniture", + "Structure + materials", + "Structure only", + "Structure with the current material and finish assignments.", + "Structure, finishes, and placed items, without guide references.", + "Structure, materials, furniture, and references.", + "Walls, slabs, roofs, stairs, windows, and doors without finishes." + ], + "packages/editor/src/components/ui/panels/collections/collections-popover.tsx": [ + "Cancel", + "Collection name…", + "Collections", + "Delete", + "Delete", + "Delete \"{name}\"?", + "New", + "No collections yet. Create one to group elements together.", + "Rename" + ], + "packages/editor/src/components/ui/panels/floor-foundation-panel.tsx": [ + "A thicker floor grows upward: the rooms below keep their height.", + "Edge finish", + "Floor plate", + "Floor plate {thicknessLabel} thick, resting on the walls below", + "Floor thickness", + "Floor top", + "Floor top +", + "Foundation finish", + "Foundation height", + "Not to scale", + "On the ground", + "Raised on a foundation", + "Slab", + "Slab thickness", + "Slab {thicknessLabel} thick on a {foundationLabel} foundation, floor top {?} above the ground", + "Slab {thicknessLabel} thick on the ground, floor top {?} above the ground", + "The floor's outside edge, all around the footprint.", + "The foundation stands on the ground; the slab sits on it.", + "The slab sits on the foundation (or the ground): a thicker slab raises the floor top and everything on it.", + "Under the floor" + ], + "packages/editor/src/components/ui/panels/floor-opening-panel.tsx": [ + " · Drag its corners to change the shape.", + " · Shape follows its owner.", + "A hatch in the mezzanine: it cuts only the mezzanine’s floor.", + "Delete", + "Done", + "Elevator", + "On {?}, as one void with this opening.", + "Owned by", + "Staircase", + "There is no floor above this storey.", + "There is no storey below." + ], + "packages/editor/src/components/ui/panels/mobile-panel-sheet.tsx": [ + "Close" + ], + "packages/editor/src/components/ui/panels/mobile-selection-bar.tsx": [ + "Delete", + "Duplicate", + "Edit properties", + "Edit {resolvedLabel}", + "Move" + ], + "packages/editor/src/components/ui/panels/multi-height-mode.tsx": [ + "Currently {currentLabel}", + "Custom height", + "Follows level", + "Height", + "Top" + ], + "packages/editor/src/components/ui/panels/multi-parametric-inspector.tsx": [ + "{label} (session only). Plain click reselects all members. Not saved with the project." + ], + "packages/editor/src/components/ui/panels/multi-selection-panel.tsx": [ + "Delete", + "Duplicate", + "Group", + "Group (Ctrl/Cmd+G)", + "Merge windows", + "Merge windows into a corner window: both take the height, sill and type of the one you selected first", + "Merge windows into one across both: it keeps the type and style of the one you selected first", + "Select building", + "Select the whole building to move all its levels", + "Ungroup", + "Ungroup (Ctrl/Cmd+Shift+G)", + "Unwrap the corner", + "Unwrap the corner: both windows stay, each framed at the corner", + "{label} (session only). Plain click reselects all members. Not saved with the project.", + "{length} selected" + ], + "packages/editor/src/components/ui/panels/panel-manager.tsx": [ + "Selection" + ], + "packages/editor/src/components/ui/panels/panel-wrapper.tsx": [ + "Close {title}", + "Collapse panel", + "Collections", + "Expand panel", + "Manage collections…", + "Open {title}", + "“{title}” hit an error and was unloaded for this session." + ], + "packages/editor/src/components/ui/panels/parametric-field-control.tsx": [ + "Mixed" + ], + "packages/editor/src/components/ui/panels/parametric-inspector.tsx": [ + "Actions", + "Delete", + "Delete", + "Delete with contents", + "Move" + ], + "packages/editor/src/components/ui/panels/reference-panel.tsx": [ + "Cancel", + "Capture", + "Capture", + "Center", + "Clear Scale", + "Click both ends of a known distance on the plan, then type its real length.", + "Delete", + "Draw a line over a known dimension on the plan, then type its real length to scale the image exactly.", + "Edit Scale", + "Guide Image", + "Hide", + "Hide", + "Hide Scale", + "Image", + "Lock", + "Move", + "Opacity", + "Overlay image unavailable. Replace the image to restore it.", + "Position", + "Quick Actions", + "Reference Scale", + "Replace", + "Replacing...", + "Reset Image Scale", + "Reset Rotation", + "Rotation", + "Scale & Opacity", + "Set Scale", + "Show", + "Show", + "Show Scale", + "Unlock", + "XYZ", + "pos", + "pos", + "pos", + "rot", + "scale" + ], + "packages/editor/src/components/ui/panels/room-construction-rows.tsx": [ + " (shared with {?})", + "+ Add mezzanine", + "+ New floor", + "A drawn slab: set its thickness and finishes here. It has no footprint height or foundation.", + "Built on", + "Built on", + "Built with", + "Ceiling", + "Close with walls", + "Edit shape", + "Floor", + "Floor is a drawn slab: ", + "Floor is several drawn slabs, mostly ", + "Floor thickness", + "Hand-drawn ceiling", + "Height", + "Height", + "Include floor", + "Include walls", + "Include {?}", + "Keep outside dimensions", + "Keep outside dimensions", + "No floor", + "Not included", + "Replace", + "Select", + "Shape", + "Sits on:", + "This floor is a drawn slab: select it to edit or delete it.", + "Turning walls off keeps the ones shared with", + "Use existing", + "Walls", + "Walls", + "Walls thicken inward, so the building's outer size stays the same." + ], + "packages/editor/src/components/ui/panels/room-openings-field.tsx": [ + "Cut opening", + "Done", + "Edit floor", + "Elevator opening", + "No openings", + "No openings yet. Cut one for a stair void or a hatch.", + "Opening {?}", + "Stair opening" + ], + "packages/editor/src/components/ui/panels/room-panel.tsx": [ + "Add stairs", + "Add to a unit", + "Area", + "Built with", + "Ceiling", + "Delete room", + "Edit shape", + "Floor", + "Height", + "Hide code", + "Loading…", + "Mezzanine", + "Mezzanine", + "Mezzanine name", + "Mezzanine names", + "New unit", + "None", + "Perimeter", + "Picking it adds a number", + "Remove", + "Remove from", + "Rename", + "Room", + "Room", + "Room", + "Room colour — used in the plan and labels", + "Room name", + "Room names", + "Scripted finish", + "Shape", + "Show mezzanine names", + "Show room names", + "Stairs", + "Unit", + "Unit", + "Unit", + "Unit", + "Use", + "View code", + "unit", + "{?} · Rename", + "{used} on this level", + "· Close its walls to build its floor and ceiling." + ], + "packages/editor/src/components/ui/panels/shape-choice.tsx": [ + "Polygon", + "Rectangle" + ], + "packages/editor/src/components/ui/panels/wall-region-list.tsx": [ + "Delete region", + "Delete region", + "Paint regions" + ], + "packages/editor/src/components/ui/primitives/dialog.tsx": [ + "Close" + ], + "packages/editor/src/components/ui/primitives/error-boundary.tsx": [ + "Something went wrong", + "Try again" + ], + "packages/editor/src/components/ui/primitives/opacity-control.tsx": [ + "Opacity" + ], + "packages/editor/src/components/ui/primitives/sheet.tsx": [ + "Close" + ], + "packages/editor/src/components/ui/primitives/shortcut-token.tsx": [ + "Left click", + "Left click", + "Middle click", + "Right click", + "Scroll" + ], + "packages/editor/src/components/ui/primitives/sidebar.tsx": [ + "Displays the mobile sidebar.", + "Sidebar", + "Toggle Sidebar", + "Toggle Sidebar", + "Toggle Sidebar" + ], + "packages/editor/src/components/ui/scene-loader.tsx": [ + "Nothing was changed. Check your connection and try again.", + "This project couldn't be loaded", + "Try again" + ], + "packages/editor/src/components/ui/sidebar/icon-rail.tsx": [ + "Settings", + "Site" + ], + "packages/editor/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx": [ + "All", + "Community", + "Library", + "Mine", + "No results for “{search}”", + "Search..." + ], + "packages/editor/src/components/ui/sidebar/panels/items-panel/index.tsx": [ + "All", + "Community", + "Library", + "Mine", + "No results for “{search}”", + "Search..." + ], + "packages/editor/src/components/ui/sidebar/panels/settings-panel/animation-speed-setting.tsx": [ + "Animation speed", + "Animation speed", + "Builds play ×{speed} as fast.", + "Higher plays a build faster; it applies to the next build.", + "The pace builds were made at.", + "Turn the construction animation on to use this." + ], + "packages/editor/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx": [ + "Audio settings", + "Audio settings", + "Master volume", + "Mute this tab", + "Radio volume", + "Sound effects", + "Unmute this tab", + "Volume levels apply to every tab. Muting applies to this tab only." + ], + "packages/editor/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx": [ + "Construction animation", + "Construction animation", + "Framing", + "Framing needs the Architect plugin.", + "Full", + "Full, plus the framing members dropping in first, where the framing plugin draws them.", + "Off", + "Pieces drop into place with dust, the roof assembles, one sound per phase.", + "Simple", + "Walls rise and the rest grows in, piece by piece. No falls, no dust, no sound.", + "What the AI builds appears at once." + ], + "packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx": [ + "(GLB/USDZ only)", + "3D model", + "Add basement", + "Add floor", + "Anyone with the link can view it.", + "Cast shadows from lights.", + "Choose which procedural content is baked into model files. GLB and USDZ use the textured portable path; STL, OBJ and IFC remain geometry-only.", + "Clear and start new", + "Control who can open this project.", + "Copied", + "Copy", + "Copy project ID", + "Danger zone", + "Dark", + "Default mode", + "Download the scene or hand it to another app.", + "Exclude hidden furniture and other hidden scene nodes", + "Expert mode", + "Explore scene graph", + "Export", + "Export options", + "Export visible nodes only", + "Export {label}", + "Exporting {label}…", + "Floor plan", + "Floors", + "Full floor plan", + "Generate thumbnail", + "Generating…", + "Include in file", + "Include {label} in GLB and USDZ", + "Include {label} in model files", + "Inspect how nodes are nested in this scene.", + "Interface theme", + "Keep a JSON copy of the scene, or restore one.", + "Light", + "Load build", + "Needs the", + "No floors yet", + "No optional procedural content is present.", + "Only you can view it.", + "Optional static surroundings are included only in GLB and USDZ.", + "Pascal add-on for Blender", + "Preferences", + "Preparing", + "Preparing floor-plan PDF…", + "Project", + "Project ID", + "Project ID copied", + "Public project", + "Reference this project from the API, MCP tools, or support.", + "Refresh the preview shown in your project list.", + "Remove floor", + "Remove {?}", + "Removes every node from this scene. This cannot be undone.", + "Rendering options for this editor session.", + "Save and load", + "Save build", + "Scene Graph", + "Scene graph", + "Select a floor to make it active. The ground floor is always kept as the building datum.", + "Send to Blender", + "Shadows", + "Sharing", + "Show 3D scans", + "Show floor plans", + "Sound levels, the construction animation and keyboard shortcuts.", + "Structure only", + "System", + "System follows your device’s appearance.", + "The ground floor cannot be removed", + "Thumbnail", + "Try again", + "USDZ", + "Viewer", + "Viewer surroundings", + "Viewer surroundings are excluded unless selected separately below.", + "Visible in the public viewer.", + "Visible in the public viewer.", + "Visible nodes only", + "Warning: {modelExportWarning}", + "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", + "Cannot import this file", + "Ceilings", + "Doors", + "Floor area", + "Hide", + "Items", + "Levels", + "Ready to import", + "Replace current scene", + "Scans", + "Schema details (", + "Show", + "Show {hiddenWarningCount} more", + "Sites", + "Slabs", + "Structure", + "The file contains no recognised nodes.", + "Walls", + "Windows", + "Zones", + "error", + "node", + "node", + "warning" + ], + "packages/editor/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx": [ + "3D print export failed.", + "Export 3D print 3MF", + "Export 3D print STL" + ], + "packages/editor/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx": [ + "Add new level", + "Building" + ], + "packages/editor/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx": [ + "Collection colour", + "Collections", + "Delete collection" + ], + "packages/editor/src/components/ui/sidebar/panels/site-panel/index.tsx": [ + "Add level", + "Add point", + "Area:", + "Base elevation", + "Building", + "Building", + "Camera snapshot", + "Camera snapshot", + "Camera snapshot", + "Camera snapshot", + "Capture", + "Clear selection", + "Clear snapshot", + "Clear snapshot", + "Clear snapshot", + "Clear snapshot", + "Close walls around a space to make a room.", + "Delete", + "Delete", + "Delete level", + "Draw a zone", + "Duplicate", + "Duplicate level", + "Duplicate level with options", + "Duplicate with options...", + "Elements", + "Guide", + "Hide", + "Level", + "New unit", + "New unit", + "No buildings yet", + "No elements on this level", + "No levels yet", + "Other zones", + "Perimeter:", + "Property Line", + "Rooms", + "Select a level to view content", + "Show", + "Site", + "Site", + "Take snapshot", + "Take snapshot", + "Take snapshot", + "Take snapshot", + "The ground level cannot be deleted", + "Units", + "Update snapshot", + "Update snapshot", + "Update snapshot", + "Update snapshot", + "Upload scan/floorplan", + "Uploading {uploadingType}... {progress}%", + "View snapshot", + "View snapshot", + "View snapshot", + "View snapshot", + "{length} objects selected" + ], + "packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx": [ + "Camera snapshot", + "Clear snapshot", + "Hide", + "Show", + "Take snapshot", + "Update snapshot", + "View snapshot" + ], + "packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node-drag.tsx": [ + "* { cursor: grabbing !important; }" + ], + "packages/editor/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx": [ + "Delete unit", + "Focused", + "Remove from unit", + "Room", + "Zone" + ], + "packages/editor/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx": [ + "In {unitName}" + ], + "packages/editor/src/components/ui/sidebar/panels/zone-panel/index.tsx": [ + "Actions", + "Add one", + "Camera snapshot", + "Clear snapshot", + "Delete", + "Delete with contents", + "No zones on this level.", + "Save to catalog", + "Select a level to view and create zones", + "Take snapshot", + "Update snapshot", + "View snapshot" + ], + "packages/editor/src/components/ui/sidebar/use-plugin-panels.tsx": [ + "\"{label}\" plugin crashed", + "Loading…", + "Plugins", + "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/slider-demo.tsx": [ + "Temperature", + "Temperature" + ], + "packages/editor/src/components/walkthrough-hud.tsx": [ + "Click", + "free cursor", + "or", + "or click to", + "to exit", + "to resume" + ], + "packages/editor/src/lib/floor-region-session.ts": [ + "Pick a material first", + "Pick a material first", + "Pick a material first" + ], + "packages/nodes/src/block/panel.tsx": [ + "Actions", + "Add slot", + "Apply {label} to selected faces", + "Block", + "Delete", + "Delete material slot and use Body on its faces", + "Delete {label} slot", + "Move", + "Position", + "Rename {label} slot", + "Select one or more faces first", + "Slots", + "face", + "faces" + ], + "packages/nodes/src/block/selection.tsx": [ + "Adjust Last Operation · F9", + "Adjust {label}", + "Adjust {label} (F9)", + "BEVEL", + "Bevel selected edges", + "Clear selection", + "Close last operation panel", + "Could not preview loop cut", + "Delete components", + "Dissolve selection", + "Edge select (2)", + "Extrude selected faces", + "Face select (3)", + "Finish edit mode (Tab)", + "Inset selected faces", + "Invert selection", + "LOOP CUT", + "Loop Cut and Slide", + "Loop cut count", + "Loop cut requires a connected ring of quad faces", + "Merge vertices", + "Mesh operations", + "Move selection", + "Operations", + "Repeat {label}", + "Rotate selection", + "Select all", + "Selection actions", + "Selection and more", + "Shift+R", + "Transform selected components (G / R / S)", + "Vertex select (1)", + "X-ray selection" + ], + "packages/nodes/src/box-vent/panel.tsx": [ + "Actions", + "Base Flange", + "Base Height", + "Base Inset", + "Box", + "Box Vent", + "Cap", + "Cap Height", + "Corner Bevel", + "Delete", + "Depth", + "Dimensions", + "Dome", + "Dome Curvature", + "Duplicate", + "Gap Height", + "Height", + "Hood Overhang", + "Move", + "Position", + "Rotation", + "Style", + "Top Taper", + "Width" + ], + "packages/nodes/src/cabinet/compartment-card.tsx": [ + "Baskets", + "Bottom", + "Bottom Freezer", + "Bowls", + "Burners on", + "Chimney", + "Chimney", + "Door", + "Door", + "Double", + "Double", + "Double", + "Drawer", + "Drawer", + "Drawers", + "Flip hinge", + "Flip the door hinge to the opposite side", + "Fridge", + "Gas", + "Glass", + "Glass", + "Height", + "Hob", + "Induction", + "Layout", + "Left", + "Micro", + "Oven", + "Pullout", + "Rack", + "Right", + "Shelf", + "Shelf", + "Shelves", + "Shelves inside", + "Single", + "Single", + "Sink", + "Style", + "Style", + "Surface", + "Top", + "Top Freezer", + "Top grate", + "Tray", + "Type", + "Washer", + "Wire" + ], + "packages/nodes/src/cabinet/essential-controls.tsx": [ + "Bottom freezer", + "Cooktop type", + "Door direction", + "Double", + "Double", + "Double", + "Fridge type", + "Gas", + "Glass", + "Induction", + "Item options", + "Left hinge", + "Right hinge", + "Single", + "Single", + "Sink layout", + "Top freezer" + ], + "packages/nodes/src/cabinet/kitchen-collection.tsx": [ + "Choose {label}", + "No kitchen items match. Try “fridge”, “sink”, or “cabinet”.", + "Search fridge, sink, cabinets…", + "Search kitchen items" + ], + "packages/nodes/src/cabinet/kitchen-module-actions.tsx": [ + "Add beside", + "Add beside selected item", + "Add {label}", + "An upper cabinet attached to this item will be removed to make room.", + "Cabinet", + "Cancel", + "Inserts on the {action} of the selected item.", + "Kitchen run preview, highlighted item is the proposed change", + "Left side", + "Replace selected item", + "Replace with {label}", + "Replace with…", + "Replaces only the selected item.", + "Right side", + "This", + "Unable to update this kitchen.", + "item cannot fit within the current run and its wall or corner limits. Move an end cabinet or free space, then try again.", + "moves {?}" + ], + "packages/nodes/src/cabinet/panel.tsx": [ + "Add chimney", + "Add compartment", + "Add wall cabinet", + "Advanced", + "Appliance", + "Appliance front", + "Auto", + "Bar", + "Base Cabinet", + "Cabinet Type", + "Cabinet construction, compartments, and opening preview.", + "Cabinet panel", + "Center", + "Close", + "Close cabinet", + "Close cabinet", + "Common wall-cabinet heights. Use the slider below for a custom height.", + "Compartments", + "Cutout", + "Depth", + "Dimensions", + "Dimensions", + "Edit kitchen run", + "Fill to ceiling", + "Finish", + "Finish", + "Finished height extends", + "Front construction", + "Handles", + "Height", + "Height", + "Height preset", + "Hole", + "Inset", + "Kitchen", + "Kitchen run", + "Knob", + "Mounting", + "None", + "None", + "Open", + "Open Animation", + "Open cabinet", + "Overlay", + "Panel-ready", + "Planning checks", + "Play", + "Play animation", + "Position", + "Raised Arch", + "Remove wall cabinet", + "Replace with…", + "Reveal gap", + "Shaker", + "Shared countertop, plinth, and finishes", + "Slab", + "Solid matching front between the cabinet and wall. Countertop and toe-kick continue across this filler.", + "Standard width", + "Stop", + "Stop animation", + "Stop animation", + "Style", + "Style", + "Tall Cabinet", + "Top", + "Top / Ceiling", + "Top Cabinet", + "Top depth", + "Top height", + "Trim / Soffit", + "Uses the cabinet front style, reveal, handle, and front material settings below.", + "Wall filler", + "Width", + "Width", + "mm above the ceiling." + ], + "packages/nodes/src/cabinet/run-panel.tsx": [ + "Add left", + "Add right", + "Align cabinets & handles", + "Applies depth, carcass, plinth, and countertop thickness to this run.", + "Auto", + "Back", + "Balances standard base cabinets while keeping appliance and corner-filler widths fixed.", + "Bar", + "Bar counter", + "Bar depth", + "Bar height", + "Carcass height", + "Center", + "Common wall-cabinet heights. Use the slider below for a custom height.", + "Copies", + "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.", + "Corner fillers cannot be used as array sources", + "Countertop depth", + "Countertop height", + "Create array", + "Cutout", + "Depth", + "Direction", + "Duplicate along run", + "Equalize widths", + "Finish & align", + "Finished back", + "Finished exposed ends", + "Fit wall fillers", + "Fits 50–150 mm gaps at run ends beside perpendicular walls.", + "Fronts", + "Handles", + "Height preset", + "Hole", + "Inset", + "Island & Bar", + "Kitchen run", + "Knob", + "Left", + "Left", + "Match base heights, backs, reveals and handles. Align upper cabinets; preserve tall appliances and custom compartments.", + "Module {?}", + "Modules", + "Mounting", + "No eligible module", + "None", + "Overlay", + "Plinth height", + "Position", + "Raised Arch", + "Reveal gap", + "Right", + "Right", + "Seating overhang", + "Shaker", + "Shared Plinth & Countertop", + "Show countertop", + "Show plinth", + "Slab", + "Source module", + "Spacing", + "Standard dimensions", + "Style", + "Style", + "Top", + "Use this module as the array source", + "Use {?} as array source", + "Waterfall ends" + ], + "packages/nodes/src/ceiling/panel.tsx": [ + "(Editing)", + "Add Hole", + "Area", + "Auto", + "Ceiling", + "Currently", + "Custom height", + "Cut opening", + "Done", + "Follows level", + "Height", + "Height", + "High (3.0m)", + "High (9'0\")", + "Hole", + "Holes", + "Info", + "Limited by the level to", + "Low (2.4m)", + "Low (8'0\")", + "Manual", + "Move", + "No holes", + "Standard (2.5m)", + "Standard (8'6\")", + "Taller than this level ({?} available). Raise the level height first.", + "pts ·", + "— raise the level height for a taller ceiling." + ], + "packages/nodes/src/chimney/panel.tsx": [ + "Above Ridge", + "Actions", + "Back", + "Bands", + "Cap", + "Chimney", + "Chimney Type", + "Corbeled", + "Corner Bevel", + "Count", + "Cricket", + "Cutout Offset", + "Delete", + "Depth", + "Depth", + "Diameter", + "Diameter", + "Double", + "Extent", + "Extent", + "Flat", + "Flues", + "Footprint", + "Front", + "Height", + "Height", + "Height", + "Height", + "Height", + "Hollow Depth", + "Length", + "None", + "None", + "None", + "None", + "None", + "Offset", + "Overhang", + "Panels", + "Position", + "Rectangular", + "Rotation", + "Round", + "Round", + "Shoulder", + "Side Margin", + "Simple", + "Single", + "Sloped", + "Spacing", + "Square", + "Square", + "Stepped", + "Style", + "Tapered", + "Thickness", + "Thickness", + "Top Offset", + "Wall Thickness", + "Wall Thickness", + "Width" + ], + "packages/nodes/src/column/panel.tsx": [ + "A-Frame", + "Actions", + "Apply preset...", + "Apply proportion...", + "Bottom Depth", + "Bottom Height", + "Bottom Spread", + "Bottom Step Spread", + "Bottom Tiers", + "Bottom Width", + "Bottom Width", + "Box Frame", + "Brace Depth", + "Brace Width", + "Bulge", + "Bulged", + "Column", + "Connector Plates", + "Delete", + "Depth", + "Dimensions", + "Edge Softness", + "End Width", + "End Width", + "Ends", + "Fork Spread", + "Heavy", + "Height", + "Height and footprint are controlled by the lean-to extension. Rotate or change the support style here; resize from the parent lean-to.", + "Hourglass", + "K Brace", + "Move", + "Neck Width", + "No Bottom", + "No Top", + "Plinth Thickness", + "Portal Frame", + "Preset", + "Rectangular", + "Ring Pairs", + "Ring Spread", + "Ring Thickness", + "Round", + "Round Band Width", + "Rounded Bottom", + "Rounded Top", + "Segment Twist", + "Shaft", + "Shaft Corner Radius", + "Shaft Width", + "Shape", + "Short / Stout", + "Simple Block Bottom", + "Simple Top", + "Single Strut", + "Slender", + "Square", + "Square Plinth Bottom", + "Standard", + "Stepped Bottom", + "Stepped Top", + "Straight", + "Taper", + "Tapered", + "Top Depth", + "Top Height", + "Top Spread", + "Top Step Spread", + "Top Tiers", + "Top Width", + "Top Width", + "Transform", + "Trestle", + "Tripod", + "Twist Segments", + "V Support", + "Vertical", + "Waist", + "Width", + "X Brace", + "Y Support", + "Yaw" + ], + "packages/nodes/src/construction-dimension/panel.tsx": [ + "Above line", + "Actions", + "Architectural tick", + "Center mark", + "Centered on line", + "Centerline", + "Construction Dimension", + "Controlled by foundation", + "Datum policy", + "Delete", + "Dimension", + "Dot", + "Drawing coordination", + "Extension gap", + "Extension overshoot", + "Feature count", + "Filled arrow", + "Finish face", + "Foundation controller", + "Foundation dimension", + "Imperial precision", + "Linked dimensions reuse the controller's associative anchors and update with it.", + "Meters", + "Metric notation", + "Millimeters", + "Mode", + "Nearest 1/16 inch", + "Nearest 1/2 inch", + "Nearest 1/4 inch", + "Nearest 1/8 inch", + "Nearest inch", + "No foundation dimensions", + "Notation", + "Omitted", + "Open arrow", + "Prefix", + "Primary drawing", + "Segment numbers are one-based and apply only in this drawing view.", + "Shown", + "Standards", + "Structural face", + "Suffix", + "Terminator", + "Text override", + "Text position", + "Use measured value", + "Wall face", + "{activeDrawingLabel} presentation", + "{activeDrawingLabel} suppressed segments" + ], + "packages/nodes/src/cupola/panel.tsx": [ + "Actions", + "Cupola", + "Delete", + "Depth", + "Dimensions", + "Dome", + "Duplicate", + "Finial", + "Height", + "Move", + "No Finial", + "Position", + "Pyramid", + "Rotation", + "Style", + "Width" + ], + "packages/nodes/src/door/panel.tsx": [ + "+ Add Segment", + "- Remove", + "Actions", + "All", + "All", + "Arch", + "Arch", + "Arch Height", + "Arch Height", + "Bar Height", + "Columns", + "Content Padding", + "Corner Radius", + "Corner Radius", + "Custom: the segments match no style.", + "Delete", + "Depth", + "Depth", + "Dimensions", + "Direction", + "Divider", + "Door", + "Door", + "Door Closer", + "Duplicate", + "Empty", + "Enable Handle", + "Enable Threshold", + "Flip Side", + "Fold", + "Frame", + "Garage", + "Garage", + "Glass", + "Handle", + "Handle Side", + "Hardware", + "Height", + "Height", + "Height", + "Height", + "Hinges Side", + "Horizontal", + "Individual", + "Individual", + "Inset", + "Inward", + "Left", + "Left", + "Left", + "Move", + "Open", + "Open", + "Open", + "Opening", + "Opening Shape", + "Outward", + "Panel", + "Panel", + "Panels", + "Panels", + "Panic Bar", + "Pocket", + "Position", + "Rail", + "Rect", + "Rect", + "Reveal Radius", + "Reveal Radius", + "Right", + "Right", + "Right", + "Roll-up", + "Rounded", + "Rounded", + "Sectional", + "Segment", + "Segments", + "Size is limited to the wall, including clearance for the opening frame.", + "Slide", + "Style", + "Swing", + "Thickness", + "Threshold", + "Tilt-up", + "Top Shape", + "Type", + "Vertical", + "Width", + "wall" + ], + "packages/nodes/src/dormer/panel-actions-section.tsx": [ + "Actions", + "Delete", + "Duplicate", + "Move" + ], + "packages/nodes/src/dormer/panel-position-section.tsx": [ + "Position", + "Rotation" + ], + "packages/nodes/src/dormer/panel-windows-section.tsx": [ + "Add Window", + "Edit window", + "Edit {?}", + "Increase the dormer width to add another window.", + "Move", + "Move window", + "Move {?}", + "No windows", + "Window {?}", + "Windows ({length})", + "front" + ], + "packages/nodes/src/dormer/panel.tsx": [ + "Depth", + "Dimensions", + "Dormer", + "Dormer", + "Dutch", + "Flat", + "Gable", + "Gambrel", + "Hip", + "Mansard", + "Pitch Direction", + "Pitch Rise", + "Rise Back", + "Rise Front", + "Roof Height", + "Roof Type", + "Section", + "Shed", + "Wall Height", + "Width", + "Windows" + ], + "packages/nodes/src/downspout/inspector-editors.tsx": [ + "Position" + ], + "packages/nodes/src/duct-fitting/inspector-editors.tsx": [ + "Swap W/H", + "Swap width and height" + ], + "packages/nodes/src/duct-fitting/tool.tsx": [ + "Axis", + "Hover a duct face that fits the door", + "Place access door", + "R/T rotate", + "⌥ axis" + ], + "packages/nodes/src/duct-terminal/tool.tsx": [ + "M surface", + "Mount {mountLabel}", + "R/T rotate", + "Snapped to duct" + ], + "packages/nodes/src/elevator/panel.tsx": [ + "Access", + "Actions", + "Cab", + "Cab Height", + "Center opening", + "Default Floor", + "Delete", + "Depth", + "Destination", + "Disabled", + "Disabled", + "Door Height", + "Door Time", + "Door Type", + "Door Width", + "Doors", + "Duplicate", + "Dwell", + "Elevator", + "From", + "Glass", + "Glass frame", + "Motion", + "Move", + "Opening Style", + "Position", + "Rotation", + "Segmented panel", + "Service", + "Service", + "Service", + "Shaft", + "Shaft Depth", + "Shaft Style", + "Shaft Width", + "Single left", + "Single right", + "Solid", + "Solid panel", + "Speed", + "Stop {stopOrder}", + "To", + "Wall Thickness", + "Width", + "Yaw" + ], + "packages/nodes/src/eyebrow-vent/panel.tsx": [ + "Actions", + "Back height", + "Delete", + "Depth", + "Dimensions", + "Duplicate", + "Eyebrow Vent", + "Half-round", + "Height", + "Louvers", + "Move", + "Position", + "Rotation", + "Scoop", + "Slant-box", + "Style", + "Width" + ], + "packages/nodes/src/fence-feature/actions.tsx": [ + "Close", + "Open" + ], + "packages/nodes/src/fence-feature/inspector.tsx": [ + "Board width", + "Bracing", + "Distance from start", + "Fence unavailable.", + "Frame width", + "Gate height", + "Gate style", + "Ground clearance", + "Hinge side", + "Hinges and latch", + "Horizontal boards", + "Infill spacing", + "Jamb posts", + "Keep the opening inside the fence and clear of other gates or passages.", + "Leaf thickness", + "Leaves", + "Left leaf proportion", + "Match fence height", + "Match fence style", + "Open rails", + "Opening angle", + "Opening width", + "Picket", + "Post height", + "Remove gate", + "Remove opening", + "Solid privacy", + "Swing direction", + "Vertical slats" + ], + "packages/nodes/src/fence/inspector-editors.tsx": [ + "Add point after", + "Choose a slab or shaped surface on this level.", + "Choose a surface", + "Corner", + "Curve", + "Curved", + "Distribution controls {subject}. Spacing is measured between centers. The available width limits the count so pieces do not overlap.", + "Edit path", + "Extend path", + "Follow highest surface", + "Follow selected surface", + "Hold starting height", + "Join", + "Length", + "Picket rail projection", + "Point", + "Remove point", + "Set each span to straight or curved, then drag its points and curve handles in either view.", + "Smooth", + "Span to point", + "Straight", + "Surface", + "Surface behavior", + "points ·" + ], + "packages/nodes/src/fence/move-endpoint-tool.tsx": [ + "Detach endpoint", + "Drag endpoint" + ], + "packages/nodes/src/gutter/downspouts-panel.tsx": [ + "Add Downspout", + "Downspout {?}", + "Downspouts", + "Remove downspout" + ], + "packages/nodes/src/hvac-equipment/tool.tsx": [ + "R/T rotate" + ], + "packages/nodes/src/item/authored-params.tsx": [ + "Couldn't rebuild with these values.", + "Parameters", + "Rebuilding in Blender…", + "Rebuilding…", + "Reset parameters", + "Reset to default", + "Reset {?}" + ], + "packages/nodes/src/item/panel.tsx": [ + "Actions", + "Delete", + "Dimensions", + "Duplicate", + "Info", + "Move", + "Position", + "Rotation", + "Scale", + "Uniform Scale", + "XYZ", + "pos", + "pos", + "pos", + "rot", + "rot", + "scale", + "scale", + "scale", + "scale" + ], + "packages/nodes/src/liquid-line/tool.tsx": [ + "Click to trace this lineset run", + "Follow: hover a lineset" + ], + "packages/nodes/src/measurement/selection.tsx": [ + "Align " + ], + "packages/nodes/src/measurement/tool.tsx": [ + "Create", + "Extrusion height", + "Extrusion height" + ], + "packages/nodes/src/pipe-fitting/tool.tsx": [ + "Axis", + "R/T rotate", + "⌥ axis" + ], + "packages/nodes/src/pipe-trap/tool.tsx": [ + "R/T rotate", + "{diameter}\" Trap" + ], + "packages/nodes/src/ridge-vent/panel.tsx": [ + "Actions", + "Delete", + "Dimensions", + "Duplicate", + "End Caps", + "Flanged", + "Height", + "Length", + "Move", + "Open", + "Position", + "Ridge Vent", + "Rotation", + "Shingled", + "Standard", + "Style", + "Width" + ], + "packages/nodes/src/roof-segment/panel.tsx": [ + "Actions", + "Angle", + "Arc", + "Auto gutters", + "Auto ridge vent", + "Barrel", + "Clipped version", + "Conical", + "Conical Shape", + "Deck Thick.", + "Delete", + "Depth", + "Diameter", + "Done editing", + "Drainage", + "Duplicate", + "Dutch", + "Eave overhang", + "Edit footprint", + "End overhang", + "Fascia", + "Fascia height", + "Flat", + "Footprint", + "Gable", + "Gable overhang", + "Gambrel", + "Hip", + "Kink Depth", + "Kink Height", + "Length", + "Mansard", + "Move", + "Pitch", + "Position", + "Reset", + "Roof Segment", + "Roof Type", + "Rotation", + "Shape", + "Shape", + "Shape", + "Shed", + "Shingle Thick.", + "Span", + "Start Angle", + "Structure", + "Top Rake Length", + "Top Rake Thick.", + "Trim", + "Waist Height", + "Waist Height", + "Waist Length", + "Waist Width", + "Waist Width", + "Wall", + "Wall Height", + "Wall Thick.", + "Width" + ], + "packages/nodes/src/roof/barrel-panel.tsx": [ + "Arch bays", + "Barrel arch", + "Flat panes follow a circular arch. Rise is measured from the eaves.", + "Rise" + ], + "packages/nodes/src/roof/glazing-controls.tsx": [ + "Alignment", + "Center", + "Choose a layout to edit the grid.", + "Empty", + "End", + "Fixed spacing", + "Glass", + "Layout", + "Max spacing", + "Maximum spacing", + "Mixed", + "Panel count", + "Panels", + "Solid", + "Spacing", + "Start", + "{title} alignment" + ], + "packages/nodes/src/roof/glazing-panel-editor.tsx": [ + "Choose a panel to override its default infill.", + "Column", + "Custom", + "Default", + "Individual panels", + "Panel infill", + "Reset to default", + "Roof face", + "Row", + "Selected panel infill", + "column", + "columns", + "row", + "rows" + ], + "packages/nodes/src/roof/glazing-panel.tsx": [ + "Changes apply to all {length} roof segments.", + "Choose one roof system to edit settings for all selected segments.", + "Close the roof ends", + "Default panel infill", + "Default panel infill", + "Divides each roof face into columns.", + "Divides the length of each arch bay into columns.", + "End infill fills the space above the walls. Edit room walls and ceilings separately.", + "Frame color", + "Frame depth", + "Frame width", + "Framing", + "Glass", + "Glass tint", + "Glazed", + "Glazing is available for gable, straight shed, and barrel roofs.", + "Grid across the roof", + "Grid along the length", + "Grid along the slope", + "Grid within each arch bay", + "Infill", + "Opacity", + "Pane thickness", + "Roof system", + "Roughness", + "Spacing is measured on the slope, not its horizontal projection.", + "Standard", + "Subdivides each flat arch bay. Arch bays controls the divisions around the curve." + ], + "packages/nodes/src/roof/panel.tsx": [ + " The floor's {roofs} roofs move together.", + "Actions", + "Add Chimney", + "Add Cupola", + "Add Dormer", + "Add Eyebrow Vent", + "Add Gutter", + "Add Skylight", + "Add Solar Panel", + "Add Vent", + "Box", + "Box Vent {?}", + "Chimney {?}", + "Currently", + "Custom", + "Delete", + "Dormer {?}", + "Draw Segment", + "Duplicate", + "Elements", + "Follows walls", + "Gutter {?}", + "Level", + "Move", + "Move to the roof level", + "Move to {?}", + "On", + "Position", + "Ridge", + "Ridge Vent {?}", + "Roof", + "Rotation", + "Segment {?}", + "Segments", + "Skylight {?}", + "Solar Panel {?}", + "Turbine", + "Turbine Vent {?}", + "box vent", + "chimney", + "dormer", + "gutter", + "ridge vent", + "skylight", + "solar panel", + "turbine vent", + "with its walls, so it hides that floor's plan in solo and exploded views." + ], + "packages/nodes/src/shared/item-interaction-actions.tsx": [ + "Turn light off", + "Turn light on" + ], + "packages/nodes/src/shared/run-hanger-inspector.tsx": [ + "Automatic support", + "Hanger", + "Hanger {?} position in metres", + "Hanger {?} support", + "Individual hangers", + "Missing support", + "No support within reach. Move the hanger or choose another host.", + "Position (m)", + "Positions are measured along each path segment. Changing spacing regenerates the numbered slots.", + "Reveal support", + "Skip", + "· segment" + ], + "packages/nodes/src/shared/system-check-panel.tsx": [ + "About these checks", + "All findings", + "All systems", + "Connections", + "Drainage", + "Error", + "Errors", + "Filter system checks", + "Hangers", + "Intersections", + "Locate {?} ({id})", + "Missing item", + "No findings", + "No findings in this category", + "Open ends", + "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances.", + "Selected connected system", + "Selected:", + "Separate branches", + "Show all findings", + "System checks", + "System findings", + "Warning", + "Warnings", + "run", + "runs" + ], + "packages/nodes/src/site/panel.tsx": [ + "1200 W Cass St, Tampa, FL", + "APN", + "Address", + "Auto — most north-facing edge", + "Contour interval (site plan and 3D)", + "County", + "Find parcel", + "Finding…", + "Front (street) edge", + "Lot area", + "No surveyed lines — contours are drawn from the sculpted ground.", + "North rotation", + "Orientation", + "Parcel", + "Project look", + "Save current look", + "Save the current lighting and display as this project's default. Personal display changes stay in this browser.", + "Setbacks", + "Show ground", + "Show the contour lines in 3D", + "Site", + "Source", + "Source / citation", + "Street address", + "Terrain", + "Use project look", + "Zone", + "e.g. RS-60", + "e.g. Tampa LDC §27-156", + "every 12 in", + "every 24 in", + "every 6 in", + "ft (", + "none", + "side", + "survey", + "surveyed lines at" + ], + "packages/nodes/src/skylight/panel.tsx": [ + "Actions", + "Along X", + "Along Z", + "Bottom", + "Curb", + "Cutout Offset", + "Delete", + "Depth", + "Dimensions", + "Frame", + "Glass Thickness", + "Height", + "Height", + "Lantern Height", + "Left", + "Motor", + "Motor Housing", + "No", + "No Motor", + "Open", + "Open", + "Opening Angle", + "Position", + "Right", + "Rotation", + "Skylight", + "Thickness", + "Top", + "Top Scale", + "Track Width", + "Type", + "Width", + "Yes" + ], + "packages/nodes/src/slab/panel.tsx": [ + "(Editing)", + "Add Hole", + "Area", + "Auto", + "Base", + "Cut hatch", + "Cut opening", + "Depth", + "Done", + "Elevation", + "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged.", + "Fixed", + "Floor", + "Follows terrain", + "Foundation", + "Hole", + "Holes", + "Info", + "Manual", + "Move", + "No holes", + "Rim", + "Slab", + "Standard (2\")", + "Standard (5cm)", + "Sunken (15cm)", + "Sunken (6\")", + "Surface", + "Thick (15cm)", + "Thick (6\")", + "Thickness", + "Thin (1\")", + "Thin (2cm)", + "pts ·" + ], + "packages/nodes/src/solar-panel/panel.tsx": [ + "Actions", + "Array", + "Auto-fit to roof", + "Columns", + "Custom — dimensions don't match any preset", + "Delete", + "Flip orientation", + "Flush", + "Frame depth", + "Frame thickness", + "Gap X", + "Gap Y", + "Height", + "Mounting", + "Panel", + "Preset", + "Rows", + "Solar Panel", + "Standoff", + "Tilt angle", + "Tilted", + "Width" + ], + "packages/nodes/src/spawn/panel.tsx": [ + "Actions", + "Delete", + "Facing", + "Move", + "Position", + "Spawn Point", + "Yaw" + ], + "packages/nodes/src/stair-segment/panel.tsx": [ + "Actions", + "Attachment", + "Delete", + "Dimensions", + "Duplicate", + "Editing switches the stair to Custom rise", + "Equal angle", + "Equal going", + "Fill to floor", + "Flight", + "Flight shape", + "Front", + "Height", + "Inner gap", + "Landing", + "Left", + "Left turn", + "Length", + "Move", + "Position", + "Right", + "Right turn", + "Rotation", + "Stair Segment", + "Steps", + "Straight", + "Structure", + "Thickness", + "Type", + "Walking line offset", + "Width", + "Winder" + ], + "packages/nodes/src/stair/construction-controls.tsx": [ + "Body", + "Center stringer", + "Closed risers", + "Inherit", + "Nosing", + "Open", + "Original", + "Riser thickness", + "Side stringers", + "Solid", + "Stringer depth", + "Stringer width", + "Tread finish", + "Tread thickness", + "Waist", + "Waist thickness" + ], + "packages/nodes/src/stair/panel.tsx": [ + "Actions", + "Add flight", + "Add landing", + "Apply {label} layout", + "Auto Cutout", + "Balusters", + "Boards", + "Both", + "Cable", + "Center Column", + "Clockwise", + "Connected to {?}. Move the stair to connect to another edge.", + "Construction", + "Counterclockwise", + "Currently", + "Curved", + "Custom rise", + "Deck", + "Delete", + "Design targets", + "Destination", + "Drag near a deck, patio, concrete slab, or landing edge to fit the stair.", + "Duplicate", + "Equal angle", + "Equal going", + "Fit To Floor", + "Fit risers and going", + "Fit uniform risers", + "Flight", + "Floors, ceilings and stairs only.", + "Follows deck", + "Follows level", + "From Level", + "Geometry", + "Glass", + "Headroom:", + "Height", + "Inner Radius", + "Inner gap", + "Integrated", + "Landing", + "Landing", + "Layout", + "Left", + "Left turn", + "Measurements", + "Metal", + "Move", + "Moving this stair keeps its current rise, steps, and run.", + "No overhead surface", + "None", + "None", + "None", + "Not evaluated", + "Opening", + "Opening Offset", + "Position", + "Post & rail", + "Railing", + "Right", + "Right turn", + "Rise", + "Rise", + "Rotation", + "Segment {?}", + "Segments", + "Sizing", + "Snap to nearby surfaces", + "Spiral", + "Staircase", + "Step Supports", + "Steps", + "Straight", + "Style", + "Surface connection", + "Sweep", + "Target going", + "Target headroom", + "Target max riser", + "Target minimum going", + "Thickness", + "To", + "Top Landing", + "Type", + "Unavailable", + "Walking line offset", + "Width", + "Winder", + "risers · R" + ], + "packages/nodes/src/stair/railing-controls.tsx": [ + "Both", + "Continuous", + "Floor", + "Handrail diameter", + "Handrail height", + "Handrail inset", + "Left", + "No return", + "None", + "Original layout", + "Post-facing", + "Return length", + "Right", + "Separate handrail", + "Set the length to reach the wall or post.", + "Wall-facing", + "{?} extension" + ], + "packages/nodes/src/turbine-vent/panel.tsx": [ + "Actions", + "Cylinder", + "Delete", + "Diameter", + "Dimensions", + "Duplicate", + "Globe", + "Height", + "Motion", + "Move", + "Neck Height", + "Pause", + "Play", + "Position", + "Rotation", + "Spin Speed", + "Style", + "Turbine Vent", + "Vanes" + ], + "packages/nodes/src/unit/unit-panel.tsx": [ + "Actions", + "Color", + "Delete", + "Focus", + "Gross area", + "Kind", + "Levels", + "Members", + "Members", + "Name", + "No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused.", + "Remove {?} from unit", + "Report", + "Unit", + "Unit" + ], + "packages/nodes/src/wall/actions.tsx": [ + "Merge walls", + "Merge walls", + "Split wall", + "Split wall" + ], + "packages/nodes/src/wall/curtain-wall-panel.tsx": [ + ", limited by frame depth.", + ", row", + "Apply tint", + "Border / opening frame", + "Bottom", + "Bottom row", + "Cancel tint", + "Center", + "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.", + "Clear hidden overrides", + "Column", + "Column", + "Column layout", + "Column {?}, row {?}: {type}", + "Construction", + "Continuous mullions and transoms assembled along the wall.", + "Curtain wall panel selection", + "Custom infill", + "Default panel", + "Edit individual panels", + "Effective thickness:", + "Empty", + "Enable panel editing", + "End", + "Fixed spacing", + "Following wall defaults", + "Frame dimensions", + "Framing", + "Fully capped", + "Glass", + "Glass appearance", + "Glass appearance is controlled by the paint tool.", + "Glass tint", + "Glass tint", + "Glazing gap", + "Grid limited to 32 panels per axis. Spacing expands to fit this wall.", + "Horizontal caps", + "Horizontal frame width", + "Layout", + "Low roughness is smooth; high roughness gives a matte surface in rendered shading.", + "Maximum spacing", + "Module joint width", + "None", + "Opacity", + "Opaque band", + "Opaque bands replace a full row with solid panels. Apply their finish with the paint tool.", + "Panel count", + "Panel infill", + "Panel infill", + "Panel thickness", + "Panels", + "Reset this panel", + "Row", + "Row layout", + "Separate framed modules with joints between units.", + "Solid", + "Spacing", + "Start", + "Stick-built", + "Structural glazing", + "Surface roughness", + "Top", + "Top row", + "Uncapped members sit behind the glazing.", + "Unitized", + "Use glass settings instead", + "Use the Door or Window tool to add an opening through the wall.", + "Vertical caps", + "Vertical frame width", + "Wall system", + "{length} custom panels are outside this grid. They return if the grid expands." + ], + "packages/nodes/src/wall/move-endpoint-tool.tsx": [ + "Alt to detach", + "Detaching corner" + ], + "packages/nodes/src/wall/panel.tsx": [ + "Actions", + "Assembly", + "Auto", + "Both", + "Bottom", + "Brick veneer", + "CMU", + "Chair rail", + "Colonial", + "Cove", + "Craft", + "Crown molding", + "Currently", + "Curtain wall", + "Curve", + "Curve", + "Custom", + "Custom height", + "Depth", + "Dimensions", + "Drywall", + "Extends downward to meet the terrain. Height and top stay unchanged.", + "Exterior", + "Fiber cement", + "Fill to terrain", + "Flat", + "Flat", + "Flat", + "Follows level", + "Frame depth", + "Framing", + "Gypsum", + "Height", + "Height", + "Hide code", + "Hide {?}", + "ICF", + "Interior", + "Lap siding", + "Layer thicknesses follow the 2021 IRC assembly data. Drafting aid, not engineering — verify with the authority having jurisdiction.", + "Layered", + "Length", + "Loading…", + "Modern", + "None", + "None", + "None", + "None (single layer)", + "OSB", + "Offset", + "Ogee", + "Ogee", + "Ogee", + "Partition: the interior finish is applied to both faces.", + "Picture", + "Plaster", + "Plywood", + "Preset", + "Reference", + "Remove", + "Round", + "Scripted finish", + "Sheathing", + "Shoe", + "Show {?}", + "Side", + "Side A", + "Side B", + "Skirting", + "Standard", + "Steel studs", + "Step", + "Stone veneer", + "Stucco", + "Thickness", + "Thickness", + "Top", + "Total thickness", + "Total thickness", + "Unverified: {presetNote}", + "View code", + "Wall", + "Wall type", + "Which face is outside is undetermined (no room detected on either side) — the exterior layers are drawn on side B.", + "Wood studs", + "· from assembly" + ], + "packages/nodes/src/window/panel.tsx": [ + "Actions", + "All", + "All", + "Arch", + "Arch", + "Arch Height", + "Arch Height", + "Col Widths", + "Columns", + "Corner", + "Corner Radius", + "Corner Radius", + "Corner post", + "Custom: the panes match no style.", + "Delete", + "Depth", + "Depth", + "Dimensions", + "Divider", + "Divider", + "Down", + "Duplicate", + "Enable Sill", + "Flip Side", + "Frame", + "French", + "Fused glass", + "Grid", + "Height", + "Individual", + "Individual", + "Left", + "Move", + "Opening", + "Opening Shape", + "Other side", + "Position", + "Rect", + "Rect", + "Reveal Radius", + "Reveal Radius", + "Right", + "Rounded", + "Rounded", + "Row Heights", + "Rows", + "Sill", + "Single", + "Size is limited to the wall, including clearance for the opening frame.", + "Style", + "Thickness", + "Thickness", + "This side", + "Top Shape", + "Type", + "Unwrap", + "Up", + "Width", + "Window", + "Window", + "Window Type", + "Wrap the corner", + "Wraps the corner with", + "its partner", + "pos", + "pos" + ], + "packages/nodes/src/zone/quantities-panel.tsx": [ + "Enclosed room", + "Floor surface", + "Footprint only", + "None", + "Not proven", + "Room quantities", + "Top view with zone edge dimensions", + "Unit", + "Unit", + "Unit", + "Volume", + "Wall surface", + "Zone boundary unavailable", + "Zone quantities" + ], + "packages/ui/src/button.tsx": [ + "Hello from your {appName} app!" + ], + "packages/ui/src/card.tsx": [ + "->" + ], + "packages/viewer/src/components/viewer/glb-scene.tsx": [ + "Door", + "Item" + ], + "packages/viewer/src/components/viewer/perf-panel.tsx": [ + "Dock panel to the side", + "Performance", + "drag {?} / settle {?} ({settleFrames} frames)", + "last action", + "no timestamp-query", + "perf", + "waiting for samples…", + "{?}ms", + "{?}ms", + "{?}ms (max {?})", + "{?}ms (max {?})", + "{?}ms (max {?})", + "{?}ms ({count}×)", + "{?}ms ({count}×, max {?})", + "{?}ms cpu (max {?})", + "{?}ms {outcome}", + "{fps} fps", + "{fps} fps", + "{geometries} geo {textures} tex {?}", + "{items} items · {instances} inst · {containers} mesh", + "{meshes} mesh {lines} line {lights} light" + ], + "packages/viewer/src/components/viewer/unsupported-gpu-fallback.tsx": [ + "3D viewer unavailable", + "This browser or environment could not initialize WebGPU or WebGL, so Pascal cannot render the 3D scene here. Try opening the editor in a browser with hardware acceleration enabled." + ], + "packages/viewer/src/systems/interactive/control-widget.tsx": [ + "Off", + "On" + ] } } diff --git a/packages/editor/src/i18n/locales/en-XA/messages.ts b/packages/editor/src/i18n/locales/en-XA/messages.ts index 25bc307d92..27e83c36c6 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("{\"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\"],\" ţĥéñ ţĥé ƒîŕšţ öñé áĝáîñ ţö çļöšé. Ƒöŕ Ļ-šĥáþéš áñð áñĝļéð ŕööɱš. ~~~~~~~~~~~~~~~~]\"],\"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\"],\" 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.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.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\":[\"[Ŵáļļš ~~]\"],\"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 96b505b693..feef521746 100644 --- a/packages/editor/src/i18n/locales/en/messages.po +++ b/packages/editor/src/i18n/locales/en/messages.po @@ -7,6 +7,262 @@ msgstr "" "X-Generator: @lingui/cli\n" "Language: en\n" +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.automaticDimensions" +msgstr "Automatic dimensions" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.camera" +msgstr "Camera" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.cleanPlanDimensionsAppearWithSelection" +msgstr "Clean plan; dimensions appear with selection" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.collapseSidebar" +msgstr "Collapse sidebar" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.crispOpaqueEdgeLines" +msgstr "Crisp, opaque edge lines" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.cutaway" +msgstr "Cutaway" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.default" +msgstr "Default" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.display" +msgstr "Display" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.displaySettings" +msgstr "Display settings" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.doorWindowMarks" +msgstr "Door/window marks" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.edges" +msgstr "Edges" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.enterVr" +msgstr "Enter VR" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.exitVr" +msgstr "Exit VR" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.expandSidebar" +msgstr "Expand sidebar" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.expert" +msgstr "Expert" + +#: apps/editor/components/viewer-toolbar.tsx +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" + +#: apps/editor/components/viewer-toolbar.tsx +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" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.floorPlanAnnotations" +msgstr "Floor plan annotations" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.floorPlanMode" +msgstr "Floor plan mode" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.fullAmbientOcclusion" +msgstr "Full ambient occlusion" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.fullDocumentationAndAnnotationControls" +msgstr "Full documentation and annotation controls" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.fullHeight" +msgstr "Full height" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.fullWallThickness" +msgstr "Full wall thickness" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.grid" +msgstr "Grid" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.levelsMode" +msgstr "Levels: {mode}" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.low" +msgstr "Low" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.magneticSnap" +msgstr "Magnetic snap" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.manual" +msgstr "Manual" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.manualDimensions" +msgstr "Manual dimensions" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.measurements" +msgstr "Measurements" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.meters" +msgstr "Meters" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.millimeters" +msgstr "Millimeters" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.n3dMeasurements" +msgstr "3D measurements" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.noEdgeLines" +msgstr "No edge lines" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.off" +msgstr "Off" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.on" +msgstr "On" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.orthographic" +msgstr "Orthographic" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.perspective" +msgstr "Perspective" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.preview" +msgstr "Preview" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.previewMode" +msgstr "Preview mode" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.render" +msgstr "Render" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.rendered" +msgstr "Rendered" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.roomLabels" +msgstr "Room labels" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.sceneTheme" +msgstr "Scene theme" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.shadows" +msgstr "Shadows" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.singleWallAxis" +msgstr "Single wall axis" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.soft" +msgstr "Soft" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.solid" +msgstr "Solid" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.solo" +msgstr "Solo" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.stack" +msgstr "Stack" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.stairAnnotations" +msgstr "Stair annotations" + +#: apps/editor/components/viewer-toolbar.tsx +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" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.translucent" +msgstr "Translucent" + +#: apps/editor/components/viewer-toolbar.tsx +msgid "app.viewerToolbar.units" +msgstr "Units" + +#: apps/editor/components/viewer-toolbar.tsx +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}" + #: packages/editor/src/i18n/level-name.ts msgid "core.level.basement" msgstr "Basement" @@ -275,31 +531,31 @@ msgstr "Viewer layout" msgid "viewer.stage.split" msgstr "Split" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.blueprint" msgstr "Blueprint" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.mediterranean" msgstr "Mediterranean" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.night" msgstr "Night" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.overcast" msgstr "Overcast" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.paper" msgstr "Paper" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.studio" msgstr "Studio" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.sunset" msgstr "Sunset" @@ -307,11 +563,11 @@ msgstr "Sunset" msgid "viewer.theme.title" msgstr "Scene theme" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.twilight" msgstr "Twilight" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.verdant" msgstr "Verdant" diff --git a/packages/editor/src/i18n/locales/en/messages.ts b/packages/editor/src/i18n/locales/en/messages.ts index 0cd37f56df..4848613578 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("{\"core.level.basement\":[\"Basement\"],\"core.level.basementNumber\":[\"Basement \",[\"number\"]],\"core.level.floorNumber\":[\"Floor \",[\"number\"]],\"core.level.groundFloor\":[\"Ground floor\"],\"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\"],\"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.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.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\"],\"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 9d86e70e75..dc09512b0b 100644 --- a/packages/editor/src/i18n/locales/es/messages.po +++ b/packages/editor/src/i18n/locales/es/messages.po @@ -13,6 +13,646 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +# Source-Hash: 3d3f438d5a49eba7 +# Review: required +# English: "Automatic dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.automaticDimensions" +msgstr "Cotas automáticas" + +# Source-Hash: 14622745dbf93f4c +# Review: required +# English: "Camera" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.camera" +msgstr "Cámara" + +# Source-Hash: e6bce525c47ba3ac +# Review: required +# English: "Clean plan; dimensions appear with selection" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cleanPlanDimensionsAppearWithSelection" +msgstr "Plano limpio; las cotas aparecen al seleccionar" + +# Source-Hash: 61ce356577cfb04a +# Review: required +# English: "Collapse sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.collapseSidebar" +msgstr "Contraer barra lateral" + +# Source-Hash: 2416a48df28d6205 +# Review: required +# English: "Crisp, opaque edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.crispOpaqueEdgeLines" +msgstr "Aristas nítidas y opacas" + +# Source-Hash: 4da8b3678ed77b45 +# Review: required +# English: "Cutaway" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cutaway" +msgstr "Corte" + +# Source-Hash: 4ca0e0e73229540c +# Review: required +# English: "Default" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.default" +msgstr "Predeterminado" + +# Source-Hash: a313661ef9dd0a65 +# Review: required +# English: "Display" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.display" +msgstr "Visualización" + +# Source-Hash: d0db46f206a88e2e +# Review: required +# English: "Display settings" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.displaySettings" +msgstr "Ajustes de visualización" + +# Source-Hash: 0286962ab8e9cfcd +# Review: required +# English: "Door/window marks" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.doorWindowMarks" +msgstr "Marcas de puertas y ventanas" + +# Source-Hash: 027bbc8b7287c06a +# Review: required +# English: "Edges" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.edges" +msgstr "Aristas" + +# Source-Hash: d86126c5d16c6238 +# Review: required +# English: "Enter VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.enterVr" +msgstr "Entrar en RV" + +# Source-Hash: eb99fb0b382e58cd +# Review: required +# English: "Exit VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exitVr" +msgstr "Salir de RV" + +# Source-Hash: aeac665749d3101d +# Review: required +# English: "Expand sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expandSidebar" +msgstr "Expandir barra lateral" + +# Source-Hash: 08c178ee733ff009 +# Review: required +# English: "Expert" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expert" +msgstr "Experto" + +# Source-Hash: be12f8788f1f0a05 +# Review: required +# English: "Exploded" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exploded" +msgstr "Despiece" + +# Source-Hash: c6f865a366ef5755 +# Review: required +# English: "Face of stud" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faceOfStud" +msgstr "Cara del montante" + +# Source-Hash: 0c583f1d4201293b +# Review: required +# English: "Faint outline of major creases" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faintOutlineOfMajorCreases" +msgstr "Contorno tenue de los pliegues principales" + +# Source-Hash: 08ecd5878b08139d +# Review: required +# English: "Feet & inches" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.feetInches" +msgstr "Pies y pulgadas" + +# Source-Hash: 43b8017fa821c46c +# Review: required +# English: "Finished faces" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.finishedFaces" +msgstr "Caras acabadas" + +# Source-Hash: 8827df1cdeb02ed9 +# Review: required +# English: "Flat and fast — no ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.flatAndFastNoAmbientOcclusion" +msgstr "Plano y rápido: sin oclusión ambiental" + +# Source-Hash: 060a718cdcff61b3 +# Review: required +# English: "Floor plan annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanAnnotations" +msgstr "Anotaciones del plano de planta" + +# Source-Hash: 483171f79dc32ae5 +# Review: required +# English: "Floor plan mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanMode" +msgstr "Modo plano de planta" + +# Source-Hash: 8bb9e54fc786ca77 +# Review: required +# English: "Full ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullAmbientOcclusion" +msgstr "Oclusión ambiental completa" + +# Source-Hash: 91fd3544d9ce16bf +# Review: required +# English: "Full documentation and annotation controls" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullDocumentationAndAnnotationControls" +msgstr "Documentación y anotaciones completas" + +# Source-Hash: 131bac2467f4fdf6 +# Review: required +# English: "Full height" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullHeight" +msgstr "Altura completa" + +# Source-Hash: c9838bc98cb35125 +# Review: required +# English: "Full wall thickness" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullWallThickness" +msgstr "Espesor total del muro" + +# Source-Hash: 7e4a0a38f694be6b +# Review: required +# English: "Grid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.grid" +msgstr "Cuadrícula" + +# Source-Hash: 4bf4a6861d7d633e +# Review: required +# English: "Levels: {mode}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.levelsMode" +msgstr "Plantas: {mode}" + +# Source-Hash: 803532407fb5962b +# Review: required +# English: "Low" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.low" +msgstr "Bajo" + +# Source-Hash: 32f9a404c0bdce10 +# Review: required +# English: "Magnetic snap" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.magneticSnap" +msgstr "Ajuste magnético" + +# Source-Hash: 387082cd5f118bed +# Review: required +# English: "Manual" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manual" +msgstr "Manual" + +# Source-Hash: 2fb69122dd996c0a +# Review: required +# English: "Manual dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manualDimensions" +msgstr "Cotas manuales" + +# Source-Hash: c6aa74075f37313a +# Review: required +# English: "Measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measurements" +msgstr "Medidas" + +# Source-Hash: 0a39470be3b84536 +# Review: required +# English: "Meters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.meters" +msgstr "Metros" + +# Source-Hash: 83cce6c521e71d01 +# Review: required +# English: "Millimeters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.millimeters" +msgstr "Milímetros" + +# Source-Hash: b784527bb90b9c5e +# Review: required +# English: "3D measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n3dMeasurements" +msgstr "Medidas 3D" + +# Source-Hash: 4ff58913a4492199 +# Review: required +# English: "No edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.noEdgeLines" +msgstr "Sin aristas" + +# Source-Hash: 50accd740fa2e736 +# Review: required +# English: "Off" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.off" +msgstr "Desactivado" + +# Source-Hash: 9cc01faad79c28da +# Review: required +# English: "On" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.on" +msgstr "Activado" + +# Source-Hash: ed59dd8ce7797a66 +# Review: required +# English: "Orthographic" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.orthographic" +msgstr "Ortográfica" + +# Source-Hash: 316e25993ff72b88 +# Review: required +# English: "Perspective" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.perspective" +msgstr "Perspectiva" + +# Source-Hash: 20226b68d5467072 +# Review: required +# English: "Preview" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.preview" +msgstr "Vista previa" + +# Source-Hash: 34c20b72a42ca618 +# Review: required +# English: "Preview mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.previewMode" +msgstr "Modo de vista previa" + +# Source-Hash: 5e58af99d6d4fa6a +# Review: required +# English: "Render" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.render" +msgstr "Renderizado" + +# Source-Hash: f363702a10aedaeb +# Review: required +# English: "Rendered" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.rendered" +msgstr "Renderizado" + +# Source-Hash: 4959d5538efc595c +# Review: required +# English: "Room labels" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomLabels" +msgstr "Etiquetas de estancias" + +# Source-Hash: 82720864e5034398 +# Review: required +# English: "Scene theme" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.sceneTheme" +msgstr "Tema de la escena" + +# Source-Hash: 4c6bcb30b40047fc +# Review: required +# English: "Shadows" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.shadows" +msgstr "Sombras" + +# Source-Hash: 59dc62417b44931d +# Review: required +# English: "Single wall axis" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.singleWallAxis" +msgstr "Eje único del muro" + +# Source-Hash: d266d83ec490df4e +# Review: required +# English: "Soft" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.soft" +msgstr "Suaves" + +# Source-Hash: ef3e765e692faf4c +# Review: required +# English: "Solid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solid" +msgstr "Sólido" + +# Source-Hash: e9f59b513f2f45ac +# Review: required +# English: "Solo" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solo" +msgstr "Aislado" + +# Source-Hash: 481b7608ce12139b +# Review: required +# English: "Stack" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stack" +msgstr "Apilado" + +# Source-Hash: 61ad94ca68b0458e +# Review: required +# English: "Stair annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stairAnnotations" +msgstr "Anotaciones de escaleras" + +# Source-Hash: f82927a01d4c5e45 +# Review: required +# English: "Strong" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.strong" +msgstr "Marcadas" + +# Source-Hash: e1be031e67d95382 +# Review: required +# English: "Structural core face" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralCoreFace" +msgstr "Cara del núcleo estructural" + +# Source-Hash: efc50964d7b0ec47 +# Review: required +# English: "Structural grids & column centers" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralGridsColumnCenters" +msgstr "Ejes estructurales y centros de pilares" + +# Source-Hash: 5ce4f6b80cd30f86 +# Review: required +# English: "Translucent" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.translucent" +msgstr "Translúcido" + +# Source-Hash: b404dded35241274 +# Review: required +# English: "Units" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.units" +msgstr "Unidades" + +# Source-Hash: faf51e28b748e0d9 +# Review: required +# English: "Walkthrough" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.walkthrough" +msgstr "Recorrido" + +# Source-Hash: 62281975e51da7e3 +# Review: required +# English: "Wall centerline" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallCenterline" +msgstr "Eje del muro" + +# Source-Hash: ff145d7003118ec6 +# Review: required +# English: "Wall dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallDimensions" +msgstr "Cotas de muros" + +# Source-Hash: 13969d1d6e310aa4 +# Review: required +# English: "Walls: {label}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallsLabel" +msgstr "Muros: {label}" + # Source-Hash: 8caa959c0ae800c3 # Review: human # English: "Basement" @@ -485,49 +1125,49 @@ msgstr "Dividida" # Source-Hash: f14b89d713d2528a # Review: human # English: "Blueprint" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.blueprint" msgstr "Plano técnico" # Source-Hash: 142bcb2841f423c5 # Review: human # English: "Mediterranean" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.mediterranean" msgstr "Mediterráneo" # Source-Hash: b399942ec5d7e1ba # Review: human # English: "Night" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.night" msgstr "Noche" # Source-Hash: f512d1b947b8ae5a # Review: human # English: "Overcast" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.overcast" msgstr "Nublado" # Source-Hash: 583542b3bc837192 # Review: human # English: "Paper" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.paper" msgstr "Papel" # Source-Hash: 7abc2dc6e39b1747 # Review: human # English: "Studio" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.studio" msgstr "Estudio" # Source-Hash: efe94d3ec8d8c44e # Review: human # English: "Sunset" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.sunset" msgstr "Atardecer" @@ -541,14 +1181,14 @@ msgstr "Ambiente" # Source-Hash: 4c10ea0aa0e2ea41 # Review: human # English: "Twilight" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.twilight" msgstr "Crepúsculo" # Source-Hash: f9592fb0672740c0 # Review: human # English: "Verdant" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.verdant" msgstr "Verde" diff --git a/packages/editor/src/i18n/locales/fr/messages.po b/packages/editor/src/i18n/locales/fr/messages.po index 89431ce1c1..bcaf4da9a0 100644 --- a/packages/editor/src/i18n/locales/fr/messages.po +++ b/packages/editor/src/i18n/locales/fr/messages.po @@ -13,6 +13,646 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +# Source-Hash: 3d3f438d5a49eba7 +# Review: required +# English: "Automatic dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.automaticDimensions" +msgstr "Cotes automatiques" + +# Source-Hash: 14622745dbf93f4c +# Review: required +# English: "Camera" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.camera" +msgstr "Caméra" + +# Source-Hash: e6bce525c47ba3ac +# Review: required +# English: "Clean plan; dimensions appear with selection" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cleanPlanDimensionsAppearWithSelection" +msgstr "Plan épuré ; les cotes apparaissent à la sélection" + +# Source-Hash: 61ce356577cfb04a +# Review: required +# English: "Collapse sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.collapseSidebar" +msgstr "Réduire la barre latérale" + +# Source-Hash: 2416a48df28d6205 +# Review: required +# English: "Crisp, opaque edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.crispOpaqueEdgeLines" +msgstr "Arêtes nettes et opaques" + +# Source-Hash: 4da8b3678ed77b45 +# Review: required +# English: "Cutaway" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cutaway" +msgstr "Coupe" + +# Source-Hash: 4ca0e0e73229540c +# Review: required +# English: "Default" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.default" +msgstr "Par défaut" + +# Source-Hash: a313661ef9dd0a65 +# Review: required +# English: "Display" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.display" +msgstr "Affichage" + +# Source-Hash: d0db46f206a88e2e +# Review: required +# English: "Display settings" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.displaySettings" +msgstr "Paramètres d’affichage" + +# Source-Hash: 0286962ab8e9cfcd +# Review: required +# English: "Door/window marks" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.doorWindowMarks" +msgstr "Repères de portes et fenêtres" + +# Source-Hash: 027bbc8b7287c06a +# Review: required +# English: "Edges" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.edges" +msgstr "Arêtes" + +# Source-Hash: d86126c5d16c6238 +# Review: required +# English: "Enter VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.enterVr" +msgstr "Entrer en VR" + +# Source-Hash: eb99fb0b382e58cd +# Review: required +# English: "Exit VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exitVr" +msgstr "Quitter la VR" + +# Source-Hash: aeac665749d3101d +# Review: required +# English: "Expand sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expandSidebar" +msgstr "Développer la barre latérale" + +# Source-Hash: 08c178ee733ff009 +# Review: required +# English: "Expert" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expert" +msgstr "Expert" + +# Source-Hash: be12f8788f1f0a05 +# Review: required +# English: "Exploded" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exploded" +msgstr "Éclatée" + +# Source-Hash: c6f865a366ef5755 +# Review: required +# English: "Face of stud" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faceOfStud" +msgstr "Nu de l’ossature" + +# Source-Hash: 0c583f1d4201293b +# Review: required +# English: "Faint outline of major creases" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faintOutlineOfMajorCreases" +msgstr "Contour léger des arêtes principales" + +# Source-Hash: 08ecd5878b08139d +# Review: required +# English: "Feet & inches" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.feetInches" +msgstr "Pieds et pouces" + +# Source-Hash: 43b8017fa821c46c +# Review: required +# English: "Finished faces" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.finishedFaces" +msgstr "Faces finies" + +# Source-Hash: 8827df1cdeb02ed9 +# Review: required +# English: "Flat and fast — no ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.flatAndFastNoAmbientOcclusion" +msgstr "Plat et rapide — sans occlusion ambiante" + +# Source-Hash: 060a718cdcff61b3 +# Review: required +# English: "Floor plan annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanAnnotations" +msgstr "Annotations du plan d’étage" + +# Source-Hash: 483171f79dc32ae5 +# Review: required +# English: "Floor plan mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanMode" +msgstr "Mode plan d’étage" + +# Source-Hash: 8bb9e54fc786ca77 +# Review: required +# English: "Full ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullAmbientOcclusion" +msgstr "Occlusion ambiante complète" + +# Source-Hash: 91fd3544d9ce16bf +# Review: required +# English: "Full documentation and annotation controls" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullDocumentationAndAnnotationControls" +msgstr "Documentation et annotations complètes" + +# Source-Hash: 131bac2467f4fdf6 +# Review: required +# English: "Full height" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullHeight" +msgstr "Pleine hauteur" + +# Source-Hash: c9838bc98cb35125 +# Review: required +# English: "Full wall thickness" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullWallThickness" +msgstr "Épaisseur totale du mur" + +# Source-Hash: 7e4a0a38f694be6b +# Review: required +# English: "Grid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.grid" +msgstr "Grille" + +# Source-Hash: 4bf4a6861d7d633e +# Review: required +# English: "Levels: {mode}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.levelsMode" +msgstr "Niveaux : {mode}" + +# Source-Hash: 803532407fb5962b +# Review: required +# English: "Low" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.low" +msgstr "Bas" + +# Source-Hash: 32f9a404c0bdce10 +# Review: required +# English: "Magnetic snap" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.magneticSnap" +msgstr "Aimantation" + +# Source-Hash: 387082cd5f118bed +# Review: required +# English: "Manual" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manual" +msgstr "Manuel" + +# Source-Hash: 2fb69122dd996c0a +# Review: required +# English: "Manual dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manualDimensions" +msgstr "Cotes manuelles" + +# Source-Hash: c6aa74075f37313a +# Review: required +# English: "Measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measurements" +msgstr "Mesures" + +# Source-Hash: 0a39470be3b84536 +# Review: required +# English: "Meters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.meters" +msgstr "Mètres" + +# Source-Hash: 83cce6c521e71d01 +# Review: required +# English: "Millimeters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.millimeters" +msgstr "Millimètres" + +# Source-Hash: b784527bb90b9c5e +# Review: required +# English: "3D measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n3dMeasurements" +msgstr "Mesures 3D" + +# Source-Hash: 4ff58913a4492199 +# Review: required +# English: "No edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.noEdgeLines" +msgstr "Aucune arête" + +# Source-Hash: 50accd740fa2e736 +# Review: required +# English: "Off" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.off" +msgstr "Désactivé" + +# Source-Hash: 9cc01faad79c28da +# Review: required +# English: "On" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.on" +msgstr "Activé" + +# Source-Hash: ed59dd8ce7797a66 +# Review: required +# English: "Orthographic" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.orthographic" +msgstr "Orthographique" + +# Source-Hash: 316e25993ff72b88 +# Review: required +# English: "Perspective" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.perspective" +msgstr "Perspective" + +# Source-Hash: 20226b68d5467072 +# Review: required +# English: "Preview" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.preview" +msgstr "Aperçu" + +# Source-Hash: 34c20b72a42ca618 +# Review: required +# English: "Preview mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.previewMode" +msgstr "Mode aperçu" + +# Source-Hash: 5e58af99d6d4fa6a +# Review: required +# English: "Render" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.render" +msgstr "Rendu" + +# Source-Hash: f363702a10aedaeb +# Review: required +# English: "Rendered" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.rendered" +msgstr "Rendu" + +# Source-Hash: 4959d5538efc595c +# Review: required +# English: "Room labels" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomLabels" +msgstr "Étiquettes des pièces" + +# Source-Hash: 82720864e5034398 +# Review: required +# English: "Scene theme" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.sceneTheme" +msgstr "Thème de la scène" + +# Source-Hash: 4c6bcb30b40047fc +# Review: required +# English: "Shadows" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.shadows" +msgstr "Ombres" + +# Source-Hash: 59dc62417b44931d +# Review: required +# English: "Single wall axis" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.singleWallAxis" +msgstr "Axe unique du mur" + +# Source-Hash: d266d83ec490df4e +# Review: required +# English: "Soft" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.soft" +msgstr "Douces" + +# Source-Hash: ef3e765e692faf4c +# Review: required +# English: "Solid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solid" +msgstr "Plein" + +# Source-Hash: e9f59b513f2f45ac +# Review: required +# English: "Solo" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solo" +msgstr "Isolé" + +# Source-Hash: 481b7608ce12139b +# Review: required +# English: "Stack" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stack" +msgstr "Empilé" + +# Source-Hash: 61ad94ca68b0458e +# Review: required +# English: "Stair annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stairAnnotations" +msgstr "Annotations d’escalier" + +# Source-Hash: f82927a01d4c5e45 +# Review: required +# English: "Strong" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.strong" +msgstr "Marquées" + +# Source-Hash: e1be031e67d95382 +# Review: required +# English: "Structural core face" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralCoreFace" +msgstr "Nu du noyau structurel" + +# Source-Hash: efc50964d7b0ec47 +# Review: required +# English: "Structural grids & column centers" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralGridsColumnCenters" +msgstr "Trames structurelles et axes des poteaux" + +# Source-Hash: 5ce4f6b80cd30f86 +# Review: required +# English: "Translucent" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.translucent" +msgstr "Translucide" + +# Source-Hash: b404dded35241274 +# Review: required +# English: "Units" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.units" +msgstr "Unités" + +# Source-Hash: faf51e28b748e0d9 +# Review: required +# English: "Walkthrough" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.walkthrough" +msgstr "Visite" + +# Source-Hash: 62281975e51da7e3 +# Review: required +# English: "Wall centerline" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallCenterline" +msgstr "Axe du mur" + +# Source-Hash: ff145d7003118ec6 +# Review: required +# English: "Wall dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallDimensions" +msgstr "Cotes des murs" + +# Source-Hash: 13969d1d6e310aa4 +# Review: required +# English: "Walls: {label}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallsLabel" +msgstr "Murs : {label}" + # Source-Hash: 8caa959c0ae800c3 # Review: human # English: "Basement" @@ -485,49 +1125,49 @@ msgstr "Partagé" # Source-Hash: f14b89d713d2528a # Review: human # English: "Blueprint" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.blueprint" msgstr "Plan" # Source-Hash: 142bcb2841f423c5 # Review: human # English: "Mediterranean" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.mediterranean" msgstr "Méditerranéen" # Source-Hash: b399942ec5d7e1ba # Review: human # English: "Night" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.night" msgstr "Nuit" # Source-Hash: f512d1b947b8ae5a # Review: human # English: "Overcast" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.overcast" msgstr "Ciel couvert" # Source-Hash: 583542b3bc837192 # Review: human # English: "Paper" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.paper" msgstr "Papier" # Source-Hash: 7abc2dc6e39b1747 # Review: human # English: "Studio" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.studio" msgstr "Studio" # Source-Hash: efe94d3ec8d8c44e # Review: human # English: "Sunset" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.sunset" msgstr "Coucher de soleil" @@ -541,14 +1181,14 @@ msgstr "Ambiance" # Source-Hash: 4c10ea0aa0e2ea41 # Review: human # English: "Twilight" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.twilight" msgstr "Crépuscule" # Source-Hash: f9592fb0672740c0 # Review: human # English: "Verdant" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.verdant" msgstr "Verdoyant" diff --git a/packages/editor/src/i18n/locales/ja/messages.po b/packages/editor/src/i18n/locales/ja/messages.po index 7fe420abfb..2110cd0196 100644 --- a/packages/editor/src/i18n/locales/ja/messages.po +++ b/packages/editor/src/i18n/locales/ja/messages.po @@ -13,6 +13,646 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +# Source-Hash: 3d3f438d5a49eba7 +# Review: required +# English: "Automatic dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.automaticDimensions" +msgstr "自動寸法" + +# Source-Hash: 14622745dbf93f4c +# Review: required +# English: "Camera" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.camera" +msgstr "カメラ" + +# Source-Hash: e6bce525c47ba3ac +# Review: required +# English: "Clean plan; dimensions appear with selection" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cleanPlanDimensionsAppearWithSelection" +msgstr "すっきりした図面。寸法は選択時に表示" + +# Source-Hash: 61ce356577cfb04a +# Review: required +# English: "Collapse sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.collapseSidebar" +msgstr "サイドバーを折りたたむ" + +# Source-Hash: 2416a48df28d6205 +# Review: required +# English: "Crisp, opaque edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.crispOpaqueEdgeLines" +msgstr "くっきりした不透明なエッジ線" + +# Source-Hash: 4da8b3678ed77b45 +# Review: required +# English: "Cutaway" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cutaway" +msgstr "カットアウェイ" + +# Source-Hash: 4ca0e0e73229540c +# Review: required +# English: "Default" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.default" +msgstr "標準" + +# Source-Hash: a313661ef9dd0a65 +# Review: required +# English: "Display" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.display" +msgstr "表示" + +# Source-Hash: d0db46f206a88e2e +# Review: required +# English: "Display settings" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.displaySettings" +msgstr "表示設定" + +# Source-Hash: 0286962ab8e9cfcd +# Review: required +# English: "Door/window marks" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.doorWindowMarks" +msgstr "建具記号" + +# Source-Hash: 027bbc8b7287c06a +# Review: required +# English: "Edges" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.edges" +msgstr "エッジ" + +# Source-Hash: d86126c5d16c6238 +# Review: required +# English: "Enter VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.enterVr" +msgstr "VR を開始" + +# Source-Hash: eb99fb0b382e58cd +# Review: required +# English: "Exit VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exitVr" +msgstr "VR を終了" + +# Source-Hash: aeac665749d3101d +# Review: required +# English: "Expand sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expandSidebar" +msgstr "サイドバーを展開" + +# Source-Hash: 08c178ee733ff009 +# Review: required +# English: "Expert" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expert" +msgstr "エキスパート" + +# Source-Hash: be12f8788f1f0a05 +# Review: required +# English: "Exploded" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exploded" +msgstr "分解" + +# Source-Hash: c6f865a366ef5755 +# Review: required +# English: "Face of stud" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faceOfStud" +msgstr "下地面" + +# Source-Hash: 0c583f1d4201293b +# Review: required +# English: "Faint outline of major creases" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faintOutlineOfMajorCreases" +msgstr "主な折れ目の淡い輪郭" + +# Source-Hash: 08ecd5878b08139d +# Review: required +# English: "Feet & inches" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.feetInches" +msgstr "フィート・インチ" + +# Source-Hash: 43b8017fa821c46c +# Review: required +# English: "Finished faces" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.finishedFaces" +msgstr "仕上げ面" + +# Source-Hash: 8827df1cdeb02ed9 +# Review: required +# English: "Flat and fast — no ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.flatAndFastNoAmbientOcclusion" +msgstr "フラットで高速 — アンビエントオクルージョンなし" + +# Source-Hash: 060a718cdcff61b3 +# Review: required +# English: "Floor plan annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanAnnotations" +msgstr "平面図の注記" + +# Source-Hash: 483171f79dc32ae5 +# Review: required +# English: "Floor plan mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanMode" +msgstr "平面図モード" + +# Source-Hash: 8bb9e54fc786ca77 +# Review: required +# English: "Full ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullAmbientOcclusion" +msgstr "フルアンビエントオクルージョン" + +# Source-Hash: 91fd3544d9ce16bf +# Review: required +# English: "Full documentation and annotation controls" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullDocumentationAndAnnotationControls" +msgstr "図面化と注記の全コントロール" + +# Source-Hash: 131bac2467f4fdf6 +# Review: required +# English: "Full height" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullHeight" +msgstr "全高" + +# Source-Hash: c9838bc98cb35125 +# Review: required +# English: "Full wall thickness" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullWallThickness" +msgstr "壁の全厚" + +# Source-Hash: 7e4a0a38f694be6b +# Review: required +# English: "Grid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.grid" +msgstr "グリッド" + +# Source-Hash: 4bf4a6861d7d633e +# Review: required +# English: "Levels: {mode}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.levelsMode" +msgstr "階層: {mode}" + +# Source-Hash: 803532407fb5962b +# Review: required +# English: "Low" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.low" +msgstr "低" + +# Source-Hash: 32f9a404c0bdce10 +# Review: required +# English: "Magnetic snap" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.magneticSnap" +msgstr "マグネットスナップ" + +# Source-Hash: 387082cd5f118bed +# Review: required +# English: "Manual" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manual" +msgstr "手動" + +# Source-Hash: 2fb69122dd996c0a +# Review: required +# English: "Manual dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manualDimensions" +msgstr "手動寸法" + +# Source-Hash: c6aa74075f37313a +# Review: required +# English: "Measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measurements" +msgstr "計測" + +# Source-Hash: 0a39470be3b84536 +# Review: required +# English: "Meters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.meters" +msgstr "メートル" + +# Source-Hash: 83cce6c521e71d01 +# Review: required +# English: "Millimeters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.millimeters" +msgstr "ミリメートル" + +# Source-Hash: b784527bb90b9c5e +# Review: required +# English: "3D measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n3dMeasurements" +msgstr "3D 計測" + +# Source-Hash: 4ff58913a4492199 +# Review: required +# English: "No edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.noEdgeLines" +msgstr "エッジ線なし" + +# Source-Hash: 50accd740fa2e736 +# Review: required +# English: "Off" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.off" +msgstr "オフ" + +# Source-Hash: 9cc01faad79c28da +# Review: required +# English: "On" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.on" +msgstr "オン" + +# Source-Hash: ed59dd8ce7797a66 +# Review: required +# English: "Orthographic" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.orthographic" +msgstr "平行投影" + +# Source-Hash: 316e25993ff72b88 +# Review: required +# English: "Perspective" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.perspective" +msgstr "透視投影" + +# Source-Hash: 20226b68d5467072 +# Review: required +# English: "Preview" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.preview" +msgstr "プレビュー" + +# Source-Hash: 34c20b72a42ca618 +# Review: required +# English: "Preview mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.previewMode" +msgstr "プレビューモード" + +# Source-Hash: 5e58af99d6d4fa6a +# Review: required +# English: "Render" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.render" +msgstr "レンダリング" + +# Source-Hash: f363702a10aedaeb +# Review: required +# English: "Rendered" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.rendered" +msgstr "レンダリング" + +# Source-Hash: 4959d5538efc595c +# Review: required +# English: "Room labels" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomLabels" +msgstr "部屋ラベル" + +# Source-Hash: 82720864e5034398 +# Review: required +# English: "Scene theme" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.sceneTheme" +msgstr "シーンテーマ" + +# Source-Hash: 4c6bcb30b40047fc +# Review: required +# English: "Shadows" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.shadows" +msgstr "影" + +# Source-Hash: 59dc62417b44931d +# Review: required +# English: "Single wall axis" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.singleWallAxis" +msgstr "壁の中心線" + +# Source-Hash: d266d83ec490df4e +# Review: required +# English: "Soft" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.soft" +msgstr "ソフト" + +# Source-Hash: ef3e765e692faf4c +# Review: required +# English: "Solid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solid" +msgstr "ソリッド" + +# Source-Hash: e9f59b513f2f45ac +# Review: required +# English: "Solo" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solo" +msgstr "単独" + +# Source-Hash: 481b7608ce12139b +# Review: required +# English: "Stack" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stack" +msgstr "積み重ね" + +# Source-Hash: 61ad94ca68b0458e +# Review: required +# English: "Stair annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stairAnnotations" +msgstr "階段の注記" + +# Source-Hash: f82927a01d4c5e45 +# Review: required +# English: "Strong" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.strong" +msgstr "強" + +# Source-Hash: e1be031e67d95382 +# Review: required +# English: "Structural core face" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralCoreFace" +msgstr "構造躯体面" + +# Source-Hash: efc50964d7b0ec47 +# Review: required +# English: "Structural grids & column centers" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralGridsColumnCenters" +msgstr "構造通り芯と柱芯" + +# Source-Hash: 5ce4f6b80cd30f86 +# Review: required +# English: "Translucent" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.translucent" +msgstr "半透明" + +# Source-Hash: b404dded35241274 +# Review: required +# English: "Units" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.units" +msgstr "単位" + +# Source-Hash: faf51e28b748e0d9 +# Review: required +# English: "Walkthrough" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.walkthrough" +msgstr "ウォークスルー" + +# Source-Hash: 62281975e51da7e3 +# Review: required +# English: "Wall centerline" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallCenterline" +msgstr "壁芯" + +# Source-Hash: ff145d7003118ec6 +# Review: required +# English: "Wall dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallDimensions" +msgstr "壁の寸法" + +# Source-Hash: 13969d1d6e310aa4 +# Review: required +# English: "Walls: {label}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallsLabel" +msgstr "壁: {label}" + # Source-Hash: 8caa959c0ae800c3 # Review: human # English: "Basement" @@ -485,49 +1125,49 @@ msgstr "分割" # Source-Hash: f14b89d713d2528a # Review: human # English: "Blueprint" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.blueprint" msgstr "青図" # Source-Hash: 142bcb2841f423c5 # Review: human # English: "Mediterranean" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.mediterranean" msgstr "地中海" # Source-Hash: b399942ec5d7e1ba # Review: human # English: "Night" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.night" msgstr "夜景" # Source-Hash: f512d1b947b8ae5a # Review: human # English: "Overcast" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.overcast" msgstr "曇天" # Source-Hash: 583542b3bc837192 # Review: human # English: "Paper" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.paper" msgstr "ペーパー" # Source-Hash: 7abc2dc6e39b1747 # Review: human # English: "Studio" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.studio" msgstr "スタジオ" # Source-Hash: efe94d3ec8d8c44e # Review: human # English: "Sunset" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.sunset" msgstr "夕景" @@ -541,14 +1181,14 @@ msgstr "シーンテーマ" # Source-Hash: 4c10ea0aa0e2ea41 # Review: human # English: "Twilight" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.twilight" msgstr "薄暮" # Source-Hash: f9592fb0672740c0 # Review: human # English: "Verdant" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.verdant" msgstr "緑景" diff --git a/packages/editor/src/i18n/locales/zh-CN/messages.po b/packages/editor/src/i18n/locales/zh-CN/messages.po index 9b059286fe..d975664c4e 100644 --- a/packages/editor/src/i18n/locales/zh-CN/messages.po +++ b/packages/editor/src/i18n/locales/zh-CN/messages.po @@ -13,6 +13,646 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +# Source-Hash: 3d3f438d5a49eba7 +# Review: required +# English: "Automatic dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.automaticDimensions" +msgstr "自动尺寸" + +# Source-Hash: 14622745dbf93f4c +# Review: required +# English: "Camera" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.camera" +msgstr "相机" + +# Source-Hash: e6bce525c47ba3ac +# Review: required +# English: "Clean plan; dimensions appear with selection" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cleanPlanDimensionsAppearWithSelection" +msgstr "简洁平面;选中时显示尺寸" + +# Source-Hash: 61ce356577cfb04a +# Review: required +# English: "Collapse sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.collapseSidebar" +msgstr "收起侧边栏" + +# Source-Hash: 2416a48df28d6205 +# Review: required +# English: "Crisp, opaque edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.crispOpaqueEdgeLines" +msgstr "清晰、不透明的边线" + +# Source-Hash: 4da8b3678ed77b45 +# Review: required +# English: "Cutaway" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.cutaway" +msgstr "剖切" + +# Source-Hash: 4ca0e0e73229540c +# Review: required +# English: "Default" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.default" +msgstr "默认" + +# Source-Hash: a313661ef9dd0a65 +# Review: required +# English: "Display" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.display" +msgstr "显示" + +# Source-Hash: d0db46f206a88e2e +# Review: required +# English: "Display settings" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.displaySettings" +msgstr "显示设置" + +# Source-Hash: 0286962ab8e9cfcd +# Review: required +# English: "Door/window marks" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.doorWindowMarks" +msgstr "门窗标记" + +# Source-Hash: 027bbc8b7287c06a +# Review: required +# English: "Edges" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.edges" +msgstr "边线" + +# Source-Hash: d86126c5d16c6238 +# Review: required +# English: "Enter VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.enterVr" +msgstr "进入 VR" + +# Source-Hash: eb99fb0b382e58cd +# Review: required +# English: "Exit VR" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exitVr" +msgstr "退出 VR" + +# Source-Hash: aeac665749d3101d +# Review: required +# English: "Expand sidebar" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expandSidebar" +msgstr "展开侧边栏" + +# Source-Hash: 08c178ee733ff009 +# Review: required +# English: "Expert" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.expert" +msgstr "专家" + +# Source-Hash: be12f8788f1f0a05 +# Review: required +# English: "Exploded" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.exploded" +msgstr "分解" + +# Source-Hash: c6f865a366ef5755 +# Review: required +# English: "Face of stud" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faceOfStud" +msgstr "龙骨面" + +# Source-Hash: 0c583f1d4201293b +# Review: required +# English: "Faint outline of major creases" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.faintOutlineOfMajorCreases" +msgstr "主要折边的淡轮廓" + +# Source-Hash: 08ecd5878b08139d +# Review: required +# English: "Feet & inches" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.feetInches" +msgstr "英尺和英寸" + +# Source-Hash: 43b8017fa821c46c +# Review: required +# English: "Finished faces" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.finishedFaces" +msgstr "完成面" + +# Source-Hash: 8827df1cdeb02ed9 +# Review: required +# English: "Flat and fast — no ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.flatAndFastNoAmbientOcclusion" +msgstr "平面且快速 — 无环境光遮蔽" + +# Source-Hash: 060a718cdcff61b3 +# Review: required +# English: "Floor plan annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanAnnotations" +msgstr "平面图标注" + +# Source-Hash: 483171f79dc32ae5 +# Review: required +# English: "Floor plan mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.floorPlanMode" +msgstr "平面图模式" + +# Source-Hash: 8bb9e54fc786ca77 +# Review: required +# English: "Full ambient occlusion" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullAmbientOcclusion" +msgstr "完整环境光遮蔽" + +# Source-Hash: 91fd3544d9ce16bf +# Review: required +# English: "Full documentation and annotation controls" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullDocumentationAndAnnotationControls" +msgstr "完整的图档与标注控件" + +# Source-Hash: 131bac2467f4fdf6 +# Review: required +# English: "Full height" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullHeight" +msgstr "全高" + +# Source-Hash: c9838bc98cb35125 +# Review: required +# English: "Full wall thickness" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.fullWallThickness" +msgstr "墙体全厚" + +# Source-Hash: 7e4a0a38f694be6b +# Review: required +# English: "Grid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.grid" +msgstr "网格" + +# Source-Hash: 4bf4a6861d7d633e +# Review: required +# English: "Levels: {mode}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.levelsMode" +msgstr "楼层:{mode}" + +# Source-Hash: 803532407fb5962b +# Review: required +# English: "Low" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.low" +msgstr "矮墙" + +# Source-Hash: 32f9a404c0bdce10 +# Review: required +# English: "Magnetic snap" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.magneticSnap" +msgstr "磁性吸附" + +# Source-Hash: 387082cd5f118bed +# Review: required +# English: "Manual" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manual" +msgstr "手动" + +# Source-Hash: 2fb69122dd996c0a +# Review: required +# English: "Manual dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.manualDimensions" +msgstr "手动尺寸" + +# Source-Hash: c6aa74075f37313a +# Review: required +# English: "Measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.measurements" +msgstr "测量" + +# Source-Hash: 0a39470be3b84536 +# Review: required +# English: "Meters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.meters" +msgstr "米" + +# Source-Hash: 83cce6c521e71d01 +# Review: required +# English: "Millimeters" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.millimeters" +msgstr "毫米" + +# Source-Hash: b784527bb90b9c5e +# Review: required +# English: "3D measurements" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.n3dMeasurements" +msgstr "3D 测量" + +# Source-Hash: 4ff58913a4492199 +# Review: required +# English: "No edge lines" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.noEdgeLines" +msgstr "无边线" + +# Source-Hash: 50accd740fa2e736 +# Review: required +# English: "Off" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.off" +msgstr "关" + +# Source-Hash: 9cc01faad79c28da +# Review: required +# English: "On" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.on" +msgstr "开" + +# Source-Hash: ed59dd8ce7797a66 +# Review: required +# English: "Orthographic" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.orthographic" +msgstr "正交" + +# Source-Hash: 316e25993ff72b88 +# Review: required +# English: "Perspective" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.perspective" +msgstr "透视" + +# Source-Hash: 20226b68d5467072 +# Review: required +# English: "Preview" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.preview" +msgstr "预览" + +# Source-Hash: 34c20b72a42ca618 +# Review: required +# English: "Preview mode" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.previewMode" +msgstr "预览模式" + +# Source-Hash: 5e58af99d6d4fa6a +# Review: required +# English: "Render" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.render" +msgstr "渲染" + +# Source-Hash: f363702a10aedaeb +# Review: required +# English: "Rendered" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.rendered" +msgstr "渲染" + +# Source-Hash: 4959d5538efc595c +# Review: required +# English: "Room labels" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.roomLabels" +msgstr "房间标签" + +# Source-Hash: 82720864e5034398 +# Review: required +# English: "Scene theme" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.sceneTheme" +msgstr "场景主题" + +# Source-Hash: 4c6bcb30b40047fc +# Review: required +# English: "Shadows" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.shadows" +msgstr "阴影" + +# Source-Hash: 59dc62417b44931d +# Review: required +# English: "Single wall axis" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.singleWallAxis" +msgstr "单一墙体轴线" + +# Source-Hash: d266d83ec490df4e +# Review: required +# English: "Soft" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.soft" +msgstr "柔和" + +# Source-Hash: ef3e765e692faf4c +# Review: required +# English: "Solid" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solid" +msgstr "实体" + +# Source-Hash: e9f59b513f2f45ac +# Review: required +# English: "Solo" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.solo" +msgstr "单独" + +# Source-Hash: 481b7608ce12139b +# Review: required +# English: "Stack" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stack" +msgstr "堆叠" + +# Source-Hash: 61ad94ca68b0458e +# Review: required +# English: "Stair annotations" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.stairAnnotations" +msgstr "楼梯标注" + +# Source-Hash: f82927a01d4c5e45 +# Review: required +# English: "Strong" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.strong" +msgstr "强烈" + +# Source-Hash: e1be031e67d95382 +# Review: required +# English: "Structural core face" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralCoreFace" +msgstr "结构核心面" + +# Source-Hash: efc50964d7b0ec47 +# Review: required +# English: "Structural grids & column centers" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.structuralGridsColumnCenters" +msgstr "结构轴网与柱中心" + +# Source-Hash: 5ce4f6b80cd30f86 +# Review: required +# English: "Translucent" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.translucent" +msgstr "半透明" + +# Source-Hash: b404dded35241274 +# Review: required +# English: "Units" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.units" +msgstr "单位" + +# Source-Hash: faf51e28b748e0d9 +# Review: required +# English: "Walkthrough" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.walkthrough" +msgstr "漫游" + +# Source-Hash: 62281975e51da7e3 +# Review: required +# English: "Wall centerline" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallCenterline" +msgstr "墙体中心线" + +# Source-Hash: ff145d7003118ec6 +# Review: required +# English: "Wall dimensions" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallDimensions" +msgstr "墙体尺寸" + +# Source-Hash: 13969d1d6e310aa4 +# Review: required +# English: "Walls: {label}" +# AI-Provider: cursor-agent +# AI-Model: claude-opus +#: apps/editor/components/viewer-toolbar.tsx +#, fuzzy +msgid "app.viewerToolbar.wallsLabel" +msgstr "墙体:{label}" + # Source-Hash: 8caa959c0ae800c3 # Review: human # English: "Basement" @@ -485,49 +1125,49 @@ msgstr "分屏" # Source-Hash: f14b89d713d2528a # Review: human # English: "Blueprint" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.blueprint" msgstr "蓝图" # Source-Hash: 142bcb2841f423c5 # Review: human # English: "Mediterranean" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.mediterranean" msgstr "地中海" # Source-Hash: b399942ec5d7e1ba # Review: human # English: "Night" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.night" msgstr "夜景" # Source-Hash: f512d1b947b8ae5a # Review: human # English: "Overcast" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.overcast" msgstr "阴天" # Source-Hash: 583542b3bc837192 # Review: human # English: "Paper" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.paper" msgstr "纸面" # Source-Hash: 7abc2dc6e39b1747 # Review: human # English: "Studio" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.studio" msgstr "影棚" # Source-Hash: efe94d3ec8d8c44e # Review: human # English: "Sunset" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.sunset" msgstr "日落" @@ -541,14 +1181,14 @@ msgstr "场景主题" # Source-Hash: 4c10ea0aa0e2ea41 # Review: human # English: "Twilight" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.twilight" msgstr "暮色" # Source-Hash: f9592fb0672740c0 # Review: human # English: "Verdant" -#: packages/editor/src/components/viewer/viewer-controls-bar.tsx +#: packages/editor/src/i18n/scene-theme-name.ts msgid "viewer.theme.verdant" msgstr "绿意" diff --git a/packages/editor/src/index.tsx b/packages/editor/src/index.tsx index 297e7687e0..f81c953885 100644 --- a/packages/editor/src/index.tsx +++ b/packages/editor/src/index.tsx @@ -394,6 +394,7 @@ export { usePlacementNotice } from './hooks/use-placement-notice' export { useReducedMotion } from './hooks/use-reduced-motion' export { useSelectedRoom } from './hooks/use-selected-room' export { type Selection, useSelection } from './hooks/use-selection' +export { sceneThemeName } from './i18n/scene-theme-name' export { clearPlacementSurface, getPlacementSurface, From 9c3159961b6b05fd143159417276c3704ee443e8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 02:42:22 +0000 Subject: [PATCH 10/24] i18n tooling: fast fixture tests; document the release review gate --- i18n/README.md | 48 ++++++--- scripts/i18n-literals.test.ts | 190 ++++++++++++++++++++++++++-------- 2 files changed, 176 insertions(+), 62 deletions(-) diff --git a/i18n/README.md b/i18n/README.md index b274f0ec8e..4910c5e905 100644 --- a/i18n/README.md +++ b/i18n/README.md @@ -50,11 +50,20 @@ that is not flagged `fuzzy` + `Review: required`, and new hardcoded UI literals (see the literal guard below). It is read-only: use `i18n:extract` or `i18n:compile` when catalogs need to be written. -Drafts awaiting review are valid in ordinary CI but never published: compiled -packs omit them, so that locale shows the English source until a reviewer -removes `fuzzy` and sets `Review: human`. `i18n:check` prints how many entries -each locale still has awaiting review. `bun scripts/i18n.ts check --reviewed` -is the locale sign-off gate: it also fails on every draft. +Ordinary CI allows drafts; releases are gated: + +- In a pull request, drafts awaiting review pass `i18n:check` but are never + shown: compiled packs omit them, so that locale shows the English source + until a reviewer removes `fuzzy` and sets `Review: human`. `i18n:check` + prints how many entries each locale still has awaiting review. +- A translation that is `Review: human` on the base branch must stay reviewed + while its English is unchanged. A PR may edit it, but turning it back into a + draft fails CI. CI compares with the pull request's base commit; locally + `i18n:check` compares with the merge base of `origin/main`, or + `I18N_BASE_REF`. +- The release workflow runs `bun scripts/i18n.ts check --reviewed` before + publishing, which fails on any draft. A package release therefore needs + every bundled translation reviewed by a fluent person. ## Literal guard and migration codemod @@ -63,18 +72,24 @@ is the locale sign-off gate: it also fails on every draft. literals: JSX text, string-valued `aria-*`, `title`, `placeholder`, `alt`, `label`, `tooltip`, `description`… props, display keys (`label`, `title`, `placeholder`, `tooltip`…) in objects, and `toast`/`alert`/`confirm`/`setError` -payloads (also in `.ts` modules). `i18n/literal-baseline.json` records how many -legacy candidates each file still has. A file may not exceed its count, and a -file missing from the baseline (every new file) must have none. When a PR -converts copy, run `bun run i18n:literals -- update` to lower the baseline. - -Not every literal is copy. Exemptions are explicit: +payloads (also in `.ts` modules), including `const` strings rendered by name +in JSX or a UI prop. Hyphenated words ("Read-only") count as copy; icon names, +paths and snake_case keys do not. `i18n/literal-baseline.json` lists, per +file, the legacy candidates by text. A file may only contain copy its entry +lists, so adding or swapping a string fails, and a file missing from the +baseline (every new file) must have none. When a PR converts copy, run +`bun run i18n:literals -- update` to remove it from the baseline. The baseline +may only shrink: CI fails when it lists anything the base branch's baseline +does not. + +Not every literal is copy. Exemptions are explicit and reviewed: - `i18n/literal-allowlist.json` lists exact strings that are never translated - (brands, file formats, unit symbols, key names) and developer-only paths, - each path with its reason. + (brands, file formats, unit symbols, modifier key names) and developer-only + paths, each path with its reason. - `// i18n-ignore: ` (or `{/* i18n-ignore: */}` in JSX) on - the line before a literal exempts it, e.g. an authored or scene value. + the line before a literal exempts it, e.g. an authored or scene value. A + bare `i18n-ignore` without a reason exempts nothing. `bun run i18n:literals -- report [--files] [path…]` lists the remaining candidates per area or per line. The one-time migration codemod rewrites them: @@ -111,8 +126,9 @@ lists every consumer to update. Review the diff, run `bun run i18n:extract`, and `en-XA` is generated from English on every extract/compile: letters are accented, text is ~30 % longer and bracketed (`[Šĥáŕé ~~]`), and ICU arguments -and tags are kept. The standalone app registers it outside production builds -(`@pascal-app/editor/locales/pseudo`), so `?lang=en-XA` shows at a glance +and tags are kept. The standalone app registers it in development and test +builds only (`apps/editor/lib/dev-locales.ts`; production bundles never include +the catalog), so `?lang=en-XA` shows at a glance which copy bypasses the catalog and which controls clip longer text. With the app running (`bun dev`), the audit opens every surface in diff --git a/scripts/i18n-literals.test.ts b/scripts/i18n-literals.test.ts index 61ac012541..8ddeb67def 100644 --- a/scripts/i18n-literals.test.ts +++ b/scripts/i18n-literals.test.ts @@ -1,10 +1,16 @@ import { expect, test } from 'bun:test' -import { readFileSync, writeFileSync } from 'node:fs' import { compileMessageOrThrow } from '@lingui/message-utils/compileMessage' -import { parsePo, stringifyPo } from 'pofile-ts' -import { checkCatalogs, pseudoLocalize } from './i18n' +import { + checkTranslationEntries, + hashSource, + type LocaleEntries, + pseudoLocalize, + reviewRegressions, + type SourceMessage, +} from './i18n' import { convertSource, IdRegistry, namespaceFor } from './i18n-codemod' import { type Candidate, checkLiterals, scanSource } from './i18n-literals' +import { untranslatedWords } from './i18n-pseudo-audit' const allowlist = { texts: ['Pascal'], paths: {} } const convert = (path: string, source: string) => @@ -114,20 +120,40 @@ test('message IDs follow the owning package and path, disambiguating different c expect(registry.idFor('apps/editor/components/navbar.tsx', 'Share…')).toBe('app.navbar.share2') }) -test('the guard fails when a file gains copy and accepts progress', () => { - const candidate: Candidate = { kind: 'jsx-text', text: 'Hello', line: 1 } +const candidate = (text: string): Candidate => ({ kind: 'jsx-text', text, line: 1 }) + +test('the guard fails on copy the baseline does not list and reports progress', () => { const scan = new Map([ - ['a.tsx', [candidate, candidate]], - ['new.tsx', [candidate]], + ['a.tsx', [candidate('Share'), candidate('Share')]], + ['new.tsx', [candidate('Hello')]], ]) const { errors, improvable } = checkLiterals(scan, { - version: 1, - files: { 'a.tsx': 3, 'gone.tsx': 1 }, + version: 2, + files: { 'a.tsx': ['Share', 'Share', 'Copy'], 'gone.tsx': ['Old'] }, }) expect(errors).toHaveLength(1) - expect(errors[0]).toContain('new.tsx: 1 untranslated user-visible literals (baseline 0)') - expect(improvable).toEqual(['a.tsx: 2 < 3', 'gone.tsx: 0 < 1']) + expect(errors[0]).toContain('new.tsx: untranslated user-visible literals not in the baseline') + expect(improvable).toEqual(['a.tsx: 1 fewer', 'gone.tsx: 1 fewer']) +}) + +test('swapping baselined copy for new copy fails even when the count is unchanged', () => { + const { errors } = checkLiterals(new Map([['a.tsx', [candidate('Delete everything now')]]]), { + version: 2, + files: { 'a.tsx': ['Share'] }, + }) + expect(errors[0]).toContain('"Delete everything now"') +}) + +test('the baseline may only shrink relative to the base branch', () => { + const { errors } = checkLiterals( + new Map([['a.tsx', [candidate('Share'), candidate('Copy')]]]), + { version: 2, files: { 'a.tsx': ['Copy', 'Share'] } }, + { version: 2, files: { 'a.tsx': ['Share'] } }, + ) + expect(errors).toEqual([ + 'a.tsx: i18n/literal-baseline.json adds "Copy" relative to the base branch; the baseline may only shrink', + ]) }) test('an i18n-ignore comment exempts data that only looks like copy', () => { @@ -143,6 +169,68 @@ test('an i18n-ignore comment exempts data that only looks like copy', () => { expect(scanSource('packages/editor/src/components/credits.tsx', source, allowlist)).toEqual([]) }) +test('an i18n-ignore without a reason does not exempt anything', () => { + const source = `export function Credits() { + // i18n-ignore + return

+} +` + expect(scanSource('packages/editor/src/components/credits.tsx', source, allowlist)).toHaveLength( + 1, + ) +}) + +test('hyphenated labels and string constants rendered in JSX are copy', () => { + const source = `const DELETE_LABEL = 'Delete everything' +const ICON = 'lucide:trash' + +export function Toolbar() { + return ( +

+
+ ) +} +` + expect( + scanSource('packages/editor/src/components/toolbar.tsx', source, allowlist).map( + (found) => found.text, + ), + ).toEqual(['zoom-in', 'Read-only', 'Delete everything']) +}) + +test('a notification description is one candidate and one edit', () => { + const source = `export function Save() { + return