mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-11 19:22:01 +00:00
Compare commits
274 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 492c750122 | |||
| 682068f7c0 | |||
| 2a802b228b | |||
| ed462d273e | |||
| c6817d49bc | |||
| 34ff474493 | |||
| ed8c42b117 | |||
| 4a46afb867 | |||
| d98d06fd01 | |||
| ac0b0b56c3 | |||
| 10882b74af | |||
| 81221ef97e | |||
| 9c79364983 | |||
| bd69229bfd | |||
| abf17984e6 | |||
| cacdd84430 | |||
| bd3b3c0897 | |||
| c56fa868e2 | |||
| c6bd384a2d | |||
| 0a2171337b | |||
| 58ed908743 | |||
| 9ed839901c | |||
| fff55b44a8 | |||
| f43ab6a42c | |||
| f756298665 | |||
| a65ecb004a | |||
| 7b3a08563f | |||
| 70339124b1 | |||
| 821a35a8aa | |||
| a5a698c96a | |||
| 2b936bd7bf | |||
| 9534ced6da | |||
| 0b3ad434ec | |||
| 76516dd5aa | |||
| fa0063d3ee | |||
| 32f9749fee | |||
| 27423c2b78 | |||
| f5d9538979 | |||
| 32f791000d | |||
| 525171eb86 | |||
| bb81f13a17 | |||
| 211a904df6 | |||
| dc911ea384 | |||
| 12189e018d | |||
| d1f1631f88 | |||
| 20d8b8bd29 | |||
| acb532e16e | |||
| a8567bf6af | |||
| 0b9ff4c122 | |||
| 4e4f5d4182 | |||
| 30d77e83f9 | |||
| f937ac0f31 | |||
| 3fc688677c | |||
| cb1b4ed203 | |||
| 1bacd8323d | |||
| 38cecb1c6a | |||
| 3134799ac3 | |||
| a23b231a60 | |||
| 3c7329899a | |||
| 1971d71904 | |||
| 180b51468c | |||
| 27de5ba0cc | |||
| eda725dc23 | |||
| 977f7a6df2 | |||
| d7920f71cd | |||
| ec363a78f3 | |||
| 26a643a7b1 | |||
| 14a78595b2 | |||
| fcc79ae793 | |||
| fc81ca5a5b | |||
| d8b95e7bf7 | |||
| 5608c7b930 | |||
| 48f1f9e7e0 | |||
| 5e54501f34 | |||
| 9b95bdd829 | |||
| 7df1139854 | |||
| 5e33828396 | |||
| d6982e5aa7 | |||
| 3bdb61aec8 | |||
| 63a8892f82 | |||
| 8a3c5ec645 | |||
| f6498ea285 | |||
| 3a00f19e71 | |||
| 5799c0d56e | |||
| 1f560322b8 | |||
| 6ca5165a92 | |||
| 76d68ca211 | |||
| 72f039add9 | |||
| c8fc027c53 | |||
| e166d22373 | |||
| ea2fa58254 | |||
| 9a34227883 | |||
| ef49550c5e | |||
| a17e1d2c9b | |||
| c7ce50187d | |||
| 32528d4dcd | |||
| 9f4fa95e13 | |||
| cd2fe9920b | |||
| eda13321af | |||
| 794cfde212 | |||
| 0f8112b74d | |||
| 224e33033c | |||
| c2fe9216bd | |||
| 40e95b706d | |||
| 6b63b3ce6e | |||
| 3b561df768 | |||
| 5d5e1208f5 | |||
| cfbd729aa8 | |||
| a97524ea67 | |||
| 5d28467789 | |||
| 8c82399584 | |||
| 75a74aeee9 | |||
| 95dec905cd | |||
| 3a40027699 | |||
| 4eaa0adb86 | |||
| 5db0502eb7 | |||
| bf68955a1f | |||
| 0e7812992a | |||
| 3170219cec | |||
| 2e8098ec5c | |||
| ac9b9125f7 | |||
| 43d4f6fa7e | |||
| af8e63e111 | |||
| 050ac6d967 | |||
| 5d7f5507f6 | |||
| 0e69276720 | |||
| feb681af51 | |||
| 76f6caf2a8 | |||
| 1a38a7585e | |||
| 70fdcc6fc7 | |||
| a395b4e049 | |||
| 54ce32cddf | |||
| 839d523123 | |||
| 1c59721006 | |||
| e7ac83a074 | |||
| 91c10128e1 | |||
| c9ae5e8072 | |||
| c3dc468507 | |||
| 201de37b96 | |||
| 0cb554058c | |||
| c481b24329 | |||
| 0bad690ed4 | |||
| 4c512a243f | |||
| 2b88913228 | |||
| 0e5e689f7c | |||
| ed7c33df66 | |||
| 46bb71b5e1 | |||
| 18928334c7 | |||
| 709133a27a | |||
| faaa92281a | |||
| d8ef6dcf15 | |||
| f56114219b | |||
| 2215a9a50a | |||
| 182d2c6bd8 | |||
| 126e91f95b | |||
| 54e5190955 | |||
| 6ca950789c | |||
| 89e3cb13b1 | |||
| 87400c80ef | |||
| d4e8c0b034 | |||
| 595bc8069c | |||
| 44fe6a0f24 | |||
| 12a9a7f0f9 | |||
| 3749c14ad1 | |||
| 9c4970d2b2 | |||
| 8d13350c30 | |||
| 995b80a78f | |||
| 7d271b3252 | |||
| a3dcc9ca55 | |||
| 2874e782fe | |||
| d8113d096c | |||
| 023b55277f | |||
| 3e2cc277ee | |||
| 5f46248771 | |||
| 176ba5464f | |||
| 1ab3a5b179 | |||
| 2b26c1729e | |||
| 99270af8d4 | |||
| 4647e30acf | |||
| b34844c34b | |||
| be098f3ac5 | |||
| 66b7d77e65 | |||
| 7f00422057 | |||
| 472bacb16f | |||
| 6a9318bd73 | |||
| 21c6faa4e9 | |||
| a7fc90bd70 | |||
| f2207de0a0 | |||
| ddacb344b4 | |||
| 312454f899 | |||
| a347568301 | |||
| b8cb6eecd6 | |||
| 9b97d8dc8f | |||
| fcf16720d4 | |||
| dfa47ab18a | |||
| 1f207899b4 | |||
| 10c8fb66c1 | |||
| 3cb35fe8c4 | |||
| 017c47a402 | |||
| ce79b4a3c3 | |||
| b0fc4c4cc5 | |||
| 89ad5ad172 | |||
| 875e30a321 | |||
| 3c81f9ece6 | |||
| 1449d50420 | |||
| 1aa2136c1b | |||
| fd40424900 | |||
| db01a69625 | |||
| 87a50d01a2 | |||
| 43655eca67 | |||
| a0585c9d1f | |||
| e54b379906 | |||
| 9d468f900f | |||
| 4d91782c69 | |||
| 390db99255 | |||
| fadefe56ab | |||
| 94ce45a1f2 | |||
| 52c9f72249 | |||
| c9d6a9f131 | |||
| c50ebfdc5b | |||
| de1a8737a9 | |||
| ceac257649 | |||
| b55c3c2da8 | |||
| 7b0ab2f23c | |||
| 100a2eb633 | |||
| 71f1db91ab | |||
| d7a6aacbb9 | |||
| 41356709bf | |||
| 5d7897b22c | |||
| ad145c6374 | |||
| efc8969f96 | |||
| 881cecb909 | |||
| 42b7892fa6 | |||
| bf5cd7a88e | |||
| cf9706890f | |||
| c3c80adf51 | |||
| a187e8dd58 | |||
| a0dbd760b4 | |||
| f048096459 | |||
| bcea30a641 | |||
| d4860e0863 | |||
| 9de15ea9bc | |||
| f5263a4853 | |||
| fbabfca7a4 | |||
| 967b0d4401 | |||
| ab07e1fd28 | |||
| 840062c991 | |||
| 2e0e4815f1 | |||
| 4f7ca2c6bf | |||
| ed1d8a5682 | |||
| cbb1ab5a42 | |||
| 005bbe6711 | |||
| 3a4f7a1a1e | |||
| 16c720dfbe | |||
| 8e0219403f | |||
| 05e9020413 | |||
| 92c2103ffb | |||
| 170f9e240c | |||
| a20d08b753 | |||
| 6802e2d86a | |||
| 2b0e51df23 | |||
| 255f7ab0af | |||
| ba61db7c33 | |||
| 6b91257c02 | |||
| 075336bfb2 | |||
| 70c2312f16 | |||
| df127b45d5 | |||
| b34a0ad748 | |||
| a52217f4e0 | |||
| e8e73e11ab | |||
| 64614d7071 | |||
| 0c0ac5faca | |||
| 68a4399ad9 | |||
| 3de9bfefc3 |
@@ -48,13 +48,6 @@ filter = "binary(action_matrix) & test(=action_matrix_sample)"
|
||||
threads-required = 12
|
||||
priority = 100
|
||||
|
||||
# The longest test by far (a median of 950 s on the 32 vCPU runner, #14362) starts at once, beside
|
||||
# the action matrix sample. In the list below it would wait behind the tests that sort before it,
|
||||
# and the run ends when it does.
|
||||
[[profile.ci.overrides]]
|
||||
filter = "package(solidcraft-kernel) & test(=thread_tests::a_long_thread_cuts_without_a_deep_tree)"
|
||||
priority = 100
|
||||
|
||||
# The slowest tests start first, so a shard does not end with one of them running alone on a
|
||||
# core while the others sit idle. Medians from the CI test timings (the junit artifacts), slowest
|
||||
# first; a test over ~100 s belongs here (the medians of 24 full runs added the last ones, #14362).
|
||||
@@ -154,5 +147,12 @@ max-threads = 1
|
||||
|
||||
[[profile.local-ci.overrides]]
|
||||
platform = "cfg(windows)"
|
||||
filter = "package(solidcraft-gpu) | package(solidcraft) | (package(solidcraft-ui-egui) & test(/(offscreen|gpu)/))"
|
||||
# Viewport tests also open real devices when their names do not contain "gpu".
|
||||
filter = """
|
||||
package(solidcraft-gpu) | package(solidcraft) | (package(solidcraft-ui-egui) & (
|
||||
test(/(offscreen|gpu)/)
|
||||
| test(/^viewport::tests::/)
|
||||
| test(=render_workspace::tests::progressive_image_controls_route_to_the_registered_host)
|
||||
))
|
||||
"""
|
||||
test-group = "windows-gpu"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Preserve canonical source receipts and the runtime icon-discovery snapshot.
|
||||
.gitattributes text eol=lf
|
||||
/assets/icons/ui/design/requested_icons.txt text eol=lf
|
||||
/crates/look/icons/design/requested_icons.txt text eol=lf
|
||||
# Shaders reach the code through include_str!, and tests match multi-line WGSL excerpts
|
||||
# written as Rust strings (always LF), so a CRLF checkout must not change them (#13138).
|
||||
*.wgsl text eol=lf
|
||||
|
||||
+30
-16
@@ -110,7 +110,7 @@ jobs:
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- name: Install advisory scanner
|
||||
run: cargo install cargo-deny --version 0.20.2 --locked
|
||||
- name: Check locked dependencies
|
||||
@@ -405,7 +405,7 @@ jobs:
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
components: rustfmt
|
||||
# Main saves the cache; every other run restores it, read-only.
|
||||
@@ -465,7 +465,7 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
key: quick-compile
|
||||
@@ -481,7 +481,7 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
components: clippy
|
||||
# Main saves the cache; every other run restores it, read-only.
|
||||
@@ -517,7 +517,7 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
# sccache lives on a Blacksmith sticky disk (an ext4 volume cloned from the last snapshot,
|
||||
# no 10 GB limit and no download). Only main commits it; pull requests, the merge queue and
|
||||
# forks mount a clone and never write back, so nothing they build can reach main's cache.
|
||||
@@ -596,7 +596,7 @@ jobs:
|
||||
sudo apt-get install -y --no-install-recommends mesa-vulkan-drivers libvulkan1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
# sccache lives on a Blacksmith sticky disk (an ext4 volume cloned from the last snapshot,
|
||||
# no 10 GB limit and no download). Only main commits it; pull requests, the merge queue and
|
||||
# forks mount a clone and never write back, so nothing they build can reach main's cache.
|
||||
@@ -723,7 +723,7 @@ jobs:
|
||||
sudo apt-get install -y --no-install-recommends mesa-vulkan-drivers libvulkan1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
# sccache lives on a Blacksmith sticky disk (an ext4 volume cloned from the last snapshot,
|
||||
# no 10 GB limit and no download). Only main commits it; pull requests, the merge queue and
|
||||
# forks mount a clone and never write back, so nothing they build can reach main's cache.
|
||||
@@ -897,7 +897,7 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
# sccache lives on a Blacksmith sticky disk (an ext4 volume cloned from the last snapshot,
|
||||
# no 10 GB limit and no download). Only main commits it; pull requests, the merge queue and
|
||||
# forks mount a clone and never write back, so nothing they build can reach main's cache.
|
||||
@@ -961,7 +961,7 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
# sccache lives on a Blacksmith sticky disk (an ext4 volume cloned from the last snapshot,
|
||||
# no 10 GB limit and no download). Only main commits it; pull requests, the merge queue and
|
||||
# forks mount a clone and never write back, so nothing they build can reach main's cache.
|
||||
@@ -1020,7 +1020,7 @@ jobs:
|
||||
VIEWPORT_TEST_REQUIRE_GPU: "1"
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
key: windows-fxc
|
||||
@@ -1044,7 +1044,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
key: windows-startup
|
||||
@@ -1093,9 +1093,23 @@ jobs:
|
||||
echo "Waiting for $pending run(s) of this commit to finish."
|
||||
sleep 30
|
||||
done
|
||||
# Runs with every job skipped (labels, before this job reported) are not a result.
|
||||
latest=$(jq -r '[.[] | select(.status == "completed" and .conclusion != "skipped")]
|
||||
| sort_by(.created_at) | last | "\(.conclusion) \(.html_url)"' <<<"$runs")
|
||||
# The result is the newest run that ran checks, by when its latest attempt finished
|
||||
# (updated_at), so a rerun that passed replaces its first attempt's failure. Only runs that
|
||||
# passed or failed count (cancelled ones don't: a run replaced by a newer push or label, or a
|
||||
# fork run that waited for approval and was cancelled), and label runs like this one don't
|
||||
# either: their only job is ci, which repeats an older result, so counting them let one
|
||||
# copied failure outlive the rerun that fixed it.
|
||||
latest=""
|
||||
for id in $(jq -r '[.[] | select(.status == "completed" and (.conclusion == "success" or .conclusion == "failure"))]
|
||||
| sort_by(.updated_at) | reverse | .[].id' <<<"$runs"); do
|
||||
ran=$(gh api "repos/$REPO/actions/runs/$id/jobs?filter=latest&per_page=100" \
|
||||
--jq '[.jobs[] | select(.name != "ci" and .conclusion != "skipped" and .conclusion != null)] | length')
|
||||
if [ "${ran:-0}" -gt 0 ]; then
|
||||
latest=$(jq -r --argjson id "$id" '.[] | select(.id == $id) | "\(.conclusion) \(.html_url)"' <<<"$runs")
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ -n "$latest" ] || latest="none (no run of this commit ran its checks)"
|
||||
echo "The commit's latest run: $latest"
|
||||
echo "A label started this run: \`ci\` repeats the commit's latest result ($latest)." >> "$GITHUB_STEP_SUMMARY"
|
||||
test "${latest%% *}" = success
|
||||
@@ -1187,7 +1201,7 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
@@ -1443,7 +1457,7 @@ jobs:
|
||||
repository: storytold/craft-fonts
|
||||
ref: ${{ env.CRAFT_FONTS_REF }}
|
||||
path: craft-fonts
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
targets: riscv64gc-unknown-linux-gnu
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- name: Build the CLI
|
||||
run: cargo build --profile ci -p solidcraft-cli
|
||||
- name: Import and check every entry
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
# Only main and develop commit the cache; pull requests and forks mount a clone and never
|
||||
# write back.
|
||||
- name: Mount the compiler cache
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
ref: main
|
||||
# main goes through the merge queue; this deploy key may push past it.
|
||||
ssh-key: ${{ secrets.GENERATED_FILES_DEPLOY_KEY }}
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
key: generated-files
|
||||
|
||||
@@ -30,7 +30,6 @@ on:
|
||||
- "crates/kernel/**"
|
||||
- "crates/geom/**"
|
||||
- "crates/smlib/**"
|
||||
- "crates/step/**"
|
||||
- "crates/io/src/**"
|
||||
- "crates/doc/src/**"
|
||||
- "crates/engine/src/**"
|
||||
@@ -51,7 +50,6 @@ on:
|
||||
- "crates/kernel/**"
|
||||
- "crates/geom/**"
|
||||
- "crates/smlib/**"
|
||||
- "crates/step/**"
|
||||
- "crates/io/src/**"
|
||||
- "crates/doc/src/**"
|
||||
- "crates/engine/src/**"
|
||||
@@ -131,7 +129,7 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Size parallel compiles to the job's memory
|
||||
run: scripts/ci/build-jobs.sh
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
# Only pushes to main and develop commit the cache; pull requests, merge groups and forks
|
||||
# mount a clone and never write back.
|
||||
- name: Mount the compiler cache
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
key: lists
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
key: release-icons
|
||||
@@ -161,7 +161,7 @@ jobs:
|
||||
curl -fsSL -o "$RUNNER_TEMP/nfpm.deb" \
|
||||
"https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_${{ matrix.deb }}.deb"
|
||||
sudo dpkg -i "$RUNNER_TEMP/nfpm.deb"
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
key: release-linux-${{ matrix.arch }}
|
||||
@@ -369,7 +369,7 @@ jobs:
|
||||
envs: "SOLIDCRAFT_VERSION SOLIDCRAFT_BUILD_DATE"
|
||||
prepare: |
|
||||
pkg install -y bash git curl pkgconf libxkbcommon wayland libX11 libXcursor libXrandr libXi libxcb mesa-libs vulkan-loader
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
|
||||
run: |
|
||||
set -e
|
||||
. "$HOME/.cargo/env"
|
||||
@@ -404,7 +404,7 @@ jobs:
|
||||
SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
@@ -502,7 +502,7 @@ jobs:
|
||||
with:
|
||||
name: icons
|
||||
path: icons
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
@@ -633,7 +633,7 @@ jobs:
|
||||
TRUNK_VERSION: 0.21.14
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@1.98.0
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
|
||||
+465
-452
File diff suppressed because it is too large
Load Diff
+23
-6
@@ -43,8 +43,11 @@ contributors without write access can't push to them. To update one:
|
||||
|
||||
## Get it running (about 10 minutes on a fast machine)
|
||||
|
||||
You need stable Rust 1.95 or newer (required by egui/eframe 0.36). For the web
|
||||
build you also need `rustup target add wasm32-unknown-unknown` and [`trunk`](https://github.com/trunk-rs/trunk)
|
||||
You need [rustup](https://rustup.rs/). The repository pins Rust 1.98.0 in
|
||||
`rust-toolchain.toml`, the version CI builds with, and rustup installs it with rustfmt, clippy and
|
||||
the `wasm32-unknown-unknown` target the first time you run `cargo` here. The code itself builds on
|
||||
Rust 1.95 or newer (`rust-version` in Cargo.toml, required by egui/eframe 0.36). For the web build
|
||||
you also need [`trunk`](https://github.com/trunk-rs/trunk)
|
||||
([documentation](https://trunk-rs.github.io/trunk/)).
|
||||
|
||||
```sh
|
||||
@@ -285,6 +288,16 @@ CI job runs `cargo xtask oracle` during full validation, and on pull requests th
|
||||
fails because of a known bug names its issue in `expected.json` (`"known_failure": "#123"`);
|
||||
never change an expected value to match SolidCraft's output.
|
||||
|
||||
### Quarantining a flaky test
|
||||
|
||||
A test that fails at random can fail a merge-queue batch, and every batch behind it starts over.
|
||||
Open an issue for it, then add one line to [`tests/QUARANTINED_TESTS`](tests/QUARANTINED_TESTS):
|
||||
`<test> #<issue> <YYYY-MM-DD> [why]`, with the test named as in `tests/KNOWN_FAILING_TESTS`.
|
||||
A quarantined test still runs. If it fails, the job summary says `quarantined, failed: <test>; see #<issue>`
|
||||
and the job stays green; if it passes, the summary says that too, so you can tell when it is safe to
|
||||
release. A quarantined line may be at most 14 days old: `cargo xtask lists` fails after that, so fix the
|
||||
test and delete the line. A test that fails every time belongs on `KNOWN_FAILING_TESTS` instead.
|
||||
|
||||
## Changing the design file format
|
||||
|
||||
A design file says which format it is in (`"format": "solidcraft/N"`). If your change saves
|
||||
@@ -321,7 +334,7 @@ and a fresh CI run:
|
||||
- **Growing Rust lists**: use slices (`const ITEMS: &[Item] = &[...];`) without a written
|
||||
length. `cargo xtask lists` rejects non-test const/static arrays with more than ten lines
|
||||
of entries, except fixed standard or algorithm tables listed with reasons in `xtask/src/lists.rs`.
|
||||
Built-in themes need only a JSON file in `assets/styles/ui/themes/`, with a unique nonnegative
|
||||
Built-in themes need only a JSON file in `crates/look/themes/`, with a unique nonnegative
|
||||
integer `order` (the picker order) and its own `provenance` line; keep existing order values.
|
||||
- **Message catalogs** (`assets/locales/*.json`): one message per line, sorted by id. Add your
|
||||
message anywhere and run `cargo xtask lists --fix`; `cargo xtask lists` (in `cargo xtask ci`
|
||||
@@ -509,11 +522,15 @@ The user guide's screenshots and short clips (`docs/book/src/media/`) are captur
|
||||
app by `examples/demo/doc_shots.py`, one function per figure. Each run starts a fresh app with its
|
||||
own settings, so your preferences never show. When a change makes a figure out of date, run
|
||||
`python3 examples/demo/doc_shots.py <page or shot>` (it needs Xvfb, ffmpeg, Pillow and a release
|
||||
build) and commit the new file. A new figure is a new function there, an ATTRIBUTION row in
|
||||
`attribution/pending/`, and a `<video>` (clips) or image link on the page. Keep a still under
|
||||
build) and commit the new file. Stills come in both themes: `--light` makes `<name>.light.png`,
|
||||
and the page shows the one that matches the book's theme (an `<img class="dark-ui">` and an
|
||||
`<img class="light-ui">`). A new figure is a new function there, an ATTRIBUTION row in
|
||||
`attribution/pending/`, and a `<video>` (clips) or the image pair on the page. Keep a still under
|
||||
about 250 KB and a clip under about 1 MB.
|
||||
|
||||
## Licence
|
||||
|
||||
By contributing you agree that your contribution is licensed as MIT OR Apache-2.0, like the rest
|
||||
of SolidCraft. SolidCraft isn't affiliated with any CAD vendor; product names are trademarks of their owners (see NOTICE).
|
||||
of SolidCraft. A contribution to the brand and interface (`crates/ui-kit`, `crates/look`,
|
||||
`crates/theme`, `assets/branding`, `assets/icons/app`) is licensed under
|
||||
[LICENSE-BRAND](LICENSE-BRAND), which lets the maintainers also license it as MIT OR Apache-2.0. SolidCraft isn't affiliated with any CAD vendor; product names are trademarks of their owners (see NOTICE).
|
||||
|
||||
Generated
+96
-59
@@ -319,7 +319,7 @@ dependencies = [
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -350,7 +350,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -376,7 +376,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
@@ -1656,7 +1656,7 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
||||
dependencies = [
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
@@ -3293,7 +3293,7 @@ dependencies = [
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -3721,9 +3721,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.5"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
|
||||
checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"errno",
|
||||
@@ -4234,6 +4234,16 @@ dependencies = [
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcore-step"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"solidcore",
|
||||
"solidcore-convert",
|
||||
"solidcore-ops",
|
||||
"solidcore-record",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcore-tess"
|
||||
version = "0.1.0"
|
||||
@@ -4249,7 +4259,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"block2 0.6.2",
|
||||
"eframe",
|
||||
@@ -4275,6 +4285,7 @@ dependencies = [
|
||||
"solidcraft-control",
|
||||
"solidcraft-engine",
|
||||
"solidcraft-gpu",
|
||||
"solidcraft-look",
|
||||
"solidcraft-space-mouse",
|
||||
"solidcraft-theme",
|
||||
"solidcraft-ui-egui",
|
||||
@@ -4291,11 +4302,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-3dx-client"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-cli"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4311,11 +4322,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-color"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-control"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"serde",
|
||||
@@ -4324,7 +4335,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-control-egui"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"image",
|
||||
@@ -4334,7 +4345,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-derive"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4343,7 +4354,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-doc"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -4365,7 +4376,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-dynamics"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4376,7 +4387,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-engine"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4402,7 +4413,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-geom"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4415,7 +4426,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-gpu"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4440,7 +4451,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-io"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"cadmpeg-core",
|
||||
"cadmpeg-ir",
|
||||
@@ -4451,7 +4462,7 @@ dependencies = [
|
||||
"gltf",
|
||||
"log",
|
||||
"quick-xml",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
@@ -4468,7 +4479,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-kernel"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"proptest",
|
||||
@@ -4477,19 +4488,31 @@ dependencies = [
|
||||
"serde_json",
|
||||
"solidcore-ops",
|
||||
"solidcore-record",
|
||||
"solidcore-step",
|
||||
"solidcore-tess",
|
||||
"solidcraft-geom",
|
||||
"solidcraft-profile",
|
||||
"solidcraft-smlib",
|
||||
"solidcraft-step",
|
||||
"spade",
|
||||
"thiserror 2.0.21",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-look"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"log",
|
||||
"solidcraft-theme",
|
||||
"solidcraft-ui-kit",
|
||||
"tiny-skia",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-mcp"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"serde_json",
|
||||
@@ -4503,14 +4526,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-mcp-server"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-profile"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"web-time",
|
||||
@@ -4518,7 +4541,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-render"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"image",
|
||||
@@ -4541,7 +4564,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-sketch"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"harfrust",
|
||||
"serde",
|
||||
@@ -4555,7 +4578,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-smlib"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"log",
|
||||
@@ -4569,28 +4592,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-space-mouse"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-step"
|
||||
version = "0.40.0-rc.3"
|
||||
dependencies = [
|
||||
"solidcore-ops",
|
||||
"solidcore-record",
|
||||
"solidcraft-geom",
|
||||
"solidcraft-profile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-testkit"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-theme"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"serde",
|
||||
@@ -4600,7 +4613,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-ui-egui"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"egui",
|
||||
@@ -4609,7 +4622,6 @@ dependencies = [
|
||||
"log",
|
||||
"lopdf",
|
||||
"minisign-verify",
|
||||
"muda",
|
||||
"nix 0.31.3",
|
||||
"pollster 0.4.0",
|
||||
"proc-macro2",
|
||||
@@ -4624,8 +4636,10 @@ dependencies = [
|
||||
"solidcraft-control-egui",
|
||||
"solidcraft-engine",
|
||||
"solidcraft-gpu",
|
||||
"solidcraft-look",
|
||||
"solidcraft-space-mouse",
|
||||
"solidcraft-theme",
|
||||
"solidcraft-ui-kit",
|
||||
"solidcraft-ui-registry",
|
||||
"solidcraft-ui-text",
|
||||
"solidcraft-viewport",
|
||||
@@ -4633,23 +4647,45 @@ dependencies = [
|
||||
"solidcraft-viewport-gpu",
|
||||
"syn 2.0.119",
|
||||
"tiny-skia",
|
||||
"toml",
|
||||
"ttf-parser",
|
||||
"web-time",
|
||||
"winreg",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-ui-kit"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"egui",
|
||||
"egui-wgpu",
|
||||
"image",
|
||||
"log",
|
||||
"muda",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"solidcraft-color",
|
||||
"solidcraft-theme",
|
||||
"solidcraft-ui-registry",
|
||||
"solidcraft-ui-text",
|
||||
"solidcraft-viewport-egui",
|
||||
"solidcraft-viewport-gpu",
|
||||
"syn 2.0.119",
|
||||
"tiny-skia",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-ui-registry"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"egui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-ui-text"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde_json",
|
||||
@@ -4659,7 +4695,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-viewport"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"serde",
|
||||
@@ -4671,7 +4707,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-viewport-egui"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"egui-wgpu",
|
||||
@@ -4682,7 +4718,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-viewport-gpu"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"naga",
|
||||
@@ -4698,7 +4734,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-web"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"eframe",
|
||||
"egui",
|
||||
@@ -4708,6 +4744,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"solidcraft-control",
|
||||
"solidcraft-engine",
|
||||
"solidcraft-look",
|
||||
"solidcraft-ui-egui",
|
||||
"solidcraft-ui-text",
|
||||
"url",
|
||||
@@ -4840,7 +4877,7 @@ dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.4.3",
|
||||
"once_cell",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -5363,7 +5400,7 @@ checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"downcast-rs",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
@@ -5376,7 +5413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"wayland-backend",
|
||||
"wayland-scanner",
|
||||
]
|
||||
@@ -5398,7 +5435,7 @@ version = "0.31.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d"
|
||||
dependencies = [
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
@@ -6093,7 +6130,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"os_pipe",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"thiserror 2.0.21",
|
||||
"tree_magic_mini",
|
||||
"wayland-backend",
|
||||
@@ -6130,7 +6167,7 @@ dependencies = [
|
||||
"libc",
|
||||
"libloading",
|
||||
"once_cell",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"x11rb-protocol",
|
||||
]
|
||||
|
||||
@@ -6183,7 +6220,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"proc-macro2",
|
||||
@@ -6279,7 +6316,7 @@ dependencies = [
|
||||
"hex",
|
||||
"libc",
|
||||
"ordered-stream",
|
||||
"rustix 1.1.5",
|
||||
"rustix 1.1.6",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"tracing",
|
||||
|
||||
+5
-2
@@ -6,7 +6,7 @@ members = ["crates/*", "apps/*", "xtask"]
|
||||
exclude = ["solidcore", "vendor"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.40.0-rc.3"
|
||||
version = "0.40.0"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
rust-version = "1.95"
|
||||
@@ -21,7 +21,6 @@ solidcraft-profile = { path = "crates/profile" }
|
||||
solidcraft-sketch = { path = "crates/sketch" }
|
||||
solidcraft-kernel = { path = "crates/kernel" }
|
||||
solidcraft-smlib = { path = "crates/smlib" }
|
||||
solidcraft-step = { path = "crates/step" }
|
||||
solidcraft-render = { path = "crates/render" }
|
||||
solidcraft-dynamics = { path = "crates/dynamics" }
|
||||
solidcraft-gpu = { path = "crates/gpu" }
|
||||
@@ -29,6 +28,8 @@ solidcraft-doc = { path = "crates/doc" }
|
||||
solidcraft-io = { path = "crates/io" }
|
||||
solidcraft-engine = { path = "crates/engine" }
|
||||
solidcraft-ui-egui = { path = "crates/ui-egui" }
|
||||
solidcraft-ui-kit = { path = "crates/ui-kit" }
|
||||
solidcraft-look = { path = "crates/look" }
|
||||
solidcraft-ui-registry = { path = "crates/ui-registry" }
|
||||
solidcraft-color = { path = "crates/color" }
|
||||
solidcraft-ui-text = { path = "crates/ui-text" }
|
||||
@@ -53,6 +54,8 @@ solidcore-record = { path = "solidcore/crates/solidcore-record" }
|
||||
# The modelling layer (solidcore's layers §1, "Ops"): the record-level calls SolidCraft makes into the
|
||||
# kernel, converting through solidcore-convert.
|
||||
solidcore-ops = { path = "solidcore/crates/solidcore-ops" }
|
||||
# STEP import and export (vendored with solidcore): the Part 21 parser is solidcore-record's.
|
||||
solidcore-step = { path = "solidcore/crates/solidcore-step" }
|
||||
# Geometry made drawable (solidcore's layers §3): the one mesher, SolidCraft's, moved into the
|
||||
# subtree (RFC 0003, item 1.1), with the display mesh and its levels of detail, the types
|
||||
# SolidCraft's meshes are. Vendored with solidcore, in the same subtree.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
SolidCraft Brand and Interface Licence
|
||||
|
||||
Copyright (c) 2026 the SolidCraft maintainers.
|
||||
|
||||
SolidCraft's code that models, imports, exports and computes geometry is open source under the MIT
|
||||
License or the Apache License 2.0 (LICENSE-MIT, LICENSE-APACHE). This licence covers something
|
||||
different: how SolidCraft looks and feels. That is its brand. A CAD program can be built from
|
||||
SolidCraft's open code; it should not look like SolidCraft unless the maintainers have agreed.
|
||||
|
||||
1. What this licence covers ("the Brand Material")
|
||||
|
||||
a. The UI kit, `crates/ui-kit` (solidcraft-ui-kit): the code and the design of SolidCraft's
|
||||
controls, panels, menus, ribbon, app bar, history bar, navigation bar, view compass,
|
||||
Preferences window, start page and window chrome.
|
||||
b. The look, `crates/look` (solidcraft-look): the interface icon masters and their artwork,
|
||||
the code-drawn glyphs, and the built-in themes.
|
||||
c. The theme, `crates/theme` (solidcraft-theme): the design tokens, colour palettes, accent
|
||||
ramps, sizes and spacing that give SolidCraft its appearance.
|
||||
d. The SolidCraft name, logo, app icon and brand kit (`assets/branding`, `assets/icons/app`).
|
||||
|
||||
Third-party material inside these folders keeps its own licence, listed in ATTRIBUTION.md.
|
||||
In particular the IBM Plex fonts are under the SIL Open Font License 1.1, and nothing here
|
||||
limits what that licence allows.
|
||||
|
||||
2. What you may do without asking
|
||||
|
||||
a. Read, build, run and modify the Brand Material as part of SolidCraft itself, including
|
||||
your own builds and forks of SolidCraft used for development, testing, learning or
|
||||
contributing back.
|
||||
b. Contribute changes to the Brand Material through the SolidCraft repository.
|
||||
c. Show SolidCraft, with its look, in reviews, tutorials, articles, videos and teaching.
|
||||
|
||||
3. What needs the maintainers' written permission first
|
||||
|
||||
a. Using any Brand Material in another program, product, service or library, including
|
||||
linking to the UI kit, the look or the theme from software that is not SolidCraft.
|
||||
b. Distributing the Brand Material, or a modified version of it, other than as part of
|
||||
SolidCraft.
|
||||
c. Distributing a fork or modified build of SolidCraft to others under the SolidCraft name,
|
||||
logo or app icon, or with a look that could be taken for SolidCraft's.
|
||||
d. Using the SolidCraft name, logo or app icon to name, promote or endorse anything else.
|
||||
|
||||
To ask, open an issue at https://github.com/tangency-labs/solidcraft or contact the
|
||||
maintainers there. Permission is given in writing and may come with conditions.
|
||||
|
||||
4. Contributions
|
||||
|
||||
By contributing to the Brand Material you agree that the maintainers may license your
|
||||
contribution under this licence, and under the MIT License or the Apache License 2.0, at
|
||||
their choice.
|
||||
|
||||
5. Earlier versions
|
||||
|
||||
Versions of SolidCraft published before this licence took effect stay under the licences
|
||||
they were published with.
|
||||
|
||||
6. No warranty
|
||||
|
||||
The Brand Material is provided "as is", without warranty of any kind, express or implied,
|
||||
including the warranties of merchantability, fitness for a particular purpose and
|
||||
non-infringement. In no event shall the maintainers or contributors be liable for any
|
||||
claim, damages or other liability arising from the Brand Material or its use.
|
||||
@@ -3,6 +3,15 @@ Copyright (c) 2026 SolidCraft contributors.
|
||||
Licensed under the MIT License or the Apache License, Version 2.0, at your option
|
||||
(LICENSE-MIT, LICENSE-APACHE).
|
||||
|
||||
Brand and interface
|
||||
|
||||
SolidCraft's brand and interface are not under MIT OR Apache-2.0. The UI kit (crates/ui-kit), the
|
||||
look (crates/look: the interface icons, glyphs and built-in themes), the theme (crates/theme: the
|
||||
design tokens and palettes), and the SolidCraft name, logo, app icon and brand kit are under the
|
||||
SolidCraft Brand and Interface Licence (LICENSE-BRAND). They may be used, changed and contributed
|
||||
to as part of SolidCraft; using them in anything else needs the maintainers' written permission.
|
||||
Third-party fonts in those folders keep their own licences.
|
||||
|
||||
Third-party material
|
||||
|
||||
Software dependencies are listed in Cargo.lock; their licences are in THIRD-PARTY-LICENSES.txt
|
||||
|
||||
@@ -133,6 +133,12 @@ MIT OR Apache-2.0, at your option. Developed under the
|
||||
[clean-room contribution rules](AGENTS.md); third-party code and assets retain their
|
||||
documented licences and attribution.
|
||||
|
||||
SolidCraft's brand and interface are licensed separately, under
|
||||
[LICENSE-BRAND](LICENSE-BRAND): the UI kit, the look (interface icons, glyphs, built-in themes),
|
||||
the theme's design tokens and palettes, and the SolidCraft name, logo and app icon. Use them freely
|
||||
as part of SolidCraft. Using them in another program or product needs the maintainers' written
|
||||
permission first.
|
||||
|
||||
SolidCraft is independent. Behaviour is designed from public documentation, general CAD
|
||||
conventions and user feedback. Reference tests use analytic values and open-source tools.
|
||||
SolidCraft is not affiliated with, sponsored by or endorsed by Autodesk, Dassault Systèmes, PTC,
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ scripts and AI agents can drive the same commands you use.
|
||||
- Sheet metal with flat patterns and DXF export, and a plastic-enclosure subset.
|
||||
- A Render workspace with GPU rendering, studio lighting, materials and image export
|
||||
(first release in 0.22.0).
|
||||
- Import and export of STEP, IGES, 3MF, STL, OBJ and DXF, and FreeCAD and Rhino files.
|
||||
- Import and export of STEP, IGES, 3MF, STL, OBJ and DXF, GLB export for viewers and renderers, and FreeCAD and Rhino files.
|
||||
- Autosave and crash recovery, and the browser build of the same app.
|
||||
|
||||
The full list of commands is in [docs/features.md](docs/features.md). Release notes for each
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Third-party software in SolidCraft
|
||||
|
||||
SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 567 crates below.
|
||||
SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 569 crates below.
|
||||
Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files.
|
||||
SolidCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE.
|
||||
SolidCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE. Its brand and interface (the UI kit,
|
||||
the look, the theme, the name, logo and app icon) are under LICENSE-BRAND: using them outside SolidCraft needs
|
||||
the maintainers' written permission.
|
||||
|
||||
accesskit 0.25.2 (MIT OR Apache-2.0)
|
||||
accesskit_atspi_common 0.21.1 (MIT OR Apache-2.0)
|
||||
@@ -399,7 +401,9 @@ smithay-client-toolkit 0.19.2 (MIT)
|
||||
smol_str 0.2.2 (MIT OR Apache-2.0)
|
||||
solidcore 1.0.1 (Apache-2.0)
|
||||
solidcore-convert 0.1.0 (Apache-2.0)
|
||||
solidcore-ops 0.1.0 (Apache-2.0)
|
||||
solidcore-record 0.1.0 (Apache-2.0)
|
||||
solidcore-step 0.1.0 (Apache-2.0)
|
||||
solidcore-tess 0.1.0 (Apache-2.0)
|
||||
spade 2.15.1 (MIT OR Apache-2.0)
|
||||
spirv 0.4.0+sdk-1.4.341.0 (Apache-2.0)
|
||||
@@ -16733,7 +16737,9 @@ r-efi 5.3.0: MIT OR Apache-2.0 OR LGPL-2.1-or-later (https://github.com/r-efi/r-
|
||||
r-efi 6.0.0: MIT OR Apache-2.0 OR LGPL-2.1-or-later (https://github.com/r-efi/r-efi)
|
||||
rustls-platform-verifier-android 0.2.0: MIT OR Apache-2.0 (https://github.com/rustls/rustls-platform-verifier)
|
||||
solidcore-convert 0.1.0: Apache-2.0 (https://github.com/tangency-labs/solidcore)
|
||||
solidcore-ops 0.1.0: Apache-2.0 (https://github.com/tangency-labs/solidcore)
|
||||
solidcore-record 0.1.0: Apache-2.0 (https://github.com/tangency-labs/solidcore)
|
||||
solidcore-step 0.1.0: Apache-2.0
|
||||
solidcore-tess 0.1.0: Apache-2.0 (https://github.com/tangency-labs/solidcore)
|
||||
spirv 0.4.0+sdk-1.4.341.0: Apache-2.0 (https://github.com/gfx-rs/rspirv)
|
||||
winapi-i686-pc-windows-gnu 0.4.0: MIT/Apache-2.0 (https://github.com/retep998/winapi-rs)
|
||||
@@ -16759,11 +16765,11 @@ Bundled fonts (SIL Open Font License, Version 1.1)
|
||||
Copyright 2014-2021 Adobe / Google Inc. (Noto Sans TC subset for SolidCraft web zh-TW)
|
||||
Source: https://github.com/notofonts/noto-cjk (Sans SubsetOTF/TC)
|
||||
|
||||
- IBMPlexSans-Variable.ttf (assets/fonts/ibm-plex-sans/IBMPlexSans-Variable.ttf)
|
||||
- IBMPlexSans-Variable.ttf (crates/look/fonts/ibm-plex-sans/IBMPlexSans-Variable.ttf)
|
||||
Copyright 2017 IBM Corp. with Reserved Font Name "Plex"
|
||||
Source: https://github.com/IBM/plex
|
||||
|
||||
- IBMPlexMono-Regular.ttf (assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.ttf)
|
||||
- IBMPlexMono-Regular.ttf (crates/look/fonts/ibm-plex-mono/IBMPlexMono-Regular.ttf)
|
||||
Copyright 2017 IBM Corp. with Reserved Font Name "Plex"
|
||||
Source: https://github.com/IBM/plex
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ fn inspect_schema(args: &[&str], env: Option<&str>) -> Result<Value, String> {
|
||||
fn compact_output_is_off_unless_asked() {
|
||||
let plain = inspect_schema(&[], None).unwrap();
|
||||
assert_eq!(plain["properties"]["sketches"]["type"], "boolean", "{plain}");
|
||||
assert!(plain["properties"].get("bodies").is_none(), "{plain}");
|
||||
assert_eq!(plain["properties"]["bodies"]["type"], json!(["boolean", "string"]), "no list of names: {plain}");
|
||||
assert_eq!(inspect_schema(&[], Some("0")).unwrap(), plain);
|
||||
|
||||
for (args, env) in [(&["--compact"][..], None), (&[][..], Some("1")), (&[][..], Some("true"))] {
|
||||
let compact = inspect_schema(args, env).unwrap();
|
||||
assert!(compact["properties"]["bodies"].is_object(), "{args:?} {env:?}: {compact}");
|
||||
assert!(compact["properties"]["bodies"]["type"].as_array().is_some_and(|t| t.contains(&json!("array"))), "{args:?} {env:?}: {compact}");
|
||||
}
|
||||
|
||||
let e = inspect_schema(&[], Some("maybe")).unwrap_err();
|
||||
|
||||
@@ -361,23 +361,54 @@ const UNSTABLE: [(&str, &str); 1] = [(
|
||||
"the halves of each swept wall lie level along every axis, so which is `#1` and which `#2` follows the order the kernel gives the faces in, which changes from one build to the next",
|
||||
)];
|
||||
|
||||
/// The designs that take longest to build, heaviest first, with one build's time (ci profile,
|
||||
/// CLI `run`, one design at a time, on P-cores, 2026-11-10). The test hands them out first, and
|
||||
/// each design's two builds go to two workers, so a heavy design is never built twice in a row on
|
||||
/// one worker while the rest wait. Every other design took under 3.6 s. Only the order of the
|
||||
/// work depends on this list: a stale entry makes the test slower, never wrong. Re-measure when a
|
||||
/// design here gets much faster, or one not listed takes over 5 s.
|
||||
const HEAVIEST: [&str; 6] = [
|
||||
"oracle/77-fillet-variable-linear", // 35.6 s
|
||||
"oracle/83-boundary-loop-thicken", // 12.4 s
|
||||
"regressions/closed_sweep_torus_cut", // 6.8 s
|
||||
"oracle/41-tube-radial-holes", // 4.6 s
|
||||
"oracle/42-overlapping-patterns", // 4.2 s
|
||||
"oracle/35-fillet-curved-curved", // 3.2 s
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn corpus_designs_name_alike_every_build_and_fail_where_a_reference_is_gone() {
|
||||
let designs = designs();
|
||||
// Every design is built twice, as two jobs: (design, which build). The heaviest go first.
|
||||
for heavy in HEAVIEST {
|
||||
assert!(designs.iter().any(|(name, _)| name == heavy), "HEAVIEST lists `{heavy}`, which is not in the corpus any more");
|
||||
}
|
||||
let rank = |name: &str| HEAVIEST.iter().position(|h| *h == name).unwrap_or(HEAVIEST.len());
|
||||
let mut jobs: Vec<(usize, usize)> = (0..designs.len()).flat_map(|d| [(d, 0), (d, 1)]).collect();
|
||||
jobs.sort_by_key(|&(d, build)| (rank(&designs[d].0), d, build));
|
||||
let next = std::sync::atomic::AtomicUsize::new(0);
|
||||
let results = std::sync::Mutex::new(Vec::new());
|
||||
let workers = std::thread::available_parallelism().map_or(4, |n| n.get()).min(designs.len().max(1));
|
||||
let builds = std::sync::Mutex::new(std::collections::BTreeMap::new());
|
||||
let workers = std::thread::available_parallelism().map_or(4, |n| n.get()).min(jobs.len().max(1));
|
||||
std::thread::scope(|scope| {
|
||||
for _ in 0..workers {
|
||||
scope.spawn(|| {
|
||||
while let Some((name, source)) = designs.get(next.fetch_add(1, std::sync::atomic::Ordering::Relaxed)) {
|
||||
let got = load(source).and_then(|first| Ok((build(&first), build(&load(source)?))));
|
||||
results.lock().unwrap_or_else(|e| e.into_inner()).push((name.clone(), got));
|
||||
while let Some(&(d, which)) = jobs.get(next.fetch_add(1, std::sync::atomic::Ordering::Relaxed)) {
|
||||
let got = load(&designs[d].1).map(|s| build(&s));
|
||||
builds.lock().unwrap_or_else(|e| e.into_inner()).insert((d, which), got);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
let mut results = results.into_inner().unwrap_or_else(|e| e.into_inner());
|
||||
let mut builds = builds.into_inner().unwrap_or_else(|e| e.into_inner());
|
||||
let mut results: Vec<(String, Result<(Build, Build), String>)> = designs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(d, (name, _))| {
|
||||
let first = builds.remove(&(d, 0)).unwrap();
|
||||
let second = builds.remove(&(d, 1)).unwrap();
|
||||
(name.clone(), first.and_then(|first| Ok((first, second?))))
|
||||
})
|
||||
.collect();
|
||||
results.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
let mut problems = Vec::new();
|
||||
for (name, got) in &results {
|
||||
|
||||
@@ -280,12 +280,26 @@ fn results_still_save_and_export_the_script_once() {
|
||||
let saved = dir.0.join("box.json");
|
||||
let stl = dir.0.join("box.stl");
|
||||
let obj = dir.0.join("box.obj");
|
||||
let glb = dir.0.join("box.glb");
|
||||
let result = json_output(
|
||||
cli().arg("run").arg(dir.script()).arg("--results").arg("--save").arg(&saved).arg("--out").arg(&stl).arg("--out").arg(&obj).output().unwrap(),
|
||||
cli()
|
||||
.arg("run")
|
||||
.arg(dir.script())
|
||||
.arg("--results")
|
||||
.arg("--save")
|
||||
.arg(&saved)
|
||||
.arg("--out")
|
||||
.arg(&stl)
|
||||
.arg("--out")
|
||||
.arg(&obj)
|
||||
.arg("--out")
|
||||
.arg(&glb)
|
||||
.output()
|
||||
.unwrap(),
|
||||
);
|
||||
assert_eq!(result.as_array().unwrap().len(), 1);
|
||||
assert_eq!(body_count(&saved), 1);
|
||||
for exported in [&stl, &obj] {
|
||||
for exported in [&stl, &obj, &glb] {
|
||||
assert!(std::fs::metadata(exported).unwrap().len() > 0);
|
||||
assert_eq!(body_count(exported), 1);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ profile = ["solidcraft-engine/profile"]
|
||||
solidcraft-engine = { workspace = true }
|
||||
solidcraft-control = { workspace = true }
|
||||
solidcraft-ui-egui = { workspace = true }
|
||||
# SolidCraft's look (icons, glyphs, built-in themes), installed at startup.
|
||||
solidcraft-look = { workspace = true }
|
||||
solidcraft-ui-text = { workspace = true }
|
||||
egui = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
||||
@@ -1246,7 +1246,7 @@ mod web {
|
||||
pub fn start() {
|
||||
eframe::WebLogger::init(log::LevelFilter::Info).ok();
|
||||
solidcraft_ui_egui::i18n::install();
|
||||
solidcraft_ui_egui::icon_svg::install();
|
||||
solidcraft_look::install_tables();
|
||||
solidcraft_ui_egui::workspace::install_tabs();
|
||||
solidcraft_ui_egui::navigation_slots::install();
|
||||
wasm_bindgen_futures::spawn_local(async {
|
||||
|
||||
@@ -44,8 +44,10 @@ const UPDATE_TIMEOUT_MS = 20000;
|
||||
const COMPLETE = "build-complete";
|
||||
/** The entry that marks a build replaced by a newer worker. */
|
||||
const RETIRED = "build-retired";
|
||||
/** A page remembered this recently may still be loading (not yet listed among the clients). */
|
||||
const PAGE_LOADING_MS = 30 * 1000;
|
||||
/** A page remembered this recently may still be loading (not yet listed among the clients). A slow
|
||||
* device can take minutes between the launch's answer and the page appearing; a live page's record is
|
||||
* kept for as long as it is listed. */
|
||||
const PAGE_LOADING_MS = 10 * 60 * 1000;
|
||||
|
||||
const url = (file) => new URL(file, self.registration.scope).href;
|
||||
const has = (name, entry) => caches.match(url(entry), { cacheName: name }).then(Boolean);
|
||||
@@ -102,10 +104,13 @@ async function started(id, build) {
|
||||
await (await caches.open(PAGES)).put(pageEntry(id), new Response(record));
|
||||
}
|
||||
|
||||
/** The build a page started; a page started before it was remembered gets this worker's. */
|
||||
/**
|
||||
* The build a page started, or null when it was not remembered. Never this worker's build instead:
|
||||
* after an update that is another build than the page's, and its files would be mixed into the page.
|
||||
*/
|
||||
async function startedBy(id) {
|
||||
const response = id ? await caches.match(pageEntry(id), { cacheName: PAGES }) : null;
|
||||
return response ? (await response.json()).build : CACHE;
|
||||
return response ? (await response.json()).build : null;
|
||||
}
|
||||
|
||||
/** The builds open pages use (pages closed since are forgotten). */
|
||||
@@ -143,11 +148,22 @@ self.addEventListener("activate", (event) => {
|
||||
for (const name of await caches.keys()) if (name.startsWith(CACHE_PREFIX) || name === PAGES) await caches.delete(name);
|
||||
return self.registration.unregister();
|
||||
}
|
||||
for (const name of await caches.keys()) {
|
||||
if (name.startsWith(CACHE_PREFIX) && name !== CACHE) await (await caches.open(name)).put(url(RETIRED), new Response(""));
|
||||
}
|
||||
await sweep();
|
||||
const older = (await caches.keys()).filter((name) => name.startsWith(CACHE_PREFIX) && name !== CACHE);
|
||||
// Claim first: from the moment this worker is the active one, a page the old worker controlled has
|
||||
// no controller until it is claimed, and a request it makes then goes straight to the network, which
|
||||
// serves the newest build, not the page's. Nothing slow goes before this.
|
||||
await self.clients.claim();
|
||||
for (const name of older) await (await caches.open(name)).put(url(RETIRED), new Response(""));
|
||||
await sweep();
|
||||
// With no earlier build kept, the pages open when the first worker takes over came from the
|
||||
// network, and get their files from it. After an update a page with no record is not
|
||||
// assumed to be anything: its record may only be late, and the network now serves a newer
|
||||
// build than the page's.
|
||||
if (!older.length) {
|
||||
for (const client of await self.clients.matchAll({ includeUncontrolled: true })) {
|
||||
if (!(await startedBy(client.id).catch(() => null))) await started(client.id, NETWORK).catch(() => {});
|
||||
}
|
||||
}
|
||||
})(),
|
||||
);
|
||||
});
|
||||
@@ -221,7 +237,12 @@ async function launchOrKept(event) {
|
||||
|
||||
/** A page's files come from the build it started, else the network. */
|
||||
async function asset(event) {
|
||||
const build = await startedBy(event.clientId).catch(() => CACHE);
|
||||
const build = await startedBy(event.clientId).catch(() => null);
|
||||
// A page whose build is not known, or whose build's copy is gone, would get another build's files
|
||||
// (a mixed page that never starts). It fails visibly instead: reloading starts a whole build.
|
||||
if (!build || (build !== NETWORK && !(await caches.has(build)))) {
|
||||
return new Response("This page's version of the app is no longer kept. Reload the page.", { status: 503, headers: { "Content-Type": "text/plain" } });
|
||||
}
|
||||
const kept = build === NETWORK ? null : await caches.match(event.request, { cacheName: build, ignoreSearch: true });
|
||||
return kept || fetch(event.request);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ solidcraft-control = { workspace = true }
|
||||
# The D3D12 shader compiler the window starts with (#6756).
|
||||
solidcraft-gpu = { workspace = true }
|
||||
solidcraft-ui-egui = { workspace = true }
|
||||
# SolidCraft's look (icons, glyphs, built-in themes), installed at startup.
|
||||
solidcraft-look = { workspace = true }
|
||||
solidcraft-ui-text = { workspace = true }
|
||||
solidcraft-theme = { workspace = true }
|
||||
solidcraft-space-mouse = { workspace = true }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! with what SolidCraft's requests mean ([`SolidCraft`]).
|
||||
|
||||
use std::net::TcpListener;
|
||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
use serde_json::{Value, json};
|
||||
@@ -12,6 +12,7 @@ use solidcraft_control::{ControlRequest, auth};
|
||||
use solidcraft_engine::MAX_LINE;
|
||||
use solidcraft_engine::control_auth::APP;
|
||||
use solidcraft_engine::control_pending;
|
||||
use solidcraft_ui_egui::control_switch;
|
||||
|
||||
/// The token files this launch wrote (its control port, the agent chat's endpoint) and the
|
||||
/// token in each, removed when the app ends unless another launch has written the file since.
|
||||
@@ -85,40 +86,60 @@ pub fn remove_token_file() {
|
||||
/// The port the app's own channel listens on and its token, for removing the discovery file at exit.
|
||||
static APP_PORT: std::sync::Mutex<Option<(u16, String)>> = std::sync::Mutex::new(None);
|
||||
|
||||
pub fn start(listen_on: auth::Listen, ctx: egui::Context) -> Receiver<ControlRequest> {
|
||||
/// Open the app's control channel (at launch, or turned on in the settings): its listener, its
|
||||
/// token file and the discovery file. Stopping it removes both files again.
|
||||
pub fn start(listen_on: auth::Listen, ctx: egui::Context) -> Result<control_switch::Started, control_switch::StartError> {
|
||||
use control_switch::StartError;
|
||||
let (tx, rx) = channel::<ControlRequest>();
|
||||
// Every connection must show the token before anything runs (docs/control-protocol.md).
|
||||
match APP.env_token().or_else(server::new_token) {
|
||||
Some(token) => {
|
||||
let listener = match listen_on {
|
||||
auth::Listen::Exact(port) => TcpListener::bind(("127.0.0.1", port)),
|
||||
auth::Listen::Default => auth::bind_with_fallback(APP.default_port, auth::PORT_TRIES),
|
||||
};
|
||||
match listener {
|
||||
Ok(l) => {
|
||||
if let Some(port) = listen_on_listener(l, token.clone(), tx, ctx, false) {
|
||||
if matches!(listen_on, auth::Listen::Default) {
|
||||
solidcraft_engine::note!(
|
||||
"solidcraft: control channel on the default port 127.0.0.1:{port} (Preferences > Assistant turns it off)"
|
||||
);
|
||||
}
|
||||
// The discovery file: where `solidcraft-cli mcp` finds this app with no arguments.
|
||||
match APP.write_current_port(port) {
|
||||
Ok(_) => {
|
||||
if let Ok(mut p) = APP_PORT.lock() {
|
||||
*p = Some((port, token));
|
||||
}
|
||||
}
|
||||
Err(e) => solidcraft_engine::note!("solidcraft: could not write the control discovery file ({e})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => solidcraft_engine::note!("solidcraft: control server failed to bind 127.0.0.1: {e}"),
|
||||
let Some(token) = APP.env_token().or_else(server::new_token) else {
|
||||
solidcraft_engine::note!("solidcraft: control server not started: no random token available");
|
||||
return Err(StartError::Failed("no random token available".into()));
|
||||
};
|
||||
let listener = match listen_on {
|
||||
auth::Listen::Exact(port) => TcpListener::bind(("127.0.0.1", port)),
|
||||
auth::Listen::Default => auth::bind_with_fallback(APP.default_port, auth::PORT_TRIES),
|
||||
};
|
||||
let listener = listener.map_err(|e| {
|
||||
solidcraft_engine::note!("solidcraft: control server failed to bind 127.0.0.1: {e}");
|
||||
match (listen_on, e.kind()) {
|
||||
// In use; Windows reports a port another program holds exclusively as denied.
|
||||
(auth::Listen::Exact(port), std::io::ErrorKind::AddrInUse | std::io::ErrorKind::PermissionDenied) => StartError::PortTaken(port),
|
||||
(auth::Listen::Default, std::io::ErrorKind::AddrInUse | std::io::ErrorKind::PermissionDenied) => StartError::PortTaken(APP.default_port),
|
||||
_ => StartError::Failed(e.to_string()),
|
||||
}
|
||||
})?;
|
||||
let (port, stop) =
|
||||
listen_on_listener(listener, token.clone(), tx, ctx, false).ok_or_else(|| StartError::Failed("the listener did not start".into()))?;
|
||||
if matches!(listen_on, auth::Listen::Default) {
|
||||
solidcraft_engine::note!("solidcraft: control channel on the default port 127.0.0.1:{port} (Preferences > Assistant turns it off)");
|
||||
}
|
||||
// The discovery file: where `solidcraft-cli mcp` finds this app with no arguments.
|
||||
match APP.write_current_port(port) {
|
||||
Ok(_) => {
|
||||
if let Ok(mut p) = APP_PORT.lock() {
|
||||
*p = Some((port, token.clone()));
|
||||
}
|
||||
}
|
||||
None => solidcraft_engine::note!("solidcraft: control server not started: no random token available"),
|
||||
Err(e) => solidcraft_engine::note!("solidcraft: could not write the control discovery file ({e})"),
|
||||
}
|
||||
rx
|
||||
let stop = Box::new(move || {
|
||||
stop.stop();
|
||||
if let Ok(mut p) = APP_PORT.lock()
|
||||
&& p.as_ref().is_some_and(|(held, _)| *held == port)
|
||||
{
|
||||
*p = None;
|
||||
}
|
||||
APP.remove_current_port(port, &token);
|
||||
if let Some(path) = APP.token_path(port) {
|
||||
auth::remove_token_file(&path, &token);
|
||||
if let Ok(mut files) = TOKEN_FILES.lock() {
|
||||
files.retain(|(p, _)| *p != path);
|
||||
}
|
||||
}
|
||||
solidcraft_engine::note!("solidcraft: control channel on 127.0.0.1:{port} closed");
|
||||
});
|
||||
Ok(control_switch::Started { port, requests: rx, stop })
|
||||
}
|
||||
|
||||
/// The agent chat's own endpoint for its agent's MCP server (docs/agent-chat.md): a free loopback
|
||||
@@ -137,12 +158,19 @@ pub fn listen_agent(tx: Sender<ControlRequest>, ctx: egui::Context) -> Option<u1
|
||||
return None;
|
||||
}
|
||||
};
|
||||
listen_on_listener(listener, token, tx, ctx, true)
|
||||
// The chat's endpoint lives as long as the app.
|
||||
listen_on_listener(listener, token, tx, ctx, true).map(|(port, _)| port)
|
||||
}
|
||||
|
||||
/// Serve `listener` (loopback) with `token`; the port it listens on.
|
||||
/// Serve `listener` (loopback) with `token`; the port it listens on and how to stop it.
|
||||
/// `patient`: every request may wait as long as a batch (a person decides on it).
|
||||
fn listen_on_listener(listener: TcpListener, token: String, tx: Sender<ControlRequest>, ctx: egui::Context, patient: bool) -> Option<u16> {
|
||||
fn listen_on_listener(
|
||||
listener: TcpListener,
|
||||
token: String,
|
||||
tx: Sender<ControlRequest>,
|
||||
ctx: egui::Context,
|
||||
patient: bool,
|
||||
) -> Option<(u16, server::Stop)> {
|
||||
let port = listener.local_addr().ok()?.port();
|
||||
match APP.token_path(port) {
|
||||
Some(path) => match APP.write_token_file(&path, &token) {
|
||||
@@ -164,8 +192,8 @@ fn listen_on_listener(listener: TcpListener, token: String, tx: Sender<ControlRe
|
||||
)
|
||||
}
|
||||
}
|
||||
match hub(ctx).listen(listener, token, tx, patient) {
|
||||
Ok(()) => Some(port),
|
||||
match hub(ctx).listen_stoppable(listener, token, tx, patient) {
|
||||
Ok(stop) => Some((port, stop)),
|
||||
Err(e) => {
|
||||
solidcraft_engine::note!("solidcraft: control server not started: {e}");
|
||||
None
|
||||
|
||||
+160
-21
@@ -87,6 +87,8 @@ struct App {
|
||||
solve: SolveApp,
|
||||
/// The settings folder whose start marker the first frame clears (`startup::started`).
|
||||
starting: Option<std::path::PathBuf>,
|
||||
/// A newly selected API is confirmed only once the first frame has been presented.
|
||||
backend_attempt: Option<(std::path::PathBuf, startup::BackendAttempt)>,
|
||||
/// Frames begun; the second one means the first was drawn (startup is over).
|
||||
frames: u32,
|
||||
/// Started over the control channel: the window doesn't ask for the foreground.
|
||||
@@ -215,6 +217,12 @@ impl eframe::App for App {
|
||||
solidcraft_ui_egui::ai_connect::begin(&mut self.solve);
|
||||
solidcraft_ui_egui::agent_chat::begin(&mut self.solve);
|
||||
}
|
||||
if let Some((path, attempt)) = self.backend_attempt.take()
|
||||
&& let Err(reason) = startup::confirm_backend_start(&path, &attempt)
|
||||
{
|
||||
log::warn!("graphics: could not confirm the startup choice: {reason}");
|
||||
self.solve.set_status(reason, true);
|
||||
}
|
||||
if let Some(dir) = self.starting.take() {
|
||||
startup::started(&dir);
|
||||
}
|
||||
@@ -341,10 +349,17 @@ impl Drop for App {
|
||||
// never return (#9044).
|
||||
device_lost::end();
|
||||
}
|
||||
// An update asked to restart into the new version or to run its installer.
|
||||
// Restart only after eframe has flushed settings. Graphics restarts also reopen
|
||||
// the saved designs collected by the normal quit flow.
|
||||
let graphics_restart = solidcraft_ui_egui::update::take_graphics_restart(&mut self.solve);
|
||||
if let Some((program, args)) = solidcraft_ui_egui::update::take_launch(&mut self.solve) {
|
||||
let mut command = std::process::Command::new(&program);
|
||||
command.args(&args);
|
||||
let mut command = if graphics_restart {
|
||||
graphics_restart_command(&program, &args, &self.solve.preferences.open_designs)
|
||||
} else {
|
||||
let mut command = std::process::Command::new(&program);
|
||||
command.args(&args);
|
||||
command
|
||||
};
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::process::CommandExt;
|
||||
@@ -360,6 +375,62 @@ impl Drop for App {
|
||||
}
|
||||
}
|
||||
|
||||
/// A UI restart applies the saved API instead of inheriting this session's recovery
|
||||
/// overrides. Explicit developer overrides remain authoritative.
|
||||
fn graphics_restart_command(program: &std::path::Path, args: &[String], designs: &[String]) -> std::process::Command {
|
||||
let mut command = std::process::Command::new(program);
|
||||
command.args(args).args(designs);
|
||||
for variable in [
|
||||
startup::RETRY_BACKEND_ENV,
|
||||
startup::FALLBACK_NOTE_ENV,
|
||||
startup::RENDERER_ENV,
|
||||
startup::SAFE_MODE_ENV,
|
||||
device_lost::LOST_ENV,
|
||||
device_lost::REASON_ENV,
|
||||
] {
|
||||
command.env_remove(variable);
|
||||
}
|
||||
command
|
||||
}
|
||||
|
||||
/// Re-enter an AppImage through its outer executable only when this process actually lives
|
||||
/// in that image's mount. An inherited APPIMAGE from another application is not our launcher.
|
||||
fn graphics_restart_program(
|
||||
exe: Option<&std::path::Path>,
|
||||
appimage: Option<&std::ffi::OsStr>,
|
||||
appdir: Option<&std::ffi::OsStr>,
|
||||
is_file: impl Fn(&std::path::Path) -> bool,
|
||||
) -> Option<std::path::PathBuf> {
|
||||
let exe = exe?;
|
||||
if let (Some(image), Some(directory)) = (appimage, appdir) {
|
||||
let image = std::path::Path::new(image);
|
||||
let directory = std::path::Path::new(directory);
|
||||
if image.is_absolute() && directory.is_absolute() && exe.starts_with(directory) && is_file(image) {
|
||||
return Some(image.to_path_buf());
|
||||
}
|
||||
}
|
||||
Some(exe.to_path_buf())
|
||||
}
|
||||
|
||||
/// Keep launch-scoped settings through a UI restart. Safe mode and the sample are one-shot;
|
||||
/// original file arguments are replaced by the current saved tabs at shutdown.
|
||||
fn graphics_restart_args(args: impl IntoIterator<Item = String>) -> Vec<String> {
|
||||
let mut retained = Vec::new();
|
||||
let mut args = args.into_iter();
|
||||
while let Some(argument) = args.next() {
|
||||
match argument.as_str() {
|
||||
"--control" | "--theme-file" | "--max-file-size" => {
|
||||
if let Some(value) = args.next() {
|
||||
retained.extend([argument, value]);
|
||||
}
|
||||
}
|
||||
value if value.starts_with("--max-file-size=") => retained.push(argument),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
retained
|
||||
}
|
||||
|
||||
/// The window's graphics device, watched for its loss.
|
||||
struct LostWatch {
|
||||
lost: eframe::egui_wgpu::DeviceLost,
|
||||
@@ -569,6 +640,15 @@ fn services(cc: &eframe::CreationContext<'_>, folder: &DialogFolder) -> Services
|
||||
Box::pin(async move { folder.answer(future.await) })
|
||||
})),
|
||||
graphics_adapters: Vec::new(),
|
||||
graphics_backend: None,
|
||||
graphics_backend_override: std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty()),
|
||||
graphics_restart: graphics_restart_program(
|
||||
std::env::current_exe().ok().as_deref(),
|
||||
std::env::var_os("APPIMAGE").as_deref(),
|
||||
std::env::var_os("APPDIR").as_deref(),
|
||||
std::path::Path::is_file,
|
||||
)
|
||||
.map(|program| (program, graphics_restart_args(std::env::args().skip(1)))),
|
||||
graphics_path: graphics_path().map(|p| p.to_string_lossy().to_string()),
|
||||
window_system: window_system_now(),
|
||||
// Linux: the desktop's dark or light setting, which the window is not told on every
|
||||
@@ -832,6 +912,12 @@ fn restore_preferences(app: &mut SolveApp, stored_ui: Option<&str>, saved_graphi
|
||||
|
||||
/// Restore startup choices after loading the separately saved UI preferences.
|
||||
fn restore_graphics_preferences(app: &mut SolveApp, saved: Option<&serde_json::Value>) {
|
||||
// Preserve legacy comma lists until the user explicitly selects a different API.
|
||||
app.preferences.graphics_backend = saved
|
||||
.and_then(|v| v.get("backend").and_then(serde_json::Value::as_str))
|
||||
.filter(|choice| !choice.trim().is_empty())
|
||||
.unwrap_or("auto")
|
||||
.to_string();
|
||||
app.preferences.graphics_adapter = saved.and_then(|v| v.get("adapter").and_then(serde_json::Value::as_str)).unwrap_or_default().to_string();
|
||||
// graphics.json chooses the window before app.ron is loaded. Reflect that saved choice,
|
||||
// not the current session's window system (which an environment override may change).
|
||||
@@ -843,11 +929,6 @@ fn restore_graphics_preferences(app: &mut SolveApp, saved: Option<&serde_json::V
|
||||
.to_string();
|
||||
}
|
||||
|
||||
/// The graphics backend preference (`graphics.json`'s `backend`: `auto`, `dx12`, `vulkan`, `gl`).
|
||||
fn backend_preference() -> Option<String> {
|
||||
graphics().and_then(|v| v.get("backend").and_then(serde_json::Value::as_str).map(str::to_string))
|
||||
}
|
||||
|
||||
/// The viewport scene's sample count, by the rule the web app shares
|
||||
/// (`solidcraft_ui_egui::gpu::scene_samples`).
|
||||
fn scene_samples(backend: eframe::wgpu::Backend, samples: u32, supported: &[u32]) -> u32 {
|
||||
@@ -934,7 +1015,7 @@ fn main() -> eframe::Result {
|
||||
objc2_foundation::NSProcessInfo::processInfo().setProcessName(objc2_foundation::ns_string!("SolidCraft"));
|
||||
mark("main");
|
||||
solidcraft_ui_egui::i18n::install();
|
||||
solidcraft_ui_egui::icon_svg::install();
|
||||
solidcraft_look::install_tables();
|
||||
solidcraft_ui_egui::workspace::install_tabs();
|
||||
solidcraft_ui_egui::navigation_slots::install();
|
||||
// On OCLP-patched Macs, wgpu picks a Metal Shading Language standard that the system's
|
||||
@@ -1016,7 +1097,27 @@ fn main() -> eframe::Result {
|
||||
safe_mode = true;
|
||||
notes.push(format!("The last {failed_starts} launches stopped before the window opened, so this one is in safe mode."));
|
||||
}
|
||||
let cpu_renderer = safe_mode || startup::cpu_renderer_env(std::env::var(startup::RENDERER_ENV).ok().as_deref());
|
||||
let mut cpu_renderer = safe_mode || startup::cpu_renderer_env(std::env::var(startup::RENDERER_ENV).ok().as_deref());
|
||||
// Persist the one-start guard before any adapter, device or depth-format probe.
|
||||
// Recovery launches and explicit overrides must not consume a pending UI choice.
|
||||
let backend_override = std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty());
|
||||
let retry_backend = std::env::var(startup::RETRY_BACKEND_ENV).ok();
|
||||
let backend_path = settings.as_ref().map(|dir| dir.join("graphics.json"));
|
||||
let backend_launch = match backend_path
|
||||
.as_ref()
|
||||
.map(|path| startup::prepare_backend_start(path, !cpu_renderer && !backend_override && retry_backend.is_none()))
|
||||
.transpose()
|
||||
{
|
||||
Ok(launch) => launch.unwrap_or_default(),
|
||||
Err(reason) => {
|
||||
// A choice that could not be guarded must not load the requested driver.
|
||||
cpu_renderer = true;
|
||||
notes.push(reason);
|
||||
startup::BackendLaunch::default()
|
||||
}
|
||||
};
|
||||
let backend_attempt = backend_path.zip(backend_launch.attempt);
|
||||
let backend_note = backend_launch.note;
|
||||
// The launch before this one closed because its graphics device was lost (`App::watch_device`).
|
||||
let after_loss = device_lost::recent(std::env::var(device_lost::LOST_ENV).ok().as_deref(), device_lost::now_secs());
|
||||
if after_loss {
|
||||
@@ -1029,14 +1130,14 @@ fn main() -> eframe::Result {
|
||||
if safe_mode {
|
||||
notes.push("Safe mode: default settings (yours are kept for the next normal start), no recovery offer, software rendering.".into());
|
||||
}
|
||||
let fallback_note = std::env::var(startup::FALLBACK_NOTE_ENV).ok().map(|s| s.chars().take(4096).collect::<String>());
|
||||
let fallback_note = std::env::var(startup::FALLBACK_NOTE_ENV).ok().map(|s| s.chars().take(4096).collect::<String>()).or(backend_note);
|
||||
if let Some(note) = &fallback_note {
|
||||
log::warn!("{note}");
|
||||
solidcraft_engine::note!("SolidCraft: {note}");
|
||||
notes.push(note.clone());
|
||||
}
|
||||
let saved_samples = if safe_mode { None } else { msaa() };
|
||||
let wgpu_options = wgpu_options(cpu_renderer, if safe_mode { None } else { backend_preference() }.as_deref());
|
||||
let wgpu_options = wgpu_options(cpu_renderer, if safe_mode { None } else { backend_launch.backend.as_deref() });
|
||||
let depth_bits = if !safe_mode && startup::float_depth_everywhere(&wgpu_options) { FLOAT_DEPTH_BITS } else { DEPTH_BITS };
|
||||
// Crashes leave a report in the crash folder (solidcraft_engine::crash, docs/crash-reports.md).
|
||||
let crashed = solidcraft_engine::crash::default_dir()
|
||||
@@ -1117,6 +1218,7 @@ fn main() -> eframe::Result {
|
||||
let created = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
let created_in_app = created.clone();
|
||||
let starting = settings.clone();
|
||||
let attempt_in_app = backend_attempt.clone();
|
||||
// A panic on the window's thread ends the app without `on_exit`; this disconnects from the
|
||||
// 3D mouse driver then too.
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -1181,6 +1283,13 @@ fn main() -> eframe::Result {
|
||||
})
|
||||
.collect();
|
||||
let info = rs.adapter.get_info();
|
||||
app.services.graphics_backend = match info.backend {
|
||||
eframe::wgpu::Backend::Vulkan => Some("vulkan"),
|
||||
eframe::wgpu::Backend::Dx12 => Some("dx12"),
|
||||
eframe::wgpu::Backend::Gl => Some("gl"),
|
||||
eframe::wgpu::Backend::Metal => Some("metal"),
|
||||
_ => None,
|
||||
};
|
||||
if !app.preferences.graphics_adapter.is_empty() && !info.name.eq_ignore_ascii_case(app.preferences.graphics_adapter.as_str()) {
|
||||
solidcraft_engine::note!(
|
||||
"SolidCraft graphics: preferred adapter {:?} was not used; using {:?} instead",
|
||||
@@ -1211,12 +1320,11 @@ fn main() -> eframe::Result {
|
||||
));
|
||||
}
|
||||
mark("viewport pipelines");
|
||||
// `--control`/the environment name a port; otherwise the preference (on by default)
|
||||
// opens the default one (docs/control-protocol.md).
|
||||
if let Some(listen_on) = solidcraft_control::auth::plan(control_port, app.preferences.agent_control) {
|
||||
let rx = control_server::start(listen_on, cc.egui_ctx.clone());
|
||||
app = app.with_control(rx);
|
||||
}
|
||||
// `--control`/the environment name a port for this run; otherwise the preference (off
|
||||
// by default) opens its port, and turning it off or on later takes effect at once
|
||||
// (docs/control-protocol.md).
|
||||
let ctx = cc.egui_ctx.clone();
|
||||
solidcraft_ui_egui::control_switch::launch(&mut app, Box::new(move |listen| control_server::start(listen, ctx.clone())), control_port);
|
||||
// The agent chat's MCP bridge reaches the app through an endpoint of its own, started
|
||||
// on a free port the first time the chat connects (docs/agent-chat.md).
|
||||
let ctx = cc.egui_ctx.clone();
|
||||
@@ -1313,6 +1421,7 @@ fn main() -> eframe::Result {
|
||||
prefs_writer: PrefsWriter::read(app.prefs()),
|
||||
solve: app,
|
||||
starting,
|
||||
backend_attempt: attempt_in_app,
|
||||
frames: 0,
|
||||
take_focus_unwanted: control_port.is_some(),
|
||||
come_forward: come_forward::ComeForward::default(),
|
||||
@@ -1328,7 +1437,9 @@ fn main() -> eframe::Result {
|
||||
);
|
||||
control_server::remove_token_file();
|
||||
match result {
|
||||
Err(e) if !created.load(std::sync::atomic::Ordering::SeqCst) => no_window(e, cpu_renderer, started, settings.as_deref()),
|
||||
Err(e) if !created.load(std::sync::atomic::Ordering::SeqCst) => {
|
||||
no_window(e, cpu_renderer, started, settings.as_deref(), backend_attempt.as_ref())
|
||||
}
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
@@ -1347,7 +1458,10 @@ fn startup_step(step: &'static str, detail: &str) {
|
||||
/// backends come from `startup::choose_backends` (on Windows D3D12 first, and only the backend
|
||||
/// in use is started); `preference` is `graphics.json`'s `backend`.
|
||||
fn wgpu_options(cpu: bool, preference: Option<&str>) -> eframe::egui_wgpu::WgpuConfiguration {
|
||||
let mut options = eframe::egui_wgpu::WgpuConfiguration::default();
|
||||
// One frame in flight, as eframe's own default (`NativeOptions::default`): egui-wgpu's
|
||||
// `WgpuConfiguration::default()` is HIGH_THROUGHPUT (two frames queued), which added a frame
|
||||
// of input-to-display latency to every pan, orbit and drag.
|
||||
let mut options = eframe::egui_wgpu::WgpuConfiguration::default().with_surface_config(eframe::egui_wgpu::SurfaceConfig::LOW_LATENCY);
|
||||
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut options.wgpu_setup {
|
||||
let env_set = std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty());
|
||||
// A retry applies only to this launch. WGPU_BACKEND always has priority.
|
||||
@@ -1378,7 +1492,13 @@ fn wgpu_options(cpu: bool, preference: Option<&str>) -> eframe::egui_wgpu::WgpuC
|
||||
|
||||
/// A failed renderer returns here before app creation. A fresh process avoids reusing winit's
|
||||
/// event loop or a failed device; each retry advances through the APIs, then software once.
|
||||
fn no_window(error: eframe::Error, tried_cpu: bool, failed: eframe::wgpu::Backends, settings: Option<&std::path::Path>) -> eframe::Result {
|
||||
fn no_window(
|
||||
error: eframe::Error,
|
||||
tried_cpu: bool,
|
||||
failed: eframe::wgpu::Backends,
|
||||
settings: Option<&std::path::Path>,
|
||||
backend_attempt: Option<&(std::path::PathBuf, startup::BackendAttempt)>,
|
||||
) -> eframe::Result {
|
||||
log::error!("the window could not open: {error}");
|
||||
solidcraft_engine::note!("SolidCraft: the window could not open: {error}");
|
||||
// This failure was handled, so neither the marker nor the journal should call it a crash.
|
||||
@@ -1386,6 +1506,25 @@ fn no_window(error: eframe::Error, tried_cpu: bool, failed: eframe::wgpu::Backen
|
||||
startup::started(dir);
|
||||
}
|
||||
solidcraft_engine::crash::end_session();
|
||||
// A rejected UI choice goes back to its previous API before ordinary fallback.
|
||||
// This is separate from startup::started: a handled failure is not confirmation.
|
||||
if let Some((path, attempt)) = backend_attempt {
|
||||
match startup::rollback_backend_start(path, attempt) {
|
||||
Ok(()) => {
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
let note = startup::backend_reverted_note(&attempt.requested, &attempt.previous);
|
||||
let mut command = std::process::Command::new(exe);
|
||||
command.args(std::env::args_os().skip(1)).env_remove(startup::RETRY_BACKEND_ENV).env(startup::FALLBACK_NOTE_ENV, note);
|
||||
match command.status() {
|
||||
Ok(status) if status.success() => return Ok(()),
|
||||
Ok(_) => return Err(error),
|
||||
Err(reason) => log::error!("could not restart with the previous graphics API: {reason}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(reason) => log::warn!("could not restore the previous graphics API: {reason}"),
|
||||
}
|
||||
}
|
||||
let explicit = std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty());
|
||||
if let Some(next) = startup::fallback_backend(cfg!(target_os = "windows"), explicit, tried_cpu, failed)
|
||||
&& let Ok(exe) = std::env::current_exe()
|
||||
|
||||
@@ -2592,11 +2592,15 @@ mod tests {
|
||||
let reader = Running::start(driver, fake.clone());
|
||||
reader.reads("spacenavd");
|
||||
// Still not readable, over two waits: the daemon read goes on, one connection, a few probes.
|
||||
let slept = std::time::Instant::now();
|
||||
std::thread::sleep(Duration::from_millis(700));
|
||||
let waited = slept.elapsed();
|
||||
assert_eq!(reader.key().as_deref(), Some("spacenavd"), "{driver:?}");
|
||||
assert_eq!(fake.world().connects, 1, "{driver:?}: the daemon read was not restarted for a device that still cannot be read");
|
||||
let opens = fake.world().opens;
|
||||
assert!(opens <= 4, "{driver:?}: {opens} tries in 700 ms with a 300 ms wait");
|
||||
// A loaded machine can sleep far past 700 ms: bound the tries by the time that really passed.
|
||||
let allowed = 4 + (waited.as_millis().saturating_sub(700) / 300) as u32;
|
||||
assert!(opens <= allowed, "{driver:?}: {opens} tries in {waited:?} with a 300 ms wait");
|
||||
// The permission is fixed.
|
||||
fake.world().openable = true;
|
||||
reader.reads(&Source::Hid(Some(IDS)).key());
|
||||
|
||||
@@ -114,6 +114,158 @@ pub fn started(dir: &Path) {
|
||||
let _ = std::fs::remove_file(dir.join(MARKER));
|
||||
}
|
||||
|
||||
/// A saved backend change that this launch is trying. Keep this value until the first
|
||||
/// frame is presented, so only this launch's matching attempt can be confirmed or reverted.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct BackendAttempt {
|
||||
pub requested: String,
|
||||
pub previous: String,
|
||||
}
|
||||
|
||||
/// The backend to use before creating any graphics device, with any pending recovery notice.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct BackendLaunch {
|
||||
pub backend: Option<String>,
|
||||
pub attempt: Option<BackendAttempt>,
|
||||
pub note: Option<String>,
|
||||
}
|
||||
|
||||
type GraphicsSettings = serde_json::Map<String, serde_json::Value>;
|
||||
const BACKEND_TRIAL: &str = "backend_trial";
|
||||
const MAX_BACKEND_PREFERENCE_BYTES: usize = 256;
|
||||
|
||||
/// Read only object-shaped settings. A missing or empty file means defaults; other failures
|
||||
/// are reported so the caller can use its safe renderer without overwriting unreadable data.
|
||||
fn read_backend_settings(path: &Path) -> Result<GraphicsSettings, String> {
|
||||
let text = match std::fs::read_to_string(path) {
|
||||
Ok(text) => text,
|
||||
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(GraphicsSettings::new()),
|
||||
Err(error) => return Err(format!("could not read graphics settings: {error}")),
|
||||
};
|
||||
if text.trim().is_empty() {
|
||||
return Ok(GraphicsSettings::new());
|
||||
}
|
||||
serde_json::from_str(&text).map_err(|error| format!("could not read graphics settings: {error}"))
|
||||
}
|
||||
|
||||
/// The attempt marker and backend are written together: a crash must leave a whole old or
|
||||
/// new record, never a selected API whose recovery data was only partly written.
|
||||
fn write_backend_settings(path: &Path, graphics: &GraphicsSettings) -> Result<(), String> {
|
||||
let bytes = serde_json::to_vec(graphics).map_err(|error| format!("could not encode graphics settings: {error}"))?;
|
||||
solidcraft_engine::io::safe_write::write_atomic(path, &bytes, false).map_err(|error| format!("could not save graphics settings: {error}"))
|
||||
}
|
||||
|
||||
/// UI choices are single API names. The previous value remains verbatim, including legacy
|
||||
/// comma lists and blanks, because startup already knows how to interpret those preferences.
|
||||
fn backend_trial(graphics: &GraphicsSettings) -> Option<(BackendAttempt, bool)> {
|
||||
let trial = graphics.get(BACKEND_TRIAL)?.as_object()?;
|
||||
let requested = trial.get("requested")?.as_str()?;
|
||||
if !matches!(requested, "auto" | "dx12" | "vulkan" | "gl" | "metal") {
|
||||
return None;
|
||||
}
|
||||
let previous = trial.get("previous")?.as_str()?;
|
||||
if previous.len() > MAX_BACKEND_PREFERENCE_BYTES {
|
||||
return None;
|
||||
}
|
||||
let started = trial.get("started")?.as_bool()?;
|
||||
Some((BackendAttempt { requested: requested.into(), previous: previous.into() }, started))
|
||||
}
|
||||
|
||||
/// Describe a restored choice using the same catalog as the Graphics preferences page.
|
||||
pub(super) fn backend_reverted_note(requested: &str, previous: &str) -> String {
|
||||
let requested = solidcraft_ui_egui::prefs::graphics_backend_label(requested);
|
||||
let previous = solidcraft_ui_egui::prefs::graphics_backend_label(previous);
|
||||
solidcraft_ui_text::format("prefs.graphics_api_start_reverted", &[("requested", &requested), ("previous", &previous)])
|
||||
}
|
||||
|
||||
/// Prepare a UI-selected API before any adapter is opened. Safe mode, an explicit environment
|
||||
/// override and process-local fallback launches pass `false` and leave the attempt untouched.
|
||||
/// An interrupted attempt restores its previous API. A new attempt is returned only after its
|
||||
/// started marker reaches disk; any I/O error must make the caller avoid the requested API.
|
||||
pub fn prepare_backend_start(path: &Path, allow_trial: bool) -> Result<BackendLaunch, String> {
|
||||
prepare_backend_launch(read_backend_settings(path)?, allow_trial, |graphics| write_backend_settings(path, graphics))
|
||||
}
|
||||
|
||||
/// Separate the state transition from persistence so a refused marker write is testable
|
||||
/// without depending on the test user's filesystem permissions.
|
||||
fn prepare_backend_launch(
|
||||
mut graphics: GraphicsSettings,
|
||||
allow_trial: bool,
|
||||
save: impl FnOnce(&GraphicsSettings) -> Result<(), String>,
|
||||
) -> Result<BackendLaunch, String> {
|
||||
let backend = graphics.get("backend").and_then(serde_json::Value::as_str).map(str::to_string);
|
||||
let mut launch = BackendLaunch { backend, ..Default::default() };
|
||||
if !allow_trial || !graphics.contains_key(BACKEND_TRIAL) {
|
||||
return Ok(launch);
|
||||
}
|
||||
let parsed = backend_trial(&graphics);
|
||||
let requested = graphics.get(BACKEND_TRIAL).and_then(|trial| trial.get("requested")).and_then(serde_json::Value::as_str);
|
||||
if requested.is_some() && requested != launch.backend.as_deref() {
|
||||
// Another edit replaced the selected API; stale recovery data cannot undo that edit.
|
||||
graphics.remove(BACKEND_TRIAL);
|
||||
} else if let Some((attempt, started)) = parsed {
|
||||
if attempt.requested == attempt.previous {
|
||||
graphics.remove(BACKEND_TRIAL);
|
||||
} else if started {
|
||||
graphics.insert("backend".into(), serde_json::Value::String(attempt.previous.clone()));
|
||||
graphics.remove(BACKEND_TRIAL);
|
||||
launch.backend = Some(attempt.previous.clone());
|
||||
launch.note = Some(backend_reverted_note(&attempt.requested, &attempt.previous));
|
||||
} else {
|
||||
let trial = graphics
|
||||
.get_mut(BACKEND_TRIAL)
|
||||
.and_then(serde_json::Value::as_object_mut)
|
||||
.ok_or_else(|| "graphics backend attempt changed before it could start".to_string())?;
|
||||
trial.insert("started".into(), serde_json::Value::Bool(true));
|
||||
launch.attempt = Some(attempt);
|
||||
}
|
||||
} else {
|
||||
// A damaged guard must not turn a protected API into an unguarded attempt. Prefer its
|
||||
// intact previous value; otherwise use Automatic, preserving the other graphics keys.
|
||||
let previous = graphics
|
||||
.get(BACKEND_TRIAL)
|
||||
.and_then(|trial| trial.get("previous"))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.filter(|value| value.len() <= MAX_BACKEND_PREFERENCE_BYTES)
|
||||
.unwrap_or("auto")
|
||||
.to_string();
|
||||
launch.note = Some(backend_reverted_note(launch.backend.as_deref().unwrap_or("auto"), &previous));
|
||||
graphics.insert("backend".into(), serde_json::Value::String(previous.clone()));
|
||||
graphics.remove(BACKEND_TRIAL);
|
||||
launch.backend = Some(previous);
|
||||
}
|
||||
save(&graphics)?;
|
||||
Ok(launch)
|
||||
}
|
||||
|
||||
/// Only a matching, started attempt still owning the saved backend may change recovery state.
|
||||
/// A newer preference edit is left alone, including a newly pending attempt at the same API.
|
||||
fn finish_backend_start(path: &Path, attempt: &BackendAttempt, revert: bool) -> Result<(), String> {
|
||||
let mut graphics = read_backend_settings(path)?;
|
||||
let matches = backend_trial(&graphics).is_some_and(|(saved, started)| started && saved == *attempt)
|
||||
&& graphics.get("backend").and_then(serde_json::Value::as_str) == Some(attempt.requested.as_str());
|
||||
if !matches {
|
||||
return Ok(());
|
||||
}
|
||||
graphics.remove(BACKEND_TRIAL);
|
||||
if revert {
|
||||
graphics.insert("backend".into(), serde_json::Value::String(attempt.previous.clone()));
|
||||
}
|
||||
write_backend_settings(path, &graphics)
|
||||
}
|
||||
|
||||
/// Keep a backend only after the window has presented its first frame. Handled startup
|
||||
/// failures must call `rollback_backend_start` instead, even if the ordinary crash marker clears.
|
||||
pub fn confirm_backend_start(path: &Path, attempt: &BackendAttempt) -> Result<(), String> {
|
||||
finish_backend_start(path, attempt, false)
|
||||
}
|
||||
|
||||
/// A handled window-start failure restores the previous backend before the host retries.
|
||||
/// Reading fresh settings and matching the attempt avoids erasing a later preference edit.
|
||||
pub fn rollback_backend_start(path: &Path, attempt: &BackendAttempt) -> Result<(), String> {
|
||||
finish_backend_start(path, attempt, true)
|
||||
}
|
||||
|
||||
/// The software adapter among `adapters` (WARP on Windows, lavapipe or llvmpipe elsewhere), else
|
||||
/// the first one that can draw to `surface`.
|
||||
pub fn pick_cpu_adapter(adapters: &[eframe::wgpu::Adapter], surface: Option<&eframe::wgpu::Surface<'_>>) -> Result<eframe::wgpu::Adapter, String> {
|
||||
@@ -486,6 +638,284 @@ mod tests {
|
||||
assert!(settings_directory(Some(file.as_os_str()), Some(default)).is_err());
|
||||
}
|
||||
|
||||
// These restart contracts apply to Windows and macOS as well as Linux.
|
||||
#[test]
|
||||
fn graphics_restart_applies_saved_choices_and_reopens_saved_designs() {
|
||||
use std::ffi::OsStr;
|
||||
let program = std::env::current_exe().unwrap();
|
||||
let designs = vec!["/saved/first design.sc".to_string(), "/saved/second.sc".to_string()];
|
||||
let command = crate::graphics_restart_command(&program, &[], &designs);
|
||||
assert_eq!(command.get_program(), program.as_os_str());
|
||||
assert_eq!(command.get_args().collect::<Vec<_>>(), designs.iter().map(OsStr::new).collect::<Vec<_>>());
|
||||
let changes: std::collections::BTreeMap<_, _> = command.get_envs().collect();
|
||||
for variable in [
|
||||
crate::startup::RETRY_BACKEND_ENV,
|
||||
crate::startup::FALLBACK_NOTE_ENV,
|
||||
crate::startup::RENDERER_ENV,
|
||||
crate::startup::SAFE_MODE_ENV,
|
||||
crate::device_lost::LOST_ENV,
|
||||
crate::device_lost::REASON_ENV,
|
||||
] {
|
||||
assert_eq!(changes.get(OsStr::new(variable)), Some(&None), "{variable}");
|
||||
}
|
||||
assert!(!changes.contains_key(OsStr::new(crate::startup::WGPU_BACKEND_ENV)));
|
||||
assert!(!changes.contains_key(OsStr::new("SOLIDCRAFT_SETTINGS_DIR")));
|
||||
assert!(!changes.contains_key(OsStr::new("WGPU_ADAPTER_NAME")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn graphics_restart_uses_an_appimage_only_from_its_own_existing_mount() {
|
||||
use crate::graphics_restart_program;
|
||||
use std::ffi::OsStr;
|
||||
let root = std::env::temp_dir().join("solidcraft-graphics-restart-fixture");
|
||||
let appdir = root.join("mount");
|
||||
let mounted = appdir.join("usr").join("bin").join("solidcraft");
|
||||
let image = root.join("SolidCraft.AppImage");
|
||||
let outside = root.join("source").join("solidcraft");
|
||||
let looks_similar = root.join("mount-other").join("solidcraft");
|
||||
let exists = |path: &std::path::Path| path == image;
|
||||
assert_eq!(graphics_restart_program(Some(&mounted), Some(image.as_os_str()), Some(appdir.as_os_str()), exists), Some(image.clone()));
|
||||
for executable in [&outside, &looks_similar] {
|
||||
assert_eq!(
|
||||
graphics_restart_program(Some(executable), Some(image.as_os_str()), Some(appdir.as_os_str()), exists),
|
||||
Some(executable.to_path_buf()),
|
||||
"a launcher inherited from another process is ignored"
|
||||
);
|
||||
}
|
||||
for (appimage, directory) in [
|
||||
(None, Some(appdir.as_os_str())),
|
||||
(Some(image.as_os_str()), None),
|
||||
(Some(OsStr::new("")), Some(appdir.as_os_str())),
|
||||
(Some(image.as_os_str()), Some(OsStr::new(""))),
|
||||
(Some(OsStr::new("relative.AppImage")), Some(appdir.as_os_str())),
|
||||
] {
|
||||
assert_eq!(graphics_restart_program(Some(&mounted), appimage, directory, exists), Some(mounted.clone()));
|
||||
}
|
||||
assert_eq!(
|
||||
graphics_restart_program(Some(&mounted), Some(image.as_os_str()), Some(appdir.as_os_str()), |_| false),
|
||||
Some(mounted.clone()),
|
||||
"a missing outer image cannot replace the running executable"
|
||||
);
|
||||
assert_eq!(graphics_restart_program(None, Some(image.as_os_str()), Some(appdir.as_os_str()), exists), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn graphics_restart_keeps_launch_options_and_uses_the_current_saved_tabs() {
|
||||
let original = [
|
||||
"--safe-mode",
|
||||
"--control",
|
||||
"7878",
|
||||
"original design.sc",
|
||||
"--theme-file",
|
||||
"a theme.json",
|
||||
"--sample",
|
||||
"--max-file-size",
|
||||
"2GB",
|
||||
"other-original.sc",
|
||||
"--max-file-size=3GB",
|
||||
];
|
||||
let args = crate::graphics_restart_args(original.into_iter().map(str::to_string));
|
||||
assert_eq!(args, ["--control", "7878", "--theme-file", "a theme.json", "--max-file-size", "2GB", "--max-file-size=3GB"]);
|
||||
let program = std::env::current_exe().unwrap();
|
||||
let designs = ["current saved.sc".to_string()];
|
||||
let command = crate::graphics_restart_command(&program, &args, &designs);
|
||||
assert_eq!(
|
||||
command.get_args().map(|value| value.to_string_lossy().into_owned()).collect::<Vec<_>>(),
|
||||
["--control", "7878", "--theme-file", "a theme.json", "--max-file-size", "2GB", "--max-file-size=3GB", "current saved.sc"]
|
||||
);
|
||||
for missing_value in ["--control", "--theme-file", "--max-file-size"] {
|
||||
assert!(crate::graphics_restart_args([missing_value.to_string()]).is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_graphics_api_is_authoritative_over_stale_ui_preferences() {
|
||||
use serde_json::json;
|
||||
for choice in ["auto", "vulkan", "dx12", "metal", "gl", "dx12,vulkan"] {
|
||||
for safe in [false, true] {
|
||||
let mut app = crate::SolveApp::new(crate::Session::default(), crate::Services::default());
|
||||
let stored = json!({"preferences":{"graphics_backend":"gl"}}).to_string();
|
||||
let saved = json!({"backend":choice});
|
||||
crate::restore_preferences(&mut app, Some(&stored), Some(&saved), safe);
|
||||
assert_eq!(app.preferences.graphics_backend, choice);
|
||||
}
|
||||
}
|
||||
let mut app = crate::SolveApp::new(crate::Session::default(), crate::Services::default());
|
||||
app.preferences.graphics_backend = "vulkan".into();
|
||||
crate::restore_graphics_preferences(&mut app, None);
|
||||
assert_eq!(app.preferences.graphics_backend, "auto");
|
||||
}
|
||||
fn backend_settings(path: &Path) -> serde_json::Value {
|
||||
serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()
|
||||
}
|
||||
|
||||
fn pending_backend(previous: &str) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"backend": "vulkan",
|
||||
"backend_trial": {"requested": "vulkan", "previous": previous, "started": false},
|
||||
"msaa": 8,
|
||||
"adapter": "Saved GPU",
|
||||
"window_system": "x11",
|
||||
"future_setting": {"enabled": true}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn backend_start_marks_the_attempt_before_selection_and_keeps_it_after_a_presented_frame() {
|
||||
let dir = scratch("backend-confirm");
|
||||
let path = dir.join("graphics.json");
|
||||
let original = pending_backend("auto");
|
||||
std::fs::write(&path, original.to_string()).unwrap();
|
||||
|
||||
let launch = prepare_backend_start(&path, true).unwrap();
|
||||
assert_eq!(launch.backend.as_deref(), Some("vulkan"));
|
||||
assert!(launch.note.is_none());
|
||||
let attempt = launch.attempt.unwrap();
|
||||
assert_eq!(attempt, BackendAttempt { requested: "vulkan".into(), previous: "auto".into() });
|
||||
let mut started = original.clone();
|
||||
started["backend_trial"]["started"] = serde_json::json!(true);
|
||||
assert_eq!(backend_settings(&path), started, "selection is returned only after the started marker is durable");
|
||||
|
||||
confirm_backend_start(&path, &attempt).unwrap();
|
||||
let mut kept = original;
|
||||
kept.as_object_mut().unwrap().remove(BACKEND_TRIAL);
|
||||
assert_eq!(backend_settings(&path), kept, "confirmation changes no other graphics preferences");
|
||||
let next = prepare_backend_start(&path, true).unwrap();
|
||||
assert_eq!(next.backend.as_deref(), Some("vulkan"));
|
||||
assert!(next.attempt.is_none() && next.note.is_none());
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interrupted_backend_start_restores_the_exact_previous_choice_once() {
|
||||
solidcraft_ui_egui::i18n::install();
|
||||
let _language = solidcraft_ui_text::scope("en");
|
||||
let dir = scratch("backend-interrupted");
|
||||
let path = dir.join("graphics.json");
|
||||
for (previous, label) in [("auto", "Automatic"), (" dx12, vulkan ", " dx12, vulkan "), ("", "Automatic")] {
|
||||
let mut expected = pending_backend(previous);
|
||||
std::fs::write(&path, expected.to_string()).unwrap();
|
||||
assert!(prepare_backend_start(&path, true).unwrap().attempt.is_some());
|
||||
|
||||
// A process crash leaves the started marker; the next normal launch rolls back.
|
||||
let recovered = prepare_backend_start(&path, true).unwrap();
|
||||
assert_eq!(recovered.backend.as_deref(), Some(previous));
|
||||
assert!(recovered.attempt.is_none());
|
||||
assert_eq!(
|
||||
recovered.note,
|
||||
Some(format!("The previous start with Vulkan did not open the window. SolidCraft restored {label}.")),
|
||||
"recovery describes both APIs using their displayed names"
|
||||
);
|
||||
expected["backend"] = serde_json::json!(previous);
|
||||
expected.as_object_mut().unwrap().remove(BACKEND_TRIAL);
|
||||
assert_eq!(backend_settings(&path), expected, "only the attempted API is reverted");
|
||||
assert!(prepare_backend_start(&path, true).unwrap().note.is_none(), "the notice is not repeated");
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn safe_override_and_fallback_launches_leave_backend_attempts_untouched() {
|
||||
let dir = scratch("backend-bypass");
|
||||
let path = dir.join("graphics.json");
|
||||
assert_eq!(prepare_backend_start(&path, true).unwrap(), BackendLaunch::default());
|
||||
assert!(!path.exists(), "default startup does not create a settings file");
|
||||
for started in [false, true] {
|
||||
let mut saved = pending_backend("dx12");
|
||||
saved["backend_trial"]["started"] = serde_json::json!(started);
|
||||
let bytes = serde_json::to_vec_pretty(&saved).unwrap();
|
||||
std::fs::write(&path, &bytes).unwrap();
|
||||
let launch = prepare_backend_start(&path, false).unwrap();
|
||||
assert_eq!(launch.backend.as_deref(), Some("vulkan"));
|
||||
assert!(launch.attempt.is_none() && launch.note.is_none());
|
||||
assert_eq!(std::fs::read(&path).unwrap(), bytes, "even an interrupted attempt waits for a normal launch");
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn backend_start_rollback_and_confirmation_cannot_overwrite_a_newer_choice() {
|
||||
let dir = scratch("backend-ownership");
|
||||
let path = dir.join("graphics.json");
|
||||
let saved = pending_backend("dx12");
|
||||
std::fs::write(&path, saved.to_string()).unwrap();
|
||||
let attempt = prepare_backend_start(&path, true).unwrap().attempt.unwrap();
|
||||
rollback_backend_start(&path, &attempt).unwrap();
|
||||
let mut reverted = saved.clone();
|
||||
reverted["backend"] = serde_json::json!("dx12");
|
||||
reverted.as_object_mut().unwrap().remove(BACKEND_TRIAL);
|
||||
assert_eq!(backend_settings(&path), reverted, "handled failure restores the last working preference");
|
||||
|
||||
for newer in [
|
||||
serde_json::json!({"backend": "gl"}),
|
||||
serde_json::json!({"backend": "vulkan", "backend_trial": {"previous": "dx12", "requested": "vulkan", "started": false}}),
|
||||
serde_json::json!({"backend": "vulkan", "backend_trial": {"previous": "auto", "requested": "vulkan", "started": true}}),
|
||||
serde_json::json!({"backend": "gl", "backend_trial": {"previous": "dx12", "requested": "vulkan", "started": true}}),
|
||||
] {
|
||||
let bytes = serde_json::to_vec_pretty(&newer).unwrap();
|
||||
std::fs::write(&path, &bytes).unwrap();
|
||||
confirm_backend_start(&path, &attempt).unwrap();
|
||||
rollback_backend_start(&path, &attempt).unwrap();
|
||||
assert_eq!(std::fs::read(&path).unwrap(), bytes, "stale launch state cannot consume another preference");
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn malformed_backend_guards_use_the_previous_api_or_automatic_without_touching_other_settings() {
|
||||
let dir = scratch("backend-malformed");
|
||||
let path = dir.join("graphics.json");
|
||||
for (trial, expected_backend) in [
|
||||
(serde_json::json!(null), "auto"),
|
||||
(serde_json::json!(42), "auto"),
|
||||
(serde_json::json!({}), "auto"),
|
||||
(serde_json::json!({"requested": "vulkan", "previous": "dx12"}), "dx12"),
|
||||
(serde_json::json!({"requested": "vulkan", "previous": "dx12", "started": "yes"}), "dx12"),
|
||||
(serde_json::json!({"requested": "vulkan", "previous": "x".repeat(257), "started": false}), "auto"),
|
||||
] {
|
||||
let mut saved = pending_backend("auto");
|
||||
saved["backend_trial"] = trial;
|
||||
std::fs::write(&path, saved.to_string()).unwrap();
|
||||
let launch = prepare_backend_start(&path, true).unwrap();
|
||||
assert_eq!(launch.backend.as_deref(), Some(expected_backend));
|
||||
assert!(launch.attempt.is_none());
|
||||
saved["backend"] = serde_json::json!(expected_backend);
|
||||
saved.as_object_mut().unwrap().remove(BACKEND_TRIAL);
|
||||
assert_eq!(backend_settings(&path), saved);
|
||||
}
|
||||
|
||||
let mut saved = pending_backend("auto");
|
||||
saved["backend"] = serde_json::json!("gl");
|
||||
std::fs::write(&path, saved.to_string()).unwrap();
|
||||
let launch = prepare_backend_start(&path, true).unwrap();
|
||||
assert_eq!(launch.backend.as_deref(), Some("gl"), "a stale marker cannot replace a newer API");
|
||||
assert!(launch.attempt.is_none() && launch.note.is_none());
|
||||
saved.as_object_mut().unwrap().remove(BACKEND_TRIAL);
|
||||
assert_eq!(backend_settings(&path), saved);
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_backend_attempt_is_never_returned_when_its_marker_cannot_be_saved() {
|
||||
for started in [false, true] {
|
||||
let mut saved = pending_backend("dx12");
|
||||
saved["backend_trial"]["started"] = serde_json::json!(started);
|
||||
let graphics = saved.as_object().unwrap().clone();
|
||||
let error = prepare_backend_launch(graphics, true, |_| Err("fixture: write refused".into())).unwrap_err();
|
||||
assert_eq!(error, "fixture: write refused", "no selected backend escapes a failed transition");
|
||||
}
|
||||
|
||||
let dir = scratch("backend-unreadable");
|
||||
let path = dir.join("graphics.json");
|
||||
for damaged in ["{", "[]", "null"] {
|
||||
std::fs::write(&path, damaged).unwrap();
|
||||
assert!(prepare_backend_start(&path, true).is_err());
|
||||
assert_eq!(std::fs::read_to_string(&path).unwrap(), damaged, "unreadable settings are never overwritten");
|
||||
}
|
||||
assert!(prepare_backend_start(&dir, true).is_err(), "a filesystem read failure is reported");
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn intel_macs_start_without_indirect_call_validation() {
|
||||
use eframe::wgpu::InstanceFlags as F;
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
Read `assets/README.md` before changing media, fonts, artwork or their consumers.
|
||||
For **any UI icon, icon assignment or review-tool change**, also read
|
||||
`assets/icons/ui/AGENTS.md` and `assets/icons/ui/STYLE_GUIDE.md` before editing.
|
||||
`crates/look/icons/AGENTS.md` and `crates/look/icons/STYLE_GUIDE.md` before editing.
|
||||
These files are the specification; chat history and old previews are not required.
|
||||
|
||||
- Keep one editable authority per resource. UI SVGs are masters, not exports of a
|
||||
|
||||
@@ -70,4 +70,10 @@ meetup. If you publish a fork or a modified build, give it its own name and logo
|
||||
don't mistake it for SolidCraft.
|
||||
|
||||
The wordmark is set in IBM Plex Sans Bold (SIL Open Font License 1.1, the interface font in
|
||||
`assets/fonts/ibm-plex-sans/`) and outlined, so you don't need the font to print it.
|
||||
`crates/look/fonts/ibm-plex-sans/`) and outlined, so you don't need the font to print it.
|
||||
|
||||
## Licence
|
||||
|
||||
The SolidCraft name, logo and brand kit are under the SolidCraft Brand and Interface Licence
|
||||
([LICENSE-BRAND](../../LICENSE-BRAND)). Using them for anything other than SolidCraft needs the
|
||||
maintainers' written permission first.
|
||||
|
||||
+228
-41
@@ -247,6 +247,7 @@
|
||||
"Drag to move the hole; click to remove it": "اسحب لتحريك الثقب؛ انقر لإزالته",
|
||||
"Drag to move the rest across the model. It snaps to sketch points on the face.": "اسحب لتحريك المسند على النموذج. يلتقط نقاط الرسم على الوجه.",
|
||||
"Drag to move the snap fit across the model. It snaps to sketch points on the face.": "اسحب لتحريك وصلة الكبس على النموذج. تلتقط نقاط الرسم على الوجه.",
|
||||
"Drag to place it on another face.": "اسحب لوضعه على وجه آخر.",
|
||||
"Drag to point the catch in another direction.": "اسحب لتوجيه لسان الكبس في اتجاه آخر.",
|
||||
"Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.": "اسحب لتدوير المسند بخطوات 5°. اضغط Alt أو Ctrl لتدويره بحرية.",
|
||||
"Drive Joint": "تحريك المفصل",
|
||||
@@ -513,6 +514,7 @@
|
||||
"Offset Y": "الإزاحة Y",
|
||||
"Offset Z": "الإزاحة Z",
|
||||
"On your computer": "على جهازك",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "مقطع آخر من الحافة المختارة، لكل منها زاويتها وارتفاعها ولفّاتها",
|
||||
"Opacity": "العتامة",
|
||||
"Open GitHub": "فتح GitHub",
|
||||
"Open GitHub draft": "فتح مسودة GitHub",
|
||||
@@ -634,6 +636,7 @@
|
||||
"Remove the track": "إزالة المسار",
|
||||
"Remove this bend": "إزالة هذا الثني",
|
||||
"Remove this point": "إزالة هذه النقطة",
|
||||
"Remove this segment": "إزالة هذا المقطع",
|
||||
"Rename Feature": "إعادة تسمية الميزة",
|
||||
"Rename Folder": "إعادة تسمية المجلد",
|
||||
"Render Stage": "مرحلة التصيير",
|
||||
@@ -723,6 +726,7 @@
|
||||
"Section position": "موضع المقطع",
|
||||
"Sections": "المقاطع",
|
||||
"Sections (one sketch each)": "المقاطع (رسم واحد لكل منها)",
|
||||
"Segments": "المقاطع",
|
||||
"Select Features": "تحديد الميزات",
|
||||
"Select Other": "تحديد آخر",
|
||||
"Select Other: hold the left button still on the model (or right-click › Select Other…) to list everything under the cursor; click again on the same spot to select the next thing there. Double-click the middle button to go Home (Preferences › Navigation).": "تحديد آخر: أبقِ الزر الأيسر ثابتًا على النموذج (أو انقر بالزر الأيمن › تحديد آخر…) لعرض كل ما تحت المؤشر؛ وانقر مرة أخرى في الموضع نفسه لتحديد العنصر التالي هناك. انقر نقرًا مزدوجًا بالزر الأوسط للانتقال إلى العرض الرئيسي (التفضيلات › التنقل).",
|
||||
@@ -772,6 +776,7 @@
|
||||
"Spacing must be a non-zero number": "يجب أن يكون التباعد عددًا غير صفري",
|
||||
"Specialise": "تخصيص",
|
||||
"Speed": "السرعة",
|
||||
"Split Edge": "تقسيم الحافة",
|
||||
"Splitting tool": "أداة التقسيم",
|
||||
"Square": "مربع",
|
||||
"Stainless Steel": "فولاذ مقاوم للصدأ",
|
||||
@@ -885,6 +890,7 @@
|
||||
"Variable Radius": "نصف قطر متغير",
|
||||
"Variable radius": "نصف قطر متغير",
|
||||
"Velocity": "السرعة المتجهة",
|
||||
"Vertical": "عمودي",
|
||||
"Vertices": "الرؤوس",
|
||||
"View": "عرض",
|
||||
"View navigator": "متصفح العرض",
|
||||
@@ -931,13 +937,20 @@
|
||||
"ai.http.confirm": "السماح لهذه النقطة الطرفية",
|
||||
"ai.http.warning": "سيُرسَل مفتاح API والمحادثة دون تشفير. يمكن لأي شخص لديه وصول إلى الشبكة قراءتهما أو تغييرهما. استخدم هذا الخيار فقط على شبكة تثق بها.",
|
||||
"ai.prefs.allow_control": "السماح لوكلاء الذكاء الاصطناعي بالاتصال",
|
||||
"ai.prefs.allow_control_note": "قناة محلية (MCP). لا شيء يغادر هذا الحاسوب.\n\nيفتح قناة تحكم على هذا الحاسوب فقط (127.0.0.1، المنفذ 27878 أو أول منفذ متاح بعده). على البرنامج الذي يتصل أن يقدّم أيضًا رمزًا سريًا لا يقرؤه إلا حساب المستخدم الخاص بك، ويُنشأ من جديد عند كل تشغيل. يُطبّق في المرة القادمة التي يبدأ فيها SolidCraft. عند الإيقاف: لا شيء يستمع ما لم تشغّل SolidCraft مع --control.",
|
||||
"ai.prefs.allow_control_note": "قناة محلية (MCP). لا شيء يغادر هذا الحاسوب.\n\nيفتح قناة تحكم على هذا الحاسوب فقط (127.0.0.1، على المنفذ أدناه؛ وإذا كان 27878 مستخدمًا فيُستخدم المنفذ الحر التالي). على البرنامج الذي يتصل أن يقدّم أيضًا رمزًا سريًا لا يقرؤه إلا حساب المستخدم الخاص بك، ويُنشأ من جديد عند كل تشغيل. يسري فورًا. عند الإيقاف: لا شيء يستمع ما لم تشغّل SolidCraft مع --control.",
|
||||
"ai.prefs.availability": "التوفر",
|
||||
"ai.prefs.background_commands": "تشغيل الأوامر البطيئة في الخلفية",
|
||||
"ai.prefs.connect_apps": "إضافة SolidCraft إلى تطبيقات الذكاء الاصطناعي",
|
||||
"ai.prefs.connect_apps_note": "إيقافه يزيل الإدخالات مجددًا.\n\nعند بدء تشغيل SolidCraft، يُضاف كخادم MCP إلى تطبيقات الذكاء الاصطناعي الموجودة على هذا الحاسوب (OpenCode وClaude Desktop وClaude Code وCursor وCodex وGemini CLI وCopilot CLI وWindsurf وZed وVS Code)، ليتمكن الوكيل من استخدامه دون أي إعداد. لا يُضاف إلا مُدخل solidcraft أو يُحدَّث مساره؛ ويُترك المُدخل الذي غيّرته كما هو، ويُنسخ الملف احتياطيًا أولًا. عند الإيقاف تُزال المُدخلات التي أضافها. الأمر «المساعدة > ربط مساعدي الذكاء الاصطناعي…» يفعل ذلك يدويًا.",
|
||||
"ai.prefs.connect_at_start": "توصيل آخر وكيل عند البدء",
|
||||
"ai.prefs.connect_at_start_note": "يبدأ في الخلفية الوكيل الذي اتصلت به آخر مرة (أو الوكيل الافتراضي) في كل مرة يبدأ فيها SolidCraft، ليكون جاهزًا للمحادثة. لا يحدث ذلك عند بدء SolidCraft مع --control. إذا تعذّر الاتصال، يعرض المساعد «فشل الاتصال» وزر «إعادة المحاولة».",
|
||||
"ai.prefs.control_failed": "تعذّر بدء قناة التحكم: {error}",
|
||||
"ai.prefs.control_from_launch": "بدأ هذا التشغيل باستخدام --control على المنفذ {port}. تسري التغييرات هنا عند تشغيل SolidCraft في المرة القادمة دون --control.",
|
||||
"ai.prefs.control_listening": "يستمع على 127.0.0.1:{port}",
|
||||
"ai.prefs.control_not_listening": "لا يستمع",
|
||||
"ai.prefs.control_port": "المنفذ",
|
||||
"ai.prefs.control_port_note": "المنفذ الذي يتصل عبره وكلاء الذكاء الاصطناعي على هذا الحاسوب (127.0.0.1). الافتراضي هو 27878: إذا كان مستخدمًا يُستخدم المنفذ الحر التالي. أي منفذ آخر يُستخدم كما هو. وجّه عميل MCP إلى المنفذ نفسه، مثل solidcraft-cli mcp --connect 127.0.0.1:7878.",
|
||||
"ai.prefs.control_port_taken": "المنفذ {port} يستخدمه برنامج آخر (أو نافذة SolidCraft أخرى). اختر منفذًا آخر.",
|
||||
"ai.prefs.follow_camera": "تتبّع الكاميرا",
|
||||
"ai.prefs.follow_camera_off": "تتبّع الكاميرا التلقائي متوقف.",
|
||||
"ai.prefs.follow_camera_on": "تتجه الكاميرا نحو الرسومات التي ينشئها الوكيل.",
|
||||
@@ -998,6 +1011,13 @@
|
||||
"browser.sketches_to_parts_not_on_face": "ليست على وجه جزء",
|
||||
"browser.sketches_to_parts_part_missing": "جزؤها لم يعد موجودًا",
|
||||
"browser.sketches_to_parts_result": "نُقلت {moved} رسومات إلى الجزء الذي رُسمت عليه؛ وبقيت {stayed}: {why}",
|
||||
"browser.straighten_angle": "اتجاه الحافة",
|
||||
"browser.straighten_choose": "اختر ما تصبح عليه الحافة، أفقية أو رأسية أو بزاوية، ثم اضغط «تقويم».",
|
||||
"browser.straighten_click_a": "انقر الصورة عند أحد طرفي حافة يجب أن تكون مستقيمة، أو اكتب إحداثياتها.",
|
||||
"browser.straighten_click_b": "انقر الطرف الآخر للحافة، أو اكتب إحداثياته.",
|
||||
"browser.straighten_horizontal": "أفقي",
|
||||
"browser.straighten_title": "تقويم: {name}",
|
||||
"browser.straighten_vertical": "رأسي",
|
||||
"browser.units": "الوحدات: {units}",
|
||||
"cam.flat": "وجه مسطح",
|
||||
"cam.follower": "التابع",
|
||||
@@ -1027,6 +1047,8 @@
|
||||
"cmd.appearance_pick_up": "التقاط المظهر",
|
||||
"cmd.appearance_replace": "استبدال المظهر",
|
||||
"cmd.assembly_bom": "قائمة المواد",
|
||||
"cmd.assembly_constraint_create": "تقييد",
|
||||
"cmd.assembly_constraint_edit": "تحرير التقييد",
|
||||
"cmd.assembly_mass_properties": "خصائص الكتلة",
|
||||
"cmd.body.print_face": "وجه الطباعة",
|
||||
"cmd.body_rename": "إعادة تسمية الجسم",
|
||||
@@ -1045,6 +1067,7 @@
|
||||
"cmd.canvas_delete": "حذف اللوحة",
|
||||
"cmd.canvas_edit": "تعديل اللوحة",
|
||||
"cmd.canvas_insert": "لوحة مرجعية",
|
||||
"cmd.canvas_straighten": "تقويم اللوحة",
|
||||
"cmd.canvas_to_sketch": "تحويل اللوحة إلى رسم",
|
||||
"cmd.component_activate": "تنشيط المكوّن",
|
||||
"cmd.component_break_link": "فك الارتباط",
|
||||
@@ -1086,7 +1109,10 @@
|
||||
"cmd.config_rule": "قاعدة التكوين",
|
||||
"cmd.config_rules": "قواعد التكوين",
|
||||
"cmd.config_table": "عرض جدول التكوينات",
|
||||
"cmd.construct.axis": "محور",
|
||||
"cmd.construct.plane": "مستوى",
|
||||
"cmd.construct.plane.axis_point": "مستوى عبر محور ونقطة",
|
||||
"cmd.construct.point": "نقطة",
|
||||
"cmd.construct_axis_edge": "محور عبر حافة",
|
||||
"cmd.construct_axis_normal_to_face": "محور عمودي على وجه",
|
||||
"cmd.construct_axis_through_cylinder": "محور عبر أسطوانة/مخروط/طارة",
|
||||
@@ -1149,6 +1175,7 @@
|
||||
"cmd.file_save_mesh": "حفظ كشبكة",
|
||||
"cmd.file_send_to_slicer": "إرسال إلى برنامج التقطيع",
|
||||
"cmd.file_slicers": "برامج التقطيع المثبتة",
|
||||
"cmd.frame_end_cap": "غطاء طرفي",
|
||||
"cmd.frame_member": "عنصر هيكلي",
|
||||
"cmd.frame_profile_insert": "إدراج مقطع",
|
||||
"cmd.frame_profile_list": "مكتبة المقاطع",
|
||||
@@ -1169,6 +1196,7 @@
|
||||
"cmd.inspect_isocurve": "تحليل خطوط المعامِل",
|
||||
"cmd.inspect_minimum_radius": "تحليل أصغر نصف قطر",
|
||||
"cmd.inspect_parameter_sweep": "مسح المعاملات",
|
||||
"cmd.inspect_parameter_variants": "مقارنة بدائل المعلمات",
|
||||
"cmd.inspect_silhouette": "الخط المحيطي",
|
||||
"cmd.inspect_zebra": "تحليل الخطوط المتعرجة (زيبرا)",
|
||||
"cmd.joint_as_built": "مفصل حسب الوضع الحالي",
|
||||
@@ -1222,6 +1250,10 @@
|
||||
"cmd.motion_trace": "أثر الحركة",
|
||||
"cmd.motion_trace_edit": "تحرير أثر الحركة",
|
||||
"cmd.motion_trace_keep": "الإبقاء على أثر الحركة",
|
||||
"cmd.note_add": "إضافة ملاحظة",
|
||||
"cmd.note_delete": "حذف ملاحظة",
|
||||
"cmd.note_list": "عرض الملاحظات",
|
||||
"cmd.note_update": "تحرير الملاحظة",
|
||||
"cmd.occurrence_align": "محاذاة النسخة",
|
||||
"cmd.occurrence_copy": "لصق (نسخة مرتبطة)",
|
||||
"cmd.occurrence_drag": "سحب النسخة",
|
||||
@@ -1347,6 +1379,7 @@
|
||||
"cmd.render_start": "تصيير صورة",
|
||||
"cmd.render_status": "تقدّم التصيير",
|
||||
"cmd.select_clear": "مسح التحديد",
|
||||
"cmd.selection_get": "الحصول على التحديد",
|
||||
"cmd.settings_profile_apply": "تطبيق ملف تعريف الإعدادات",
|
||||
"cmd.settings_profile_delete": "حذف ملف تعريف الإعدادات",
|
||||
"cmd.settings_profile_export": "تصدير ملف تعريف الإعدادات",
|
||||
@@ -1510,6 +1543,7 @@
|
||||
"cmd.timeline_suppress": "تعطيل الميزة",
|
||||
"cmd.ui.assistant": "إظهار المساعد أو إخفاؤه",
|
||||
"cmd.ui.palette": "البحث في الأوامر",
|
||||
"cmd.ui.toggle_visibility": "إظهار/إخفاء التحديد",
|
||||
"cmd.view.navigator": "متصفح العرض المخصص",
|
||||
"cmd.view.render_browser": "مستعرض التصيير",
|
||||
"cmd.view.render_dock": "نقل لوحة التصيير",
|
||||
@@ -1567,6 +1601,7 @@
|
||||
"color.step_down": "إنقاص خطوة",
|
||||
"color.step_up": "زيادة خطوة",
|
||||
"color.value": "القيمة، أي السطوع (بالمئة)",
|
||||
"component.error.ambiguous_name": "توجد عدة مكونات بالاسم `{name}`. استخدم معرّف مكوّن رقميًا: {ids}.",
|
||||
"config.column_filter_empty": "لا توجد أعمدة مطابقة",
|
||||
"config.rule_parameter_columns": "لا تظهر هنا إلا المعاملات التي لها عمود في الجدول. أضف عمودًا عبر «إضافة عمود» (+) لاستخدام المعامل هنا.",
|
||||
"config.rule_suppression_columns": "لا تظهر هنا إلا الميزات التي لها عمود «تعطيل» في الجدول. أضف عمودًا عبر «إضافة عمود» (+) للتحكم بالميزة هنا.",
|
||||
@@ -1607,6 +1642,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}: المرجع `{reference}` لم يعد موجودًا كما اختير؛ أعد اختياره",
|
||||
"dialog.bodies_count": "{count} أجسام",
|
||||
"dialog.clearance_invalid": "يجب أن يكون الخلوص طولًا قيمته 0 أو أكثر",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "احسب",
|
||||
"dialog.compute_again": "احسب مرة أخرى",
|
||||
"dialog.computing": "جارٍ الحساب… {seconds} ث",
|
||||
@@ -1619,10 +1655,12 @@
|
||||
"dialog.dimension_step_expression": "يتغير الرقم فقط بالخطوات؛ يبقى التعبير كما كُتب",
|
||||
"dialog.dimension_step_up": "زيادة بمقدار {step}",
|
||||
"dialog.edit_title": "تعديل {title}",
|
||||
"dialog.hole_held_off_its_line": "الحافة المرجعية تُبقي هذا الثقب على خط يغادر الوجه قبل النقطة المختارة. اختر حيث يعبر الخط الوجه، أو أزل الحافة لتحريك الثقب بحرية.",
|
||||
"dialog.no_shown_body": "لا يوجد جسم ظاهر لتغييره: أظهر جسمًا، أو اختر «جسم جديد»",
|
||||
"dialog.pattern_sketch_not_object": "اختر أجسامًا أو ميزات: الرسم ليس أيًّا منهما. كرّر منحنياته بأداة النمط أو المرآة داخل الرسم، أو ابثقه أولًا.",
|
||||
"dialog.primitive_point_tip": "نقطة تملأ X وY وZ: انقر هنا ثم على رأس أو حافة أو وجه من النموذج، أو على نقطة من رسم، أو على نقطة الأصل.",
|
||||
"dialog.reference_edge_tip": "حافة مستقيمة من الوجه المختار تُقاس منها المسافة أدناه: انقر هنا ثم على الحافة.",
|
||||
"dialog.right_click_pick": "حدد {input} أولًا",
|
||||
"dialog.select": "↖ تحديد",
|
||||
"dialog.selected_count": "↖ {count} محدد",
|
||||
"dialog.selection_constraint": "قيد {id}",
|
||||
@@ -1636,9 +1674,12 @@
|
||||
"document.changed_on_disk": "تغيّر {name} على القرص",
|
||||
"document.changed_on_disk_detail": "غيّر برنامج أو حاسوب آخر {name} منذ أن فتحته أو حفظته آخر مرة. الكتابة فوقه تستبدل تلك التغييرات بتغييراتك؛ وحفظ نسخة يحتفظ بالاثنين.",
|
||||
"document.copy_name": "نسخة من {name}",
|
||||
"document.discard_row": "تجاهل",
|
||||
"document.finish_save_prompt": "أكمل الرد على نافذة الحفظ قبل فتح تصميم آخر.",
|
||||
"document.newer_file": "تم الحفظ بإصدار أحدث من SolidCraft (صيغة الملف {format}، وهذا الإصدار يقرأ حتى {reads}). إذا كان هناك شيء مفقود، فحدّث البرنامج.",
|
||||
"document.newer_file_change": "تم الحفظ بإصدار أحدث من SolidCraft (صيغة الملف {format} مع `{change}`، وهو ما لا يعرفه هذا الإصدار). إذا كان هناك شيء مفقود، فحدّث البرنامج.",
|
||||
"document.newer_file_not_read": "لم يُقرأ: {what}. يبقى في الملف عند الحفظ.",
|
||||
"document.not_saved_yet": "لم يُحفظ بعد",
|
||||
"document.open_anyway": "افتح على أي حال",
|
||||
"document.open_elsewhere": "{name} مفتوح بالفعل",
|
||||
"document.open_elsewhere_detail": "{name} مفتوح في SolidCraft {app} على {who}، فُتح {when}. إذا حفظتما كلاكما، فسيخسر أحدكما عمله. افتحه للقراءة فقط لتطّلع عليه دون الحفظ فوقه.",
|
||||
@@ -1648,6 +1689,9 @@
|
||||
"document.read_only_save": "فُتح هذا التصميم للقراءة فقط: احفظه كملف جديد",
|
||||
"document.save_changes": "حفظ التغييرات على {name}؟",
|
||||
"document.save_copy": "حفظ نسخة…",
|
||||
"document.save_many": "حفظ التغييرات في {n} من التصاميم؟",
|
||||
"document.save_row": "حفظ",
|
||||
"document.save_selected": "حفظ المحدد",
|
||||
"document.tab_unsaved_changes": "تغييرات غير محفوظة",
|
||||
"document.unsaved_changes": "في {name} تغييرات غير محفوظة. إن لم تحفظها فستضيع.",
|
||||
"drive.rigid": "{joint} مفصل صلب: يثبّت أجزاءه في مكانها، لذا لا يوجد ما يمكن تحريكه. لتتحرك الأجزاء، غيّر نوعه في «تعديل المفصل»: «دوراني» للدوران، «منزلق» للانزلاق، «أسطواني» لكليهما.",
|
||||
@@ -1667,6 +1711,8 @@
|
||||
"dxf.tolerance": "تفاوت المنحنى",
|
||||
"dxf.tolerance_help": "الأجسام الظاهرة فقط. المنحنيات تُمثَّل بقطع مستقيمة. التفاوت الأصغر يعطي منحنيات أنعم ويستهلك وقتًا وذاكرة أكثر.",
|
||||
"each rail's curves must be in one sketch": "يجب أن تكون منحنيات كل دليل في رسم واحد",
|
||||
"error.end_cap_faces": "اختر وجهًا طرفيًا مفتوحًا واحدًا على الأقل لعضو إطار",
|
||||
"error.end_cap_unresolved": "الطرف {ends} لهذا الغطاء لم يعد موجودًا في النموذج. اختر الأوجه الطرفية مرة أخرى",
|
||||
"feature computation ended without a result": "انتهى حساب الميزة دون نتيجة",
|
||||
"file.open.drawing_filter": "التصاميم وملفات CAD والشبكات والرسومات",
|
||||
"file.open.portal_fallback.no_portal_service": "منتقي الملفات الذي فُتح ليس تابعًا لسطح المكتب: خدمة منتقي الملفات في سطح المكتب غير متاحة.",
|
||||
@@ -1678,6 +1724,7 @@
|
||||
"file_load.inserting": "إدراج الهندسة",
|
||||
"file_load.link_item": "{name} ({done} من {total})",
|
||||
"file_load.opened": "تم فتح {name}",
|
||||
"file_load.opened_behind": "فُتح {name} في علامة تبويب جديدة",
|
||||
"file_load.opened_in_tab": "تم فتح {name} في علامة تبويب جديدة",
|
||||
"file_load.opening": "فتح التصميم",
|
||||
"file_load.preparing_thumbnail": "تجهيز الصورة المصغّرة...",
|
||||
@@ -1725,11 +1772,13 @@
|
||||
"help.config.table": "يعرض جدول التكوينات: صف لكل نسخة وعمود لكل معامل أو ميزة، ويبيّن هل ما زال التصميم مطابقًا للصف النشط. استخدمه لمراجعة نسخ التصميم.",
|
||||
"help.connect_note": "أعد تشغيل كل مساعد لتحميل خادم SolidCraft. نُسخ كل ملف احتياطيًا بامتداد .bak قبل تغييره.",
|
||||
"help.connect_title": "ربط مساعدي الذكاء الاصطناعي",
|
||||
"help.construct.axis": "ينشئ محورًا إنشائيًا بالطريقة التي تناسب ما تختاره: على امتداد حافة أو خط، أو عبر ثقب أو وجه دائري، أو عند تقاطع مستويين، أو عبر نقطتين، أو عموديًا على وجه عبر نقطة. استخدمه عندما تعرف المراجع ولا تعرف الطريقة.",
|
||||
"help.construct.axis.edge": "ينشئ محورًا إنشائيًا على امتداد حافة مستقيمة أو خط رسم. استخدمه كمحور لعملية دوران أو لنمط دائري أو لمفصل.",
|
||||
"help.construct.axis.normal_to_face": "ينشئ محورًا إنشائيًا يمر بنقطة ويكون عموديًا على وجه. استخدمه كمحور يبرز مستقيمًا من السطح.",
|
||||
"help.construct.axis.through_cylinder": "ينشئ محورًا إنشائيًا عبر مركز وجه أسطوانة أو مخروط أو طارة، أو حافة دائرية. استخدمه لتدوير الميزات أو تكرارها حول قطعة مستديرة.",
|
||||
"help.construct.axis.two_planes": "ينشئ محورًا إنشائيًا عند التقاء مستويين أو وجهين مسطحين. استخدمه حين يكون المحور المطلوب هو الخط بين وجهين.",
|
||||
"help.construct.axis.two_points": "ينشئ محورًا إنشائيًا يمر بنقطتين أو رأسين أو نقطتي رسم. استخدمه لمحور يمتد بين موضعين معروفين.",
|
||||
"help.construct.plane": "ينشئ مستوى إنشائيًا بالطريقة التي تناسب ما تختاره: إزاحة عن مستوى، أو عبر نقطة، أو بين مستويين، أو عبر خطوط أو نقاط، أو مماسًا لوجه منحنٍ، أو عموديًا على مسار. استخدمه عندما تعرف المراجع ولا تعرف الطريقة.",
|
||||
"help.construct.plane.along_path": "ينشئ مستوى إنشائيًا عموديًا على حافة أو منحنى عند موضع على امتداده. استخدمه لرسم مقطع من أجل كنس أو لمقطع عرضي للمسار.",
|
||||
"help.construct.plane.at_angle": "ينشئ مستوى إنشائيًا مائلًا بزاوية عن مستوى أو وجه، حول محور أو حافة. استخدمه للرسوم المائلة، مثل حامل مائل.",
|
||||
"help.construct.plane.axis_point": "ينشئ مستوى إنشاء يحتوي على محور ونقطة خارجه. اختر محور الأصل أو محور إنشاء أو حافة مستقيمة أو خط رسم، ثم رأسًا أو نقطة رسم أو نقطة إنشاء. النقطة الواقعة على المحور لا تحدد مستوى وحيدًا.",
|
||||
@@ -1739,6 +1788,7 @@
|
||||
"help.construct.plane.tangent": "ينشئ مستوى إنشائيًا يمس أسطوانة أو مخروطًا أو كرة أو طارة عند نقطة. استخدمه للرسم على جانب قطعة مستديرة.",
|
||||
"help.construct.plane.three_points": "ينشئ مستوى إنشائيًا يمر بثلاث نقاط. استخدمه لمستوى تحدده مواضع على النموذج، مثل ثلاث زوايا.",
|
||||
"help.construct.plane.two_edges": "ينشئ مستوى إنشائيًا يمر بحافتين مستقيمتين أو خطين يقعان في مستوى واحد. استخدمه لمستوى يقطع القطعة، مثل مستوى يمر بحافتين متقابلتين.",
|
||||
"help.construct.point": "ينشئ نقطة إنشائية بالطريقة التي تناسب ما تختاره: عند رأس، أو في مركز دائرة أو كرة، أو على امتداد حافة، أو عند تقاطع خطين أو ثلاثة مستويات، أو حيث يقطع خط مستوى. استخدمه عندما تعرف المراجع ولا تعرف الطريقة.",
|
||||
"help.construct.point.along_path": "ينشئ نقطة إنشائية عند موضع على امتداد حافة أو منحنى. استخدمها كمرجع في موضع بين طرفي المسار.",
|
||||
"help.construct.point.center": "ينشئ نقطة إنشائية في مركز حافة دائرية أو دائرة رسم أو قوس أو كرة أو طارة. استخدمها كمرجع للثقوب والمحاور والمفاصل.",
|
||||
"help.construct.point.edge_plane": "ينشئ نقطة إنشائية حيث تخترق حافة أو خط مستوى أو وجهًا مسطحًا. استخدمها لتحديد موضع عبور المسار للمستوى.",
|
||||
@@ -1764,6 +1814,7 @@
|
||||
"help.file.send_to_slicer": "يحفظ الأجسام المحددة في ملف 3MF ويفتحه في برنامج التقطيع الذي تختاره. استخدمه للانتقال من النموذج إلى الطباعة بخطوة واحدة.",
|
||||
"help.font_details": "تستخدم الواجهة خطوط egui المدمجة (Ubuntu Light وHack، بموجب رخصة Ubuntu Font ورخصة MIT/Bitstream Vera، وNoto Emoji وخط أيقونات الرموز التعبيرية بموجب OFL وMIT). يستخدم نص الرسم خط Liberation Sans (SIL OFL 1.1). حزمة الخطوط الاختيارية craft-fonts لتطبيقات Crafting (BIZ UDPGothic وShippori Mincho وBIZ UDMincho وNoto Sans CJK SC وNoto Sans Arabic، بموجب SIL OFL 1.1) غير مضمّنة في إصدارات SolidCraft.",
|
||||
"help.fonts": "الخطوط",
|
||||
"help.frame.end_cap": "يغلق الأطراف المفتوحة لأعضاء الإطار بألواح على شكل محيط المقطع. استخدمه لسد الأنابيب والزوايا والعوارض، فوق الطرف أو مغروسًا فيه.",
|
||||
"help.frame.member": "يضع مقطعًا، مثل أنبوب أو قطاع ألومنيوم مبثوق، على امتداد خطوط رسم هيكل، بعنصر واحد لكل خط. استخدمه لبناء الهياكل والرفوف والمنشآت الملحومة.",
|
||||
"help.inspect.accessibility": "يلوّن الأوجه التي تستطيع أداة الوصول إليها من اتجاه واحد، وتلك التي لا تستطيع. استخدمه لفحص قطعة للتشغيل الآلي أو القولبة من ذلك الجانب.",
|
||||
"help.inspect.center_of_mass": "يعرض مركز كتلة الأجسام، كلٍّ على حدة ومجتمعةً، بكثافة منتظمة. استخدمه لفحص التوازن ومعرفة أين ستميل القطعة.",
|
||||
@@ -1890,13 +1941,13 @@
|
||||
"help.sketch.construction_line": "أنشئ خطًا إنشائيًا لا نهائيًا يمر بنقطتين. استخدمه لتخطيط الرسم دون تقسيم مقاطعه.",
|
||||
"help.sketch.construction_line.angle": "أنشئ خطًا إنشائيًا لا نهائيًا بزاوية من محور X للرسم. اختر النقطة ثم اكتب الزاوية، أو اختر اتجاهه.",
|
||||
"help.sketch.construction_line.bisector": "اختر خطين مستقيمين متقاطعين في الرسم، ثم اختر أحد منصفي الزاوية. يتبع الناتج الخطين اللذين أُنشئ منهما.",
|
||||
"help.sketch.construction_line.horizontal": "أنشئ خطًا إنشائيًا أفقيًا لا نهائيًا يمر بنقطة. يحافظ القيد الأفقي على الاتجاه بعد التعديلات.",
|
||||
"help.sketch.construction_line.parallel": "اختر خطًا مستقيمًا في الرسم ثم ضع خطًا إنشائيًا لا نهائيًا موازيًا له. انقر بزر الفأرة الأيمن لتغيير المرجع.",
|
||||
"help.sketch.construction_line.horizontal": "أنشئ خطًا إنشائيًا أفقيًا لا نهائيًا يمر بنقطة، أو أدخل بعده عن المحور X للرسم. يصبح البعد المُدخل بُعدًا قائدًا. يحافظ القيد الأفقي على الاتجاه بعد التعديلات.",
|
||||
"help.sketch.construction_line.parallel": "اختر خطًا مستقيمًا في الرسم ثم ضع خطًا إنشائيًا لا نهائيًا موازيًا له، أو أدخل إزاحته. تصبح الإزاحة المُدخلة مسافة قائدة. انقر بزر الفأرة الأيمن لتغيير المرجع.",
|
||||
"help.sketch.construction_line.perpendicular": "اختر خطًا مستقيمًا في الرسم ثم ضع خطًا إنشائيًا لا نهائيًا عموديًا عليه. انقر بزر الفأرة الأيمن لتغيير المرجع.",
|
||||
"help.sketch.construction_line.tangent_at": "أنشئ مماسًا عند نقطة على دائرة أو قوس دائري، أو عند نهاية منحنى شريحي مفتوح أو قطع مخروطي مفتوح. اختر المنحنى ثم نقطة التماس.",
|
||||
"help.sketch.construction_line.tangent_external": "اختر دائرة أو قوسًا دائريًا، ثم نقطة خارجية وحل المماس. تعرض المعاينة نقاط التماس الواقعة على القوس المرسوم فقط.",
|
||||
"help.sketch.construction_line.tangent_two": "اختر دائرتين أو قوسين دائريين ثم اختر مماسًا مشتركًا من المعاينة. يجب أن تقع نقطتا التماس على المنحنيين المرسومين.",
|
||||
"help.sketch.construction_line.vertical": "أنشئ خطًا إنشائيًا رأسيًا لا نهائيًا يمر بنقطة. يحافظ القيد الرأسي على الاتجاه بعد التعديلات.",
|
||||
"help.sketch.construction_line.vertical": "أنشئ خطًا إنشائيًا رأسيًا لا نهائيًا يمر بنقطة، أو أدخل بعده عن المحور Y للرسم. يصبح البعد المُدخل بُعدًا قائدًا. يحافظ القيد الرأسي على الاتجاه بعد التعديلات.",
|
||||
"help.sketch.copy": "ينسخ منحنيات الرسم ونقاطه المحددة مع القيود والأبعاد بينها. الصقها في هذا الرسم أو في رسم آخر.",
|
||||
"help.sketch.create": "يبدأ رسمًا ثنائي الأبعاد جديدًا على مستوى أو على وجه مسطح من النموذج. يبدأ كل بثق ودوران وكنس برسم.",
|
||||
"help.sketch.cut": "ينسخ هندسة الرسم المحددة ويحذفها من الرسم بخطوة تراجع واحدة. الصقها في مكان آخر من هذا الرسم أو في رسم آخر.",
|
||||
@@ -2240,6 +2291,9 @@
|
||||
"measure.at": "عند",
|
||||
"measure.item": "العنصر {number}",
|
||||
"measure.line_to_centre": "من الخط إلى المركز",
|
||||
"measure.perimeter": "المحيط",
|
||||
"measure.perimeter_inner": "المحيط الداخلي",
|
||||
"measure.perimeter_outer": "المحيط الخارجي",
|
||||
"measure.quick_copied": "تم نسخ القياس",
|
||||
"measure.quick_copy": "انقر لنسخ القياس",
|
||||
"measure.quick_edges": "{count} حواف",
|
||||
@@ -2281,6 +2335,8 @@
|
||||
"nav.hfss.help": "Alt مع السحب بالزر الأيسر يُزيح العرض، وShift+Alt مع الأيسر يكبّره، وCtrl مع السحب بالأيسر من مساحة فارغة يدوّره",
|
||||
"nav.inventor.help": "السحب بالزر الأوسط يُزيح العرض، وShift مع الأوسط يدوّره، وCtrl مع الأوسط يكبّره، والسحب بالأيمن يدوّره",
|
||||
"nav.maya.help": "Alt مع السحب بالزر الأيسر يدوّر العرض، وAlt مع الأوسط يُزيحه، وAlt مع الأيمن يكبّره؛ والسحب بالزر الأوسط يُزيح أيضًا",
|
||||
"nav.maya_horizontal_zoom.help": "اسحب مع Alt وزر الفأرة الأيمن: إلى اليمين للتكبير وإلى اليسار للتصغير. عطّل هذا الخيار لاستعادة التكبير بالسحب العمودي.",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: التكبير بالسحب الأفقي",
|
||||
"nav.nx.help": "السحب بالزر الأوسط يدوّر العرض، وShift مع الأوسط يُزيحه (في NX: الأوسط مع الأيمن)، وCtrl مع الأوسط يكبّره (في NX: الأوسط مع الأيسر)؛ والسحب بالأيمن لا يحرك الكاميرا",
|
||||
"nav.openscad.help": "السحب بالزر الأيسر على مساحة فارغة يدوّر العرض، وShift مع السحب بالأيسر يحدد بمربع، وسحب هندسة الرسم يعدّلها؛ والسحب بالأيمن أو الأوسط يُزيح، وShift مع السحب بالأيمن أو الأوسط يكبّر",
|
||||
"nav.orbit_cursor_wrap.help": "عندما يصل سحب التدوير إلى حافة العرض، ينتقل المؤشر إلى الحافة المقابلة ويستمر التدوير. عند الإيقاف: يتوقف السحب عند حافة الشاشة. لا تأثير له على Wayland أو داخل المتصفح.",
|
||||
@@ -2411,6 +2467,16 @@
|
||||
"not a move": "ليس تحريكًا",
|
||||
"not a number": "ليس عددًا",
|
||||
"open a sketch first": "افتح رسمًا أولًا",
|
||||
"operations.cancel": "إلغاء {name}",
|
||||
"operations.cancelled": "تم إلغاء {name}",
|
||||
"operations.cancelling": "جارٍ الإلغاء…",
|
||||
"operations.cannot_cancel": "لا يمكن إلغاء {name}",
|
||||
"operations.feature": "ميزة",
|
||||
"operations.feature_edit": "تحرير الميزة",
|
||||
"operations.meshing": "جارٍ تحميل الأجزاء",
|
||||
"operations.queued": "في الانتظار",
|
||||
"operations.stopped": "أُلغي",
|
||||
"operations.waiting": "جاهز",
|
||||
"parameters.apply_live": "تطبيق كل تغيير عند مغادرة حقله",
|
||||
"parameters.apply_live_tip": "عند الإيقاف: تنتظر التغييرات حتى «تطبيق» أو «موافق»، ثم يُعاد بناء التصميم مرة واحدة لها جميعًا. «إلغاء» أو Escape يلغيها.",
|
||||
"parameters.held": "{count} تغييرات بانتظار «تطبيق»",
|
||||
@@ -2499,6 +2565,7 @@
|
||||
"prefs.appearance.viewport_colours": "ألوان العرض ثلاثي الأبعاد",
|
||||
"prefs.appearance.viewport_logo": "منطقة العرض والشعار",
|
||||
"prefs.applies_on_restart": "يُطبَّق عند إعادة التشغيل",
|
||||
"prefs.assemblies": "التجميعات",
|
||||
"prefs.assistant": "المساعد",
|
||||
"prefs.assistant_connecting": "الاتصال",
|
||||
"prefs.assistant_follow_help": "النظر إلى الرسومات يحرّك العرض مع المؤشر.",
|
||||
@@ -2551,6 +2618,10 @@
|
||||
"prefs.choose_font": "اختيار ملف خط…",
|
||||
"prefs.click": "نقر",
|
||||
"prefs.command_dialog_values": "مربعات حوار الأوامر",
|
||||
"prefs.constraint_glyph_size": "حجم رموز القيود",
|
||||
"prefs.constraint_glyph_size_note": "حجم رسم رموز القيود وحروفها أو أيقوناتها في الرسم. 100% هو الحجم المعتاد؛ وتحتفظ الرموز بهذا الحجم على الشاشة عند أي مستوى تكبير.",
|
||||
"prefs.construct_menu_groups": "تجميع أدوات الإنشاء حسب نوع العنصر",
|
||||
"prefs.construct_menu_groups_help": "إظهار عناوين المستويات والمحاور والنقاط. يحافظ التعطيل على ترتيب القائمة الأصلي.",
|
||||
"prefs.contact_shading": "تظليل التلامس الناعم",
|
||||
"prefs.contact_shading_note": "تظليل ناعم حيث تقترب القطع من بعضها.",
|
||||
"prefs.context_menu": "القائمة السياقية",
|
||||
@@ -2586,6 +2657,8 @@
|
||||
"prefs.design_tools.rows": "صفوف",
|
||||
"prefs.devices": "الفأرة ثلاثية الأبعاد",
|
||||
"prefs.dialog_buttons": "أزرار مربعات الحوار",
|
||||
"prefs.dialog_first_letter_buttons": "أزرار نوافذ الحوار تستجيب لحرفها الأول",
|
||||
"prefs.dialog_first_letter_buttons_help": "عند فتح نافذة حوار، كتابة الحرف الأول من تسمية الزر تضغطه: حرف «ا» يضغط زر «إلغاء» مثلًا. الحرف الذي يناسب زرَّين لا يفعل شيئًا، وحقل النص المركَّز عليه يحتفظ بالتضغطة. عند الإيقاف: الكتابة لا تفعل شيئًا للأزرار، كما كان سابقًا.",
|
||||
"prefs.dialogs": "الحوارات",
|
||||
"prefs.dialogs_edge": "عند حافة العرض",
|
||||
"prefs.dialogs_left_column": "في العمود الأيسر",
|
||||
@@ -2599,12 +2672,23 @@
|
||||
"prefs.dimension_values_window": "في نافذة",
|
||||
"prefs.display": "العرض",
|
||||
"prefs.edges": "الحواف والتظليل",
|
||||
"prefs.export": "التصدير",
|
||||
"prefs.export_name": "اسم ملف التصدير",
|
||||
"prefs.export_name.body": "اسم الجسم المُصدَّر (الأول إن تعددت الأجسام)",
|
||||
"prefs.export_name.design": "اسم التصميم",
|
||||
"prefs.export_name_hint": "مثلًا {design}-{body}",
|
||||
"prefs.export_name_sample": "تصدير هذا التصميم يقترح: {name}",
|
||||
"prefs.export_name_tip": "اسم الملف الذي يقترحه «ملف › تصدير» و«حفظ كشبكة». تُستبدل هذه العناصر النائبة:\n{placeholders}\nتُحذف خاصية التصميم غير المعيّنة. اترك الحقل فارغًا لاقتراح اسم التصميم، أو اسم الجسم للشبكة.",
|
||||
"prefs.extend": "توسيع",
|
||||
"prefs.extra_navigation": "Ctrl مع السحب بالزر الأيسر في مساحة فارغة يدوّر العرض، واضغط مطولًا على Space للإزاحة.",
|
||||
"prefs.extrude_arrow_face_stops": "يتوقف سهم البثق عند الأوجه",
|
||||
"prefs.extrude_arrow_face_stops_note": "عند سحب سهم مسافة البثق يتوقف عند الأوجه المستوية الموازية للمقطع، مثل الجانب البعيد من كتلة يجري قطعها، ويحدد الوجه. عند الإيقاف: يتحرك السهم بخطوات مستديرة فقط.",
|
||||
"prefs.extrude_view_isometric": "التحويل إلى العرض المتساوي القياس عند فتح البثق",
|
||||
"prefs.extrude_view_return": "العودة إلى العرض السابق عند إغلاق البثق",
|
||||
"prefs.file_operations_wait": "انتظار فتح الملفات",
|
||||
"prefs.file_operations_wait_note": "أثناء فتح ملف أو إدراجه أو إعادة قراءة الروابط، ينتظر التصميم خلف بطاقة تعرض التقدم وزر الإلغاء. عند الإيقاف: يظهر الملف في لوحة العمليات ويمكنك متابعة العمل؛ يُطبَّق الإدراج بعد أن تنتهي مما تفعله، ويُفتح الملف المفتوح في الأثناء في علامة تبويب جديدة.",
|
||||
"prefs.fillet_legacy_radius": "استخدام نصف القطر الافتراضي السابق للتقويس المصمت",
|
||||
"prefs.fillet_legacy_radius.help": "معطّل افتراضيًا. عند التفعيل، يفتح التقويس المصمت الجديد على الرقم 2 مقروءًا بوحدات التصميم («2 بوصة» في تصميم بالبوصة)، كما كان سابقًا؛ وعند الإيقاف، يفتح على نصف القطر الافتراضي للأداة، 2 مم، معروضًا بوحدات التصميم («0.07874 بوصة» في تصميم بالبوصة).",
|
||||
"prefs.follows_os": "يتبع النظام",
|
||||
"prefs.font": "الخط",
|
||||
"prefs.font_fallback": "الرموز التي يفتقدها الخط المختار تُرسم بالخط المدمج، فلا تظهر أي تسمية كمربع فارغ.",
|
||||
@@ -2628,6 +2712,17 @@
|
||||
"prefs.gesture_pan": "إزاحة العرض",
|
||||
"prefs.gesture_zoom": "تكبير",
|
||||
"prefs.graphics": "الرسوميات",
|
||||
"prefs.graphics_api": "واجهة برمجة تطبيقات الرسوميات",
|
||||
"prefs.graphics_api_auto": "تلقائي",
|
||||
"prefs.graphics_api_help": "اختر واجهة الرسوميات المستخدمة لفتح SolidCraft. إذا تعذّر فتح النافذة عند التشغيل التالي، فستُستعاد السابقة.",
|
||||
"prefs.graphics_api_override": "يتحكم إعداد عند التشغيل في واجهة الرسوميات. سيُطبّق الاختيار المحفوظ عند فتح SolidCraft بالطريقة العادية.",
|
||||
"prefs.graphics_api_restart_note": "يُطبّق بعد إعادة التشغيل. تُعالَج التصاميم غير المحفوظة قبل الإغلاق.",
|
||||
"prefs.graphics_api_restart_unavailable": "أعد تشغيل SolidCraft لتطبيق واجهة الرسوميات المحفوظة.",
|
||||
"prefs.graphics_api_running": "الحالية: {current}. المختارة للتشغيل التالي: {selected}.",
|
||||
"prefs.graphics_api_save_failed": "تعذّر حفظ اختيار واجهة الرسوميات: {error}",
|
||||
"prefs.graphics_api_start_failed": "تعذّر تجهيز واجهة الرسوميات المختارة: {error}",
|
||||
"prefs.graphics_api_start_reverted": "لم يفتح التشغيل السابق باستخدام {requested} النافذة. استعاد SolidCraft الاختيار {previous}.",
|
||||
"prefs.graphics_api_unavailable": "اختيار واجهة الرسوميات متاح في تطبيق سطح المكتب.",
|
||||
"prefs.graphics_card": "بطاقة الرسوميات",
|
||||
"prefs.graphics_card_auto": "تلقائي",
|
||||
"prefs.graphics_card_missing": "بطاقة الرسوميات المحفوظة غير متاحة؛ يُستخدم الخيار «تلقائي».",
|
||||
@@ -2671,6 +2766,8 @@
|
||||
"prefs.history_sketches_in_order": "بالترتيب",
|
||||
"prefs.history_sketches_note": "عند ضبط الرسومات على «تحت ميزتها»، يعرض السجل على اليسار كل رسم بمستوى واحد للداخل، تحت أول ميزة بُنيت منه، متى كان عريضًا بما يكفي لإظهار الأسماء. أما الخط الزمني في الأسفل فيحتفظ دائمًا بترتيب الإنشاء.",
|
||||
"prefs.history_sketches_under_feature": "تحت ميزتها",
|
||||
"prefs.history_steps_component": "خطوات السجل حسب المكوّن",
|
||||
"prefs.history_steps_component_note": "عندما يكون مكوّن نشطًا أو محددًا، تتنقل عناصر تحكم السجل بين ميزات ذلك المكوّن كما يعرضها السجل في الأسفل. عند إيقافه تتنقل بين كل ميزات التصميم. السجل على اليسار أو تحت المستعرض يتنقل دائمًا بين كل الميزات.",
|
||||
"prefs.hold_stop_snapping": "اضغط مطولًا لإيقاف الالتقاط",
|
||||
"prefs.home_fit_size": "حجم العرض الرئيسي والملاءمة",
|
||||
"prefs.home_fit_size_note": "مقدار ما يملؤه النموذج من العرض عندما يُظهره العرض الرئيسي أو الملاءمة أو تصميم مفتوح أو تغيير العرض من متصفح العرض، سواء كان الإعداد أدناه مفعّلًا أم لا. 100 %: يملأ العرض بين اللوحات والبوصلة وشريط التنقل.",
|
||||
@@ -2686,6 +2783,8 @@
|
||||
"prefs.invert_curved_roll_arrows_note": "سهما التدوير المنحنيان عند زاوية المكعب يدوران العرض داخل مستوى الشاشة. عند التشغيل: سهم التدوير مع عقارب الساعة يدور عكسها، وسهم العكس يدور معها. عند الإيقاف: يدور كل سهم بالعرض حسب انحنائه.",
|
||||
"prefs.invert_navigator_arrows": "عكس أسهم تدوير مكعب العرض",
|
||||
"prefs.invert_navigator_arrows_note": "تدوّر الأسهم المحيطة بالمكعب الكاميرا في الاتجاه الذي تشير إليه، كما في Fusion وInventor: السهم الموجود على اليسار يشير إلى اليمين ويدوّر الكاميرا إلى اليمين. عند الإيقاف: يدوّر السهم المكعب نحو الجهة التي يقع فيها، فيدوّر السهم الأيسر الكاميرا إلى اليسار. لا يتأثر سهما الدوران المنحنيان.",
|
||||
"prefs.joint_drag_trackball": "تدوير الأجزاء على مفصل كروي مثل كرة التتبع عند سحبها",
|
||||
"prefs.joint_drag_trackball_help": "سحب جزء يثبّته مفصل كروي يدوّره بأصغر دوران حول المفصل، كأنك تدحرج كرة بحجم الجزء. عند الإيقاف: تتبع النقطة التي أمسكتها المؤشر تمامًا، وقد يدور الجزء أيضًا حولها.",
|
||||
"prefs.keep_unsaved_also_asks": "السؤال أيضًا عند إغلاق علامة التبويب",
|
||||
"prefs.keep_unsaved_also_asks_tip": "عند إيقاف هذا الخيار، تُغلق علامة التبويب دون مربع حوار المتصفح بعد تحديث نسخة كل تصميم غير محفوظ.",
|
||||
"prefs.keep_unsaved_in_browser": "الاحتفاظ بالعمل غير المحفوظ في هذا المتصفح",
|
||||
@@ -2761,6 +2860,8 @@
|
||||
"prefs.not_on_gpu": "غير متاح على هذا المعالج الرسومي",
|
||||
"prefs.on": "تشغيل",
|
||||
"prefs.opaque": "معتم",
|
||||
"prefs.operations_panel": "إظهار العمليات في العرض",
|
||||
"prefs.operations_panel_note": "تظهر العمليات الطويلة (فتح ملف، حساب ميزة، أمر من وكيل) في الزاوية السفلية اليمنى من العرض مع تقدّمها وزر لإلغائها. عند الإيقاف: إشعار «جارٍ الحساب» كما كان من قبل.",
|
||||
"prefs.orbit_snap": "اضغط Shift أثناء التدوير للالتقاط على محور.",
|
||||
"prefs.orientation": "الاتجاه",
|
||||
"prefs.origin_plane_names": "أسماء مستويات الأصل",
|
||||
@@ -2841,6 +2942,8 @@
|
||||
"prefs.ribbon_tabs_only": "إظهار علامات تبويب الشريط فقط",
|
||||
"prefs.ribbon_tabs_only_note": "يُطوى الشريط إلى صف علامات التبويب. يؤدي النقر على علامة تبويب إلى إظهار لوحاتها فوق منطقة العرض حتى يبدأ أمر أو يغادرها المؤشر. يبدّل الأمر «علامات تبويب الشريط فقط» في تبويب العرض، أو اختصاره، هذا الخيار.",
|
||||
"prefs.right_click": "نقر أيمن",
|
||||
"prefs.save_prompt_one_at_a_time": "السؤال عن كل تصميم غير محفوظ على حدة عند إغلاق عدة تصاميم",
|
||||
"prefs.save_prompt_one_at_a_time_help": "عرض نافذة حفظ لكل تصميم غير محفوظ بدلًا من قائمة مجمّعة.",
|
||||
"prefs.saving": "البدء والحفظ",
|
||||
"prefs.scale_note": "أو Ctrl + / Ctrl − في النافذة. الأزرار 28 px عند 100%.",
|
||||
"prefs.scale_text": "الحجم والنص",
|
||||
@@ -2877,6 +2980,8 @@
|
||||
"prefs.sketch.center_arc": "القوس بنقطة مركز يتبع المؤشر",
|
||||
"prefs.sketch.click_selects": "النقر يحدد",
|
||||
"prefs.sketch.conflict_colour": "لون التعارض",
|
||||
"prefs.sketch.cursor_coordinates": "إظهار إحداثيات المؤشر في الرسم",
|
||||
"prefs.sketch.cursor_coordinates_note": "بجانب المؤشر، قيمتا X وY من أصل الرسم، حتى دون تشغيل أي أداة. عند الإيقاف: فقط عندما تضع أداةٌ نقطة.",
|
||||
"prefs.sketch.drawing": "الرسم",
|
||||
"prefs.sketch.ellipse_axes": "رسم القطوع الناقصة مع محاورها",
|
||||
"prefs.sketch.ellipse_axes_note": "المحوران الأكبر والأصغر كخطوط مساعدة، لتحديد أبعاد أنصاف المحاور والمحاور. عند الإيقاف: القطع الناقص وحده، ويعطي D عليه نصف قطره الأصغر أينما سُحبت القيمة، مرسومًا ومُعلَّمًا بـ R كما في السابق.",
|
||||
@@ -2888,14 +2993,20 @@
|
||||
"prefs.sketch.faces_edges": "الأوجه والحواف",
|
||||
"prefs.sketch.hide_glyphs": "إخفاء الرموز عند التصغير",
|
||||
"prefs.sketch.marks": "العلامات في الرسم",
|
||||
"prefs.sketch.max_points": "أكبر حجم للرسم",
|
||||
"prefs.sketch.max_points_note": "أكبر عدد من النقاط أو المنحنيات في رسم واحد: 20000 افتراضيًا، و200000 كحد أقصى. يرفض «إدراج SVG» و«إدراج DXF» رسمًا أكبر. الرسم الكبير يُحل ويُعرض بشكل أبطأ.",
|
||||
"prefs.sketch.max_points_unit": "نقطة",
|
||||
"prefs.sketch.note": "الرسم والالتقاط والتحديد.",
|
||||
"prefs.sketch.opening_closing": "الفتح والإغلاق",
|
||||
"prefs.sketch.prefer_free_points": "تفضيل النقاط القابلة للتحريك عند تداخلها",
|
||||
"prefs.sketch.project_options": "السؤال عن خيارات الإسقاط أولًا",
|
||||
"prefs.sketch.recent_snap": "الالتقاط عند تقاطع دليلين",
|
||||
"prefs.sketch.select_3d_curve_points": "تحديد نقاط منحنيات الرسم ثلاثي الأبعاد",
|
||||
"prefs.sketch.select_3d_curve_points_help": "إظهار نقاط منحنيات الرسم ثلاثي الأبعاد المرسومة وتحديدها كمراجع للإنشاء.",
|
||||
"prefs.sketch.select_other_hidden": "تحديد آخر يشمل الهندسة المخفية",
|
||||
"prefs.sketch.shortcut_cycles_modes": "الاختصار مجددًا يبدّل الوضع",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "عند الإيقاف: تبدأ الأداة مجددًا.",
|
||||
"prefs.sketch.snap_to_visible_grid": "الالتقاط عند تقاطع الشبكة المرئي",
|
||||
"prefs.sketch.snapping_guides": "الالتقاط والأدلة",
|
||||
"prefs.sketch.state_icons": "أيقونات الحالة",
|
||||
"prefs.sketch.tracking_guides": "أدلة المراكز ونقاط المنتصف",
|
||||
@@ -2923,6 +3034,7 @@
|
||||
"prefs.sketch_selection": "الرسم والتحديد",
|
||||
"prefs.sketch_selection_heading": "الرسم والتحديد",
|
||||
"prefs.sketch_selection_note": "كيف تلتقط الرسومات وكيف تحدد النقرات.",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "تلتصق النقطة في الرسم عند تقاطع الخطوط التي ترسمها الشبكة عندما يشير المؤشر إلى أحدها، وإلا تلتصق بالشبكة الأدق بينها. عند الإيقاف: تلتصق النقطة بالشبكة الأدق فقط، كما كان.",
|
||||
"prefs.sketch_state_icons": "أيقونات الرسومات بلون حالتها",
|
||||
"prefs.sketch_state_icons_note": "في السجل والمستعرض، تأخذ أيقونة الرسم لون حالته (قيود ناقصة، مقيّد بالكامل أو متعارض) ويذكر تلميحه الحالة. عند الإيقاف: لكل الرسومات الأيقونة نفسها.",
|
||||
"prefs.sketch_tab_always": "إبقاء تبويب الرسم ظاهرًا",
|
||||
@@ -3224,10 +3336,10 @@
|
||||
"render.category_paint": "طلاء",
|
||||
"render.category_plastic": "بلاستيك",
|
||||
"render.category_wood": "خشب",
|
||||
"render.caustics_area_lights": "تأثيرات الضوء المركّز من الأضواء المساحية",
|
||||
"render.caustics_area_lights": "تجمّع الضوء من الأضواء المساحية",
|
||||
"render.caustics_depth": "عمق مسار تجمّع الضوء",
|
||||
"render.caustics_enable": "تجمّع الضوء عبر الزجاج من مصادر نقطية واتجاهية",
|
||||
"render.caustics_environment": "تأثيرات الضوء المركّز من البيئة",
|
||||
"render.caustics_environment": "تجمّع الضوء من البيئة",
|
||||
"render.caustics_help": "يتحكم عدد الفوتونات في الضجيج وكلفة الحساب. يوازن نصف قطر التجميع بين التفاصيل الدقيقة والتقدير الأنعم. يتطلب CPU إضاءة غير مباشرة.",
|
||||
"render.caustics_path_required": "يتطلب تجمّع الضوء على CPU إضاءة غير مباشرة.",
|
||||
"render.caustics_photons": "عدد الفوتونات",
|
||||
@@ -3235,7 +3347,7 @@
|
||||
"render.check_glass_cpu": "يدعم CPU صفائح زجاج مستوية وصناديق محاذية للمحاور بعد التحقق منها. تتطلب الشبكات المغلقة العامة والتعشيق والتشتت الداخلي إضاءة غير مباشرة. لا تزال الظلال النافذة عبر الزجاج المغلق غير مدعومة.",
|
||||
"render.check_glass_gpu": "يدعم GPU أوساط زجاج منفصلة متحققًا منها، أو تعشيقًا متحققًا منه عند تفعيله صراحةً. يتطلب التعشيق أغلفة خارجية محدبة وأجسامًا داخلية محتواة بالكامل وحدودًا غير متلامسة.",
|
||||
"render.check_media_remaining": "لا تزال شبكات الكثافة والإزاحة والتكامل الطيفي الكامل ونقل حالة الاستقطاب غير متاحة.",
|
||||
"render.check_media_scope": "يتطلب التشتت الداخلي النشط وسطًا زجاجيًا مغلقًا مع إيقاف نفاذ أشعة الظل المستقيمة وإزالة الضجيج. ويتطلب GPU أيضًا طبقة عينات فرينل واحدة. لا يمكن جمع الغلاف الجوي الخارجي النشط مع الزجاج أو إزالة ضجيج الأسطح.",
|
||||
"render.check_media_scope": "يتطلب التشتت الداخلي النشط وسطًا زجاجيًا مغلقًا مع إيقاف نفاذ أشعة الظل المستقيمة وإزالة التشويش. ويتطلب GPU أيضًا طبقة عينات فرينل واحدة. لا يمكن جمع الغلاف الجوي الخارجي النشط مع الزجاج أو إزالة تشويش الأسطح.",
|
||||
"render.check_opaque": "الشفافية: أسطح معتمة فقط؛ ألفا الخلفية مدعومة.",
|
||||
"render.check_sorted_alpha": "الشفافية: تقريب ألفا مرتّب.",
|
||||
"render.check_transmission": "الشفافية: نفاذية فيزيائية.",
|
||||
@@ -3441,8 +3553,8 @@
|
||||
"render.cpu_studio_enable_apply": "تفعيل الإضاءة غير المباشرة وتطبيقها",
|
||||
"render.cpu_studio_indirect_help": "يحتاج توزيع الشمس هذا إلى إضاءة غير مباشرة بعمق 8 وظلال متتبعة وعينة كاميرا واحدة لكل مرور. إذا كان التصيير التدريجي معطلًا، يبدأ بـ 16 عينة لكل بكسل وبذرة 0. تُحفظ الإعدادات التدريجية الحالية وملف الموارد. تمنع الإعدادات غير المتوافقة التطبيق دون تغييرها.",
|
||||
"render.cpu_studio_radiance_limit": "سطوع المصدر المساحي في هذا التوزيع هو {radiance}، ويتجاوز حد CPU البالغ 64. تُحفظ الإضاءة المؤلَّفة؛ اختر توزيعًا آخر أو GPU.",
|
||||
"render.cpu_subsurface_denoise_reason": "يتطلب التشتت داخل الزجاج على CPU إيقاف إزالة الضجيج. تبقى إعداداتك محفوظة.",
|
||||
"render.cpu_subsurface_help": "يغيّر التشتت اتجاه الضوء داخل الزجاج المغلق. تتطلب المعدلات الموجبة إضاءة غير مباشرة مع إيقاف إزالة الضجيج. المعدل هو عدد التصادمات لكل مم؛ لا يضيف الصفر أي تشتت. يفضّل انحياز الاتجاه الموجب الأمام، والسالب الخلف.",
|
||||
"render.cpu_subsurface_denoise_reason": "يتطلب التشتت داخل الزجاج على CPU إيقاف إزالة التشويش. تبقى إعداداتك محفوظة.",
|
||||
"render.cpu_subsurface_help": "يغيّر التشتت اتجاه الضوء داخل الزجاج المغلق. تتطلب المعدلات الموجبة إضاءة غير مباشرة مع إيقاف إزالة التشويش. المعدل هو عدد التصادمات لكل مم؛ لا يضيف الصفر أي تشتت. يفضّل انحياز الاتجاه الموجب الأمام، والسالب الخلف.",
|
||||
"render.cpu_summary": "تتبع الأشعة على CPU · انعكاسات · HDR · أضواء اتجاهية ونقطية",
|
||||
"render.cpu_threads": "خيوط المعالجة",
|
||||
"render.cpu_threads_auto": "تلقائي",
|
||||
@@ -3458,40 +3570,40 @@
|
||||
"render.cpu_volume_method_incompatible": "لا يمكن نقل إعدادات الإضاءة أو أخذ العينات أو الغلاف الجوي هذه إلى هذه الطريقة. تبقى إعداداتك محفوظة.",
|
||||
"render.cpu_volume_path_required": "فعّل الإضاءة غير المباشرة لاستخدام الغلاف الجوي على CPU.",
|
||||
"render.cpu_warm_cool": "دافئ وبارد",
|
||||
"render.denoise_class_background": "متجاوز: خلفية",
|
||||
"render.denoise_class_coverage": "متجاوز: تغطية جزئية",
|
||||
"render.denoise_class_degenerate": "متجاوز: مسار متدهور",
|
||||
"render.denoise_class_depth": "متجاوز: حد عمق المسار",
|
||||
"render.denoise_class_emitter": "متجاوز: مصدر ضوء",
|
||||
"render.denoise_class_exit": "متجاوز: خروج غير متوافق",
|
||||
"render.denoise_class_identity": "متجاوز: حد هوية الدليل",
|
||||
"render.denoise_class_lens": "متجاوز: عمق المجال",
|
||||
"render.denoise_class_material": "متجاوز: مادة غير مدعومة",
|
||||
"render.denoise_class_nested": "متجاوز: وسط متداخل",
|
||||
"render.denoise_class_optical": "مؤهل: سطح عبر انكسار",
|
||||
"render.denoise_class_reflection": "متجاوز: نهاية عاكسة",
|
||||
"render.denoise_class_background": "مستبعد: خلفية",
|
||||
"render.denoise_class_coverage": "مستبعد: تغطية جزئية",
|
||||
"render.denoise_class_degenerate": "مستبعد: مسار منحلّ",
|
||||
"render.denoise_class_depth": "مستبعد: حد عمق المسار",
|
||||
"render.denoise_class_emitter": "مستبعد: مصدر ضوء",
|
||||
"render.denoise_class_exit": "مستبعد: خروج غير متوافق",
|
||||
"render.denoise_class_identity": "مستبعد: حد هوية الدليل",
|
||||
"render.denoise_class_lens": "مستبعد: عمق المجال",
|
||||
"render.denoise_class_material": "مستبعد: مادة غير مدعومة",
|
||||
"render.denoise_class_nested": "مستبعد: وسط متداخل",
|
||||
"render.denoise_class_optical": "مؤهل: سطح مرئي عبر الانكسار",
|
||||
"render.denoise_class_reflection": "مستبعد: نهاية عاكسة",
|
||||
"render.denoise_class_surface": "مؤهل: سطح",
|
||||
"render.denoise_class_tir": "متجاوز: انعكاس داخلي كلي",
|
||||
"render.denoise_class_transmission": "متجاوز: نفاذ إضافي",
|
||||
"render.denoise_class_unavailable": "متجاوز: بلا دليل",
|
||||
"render.denoise_class_volume": "متجاوز: تشتت حجمي",
|
||||
"render.denoise_diagnostics_counts": "المؤهلة: {eligible} · المتجاوزة: {skipped}",
|
||||
"render.denoise_diagnostics_enable": "جمع تشخيصات إزالة الضوضاء",
|
||||
"render.denoise_class_tir": "مستبعد: انعكاس داخلي كلي",
|
||||
"render.denoise_class_transmission": "مستبعد: نفاذ إضافي",
|
||||
"render.denoise_class_unavailable": "مستبعد: بلا دليل",
|
||||
"render.denoise_class_volume": "مستبعد: تشتت حجمي",
|
||||
"render.denoise_diagnostics_counts": "المؤهلة: {eligible} · المستبعدة: {skipped}",
|
||||
"render.denoise_diagnostics_enable": "جمع تشخيصات إزالة التشويش",
|
||||
"render.denoise_diagnostics_grid": "أعداد البكسلات بالحجم الداخلي {width} × {height}.",
|
||||
"render.denoise_diagnostics_help": "يجمع أعداد البكسلات المؤهلة والمتجاوزة حتى عند إيقاف إزالة الضوضاء. تعتمد الأعداد على حجم التصيير الداخلي، ويعتمد القناع على حجم الإخراج.",
|
||||
"render.denoise_diagnostics_title": "تشخيصات إزالة الضوضاء",
|
||||
"render.denoise_diagnostics_help": "يجمع أعداد البكسلات المؤهلة والمستبعدة حتى عند إيقاف إزالة التشويش. تعتمد الأعداد على حجم التصيير الداخلي، ويعتمد القناع على حجم الإخراج.",
|
||||
"render.denoise_diagnostics_title": "تشخيصات إزالة التشويش",
|
||||
"render.denoise_export_mask": "تصدير القناع بصيغة PNG",
|
||||
"render.denoise_firefly": "تقليل البكسلات الساطعة المعزولة",
|
||||
"render.denoise_format_mask": "قناع PNG",
|
||||
"render.denoise_mask_copy_help": "صدّر قناع إزالة الضوضاء بصيغة PNG، أو عُد إلى الصورة المصيّرة لنسخها.",
|
||||
"render.denoise_mask_unavailable": "فعّل تشخيصات إزالة الضوضاء وصيّر صورة لفحص قناعها.",
|
||||
"render.denoise_optical_filter": "تصفية المرايا والزجاج",
|
||||
"render.denoise_optical_filter_help": "تصفية الضوء المنعكس والنافذ المؤهّل. أوقف هذا الخيار لإزالة الضجيج من الأسطح المعتمة فقط.",
|
||||
"render.denoise_passes": "مرات الترشيح",
|
||||
"render.denoise_settings_help": "تُنعّم مرات الترشيح الإضافية مساحة أوسع. تحدد القوة مقدار الترشيح المطبّق في كل مرة. تبقى المسارات البصرية غير المدعومة دون ترشيح.",
|
||||
"render.denoise_strength": "قوة إزالة الضوضاء",
|
||||
"render.denoise_mask_copy_help": "صدّر قناع إزالة التشويش بصيغة PNG، أو عُد إلى الصورة المصيّرة لنسخها.",
|
||||
"render.denoise_mask_unavailable": "فعّل تشخيصات إزالة التشويش وصيّر صورة لفحص قناعها.",
|
||||
"render.denoise_optical_filter": "ترشيح المرايا والزجاج",
|
||||
"render.denoise_optical_filter_help": "يرشّح الضوء المنعكس والنافذ المؤهّل. أوقف هذا الخيار لإزالة التشويش من الأسطح المعتمة فقط.",
|
||||
"render.denoise_passes": "تمريرات الترشيح",
|
||||
"render.denoise_settings_help": "تُنعّم تمريرات الترشيح الإضافية مساحة أوسع. تحدد القوة مقدار الترشيح الذي يطبّقه كل تمرير. تبقى المسارات البصرية غير المدعومة دون ترشيح.",
|
||||
"render.denoise_strength": "قوة إزالة التشويش",
|
||||
"render.denoise_view_image": "الصورة المصيّرة",
|
||||
"render.denoise_view_mask": "قناع إزالة الضوضاء",
|
||||
"render.denoise_view_mask": "قناع إزالة التشويش",
|
||||
"render.diag_bodies": "الأجسام المرئية",
|
||||
"render.diag_job_details": "تفاصيل المهمة الملتقطة",
|
||||
"render.diag_last_check": "آخر فحص مسبق",
|
||||
@@ -3624,6 +3736,7 @@
|
||||
"render.error_pbr_opacity": "PBR المعتم يتطلب عتامة 1",
|
||||
"render.error_physical_glass": "الوصفة المحددة ليست زجاجًا فيزيائيًا",
|
||||
"render.error_preview_device": "معاينة المنتج تتطلب جهازًا مثبّتًا بمخزن عمق",
|
||||
"render.error_product_placement": "موضع منتج غير صالح",
|
||||
"render.error_product_triangle": "مثلث منتج غير صالح",
|
||||
"render.error_provisional_identity": "هوية تصيير مؤقتة أو عدد عينات غير صالح",
|
||||
"render.error_quality_bounds": "إسقاط الجودة يتجاوز الحدود الأصلية",
|
||||
@@ -3707,6 +3820,10 @@
|
||||
"render.gpu_path_retry": "حاول مرة أخرى",
|
||||
"render.gpu_seed": "البذرة العشوائية",
|
||||
"render.gpu_unavailable": "تتبع المسارات على GPU غير جاهز على هذا الجهاز.",
|
||||
"render.graphics_api_restart_vulkan": "إعادة التشغيل باستخدام Vulkan",
|
||||
"render.graphics_api_restart_warning": "يؤدي تغيير واجهة الرسوميات إلى إعادة تشغيل SolidCraft ويطلب منك حفظ التصاميم غير المحفوظة. إذا تعذّر فتح النافذة بالواجهة الجديدة، فسيُستعاد الاختيار السابق عند التشغيل التالي.",
|
||||
"render.graphics_api_settings": "إعدادات الرسوميات",
|
||||
"render.graphics_api_vulkan_required": "يتطلب تتبّع المسارات بمعالج الرسوميات Vulkan في هذه الجلسة. أعد التشغيل باستخدام Vulkan، أو واصل استخدام طريقة صور بمعالج CPU.",
|
||||
"render.ground_apply": "ملاءمة الأرضية وحفظها",
|
||||
"render.ground_gap": "فجوة خلوص صريحة",
|
||||
"render.ground_linear_rgb": "الانعكاسية المنتشرة · RGB خطي",
|
||||
@@ -4047,7 +4164,7 @@
|
||||
"render.material_v_up": "اتجاه V للنسيج يشير للأعلى في الصورة",
|
||||
"render.material_weight": "وزن الطبقة (0–1)",
|
||||
"render.metal_energy_compensation": "استعادة انعكاس المعادن الخشنة",
|
||||
"render.metal_energy_compensation_help": "عوّض الضوء الذي تفقده الأسطح المعدنية الخشنة بين أوجهها المجهرية. يتطلب معالج CPU إضاءة غير مباشرة.",
|
||||
"render.metal_energy_compensation_help": "عوّض الضوء المفقود بين الأوجه المجهرية للمعادن الخشنة. يتطلب التصيير على CPU إضاءة غير مباشرة.",
|
||||
"render.method_cpu": "تتبع الأشعة على CPU",
|
||||
"render.method_gpu": "تتبع المسارات على GPU",
|
||||
"render.method_limit_raster": "التنقيط يستخدم معاينة الاستوديو المعتمة الثابتة. اختر طريقة تتبع أشعة صريحة لعناصر التحكم البصرية المدعومة.",
|
||||
@@ -4507,7 +4624,7 @@
|
||||
"render.surface_import.source": "المصدر",
|
||||
"render.surface_import.title": "استيراد صورة",
|
||||
"render.texture_filtering": "ترشيح تفاصيل الخامات",
|
||||
"render.texture_filtering_help": "استخدم مستويات التفاصيل والترشيح المتباين لتقليل تعرّج الخامات عند التصغير. يزيد استهلاك الذاكرة؛ يبقى الوضع القديم معطّلاً.",
|
||||
"render.texture_filtering_help": "استخدم مستويات MIP والترشيح متباين الخواص لتقليل تعرّج الخامات عند التصغير. يستهلك ذاكرة أكبر؛ وعند إيقافه يبقى الترشيح السابق.",
|
||||
"render.tone_aces_fitted": "ACES مُلاءَم",
|
||||
"render.tone_reinhard": "راينهارد",
|
||||
"render.transmission_scope": "يدعم زجاج GPU الأوساط المنفصلة المعتمدة. لا تتوفر الأوساط المتداخلة غير المقيدة ولا مقدّر نفاذ خالٍ من التشويش.",
|
||||
@@ -4552,7 +4669,7 @@
|
||||
"render.use_preview": "استخدام المعاينة المدمجة",
|
||||
"render.volume_albedo": "بياض التشتت · RGB خطي",
|
||||
"render.volume_anisotropy": "متوسط جيب تمام الطور",
|
||||
"render.volume_denoise_required": "أوقف تقليل الضوضاء لاستخدام الغلاف الجوي.",
|
||||
"render.volume_denoise_required": "أوقف تقليل التشويش لاستخدام الغلاف الجوي.",
|
||||
"render.volume_enable": "تفعيل الوسط المشارك",
|
||||
"render.volume_extinction": "معامل الإخماد",
|
||||
"render.volume_glass_required": "لا يمكن الجمع بين الغلاف الجوي والزجاج في هذا الإعداد.",
|
||||
@@ -4708,6 +4825,8 @@
|
||||
"sketch.hint.spline3d": "منحنى شريحي ثلاثي الأبعاد: انقر نقاط الملاءمة في الفضاء ثلاثي الأبعاد؛ انقر بالزر الأيمن أو اضغط Esc للإنهاء",
|
||||
"sketch.hint.trim": "قص: انقر على الجزء المراد إزالته من المنحنى، أو اسحب عبر الأجزاء المراد إزالتها",
|
||||
"sketch.make_selection": "تحويل التحديد إلى {linetype}",
|
||||
"sketch.move_released": "تم النقل: أُزيلت {count} قيود كانت تربطه بما بقي ({names}).",
|
||||
"sketch.move_released_one": "تم النقل: أُزيل {count} قيد كان يربطه بما بقي ({names}).",
|
||||
"sketch.open_ends": "مفتوحة {count}",
|
||||
"sketch.status_conflict": "تعارض القيود",
|
||||
"sketch.status_fully_constrained": "مقيّد بالكامل",
|
||||
@@ -4738,6 +4857,10 @@
|
||||
"sketch_text.path_clear": "فصل النص عن منحناه",
|
||||
"sketch_text.path_hint": "منحنى من الرسم يتبعه النص: انقر هنا ثم على المنحنى",
|
||||
"sketch_text.use_font_file": "استخدام ملف الخط {path}",
|
||||
"sketch_text.valign_baseline": "خط الأساس",
|
||||
"sketch_text.valign_bottom": "أسفل",
|
||||
"sketch_text.valign_middle": "وسط",
|
||||
"sketch_text.valign_top": "أعلى",
|
||||
"solid": "مصمت",
|
||||
"status.editing": "تحرير {name}",
|
||||
"status.navigation": "تعيين أزرار الفأرة: {mapping}",
|
||||
@@ -4938,6 +5061,7 @@
|
||||
"ui.agent_chat_allow_once": "السماح مرة واحدة",
|
||||
"ui.agent_chat_allowed": "مسموح",
|
||||
"ui.agent_chat_answered": "الإجابة: {option}",
|
||||
"ui.agent_chat_answered_in": "أُجيب خلال {time}",
|
||||
"ui.agent_chat_approval": "السماح للوكيل بفعل هذا؟",
|
||||
"ui.agent_chat_attach_selection": "إرفاق التحديد",
|
||||
"ui.agent_chat_attach_selection_tip": "إرسال ما هو محدد في النموذج (أوجه وحواف وميزات وأجسام) مع الرسالة، ليعرف الوكيل ما تقصده",
|
||||
@@ -4966,6 +5090,7 @@
|
||||
"ui.agent_chat_ctx_bodies": "الأجسام",
|
||||
"ui.agent_chat_ctx_elements": "العناصر",
|
||||
"ui.agent_chat_ctx_features": "الميزات",
|
||||
"ui.agent_chat_ctx_gone": "لم يعد في التصميم: تم تغييره أو حذفه.",
|
||||
"ui.agent_chat_ctx_more": "+{n} أخرى",
|
||||
"ui.agent_chat_ctx_other": "أخرى",
|
||||
"ui.agent_chat_custom_heading": "نموذج مخصص",
|
||||
@@ -4979,6 +5104,7 @@
|
||||
"ui.agent_chat_dock_right": "التثبيت على اليمين",
|
||||
"ui.agent_chat_drop_hint": "أفلت لإرفاقه برسالتك التالية",
|
||||
"ui.agent_chat_edit": "تعديل",
|
||||
"ui.agent_chat_ended_after": "انتهى بعد {time}",
|
||||
"ui.agent_chat_exited": "توقف الوكيل.",
|
||||
"ui.agent_chat_failed_start": "تعذّر بدء الوكيل: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: ملف CAD يُستورد إلى التصميم ولا يُقرأ",
|
||||
@@ -5016,6 +5142,7 @@
|
||||
"ui.agent_chat_model_no_tools": "لا يستطيع {model} استخدام أدوات SolidCraft، لذا يمكنه المحادثة فقط. اختر نموذجًا يدعم الأدوات.",
|
||||
"ui.agent_chat_model_rejected": "لم يقبل الوكيل {model}: {error}",
|
||||
"ui.agent_chat_model_search": "البحث عن النماذج…",
|
||||
"ui.agent_chat_model_search_or_id": "ابحث، أو اكتب أي معرّف نموذج…",
|
||||
"ui.agent_chat_model_tip": "النموذج الذي يستخدمه الوكيل. يُحفظ اختيارك لهذا الوكيل.",
|
||||
"ui.agent_chat_models_failed": "تعذّر جلب قائمة النماذج: {error}",
|
||||
"ui.agent_chat_models_heading": "النماذج المتاحة",
|
||||
@@ -5027,6 +5154,7 @@
|
||||
"ui.agent_chat_next_picture": "الصورة التالية",
|
||||
"ui.agent_chat_no_cli": "لم يُعثر على solidcraft-cli بجوار التطبيق، لذا لا يستطيع الوكيل الوصول إلى التصميم.",
|
||||
"ui.agent_chat_no_control": "لم تبدأ نقطة نهاية محادثة الوكيل، لذا لا يستطيع الوكيل الوصول إلى التصميم.",
|
||||
"ui.agent_chat_no_design_hint": "يعمل الوكيل دون أدوات SolidCraft، لذا لا يستطيع قراءة التصميم أو تغييره: لم يُعثر على solidcraft-cli بجانب التطبيق. ثبّت SolidCraft مع solidcraft-cli بجانبه (في Windows: حزمة MSI أو ملف zip المحمول)، أو اضبط SOLIDCRAFT_CLI على مساره، ثم اتصل مرة أخرى.",
|
||||
"ui.agent_chat_no_images": "هذا الوكيل لا يقبل الصور",
|
||||
"ui.agent_chat_no_picture": "لا توجد صورة في الحافظة",
|
||||
"ui.agent_chat_no_tool_call": "لم يستخدم النموذج أدوات SolidCraft، لذا لم يتغيّر التصميم. اختر نموذجًا يدعم استدعاء الأدوات؛ راجع «النماذج المحلية» في دليل محادثة الوكيل.",
|
||||
@@ -5041,7 +5169,7 @@
|
||||
"ui.agent_chat_permission": "يطلب الوكيل تشغيل: {title}",
|
||||
"ui.agent_chat_pick": "الوكيل",
|
||||
"ui.agent_chat_pick_context": "اختيار السياق",
|
||||
"ui.agent_chat_pick_context_tip": "اختر أوجهًا وحوافًا وميزات وأجسامًا في النموذج ليطّلع عليها الوكيل، ثم اضغط «موافق»",
|
||||
"ui.agent_chat_pick_context_tip": "اختر أوجهًا وحوافًا وميزات وأجسامًا في النموذج، ثم اضغط «موافق»: تُدرج في الرسالة كشارة في موضع المؤشر (كتابة @ تفعل الشيء نفسه)",
|
||||
"ui.agent_chat_placeholder": "اطلب من الوكيل تغيير التصميم…",
|
||||
"ui.agent_chat_placeholder_busy": "ضع رسالة في قائمة الانتظار لحين انتهاء الوكيل (Ctrl+Enter: أرسل الآن)",
|
||||
"ui.agent_chat_pop_out": "فتح في نافذة مستقلة يمكنك نقلها إلى شاشة أخرى",
|
||||
@@ -5073,16 +5201,26 @@
|
||||
"ui.agent_chat_setup_title": "إعداد مساعد",
|
||||
"ui.agent_chat_side": "تثبيت المحادثة",
|
||||
"ui.agent_chat_signed_in": "سجّل الدخول",
|
||||
"ui.agent_chat_snap_none_found": "لم يُعثر على وكيل برمجي. تعمل حزمة Snap في بيئة معزولة، لذا لا يمكنها رؤية الوكلاء البرمجيين المثبّتين على هذا الحاسوب ولا تشغيلهم. لاستخدامهم، ثبّت SolidCraft من حزمة AppImage أو .deb أو .rpm بدلًا من ذلك. يعمل الوكيل الذي يستخدم واجهة برمجية متوافقة مع OpenAI في حزمة Snap أيضًا: أعدّه من «إضافة وكيل».",
|
||||
"ui.agent_chat_span_h": "{h} ساعة {min} دقيقة",
|
||||
"ui.agent_chat_span_min": "{n} دقيقة",
|
||||
"ui.agent_chat_span_s": "{n} ث",
|
||||
"ui.agent_chat_state_auth": "يلزم تسجيل الدخول",
|
||||
"ui.agent_chat_state_busy": "جارٍ العمل…",
|
||||
"ui.agent_chat_state_exited": "توقف الوكيل",
|
||||
"ui.agent_chat_state_failed": "فشل الاتصال",
|
||||
"ui.agent_chat_state_no_design": "لا وصول إلى التصميم",
|
||||
"ui.agent_chat_state_off": "غير متصل",
|
||||
"ui.agent_chat_state_ready": "جاهز",
|
||||
"ui.agent_chat_state_starting": "جارٍ البدء…",
|
||||
"ui.agent_chat_stop": "إيقاف",
|
||||
"ui.agent_chat_stop_tip": "إيقاف الوكيل وكل ما بدأه",
|
||||
"ui.agent_chat_stop_turn_tip": "إيقاف الوكيل (Esc). تبقى الرسائل المنتظرة في قائمة الانتظار.",
|
||||
"ui.agent_chat_thinking_for": "يفكر منذ {time}",
|
||||
"ui.agent_chat_tool_running_for": "قيد التشغيل منذ {time}",
|
||||
"ui.agent_chat_tools_not_started": "يعمل الوكيل دون أدوات SolidCraft، لذا لا يستطيع قراءة التصميم أو تغييره: عُثر على solidcraft-cli، لكن أدواته لم تبدأ (رسالة الخطأ في المحادثة توضح السبب). اتصل مرة أخرى، وإذا تكرر ذلك فأعد تثبيت SolidCraft.",
|
||||
"ui.agent_chat_transcript_assistant": "المساعد:",
|
||||
"ui.agent_chat_transcript_user": "المستخدم:",
|
||||
"ui.agent_chat_turn_limit": "التغييرات لكل رسالة",
|
||||
"ui.agent_chat_turn_unlimited": "بلا حد",
|
||||
"ui.agent_chat_undo_changes": "التراجع عن هذه التغييرات",
|
||||
@@ -5239,7 +5377,9 @@
|
||||
"ui.browser_bodies_one": "{count} جسم",
|
||||
"ui.browser_bodies_other": "{count} أجسام",
|
||||
"ui.browser_collapse": "طي المستعرض",
|
||||
"ui.browser_collapse_below": "طي ما بالأسفل",
|
||||
"ui.browser_expand": "توسيع المستعرض",
|
||||
"ui.browser_expand_below": "توسيع ما بالأسفل",
|
||||
"ui.browser_title": "المستعرض",
|
||||
"ui.calibrate": "معايرة",
|
||||
"ui.cancel": "إلغاء",
|
||||
@@ -5269,6 +5409,7 @@
|
||||
"ui.collapse": "طي",
|
||||
"ui.collinear": "على خط واحد",
|
||||
"ui.colour_vision": "رؤية الألوان",
|
||||
"ui.colour_vision_bends": "الثنيات",
|
||||
"ui.colour_vision_deutan": "ضعف الأخضر",
|
||||
"ui.colour_vision_deutan_tip": "لضعف أو غياب الإحساس باللون الأخضر",
|
||||
"ui.colour_vision_failed": "فشل",
|
||||
@@ -5298,14 +5439,24 @@
|
||||
"ui.conic_curve": "منحنى مخروطي",
|
||||
"ui.constant": "ثابت",
|
||||
"ui.constraints_conflict": "تعارض في القيود",
|
||||
"ui.construct_auto.chosen": "اختيرت الطريقة من اختياراتك. اختر مرجعًا آخر أو أزل مرجعًا لتغيير الطريقة.",
|
||||
"ui.construct_auto.no_fit": "اختر مراجع أخرى: لا توجد طريقة تبني من هذه المراجع.",
|
||||
"ui.construct_auto.pick": "اختر ما تبني منه: الطريقة تتبع اختياراتك.",
|
||||
"ui.construct_auto.refs": "المراجع",
|
||||
"ui.construct_auto.select": "اختر أولًا المراجع التي تبني منها",
|
||||
"ui.construct_axes": "المحاور",
|
||||
"ui.construct_planes": "المستويات",
|
||||
"ui.construct_points": "النقاط",
|
||||
"ui.construction": "مساعد",
|
||||
"ui.construction.angle_hint": "خط إنشائي: انقر نقطة ثم أدخل زاوية أو اختر اتجاهًا",
|
||||
"ui.construction.axis_hint": "خط إنشائي: انقر نقطة، أو أدخل بعدها عن محور الرسم",
|
||||
"ui.construction.bisector_hint": "منصف زاوية: اختر خطين مستقيمين متقاطعين ثم الحل المطلوب",
|
||||
"ui.construction.common_hint": "مماس مشترك: اختر دائرتين/قوسين ثم الحل المطلوب",
|
||||
"ui.construction.contact_hint": "مماس: اختر دائرة/قوسًا أو منحنى شريحيًا/قطعًا مخروطيًا مفتوحًا ثم نقطة التماس (للمنحنيات الحرة: النهايات فقط)",
|
||||
"ui.construction.external_hint": "مماس: اختر دائرة أو قوسًا ثم نقطة خارجية ثم الحل المطلوب",
|
||||
"ui.construction.free_hint": "خط إنشائي: انقر نقطتين؛ انقر بزر الفأرة الأيمن للبدء من جديد",
|
||||
"ui.construction.normal_needs_length": "الخط اللانهائي إنشائي دائمًا: اكتب طولًا لرسم خط عادي",
|
||||
"ui.construction.parallel_hint": "خط إنشائي: اختر خطًا مستقيمًا ثم انقر أو أدخل الإزاحة؛ انقر بزر الفأرة الأيمن لتغيير المرجع",
|
||||
"ui.construction.point_hint": "خط إنشائي: انقر نقطة المرور",
|
||||
"ui.construction.reference_hint": "خط إنشائي: اختر خطًا مستقيمًا ثم نقطة؛ انقر بزر الفأرة الأيمن لتغيير المرجع",
|
||||
"ui.construction.ribbon_label": "خطوط مساعدة",
|
||||
@@ -5448,6 +5599,17 @@
|
||||
"ui.ellipse": "قطع ناقص",
|
||||
"ui.emboss_wrap_note": "تلتف ملامح الخطوط المتعامدة المماسة لأسطوانة مدعومة تلقائيًا. اختر جدارًا لتحديد الهدف.",
|
||||
"ui.end": "النهاية",
|
||||
"ui.end_cap.chamfer": "شطف الزوايا",
|
||||
"ui.end_cap.direction": "الاتجاه",
|
||||
"ui.end_cap.faces": "الوجوه الطرفية",
|
||||
"ui.end_cap.inset": "الإزاحة للداخل",
|
||||
"ui.end_cap.inset_kind": "الإزاحة حسب",
|
||||
"ui.end_cap.inset_ratio": "نسبة الإزاحة",
|
||||
"ui.end_cap.inward": "للداخل",
|
||||
"ui.end_cap.length": "الطول",
|
||||
"ui.end_cap.outward": "للخارج",
|
||||
"ui.end_cap.ratio": "نسبة من السماكة",
|
||||
"ui.end_cap_title": "غطاء طرفي",
|
||||
"ui.end_radius": "نصف قطر النهاية",
|
||||
"ui.end_scale": "مقياس النهاية",
|
||||
"ui.ends": "الطرفان",
|
||||
@@ -5468,7 +5630,10 @@
|
||||
"ui.explode_needs_two_components": "يُبعد العرض المفكك المكوّنات بعضها عن بعض، لذا يحتاج التصميم إلى مكوّنين أو أكثر (مكوّن جديد، أو إدراج تصميم، أو إنشاء مكوّنات من الأجسام)",
|
||||
"ui.exportDxf": "تصدير DXF…",
|
||||
"ui.export_ellipsis_keymap": "تصدير…",
|
||||
"ui.export_glb": "تصدير GLB",
|
||||
"ui.export_keymap_tip": "المفاتيح ومفضلات مربع S وشريط الأدوات، كملف",
|
||||
"ui.export_selects_only_body": "تحديد الجسم الوحيد عند تصدير شبكة",
|
||||
"ui.export_selects_only_body_tip": "تبدأ أوامر تصدير STL وتصدير 3MF والإرسال إلى برنامج التقطيع بتحديد جسم التصميم عندما لا يحتوي إلا على جسم واحد.",
|
||||
"ui.extend": "تمديد",
|
||||
"ui.extent": "الامتداد",
|
||||
"ui.extent_type": "نوع الامتداد",
|
||||
@@ -5528,6 +5693,8 @@
|
||||
"ui.finest": "الأدق",
|
||||
"ui.finish_sketch": "إنهاء الرسم",
|
||||
"ui.first_dimension_scales": "البُعد الأول يغيّر مقياس الرسم",
|
||||
"ui.first_dimension_scales_about_origin": "تغيير المقياس حول أصل الرسم",
|
||||
"ui.first_dimension_scales_about_origin_tip": "عند التفعيل: يكبر المرسوم أو يصغر دائمًا حول أصل الرسم، فإذا كان الشكل مرسومًا بعيدًا عن الأصل تحرّك. عند الإيقاف: المرسوم غير المرتبط بالأصل يتغير مقياسه حول منتصفه ويبقى حيث رُسم.",
|
||||
"ui.first_dimension_scales_tip": "تشغيل: أول بُعد طولي في الرسم يغيّر مقياس الشكل الذي يقيسه، فيبقى شكله كما هو. إيقاف: يغيّر البُعد حجم ما يقيسه فقط.",
|
||||
"ui.fit": "ملاءمة",
|
||||
"ui.fix_unfix": "تثبيت/فك التثبيت",
|
||||
@@ -5950,6 +6117,7 @@
|
||||
"ui.project_references_construction_note": "تصبح الهندسة التي تنشئها أوامر «إسقاط» و«تقاطع» و«تضمين هندسة ثلاثية الأبعاد»، وحواف الوجه في رسم جديد على وجه، هندسةً مساعدة: مراجع للرسم عليها لا تدخل في المقاطع. وتبقى مرتبطة بالنموذج.",
|
||||
"ui.properties": "الخصائص",
|
||||
"ui.properties.copy_matrix": "نسخ المصفوفة",
|
||||
"ui.properties.copy_value": "انقر للنسخ",
|
||||
"ui.properties.first_moments": "العزوم الأولى",
|
||||
"ui.properties.inertia": "عزم القصور الذاتي",
|
||||
"ui.properties.inertia_note": "حول مركز الكتلة، بمحاور العالم (g·{unit}²)",
|
||||
@@ -5962,6 +6130,7 @@
|
||||
"ui.properties.measuring_failed": "توقف القياس قبل أن يكتمل.",
|
||||
"ui.properties.principal_axis": "المحور الرئيسي {number}",
|
||||
"ui.properties.principal_moments": "العزوم الرئيسية",
|
||||
"ui.properties.value_copied": "تم نسخ القيمة",
|
||||
"ui.pull_direction": "اتجاه السحب",
|
||||
"ui.quality": "الجودة",
|
||||
"ui.quantity": "الكمية",
|
||||
@@ -5982,11 +6151,14 @@
|
||||
"ui.relink_design_changed": "تغيّر التجميع أثناء اختيار المصدر. ابدأ «إعادة ربط المصدر» من جديد.",
|
||||
"ui.relink_done": "أُعيد ربط المصدر لكل النسخ.",
|
||||
"ui.relink_not_linked": "هذا المكوّن غير مرتبط بتصميم مصدر.",
|
||||
"ui.relink_one_done": "أُعيد ربط المصدر لهذه النسخة.",
|
||||
"ui.relink_select_one": "حدد مكوّنًا مرتبطًا واحدًا أو إحدى نسخه أولًا.",
|
||||
"ui.relink_source_all": "إعادة ربط المصدر (كل النسخ)…",
|
||||
"ui.relink_source_one": "إعادة ربط المصدر…",
|
||||
"ui.removeFromQuickAccess": "إزالة من الوصول السريع",
|
||||
"ui.removeFromToolbar": "إزالة من شريط الأدوات",
|
||||
"ui.removeSection": "إزالة المقطع",
|
||||
"ui.renameSelectedBodies": "إعادة تسمية الأجسام المحددة",
|
||||
"ui.render": "التصيير",
|
||||
"ui.renderer": "محرك التصيير",
|
||||
"ui.repeat": "تكرار",
|
||||
@@ -6017,6 +6189,8 @@
|
||||
"ui.ribbon_pin_footer": "الأوامر المثبتة تظهر في الشريط. مرّر المؤشر على صف لتثبيته أو إلغاء تثبيته.",
|
||||
"ui.ribbon_workspace": "مساحة العمل",
|
||||
"ui.right": "يمين",
|
||||
"ui.right_click_confirms": "النقر بزر الفأرة الأيمن يؤكد مدخلات مربع الحوار",
|
||||
"ui.right_click_confirms_tip": "عندما يكون مربع حوار مفتوحًا، ينتقل النقر بزر الفأرة الأيمن في العرض إلى المدخل الفارغ التالي، وعند المدخل الأخير ينفّذ «موافق»",
|
||||
"ui.save": "حفظ",
|
||||
"ui.save_as": "حفظ باسم",
|
||||
"ui.save_mesh_no_slicer_open": "لم يُعثر على برنامج تقطيع: اختر «مخصص…» وحدد برنامج التقطيع الخاص بك",
|
||||
@@ -6076,6 +6250,16 @@
|
||||
"ui.sketch_intersect_selection_filter": "مرشح التحديد",
|
||||
"ui.sketch_keys_only": "إبقاء مفاتيح النموذج خارج الرسومات",
|
||||
"ui.sketch_keys_only_tip": "أثناء تحرير رسم، تعمل مفاتيح الرسم والمفاتيح التي تعمل في كل مكان فقط؛ ولا يفعل مفتاح نموذج مثل E أو F شيئًا، فلا يمكن لمفتاح مضغوط بالخطأ أن يغلق رسمًا ثقيلًا.",
|
||||
"ui.sketch_links_added_curve": "أضاف {command} منحنى واحدًا إلى الرسم.",
|
||||
"ui.sketch_links_added_curves": "أضاف {command} منحنيات إلى الرسم (العدد: {count}).",
|
||||
"ui.sketch_links_added_curves_and_points": "أضاف {command} إلى الرسم {curves} و{points}.",
|
||||
"ui.sketch_links_added_point": "أضاف {command} نقطة واحدة إلى الرسم.",
|
||||
"ui.sketch_links_added_points": "أضاف {command} نقاطًا إلى الرسم (العدد: {count}).",
|
||||
"ui.sketch_links_curve_count": "منحنيات (العدد: {count})",
|
||||
"ui.sketch_links_curve_count_one": "منحنى واحدًا",
|
||||
"ui.sketch_links_hidden": "النتيجة مخفية لأن خيار {option} مُعطَّل في خيارات الرسم.",
|
||||
"ui.sketch_links_point_count": "نقاطًا (العدد: {count})",
|
||||
"ui.sketch_links_point_count_one": "نقطة واحدة",
|
||||
"ui.sketch_modifiers": "مُعدِّلات الرسم",
|
||||
"ui.sketch_project_geometry": "الهندسة",
|
||||
"ui.sketch_report.all_constrained": "كل شيء مقيد بالكامل.",
|
||||
@@ -6115,6 +6299,7 @@
|
||||
"ui.step_values": "تغيير القيم بالأسهم والعجلة",
|
||||
"ui.step_values_tip": "يغيّر السهمان لأعلى ولأسفل والعجلة فوق حقل قيمة الرقم فيه.",
|
||||
"ui.stitch_tolerance_hint": "دقيقة",
|
||||
"ui.straighten": "تقويم",
|
||||
"ui.stretch": "مطّ",
|
||||
"ui.supersampling": "التنعيم الفائق (SSAA)",
|
||||
"ui.supersampling_adaptive": "فقط عندما يكون العرض ساكنًا",
|
||||
@@ -6188,6 +6373,8 @@
|
||||
"ui.view_angles_yaw": "الانعراج",
|
||||
"ui.view_angles_zero": "تعيين {axis} إلى 0°",
|
||||
"ui.view_centre": "مركز العرض",
|
||||
"ui.view_compass_tip": "العرض من {axis}. انقر مرة أخرى للعكس. اسحب لتدوير العرض.",
|
||||
"ui.view_compass_tip_snap": "العرض من {axis}. انقر مرة أخرى للعكس. اسحب لتدوير العرض؛ اضغط مطولًا على Shift للالتقاط.",
|
||||
"ui.viewport_status_clear": "إيقاف {name}",
|
||||
"ui.viewport_status_clear_hint": "إيقاف {name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} حواف",
|
||||
|
||||
@@ -602,6 +602,7 @@
|
||||
"Value": "Value",
|
||||
"Variable Radius": "Variable Radius",
|
||||
"Velocity": "Velocity",
|
||||
"Vertical": "Вертикално",
|
||||
"Vertices": "Vertices",
|
||||
"View navigator": "View navigator",
|
||||
"Volume": "Обем",
|
||||
@@ -2574,6 +2575,10 @@
|
||||
"sketch_text.path_clear": "Take the text off its curve",
|
||||
"sketch_text.path_hint": "A curve of the sketch the text follows: click here, then the curve",
|
||||
"sketch_text.use_font_file": "Use the font file {path}",
|
||||
"sketch_text.valign_baseline": "Базова линия",
|
||||
"sketch_text.valign_bottom": "Долу",
|
||||
"sketch_text.valign_middle": "Среда",
|
||||
"sketch_text.valign_top": "Горе",
|
||||
"solid": "solid",
|
||||
"the parts library is not available": "the parts library is not available",
|
||||
"thread.automatic_size": "Automatic size",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Vrijednost",
|
||||
"Variable Radius": "Promjenljivi poluprečnik",
|
||||
"Velocity": "Brzina",
|
||||
"Vertical": "Vertikalno",
|
||||
"Vertices": "Vrhovi",
|
||||
"View navigator": "Navigator prikaza",
|
||||
"Volume": "Zapremina",
|
||||
@@ -3929,6 +3930,10 @@
|
||||
"sketch_text.path_clear": "Skini tekst s njegove krive",
|
||||
"sketch_text.path_hint": "Kriva skice koju tekst prati: kliknite ovdje, a zatim krivu",
|
||||
"sketch_text.use_font_file": "Koristi datoteku fonta {path}",
|
||||
"sketch_text.valign_baseline": "Osnovna linija",
|
||||
"sketch_text.valign_bottom": "Dno",
|
||||
"sketch_text.valign_middle": "Sredina",
|
||||
"sketch_text.valign_top": "Vrh",
|
||||
"solid": "puno",
|
||||
"status.editing": "Uređivanje: {name}",
|
||||
"status.navigation": "Mapiranje miša: {mapping}",
|
||||
|
||||
+134
-1
@@ -265,6 +265,7 @@
|
||||
"Edge": "Aresta",
|
||||
"Edges": "Arestes",
|
||||
"Edit": "Editar",
|
||||
"Edit Holes": "Editar forats",
|
||||
"Edit Profile Sketch": "Editar el bocet del perfil",
|
||||
"Edit shortcuts": "Editar les dreceres",
|
||||
"Enable rule": "Activar la regla",
|
||||
@@ -884,6 +885,7 @@
|
||||
"Variable Radius": "Radi variable",
|
||||
"Variable radius": "Radi variable",
|
||||
"Velocity": "Velocitat",
|
||||
"Vertical": "Vertical",
|
||||
"Vertices": "Vèrtexs",
|
||||
"View": "Vista",
|
||||
"View navigator": "Navegador de vistes",
|
||||
@@ -976,6 +978,7 @@
|
||||
"browser.calibrate_click_a": "Feu clic a la imatge per al punt A, o escriviu-ne les coordenades.",
|
||||
"browser.calibrate_click_b": "Feu clic a la imatge per al punt B, o escriviu-ne les coordenades.",
|
||||
"browser.calibrate_title": "Calibrar: {name}",
|
||||
"browser.canvas_locked": "El llenç està bloquejat. Desbloquegeu-lo primer.",
|
||||
"browser.capture_many": "S'han mogut {count} components, però no s'han capturat les seves posicions.",
|
||||
"browser.capture_note": "Capturar la posició conserva la posició nova; Revertir la posició restaura l'anterior.",
|
||||
"browser.capture_one": "S'ha mogut un component, però no s'ha capturat la seva posició.",
|
||||
@@ -1205,6 +1208,7 @@
|
||||
"cmd.material_properties_directional": "Mòdul elàstic direccional",
|
||||
"cmd.material_properties_validate": "Validar les dades del material físic",
|
||||
"cmd.mesh_convert": "Convertir la malla",
|
||||
"cmd.model_body_features": "Llistar les operacions del cos",
|
||||
"cmd.model_edges": "Llistar les arestes",
|
||||
"cmd.model_faces": "Llistar les cares",
|
||||
"cmd.model_threads": "Llistar les roscas",
|
||||
@@ -1233,8 +1237,11 @@
|
||||
"cmd.panel.dismiss": "Descartar la vista prèvia del panell",
|
||||
"cmd.panel.float": "Panell flotant",
|
||||
"cmd.panel.focus": "Enfocar el panell",
|
||||
"cmd.panel.focus.next": "Enfocar el panell següent",
|
||||
"cmd.panel.focus.previous": "Enfocar el panell anterior",
|
||||
"cmd.panel.list": "Llistar els panells",
|
||||
"cmd.panel.move": "Moure el panell",
|
||||
"cmd.panel.move.next_zone": "Moure el panell a la zona següent",
|
||||
"cmd.panel.native_close": "Tornar a acoblar la secció de panell nativa",
|
||||
"cmd.panel.open": "Obrir el panell",
|
||||
"cmd.panel.peek": "Vista prèvia d'un panell contret",
|
||||
@@ -1242,6 +1249,12 @@
|
||||
"cmd.panel.reset_pair": "Restablir el divisor del panell",
|
||||
"cmd.panel.resize": "Redimensionar la secció del panell",
|
||||
"cmd.panel.resize_pair": "Redimensionar el divisor del panell",
|
||||
"cmd.panel.sash.down": "Redimensionar el divisor del panell cap avall",
|
||||
"cmd.panel.sash.left": "Redimensionar el divisor del panell cap a l'esquerra",
|
||||
"cmd.panel.sash.reset": "Restablir el divisor del panell enfocat",
|
||||
"cmd.panel.sash.right": "Redimensionar el divisor del panell cap a la dreta",
|
||||
"cmd.panel.sash.up": "Redimensionar el divisor del panell cap amunt",
|
||||
"cmd.panel.toggle": "Alternar el panell enfocat",
|
||||
"cmd.parameters_add": "Afegir un paràmetre d'usuari",
|
||||
"cmd.parameters_change": "Canviar paràmetres",
|
||||
"cmd.parameters_comment": "Comentar el paràmetre",
|
||||
@@ -1365,6 +1378,7 @@
|
||||
"cmd.sketch.construction_line.tangent_external": "Tangent per un punt exterior",
|
||||
"cmd.sketch.construction_line.tangent_two": "Tangent comuna",
|
||||
"cmd.sketch.construction_line.vertical": "Línia de construcció vertical",
|
||||
"cmd.sketch.replace": "Substituir el bocet",
|
||||
"cmd.sketch_arc3d": "Arc 3D",
|
||||
"cmd.sketch_arc_center_point": "Arc de centre i punt",
|
||||
"cmd.sketch_arc_tangent": "Arc tangent",
|
||||
@@ -1496,6 +1510,7 @@
|
||||
"cmd.timeline_stop": "Aturar l'historial",
|
||||
"cmd.timeline_suppress": "Suprimir l'operació",
|
||||
"cmd.ui.assistant": "Alternar l'Assistent",
|
||||
"cmd.ui.palette": "Cercar ordres",
|
||||
"cmd.view.navigator": "Navegador de vistes personalitzat",
|
||||
"cmd.view.render_browser": "Explorador de render",
|
||||
"cmd.view.render_dock": "Moure l'acoblament del render",
|
||||
@@ -2015,6 +2030,7 @@
|
||||
"help.view.visual_style": "Canvia com es dibuixa el model: sombrejat amb o sense arestes, filferro, o amb arestes ocultes. Feu servir filferro per veure-hi a dins, i sombrejat per a un aspecte net.",
|
||||
"history.sketch_under_constrained": "Restricció insuficient ({count} graus de llibertat)",
|
||||
"history.sketch_under_constrained_one": "Restricció insuficient ({count} grau de llibertat)",
|
||||
"hole_folder.applies_to": "Els canvis s'apliquen als {count} forats de {folder}; cadascun conserva la seva posició.",
|
||||
"hole_presets.confirm_delete": "Confirmar l'eliminació",
|
||||
"hole_presets.delete": "Eliminar",
|
||||
"hole_presets.delete_prompt": "Voleu eliminar aquest preajust personal? Els forats existents no canvien.",
|
||||
@@ -2417,6 +2433,7 @@
|
||||
"parts.dimension.width": "Amplada",
|
||||
"parts.family.bearing": "Rodament rígid de boles (envolupant)",
|
||||
"parts.family.button_head_cap_screw": "Cargol de cap botó",
|
||||
"parts.family.countersunk_socket_screw": "Cargol avellanat amb hexàgon interior",
|
||||
"parts.family.dowel_pin": "Passador cilíndric",
|
||||
"parts.family.hex_bolt": "Cargol de cap hexagonal",
|
||||
"parts.family.hex_cap_screw_inch": "Cargol de cap hexagonal (polzades)",
|
||||
@@ -2515,6 +2532,8 @@
|
||||
"prefs.bottom_centre": "Baix al centre",
|
||||
"prefs.bottom_right": "Baix a la dreta",
|
||||
"prefs.browser": "Explorador",
|
||||
"prefs.browser_body_features": "Operacions sota els cossos",
|
||||
"prefs.browser_body_features_note": "Cada cos de l'explorador es desplega sobre les operacions de la línia de temps que el van construir, en l'ordre de la línia de temps.",
|
||||
"prefs.browser_components_open": "Els components comencen oberts",
|
||||
"prefs.browser_components_open_note": "Cada component de l'explorador comença obert, com abans, en lloc de tancat fins que l'obriu.",
|
||||
"prefs.browser_eye_left": "Ull al costat de la fletxa de plegat",
|
||||
@@ -2555,7 +2574,11 @@
|
||||
"prefs.design_tools.degrees": "Graus",
|
||||
"prefs.design_tools.double_click_help": "O per editar-ne un de vinculat al seu lloc.",
|
||||
"prefs.design_tools.ghost": "Mostrar com un fantasma la posició anterior de les peces mogudes",
|
||||
"prefs.design_tools.hole_group": "Agrupar els forats creats junts",
|
||||
"prefs.design_tools.hole_group_help": "Els forats creats alhora comparteixen una carpeta a l'historial, tancada al principi; obriu-la per editar un forat per separat.",
|
||||
"prefs.design_tools.hole_moves_help": "Tornar a triar la cara mou el forat en lloc d'eliminar-lo.",
|
||||
"prefs.design_tools.hole_several": "Diversos forats en una cara",
|
||||
"prefs.design_tools.hole_several_help": "Fer clic en un altre punt d'una cara afegeix un altre forat; fer clic en un forat el treu.",
|
||||
"prefs.design_tools.hole_snaps_help": "El centre d'una cara i els centres de les seves arestes rodones.",
|
||||
"prefs.design_tools.imported_files": "Fitxers importats",
|
||||
"prefs.design_tools.note": "Nota",
|
||||
@@ -2637,6 +2660,8 @@
|
||||
"prefs.history": "Historial",
|
||||
"prefs.history_bar_groups": "Plegar la barra Historial en grups",
|
||||
"prefs.history_bar_groups_note": "En un historial llarg, una sèrie d'operacions d'un mateix component es plega en una fitxa, i les carpetes d'operacions comencen plegades. Un ensamblatge STEP inserit va a una carpeta Grup. Desactivat, es mostra cada operació, les carpetes comencen obertes i no es crea cap carpeta.",
|
||||
"prefs.history_folder_kind_icon": "Icona de carpeta segons les seves operacions",
|
||||
"prefs.history_folder_kind_icon_note": "Una carpeta de l'historial les operacions de la qual són totes del mateix tipus mostra la seva icona.",
|
||||
"prefs.history_group_joints": "Agrupar les unions a l'historial",
|
||||
"prefs.history_group_joints_note": "Dues o més unions es mostren com un botó amb el seu nombre, i en fer clic es mostra cadascuna. Desactivat, es mostra cada unió.",
|
||||
"prefs.history_origin_bodies": "Mostrar l'origen i els cossos a dalt",
|
||||
@@ -2742,6 +2767,7 @@
|
||||
"prefs.origin_plane_names": "Noms dels plans d'origen",
|
||||
"prefs.origin_plane_names_note": "Noms que es mostren a l'explorador, als diàlegs i a les llistes. {top} és XY, {front} és XZ i {right} és YZ, amb Z cap amunt. Les ordres, els scripts i els dissenys desats mantenen XY, XZ i YZ.",
|
||||
"prefs.overall_speed": "Velocitat general",
|
||||
"prefs.panel_layout.recovery": "No s'han pogut restaurar les disposicions de panells desades. Les dades desades es conserven; Clàssic continua disponible.",
|
||||
"prefs.parameter_list_rows": "Files de la llista de paràmetres",
|
||||
"prefs.parameter_list_rows_tip": "El nombre de paràmetres que la fletxa avall llista en un quadre d'expressió buit.",
|
||||
"prefs.persistent_ribbon_pressed": "Ressaltar les ordres actives de la cinta",
|
||||
@@ -2803,6 +2829,8 @@
|
||||
"prefs.remember_dialog_values.help": "Desactivat de manera predeterminada. Si s'activa, quan una ordre acaba correctament, els seus valors i opcions segurs es reutilitzen la propera vegada que obriu la mateixa ordre, fins que es tanqui SolidCraft.",
|
||||
"prefs.render_legacy_image_defaults": "Fer servir els valors d'imatge anteriors de Render",
|
||||
"prefs.render_legacy_image_defaults_help": "Manté el flux manual anterior: les configuracions noves fan servir el rasteritzat de CPU, el ray tracing de CPU conserva el mostreig fix i els resultats renderitzats s'obren a mà. En entrar a Render es reenquadra, es canvien les preses sense restaurar-ne les càmeres i es fa servir l'enquadrament i la navegació anteriors. Es desactiva la vista prèvia automàtica de la imatge en directe. Les configuracions desades no canvien.",
|
||||
"prefs.render_legacy_memory_admission": "Fer servir les comprovacions de memòria de renderitzat anteriors",
|
||||
"prefs.render_legacy_memory_admission_help": "Permet els renderitzats natius dins dels pressupostos fixos de memòria compartida i de l'amfitrió encara que la seva estimació superi la RAM disponible. Els límits del dispositiu i les comprovacions d'assignació es continuen aplicant.",
|
||||
"prefs.render_previous_geometry_budget": "Fer servir el pressupost de geometria anterior de la previsualització del renderitzat",
|
||||
"prefs.render_previous_geometry_budget_help": "Restaura el límit fix anterior (512 MiB a l'escriptori de 64 bits, 128 MiB a la resta) en lloc del pressupost basat en el dispositiu.",
|
||||
"prefs.reports_saved": "{n} desats",
|
||||
@@ -2829,6 +2857,8 @@
|
||||
"prefs.select_other_hidden": "Seleccionar geometria oculta amb Seleccionar-ne un altre",
|
||||
"prefs.select_other_hidden_help": "Activat: inclou cossos, bocets i arestes ocults o ocluïts a prop del punter. Desactivat: usa la llista original de geometria visible sota el punter.",
|
||||
"prefs.selecting": "Selecció",
|
||||
"prefs.shared_panel_layout": "Fer servir la disposició de panells compartida",
|
||||
"prefs.shared_panel_layout_help": "Mostra l'explorador, l'historial i l'assistent existents en panells movibles. El canvi s'aplica en aplicar les preferències.",
|
||||
"prefs.shift": "Majúscules",
|
||||
"prefs.shift_add_ctrl_toggle": "El Majúscules només afegeix; Ctrl/Cmd alterna",
|
||||
"prefs.shift_add_note": "Activat: el Majúscules afegeix i Ctrl/Cmd alterna. Desactivat (predeterminat): tots dos alternen.",
|
||||
@@ -2851,6 +2881,8 @@
|
||||
"prefs.sketch.drawing": "Dibuix",
|
||||
"prefs.sketch.ellipse_axes": "Dibuixar les el·lipses amb els seus eixos",
|
||||
"prefs.sketch.ellipse_axes_note": "Els eixos major i menor com a línies de construcció, per poder acotar els semieixos i els eixos. Desactivat: només l'el·lipse, i D a sobre seu dóna el radi menor allà on es tiri el valor, dibuixat i etiquetat R com abans.",
|
||||
"prefs.sketch.escape_twice_finishes": "Doble Esc acaba el bocet",
|
||||
"prefs.sketch.escape_twice_finishes_note": "Dues pulsacions ràpides d'Esc acaben el bocet. Desactivat: Esc només cancel·la l'eina o la selecció, i el bocet només s'acaba amb Acabar el bocet.",
|
||||
"prefs.sketch.exit_keep": "Mantenir",
|
||||
"prefs.sketch.exit_previous": "Tornar a la vista anterior",
|
||||
"prefs.sketch.exit_unless_rotated": "Tret que s'hagi girat",
|
||||
@@ -3193,8 +3225,10 @@
|
||||
"render.category_paint": "Pintura",
|
||||
"render.category_plastic": "Plàstic",
|
||||
"render.category_wood": "Fusta",
|
||||
"render.caustics_area_lights": "Càustiques de llums d'àrea",
|
||||
"render.caustics_depth": "Profunditat del camí de càustiques",
|
||||
"render.caustics_enable": "Càustiques de vidre amb llums puntuals i direccionals",
|
||||
"render.caustics_environment": "Càustiques de l'entorn",
|
||||
"render.caustics_help": "El nombre de fotons controla el soroll i la feina. El radi de captació canvia detall nítid per una estimació més suau. La CPU necessita il·luminació indirecta.",
|
||||
"render.caustics_path_required": "Les càustiques de CPU necessiten il·luminació indirecta.",
|
||||
"render.caustics_photons": "Fotons",
|
||||
@@ -3371,7 +3405,7 @@
|
||||
"render.cpu_opaque_required": "El ray tracing de CPU necessita un fons opac. Desactiveu Fons transparent per continuar.",
|
||||
"render.cpu_options_pending": "Aquest panell de CPU encara no pot editar l'emissió, els efectes de superfície, el vidre ni l'anisotropia. Esborreu aquestes opcions de l'API abans de fer-lo servir.",
|
||||
"render.cpu_path_depth": "Profunditat del camí",
|
||||
"render.cpu_path_help": "Afegeix rebots de llum entre superfícies opaques i a través de formes de vidre admeses. Requereix renderitzat progressiu i ombres traçades. La profunditat del camí compta superfícies ombrejades, límits de vidre i esdeveniments de dispersió, començant pel primer impacte (1–16). La profunditat 1 dona il·luminació directa sobre superfícies opaques; els valors més alts permeten més rebots o creuaments de vidre i poden trigar més. Desactiveu la il·luminació indirecta per fer servir reflexos personalitzats o anisotropia.",
|
||||
"render.cpu_path_help": "Afegeix rebots de llum entre superfícies opaques i a través de formes de vidre admeses. Requereix renderitzat progressiu i ombres traçades. La profunditat del camí compta superfícies ombrejades, límits de vidre i esdeveniments de dispersió, començant pel primer impacte (1–64). La profunditat 1 dona il·luminació directa sobre superfícies opaques; els valors més alts permeten més rebots o creuaments de vidre i poden trigar més. Desactiveu la il·luminació indirecta per fer servir reflexos personalitzats o anisotropia.",
|
||||
"render.cpu_path_lighting": "Il·luminació indirecta",
|
||||
"render.cpu_path_optics_reason": "Es conserven els vostres ajustos. Desactiveu la il·luminació indirecta per fer servir reflexos personalitzats o anisotropia.",
|
||||
"render.cpu_point": "Llum puntual",
|
||||
@@ -3411,6 +3445,12 @@
|
||||
"render.cpu_subsurface_denoise_reason": "La dispersió subsuperficial de CPU necessita la reducció de soroll desactivada. Es conserven els vostres ajustos.",
|
||||
"render.cpu_subsurface_help": "La dispersió redirigeix la llum dins del vidre tancat. Les taxes positives necessiten il·luminació indirecta amb la reducció de soroll desactivada. La taxa és de col·lisions per mm; 0 no afegeix dispersió. Un biaix de fase positiu afavoreix les direccions cap endavant; un de negatiu, les cap enrere.",
|
||||
"render.cpu_summary": "Ray tracing de CPU · reflexos · HDR · llums direccionals i puntuals",
|
||||
"render.cpu_threads": "Processos de CPU",
|
||||
"render.cpu_threads_auto": "Automàtic",
|
||||
"render.cpu_threads_custom": "Personalitzat",
|
||||
"render.cpu_threads_help": "Automàtic fa servir els processos de CPU disponibles. Un procés s'executa en sèrie. Més processos poden necessitar més memòria.",
|
||||
"render.cpu_threads_single": "Un",
|
||||
"render.cpu_threads_web": "El renderitzat al navegador fa servir un procés cooperatiu. Es conserva l'elecció de processos desada per a l'escriptori.",
|
||||
"render.cpu_transparent_help": "El PNG transparent treu el fons i conserva la cobertura de les vores. L'opacitat del cos i de la cara ha de mantenir-se al 100 %.",
|
||||
"render.cpu_volume_enable_path": "Activar la il·luminació indirecta",
|
||||
"render.cpu_volume_enable_path_plan": "Ray tracing de CPU · profunditat {depth} · {spp} mostres/píxel · llavor {seed} · ombres traçades. Conserva l'atmosfera definida i el pressupost d'imatge.",
|
||||
@@ -3419,6 +3459,40 @@
|
||||
"render.cpu_volume_method_incompatible": "Aquests ajustos de llum, mostreig o atmosfera no es poden transferir a aquest mètode. Es conserven els vostres ajustos.",
|
||||
"render.cpu_volume_path_required": "Activeu la il·luminació indirecta per fer servir l'atmosfera de CPU.",
|
||||
"render.cpu_warm_cool": "Càlid i fred",
|
||||
"render.denoise_class_background": "Omès: fons",
|
||||
"render.denoise_class_coverage": "Omès: cobertura parcial",
|
||||
"render.denoise_class_degenerate": "Omès: camí degenerat",
|
||||
"render.denoise_class_depth": "Omès: límit de profunditat del camí",
|
||||
"render.denoise_class_emitter": "Omès: emissor de llum",
|
||||
"render.denoise_class_exit": "Omès: sortida incompatible",
|
||||
"render.denoise_class_identity": "Omès: límit d'identitat de guia",
|
||||
"render.denoise_class_lens": "Omès: profunditat de camp",
|
||||
"render.denoise_class_material": "Omès: material no admès",
|
||||
"render.denoise_class_nested": "Omès: medi imbricat",
|
||||
"render.denoise_class_optical": "Elegible: superfície refractada",
|
||||
"render.denoise_class_reflection": "Omès: punt final reflectant",
|
||||
"render.denoise_class_surface": "Elegible: superfície",
|
||||
"render.denoise_class_tir": "Omès: reflexió total interna",
|
||||
"render.denoise_class_transmission": "Omès: transmissió addicional",
|
||||
"render.denoise_class_unavailable": "Omès: sense guia",
|
||||
"render.denoise_class_volume": "Omès: dispersió de volum",
|
||||
"render.denoise_diagnostics_counts": "Elegibles: {eligible} · Omessos: {skipped}",
|
||||
"render.denoise_diagnostics_enable": "Recollir el diagnòstic de reducció de soroll",
|
||||
"render.denoise_diagnostics_grid": "Recomptes de píxels amb la mida interna {width} × {height}.",
|
||||
"render.denoise_diagnostics_help": "Recull els recomptes de píxels elegibles i omesos fins i tot amb la reducció de soroll desactivada. Els recomptes fan servir la mida interna de renderitzat; la màscara fa servir la mida de sortida.",
|
||||
"render.denoise_diagnostics_title": "Diagnòstic de reducció de soroll",
|
||||
"render.denoise_export_mask": "Exportar la màscara PNG",
|
||||
"render.denoise_firefly": "Suprimir els píxels brillants aïllats",
|
||||
"render.denoise_format_mask": "Màscara PNG",
|
||||
"render.denoise_mask_copy_help": "Exporteu la màscara de reducció de soroll com a PNG o torneu a la imatge renderitzada per copiar-la.",
|
||||
"render.denoise_mask_unavailable": "Activeu el diagnòstic de reducció de soroll i renderitzeu una imatge per inspeccionar-ne la màscara.",
|
||||
"render.denoise_optical_filter": "Filtrar miralls i vidre",
|
||||
"render.denoise_optical_filter_help": "Filtra la llum reflectida i transmesa elegible. Desactiveu-ho per reduir el soroll només a les superfícies opaques.",
|
||||
"render.denoise_passes": "Passades del filtre",
|
||||
"render.denoise_settings_help": "Més passades suavitzen una àrea més gran. La intensitat controla quant filtra cada passada. Els camins òptics no admesos no es filtren.",
|
||||
"render.denoise_strength": "Intensitat de la reducció de soroll",
|
||||
"render.denoise_view_image": "Imatge renderitzada",
|
||||
"render.denoise_view_mask": "Màscara de reducció de soroll",
|
||||
"render.diag_bodies": "Cossos visibles",
|
||||
"render.diag_job_details": "Detalls del treball capturat",
|
||||
"render.diag_last_check": "Última comprovació prèvia",
|
||||
@@ -3973,6 +4047,8 @@
|
||||
"render.material_transient": "Sobreescriptures òptiques temporals d'aquesta pestanya del document. No es desen al disseny, a la configuració de renderitzat ni a la biblioteca de materials.",
|
||||
"render.material_v_up": "La coordenada V apunta cap amunt a la imatge",
|
||||
"render.material_weight": "Pes del recobriment (0–1)",
|
||||
"render.metal_energy_compensation": "Recuperar la reflectància del metall rugós",
|
||||
"render.metal_energy_compensation_help": "Compensa la llum perduda entre les microfacetes del metall rugós. El renderitzat per CPU necessita il·luminació indirecta.",
|
||||
"render.method_cpu": "Ray tracing de CPU",
|
||||
"render.method_gpu": "Path tracing de GPU",
|
||||
"render.method_limit_raster": "El raster fa servir la vista prèvia d'estudi opaca fixa. Trieu un mètode de ray tracing explícit per als controls òptics compatibles.",
|
||||
@@ -4101,6 +4177,8 @@
|
||||
"render.quality_denoise_on": "Reducció de soroll: Activada",
|
||||
"render.quality_draft": "Esborrany",
|
||||
"render.quality_high": "Alt",
|
||||
"render.quality_legacy_samples": "Valor desat: {samples} spp. Les seleccions noves es limiten a {maximum} spp.",
|
||||
"render.quality_preset_limit": "Aquest preajust supera el límit de selecció de 16384 spp. Trieu un nombre de mostres de fins a 16384.",
|
||||
"render.quality_projection_help": "Aquesta revisió només canvia la resolució, el pressupost de mostres, la profunditat del camí, la llavor i la reducció de soroll. Els altres ajustos es conserven; el pressupost no certifica la convergència.",
|
||||
"render.quality_review": "Revisar el pressupost de mostres",
|
||||
"render.quality_summary": "{width} × {height} · {samples} mostres · profunditat {depth} · llavor {seed} · {denoise}",
|
||||
@@ -4248,6 +4326,7 @@
|
||||
"render.show_shots_label": "Mostrar la tira de preses",
|
||||
"render.size_4k": "4K",
|
||||
"render.size_4k_uhd": "4K UHD",
|
||||
"render.size_8k_uhd": "8K UHD",
|
||||
"render.size_custom": "Personalitzat…",
|
||||
"render.size_full_hd": "Full HD",
|
||||
"render.size_hd": "HD",
|
||||
@@ -4410,6 +4489,11 @@
|
||||
"render.subsurface_enable": "Recorregut aleatori de dispersió interior",
|
||||
"render.subsurface_help": "Només dielèctrics tancats. La dispersió i l'absorció RGB són coeficients separats per mm. Els camins es dispersen dins de la geometria real i després es refracten o reflecteixen a la frontera. Desactiveu la transmissió recta d'ombres, la reducció de soroll de superfície i el volum exterior; feu servir un estrat de Fresnel. No és un shader de difusió, una graella de densitat ni un material mesurat. Els medis densos poden necessitar més mostres i profunditat de camí.",
|
||||
"render.subsurface_rate": "Taxa de col·lisions de dispersió",
|
||||
"render.supersampling": "Supermostreig",
|
||||
"render.supersampling_dimensions": "Renderitza {width} × {height} i redueix a {output_width} × {output_height}. Fa servir el quàdruple de píxels.",
|
||||
"render.supersampling_help": "Renderitzeu al doble d'amplada i alçada i després reduïu-ho en llum lineal. La mida de sortida no canvia.",
|
||||
"render.supersampling_off": "Desactivat",
|
||||
"render.supersampling_x2": "2×",
|
||||
"render.surface_import.author": "Autor",
|
||||
"render.surface_import.busy": "S'està important la imatge…",
|
||||
"render.surface_import.complete": "Trieu una imatge i introduïu-ne l'autor, la font i la llicència.",
|
||||
@@ -4423,6 +4507,8 @@
|
||||
"render.surface_import.saved_cpu": "Deseu els mapes per fer-los servir amb el renderitzat de CPU.",
|
||||
"render.surface_import.source": "Font",
|
||||
"render.surface_import.title": "Importar una imatge",
|
||||
"render.texture_filtering": "Filtrar el detall de les textures",
|
||||
"render.texture_filtering_help": "Fa servir nivells mip i filtratge anisotròpic per reduir l'aliasing de les textures en reduir-les. Consumeix més memòria; desactivat manté el filtratge anterior.",
|
||||
"render.tone_aces_fitted": "ACES ajustat",
|
||||
"render.tone_reinhard": "Reinhard",
|
||||
"render.transmission_scope": "El vidre de GPU admet medis disjunts certificats. No s'ofereixen medis imbricats sense restriccions ni un estimador de transmissió sense soroll.",
|
||||
@@ -4653,6 +4739,10 @@
|
||||
"sketch_text.path_clear": "Treure el text de la seva corba",
|
||||
"sketch_text.path_hint": "Corba del bocet que seguirà el text: feu clic aquí i després a la corba",
|
||||
"sketch_text.use_font_file": "Fer servir el fitxer de font {path}",
|
||||
"sketch_text.valign_baseline": "Línia base",
|
||||
"sketch_text.valign_bottom": "Baix",
|
||||
"sketch_text.valign_middle": "Mig",
|
||||
"sketch_text.valign_top": "Dalt",
|
||||
"solid": "sòlid",
|
||||
"status.editing": "Editant {name}",
|
||||
"status.navigation": "Assignació del ratolí: {mapping}",
|
||||
@@ -5517,6 +5607,7 @@
|
||||
"ui.heading_plastic": "PLÀSTIC",
|
||||
"ui.heading_position": "POSICIÓ",
|
||||
"ui.heading_prepare": "PREPARAR",
|
||||
"ui.heading_press_pull": "PRÉMER I ESTIRAR",
|
||||
"ui.heading_rectangular_pattern": "PATRÓ RECTANGULAR",
|
||||
"ui.heading_revolve": "REVOLUCIÓ",
|
||||
"ui.heading_right": "DRETA",
|
||||
@@ -5653,6 +5744,8 @@
|
||||
"ui.mesh_format_3mf": "3MF",
|
||||
"ui.mesh_format_3mf_tagged": "3MF amb etiquetes de cara",
|
||||
"ui.mesh_format_stl": "STL",
|
||||
"ui.mesh_import_origin": "Moure a l'origen",
|
||||
"ui.mesh_import_origin_tip": "Centra la malla en X i Y amb la base a Z = 0. Si està desactivat, la malla conserva les coordenades desades al fitxer.",
|
||||
"ui.minor_radius": "Radi menor",
|
||||
"ui.mirror": "Simetria",
|
||||
"ui.mirror_line": "Línia de simetria",
|
||||
@@ -5757,6 +5850,42 @@
|
||||
"ui.panel_host.surface": "Panell",
|
||||
"ui.panel_host.tab": "Pestanya del panell",
|
||||
"ui.panel_host.tabs": "Totes les pestanyes",
|
||||
"ui.panel_layout.applied": "S'ha aplicat {name} a {workspace}",
|
||||
"ui.panel_layout.cancel": "Cancel·lar",
|
||||
"ui.panel_layout.confirm_replace": "Voleu substituir «{name}»?",
|
||||
"ui.panel_layout.copy": "Copiar",
|
||||
"ui.panel_layout.current": "Disposició actual",
|
||||
"ui.panel_layout.custom": "Personalitzada",
|
||||
"ui.panel_layout.custom_hint": "S'han mogut panells des de {name}.",
|
||||
"ui.panel_layout.details": "Detalls",
|
||||
"ui.panel_layout.layout_workspace": "Espai de treball de disposició",
|
||||
"ui.panel_layout.page_defaults_hint": "Restableix els ajustos d'aquesta pàgina. L'organització dels panells i les disposicions desades es conserven.",
|
||||
"ui.panel_layout.panel_layout": "Disposició de panells",
|
||||
"ui.panel_layout.panel_style": "Estil de panells",
|
||||
"ui.panel_layout.replace": "Substituir la disposició",
|
||||
"ui.panel_layout.replace_current": "Substituir per l'actual",
|
||||
"ui.panel_layout.replace_short": "Substituir",
|
||||
"ui.panel_layout.reset": "Restablir l'espai de treball",
|
||||
"ui.panel_layout.reset_hint": "Restableix {workspace} a la seva disposició predeterminada. Les disposicions desades es conserven.",
|
||||
"ui.panel_layout.reset_short": "Restablir",
|
||||
"ui.panel_layout.restore_failed": "No s'ha pogut restaurar la vostra disposició",
|
||||
"ui.panel_layout.save": "Desar la disposició",
|
||||
"ui.panel_layout.save_as": "Desar com a",
|
||||
"ui.panel_layout.save_as_tile": "Desar com a…",
|
||||
"ui.panel_layout.selected": "seleccionada",
|
||||
"ui.panel_layout.suggested_name": "Disposició {n}",
|
||||
"ui.panel_layout.try_again": "Torneu-ho a provar",
|
||||
"ui.panel_layout.validation.builtin": "Les disposicions integrades no es poden canviar",
|
||||
"ui.panel_layout.validation.duplicate": "Ja teniu aquest nom",
|
||||
"ui.panel_layout.validation.empty": "Introduïu un nom",
|
||||
"ui.panel_layout.validation.full": "64 de 64 desades. Trieu-ne una per substituir-la.",
|
||||
"ui.panel_layout.validation.invalid": "Feu servir d'1 a 64 caràcters, sense caràcters de control",
|
||||
"ui.panel_layout.workspace.classic": "Clàssic",
|
||||
"ui.panel_layout.workspace.modelling": "Modelatge",
|
||||
"ui.panel_layout.workspace.render": "Renderitzat",
|
||||
"ui.panel_layout.workspace.review": "Revisió",
|
||||
"ui.panel_layout.workspace.sketch": "Bocet",
|
||||
"ui.panel_layout.your_layout": "la vostra disposició",
|
||||
"ui.parallel": "Paral·lel",
|
||||
"ui.parameters": "Paràmetres",
|
||||
"ui.part_size_needs_a_part": "Seleccioneu una peça normalitzada inserida (un cargol, una femella, una volandera o un passador) per canviar-ne la mida. Per fer un cos més gran o més petit, feu servir Escala.",
|
||||
@@ -5822,6 +5951,8 @@
|
||||
"ui.profiles": "Perfils",
|
||||
"ui.project": "Projectar",
|
||||
"ui.project_face_edges_sketch": "Projectar arestes de cares als bocets nous",
|
||||
"ui.project_references_construction": "Projectar les referències com a geometria de construcció",
|
||||
"ui.project_references_construction_note": "Projectar, Intersecar, Incloure geometria 3D i les arestes de cara d'un bocet nou sobre una cara creen geometria de construcció: referències sobre les quals dibuixar, excloses dels perfils. Continuen vinculades al model.",
|
||||
"ui.properties": "Propietats",
|
||||
"ui.properties.copy_matrix": "Copiar la matriu",
|
||||
"ui.properties.first_moments": "Primers moments",
|
||||
@@ -5865,6 +5996,8 @@
|
||||
"ui.renderer": "Motor de renderitzat",
|
||||
"ui.repeat": "Repetir",
|
||||
"ui.repeat_nothing": "Encara no hi ha res a repetir: inicieu una eina o un diàleg primer.",
|
||||
"ui.replace_sketch.from_file": "Des d'un fitxer de disseny…",
|
||||
"ui.replace_sketch.no_sketches": "Aquest disseny no té cap bocet per reutilitzar",
|
||||
"ui.replace_with_link_done": "Les còpies ja són col·locacions del disseny vinculat.",
|
||||
"ui.report_a_bug": "Notificar un error",
|
||||
"ui.report_characters_left_one": "Queda {count} caràcter",
|
||||
|
||||
@@ -884,6 +884,7 @@
|
||||
"Variable Radius": "Proměnný poloměr",
|
||||
"Variable radius": "Proměnný poloměr",
|
||||
"Velocity": "Rychlost",
|
||||
"Vertical": "Svisle",
|
||||
"Vertices": "Vrcholy",
|
||||
"View": "Zobrazit",
|
||||
"View navigator": "Navigátor pohledu",
|
||||
@@ -1609,6 +1610,7 @@
|
||||
"dialog.pattern_sketch_not_object": "Vyberte tělesa nebo prvky: náčrt není ani jedno. Opakujte jeho křivky vlastním nástrojem Pole nebo Zrcadlit v náčrtu, nebo jej nejprve vysuňte.",
|
||||
"dialog.primitive_point_tip": "Bod, který vyplní X, Y a Z: klikněte sem a pak na vrchol, hranu nebo plochu modelu, bod náčrtu nebo počátek.",
|
||||
"dialog.reference_edge_tip": "Přímá hrana vybrané plochy, od které se měří vzdálenost níže: klikněte sem a pak na hranu.",
|
||||
"dialog.right_click_pick": "Nejprve vyberte {input}",
|
||||
"dialog.select": "↖ Vybrat",
|
||||
"dialog.selected_count": "↖ Vybráno: {count}",
|
||||
"dialog.selection_constraint": "Vazba {id}",
|
||||
@@ -4654,6 +4656,10 @@
|
||||
"sketch_text.path_clear": "Odpojit text od křivky",
|
||||
"sketch_text.path_hint": "Křivka náčrtu, kterou text sleduje: klikněte sem a poté na křivku",
|
||||
"sketch_text.use_font_file": "Použít soubor písma {path}",
|
||||
"sketch_text.valign_baseline": "Účaří",
|
||||
"sketch_text.valign_bottom": "Dole",
|
||||
"sketch_text.valign_middle": "Uprostřed",
|
||||
"sketch_text.valign_top": "Nahoře",
|
||||
"solid": "těleso",
|
||||
"status.editing": "Upravuje se {name}",
|
||||
"status.navigation": "Přiřazení myši: {mapping}",
|
||||
@@ -4989,6 +4995,7 @@
|
||||
"ui.agent_chat_setup_title": "Nastavit asistenta",
|
||||
"ui.agent_chat_side": "Strana chatu s agentem",
|
||||
"ui.agent_chat_signed_in": "přihlášen",
|
||||
"ui.agent_chat_snap_none_found": "Nebyl nalezen žádný kódovací agent. Balíček Snap běží v izolovaném prostředí, takže nevidí kódovací agenty nainstalované v tomto počítači a nemůže je spustit. Chcete-li je používat, nainstalujte SolidCraft z balíčku AppImage, .deb nebo .rpm. Agent, který používá API kompatibilní s OpenAI, v balíčku Snap funguje: nastavte ho přes Přidat agenta.",
|
||||
"ui.agent_chat_state_auth": "Vyžadováno přihlášení",
|
||||
"ui.agent_chat_state_busy": "Pracuje…",
|
||||
"ui.agent_chat_state_exited": "Agent zastaven",
|
||||
@@ -5185,6 +5192,7 @@
|
||||
"ui.collapse": "Sbalit",
|
||||
"ui.collinear": "Kolineární",
|
||||
"ui.colour_vision": "Barevné vidění",
|
||||
"ui.colour_vision_bends": "Ohyby",
|
||||
"ui.colour_vision_deutan": "Deuteranopie",
|
||||
"ui.colour_vision_deutan_tip": "Pro oslabené nebo chybějící vnímání zelené",
|
||||
"ui.colour_vision_failed": "Selhalo",
|
||||
@@ -5926,6 +5934,8 @@
|
||||
"ui.ribbon_pin_footer": "Připnuté příkazy se zobrazují na pásu karet. Najetím na řádek jej připnete nebo odepnete.",
|
||||
"ui.ribbon_workspace": "Pracovní prostředí",
|
||||
"ui.right": "Zprava",
|
||||
"ui.right_click_confirms": "Pravé kliknutí potvrzuje vstupy dialogu",
|
||||
"ui.right_click_confirms_tip": "Při otevřeném dialogu přejde pravé kliknutí v zobrazení na další prázdný vstup a u posledního provede OK",
|
||||
"ui.save": "Uložit",
|
||||
"ui.save_as": "Uložit jako",
|
||||
"ui.save_mesh_no_slicer_open": "Nenalezen žádný slicer: zvolte Vlastní… a vyberte program svého sliceru",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Værdi",
|
||||
"Variable Radius": "Variabel radius",
|
||||
"Velocity": "Hastighed",
|
||||
"Vertical": "Lodret",
|
||||
"Vertices": "Hjørnepunkter",
|
||||
"View navigator": "Visningsnavigator",
|
||||
"Volume": "Volumen",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "REDIGÉR {title}",
|
||||
"dialog.no_shown_body": "Intet vist emne at ændre: Vis et, eller vælg Nyt emne",
|
||||
"dialog.pattern_sketch_not_object": "Vælg emner eller features: En skitse er ingen af delene. Gentag dens kurver med skitsens eget Mønster eller Spejling, eller ekstruder den først.",
|
||||
"dialog.right_click_pick": "Vælg først {input}",
|
||||
"dialog.select": "↖ Vælg",
|
||||
"dialog.selected_count": "↖ Valgte: {count}",
|
||||
"dialog.selection_constraint": "Binding {id}",
|
||||
@@ -3931,6 +3933,10 @@
|
||||
"sketch_text.path_clear": "Frigør teksten fra dens kurve",
|
||||
"sketch_text.path_hint": "En kurve i skitsen, som teksten følger: Klik her og derefter på kurven",
|
||||
"sketch_text.use_font_file": "Brug skrifttypefilen {path}",
|
||||
"sketch_text.valign_baseline": "Grundlinje",
|
||||
"sketch_text.valign_bottom": "Bund",
|
||||
"sketch_text.valign_middle": "Midte",
|
||||
"sketch_text.valign_top": "Top",
|
||||
"solid": "massivt emne",
|
||||
"status.editing": "Redigerer {name}",
|
||||
"status.navigation": "Musetildeling: {mapping}",
|
||||
@@ -4445,6 +4451,7 @@
|
||||
"ui.collapse": "Fold sammen",
|
||||
"ui.collinear": "Kollineær",
|
||||
"ui.colour_vision": "Farvesyn",
|
||||
"ui.colour_vision_bends": "Bukninger",
|
||||
"ui.colour_vision_deutan": "Deutan",
|
||||
"ui.colour_vision_deutan_tip": "Ved svækket eller manglende følsomhed for grønt",
|
||||
"ui.colour_vision_failed": "Mislykkedes",
|
||||
@@ -5013,6 +5020,8 @@
|
||||
"ui.ribbon_pin_footer": "Fastgjorte kommandoer vises på båndet. Hold musen over en række for at fastgøre eller frigøre den.",
|
||||
"ui.ribbon_workspace": "Arbejdsområde",
|
||||
"ui.right": "Fra højre",
|
||||
"ui.right_click_confirms": "Højreklik bekræfter dialogens input",
|
||||
"ui.right_click_confirms_tip": "Med en dialog åben går et højreklik i visningen videre til næste tomme input, og ved det sidste udføres OK",
|
||||
"ui.save": "Gem",
|
||||
"ui.save_as": "Gem som",
|
||||
"ui.save_mesh_no_slicer_open": "Ingen slicer fundet: Vælg Brugerdefineret… og vælg dit slicerprogram",
|
||||
|
||||
@@ -197,6 +197,7 @@
|
||||
"Drag to move the hole; click to remove it": "Ziehen, um die Bohrung zu verschieben; anklicken, um sie zu entfernen",
|
||||
"Drag to move the rest across the model. It snaps to sketch points on the face.": "Ziehen, um die Auflage über das Modell zu verschieben. Sie rastet an Skizzenpunkten auf der Fläche ein.",
|
||||
"Drag to move the snap fit across the model. It snaps to sketch points on the face.": "Ziehen, um die Rastverbindung über das Modell zu verschieben. Sie rastet an Skizzenpunkten auf der Fläche ein.",
|
||||
"Drag to place it on another face.": "Ziehen, um es auf eine andere Fläche zu setzen.",
|
||||
"Drag to point the catch in another direction.": "Ziehen, um den Rasthaken anders auszurichten.",
|
||||
"Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.": "Ziehen, um die Auflage in 5°-Schritten zu drehen. Alt oder Strg gedrückt halten, um sie stufenlos zu drehen.",
|
||||
"Drive Joint": "Gelenk antreiben",
|
||||
@@ -706,6 +707,7 @@
|
||||
"Value": "Value",
|
||||
"Variable Radius": "Variabler Radius",
|
||||
"Velocity": "Geschwindigkeit",
|
||||
"Vertical": "Vertikal",
|
||||
"Vertices": "Scheitelpunkte",
|
||||
"View navigator": "Ansichtsnavigator",
|
||||
"Volume": "Volumen",
|
||||
@@ -757,6 +759,13 @@
|
||||
"ai.prefs.connect_apps_note": "Aus entfernt die Einträge wieder.\n\nTrägt SolidCraft beim Start als MCP-Server in die auf diesem Computer gefundenen KI-Apps ein (OpenCode, Claude Desktop, Claude Code, Cursor, Codex, Gemini CLI, Copilot CLI, Windsurf, Zed, VS Code), damit ein Agent es ohne Einrichtung nutzen kann. Nur der Eintrag „solidcraft“ wird hinzugefügt oder sein Pfad aktualisiert; ein von Ihnen geänderter Eintrag bleibt unberührt, und die Datei wird vorher gesichert. Aus: Die hinzugefügten Einträge werden entfernt. Hilfe > KI-Assistenten verbinden… erledigt das von Hand.",
|
||||
"ai.prefs.connect_at_start": "Letzten Agenten beim Start verbinden",
|
||||
"ai.prefs.connect_at_start_note": "Verbindet beim Start von SolidCraft automatisch den zuletzt verwendeten Agenten (oder den Standardagenten) im Hintergrund, damit er für den Chat bereitsteht. Diese Funktion ist deaktiviert, wenn SolidCraft mit --control gestartet wird. Kann keine Verbindung hergestellt werden, zeigt der Assistent „Verbindung fehlgeschlagen“ und eine Schaltfläche zum erneuten Verbindungsversuch an.",
|
||||
"ai.prefs.control_failed": "Der Steuerkanal konnte nicht starten: {error}",
|
||||
"ai.prefs.control_from_launch": "Für diese Sitzung mit --control auf Port {port} gestartet. Änderungen hier gelten beim nächsten Start von SolidCraft ohne --control.",
|
||||
"ai.prefs.control_listening": "Wartet auf 127.0.0.1:{port}",
|
||||
"ai.prefs.control_not_listening": "Nicht aktiv",
|
||||
"ai.prefs.control_port": "Port",
|
||||
"ai.prefs.control_port_note": "Der Port, über den sich KI-Agenten auf diesem Computer verbinden (127.0.0.1). Standard ist 27878: Ist er belegt, wird der nächste freie Port genommen. Jeder andere Port wird genau so verwendet. Richte deinen MCP-Client auf denselben Port, zum Beispiel solidcraft-cli mcp --connect 127.0.0.1:7878.",
|
||||
"ai.prefs.control_port_taken": "Port {port} wird von einem anderen Programm (oder einem anderen SolidCraft-Fenster) verwendet. Wähle einen anderen Port.",
|
||||
"ai.prefs.follow_camera": "Der Kamera folgen",
|
||||
"ai.prefs.follow_camera_off": "Die automatische Kameraführung ist aus.",
|
||||
"ai.prefs.follow_camera_on": "Die Kamera dreht sich zu Skizzen, die der Agent erstellt.",
|
||||
@@ -815,6 +824,13 @@
|
||||
"browser.sketches_to_parts_not_on_face": "nicht auf der Fläche eines Teils",
|
||||
"browser.sketches_to_parts_part_missing": "ihr Teil gibt es nicht mehr",
|
||||
"browser.sketches_to_parts_result": "{moved} Skizzen in das Teil verschoben, auf dem sie liegen; {stayed} geblieben: {why}",
|
||||
"browser.straighten_angle": "Richtung der Kante",
|
||||
"browser.straighten_choose": "Wählen Sie, wie die Kante liegen soll (Horizontal, Vertikal oder ein Winkel), und klicken Sie dann auf Ausrichten.",
|
||||
"browser.straighten_click_a": "Klicken Sie im Bild auf ein Ende einer Kante, die gerade sein soll, oder geben Sie die Koordinaten ein.",
|
||||
"browser.straighten_click_b": "Klicken Sie auf das andere Ende der Kante, oder geben Sie die Koordinaten ein.",
|
||||
"browser.straighten_horizontal": "Horizontal",
|
||||
"browser.straighten_title": "Ausrichten: {name}",
|
||||
"browser.straighten_vertical": "Vertikal",
|
||||
"browser.units": "Einheiten: {units}",
|
||||
"cam.flat": "Flachstößel",
|
||||
"cam.follower": "Stößel",
|
||||
@@ -844,6 +860,8 @@
|
||||
"cmd.appearance_pick_up": "Aussehen aufnehmen",
|
||||
"cmd.appearance_replace": "Erscheinungsbild ersetzen",
|
||||
"cmd.assembly_bom": "Stückliste",
|
||||
"cmd.assembly_constraint_create": "Abhängigkeit",
|
||||
"cmd.assembly_constraint_edit": "Abhängigkeit bearbeiten",
|
||||
"cmd.assembly_mass_properties": "Masseeigenschaften",
|
||||
"cmd.body.print_face": "Auflagefläche",
|
||||
"cmd.body_rename": "Körper umbenennen",
|
||||
@@ -862,6 +880,7 @@
|
||||
"cmd.canvas_delete": "Zeichenfläche löschen",
|
||||
"cmd.canvas_edit": "Zeichenfläche bearbeiten",
|
||||
"cmd.canvas_insert": "Zeichenfläche",
|
||||
"cmd.canvas_straighten": "Zeichenfläche ausrichten",
|
||||
"cmd.canvas_to_sketch": "Skizze aus Zeichenfläche",
|
||||
"cmd.component_activate": "Komponente aktivieren",
|
||||
"cmd.component_break_link": "Verknüpfung trennen",
|
||||
@@ -964,6 +983,7 @@
|
||||
"cmd.file_save_mesh": "Als Netz speichern",
|
||||
"cmd.file_send_to_slicer": "An Slicer senden",
|
||||
"cmd.file_slicers": "Installierte Slicer",
|
||||
"cmd.frame_end_cap": "Endkappe",
|
||||
"cmd.frame_member": "Rahmenelement",
|
||||
"cmd.frame_profile_insert": "Profil einfügen",
|
||||
"cmd.frame_profile_list": "Profilbibliothek",
|
||||
@@ -981,6 +1001,7 @@
|
||||
"cmd.inspect_isocurve": "Isokurvenanalyse",
|
||||
"cmd.inspect_minimum_radius": "Mindestradiusanalyse",
|
||||
"cmd.inspect_parameter_sweep": "Parametervariation",
|
||||
"cmd.inspect_parameter_variants": "Parametervarianten vergleichen",
|
||||
"cmd.inspect_silhouette": "Silhouette",
|
||||
"cmd.inspect_zebra": "Zebra-Analyse",
|
||||
"cmd.joint_as_built": "Fertigungsgelenk",
|
||||
@@ -1320,6 +1341,7 @@
|
||||
"cmd.timeline_suppress": "Merkmal unterdrücken",
|
||||
"cmd.ui.assistant": "Assistenten ein-/ausblenden",
|
||||
"cmd.ui.palette": "Befehle suchen",
|
||||
"cmd.ui.toggle_visibility": "Auswahl ein-/ausblenden",
|
||||
"cmd.view.navigator": "Eigener Ansichtsnavigator",
|
||||
"cmd.view.render_browser": "Render-Browser",
|
||||
"cmd.view.render_dock": "Render-Panel verschieben",
|
||||
@@ -1376,6 +1398,7 @@
|
||||
"color.step_down": "Schritt nach unten",
|
||||
"color.step_up": "Schritt nach oben",
|
||||
"color.value": "Hellwert (Prozent)",
|
||||
"component.error.ambiguous_name": "Mehrere Komponenten heißen `{name}`. Verwende eine numerische Komponenten-ID: {ids}.",
|
||||
"config.column_filter_empty": "Keine passenden Spalten",
|
||||
"config.rule_parameter_columns": "Hier stehen nur Parameter mit einer Spalte in der Tabelle. Fügen Sie eine mit „Spalte hinzufügen“ (+) hinzu, um den Parameter hier zu verwenden.",
|
||||
"config.rule_suppression_columns": "Hier stehen nur Funktionen mit einer Spalte „Unterdrücken“ in der Tabelle. Fügen Sie eine mit „Spalte hinzufügen“ (+) hinzu, um die Funktion hier zu steuern.",
|
||||
@@ -1416,6 +1439,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}: Die Referenz `{reference}` existiert nicht mehr so, wie sie ausgewählt wurde; wählen Sie sie erneut aus",
|
||||
"dialog.bodies_count": "{count} Körper",
|
||||
"dialog.clearance_invalid": "der Abstand muss eine Länge von 0 oder mehr sein",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "Berechnen",
|
||||
"dialog.compute_again": "Erneut berechnen",
|
||||
"dialog.computing": "Wird berechnet… {seconds} s",
|
||||
@@ -1432,6 +1456,7 @@
|
||||
"dialog.pattern_sketch_not_object": "Körper oder Funktionen wählen: Eine Skizze ist keines von beiden. Ihre Kurven mit Muster oder Spiegeln in der Skizze wiederholen oder sie zuerst extrudieren.",
|
||||
"dialog.primitive_point_tip": "Ein Punkt, der X, Y und Z füllt: hier klicken, dann einen Eckpunkt, eine Kante oder Fläche des Modells, einen Punkt einer Skizze oder den Ursprung anklicken.",
|
||||
"dialog.reference_edge_tip": "Eine gerade Kante der gewählten Fläche, von der aus der Abstand darunter gemessen wird: hier klicken, dann die Kante anklicken.",
|
||||
"dialog.right_click_pick": "Zuerst {input} auswählen",
|
||||
"dialog.select": "↖ Auswählen",
|
||||
"dialog.selected_count": "↖ {count} ausgewählt",
|
||||
"dialog.selection_constraint": "Bedingung {id}",
|
||||
@@ -1444,6 +1469,9 @@
|
||||
"document.changed_on_disk": "{name} wurde auf dem Datenträger geändert",
|
||||
"document.changed_on_disk_detail": "{name} wurde seit dem Öffnen oder letzten Speichern von einem anderen Programm oder Computer geändert. „Überschreiben“ ersetzt diese Änderungen durch Ihre; „Kopie speichern“ behält beide.",
|
||||
"document.copy_name": "{name} - Kopie",
|
||||
"document.discard_row": "Verwerfen",
|
||||
"document.finish_save_prompt": "Beantworten Sie die Speicherabfrage, bevor Sie einen weiteren Entwurf öffnen.",
|
||||
"document.not_saved_yet": "Noch nicht gespeichert",
|
||||
"document.open_anyway": "Trotzdem öffnen",
|
||||
"document.open_elsewhere": "{name} ist bereits geöffnet",
|
||||
"document.open_elsewhere_detail": "{name} ist in SolidCraft {app} auf {who} geöffnet, seit {when}. Wenn Sie beide speichern, verliert einer von Ihnen Arbeit. Öffnen Sie die Datei schreibgeschützt, um sie anzusehen, ohne sie zu überschreiben.",
|
||||
@@ -1453,6 +1481,9 @@
|
||||
"document.read_only_save": "Dieses Design wurde schreibgeschützt geöffnet: Speichern Sie es als neue Datei",
|
||||
"document.save_changes": "Änderungen in {name} speichern?",
|
||||
"document.save_copy": "Kopie speichern…",
|
||||
"document.save_many": "Änderungen an {n} Entwürfen speichern?",
|
||||
"document.save_row": "Speichern",
|
||||
"document.save_selected": "Auswahl speichern",
|
||||
"document.tab_unsaved_changes": "Ungespeicherte Änderungen",
|
||||
"document.unsaved_changes": "{name} enthält ungespeicherte Änderungen. Wenn Sie nicht speichern, gehen sie verloren.",
|
||||
"drive.rigid": "{joint} ist ein starres Gelenk. Es hält die verbundenen Teile fest zusammen und ermöglicht daher keine Bewegung. Um die Teile beweglich zu machen, ändern Sie den Gelenktyp unter „Gelenk bearbeiten“: Drehgelenk für Drehbewegungen, Schubgelenk für lineare Bewegungen oder Zylindergelenk für beides.",
|
||||
@@ -1472,6 +1503,8 @@
|
||||
"dxf.tolerance": "Kurventoleranz",
|
||||
"dxf.tolerance_help": "Nur sichtbare Körper und angezeigte Skizzen. Kurven werden durch gerade Segmente angenähert. Eine kleinere Toleranz liefert feinere Kurven und benötigt mehr Zeit und Speicher.",
|
||||
"each rail's curves must be in one sketch": "die Kurven jeder Führungskurve müssen in derselben Skizze liegen",
|
||||
"error.end_cap_faces": "Mindestens eine offene Stirnfläche eines Rahmenelements auswählen",
|
||||
"error.end_cap_unresolved": "Ende {ends} dieser Abdeckung ist nicht mehr im Modell. Stirnflächen erneut auswählen",
|
||||
"feature computation ended without a result": "die Berechnung des Merkmals wurde ohne Ergebnis beendet",
|
||||
"file.open.drawing_filter": "Designs, CAD-Dateien, Netze und Zeichnungen",
|
||||
"file.open.portal_fallback.no_portal_service": "Die geöffnete Dateiauswahl ist nicht die des Desktops: Der Dateiauswahl-Dienst des Desktops ist nicht verfügbar.",
|
||||
@@ -1483,6 +1516,7 @@
|
||||
"file_load.inserting": "Geometrie wird eingefügt",
|
||||
"file_load.link_item": "{name} ({done} von {total})",
|
||||
"file_load.opened": "{name} geöffnet",
|
||||
"file_load.opened_behind": "{name} in einem neuen Tab geöffnet",
|
||||
"file_load.opened_in_tab": "{name} in neuem Tab geöffnet",
|
||||
"file_load.opening": "Design wird geöffnet",
|
||||
"file_load.preparing_thumbnail": "Vorschaubild wird vorbereitet...",
|
||||
@@ -1569,6 +1603,7 @@
|
||||
"help.file.send_to_slicer": "Speichert die gewählten Körper als 3MF-Datei und öffnet sie im gewählten Slicer. Damit kommen Sie in einem Schritt vom Modell zum Druck.",
|
||||
"help.font_details": "Die Oberfläche verwendet die integrierten Schriftarten von egui (Ubuntu Light und Hack unter der Ubuntu Font Licence und der MIT/Bitstream-Vera-Lizenz; Noto Emoji und die Emoji-Symbolschrift unter OFL und MIT). Skizzentext verwendet Liberation Sans (SIL OFL 1.1). Das optionale Schriftpaket craft-fonts von The Crafting Apps (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1) ist nicht in SolidCraft-Builds enthalten.",
|
||||
"help.fonts": "Schriftarten",
|
||||
"help.frame.end_cap": "Schließt offene Enden von Rahmenelementen mit Platten in der Form des Profilumrisses. Damit verschließen Sie Rohre, Winkel und Träger, auf dem Ende oder darin eingelassen.",
|
||||
"help.frame.member": "Setzt ein Profil, etwa ein Rohr oder ein Aluprofil, entlang der Linien einer Rahmenskizze, ein Stab je Linie. Für Rahmen, Gestelle und Schweißkonstruktionen.",
|
||||
"help.inspect.accessibility": "Färbt die Flächen, die ein Werkzeug aus einer Richtung erreicht, und die, die es nicht erreicht. Damit prüfen Sie ein Teil auf Fräsen oder Formen von dieser Seite.",
|
||||
"help.inspect.center_of_mass": "Zeigt den Schwerpunkt von Körpern, einzeln und zusammen, bei gleichmäßiger Dichte. Damit prüfen Sie die Balance und wohin ein Teil kippt.",
|
||||
@@ -2032,6 +2067,9 @@
|
||||
"measure.at": "Bei",
|
||||
"measure.item": "Element {number}",
|
||||
"measure.line_to_centre": "Linie zum Mittelpunkt",
|
||||
"measure.perimeter": "Umfang",
|
||||
"measure.perimeter_inner": "Innenumfang",
|
||||
"measure.perimeter_outer": "Außenumfang",
|
||||
"measure.quick_copied": "Messwert kopiert",
|
||||
"measure.quick_copy": "Klicken, um den Messwert zu kopieren",
|
||||
"measure.quick_edges": "{count} Kanten",
|
||||
@@ -2073,6 +2111,8 @@
|
||||
"nav.hfss.help": "Alt+Linksziehen verschiebt, Umschalt+Alt+Linksziehen zoomt, Strg+Linksziehen auf leerer Fläche dreht",
|
||||
"nav.inventor.help": "Mittlere Maustaste verschiebt, Umschalt+Mitte dreht, Strg+Mitte zoomt, rechte Maustaste dreht",
|
||||
"nav.maya.help": "Alt+Linksziehen dreht, Alt+Mitte verschiebt, Alt+Rechtsziehen zoomt; mittleres Ziehen verschiebt ebenfalls",
|
||||
"nav.maya_horizontal_zoom.help": "Alt+Rechtsziehen: nach rechts vergrößern, nach links verkleinern. Ausschalten, um wieder vertikal zu zoomen.",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: horizontal ziehen zum Zoomen",
|
||||
"nav.nx.help": "Mittlere Maustaste dreht, Umschalt+Mitte verschiebt (in NX Mitte + rechts), Strg+Mitte zoomt (in NX Mitte + links); rechtes Ziehen lässt die Kamera unverändert",
|
||||
"nav.openscad.help": "Linksziehen auf leerem Hintergrund dreht, Umschalt+Linksziehen zieht ein Auswahlrechteck auf, Skizzengeometrie wird durch Ziehen bearbeitet; rechtes oder mittleres Ziehen verschiebt, Umschalt+rechtes oder Umschalt+mittleres Ziehen zoomt",
|
||||
"nav.perspective.sketch": "Beim Bearbeiten einer Skizze wird die orthografische Ansicht verwendet. Beenden Sie die Skizze, um die Perspektive umzuschalten.",
|
||||
@@ -2201,6 +2241,16 @@
|
||||
"not a move": "keine Verschiebung",
|
||||
"not a number": "keine Zahl",
|
||||
"open a sketch first": "zuerst eine Skizze öffnen",
|
||||
"operations.cancel": "{name} abbrechen",
|
||||
"operations.cancelled": "{name} abgebrochen",
|
||||
"operations.cancelling": "Wird abgebrochen…",
|
||||
"operations.cannot_cancel": "{name} kann nicht abgebrochen werden",
|
||||
"operations.feature": "Feature",
|
||||
"operations.feature_edit": "Feature bearbeiten",
|
||||
"operations.meshing": "Teile werden geladen",
|
||||
"operations.queued": "Wartet",
|
||||
"operations.stopped": "Abgebrochen",
|
||||
"operations.waiting": "Bereit",
|
||||
"parameters.apply_live": "Jede Änderung beim Verlassen des Feldes übernehmen",
|
||||
"parameters.apply_live_tip": "Aus: Änderungen warten auf Übernehmen oder OK, dann wird das Modell einmal für alle neu aufgebaut. Abbrechen oder Esc verwirft sie.",
|
||||
"parameters.held": "{count} Änderungen warten auf Übernehmen",
|
||||
@@ -2289,6 +2339,7 @@
|
||||
"prefs.appearance.viewport_colours": "Farben der 3D-Ansicht",
|
||||
"prefs.appearance.viewport_logo": "Ansichtsfenster und Logo",
|
||||
"prefs.applies_on_restart": "Wird nach einem Neustart übernommen",
|
||||
"prefs.assemblies": "Baugruppen",
|
||||
"prefs.assistant": "Assistent",
|
||||
"prefs.assistant_connecting": "Verbindung",
|
||||
"prefs.assistant_follow_help": "Look At bei Skizzen bewegt die Ansicht mit dem Zeiger.",
|
||||
@@ -2338,6 +2389,10 @@
|
||||
"prefs.choose_font": "Schriftdatei auswählen…",
|
||||
"prefs.click": "Klicken",
|
||||
"prefs.command_dialog_values": "Befehlsdialoge",
|
||||
"prefs.constraint_glyph_size": "Größe der Bindungssymbole",
|
||||
"prefs.constraint_glyph_size_note": "Wie groß Bindungssymbole samt Buchstaben oder Icons in einer Skizze gezeichnet werden. 100 % ist die übliche Größe; die Symbole behalten diese Bildschirmgröße bei jedem Zoom.",
|
||||
"prefs.construct_menu_groups": "Konstruktionswerkzeuge nach Elementtyp gruppieren",
|
||||
"prefs.construct_menu_groups_help": "Zeigt Überschriften für Ebenen, Achsen und Punkte. Aus behält die ursprüngliche Menüreihenfolge bei.",
|
||||
"prefs.contact_shading": "Weiche Kontaktschattierung",
|
||||
"prefs.contact_shading_note": "Erzeugt weiche Schatten an Stellen, an denen sich Bauteile nahekommen.",
|
||||
"prefs.context_menu": "Kontextmenü",
|
||||
@@ -2373,6 +2428,8 @@
|
||||
"prefs.design_tools.rows": "Zeilen",
|
||||
"prefs.devices": "3D-Maus",
|
||||
"prefs.dialog_buttons": "Dialogschaltflächen",
|
||||
"prefs.dialog_first_letter_buttons": "Dialogschaltflächen reagieren auf ihren Anfangsbuchstaben",
|
||||
"prefs.dialog_first_letter_buttons_help": "Ist ein Dialog geöffnet, drückt der Anfangsbuchstabe einer Beschriftung die zugehörige Schaltfläche: O für OK, A für Abbrechen. Ein Buchstabe, der zu zwei Schaltflächen passt, tut nichts, und ein fokussiertes Textfeld behält die Tasteneingabe. Aus: Eingaben drücken keine Schaltfläche, wie bisher.",
|
||||
"prefs.dialogs": "Dialoge",
|
||||
"prefs.dialogs_edge": "Am Rand der Ansicht",
|
||||
"prefs.dialogs_left_column": "In der linken Spalte",
|
||||
@@ -2386,12 +2443,23 @@
|
||||
"prefs.dimension_values_window": "In einem Fenster",
|
||||
"prefs.display": "Anzeige",
|
||||
"prefs.edges": "Kanten und Schattierung",
|
||||
"prefs.export": "Export",
|
||||
"prefs.export_name": "Dateiname beim Export",
|
||||
"prefs.export_name.body": "Name des exportierten Körpers (des ersten, wenn es mehrere sind)",
|
||||
"prefs.export_name.design": "Name des Designs",
|
||||
"prefs.export_name_hint": "z. B. {design}-{body}",
|
||||
"prefs.export_name_sample": "Beim Export dieses Designs vorgeschlagen: {name}",
|
||||
"prefs.export_name_tip": "Der Dateiname, den Datei › Exportieren und Als Netz speichern vorschlagen. Diese Platzhalter werden ersetzt:\n{placeholders}\nEine nicht gesetzte Konstruktionseigenschaft entfällt. Leer lassen, um den Namen des Designs vorzuschlagen, bei einem Netz den des Körpers.",
|
||||
"prefs.extend": "Erweitern",
|
||||
"prefs.extra_navigation": "Mit Strg und gedrückter linker Maustaste auf einer freien Fläche drehen. Leertaste gedrückt halten, um die Ansicht zu verschieben.",
|
||||
"prefs.extrude_arrow_face_stops": "Extrusionspfeil hält an Flächen",
|
||||
"prefs.extrude_arrow_face_stops_note": "Beim Ziehen des Abstandspfeils von Extrusion hält er an ebenen Flächen parallel zum Profil, etwa an der Rückseite eines Blocks, in den geschnitten wird, und hebt die Fläche hervor. Aus: Der Pfeil bewegt sich nur in runden Schritten.",
|
||||
"prefs.extrude_view_isometric": "Beim Öffnen von Extrudieren isometrisch ausrichten",
|
||||
"prefs.extrude_view_return": "Beim Schließen von Extrudieren zur vorigen Ansicht zurück",
|
||||
"prefs.file_operations_wait": "Auf das Öffnen von Dateien warten",
|
||||
"prefs.file_operations_wait_note": "Während eine Datei geöffnet oder eingefügt wird oder Verknüpfungen neu gelesen werden, wartet die Konstruktion hinter einer Karte mit dem Fortschritt und Abbrechen. Aus: Die Datei erscheint im Vorgangsbereich und Sie können weiterarbeiten; ein Einfügen wird übernommen, sobald Sie fertig sind, und eine inzwischen geöffnete Datei kommt in einen neuen Tab.",
|
||||
"prefs.fillet_legacy_radius": "Den vorherigen Standardradius für Solid-Fillet verwenden",
|
||||
"prefs.fillet_legacy_radius.help": "Standardmäßig aus. Ein: Ein neuer Solid-Fillet öffnet mit der in den Einheiten des Designs gelesenen Zahl 2 (\"2 in\" in einem Design in Zoll), wie zuvor; aus: Er öffnet mit dem Radius, mit dem das Werkzeug ausgeliefert wird, 2 mm, in den Einheiten des Designs angezeigt (\"0.07874 in\" in einem Design in Zoll).",
|
||||
"prefs.follows_os": "Wie im Betriebssystem",
|
||||
"prefs.font": "Schrift",
|
||||
"prefs.font_fallback": "Zeichen, die in der ausgewählten Schrift fehlen, werden mit der integrierten Ersatzschrift dargestellt. So werden keine Beschriftungen als leere Kästchen angezeigt.",
|
||||
@@ -2415,6 +2483,17 @@
|
||||
"prefs.gesture_pan": "Ansicht verschieben",
|
||||
"prefs.gesture_zoom": "Ansicht zoomen",
|
||||
"prefs.graphics": "Grafik",
|
||||
"prefs.graphics_api": "Grafik-API",
|
||||
"prefs.graphics_api_auto": "Automatisch",
|
||||
"prefs.graphics_api_help": "Wählen Sie die Grafik-API zum Starten von SolidCraft. Wenn sich beim nächsten Start kein Fenster öffnen lässt, wird die vorherige Auswahl wiederhergestellt.",
|
||||
"prefs.graphics_api_override": "Eine Startvorgabe bestimmt die Grafik-API. Die gespeicherte Auswahl gilt, wenn SolidCraft normal geöffnet wird.",
|
||||
"prefs.graphics_api_restart_note": "Gilt nach einem Neustart. Ungespeicherte Entwürfe werden vor dem Schließen berücksichtigt.",
|
||||
"prefs.graphics_api_restart_unavailable": "Starten Sie SolidCraft neu, um die gespeicherte Grafik-API anzuwenden.",
|
||||
"prefs.graphics_api_running": "Aktuell: {current}. Für den nächsten Start ausgewählt: {selected}.",
|
||||
"prefs.graphics_api_save_failed": "Die Auswahl der Grafik-API konnte nicht gespeichert werden: {error}",
|
||||
"prefs.graphics_api_start_failed": "Die ausgewählte Grafik-API konnte nicht vorbereitet werden: {error}",
|
||||
"prefs.graphics_api_start_reverted": "Der vorherige Start mit {requested} konnte kein Fenster öffnen. SolidCraft hat {previous} wiederhergestellt.",
|
||||
"prefs.graphics_api_unavailable": "Die Grafik-API kann in der Desktop-App ausgewählt werden.",
|
||||
"prefs.graphics_card": "Grafikkarte",
|
||||
"prefs.graphics_card_auto": "Automatisch",
|
||||
"prefs.graphics_card_missing": "Die gespeicherte Grafikkarte ist nicht verfügbar. Stattdessen wird „Automatisch“ verwendet.",
|
||||
@@ -2458,6 +2537,8 @@
|
||||
"prefs.history_sketches_in_order": "In Erstellungsreihenfolge",
|
||||
"prefs.history_sketches_note": "Wenn „Skizzen“ auf „Unter dem zugehörigen Feature“ eingestellt ist, wird jede Skizze im linken Verlauf eine Ebene unter dem ersten daraus erstellten Feature angezeigt, sofern der Bereich breit genug für die Namen ist. Die Timeline unten zeigt weiterhin die Reihenfolge, in der die Elemente erstellt wurden.",
|
||||
"prefs.history_sketches_under_feature": "Unter dem zugehörigen Feature",
|
||||
"prefs.history_steps_component": "Verlaufsschritte je Komponente",
|
||||
"prefs.history_steps_component_note": "Ist eine Komponente aktiv oder ausgewählt, gehen die Verlaufssteuerelemente durch deren Features, so wie der Verlauf unten sie zeigt. Aus: Sie gehen durch alle Features des Designs. Der Verlauf links oder unter dem Browser geht immer durch alle Features.",
|
||||
"prefs.hold_stop_snapping": "Gedrückt halten, um das Einrasten zu deaktivieren",
|
||||
"prefs.home_fit_size": "Größe bei Home und Einpassen",
|
||||
"prefs.home_fit_size_note": "Wie viel der Ansicht das Modell füllt, wenn Home, Einpassen, ein geöffnetes Design oder ein Ansichtswechsel am Navigator es einrahmt, unabhängig von der Einstellung darunter. 100 %: füllt die Ansicht zwischen den Leisten, dem Kompass und der Navigationsleiste.",
|
||||
@@ -2471,6 +2552,8 @@
|
||||
"prefs.interval_minutes": "{n} min",
|
||||
"prefs.invert_navigator_arrows": "Drehpfeile des Ansichtswürfels umkehren",
|
||||
"prefs.invert_navigator_arrows_note": "Die Pfeile um den Würfel drehen die Kamera in die Richtung, in die sie zeigen, wie in Fusion und Inventor: Der linke Pfeil zeigt nach rechts und schwenkt die Kamera nach rechts. Aus: Ein Pfeil dreht den Würfel zu der Seite hin, an der er sitzt, sodass der linke Pfeil die Kamera nach links schwenkt. Die gebogenen Rollpfeile sind davon nicht betroffen.",
|
||||
"prefs.joint_drag_trackball": "Teile an einem Kugelgelenk beim Ziehen wie einen Trackball drehen",
|
||||
"prefs.joint_drag_trackball_help": "Wenn Sie ein Teil ziehen, das ein Kugelgelenk hält, dreht es sich um die kleinste Drehung um das Gelenk, als rollten Sie eine Kugel von der Größe des Teils. Aus: Der gegriffene Punkt folgt genau dem Zeiger, und das Teil kann sich zusätzlich um ihn drehen.",
|
||||
"prefs.keep_work_on_tab_switch": "Dialoge und Werkzeuge beim Wechsel zwischen Konstruktionen offen lassen",
|
||||
"prefs.keep_work_on_tab_switch_note": "Jeder Konstruktions-Tab behält seinen offenen Dialog oder sein Werkzeug mit allem, was darin ausgewählt und eingegeben wurde, sowie seinen Werkzeugleisten-Tab. Beim Zurückkehren zur Konstruktion ist alles wieder da. Aus: Ein Wechsel bricht sie ab und zeigt den Tab Modell.",
|
||||
"prefs.labels": "Beschriftungen",
|
||||
@@ -2542,6 +2625,8 @@
|
||||
"prefs.not_on_gpu": "Auf dieser GPU nicht verfügbar",
|
||||
"prefs.on": "An",
|
||||
"prefs.opaque": "Undurchsichtig",
|
||||
"prefs.operations_panel": "Vorgänge in der Ansicht zeigen",
|
||||
"prefs.operations_panel_note": "Lange Vorgänge (eine Datei öffnen, ein Feature berechnen, der Befehl eines Agenten) erscheinen unten rechts in der Ansicht mit ihrem Fortschritt und einer Schaltfläche zum Abbrechen. Aus: wie bisher ein Hinweis „Berechnung“.",
|
||||
"prefs.orbit_snap": "Halten Sie beim Drehen die Umschalttaste gedrückt, um die Ansicht an einer Achse einrasten zu lassen.",
|
||||
"prefs.orientation": "Ausrichtung",
|
||||
"prefs.origin_plane_names": "Namen der Ursprungsebenen",
|
||||
@@ -2604,6 +2689,8 @@
|
||||
"prefs.ribbon_reveal": "Suchergebnisse im Menüband zeigen",
|
||||
"prefs.ribbon_reveal_note": "Steht der Zeiger über einem Ergebnis in Befehle suchen, zeigt das Menüband, wo der Befehl liegt: seine Registerkarte, seine Schaltfläche oder seine Zeile im Aufklappmenü eines Panels. Ein aus der Suche gestarteter Befehl blinkt dort, und ein laufender Befehl aus einem Aufklappmenü markiert sein Panel.",
|
||||
"prefs.right_click": "Rechtsklick",
|
||||
"prefs.save_prompt_one_at_a_time": "Beim Schließen mehrerer Entwürfe für jeden ungespeicherten Entwurf einzeln fragen",
|
||||
"prefs.save_prompt_one_at_a_time_help": "Für jeden ungespeicherten Entwurf eine eigene Speicherabfrage statt einer gemeinsamen Liste anzeigen.",
|
||||
"prefs.saving": "Starten und Speichern",
|
||||
"prefs.scale_note": "Die Skalierung lässt sich auch mit Strg + / Strg − im Fenster ändern. Bei 100 % sind die Schaltflächen 28 px groß.",
|
||||
"prefs.scale_text": "Skalierung und Text",
|
||||
@@ -2637,6 +2724,8 @@
|
||||
"prefs.sketch.center_arc": "Mittelpunktbogen folgt dem Zeiger",
|
||||
"prefs.sketch.click_selects": "Klick wählt",
|
||||
"prefs.sketch.conflict_colour": "Konfliktfarbe",
|
||||
"prefs.sketch.cursor_coordinates": "Cursorkoordinaten in der Skizze anzeigen",
|
||||
"prefs.sketch.cursor_coordinates_note": "Neben dem Zeiger seine X- und Y-Werte vom Skizzenursprung, auch ohne aktives Werkzeug. Aus: nur während ein Werkzeug einen Punkt setzt.",
|
||||
"prefs.sketch.drawing": "Zeichnen",
|
||||
"prefs.sketch.ellipse_axes": "Ellipsen mit ihren Achsen zeichnen",
|
||||
"prefs.sketch.ellipse_axes_note": "Haupt- und Nebenachse als Konstruktionslinien, damit Halbachsen und Achsen bemaßt werden können. Aus: nur die Ellipse, und D darauf ergibt ihren Nebenradius, wohin der Wert auch gezogen wird, gezeichnet und mit R beschriftet wie bisher.",
|
||||
@@ -2648,14 +2737,20 @@
|
||||
"prefs.sketch.faces_edges": "Flächen und Kanten",
|
||||
"prefs.sketch.hide_glyphs": "Symbole beim Herauszoomen ausblenden",
|
||||
"prefs.sketch.marks": "Markierungen in der Skizze",
|
||||
"prefs.sketch.max_points": "Größte Skizze",
|
||||
"prefs.sketch.max_points_note": "Die meisten Punkte oder Kurven, die eine Skizze aufnimmt: standardmäßig 20000, höchstens 200000. SVG einfügen und DXF einfügen lehnen eine größere Zeichnung ab. Eine große Skizze wird langsamer gelöst und gezeichnet.",
|
||||
"prefs.sketch.max_points_unit": "Punkte",
|
||||
"prefs.sketch.note": "Zeichnen, Fangen und Auswählen.",
|
||||
"prefs.sketch.opening_closing": "Öffnen und Schließen",
|
||||
"prefs.sketch.prefer_free_points": "Bei Überlappung bewegliche Punkte bevorzugen",
|
||||
"prefs.sketch.project_options": "Zuerst Projektionsoptionen abfragen",
|
||||
"prefs.sketch.recent_snap": "Am Schnittpunkt zweier Hilfslinien fangen",
|
||||
"prefs.sketch.select_3d_curve_points": "Punkte von 3D-Skizzenkurven auswählen",
|
||||
"prefs.sketch.select_3d_curve_points_help": "Punkte auf gezeichneten 3D-Skizzenkurven als Referenzen für Konstruktionselemente anzeigen und auswählen.",
|
||||
"prefs.sketch.select_other_hidden": "Andere auswählen erfasst verdeckte Geometrie",
|
||||
"prefs.sketch.shortcut_cycles_modes": "Erneuter Kurzbefehl wechselt den Modus",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "Aus: Das Werkzeug startet erneut.",
|
||||
"prefs.sketch.snap_to_visible_grid": "Am sichtbaren Schnittpunkt des Rasters fangen",
|
||||
"prefs.sketch.snapping_guides": "Fangen und Hilfslinien",
|
||||
"prefs.sketch.state_icons": "Statussymbole",
|
||||
"prefs.sketch.tracking_guides": "Hilfslinien für Mittelpunkte und Kantenmitten",
|
||||
@@ -2683,6 +2778,7 @@
|
||||
"prefs.sketch_selection": "Skizzen und Auswahl",
|
||||
"prefs.sketch_selection_heading": "Skizzen und Auswahl",
|
||||
"prefs.sketch_selection_note": "Legt fest, wie Skizzenelemente einrasten und wie Klicks Elemente auswählen.",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "Ein Punkt in einer Skizze rastet am Schnittpunkt der vom Raster gezeichneten Linien ein, wenn der Zeiger auf einen davon zeigt, sonst am feineren Gitter zwischen ihnen. Aus: Der Punkt rastet nur am feineren Gitter ein, wie zuvor.",
|
||||
"prefs.sketch_state_icons": "Skizzensymbole in der Farbe ihres Zustands",
|
||||
"prefs.sketch_state_icons_note": "Im Verlauf und im Browser nimmt das Symbol einer Skizze die Farbe ihres Zustands an (unterbestimmt, vollständig bestimmt oder im Konflikt), und ihr Tooltip nennt den Zustand. Aus: Alle Skizzen haben dasselbe Symbol.",
|
||||
"prefs.sketch_tab_always": "Registerkarte Skizze immer zeigen",
|
||||
@@ -3461,6 +3557,10 @@
|
||||
"render.gpu_path_retry": "Erneut versuchen",
|
||||
"render.gpu_seed": "Zufallsstartwert",
|
||||
"render.gpu_unavailable": "GPU-Pathtracing ist auf diesem Gerät nicht bereit.",
|
||||
"render.graphics_api_restart_vulkan": "Mit Vulkan neu starten",
|
||||
"render.graphics_api_restart_warning": "Ein Wechsel der Grafik-API startet SolidCraft neu und fragt nach dem Speichern ungespeicherter Entwürfe. Wenn die neue API kein Fenster öffnen kann, wird beim nächsten Start die vorherige Auswahl wiederhergestellt.",
|
||||
"render.graphics_api_settings": "Grafikeinstellungen",
|
||||
"render.graphics_api_vulkan_required": "GPU-Pathtracing benötigt Vulkan in dieser Sitzung. Starten Sie mit Vulkan neu oder verwenden Sie weiterhin ein CPU-Bildverfahren.",
|
||||
"render.ground_apply": "Boden anpassen und speichern",
|
||||
"render.ground_gap": "Definierter Abstand",
|
||||
"render.ground_linear_rgb": "Diffuser Reflexionsgrad · lineares RGB",
|
||||
@@ -4436,6 +4536,8 @@
|
||||
"sketch.dof_left_one": "{count} Freiheitsgrad übrig",
|
||||
"sketch.draw_curves": "Als {linetype} zeichnen",
|
||||
"sketch.make_selection": "Auswahl als {linetype} markieren",
|
||||
"sketch.move_released": "Verschoben: {count} Abhängigkeiten zum Rest wurden gelöst ({names}).",
|
||||
"sketch.move_released_one": "Verschoben: {count} Abhängigkeit zum Rest wurde gelöst ({names}).",
|
||||
"sketch.open_ends": "Offen {count}",
|
||||
"sketch.status_conflict": "Bedingungen widersprechen sich",
|
||||
"sketch.status_fully_constrained": "vollständig bestimmt",
|
||||
@@ -4466,6 +4568,10 @@
|
||||
"sketch_text.path_clear": "Text von der Kurve lösen",
|
||||
"sketch_text.path_hint": "Eine Skizzenkurve, der der Text folgt: hier klicken, dann die Kurve",
|
||||
"sketch_text.use_font_file": "Schriftdatei {path} verwenden",
|
||||
"sketch_text.valign_baseline": "Grundlinie",
|
||||
"sketch_text.valign_bottom": "Unten",
|
||||
"sketch_text.valign_middle": "Mitte",
|
||||
"sketch_text.valign_top": "Oben",
|
||||
"solid": "Volumenkörper",
|
||||
"status.editing": "{name} wird bearbeitet",
|
||||
"status.navigation": "Mausbelegung: {mapping}",
|
||||
@@ -4664,6 +4770,7 @@
|
||||
"ui.agent_chat_allow_once": "Einmal erlauben",
|
||||
"ui.agent_chat_allowed": "Erlaubt",
|
||||
"ui.agent_chat_answered": "Antwort: {option}",
|
||||
"ui.agent_chat_answered_in": "Beantwortet in {time}",
|
||||
"ui.agent_chat_approval": "Darf der Agent das tun?",
|
||||
"ui.agent_chat_attach_selection": "Auswahl anhängen",
|
||||
"ui.agent_chat_attach_selection_tip": "Das im Modell Ausgewählte (Flächen, Kanten, Merkmale, Körper) mit der Nachricht senden, damit der Agent weiß, was Sie meinen",
|
||||
@@ -4705,6 +4812,7 @@
|
||||
"ui.agent_chat_dock_right": "Rechts andocken",
|
||||
"ui.agent_chat_drop_hint": "Ablegen, um an die nächste Nachricht anzuhängen",
|
||||
"ui.agent_chat_edit": "Bearbeiten",
|
||||
"ui.agent_chat_ended_after": "Beendet nach {time}",
|
||||
"ui.agent_chat_exited": "Der Agent wurde beendet.",
|
||||
"ui.agent_chat_failed_start": "Der Agent konnte nicht starten: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: Eine CAD-Datei wird in das Design importiert, nicht gelesen",
|
||||
@@ -4742,6 +4850,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model} kann die Werkzeuge von SolidCraft nicht verwenden und daher nur chatten. Wählen Sie ein Modell mit Werkzeugunterstützung.",
|
||||
"ui.agent_chat_model_rejected": "Der Agent hat {model} nicht akzeptiert: {error}",
|
||||
"ui.agent_chat_model_search": "Modelle suchen…",
|
||||
"ui.agent_chat_model_search_or_id": "Suchen oder eine beliebige Modell-ID eingeben…",
|
||||
"ui.agent_chat_model_tip": "Das vom Agenten verwendete Modell. Ihre Auswahl wird für diesen Agenten gespeichert.",
|
||||
"ui.agent_chat_models_failed": "Modelle konnten nicht abgerufen werden: {error}",
|
||||
"ui.agent_chat_models_heading": "Verfügbare Modelle",
|
||||
@@ -4799,6 +4908,10 @@
|
||||
"ui.agent_chat_setup_title": "Assistenten einrichten",
|
||||
"ui.agent_chat_side": "Chat andocken",
|
||||
"ui.agent_chat_signed_in": "angemeldet",
|
||||
"ui.agent_chat_snap_none_found": "Kein Coding-Agent gefunden. Das Snap-Paket ist abgeschottet und kann die auf diesem Computer installierten Coding-Agenten weder sehen noch starten. Um sie zu nutzen, installieren Sie SolidCraft stattdessen aus dem AppImage-, .deb- oder .rpm-Paket. Ein Agent, der eine OpenAI-kompatible API nutzt, funktioniert auch im Snap-Paket: Richten Sie ihn mit Agent hinzufügen ein.",
|
||||
"ui.agent_chat_span_h": "{h} Std. {min} Min.",
|
||||
"ui.agent_chat_span_min": "{n} Min.",
|
||||
"ui.agent_chat_span_s": "{n} Sek.",
|
||||
"ui.agent_chat_state_auth": "Anmeldung nötig",
|
||||
"ui.agent_chat_state_busy": "Arbeitet…",
|
||||
"ui.agent_chat_state_exited": "Agent beendet",
|
||||
@@ -4809,6 +4922,10 @@
|
||||
"ui.agent_chat_stop": "Beenden",
|
||||
"ui.agent_chat_stop_tip": "Den Agenten und alles, was er gestartet hat, beenden",
|
||||
"ui.agent_chat_stop_turn_tip": "Agenten stoppen (Esc). Eingereihte Nachrichten bleiben eingereiht.",
|
||||
"ui.agent_chat_thinking_for": "Denkt seit {time} nach",
|
||||
"ui.agent_chat_tool_running_for": "läuft seit {time}",
|
||||
"ui.agent_chat_transcript_assistant": "Assistent:",
|
||||
"ui.agent_chat_transcript_user": "Benutzer:",
|
||||
"ui.agent_chat_turn_limit": "Änderungen pro Nachricht",
|
||||
"ui.agent_chat_turn_unlimited": "Unbegrenzt",
|
||||
"ui.agent_chat_undo_changes": "Diese Änderungen rückgängig machen",
|
||||
@@ -4965,7 +5082,9 @@
|
||||
"ui.browser_bodies_one": "{count} Körper",
|
||||
"ui.browser_bodies_other": "{count} Körper",
|
||||
"ui.browser_collapse": "Browser einklappen",
|
||||
"ui.browser_collapse_below": "Darunter einklappen",
|
||||
"ui.browser_expand": "Browser ausklappen",
|
||||
"ui.browser_expand_below": "Darunter ausklappen",
|
||||
"ui.browser_title": "Browser",
|
||||
"ui.calibrate": "Kalibrieren",
|
||||
"ui.cancel": "Abbrechen",
|
||||
@@ -4993,6 +5112,7 @@
|
||||
"ui.collapse": "Einklappen",
|
||||
"ui.collinear": "Kollinear",
|
||||
"ui.colour_vision": "Farbsehen",
|
||||
"ui.colour_vision_bends": "Biegungen",
|
||||
"ui.colour_vision_deutan": "Deutan",
|
||||
"ui.colour_vision_deutan_tip": "Bei schwachem oder fehlendem Grünsinn",
|
||||
"ui.colour_vision_failed": "Fehler",
|
||||
@@ -5022,6 +5142,9 @@
|
||||
"ui.conic_curve": "Kegelschnitt",
|
||||
"ui.constant": "Konstant",
|
||||
"ui.constraints_conflict": "Bedingungen konfliktreich",
|
||||
"ui.construct_axes": "Achsen",
|
||||
"ui.construct_planes": "Ebenen",
|
||||
"ui.construct_points": "Punkte",
|
||||
"ui.construction": "Konstruktionslinie",
|
||||
"ui.construction.angle_hint": "Konstruktionslinie: Punkt anklicken, dann Winkel eingeben oder Richtung wählen",
|
||||
"ui.construction.bisector_hint": "Winkelhalbierende: zwei sich schneidende Geraden wählen, dann gewünschte Lösung",
|
||||
@@ -5172,6 +5295,17 @@
|
||||
"ui.ellipse": "Ellipse",
|
||||
"ui.emboss_wrap_note": "Senkrechte Linienprofile, die einen unterstützten Zylinder berühren, werden automatisch aufgewickelt. Eine Wand auswählen, um ein Ziel festzulegen.",
|
||||
"ui.end": "Ende",
|
||||
"ui.end_cap.chamfer": "Eckfase",
|
||||
"ui.end_cap.direction": "Richtung",
|
||||
"ui.end_cap.faces": "Stirnflächen",
|
||||
"ui.end_cap.inset": "Einzug",
|
||||
"ui.end_cap.inset_kind": "Einzug als",
|
||||
"ui.end_cap.inset_ratio": "Einzugsverhältnis",
|
||||
"ui.end_cap.inward": "Nach innen",
|
||||
"ui.end_cap.length": "Länge",
|
||||
"ui.end_cap.outward": "Nach außen",
|
||||
"ui.end_cap.ratio": "Anteil der Dicke",
|
||||
"ui.end_cap_title": "ENDKAPPE",
|
||||
"ui.end_radius": "Endradius",
|
||||
"ui.end_scale": "Endskalierung",
|
||||
"ui.entities": "Elemente",
|
||||
@@ -5191,7 +5325,10 @@
|
||||
"ui.explode_needs_two_components": "Die Explosionsdarstellung zieht Komponenten auseinander, daher braucht die Konstruktion mindestens zwei davon (Neue Komponente, Konstruktion einfügen oder Komponenten aus Körpern erstellen)",
|
||||
"ui.exportDxf": "Als DXF exportieren…",
|
||||
"ui.export_ellipsis_keymap": "Exportieren…",
|
||||
"ui.export_glb": "Als GLB exportieren",
|
||||
"ui.export_keymap_tip": "Tasten, S-Box-Favoriten und die Symbolleiste als Datei",
|
||||
"ui.export_selects_only_body": "Einzigen Körper beim Mesh-Export auswählen",
|
||||
"ui.export_selects_only_body_tip": "Als STL exportieren, Als 3MF exportieren und An Slicer senden starten mit dem Körper des Designs ausgewählt, wenn es nur einen hat.",
|
||||
"ui.extend": "Verlängern",
|
||||
"ui.extent_type": "Ausdehnungstyp",
|
||||
"ui.extract_component": "In Datei extrahieren…",
|
||||
@@ -5249,6 +5386,8 @@
|
||||
"ui.fine": "Fein",
|
||||
"ui.finest": "Sehr fein",
|
||||
"ui.finish_sketch": "Skizze beenden",
|
||||
"ui.first_dimension_scales_about_origin": "Um den Skizzenursprung skalieren",
|
||||
"ui.first_dimension_scales_about_origin_tip": "Ein: Die Zeichnung wird immer um den Skizzenursprung vergrößert oder verkleinert, eine vom Ursprung entfernt gezeichnete Form verschiebt sich also. Aus: Eine Zeichnung, die nichts an den Ursprung bindet, wird um ihre eigene Mitte skaliert und bleibt an ihrem Platz.",
|
||||
"ui.fit": "Einpassen",
|
||||
"ui.fix_unfix": "Fixieren/Lösen",
|
||||
"ui.flat": "Flach",
|
||||
@@ -5666,6 +5805,7 @@
|
||||
"ui.project_references_construction_note": "Projizieren, Schneiden, 3D-Geometrie einbeziehen und die Flächenkanten einer neuen Skizze auf einer Fläche erzeugen Konstruktionsgeometrie: Bezüge zum Zeichnen, die nicht zu Profilen gehören. Sie bleiben mit dem Modell verknüpft.",
|
||||
"ui.properties": "Eigenschaften",
|
||||
"ui.properties.copy_matrix": "Matrix kopieren",
|
||||
"ui.properties.copy_value": "Klicken, um den Wert zu kopieren",
|
||||
"ui.properties.first_moments": "Statische Momente",
|
||||
"ui.properties.inertia": "Trägheitsmoment",
|
||||
"ui.properties.inertia_note": "Um den Massenschwerpunkt, in Weltachsen (g·{unit}²)",
|
||||
@@ -5678,6 +5818,7 @@
|
||||
"ui.properties.measuring_failed": "Die Messung wurde vor dem Ende abgebrochen.",
|
||||
"ui.properties.principal_axis": "Hauptachse {number}",
|
||||
"ui.properties.principal_moments": "Hauptträgheitsmomente",
|
||||
"ui.properties.value_copied": "Wert kopiert",
|
||||
"ui.pull_direction": "Entformungsrichtung",
|
||||
"ui.quality": "Qualität",
|
||||
"ui.quantity": "Anzahl",
|
||||
@@ -5697,10 +5838,13 @@
|
||||
"ui.relink_design_changed": "Die Baugruppe hat sich beim Wählen einer Quelle geändert. Starten Sie Quelle neu verknüpfen erneut.",
|
||||
"ui.relink_done": "Quelle für alle Instanzen neu verknüpft.",
|
||||
"ui.relink_not_linked": "Diese Komponente ist nicht mit einem Quelldesign verknüpft.",
|
||||
"ui.relink_one_done": "Quelle für diese Instanz neu verknüpft.",
|
||||
"ui.relink_select_one": "Wählen Sie zuerst eine verknüpfte Komponente oder eine ihrer Instanzen aus.",
|
||||
"ui.relink_source_all": "Quelle neu verknüpfen (alle Instanzen)…",
|
||||
"ui.relink_source_one": "Quelle neu verknüpfen…",
|
||||
"ui.removeFromToolbar": "Aus der Symbolleiste entfernen",
|
||||
"ui.removeSection": "Schnitt entfernen",
|
||||
"ui.renameSelectedBodies": "Ausgewählte Körper umbenennen",
|
||||
"ui.render": "Rendern",
|
||||
"ui.renderer": "Renderer",
|
||||
"ui.repeat": "Wiederholen",
|
||||
@@ -5731,6 +5875,8 @@
|
||||
"ui.ribbon_pin_footer": "Angeheftete Befehle erscheinen im Menüband. Fahren Sie über eine Zeile, um sie anzuheften oder zu lösen.",
|
||||
"ui.ribbon_workspace": "Arbeitsbereich",
|
||||
"ui.right": "Rechts",
|
||||
"ui.right_click_confirms": "Rechtsklick bestätigt Dialogeingaben",
|
||||
"ui.right_click_confirms_tip": "Bei offenem Dialog springt ein Rechtsklick in der Ansicht zur nächsten leeren Eingabe und führt bei der letzten OK aus",
|
||||
"ui.save": "Speichern",
|
||||
"ui.save_as": "Speichern unter",
|
||||
"ui.save_mesh_no_slicer_open": "Kein Slicer gefunden: Wählen Sie „Benutzerdefiniert…“ und wählen Sie Ihr Slicer-Programm",
|
||||
@@ -5826,6 +5972,7 @@
|
||||
"ui.step_values": "Werte mit Pfeilen und Mausrad ändern",
|
||||
"ui.step_values_tip": "Pfeil auf/ab und das Mausrad über einem Wertefeld ändern dessen Zahl.",
|
||||
"ui.stitch_tolerance_hint": "eng",
|
||||
"ui.straighten": "Ausrichten",
|
||||
"ui.stretch": "Strecken",
|
||||
"ui.supersampling": "Supersampling (SSAA)",
|
||||
"ui.supersampling_adaptive": "Nur bei ruhender Ansicht",
|
||||
@@ -5899,6 +6046,8 @@
|
||||
"ui.view_angles_yaw": "Gieren",
|
||||
"ui.view_angles_zero": "{axis} auf 0° setzen",
|
||||
"ui.view_centre": "Ansichtszentrum",
|
||||
"ui.view_compass_tip": "Ansicht von {axis}. Erneut klicken zum Umkehren. Ziehen zum Drehen.",
|
||||
"ui.view_compass_tip_snap": "Ansicht von {axis}. Erneut klicken zum Umkehren. Ziehen zum Drehen; Umschalttaste halten zum Einrasten.",
|
||||
"ui.viewport_status_clear": "{name} ausschalten",
|
||||
"ui.viewport_status_clear_hint": "{name} ausschalten · Esc",
|
||||
"ui.viewport_status_edges": "{count} Kanten",
|
||||
|
||||
+187
-2
@@ -247,6 +247,7 @@
|
||||
"Drag to move the hole; click to remove it": "Drag to move the hole; click to remove it",
|
||||
"Drag to move the rest across the model. It snaps to sketch points on the face.": "Drag to move the rest across the model. It snaps to sketch points on the face.",
|
||||
"Drag to move the snap fit across the model. It snaps to sketch points on the face.": "Drag to move the snap fit across the model. It snaps to sketch points on the face.",
|
||||
"Drag to place it on another face.": "Drag to place it on another face.",
|
||||
"Drag to point the catch in another direction.": "Drag to point the catch in another direction.",
|
||||
"Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.": "Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.",
|
||||
"Drive Joint": "Drive Joint",
|
||||
@@ -513,6 +514,7 @@
|
||||
"Offset Y": "Offset Y",
|
||||
"Offset Z": "Offset Z",
|
||||
"On your computer": "On your computer",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "One more stretch of the picked edge, each with its own angle, height and turns",
|
||||
"Opacity": "Opacity",
|
||||
"Open GitHub": "Open GitHub",
|
||||
"Open GitHub draft": "Open GitHub draft",
|
||||
@@ -634,6 +636,7 @@
|
||||
"Remove the track": "Remove the track",
|
||||
"Remove this bend": "Remove this bend",
|
||||
"Remove this point": "Remove this point",
|
||||
"Remove this segment": "Remove this segment",
|
||||
"Rename Feature": "Rename Feature",
|
||||
"Rename Folder": "Rename Folder",
|
||||
"Render Stage": "Render Stage",
|
||||
@@ -723,6 +726,7 @@
|
||||
"Section position": "Section position",
|
||||
"Sections": "Sections",
|
||||
"Sections (one sketch each)": "Sections (one sketch each)",
|
||||
"Segments": "Segments",
|
||||
"Select Features": "Select Features",
|
||||
"Select Other": "Select Other",
|
||||
"Select Other: hold the left button still on the model (or right-click › Select Other…) to list everything under the cursor; click again on the same spot to select the next thing there. Double-click the middle button to go Home (Preferences › Navigation).": "Select Other: hold the left button still on the model (or right-click › Select Other…) to list everything under the cursor; click again on the same spot to select the next thing there. Double-click the middle button to go Home (Preferences › Navigation).",
|
||||
@@ -772,6 +776,7 @@
|
||||
"Spacing must be a non-zero number": "Spacing must be a non-zero number",
|
||||
"Specialise": "Specialize",
|
||||
"Speed": "Speed",
|
||||
"Split Edge": "Split Edge",
|
||||
"Splitting tool": "Splitting tool",
|
||||
"Square": "Square",
|
||||
"Stainless Steel": "Stainless Steel",
|
||||
@@ -885,6 +890,7 @@
|
||||
"Variable Radius": "Variable Radius",
|
||||
"Variable radius": "Variable radius",
|
||||
"Velocity": "Velocity",
|
||||
"Vertical": "Vertical",
|
||||
"Vertices": "Vertices",
|
||||
"View": "View",
|
||||
"View navigator": "View navigator",
|
||||
@@ -931,13 +937,20 @@
|
||||
"ai.http.confirm": "Allow for this endpoint",
|
||||
"ai.http.warning": "The API key and conversation will be sent unencrypted. Anyone with access to the network may read or change them. Use this only on a network you trust.",
|
||||
"ai.prefs.allow_control": "Let AI agents connect",
|
||||
"ai.prefs.allow_control_note": "A local channel (MCP). Nothing leaves this computer.\n\nOpens a control channel on this computer only (127.0.0.1, port 27878 or the next free one). A program that connects must also show a secret token that only your user account can read, made fresh at every start. Takes effect the next time SolidCraft starts. Off: nothing listens unless you start SolidCraft with --control.",
|
||||
"ai.prefs.allow_control_note": "A local channel (MCP). Nothing leaves this computer.\n\nOpens a control channel on this computer only (127.0.0.1, on the port below; 27878 takes the next free one when it is in use). A program that connects must also show a secret token that only your user account can read, made fresh at every start. Takes effect at once. Off: nothing listens unless you start SolidCraft with --control.",
|
||||
"ai.prefs.availability": "Availability",
|
||||
"ai.prefs.background_commands": "Run slow commands in the background",
|
||||
"ai.prefs.connect_apps": "Add SolidCraft to AI apps",
|
||||
"ai.prefs.connect_apps_note": "Off takes the entries out again.\n\nWhen SolidCraft starts, adds it as an MCP server to the AI apps found on this computer (OpenCode, Claude Desktop, Claude Code, Cursor, Codex, Gemini CLI, Copilot CLI, Windsurf, Zed, VS Code), so an agent can use it without any setup. Only the solidcraft entry is added or its path refreshed; an entry you changed is left alone, and the file is backed up first. Off: the entries it added are removed. Help > Connect AI assistants… does this by hand.",
|
||||
"ai.prefs.connect_at_start": "Connect the last agent at start",
|
||||
"ai.prefs.connect_at_start_note": "Starts the agent you connected last (or the default one) in the background each time SolidCraft starts, so it is ready for chatting. Not when SolidCraft is started with --control. If it cannot connect, the Assistant shows Connection failed and a Retry button.",
|
||||
"ai.prefs.control_failed": "The control channel could not start: {error}",
|
||||
"ai.prefs.control_from_launch": "Started with --control on port {port} for this run. Changes here take effect the next time SolidCraft starts without --control.",
|
||||
"ai.prefs.control_listening": "Listening on 127.0.0.1:{port}",
|
||||
"ai.prefs.control_not_listening": "Not listening",
|
||||
"ai.prefs.control_port": "Port",
|
||||
"ai.prefs.control_port_note": "The port AI agents connect to on this computer (127.0.0.1). 27878 is the default: when it is in use, the next free port is taken. Any other port is used exactly. Point your MCP client at the same port, for example solidcraft-cli mcp --connect 127.0.0.1:7878.",
|
||||
"ai.prefs.control_port_taken": "Port {port} is in use by another program (or another SolidCraft window). Choose another port.",
|
||||
"ai.prefs.follow_camera": "Follow the camera",
|
||||
"ai.prefs.follow_camera_off": "Automatic camera following is off.",
|
||||
"ai.prefs.follow_camera_on": "The camera turns to face sketches the agent creates.",
|
||||
@@ -998,6 +1011,13 @@
|
||||
"browser.sketches_to_parts_not_on_face": "not on a part's face",
|
||||
"browser.sketches_to_parts_part_missing": "their part is gone",
|
||||
"browser.sketches_to_parts_result": "Moved {moved} sketches to the part they're on; {stayed} stayed: {why}",
|
||||
"browser.straighten_angle": "Edge direction",
|
||||
"browser.straighten_choose": "Choose Horizontal, Vertical or Angle for the edge, then press Straighten.",
|
||||
"browser.straighten_click_a": "Click the image at one end of an edge that should be straight, or type its coordinates.",
|
||||
"browser.straighten_click_b": "Click the other end of the edge, or type its coordinates.",
|
||||
"browser.straighten_horizontal": "Horizontal",
|
||||
"browser.straighten_title": "Straighten: {name}",
|
||||
"browser.straighten_vertical": "Vertical",
|
||||
"browser.units": "Units: {units}",
|
||||
"cam.flat": "Flat face",
|
||||
"cam.follower": "Follower",
|
||||
@@ -1027,6 +1047,8 @@
|
||||
"cmd.appearance_pick_up": "Pick Up Appearance",
|
||||
"cmd.appearance_replace": "Replace Appearance",
|
||||
"cmd.assembly_bom": "Bill of Materials",
|
||||
"cmd.assembly_constraint_create": "Constrain",
|
||||
"cmd.assembly_constraint_edit": "Edit Constraint",
|
||||
"cmd.assembly_mass_properties": "Mass Properties",
|
||||
"cmd.body.print_face": "Print Face",
|
||||
"cmd.body_rename": "Rename Body",
|
||||
@@ -1045,6 +1067,7 @@
|
||||
"cmd.canvas_delete": "Delete Canvas",
|
||||
"cmd.canvas_edit": "Edit Canvas",
|
||||
"cmd.canvas_insert": "Canvas",
|
||||
"cmd.canvas_straighten": "Straighten Canvas",
|
||||
"cmd.canvas_to_sketch": "Canvas to Sketch",
|
||||
"cmd.component_activate": "Activate Component",
|
||||
"cmd.component_break_link": "Break Link",
|
||||
@@ -1086,7 +1109,10 @@
|
||||
"cmd.config_rule": "Configuration Rule",
|
||||
"cmd.config_rules": "Configuration Rules",
|
||||
"cmd.config_table": "Display Configuration Table",
|
||||
"cmd.construct.axis": "Axis",
|
||||
"cmd.construct.plane": "Plane",
|
||||
"cmd.construct.plane.axis_point": "Plane Through Axis And Point",
|
||||
"cmd.construct.point": "Point",
|
||||
"cmd.construct_axis_edge": "Axis Through Edge",
|
||||
"cmd.construct_axis_normal_to_face": "Axis Perpendicular To Face",
|
||||
"cmd.construct_axis_through_cylinder": "Axis Through Cylinder/Cone/Torus",
|
||||
@@ -1149,6 +1175,7 @@
|
||||
"cmd.file_save_mesh": "Save As Mesh",
|
||||
"cmd.file_send_to_slicer": "Send to Slicer",
|
||||
"cmd.file_slicers": "Installed Slicers",
|
||||
"cmd.frame_end_cap": "End Cap",
|
||||
"cmd.frame_member": "Frame Member",
|
||||
"cmd.frame_profile_insert": "Insert Profile",
|
||||
"cmd.frame_profile_list": "Profile Library",
|
||||
@@ -1169,6 +1196,7 @@
|
||||
"cmd.inspect_isocurve": "Isocurve Analysis",
|
||||
"cmd.inspect_minimum_radius": "Minimum Radius Analysis",
|
||||
"cmd.inspect_parameter_sweep": "Parameter Sweep",
|
||||
"cmd.inspect_parameter_variants": "Compare Parameter Variants",
|
||||
"cmd.inspect_silhouette": "Silhouette",
|
||||
"cmd.inspect_zebra": "Zebra Analysis",
|
||||
"cmd.joint_as_built": "As-Built Joint",
|
||||
@@ -1222,6 +1250,10 @@
|
||||
"cmd.motion_trace": "Motion Trace",
|
||||
"cmd.motion_trace_edit": "Edit Motion Trace",
|
||||
"cmd.motion_trace_keep": "Keep Motion Trace",
|
||||
"cmd.note_add": "Add Note",
|
||||
"cmd.note_delete": "Delete Note",
|
||||
"cmd.note_list": "List Notes",
|
||||
"cmd.note_update": "Edit Note",
|
||||
"cmd.occurrence_align": "Align Occurrence",
|
||||
"cmd.occurrence_copy": "Paste (Instance)",
|
||||
"cmd.occurrence_drag": "Drag Occurrence",
|
||||
@@ -1347,6 +1379,7 @@
|
||||
"cmd.render_start": "Render Image",
|
||||
"cmd.render_status": "Render Progress",
|
||||
"cmd.select_clear": "Clear Selection",
|
||||
"cmd.selection_get": "Get Selection",
|
||||
"cmd.settings_profile_apply": "Apply Settings Profile",
|
||||
"cmd.settings_profile_delete": "Delete Settings Profile",
|
||||
"cmd.settings_profile_export": "Export Settings Profile",
|
||||
@@ -1510,6 +1543,7 @@
|
||||
"cmd.timeline_suppress": "Suppress Feature",
|
||||
"cmd.ui.assistant": "Toggle Assistant",
|
||||
"cmd.ui.palette": "Search Commands",
|
||||
"cmd.ui.toggle_visibility": "Show/Hide Selection",
|
||||
"cmd.view.navigator": "Custom View Navigator",
|
||||
"cmd.view.render_browser": "Render Browser",
|
||||
"cmd.view.render_dock": "Move Render Dock",
|
||||
@@ -1567,6 +1601,7 @@
|
||||
"color.step_down": "Step down",
|
||||
"color.step_up": "Step up",
|
||||
"color.value": "Value, the brightness (percent)",
|
||||
"component.error.ambiguous_name": "Several components are named `{name}`. Use a numeric component ID: {ids}.",
|
||||
"config.column_filter_empty": "No matching columns",
|
||||
"config.rule_parameter_columns": "Only parameters with a column in the table are listed. Add one with Add Column (+) to use it here.",
|
||||
"config.rule_suppression_columns": "Only features with a Suppress column in the table are listed. Add one with Add Column (+) to drive it here.",
|
||||
@@ -1607,6 +1642,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}: the reference `{reference}` no longer exists as it was picked; reselect it",
|
||||
"dialog.bodies_count": "{count} bodies",
|
||||
"dialog.clearance_invalid": "the clearance must be a length of 0 or more",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "Compute",
|
||||
"dialog.compute_again": "Compute again",
|
||||
"dialog.computing": "Computing… {seconds} s",
|
||||
@@ -1619,10 +1655,12 @@
|
||||
"dialog.dimension_step_expression": "Only a number steps; an expression stays as typed",
|
||||
"dialog.dimension_step_up": "Up by {step}",
|
||||
"dialog.edit_title": "EDIT {title}",
|
||||
"dialog.hole_held_off_its_line": "The reference edge holds this hole on a line that leaves the face before the picked point. Pick where the line crosses the face, or take the edge out to move the hole freely.",
|
||||
"dialog.no_shown_body": "No shown body to change: show one, or choose New Body",
|
||||
"dialog.pattern_sketch_not_object": "Pick bodies or features: a sketch is neither. Repeat its curves with the sketch's own Pattern or Mirror, or extrude it first.",
|
||||
"dialog.primitive_point_tip": "A point that fills X, Y and Z: click here, then click a vertex, edge or face of the model, a point of a sketch, or the origin.",
|
||||
"dialog.reference_edge_tip": "A straight edge of the picked face to measure the distance below from: click here, then click the edge.",
|
||||
"dialog.right_click_pick": "Select {input} first",
|
||||
"dialog.select": "↖ Select",
|
||||
"dialog.selected_count": "↖ {count} selected",
|
||||
"dialog.selection_constraint": "Constraint {id}",
|
||||
@@ -1636,9 +1674,12 @@
|
||||
"document.changed_on_disk": "{name} changed on disk",
|
||||
"document.changed_on_disk_detail": "{name} was changed by another program or computer since you opened or last saved it. Overwrite replaces those changes with yours; Save a Copy keeps both.",
|
||||
"document.copy_name": "{name} copy",
|
||||
"document.discard_row": "Discard",
|
||||
"document.finish_save_prompt": "Finish answering the save prompt before opening another design.",
|
||||
"document.newer_file": "Saved by a newer SolidCraft (format {format}, this version reads up to {reads}). If something's missing, update.",
|
||||
"document.newer_file_change": "Saved by a newer SolidCraft (format {format} with `{change}`, which this version doesn't know). If something's missing, update.",
|
||||
"document.newer_file_not_read": "Not read: {what}. Saving keeps it.",
|
||||
"document.not_saved_yet": "Not saved yet",
|
||||
"document.open_anyway": "Open Anyway",
|
||||
"document.open_elsewhere": "{name} is already open",
|
||||
"document.open_elsewhere_detail": "{name} is open in SolidCraft {app} on {who}, opened {when}. If you both save, one of you loses work. Open it read-only to look at it without saving over it.",
|
||||
@@ -1648,6 +1689,9 @@
|
||||
"document.read_only_save": "This design was opened read-only: save it as a new file",
|
||||
"document.save_changes": "Save changes to {name}?",
|
||||
"document.save_copy": "Save a Copy…",
|
||||
"document.save_many": "Save changes to {n} designs?",
|
||||
"document.save_row": "Save",
|
||||
"document.save_selected": "Save Selected",
|
||||
"document.tab_unsaved_changes": "Unsaved changes",
|
||||
"document.unsaved_changes": "{name} has unsaved changes. If you don't save, they are lost.",
|
||||
"drive.rigid": "{joint} is a rigid joint: it holds its parts still, so it has nothing to drive. To let them move, change its type in Edit Joint: Revolute to rotate, Slider to slide, Cylindrical for both.",
|
||||
@@ -1667,6 +1711,8 @@
|
||||
"dxf.tolerance": "Curve tolerance",
|
||||
"dxf.tolerance_help": "Visible bodies and shown sketches only. Curves use straight segments. Smaller tolerance gives finer curves and uses more time and memory.",
|
||||
"each rail's curves must be in one sketch": "each rail's curves must be in one sketch",
|
||||
"error.end_cap_faces": "Pick at least one open end face of a frame member",
|
||||
"error.end_cap_unresolved": "End {ends} of this cap is no longer on the model. Pick the end faces again",
|
||||
"feature computation ended without a result": "feature computation ended without a result",
|
||||
"file.open.drawing_filter": "Designs, CAD files, meshes and drawings",
|
||||
"file.open.portal_fallback.no_portal_service": "The file chooser that opened is not the desktop's own: the desktop portal service is not available.",
|
||||
@@ -1678,6 +1724,7 @@
|
||||
"file_load.inserting": "Inserting geometry",
|
||||
"file_load.link_item": "{name} ({done} of {total})",
|
||||
"file_load.opened": "Opened {name}",
|
||||
"file_load.opened_behind": "{name} opened in a new tab",
|
||||
"file_load.opened_in_tab": "Opened {name} in a new tab",
|
||||
"file_load.opening": "Opening design",
|
||||
"file_load.preparing_thumbnail": "Preparing the thumbnail...",
|
||||
@@ -1725,11 +1772,13 @@
|
||||
"help.config.table": "Shows the configuration table: one row per variant, one column per parameter or feature, and whether the design still matches the active row. Use it to review the variants of a design.",
|
||||
"help.connect_note": "Restart each assistant to load the SolidCraft server. Each file was backed up as .bak before it changed.",
|
||||
"help.connect_title": "Connect AI assistants",
|
||||
"help.construct.axis": "Creates a construction axis with the method your picks call for: along an edge or line, through a hole or round face, where two planes meet, through two points, or square to a face through a point. Use it when you know the references and not the method.",
|
||||
"help.construct.axis.edge": "Creates a construction axis along a straight edge or sketch line. Use it as the axis for a revolve, a circular pattern or a joint.",
|
||||
"help.construct.axis.normal_to_face": "Creates a construction axis through a point, square to a face. Use it as an axis that stands straight out of a surface.",
|
||||
"help.construct.axis.through_cylinder": "Creates a construction axis through the centre of a cylinder, cone or torus face, or a circular edge. Use it to turn or pattern features around a round part.",
|
||||
"help.construct.axis.two_planes": "Creates a construction axis where two planes or flat faces meet. Use it when the axis you need is the line between two faces.",
|
||||
"help.construct.axis.two_points": "Creates a construction axis through two points, vertices or sketch points. Use it for an axis that runs between two known positions.",
|
||||
"help.construct.plane": "Creates a construction plane with the method your picks call for: offset from a plane, through a point, between two planes, through lines or points, tangent to a curved face, or square to a path. Use it when you know the references and not the method.",
|
||||
"help.construct.plane.along_path": "Creates a construction plane square to an edge or curve, at a position along it. Use it to sketch a profile for a sweep or a section of a path.",
|
||||
"help.construct.plane.at_angle": "Creates a construction plane turned by an angle from a plane or face, about an axis or edge. Turn on Use axis direction only to project the axis onto the base and pivot about a point on that plane (the base origin when none is picked). Use it for sloped sketches, such as an angled bracket.",
|
||||
"help.construct.plane.axis_point": "Creates a construction plane containing an axis and a point off that axis. Pick an origin or construction axis, a straight edge or sketch line, then a vertex, sketch point or construction point. A point on the axis cannot define a unique plane.",
|
||||
@@ -1739,6 +1788,7 @@
|
||||
"help.construct.plane.tangent": "Creates a construction plane that touches a cylinder, cone, sphere or torus at a point. Use it to sketch on the side of a round part.",
|
||||
"help.construct.plane.three_points": "Creates a construction plane through three points. Use it for a plane set by positions on the model, such as three corners.",
|
||||
"help.construct.plane.two_edges": "Creates a construction plane through two straight edges or lines that lie in one plane. Use it for a plane across a part, such as through two opposite edges.",
|
||||
"help.construct.point": "Creates a construction point with the method your picks call for: at a vertex, at the centre of a circle or sphere, along an edge, where two lines or three planes meet, or where a line crosses a plane. Use it when you know the references and not the method.",
|
||||
"help.construct.point.along_path": "Creates a construction point at a position along an edge or curve. Use it as a reference partway along a path.",
|
||||
"help.construct.point.center": "Creates a construction point at the centre of a circular edge, sketch circle or arc, sphere or torus. Use it as a reference for holes, axes and joints.",
|
||||
"help.construct.point.edge_plane": "Creates a construction point where an edge or line passes through a plane or flat face. Use it to mark where a path crosses a plane.",
|
||||
@@ -1764,6 +1814,7 @@
|
||||
"help.file.send_to_slicer": "Saves the selected bodies as a 3MF file and opens it in the slicer you choose. Use it to go from the model to printing in one step.",
|
||||
"help.font_details": "The interface uses egui's built-in fonts (Ubuntu Light and Hack, under the Ubuntu Font Licence and the MIT/Bitstream Vera license; Noto Emoji and the emoji icon font, under the OFL and MIT). Sketch text uses Liberation Sans (SIL OFL 1.1). The Crafting Apps' optional font pack, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), is not bundled in SolidCraft builds.",
|
||||
"help.fonts": "Fonts",
|
||||
"help.frame.end_cap": "Closes the open ends of frame members with plates shaped like the profile's outline. Use it to seal tubes, angles and beams, on top of the end or set into it.",
|
||||
"help.frame.member": "Places a profile, such as a tube or an aluminium extrusion, along the lines of a frame sketch, one member per line. Use it to build frames, racks and welded structures.",
|
||||
"help.inspect.accessibility": "Colours the faces a tool can reach from one direction, and those it cannot. Use it to check a part for machining or moulding from that side.",
|
||||
"help.inspect.center_of_mass": "Shows the centre of mass of bodies, each on its own and all together, at uniform density. Use it to check balance and where a part will tip.",
|
||||
@@ -2240,6 +2291,9 @@
|
||||
"measure.at": "At",
|
||||
"measure.item": "Item {number}",
|
||||
"measure.line_to_centre": "Line to center",
|
||||
"measure.perimeter": "Perimeter",
|
||||
"measure.perimeter_inner": "Inner perimeter",
|
||||
"measure.perimeter_outer": "Outer perimeter",
|
||||
"measure.quick_copied": "Measurement copied",
|
||||
"measure.quick_copy": "Click to copy the measurement",
|
||||
"measure.quick_edges": "{count} edges",
|
||||
@@ -2281,6 +2335,8 @@
|
||||
"nav.hfss.help": "Alt+left drag pans, Shift+Alt+left zooms, Ctrl+left drag on empty space orbits",
|
||||
"nav.inventor.help": "Middle drag pans, Shift+middle orbits, Ctrl+middle zooms, right drag orbits",
|
||||
"nav.maya.help": "Alt+left drag orbits, Alt+middle pans, Alt+right zooms; middle drag also pans",
|
||||
"nav.maya_horizontal_zoom.help": "Alt+right drag: right zooms in, left zooms out. Turn off to restore vertical drag zoom.",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: horizontal drag zoom",
|
||||
"nav.nx.help": "Middle drag orbits, Shift+middle pans (NX's middle + right), Ctrl+middle zooms (NX's middle + left); right drag leaves the camera",
|
||||
"nav.openscad.help": "Left drag on empty space orbits, Shift+left drag box-selects, sketch geometry drags edit; right or middle drag pans, Shift+right or Shift+middle drag zooms",
|
||||
"nav.orbit_cursor_wrap.help": "An orbit drag that reaches the edge of the view moves the cursor to the opposite edge and keeps turning. Off: the drag stops at the edge of the screen. Has no effect on Wayland or in the browser.",
|
||||
@@ -2411,6 +2467,16 @@
|
||||
"not a move": "not a move",
|
||||
"not a number": "not a number",
|
||||
"open a sketch first": "open a sketch first",
|
||||
"operations.cancel": "Cancel {name}",
|
||||
"operations.cancelled": "{name} cancelled",
|
||||
"operations.cancelling": "Cancelling…",
|
||||
"operations.cannot_cancel": "{name} can't be cancelled",
|
||||
"operations.feature": "Feature",
|
||||
"operations.feature_edit": "Edit feature",
|
||||
"operations.meshing": "Loading parts",
|
||||
"operations.queued": "Queued",
|
||||
"operations.stopped": "Cancelled",
|
||||
"operations.waiting": "Ready",
|
||||
"parameters.apply_live": "Apply each change as you leave its field",
|
||||
"parameters.apply_live_tip": "Off: changes wait until Apply or OK, then the design rebuilds once for all of them. Cancel or Escape drops them.",
|
||||
"parameters.held": "{count} changes waiting for Apply",
|
||||
@@ -2499,6 +2565,7 @@
|
||||
"prefs.appearance.viewport_colours": "3D view colors",
|
||||
"prefs.appearance.viewport_logo": "Viewport and logo",
|
||||
"prefs.applies_on_restart": "Applies on restart",
|
||||
"prefs.assemblies": "Assemblies",
|
||||
"prefs.assistant": "Assistant",
|
||||
"prefs.assistant_connecting": "Connecting",
|
||||
"prefs.assistant_follow_help": "Look At sketches move the view with the pointer.",
|
||||
@@ -2551,6 +2618,10 @@
|
||||
"prefs.choose_font": "Choose font file…",
|
||||
"prefs.click": "Click",
|
||||
"prefs.command_dialog_values": "Command dialogs",
|
||||
"prefs.constraint_glyph_size": "Constraint glyph size",
|
||||
"prefs.constraint_glyph_size_note": "How large constraint glyphs and their letters or icons are drawn in a sketch. 100% is the usual size; glyphs keep this screen size at every zoom.",
|
||||
"prefs.construct_menu_groups": "Group Construct tools by entity type",
|
||||
"prefs.construct_menu_groups_help": "Show Planes, Axes and Points headings. Off keeps the original menu order.",
|
||||
"prefs.contact_shading": "Soft contact shading",
|
||||
"prefs.contact_shading_note": "Soft shading where parts come close.",
|
||||
"prefs.context_menu": "Context menu",
|
||||
@@ -2586,6 +2657,8 @@
|
||||
"prefs.design_tools.rows": "Rows",
|
||||
"prefs.devices": "3D mouse",
|
||||
"prefs.dialog_buttons": "Dialog buttons",
|
||||
"prefs.dialog_first_letter_buttons": "Dialog buttons answer their first letter",
|
||||
"prefs.dialog_first_letter_buttons_help": "With a dialog open, typing the first letter of a button's label presses it: O for OK, C for Cancel. A letter that fits two buttons does nothing, and a focused text field keeps the keystroke. Off: typing does nothing to the buttons, as before.",
|
||||
"prefs.dialogs": "Dialogs",
|
||||
"prefs.dialogs_edge": "At the view's edge",
|
||||
"prefs.dialogs_left_column": "In the left column",
|
||||
@@ -2599,12 +2672,23 @@
|
||||
"prefs.dimension_values_window": "In a window",
|
||||
"prefs.display": "Display",
|
||||
"prefs.edges": "Edges and shading",
|
||||
"prefs.export": "Export",
|
||||
"prefs.export_name": "Export file name",
|
||||
"prefs.export_name.body": "Exported body's name (the first one when there are several)",
|
||||
"prefs.export_name.design": "Design name",
|
||||
"prefs.export_name_hint": "e.g. {design}-{body}",
|
||||
"prefs.export_name_sample": "Exporting this design offers: {name}",
|
||||
"prefs.export_name_tip": "The file name File › Export and Save As Mesh offer. These placeholders are replaced:\n{placeholders}\nA design property that is not set is left out. Leave the field empty to offer the design's name, or the body's for a mesh.",
|
||||
"prefs.extend": "Extend",
|
||||
"prefs.extra_navigation": "Ctrl+left drag on empty space orbits; hold Space to pan.",
|
||||
"prefs.extrude_arrow_face_stops": "Extrude arrow stops at faces",
|
||||
"prefs.extrude_arrow_face_stops_note": "Dragging Extrude's distance arrow stops at flat faces parallel to the profile, such as the far side of a block being cut, and outlines the face. Off: the arrow moves in round steps only.",
|
||||
"prefs.extrude_view_isometric": "Turn the view to isometric when Extrude opens",
|
||||
"prefs.extrude_view_return": "Go back to the earlier view when Extrude closes",
|
||||
"prefs.file_operations_wait": "Wait for files to open",
|
||||
"prefs.file_operations_wait_note": "While a file opens or is inserted, or links are read again, the design waits behind a card with the file's progress and Cancel. Off: the file shows in the operations panel and you can keep working; an insert lands once you finish what you are doing, and a file opened meanwhile goes in a new tab.",
|
||||
"prefs.fillet_legacy_radius": "Use the previous Solid Fillet radius default",
|
||||
"prefs.fillet_legacy_radius.help": "Off by default. When on, a new Solid Fillet opens at the number 2 read in the design's units (\"2 in\" in an inch design), as before; when off, it opens at the radius the tool ships with, 2 mm, shown in the design's units (\"0.07874 in\" in an inch design).",
|
||||
"prefs.follows_os": "Follows the OS",
|
||||
"prefs.font": "Font",
|
||||
"prefs.font_fallback": "Glyphs the chosen font lacks fall back to the built-in font, so no label shows an empty box.",
|
||||
@@ -2628,6 +2712,17 @@
|
||||
"prefs.gesture_pan": "Pan",
|
||||
"prefs.gesture_zoom": "Zoom",
|
||||
"prefs.graphics": "Graphics",
|
||||
"prefs.graphics_api": "Graphics API",
|
||||
"prefs.graphics_api_auto": "Automatic",
|
||||
"prefs.graphics_api_help": "Choose the graphics API used to open SolidCraft. If the next start cannot open the window, the previous choice is restored.",
|
||||
"prefs.graphics_api_override": "A launch override is controlling the graphics API. The saved choice will apply when SolidCraft is opened normally.",
|
||||
"prefs.graphics_api_restart_note": "Applies after a restart. Unsaved designs are handled before closing.",
|
||||
"prefs.graphics_api_restart_unavailable": "Restart SolidCraft to apply the saved graphics API.",
|
||||
"prefs.graphics_api_running": "Current: {current}. Selected for next start: {selected}.",
|
||||
"prefs.graphics_api_save_failed": "The graphics API choice could not be saved: {error}",
|
||||
"prefs.graphics_api_start_failed": "The selected graphics API could not be prepared: {error}",
|
||||
"prefs.graphics_api_start_reverted": "The previous start with {requested} did not open the window. SolidCraft restored {previous}.",
|
||||
"prefs.graphics_api_unavailable": "Graphics API selection is available in the desktop app.",
|
||||
"prefs.graphics_card": "Graphics card",
|
||||
"prefs.graphics_card_auto": "Automatic",
|
||||
"prefs.graphics_card_missing": "The saved graphics card is unavailable; Automatic is used.",
|
||||
@@ -2671,6 +2766,8 @@
|
||||
"prefs.history_sketches_in_order": "In order",
|
||||
"prefs.history_sketches_note": "With Sketches set to Under their feature, the History at the left lists each sketch one level in, under the first feature built from it, whenever it is wide enough for names. The timeline at the bottom always keeps the creation order.",
|
||||
"prefs.history_sketches_under_feature": "Under their feature",
|
||||
"prefs.history_steps_component": "History steps by component",
|
||||
"prefs.history_steps_component_note": "With a component active or picked, the History controls step through that component's features, as the History at the bottom shows them. Off: they step through every feature of the design. The History on the left or under the browser always steps through every feature.",
|
||||
"prefs.hold_stop_snapping": "Hold to stop snapping",
|
||||
"prefs.home_fit_size": "Home and Fit size",
|
||||
"prefs.home_fit_size_note": "How much of the view the model fills when Home, Fit, an opened design or a navigator view change frames it, whether or not the setting below is on. 100 %: fills the view between the panels, the compass and the navigation bar.",
|
||||
@@ -2686,6 +2783,8 @@
|
||||
"prefs.invert_curved_roll_arrows_note": "The two curved arrows at the cube's corner roll the view within the screen plane. On: the clockwise arrow rolls counterclockwise and the counterclockwise arrow rolls clockwise. Off: each arrow rolls the view the way it curls.",
|
||||
"prefs.invert_navigator_arrows": "Invert the view cube rotation arrows",
|
||||
"prefs.invert_navigator_arrows_note": "The arrows around the cube orbit the camera the way they point, as in Fusion and Inventor: the arrow on the left points right and swings the camera right. Off: an arrow rotates the cube toward the side it sits on, so the left arrow swings the camera left. The curved roll arrows are not affected.",
|
||||
"prefs.joint_drag_trackball": "Turn parts on a ball joint like a trackball when dragged",
|
||||
"prefs.joint_drag_trackball_help": "Dragging a part that a ball joint holds turns it by the smallest turn about the joint, as if rolling a ball the size of the part. Off: the point you grabbed follows the pointer exactly, and the part may also spin about it.",
|
||||
"prefs.keep_unsaved_also_asks": "Still ask when the tab closes",
|
||||
"prefs.keep_unsaved_also_asks_tip": "With this off, the tab closes without the browser's box once every unsaved design's copy is current.",
|
||||
"prefs.keep_unsaved_in_browser": "Keep unsaved work in this browser",
|
||||
@@ -2761,6 +2860,8 @@
|
||||
"prefs.not_on_gpu": "not on this GPU",
|
||||
"prefs.on": "On",
|
||||
"prefs.opaque": "Opaque",
|
||||
"prefs.operations_panel": "Show operations in the view",
|
||||
"prefs.operations_panel_note": "Long operations (opening a file, computing a feature, an agent's command) show in the view's bottom-right corner with their progress and a button that cancels them. Off: a Computing notice, as before.",
|
||||
"prefs.orbit_snap": "Hold Shift during orbit to snap to an axis.",
|
||||
"prefs.orientation": "Orientation",
|
||||
"prefs.origin_plane_names": "Origin plane names",
|
||||
@@ -2841,6 +2942,8 @@
|
||||
"prefs.ribbon_tabs_only": "Show only the ribbon's tabs",
|
||||
"prefs.ribbon_tabs_only_note": "The ribbon folds to its tab row. Clicking a tab shows its panels over the view until a command starts or the pointer leaves them. Ribbon Tabs Only in the View tab, or its shortcut, switches this.",
|
||||
"prefs.right_click": "Right click",
|
||||
"prefs.save_prompt_one_at_a_time": "Ask about each unsaved design separately when closing several",
|
||||
"prefs.save_prompt_one_at_a_time_help": "Show one save prompt per unsaved design instead of a combined list.",
|
||||
"prefs.saving": "Start and save",
|
||||
"prefs.scale_note": "Also Ctrl + / Ctrl − in the window. Buttons are 28 px at 100%.",
|
||||
"prefs.scale_text": "Scale and text",
|
||||
@@ -2877,6 +2980,8 @@
|
||||
"prefs.sketch.center_arc": "Center-point arc follows the cursor",
|
||||
"prefs.sketch.click_selects": "Click selects",
|
||||
"prefs.sketch.conflict_colour": "Conflict color",
|
||||
"prefs.sketch.cursor_coordinates": "Show the cursor's coordinates in a sketch",
|
||||
"prefs.sketch.cursor_coordinates_note": "Beside the pointer, its X and Y from the sketch origin, also with no tool running. Off: only while a tool places a point.",
|
||||
"prefs.sketch.drawing": "Drawing",
|
||||
"prefs.sketch.ellipse_axes": "Draw ellipses with their axes",
|
||||
"prefs.sketch.ellipse_axes_note": "The major and minor axes as construction lines, so the half-axes and axes can be dimensioned. Off: the ellipse alone, and D on it gives its minor radius wherever the value is pulled, drawn and labelled R as before.",
|
||||
@@ -2888,14 +2993,20 @@
|
||||
"prefs.sketch.faces_edges": "Faces and edges",
|
||||
"prefs.sketch.hide_glyphs": "Hide glyphs zoomed out",
|
||||
"prefs.sketch.marks": "Marks in the sketch",
|
||||
"prefs.sketch.max_points": "Largest sketch",
|
||||
"prefs.sketch.max_points_note": "The most points or curves one sketch holds: 20000 by default, at most 200000. Insert SVG and Insert DXF refuse a larger drawing. A large sketch solves and draws more slowly.",
|
||||
"prefs.sketch.max_points_unit": "points",
|
||||
"prefs.sketch.note": "Drawing, snapping and selecting.",
|
||||
"prefs.sketch.opening_closing": "Opening and closing",
|
||||
"prefs.sketch.prefer_free_points": "Prefer movable points where they overlap",
|
||||
"prefs.sketch.project_options": "Ask for Project options first",
|
||||
"prefs.sketch.recent_snap": "Snap to where two guides cross",
|
||||
"prefs.sketch.select_3d_curve_points": "Select 3D sketch curve points",
|
||||
"prefs.sketch.select_3d_curve_points_help": "Show and select points on drawn 3D sketch curves for construction references.",
|
||||
"prefs.sketch.select_other_hidden": "Select Other reaches hidden geometry",
|
||||
"prefs.sketch.shortcut_cycles_modes": "Shortcut again switches mode",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "Off: it starts the tool again.",
|
||||
"prefs.sketch.snap_to_visible_grid": "Snap to the grid's visible crossings",
|
||||
"prefs.sketch.snapping_guides": "Snapping and guides",
|
||||
"prefs.sketch.state_icons": "State icons",
|
||||
"prefs.sketch.tracking_guides": "Center and midpoint guides",
|
||||
@@ -2923,6 +3034,7 @@
|
||||
"prefs.sketch_selection": "Sketch & selection",
|
||||
"prefs.sketch_selection_heading": "Sketch and selection",
|
||||
"prefs.sketch_selection_note": "How sketches snap and how clicks select.",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "A point in a sketch snaps to the crossings of the lines the grid draws when the pointer means one, and to the finer lattice between them otherwise. Off: the point snaps to the finer lattice only, as before.",
|
||||
"prefs.sketch_state_icons": "Sketch icons in the color of their state",
|
||||
"prefs.sketch_state_icons_note": "In History and the browser, a sketch's icon takes the color of its state (under constrained, fully constrained or conflicting) and its tooltip names the state. Off: every sketch has the same icon.",
|
||||
"prefs.sketch_tab_always": "Keep the Sketch tab shown",
|
||||
@@ -3624,6 +3736,7 @@
|
||||
"render.error_pbr_opacity": "opaque PBR requires opacity 1",
|
||||
"render.error_physical_glass": "the selected recipe is not physical glass",
|
||||
"render.error_preview_device": "product preview requires an installed device with a depth buffer",
|
||||
"render.error_product_placement": "invalid product placement",
|
||||
"render.error_product_triangle": "invalid product triangle",
|
||||
"render.error_provisional_identity": "invalid provisional render identity or sample count",
|
||||
"render.error_quality_bounds": "quality projection exceeds native bounds",
|
||||
@@ -3707,6 +3820,10 @@
|
||||
"render.gpu_path_retry": "Try again",
|
||||
"render.gpu_seed": "Random seed",
|
||||
"render.gpu_unavailable": "GPU path tracing is not ready on this device.",
|
||||
"render.graphics_api_restart_vulkan": "Restart with Vulkan",
|
||||
"render.graphics_api_restart_warning": "Changing graphics API restarts SolidCraft and asks you to save unsaved designs. If the new API cannot open the window, the previous choice is restored on the next start.",
|
||||
"render.graphics_api_settings": "Graphics settings",
|
||||
"render.graphics_api_vulkan_required": "GPU path tracing needs Vulkan in this session. Restart with Vulkan, or keep using a CPU image method.",
|
||||
"render.ground_apply": "Fit and save ground",
|
||||
"render.ground_gap": "Explicit clearance gap",
|
||||
"render.ground_linear_rgb": "Diffuse reflectance · linear RGB",
|
||||
@@ -4708,6 +4825,8 @@
|
||||
"sketch.hint.spline3d": "3D Spline: click fit points in 3D; right-click or Esc to finish",
|
||||
"sketch.hint.trim": "Trim: click the piece of a curve to remove, or drag across the pieces to remove",
|
||||
"sketch.make_selection": "Convert the selection to {linetype}",
|
||||
"sketch.move_released": "Moved: {count} constraints tying it to what stays were let go ({names}).",
|
||||
"sketch.move_released_one": "Moved: {count} constraint tying it to what stays was let go ({names}).",
|
||||
"sketch.open_ends": "Open {count}",
|
||||
"sketch.status_conflict": "constraints conflict",
|
||||
"sketch.status_fully_constrained": "fully constrained",
|
||||
@@ -4738,6 +4857,10 @@
|
||||
"sketch_text.path_clear": "Take the text off its curve",
|
||||
"sketch_text.path_hint": "A curve of the sketch the text follows: click here, then the curve",
|
||||
"sketch_text.use_font_file": "Use the font file {path}",
|
||||
"sketch_text.valign_baseline": "Baseline",
|
||||
"sketch_text.valign_bottom": "Bottom",
|
||||
"sketch_text.valign_middle": "Middle",
|
||||
"sketch_text.valign_top": "Top",
|
||||
"solid": "solid",
|
||||
"status.editing": "Editing {name}",
|
||||
"status.navigation": "Mouse mapping: {mapping}",
|
||||
@@ -4938,6 +5061,7 @@
|
||||
"ui.agent_chat_allow_once": "Allow once",
|
||||
"ui.agent_chat_allowed": "Allowed",
|
||||
"ui.agent_chat_answered": "Answer: {option}",
|
||||
"ui.agent_chat_answered_in": "Answered in {time}",
|
||||
"ui.agent_chat_approval": "Allow the agent to do this?",
|
||||
"ui.agent_chat_attach_selection": "Attach selection",
|
||||
"ui.agent_chat_attach_selection_tip": "Send what is selected in the model (faces, edges, features, bodies) with the message, so the agent knows what you mean",
|
||||
@@ -4966,6 +5090,7 @@
|
||||
"ui.agent_chat_ctx_bodies": "Bodies",
|
||||
"ui.agent_chat_ctx_elements": "Elements",
|
||||
"ui.agent_chat_ctx_features": "Features",
|
||||
"ui.agent_chat_ctx_gone": "No longer in the design: it was changed or deleted.",
|
||||
"ui.agent_chat_ctx_more": "+{n} more",
|
||||
"ui.agent_chat_ctx_other": "Other",
|
||||
"ui.agent_chat_custom_heading": "Custom model",
|
||||
@@ -4979,6 +5104,7 @@
|
||||
"ui.agent_chat_dock_right": "Dock on the right",
|
||||
"ui.agent_chat_drop_hint": "Drop to attach to your next message",
|
||||
"ui.agent_chat_edit": "Edit",
|
||||
"ui.agent_chat_ended_after": "Ended after {time}",
|
||||
"ui.agent_chat_exited": "The agent stopped.",
|
||||
"ui.agent_chat_failed_start": "The agent could not start: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: a CAD file is imported into the design, not read",
|
||||
@@ -5016,6 +5142,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model} can't use SolidCraft's tools, so it can only chat. Pick a model with tool support.",
|
||||
"ui.agent_chat_model_rejected": "The agent did not accept {model}: {error}",
|
||||
"ui.agent_chat_model_search": "Search models…",
|
||||
"ui.agent_chat_model_search_or_id": "Search, or type any model id…",
|
||||
"ui.agent_chat_model_tip": "The model the agent uses. Your choice is remembered for this agent.",
|
||||
"ui.agent_chat_models_failed": "Couldn't list models: {error}",
|
||||
"ui.agent_chat_models_heading": "Available models",
|
||||
@@ -5027,6 +5154,7 @@
|
||||
"ui.agent_chat_next_picture": "Next picture",
|
||||
"ui.agent_chat_no_cli": "solidcraft-cli was not found next to the app, so the agent can't reach the design.",
|
||||
"ui.agent_chat_no_control": "The agent chat's endpoint did not start, so the agent can't reach the design.",
|
||||
"ui.agent_chat_no_design_hint": "The agent runs without SolidCraft's tools, so it can't read or change the design: solidcraft-cli was not found next to the app. Install SolidCraft with solidcraft-cli beside it (on Windows, the MSI or the portable zip), or set SOLIDCRAFT_CLI to its path, then connect again.",
|
||||
"ui.agent_chat_no_images": "This agent doesn't take pictures",
|
||||
"ui.agent_chat_no_picture": "There is no picture on the clipboard",
|
||||
"ui.agent_chat_no_tool_call": "The model didn't use SolidCraft's tools, so the design wasn't changed. Choose a model that supports tool calling; see Local models in the agent chat guide.",
|
||||
@@ -5041,7 +5169,7 @@
|
||||
"ui.agent_chat_permission": "The agent asks to run: {title}",
|
||||
"ui.agent_chat_pick": "Agent",
|
||||
"ui.agent_chat_pick_context": "Pick context",
|
||||
"ui.agent_chat_pick_context_tip": "Choose faces, edges, features and bodies in the model for the agent to look at, then press OK",
|
||||
"ui.agent_chat_pick_context_tip": "Choose faces, edges, features and bodies in the model, then press OK: they are put into the message as a pill where the cursor is (typing @ does the same)",
|
||||
"ui.agent_chat_placeholder": "Ask the agent to change the design…",
|
||||
"ui.agent_chat_placeholder_busy": "Queue a message for when the agent is done (Ctrl+Enter: send now)",
|
||||
"ui.agent_chat_pop_out": "Open in its own window, which you can move to another screen",
|
||||
@@ -5073,16 +5201,26 @@
|
||||
"ui.agent_chat_setup_title": "Set up an assistant",
|
||||
"ui.agent_chat_side": "Dock the chat",
|
||||
"ui.agent_chat_signed_in": "signed in",
|
||||
"ui.agent_chat_snap_none_found": "No coding agent found. The Snap package is confined, so it cannot see or start the coding agents installed on this computer. To use them, install SolidCraft from the AppImage, .deb or .rpm package instead. An agent that uses an OpenAI-compatible API works in the Snap package too: set one up with Add agent.",
|
||||
"ui.agent_chat_span_h": "{h} h {min} min",
|
||||
"ui.agent_chat_span_min": "{n} min",
|
||||
"ui.agent_chat_span_s": "{n} s",
|
||||
"ui.agent_chat_state_auth": "Sign-in needed",
|
||||
"ui.agent_chat_state_busy": "Working…",
|
||||
"ui.agent_chat_state_exited": "Agent stopped",
|
||||
"ui.agent_chat_state_failed": "Connection failed",
|
||||
"ui.agent_chat_state_no_design": "No design access",
|
||||
"ui.agent_chat_state_off": "Not connected",
|
||||
"ui.agent_chat_state_ready": "Ready",
|
||||
"ui.agent_chat_state_starting": "Starting…",
|
||||
"ui.agent_chat_stop": "Stop",
|
||||
"ui.agent_chat_stop_tip": "Stop the agent and everything it started",
|
||||
"ui.agent_chat_stop_turn_tip": "Stop the agent (Esc). Queued messages stay queued.",
|
||||
"ui.agent_chat_thinking_for": "Thinking for {time}",
|
||||
"ui.agent_chat_tool_running_for": "running for {time}",
|
||||
"ui.agent_chat_tools_not_started": "The agent runs without SolidCraft's tools, so it can't read or change the design: solidcraft-cli was found, but its tools did not start (the error in the chat says why). Connect again; if it keeps happening, reinstall SolidCraft.",
|
||||
"ui.agent_chat_transcript_assistant": "Assistant:",
|
||||
"ui.agent_chat_transcript_user": "User:",
|
||||
"ui.agent_chat_turn_limit": "Changes per message",
|
||||
"ui.agent_chat_turn_unlimited": "Unlimited",
|
||||
"ui.agent_chat_undo_changes": "Undo these changes",
|
||||
@@ -5239,7 +5377,9 @@
|
||||
"ui.browser_bodies_one": "{count} body",
|
||||
"ui.browser_bodies_other": "{count} bodies",
|
||||
"ui.browser_collapse": "Collapse the browser",
|
||||
"ui.browser_collapse_below": "Collapse Below",
|
||||
"ui.browser_expand": "Expand the browser",
|
||||
"ui.browser_expand_below": "Expand Below",
|
||||
"ui.browser_title": "Browser",
|
||||
"ui.calibrate": "Calibrate",
|
||||
"ui.cancel": "Cancel",
|
||||
@@ -5269,6 +5409,7 @@
|
||||
"ui.collapse": "Collapse",
|
||||
"ui.collinear": "Collinear",
|
||||
"ui.colour_vision": "Color vision",
|
||||
"ui.colour_vision_bends": "Bends",
|
||||
"ui.colour_vision_deutan": "Deutan",
|
||||
"ui.colour_vision_deutan_tip": "For a weak or missing green sense",
|
||||
"ui.colour_vision_failed": "Failed",
|
||||
@@ -5298,6 +5439,14 @@
|
||||
"ui.conic_curve": "Conic Curve",
|
||||
"ui.constant": "Constant",
|
||||
"ui.constraints_conflict": "Constraints conflict",
|
||||
"ui.construct_auto.chosen": "Chosen from your picks. Pick another reference, or take one out, to change the method.",
|
||||
"ui.construct_auto.no_fit": "Pick other references: no method builds from these.",
|
||||
"ui.construct_auto.pick": "Pick what to build from: the method follows from your picks.",
|
||||
"ui.construct_auto.refs": "References",
|
||||
"ui.construct_auto.select": "Select references to build from first",
|
||||
"ui.construct_axes": "Axes",
|
||||
"ui.construct_planes": "Planes",
|
||||
"ui.construct_points": "Points",
|
||||
"ui.construction": "Construction",
|
||||
"ui.construction.angle_hint": "Construction line: click a point, then type an angle or pick a direction",
|
||||
"ui.construction.axis_hint": "Construction line: click a point, or type its distance from the sketch axis",
|
||||
@@ -5450,6 +5599,17 @@
|
||||
"ui.ellipse": "Ellipse",
|
||||
"ui.emboss_wrap_note": "Orthogonal line profiles tangent to one supported cylinder wrap automatically. Pick a wall to choose a target.",
|
||||
"ui.end": "End",
|
||||
"ui.end_cap.chamfer": "Corner Chamfer",
|
||||
"ui.end_cap.direction": "Direction",
|
||||
"ui.end_cap.faces": "End Faces",
|
||||
"ui.end_cap.inset": "Inset",
|
||||
"ui.end_cap.inset_kind": "Inset By",
|
||||
"ui.end_cap.inset_ratio": "Inset Ratio",
|
||||
"ui.end_cap.inward": "Inward",
|
||||
"ui.end_cap.length": "Length",
|
||||
"ui.end_cap.outward": "Outward",
|
||||
"ui.end_cap.ratio": "Ratio of thickness",
|
||||
"ui.end_cap_title": "END CAP",
|
||||
"ui.end_radius": "End Radius",
|
||||
"ui.end_scale": "End Scale",
|
||||
"ui.ends": "Ends",
|
||||
@@ -5470,7 +5630,10 @@
|
||||
"ui.explode_needs_two_components": "Exploded View pulls components apart, so the design needs two or more of them (New Component, Insert Design or Create Components from Bodies)",
|
||||
"ui.exportDxf": "Export DXF…",
|
||||
"ui.export_ellipsis_keymap": "Export…",
|
||||
"ui.export_glb": "Export GLB",
|
||||
"ui.export_keymap_tip": "Keys, S box favorites and the toolbar, as a file",
|
||||
"ui.export_selects_only_body": "Select the only body when exporting a mesh",
|
||||
"ui.export_selects_only_body_tip": "Export STL, Export 3MF and Send to Slicer start with the design's body selected when it has just one.",
|
||||
"ui.extend": "Extend",
|
||||
"ui.extent": "Extent",
|
||||
"ui.extent_type": "Extent Type",
|
||||
@@ -5530,6 +5693,8 @@
|
||||
"ui.finest": "Finest",
|
||||
"ui.finish_sketch": "Finish Sketch",
|
||||
"ui.first_dimension_scales": "The first dimension scales the drawing",
|
||||
"ui.first_dimension_scales_about_origin": "Scale about the sketch origin",
|
||||
"ui.first_dimension_scales_about_origin_tip": "On: the drawing always grows or shrinks about the sketch origin, so a shape drawn away from the origin moves. Off: a drawing that nothing ties to the origin scales about its own middle and stays where it was drawn.",
|
||||
"ui.first_dimension_scales_tip": "On: a sketch's first length dimension scales the drawing it measures, so its shape stays the same. Off: the dimension sizes only what it measures.",
|
||||
"ui.fit": "Fit",
|
||||
"ui.fix_unfix": "Fix/Unfix",
|
||||
@@ -5952,6 +6117,7 @@
|
||||
"ui.project_references_construction_note": "Project, Intersect, Include 3D Geometry and the face edges of a new sketch on a face make construction geometry: references to draw against, left out of profiles. They stay linked to the model.",
|
||||
"ui.properties": "Properties",
|
||||
"ui.properties.copy_matrix": "Copy matrix",
|
||||
"ui.properties.copy_value": "Click to copy",
|
||||
"ui.properties.first_moments": "First moments",
|
||||
"ui.properties.inertia": "Moment of inertia",
|
||||
"ui.properties.inertia_note": "About the center of mass, in world axes (g·{unit}²)",
|
||||
@@ -5964,6 +6130,7 @@
|
||||
"ui.properties.measuring_failed": "Measuring stopped before it finished.",
|
||||
"ui.properties.principal_axis": "Principal axis {number}",
|
||||
"ui.properties.principal_moments": "Principal moments",
|
||||
"ui.properties.value_copied": "Value copied",
|
||||
"ui.pull_direction": "Pull direction",
|
||||
"ui.quality": "Quality",
|
||||
"ui.quantity": "Quantity",
|
||||
@@ -5984,11 +6151,14 @@
|
||||
"ui.relink_design_changed": "The assembly changed while choosing a source. Start Relink Source again.",
|
||||
"ui.relink_done": "Source relinked for all instances.",
|
||||
"ui.relink_not_linked": "This component is not linked to a source design.",
|
||||
"ui.relink_one_done": "Source relinked for this instance.",
|
||||
"ui.relink_select_one": "Select one linked component or one of its instances first.",
|
||||
"ui.relink_source_all": "Relink Source (All Instances)…",
|
||||
"ui.relink_source_one": "Relink Source…",
|
||||
"ui.removeFromQuickAccess": "Remove from Quick Access",
|
||||
"ui.removeFromToolbar": "Remove from Toolbar",
|
||||
"ui.removeSection": "Remove Section",
|
||||
"ui.renameSelectedBodies": "Rename Selected Bodies",
|
||||
"ui.render": "Render",
|
||||
"ui.renderer": "Renderer",
|
||||
"ui.repeat": "Repeat",
|
||||
@@ -6019,6 +6189,8 @@
|
||||
"ui.ribbon_pin_footer": "Pinned commands show on the ribbon. Hover a row to pin or unpin it.",
|
||||
"ui.ribbon_workspace": "Workspace",
|
||||
"ui.right": "Right",
|
||||
"ui.right_click_confirms": "Right-click confirms dialog inputs",
|
||||
"ui.right_click_confirms_tip": "With a dialog open, a right-click in the view goes on to its next empty input, and on the last one runs OK",
|
||||
"ui.save": "Save",
|
||||
"ui.save_as": "Save As",
|
||||
"ui.save_mesh_no_slicer_open": "No slicer found: choose Custom… and pick your slicer program",
|
||||
@@ -6078,6 +6250,16 @@
|
||||
"ui.sketch_intersect_selection_filter": "Selection Filter",
|
||||
"ui.sketch_keys_only": "Keep model keys out of sketches",
|
||||
"ui.sketch_keys_only_tip": "While editing a sketch, only sketch keys and keys that work everywhere run; a model key such as E or F does nothing, so a stray key can't close a heavy sketch.",
|
||||
"ui.sketch_links_added_curve": "{command} added 1 curve to the sketch.",
|
||||
"ui.sketch_links_added_curves": "{command} added {count} curves to the sketch.",
|
||||
"ui.sketch_links_added_curves_and_points": "{command} added {curves} and {points} to the sketch.",
|
||||
"ui.sketch_links_added_point": "{command} added 1 point to the sketch.",
|
||||
"ui.sketch_links_added_points": "{command} added {count} points to the sketch.",
|
||||
"ui.sketch_links_curve_count": "{count} curves",
|
||||
"ui.sketch_links_curve_count_one": "1 curve",
|
||||
"ui.sketch_links_hidden": "The result is hidden because {option} is off in the sketch palette.",
|
||||
"ui.sketch_links_point_count": "{count} points",
|
||||
"ui.sketch_links_point_count_one": "1 point",
|
||||
"ui.sketch_modifiers": "Sketch modifiers",
|
||||
"ui.sketch_project_geometry": "Geometry",
|
||||
"ui.sketch_report.all_constrained": "Everything is fully constrained.",
|
||||
@@ -6117,6 +6299,7 @@
|
||||
"ui.step_values": "Step values with arrows and wheel",
|
||||
"ui.step_values_tip": "Up/Down and the wheel over a value field change its number.",
|
||||
"ui.stitch_tolerance_hint": "tight",
|
||||
"ui.straighten": "Straighten",
|
||||
"ui.stretch": "Stretch",
|
||||
"ui.supersampling": "Supersampling (SSAA)",
|
||||
"ui.supersampling_adaptive": "Only when the view is still",
|
||||
@@ -6190,6 +6373,8 @@
|
||||
"ui.view_angles_yaw": "Yaw",
|
||||
"ui.view_angles_zero": "Set {axis} to 0°",
|
||||
"ui.view_centre": "View center",
|
||||
"ui.view_compass_tip": "View from {axis}. Click again to reverse. Drag to orbit.",
|
||||
"ui.view_compass_tip_snap": "View from {axis}. Click again to reverse. Drag to orbit; hold Shift to snap.",
|
||||
"ui.viewport_status_clear": "Turn off {name}",
|
||||
"ui.viewport_status_clear_hint": "Turn off {name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} edges",
|
||||
|
||||
+313
-265
@@ -885,6 +885,7 @@
|
||||
"Variable Radius": "Radio variable",
|
||||
"Variable radius": "Radio variable",
|
||||
"Velocity": "Velocidad",
|
||||
"Vertical": "Vertical",
|
||||
"Vertices": "Vértices",
|
||||
"View": "Vista",
|
||||
"View navigator": "Navegador de vistas",
|
||||
@@ -1149,6 +1150,7 @@
|
||||
"cmd.file_save_mesh": "Guardar como malla",
|
||||
"cmd.file_send_to_slicer": "Enviar al laminador",
|
||||
"cmd.file_slicers": "Laminadores instalados",
|
||||
"cmd.frame_end_cap": "Tapa de extremo",
|
||||
"cmd.frame_member": "Miembro estructural",
|
||||
"cmd.frame_profile_insert": "Insertar perfil",
|
||||
"cmd.frame_profile_list": "Biblioteca de perfiles",
|
||||
@@ -1169,6 +1171,7 @@
|
||||
"cmd.inspect_isocurve": "Análisis de isocurvas",
|
||||
"cmd.inspect_minimum_radius": "Análisis de radio mínimo",
|
||||
"cmd.inspect_parameter_sweep": "Barrido de parámetros",
|
||||
"cmd.inspect_parameter_variants": "Comparar variantes de parámetros",
|
||||
"cmd.inspect_silhouette": "Silueta",
|
||||
"cmd.inspect_zebra": "Análisis de franjas cebra",
|
||||
"cmd.joint_as_built": "Unión según posición actual",
|
||||
@@ -1623,6 +1626,7 @@
|
||||
"dialog.pattern_sketch_not_object": "Selecciona cuerpos o operaciones: un boceto no es ninguno. Repite sus curvas con el Patrón o Espejo del propio boceto, o extrúdelas primero.",
|
||||
"dialog.primitive_point_tip": "Un punto que rellena X, Y y Z: haz clic aquí y después en un vértice, una arista o una cara del modelo, en un punto de un boceto o en el origen.",
|
||||
"dialog.reference_edge_tip": "Una arista recta de la cara elegida desde la que se mide la distancia de abajo: haz clic aquí y después en la arista.",
|
||||
"dialog.right_click_pick": "Selecciona primero {input}",
|
||||
"dialog.select": "↖ Seleccionar",
|
||||
"dialog.selected_count": "↖ {count} seleccionados",
|
||||
"dialog.selection_constraint": "Restricción {id}",
|
||||
@@ -1667,6 +1671,8 @@
|
||||
"dxf.tolerance": "Tolerancia de curva",
|
||||
"dxf.tolerance_help": "Solo cuerpos visibles y bocetos mostrados. Las curvas usan segmentos rectos. Una tolerancia menor da curvas más finas y consume más tiempo y memoria.",
|
||||
"each rail's curves must be in one sketch": "las curvas de cada guía deben estar en un solo boceto",
|
||||
"error.end_cap_faces": "Selecciona al menos una cara de extremo abierta de un miembro",
|
||||
"error.end_cap_unresolved": "El extremo {ends} de esta tapa ya no está en el modelo. Vuelve a seleccionar las caras de extremo",
|
||||
"feature computation ended without a result": "el cálculo de la operación terminó sin resultado",
|
||||
"file.open.drawing_filter": "Diseños, archivos CAD, mallas y dibujos",
|
||||
"file.open.portal_fallback.no_portal_service": "El selector de archivos que se ha abierto no es el del escritorio: el servicio de portal del escritorio no está disponible.",
|
||||
@@ -1704,189 +1710,190 @@
|
||||
"from the rule": "de la regla",
|
||||
"help.apache": "Licencia Apache 2.0",
|
||||
"help.appearance.assign": "Da a los cuerpos, caras o componentes seleccionados un color o un aspecto de material, con",
|
||||
"help.assembly.bom": "Lists the parts of the design or a component with their counts, by part number, and can save the list as CSV or JSON. Use it as the parts list for ordering and assembly.",
|
||||
"help.assembly.bom": "Lista las piezas del diseño o de un componente con sus cantidades, por número de pieza, y puede guardar la lista como CSV o JSON. Úsalo como lista de piezas para pedidos y ensamblaje.",
|
||||
"help.attributions": "Atribuciones (ATTRIBUTION.md)",
|
||||
"help.build": "Versión {version} · commit {commit} · compilada el {date}",
|
||||
"help.canvas.decal": "Places an image on a planar face of the model, like a sticker. Use it to show a label, logo or printed pattern on a part.",
|
||||
"help.canvas.edit": "Changes a canvas: its position, size, angle, opacity, mirroring, visibility or name. Use it to line up a reference image with the sketch you trace over it.",
|
||||
"help.canvas.insert": "Places a PNG or JPEG image on a plane or face as a see-through reference. Use it to trace a photo or drawing in a sketch, with the image scaled to a known size.",
|
||||
"help.component.break_link": "Cuts a linked component loose from its design file, keeping its bodies as they are. Use it when the part should no longer follow changes to the original file.",
|
||||
"help.component.capture_position": "Keeps the positions of parts you moved by hand, so they become where those parts are. Use it after dragging parts into place that no joint holds.",
|
||||
"help.component.create": "Adds a new, empty component to the design, inside the active component unless you choose another parent. Use it to give a new part of an assembly its own place for bodies and sketches.",
|
||||
"help.canvas.decal": "Coloca una imagen sobre una cara plana del modelo, como una pegatina. Úsalo para mostrar una etiqueta, un logotipo o un dibujo impreso en una pieza.",
|
||||
"help.canvas.edit": "Cambia un lienzo: su posición, tamaño, ángulo, opacidad, simetría, visibilidad o nombre. Úsalo para alinear una imagen de referencia con el boceto que dibujas sobre ella.",
|
||||
"help.canvas.insert": "Coloca una imagen PNG o JPEG en un plano o una cara como referencia translúcida. Úsalo para calcar una foto o un dibujo en un boceto, con la imagen escalada a un tamaño conocido.",
|
||||
"help.component.break_link": "Desvincula un componente enlazado de su archivo de diseño y conserva sus cuerpos tal como están. Úsalo cuando la pieza ya no deba seguir los cambios del archivo original.",
|
||||
"help.component.capture_position": "Conserva las posiciones de las piezas que moviste a mano, de modo que pasan a ser donde están ahora. Úsalo tras arrastrar a su sitio piezas que ninguna unión sujeta.",
|
||||
"help.component.create": "Añade un componente nuevo y vacío al diseño, dentro del componente activo salvo que elijas otro padre. Úsalo para dar a una pieza nueva de un ensamblaje su propio lugar para cuerpos y bocetos.",
|
||||
"help.component.finish_edit": "Guarda la pieza que estás editando en contexto, vuelve a su ensamblaje y actualiza el",
|
||||
"help.component.from_bodies": "Turns each selected body into a component of its own, named after the body. Use it when a design built as loose bodies should become an assembly whose parts can be joined and moved.",
|
||||
"help.component.insert_design": "Inserts another saved design as a component linked to its file, with its solid bodies placed as they are there. Use it to reuse a part in an assembly and pick up later changes with Update Links.",
|
||||
"help.component.properties": "Shows the volume, mass, centre of mass and moments of inertia of a component, using its bodies' materials. Use it to check weight and balance of an assembly.",
|
||||
"help.component.revert_position": "Puts parts you moved by hand back where they were, dropping moves that were not captured. Use it to undo trial moves in an assembly.",
|
||||
"help.component.update_links": "Reads the linked design files again and replaces bodies where they changed. Use it after editing a part that this assembly uses.",
|
||||
"help.config.configure": "Adds parameters, features, materials or appearances as columns of the configuration table. Use it to build variants of one design, such as sizes of a part.",
|
||||
"help.config.preview": "Checks that a row of the configuration table rebuilds, without changing the design or its history. Use it before switching to a variant you are not sure of.",
|
||||
"help.config.rules": "Shows the rules of the configuration table, its rows and which row is active. Use it to see how the variants of a design are set up.",
|
||||
"help.config.table": "Shows the configuration table: one row per variant, one column per parameter or feature, and whether the design still matches the active row. Use it to review the variants of a design.",
|
||||
"help.component.from_bodies": "Convierte cada cuerpo seleccionado en un componente propio, con el nombre del cuerpo. Úsalo cuando un diseño hecho con cuerpos sueltos deba pasar a ser un ensamblaje cuyas piezas se puedan unir y mover.",
|
||||
"help.component.insert_design": "Inserta otro diseño guardado como componente vinculado a su archivo, con sus cuerpos sólidos colocados como están allí. Úsalo para reutilizar una pieza en un ensamblaje y recoger los cambios posteriores con Actualizar vínculos.",
|
||||
"help.component.properties": "Muestra el volumen, la masa, el centro de masa y los momentos de inercia de un componente, según los materiales de sus cuerpos. Úsalo para comprobar el peso y el equilibrio de un ensamblaje.",
|
||||
"help.component.revert_position": "Devuelve a su sitio las piezas que moviste a mano y descarta los movimientos que no se capturaron. Úsalo para deshacer movimientos de prueba en un ensamblaje.",
|
||||
"help.component.update_links": "Vuelve a leer los archivos de diseño vinculados y reemplaza los cuerpos que cambiaron. Úsalo después de editar una pieza que usa este ensamblaje.",
|
||||
"help.config.configure": "Añade parámetros, operaciones, materiales o aspectos como columnas de la tabla de configuración. Úsalo para crear variantes de un diseño, como tamaños de una pieza.",
|
||||
"help.config.preview": "Comprueba que una fila de la tabla de configuración se reconstruye, sin cambiar el diseño ni su historial. Úsalo antes de cambiar a una variante de la que no estés seguro.",
|
||||
"help.config.rules": "Muestra las reglas de la tabla de configuración, sus filas y cuál está activa. Úsalo para ver cómo están definidas las variantes de un diseño.",
|
||||
"help.config.table": "Muestra la tabla de configuración: una fila por variante, una columna por parámetro u operación, y si el diseño sigue coincidiendo con la fila activa. Úsalo para revisar las variantes de un diseño.",
|
||||
"help.connect_note": "Reinicia cada asistente para que cargue el servidor de SolidCraft. Cada archivo se guardó como .bak antes de modificarlo.",
|
||||
"help.connect_title": "Conectar asistentes de IA",
|
||||
"help.construct.axis.edge": "Creates a construction axis along a straight edge or sketch line. Use it as the axis for a revolve, a circular pattern or a joint.",
|
||||
"help.construct.axis.normal_to_face": "Creates a construction axis through a point, square to a face. Use it as an axis that stands straight out of a surface.",
|
||||
"help.construct.axis.through_cylinder": "Creates a construction axis through the centre of a cylinder, cone or torus face, or a circular edge. Use it to turn or pattern features around a round part.",
|
||||
"help.construct.axis.two_planes": "Creates a construction axis where two planes or flat faces meet. Use it when the axis you need is the line between two faces.",
|
||||
"help.construct.axis.two_points": "Creates a construction axis through two points, vertices or sketch points. Use it for an axis that runs between two known positions.",
|
||||
"help.construct.plane.along_path": "Creates a construction plane square to an edge or curve, at a position along it. Use it to sketch a profile for a sweep or a section of a path.",
|
||||
"help.construct.axis.edge": "Crea un eje de construcción a lo largo de una arista recta o de una línea de boceto. Úsalo como eje de una revolución, un patrón circular o una unión.",
|
||||
"help.construct.axis.normal_to_face": "Crea un eje de construcción que pasa por un punto, perpendicular a una cara. Úsalo como un eje que sale recto de una superficie.",
|
||||
"help.construct.axis.through_cylinder": "Crea un eje de construcción por el centro de una cara cilíndrica, cónica o toroidal, o de una arista circular. Úsalo para girar o repetir operaciones alrededor de una pieza redonda.",
|
||||
"help.construct.axis.two_planes": "Crea un eje de construcción donde se cortan dos planos o caras planas. Úsalo cuando el eje que necesitas sea la línea entre dos caras.",
|
||||
"help.construct.axis.two_points": "Crea un eje de construcción por dos puntos, vértices o puntos de boceto. Úsalo para un eje que va entre dos posiciones conocidas.",
|
||||
"help.construct.plane.along_path": "Crea un plano de construcción perpendicular a una arista o curva, en una posición a lo largo de ella. Úsalo para dibujar el perfil de un barrido o una sección de una trayectoria.",
|
||||
"help.construct.plane.at_angle": "Crea un plano de construcción girado un ángulo respecto a un plano o cara, alrededor de un eje o arista. Activa «Usar solo la dirección del eje» para proyectar el eje sobre la base y pivotar alrededor de un punto de ese plano (el origen de la base cuando no se elige ninguno). Úsalo para bocetos inclinados, como un soporte angular.",
|
||||
"help.construct.plane.axis_point": "Creates a construction plane containing an axis and a point off that axis. Pick an origin or construction axis, a straight edge or sketch line, then a vertex, sketch point or construction point. A point on the axis cannot define a unique plane.",
|
||||
"help.construct.plane.midplane": "Creates a construction plane halfway between two planes or flat faces, or bisecting them where they meet at an angle. Use it as a symmetry plane for mirroring.",
|
||||
"help.construct.plane.offset": "Creates a construction plane parallel to a plane or flat face, at a distance or through a point. Use it to sketch at a set height above a face.",
|
||||
"help.construct.plane.perpendicular": "Creates a construction plane that holds a line or edge and stands square to a plane or face. Use it to sketch upright on a model along an edge.",
|
||||
"help.construct.plane.tangent": "Creates a construction plane that touches a cylinder, cone, sphere or torus at a point. Use it to sketch on the side of a round part.",
|
||||
"help.construct.plane.three_points": "Creates a construction plane through three points. Use it for a plane set by positions on the model, such as three corners.",
|
||||
"help.construct.plane.two_edges": "Creates a construction plane through two straight edges or lines that lie in one plane. Use it for a plane across a part, such as through two opposite edges.",
|
||||
"help.construct.point.along_path": "Creates a construction point at a position along an edge or curve. Use it as a reference partway along a path.",
|
||||
"help.construct.point.center": "Creates a construction point at the centre of a circular edge, sketch circle or arc, sphere or torus. Use it as a reference for holes, axes and joints.",
|
||||
"help.construct.point.edge_plane": "Creates a construction point where an edge or line passes through a plane or flat face. Use it to mark where a path crosses a plane.",
|
||||
"help.construct.point.three_planes": "Creates a construction point where three planes or flat faces meet. Use it as a corner reference, even where the model has no vertex.",
|
||||
"help.construct.point.two_edges": "Creates a construction point where two edges or lines meet, or come closest. Use it as a reference at a virtual corner.",
|
||||
"help.construct.point.vertex": "Creates a construction point on a vertex or sketch point. Use it as a reference that stays when the sketch or body around it is hidden.",
|
||||
"help.contact.check": "Lists the pairs of parts in contact sets that pass through each other in their current position. Use it to find collisions before you drive joints or run a motion study.",
|
||||
"help.contact.create": "Groups two or more parts into a contact set, whose bodies are kept from passing through each other while joints move. Use it for parts that should stop when they touch, such as a lever against its stop.",
|
||||
"help.contact.disable_all": "Turns contact off, so driven joints and motion studies no longer stop where parts touch. Use it to move parts freely again, or to keep a large assembly responsive.",
|
||||
"help.contact.edit": "Changes a contact set: the parts it holds, its name, or whether it is suppressed; it can also delete the set. Use it to adjust which parts are kept from passing through each other.",
|
||||
"help.contact.enable_all": "Puts every part of the assembly into one contact set, so no two parts can pass through each other while joints move. Use it for a quick check of a whole mechanism.",
|
||||
"help.contact.enable_sets": "Turns contact on for the contact sets you defined, so driven joints and motion studies stop where their parts would pass through each other. Use it to bring your sets back after turning contact off.",
|
||||
"help.contact.list": "Lists the contact sets of the design, the parts in each one and whether contact is on. Use it to check how contact is set up before you drive the assembly.",
|
||||
"help.document.inspect": "Shows an overview of the design: its components, bodies, sketches, features and parameters. Use it to get your bearings in a design you did not build yourself.",
|
||||
"help.document.units": "Changes the units the design shows lengths in, such as mm or inches. The geometry keeps its size; only the display and plain numbers follow.",
|
||||
"help.edit.checkpoint": "Remembers the design, the active sketch and the undo history as they are now. Use it before trying something risky that you may want to go back from.",
|
||||
"help.edit.restore_checkpoint": "Goes back to a checkpoint, undo history included. Use it to drop everything done since the checkpoint in one step.",
|
||||
"help.explode.create": "Creates an exploded view that pushes the parts away from the assembly's centre, or by the moves you set. Use it to show how an assembly goes together, for instructions or presentations.",
|
||||
"help.construct.plane.axis_point": "Crea un plano de construcción que contiene un eje y un punto fuera de ese eje. Elige un origen o un eje de construcción, una arista recta o una línea de boceto, y después un vértice, un punto de boceto o un punto de construcción. Un punto del eje no define un plano único.",
|
||||
"help.construct.plane.midplane": "Crea un plano de construcción a medio camino entre dos planos o caras planas, o que los biseca donde se encuentran en ángulo. Úsalo como plano de simetría para un espejo.",
|
||||
"help.construct.plane.offset": "Crea un plano de construcción paralelo a un plano o una cara plana, a una distancia o por un punto. Úsalo para dibujar a una altura fija sobre una cara.",
|
||||
"help.construct.plane.perpendicular": "Crea un plano de construcción que contiene una línea o arista y es perpendicular a un plano o una cara. Úsalo para dibujar en vertical sobre un modelo a lo largo de una arista.",
|
||||
"help.construct.plane.tangent": "Crea un plano de construcción que toca un cilindro, cono, esfera o toro en un punto. Úsalo para dibujar en el lado de una pieza redonda.",
|
||||
"help.construct.plane.three_points": "Crea un plano de construcción por tres puntos. Úsalo para un plano definido por posiciones del modelo, como tres esquinas.",
|
||||
"help.construct.plane.two_edges": "Crea un plano de construcción por dos aristas rectas o líneas que están en un mismo plano. Úsalo para un plano que cruza una pieza, por ejemplo por dos aristas opuestas.",
|
||||
"help.construct.point.along_path": "Crea un punto de construcción en una posición a lo largo de una arista o curva. Úsalo como referencia a mitad de una trayectoria.",
|
||||
"help.construct.point.center": "Crea un punto de construcción en el centro de una arista circular, un círculo o arco de boceto, una esfera o un toro. Úsalo como referencia para agujeros, ejes y uniones.",
|
||||
"help.construct.point.edge_plane": "Crea un punto de construcción donde una arista o línea atraviesa un plano o una cara plana. Úsalo para marcar dónde una trayectoria cruza un plano.",
|
||||
"help.construct.point.three_planes": "Crea un punto de construcción donde se encuentran tres planos o caras planas. Úsalo como referencia de esquina, incluso donde el modelo no tiene vértice.",
|
||||
"help.construct.point.two_edges": "Crea un punto de construcción donde se cortan dos aristas o líneas, o donde están más cerca. Úsalo como referencia en una esquina virtual.",
|
||||
"help.construct.point.vertex": "Crea un punto de construcción sobre un vértice o un punto de boceto. Úsalo como referencia que permanece cuando se oculta el boceto o el cuerpo que lo rodea.",
|
||||
"help.contact.check": "Lista los pares de piezas de los conjuntos de contacto que se atraviesan en su posición actual. Úsalo para encontrar colisiones antes de accionar uniones o ejecutar un estudio de movimiento.",
|
||||
"help.contact.create": "Agrupa dos o más piezas en un conjunto de contacto, cuyos cuerpos no pueden atravesarse mientras las uniones se mueven. Úsalo para piezas que deben detenerse al tocarse, como una palanca contra su tope.",
|
||||
"help.contact.disable_all": "Desactiva el contacto, de modo que las uniones accionadas y los estudios de movimiento ya no se detienen donde las piezas se tocan. Úsalo para mover las piezas con libertad o para mantener ágil un ensamblaje grande.",
|
||||
"help.contact.edit": "Cambia un conjunto de contacto: las piezas que contiene, su nombre o si está desactivado; también puede eliminar el conjunto. Úsalo para ajustar qué piezas no pueden atravesarse.",
|
||||
"help.contact.enable_all": "Pone todas las piezas del ensamblaje en un único conjunto de contacto, de modo que ningún par de piezas se atraviese mientras las uniones se mueven. Úsalo para una comprobación rápida de todo un mecanismo.",
|
||||
"help.contact.enable_sets": "Activa el contacto de los conjuntos de contacto que definiste, de modo que las uniones accionadas y los estudios de movimiento se detienen donde sus piezas se atravesarían. Úsalo para recuperar tus conjuntos tras desactivar el contacto.",
|
||||
"help.contact.list": "Lista los conjuntos de contacto del diseño, las piezas de cada uno y si el contacto está activado. Úsalo para comprobar cómo está configurado el contacto antes de accionar el ensamblaje.",
|
||||
"help.document.inspect": "Muestra un resumen del diseño: sus componentes, cuerpos, bocetos, operaciones y parámetros. Úsalo para orientarte en un diseño que no construiste tú.",
|
||||
"help.document.units": "Cambia las unidades en que el diseño muestra las longitudes, como mm o pulgadas. La geometría mantiene su tamaño; solo cambian la visualización y los números sin unidad.",
|
||||
"help.edit.checkpoint": "Recuerda el diseño, el boceto activo y el historial de deshacer tal como están ahora. Úsalo antes de probar algo arriesgado de lo que quizá quieras volver.",
|
||||
"help.edit.restore_checkpoint": "Vuelve a un punto de control, historial de deshacer incluido. Úsalo para descartar de una vez todo lo hecho desde el punto de control.",
|
||||
"help.explode.create": "Crea una vista explosionada que aleja las piezas del centro del ensamblaje, o según los movimientos que indiques. Úsalo para mostrar cómo se monta un ensamblaje, en instrucciones o presentaciones.",
|
||||
"help.face.delete": "Elimina las caras seleccionadas y deja que las caras vecinas cierren el hueco, o deja",
|
||||
"help.file.insert_mesh": "Adds a 3MF, STL, OBJ, PLY or glTF file to the design as mesh bodies in a new component. Use it to place a downloaded or scanned model beside your design as a reference.",
|
||||
"help.file.insert_step": "Adds a STEP, IGES, FreeCAD or Rhino file to the design as solid bodies in a new component; an assembly's parts become nested components. Use it to bring in models from suppliers or other CAD programs.",
|
||||
"help.file.save_mesh": "Saves bodies as an STL, 3MF or OBJ mesh, with the smoothness of curved faces you choose. Use it to prepare parts for 3D printing or for programs that read meshes.",
|
||||
"help.file.send_to_slicer": "Saves the selected bodies as a 3MF file and opens it in the slicer you choose. Use it to go from the model to printing in one step.",
|
||||
"help.file.insert_mesh": "Añade un archivo 3MF, STL, OBJ, PLY o glTF al diseño como cuerpos de malla en un componente nuevo. Úsalo para colocar un modelo descargado o escaneado junto a tu diseño como referencia.",
|
||||
"help.file.insert_step": "Añade un archivo STEP, IGES, FreeCAD o Rhino al diseño como cuerpos sólidos en un componente nuevo; las piezas de un ensamblaje pasan a ser componentes anidados. Úsalo para traer modelos de proveedores o de otros programas de CAD.",
|
||||
"help.file.save_mesh": "Guarda cuerpos como una malla STL, 3MF u OBJ, con la suavidad de las caras curvas que elijas. Úsalo para preparar piezas para la impresión 3D o para programas que leen mallas.",
|
||||
"help.file.send_to_slicer": "Guarda los cuerpos seleccionados como un archivo 3MF y lo abre en el laminador que elijas. Úsalo para pasar del modelo a la impresión en un solo paso.",
|
||||
"help.font_details": "La interfaz utiliza las fuentes integradas de egui (Ubuntu Light y Hack, bajo las licencias Ubuntu Font Licence y MIT/Bitstream Vera; Noto Emoji y la fuente de iconos emoji, bajo OFL y MIT). El texto de los bocetos utiliza Liberation Sans (SIL OFL 1.1). El paquete opcional de fuentes de The Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), no se incluye en las compilaciones de SolidCraft.",
|
||||
"help.fonts": "Fuentes",
|
||||
"help.frame.member": "Places a profile, such as a tube or an aluminium extrusion, along the lines of a frame sketch, one member per line. Use it to build frames, racks and welded structures.",
|
||||
"help.inspect.accessibility": "Colours the faces a tool can reach from one direction, and those it cannot. Use it to check a part for machining or moulding from that side.",
|
||||
"help.inspect.center_of_mass": "Shows the centre of mass of bodies, each on its own and all together, at uniform density. Use it to check balance and where a part will tip.",
|
||||
"help.inspect.colored_components": "Gives each component its own temporary colour, without changing appearances. Use it to tell the parts of an assembly apart at a glance.",
|
||||
"help.inspect.compare": "Compares two bodies and shows where one has material the other does not, with volume and deviation. Use it to check a changed or imported part against the original.",
|
||||
"help.inspect.continuity": "Checks how smoothly faces meet along their edges: gaps, kinks or curvature jumps, and shades the seams. Use it to find where surfaces do not join cleanly.",
|
||||
"help.inspect.curvature_comb": "Draws combs along curves, edges or faces whose teeth show how strongly they bend. Use it to spot flat spots, kinks and uneven curvature.",
|
||||
"help.inspect.curvature_map": "Colours faces by how strongly they curve, red where the radius is small. Use it to find tight spots and to judge how smooth a surface is.",
|
||||
"help.inspect.draft": "Colours faces by their draft angle to a pull direction, marking those with too little. Use it to check a part before moulding or casting.",
|
||||
"help.inspect.environment_map": "Shows the model with a reflective, mirror-like finish. Use it to judge the flow of surfaces by the way reflections run across them.",
|
||||
"help.inspect.interference": "Finds bodies that overlap and shows each overlap with its volume. Use it to check an assembly for parts that collide.",
|
||||
"help.inspect.isocurve": "Draws the isoparametric curves of faces, the grid the surface is built on. Use it to see how a surface flows and where it bunches up.",
|
||||
"help.inspect.measure": "Measures lengths, distances, angles, areas and radii between what you pick, or the volume and mass of bodies. Use it to check sizes and clearances.",
|
||||
"help.inspect.minimum_radius": "Finds the smallest radius of curvature of curves, edges or faces, and where it is. Use it to check that a tool or nozzle can follow the shape.",
|
||||
"help.inspect.section": "Cuts the view open along a plane and hatches the cut faces, without changing the model. Use it to look inside parts and assemblies.",
|
||||
"help.inspect.zebra": "Shows black and white stripes reflected on the model's faces. Use it to judge smoothness: stripes that break or kink at an edge show a poor transition.",
|
||||
"help.joint.as_built": "Joins two parts where they already are, without moving either one, and sets how they may still move. Use it for parts you have already placed in their final position.",
|
||||
"help.joint.cam": "Links a turning cam to a follower, so the follower slides or swings as the cam's outline passes under it. Use it for cams, eccentrics and valve drives.",
|
||||
"help.joint.create": "Joins two parts at the joint origins you pick and moves the second part into place; the joint type sets how they may still move. Use it to build an assembly whose parts move like the real mechanism.",
|
||||
"help.joint.drive": "Sets a joint's angle or distance and moves the parts with it, within its limits; linked joints and closed loops follow. Use it to check that a mechanism moves as intended.",
|
||||
"help.joint.gear": "Links two turning joints with a gear ratio, so driving one turns the other. Use it for spur and ring gears, with the ratio from pitch radii or tooth counts.",
|
||||
"help.joint.limits": "Sets how far a joint may turn or slide, as a minimum and a maximum, or clears those limits. Use it to keep a hinge, slider or lever within its real range of travel.",
|
||||
"help.joint.motion_link": "Couples two joints with a ratio and an offset, so driving one moves the other. Use it for a fixed relation between joints that Gear, Rack and Pinion or Screw do not cover.",
|
||||
"help.joint.origin": "Places a named joint origin on a part: at the centre of a face or round end, the middle of an edge, a corner or a point. Use it to prepare where joints attach; one picked on a face follows it when the part changes size.",
|
||||
"help.joint.rack_pinion": "Links a turning pinion to a sliding rack, so the rack moves by the length of pitch circle the pinion rolls through. Use it for rack drives, steering and linear stages.",
|
||||
"help.joint.reach": "Moves a point on a part toward a target by changing the joints on its chain, within their limits. Use it to pose a mechanism by where its end should be, such as the tip of a robot arm.",
|
||||
"help.joint.rigid_group": "Locks the selected parts together as they are, so they move as one. Use it for parts that belong together and have no motion between them.",
|
||||
"help.joint.screw": "Links turning and sliding by a pitch, so each turn advances by that distance. Use it for lead screws, bolts and threaded spindles.",
|
||||
"help.layout.apply": "Apply a saved layout to the current workspace. Retained editors keep their drafts.",
|
||||
"help.layout.get": "Read the committed layout and discover registered workspaces.",
|
||||
"help.layout.reset": "Restore the current workspace's registered default layout. User presets remain available.",
|
||||
"help.layout.save": "Save the complete layout under a name. Replacing a user preset requires explicit overwrite permission.",
|
||||
"help.layout.workspace.select": "Select a registered layout workspace and remember the outgoing layout.",
|
||||
"help.library.apply": "Applies a material or appearance from a local library file to bodies, faces or components. Use it to reuse materials you saved from another design.",
|
||||
"help.library.export": "Saves the design's materials and appearances to a library file. Use it to share them or reuse them in other designs.",
|
||||
"help.library.inspect": "Checks a library file and lists its materials and appearances, without changing the design. Use it to see what a library holds before applying it.",
|
||||
"help.frame.end_cap": "Cierra los extremos abiertos de los miembros de una estructura con placas con la forma del contorno del perfil. Úsalo para tapar tubos, angulares y vigas, sobre el extremo o embutidas en él.",
|
||||
"help.frame.member": "Coloca un perfil, como un tubo o un perfil de aluminio extruido, a lo largo de las líneas de un boceto de estructura, un miembro por línea. Úsalo para construir bastidores, estanterías y estructuras soldadas.",
|
||||
"help.inspect.accessibility": "Colorea las caras a las que una herramienta puede llegar desde una dirección y las que no. Úsalo para comprobar una pieza para mecanizado o moldeo desde ese lado.",
|
||||
"help.inspect.center_of_mass": "Muestra el centro de masa de los cuerpos, cada uno por separado y todos juntos, con densidad uniforme. Úsalo para comprobar el equilibrio y dónde volcará una pieza.",
|
||||
"help.inspect.colored_components": "Da a cada componente su propio color temporal, sin cambiar los aspectos. Úsalo para distinguir de un vistazo las piezas de un ensamblaje.",
|
||||
"help.inspect.compare": "Compara dos cuerpos y muestra dónde uno tiene material que el otro no, con volumen y desviación. Úsalo para comprobar una pieza modificada o importada con el original.",
|
||||
"help.inspect.continuity": "Comprueba con qué suavidad se encuentran las caras a lo largo de sus aristas: huecos, quiebros o saltos de curvatura, y sombrea las uniones. Úsalo para encontrar dónde las superficies no se unen limpiamente.",
|
||||
"help.inspect.curvature_comb": "Dibuja peines a lo largo de curvas, aristas o caras, cuyos dientes muestran cuánto se curvan. Úsalo para detectar zonas planas, quiebros y curvatura irregular.",
|
||||
"help.inspect.curvature_map": "Colorea las caras según cuánto se curvan, en rojo donde el radio es pequeño. Úsalo para encontrar zonas cerradas y para juzgar lo suave que es una superficie.",
|
||||
"help.inspect.draft": "Colorea las caras según su ángulo de desmoldeo respecto a una dirección de extracción, y marca las que tienen muy poco. Úsalo para comprobar una pieza antes del moldeo o la fundición.",
|
||||
"help.inspect.environment_map": "Muestra el modelo con un acabado reflectante, como un espejo. Úsalo para juzgar el fluir de las superficies por cómo corren los reflejos sobre ellas.",
|
||||
"help.inspect.interference": "Encuentra cuerpos que se solapan y muestra cada solapamiento con su volumen. Úsalo para comprobar si un ensamblaje tiene piezas que chocan.",
|
||||
"help.inspect.isocurve": "Dibuja las curvas isoparamétricas de las caras, la malla sobre la que se construye la superficie. Úsalo para ver cómo fluye una superficie y dónde se amontona.",
|
||||
"help.inspect.measure": "Mide longitudes, distancias, ángulos, áreas y radios entre lo que elijas, o el volumen y la masa de los cuerpos. Úsalo para comprobar tamaños y holguras.",
|
||||
"help.inspect.minimum_radius": "Encuentra el menor radio de curvatura de curvas, aristas o caras, y dónde está. Úsalo para comprobar que una herramienta o una boquilla puede seguir la forma.",
|
||||
"help.inspect.section": "Corta la vista a lo largo de un plano y raya las caras cortadas, sin cambiar el modelo. Úsalo para mirar dentro de piezas y ensamblajes.",
|
||||
"help.inspect.zebra": "Muestra rayas blancas y negras reflejadas en las caras del modelo. Úsalo para juzgar la suavidad: las rayas que se rompen o se doblan en una arista indican una mala transición.",
|
||||
"help.joint.as_built": "Une dos piezas donde ya están, sin mover ninguna, y define cómo pueden seguir moviéndose. Úsalo para piezas que ya colocaste en su posición final.",
|
||||
"help.joint.cam": "Enlaza una leva giratoria con un seguidor, de modo que el seguidor se desliza o oscila cuando el contorno de la leva pasa por debajo. Úsalo para levas, excéntricas y accionamientos de válvulas.",
|
||||
"help.joint.create": "Une dos piezas en los orígenes de unión que elijas y mueve la segunda pieza a su sitio; el tipo de unión define cómo pueden seguir moviéndose. Úsalo para construir un ensamblaje cuyas piezas se muevan como el mecanismo real.",
|
||||
"help.joint.drive": "Fija el ángulo o la distancia de una unión y mueve las piezas con ella, dentro de sus límites; las uniones enlazadas y los lazos cerrados la siguen. Úsalo para comprobar que un mecanismo se mueve como se pretende.",
|
||||
"help.joint.gear": "Enlaza dos uniones giratorias con una relación de engranaje, de modo que mover una hace girar la otra. Úsalo para engranajes rectos y de corona, con la relación a partir de los radios primitivos o del número de dientes.",
|
||||
"help.joint.limits": "Fija hasta dónde puede girar o deslizarse una unión, con un mínimo y un máximo, o quita esos límites. Úsalo para mantener una bisagra, una guía o una palanca dentro de su recorrido real.",
|
||||
"help.joint.motion_link": "Acopla dos uniones con una relación y un desfase, de modo que mover una mueve la otra. Úsalo para una relación fija entre uniones que Engranaje, Cremallera y piñón o Tornillo no cubren.",
|
||||
"help.joint.origin": "Coloca un origen de unión con nombre en una pieza: en el centro de una cara o de un extremo redondo, en el medio de una arista, en una esquina o en un punto. Úsalo para preparar dónde se acoplan las uniones; el elegido en una cara la sigue cuando la pieza cambia de tamaño.",
|
||||
"help.joint.rack_pinion": "Enlaza un piñón giratorio con una cremallera deslizante, de modo que la cremallera se mueve la longitud del círculo primitivo que recorre el piñón. Úsalo para accionamientos de cremallera, dirección y mesas lineales.",
|
||||
"help.joint.reach": "Mueve un punto de una pieza hacia un objetivo cambiando las uniones de su cadena, dentro de sus límites. Úsalo para posicionar un mecanismo según dónde deba estar su extremo, como la punta de un brazo robótico.",
|
||||
"help.joint.rigid_group": "Bloquea las piezas seleccionadas tal como están, de modo que se muevan como una sola. Úsalo para piezas que van juntas y no tienen movimiento entre ellas.",
|
||||
"help.joint.screw": "Enlaza giro y deslizamiento mediante un paso, de modo que cada vuelta avanza esa distancia. Úsalo para husillos, tornillos y ejes roscados.",
|
||||
"help.layout.apply": "Aplica una disposición guardada al espacio de trabajo actual. Los editores retenidos conservan sus borradores.",
|
||||
"help.layout.get": "Lee la disposición confirmada y descubre los espacios de trabajo registrados.",
|
||||
"help.layout.reset": "Restaura la disposición predeterminada registrada del espacio de trabajo actual. Los ajustes del usuario siguen disponibles.",
|
||||
"help.layout.save": "Guarda la disposición completa con un nombre. Reemplazar un ajuste del usuario exige permiso explícito de sobrescritura.",
|
||||
"help.layout.workspace.select": "Selecciona un espacio de trabajo de disposición registrado y recuerda la disposición que se abandona.",
|
||||
"help.library.apply": "Aplica un material o un aspecto de un archivo de biblioteca local a cuerpos, caras o componentes. Úsalo para reutilizar materiales que guardaste desde otro diseño.",
|
||||
"help.library.export": "Guarda los materiales y aspectos del diseño en un archivo de biblioteca. Úsalo para compartirlos o reutilizarlos en otros diseños.",
|
||||
"help.library.inspect": "Comprueba un archivo de biblioteca y lista sus materiales y aspectos, sin cambiar el diseño. Úsalo para ver qué contiene una biblioteca antes de aplicarla.",
|
||||
"help.licences": "Licencias",
|
||||
"help.material.assign": "Define de qué están hechos los cuerpos seleccionados, como acero, aluminio o ABS. Usa",
|
||||
"help.material.properties.validate": "Checks a material data card for consistent numbers and missing values. Use it before relying on the data for mass or stiffness.",
|
||||
"help.mesh.convert": "Rebuilds a mesh body, such as an STL, as an editable solid with flat and cylindrical faces. Use it to modify imported mechanical parts like a modelled body.",
|
||||
"help.material.properties.validate": "Comprueba que una ficha de datos de material tiene números coherentes y no le faltan valores. Úsalo antes de fiarte de los datos para la masa o la rigidez.",
|
||||
"help.mesh.convert": "Reconstruye un cuerpo de malla, como un STL, en un sólido editable con caras planas y cilíndricas. Úsalo para modificar piezas mecánicas importadas como un cuerpo modelado.",
|
||||
"help.mit": "Licencia MIT",
|
||||
"help.motion.study": "Sets joint values at steps along a timeline and plays them back as an animation. Use it to watch a mechanism move through a sequence and check clearances along the way.",
|
||||
"help.motion.trace": "Traces the path a point on a part follows while a motion study plays or a joint is driven, and keeps it as a 3D sketch curve when you confirm. Use it to see where a mechanism reaches, or to build on its path.",
|
||||
"help.motion.study": "Fija valores de unión en pasos a lo largo de una línea de tiempo y los reproduce como una animación. Úsalo para ver cómo se mueve un mecanismo en una secuencia y comprobar las holguras por el camino.",
|
||||
"help.motion.trace": "Traza el camino que sigue un punto de una pieza mientras se reproduce un estudio de movimiento o se acciona una unión, y lo conserva como una curva de boceto 3D al confirmar. Úsalo para ver hasta dónde llega un mecanismo o para construir sobre su trayectoria.",
|
||||
"help.notice": "AVISO",
|
||||
"help.occurrence.ground": "Fixes a part in place, or frees it again, so that joints move the other parts around it. Use it for the frame or base that the rest of the assembly is built on.",
|
||||
"help.occurrence.ground": "Fija una pieza en su sitio, o la libera de nuevo, para que las uniones muevan las demás piezas a su alrededor. Úsalo para el bastidor o la base sobre la que se construye el resto del ensamblaje.",
|
||||
"help.occurrence.move": "Mueve una pieza de ensamblaje solo por las libertades permitidas por sus uniones. Selecciona una pieza",
|
||||
"help.panel.activate": "Select an open panel tab without requesting keyboard focus.",
|
||||
"help.panel.close": "Close a panel through its content lifecycle guard. Its placement is remembered.",
|
||||
"help.panel.collapse": "Collapse or expand a panel section while retaining its requested dimensions.",
|
||||
"help.panel.dismiss": "Dismiss the temporary view of a collapsed panel.",
|
||||
"help.panel.float": "Move a panel into an explicitly positioned floating section.",
|
||||
"help.panel.focus": "Focus a panel, reopening its retained state and expanding its section when needed.",
|
||||
"help.panel.list": "Read registered panel kinds, committed instances, active tabs, availability and host capabilities.",
|
||||
"help.panel.move": "Move a panel into a new section or join an existing tab group.",
|
||||
"help.panel.native_close": "Return a native panel section to its remembered dock without cancelling its content.",
|
||||
"help.panel.open": "Open a panel kind with an explicit instance identity and placement for a new instance.",
|
||||
"help.panel.peek": "Temporarily show a collapsed panel without changing its saved size or collapse state.",
|
||||
"help.panel.popout": "Move a panel to a native host when supported. Browser hosts use a floating section.",
|
||||
"help.panel.reset_pair": "Restore an adjacent dock pair's default size ratio within its shared bounds.",
|
||||
"help.panel.resize": "Set a panel section's outer width and height within every tab's bounds.",
|
||||
"help.panel.resize_pair": "Resize adjacent dock sections together while conserving their shared extent.",
|
||||
"help.panel.activate": "Selecciona una pestaña de panel abierta sin pedir el foco del teclado.",
|
||||
"help.panel.close": "Cierra un panel mediante la protección del ciclo de vida de su contenido. Se recuerda su ubicación.",
|
||||
"help.panel.collapse": "Contrae o expande una sección de panel conservando las dimensiones solicitadas.",
|
||||
"help.panel.dismiss": "Descarta la vista temporal de un panel contraído.",
|
||||
"help.panel.float": "Mueve un panel a una sección flotante con posición explícita.",
|
||||
"help.panel.focus": "Da el foco a un panel, reabre su estado retenido y expande su sección cuando hace falta.",
|
||||
"help.panel.list": "Lee los tipos de panel registrados, las instancias confirmadas, las pestañas activas, la disponibilidad y las capacidades del anfitrión.",
|
||||
"help.panel.move": "Mueve un panel a una sección nueva o lo une a un grupo de pestañas existente.",
|
||||
"help.panel.native_close": "Devuelve una sección de panel nativa a su acoplamiento recordado sin cancelar su contenido.",
|
||||
"help.panel.open": "Abre un tipo de panel con una identidad de instancia explícita y una ubicación para una instancia nueva.",
|
||||
"help.panel.peek": "Muestra temporalmente un panel contraído sin cambiar su tamaño guardado ni su estado de contracción.",
|
||||
"help.panel.popout": "Mueve un panel a un anfitrión nativo cuando se admite. Los anfitriones de navegador usan una sección flotante.",
|
||||
"help.panel.reset_pair": "Restaura la proporción de tamaño predeterminada de un par de acoplamientos adyacentes dentro de sus límites compartidos.",
|
||||
"help.panel.resize": "Fija el ancho y el alto exteriores de una sección de panel dentro de los límites de cada pestaña.",
|
||||
"help.panel.resize_pair": "Redimensiona juntas secciones de acoplamiento adyacentes conservando su extensión compartida.",
|
||||
"help.parameters.change": "Abre la tabla de valores y expresiones con nombre que controlan las dimensiones del",
|
||||
"help.parameters.export": "Saves the design's parameters as CSV or JSON. Use it to edit them in a spreadsheet or move them to another design.",
|
||||
"help.parameters.graph": "Shows which parameters and features use which others, and any loops or errors among them. Use it to see what a change to a parameter will affect.",
|
||||
"help.parameters.import": "Reads parameters from CSV or JSON into the design, all or none of them. Use it to bring in values from a spreadsheet or another design.",
|
||||
"help.parameters.move": "Moves a user parameter before or after another in the list. Use it to keep related parameters together.",
|
||||
"help.parts.fastener": "Adds a standard screw, bolt, nut, washer, pin or bearing in the size you pick. Placed on a hole, it seats in the hole with a joint, so you need not model fasteners yourself.",
|
||||
"help.parts.insert": "Inserts a standard part in the family, size and length you pick. Placed on the rim or wall of a hole, it seats on the hole with a rigid joint.",
|
||||
"help.parts.library": "Opens the standard parts: screws, bolts, nuts, washers, set screws, dowel pins and bearings in standard sizes. Use it to add a standard part instead of modelling it yourself.",
|
||||
"help.parts.resize": "Changes the size or length of an inserted standard part and rebuilds it; its joints keep it seated. Use it when a screw turns out too long or a hole needs another size.",
|
||||
"help.plastic.assign_rule": "Assigns a plastic rule to bodies, so their plastic features take its draft and clearance as defaults. Use it to set up a moulded part once for all its features.",
|
||||
"help.plastic.boss": "Adds a screw boss on a face: a post with an optional hole, draft, root fillet and supporting ribs. Use it for screw points in moulded or printed housings.",
|
||||
"help.parameters.export": "Guarda los parámetros del diseño como CSV o JSON. Úsalo para editarlos en una hoja de cálculo o pasarlos a otro diseño.",
|
||||
"help.parameters.graph": "Muestra qué parámetros y operaciones usan a cuáles otros, y los lazos o errores que haya entre ellos. Úsalo para ver qué afectará un cambio en un parámetro.",
|
||||
"help.parameters.import": "Lee parámetros de un CSV o JSON al diseño, todos o ninguno. Úsalo para traer valores de una hoja de cálculo o de otro diseño.",
|
||||
"help.parameters.move": "Mueve un parámetro de usuario antes o después de otro en la lista. Úsalo para mantener juntos los parámetros relacionados.",
|
||||
"help.parts.fastener": "Añade un tornillo, perno, tuerca, arandela, pasador o rodamiento estándar del tamaño que elijas. Colocado sobre un agujero, se asienta en él con una unión, así que no necesitas modelar los elementos de fijación.",
|
||||
"help.parts.insert": "Inserta una pieza estándar de la familia, el tamaño y la longitud que elijas. Colocada en el borde o la pared de un agujero, se asienta en él con una unión rígida.",
|
||||
"help.parts.library": "Abre las piezas estándar: tornillos, pernos, tuercas, arandelas, tornillos sin cabeza, pasadores cilíndricos y rodamientos en tamaños estándar. Úsalo para añadir una pieza estándar en lugar de modelarla tú.",
|
||||
"help.parts.resize": "Cambia el tamaño o la longitud de una pieza estándar insertada y la reconstruye; sus uniones la mantienen asentada. Úsalo cuando un tornillo resulta demasiado largo o un agujero necesita otro tamaño.",
|
||||
"help.plastic.assign_rule": "Asigna una regla de plástico a cuerpos, de modo que sus operaciones de plástico toman su desmoldeo y holgura como valores por defecto. Úsalo para configurar una pieza moldeada una sola vez para todas sus operaciones.",
|
||||
"help.plastic.boss": "Añade una torreta para tornillo en una cara: un poste con agujero opcional, desmoldeo, redondeo en la base y nervios de apoyo. Úsalo para los puntos de tornillo en carcasas moldeadas o impresas.",
|
||||
"help.plastic.lip": "Adds a lip or a matching groove along the rim of a shelled body. Use it so that two housing halves locate on each other and close tightly.",
|
||||
"help.plastic.manage_rules": "Creates and edits plastic rules: material, wall thickness, radii, clearance and draft. Use them to keep the features of a moulded part consistent.",
|
||||
"help.plastic.rest": "Adds a rest on a face: a round or rectangular pad, solid or hollow, with draft. Use it as a support or standoff in a moulded housing.",
|
||||
"help.plastic.snap_fit": "Adds a snap-fit hook on a face, with its length, thickness and catch. Use it to clip parts together without screws.",
|
||||
"help.plastic.manage_rules": "Crea y edita reglas de plástico: material, espesor de pared, radios, holgura y desmoldeo. Úsalas para mantener coherentes las operaciones de una pieza moldeada.",
|
||||
"help.plastic.rest": "Añade un apoyo en una cara: un taco redondo o rectangular, macizo o hueco, con desmoldeo. Úsalo como soporte o separador en una carcasa moldeada.",
|
||||
"help.plastic.snap_fit": "Añade un gancho de encaje a presión en una cara, con su longitud, espesor y resalte. Úsalo para unir piezas sin tornillos.",
|
||||
"help.pointcloud.insert": "Inserta un escaneo PLY, XYZ o PTS como nube de puntos junto al modelo. Úsala como",
|
||||
"help.sheet.convert": "Turns a plate or shelled body of even thickness into a sheet metal body, with bends at the edges you pick. Use it to make an existing part unfoldable.",
|
||||
"help.sheet.export_bend_table": "Saves the bend table of a sheet metal body as CSV or JSON: angles, radii and bend positions in the flat. Use it for the press brake or the workshop.",
|
||||
"help.sheet.export_dxf": "Saves the flat pattern as a DXF, with outlines, bend lines and optional bend notes. Use it for laser, plasma or waterjet cutting.",
|
||||
"help.sheet.flange": "Adds a flange: a base plate from a sketch, a wall along an open sketch contour, or a bent wall on sheet edges. Use it to build up sheet metal parts.",
|
||||
"help.sheet.flat_pattern": "Creates the flat pattern of a sheet metal body, with its size, cut-outs and bend lines. Use it to check the blank before you cut it.",
|
||||
"help.sheet.fold": "Bends a sheet along a sketch line by an angle and radius. Use it to fold a flat sheet after cutting features into it.",
|
||||
"help.sheet.hem": "Folds a sheet edge back on itself. Use it for safe, stiff edges without sharp burrs.",
|
||||
"help.sheet.manage_rules": "Creates and edits sheet metal rules: thickness, bend radius, K-factor, reliefs and gaps. Use them to match the material and tools of your workshop.",
|
||||
"help.sheet.path_flange": "Adds a chain of flanges along a sheet edge, following an open chain of sketch lines. Use it for profiles such as a U or Z shape in one step.",
|
||||
"help.sheet.perforate": "Adds a field of holes over the whole flat sheet, in a staggered or square pattern. Use it for vents, grilles and lighter panels.",
|
||||
"help.sheet.refold": "Folds an unfolded sheet metal body back up. Use it after adding features to the flat sheet.",
|
||||
"help.sheet.unfold": "Unfolds all bends of a sheet metal body. Use it to add holes or cuts that have to cross a bend, then refold.",
|
||||
"help.sketch.arc.center_point": "Draws a circular arc around a centre point, from a start point to an end point. Use it when the arc's centre is known, such as a radius around a hole or a pivot.",
|
||||
"help.sketch.arc.tangent": "Draws an arc that starts at the end of a line or arc and continues tangent to it. Use it to carry on a chain with a smooth bend instead of a corner.",
|
||||
"help.sketch.arc.three_point": "Draws an arc from a start point to an end point through a third point. Use it when the arc has to pass through given points rather than around a known centre.",
|
||||
"help.sketch.arc3d": "Draws an exact circular arc in space through three points, with 3D Sketch on. Use it for bends in paths and guide rails that leave the sketch plane.",
|
||||
"help.sketch.auto_constrain": "Adds the constraints the sketch nearly has already, such as horizontal, parallel or coincident, then dimensions it until it is fully defined. Use it to lock a roughly drawn sketch in one step.",
|
||||
"help.sketch.auto_constrain_from_datum": "Works like AutoConstrain, but measures the positions from a datum point you pick instead of the origin. Use it when the part is laid out from one reference point, such as a corner or a hole.",
|
||||
"help.sketch.blend_curve": "Joins the ends of two curves with a smooth spline that is tangent to both, or also curvature continuous if you choose. Use it to bridge a gap between curves without a kink.",
|
||||
"help.sketch.break": "Splits a curve into pieces where other curves cross it, or at points you place on it. Use it when part of a curve needs its own constraint or should be deleted on its own.",
|
||||
"help.sketch.cancel": "Leaves the sketch and discards everything changed since it was created or opened for editing. Undo brings the changes back.",
|
||||
"help.sketch.centerline": "Switches lines between normal lines and centerlines, axes that profiles leave out. Use a centerline as the axis for a revolve, a mirror or a symmetry constraint.",
|
||||
"help.sketch.chamfer.distance_angle": "Bevels the corner between two lines, set by a distance along the first line and an angle. Use it when a drawing gives the chamfer as a length and an angle, such as 2 mm × 30°.",
|
||||
"help.sketch.chamfer.equal_distance": "Bevels the corner between two lines the same distance back along both. Use it for the usual 45° chamfer on an outline.",
|
||||
"help.sketch.chamfer.two_distance": "Bevels the corner between two lines, set by a separate distance along each line. Use it for chamfers that are not 45°, given as two lengths.",
|
||||
"help.sketch.circle.center": "Draws a circle from its centre and its diameter. Use it for holes, bosses and other round features whose centre is known.",
|
||||
"help.sketch.circle.three_point": "Draws a circle through three points. Use it when the circle has to pass through given points, for example of existing geometry.",
|
||||
"help.sketch.circle.three_tangent": "Draws a circle that touches three lines, circles or arcs. Use it to fit a circle into the space between three curves, such as the inscribed circle of a triangle.",
|
||||
"help.sketch.circle.two_point": "Draws a circle from the two ends of its diameter. Use it when the circle's edge points are known rather than its centre.",
|
||||
"help.sketch.circle.two_tangent": "Draws a circle of a given size that touches two lines, circles or arcs. Use it for a rounding of fixed radius between two curves.",
|
||||
"help.sketch.conic": "Draws a conic curve between two end points, shaped by an apex point and a rho value. Use it for smooth transitions whose fullness you want to tune, from flat to nearly a sharp corner.",
|
||||
"help.sketch.constrainer": "Applies the constraint that one or two picked curves nearly have already, such as horizontal, parallel, tangent or equal. Use it to tidy a hand-drawn sketch one relation at a time.",
|
||||
"help.sketch.constraint.coincident": "Makes a point lie on another point, a curve or a sketch axis. Use it to close gaps in a profile or to put a point on a line.",
|
||||
"help.sketch.constraint.collinear": "Makes two lines lie on one straight line. Use it to line up interrupted edges, such as both sides of a notch.",
|
||||
"help.sketch.constraint.concentric": "Gives two circles or arcs the same centre, or centres a circle or arc on a sketch point, including the origin. Pick either pair in either order.",
|
||||
"help.sketch.constraint.curvature": "Makes two curves that meet at an end point continue with the same curvature (G2). Use it where a tangent join is not smooth enough, for example on visible surfaces.",
|
||||
"help.sketch.constraint.equal": "Makes lines the same length, or circles and arcs the same radius. Use it so that one dimension drives several matching features.",
|
||||
"help.sketch.constraint.fix": "Fixes points or curves where they are, or frees them again. Use it for geometry that must not move when you drag or solve the sketch.",
|
||||
"help.sketch.constraint.horizontal_vertical": "Makes a line, or the line between two points, horizontal or vertical, whichever is closer. Use it to square an outline up to the sketch axes.",
|
||||
"help.sketch.constraint.midpoint": "Puts a point on the middle of a line, or makes the midpoints of two lines meet. Use it to centre geometry on an edge.",
|
||||
"help.sketch.constraint.parallel": "Makes two lines parallel. Use it for sides that must stay parallel when other dimensions change.",
|
||||
"help.sketch.constraint.perpendicular": "Makes two lines meet at a right angle. Use it for square corners between lines that are not on the sketch axes.",
|
||||
"help.sketch.constraint.polygon": "Makes a closed chain of lines a regular polygon: equal sides, with every corner on one circle. Use it to make a hand-drawn polygon regular and keep it so.",
|
||||
"help.sketch.constraint.symmetry": "Makes two points or curves mirror each other across a line or about a point. Use it to keep a profile symmetric when you change one side.",
|
||||
"help.sketch.constraint.tangent": "Makes two curves touch tangentially, such as a line and an arc. Use it for smooth joins without a kink.",
|
||||
"help.sketch.construction": "Switches curves between normal geometry and construction geometry, which profiles leave out. Use construction curves as helpers for layout, references and dimensions.",
|
||||
"help.sheet.convert": "Convierte una placa o un cuerpo vaciado de espesor uniforme en un cuerpo de chapa metálica, con pliegues en las aristas que elijas. Úsalo para hacer desplegable una pieza existente.",
|
||||
"help.sheet.export_bend_table": "Guarda la tabla de plegado de un cuerpo de chapa metálica como CSV o JSON: ángulos, radios y posiciones de los pliegues en el desarrollo. Úsalo para la plegadora o el taller.",
|
||||
"help.sheet.export_dxf": "Guarda el desarrollo plano como DXF, con contornos, líneas de plegado y notas de plegado opcionales. Úsalo para corte por láser, plasma o chorro de agua.",
|
||||
"help.sheet.flange": "Añade una pestaña: una placa base a partir de un boceto, una pared a lo largo de un contorno abierto de boceto, o una pared plegada en aristas de chapa. Úsalo para construir piezas de chapa metálica.",
|
||||
"help.sheet.flat_pattern": "Crea el desarrollo plano de un cuerpo de chapa metálica, con su tamaño, recortes y líneas de plegado. Úsalo para comprobar la pieza en bruto antes de cortarla.",
|
||||
"help.sheet.fold": "Pliega una chapa a lo largo de una línea de boceto con un ángulo y un radio. Úsalo para plegar una chapa plana tras practicarle operaciones de corte.",
|
||||
"help.sheet.hem": "Dobla el borde de una chapa sobre sí mismo. Úsalo para bordes seguros y rígidos, sin rebabas cortantes.",
|
||||
"help.sheet.manage_rules": "Crea y edita reglas de chapa metálica: espesor, radio de plegado, factor K, alivios y holguras. Úsalas para ajustarte al material y a las herramientas de tu taller.",
|
||||
"help.sheet.path_flange": "Añade una cadena de pestañas a lo largo del borde de una chapa, siguiendo una cadena abierta de líneas de boceto. Úsalo para perfiles como una U o una Z en un solo paso.",
|
||||
"help.sheet.perforate": "Añade un campo de agujeros sobre toda la chapa plana, en patrón al tresbolillo o cuadrado. Úsalo para rejillas, ventilaciones y paneles más ligeros.",
|
||||
"help.sheet.refold": "Vuelve a plegar un cuerpo de chapa metálica desplegado. Úsalo tras añadir operaciones a la chapa plana.",
|
||||
"help.sheet.unfold": "Despliega todos los pliegues de un cuerpo de chapa metálica. Úsalo para añadir agujeros o cortes que deban cruzar un pliegue, y luego vuelve a plegar.",
|
||||
"help.sketch.arc.center_point": "Dibuja un arco circular alrededor de un punto central, de un punto inicial a un punto final. Úsalo cuando se conoce el centro del arco, como un radio alrededor de un agujero o de un pivote.",
|
||||
"help.sketch.arc.tangent": "Dibuja un arco que empieza en el extremo de una línea o arco y continúa tangente a él. Úsalo para seguir una cadena con una curva suave en lugar de una esquina.",
|
||||
"help.sketch.arc.three_point": "Dibuja un arco de un punto inicial a un punto final pasando por un tercer punto. Úsalo cuando el arco deba pasar por puntos dados y no alrededor de un centro conocido.",
|
||||
"help.sketch.arc3d": "Dibuja un arco circular exacto en el espacio por tres puntos, con el Boceto 3D activado. Úsalo para curvas en trayectorias y guías que salen del plano del boceto.",
|
||||
"help.sketch.auto_constrain": "Añade las restricciones que el boceto ya casi cumple, como horizontal, paralela o coincidente, y luego lo acota hasta definirlo por completo. Úsalo para fijar de un paso un boceto dibujado a mano alzada.",
|
||||
"help.sketch.auto_constrain_from_datum": "Funciona como Restricción automática, pero mide las posiciones desde un punto de referencia que eliges en lugar del origen. Úsalo cuando la pieza se organiza a partir de un punto de referencia, como una esquina o un agujero.",
|
||||
"help.sketch.blend_curve": "Une los extremos de dos curvas con una spline suave tangente a ambas, o también de curvatura continua si lo eliges. Úsalo para salvar un hueco entre curvas sin quiebros.",
|
||||
"help.sketch.break": "Divide una curva en trozos donde otras curvas la cruzan, o en puntos que colocas sobre ella. Úsalo cuando una parte de una curva necesite su propia restricción o deba borrarse por separado.",
|
||||
"help.sketch.cancel": "Sale del boceto y descarta todo lo cambiado desde que se creó o se abrió para editarlo. Deshacer recupera los cambios.",
|
||||
"help.sketch.centerline": "Cambia las líneas entre líneas normales y líneas de eje, ejes que los perfiles dejan fuera. Usa una línea de eje como eje de una revolución, un espejo o una restricción de simetría.",
|
||||
"help.sketch.chamfer.distance_angle": "Bisela la esquina entre dos líneas, definido por una distancia a lo largo de la primera línea y un ángulo. Úsalo cuando un plano da el chaflán como una longitud y un ángulo, como 2 mm × 30°.",
|
||||
"help.sketch.chamfer.equal_distance": "Bisela la esquina entre dos líneas la misma distancia hacia atrás en ambas. Úsalo para el chaflán habitual de 45° en un contorno.",
|
||||
"help.sketch.chamfer.two_distance": "Bisela la esquina entre dos líneas, definido por una distancia distinta a lo largo de cada línea. Úsalo para chaflanes que no son de 45°, dados como dos longitudes.",
|
||||
"help.sketch.circle.center": "Dibuja un círculo a partir de su centro y su diámetro. Úsalo para agujeros, salientes y otras formas redondas cuyo centro se conoce.",
|
||||
"help.sketch.circle.three_point": "Dibuja un círculo por tres puntos. Úsalo cuando el círculo deba pasar por puntos dados, por ejemplo de geometría existente.",
|
||||
"help.sketch.circle.three_tangent": "Dibuja un círculo que toca tres líneas, círculos o arcos. Úsalo para ajustar un círculo en el espacio entre tres curvas, como el círculo inscrito de un triángulo.",
|
||||
"help.sketch.circle.two_point": "Dibuja un círculo a partir de los dos extremos de su diámetro. Úsalo cuando se conocen los puntos del borde del círculo y no su centro.",
|
||||
"help.sketch.circle.two_tangent": "Dibuja un círculo de un tamaño dado que toca dos líneas, círculos o arcos. Úsalo para un redondeo de radio fijo entre dos curvas.",
|
||||
"help.sketch.conic": "Dibuja una curva cónica entre dos puntos finales, definida por un punto de vértice y un valor rho. Úsalo para transiciones suaves cuya plenitud quieras ajustar, de plana a casi una esquina viva.",
|
||||
"help.sketch.constrainer": "Aplica la restricción que una o dos curvas elegidas ya casi cumplen, como horizontal, paralela, tangente o igual. Úsalo para ordenar un boceto dibujado a mano, una relación cada vez.",
|
||||
"help.sketch.constraint.coincident": "Hace que un punto quede sobre otro punto, una curva o un eje del boceto. Úsalo para cerrar huecos en un perfil o para poner un punto sobre una línea.",
|
||||
"help.sketch.constraint.collinear": "Hace que dos líneas queden sobre una misma recta. Úsalo para alinear aristas interrumpidas, como los dos lados de una muesca.",
|
||||
"help.sketch.constraint.concentric": "Da a dos círculos o arcos el mismo centro, o centra un círculo o arco en un punto de boceto, incluido el origen. Elige cualquiera de los dos pares en cualquier orden.",
|
||||
"help.sketch.constraint.curvature": "Hace que dos curvas que se encuentran en un punto final continúen con la misma curvatura (G2). Úsalo donde una unión tangente no es lo bastante suave, por ejemplo en superficies visibles.",
|
||||
"help.sketch.constraint.equal": "Hace que las líneas tengan la misma longitud, o los círculos y arcos el mismo radio. Úsalo para que una sola cota controle varias formas iguales.",
|
||||
"help.sketch.constraint.fix": "Fija puntos o curvas donde están, o los libera de nuevo. Úsalo para geometría que no debe moverse al arrastrar o resolver el boceto.",
|
||||
"help.sketch.constraint.horizontal_vertical": "Hace que una línea, o la línea entre dos puntos, sea horizontal o vertical, la más cercana. Úsalo para ajustar un contorno a los ejes del boceto.",
|
||||
"help.sketch.constraint.midpoint": "Pone un punto en el medio de una línea, o hace que se encuentren los puntos medios de dos líneas. Úsalo para centrar geometría sobre una arista.",
|
||||
"help.sketch.constraint.parallel": "Hace paralelas dos líneas. Úsalo para lados que deben seguir paralelos cuando cambian otras cotas.",
|
||||
"help.sketch.constraint.perpendicular": "Hace que dos líneas se encuentren en ángulo recto. Úsalo para esquinas en escuadra entre líneas que no están sobre los ejes del boceto.",
|
||||
"help.sketch.constraint.polygon": "Convierte una cadena cerrada de líneas en un polígono regular: lados iguales, con todas las esquinas en un mismo círculo. Úsalo para hacer regular un polígono dibujado a mano y mantenerlo así.",
|
||||
"help.sketch.constraint.symmetry": "Hace que dos puntos o curvas sean reflejo uno de otro respecto a una línea o a un punto. Úsalo para mantener simétrico un perfil cuando cambias un lado.",
|
||||
"help.sketch.constraint.tangent": "Hace que dos curvas se toquen tangencialmente, como una línea y un arco. Úsalo para uniones suaves sin quiebros.",
|
||||
"help.sketch.construction": "Cambia las curvas entre geometría normal y geometría de construcción, que los perfiles dejan fuera. Usa las curvas de construcción como ayuda para la disposición, las referencias y las cotas.",
|
||||
"help.sketch.construction_line": "Crea una línea de construcción infinita a través de dos puntos. Úsala para organizar un boceto.",
|
||||
"help.sketch.construction_line.angle": "Crea una línea de construcción infinita en un ángulo desde el eje X del boceto. Elige el punto a",
|
||||
"help.sketch.construction_line.bisector": "Elige dos líneas rectas de boceto que se intersecten, luego elige una de las dos bisectrices del ángulo.",
|
||||
@@ -1897,72 +1904,72 @@
|
||||
"help.sketch.construction_line.tangent_external": "Elige un círculo o arco circular, luego un punto externo y una solución de tangente. Th",
|
||||
"help.sketch.construction_line.tangent_two": "Elige dos círculos o arcos circulares, luego elige una tangente común en la previsualización.",
|
||||
"help.sketch.construction_line.vertical": "Crea una línea de construcción vertical infinita a través de un punto. Su dirección vertical",
|
||||
"help.sketch.copy": "Copies the selected sketch curves and points, together with the constraints and dimensions among them. Paste them into this sketch or another one.",
|
||||
"help.sketch.create": "Starts a new 2D sketch on a plane or on a flat face of the model. Every extrude, revolve and sweep begins with a sketch.",
|
||||
"help.sketch.cut": "Copies the selected sketch geometry and deletes it from the sketch, in one undo step. Paste it elsewhere in this sketch or into another one.",
|
||||
"help.sketch.dimension": "Adds a driving dimension: a length, distance, angle, radius or diameter, depending on what you pick. Type a value or a parameter name, and the sketch follows it.",
|
||||
"help.sketch.edit": "Opens an existing sketch for editing. The features built on it update when you finish the sketch.",
|
||||
"help.sketch.ellipse": "Draws an ellipse from its centre, the end of its major axis and a point on its minor side. Use it for oval openings, cams and other elongated round shapes.",
|
||||
"help.sketch.copy": "Copia las curvas y puntos de boceto seleccionados, junto con las restricciones y cotas entre ellos. Pégalos en este boceto o en otro.",
|
||||
"help.sketch.create": "Empieza un nuevo boceto 2D en un plano o en una cara plana del modelo. Toda extrusión, revolución y barrido empieza con un boceto.",
|
||||
"help.sketch.cut": "Copia la geometría de boceto seleccionada y la borra del boceto, en un solo paso de deshacer. Pégala en otro lugar de este boceto o en otro.",
|
||||
"help.sketch.dimension": "Añade una cota conductora: una longitud, distancia, ángulo, radio o diámetro, según lo que elijas. Escribe un valor o el nombre de un parámetro y el boceto lo sigue.",
|
||||
"help.sketch.edit": "Abre un boceto existente para editarlo. Las operaciones construidas sobre él se actualizan al terminar el boceto.",
|
||||
"help.sketch.ellipse": "Dibuja una elipse a partir de su centro, el extremo de su eje mayor y un punto de su lado menor. Úsalo para aberturas ovaladas, levas y otras formas redondas alargadas.",
|
||||
"help.sketch.equation_curve": "Dibuja una curva a partir de fórmulas: x(t) e y(t), o y = f(x), sobre un rango. La fórmula",
|
||||
"help.sketch.extend": "Lengthens a line or arc up to the nearest curve in its way, or grows two curves until they meet. Use it to close gaps in a profile after trimming or editing.",
|
||||
"help.sketch.fillet": "Rounds the corner where two lines or arcs meet with an arc of a given radius. Several corners rounded together share one radius.",
|
||||
"help.sketch.finish": "Leaves the sketch and returns to the model. Its closed profiles are then ready for Extrude, Revolve and other features.",
|
||||
"help.sketch.finish_auto_constrain": "Runs AutoConstrain on the sketch, then finishes it. Use it to leave a sketch fully defined in one step.",
|
||||
"help.sketch.fit_curves_to_section": "Cuts a mesh or solid body with the sketch plane and fits lines and arcs to the section. Use it to rebuild a scanned or imported part as an editable sketch.",
|
||||
"help.sketch.include_3d": "Brings model edges, vertices and curves of other sketches into this sketch as linked references, flattening those off its plane onto it. Use it to build on geometry that does not lie in the sketch plane.",
|
||||
"help.sketch.infinite": "Switches lines between normal lines and infinite construction lines that run across the whole view. Use them as layout references that never end too short.",
|
||||
"help.sketch.insert_dxf": "Reads the curves of a DXF drawing into a sketch, scaled, turned and placed where you set. Use it to build on a 2D drawing from another program, such as a laser-cut outline.",
|
||||
"help.sketch.insert_svg": "Reads the paths of an SVG drawing into a sketch, scaled, turned and placed where you set. Use it to turn a logo or vector outline into curves you can extrude.",
|
||||
"help.sketch.extend": "Alarga una línea o un arco hasta la curva más cercana que encuentre, o hace crecer dos curvas hasta que se encuentran. Úsalo para cerrar huecos de un perfil tras recortar o editar.",
|
||||
"help.sketch.fillet": "Redondea la esquina donde se encuentran dos líneas o arcos con un arco de un radio dado. Varias esquinas redondeadas a la vez comparten un radio.",
|
||||
"help.sketch.finish": "Sale del boceto y vuelve al modelo. Sus perfiles cerrados quedan listos para Extrusión, Revolución y otras operaciones.",
|
||||
"help.sketch.finish_auto_constrain": "Ejecuta Restricción automática en el boceto y luego lo finaliza. Úsalo para dejar un boceto totalmente definido de un paso.",
|
||||
"help.sketch.fit_curves_to_section": "Corta un cuerpo de malla o sólido con el plano del boceto y ajusta líneas y arcos a la sección. Úsalo para reconstruir como boceto editable una pieza escaneada o importada.",
|
||||
"help.sketch.include_3d": "Trae aristas del modelo, vértices y curvas de otros bocetos a este boceto como referencias vinculadas, aplanando sobre él las que no están en su plano. Úsalo para construir sobre geometría que no está en el plano del boceto.",
|
||||
"help.sketch.infinite": "Cambia las líneas entre líneas normales y líneas de construcción infinitas que cruzan toda la vista. Úsalas como referencias de disposición que nunca se quedan cortas.",
|
||||
"help.sketch.insert_dxf": "Lee las curvas de un dibujo DXF en un boceto, escaladas, giradas y colocadas donde indiques. Úsalo para construir sobre un dibujo 2D de otro programa, como un contorno para corte láser.",
|
||||
"help.sketch.insert_svg": "Lee los trazados de un dibujo SVG en un boceto, escalados, girados y colocados donde indiques. Úsalo para convertir un logotipo o un contorno vectorial en curvas que puedas extruir.",
|
||||
"help.sketch.inspect": "Abre un informe sobre el boceto abierto: cuántos grados de libertad quedan y qué",
|
||||
"help.sketch.intersect": "Adds the curves or points where bodies, faces, edges or other sketches cross the sketch plane. They stay linked and follow the model when it changes.",
|
||||
"help.sketch.intersect": "Añade las curvas o puntos donde cuerpos, caras, aristas u otros bocetos cruzan el plano del boceto. Quedan vinculados y siguen al modelo cuando cambia.",
|
||||
"help.sketch.intersection_curve": "Crea curvas 3D donde se encuentran dos cuerpos, caras o curvas de otros bocetos, vinculadas a ellos. Úsalas como trayectorias o líneas guía que siguen el modelo.",
|
||||
"help.sketch.isoparametric_curve": "Creates a 3D curve along a face's U or V direction through a point you pick, linked to the face. Use it as a path or split line that follows the surface.",
|
||||
"help.sketch.line": "Draws connected lines point by point, as an open chain or a closed outline. It is the basic tool for most profiles.",
|
||||
"help.sketch.line.midpoint": "Draws a line from its midpoint out to one end, with the other end mirrored. Use it for lines centred on a point, such as a symmetric edge.",
|
||||
"help.sketch.line3d": "Draws connected straight lines between points in space, with 3D Sketch on. Use it for paths and frames that leave the sketch plane.",
|
||||
"help.sketch.mirror": "Mirrors sketch curves and points across a line or axis and adds symmetry constraints. Use it to draw half of a symmetric profile and complete it.",
|
||||
"help.sketch.move": "Moves or rotates sketch curves and points, or a copy of them. Use it to reposition geometry while keeping its shape and constraints.",
|
||||
"help.sketch.offset": "Creates a copy of a chain of curves at a set distance, on one side or both. Use it for walls, outlines and clearances; the distance stays an editable dimension.",
|
||||
"help.sketch.paste": "Pastes sketch geometry you copied or cut into the active sketch. Place it at a point or shift it by an offset.",
|
||||
"help.sketch.pattern.circular": "Copies sketch geometry around a centre point, over a full circle or a set angle. Use it for bolt circles, spokes and teeth.",
|
||||
"help.sketch.pattern.rectangular": "Copies sketch geometry in rows and columns at set spacings. Use it for grids of holes, slots or vents.",
|
||||
"help.sketch.point": "Places a sketch point. Use it as a reference for dimensions, constraints, hole centres or later features.",
|
||||
"help.sketch.isoparametric_curve": "Crea una curva 3D en la dirección U o V de una cara, por un punto que eliges, vinculada a la cara. Úsala como trayectoria o línea de división que sigue la superficie.",
|
||||
"help.sketch.line": "Dibuja líneas conectadas punto por punto, como cadena abierta o contorno cerrado. Es la herramienta básica de la mayoría de los perfiles.",
|
||||
"help.sketch.line.midpoint": "Dibuja una línea desde su punto medio hasta un extremo, con el otro extremo reflejado. Úsalo para líneas centradas en un punto, como una arista simétrica.",
|
||||
"help.sketch.line3d": "Dibuja líneas rectas conectadas entre puntos del espacio, con el Boceto 3D activado. Úsalo para trayectorias y estructuras que salen del plano del boceto.",
|
||||
"help.sketch.mirror": "Refleja curvas y puntos de boceto respecto a una línea o un eje y añade restricciones de simetría. Úsalo para dibujar la mitad de un perfil simétrico y completarlo.",
|
||||
"help.sketch.move": "Mueve o gira curvas y puntos de boceto, o una copia de ellos. Úsalo para recolocar geometría conservando su forma y sus restricciones.",
|
||||
"help.sketch.offset": "Crea una copia de una cadena de curvas a una distancia fijada, por un lado o por ambos. Úsalo para paredes, contornos y holguras; la distancia sigue siendo una cota editable.",
|
||||
"help.sketch.paste": "Pega en el boceto activo la geometría de boceto que copiaste o cortaste. Colócala en un punto o desplázala un desfase.",
|
||||
"help.sketch.pattern.circular": "Copia la geometría de boceto alrededor de un punto central, en un círculo completo o un ángulo fijado. Úsalo para círculos de pernos, radios y dientes.",
|
||||
"help.sketch.pattern.rectangular": "Copia la geometría de boceto en filas y columnas con separaciones fijadas. Úsalo para cuadrículas de agujeros, ranuras o ventilaciones.",
|
||||
"help.sketch.point": "Coloca un punto de boceto. Úsalo como referencia para cotas, restricciones, centros de agujeros u operaciones posteriores.",
|
||||
"help.sketch.point.divide": "Coloca puntos que dividen las curvas elegidas en longitudes iguales. Los puntos permanecen en cada curva y mantienen su separación cuando esta cambia.",
|
||||
"help.sketch.point3d": "Places a point in space, with 3D Sketch on. Use it as a reference for 3D curves and paths.",
|
||||
"help.sketch.polygon.circumscribed": "Draws a regular polygon around a circle, sized from its centre to the middle of a side. Use it when the width across flats is known, as for a hex nut.",
|
||||
"help.sketch.polygon.edge": "Draws a regular polygon from the two ends of one side. Use it when the length and position of a side are known.",
|
||||
"help.sketch.polygon.inscribed": "Draws a regular polygon inside a circle, sized from its centre to a corner. Use it when the size across corners is known.",
|
||||
"help.sketch.project": "Brings model edges, faces, vertices and curves of other sketches into this sketch, projected onto its plane. They stay linked and follow the model when it changes.",
|
||||
"help.sketch.project_to_surface": "Projects curves of other sketches along this sketch's normal onto a face, as linked 3D curves. Use it to put a logo, split line or path onto a curved surface.",
|
||||
"help.sketch.rectangle.center": "Draws a rectangle from its centre and one corner. Use it for outlines centred on a point, such as the origin.",
|
||||
"help.sketch.rectangle.rounded": "Draws a rectangle with all four corners rounded to one radius. Use it for plates, lids and openings with rounded corners.",
|
||||
"help.sketch.rectangle.three_point": "Draws a rectangle from one edge and a point on the opposite side. Use it for rectangles at an angle to the sketch axes.",
|
||||
"help.sketch.rectangle.two_point": "Draws a rectangle from two opposite corners. Use it for the outlines of plates, blocks and pockets.",
|
||||
"help.sketch.scale": "Scales sketch curves and points by a factor about a base point. Use it to resize part of a sketch without drawing it again.",
|
||||
"help.sketch.slot.arc_center": "Draws a curved slot of a given width along an arc set by its centre, start and end. Use it for adjustment slots around a pivot.",
|
||||
"help.sketch.slot.arc_three_point": "Draws a curved slot of a given width along an arc through three points. Use it when the slot's path has to pass through given points.",
|
||||
"help.sketch.slot.center_point": "Draws a straight slot of a given width from its centre to the centre of one end arc. Use it for slots centred on a point.",
|
||||
"help.sketch.slot.center_to_center": "Draws a straight slot of a given width between the centres of its two end arcs. Use it for slots dimensioned centre to centre, such as adjustment slots for screws.",
|
||||
"help.sketch.slot.overall": "Draws a straight slot of a given width from one outer end to the other. Use it when the slot's overall length is what matters.",
|
||||
"help.sketch.spline.control_point": "Draws a cubic spline shaped by control points that it does not pass through. Use it for smooth, flowing curves that you shape by moving the points.",
|
||||
"help.sketch.spline.control_point_5": "Draws a degree 5 spline shaped by control points. Use it where curves have to join with smoother curvature, for example on visible styled surfaces.",
|
||||
"help.sketch.spline.fit_point": "Draws a smooth spline that passes through every point you place, open or closed. Use it to trace a shape through known points.",
|
||||
"help.sketch.spline3d": "Draws a smooth curve in space through points, with 3D Sketch on. Use it for sweep paths and cable runs that leave the sketch plane.",
|
||||
"help.sketch.spun_profile": "Creates in the sketch plane the outline a body sweeps when it turns about an axis. Use it to get the silhouette of a turned part for a revolve or a drawing.",
|
||||
"help.sketch.text": "Writes text in the sketch in a chosen font, height and angle; its words can follow parameters. Extrude or emboss it for labels and lettering.",
|
||||
"help.sketch.transform": "Scales, turns and moves sketch geometry about a centre point in one step. Use it to reposition and resize a selection at once.",
|
||||
"help.sketch.trim": "Removes the piece of a curve between the nearest crossings around where you click. Use it to clean up overlapping lines into a closed profile.",
|
||||
"help.sketch.point3d": "Coloca un punto en el espacio, con el Boceto 3D activado. Úsalo como referencia para curvas y trayectorias 3D.",
|
||||
"help.sketch.polygon.circumscribed": "Dibuja un polígono regular alrededor de un círculo, dimensionado desde su centro hasta el medio de un lado. Úsalo cuando se conoce la anchura entre caras, como en una tuerca hexagonal.",
|
||||
"help.sketch.polygon.edge": "Dibuja un polígono regular a partir de los dos extremos de un lado. Úsalo cuando se conocen la longitud y la posición de un lado.",
|
||||
"help.sketch.polygon.inscribed": "Dibuja un polígono regular dentro de un círculo, dimensionado desde su centro hasta una esquina. Úsalo cuando se conoce la medida entre esquinas.",
|
||||
"help.sketch.project": "Trae aristas del modelo, caras, vértices y curvas de otros bocetos a este boceto, proyectados sobre su plano. Quedan vinculados y siguen al modelo cuando cambia.",
|
||||
"help.sketch.project_to_surface": "Proyecta curvas de otros bocetos a lo largo de la normal de este boceto sobre una cara, como curvas 3D vinculadas. Úsalo para poner un logotipo, una línea de división o una trayectoria sobre una superficie curva.",
|
||||
"help.sketch.rectangle.center": "Dibuja un rectángulo a partir de su centro y una esquina. Úsalo para contornos centrados en un punto, como el origen.",
|
||||
"help.sketch.rectangle.rounded": "Dibuja un rectángulo con las cuatro esquinas redondeadas con un mismo radio. Úsalo para placas, tapas y aberturas con esquinas redondeadas.",
|
||||
"help.sketch.rectangle.three_point": "Dibuja un rectángulo a partir de un borde y un punto del lado opuesto. Úsalo para rectángulos inclinados respecto a los ejes del boceto.",
|
||||
"help.sketch.rectangle.two_point": "Dibuja un rectángulo a partir de dos esquinas opuestas. Úsalo para los contornos de placas, bloques y vaciados.",
|
||||
"help.sketch.scale": "Escala curvas y puntos de boceto por un factor respecto a un punto base. Úsalo para cambiar el tamaño de parte de un boceto sin volver a dibujarla.",
|
||||
"help.sketch.slot.arc_center": "Dibuja una ranura curva de una anchura dada a lo largo de un arco definido por su centro, inicio y fin. Úsalo para ranuras de ajuste alrededor de un pivote.",
|
||||
"help.sketch.slot.arc_three_point": "Dibuja una ranura curva de una anchura dada a lo largo de un arco por tres puntos. Úsalo cuando la trayectoria de la ranura deba pasar por puntos dados.",
|
||||
"help.sketch.slot.center_point": "Dibuja una ranura recta de una anchura dada desde su centro hasta el centro de un arco de extremo. Úsalo para ranuras centradas en un punto.",
|
||||
"help.sketch.slot.center_to_center": "Dibuja una ranura recta de una anchura dada entre los centros de sus dos arcos de extremo. Úsalo para ranuras acotadas de centro a centro, como las ranuras de ajuste de tornillos.",
|
||||
"help.sketch.slot.overall": "Dibuja una ranura recta de una anchura dada de un extremo exterior al otro. Úsalo cuando lo que importa es la longitud total de la ranura.",
|
||||
"help.sketch.spline.control_point": "Dibuja una spline cúbica definida por puntos de control por los que no pasa. Úsalo para curvas suaves y fluidas que moldeas moviendo los puntos.",
|
||||
"help.sketch.spline.control_point_5": "Dibuja una spline de grado 5 definida por puntos de control. Úsalo donde las curvas deban unirse con una curvatura más suave, por ejemplo en superficies de diseño visibles.",
|
||||
"help.sketch.spline.fit_point": "Dibuja una spline suave que pasa por cada punto que colocas, abierta o cerrada. Úsalo para trazar una forma por puntos conocidos.",
|
||||
"help.sketch.spline3d": "Dibuja una curva suave en el espacio por puntos, con el Boceto 3D activado. Úsalo para trayectorias de barrido y recorridos de cable que salen del plano del boceto.",
|
||||
"help.sketch.spun_profile": "Crea en el plano del boceto el contorno que barre un cuerpo al girar sobre un eje. Úsalo para obtener la silueta de una pieza torneada para una revolución o un plano.",
|
||||
"help.sketch.text": "Escribe texto en el boceto con una fuente, altura y ángulo elegidos; sus palabras pueden seguir parámetros. Extrúyelo o grábalo para etiquetas y rótulos.",
|
||||
"help.sketch.transform": "Escala, gira y mueve la geometría del boceto respecto a un punto central en un solo paso. Úsalo para recolocar y cambiar de tamaño una selección a la vez.",
|
||||
"help.sketch.trim": "Elimina el trozo de una curva entre los cruces más cercanos alrededor de donde haces clic. Úsalo para limpiar líneas solapadas y obtener un perfil cerrado.",
|
||||
"help.solid.align": "Mueve los cuerpos seleccionados para que un punto, cara o plano de ellos coincida con un punto,",
|
||||
"help.solid.boundary_fill": "Makes solids from the regions enclosed by overlapping tool bodies, filling only the regions you pick. Use it to build a shape from the space that several bodies bound together.",
|
||||
"help.solid.bounding_solid": "Creates a box that encloses the selected bodies, with an optional margin. Use it to see a part's overall size, or as the stock it is machined from.",
|
||||
"help.solid.box": "Creates a box from a length, width and height, from a corner point or centred on a point. Use it for a quick block, a placeholder or a body to cut features into.",
|
||||
"help.solid.boundary_fill": "Crea sólidos a partir de las regiones encerradas por cuerpos herramienta que se solapan, rellenando solo las regiones que elijas. Úsalo para construir una forma a partir del espacio que delimitan varios cuerpos juntos.",
|
||||
"help.solid.bounding_solid": "Crea una caja que envuelve los cuerpos seleccionados, con un margen opcional. Úsalo para ver el tamaño total de una pieza, o como material en bruto del que se mecaniza.",
|
||||
"help.solid.box": "Crea una caja a partir de largo, ancho y alto, desde un punto de esquina o centrada en un punto. Úsalo para un bloque rápido, un marcador de posición o un cuerpo en el que practicar operaciones de corte.",
|
||||
"help.solid.chamfer": "Corta las aristas seleccionadas con un chaflán plano de la distancia que indiques. Úsalo para romper aristas vivas o para facilitar la entrada de un pasador o un tornillo.",
|
||||
"help.solid.coil": "Creates a helical body, such as a spring, from a diameter, turns, height or pitch and a round or square section. Use it for springs, coils and helical ridges.",
|
||||
"help.solid.coil": "Crea un cuerpo helicoidal, como un muelle, a partir de un diámetro, vueltas, altura o paso y una sección redonda o cuadrada. Úsalo para muelles, bobinas y resaltes helicoidales.",
|
||||
"help.solid.combine": "Combina cuerpos: los une, los recorta de un cuerpo de destino o conserva solo el volumen que comparten, y puede mantener los cuerpos de herramienta. Úsalo para fusionar piezas, recortar una forma con otra o encontrar dónde se solapan dos cuerpos.",
|
||||
"help.solid.cone": "Creates a cone from a base circle and a height, or a truncated cone when the top has a radius too. Use it for tapers, funnels, countersinks and points.",
|
||||
"help.solid.cylinder": "Creates a cylinder from a radius or diameter and a height, standing on a point along an axis. Use it for shafts, pins, bosses and round blanks.",
|
||||
"help.solid.cone": "Crea un cono a partir de un círculo base y una altura, o un cono truncado cuando la parte superior también tiene radio. Úsalo para conicidades, embudos, avellanados y puntas.",
|
||||
"help.solid.cylinder": "Crea un cilindro a partir de un radio o diámetro y una altura, apoyado en un punto a lo largo de un eje. Úsalo para ejes, pasadores, salientes y piezas en bruto redondas.",
|
||||
"help.solid.draft": "Inclina las caras seleccionadas según el ángulo que indiques, medido desde un plano neutro. Usa",
|
||||
"help.solid.emboss": "Raises sketch profiles, such as text or a logo, out of a face, or sinks them into it. Use it for lettering, labels and markings on flat or round faces.",
|
||||
"help.solid.emboss": "Eleva perfiles de boceto, como texto o un logotipo, sobre una cara, o los hunde en ella. Úsalo para rótulos, etiquetas y marcas en caras planas o redondas.",
|
||||
"help.solid.extrude": "Empuja un perfil de boceto hacia el 3D a lo largo de una distancia, añadiendo o quitando material. Úsalo para convertir un contorno plano en un bloque, un saliente o una cavidad.",
|
||||
"help.solid.fillet": "Redondea las aristas seleccionadas con una transición circular suave del radio que indiques. Úsalo para suavizar aristas vivas por resistencia, comodidad o aspecto.",
|
||||
"help.solid.hole": "Perfora un agujero redondo del diámetro que indiques en un punto elegido de una cara. Úsalo para holguras de tornillos, pasadores y otras aberturas redondas sencillas.",
|
||||
@@ -1971,62 +1978,62 @@
|
||||
"help.solid.move": "Mueve o rota los cuerpos seleccionados, o una copia de ellos, por la distancia y el ángulo",
|
||||
"help.solid.offset_face": "Empuja las caras seleccionadas hacia dentro o fuera por la distancia que indiques, y las caras de alrededor",
|
||||
"help.solid.pattern.circular": "Repite los objetos seleccionados alrededor de un eje, con el recuento y el ángulo total que indiques. Úsalo para círculos de tornillos, radios, aletas y dientes.",
|
||||
"help.solid.pattern.path": "Copies features or bodies along a sketch path, by count and spacing. Use it for holes along a curved edge or parts along a rail.",
|
||||
"help.solid.pattern.path": "Copia operaciones o cuerpos a lo largo de una trayectoria de boceto, por número y separación. Úsalo para agujeros a lo largo de una arista curva o piezas a lo largo de un carril.",
|
||||
"help.solid.pattern.rectangular": "Repite los objetos seleccionados en una o dos direcciones con el recuento y el espaciado que indiques. Úsalo para filas y cuadrículas de agujeros, nervios, pasadores o patas.",
|
||||
"help.solid.pipe": "Creates a round tube along a path of sketch curves, solid or hollow with a wall thickness. Use it for tubes, wires, cables and rails.",
|
||||
"help.solid.pipe": "Crea un tubo redondo a lo largo de una trayectoria de curvas de boceto, macizo o hueco con un espesor de pared. Úsalo para tubos, cables y carriles.",
|
||||
"help.solid.press_pull": "Añade o quita material al arrastrar una cara, o redondea aristas al arrastrarlas. Usa",
|
||||
"help.solid.remove": "Saca los cuerpos seleccionados del diseño desde este punto de la línea de tiempo en adelante;",
|
||||
"help.solid.replace_face": "Mueve las caras planas seleccionadas sobre un plano o sobre una cara paralela, y el cuerpo",
|
||||
"help.solid.revolve": "Gira un perfil de boceto alrededor de un eje para crear un sólido de revolución. Úsalo para ejes, pomos, cuencos y cualquier otra pieza de revolución.",
|
||||
"help.solid.rib": "Adds a thin wall along an open sketch curve, filled out to the next faces of the body. Use it to stiffen walls and corners, for example in moulded or printed parts.",
|
||||
"help.solid.rib": "Añade una pared fina a lo largo de una curva de boceto abierta, extendida hasta las siguientes caras del cuerpo. Úsalo para reforzar paredes y esquinas, por ejemplo en piezas moldeadas o impresas.",
|
||||
"help.solid.scale": "Hace los cuerpos seleccionados más grandes o más pequeños por un factor, el mismo en todas las direcciones",
|
||||
"help.solid.shell": "Vacía un sólido y deja paredes del grosor que indiques; además, puede abrir las caras que elijas. Úsalo para cajas, tapas y otras piezas de paredes finas.",
|
||||
"help.solid.sphere": "Creates a sphere from a radius or diameter around a centre point. Use it for balls, knobs and rounded ends.",
|
||||
"help.solid.sphere": "Crea una esfera a partir de un radio o diámetro alrededor de un punto central. Úsalo para bolas, pomos y extremos redondeados.",
|
||||
"help.solid.split_body": "Corta un cuerpo en cuerpos separados con un plano, la cara de otro cuerpo o un boceto",
|
||||
"help.solid.split_face": "Divide las caras seleccionadas a lo largo de un plano, la cara de otro cuerpo o una curva de boceto",
|
||||
"help.solid.sweep": "Arrastra un perfil de boceto a lo largo de una trayectoria para crear un sólido. Úsalo para tubos, raíles, asas y cualquier pieza de sección constante que siga una curva.",
|
||||
"help.solid.thread": "Adds an ISO metric thread to a cylindrical face, either as a cosmetic thread or cut into the body. Use it for bolts, threaded holes and printed screw parts.",
|
||||
"help.solid.torus": "Creates a ring from a major radius around its axis and a minor radius for its round section. Use it for O-rings, handles and round beads.",
|
||||
"help.solid.web": "Adds a thin wall along each open sketch curve, each filled out to the next faces of the body. Use it for a grid of supporting walls inside housings and trays.",
|
||||
"help.surface.blend": "Creates a surface that bridges the edges of two bodies, tangent or curvature continuous to both. Use it to join two surfaces smoothly across a gap.",
|
||||
"help.surface.boundary": "Creates a surface filling a loop of two to four sketch curves, or a network of curves. Use it for free-form panels defined by their edges.",
|
||||
"help.surface.extend": "Lengthens a surface past its edges, by a distance or up to a plane or face. Use it so that surfaces overlap before you trim or stitch them.",
|
||||
"help.surface.extrude": "Pushes sketch curves or profiles along a distance into a surface, walls only, without caps. Use it for thin walls and for cutting or splitting tools.",
|
||||
"help.surface.fair": "Smooths the inside of free-form faces while their edges stay put. Use it to even out bumps and wavy reflections in a surface.",
|
||||
"help.surface.loft": "Creates a surface that passes through two or more sections in order, without caps. Use it for shells and transitions between different shapes.",
|
||||
"help.surface.match": "Rebuilds the edge of a surface so it meets another body's edge, with matching tangent or curvature. Use it to close a seam smoothly between two surfaces.",
|
||||
"help.surface.offset": "Creates a copy of faces at a distance along their normals, as a new surface body. Use it for skins, clearances or the other side of a wall.",
|
||||
"help.surface.patch": "Fills a sketch region or a closed loop of edges with a face, flat or smoothly curved. Use it to close holes in a surface body.",
|
||||
"help.surface.reverse_normal": "Turns faces of a surface body over, so their outside faces the other way. Use it before thickening or stitching when the faces point inward.",
|
||||
"help.surface.revolve": "Turns sketch curves or profiles about an axis into a surface, without caps. Use it for round shells such as lampshades, bowls and nozzles.",
|
||||
"help.surface.ruled": "Creates a strip of straight lines out from a chain of edges, along the face's normal, tangent or at an angle. Use it for draft walls, run-offs and parting surfaces.",
|
||||
"help.surface.stitch": "Sews surface bodies together along their shared edges, into a solid when they close. Use it to turn a set of surfaces into one body.",
|
||||
"help.surface.sweep": "Moves sketch curves or profiles along a path into a surface, without caps. Use it for gutters, trims and other thin shapes that follow a path.",
|
||||
"help.surface.thicken": "Gives a surface body a thickness, turning it into a solid. Use it to make printable or machinable parts from surfaces.",
|
||||
"help.surface.trim": "Cuts a surface with a plane, another surface or sketch curves, and keeps the side you pick. Use it to cut surfaces to shape before stitching.",
|
||||
"help.surface.unstitch": "Separates faces of a body into surface bodies of their own; a solid comes apart into surfaces. Use it to rework single faces of a body.",
|
||||
"help.surface.untrim": "Removes holes from a face, or restores its outer boundary to the surface's natural bounds. Use it to get back the full surface after a trim.",
|
||||
"help.solid.thread": "Añade una rosca métrica ISO a una cara cilíndrica, como rosca cosmética o tallada en el cuerpo. Úsalo para pernos, agujeros roscados y piezas impresas con rosca.",
|
||||
"help.solid.torus": "Crea un anillo a partir de un radio mayor alrededor de su eje y un radio menor para su sección redonda. Úsalo para juntas tóricas, asas y cuentas redondas.",
|
||||
"help.solid.web": "Añade una pared fina a lo largo de cada curva de boceto abierta, cada una extendida hasta las siguientes caras del cuerpo. Úsalo para una rejilla de paredes de apoyo dentro de carcasas y bandejas.",
|
||||
"help.surface.blend": "Crea una superficie que une las aristas de dos cuerpos, tangente o de curvatura continua con ambos. Úsalo para unir suavemente dos superficies a través de un hueco.",
|
||||
"help.surface.boundary": "Crea una superficie que rellena un lazo de dos a cuatro curvas de boceto, o una red de curvas. Úsalo para paneles de forma libre definidos por sus bordes.",
|
||||
"help.surface.extend": "Alarga una superficie más allá de sus bordes, una distancia o hasta un plano o una cara. Úsalo para que las superficies se solapen antes de recortarlas o coserlas.",
|
||||
"help.surface.extrude": "Empuja curvas o perfiles de boceto una distancia para crear una superficie, solo paredes, sin tapas. Úsalo para paredes finas y para herramientas de corte o división.",
|
||||
"help.surface.fair": "Suaviza el interior de caras de forma libre mientras sus bordes se quedan donde están. Úsalo para igualar bultos y reflejos ondulados en una superficie.",
|
||||
"help.surface.loft": "Crea una superficie que pasa por dos o más secciones en orden, sin tapas. Úsalo para cascarones y transiciones entre formas distintas.",
|
||||
"help.surface.match": "Reconstruye el borde de una superficie para que encuentre el borde de otro cuerpo, con tangencia o curvatura coincidentes. Úsalo para cerrar suavemente una unión entre dos superficies.",
|
||||
"help.surface.offset": "Crea una copia de caras a una distancia a lo largo de sus normales, como un nuevo cuerpo de superficie. Úsalo para pieles, holguras o el otro lado de una pared.",
|
||||
"help.surface.patch": "Rellena una región de boceto o un lazo cerrado de aristas con una cara, plana o suavemente curva. Úsalo para cerrar agujeros en un cuerpo de superficie.",
|
||||
"help.surface.reverse_normal": "Da la vuelta a caras de un cuerpo de superficie, de modo que su exterior mire al otro lado. Úsalo antes de engrosar o coser cuando las caras apuntan hacia dentro.",
|
||||
"help.surface.revolve": "Gira curvas o perfiles de boceto alrededor de un eje para crear una superficie, sin tapas. Úsalo para cascarones redondos como pantallas de lámpara, cuencos y toberas.",
|
||||
"help.surface.ruled": "Crea una tira de líneas rectas a partir de una cadena de aristas, a lo largo de la normal de la cara, tangente o en ángulo. Úsalo para paredes con desmoldeo, salidas y superficies de partición.",
|
||||
"help.surface.stitch": "Cose cuerpos de superficie a lo largo de sus aristas compartidas, en un sólido cuando se cierran. Úsalo para convertir un conjunto de superficies en un solo cuerpo.",
|
||||
"help.surface.sweep": "Mueve curvas o perfiles de boceto a lo largo de una trayectoria para crear una superficie, sin tapas. Úsalo para canalones, molduras y otras formas finas que siguen una trayectoria.",
|
||||
"help.surface.thicken": "Da espesor a un cuerpo de superficie y lo convierte en sólido. Úsalo para obtener piezas imprimibles o mecanizables a partir de superficies.",
|
||||
"help.surface.trim": "Corta una superficie con un plano, otra superficie o curvas de boceto, y conserva el lado que elijas. Úsalo para dar forma a las superficies antes de coserlas.",
|
||||
"help.surface.unstitch": "Separa caras de un cuerpo en cuerpos de superficie propios; un sólido se descompone en superficies. Úsalo para retocar caras sueltas de un cuerpo.",
|
||||
"help.surface.untrim": "Quita agujeros de una cara, o restaura su contorno exterior a los límites naturales de la superficie. Úsalo para recuperar la superficie completa tras un recorte.",
|
||||
"help.third_party": "Licencias de terceros",
|
||||
"help.timeline.compute_all": "Reconstruye cada operación de la línea de tiempo desde el inicio. Úsalo para refrescar el modelo",
|
||||
"help.timeline.delete": "Elimina las operaciones seleccionadas de la línea de tiempo; borrar un boceto también elimina",
|
||||
"help.timeline.dependents": "Lists the features that would be deleted with a feature, and those that would fail without it. Use it before deleting or changing a feature.",
|
||||
"help.timeline.dependents": "Lista las operaciones que se borrarían junto con una operación, y las que fallarían sin ella. Úsalo antes de borrar o cambiar una operación.",
|
||||
"help.timeline.play": "Reproduce las operaciones restantes una a una, con una pausa de medio segundo tras cada una",
|
||||
"help.version": "Version {version}",
|
||||
"help.view.apply": "Turns the view to a standard direction such as front, top or iso, or to a saved named view. Use it to look at the model from a fixed angle.",
|
||||
"help.view.delete": "Deletes a saved named view. The model is not changed.",
|
||||
"help.view.fit": "Zooms and pans so the whole model, or the selection, fills the view. Use it when the model has gone out of sight.",
|
||||
"help.view.grid": "Shows or hides the grid in the viewport. Use it as a size and orientation guide while modelling.",
|
||||
"help.view.ground_shadow": "Shows or hides the model's shadow on the ground. Use it to judge height and position more easily.",
|
||||
"help.view.home": "Turns the view back to the home direction and fits the model. Use it to get back to a known view quickly.",
|
||||
"help.view.list": "Lists the named views saved in the design. Use it to find a view you saved earlier.",
|
||||
"help.view.navigate": "Turns, pans or zooms the view by steps, such as a quarter turn left. Use it to move the camera precisely instead of dragging.",
|
||||
"help.view.navigation_bar": "Shows or hides the navigation bar at the bottom of the viewport. Hide it for more room, show it to reach the view tools by mouse.",
|
||||
"help.view.rename": "Gives a saved named view a new name. The view itself stays the same.",
|
||||
"help.version": "Versión {version}",
|
||||
"help.view.apply": "Gira la vista a una dirección estándar como frontal, superior o isométrica, o a una vista con nombre guardada. Úsalo para mirar el modelo desde un ángulo fijo.",
|
||||
"help.view.delete": "Borra una vista con nombre guardada. El modelo no cambia.",
|
||||
"help.view.fit": "Acerca y desplaza para que todo el modelo, o la selección, llene la vista. Úsalo cuando el modelo se ha salido de la vista.",
|
||||
"help.view.grid": "Muestra u oculta la cuadrícula en la vista. Úsala como guía de tamaño y orientación al modelar.",
|
||||
"help.view.ground_shadow": "Muestra u oculta la sombra del modelo en el suelo. Úsalo para juzgar con más facilidad la altura y la posición.",
|
||||
"help.view.home": "Devuelve la vista a la dirección de inicio y encuadra el modelo. Úsalo para volver rápido a una vista conocida.",
|
||||
"help.view.list": "Lista las vistas con nombre guardadas en el diseño. Úsalo para encontrar una vista que guardaste antes.",
|
||||
"help.view.navigate": "Gira, desplaza o acerca la vista por pasos, como un cuarto de vuelta a la izquierda. Úsalo para mover la cámara con precisión en lugar de arrastrar.",
|
||||
"help.view.navigation_bar": "Muestra u oculta la barra de navegación en la parte inferior de la vista. Ocúltala para tener más espacio, muéstrala para llegar a las herramientas de vista con el ratón.",
|
||||
"help.view.rename": "Da un nombre nuevo a una vista con nombre guardada. La vista en sí no cambia.",
|
||||
"help.view.ribbon_tabs_only": "Pliega la cinta hasta su fila de pestañas para que la vista recupere el espacio de los paneles. Haz clic en una pestaña para mostrar sus paneles sobre la vista; vuelve a elegir esta opción para mantener toda la cinta visible.",
|
||||
"help.view.save": "Saves the current camera position as a named view in the design. Use it to come back to the same angle later, for example for screenshots.",
|
||||
"help.view.spin": "Orbits the view around the model continuously until the next click or key. Use it to present a model from all sides.",
|
||||
"help.view.tool": "Latches a camera tool, orbit, pan or zoom, so that dragging with the left mouse button moves the view until you switch it off. Use it on a trackpad or without a middle mouse button.",
|
||||
"help.view.visual_style": "Switches how the model is drawn: shaded with or without edges, wireframe, or with hidden edges. Use wireframe to see inside, shaded for a clean look.",
|
||||
"help.view.save": "Guarda la posición actual de la cámara como una vista con nombre en el diseño. Úsalo para volver al mismo ángulo más tarde, por ejemplo para capturas de pantalla.",
|
||||
"help.view.spin": "Hace orbitar la vista alrededor del modelo de forma continua hasta el siguiente clic o tecla. Úsalo para presentar un modelo por todos sus lados.",
|
||||
"help.view.tool": "Fija una herramienta de cámara, órbita, desplazamiento o zoom, de modo que arrastrar con el botón izquierdo del ratón mueva la vista hasta que la desactives. Úsalo en un trackpad o sin botón central del ratón.",
|
||||
"help.view.visual_style": "Cambia cómo se dibuja el modelo: sombreado con o sin aristas, estructura alámbrica o con aristas ocultas. Usa la estructura alámbrica para ver el interior y el sombreado para un aspecto limpio.",
|
||||
"history.sketch_under_constrained": "Bajo restricción ({count} grados de libertad)",
|
||||
"history.sketch_under_constrained_one": "Bajo restricción ({count} grado de libertad)",
|
||||
"hole_folder.applies_to": "Los cambios se aplican a los {count} agujeros de {folder}; cada uno conserva su posición.",
|
||||
@@ -2628,6 +2635,17 @@
|
||||
"prefs.gesture_pan": "Desplazar",
|
||||
"prefs.gesture_zoom": "Zoom",
|
||||
"prefs.graphics": "Gráficos",
|
||||
"prefs.graphics_api": "API gráfica",
|
||||
"prefs.graphics_api_auto": "Automático",
|
||||
"prefs.graphics_api_help": "Elige la API gráfica usada para abrir SolidCraft. Si el próximo inicio no puede abrir la ventana, se restaurará la selección anterior.",
|
||||
"prefs.graphics_api_override": "Una configuración de arranque está imponiendo la API gráfica. La selección guardada se aplicará al abrir SolidCraft de forma normal.",
|
||||
"prefs.graphics_api_restart_note": "Se aplica después de reiniciar. Antes de cerrar se revisan los diseños sin guardar.",
|
||||
"prefs.graphics_api_restart_unavailable": "Reinicia SolidCraft para aplicar la API gráfica guardada.",
|
||||
"prefs.graphics_api_running": "Actual: {current}. Seleccionada para el próximo inicio: {selected}.",
|
||||
"prefs.graphics_api_save_failed": "No se pudo guardar la selección de API gráfica: {error}",
|
||||
"prefs.graphics_api_start_failed": "No se pudo preparar la API gráfica seleccionada: {error}",
|
||||
"prefs.graphics_api_start_reverted": "El inicio anterior con {requested} no abrió la ventana. SolidCraft ha restaurado {previous}.",
|
||||
"prefs.graphics_api_unavailable": "La selección de API gráfica está disponible en la aplicación de escritorio.",
|
||||
"prefs.graphics_card": "Tarjeta gráfica",
|
||||
"prefs.graphics_card_auto": "Automática",
|
||||
"prefs.graphics_card_missing": "La tarjeta gráfica guardada no está disponible; se usa Automática.",
|
||||
@@ -2877,6 +2895,8 @@
|
||||
"prefs.sketch.center_arc": "El arco por centro sigue al cursor",
|
||||
"prefs.sketch.click_selects": "El clic selecciona",
|
||||
"prefs.sketch.conflict_colour": "Color de conflicto",
|
||||
"prefs.sketch.cursor_coordinates": "Mostrar las coordenadas del cursor en un croquis",
|
||||
"prefs.sketch.cursor_coordinates_note": "Junto al puntero, su X e Y desde el origen del croquis, también sin ninguna herramienta activa. Desactivado: solo mientras una herramienta coloca un punto.",
|
||||
"prefs.sketch.drawing": "Dibujo",
|
||||
"prefs.sketch.ellipse_axes": "Dibujar elipses con sus ejes",
|
||||
"prefs.sketch.ellipse_axes_note": "Los ejes mayor y menor como líneas de construcción, para poder acotar los semiejes y los ejes. Desactivado: solo la elipse, y al pulsar D sobre ella se da su radio menor allí donde se arrastre el valor, dibujado y etiquetado como R, como antes.",
|
||||
@@ -3707,6 +3727,10 @@
|
||||
"render.gpu_path_retry": "Intentar de nuevo",
|
||||
"render.gpu_seed": "Semilla aleatoria",
|
||||
"render.gpu_unavailable": "El trazado GPU aún no está disponible en este dispositivo.",
|
||||
"render.graphics_api_restart_vulkan": "Reiniciar con Vulkan",
|
||||
"render.graphics_api_restart_warning": "Cambiar la API gráfica reinicia SolidCraft y te pide guardar los diseños sin guardar. Si la nueva API no puede abrir la ventana, se restaurará la selección anterior en el próximo inicio.",
|
||||
"render.graphics_api_settings": "Ajustes gráficos",
|
||||
"render.graphics_api_vulkan_required": "El trazado de trayectorias por GPU necesita Vulkan en esta sesión. Reinicia con Vulkan o sigue usando un método de imagen por CPU.",
|
||||
"render.ground_apply": "Ajustar y guardar suelo",
|
||||
"render.ground_gap": "Separación geométrica explícita",
|
||||
"render.ground_linear_rgb": "Reflectancia difusa · RGB lineal",
|
||||
@@ -4708,6 +4732,8 @@
|
||||
"sketch.hint.spline3d": "Spline 3D: pulsa puntos de ajuste en 3D; clic derecho o Esc para terminar",
|
||||
"sketch.hint.trim": "Recortar: pulsa el trozo de curva que quieres quitar, o arrastra sobre los trozos que quieres quitar",
|
||||
"sketch.make_selection": "Convertir la selección a {linetype}",
|
||||
"sketch.move_released": "Movido: se soltaron {count} restricciones que lo unían a lo que queda ({names}).",
|
||||
"sketch.move_released_one": "Movido: se soltó {count} restricción que lo unía a lo que queda ({names}).",
|
||||
"sketch.open_ends": "Abiertos {count}",
|
||||
"sketch.status_conflict": "restricciones en conflicto",
|
||||
"sketch.status_fully_constrained": "totalmente restringido",
|
||||
@@ -4738,6 +4764,10 @@
|
||||
"sketch_text.path_clear": "Separar el texto de su curva",
|
||||
"sketch_text.path_hint": "Curva del boceto que seguirá el texto: haz clic aquí y después en la curva",
|
||||
"sketch_text.use_font_file": "Usar el archivo de fuente {path}",
|
||||
"sketch_text.valign_baseline": "Línea base",
|
||||
"sketch_text.valign_bottom": "Abajo",
|
||||
"sketch_text.valign_middle": "Centro",
|
||||
"sketch_text.valign_top": "Arriba",
|
||||
"solid": "sólido",
|
||||
"status.editing": "Editando {name}",
|
||||
"status.navigation": "Asignación del ratón: {mapping}",
|
||||
@@ -5073,6 +5103,7 @@
|
||||
"ui.agent_chat_setup_title": "Configurar un asistente",
|
||||
"ui.agent_chat_side": "Lado del chat del agente",
|
||||
"ui.agent_chat_signed_in": "sesión iniciada",
|
||||
"ui.agent_chat_snap_none_found": "No se ha encontrado ningún agente de programación. El paquete Snap está confinado, así que no puede ver ni iniciar los agentes de programación instalados en este equipo. Para usarlos, instala SolidCraft desde el paquete AppImage, .deb o .rpm. Un agente que use una API compatible con OpenAI también funciona en el paquete Snap: configúralo con Añadir agente.",
|
||||
"ui.agent_chat_state_auth": "Se requiere iniciar sesión",
|
||||
"ui.agent_chat_state_busy": "Trabajando…",
|
||||
"ui.agent_chat_state_exited": "Agente detenido",
|
||||
@@ -5239,7 +5270,9 @@
|
||||
"ui.browser_bodies_one": "{count} cuerpo",
|
||||
"ui.browser_bodies_other": "{count} cuerpos",
|
||||
"ui.browser_collapse": "Contraer el navegador",
|
||||
"ui.browser_collapse_below": "Contraer debajo",
|
||||
"ui.browser_expand": "Expandir el navegador",
|
||||
"ui.browser_expand_below": "Expandir debajo",
|
||||
"ui.browser_title": "Navegador",
|
||||
"ui.calibrate": "Calibrar",
|
||||
"ui.cancel": "Cancelar",
|
||||
@@ -5448,6 +5481,17 @@
|
||||
"ui.ellipse": "Elipse",
|
||||
"ui.emboss_wrap_note": "Los perfiles de líneas ortogonales tangentes a un cilindro compatible se envuelven automáticamente. Elegir una pared para definir el destino.",
|
||||
"ui.end": "Fin",
|
||||
"ui.end_cap.chamfer": "Chaflán de esquina",
|
||||
"ui.end_cap.direction": "Dirección",
|
||||
"ui.end_cap.faces": "Caras de extremo",
|
||||
"ui.end_cap.inset": "Retranqueo",
|
||||
"ui.end_cap.inset_kind": "Retranqueo por",
|
||||
"ui.end_cap.inset_ratio": "Proporción de retranqueo",
|
||||
"ui.end_cap.inward": "Hacia dentro",
|
||||
"ui.end_cap.length": "Longitud",
|
||||
"ui.end_cap.outward": "Hacia fuera",
|
||||
"ui.end_cap.ratio": "Proporción del espesor",
|
||||
"ui.end_cap_title": "TAPA DE EXTREMO",
|
||||
"ui.end_radius": "Radio final",
|
||||
"ui.end_scale": "Escala final",
|
||||
"ui.ends": "Extremos",
|
||||
@@ -5950,6 +5994,7 @@
|
||||
"ui.project_references_construction_note": "Proyectar, Intersecar, Incluir geometría 3D y las aristas de cara de un boceto nuevo sobre una cara crean geometría de construcción: referencias sobre las que dibujar, excluidas de los perfiles. Siguen vinculadas al modelo.",
|
||||
"ui.properties": "Propiedades",
|
||||
"ui.properties.copy_matrix": "Copiar matriz",
|
||||
"ui.properties.copy_value": "Haz clic para copiar",
|
||||
"ui.properties.first_moments": "Primeros momentos",
|
||||
"ui.properties.inertia": "Momento de inercia",
|
||||
"ui.properties.inertia_note": "Respecto al centro de masas, en ejes mundiales (g·{unit}²)",
|
||||
@@ -5962,6 +6007,7 @@
|
||||
"ui.properties.measuring_failed": "La medición se detuvo antes de terminar.",
|
||||
"ui.properties.principal_axis": "Eje principal {number}",
|
||||
"ui.properties.principal_moments": "Momentos principales",
|
||||
"ui.properties.value_copied": "Valor copiado",
|
||||
"ui.pull_direction": "Dirección de tracción",
|
||||
"ui.quality": "Calidad",
|
||||
"ui.quantity": "Cantidad",
|
||||
@@ -6017,6 +6063,8 @@
|
||||
"ui.ribbon_pin_footer": "Los comandos anclados se muestran en la cinta. Pasa el ratón sobre una fila para anclarla o desanclarla.",
|
||||
"ui.ribbon_workspace": "Espacio de trabajo",
|
||||
"ui.right": "Derecha",
|
||||
"ui.right_click_confirms": "El clic derecho confirma las entradas del diálogo",
|
||||
"ui.right_click_confirms_tip": "Con un diálogo abierto, un clic derecho en la vista pasa a la siguiente entrada vacía y, en la última, ejecuta OK",
|
||||
"ui.save": "Guardar",
|
||||
"ui.save_as": "Guardar como",
|
||||
"ui.save_mesh_no_slicer_open": "No se ha encontrado laminador: elige Personalizado… y elige tu programa de laminado.",
|
||||
|
||||
@@ -885,6 +885,7 @@
|
||||
"Variable Radius": "Muuttuva säde",
|
||||
"Variable radius": "Muuttuva säde",
|
||||
"Velocity": "Nopeus",
|
||||
"Vertical": "Pystysuunta",
|
||||
"Vertices": "Kärkipisteet",
|
||||
"View": "Näkymä",
|
||||
"View navigator": "Näkymänavigaattori",
|
||||
@@ -4680,6 +4681,10 @@
|
||||
"sketch_text.path_clear": "Irrota teksti käyrältään",
|
||||
"sketch_text.path_hint": "Luonnoksen käyrä, jota teksti seuraa: napsauta tätä ja sitten käyrää",
|
||||
"sketch_text.use_font_file": "Käytä fonttitiedostoa {path}",
|
||||
"sketch_text.valign_baseline": "Perusviiva",
|
||||
"sketch_text.valign_bottom": "Ala",
|
||||
"sketch_text.valign_middle": "Keski",
|
||||
"sketch_text.valign_top": "Ylä",
|
||||
"solid": "yhtenäinen",
|
||||
"status.editing": "Muokataan: {name}",
|
||||
"status.navigation": "Hiiren toiminnot: {mapping}",
|
||||
|
||||
+422
-65
File diff suppressed because it is too large
Load Diff
@@ -698,6 +698,7 @@
|
||||
"Value": "Valor",
|
||||
"Variable Radius": "Raio variable",
|
||||
"Velocity": "Velocidade",
|
||||
"Vertical": "Vertical",
|
||||
"Vertices": "Vértices",
|
||||
"View navigator": "Navegador de vistas",
|
||||
"Volume": "Volume",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "EDITAR {title}",
|
||||
"dialog.no_shown_body": "Non hai ningún corpo visible para modificar: mostra un ou escolle Corpo novo",
|
||||
"dialog.pattern_sketch_not_object": "Escolle corpos ou operacións: un bosquexo non é ningunha das dúas cousas. Repite as súas curvas co Patrón ou a Simetría do propio bosquexo, ou extrúeo primeiro.",
|
||||
"dialog.right_click_pick": "Selecciona primeiro {input}",
|
||||
"dialog.select": "↖ Seleccionar",
|
||||
"dialog.selected_count": "↖ {count} seleccionados",
|
||||
"dialog.selection_constraint": "Restrición {id}",
|
||||
@@ -3931,6 +3933,10 @@
|
||||
"sketch_text.path_clear": "Separar o texto da súa curva",
|
||||
"sketch_text.path_hint": "Unha curva do bosquexo que segue o texto: fai clic aquí e despois na curva",
|
||||
"sketch_text.use_font_file": "Usar o ficheiro de tipo de letra {path}",
|
||||
"sketch_text.valign_baseline": "Liña base",
|
||||
"sketch_text.valign_bottom": "Abaixo",
|
||||
"sketch_text.valign_middle": "Medio",
|
||||
"sketch_text.valign_top": "Arriba",
|
||||
"solid": "sólido",
|
||||
"status.editing": "Editando {name}",
|
||||
"status.navigation": "Asignación do rato: {mapping}",
|
||||
@@ -5013,6 +5019,8 @@
|
||||
"ui.ribbon_pin_footer": "As ordes fixadas móstranse na cinta. Pasa o cursor sobre unha fila para fixala ou soltala.",
|
||||
"ui.ribbon_workspace": "Espazo de traballo",
|
||||
"ui.right": "Dereita",
|
||||
"ui.right_click_confirms": "O clic dereito confirma as entradas do diálogo",
|
||||
"ui.right_click_confirms_tip": "Cun diálogo aberto, un clic dereito na vista pasa á seguinte entrada baleira e, na última, executa OK",
|
||||
"ui.save": "Gardar",
|
||||
"ui.save_as": "Gardar como",
|
||||
"ui.save_mesh_no_slicer_open": "Non se atopou ningún laminador: escolle Personalizado… e selecciona o programa do teu laminador",
|
||||
|
||||
@@ -247,6 +247,7 @@
|
||||
"Drag to move the hole; click to remove it": "יש לגרור כדי להזיז את החור; לחיצה מסירה אותו",
|
||||
"Drag to move the rest across the model. It snaps to sketch points on the face.": "יש לגרור כדי להזיז את המשען על פני המודל. הוא נצמד לנקודות סקיצה על הפאה.",
|
||||
"Drag to move the snap fit across the model. It snaps to sketch points on the face.": "יש לגרור כדי להזיז את חיבור ההצמדה על פני המודל. הוא נצמד לנקודות סקיצה על הפאה.",
|
||||
"Drag to place it on another face.": "יש לגרור כדי להציב אותו על פאה אחרת.",
|
||||
"Drag to point the catch in another direction.": "יש לגרור כדי לכוון את התפס לכיוון אחר.",
|
||||
"Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.": "יש לגרור כדי לסובב את המשען בצעדים של 5°. יש להחזיק Alt או Ctrl לסיבוב חופשי.",
|
||||
"Drive Joint": "הנעת מפרק",
|
||||
@@ -513,6 +514,7 @@
|
||||
"Offset Y": "היסט Y",
|
||||
"Offset Z": "היסט Z",
|
||||
"On your computer": "במחשב שלך",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "מקטע נוסף של המקצוע הנבחר, שלכל אחד זווית, גובה וכיפופים משלו",
|
||||
"Opacity": "אטימות",
|
||||
"Open GitHub": "פתיחת GitHub",
|
||||
"Open GitHub draft": "פתיחת טיוטה ב־GitHub",
|
||||
@@ -634,6 +636,7 @@
|
||||
"Remove the track": "הסרת הרצועה",
|
||||
"Remove this bend": "הסרת הכיפוף הזה",
|
||||
"Remove this point": "הסרת נקודה זו",
|
||||
"Remove this segment": "הסרת המקטע הזה",
|
||||
"Rename Feature": "שינוי שם פיצ'ר",
|
||||
"Rename Folder": "שינוי שם תיקייה",
|
||||
"Render Stage": "שלב הרינדור",
|
||||
@@ -723,6 +726,7 @@
|
||||
"Section position": "מיקום החתך",
|
||||
"Sections": "חתכים",
|
||||
"Sections (one sketch each)": "חתכים (סקיצה אחת לכל אחד)",
|
||||
"Segments": "מקטעים",
|
||||
"Select Features": "בחירת פיצ'רים",
|
||||
"Select Other": "בחירת אחר",
|
||||
"Select Other: hold the left button still on the model (or right-click › Select Other…) to list everything under the cursor; click again on the same spot to select the next thing there. Double-click the middle button to go Home (Preferences › Navigation).": "בחירת אחר: החזקת הכפתור השמאלי ללא תזוזה על המודל (או לחיצה ימנית › בחירת אחר…) מציגה את כל מה שמתחת לסמן; לחיצה נוספת באותה נקודה בוחרת את הפריט הבא שם. לחיצה כפולה על הכפתור האמצעי חוזרת לתצוגת הבית (העדפות › ניווט).",
|
||||
@@ -772,6 +776,7 @@
|
||||
"Spacing must be a non-zero number": "המרווח חייב להיות מספר שונה מאפס",
|
||||
"Specialise": "התמחות",
|
||||
"Speed": "מהירות",
|
||||
"Split Edge": "פיצול המקצוע",
|
||||
"Splitting tool": "כלי פיצול",
|
||||
"Square": "ריבוע",
|
||||
"Stainless Steel": "פלדת אל-חלד",
|
||||
@@ -885,6 +890,7 @@
|
||||
"Variable Radius": "רדיוס משתנה",
|
||||
"Variable radius": "רדיוס משתנה",
|
||||
"Velocity": "מהירות",
|
||||
"Vertical": "אנכי",
|
||||
"Vertices": "קודקודים",
|
||||
"View": "תצוגה",
|
||||
"View navigator": "ניווט תצוגה",
|
||||
@@ -938,6 +944,13 @@
|
||||
"ai.prefs.connect_apps_note": "כיבוי מסיר שוב את הרשומות.\n\nבהפעלת SolidCraft הוא מתווסף כשרת MCP ליישומי הבינה המלאכותית שנמצאו במחשב זה (OpenCode, Claude Desktop, Claude Code, Cursor, Codex, Gemini CLI, Copilot CLI, Windsurf, Zed, VS Code), כך שסוכן יכול להשתמש בו בלי שום הגדרה. רק הרשומה solidcraft נוספת או שהנתיב שלה מתעדכן; רשומה ששינית נשארת כפי שהיא, ולפני כן נשמר גיבוי של הקובץ. כבוי: הרשומות שנוספו מוסרות. הפקודה עזרה > חיבור עוזרי בינה מלאכותית… עושה זאת ידנית.",
|
||||
"ai.prefs.connect_at_start": "לחבר את הסוכן האחרון בהפעלה",
|
||||
"ai.prefs.connect_at_start_note": "מפעיל ברקע את הסוכן שאליו התחברת לאחרונה (או את סוכן ברירת המחדל) בכל הפעלה של SolidCraft, כך שהוא מוכן לשיחה. לא כש-SolidCraft מופעל עם --control. אם ההתחברות נכשלת, העוזר מציג „ההתחברות נכשלה” ולחצן „ניסיון חוזר”.",
|
||||
"ai.prefs.control_failed": "לא ניתן היה להפעיל את ערוץ הבקרה: {error}",
|
||||
"ai.prefs.control_from_launch": "הפעלה זו התחילה עם --control בפורט {port}. שינויים כאן ייכנסו לתוקף בפעם הבאה ש-SolidCraft יופעל ללא --control.",
|
||||
"ai.prefs.control_listening": "מאזין ב-127.0.0.1:{port}",
|
||||
"ai.prefs.control_not_listening": "לא מאזין",
|
||||
"ai.prefs.control_port": "פורט",
|
||||
"ai.prefs.control_port_note": "הפורט שאליו סוכני AI מתחברים במחשב זה (127.0.0.1). ברירת המחדל היא 27878: אם הוא תפוס, נלקח הפורט הפנוי הבא. כל פורט אחר משמש בדיוק כפי שהוא. כוונו את לקוח ה-MCP לאותו פורט, למשל solidcraft-cli mcp --connect 127.0.0.1:7878.",
|
||||
"ai.prefs.control_port_taken": "פורט {port} בשימוש של תוכנה אחרת (או חלון SolidCraft אחר). בחרו פורט אחר.",
|
||||
"ai.prefs.follow_camera": "לעקוב אחר המצלמה",
|
||||
"ai.prefs.follow_camera_off": "מעקב המצלמה האוטומטי כבוי.",
|
||||
"ai.prefs.follow_camera_on": "המצלמה פונה אל הסקיצות שהסוכן יוצר.",
|
||||
@@ -998,6 +1011,13 @@
|
||||
"browser.sketches_to_parts_not_on_face": "לא על פאה של חלק",
|
||||
"browser.sketches_to_parts_part_missing": "החלק שלהם כבר לא קיים",
|
||||
"browser.sketches_to_parts_result": "{moved} שרטוטים הועברו לחלק שעליו הם נמצאים; {stayed} נשארו: {why}",
|
||||
"browser.straighten_angle": "כיוון הקצה",
|
||||
"browser.straighten_choose": "בחר מה יהיה הקצה, אופקי, אנכי או בזווית, ואז לחץ על יישור.",
|
||||
"browser.straighten_click_a": "לחץ על התמונה בקצה אחד של קצה שאמור להיות ישר, או הקלד את הקואורדינטות שלו.",
|
||||
"browser.straighten_click_b": "לחץ על הקצה השני, או הקלד את הקואורדינטות שלו.",
|
||||
"browser.straighten_horizontal": "אופקי",
|
||||
"browser.straighten_title": "יישור: {name}",
|
||||
"browser.straighten_vertical": "אנכי",
|
||||
"browser.units": "יחידות: {units}",
|
||||
"cam.flat": "פאה שטוחה",
|
||||
"cam.follower": "עוקב",
|
||||
@@ -1027,6 +1047,8 @@
|
||||
"cmd.appearance_pick_up": "בחירת מראה",
|
||||
"cmd.appearance_replace": "החלפת מראה",
|
||||
"cmd.assembly_bom": "רשימת חלקים",
|
||||
"cmd.assembly_constraint_create": "אילוץ",
|
||||
"cmd.assembly_constraint_edit": "עריכת אילוץ",
|
||||
"cmd.assembly_mass_properties": "תכונות מסה",
|
||||
"cmd.body.print_face": "פאת הדפסה",
|
||||
"cmd.body_rename": "שינוי שם גוף",
|
||||
@@ -1045,6 +1067,7 @@
|
||||
"cmd.canvas_delete": "מחיקת קנבס",
|
||||
"cmd.canvas_edit": "עריכת קנבס",
|
||||
"cmd.canvas_insert": "קנבס",
|
||||
"cmd.canvas_straighten": "יישור קנבס",
|
||||
"cmd.canvas_to_sketch": "קנבס לסקיצה",
|
||||
"cmd.component_activate": "הפעלת רכיב",
|
||||
"cmd.component_break_link": "ניתוק קישור",
|
||||
@@ -1086,7 +1109,10 @@
|
||||
"cmd.config_rule": "כלל תצורה",
|
||||
"cmd.config_rules": "כללי תצורה",
|
||||
"cmd.config_table": "הצגת טבלת תצורות",
|
||||
"cmd.construct.axis": "ציר",
|
||||
"cmd.construct.plane": "מישור",
|
||||
"cmd.construct.plane.axis_point": "מישור דרך ציר ונקודה",
|
||||
"cmd.construct.point": "נקודה",
|
||||
"cmd.construct_axis_edge": "ציר דרך מקצוע",
|
||||
"cmd.construct_axis_normal_to_face": "ציר ניצב לפאה",
|
||||
"cmd.construct_axis_through_cylinder": "ציר דרך גליל/חרוט/טורוס",
|
||||
@@ -1149,6 +1175,7 @@
|
||||
"cmd.file_save_mesh": "שמירה כרשת משולשים",
|
||||
"cmd.file_send_to_slicer": "שליחה לסלייסר",
|
||||
"cmd.file_slicers": "תוכנות סלייסר מותקנות",
|
||||
"cmd.frame_end_cap": "מכסה קצה",
|
||||
"cmd.frame_member": "איבר מסגרת",
|
||||
"cmd.frame_profile_insert": "הוספת פרופיל",
|
||||
"cmd.frame_profile_list": "ספריית פרופילים",
|
||||
@@ -1169,6 +1196,7 @@
|
||||
"cmd.inspect_isocurve": "ניתוח איזו־עקומות",
|
||||
"cmd.inspect_minimum_radius": "ניתוח רדיוס מינימלי",
|
||||
"cmd.inspect_parameter_sweep": "סריקת פרמטרים",
|
||||
"cmd.inspect_parameter_variants": "השוואת חלופות פרמטרים",
|
||||
"cmd.inspect_silhouette": "צללית",
|
||||
"cmd.inspect_zebra": "ניתוח זברה",
|
||||
"cmd.joint_as_built": "מפרק במצב הקיים",
|
||||
@@ -1222,6 +1250,10 @@
|
||||
"cmd.motion_trace": "עקבת תנועה",
|
||||
"cmd.motion_trace_edit": "עריכת עקבת תנועה",
|
||||
"cmd.motion_trace_keep": "שמירת עקבת תנועה",
|
||||
"cmd.note_add": "הוספת הערה",
|
||||
"cmd.note_delete": "מחיקת הערה",
|
||||
"cmd.note_list": "הצגת הערות",
|
||||
"cmd.note_update": "עריכת הערה",
|
||||
"cmd.occurrence_align": "יישור מופע",
|
||||
"cmd.occurrence_copy": "הדבקה (מופע)",
|
||||
"cmd.occurrence_drag": "גרירת מופע",
|
||||
@@ -1347,6 +1379,7 @@
|
||||
"cmd.render_start": "יצירת תמונת הדמיה",
|
||||
"cmd.render_status": "התקדמות ההדמיה",
|
||||
"cmd.select_clear": "ניקוי הבחירה",
|
||||
"cmd.selection_get": "קבלת הבחירה",
|
||||
"cmd.settings_profile_apply": "החלת פרופיל הגדרות",
|
||||
"cmd.settings_profile_delete": "מחיקת פרופיל הגדרות",
|
||||
"cmd.settings_profile_export": "ייצוא פרופיל הגדרות",
|
||||
@@ -1510,6 +1543,7 @@
|
||||
"cmd.timeline_suppress": "השבתת פיצ'ר",
|
||||
"cmd.ui.assistant": "הצגה או הסתרה של העוזר",
|
||||
"cmd.ui.palette": "חיפוש פקודות",
|
||||
"cmd.ui.toggle_visibility": "הצגה/הסתרה של הבחירה",
|
||||
"cmd.view.navigator": "ניווט תצוגה מותאם אישית",
|
||||
"cmd.view.render_browser": "דפדפן רינדור",
|
||||
"cmd.view.render_dock": "הזז את עגינת הרינדור",
|
||||
@@ -1567,6 +1601,7 @@
|
||||
"color.step_down": "צעד למטה",
|
||||
"color.step_up": "צעד למעלה",
|
||||
"color.value": "ערך, הבהירות (אחוזים)",
|
||||
"component.error.ambiguous_name": "לכמה רכיבים יש השם `{name}`. יש להשתמש במזהה רכיב מספרי: {ids}.",
|
||||
"config.column_filter_empty": "אין עמודות תואמות",
|
||||
"config.rule_parameter_columns": "מוצגים כאן רק פרמטרים שיש להם עמודה בטבלה. הוסיפו עמודה דרך \"הוספת עמודה\" (+) כדי להשתמש בפרמטר כאן.",
|
||||
"config.rule_suppression_columns": "מוצגים כאן רק פיצ'רים שיש להם עמודת \"השבתה\" בטבלה. הוסיפו עמודה דרך \"הוספת עמודה\" (+) כדי לשלוט בפיצ'ר כאן.",
|
||||
@@ -1607,6 +1642,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}: ההפניה `{reference}` כבר אינה קיימת כפי שנבחרה; יש לבחור אותה מחדש",
|
||||
"dialog.bodies_count": "{count} גופים",
|
||||
"dialog.clearance_invalid": "המרווח חייב להיות אורך של 0 ומעלה",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "חישוב",
|
||||
"dialog.compute_again": "חישוב מחדש",
|
||||
"dialog.computing": "מחשב… {seconds} שנ'",
|
||||
@@ -1619,10 +1655,12 @@
|
||||
"dialog.dimension_step_expression": "רק מספר משתנה בצעדים; ביטוי נשאר כפי שנכתב",
|
||||
"dialog.dimension_step_up": "הוספה של {step}",
|
||||
"dialog.edit_title": "עריכת {title}",
|
||||
"dialog.hole_held_off_its_line": "קצה הייחוס מחזיק את החור על קו שיוצא מהפאה לפני הנקודה שנבחרה. יש לבחור במקום שבו הקו עובר על הפאה, או להסיר את הקצה כדי להזיז את החור בחופשיות.",
|
||||
"dialog.no_shown_body": "אין גוף מוצג לשינוי: הציגו גוף, או בחרו „גוף חדש”",
|
||||
"dialog.pattern_sketch_not_object": "בחרו גופים או פיצ'רים: סקיצה אינה אף אחד מהם. חזרו על העקומות שלה בעזרת המערך או השיקוף של הסקיצה עצמה, או בצעו לה שליפה קודם.",
|
||||
"dialog.primitive_point_tip": "נקודה שממלאת את X, Y ו-Z: יש ללחוץ כאן ואז על קודקוד, מקצוע או פאה של המודל, על נקודה של סקיצה, או על הראשית.",
|
||||
"dialog.reference_edge_tip": "מקצוע ישר של הפאה שנבחרה שממנו נמדד המרחק שלמטה: יש ללחוץ כאן ואז על המקצוע.",
|
||||
"dialog.right_click_pick": "יש לבחור תחילה {input}",
|
||||
"dialog.select": "↖ בחירה",
|
||||
"dialog.selected_count": "↖ {count} נבחרו",
|
||||
"dialog.selection_constraint": "אילוץ {id}",
|
||||
@@ -1636,9 +1674,12 @@
|
||||
"document.changed_on_disk": "{name} השתנה בדיסק",
|
||||
"document.changed_on_disk_detail": "{name} שונה על ידי תוכנה או מחשב אחרים מאז שנפתח או נשמר לאחרונה. דריסה מחליפה את השינויים האלה בשינויים שלך; שמירת עותק שומרת את שניהם.",
|
||||
"document.copy_name": "עותק של {name}",
|
||||
"document.discard_row": "ביטול שינויים",
|
||||
"document.finish_save_prompt": "יש לסיים לענות על חלון השמירה לפני פתיחת תכן אחר.",
|
||||
"document.newer_file": "נשמר בגרסה חדשה יותר של SolidCraft (פורמט {format}, גרסה זו קוראת עד {reads}). אם משהו חסר, יש לעדכן.",
|
||||
"document.newer_file_change": "נשמר בגרסה חדשה יותר של SolidCraft (פורמט {format} עם `{change}`, שגרסה זו אינה מכירה). אם משהו חסר, יש לעדכן.",
|
||||
"document.newer_file_not_read": "לא נקרא: {what}. השמירה משאירה אותו בקובץ.",
|
||||
"document.not_saved_yet": "עדיין לא נשמר",
|
||||
"document.open_anyway": "פתיחה בכל זאת",
|
||||
"document.open_elsewhere": "{name} כבר פתוח",
|
||||
"document.open_elsewhere_detail": "{name} פתוח ב־SolidCraft {app} אצל {who}, נפתח {when}. אם שניכם תשמרו, אחד מכם יאבד עבודה. יש לפתוח אותו לקריאה בלבד כדי לעיין בו בלי לדרוס אותו.",
|
||||
@@ -1648,6 +1689,9 @@
|
||||
"document.read_only_save": "התכן הזה נפתח לקריאה בלבד: יש לשמור אותו כקובץ חדש",
|
||||
"document.save_changes": "לשמור את השינויים ב־{name}?",
|
||||
"document.save_copy": "שמירת עותק…",
|
||||
"document.save_many": "לשמור שינויים ב־{n} תכנים?",
|
||||
"document.save_row": "שמירה",
|
||||
"document.save_selected": "שמירת הנבחרים",
|
||||
"document.tab_unsaved_changes": "שינויים שלא נשמרו",
|
||||
"document.unsaved_changes": "ב־{name} יש שינויים שלא נשמרו. ללא שמירה, הם יאבדו.",
|
||||
"drive.rigid": "{joint} הוא מפרק קשיח: הוא מחזיק את החלקים שלו במקומם, ולכן אין מה להניע. כדי שהחלקים יזוזו, שנו את הסוג שלו ב״עריכת מפרק״: Revolute לסיבוב, Slider להחלקה, Cylindrical לשניהם.",
|
||||
@@ -1667,6 +1711,8 @@
|
||||
"dxf.tolerance": "סבולת עקומה",
|
||||
"dxf.tolerance_help": "גופים גלויים בלבד. עקומות מורכבות מקטעים ישרים. סבולת קטנה יותר יוצרת עקומות עדינות יותר ודורשת יותר זמן וזיכרון.",
|
||||
"each rail's curves must be in one sketch": "עקומות כל מסילה חייבות להיות בסקיצה אחת",
|
||||
"error.end_cap_faces": "בחר לפחות פאת קצה פתוחה אחת של איבר מסגרת",
|
||||
"error.end_cap_unresolved": "קצה {ends} של מכסה זה כבר אינו במודל. בחר שוב את פאות הקצה",
|
||||
"feature computation ended without a result": "חישוב הפיצ'ר הסתיים ללא תוצאה",
|
||||
"file.open.drawing_filter": "תכנים, קובצי CAD, רשתות משולשים ושרטוטים",
|
||||
"file.open.portal_fallback.no_portal_service": "בורר הקבצים שנפתח אינו של שולחן העבודה: שירות בחירת הקבצים של שולחן העבודה אינו זמין.",
|
||||
@@ -1678,6 +1724,7 @@
|
||||
"file_load.inserting": "הוספת גאומטריה",
|
||||
"file_load.link_item": "{name} ({done} מתוך {total})",
|
||||
"file_load.opened": "{name} נפתח",
|
||||
"file_load.opened_behind": "{name} נפתח בכרטיסייה חדשה",
|
||||
"file_load.opened_in_tab": "{name} נפתח בלשונית חדשה",
|
||||
"file_load.opening": "פותח את התכן",
|
||||
"file_load.preparing_thumbnail": "מכין את התמונה הממוזערת...",
|
||||
@@ -1725,11 +1772,13 @@
|
||||
"help.config.table": "הצגת טבלת התצורות: שורה לכל גרסה, עמודה לכל פרמטר או פיצ'ר, ואם התכן עדיין תואם לשורה הפעילה. מתאים לסקירת הגרסאות של התכן.",
|
||||
"help.connect_note": "יש להפעיל מחדש כל עוזר כדי לטעון את שרת SolidCraft. לכל קובץ נשמר גיבוי בסיומת .bak לפני השינוי.",
|
||||
"help.connect_title": "חיבור עוזרי בינה מלאכותית",
|
||||
"help.construct.axis": "יוצר ציר עזר בשיטה שמתאימה למה שבחרת: לאורך קצה או קו, דרך חור או פאה עגולה, במפגש של שני מישורים, דרך שתי נקודות, או ניצב לפאה דרך נקודה. השתמש בו כשאתה יודע את ההפניות ולא את השיטה.",
|
||||
"help.construct.axis.edge": "יצירת ציר עזר לאורך מקצוע ישר או קו של סקיצה. משמש כציר לסיבוב, לשכפול מעגלי או למפרק.",
|
||||
"help.construct.axis.normal_to_face": "יצירת ציר עזר דרך נקודה, ניצב לפאה. משמש כציר שיוצא ישר מתוך משטח.",
|
||||
"help.construct.axis.through_cylinder": "יצירת ציר עזר דרך מרכז פאה של גליל, חרוט או טורוס, או מקצוע עגול. מתאים לסיבוב או לשכפול פיצ'רים סביב חלק עגול.",
|
||||
"help.construct.axis.two_planes": "יצירת ציר עזר במפגש של שני מישורים או שתי פאות שטוחות. מתאים כשהציר הדרוש הוא הקו שבין שתי פאות.",
|
||||
"help.construct.axis.two_points": "יצירת ציר עזר דרך שתי נקודות, קודקודים או נקודות סקיצה. מתאים לציר שעובר בין שני מיקומים ידועים.",
|
||||
"help.construct.plane": "יוצר מישור עזר בשיטה שמתאימה למה שבחרת: בהיסט ממישור, דרך נקודה, בין שני מישורים, דרך קווים או נקודות, משיק לפאה מעוקלת, או ניצב למסלול. השתמש בו כשאתה יודע את ההפניות ולא את השיטה.",
|
||||
"help.construct.plane.along_path": "יצירת מישור עזר ניצב למקצוע או לעקומה, במיקום לאורכם. משמש לשרטוט פרופיל לסחיפה או חתך של מסלול.",
|
||||
"help.construct.plane.at_angle": "יצירת מישור עזר מוטה בזווית ממישור או מפאה, סביב ציר או מקצוע. מתאים לסקיצות משופעות, כמו תמוכה בזווית.",
|
||||
"help.construct.plane.axis_point": "יוצר מישור עזר המכיל ציר ונקודה שאינה עליו. יש לבחור ציר ראשי או ציר עזר, קצה ישר או קו סקיצה, ואז קודקוד, נקודת סקיצה או נקודת עזר. נקודה על הציר אינה מגדירה מישור יחיד.",
|
||||
@@ -1739,6 +1788,7 @@
|
||||
"help.construct.plane.tangent": "יצירת מישור עזר שמשיק לגליל, לחרוט, לכדור או לטורוס בנקודה. מתאים לשרטוט על צידו של חלק עגול.",
|
||||
"help.construct.plane.three_points": "יצירת מישור עזר דרך שלוש נקודות. מתאים למישור שנקבע לפי מיקומים על המודל, כמו שלוש פינות.",
|
||||
"help.construct.plane.two_edges": "יצירת מישור עזר דרך שני מקצועות ישרים או קווים הנמצאים באותו מישור. מתאים למישור שחותך חלק, למשל דרך שני מקצועות מנוגדים.",
|
||||
"help.construct.point": "יוצר נקודת עזר בשיטה שמתאימה למה שבחרת: בקודקוד, במרכז של מעגל או כדור, לאורך קצה, במפגש של שני קווים או שלושה מישורים, או במקום שבו קו חוצה מישור. השתמש בו כשאתה יודע את ההפניות ולא את השיטה.",
|
||||
"help.construct.point.along_path": "יצירת נקודת עזר במיקום לאורך מקצוע או עקומה. משמשת כנקודת ייחוס בחלק כלשהו של המסלול.",
|
||||
"help.construct.point.center": "יצירת נקודת עזר במרכז של מקצוע עגול, מעגל או קשת בסקיצה, כדור או טורוס. משמשת כנקודת ייחוס לחורים, לצירים ולמפרקים.",
|
||||
"help.construct.point.edge_plane": "יצירת נקודת עזר במקום שבו מקצוע או קו חוצים מישור או פאה שטוחה. משמשת לסימון המקום שבו מסלול חוצה מישור.",
|
||||
@@ -1764,6 +1814,7 @@
|
||||
"help.file.send_to_slicer": "שמירת הגופים שנבחרו כקובץ 3MF ופתיחתו בסלייסר שנבחר. כך עוברים מהמודל להדפסה בצעד אחד.",
|
||||
"help.font_details": "הממשק משתמש בגופנים המובנים של egui (Ubuntu Light ו־Hack, תחת Ubuntu Font Licence ותחת רישיון MIT/Bitstream Vera; Noto Emoji וגופן סמלי האימוג'י, תחת OFL ו־MIT). טקסט בסקיצות משתמש ב־Liberation Sans (SIL OFL 1.1). חבילת הגופנים האופציונלית של Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), אינה כלולה בגרסאות של SolidCraft.",
|
||||
"help.fonts": "גופנים",
|
||||
"help.frame.end_cap": "סוגר קצוות פתוחים של איברי מסגרת בלוחות בצורת קו המתאר של הפרופיל. השתמש בו כדי לאטום צינורות, זוויתנים וקורות, מעל הקצה או שקוע בו.",
|
||||
"help.frame.member": "הצבת פרופיל, כמו צינור או פרופיל אלומיניום שחול, לאורך קווי סקיצה של מסגרת, איבר אחד לכל קו. מתאים לבניית מסגרות, מדפים ומבנים מולחמים.",
|
||||
"help.inspect.accessibility": "צביעת הפאות שכלי יכול להגיע אליהן מכיוון אחד, ואלה שאינו יכול. מתאים לבדיקת חלק לעיבוד שבבי או להזרקה מאותו צד.",
|
||||
"help.inspect.center_of_mass": "הצגת מרכז המסה של גופים, כל אחד לחוד וכולם יחד, בצפיפות אחידה. מתאים לבדיקת איזון ולזיהוי המקום שבו חלק יתהפך.",
|
||||
@@ -2240,6 +2291,9 @@
|
||||
"measure.at": "מיקום",
|
||||
"measure.item": "פריט {number}",
|
||||
"measure.line_to_centre": "מהקו למרכז",
|
||||
"measure.perimeter": "היקף",
|
||||
"measure.perimeter_inner": "היקף פנימי",
|
||||
"measure.perimeter_outer": "היקף חיצוני",
|
||||
"measure.quick_copied": "המדידה הועתקה",
|
||||
"measure.quick_copy": "לחיצה מעתיקה את המדידה",
|
||||
"measure.quick_edges": "{count} מקצועות",
|
||||
@@ -2281,6 +2335,8 @@
|
||||
"nav.hfss.help": "Alt וגרירה שמאלית מזיזים, Shift+Alt וגרירה שמאלית מבצעים זום, Ctrl וגרירה שמאלית משטח ריק מסובבים",
|
||||
"nav.inventor.help": "גרירה אמצעית מזיזה, Shift וגרירה אמצעית מסובבים, Ctrl וגרירה אמצעית מבצעים זום, גרירה ימנית מסובבת",
|
||||
"nav.maya.help": "Alt וגרירה שמאלית מסובבים, Alt וגרירה אמצעית מזיזים, Alt וגרירה ימנית מבצעים זום; גם גרירה אמצעית מזיזה",
|
||||
"nav.maya_horizontal_zoom.help": "Alt וגרירה עם לחצן העכבר הימני: ימינה לקירוב, שמאלה להרחקה. כבו כדי לחזור לזום בגרירה אנכית.",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: זום בגרירה אופקית",
|
||||
"nav.nx.help": "גרירה בלחצן האמצעי מסובבת, Shift+האמצעי מזיז את התצוגה (ב-NX: אמצעי + ימני), Ctrl+האמצעי מקרב ומרחיק (ב-NX: אמצעי + שמאלי); גרירה בלחצן הימני לא מזיזה את המצלמה",
|
||||
"nav.openscad.help": "גרירה שמאלית על שטח ריק מסובבת, Shift וגרירה שמאלית בוחרים במלבן, גרירת גאומטריית סקיצה עורכת אותה; גרירה ימנית או אמצעית מזיזה, Shift וגרירה ימנית או אמצעית מבצעים זום",
|
||||
"nav.orbit_cursor_wrap.help": "גרירת סיבוב שמגיעה לקצה המבט מעבירה את הסמן לקצה הנגדי וממשיכה לסובב. כבוי: הגרירה נעצרת בקצה המסך. ללא השפעה ב־Wayland או בדפדפן.",
|
||||
@@ -2411,6 +2467,16 @@
|
||||
"not a move": "זו אינה הזזה",
|
||||
"not a number": "לא מספר",
|
||||
"open a sketch first": "יש לפתוח סקיצה תחילה",
|
||||
"operations.cancel": "ביטול {name}",
|
||||
"operations.cancelled": "{name} בוטל",
|
||||
"operations.cancelling": "מבטל…",
|
||||
"operations.cannot_cancel": "לא ניתן לבטל את {name}",
|
||||
"operations.feature": "פיצ'ר",
|
||||
"operations.feature_edit": "עריכת פיצ'ר",
|
||||
"operations.meshing": "טוען חלקים",
|
||||
"operations.queued": "ממתין",
|
||||
"operations.stopped": "בוטל",
|
||||
"operations.waiting": "מוכן",
|
||||
"parameters.apply_live": "להחיל כל שינוי ביציאה מהשדה שלו",
|
||||
"parameters.apply_live_tip": "כבוי: השינויים ממתינים עד ל„החל” או „אישור”, ואז התכן נבנה מחדש פעם אחת עבור כולם. „ביטול” או Escape משליכים אותם.",
|
||||
"parameters.held": "{count} שינויים ממתינים ל„החל”",
|
||||
@@ -2499,6 +2565,7 @@
|
||||
"prefs.appearance.viewport_colours": "צבעי תצוגת תלת־ממד",
|
||||
"prefs.appearance.viewport_logo": "חלון התצוגה והלוגו",
|
||||
"prefs.applies_on_restart": "ייכנס לתוקף בהפעלה מחדש",
|
||||
"prefs.assemblies": "מכלולים",
|
||||
"prefs.assistant": "עוזר",
|
||||
"prefs.assistant_connecting": "חיבור",
|
||||
"prefs.assistant_follow_help": "פעולות Look At בסקיצות מזיזות את התצוגה עם המצביע.",
|
||||
@@ -2551,6 +2618,10 @@
|
||||
"prefs.choose_font": "בחירת קובץ גופן…",
|
||||
"prefs.click": "לחיצה",
|
||||
"prefs.command_dialog_values": "תיבות דו-שיח של פקודות",
|
||||
"prefs.constraint_glyph_size": "גודל סמלי האילוצים",
|
||||
"prefs.constraint_glyph_size_note": "הגודל שבו מצוירים סמלי האילוצים, עם האותיות או הסמלונים שלהם, בשרטוט. 100% הוא הגודל הרגיל; הסמלים שומרים על גודל המסך הזה בכל זום.",
|
||||
"prefs.construct_menu_groups": "קיבוץ כלי הבנייה לפי סוג ישות",
|
||||
"prefs.construct_menu_groups_help": "הצגת כותרות מישורים, צירים ונקודות. כיבוי שומר על סדר התפריט המקורי.",
|
||||
"prefs.contact_shading": "הצללת מגע רכה",
|
||||
"prefs.contact_shading_note": "הצללה רכה במקומות שבהם חלקים מתקרבים.",
|
||||
"prefs.context_menu": "תפריט הקשר",
|
||||
@@ -2586,6 +2657,8 @@
|
||||
"prefs.design_tools.rows": "שורות",
|
||||
"prefs.devices": "עכבר תלת־ממדי",
|
||||
"prefs.dialog_buttons": "לחצני תיבות דו־שיח",
|
||||
"prefs.dialog_first_letter_buttons": "כפתורי תיבות דו-שיח נענים לאות הראשונה שלהם",
|
||||
"prefs.dialog_first_letter_buttons_help": "כשתיבת דו-שיח פתוחה, הקלדת האות הראשונה של שם הכפתור לוחצת עליו: האות «ב» לוחצת על «ביטול», למשל. אות שמתאימה לשני כפתורים אינה עושה דבר, ושדה טקסט שבו נמצא הסמן שומר את ההקלדה. כבוי: הקלדה אינה משפיעה על הכפתורים, כמו קודם.",
|
||||
"prefs.dialogs": "תיבות דו־שיח",
|
||||
"prefs.dialogs_edge": "בקצה התצוגה",
|
||||
"prefs.dialogs_left_column": "בעמודה השמאלית",
|
||||
@@ -2599,12 +2672,23 @@
|
||||
"prefs.dimension_values_window": "בחלון",
|
||||
"prefs.display": "תצוגה",
|
||||
"prefs.edges": "מקצועות והצללה",
|
||||
"prefs.export": "ייצוא",
|
||||
"prefs.export_name": "שם קובץ הייצוא",
|
||||
"prefs.export_name.body": "שם הגוף המיוצא (הראשון כשיש כמה)",
|
||||
"prefs.export_name.design": "שם התכן",
|
||||
"prefs.export_name_hint": "לדוגמה {design}-{body}",
|
||||
"prefs.export_name_sample": "ייצוא התכן הזה מציע: {name}",
|
||||
"prefs.export_name_tip": "שם הקובץ שמציעים קובץ › ייצוא ושמירה כרשת משולשים. מצייני המיקום האלה מוחלפים:\n{placeholders}\nמאפיין תכן שלא הוגדר מושמט. השאירו את השדה ריק כדי להציע את שם התכן, או את שם הגוף לרשת.",
|
||||
"prefs.extend": "הרחבה",
|
||||
"prefs.extra_navigation": "Ctrl עם גרירה שמאלית במקום ריק מסובב את המבט; החזקת Space מזיזה אותו.",
|
||||
"prefs.extrude_arrow_face_stops": "חץ השליפה נעצר בפאות",
|
||||
"prefs.extrude_arrow_face_stops_note": "גרירת חץ המרחק של השליפה נעצרת בפאות שטוחות המקבילות לפרופיל, כמו הצד הרחוק של גוש שנחתך, ומדגישה את קו המתאר של הפאה. כבוי: החץ זז בצעדים עגולים בלבד.",
|
||||
"prefs.extrude_view_isometric": "סיבוב התצוגה לאיזומטרית בפתיחת שליפה",
|
||||
"prefs.extrude_view_return": "חזרה לתצוגה הקודמת בסגירת שליפה",
|
||||
"prefs.file_operations_wait": "המתנה לפתיחת קבצים",
|
||||
"prefs.file_operations_wait_note": "בזמן שקובץ נפתח או מוכנס, או שקישורים נקראים מחדש, התכנון ממתין מאחורי כרטיס עם ההתקדמות וביטול. כבוי: הקובץ מוצג בחלונית הפעולות ואפשר להמשיך לעבוד; הוספה נכנסת לאחר שתסיימו את מה שאתם עושים, וקובץ שנפתח בינתיים נפתח בכרטיסייה חדשה.",
|
||||
"prefs.fillet_legacy_radius": "השתמש בברירת המחדש הקודמת לרדיוס Fillet מוצק",
|
||||
"prefs.fillet_legacy_radius.help": "כבוי כברירת מחדש. כשהוא פעיל, Solid Fillet חדש נפתח במספר 2 שנקרא ביחידות התכנון (\"2 אינץ\" בתכנון באינצ'ים), כמו קודם; כשהוא כבוי, הוא נפתח ברדיוס שבו הכלי נמסר, 2 מ\"מ, מוצג ביחידות התכנון (\"0.07874 אינץ\" בתכנון באינצ'ים).",
|
||||
"prefs.follows_os": "לפי מערכת ההפעלה",
|
||||
"prefs.font": "גופן",
|
||||
"prefs.font_fallback": "תווים שחסרים בגופן הנבחר מוצגים בגופן המובנה, כך שאף תווית לא מופיעה כריבוע ריק.",
|
||||
@@ -2628,6 +2712,17 @@
|
||||
"prefs.gesture_pan": "הזזת מבט",
|
||||
"prefs.gesture_zoom": "זום",
|
||||
"prefs.graphics": "גרפיקה",
|
||||
"prefs.graphics_api": "ממשק גרפי",
|
||||
"prefs.graphics_api_auto": "אוטומטי",
|
||||
"prefs.graphics_api_help": "בחרו את הממשק הגרפי המשמש לפתיחת SolidCraft. אם ההפעלה הבאה לא תצליח לפתוח את החלון, הבחירה הקודמת תשוחזר.",
|
||||
"prefs.graphics_api_override": "הגדרת הפעלה עוקפת קובעת את הממשק הגרפי. הבחירה השמורה תחול כאשר SolidCraft ייפתח כרגיל.",
|
||||
"prefs.graphics_api_restart_note": "חל לאחר הפעלה מחדש. עיצובים שלא נשמרו יטופלו לפני הסגירה.",
|
||||
"prefs.graphics_api_restart_unavailable": "הפעילו מחדש את SolidCraft כדי להחיל את הממשק הגרפי השמור.",
|
||||
"prefs.graphics_api_running": "נוכחי: {current}. נבחר להפעלה הבאה: {selected}.",
|
||||
"prefs.graphics_api_save_failed": "לא ניתן לשמור את בחירת הממשק הגרפי: {error}",
|
||||
"prefs.graphics_api_start_failed": "לא ניתן להכין את הממשק הגרפי שנבחר: {error}",
|
||||
"prefs.graphics_api_start_reverted": "ההפעלה הקודמת עם {requested} לא פתחה את החלון. SolidCraft שחזר את {previous}.",
|
||||
"prefs.graphics_api_unavailable": "בחירת ממשק גרפי זמינה ביישום שולחן העבודה.",
|
||||
"prefs.graphics_card": "כרטיס גרפי",
|
||||
"prefs.graphics_card_auto": "אוטומטי",
|
||||
"prefs.graphics_card_missing": "הכרטיס הגרפי השמור אינו זמין; נעשה שימוש באפשרות אוטומטי.",
|
||||
@@ -2671,6 +2766,8 @@
|
||||
"prefs.history_sketches_in_order": "לפי הסדר",
|
||||
"prefs.history_sketches_note": "כשהסקיצות מוגדרות ל„מתחת לפיצ'ר שלהן”, ציר הזמן משמאל מציג כל סקיצה רמה אחת פנימה, מתחת לפיצ'ר הראשון שנבנה ממנה, בכל פעם שהוא רחב מספיק להצגת שמות. ציר הזמן בתחתית שומר תמיד על סדר היצירה.",
|
||||
"prefs.history_sketches_under_feature": "מתחת לפיצ'ר שלהן",
|
||||
"prefs.history_steps_component": "צעדי ציר הזמן לפי רכיב",
|
||||
"prefs.history_steps_component_note": "כשרכיב פעיל או נבחר, פקדי ציר הזמן עוברים בין הפיצ'רים של אותו רכיב, כפי שציר הזמן למטה מציג אותם. כבוי: הם עוברים בין כל הפיצ'רים של התכנון. ציר הזמן משמאל או מתחת לדפדפן עובר תמיד בין כל הפיצ'רים.",
|
||||
"prefs.hold_stop_snapping": "החזקה לעצירת ההצמדה",
|
||||
"prefs.home_fit_size": "גודל בתצוגת בית ובהתאמה",
|
||||
"prefs.home_fit_size_note": "כמה מהתצוגה המודל ממלא כשתצוגת בית, התאמה, עיצוב שנפתח או שינוי תצוגה בניווט ממסגרים אותו, בין אם ההגדרה שלמטה פעילה ובין אם לא. 100 %: ממלא את התצוגה שבין הלוחות, המצפן וסרגל הניווט.",
|
||||
@@ -2686,6 +2783,8 @@
|
||||
"prefs.invert_curved_roll_arrows_note": "שני החצים המעוגלים בפינת הקובייה מסובבים את התצוגה במישור המסך. פועל: החץ עם כיוון השעון מסובב נגד כיוון השעון, והחץ נגד כיוון השעון מסובב עם כיוון השעון. כבוי: כל חץ מסובב את התצוגה לפי העקום שלו.",
|
||||
"prefs.invert_navigator_arrows": "היפוך חצי סיבוב קוביית התצוגה",
|
||||
"prefs.invert_navigator_arrows_note": "החצים סביב הקובייה מחוויים את המצלמה לכיוון שהחץ מצביע, כמו ב-Fusion ו-Inventor: החץ שמשמאל מצביע ימימה ומניע את המצלמה ימימה. כבוי: החץ מסובב את הקובייה אל הצד שבו הוא יושב, כך שחץ שמאל מניע את המצלמה שמאלה. חצי הגלילה המעוגלים אינם מושפעים.",
|
||||
"prefs.joint_drag_trackball": "סיבוב חלקים על מפרק כדורי כמו כדור עקיבה בעת גרירה",
|
||||
"prefs.joint_drag_trackball_help": "גרירת חלק שמפרק כדורי מחזיק מסובבת אותו בסיבוב הקטן ביותר סביב המפרק, כאילו מגלגלים כדור בגודל החלק. כבוי: הנקודה שתפסת עוקבת אחרי המצביע במדויק, והחלק עלול גם להסתובב סביבה.",
|
||||
"prefs.keep_unsaved_also_asks": "לשאול גם כשהכרטיסייה נסגרת",
|
||||
"prefs.keep_unsaved_also_asks_tip": "כשאפשרות זו כבויה, הכרטיסייה נסגרת ללא חלון הדפדפן לאחר שהעותק של כל תכן שלא נשמר עודכן.",
|
||||
"prefs.keep_unsaved_in_browser": "לשמור עבודה שלא נשמרה בדפדפן זה",
|
||||
@@ -2761,6 +2860,8 @@
|
||||
"prefs.not_on_gpu": "לא זמין במעבד הגרפי הזה",
|
||||
"prefs.on": "פועל",
|
||||
"prefs.opaque": "אטום",
|
||||
"prefs.operations_panel": "הצגת פעולות בתצוגה",
|
||||
"prefs.operations_panel_note": "פעולות ארוכות (פתיחת קובץ, חישוב פיצ'ר, פקודה של סוכן) מוצגות בפינה הימנית התחתונה של התצוגה עם ההתקדמות שלהן וכפתור לביטולן. כבוי: הודעת „מחשב” כמו קודם.",
|
||||
"prefs.orbit_snap": "החזקת Shift בזמן סיבוב מצמידה לציר.",
|
||||
"prefs.orientation": "כיוון",
|
||||
"prefs.origin_plane_names": "שמות מישורי הראשית",
|
||||
@@ -2841,6 +2942,8 @@
|
||||
"prefs.ribbon_tabs_only": "הצגת לשוניות הסרט בלבד",
|
||||
"prefs.ribbon_tabs_only_note": "הסרט מתקפל לשורת הלשוניות שלו. לחיצה על לשונית מציגה את הלוחות שלה מעל התצוגה עד שפקודה מתחילה או שהמצביע עוזב אותם. הפקודה ״רק לשוניות הסרט״ בלשונית תצוגה, או קיצור המקשים שלה, מחליפה הגדרה זו.",
|
||||
"prefs.right_click": "לחיצה ימנית",
|
||||
"prefs.save_prompt_one_at_a_time": "לשאול על כל תכן שלא נשמר בנפרד בעת סגירת כמה",
|
||||
"prefs.save_prompt_one_at_a_time_help": "להציג חלון שמירה נפרד לכל תכן שלא נשמר במקום רשימה משותפת.",
|
||||
"prefs.saving": "הפעלה ושמירה",
|
||||
"prefs.scale_note": "גם Ctrl + / Ctrl − בחלון. הכפתורים בגודל 28 px ב־100%.",
|
||||
"prefs.scale_text": "קנה מידה וטקסט",
|
||||
@@ -2877,6 +2980,8 @@
|
||||
"prefs.sketch.center_arc": "קשת מנקודת מרכז עוקבת אחר הסמן",
|
||||
"prefs.sketch.click_selects": "לחיצה בוחרת",
|
||||
"prefs.sketch.conflict_colour": "צבע התנגשות",
|
||||
"prefs.sketch.cursor_coordinates": "הצגת קואורדינטות הסמן בסקיצה",
|
||||
"prefs.sketch.cursor_coordinates_note": "ליד הסמן, ערכי X ו-Y שלו מראשית הסקיצה, גם כשאין כלי פעיל. כבוי: רק בזמן שכלי ממקם נקודה.",
|
||||
"prefs.sketch.drawing": "שרטוט",
|
||||
"prefs.sketch.ellipse_axes": "שרטוט אליפסות עם הצירים שלהן",
|
||||
"prefs.sketch.ellipse_axes_note": "הציר הראשי והציר המשני כקווי עזר, כדי שאפשר יהיה לתת מידות לחצאי הצירים ולצירים. כבוי: האליפסה בלבד, ו-D עליה נותן את הרדיוס המשני שלה בכל מקום שאליו נגרר הערך, משורטט ומסומן R כמו קודם.",
|
||||
@@ -2888,14 +2993,20 @@
|
||||
"prefs.sketch.faces_edges": "פאות וקצוות",
|
||||
"prefs.sketch.hide_glyphs": "הסתרת סמלים בהתרחקות",
|
||||
"prefs.sketch.marks": "סימונים בסקיצה",
|
||||
"prefs.sketch.max_points": "הסקיצה הגדולה ביותר",
|
||||
"prefs.sketch.max_points_note": "המספר המרבי של נקודות או עקומות בסקיצה אחת: 20000 כברירת מחדל, ועד 200000. הוספת SVG והוספת DXF דוחות שרטוט גדול יותר. סקיצה גדולה נפתרת ומוצגת לאט יותר.",
|
||||
"prefs.sketch.max_points_unit": "נקודות",
|
||||
"prefs.sketch.note": "שרטוט, הצמדה ובחירה.",
|
||||
"prefs.sketch.opening_closing": "פתיחה וסגירה",
|
||||
"prefs.sketch.prefer_free_points": "העדפת נקודות ניתנות להזזה כשהן חופפות",
|
||||
"prefs.sketch.project_options": "בקשת אפשרויות ההיטל תחילה",
|
||||
"prefs.sketch.recent_snap": "הצמדה למפגש שני קווי עזר",
|
||||
"prefs.sketch.select_3d_curve_points": "בחירת נקודות על עקומות סקיצה תלת־ממדית",
|
||||
"prefs.sketch.select_3d_curve_points_help": "הצגה ובחירה של נקודות על עקומות סקיצה תלת־ממדית שצוירו, לשימוש כהפניות בנייה.",
|
||||
"prefs.sketch.select_other_hidden": "בחירת אחר כוללת גאומטריה מוסתרת",
|
||||
"prefs.sketch.shortcut_cycles_modes": "לחיצה חוזרת על קיצור מחליפה מצב",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "כבוי: הכלי מתחיל מחדש.",
|
||||
"prefs.sketch.snap_to_visible_grid": "הצמדה למפגשים הנראים של הרשת",
|
||||
"prefs.sketch.snapping_guides": "הצמדה וקווי עזר",
|
||||
"prefs.sketch.state_icons": "סמלי מצב",
|
||||
"prefs.sketch.tracking_guides": "קווי עזר למרכזים ולנקודות אמצע",
|
||||
@@ -2923,6 +3034,7 @@
|
||||
"prefs.sketch_selection": "סקיצה ובחירה",
|
||||
"prefs.sketch_selection_heading": "סקיצה ובחירה",
|
||||
"prefs.sketch_selection_note": "איך סקיצות נצמדות ואיך לחיצות בוחרות.",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "נקודה בסקיצה נצמדת למפגש של הקווים שהרשת מציירת כשהמצביע מכוון לאחד מהם, ולרשת הדקה שביניהם אחרת. כבוי: הנקודה נצמדת לרשת הדקה בלבד, כמו קודם.",
|
||||
"prefs.sketch_state_icons": "סמלי סקיצות בצבע המצב שלהן",
|
||||
"prefs.sketch_state_icons_note": "בהיסטוריה ובדפדפן, סמל הסקיצה מקבל את צבע המצב שלה (אילוצים חסרים, מאולצת במלואה או סותרת) וחלונית העזרה מציינת את המצב. כבוי: לכל הסקיצות אותו סמל.",
|
||||
"prefs.sketch_tab_always": "השארת לשונית הסקיצה מוצגת",
|
||||
@@ -3624,6 +3736,7 @@
|
||||
"render.error_pbr_opacity": "PBR אטום דורש אטימות 1",
|
||||
"render.error_physical_glass": "המתכון שנבחר אינו זכוכית פיזיקלית",
|
||||
"render.error_preview_device": "תצוגה מקדימה של מוצר דורשת התקן מותקן עם מאגר עומק",
|
||||
"render.error_product_placement": "מיקום מוצר לא תקין",
|
||||
"render.error_product_triangle": "משולש מוצר לא תקין",
|
||||
"render.error_provisional_identity": "זהות רינדור זמנית או מספר דגימות לא תקינים",
|
||||
"render.error_quality_bounds": "הטלת האיכות חורגת מהגבולות המקוריים",
|
||||
@@ -3707,6 +3820,10 @@
|
||||
"render.gpu_path_retry": "לנסות שוב",
|
||||
"render.gpu_seed": "זרע אקראי",
|
||||
"render.gpu_unavailable": "מעקב מסלולים ב־GPU אינו מוכן במכשיר הזה.",
|
||||
"render.graphics_api_restart_vulkan": "הפעלה מחדש עם Vulkan",
|
||||
"render.graphics_api_restart_warning": "שינוי הממשק הגרפי מפעיל מחדש את SolidCraft ומבקש לשמור עיצובים שלא נשמרו. אם הממשק החדש לא יצליח לפתוח את החלון, הבחירה הקודמת תשוחזר בהפעלה הבאה.",
|
||||
"render.graphics_api_settings": "הגדרות גרפיקה",
|
||||
"render.graphics_api_vulkan_required": "מעקב נתיבים ב־GPU דורש Vulkan בהפעלה זו. הפעילו מחדש עם Vulkan, או המשיכו להשתמש בשיטת תמונה ב־CPU.",
|
||||
"render.ground_apply": "התאמת הקרקע ושמירתה",
|
||||
"render.ground_gap": "מרווח חופש מפורש",
|
||||
"render.ground_linear_rgb": "החזרה מפוזרת · RGB ליניארי",
|
||||
@@ -4708,6 +4825,8 @@
|
||||
"sketch.hint.spline3d": "3D Spline: click fit points in 3D; right-click or Esc to finish",
|
||||
"sketch.hint.trim": "Trim: click the piece of a curve to remove, or drag across the pieces to remove",
|
||||
"sketch.make_selection": "המרת הבחירה ל־{linetype}",
|
||||
"sketch.move_released": "הוזז: {count} אילוצים שקשרו אותו למה שנשאר שוחררו ({names}).",
|
||||
"sketch.move_released_one": "הוזז: {count} אילוץ שקשר אותו למה שנשאר שוחרר ({names}).",
|
||||
"sketch.open_ends": "קצוות פתוחים: {count}",
|
||||
"sketch.status_conflict": "אילוצים סותרים",
|
||||
"sketch.status_fully_constrained": "מאולץ במלואו",
|
||||
@@ -4738,6 +4857,10 @@
|
||||
"sketch_text.path_clear": "הסרת הטקסט מהעקומה",
|
||||
"sketch_text.path_hint": "עקומה בסקיצה שהטקסט עוקב אחריה: יש ללחוץ כאן ואז על העקומה",
|
||||
"sketch_text.use_font_file": "שימוש בקובץ הגופן {path}",
|
||||
"sketch_text.valign_baseline": "קו בסיס",
|
||||
"sketch_text.valign_bottom": "למטה",
|
||||
"sketch_text.valign_middle": "אמצע",
|
||||
"sketch_text.valign_top": "למעלה",
|
||||
"solid": "מוצק",
|
||||
"status.editing": "עריכת {name}",
|
||||
"status.navigation": "מיפוי העכבר: {mapping}",
|
||||
@@ -4938,6 +5061,7 @@
|
||||
"ui.agent_chat_allow_once": "התרה פעם אחת",
|
||||
"ui.agent_chat_allowed": "הותר",
|
||||
"ui.agent_chat_answered": "תשובה: {option}",
|
||||
"ui.agent_chat_answered_in": "נענה תוך {time}",
|
||||
"ui.agent_chat_approval": "לאפשר לסוכן לעשות זאת?",
|
||||
"ui.agent_chat_attach_selection": "צירוף הבחירה",
|
||||
"ui.agent_chat_attach_selection_tip": "שליחת מה שנבחר במודל (פאות, מקצועות, פיצ'רים, גופים) עם ההודעה, כדי שהסוכן יבין למה הכוונה",
|
||||
@@ -4966,6 +5090,7 @@
|
||||
"ui.agent_chat_ctx_bodies": "גופים",
|
||||
"ui.agent_chat_ctx_elements": "אלמנטים",
|
||||
"ui.agent_chat_ctx_features": "פיצ'רים",
|
||||
"ui.agent_chat_ctx_gone": "כבר לא בעיצוב: הוא שונה או נמחק.",
|
||||
"ui.agent_chat_ctx_more": "+{n} נוספים",
|
||||
"ui.agent_chat_ctx_other": "אחר",
|
||||
"ui.agent_chat_custom_heading": "מודל מותאם אישית",
|
||||
@@ -4979,6 +5104,7 @@
|
||||
"ui.agent_chat_dock_right": "עגינה מימין",
|
||||
"ui.agent_chat_drop_hint": "יש לשחרר כדי לצרף להודעה הבאה",
|
||||
"ui.agent_chat_edit": "עריכה",
|
||||
"ui.agent_chat_ended_after": "הסתיים אחרי {time}",
|
||||
"ui.agent_chat_exited": "הסוכן נעצר.",
|
||||
"ui.agent_chat_failed_start": "לא ניתן להפעיל את הסוכן: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: קובץ CAD מיובא לתכן, ולא נקרא",
|
||||
@@ -5016,6 +5142,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model} לא יכול להשתמש בכלים של SolidCraft, ולכן הוא יכול רק לשוחח. יש לבחור מודל שתומך בכלים.",
|
||||
"ui.agent_chat_model_rejected": "הסוכן לא קיבל את {model}: {error}",
|
||||
"ui.agent_chat_model_search": "חיפוש מודלים…",
|
||||
"ui.agent_chat_model_search_or_id": "חיפוש, או הקלדת מזהה מודל כלשהו…",
|
||||
"ui.agent_chat_model_tip": "המודל שבו הסוכן משתמש. הבחירה נשמרת עבור הסוכן הזה.",
|
||||
"ui.agent_chat_models_failed": "לא ניתן היה לטעון את רשימת המודלים: {error}",
|
||||
"ui.agent_chat_models_heading": "מודלים זמינים",
|
||||
@@ -5027,6 +5154,7 @@
|
||||
"ui.agent_chat_next_picture": "התמונה הבאה",
|
||||
"ui.agent_chat_no_cli": "solidcraft-cli לא נמצא לצד האפליקציה, ולכן הסוכן לא יכול לגשת לתכן.",
|
||||
"ui.agent_chat_no_control": "נקודת הקצה של הצ'אט עם הסוכן לא הופעלה, ולכן הסוכן לא יכול לגשת לתכן.",
|
||||
"ui.agent_chat_no_design_hint": "הסוכן פועל בלי הכלים של SolidCraft, ולכן אינו יכול לקרוא או לשנות את התכן: solidcraft-cli לא נמצא ליד היישום. התקינו את SolidCraft עם solidcraft-cli לצידו (ב-Windows: קובץ ה-MSI או ה-zip הנייד), או הגדירו את SOLIDCRAFT_CLI לנתיב שלו, ואז התחברו שוב.",
|
||||
"ui.agent_chat_no_images": "הסוכן הזה לא מקבל תמונות",
|
||||
"ui.agent_chat_no_picture": "אין תמונה בלוח",
|
||||
"ui.agent_chat_no_tool_call": "המודל לא השתמש בכלים של SolidCraft, ולכן התכן לא השתנה. יש לבחור מודל שתומך בקריאה לכלים; ראו „מודלים מקומיים” במדריך צ'אט הסוכן.",
|
||||
@@ -5073,16 +5201,26 @@
|
||||
"ui.agent_chat_setup_title": "הגדרת עוזר",
|
||||
"ui.agent_chat_side": "לעגן את הצ'אט",
|
||||
"ui.agent_chat_signed_in": "מחובר",
|
||||
"ui.agent_chat_snap_none_found": "לא נמצא סוכן קוד. חבילת ה־Snap מבודדת, ולכן היא לא יכולה לראות או להפעיל את סוכני הקוד שמותקנים במחשב הזה. כדי להשתמש בהם, יש להתקין את SolidCraft מחבילת AppImage, .deb או .rpm במקום זאת. סוכן שמשתמש ב־API תואם OpenAI עובד גם בחבילת ה־Snap, ואפשר להגדיר אותו בעזרת הוספת סוכן.",
|
||||
"ui.agent_chat_span_h": "{h} שע' {min} דק'",
|
||||
"ui.agent_chat_span_min": "{n} דק'",
|
||||
"ui.agent_chat_span_s": "{n} שנ'",
|
||||
"ui.agent_chat_state_auth": "נדרשת התחברות",
|
||||
"ui.agent_chat_state_busy": "עובד…",
|
||||
"ui.agent_chat_state_exited": "הסוכן נעצר",
|
||||
"ui.agent_chat_state_failed": "ההתחברות נכשלה",
|
||||
"ui.agent_chat_state_no_design": "אין גישה לתכן",
|
||||
"ui.agent_chat_state_off": "לא מחובר",
|
||||
"ui.agent_chat_state_ready": "מוכן",
|
||||
"ui.agent_chat_state_starting": "מופעל…",
|
||||
"ui.agent_chat_stop": "עצירה",
|
||||
"ui.agent_chat_stop_tip": "עצירת הסוכן וכל מה שהוא הפעיל",
|
||||
"ui.agent_chat_stop_turn_tip": "עצירת הסוכן (Esc). הודעות בתור נשארות בתור.",
|
||||
"ui.agent_chat_thinking_for": "חושב כבר {time}",
|
||||
"ui.agent_chat_tool_running_for": "רץ כבר {time}",
|
||||
"ui.agent_chat_tools_not_started": "הסוכן פועל בלי הכלים של SolidCraft, ולכן אינו יכול לקרוא או לשנות את התכן: solidcraft-cli נמצא, אבל הכלים שלו לא הופעלו (הודעת השגיאה בצ'אט מסבירה למה). התחברו שוב, ואם זה חוזר, התקינו מחדש את SolidCraft.",
|
||||
"ui.agent_chat_transcript_assistant": "עוזר:",
|
||||
"ui.agent_chat_transcript_user": "משתמש:",
|
||||
"ui.agent_chat_turn_limit": "שינויים להודעה",
|
||||
"ui.agent_chat_turn_unlimited": "ללא הגבלה",
|
||||
"ui.agent_chat_undo_changes": "ביטול השינויים האלה",
|
||||
@@ -5239,7 +5377,9 @@
|
||||
"ui.browser_bodies_one": "גוף {count}",
|
||||
"ui.browser_bodies_other": "{count} גופים",
|
||||
"ui.browser_collapse": "כיווץ עץ התכן",
|
||||
"ui.browser_collapse_below": "כיווץ מה שמתחת",
|
||||
"ui.browser_expand": "הרחבת עץ התכן",
|
||||
"ui.browser_expand_below": "הרחבת מה שמתחת",
|
||||
"ui.browser_title": "עץ התכן",
|
||||
"ui.calibrate": "כיול",
|
||||
"ui.cancel": "ביטול",
|
||||
@@ -5269,6 +5409,7 @@
|
||||
"ui.collapse": "כיווץ",
|
||||
"ui.collinear": "על ישר אחד",
|
||||
"ui.colour_vision": "ראיית צבעים",
|
||||
"ui.colour_vision_bends": "כיפופים",
|
||||
"ui.colour_vision_deutan": "דויטרן",
|
||||
"ui.colour_vision_deutan_tip": "לתחושת ירוק חלשה או חסרה",
|
||||
"ui.colour_vision_failed": "נכשל",
|
||||
@@ -5298,14 +5439,24 @@
|
||||
"ui.conic_curve": "עקום חרוטי",
|
||||
"ui.constant": "קבוע",
|
||||
"ui.constraints_conflict": "התנגשות בין אילוצים",
|
||||
"ui.construct_auto.chosen": "השיטה נבחרה לפי הבחירות שלך. בחר הפניה נוספת, או הסר אחת, כדי לשנות את השיטה.",
|
||||
"ui.construct_auto.no_fit": "בחר הפניות אחרות: אין שיטה שבונה מאלה.",
|
||||
"ui.construct_auto.pick": "בחר ממה לבנות: השיטה נקבעת לפי הבחירות שלך.",
|
||||
"ui.construct_auto.refs": "הפניות",
|
||||
"ui.construct_auto.select": "בחר קודם את ההפניות לבנייה",
|
||||
"ui.construct_axes": "צירים",
|
||||
"ui.construct_planes": "מישורים",
|
||||
"ui.construct_points": "נקודות",
|
||||
"ui.construction": "עזר",
|
||||
"ui.construction.angle_hint": "ישר עזר: בחירת נקודה ואז הקלדת זווית או בחירת כיוון",
|
||||
"ui.construction.axis_hint": "ישר עזר: לחיצה על נקודה, או הקלדת המרחק מציר הסקיצה",
|
||||
"ui.construction.bisector_hint": "חוצה זווית: בחירת שני ישרים נחתכים ואז הפתרון הרצוי",
|
||||
"ui.construction.common_hint": "משיק משותף: בחירת שני מעגלים/קשתות ואז הפתרון הרצוי",
|
||||
"ui.construction.contact_hint": "משיק: בחירת מעגל/קשת או ספליין/חתך חרוט פתוח ואז נקודת השקה (לעקומות חופשיות: קצוות בלבד)",
|
||||
"ui.construction.external_hint": "משיק: בחירת מעגל או קשת, נקודה חיצונית ואז הפתרון הרצוי",
|
||||
"ui.construction.free_hint": "ישר עזר: לחיצה על שתי נקודות; לחיצה ימנית להתחלה מחדש",
|
||||
"ui.construction.normal_needs_length": "קו אינסופי הוא תמיד קו עזר: הקלדת אורך משרטטת קו רגיל",
|
||||
"ui.construction.parallel_hint": "ישר עזר: בחירת ישר, ואז לחיצה או הקלדת ההיסט; לחיצה ימנית להחלפת הייחוס",
|
||||
"ui.construction.point_hint": "ישר עזר: לחיצה על נקודת המעבר",
|
||||
"ui.construction.reference_hint": "ישר עזר: בחירת ישר ואז נקודה; לחיצה ימנית להחלפת הייחוס",
|
||||
"ui.construction.ribbon_label": "קווי עזר",
|
||||
@@ -5448,6 +5599,17 @@
|
||||
"ui.ellipse": "אליפסה",
|
||||
"ui.emboss_wrap_note": "פרופילי קווים ניצבים המשיקים לגליל נתמך נכרכים אוטומטית. יש לבחור דופן כדי לקבוע יעד.",
|
||||
"ui.end": "סוף",
|
||||
"ui.end_cap.chamfer": "שיפוע פינות",
|
||||
"ui.end_cap.direction": "כיוון",
|
||||
"ui.end_cap.faces": "פאות קצה",
|
||||
"ui.end_cap.inset": "היסט פנימה",
|
||||
"ui.end_cap.inset_kind": "היסט לפי",
|
||||
"ui.end_cap.inset_ratio": "יחס היסט",
|
||||
"ui.end_cap.inward": "פנימה",
|
||||
"ui.end_cap.length": "אורך",
|
||||
"ui.end_cap.outward": "החוצה",
|
||||
"ui.end_cap.ratio": "יחס מהעובי",
|
||||
"ui.end_cap_title": "מכסה קצה",
|
||||
"ui.end_radius": "רדיוס סיום",
|
||||
"ui.end_scale": "קנה מידה בסיום",
|
||||
"ui.ends": "קצוות",
|
||||
@@ -5468,7 +5630,10 @@
|
||||
"ui.explode_needs_two_components": "תצוגה מפוצצת מרחיקה רכיבים זה מזה, ולכן התכן צריך שניים או יותר מהם (רכיב חדש, הוספת תכן או יצירת רכיבים מגופים)",
|
||||
"ui.exportDxf": "ייצוא DXF…",
|
||||
"ui.export_ellipsis_keymap": "ייצוא…",
|
||||
"ui.export_glb": "ייצוא GLB",
|
||||
"ui.export_keymap_tip": "מקשים, מועדפי תיבת S וסרגל הכלים, כקובץ",
|
||||
"ui.export_selects_only_body": "בחירת הגוף היחיד בייצוא רשת",
|
||||
"ui.export_selects_only_body_tip": "ייצוא STL, ייצוא 3MF ושליחה לסלייסר מתחילים כשגוף התכנון כבר נבחר, כשיש בו גוף אחד בלבד.",
|
||||
"ui.extend": "הארכה",
|
||||
"ui.extent": "גבול",
|
||||
"ui.extent_type": "סוג גבול",
|
||||
@@ -5528,6 +5693,8 @@
|
||||
"ui.finest": "העדינה ביותר",
|
||||
"ui.finish_sketch": "סיום סקיצה",
|
||||
"ui.first_dimension_scales": "המידה הראשונה משנה את קנה המידה של הציור",
|
||||
"ui.first_dimension_scales_about_origin": "שינוי קנה מידה סביב ראשית הסקיצה",
|
||||
"ui.first_dimension_scales_about_origin_tip": "מופעל: הציור תמיד גדל או קטן סביב ראשית הסקיצה, כך שצורה שצוירה הרחק מהראשית זזה. כבוי: ציור שדבר אינו קושר לראשית משנה קנה מידה סביב מרכזו ונשאר במקומו.",
|
||||
"ui.first_dimension_scales_tip": "פועל: מידת האורך הראשונה בסקיצה משנה את קנה המידה של הציור שהיא מודדת, כך שצורתו נשמרת. כבוי: המידה משנה רק את גודל מה שהיא מודדת.",
|
||||
"ui.fit": "התאמה לחלון",
|
||||
"ui.fix_unfix": "קיבוע/שחרור",
|
||||
@@ -5950,6 +6117,7 @@
|
||||
"ui.project_references_construction_note": "הטלה, חיתוך, הכללת גאומטריה תלת־ממדית ומקצועות הפאה של סקיצה חדשה על פאה יוצרים גאומטריית עזר: הפניות לשרטוט שאינן נכללות בפרופילים. הן נשארות מקושרות למודל.",
|
||||
"ui.properties": "מאפיינים",
|
||||
"ui.properties.copy_matrix": "העתקת המטריצה",
|
||||
"ui.properties.copy_value": "לחיצה מעתיקה את הערך",
|
||||
"ui.properties.first_moments": "מומנטים ראשונים",
|
||||
"ui.properties.inertia": "מומנט התמד",
|
||||
"ui.properties.inertia_note": "סביב מרכז מסה, בצירי העולם (g·{unit}²)",
|
||||
@@ -5962,6 +6130,7 @@
|
||||
"ui.properties.measuring_failed": "המדידה נעצרה לפני שהסתיימה.",
|
||||
"ui.properties.principal_axis": "ציר ראשי {number}",
|
||||
"ui.properties.principal_moments": "מומנטים ראשיים",
|
||||
"ui.properties.value_copied": "הערך הועתק",
|
||||
"ui.pull_direction": "כיוון משיכה",
|
||||
"ui.quality": "איכות",
|
||||
"ui.quantity": "כמות",
|
||||
@@ -5982,11 +6151,14 @@
|
||||
"ui.relink_design_changed": "ההרכבה השתנתה במהלך בחירת המקור. יש להפעיל שוב את 'קישור מחדש למקור'.",
|
||||
"ui.relink_done": "המקור קושר מחדש לכל המופעים.",
|
||||
"ui.relink_not_linked": "רכיב זה אינו מקושר לתכן מקור.",
|
||||
"ui.relink_one_done": "המקור קושר מחדש למופע זה.",
|
||||
"ui.relink_select_one": "יש לבחור תחילה רכיב מקושר אחד או אחד המופעים שלו.",
|
||||
"ui.relink_source_all": "קישור מחדש למקור (כל המופעים)…",
|
||||
"ui.relink_source_one": "קישור מחדש למקור…",
|
||||
"ui.removeFromQuickAccess": "הסרה מהגישה המהירה",
|
||||
"ui.removeFromToolbar": "הסרה מסרגל הכלים",
|
||||
"ui.removeSection": "הסרת מקטע",
|
||||
"ui.renameSelectedBodies": "שינוי שם הגופים הנבחרים",
|
||||
"ui.render": "הדמיה",
|
||||
"ui.renderer": "מנוע גרפי",
|
||||
"ui.repeat": "חזרה",
|
||||
@@ -6017,6 +6189,8 @@
|
||||
"ui.ribbon_pin_footer": "פקודות מוצמדות מוצגות ברצועת הכלים. יש לרחף מעל שורה כדי להצמיד אותה או לבטל את הצמדתה.",
|
||||
"ui.ribbon_workspace": "סביבת עבודה",
|
||||
"ui.right": "ימין",
|
||||
"ui.right_click_confirms": "לחיצה ימנית מאשרת קלטים בתיבת דו-שיח",
|
||||
"ui.right_click_confirms_tip": "כאשר תיבת דו-שיח פתוחה, לחיצה ימנית בתצוגה עוברת לקלט הריק הבא, ובקלט האחרון מבצעת אישור",
|
||||
"ui.save": "שמירה",
|
||||
"ui.save_as": "שמירה בשם",
|
||||
"ui.save_mesh_no_slicer_open": "לא נמצא סלייסר: יש לבחור „מותאם אישית…” ולבחור את תוכנת הסלייסר",
|
||||
@@ -6076,6 +6250,16 @@
|
||||
"ui.sketch_intersect_selection_filter": "מסנן בחירה",
|
||||
"ui.sketch_keys_only": "להשאיר את מקשי המודל מחוץ לסקיצות",
|
||||
"ui.sketch_keys_only_tip": "בזמן עריכת סקיצה פועלים רק מקשי סקיצה ומקשים שפועלים בכל מקום; מקש של המודל כמו E או F לא עושה דבר, כך שמקש שנלחץ בטעות לא יסגור סקיצה כבדה.",
|
||||
"ui.sketch_links_added_curve": "{command} הוסיף עקומה אחת לסקיצה.",
|
||||
"ui.sketch_links_added_curves": "{command} הוסיף {count} עקומות לסקיצה.",
|
||||
"ui.sketch_links_added_curves_and_points": "{command} הוסיף לסקיצה {curves} ו־{points}.",
|
||||
"ui.sketch_links_added_point": "{command} הוסיף נקודה אחת לסקיצה.",
|
||||
"ui.sketch_links_added_points": "{command} הוסיף {count} נקודות לסקיצה.",
|
||||
"ui.sketch_links_curve_count": "{count} עקומות",
|
||||
"ui.sketch_links_curve_count_one": "עקומה אחת",
|
||||
"ui.sketch_links_hidden": "התוצאה מוסתרת כי האפשרות {option} כבויה באפשרויות הסקיצה.",
|
||||
"ui.sketch_links_point_count": "{count} נקודות",
|
||||
"ui.sketch_links_point_count_one": "נקודה אחת",
|
||||
"ui.sketch_modifiers": "מקשי שינוי בסקיצה",
|
||||
"ui.sketch_project_geometry": "גאומטריה",
|
||||
"ui.sketch_report.all_constrained": "הכול מאולץ במלואו.",
|
||||
@@ -6115,6 +6299,7 @@
|
||||
"ui.step_values": "שינוי ערכים בחצים ובגלגלת",
|
||||
"ui.step_values_tip": "מקשי מעלה/מטה והגלגלת מעל שדה ערך משנים את המספר בו.",
|
||||
"ui.stitch_tolerance_hint": "הדוקה",
|
||||
"ui.straighten": "יישור",
|
||||
"ui.stretch": "מתיחה",
|
||||
"ui.supersampling": "דגימת־על (SSAA)",
|
||||
"ui.supersampling_adaptive": "רק כשהמבט נייח",
|
||||
@@ -6188,6 +6373,8 @@
|
||||
"ui.view_angles_yaw": "סבסוב",
|
||||
"ui.view_angles_zero": "הגדר את {axis} ל-0°",
|
||||
"ui.view_centre": "מרכז המבט",
|
||||
"ui.view_compass_tip": "מבט מ־{axis}. לחיצה נוספת הופכת את הכיוון. גרירה מסובבת את המבט.",
|
||||
"ui.view_compass_tip_snap": "מבט מ־{axis}. לחיצה נוספת הופכת את הכיוון. גרירה מסובבת את המבט; יש להחזיק את Shift כדי להצמיד.",
|
||||
"ui.viewport_status_clear": "כיבוי {name}",
|
||||
"ui.viewport_status_clear_hint": "כיבוי {name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} קצוות",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Vrijednost",
|
||||
"Variable Radius": "Promjenjivi polumjer",
|
||||
"Velocity": "Brzina",
|
||||
"Vertical": "Okomito",
|
||||
"Vertices": "Vrhovi",
|
||||
"View navigator": "Navigator prikaza",
|
||||
"Volume": "Volumen",
|
||||
@@ -3929,6 +3930,10 @@
|
||||
"sketch_text.path_clear": "Skini tekst s njegove krivulje",
|
||||
"sketch_text.path_hint": "Krivulja skice koju tekst prati: kliknite ovdje, a zatim krivulju",
|
||||
"sketch_text.use_font_file": "Upotrijebi datoteku fonta {path}",
|
||||
"sketch_text.valign_baseline": "Osnovna linija",
|
||||
"sketch_text.valign_bottom": "Dno",
|
||||
"sketch_text.valign_middle": "Sredina",
|
||||
"sketch_text.valign_top": "Vrh",
|
||||
"solid": "puno",
|
||||
"status.editing": "Uređivanje: {name}",
|
||||
"status.navigation": "Mapiranje miša: {mapping}",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Érték",
|
||||
"Variable Radius": "Változó sugár",
|
||||
"Velocity": "Sebesség",
|
||||
"Vertical": "Függőleges",
|
||||
"Vertices": "Csúcsok",
|
||||
"View navigator": "Nézetnavigátor",
|
||||
"Volume": "Térfogat",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "{title} SZERKESZTÉSE",
|
||||
"dialog.no_shown_body": "Nincs módosítható megjelenített test: jelenítsen meg egyet, vagy válassza az Új test lehetőséget",
|
||||
"dialog.pattern_sketch_not_object": "Válasszon testeket vagy elemeket: a vázlat egyik sem. Ismételje a görbéit a vázlat saját Minta vagy Tükrözés parancsával, vagy húzza ki előbb.",
|
||||
"dialog.right_click_pick": "Előbb jelölje ki ezt: {input}",
|
||||
"dialog.select": "↖ Kijelölés",
|
||||
"dialog.selected_count": "↖ {count} kijelölve",
|
||||
"dialog.selection_constraint": "Kényszer {id}",
|
||||
@@ -3931,6 +3933,10 @@
|
||||
"sketch_text.path_clear": "Szöveg levétele a görbéről",
|
||||
"sketch_text.path_hint": "A vázlat egy görbéje, amelyet a szöveg követ: kattintson ide, majd a görbére",
|
||||
"sketch_text.use_font_file": "A(z) {path} betűtípusfájl használata",
|
||||
"sketch_text.valign_baseline": "Alapvonal",
|
||||
"sketch_text.valign_bottom": "Lent",
|
||||
"sketch_text.valign_middle": "Középen",
|
||||
"sketch_text.valign_top": "Fent",
|
||||
"solid": "szilárd test",
|
||||
"status.editing": "Szerkesztés: {name}",
|
||||
"status.navigation": "Egérkiosztás: {mapping}",
|
||||
@@ -5013,6 +5019,8 @@
|
||||
"ui.ribbon_pin_footer": "A rögzített parancsok megjelennek a menüszalagon. Egy sor fölé víve rögzíthető vagy feloldható.",
|
||||
"ui.ribbon_workspace": "Munkaterület",
|
||||
"ui.right": "Jobb",
|
||||
"ui.right_click_confirms": "A jobb kattintás jóváhagyja a párbeszédablak bemeneteit",
|
||||
"ui.right_click_confirms_tip": "Nyitott párbeszédablaknál a nézetben a jobb kattintás a következő üres bemenetre lép, az utolsónál pedig OK-t nyom",
|
||||
"ui.save": "Mentés",
|
||||
"ui.save_as": "Mentés másként",
|
||||
"ui.save_mesh_no_slicer_open": "Nem található szeletelő: válassza az Egyéni… lehetőséget, és jelölje ki a szeletelő programját",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Nilai",
|
||||
"Variable Radius": "Radius Variabel",
|
||||
"Velocity": "Kecepatan",
|
||||
"Vertical": "Vertikal",
|
||||
"Vertices": "Titik sudut",
|
||||
"View navigator": "Navigator tampilan",
|
||||
"Volume": "Volume",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "EDIT {title}",
|
||||
"dialog.no_shown_body": "Tidak ada bodi yang ditampilkan untuk diubah: tampilkan satu, atau pilih Bodi Baru",
|
||||
"dialog.pattern_sketch_not_object": "Pilih bodi atau fitur: sketsa bukan keduanya. Ulangi kurvanya dengan Pola atau Cermin milik sketsa itu sendiri, atau ekstrusi dulu.",
|
||||
"dialog.right_click_pick": "Pilih {input} terlebih dahulu",
|
||||
"dialog.select": "↖ Pilih",
|
||||
"dialog.selected_count": "↖ {count} terpilih",
|
||||
"dialog.selection_constraint": "Batasan {id}",
|
||||
@@ -3931,6 +3933,10 @@
|
||||
"sketch_text.path_clear": "Lepaskan teks dari kurvanya",
|
||||
"sketch_text.path_hint": "Kurva sketsa yang diikuti teks: klik di sini, lalu kurvanya",
|
||||
"sketch_text.use_font_file": "Gunakan file font {path}",
|
||||
"sketch_text.valign_baseline": "Garis dasar",
|
||||
"sketch_text.valign_bottom": "Bawah",
|
||||
"sketch_text.valign_middle": "Tengah",
|
||||
"sketch_text.valign_top": "Atas",
|
||||
"solid": "solid",
|
||||
"status.editing": "Mengedit {name}",
|
||||
"status.navigation": "Pemetaan mouse: {mapping}",
|
||||
@@ -5013,6 +5019,8 @@
|
||||
"ui.ribbon_pin_footer": "Perintah yang disematkan tampil di ribbon. Arahkan kursor ke baris untuk menyematkan atau melepas sematan.",
|
||||
"ui.ribbon_workspace": "Workspace",
|
||||
"ui.right": "Kanan",
|
||||
"ui.right_click_confirms": "Klik kanan mengonfirmasi input dialog",
|
||||
"ui.right_click_confirms_tip": "Saat dialog terbuka, klik kanan di tampilan berpindah ke input kosong berikutnya, dan pada input terakhir menjalankan OK",
|
||||
"ui.save": "Simpan",
|
||||
"ui.save_as": "Simpan Sebagai",
|
||||
"ui.save_mesh_no_slicer_open": "Slicer tidak ditemukan: pilih Kustom… dan pilih program slicer Anda",
|
||||
|
||||
@@ -885,6 +885,7 @@
|
||||
"Variable Radius": "Raggio variabile",
|
||||
"Variable radius": "Raggio variabile",
|
||||
"Velocity": "Velocità",
|
||||
"Vertical": "Verticale",
|
||||
"Vertices": "Vertici",
|
||||
"View": "Vista",
|
||||
"View navigator": "Navigatore della vista",
|
||||
@@ -1149,6 +1150,7 @@
|
||||
"cmd.file_save_mesh": "Salva come mesh",
|
||||
"cmd.file_send_to_slicer": "Invia allo Slicer",
|
||||
"cmd.file_slicers": "Slicer installati",
|
||||
"cmd.frame_end_cap": "Tappo di estremità",
|
||||
"cmd.frame_member": "Membro strutturale",
|
||||
"cmd.frame_profile_insert": "Inserisci profilo",
|
||||
"cmd.frame_profile_list": "Libreria profili",
|
||||
@@ -1623,6 +1625,7 @@
|
||||
"dialog.pattern_sketch_not_object": "Seleziona corpi o lavorazioni: uno schizzo non è nessuno dei due. Ripeti le sue curve con Ripetizione o Specchia dello schizzo stesso, oppure estrudilo prima.",
|
||||
"dialog.primitive_point_tip": "Un punto che compila X, Y e Z: fai clic qui, poi su un vertice, uno spigolo o una faccia del modello, su un punto di uno schizzo oppure sull'origine.",
|
||||
"dialog.reference_edge_tip": "Uno spigolo rettilineo della faccia scelta da cui si misura la distanza sotto: fai clic qui, poi sullo spigolo.",
|
||||
"dialog.right_click_pick": "Seleziona prima {input}",
|
||||
"dialog.select": "↖ Seleziona",
|
||||
"dialog.selected_count": "↖ Selezionati: {count}",
|
||||
"dialog.selection_constraint": "Vincolo {id}",
|
||||
@@ -1667,6 +1670,8 @@
|
||||
"dxf.tolerance": "Tolleranza delle curve",
|
||||
"dxf.tolerance_help": "Solo corpi visibili e schizzi mostrati. Le curve usano segmenti rettilinei. Una tolleranza minore produce curve più precise e richiede più tempo e memoria.",
|
||||
"each rail's curves must be in one sketch": "le curve di ogni guida devono stare in un solo schizzo",
|
||||
"error.end_cap_faces": "Seleziona almeno una faccia di estremità aperta di un elemento",
|
||||
"error.end_cap_unresolved": "L'estremità {ends} di questa chiusura non è più nel modello. Seleziona di nuovo le facce di estremità",
|
||||
"feature computation ended without a result": "il calcolo dell'operazione si è concluso senza risultato",
|
||||
"file.open.drawing_filter": "Progettazioni, file CAD, mesh e disegni",
|
||||
"file.open.portal_fallback.no_portal_service": "La finestra di selezione file aperta non è quella del desktop: il servizio portale del desktop non è disponibile.",
|
||||
@@ -1764,6 +1769,7 @@
|
||||
"help.file.send_to_slicer": "Salva i corpi selezionati come file 3MF e lo apre nello slicer che scegli. Usalo per passare dal modello alla stampa in un solo passo.",
|
||||
"help.font_details": "L’interfaccia usa i caratteri integrati di egui (Ubuntu Light e Hack, con licenze Ubuntu Font Licence e MIT/Bitstream Vera; Noto Emoji e il carattere per icone emoji, con licenze OFL e MIT). Il testo degli schizzi usa Liberation Sans (SIL OFL 1.1). Il pacchetto di caratteri facoltativo di The Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), non è incluso nelle build di SolidCraft.",
|
||||
"help.fonts": "Caratteri",
|
||||
"help.frame.end_cap": "Chiude le estremità aperte degli elementi con piastre sagomate sul contorno del profilo. Usalo per chiudere tubi, angolari e travi, sopra l'estremità o incassate.",
|
||||
"help.frame.member": "Posiziona un profilo, come un tubo o un profilato di alluminio, lungo le linee di uno schizzo del telaio, un membro per linea. Usalo per costruire telai, scaffalature e strutture saldate.",
|
||||
"help.inspect.accessibility": "Colora le facce che un utensile può raggiungere da una direzione e quelle che non può raggiungere. Usalo per verificare un pezzo per la lavorazione meccanica o lo stampaggio da quel lato.",
|
||||
"help.inspect.center_of_mass": "Mostra il centro di massa dei corpi, ciascuno da solo e tutti insieme, a densità uniforme. Usalo per controllare il bilanciamento e dove un pezzo si ribalterà.",
|
||||
@@ -2875,6 +2881,8 @@
|
||||
"prefs.sketch.center_arc": "L'arco per centro segue il cursore",
|
||||
"prefs.sketch.click_selects": "Il clic seleziona",
|
||||
"prefs.sketch.conflict_colour": "Colore di conflitto",
|
||||
"prefs.sketch.cursor_coordinates": "Mostra le coordinate del cursore in uno schizzo",
|
||||
"prefs.sketch.cursor_coordinates_note": "Accanto al puntatore, la sua X e Y dall'origine dello schizzo, anche senza strumenti attivi. Disattivato: solo mentre uno strumento posiziona un punto.",
|
||||
"prefs.sketch.drawing": "Disegno",
|
||||
"prefs.sketch.ellipse_axes": "Disegna le ellissi con i loro assi",
|
||||
"prefs.sketch.ellipse_axes_note": "Gli assi maggiore e minore come rette di costruzione, così si possono quotare i semiassi e gli assi. Disattivato: solo l'ellisse, e D su di essa dà il raggio minore ovunque si trascini il valore, disegnato ed etichettato R come prima.",
|
||||
@@ -4682,6 +4690,10 @@
|
||||
"sketch_text.path_clear": "Scollega il testo dalla curva",
|
||||
"sketch_text.path_hint": "Una curva dello schizzo seguita dal testo: fai clic qui, poi sulla curva",
|
||||
"sketch_text.use_font_file": "Usa il file di carattere {path}",
|
||||
"sketch_text.valign_baseline": "Linea di base",
|
||||
"sketch_text.valign_bottom": "Basso",
|
||||
"sketch_text.valign_middle": "Centro",
|
||||
"sketch_text.valign_top": "Alto",
|
||||
"solid": "solido",
|
||||
"status.editing": "Modifica di {name}",
|
||||
"status.navigation": "Assegnazione del mouse: {mapping}",
|
||||
@@ -5017,6 +5029,7 @@
|
||||
"ui.agent_chat_setup_title": "Configura un assistente",
|
||||
"ui.agent_chat_side": "Lato della chat con l'agente",
|
||||
"ui.agent_chat_signed_in": "accesso effettuato",
|
||||
"ui.agent_chat_snap_none_found": "Nessun agente di programmazione trovato. Il pacchetto Snap è confinato, quindi non può vedere né avviare gli agenti di programmazione installati su questo computer. Per usarli, installa SolidCraft dal pacchetto AppImage, .deb o .rpm. Un agente che usa un’API compatibile con OpenAI funziona anche nel pacchetto Snap: configuralo con Aggiungi agente.",
|
||||
"ui.agent_chat_state_auth": "Accesso richiesto",
|
||||
"ui.agent_chat_state_busy": "Elaborazione…",
|
||||
"ui.agent_chat_state_exited": "Agente arrestato",
|
||||
@@ -5183,7 +5196,9 @@
|
||||
"ui.browser_bodies_one": "{count} corpo",
|
||||
"ui.browser_bodies_other": "{count} corpi",
|
||||
"ui.browser_collapse": "Comprimi la struttura",
|
||||
"ui.browser_collapse_below": "Comprimi sotto",
|
||||
"ui.browser_expand": "Espandi la struttura",
|
||||
"ui.browser_expand_below": "Espandi sotto",
|
||||
"ui.browser_title": "Struttura",
|
||||
"ui.calibrate": "Calibra",
|
||||
"ui.cancel": "Annulla",
|
||||
@@ -5392,6 +5407,17 @@
|
||||
"ui.ellipse": "Ellisse",
|
||||
"ui.emboss_wrap_note": "I profili di linee ortogonali tangenti a un cilindro supportato si avvolgono automaticamente. Scegliere una parete per definire la destinazione.",
|
||||
"ui.end": "Fine",
|
||||
"ui.end_cap.chamfer": "Smusso degli angoli",
|
||||
"ui.end_cap.direction": "Direzione",
|
||||
"ui.end_cap.faces": "Facce di estremità",
|
||||
"ui.end_cap.inset": "Rientro",
|
||||
"ui.end_cap.inset_kind": "Rientro come",
|
||||
"ui.end_cap.inset_ratio": "Rapporto di rientro",
|
||||
"ui.end_cap.inward": "Verso l'interno",
|
||||
"ui.end_cap.length": "Lunghezza",
|
||||
"ui.end_cap.outward": "Verso l'esterno",
|
||||
"ui.end_cap.ratio": "Rapporto dello spessore",
|
||||
"ui.end_cap_title": "TAPPO DI ESTREMITÀ",
|
||||
"ui.end_radius": "Raggio finale",
|
||||
"ui.end_scale": "Scala finale",
|
||||
"ui.ends": "Estremità",
|
||||
@@ -5894,6 +5920,7 @@
|
||||
"ui.project_references_construction_note": "Proietta, Interseca, Includi geometria 3D e gli spigoli della faccia di un nuovo schizzo su una faccia creano geometria di costruzione: riferimenti su cui disegnare, esclusi dai profili. Restano collegati al modello.",
|
||||
"ui.properties": "Proprietà",
|
||||
"ui.properties.copy_matrix": "Copia matrice",
|
||||
"ui.properties.copy_value": "Fai clic per copiare",
|
||||
"ui.properties.first_moments": "Momenti del primo ordine",
|
||||
"ui.properties.inertia": "Momento d'inerzia",
|
||||
"ui.properties.inertia_note": "Rispetto al centro di massa, negli assi globali (g·{unit}²)",
|
||||
@@ -5906,6 +5933,7 @@
|
||||
"ui.properties.measuring_failed": "La misurazione si è interrotta prima del termine.",
|
||||
"ui.properties.principal_axis": "Asse principale {number}",
|
||||
"ui.properties.principal_moments": "Momenti principali",
|
||||
"ui.properties.value_copied": "Valore copiato",
|
||||
"ui.pull_direction": "Direzione di estrazione",
|
||||
"ui.quality": "Qualità",
|
||||
"ui.quantity": "Quantità",
|
||||
@@ -5961,6 +5989,8 @@
|
||||
"ui.ribbon_pin_footer": "I comandi fissati compaiono sulla barra multifunzione. Passa sopra una riga per fissarla o rimuoverla.",
|
||||
"ui.ribbon_workspace": "Area di lavoro",
|
||||
"ui.right": "Destra",
|
||||
"ui.right_click_confirms": "Il clic destro conferma gli input della finestra di dialogo",
|
||||
"ui.right_click_confirms_tip": "Con una finestra di dialogo aperta, un clic destro nella vista passa al successivo input vuoto e, sull’ultimo, esegue OK",
|
||||
"ui.save": "Salva",
|
||||
"ui.save_as": "Salva con nome",
|
||||
"ui.save_mesh_no_slicer_open": "Nessuno slicer trovato: scegli Personalizzato… e seleziona il tuo programma slicer",
|
||||
|
||||
+188
-1
@@ -247,6 +247,7 @@
|
||||
"Drag to move the hole; click to remove it": "ドラッグで穴を移動、クリックで削除",
|
||||
"Drag to move the rest across the model. It snaps to sketch points on the face.": "ドラッグしてレストをモデル上で移動します。面上のスケッチ点にスナップします。",
|
||||
"Drag to move the snap fit across the model. It snaps to sketch points on the face.": "ドラッグしてスナップ フィットをモデル上で移動します。面上のスケッチ点にスナップします。",
|
||||
"Drag to place it on another face.": "ドラッグして別の面に配置します。",
|
||||
"Drag to point the catch in another direction.": "ドラッグしてキャッチの向きを変えます。",
|
||||
"Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.": "ドラッグしてレストを 5° 刻みで回転します。Alt または Ctrl を押したままにすると自由に回転します。",
|
||||
"Drive Joint": "ジョイントを駆動",
|
||||
@@ -513,6 +514,7 @@
|
||||
"Offset Y": "オフセット Y",
|
||||
"Offset Z": "オフセット Z",
|
||||
"On your computer": "このコンピューター上",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "選択したエッジのもう一つの区間。それぞれに独自の角度、高さ、曲げ方向があります",
|
||||
"Opacity": "不透明度",
|
||||
"Open GitHub": "GitHubを開く",
|
||||
"Open GitHub draft": "GitHubの下書きを開く",
|
||||
@@ -634,6 +636,7 @@
|
||||
"Remove the track": "トラックを削除",
|
||||
"Remove this bend": "この曲げを削除",
|
||||
"Remove this point": "この点を削除",
|
||||
"Remove this segment": "このセグメントを削除",
|
||||
"Rename Feature": "フィーチャーの名前を変更",
|
||||
"Rename Folder": "フォルダーの名前を変更",
|
||||
"Render Stage": "レンダリング段階",
|
||||
@@ -723,6 +726,7 @@
|
||||
"Section position": "断面の位置",
|
||||
"Sections": "セクション",
|
||||
"Sections (one sketch each)": "セクション (各1スケッチ)",
|
||||
"Segments": "セグメント",
|
||||
"Select Features": "フィーチャーを選択",
|
||||
"Select Other": "その他を選択",
|
||||
"Select Other: hold the left button still on the model (or right-click › Select Other…) to list everything under the cursor; click again on the same spot to select the next thing there. Double-click the middle button to go Home (Preferences › Navigation).": "その他を選択: モデル上で左ボタンを長押し(または右クリック › その他を選択…)するとカーソル下の要素が一覧表示されます。同じ場所を再度クリックすると次の要素が選択されます。中ボタンをダブルクリックするとホームビューに戻ります(環境設定 › ナビゲーション)。",
|
||||
@@ -772,6 +776,7 @@
|
||||
"Spacing must be a non-zero number": "間隔は0以外の数値にしてください",
|
||||
"Specialise": "特殊操作",
|
||||
"Speed": "速度",
|
||||
"Split Edge": "エッジを分割",
|
||||
"Splitting tool": "分割ツール",
|
||||
"Square": "正方形",
|
||||
"Stainless Steel": "ステンレス鋼",
|
||||
@@ -885,6 +890,7 @@
|
||||
"Variable Radius": "可変半径",
|
||||
"Variable radius": "可変半径",
|
||||
"Velocity": "速度",
|
||||
"Vertical": "垂直",
|
||||
"Vertices": "頂点",
|
||||
"View": "表示",
|
||||
"View navigator": "ビューナビゲーター",
|
||||
@@ -938,6 +944,13 @@
|
||||
"ai.prefs.connect_apps_note": "オフにすると追加した項目を削除します。\n\nSolidCraft の起動時に、このコンピューターで見つかった AI アプリ(OpenCode、Claude Desktop、Claude Code、Cursor、Codex、Gemini CLI、Copilot CLI、Windsurf、Zed、VS Code)へ MCP サーバーとして追加します。追加または更新するのは solidcraft のエントリのみで、変更済みのエントリには触れず、ファイルは先にバックアップされます。オフにすると追加したエントリを削除します。",
|
||||
"ai.prefs.connect_at_start": "起動時に前回のエージェントに接続",
|
||||
"ai.prefs.connect_at_start_note": "SolidCraft を起動するたびに、前回接続したエージェント (またはデフォルトのエージェント) をバックグラウンドで起動し、すぐにチャットできるようにします。--control を付けて起動した場合は行いません。接続できない場合、アシスタントに「接続に失敗しました」と「再試行」ボタンが表示されます。",
|
||||
"ai.prefs.control_failed": "コントロールチャネルを開始できませんでした: {error}",
|
||||
"ai.prefs.control_from_launch": "この実行は --control でポート {port} を使って開始されました。ここでの変更は、次に --control なしで SolidCraft を起動したときに反映されます。",
|
||||
"ai.prefs.control_listening": "127.0.0.1:{port} で待機中",
|
||||
"ai.prefs.control_not_listening": "待機していません",
|
||||
"ai.prefs.control_port": "ポート",
|
||||
"ai.prefs.control_port_note": "このコンピューター上で AI エージェントが接続するポート (127.0.0.1)。既定は 27878 で、使用中の場合は次の空いているポートを使います。それ以外のポートはそのまま使います。MCP クライアントも同じポートに向けてください (例: solidcraft-cli mcp --connect 127.0.0.1:7878)。",
|
||||
"ai.prefs.control_port_taken": "ポート {port} は別のプログラム (または別の SolidCraft ウィンドウ) が使用しています。別のポートを選んでください。",
|
||||
"ai.prefs.follow_camera": "カメラを追従",
|
||||
"ai.prefs.follow_camera_off": "カメラの自動追従はオフです。",
|
||||
"ai.prefs.follow_camera_on": "エージェントが作成するスケッチにカメラを向けます。",
|
||||
@@ -998,6 +1011,13 @@
|
||||
"browser.sketches_to_parts_not_on_face": "部品の面上にない",
|
||||
"browser.sketches_to_parts_part_missing": "部品がもうない",
|
||||
"browser.sketches_to_parts_result": "{moved} 個のスケッチを描かれている部品に移動しました。{stayed} 個はそのまま:{why}",
|
||||
"browser.straighten_angle": "エッジの向き",
|
||||
"browser.straighten_choose": "エッジの向き(水平、垂直、または角度)を選んでから、[傾き補正]を押してください。",
|
||||
"browser.straighten_click_a": "まっすぐにしたいエッジの一端を画像上でクリックするか、座標を入力してください。",
|
||||
"browser.straighten_click_b": "エッジのもう一端をクリックするか、座標を入力してください。",
|
||||
"browser.straighten_horizontal": "水平",
|
||||
"browser.straighten_title": "傾き補正: {name}",
|
||||
"browser.straighten_vertical": "垂直",
|
||||
"browser.units": "単位: {units}",
|
||||
"cam.flat": "平面",
|
||||
"cam.follower": "従動節",
|
||||
@@ -1027,6 +1047,8 @@
|
||||
"cmd.appearance_pick_up": "外観を取得",
|
||||
"cmd.appearance_replace": "外観を置換",
|
||||
"cmd.assembly_bom": "部品表",
|
||||
"cmd.assembly_constraint_create": "拘束",
|
||||
"cmd.assembly_constraint_edit": "拘束を編集",
|
||||
"cmd.assembly_mass_properties": "質量特性",
|
||||
"cmd.body.print_face": "造形面",
|
||||
"cmd.body_rename": "ボディの名前を変更",
|
||||
@@ -1045,6 +1067,7 @@
|
||||
"cmd.canvas_delete": "キャンバスを削除",
|
||||
"cmd.canvas_edit": "キャンバスを編集",
|
||||
"cmd.canvas_insert": "キャンバス",
|
||||
"cmd.canvas_straighten": "キャンバスの傾き補正",
|
||||
"cmd.canvas_to_sketch": "キャンバスからスケッチ",
|
||||
"cmd.component_activate": "コンポーネントをアクティブ化",
|
||||
"cmd.component_break_link": "リンクを解除",
|
||||
@@ -1086,7 +1109,10 @@
|
||||
"cmd.config_rule": "構成ルール",
|
||||
"cmd.config_rules": "構成ルール一覧",
|
||||
"cmd.config_table": "構成テーブルを表示",
|
||||
"cmd.construct.axis": "軸",
|
||||
"cmd.construct.plane": "平面",
|
||||
"cmd.construct.plane.axis_point": "軸と点を通る平面",
|
||||
"cmd.construct.point": "点",
|
||||
"cmd.construct_axis_edge": "エッジを通る軸",
|
||||
"cmd.construct_axis_normal_to_face": "面に垂直な軸",
|
||||
"cmd.construct_axis_through_cylinder": "円柱/円錐/トーラスを通る軸",
|
||||
@@ -1149,6 +1175,7 @@
|
||||
"cmd.file_save_mesh": "メッシュとして保存",
|
||||
"cmd.file_send_to_slicer": "スライサーに送る",
|
||||
"cmd.file_slicers": "インストール済みのスライサー",
|
||||
"cmd.frame_end_cap": "エンドキャップ",
|
||||
"cmd.frame_member": "フレーム部材",
|
||||
"cmd.frame_profile_insert": "形材を挿入",
|
||||
"cmd.frame_profile_list": "形材ライブラリ",
|
||||
@@ -1169,6 +1196,7 @@
|
||||
"cmd.inspect_isocurve": "アイソカーブ解析",
|
||||
"cmd.inspect_minimum_radius": "最小半径解析",
|
||||
"cmd.inspect_parameter_sweep": "パラメータスイープ",
|
||||
"cmd.inspect_parameter_variants": "パラメーターの組み合わせを比較",
|
||||
"cmd.inspect_silhouette": "シルエット",
|
||||
"cmd.inspect_zebra": "ゼブラ解析",
|
||||
"cmd.joint_as_built": "現位置ジョイント",
|
||||
@@ -1222,6 +1250,10 @@
|
||||
"cmd.motion_trace": "モーション トレース",
|
||||
"cmd.motion_trace_edit": "モーション トレースを編集",
|
||||
"cmd.motion_trace_keep": "モーション トレースを保持",
|
||||
"cmd.note_add": "メモを追加",
|
||||
"cmd.note_delete": "メモを削除",
|
||||
"cmd.note_list": "メモを一覧表示",
|
||||
"cmd.note_update": "メモを編集",
|
||||
"cmd.occurrence_align": "オカレンスを整列",
|
||||
"cmd.occurrence_copy": "貼り付け(インスタンス)",
|
||||
"cmd.occurrence_drag": "オカレンスをドラッグ",
|
||||
@@ -1347,6 +1379,7 @@
|
||||
"cmd.render_start": "画像をレンダリング",
|
||||
"cmd.render_status": "レンダリングの進行状況",
|
||||
"cmd.select_clear": "選択をクリア",
|
||||
"cmd.selection_get": "選択を取得",
|
||||
"cmd.settings_profile_apply": "設定プロファイルを適用",
|
||||
"cmd.settings_profile_delete": "設定プロファイルを削除",
|
||||
"cmd.settings_profile_export": "設定プロファイルをエクスポート",
|
||||
@@ -1510,6 +1543,7 @@
|
||||
"cmd.timeline_suppress": "フィーチャーを抑制",
|
||||
"cmd.ui.assistant": "アシスタントの表示切り替え",
|
||||
"cmd.ui.palette": "コマンドを検索",
|
||||
"cmd.ui.toggle_visibility": "選択項目の表示/非表示",
|
||||
"cmd.view.navigator": "カスタム ビューナビゲーター",
|
||||
"cmd.view.render_browser": "Renderブラウザー",
|
||||
"cmd.view.render_dock": "レンダードックを移動",
|
||||
@@ -1567,6 +1601,7 @@
|
||||
"color.step_down": "1 ステップ下げる",
|
||||
"color.step_up": "1 ステップ上げる",
|
||||
"color.value": "明度(パーセント)",
|
||||
"component.error.ambiguous_name": "複数のコンポーネントに `{name}` という名前が付いています。数値のコンポーネント ID を使用してください: {ids}。",
|
||||
"config.column_filter_empty": "一致する列がありません",
|
||||
"config.rule_parameter_columns": "表に列があるパラメータのみが表示されます。ここで使うには「列を追加」(+) で列を追加してください。",
|
||||
"config.rule_suppression_columns": "表に「抑制」列があるフィーチャーのみが表示されます。ここで制御するには「列を追加」(+) で列を追加してください。",
|
||||
@@ -1607,6 +1642,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}: 参照 `{reference}` は選択したときのままでは存在しません。選択し直してください",
|
||||
"dialog.bodies_count": "{count} ボディ",
|
||||
"dialog.clearance_invalid": "クリアランスは 0 以上の長さにしてください",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "計算",
|
||||
"dialog.compute_again": "再計算",
|
||||
"dialog.computing": "計算中… {seconds} 秒",
|
||||
@@ -1619,10 +1655,12 @@
|
||||
"dialog.dimension_step_expression": "増減できるのは数値だけです。式はそのまま残ります",
|
||||
"dialog.dimension_step_up": "{step} 増やす",
|
||||
"dialog.edit_title": "{title}を編集",
|
||||
"dialog.hole_held_off_its_line": "参照エッジがこの穴を直線上に固定していますが、その直線は選択した点より手前で面の外に出ます。直線が面の上を通る位置を選択するか、エッジを外すと穴を自由に移動できます。",
|
||||
"dialog.no_shown_body": "変更できる表示中のボディがありません。ボディを表示するか、新規ボディを選択してください",
|
||||
"dialog.pattern_sketch_not_object": "ボディかフィーチャーを選んでください。スケッチはどちらでもありません。曲線はスケッチ内のパターンかミラーで繰り返すか、先に押し出してください。",
|
||||
"dialog.primitive_point_tip": "X、Y、Z を埋める点: ここをクリックしてから、モデルの頂点、エッジ、面、スケッチの点、または原点をクリック。",
|
||||
"dialog.reference_edge_tip": "下の距離を測る基準となる、選んだ面の直線エッジ: ここをクリックしてからエッジをクリック。",
|
||||
"dialog.right_click_pick": "先に {input} を選択",
|
||||
"dialog.select": "↖ 選択",
|
||||
"dialog.selected_count": "↖ {count} 個選択中",
|
||||
"dialog.selection_constraint": "拘束 {id}",
|
||||
@@ -1636,9 +1674,12 @@
|
||||
"document.changed_on_disk": "{name} がディスク上で変更されました",
|
||||
"document.changed_on_disk_detail": "{name} は、開いたとき(または最後に保存したとき)以降に別のプログラムまたはコンピューターによって変更されました。上書きするとその変更は失われます。コピーを保存すると両方が残ります。",
|
||||
"document.copy_name": "{name} のコピー",
|
||||
"document.discard_row": "破棄",
|
||||
"document.finish_save_prompt": "別のデザインを開く前に、保存の確認に回答してください。",
|
||||
"document.newer_file": "新しいバージョンの SolidCraft で保存されています(形式 {format}、このバージョンは {reads} まで読み取れます)。足りないものがあれば更新してください。",
|
||||
"document.newer_file_change": "新しいバージョンの SolidCraft で保存されています(形式 {format}、このバージョンが認識しない `{change}` を含みます)。足りないものがあれば更新してください。",
|
||||
"document.newer_file_not_read": "読み取れませんでした: {what}。保存しても失われません。",
|
||||
"document.not_saved_yet": "未保存",
|
||||
"document.open_anyway": "このまま開く",
|
||||
"document.open_elsewhere": "{name} はすでに開かれています",
|
||||
"document.open_elsewhere_detail": "{name} は {who} の SolidCraft {app} で開かれています({when}に開かれました)。両方で保存すると、どちらかの作業が失われます。上書きせずに確認するには読み取り専用で開いてください。",
|
||||
@@ -1648,6 +1689,9 @@
|
||||
"document.read_only_save": "このデザインは読み取り専用で開かれています:新しいファイルとして保存してください",
|
||||
"document.save_changes": "{name} への変更を保存しますか?",
|
||||
"document.save_copy": "コピーを保存…",
|
||||
"document.save_many": "{n} 件のデザインの変更を保存しますか?",
|
||||
"document.save_row": "保存",
|
||||
"document.save_selected": "選択項目を保存",
|
||||
"document.tab_unsaved_changes": "未保存の変更",
|
||||
"document.unsaved_changes": "{name} には保存されていない変更があります。保存しない場合、変更内容は失われます。",
|
||||
"drive.rigid": "{joint} は剛体ジョイントです。部品をその場に固定するため、駆動するものがありません。動かすには「ジョイントを編集」で種類を変更してください: 回転させるなら Revolute、スライドさせるなら Slider、両方なら Cylindrical。",
|
||||
@@ -1667,6 +1711,8 @@
|
||||
"dxf.tolerance": "曲線の許容誤差",
|
||||
"dxf.tolerance_help": "表示中のボディとスケッチを出力し、曲線は線分で近似します。許容誤差を小さくすると曲線が滑らかになりますが、処理時間とメモリ使用量が増えます。",
|
||||
"each rail's curves must be in one sketch": "各レールの曲線は1つのスケッチ内にある必要があります",
|
||||
"error.end_cap_faces": "フレーム部材の開いた端面を1つ以上選択してください",
|
||||
"error.end_cap_unresolved": "このエンドキャップの端 {ends} はモデル上にありません。端面を選択し直してください",
|
||||
"feature computation ended without a result": "フィーチャーの計算が結果なしで終了しました",
|
||||
"file.open.drawing_filter": "デザイン、CADファイル、メッシュ、図面",
|
||||
"file.open.portal_fallback.no_portal_service": "開いたファイル選択はデスクトップのものではありません。デスクトップのファイル選択サービスが利用できません。",
|
||||
@@ -1678,6 +1724,7 @@
|
||||
"file_load.inserting": "ジオメトリを挿入中",
|
||||
"file_load.link_item": "{name} ({done}/{total})",
|
||||
"file_load.opened": "{name} を開きました",
|
||||
"file_load.opened_behind": "{name} を新しいタブで開きました",
|
||||
"file_load.opened_in_tab": "{name} を新しいタブで開きました",
|
||||
"file_load.opening": "デザインを開いています",
|
||||
"file_load.preparing_thumbnail": "サムネイルを準備中...",
|
||||
@@ -1725,11 +1772,13 @@
|
||||
"help.config.table": "構成テーブルを表示します。1行が1つのバリエーション、1列が1つのパラメータまたはフィーチャーで、デザインが有効な行と一致しているかも分かります。デザインのバリエーションを見直すときに使います。",
|
||||
"help.connect_note": "各アシスタントを再起動すると SolidCraft サーバーが読み込まれます。変更したファイルは .bak としてバックアップされています。",
|
||||
"help.connect_title": "AI アシスタントを接続",
|
||||
"help.construct.axis": "選択に応じた方法で構築軸を作ります。エッジや線に沿って、穴や丸い面を通って、2つの平面の交線に、2点を通って、または点を通り面に垂直に作ります。参照は決まっているが方法を選びたくないときに使います。",
|
||||
"help.construct.axis.edge": "直線のエッジまたはスケッチ線に沿って構築軸を作ります。回転、円形パターン、ジョイントの軸として使います。",
|
||||
"help.construct.axis.normal_to_face": "指定した点を通り、面に垂直な構築軸を作ります。表面からまっすぐ立ち上がる軸として使います。",
|
||||
"help.construct.axis.through_cylinder": "円柱、円錐、トーラスの面、または円形のエッジの中心を通る構築軸を作ります。丸い部品のまわりでフィーチャーを回転させたりパターン化したりするときに使います。",
|
||||
"help.construct.axis.two_planes": "2つの平面または平らな面が交わる位置に構築軸を作ります。必要な軸が2つの面の間の線であるときに使います。",
|
||||
"help.construct.axis.two_points": "2つの点、頂点、スケッチ点を通る構築軸を作ります。位置が分かっている2か所の間を通る軸に使います。",
|
||||
"help.construct.plane": "選択に応じた方法で構築平面を作ります。平面からのオフセット、点を通る、2つの平面の中間、線や点を通る、曲面に接する、またはパスに垂直に作ります。参照は決まっているが方法を選びたくないときに使います。",
|
||||
"help.construct.plane.along_path": "エッジまたは曲線に垂直な構築平面を、その上の指定位置に作ります。スイープ用のプロファイルや、パスの断面をスケッチするときに使います。",
|
||||
"help.construct.plane.at_angle": "平面または面を、軸またはエッジを中心に指定した角度だけ傾けた構築平面を作ります。斜めのブラケットなど、傾いたスケッチに使います。",
|
||||
"help.construct.plane.axis_point": "軸と、その軸上にない点を含む構築平面を作成します。原点軸、構築軸、直線エッジまたはスケッチの直線を選択し、次に頂点、スケッチ点または構築点を選択します。軸上の点では平面が一意に定まりません。",
|
||||
@@ -1739,6 +1788,7 @@
|
||||
"help.construct.plane.tangent": "円柱、円錐、球、トーラスに1点で接する構築平面を作ります。丸い部品の側面にスケッチするときに使います。",
|
||||
"help.construct.plane.three_points": "3つの点を通る構築平面を作ります。3つの角など、モデル上の位置で決まる平面に使います。",
|
||||
"help.construct.plane.two_edges": "同一平面上にある2本の直線エッジまたは線を通る構築平面を作ります。向かい合う2本のエッジを通る面など、部品を横切る平面に使います。",
|
||||
"help.construct.point": "選択に応じた方法で構築点を作ります。頂点、円や球の中心、エッジ上、2本の線や3つの平面の交点、または線が平面と交わる位置に作ります。参照は決まっているが方法を選びたくないときに使います。",
|
||||
"help.construct.point.along_path": "エッジまたは曲線上の指定位置に構築点を作ります。パスの途中の基準として使います。",
|
||||
"help.construct.point.center": "円形のエッジ、スケッチの円や円弧、球、トーラスの中心に構築点を作ります。穴、軸、ジョイントの基準として使います。",
|
||||
"help.construct.point.edge_plane": "エッジまたは線が平面や平らな面を通る位置に構築点を作ります。パスが平面と交わる位置を示すときに使います。",
|
||||
@@ -1764,6 +1814,7 @@
|
||||
"help.file.send_to_slicer": "選択したボディを 3MF ファイルとして保存し、選んだスライサーで開きます。モデルからプリントまでを1ステップで進めるときに使います。",
|
||||
"help.font_details": "インターフェースにはegui組み込みのフォントを使用しています(Ubuntu Font LicenceおよびMIT/Bitstream VeraライセンスのUbuntu LightとHack、OFLおよびMITのNoto Emojiと絵文字アイコンフォント)。スケッチのテキストにはLiberation Sans(SIL OFL 1.1)を使用しています。The Crafting Appsのオプションフォントパックcraft-fonts(BIZ UDPGothic、Shippori Mincho、BIZ UDMincho、Noto Sans CJK SC、Noto Sans Arabic、SIL OFL 1.1)はSolidCraftのビルドに同梱されていません。",
|
||||
"help.fonts": "フォント",
|
||||
"help.frame.end_cap": "フレーム部材の開いた端を、プロファイルの外形に沿ったプレートで閉じます。パイプ、アングル、梁の端をふさぐときに、端の上に載せるか端に埋め込んで使います。",
|
||||
"help.frame.member": "チューブやアルミ押し出し材などのプロファイルを、フレームスケッチの線に沿って1本につき1部材ずつ配置します。フレーム、ラック、溶接構造を作るときに使います。",
|
||||
"help.inspect.accessibility": "ツールが一方向から届く面と届かない面を色分けします。その方向からの切削加工や成形が可能か、部品を確認するときに使います。",
|
||||
"help.inspect.center_of_mass": "一様な密度を仮定して、各ボディと全体の重心を表示します。バランスや、部品が倒れる位置を確認するときに使います。",
|
||||
@@ -2240,6 +2291,9 @@
|
||||
"measure.at": "位置",
|
||||
"measure.item": "項目 {number}",
|
||||
"measure.line_to_centre": "線から中心まで",
|
||||
"measure.perimeter": "周長",
|
||||
"measure.perimeter_inner": "内周長",
|
||||
"measure.perimeter_outer": "外周長",
|
||||
"measure.quick_copied": "測定値をコピーしました",
|
||||
"measure.quick_copy": "クリックで測定値をコピー",
|
||||
"measure.quick_edges": "エッジ {count} 本",
|
||||
@@ -2281,6 +2335,8 @@
|
||||
"nav.hfss.help": "Alt+左ドラッグでパン、Shift+Alt+左ドラッグでズーム、何もない所からの Ctrl+左ドラッグで回転。",
|
||||
"nav.inventor.help": "中ドラッグでパン、Shift+中ドラッグで回転、Ctrl+中ドラッグでズーム、右ドラッグで回転。",
|
||||
"nav.maya.help": "Alt+左ドラッグで回転、Alt+中ドラッグでパン、Alt+右ドラッグでズーム。中ドラッグでもパン。",
|
||||
"nav.maya_horizontal_zoom.help": "Alt+右ドラッグで右に動かすと拡大、左に動かすと縮小します。オフにすると従来の垂直ドラッグに戻ります。",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: 水平方向のドラッグでズーム",
|
||||
"nav.nx.help": "中ボタンのドラッグで回転、Shift+中ボタンで平行移動(NXの中ボタン+右ボタン)、Ctrl+中ボタンでズーム(NXの中ボタン+左ボタン)。右ボタンのドラッグではカメラは動きません",
|
||||
"nav.openscad.help": "空きスペースで左ドラッグすると回転、Shift+左ドラッグで矩形選択、スケッチ ジオメトリはドラッグで編集。右または中ドラッグでパン、Shift+右または Shift+中ドラッグでズーム。",
|
||||
"nav.orbit_cursor_wrap.help": "回転のドラッグがビューの端に達すると、カーソルが反対側の端へ移り、そのまま回転を続けます。オフ:ドラッグは画面の端で止まります。Wayland とブラウザーでは効果がありません。",
|
||||
@@ -2411,6 +2467,16 @@
|
||||
"not a move": "移動ではありません",
|
||||
"not a number": "数値ではありません",
|
||||
"open a sketch first": "先にスケッチを開いてください",
|
||||
"operations.cancel": "{name} をキャンセル",
|
||||
"operations.cancelled": "{name} をキャンセルしました",
|
||||
"operations.cancelling": "キャンセル中…",
|
||||
"operations.cannot_cancel": "{name} はキャンセルできません",
|
||||
"operations.feature": "フィーチャー",
|
||||
"operations.feature_edit": "フィーチャーを編集",
|
||||
"operations.meshing": "パーツを読み込み中",
|
||||
"operations.queued": "待機中",
|
||||
"operations.stopped": "キャンセル済み",
|
||||
"operations.waiting": "準備完了",
|
||||
"parameters.apply_live": "フィールドを離れるたびに変更を適用",
|
||||
"parameters.apply_live_tip": "オフ: 変更は「適用」または「OK」まで保留され、その後すべてをまとめて一度だけ再構築します。「キャンセル」または Esc で破棄します。",
|
||||
"parameters.held": "{count} 件の変更が適用待ちです",
|
||||
@@ -2499,6 +2565,7 @@
|
||||
"prefs.appearance.viewport_colours": "3D ビューの色",
|
||||
"prefs.appearance.viewport_logo": "ビューポートとロゴ",
|
||||
"prefs.applies_on_restart": "再起動後に適用",
|
||||
"prefs.assemblies": "アセンブリ",
|
||||
"prefs.assistant": "アシスタント",
|
||||
"prefs.assistant_connecting": "接続",
|
||||
"prefs.assistant_follow_help": "スケッチのLook At操作で、ポインターに合わせてビューが移動します。",
|
||||
@@ -2551,6 +2618,10 @@
|
||||
"prefs.choose_font": "フォントファイルを選択…",
|
||||
"prefs.click": "クリック",
|
||||
"prefs.command_dialog_values": "コマンドダイアログ",
|
||||
"prefs.constraint_glyph_size": "拘束グリフのサイズ",
|
||||
"prefs.constraint_glyph_size_note": "スケッチ内の拘束グリフとその文字やアイコンを描く大きさ。100% が通常のサイズです。グリフはどのズームでもこの画面サイズを保ちます。",
|
||||
"prefs.construct_menu_groups": "構築ツールを要素の種類でグループ化",
|
||||
"prefs.construct_menu_groups_help": "平面、軸、点の見出しを表示します。オフにすると元のメニュー順序を維持します。",
|
||||
"prefs.contact_shading": "柔らかな接触陰影",
|
||||
"prefs.contact_shading_note": "部品が近接する部分に柔らかな陰影を付けます。",
|
||||
"prefs.context_menu": "コンテキストメニュー",
|
||||
@@ -2586,6 +2657,8 @@
|
||||
"prefs.design_tools.rows": "行数",
|
||||
"prefs.devices": "3D マウス",
|
||||
"prefs.dialog_buttons": "ダイアログのボタン",
|
||||
"prefs.dialog_first_letter_buttons": "ダイアログのボタンはラベルの先頭文字で押せる",
|
||||
"prefs.dialog_first_letter_buttons_help": "ダイアログが開いているとき、ボタンのラベルの先頭文字を入力するとそのボタンが押されます:「キ」で「キャンセル」など。2 つのボタンに当てはまる文字は何もしません。フォーカス中のテキストフィールドはそのまま入力を受け取ります。オフ:従来どおり、入力ではボタンは押されません。",
|
||||
"prefs.dialogs": "ダイアログ",
|
||||
"prefs.dialogs_edge": "ビューの端",
|
||||
"prefs.dialogs_left_column": "左の列",
|
||||
@@ -2599,12 +2672,23 @@
|
||||
"prefs.dimension_values_window": "ウィンドウ",
|
||||
"prefs.display": "表示",
|
||||
"prefs.edges": "エッジと陰影",
|
||||
"prefs.export": "エクスポート",
|
||||
"prefs.export_name": "エクスポートのファイル名",
|
||||
"prefs.export_name.body": "エクスポートするボディ名(複数ある場合は最初のボディ)",
|
||||
"prefs.export_name.design": "デザイン名",
|
||||
"prefs.export_name_hint": "例: {design}-{body}",
|
||||
"prefs.export_name_sample": "このデザインのエクスポート時の名前: {name}",
|
||||
"prefs.export_name_tip": "ファイル › エクスポートとメッシュとして保存が提案するファイル名です。次のプレースホルダーが置き換えられます:\n{placeholders}\n設定されていないデザインのプロパティは省かれます。空のままにすると、デザイン名(メッシュではボディ名)を提案します。",
|
||||
"prefs.extend": "拡張",
|
||||
"prefs.extra_navigation": "何もない場所でCtrl+左ドラッグすると回転し、Spaceを押しながらドラッグすると移動します。",
|
||||
"prefs.extrude_arrow_face_stops": "押し出し矢印を面で止める",
|
||||
"prefs.extrude_arrow_face_stops_note": "押し出しの距離矢印をドラッグすると、プロファイルに平行な平らな面(カットするブロックの反対側など)で止まり、その面の輪郭を表示します。オフ: 矢印はきりのよい刻みでのみ動きます。",
|
||||
"prefs.extrude_view_isometric": "押し出しを開いたときに等角ビューにする",
|
||||
"prefs.extrude_view_return": "押し出しを閉じたときに元のビューに戻す",
|
||||
"prefs.file_operations_wait": "ファイルを開く間は待つ",
|
||||
"prefs.file_operations_wait_note": "ファイルを開く・挿入する・リンクを読み直す間、デザインは進行状況とキャンセルを示すカードの後ろで待機します。オフ:ファイルは処理パネルに表示され、作業を続けられます。挿入は作業が終わってから反映され、その間に開いたファイルは新しいタブに入ります。",
|
||||
"prefs.fillet_legacy_radius": "以前のフィレット半径の既定値を使う",
|
||||
"prefs.fillet_legacy_radius.help": "既定ではオフです。オンのとき:新しい Solid Fillet は設計の単位として読み取った数値 2(「2 in」)で始まり、以前と同じです。オフのとき:そのツールが標準で持つ半径 2 mm を設計の単位に換算した値(「0.07874 in」)で始まります。",
|
||||
"prefs.follows_os": "OS の設定に従う",
|
||||
"prefs.font": "フォント",
|
||||
"prefs.font_fallback": "選択したフォントにない文字は組み込みフォントで表示し、ラベルが空の四角になるのを防ぎます。",
|
||||
@@ -2628,6 +2712,17 @@
|
||||
"prefs.gesture_pan": "移動",
|
||||
"prefs.gesture_zoom": "ズーム",
|
||||
"prefs.graphics": "グラフィックス",
|
||||
"prefs.graphics_api": "グラフィックスAPI",
|
||||
"prefs.graphics_api_auto": "自動",
|
||||
"prefs.graphics_api_help": "SolidCraftの起動に使用するグラフィックスAPIを選択します。次回起動時にウィンドウを開けなかった場合は、以前の選択に戻ります。",
|
||||
"prefs.graphics_api_override": "起動時の上書き設定がグラフィックスAPIを指定しています。SolidCraftを通常どおり開くと、保存した選択が適用されます。",
|
||||
"prefs.graphics_api_restart_note": "再起動後に適用されます。閉じる前に未保存のデザインを確認します。",
|
||||
"prefs.graphics_api_restart_unavailable": "保存したグラフィックスAPIを適用するには、SolidCraftを再起動してください。",
|
||||
"prefs.graphics_api_running": "現在: {current}。次回起動時の選択: {selected}。",
|
||||
"prefs.graphics_api_save_failed": "グラフィックスAPIの選択を保存できませんでした: {error}",
|
||||
"prefs.graphics_api_start_failed": "選択したグラフィックスAPIを準備できませんでした: {error}",
|
||||
"prefs.graphics_api_start_reverted": "前回は{requested}でウィンドウを開けませんでした。SolidCraftは{previous}に戻しました。",
|
||||
"prefs.graphics_api_unavailable": "グラフィックスAPIの選択はデスクトップアプリで利用できます。",
|
||||
"prefs.graphics_card": "グラフィックスカード",
|
||||
"prefs.graphics_card_auto": "自動",
|
||||
"prefs.graphics_card_missing": "保存されたグラフィックスカードが利用できないため、自動選択を使用します。",
|
||||
@@ -2671,6 +2766,8 @@
|
||||
"prefs.history_sketches_in_order": "作成順",
|
||||
"prefs.history_sketches_note": "スケッチ:「フィーチャーの下」では、左側の履歴に名前が表示される幅があるとき、スケッチをそれから作成した最初のフィーチャーの下に 1 段字下げして表示します。下部のタイムラインは常に作成順です。",
|
||||
"prefs.history_sketches_under_feature": "フィーチャーの下",
|
||||
"prefs.history_steps_component": "コンポーネント単位で履歴を移動",
|
||||
"prefs.history_steps_component_note": "コンポーネントがアクティブまたは選択されているとき、履歴コントロールは下部の履歴に表示されるとおり、そのコンポーネントのフィーチャだけを移動します。オフにすると、デザインのすべてのフィーチャを移動します。左側またはブラウザー下の履歴は常にすべてのフィーチャを移動します。",
|
||||
"prefs.hold_stop_snapping": "押している間スナップを解除",
|
||||
"prefs.home_fit_size": "ホームと全体表示の大きさ",
|
||||
"prefs.home_fit_size_note": "ホーム、全体表示、開いたデザイン、ナビゲーターでの視点変更がモデルを画面に収めるときに、モデルがビューに占める割合。下の設定のオン・オフにかかわらず適用されます。100 %: パネル、コンパス、ナビゲーションバーの間のビューをいっぱいに使います。",
|
||||
@@ -2686,6 +2783,8 @@
|
||||
"prefs.invert_curved_roll_arrows_note": "キューブの隅にある2つのカーブした矢印は、画面内でビューをロールします。オン: 時計回りの矢印が反時計回りに、反時計回りの矢印が時計回りにロールします。オフ: 各矢印は、そのカーブの向きにビューをロールします。",
|
||||
"prefs.invert_navigator_arrows": "ビューキューブの回転矢印を反転",
|
||||
"prefs.invert_navigator_arrows_note": "キューブの周りの矢印が、矢印の指す方向にカメラを回します(Fusion や Inventor と同じ動き):左の矢印は右を指し、カメラを右に振ります。オフ: 矢印は、そのある面の方へキューブを回すため、左の矢印はカメラを左に振ります。カーブしたロール矢印は影響を受けません。",
|
||||
"prefs.joint_drag_trackball": "ボールジョイントの部品をドラッグするとトラックボールのように回転",
|
||||
"prefs.joint_drag_trackball_help": "ボールジョイントで保持された部品をドラッグすると、部品の大きさのボールを転がすように、ジョイントを中心に最小の回転で回ります。オフ:つかんだ点がポインターに正確に追従し、部品がその点を軸にさらに回転することがあります。",
|
||||
"prefs.keep_unsaved_also_asks": "タブを閉じるときにも確認する",
|
||||
"prefs.keep_unsaved_also_asks_tip": "オフにすると、未保存の各デザインのコピーが最新であれば、ブラウザーの確認なしでタブが閉じます。",
|
||||
"prefs.keep_unsaved_in_browser": "未保存の作業をこのブラウザーに保持する",
|
||||
@@ -2761,6 +2860,8 @@
|
||||
"prefs.not_on_gpu": "この GPU は非対応",
|
||||
"prefs.on": "オン",
|
||||
"prefs.opaque": "不透明",
|
||||
"prefs.operations_panel": "ビューに処理を表示",
|
||||
"prefs.operations_panel_note": "時間のかかる処理(ファイルを開く、フィーチャーの計算、エージェントのコマンド)が、進行状況とキャンセルボタンとともにビューの右下に表示されます。オフ:従来どおり「計算中」の通知を表示します。",
|
||||
"prefs.orbit_snap": "回転中にShiftを押すと軸にスナップします。",
|
||||
"prefs.orientation": "方向",
|
||||
"prefs.origin_plane_names": "原点平面の名前",
|
||||
@@ -2841,6 +2942,8 @@
|
||||
"prefs.ribbon_tabs_only": "リボンのタブだけを表示",
|
||||
"prefs.ribbon_tabs_only_note": "リボンをタブの行だけに折りたたみます。タブをクリックすると、コマンドが始まるかポインターが離れるまで、そのパネルがビューの上に表示されます。表示タブの「リボンのタブのみ」またはそのショートカットで切り替えます。",
|
||||
"prefs.right_click": "右クリック",
|
||||
"prefs.save_prompt_one_at_a_time": "複数を閉じるとき、未保存のデザインごとに確認する",
|
||||
"prefs.save_prompt_one_at_a_time_help": "一覧でまとめて確認する代わりに、未保存のデザインごとに保存を確認します。",
|
||||
"prefs.saving": "起動と保存",
|
||||
"prefs.scale_note": "ウィンドウ内では Ctrl + / Ctrl − でも変更できます。100% のボタンは 28 px です。",
|
||||
"prefs.scale_text": "拡大率と文字",
|
||||
@@ -2877,6 +2980,8 @@
|
||||
"prefs.sketch.center_arc": "中心点指定の円弧がカーソルに追従",
|
||||
"prefs.sketch.click_selects": "クリックで選択",
|
||||
"prefs.sketch.conflict_colour": "競合色",
|
||||
"prefs.sketch.cursor_coordinates": "スケッチでカーソル座標を表示",
|
||||
"prefs.sketch.cursor_coordinates_note": "ツールを実行していないときも、ポインターの横にスケッチ原点からの X と Y を表示します。オフ: ツールで点を配置している間だけ表示します。",
|
||||
"prefs.sketch.drawing": "作図",
|
||||
"prefs.sketch.ellipse_axes": "楕円を軸と一緒に描く",
|
||||
"prefs.sketch.ellipse_axes_note": "長軸と短軸をコンストラクション線として描き、半軸と軸に寸法を付けられるようにします。オフ: 楕円のみを描き、D で短半径を寸法にします。値をどこへ引いても、これまでどおり R 付きで描かれます。",
|
||||
@@ -2888,14 +2993,20 @@
|
||||
"prefs.sketch.faces_edges": "面とエッジ",
|
||||
"prefs.sketch.hide_glyphs": "ズームアウト時に記号を非表示",
|
||||
"prefs.sketch.marks": "スケッチ内のマーク",
|
||||
"prefs.sketch.max_points": "最大スケッチ",
|
||||
"prefs.sketch.max_points_note": "1 つのスケッチに入る点または曲線の最大数です。既定は 20000、上限は 200000 です。SVG を挿入と DXF を挿入は、これより大きい図面を受け付けません。大きなスケッチは解決と描画が遅くなります。",
|
||||
"prefs.sketch.max_points_unit": "点",
|
||||
"prefs.sketch.note": "作図、スナップ、選択。",
|
||||
"prefs.sketch.opening_closing": "開始と終了",
|
||||
"prefs.sketch.prefer_free_points": "重なる場合は移動可能な点を優先",
|
||||
"prefs.sketch.project_options": "投影オプションを先に確認",
|
||||
"prefs.sketch.recent_snap": "2本のガイドの交点にスナップ",
|
||||
"prefs.sketch.select_3d_curve_points": "3Dスケッチ曲線の点を選択",
|
||||
"prefs.sketch.select_3d_curve_points_help": "描画した3Dスケッチ曲線の点を表示し、構築要素の参照として選択します。",
|
||||
"prefs.sketch.select_other_hidden": "他を選択で非表示のジオメトリも対象に",
|
||||
"prefs.sketch.shortcut_cycles_modes": "ショートカットの再入力でモード切替",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "オフの場合はツールを再起動します。",
|
||||
"prefs.sketch.snap_to_visible_grid": "グリッドの交点にスナップ",
|
||||
"prefs.sketch.snapping_guides": "スナップとガイド",
|
||||
"prefs.sketch.state_icons": "状態アイコン",
|
||||
"prefs.sketch.tracking_guides": "中心と中点のガイド",
|
||||
@@ -2923,6 +3034,7 @@
|
||||
"prefs.sketch_selection": "スケッチと選択",
|
||||
"prefs.sketch_selection_heading": "スケッチと選択",
|
||||
"prefs.sketch_selection_note": "スケッチのスナップとクリックによる選択。",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "スケッチ内の点は、グリッドが描画する線の交点にポインターが指しているときはその交点にスナップし、それ以外ではその間のより細かい格子の交点にスナップします。オフ: 前也是一样で、点はより細かい格子の交点にだけスナップします。",
|
||||
"prefs.sketch_state_icons": "スケッチアイコンを状態の色で表示",
|
||||
"prefs.sketch_state_icons_note": "履歴とブラウザーで、スケッチのアイコンがその状態(拘束不足、完全拘束、競合)の色になり、ツールチップに状態が表示されます。オフ: すべてのスケッチが同じアイコンになります。",
|
||||
"prefs.sketch_tab_always": "スケッチ タブを常に表示",
|
||||
@@ -3624,6 +3736,7 @@
|
||||
"render.error_pbr_opacity": "不透明PBRには不透明度1が必要です",
|
||||
"render.error_physical_glass": "選択したレシピは物理ガラスではありません",
|
||||
"render.error_preview_device": "製品プレビューには深度バッファーを備えたデバイスが必要です",
|
||||
"render.error_product_placement": "製品の配置が無効です",
|
||||
"render.error_product_triangle": "製品の三角形が無効です",
|
||||
"render.error_provisional_identity": "仮レンダリングの識別情報またはサンプル数が無効です",
|
||||
"render.error_quality_bounds": "品質設定の反映がネイティブ上限を超えています",
|
||||
@@ -3707,6 +3820,10 @@
|
||||
"render.gpu_path_retry": "もう一度試す",
|
||||
"render.gpu_seed": "乱数シード",
|
||||
"render.gpu_unavailable": "このデバイスでは GPU パストレーシングの準備ができていません。",
|
||||
"render.graphics_api_restart_vulkan": "Vulkanで再起動",
|
||||
"render.graphics_api_restart_warning": "グラフィックスAPIを変更するとSolidCraftが再起動し、未保存のデザインの保存を確認します。新しいAPIでウィンドウを開けない場合は、次回起動時に以前の選択に戻ります。",
|
||||
"render.graphics_api_settings": "グラフィックス設定",
|
||||
"render.graphics_api_vulkan_required": "このセッションでGPUパストレーシングを使用するにはVulkanが必要です。Vulkanで再起動するか、CPUの画像方式を引き続き使用してください。",
|
||||
"render.ground_apply": "床をフィットして保存",
|
||||
"render.ground_gap": "明示的なクリアランス",
|
||||
"render.ground_linear_rgb": "拡散反射率・線形RGB",
|
||||
@@ -4708,6 +4825,8 @@
|
||||
"sketch.hint.spline3d": "3D Spline: click fit points in 3D; right-click or Esc to finish",
|
||||
"sketch.hint.trim": "Trim: click the piece of a curve to remove, or drag across the pieces to remove",
|
||||
"sketch.make_selection": "選択を{linetype}にする",
|
||||
"sketch.move_released": "移動しました: 残る要素とつないでいた拘束 {count} 個を解除しました ({names})。",
|
||||
"sketch.move_released_one": "移動しました: 残る要素とつないでいた拘束 {count} 個を解除しました ({names})。",
|
||||
"sketch.open_ends": "開放 {count}",
|
||||
"sketch.status_conflict": "拘束が競合しています",
|
||||
"sketch.status_fully_constrained": "完全拘束",
|
||||
@@ -4738,6 +4857,10 @@
|
||||
"sketch_text.path_clear": "文字を曲線から外す",
|
||||
"sketch_text.path_hint": "文字が沿うスケッチの曲線: ここをクリックしてから曲線をクリック",
|
||||
"sketch_text.use_font_file": "フォント ファイル {path} を使用",
|
||||
"sketch_text.valign_baseline": "ベースライン",
|
||||
"sketch_text.valign_bottom": "下",
|
||||
"sketch_text.valign_middle": "中央",
|
||||
"sketch_text.valign_top": "上",
|
||||
"solid": "中実",
|
||||
"status.editing": "編集中: {name}",
|
||||
"status.navigation": "マウスの割り当て: {mapping}",
|
||||
@@ -4938,6 +5061,7 @@
|
||||
"ui.agent_chat_allow_once": "今回のみ許可",
|
||||
"ui.agent_chat_allowed": "許可しました",
|
||||
"ui.agent_chat_answered": "回答: {option}",
|
||||
"ui.agent_chat_answered_in": "{time}で回答",
|
||||
"ui.agent_chat_approval": "エージェントにこの操作を許可しますか?",
|
||||
"ui.agent_chat_attach_selection": "選択を添付",
|
||||
"ui.agent_chat_attach_selection_tip": "モデルで選択中のもの(面、エッジ、フィーチャ、ボディ)をメッセージと一緒に送り、何を指しているかをエージェントに伝えます",
|
||||
@@ -4966,6 +5090,7 @@
|
||||
"ui.agent_chat_ctx_bodies": "ボディ",
|
||||
"ui.agent_chat_ctx_elements": "要素",
|
||||
"ui.agent_chat_ctx_features": "フィーチャ",
|
||||
"ui.agent_chat_ctx_gone": "デザインにはもうありません(変更または削除されました)。",
|
||||
"ui.agent_chat_ctx_more": "ほか{n}件",
|
||||
"ui.agent_chat_ctx_other": "その他",
|
||||
"ui.agent_chat_custom_heading": "カスタムモデル",
|
||||
@@ -4979,6 +5104,7 @@
|
||||
"ui.agent_chat_dock_right": "右にドッキング",
|
||||
"ui.agent_chat_drop_hint": "ドロップして次のメッセージに添付",
|
||||
"ui.agent_chat_edit": "編集",
|
||||
"ui.agent_chat_ended_after": "{time}後に終了",
|
||||
"ui.agent_chat_exited": "エージェントが停止しました。",
|
||||
"ui.agent_chat_failed_start": "エージェントを起動できませんでした: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: CAD ファイルは読み込まず、デザインにインポートします",
|
||||
@@ -5016,6 +5142,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model} は SolidCraft のツールを使えず、チャットのみ可能です。ツール対応のモデルを選んでください。",
|
||||
"ui.agent_chat_model_rejected": "エージェントは {model} を受け付けませんでした: {error}",
|
||||
"ui.agent_chat_model_search": "モデルを検索…",
|
||||
"ui.agent_chat_model_search_or_id": "検索、または任意のモデル ID を入力…",
|
||||
"ui.agent_chat_model_tip": "エージェントが使うモデル。選択はこのエージェントに対して記憶されます。",
|
||||
"ui.agent_chat_models_failed": "モデルを一覧表示できませんでした: {error}",
|
||||
"ui.agent_chat_models_heading": "利用可能なモデル",
|
||||
@@ -5027,6 +5154,7 @@
|
||||
"ui.agent_chat_next_picture": "次の画像",
|
||||
"ui.agent_chat_no_cli": "アプリの隣に solidcraft-cli が見つからないため、エージェントはデザインにアクセスできません。",
|
||||
"ui.agent_chat_no_control": "エージェントチャットのエンドポイントが起動しなかったため、エージェントはデザインにアクセスできません。",
|
||||
"ui.agent_chat_no_design_hint": "エージェントは SolidCraft のツールなしで動作しているため、デザインを読み取ることも変更することもできません。アプリの隣に solidcraft-cli が見つかりませんでした。solidcraft-cli が同梱された SolidCraft をインストールするか(Windows では MSI またはポータブル zip)、SOLIDCRAFT_CLI にそのパスを設定してから、もう一度接続してください。",
|
||||
"ui.agent_chat_no_images": "このエージェントは画像を受け付けません",
|
||||
"ui.agent_chat_no_picture": "クリップボードに画像がありません",
|
||||
"ui.agent_chat_no_tool_call": "モデルが SolidCraft のツールを使わなかったため、デザインは変更されませんでした。ツール呼び出しに対応したモデルを選んでください。エージェントチャットのガイドの「ローカルモデル」を参照してください。",
|
||||
@@ -5041,7 +5169,7 @@
|
||||
"ui.agent_chat_permission": "エージェントが実行の許可を求めています: {title}",
|
||||
"ui.agent_chat_pick": "エージェント",
|
||||
"ui.agent_chat_pick_context": "コンテキストを選ぶ",
|
||||
"ui.agent_chat_pick_context_tip": "エージェントに見てほしい面、エッジ、フィーチャ、ボディをモデルから選び、OK を押します",
|
||||
"ui.agent_chat_pick_context_tip": "モデルの面、エッジ、フィーチャ、ボディを選んで OK を押すと、カーソルの位置にピルとしてメッセージに入ります(@ を入力しても同じです)",
|
||||
"ui.agent_chat_placeholder": "デザインの変更をエージェントに依頼…",
|
||||
"ui.agent_chat_placeholder_busy": "エージェントの作業が終わったら送るメッセージを入力(Ctrl+Enter: 今すぐ送信)",
|
||||
"ui.agent_chat_pop_out": "独立したウィンドウで開く(別の画面に移動できます)",
|
||||
@@ -5073,16 +5201,26 @@
|
||||
"ui.agent_chat_setup_title": "アシスタントを設定",
|
||||
"ui.agent_chat_side": "チャットをドッキング",
|
||||
"ui.agent_chat_signed_in": "サインイン済み",
|
||||
"ui.agent_chat_snap_none_found": "コーディングエージェントが見つかりません。Snap パッケージは制限された環境で動作するため、このコンピューターにインストールされたコーディングエージェントを認識することも起動することもできません。それらを使うには、代わりに AppImage、.deb または .rpm パッケージから SolidCraft をインストールしてください。OpenAI 互換 API を使うエージェントは Snap パッケージでも動作します。「エージェントを追加」から設定してください。",
|
||||
"ui.agent_chat_span_h": "{h} 時間 {min} 分",
|
||||
"ui.agent_chat_span_min": "{n} 分",
|
||||
"ui.agent_chat_span_s": "{n} 秒",
|
||||
"ui.agent_chat_state_auth": "サインインが必要",
|
||||
"ui.agent_chat_state_busy": "作業中…",
|
||||
"ui.agent_chat_state_exited": "エージェント停止",
|
||||
"ui.agent_chat_state_failed": "接続に失敗しました",
|
||||
"ui.agent_chat_state_no_design": "デザインにアクセスできません",
|
||||
"ui.agent_chat_state_off": "未接続",
|
||||
"ui.agent_chat_state_ready": "準備完了",
|
||||
"ui.agent_chat_state_starting": "起動中…",
|
||||
"ui.agent_chat_stop": "停止",
|
||||
"ui.agent_chat_stop_tip": "エージェントと、それが起動したものをすべて停止します",
|
||||
"ui.agent_chat_stop_turn_tip": "エージェントを停止します(Esc)。待機中のメッセージは待機のままです。",
|
||||
"ui.agent_chat_thinking_for": "{time}考え中",
|
||||
"ui.agent_chat_tool_running_for": "実行中 ({time})",
|
||||
"ui.agent_chat_tools_not_started": "エージェントは SolidCraft のツールなしで動作しているため、デザインを読み取ることも変更することもできません。solidcraft-cli は見つかりましたが、そのツールが起動しませんでした(理由はチャットのエラーに表示されています)。もう一度接続してください。繰り返し起きる場合は SolidCraft を再インストールしてください。",
|
||||
"ui.agent_chat_transcript_assistant": "アシスタント:",
|
||||
"ui.agent_chat_transcript_user": "ユーザー:",
|
||||
"ui.agent_chat_turn_limit": "1メッセージあたりの変更数",
|
||||
"ui.agent_chat_turn_unlimited": "無制限",
|
||||
"ui.agent_chat_undo_changes": "これらの変更を元に戻す",
|
||||
@@ -5239,7 +5377,9 @@
|
||||
"ui.browser_bodies_one": "{count} ボディ",
|
||||
"ui.browser_bodies_other": "{count} ボディ",
|
||||
"ui.browser_collapse": "ブラウザを折りたたむ",
|
||||
"ui.browser_collapse_below": "この下を折りたたむ",
|
||||
"ui.browser_expand": "ブラウザを展開",
|
||||
"ui.browser_expand_below": "この下を展開",
|
||||
"ui.browser_title": "ブラウザ",
|
||||
"ui.calibrate": "校正",
|
||||
"ui.cancel": "キャンセル",
|
||||
@@ -5269,6 +5409,7 @@
|
||||
"ui.collapse": "折りたたむ",
|
||||
"ui.collinear": "同一直線上",
|
||||
"ui.colour_vision": "色覚",
|
||||
"ui.colour_vision_bends": "曲げ",
|
||||
"ui.colour_vision_deutan": "2型色覚(D型)",
|
||||
"ui.colour_vision_deutan_tip": "緑を感じにくい、または感じない場合に",
|
||||
"ui.colour_vision_failed": "エラー",
|
||||
@@ -5298,14 +5439,24 @@
|
||||
"ui.conic_curve": "円錐曲線",
|
||||
"ui.constant": "一定",
|
||||
"ui.constraints_conflict": "拘束が競合しています",
|
||||
"ui.construct_auto.chosen": "選択から方法を選びました。参照を追加または削除すると方法が変わります。",
|
||||
"ui.construct_auto.no_fit": "別の参照を選択してください。これらから作れる方法がありません。",
|
||||
"ui.construct_auto.pick": "作成元を選択してください。方法は選択から決まります。",
|
||||
"ui.construct_auto.refs": "参照",
|
||||
"ui.construct_auto.select": "先に作成元の参照を選択してください",
|
||||
"ui.construct_axes": "軸",
|
||||
"ui.construct_planes": "平面",
|
||||
"ui.construct_points": "点",
|
||||
"ui.construction": "コンストラクション",
|
||||
"ui.construction.angle_hint": "補助直線: 点をクリックし、角度を入力するか方向を選択",
|
||||
"ui.construction.axis_hint": "補助直線: 点をクリックするか、スケッチ軸からの距離を入力",
|
||||
"ui.construction.bisector_hint": "二等分線: 交差する2直線を選び、必要な解を選択",
|
||||
"ui.construction.common_hint": "共通接線: 2つの円/円弧を選び、必要な解を選択",
|
||||
"ui.construction.contact_hint": "接線: 円/円弧または開いたスプライン/円錐曲線を選び、接点を選択 (自由曲線は端点のみ)",
|
||||
"ui.construction.external_hint": "接線: 円または円弧、外部点、必要な解の順に選択",
|
||||
"ui.construction.free_hint": "補助直線: 2点をクリック。右クリックで最初から",
|
||||
"ui.construction.normal_needs_length": "無限直線は常に補助線です。通常の線を描くには長さを入力",
|
||||
"ui.construction.parallel_hint": "補助直線: 直線を選択し、クリックするかオフセットを入力。右クリックで参照を変更",
|
||||
"ui.construction.point_hint": "補助直線: 通過点をクリック",
|
||||
"ui.construction.reference_hint": "補助直線: 直線、点の順に選択。右クリックで参照を変更",
|
||||
"ui.construction.ribbon_label": "補助線",
|
||||
@@ -5448,6 +5599,17 @@
|
||||
"ui.ellipse": "楕円",
|
||||
"ui.emboss_wrap_note": "サポートされる円柱に接する直交線のプロファイルは自動的に巻き付けられます。対象を選ぶには壁を選択してください。",
|
||||
"ui.end": "終端",
|
||||
"ui.end_cap.chamfer": "角の面取り",
|
||||
"ui.end_cap.direction": "方向",
|
||||
"ui.end_cap.faces": "端面",
|
||||
"ui.end_cap.inset": "内側オフセット",
|
||||
"ui.end_cap.inset_kind": "オフセットの指定",
|
||||
"ui.end_cap.inset_ratio": "オフセット比",
|
||||
"ui.end_cap.inward": "内向き",
|
||||
"ui.end_cap.length": "長さ",
|
||||
"ui.end_cap.outward": "外向き",
|
||||
"ui.end_cap.ratio": "厚さに対する比",
|
||||
"ui.end_cap_title": "エンドキャップ",
|
||||
"ui.end_radius": "終了半径",
|
||||
"ui.end_scale": "終端スケール",
|
||||
"ui.ends": "端部",
|
||||
@@ -5468,7 +5630,10 @@
|
||||
"ui.explode_needs_two_components": "分解図はコンポーネント同士を引き離すため、デザインに 2 つ以上のコンポーネントが必要です(新規コンポーネント、デザインを挿入、またはボディからコンポーネントを作成)",
|
||||
"ui.exportDxf": "DXF をエクスポート…",
|
||||
"ui.export_ellipsis_keymap": "エクスポート…",
|
||||
"ui.export_glb": "GLB をエクスポート",
|
||||
"ui.export_keymap_tip": "ショートカット、Sボックスのお気に入り、ツールバー設定をファイルに保存",
|
||||
"ui.export_selects_only_body": "メッシュのエクスポート時に唯一のボディを選択する",
|
||||
"ui.export_selects_only_body_tip": "デザインのボディが 1 つだけのとき、STL をエクスポート、3MF をエクスポート、スライサーに送るはそのボディを選択した状態で始まります。",
|
||||
"ui.extend": "延長",
|
||||
"ui.extent": "範囲",
|
||||
"ui.extent_type": "範囲タイプ",
|
||||
@@ -5528,6 +5693,8 @@
|
||||
"ui.finest": "最も細かい",
|
||||
"ui.finish_sketch": "スケッチを終了",
|
||||
"ui.first_dimension_scales": "最初の寸法で図形全体をスケールする",
|
||||
"ui.first_dimension_scales_about_origin": "スケッチ原点を中心にスケールする",
|
||||
"ui.first_dimension_scales_about_origin_tip": "オン: 図形は常にスケッチ原点を中心に拡大・縮小されるため、原点から離れて描いた図形は移動します。オフ: 原点に拘束されていない図形は自身の中心を基準にスケールし、描いた位置に留まります。",
|
||||
"ui.first_dimension_scales_tip": "オン: スケッチの最初の長さ寸法で、測定する図形全体をスケールし、形を保ちます。オフ: 寸法は測定する対象のサイズだけを変えます。",
|
||||
"ui.fit": "フィット",
|
||||
"ui.fix_unfix": "固定/固定解除",
|
||||
@@ -5950,6 +6117,7 @@
|
||||
"ui.project_references_construction_note": "投影、交差、3D ジオメトリを含める、および面上の新規スケッチの面のエッジは、コンストラクションジオメトリになります。描画の参照用で、プロファイルには含まれません。モデルとのリンクは保たれます。",
|
||||
"ui.properties": "プロパティ",
|
||||
"ui.properties.copy_matrix": "行列をコピー",
|
||||
"ui.properties.copy_value": "クリックでコピー",
|
||||
"ui.properties.first_moments": "一次モーメント",
|
||||
"ui.properties.inertia": "慣性モーメント",
|
||||
"ui.properties.inertia_note": "重心まわり、ワールド軸 (g·{unit}²)",
|
||||
@@ -5962,6 +6130,7 @@
|
||||
"ui.properties.measuring_failed": "測定が完了する前に停止しました。",
|
||||
"ui.properties.principal_axis": "主軸 {number}",
|
||||
"ui.properties.principal_moments": "主慣性モーメント",
|
||||
"ui.properties.value_copied": "値をコピーしました",
|
||||
"ui.pull_direction": "抜き方向",
|
||||
"ui.quality": "品質",
|
||||
"ui.quantity": "数量",
|
||||
@@ -5982,11 +6151,14 @@
|
||||
"ui.relink_design_changed": "参照元の選択中にアセンブリが変更されました。再リンクをやり直してください。",
|
||||
"ui.relink_done": "すべてのインスタンスの参照元を再リンクしました。",
|
||||
"ui.relink_not_linked": "このコンポーネントは参照元の設計にリンクされていません。",
|
||||
"ui.relink_one_done": "このインスタンスの参照元を再リンクしました。",
|
||||
"ui.relink_select_one": "リンクされたコンポーネントまたはそのインスタンスを1つ選択してください。",
|
||||
"ui.relink_source_all": "参照元を再リンク(すべてのインスタンス)…",
|
||||
"ui.relink_source_one": "参照元を再リンク…",
|
||||
"ui.removeFromQuickAccess": "クイックアクセスから削除",
|
||||
"ui.removeFromToolbar": "ツールバーから削除",
|
||||
"ui.removeSection": "セクションを解除",
|
||||
"ui.renameSelectedBodies": "選択したボディの名前を変更",
|
||||
"ui.render": "レンダリング",
|
||||
"ui.renderer": "レンダラー",
|
||||
"ui.repeat": "繰り返し",
|
||||
@@ -6017,6 +6189,8 @@
|
||||
"ui.ribbon_pin_footer": "ピン留めしたコマンドはリボンに表示されます。行にポインターを合わせて、ピン留めや解除ができます。",
|
||||
"ui.ribbon_workspace": "ワークスペース",
|
||||
"ui.right": "右側面",
|
||||
"ui.right_click_confirms": "右クリックでダイアログの入力を確定",
|
||||
"ui.right_click_confirms_tip": "ダイアログが開いているとき、ビューで右クリックすると次の空の入力へ進み、最後の入力では OK を実行します",
|
||||
"ui.save": "保存",
|
||||
"ui.save_as": "名前を付けて保存",
|
||||
"ui.save_mesh_no_slicer_open": "スライサーが見つかりません。「カスタム…」でスライサーのプログラムを選んでください",
|
||||
@@ -6076,6 +6250,16 @@
|
||||
"ui.sketch_intersect_selection_filter": "選択フィルター",
|
||||
"ui.sketch_keys_only": "スケッチ中はモデルのキーを使わない",
|
||||
"ui.sketch_keys_only_tip": "スケッチの編集中は、スケッチのキーとどこでも使えるキーだけが働きます。E や F などのモデルのキーは何もしないので、うっかり押したキーで重いスケッチが閉じることはありません。",
|
||||
"ui.sketch_links_added_curve": "{command} でスケッチに曲線を 1 本追加しました。",
|
||||
"ui.sketch_links_added_curves": "{command} でスケッチに曲線を {count} 本追加しました。",
|
||||
"ui.sketch_links_added_curves_and_points": "{command} でスケッチに{curves}と{points}を追加しました。",
|
||||
"ui.sketch_links_added_point": "{command} でスケッチに点を 1 個追加しました。",
|
||||
"ui.sketch_links_added_points": "{command} でスケッチに点を {count} 個追加しました。",
|
||||
"ui.sketch_links_curve_count": "曲線 {count} 本",
|
||||
"ui.sketch_links_curve_count_one": "曲線 1 本",
|
||||
"ui.sketch_links_hidden": "スケッチオプションの {option} がオフのため、結果は表示されていません。",
|
||||
"ui.sketch_links_point_count": "点 {count} 個",
|
||||
"ui.sketch_links_point_count_one": "点 1 個",
|
||||
"ui.sketch_modifiers": "スケッチ修飾キー",
|
||||
"ui.sketch_project_geometry": "ジオメトリ",
|
||||
"ui.sketch_report.all_constrained": "すべて完全に拘束されています。",
|
||||
@@ -6115,6 +6299,7 @@
|
||||
"ui.step_values": "矢印キーとホイールで値を変更",
|
||||
"ui.step_values_tip": "値入力欄の上で上下矢印キーやホイールを使うと数値が変わります。",
|
||||
"ui.stitch_tolerance_hint": "厳密",
|
||||
"ui.straighten": "傾き補正",
|
||||
"ui.stretch": "伸縮",
|
||||
"ui.supersampling": "スーパーサンプリング (SSAA)",
|
||||
"ui.supersampling_adaptive": "ビューが静止しているときのみ",
|
||||
@@ -6188,6 +6373,8 @@
|
||||
"ui.view_angles_yaw": "ヨー",
|
||||
"ui.view_angles_zero": "{axis}を0°に設定",
|
||||
"ui.view_centre": "ビュー中心",
|
||||
"ui.view_compass_tip": "{axis}方向から表示します。もう一度クリックすると反転します。ドラッグでオービットします。",
|
||||
"ui.view_compass_tip_snap": "{axis}方向から表示します。もう一度クリックすると反転します。ドラッグでオービットし、Shiftを押すとスナップします。",
|
||||
"ui.viewport_status_clear": "{name}をオフにする",
|
||||
"ui.viewport_status_clear_hint": "{name}をオフにする · Esc",
|
||||
"ui.viewport_status_edges": "{count} エッジ",
|
||||
|
||||
@@ -699,6 +699,7 @@
|
||||
"Value": "მნიშვნელობა",
|
||||
"Variable Radius": "ცვლადი რადიუსი",
|
||||
"Velocity": "სიჩქარე",
|
||||
"Vertical": "ვერტიკალური",
|
||||
"Vertices": "წვეროები",
|
||||
"View navigator": "ხედის ნავიგატორი",
|
||||
"Volume": "მოცულობა",
|
||||
@@ -4028,6 +4029,10 @@
|
||||
"sketch_text.path_clear": "ტექსტის მოხსნა მრუდიდან",
|
||||
"sketch_text.path_hint": "ესკიზის მრუდი, რომელსაც ტექსტი მიჰყვება: დაწკაპეთ აქ, შემდეგ მრუდზე",
|
||||
"sketch_text.use_font_file": "შრიფტის ფაილის {path} გამოყენება",
|
||||
"sketch_text.valign_baseline": "საბაზისო ხაზი",
|
||||
"sketch_text.valign_bottom": "ქვემოთ",
|
||||
"sketch_text.valign_middle": "შუა",
|
||||
"sketch_text.valign_top": "ზემოთ",
|
||||
"solid": "სხეული",
|
||||
"status.editing": "რედაქტირდება {name}",
|
||||
"status.navigation": "მაუსის მინიჭება: {mapping}",
|
||||
|
||||
@@ -188,6 +188,7 @@
|
||||
"Double-click to rename": "두 번 클릭하여 이름 변경",
|
||||
"Double-clicking the middle button in the view: Home (the home view, framing what is shown), Fit (frame what is shown, keeping the orientation) or nothing": "뷰에서 가운데 버튼을 더블 클릭: 홈(홈 뷰, 표시된 항목에 맞춤), 맞춤(방향을 유지하며 표시된 항목에 맞춤) 또는 없음",
|
||||
"Drag to move the hole; click to remove it": "드래그하면 구멍이 이동하고, 클릭하면 제거됩니다",
|
||||
"Drag to place it on another face.": "드래그하여 다른 면에 배치합니다.",
|
||||
"Drive Joint": "조인트 구동",
|
||||
"Duration": "지속 시간",
|
||||
"Each new shape is also dimensioned from the sketch origin until nothing of it is left free. A shape already attached to the origin or to placed geometry gets none.": "새 도형마다 자유로운 부분이 없어질 때까지 스케치 원점 기준 치수도 지정됩니다. 원점이나 배치된 형상에 이미 연결된 도형은 지정되지 않습니다.",
|
||||
@@ -676,6 +677,7 @@
|
||||
"Value": "값",
|
||||
"Variable Radius": "가변 반지름",
|
||||
"Velocity": "속도",
|
||||
"Vertical": "수직",
|
||||
"Vertices": "꼭짓점",
|
||||
"View navigator": "뷰 탐색기",
|
||||
"Volume": "체적",
|
||||
@@ -726,6 +728,13 @@
|
||||
"ai.prefs.connect_apps": "AI 앱에 SolidCraft 추가",
|
||||
"ai.prefs.connect_apps_note": "끄면 추가한 항목이 다시 제거됩니다.\n\nSolidCraft 시작 시 이 컴퓨터에서 찾은 AI 앱(OpenCode, Claude Desktop, Claude Code, Cursor, Codex, Gemini CLI, Copilot CLI, Windsurf, Zed, VS Code)에 MCP 서버로 추가합니다. solidcraft 항목만 추가하거나 경로를 갱신하며, 사용자가 변경한 항목은 그대로 두고 파일을 먼저 백업합니다. 끄면 추가했던 항목을 제거합니다. 도움말 > AI 어시스턴트 연결…에서 수동으로 실행할 수도 있습니다.",
|
||||
"ai.prefs.connect_at_start": "시작할 때 마지막 에이전트 연결",
|
||||
"ai.prefs.control_failed": "제어 채널을 시작할 수 없습니다: {error}",
|
||||
"ai.prefs.control_from_launch": "이번 실행은 --control로 포트 {port}에서 시작되었습니다. 여기서 바꾼 내용은 다음에 --control 없이 SolidCraft를 시작할 때 적용됩니다.",
|
||||
"ai.prefs.control_listening": "127.0.0.1:{port}에서 대기 중",
|
||||
"ai.prefs.control_not_listening": "대기하지 않음",
|
||||
"ai.prefs.control_port": "포트",
|
||||
"ai.prefs.control_port_note": "이 컴퓨터에서 AI 에이전트가 연결하는 포트(127.0.0.1)입니다. 기본값은 27878이며, 사용 중이면 다음 빈 포트를 사용합니다. 다른 포트는 그대로 사용합니다. MCP 클라이언트도 같은 포트를 가리키게 하세요(예: solidcraft-cli mcp --connect 127.0.0.1:7878).",
|
||||
"ai.prefs.control_port_taken": "포트 {port}을(를) 다른 프로그램(또는 다른 SolidCraft 창)이 사용 중입니다. 다른 포트를 선택하세요.",
|
||||
"ai.prefs.follow_camera": "카메라 따라가기",
|
||||
"ai.prefs.follow_camera_off": "카메라 자동 따라가기가 꺼져 있습니다.",
|
||||
"ai.prefs.follow_camera_on": "에이전트가 만드는 스케치를 향해 카메라가 회전합니다.",
|
||||
@@ -774,6 +783,13 @@
|
||||
"browser.sketch_attachment_lost": "{name} (부착 해제됨)",
|
||||
"browser.sketch_editing": "{name} (편집 중)",
|
||||
"browser.sketch_name": "스케치{number}",
|
||||
"browser.straighten_angle": "모서리 방향",
|
||||
"browser.straighten_choose": "모서리 방향(수평, 수직 또는 각도)을 고른 다음 수평 맞추기를 누르세요.",
|
||||
"browser.straighten_click_a": "곧아야 하는 모서리의 한쪽 끝을 이미지에서 클릭하거나 좌표를 입력하세요.",
|
||||
"browser.straighten_click_b": "모서리의 다른 쪽 끝을 클릭하거나 좌표를 입력하세요.",
|
||||
"browser.straighten_horizontal": "수평",
|
||||
"browser.straighten_title": "수평 맞추기: {name}",
|
||||
"browser.straighten_vertical": "수직",
|
||||
"browser.units": "단위: {units}",
|
||||
"cam.flat": "평면",
|
||||
"cam.follower": "종동절",
|
||||
@@ -801,6 +817,8 @@
|
||||
"cmd.appearance_pick_up": "모양 가져오기",
|
||||
"cmd.appearance_replace": "모양 바꾸기",
|
||||
"cmd.assembly_bom": "자재 명세서",
|
||||
"cmd.assembly_constraint_create": "구속",
|
||||
"cmd.assembly_constraint_edit": "구속 편집",
|
||||
"cmd.assembly_mass_properties": "질량 특성",
|
||||
"cmd.body.print_face": "출력 바닥면",
|
||||
"cmd.body_rename": "바디 이름 변경",
|
||||
@@ -819,6 +837,7 @@
|
||||
"cmd.canvas_delete": "캔버스 삭제",
|
||||
"cmd.canvas_edit": "캔버스 편집",
|
||||
"cmd.canvas_insert": "캔버스",
|
||||
"cmd.canvas_straighten": "캔버스 수평 맞추기",
|
||||
"cmd.canvas_to_sketch": "캔버스에서 스케치",
|
||||
"cmd.component_activate": "구성 요소 활성화",
|
||||
"cmd.component_break_link": "링크 끊기",
|
||||
@@ -929,6 +948,7 @@
|
||||
"cmd.inspect_isocurve": "등가곡선 분석",
|
||||
"cmd.inspect_minimum_radius": "최소 반경 분석",
|
||||
"cmd.inspect_parameter_sweep": "매개변수 스윕",
|
||||
"cmd.inspect_parameter_variants": "매개변수 조합 비교",
|
||||
"cmd.inspect_silhouette": "실루엣",
|
||||
"cmd.inspect_zebra": "얼룩말줄무늬 분석",
|
||||
"cmd.joint_as_built": "조립 상태 관절",
|
||||
@@ -1253,6 +1273,7 @@
|
||||
"cmd.timeline_suppress": "특성 비활성화",
|
||||
"cmd.ui.assistant": "도우미 표시 전환",
|
||||
"cmd.ui.palette": "명령 검색",
|
||||
"cmd.ui.toggle_visibility": "선택 항목 표시/숨기기",
|
||||
"cmd.view.navigator": "사용자 지정 뷰 탐색기",
|
||||
"cmd.view.render_browser": "렌더 브라우저",
|
||||
"cmd.view.render_dock": "렌더 도크 이동",
|
||||
@@ -1293,6 +1314,7 @@
|
||||
"color.red": "빨강",
|
||||
"color.saturation_value": "채도 및 명도",
|
||||
"color.selected": "선택한 색상",
|
||||
"component.error.ambiguous_name": "이름이 `{name}`인 구성요소가 여러 개입니다. 숫자 구성요소 ID를 사용하세요: {ids}.",
|
||||
"config.column_filter_empty": "일치하는 열이 없습니다",
|
||||
"contact.components_count": "구성요소 {count}개",
|
||||
"contact.enabled_label": "활성화됨",
|
||||
@@ -1346,6 +1368,7 @@
|
||||
"dialog.pattern_sketch_not_object": "바디나 피처를 선택하세요. 스케치는 둘 다 아닙니다. 곡선은 스케치 안의 패턴이나 대칭 복사로 반복하거나, 먼저 돌출하세요.",
|
||||
"dialog.primitive_point_tip": "X, Y, Z를 채우는 점: 여기를 클릭한 다음 모델의 꼭짓점, 모서리, 면, 스케치의 점 또는 원점을 클릭.",
|
||||
"dialog.reference_edge_tip": "아래 거리를 재는 기준이 되는, 선택한 면의 직선 모서리: 여기를 클릭한 다음 모서리를 클릭.",
|
||||
"dialog.right_click_pick": "먼저 {input} 선택",
|
||||
"dialog.select": "↖ 선택",
|
||||
"dialog.selected_count": "↖ {count}개 선택됨",
|
||||
"dialog.selection_constraint": "구속 조건 {id}",
|
||||
@@ -1358,6 +1381,9 @@
|
||||
"document.changed_on_disk": "{name}이(가) 디스크에서 변경되었습니다",
|
||||
"document.changed_on_disk_detail": "{name}을(를) 열거나 마지막으로 저장한 뒤 다른 프로그램이나 컴퓨터가 이 파일을 변경했습니다. 덮어쓰기는 그 변경 내용을 사용자의 변경 내용으로 대체하고, 복사본 저장은 둘 다 유지합니다.",
|
||||
"document.copy_name": "{name} 복사본",
|
||||
"document.discard_row": "버리기",
|
||||
"document.finish_save_prompt": "다른 디자인을 열기 전에 저장 여부를 선택하세요.",
|
||||
"document.not_saved_yet": "아직 저장하지 않음",
|
||||
"document.open_anyway": "그래도 열기",
|
||||
"document.open_elsewhere": "{name}이(가) 이미 열려 있습니다",
|
||||
"document.open_elsewhere_detail": "{name}이(가) {who}의 SolidCraft {app}에서 열려 있습니다(열린 시점: {when}). 둘 다 저장하면 한쪽의 작업이 사라집니다. 덮어쓰지 않고 내용만 보려면 읽기 전용으로 여세요.",
|
||||
@@ -1367,6 +1393,9 @@
|
||||
"document.read_only_save": "이 디자인은 읽기 전용으로 열렸습니다: 새 파일로 저장하세요",
|
||||
"document.save_changes": "{name}의 변경 사항을 저장하시겠습니까?",
|
||||
"document.save_copy": "복사본 저장…",
|
||||
"document.save_many": "디자인 {n}개의 변경 사항을 저장하시겠습니까?",
|
||||
"document.save_row": "저장",
|
||||
"document.save_selected": "선택 항목 저장",
|
||||
"document.unsaved_changes": "{name}에 저장되지 않은 변경 사항이 있습니다. 저장하지 않으면 변경 사항이 사라집니다.",
|
||||
"drive.stopped_by_contact": "{value}에서 멈춤: {a}이(가) {b}을(를) 통과하게 됩니다",
|
||||
"drive.stopped_by_loop": "{value}에서 멈춤: {joint}을(를) 지나는 루프를 더 이상 닫을 수 없습니다",
|
||||
@@ -1395,6 +1424,7 @@
|
||||
"file_load.inserting": "기하 삽입 중",
|
||||
"file_load.link_item": "{name} ({done}/{total})",
|
||||
"file_load.opened": "{name}을(를) 열었습니다",
|
||||
"file_load.opened_behind": "{name}을(를) 새 탭에서 열었습니다",
|
||||
"file_load.opened_in_tab": "{name}을(를) 새 탭에서 열었습니다",
|
||||
"file_load.opening": "디자인 여는 중",
|
||||
"file_load.preparing_thumbnail": "미리보기 이미지 준비 중...",
|
||||
@@ -1645,6 +1675,9 @@
|
||||
"measure.at": "위치",
|
||||
"measure.item": "항목 {number}",
|
||||
"measure.line_to_centre": "선에서 중심까지",
|
||||
"measure.perimeter": "둘레",
|
||||
"measure.perimeter_inner": "내부 둘레",
|
||||
"measure.perimeter_outer": "외부 둘레",
|
||||
"messages.ago_h": "{n}시간 전",
|
||||
"messages.ago_min": "{n}분 전",
|
||||
"messages.ago_s": "{n}초 전",
|
||||
@@ -1682,6 +1715,8 @@
|
||||
"nav.hfss.help": "Alt+왼쪽 드래그는 이동, Shift+Alt+왼쪽 드래그는 확대/축소, 빈 공간에서 Ctrl+왼쪽 드래그는 회전입니다",
|
||||
"nav.inventor.help": "가운데 드래그는 이동, Shift+가운데 드래그는 회전, Ctrl+가운데 드래그는 확대/축소, 오른쪽 드래그는 회전입니다",
|
||||
"nav.maya.help": "Alt+왼쪽 드래그는 회전, Alt+가운데 드래그는 이동, Alt+오른쪽 드래그는 확대/축소입니다. 가운데 드래그로도 이동합니다",
|
||||
"nav.maya_horizontal_zoom.help": "Alt+오른쪽 버튼 드래그: 오른쪽으로 움직이면 확대하고 왼쪽으로 움직이면 축소합니다. 끄면 세로 드래그 확대/축소로 돌아갑니다.",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: 가로 드래그로 확대/축소",
|
||||
"nav.openscad.help": "빈 공간에서 왼쪽 드래그는 회전, Shift+왼쪽 드래그는 상자 선택, 스케치 형상 드래그는 편집입니다. 오른쪽 또는 가운데 드래그는 이동, Shift+오른쪽 또는 Shift+가운데 드래그는 확대/축소입니다",
|
||||
"nav.perspective.sketch": "스케치 편집 중에는 직교 뷰를 사용합니다. 원근 뷰를 전환하려면 스케치를 마치세요.",
|
||||
"nav.right_drag_orbits.help": "끄면 오른쪽 드래그는 카메라에 영향을 주지 않고 오른쪽 버튼은 컨텍스트 메뉴만 엽니다. SolidWorks 마우스 매핑을 선택하면 꺼집니다.",
|
||||
@@ -1802,6 +1837,16 @@
|
||||
"not a move": "이동이 아닙니다",
|
||||
"not a number": "숫자가 아닙니다",
|
||||
"open a sketch first": "먼저 스케치를 여세요",
|
||||
"operations.cancel": "{name} 취소",
|
||||
"operations.cancelled": "{name} 취소됨",
|
||||
"operations.cancelling": "취소하는 중…",
|
||||
"operations.cannot_cancel": "{name}은(는) 취소할 수 없습니다",
|
||||
"operations.feature": "피처",
|
||||
"operations.feature_edit": "피처 편집",
|
||||
"operations.meshing": "파트 불러오는 중",
|
||||
"operations.queued": "대기 중",
|
||||
"operations.stopped": "취소됨",
|
||||
"operations.waiting": "준비됨",
|
||||
"parts.automatic_name": "자동",
|
||||
"parts.dimension.across_flats": "대변 거리",
|
||||
"parts.dimension.bore": "내경",
|
||||
@@ -1874,6 +1919,7 @@
|
||||
"prefs.appearance.viewport_colours": "3D 보기 색상",
|
||||
"prefs.appearance.viewport_logo": "뷰포트 및 로고",
|
||||
"prefs.applies_on_restart": "다시 시작하면 적용됩니다",
|
||||
"prefs.assemblies": "어셈블리",
|
||||
"prefs.assistant": "어시스턴트",
|
||||
"prefs.assistant_connecting": "연결",
|
||||
"prefs.assistant_follow_help": "스케치의 Look At 동작이 포인터와 함께 보기를 이동합니다.",
|
||||
@@ -1917,6 +1963,10 @@
|
||||
"prefs.choose_font": "글꼴 파일 선택…",
|
||||
"prefs.click": "클릭",
|
||||
"prefs.command_dialog_values": "명령 대화 상자",
|
||||
"prefs.constraint_glyph_size": "구속 조건 기호 크기",
|
||||
"prefs.constraint_glyph_size_note": "스케치에서 구속 조건 기호와 그 문자나 아이콘을 그리는 크기입니다. 100%가 기본 크기이며, 기호는 확대/축소와 관계없이 이 화면 크기를 유지합니다.",
|
||||
"prefs.construct_menu_groups": "요소 유형별로 구성 도구 그룹화",
|
||||
"prefs.construct_menu_groups_help": "평면, 축, 점 제목을 표시합니다. 끄면 원래 메뉴 순서를 유지합니다.",
|
||||
"prefs.contact_shading": "부드러운 접촉 음영",
|
||||
"prefs.contact_shading_note": "부품이 가까워지는 곳의 부드러운 음영.",
|
||||
"prefs.context_menu": "컨텍스트 메뉴",
|
||||
@@ -1950,6 +2000,8 @@
|
||||
"prefs.design_tools.rows": "행",
|
||||
"prefs.devices": "3D 마우스",
|
||||
"prefs.dialog_buttons": "대화 상자 버튼",
|
||||
"prefs.dialog_first_letter_buttons": "다이얼로그 단추가 첫 글자에 반응",
|
||||
"prefs.dialog_first_letter_buttons_help": "다이얼로그가 열려 있을 때 단추 레이블의 첫 글자를 입력하면 그 단추를 누릅니다: 예를 들어 「ㅊ」은 「취소」를 누릅니다. 두 단추에 모두 해당하는 글자는 아무 동작을 하지 않으며, 포커스된 텍스트 필드는 입력을 그대로 받습니다. 끔: 기존처럼 입력이 단추에 영향을 주지 않습니다.",
|
||||
"prefs.dialogs": "대화 상자",
|
||||
"prefs.dialogs_edge": "뷰 가장자리",
|
||||
"prefs.dialogs_left_column": "왼쪽 열",
|
||||
@@ -1963,8 +2015,19 @@
|
||||
"prefs.dimension_values_window": "창에서",
|
||||
"prefs.display": "표시",
|
||||
"prefs.edges": "모서리 및 음영",
|
||||
"prefs.export": "내보내기",
|
||||
"prefs.export_name": "내보내기 파일 이름",
|
||||
"prefs.export_name.body": "내보내는 바디 이름(여러 개면 첫 번째 바디)",
|
||||
"prefs.export_name.design": "디자인 이름",
|
||||
"prefs.export_name_hint": "예: {design}-{body}",
|
||||
"prefs.export_name_sample": "이 디자인을 내보낼 때 제안되는 이름: {name}",
|
||||
"prefs.export_name_tip": "파일 › 내보내기와 메쉬로 저장이 제안하는 파일 이름입니다. 다음 자리 표시자가 바뀝니다:\n{placeholders}\n설정되지 않은 설계 속성은 빠집니다. 비워 두면 디자인 이름(메쉬의 경우 바디 이름)을 제안합니다.",
|
||||
"prefs.extend": "확장",
|
||||
"prefs.extra_navigation": "Ctrl+왼쪽 드래그로 빈 공간에서 회전하고, Space를 누른 채 이동합니다.",
|
||||
"prefs.file_operations_wait": "파일이 열릴 때까지 기다리기",
|
||||
"prefs.file_operations_wait_note": "파일을 열거나 삽입하거나 링크를 다시 읽는 동안 디자인이 진행 상황과 취소가 있는 카드 뒤에서 기다립니다. 끄면: 파일이 작업 패널에 표시되고 계속 작업할 수 있습니다. 삽입은 하던 작업을 마친 뒤 반영되고, 그 사이에 연 파일은 새 탭에 열립니다.",
|
||||
"prefs.fillet_legacy_radius": "이전 필렛 반지름 기본값 사용",
|
||||
"prefs.fillet_legacy_radius.help": "기본적으로 꺼짐입니다. 켜면: 새 Solid Fillet은 설계 단위로 읽힌 숫자 2(\"2 in\")로 시작하며 이전과 같습니다. 끄면: 그 도구가 기본으로 제공하는 반지름 2 mm를 설계 단위로 표시한 값(\"0.07874 in\")으로 시작합니다.",
|
||||
"prefs.follows_os": "운영 체제 설정을 따름",
|
||||
"prefs.font": "글꼴",
|
||||
"prefs.font_fallback": "선택한 글꼴에 없는 글리프는 기본 제공 글꼴로 대체되므로 빈 상자로 표시되는 레이블이 없습니다.",
|
||||
@@ -1988,6 +2051,17 @@
|
||||
"prefs.gesture_pan": "이동",
|
||||
"prefs.gesture_zoom": "확대/축소",
|
||||
"prefs.graphics": "그래픽",
|
||||
"prefs.graphics_api": "그래픽 API",
|
||||
"prefs.graphics_api_auto": "자동",
|
||||
"prefs.graphics_api_help": "SolidCraft를 시작할 그래픽 API를 선택합니다. 다음 시작에서 창을 열지 못하면 이전 선택으로 복원됩니다.",
|
||||
"prefs.graphics_api_override": "시작 시 재정의 설정이 그래픽 API를 제어하고 있습니다. SolidCraft를 일반적인 방법으로 열면 저장된 선택이 적용됩니다.",
|
||||
"prefs.graphics_api_restart_note": "다시 시작한 후 적용됩니다. 닫기 전에 저장하지 않은 설계를 처리합니다.",
|
||||
"prefs.graphics_api_restart_unavailable": "저장된 그래픽 API를 적용하려면 SolidCraft를 다시 시작하세요.",
|
||||
"prefs.graphics_api_running": "현재: {current}. 다음 시작 시 선택: {selected}.",
|
||||
"prefs.graphics_api_save_failed": "그래픽 API 선택을 저장할 수 없습니다: {error}",
|
||||
"prefs.graphics_api_start_failed": "선택한 그래픽 API를 준비할 수 없습니다: {error}",
|
||||
"prefs.graphics_api_start_reverted": "{requested}을(를) 사용한 이전 시작에서 창을 열지 못했습니다. SolidCraft가 {previous}(으)로 복원했습니다.",
|
||||
"prefs.graphics_api_unavailable": "그래픽 API는 데스크톱 앱에서 선택할 수 있습니다.",
|
||||
"prefs.graphics_card": "그래픽 카드",
|
||||
"prefs.graphics_card_auto": "자동",
|
||||
"prefs.graphics_card_missing": "저장된 그래픽 카드를 사용할 수 없어 자동을 사용합니다.",
|
||||
@@ -2027,6 +2101,8 @@
|
||||
"prefs.history_play_button": "기록 컨트롤에 기록 재생 버튼 표시",
|
||||
"prefs.history_play_button_note": "기록 컨트롤의 한 단계 뒤로와 한 단계 앞으로 사이에 기록 재생을 추가합니다. 컨트롤을 마우스 오른쪽 버튼으로 클릭해 표시하거나 숨길 수도 있습니다.",
|
||||
"prefs.history_sketches": "히스토리의 스케치",
|
||||
"prefs.history_steps_component": "구성 요소별 히스토리 이동",
|
||||
"prefs.history_steps_component_note": "구성 요소가 활성화되었거나 선택되어 있으면 기록 컨트롤이 아래쪽 히스토리에 보이는 대로 그 구성 요소의 피처만 이동합니다. 끄면 디자인의 모든 피처를 이동합니다. 왼쪽 또는 브라우저 아래의 히스토리는 항상 모든 피처를 이동합니다.",
|
||||
"prefs.hold_stop_snapping": "누르고 있으면 스냅 중지",
|
||||
"prefs.home_fit_size": "홈·맞춤 크기",
|
||||
"prefs.home_fit_size_note": "홈, 맞춤, 연 디자인 또는 뷰 탐색기의 뷰 변경으로 모델을 화면에 맞출 때 모델이 뷰에서 차지하는 비율. 아래 설정과 관계없이 적용됩니다. 100 %: 패널, 나침반, 내비게이션 바 사이의 뷰를 가득 채웁니다.",
|
||||
@@ -2037,6 +2113,8 @@
|
||||
"prefs.interface_language": "인터페이스 언어",
|
||||
"prefs.interface_note": "SolidCraft의 모양과 각 부분의 위치입니다.",
|
||||
"prefs.interval_minutes": "{n}분",
|
||||
"prefs.joint_drag_trackball": "볼 조인트의 부품을 끌 때 트랙볼처럼 회전",
|
||||
"prefs.joint_drag_trackball_help": "볼 조인트가 잡고 있는 부품을 끌면 부품 크기의 공을 굴리듯 조인트를 중심으로 가장 작은 회전만큼 돌아갑니다. 끄면: 잡은 점이 포인터를 정확히 따라가고, 부품이 그 점을 축으로 더 돌 수도 있습니다.",
|
||||
"prefs.labels": "레이블",
|
||||
"prefs.language_system": "시스템",
|
||||
"prefs.layout": "레이아웃",
|
||||
@@ -2096,6 +2174,8 @@
|
||||
"prefs.not_on_gpu": "이 GPU에서는 사용할 수 없음",
|
||||
"prefs.on": "켜짐",
|
||||
"prefs.opaque": "불투명",
|
||||
"prefs.operations_panel": "뷰에 작업 표시",
|
||||
"prefs.operations_panel_note": "오래 걸리는 작업(파일 열기, 피처 계산, 에이전트 명령)이 진행 상황과 취소 버튼과 함께 뷰의 오른쪽 아래에 표시됩니다. 끄면: 이전처럼 계산 중 알림이 표시됩니다.",
|
||||
"prefs.orbit_snap": "회전하는 동안 Shift를 누르면 축에 맞춰집니다.",
|
||||
"prefs.orientation": "방향",
|
||||
"prefs.origin_plane_names": "원점 평면 이름",
|
||||
@@ -2137,6 +2217,8 @@
|
||||
"prefs.ribbon_click_ends_tool": "실행 중인 도구의 버튼을 클릭하면 도구 종료",
|
||||
"prefs.ribbon_click_ends_tool_note": "사용 중인 스케치 도구의 강조된 리본 버튼을 클릭하면 도구가 종료되어 뷰에서 클릭하면 다시 선택됩니다. 끄기: 클릭하면 도구가 다시 시작됩니다.",
|
||||
"prefs.right_click": "오른쪽 클릭",
|
||||
"prefs.save_prompt_one_at_a_time": "여러 디자인을 닫을 때 저장하지 않은 디자인마다 따로 묻기",
|
||||
"prefs.save_prompt_one_at_a_time_help": "통합 목록 대신 저장하지 않은 디자인마다 저장 여부를 묻습니다.",
|
||||
"prefs.saving": "시작 및 저장",
|
||||
"prefs.scale_note": "창에서 Ctrl + / Ctrl −로도 조절합니다. 버튼은 100%에서 28 px입니다.",
|
||||
"prefs.scale_text": "배율 및 텍스트",
|
||||
@@ -2170,6 +2252,8 @@
|
||||
"prefs.sketch.center_arc": "중심점 호가 커서를 따라감",
|
||||
"prefs.sketch.click_selects": "클릭으로 선택",
|
||||
"prefs.sketch.conflict_colour": "충돌 색상",
|
||||
"prefs.sketch.cursor_coordinates": "스케치에서 커서 좌표 표시",
|
||||
"prefs.sketch.cursor_coordinates_note": "도구를 실행하지 않을 때도 포인터 옆에 스케치 원점 기준 X와 Y를 표시합니다. 끄기: 도구로 점을 배치하는 동안에만 표시합니다.",
|
||||
"prefs.sketch.drawing": "그리기",
|
||||
"prefs.sketch.ellipse_axes": "타원을 축과 함께 그리기",
|
||||
"prefs.sketch.ellipse_axes_note": "장축과 단축을 구성선으로 그려 반축과 축에 치수를 지정할 수 있습니다. 끄면: 타원만 그리며, D는 값을 어디로 끌든 단반경을 주며, 이전처럼 R로 표시되어 그려집니다.",
|
||||
@@ -2181,14 +2265,20 @@
|
||||
"prefs.sketch.faces_edges": "면과 모서리",
|
||||
"prefs.sketch.hide_glyphs": "축소 시 기호 숨기기",
|
||||
"prefs.sketch.marks": "스케치의 표시",
|
||||
"prefs.sketch.max_points": "최대 스케치",
|
||||
"prefs.sketch.max_points_note": "스케치 하나에 들어가는 점 또는 곡선의 최대 개수입니다. 기본값은 20000, 최대 200000입니다. SVG 삽입과 DXF 삽입은 이보다 큰 도면을 거부합니다. 큰 스케치는 해석과 그리기가 느려집니다.",
|
||||
"prefs.sketch.max_points_unit": "점",
|
||||
"prefs.sketch.note": "그리기, 스냅 및 선택.",
|
||||
"prefs.sketch.opening_closing": "열기 및 닫기",
|
||||
"prefs.sketch.prefer_free_points": "겹치는 곳에서는 이동 가능한 점 우선",
|
||||
"prefs.sketch.project_options": "투영 옵션을 먼저 묻기",
|
||||
"prefs.sketch.recent_snap": "두 안내선의 교차점에 스냅",
|
||||
"prefs.sketch.select_3d_curve_points": "3D 스케치 곡선의 점 선택",
|
||||
"prefs.sketch.select_3d_curve_points_help": "그린 3D 스케치 곡선의 점을 표시하고 구성 요소의 참조로 선택합니다.",
|
||||
"prefs.sketch.select_other_hidden": "다른 항목 선택에 숨겨진 형상 포함",
|
||||
"prefs.sketch.shortcut_cycles_modes": "단축키를 다시 누르면 모드 전환",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "끄면 도구를 다시 시작합니다.",
|
||||
"prefs.sketch.snap_to_visible_grid": "격자의 보이는 교차점에 스냅",
|
||||
"prefs.sketch.snapping_guides": "스냅 및 안내선",
|
||||
"prefs.sketch.state_icons": "상태 아이콘",
|
||||
"prefs.sketch.tracking_guides": "중심 및 중점 안내선",
|
||||
@@ -2209,6 +2299,7 @@
|
||||
"prefs.sketch_selection": "스케치 및 선택",
|
||||
"prefs.sketch_selection_heading": "스케치 및 선택",
|
||||
"prefs.sketch_selection_note": "스케치가 스냅되는 방식과 클릭으로 선택하는 방식입니다.",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "스케치의 점은 포인터가 가리키는 경우 격자가 그리는 선들의 교차점에 스냅되고, 그렇지 않으면 그 사이의 더 촘촘한 격자에 스냅됩니다. 끄기: 이전과 같이 점은 촘촘한 격자에만 스냅됩니다.",
|
||||
"prefs.sketch_state_icons": "스케치 아이콘을 상태 색상으로 표시",
|
||||
"prefs.sketch_state_icons_note": "이력과 브라우저에서 스케치 아이콘이 상태(구속 부족, 완전 구속, 충돌)의 색상을 띠고 도구 설명에 상태가 표시됩니다. 끄기: 모든 스케치가 같은 아이콘을 사용합니다.",
|
||||
"prefs.sketch_tab_always": "스케치 탭 항상 표시",
|
||||
@@ -2975,6 +3066,10 @@
|
||||
"render.gpu_path_preparing": "GPU 패스 트레이서: 셰이더 컴파일 중…",
|
||||
"render.gpu_seed": "난수 시드",
|
||||
"render.gpu_unavailable": "이 장치에서는 GPU 패스 트레이싱을 사용할 준비가 되지 않았습니다.",
|
||||
"render.graphics_api_restart_vulkan": "Vulkan으로 다시 시작",
|
||||
"render.graphics_api_restart_warning": "그래픽 API를 변경하면 SolidCraft가 다시 시작되고 저장하지 않은 설계를 저장할지 묻습니다. 새 API로 창을 열지 못하면 다음 시작에서 이전 선택으로 복원됩니다.",
|
||||
"render.graphics_api_settings": "그래픽 설정",
|
||||
"render.graphics_api_vulkan_required": "이 세션의 GPU 경로 추적에는 Vulkan이 필요합니다. Vulkan으로 다시 시작하거나 CPU 이미지 방식을 계속 사용하세요.",
|
||||
"render.ground_apply": "지면 맞춤 및 저장",
|
||||
"render.ground_gap": "명시적 여유 간격",
|
||||
"render.ground_linear_rgb": "확산 반사율 · 선형 RGB",
|
||||
@@ -3976,6 +4071,10 @@
|
||||
"sketch_text.path_clear": "곡선에서 텍스트 떼기",
|
||||
"sketch_text.path_hint": "텍스트가 따라갈 스케치 곡선: 여기를 클릭한 다음 곡선을 클릭",
|
||||
"sketch_text.use_font_file": "글꼴 파일 {path} 사용",
|
||||
"sketch_text.valign_baseline": "기준선",
|
||||
"sketch_text.valign_bottom": "아래",
|
||||
"sketch_text.valign_middle": "가운데",
|
||||
"sketch_text.valign_top": "위",
|
||||
"solid": "솔리드",
|
||||
"status.editing": "{name} 편집 중",
|
||||
"status.under_constrained": "구속 부족 (자유도 {count}개)",
|
||||
@@ -4164,6 +4263,7 @@
|
||||
"ui.agent_chat_allow_once": "한 번 허용",
|
||||
"ui.agent_chat_allowed": "허용함",
|
||||
"ui.agent_chat_answered": "응답: {option}",
|
||||
"ui.agent_chat_answered_in": "{time} 만에 답변",
|
||||
"ui.agent_chat_approval": "에이전트가 이 작업을 하도록 허용할까요?",
|
||||
"ui.agent_chat_attach_selection": "선택 항목 첨부",
|
||||
"ui.agent_chat_attach_selection_tip": "모델에서 선택한 항목(면, 모서리, 피처, 바디)을 메시지와 함께 보내 에이전트가 무엇을 말하는지 알 수 있게 합니다",
|
||||
@@ -4204,6 +4304,7 @@
|
||||
"ui.agent_chat_dock_right": "오른쪽에 고정",
|
||||
"ui.agent_chat_drop_hint": "놓으면 다음 메시지에 첨부됩니다",
|
||||
"ui.agent_chat_edit": "편집",
|
||||
"ui.agent_chat_ended_after": "{time} 후 종료",
|
||||
"ui.agent_chat_exited": "에이전트가 중지되었습니다.",
|
||||
"ui.agent_chat_failed_start": "에이전트를 시작할 수 없습니다: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: CAD 파일은 읽지 않고 디자인으로 가져옵니다",
|
||||
@@ -4239,6 +4340,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model}은(는) SolidCraft 도구를 사용할 수 없어 채팅만 할 수 있습니다. 도구를 지원하는 모델을 고르세요.",
|
||||
"ui.agent_chat_model_rejected": "에이전트가 {model}을(를) 받아들이지 않았습니다: {error}",
|
||||
"ui.agent_chat_model_search": "모델 검색…",
|
||||
"ui.agent_chat_model_search_or_id": "검색하거나 모델 ID를 직접 입력…",
|
||||
"ui.agent_chat_model_tip": "에이전트가 사용하는 모델입니다. 선택은 이 에이전트에 기억됩니다.",
|
||||
"ui.agent_chat_models_failed": "모델 목록을 가져올 수 없습니다: {error}",
|
||||
"ui.agent_chat_models_heading": "사용 가능한 모델",
|
||||
@@ -4295,6 +4397,10 @@
|
||||
"ui.agent_chat_setup_title": "어시스턴트 설정",
|
||||
"ui.agent_chat_side": "채팅 도킹",
|
||||
"ui.agent_chat_signed_in": "로그인됨",
|
||||
"ui.agent_chat_snap_none_found": "코딩 에이전트를 찾지 못했습니다. Snap 패키지는 격리된 환경에서 실행되므로 이 컴퓨터에 설치된 코딩 에이전트를 보거나 시작할 수 없습니다. 이 에이전트를 사용하려면 대신 AppImage, .deb 또는 .rpm 패키지로 SolidCraft를 설치하세요. OpenAI 호환 API를 사용하는 에이전트는 Snap 패키지에서도 작동합니다. 에이전트 추가에서 설정하세요.",
|
||||
"ui.agent_chat_span_h": "{h}시간 {min}분",
|
||||
"ui.agent_chat_span_min": "{n}분",
|
||||
"ui.agent_chat_span_s": "{n}초",
|
||||
"ui.agent_chat_state_auth": "로그인 필요",
|
||||
"ui.agent_chat_state_busy": "작업 중…",
|
||||
"ui.agent_chat_state_exited": "에이전트 중지됨",
|
||||
@@ -4304,6 +4410,10 @@
|
||||
"ui.agent_chat_stop": "중지",
|
||||
"ui.agent_chat_stop_tip": "에이전트와 에이전트가 시작한 모든 것을 중지",
|
||||
"ui.agent_chat_stop_turn_tip": "에이전트 중지 (Esc). 대기 중인 메시지는 그대로 대기합니다.",
|
||||
"ui.agent_chat_thinking_for": "{time}째 생각 중",
|
||||
"ui.agent_chat_tool_running_for": "{time}째 실행 중",
|
||||
"ui.agent_chat_transcript_assistant": "어시스턴트:",
|
||||
"ui.agent_chat_transcript_user": "사용자:",
|
||||
"ui.agent_chat_turn_limit": "메시지당 변경 수",
|
||||
"ui.agent_chat_turn_unlimited": "무제한",
|
||||
"ui.agent_chat_undo_changes": "이 변경 사항 실행 취소",
|
||||
@@ -4436,7 +4546,9 @@
|
||||
"ui.browser_bodies_one": "{count}개 바디",
|
||||
"ui.browser_bodies_other": "{count}개 바디",
|
||||
"ui.browser_collapse": "브라우저 접기",
|
||||
"ui.browser_collapse_below": "하위 항목 접기",
|
||||
"ui.browser_expand": "브라우저 펼치기",
|
||||
"ui.browser_expand_below": "하위 항목 펼치기",
|
||||
"ui.browser_title": "브라우저",
|
||||
"ui.calibrate": "캘리브레이션",
|
||||
"ui.cancel": "취소",
|
||||
@@ -4462,6 +4574,7 @@
|
||||
"ui.collapse": "접기",
|
||||
"ui.collinear": "동일 선상",
|
||||
"ui.colour_vision": "색각",
|
||||
"ui.colour_vision_bends": "벤딩",
|
||||
"ui.colour_vision_deutan": "녹색각이상 (Deutan)",
|
||||
"ui.colour_vision_deutan_tip": "녹색 감각이 약하거나 없는 경우",
|
||||
"ui.colour_vision_failed": "실패",
|
||||
@@ -4491,6 +4604,9 @@
|
||||
"ui.conic_curve": "원뿔 곡선",
|
||||
"ui.constant": "상수",
|
||||
"ui.constraints_conflict": "구속 조건 충돌",
|
||||
"ui.construct_axes": "축",
|
||||
"ui.construct_planes": "평면",
|
||||
"ui.construct_points": "점",
|
||||
"ui.construction": "구성선",
|
||||
"ui.construction.angle_hint": "보조 직선: 점 클릭 후 각도 입력 또는 방향 선택",
|
||||
"ui.construction.bisector_hint": "이등분선: 교차하는 두 직선 선택 후 원하는 해 선택",
|
||||
@@ -4659,7 +4775,10 @@
|
||||
"ui.explode_needs_two_components": "분해 보기는 구성 요소를 서로 떼어 놓으므로 설계에 구성 요소가 두 개 이상 있어야 합니다(새 구성 요소, 설계 삽입 또는 바디로 구성 요소 만들기)",
|
||||
"ui.exportDxf": "DXF 내보내기…",
|
||||
"ui.export_ellipsis_keymap": "내보내기…",
|
||||
"ui.export_glb": "GLB 내보내기",
|
||||
"ui.export_keymap_tip": "키, S 상자 즐겨찾기, 도구 모음을 파일로 내보내기",
|
||||
"ui.export_selects_only_body": "메시 내보내기 시 유일한 바디 선택",
|
||||
"ui.export_selects_only_body_tip": "디자인에 바디가 하나뿐이면 STL 내보내기, 3MF 내보내기, 슬라이서로 보내기가 그 바디를 선택한 상태로 시작합니다.",
|
||||
"ui.extend": "연장",
|
||||
"ui.extent_type": "범위 유형",
|
||||
"ui.extract_component": "파일로 추출…",
|
||||
@@ -4717,6 +4836,8 @@
|
||||
"ui.fine": "세밀",
|
||||
"ui.finest": "가장 세밀",
|
||||
"ui.finish_sketch": "스케치 종료",
|
||||
"ui.first_dimension_scales_about_origin": "스케치 원점을 기준으로 배율 조정",
|
||||
"ui.first_dimension_scales_about_origin_tip": "켜기: 도면이 항상 스케치 원점을 기준으로 커지거나 작아지므로 원점에서 떨어져 그린 도형은 이동합니다. 끄기: 원점에 묶이지 않은 도면은 자신의 중심을 기준으로 배율이 바뀌고 그린 자리에 그대로 있습니다.",
|
||||
"ui.fit": "맞춤",
|
||||
"ui.fix_unfix": "고정/고정 해제",
|
||||
"ui.flat": "플랫",
|
||||
@@ -5115,6 +5236,7 @@
|
||||
"ui.project_references_construction_note": "투영, 교차, 3D 형상 포함과 면 위 새 스케치의 면 모서리가 구성선으로 만들어집니다. 프로파일에 포함되지 않는 그리기용 참조이며, 모델과의 연결은 유지됩니다.",
|
||||
"ui.properties": "속성",
|
||||
"ui.properties.copy_matrix": "행렬 복사",
|
||||
"ui.properties.copy_value": "클릭하여 복사",
|
||||
"ui.properties.first_moments": "1차 모멘트",
|
||||
"ui.properties.inertia": "관성 모멘트",
|
||||
"ui.properties.inertia_note": "질량 중심 기준, 월드 축 (g·{unit}²)",
|
||||
@@ -5127,6 +5249,7 @@
|
||||
"ui.properties.measuring_failed": "측정이 끝나기 전에 중단되었습니다.",
|
||||
"ui.properties.principal_axis": "주축 {number}",
|
||||
"ui.properties.principal_moments": "주관성 모멘트",
|
||||
"ui.properties.value_copied": "값을 복사했습니다",
|
||||
"ui.pull_direction": "빼기 방향",
|
||||
"ui.quality": "품질",
|
||||
"ui.quantity": "수량",
|
||||
@@ -5150,6 +5273,7 @@
|
||||
"ui.relink_source_all": "소스 다시 연결 (모든 인스턴스)…",
|
||||
"ui.removeFromToolbar": "도구 모음에서 제거",
|
||||
"ui.removeSection": "단면 제거",
|
||||
"ui.renameSelectedBodies": "선택한 바디 이름 변경",
|
||||
"ui.render": "렌더",
|
||||
"ui.renderer": "렌더러",
|
||||
"ui.repeat": "반복",
|
||||
@@ -5177,6 +5301,8 @@
|
||||
"ui.ribbon_pin_footer": "고정된 명령은 리본에 표시됩니다. 행 위에 마우스를 올려 고정하거나 해제하세요.",
|
||||
"ui.ribbon_workspace": "작업 공간",
|
||||
"ui.right": "우측면",
|
||||
"ui.right_click_confirms": "오른쪽 클릭으로 대화 상자 입력 확인",
|
||||
"ui.right_click_confirms_tip": "대화 상자가 열려 있을 때 뷰에서 오른쪽 클릭하면 다음 빈 입력으로 이동하고, 마지막 입력에서는 OK를 실행합니다",
|
||||
"ui.save": "저장",
|
||||
"ui.save_as": "다른 이름으로 저장",
|
||||
"ui.save_mesh_pick_bodies": "저장할 바디를 선택하세요",
|
||||
@@ -5256,6 +5382,7 @@
|
||||
"ui.step_values": "화살표와 휠로 값 변경",
|
||||
"ui.step_values_tip": "값 필드에서 위/아래 화살표와 휠로 숫자를 변경합니다.",
|
||||
"ui.stitch_tolerance_hint": "엄격",
|
||||
"ui.straighten": "수평 맞추기",
|
||||
"ui.stretch": "늘이기",
|
||||
"ui.supersampling": "슈퍼샘플링 (SSAA)",
|
||||
"ui.supersampling_adaptive": "뷰가 멈춰 있을 때만",
|
||||
@@ -5326,6 +5453,8 @@
|
||||
"ui.view_angles_roll": "롤",
|
||||
"ui.view_angles_yaw": "요",
|
||||
"ui.view_centre": "뷰 중심",
|
||||
"ui.view_compass_tip": "{axis} 방향에서 봅니다. 다시 클릭하면 반대 방향으로 바뀝니다. 드래그하여 회전합니다.",
|
||||
"ui.view_compass_tip_snap": "{axis} 방향에서 봅니다. 다시 클릭하면 반대 방향으로 바뀝니다. 드래그하여 회전하고, Shift를 누르면 스냅됩니다.",
|
||||
"ui.viewport_status_clear": "{name} 끄기",
|
||||
"ui.viewport_status_clear_hint": "{name} 끄기 · Esc",
|
||||
"ui.viewport_status_edges": "모서리 {count}개",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Nilai",
|
||||
"Variable Radius": "Jejari Berubah",
|
||||
"Velocity": "Halaju",
|
||||
"Vertical": "Menegak",
|
||||
"Vertices": "Bucu",
|
||||
"View navigator": "Kawalan pandangan",
|
||||
"Volume": "Isi padu",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "SUNTING {title}",
|
||||
"dialog.no_shown_body": "Tiada jasad dipaparkan untuk diubah: paparkan satu, atau pilih Jasad Baharu",
|
||||
"dialog.pattern_sketch_not_object": "Pilih jasad atau ciri: lakaran bukan kedua-duanya. Ulang lengkungnya dengan Corak atau Cermin milik lakaran itu sendiri, atau semperit dahulu.",
|
||||
"dialog.right_click_pick": "Pilih {input} dahulu",
|
||||
"dialog.select": "↖ Pilih",
|
||||
"dialog.selected_count": "↖ {count} dipilih",
|
||||
"dialog.selection_constraint": "Kekangan {id}",
|
||||
@@ -3931,6 +3933,10 @@
|
||||
"sketch_text.path_clear": "Pisahkan teks daripada lengkung",
|
||||
"sketch_text.path_hint": "Lengkung lakaran yang akan diikuti teks: klik di sini, kemudian klik lengkung",
|
||||
"sketch_text.use_font_file": "Gunakan fail fon {path}",
|
||||
"sketch_text.valign_baseline": "Garis dasar",
|
||||
"sketch_text.valign_bottom": "Bawah",
|
||||
"sketch_text.valign_middle": "Tengah",
|
||||
"sketch_text.valign_top": "Atas",
|
||||
"solid": "pepejal",
|
||||
"status.editing": "Menyunting {name}",
|
||||
"status.navigation": "Pemetaan tetikus: {mapping}",
|
||||
@@ -5013,6 +5019,8 @@
|
||||
"ui.ribbon_pin_footer": "Arahan tersemat dipaparkan pada reben. Lalukan tetikus pada baris untuk menyemat atau menyahsemat.",
|
||||
"ui.ribbon_workspace": "Ruang kerja",
|
||||
"ui.right": "Kanan",
|
||||
"ui.right_click_confirms": "Klik kanan mengesahkan input dialog",
|
||||
"ui.right_click_confirms_tip": "Apabila dialog dibuka, klik kanan dalam paparan beralih ke input kosong seterusnya, dan pada input terakhir menjalankan OK",
|
||||
"ui.save": "Simpan",
|
||||
"ui.save_as": "Simpan Sebagai",
|
||||
"ui.save_mesh_no_slicer_open": "Tiada penghiris ditemui: pilih Tersuai… dan pilih program penghiris anda",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Verdi",
|
||||
"Variable Radius": "Variabel radius",
|
||||
"Velocity": "Hastighet",
|
||||
"Vertical": "Loddrett",
|
||||
"Vertices": "Hjørner",
|
||||
"View navigator": "Visningsnavigator",
|
||||
"Volume": "Volum",
|
||||
@@ -3931,6 +3932,10 @@
|
||||
"sketch_text.path_clear": "Ta teksten av kurven",
|
||||
"sketch_text.path_hint": "Velg en kurve i skissen som teksten skal følge: klikk her og deretter på kurven",
|
||||
"sketch_text.use_font_file": "Bruk skriftfilen {path}",
|
||||
"sketch_text.valign_baseline": "Grunnlinje",
|
||||
"sketch_text.valign_bottom": "Bunn",
|
||||
"sketch_text.valign_middle": "Midt",
|
||||
"sketch_text.valign_top": "Topp",
|
||||
"solid": "volumkropp",
|
||||
"status.editing": "Redigerer {name}",
|
||||
"status.navigation": "Museoppsett: {mapping}",
|
||||
@@ -4445,6 +4450,7 @@
|
||||
"ui.collapse": "Skjul",
|
||||
"ui.collinear": "Kollineær",
|
||||
"ui.colour_vision": "Fargesyn",
|
||||
"ui.colour_vision_bends": "Bøyninger",
|
||||
"ui.colour_vision_deutan": "Deutan",
|
||||
"ui.colour_vision_deutan_tip": "For svak eller manglende grønnsans",
|
||||
"ui.colour_vision_failed": "Mislyktes",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Waarde",
|
||||
"Variable Radius": "Variabele straal",
|
||||
"Velocity": "Snelheid",
|
||||
"Vertical": "Verticaal",
|
||||
"Vertices": "Hoekpunten",
|
||||
"View navigator": "Weergavenavigator",
|
||||
"Volume": "Volume",
|
||||
@@ -1372,6 +1373,7 @@
|
||||
"dialog.edit_title": "{title} BEWERKEN",
|
||||
"dialog.no_shown_body": "Geen zichtbaar lichaam om te wijzigen: toon er een of kies Nieuw lichaam",
|
||||
"dialog.pattern_sketch_not_object": "Kies lichamen of kenmerken: een schets is geen van beide. Herhaal de curven ervan met het eigen Patroon of Spiegelen van de schets, of extrudeer de schets eerst.",
|
||||
"dialog.right_click_pick": "Eerst {input} selecteren",
|
||||
"dialog.select": "↖ Selecteren",
|
||||
"dialog.selected_count": "↖ {count} geselecteerd",
|
||||
"dialog.selection_constraint": "Beperking {id}",
|
||||
@@ -3942,6 +3944,10 @@
|
||||
"sketch_text.path_clear": "De tekst van zijn curve halen",
|
||||
"sketch_text.path_hint": "Een curve van de schets die de tekst volgt: klik hier en daarna op de curve",
|
||||
"sketch_text.use_font_file": "Lettertypebestand {path} gebruiken",
|
||||
"sketch_text.valign_baseline": "Basislijn",
|
||||
"sketch_text.valign_bottom": "Onder",
|
||||
"sketch_text.valign_middle": "Midden",
|
||||
"sketch_text.valign_top": "Boven",
|
||||
"solid": "solid",
|
||||
"status.editing": "{name} wordt bewerkt",
|
||||
"status.navigation": "Muistoewijzing: {mapping}",
|
||||
@@ -4263,6 +4269,7 @@
|
||||
"ui.agent_chat_setup_title": "Een assistent instellen",
|
||||
"ui.agent_chat_side": "Zijde van agentchat",
|
||||
"ui.agent_chat_signed_in": "aangemeld",
|
||||
"ui.agent_chat_snap_none_found": "Geen codeeragent gevonden. Het Snap-pakket is afgeschermd en kan de codeeragents die op deze computer zijn geïnstalleerd niet zien of starten. Installeer SolidCraft in plaats daarvan via het AppImage-, .deb- of .rpm-pakket om ze te gebruiken. Een agent die een OpenAI-compatibele API gebruikt, werkt ook in het Snap-pakket: stel er een in met Agent toevoegen.",
|
||||
"ui.agent_chat_state_auth": "Aanmelden vereist",
|
||||
"ui.agent_chat_state_busy": "Bezig…",
|
||||
"ui.agent_chat_state_exited": "Agent gestopt",
|
||||
@@ -4429,7 +4436,9 @@
|
||||
"ui.browser_bodies_one": "{count} lichaam",
|
||||
"ui.browser_bodies_other": "{count} lichamen",
|
||||
"ui.browser_collapse": "De browser samenvouwen",
|
||||
"ui.browser_collapse_below": "Onderliggende samenvouwen",
|
||||
"ui.browser_expand": "De browser uitvouwen",
|
||||
"ui.browser_expand_below": "Onderliggende uitvouwen",
|
||||
"ui.browser_title": "Browser",
|
||||
"ui.calibrate": "Kalibreren",
|
||||
"ui.cancel": "Annuleren",
|
||||
@@ -5024,6 +5033,8 @@
|
||||
"ui.ribbon_pin_footer": "Vastgepinde opdrachten verschijnen in het lint. Beweeg over een rij om vast te pinnen of los te maken.",
|
||||
"ui.ribbon_workspace": "Werkruimte",
|
||||
"ui.right": "Rechts",
|
||||
"ui.right_click_confirms": "Rechtsklik bevestigt dialooginvoer",
|
||||
"ui.right_click_confirms_tip": "Met een dialoog open gaat een rechtsklik in de weergave naar de volgende lege invoer, en bij de laatste voert hij OK uit",
|
||||
"ui.save": "Opslaan",
|
||||
"ui.save_as": "Opslaan als",
|
||||
"ui.save_mesh_no_slicer_open": "Geen slicer gevonden: kies Aangepast… en selecteer je slicerprogramma",
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"en": { "ui.agent_chat_snap_none_found": "No coding agent found. The Snap package is confined, so it cannot see or start the coding agents installed on this computer. To use them, install SolidCraft from the AppImage, .deb or .rpm package instead. An agent that uses an OpenAI-compatible API works in the Snap package too: set one up with Add agent." },
|
||||
"ar": { "ui.agent_chat_snap_none_found": "لم يُعثر على وكيل برمجي. تعمل حزمة Snap في بيئة معزولة، لذا لا يمكنها رؤية الوكلاء البرمجيين المثبّتين على هذا الحاسوب ولا تشغيلهم. لاستخدامهم، ثبّت SolidCraft من حزمة AppImage أو .deb أو .rpm بدلًا من ذلك. يعمل الوكيل الذي يستخدم واجهة برمجية متوافقة مع OpenAI في حزمة Snap أيضًا: أعدّه من «إضافة وكيل»." },
|
||||
"cs": { "ui.agent_chat_snap_none_found": "Nebyl nalezen žádný kódovací agent. Balíček Snap běží v izolovaném prostředí, takže nevidí kódovací agenty nainstalované v tomto počítači a nemůže je spustit. Chcete-li je používat, nainstalujte SolidCraft z balíčku AppImage, .deb nebo .rpm. Agent, který používá API kompatibilní s OpenAI, v balíčku Snap funguje: nastavte ho přes Přidat agenta." },
|
||||
"de": { "ui.agent_chat_snap_none_found": "Kein Coding-Agent gefunden. Das Snap-Paket ist abgeschottet und kann die auf diesem Computer installierten Coding-Agenten weder sehen noch starten. Um sie zu nutzen, installieren Sie SolidCraft stattdessen aus dem AppImage-, .deb- oder .rpm-Paket. Ein Agent, der eine OpenAI-kompatible API nutzt, funktioniert auch im Snap-Paket: Richten Sie ihn mit Agent hinzufügen ein." },
|
||||
"es": { "ui.agent_chat_snap_none_found": "No se ha encontrado ningún agente de programación. El paquete Snap está confinado, así que no puede ver ni iniciar los agentes de programación instalados en este equipo. Para usarlos, instala SolidCraft desde el paquete AppImage, .deb o .rpm. Un agente que use una API compatible con OpenAI también funciona en el paquete Snap: configúralo con Añadir agente." },
|
||||
"fr": { "ui.agent_chat_snap_none_found": "Aucun agent de programmation trouvé. Le paquet Snap est confiné, il ne peut donc ni voir ni lancer les agents de programmation installés sur cet ordinateur. Pour les utiliser, installer plutôt SolidCraft depuis le paquet AppImage, .deb ou .rpm. Un agent qui utilise une API compatible OpenAI fonctionne aussi dans le paquet Snap. Le configurer avec Ajouter un agent." },
|
||||
"he": { "ui.agent_chat_snap_none_found": "לא נמצא סוכן קוד. חבילת ה־Snap מבודדת, ולכן היא לא יכולה לראות או להפעיל את סוכני הקוד שמותקנים במחשב הזה. כדי להשתמש בהם, יש להתקין את SolidCraft מחבילת AppImage, .deb או .rpm במקום זאת. סוכן שמשתמש ב־API תואם OpenAI עובד גם בחבילת ה־Snap, ואפשר להגדיר אותו בעזרת הוספת סוכן." },
|
||||
"it": { "ui.agent_chat_snap_none_found": "Nessun agente di programmazione trovato. Il pacchetto Snap è confinato, quindi non può vedere né avviare gli agenti di programmazione installati su questo computer. Per usarli, installa SolidCraft dal pacchetto AppImage, .deb o .rpm. Un agente che usa un’API compatibile con OpenAI funziona anche nel pacchetto Snap: configuralo con Aggiungi agente." },
|
||||
"ja": { "ui.agent_chat_snap_none_found": "コーディングエージェントが見つかりません。Snap パッケージは制限された環境で動作するため、このコンピューターにインストールされたコーディングエージェントを認識することも起動することもできません。それらを使うには、代わりに AppImage、.deb または .rpm パッケージから SolidCraft をインストールしてください。OpenAI 互換 API を使うエージェントは Snap パッケージでも動作します。「エージェントを追加」から設定してください。" },
|
||||
"ko": { "ui.agent_chat_snap_none_found": "코딩 에이전트를 찾지 못했습니다. Snap 패키지는 격리된 환경에서 실행되므로 이 컴퓨터에 설치된 코딩 에이전트를 보거나 시작할 수 없습니다. 이 에이전트를 사용하려면 대신 AppImage, .deb 또는 .rpm 패키지로 SolidCraft를 설치하세요. OpenAI 호환 API를 사용하는 에이전트는 Snap 패키지에서도 작동합니다. 에이전트 추가에서 설정하세요." },
|
||||
"nl": { "ui.agent_chat_snap_none_found": "Geen codeeragent gevonden. Het Snap-pakket is afgeschermd en kan de codeeragents die op deze computer zijn geïnstalleerd niet zien of starten. Installeer SolidCraft in plaats daarvan via het AppImage-, .deb- of .rpm-pakket om ze te gebruiken. Een agent die een OpenAI-compatibele API gebruikt, werkt ook in het Snap-pakket: stel er een in met Agent toevoegen." },
|
||||
"pl": { "ui.agent_chat_snap_none_found": "Nie znaleziono agenta programistycznego. Pakiet Snap działa w izolacji, więc nie widzi agentów programistycznych zainstalowanych na tym komputerze i nie może ich uruchomić. Aby z nich korzystać, zainstaluj SolidCraft z pakietu AppImage, .deb lub .rpm. Agent korzystający z API zgodnego z OpenAI działa także w pakiecie Snap: skonfiguruj go przyciskiem Dodaj agenta." },
|
||||
"pt-BR": { "ui.agent_chat_snap_none_found": "Nenhum agente de programação encontrado. O pacote Snap é confinado, então não consegue ver nem iniciar os agentes de programação instalados neste computador. Para usá-los, instale o SolidCraft pelo pacote AppImage, .deb ou .rpm. Um agente que usa uma API compatível com OpenAI também funciona no pacote Snap: configure-o em Adicionar agente." },
|
||||
"ru": { "ui.agent_chat_snap_none_found": "Кодирующий агент не найден. Пакет Snap работает в изолированной среде, поэтому не видит и не может запускать кодирующих агентов, установленных на этом компьютере. Чтобы пользоваться ими, установите SolidCraft из пакета AppImage, .deb или .rpm. Агент, использующий API, совместимый с OpenAI, работает и в пакете Snap: настройте его через «Добавить агент»." },
|
||||
"tr": { "ui.agent_chat_snap_none_found": "Kodlama ajanı bulunamadı. Snap paketi yalıtılmış çalıştığı için bu bilgisayarda yüklü kodlama ajanlarını göremez ve başlatamaz. Bunları kullanmak için SolidCraft'ı bunun yerine AppImage, .deb veya .rpm paketinden yükleyin. OpenAI uyumlu API kullanan bir ajan Snap paketinde de çalışır: Ajan ekle ile ayarlayın." },
|
||||
"uk": { "ui.agent_chat_snap_none_found": "Агента для програмування не знайдено. Пакет Snap працює в ізольованому середовищі, тому не бачить і не може запускати агентів для програмування, установлених на цьому комп’ютері. Щоб користуватися ними, установіть SolidCraft з пакета AppImage, .deb або .rpm. Агент, що використовує API, сумісний з OpenAI, працює і в пакеті Snap: налаштуйте його через «Додати агента»." },
|
||||
"vi": { "ui.agent_chat_snap_none_found": "Không tìm thấy tác tử lập trình nào. Gói Snap chạy trong môi trường bị giới hạn nên không thể thấy hay khởi động các tác tử lập trình được cài trên máy tính này. Để dùng chúng, hãy cài SolidCraft từ gói AppImage, .deb hoặc .rpm thay vào đó. Tác tử dùng API tương thích OpenAI vẫn hoạt động trong gói Snap: hãy thiết lập bằng Thêm AI Agent." },
|
||||
"zh": { "ui.agent_chat_snap_none_found": "未找到编程代理。Snap 软件包运行在受限环境中,无法看到或启动此计算机上安装的编程代理。要使用它们,请改用 AppImage、.deb 或 .rpm 软件包安装 SolidCraft。使用 OpenAI 兼容 API 的代理在 Snap 软件包中同样可用:请通过“添加智能体”进行设置。" },
|
||||
"zh-TW": { "ui.agent_chat_snap_none_found": "未找到程式設計代理。Snap 套件在受限環境中執行,無法看到或啟動這台電腦上安裝的程式設計代理。若要使用它們,請改用 AppImage、.deb 或 .rpm 套件安裝 SolidCraft。使用 OpenAI 相容 API 的代理在 Snap 套件中同樣可用:請透過「新增代理」進行設定。" }
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"en": {
|
||||
"component.error.ambiguous_name": "Several components are named `{name}`. Use a numeric component ID: {ids}."
|
||||
},
|
||||
"ar": {
|
||||
"component.error.ambiguous_name": "توجد عدة مكونات بالاسم `{name}`. استخدم معرّف مكوّن رقميًا: {ids}."
|
||||
},
|
||||
"de": {
|
||||
"component.error.ambiguous_name": "Mehrere Komponenten heißen `{name}`. Verwende eine numerische Komponenten-ID: {ids}."
|
||||
},
|
||||
"he": {
|
||||
"component.error.ambiguous_name": "לכמה רכיבים יש השם `{name}`. יש להשתמש במזהה רכיב מספרי: {ids}."
|
||||
},
|
||||
"ja": {
|
||||
"component.error.ambiguous_name": "複数のコンポーネントに `{name}` という名前が付いています。数値のコンポーネント ID を使用してください: {ids}。"
|
||||
},
|
||||
"ko": {
|
||||
"component.error.ambiguous_name": "이름이 `{name}`인 구성요소가 여러 개입니다. 숫자 구성요소 ID를 사용하세요: {ids}."
|
||||
},
|
||||
"vi": {
|
||||
"component.error.ambiguous_name": "Nhiều thành phần có tên `{name}`. Hãy dùng ID thành phần dạng số: {ids}."
|
||||
},
|
||||
"zh": {
|
||||
"component.error.ambiguous_name": "多个组件名为 `{name}`。请使用数字组件 ID:{ids}。"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"en": { "ui.browser_collapse_below": "Collapse Below", "ui.browser_expand_below": "Expand Below" },
|
||||
"ar": { "ui.browser_collapse_below": "طي ما بالأسفل", "ui.browser_expand_below": "توسيع ما بالأسفل" },
|
||||
"de": { "ui.browser_collapse_below": "Darunter einklappen", "ui.browser_expand_below": "Darunter ausklappen" },
|
||||
"es": { "ui.browser_collapse_below": "Contraer debajo", "ui.browser_expand_below": "Expandir debajo" },
|
||||
"fr": { "ui.browser_collapse_below": "Réduire en dessous", "ui.browser_expand_below": "Développer en dessous" },
|
||||
"he": { "ui.browser_collapse_below": "כיווץ מה שמתחת", "ui.browser_expand_below": "הרחבת מה שמתחת" },
|
||||
"it": { "ui.browser_collapse_below": "Comprimi sotto", "ui.browser_expand_below": "Espandi sotto" },
|
||||
"ja": { "ui.browser_collapse_below": "この下を折りたたむ", "ui.browser_expand_below": "この下を展開" },
|
||||
"ko": { "ui.browser_collapse_below": "하위 항목 접기", "ui.browser_expand_below": "하위 항목 펼치기" },
|
||||
"nl": { "ui.browser_collapse_below": "Onderliggende samenvouwen", "ui.browser_expand_below": "Onderliggende uitvouwen" },
|
||||
"pl": { "ui.browser_collapse_below": "Zwiń poniżej", "ui.browser_expand_below": "Rozwiń poniżej" },
|
||||
"ru": { "ui.browser_collapse_below": "Свернуть вложенное", "ui.browser_expand_below": "Развернуть вложенное" },
|
||||
"uk": { "ui.browser_collapse_below": "Згорнути вкладене", "ui.browser_expand_below": "Розгорнути вкладене" },
|
||||
"vi": { "ui.browser_collapse_below": "Thu gọn bên dưới", "ui.browser_expand_below": "Mở rộng bên dưới" },
|
||||
"zh": { "ui.browser_collapse_below": "折叠下级", "ui.browser_expand_below": "展开下级" },
|
||||
"zh-TW": { "ui.browser_collapse_below": "折疊下層", "ui.browser_expand_below": "展開下層" }
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"ar": {
|
||||
"ui.construction.axis_hint": "خط إنشائي: انقر نقطة، أو أدخل بعدها عن محور الرسم",
|
||||
"ui.construction.parallel_hint": "خط إنشائي: اختر خطًا مستقيمًا ثم انقر أو أدخل الإزاحة؛ انقر بزر الفأرة الأيمن لتغيير المرجع"
|
||||
},
|
||||
"he": {
|
||||
"ui.construction.axis_hint": "ישר עזר: לחיצה על נקודה, או הקלדת המרחק מציר הסקיצה",
|
||||
"ui.construction.parallel_hint": "ישר עזר: בחירת ישר, ואז לחיצה או הקלדת ההיסט; לחיצה ימנית להחלפת הייחוס"
|
||||
},
|
||||
"ja": {
|
||||
"ui.construction.axis_hint": "補助直線: 点をクリックするか、スケッチ軸からの距離を入力",
|
||||
"ui.construction.parallel_hint": "補助直線: 直線を選択し、クリックするかオフセットを入力。右クリックで参照を変更"
|
||||
},
|
||||
"vi": {
|
||||
"ui.construction.axis_hint": "Đường dựng hình: nhấp một điểm, hoặc nhập khoảng cách tới trục phác thảo",
|
||||
"ui.construction.parallel_hint": "Đường dựng hình: chọn đường thẳng, rồi nhấp hoặc nhập khoảng dời; nhấp chuột phải để đổi tham chiếu"
|
||||
},
|
||||
"zh": {
|
||||
"ui.construction.axis_hint": "构造直线:单击一点,或输入它到草图轴的距离",
|
||||
"ui.construction.parallel_hint": "构造直线:先选直线,再单击或输入偏移;右键单击更换参照"
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"ar": {
|
||||
"prefs.history_steps_component": "خطوات السجل حسب المكوّن",
|
||||
"prefs.history_steps_component_note": "عندما يكون مكوّن نشطًا أو محددًا، تتنقل عناصر تحكم السجل بين ميزات ذلك المكوّن كما يعرضها السجل في الأسفل. عند إيقافه تتنقل بين كل ميزات التصميم. السجل على اليسار أو تحت المستعرض يتنقل دائمًا بين كل الميزات."
|
||||
},
|
||||
"de": {
|
||||
"prefs.history_steps_component": "Verlaufsschritte je Komponente",
|
||||
"prefs.history_steps_component_note": "Ist eine Komponente aktiv oder ausgewählt, gehen die Verlaufssteuerelemente durch deren Features, so wie der Verlauf unten sie zeigt. Aus: Sie gehen durch alle Features des Designs. Der Verlauf links oder unter dem Browser geht immer durch alle Features."
|
||||
},
|
||||
"en": {
|
||||
"prefs.history_steps_component": "History steps by component",
|
||||
"prefs.history_steps_component_note": "With a component active or picked, the History controls step through that component's features, as the History at the bottom shows them. Off: they step through every feature of the design. The History on the left or under the browser always steps through every feature."
|
||||
},
|
||||
"he": {
|
||||
"prefs.history_steps_component": "צעדי ציר הזמן לפי רכיב",
|
||||
"prefs.history_steps_component_note": "כשרכיב פעיל או נבחר, פקדי ציר הזמן עוברים בין הפיצ'רים של אותו רכיב, כפי שציר הזמן למטה מציג אותם. כבוי: הם עוברים בין כל הפיצ'רים של התכנון. ציר הזמן משמאל או מתחת לדפדפן עובר תמיד בין כל הפיצ'רים."
|
||||
},
|
||||
"ja": {
|
||||
"prefs.history_steps_component": "コンポーネント単位で履歴を移動",
|
||||
"prefs.history_steps_component_note": "コンポーネントがアクティブまたは選択されているとき、履歴コントロールは下部の履歴に表示されるとおり、そのコンポーネントのフィーチャだけを移動します。オフにすると、デザインのすべてのフィーチャを移動します。左側またはブラウザー下の履歴は常にすべてのフィーチャを移動します。"
|
||||
},
|
||||
"ko": {
|
||||
"prefs.history_steps_component": "구성 요소별 히스토리 이동",
|
||||
"prefs.history_steps_component_note": "구성 요소가 활성화되었거나 선택되어 있으면 기록 컨트롤이 아래쪽 히스토리에 보이는 대로 그 구성 요소의 피처만 이동합니다. 끄면 디자인의 모든 피처를 이동합니다. 왼쪽 또는 브라우저 아래의 히스토리는 항상 모든 피처를 이동합니다."
|
||||
},
|
||||
"vi": {
|
||||
"prefs.history_steps_component": "Bước Lịch sử theo cụm chi tiết",
|
||||
"prefs.history_steps_component_note": "Khi một cụm chi tiết đang kích hoạt hoặc được chọn, các điều khiển Lịch sử đi qua các tính năng của cụm đó, như dòng Lịch sử ở cạnh dưới hiển thị. Tắt: chúng đi qua mọi tính năng của thiết kế. Cây Lịch sử ở bên trái hoặc dưới cây thư mục luôn đi qua mọi tính năng."
|
||||
},
|
||||
"zh": {
|
||||
"prefs.history_steps_component": "历史按组件逐步移动",
|
||||
"prefs.history_steps_component_note": "当某个组件处于活动或选中状态时,历史控件按底部历史的显示,只在该组件的特征之间移动。关闭后,它们在设计的所有特征之间移动。左侧或浏览器下方的历史始终在所有特征之间移动。"
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"en": {
|
||||
"measure.perimeter": "Perimeter",
|
||||
"measure.perimeter_inner": "Inner perimeter",
|
||||
"measure.perimeter_outer": "Outer perimeter"
|
||||
},
|
||||
"ar": {
|
||||
"measure.perimeter": "المحيط",
|
||||
"measure.perimeter_inner": "المحيط الداخلي",
|
||||
"measure.perimeter_outer": "المحيط الخارجي"
|
||||
},
|
||||
"de": {
|
||||
"measure.perimeter": "Umfang",
|
||||
"measure.perimeter_inner": "Innenumfang",
|
||||
"measure.perimeter_outer": "Außenumfang"
|
||||
},
|
||||
"fr": {
|
||||
"measure.perimeter": "Périmètre",
|
||||
"measure.perimeter_inner": "Périmètre intérieur",
|
||||
"measure.perimeter_outer": "Périmètre extérieur"
|
||||
},
|
||||
"he": {
|
||||
"measure.perimeter": "היקף",
|
||||
"measure.perimeter_inner": "היקף פנימי",
|
||||
"measure.perimeter_outer": "היקף חיצוני"
|
||||
},
|
||||
"ja": {
|
||||
"measure.perimeter": "周長",
|
||||
"measure.perimeter_inner": "内周長",
|
||||
"measure.perimeter_outer": "外周長"
|
||||
},
|
||||
"ko": {
|
||||
"measure.perimeter": "둘레",
|
||||
"measure.perimeter_inner": "내부 둘레",
|
||||
"measure.perimeter_outer": "외부 둘레"
|
||||
},
|
||||
"vi": {
|
||||
"measure.perimeter": "Chu vi",
|
||||
"measure.perimeter_inner": "Chu vi trong",
|
||||
"measure.perimeter_outer": "Chu vi ngoài"
|
||||
},
|
||||
"zh": {
|
||||
"measure.perimeter": "周长",
|
||||
"measure.perimeter_inner": "内周长",
|
||||
"measure.perimeter_outer": "外周长"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"ar": { "cmd.inspect_parameter_variants": "مقارنة بدائل المعلمات" },
|
||||
"de": { "cmd.inspect_parameter_variants": "Parametervarianten vergleichen" },
|
||||
"en": { "cmd.inspect_parameter_variants": "Compare Parameter Variants" },
|
||||
"es": { "cmd.inspect_parameter_variants": "Comparar variantes de parámetros" },
|
||||
"he": { "cmd.inspect_parameter_variants": "השוואת חלופות פרמטרים" },
|
||||
"ja": { "cmd.inspect_parameter_variants": "パラメーターの組み合わせを比較" },
|
||||
"ko": { "cmd.inspect_parameter_variants": "매개변수 조합 비교" },
|
||||
"vi": { "cmd.inspect_parameter_variants": "So sánh các phương án tham số" },
|
||||
"zh": { "cmd.inspect_parameter_variants": "比较参数方案" }
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"en": { "ui.properties.copy_value": "Click to copy", "ui.properties.value_copied": "Value copied" },
|
||||
"ar": { "ui.properties.copy_value": "انقر للنسخ", "ui.properties.value_copied": "تم نسخ القيمة" },
|
||||
"de": { "ui.properties.copy_value": "Klicken, um den Wert zu kopieren", "ui.properties.value_copied": "Wert kopiert" },
|
||||
"es": { "ui.properties.copy_value": "Haz clic para copiar", "ui.properties.value_copied": "Valor copiado" },
|
||||
"fr": { "ui.properties.copy_value": "Cliquer pour copier", "ui.properties.value_copied": "Valeur copiée" },
|
||||
"he": { "ui.properties.copy_value": "לחיצה מעתיקה את הערך", "ui.properties.value_copied": "הערך הועתק" },
|
||||
"it": { "ui.properties.copy_value": "Fai clic per copiare", "ui.properties.value_copied": "Valore copiato" },
|
||||
"ja": { "ui.properties.copy_value": "クリックでコピー", "ui.properties.value_copied": "値をコピーしました" },
|
||||
"ko": { "ui.properties.copy_value": "클릭하여 복사", "ui.properties.value_copied": "값을 복사했습니다" },
|
||||
"vi": { "ui.properties.copy_value": "Nhấp để sao chép", "ui.properties.value_copied": "Đã sao chép giá trị" },
|
||||
"zh": { "ui.properties.copy_value": "点击复制", "ui.properties.value_copied": "已复制数值" },
|
||||
"zh-TW": { "ui.properties.copy_value": "按一下以複製", "ui.properties.value_copied": "已複製數值" }
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
{
|
||||
"ar": {
|
||||
"document.discard_row": "تجاهل",
|
||||
"document.finish_save_prompt": "أكمل الرد على نافذة الحفظ قبل فتح تصميم آخر.",
|
||||
"document.not_saved_yet": "لم يُحفظ بعد",
|
||||
"document.save_many": "حفظ التغييرات في {n} من التصاميم؟",
|
||||
"document.save_row": "حفظ",
|
||||
"document.save_selected": "حفظ المحدد",
|
||||
"prefs.save_prompt_one_at_a_time": "السؤال عن كل تصميم غير محفوظ على حدة عند إغلاق عدة تصاميم",
|
||||
"prefs.save_prompt_one_at_a_time_help": "عرض نافذة حفظ لكل تصميم غير محفوظ بدلاً من قائمة مجمّعة."
|
||||
},
|
||||
"de": {
|
||||
"document.discard_row": "Verwerfen",
|
||||
"document.finish_save_prompt": "Beantworten Sie die Speicherabfrage, bevor Sie einen weiteren Entwurf öffnen.",
|
||||
"document.not_saved_yet": "Noch nicht gespeichert",
|
||||
"document.save_many": "Änderungen an {n} Entwürfen speichern?",
|
||||
"document.save_row": "Speichern",
|
||||
"document.save_selected": "Auswahl speichern",
|
||||
"prefs.save_prompt_one_at_a_time": "Beim Schließen mehrerer Entwürfe für jeden ungespeicherten Entwurf einzeln fragen",
|
||||
"prefs.save_prompt_one_at_a_time_help": "Für jeden ungespeicherten Entwurf eine eigene Speicherabfrage statt einer gemeinsamen Liste anzeigen."
|
||||
},
|
||||
"en": {
|
||||
"document.discard_row": "Discard",
|
||||
"document.finish_save_prompt": "Finish answering the save prompt before opening another design.",
|
||||
"document.not_saved_yet": "Not saved yet",
|
||||
"document.save_many": "Save changes to {n} designs?",
|
||||
"document.save_row": "Save",
|
||||
"document.save_selected": "Save Selected",
|
||||
"prefs.save_prompt_one_at_a_time": "Ask about each unsaved design separately when closing several",
|
||||
"prefs.save_prompt_one_at_a_time_help": "Show one save prompt per unsaved design instead of a combined list."
|
||||
},
|
||||
"he": {
|
||||
"document.discard_row": "ביטול שינויים",
|
||||
"document.finish_save_prompt": "יש לסיים לענות על חלון השמירה לפני פתיחת תכן אחר.",
|
||||
"document.not_saved_yet": "עדיין לא נשמר",
|
||||
"document.save_many": "לשמור שינויים ב־{n} תכנים?",
|
||||
"document.save_row": "שמירה",
|
||||
"document.save_selected": "שמירת הנבחרים",
|
||||
"prefs.save_prompt_one_at_a_time": "לשאול על כל תכן שלא נשמר בנפרד בעת סגירת כמה",
|
||||
"prefs.save_prompt_one_at_a_time_help": "להציג חלון שמירה נפרד לכל תכן שלא נשמר במקום רשימה משותפת."
|
||||
},
|
||||
"ja": {
|
||||
"document.discard_row": "破棄",
|
||||
"document.finish_save_prompt": "別のデザインを開く前に、保存の確認に回答してください。",
|
||||
"document.not_saved_yet": "未保存",
|
||||
"document.save_many": "{n} 件のデザインの変更を保存しますか?",
|
||||
"document.save_row": "保存",
|
||||
"document.save_selected": "選択項目を保存",
|
||||
"prefs.save_prompt_one_at_a_time": "複数を閉じるとき、未保存のデザインごとに確認する",
|
||||
"prefs.save_prompt_one_at_a_time_help": "一覧でまとめて確認する代わりに、未保存のデザインごとに保存を確認します。"
|
||||
},
|
||||
"ko": {
|
||||
"document.discard_row": "버리기",
|
||||
"document.finish_save_prompt": "다른 디자인을 열기 전에 저장 여부를 선택하세요.",
|
||||
"document.not_saved_yet": "아직 저장하지 않음",
|
||||
"document.save_many": "디자인 {n}개의 변경 사항을 저장하시겠습니까?",
|
||||
"document.save_row": "저장",
|
||||
"document.save_selected": "선택 항목 저장",
|
||||
"prefs.save_prompt_one_at_a_time": "여러 디자인을 닫을 때 저장하지 않은 디자인마다 따로 묻기",
|
||||
"prefs.save_prompt_one_at_a_time_help": "통합 목록 대신 저장하지 않은 디자인마다 저장 여부를 묻습니다."
|
||||
},
|
||||
"vi": {
|
||||
"document.discard_row": "Bỏ thay đổi",
|
||||
"document.finish_save_prompt": "Hãy trả lời xong hộp thoại lưu trước khi mở thiết kế khác.",
|
||||
"document.not_saved_yet": "Chưa lưu",
|
||||
"document.save_many": "Lưu thay đổi cho {n} thiết kế?",
|
||||
"document.save_row": "Lưu",
|
||||
"document.save_selected": "Lưu mục đã chọn",
|
||||
"prefs.save_prompt_one_at_a_time": "Hỏi riêng từng thiết kế chưa lưu khi đóng nhiều thiết kế",
|
||||
"prefs.save_prompt_one_at_a_time_help": "Hiển thị một hộp thoại lưu cho mỗi thiết kế chưa lưu thay vì một danh sách chung."
|
||||
},
|
||||
"zh": {
|
||||
"document.discard_row": "放弃",
|
||||
"document.finish_save_prompt": "请先回答保存提示,再打开其他设计。",
|
||||
"document.not_saved_yet": "尚未保存",
|
||||
"document.save_many": "保存 {n} 个设计的更改?",
|
||||
"document.save_row": "保存",
|
||||
"document.save_selected": "保存所选项",
|
||||
"prefs.save_prompt_one_at_a_time": "关闭多个设计时,逐个询问未保存的设计",
|
||||
"prefs.save_prompt_one_at_a_time_help": "对每个未保存的设计分别显示保存提示,而不是合并列表。"
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"en": {
|
||||
"Segments": "Segments",
|
||||
"Split Edge": "Split Edge",
|
||||
"Remove this segment": "Remove this segment",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "One more stretch of the picked edge, each with its own angle, height and turns"
|
||||
},
|
||||
"ar": {
|
||||
"Segments": "المقاطع",
|
||||
"Split Edge": "تقسيم الحافة",
|
||||
"Remove this segment": "إزالة هذا المقطع",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "مقطع آخر من الحافة المختارة، لكل منها زاويتها وارتفاعها ولفّاتها"
|
||||
},
|
||||
"he": {
|
||||
"Segments": "מקטעים",
|
||||
"Split Edge": "פיצול המקצוע",
|
||||
"Remove this segment": "הסרת המקטע הזה",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "מקטע נוסף של המקצוע הנבחר, שלכל אחד זווית, גובה וכיפופים משלו"
|
||||
},
|
||||
"ja": {
|
||||
"Segments": "セグメント",
|
||||
"Split Edge": "エッジを分割",
|
||||
"Remove this segment": "このセグメントを削除",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "選択したエッジのもう一つの区間。それぞれに独自の角度、高さ、曲げ方向があります"
|
||||
},
|
||||
"vi": {
|
||||
"Segments": "Đoạn",
|
||||
"Split Edge": "Chia cạnh",
|
||||
"Remove this segment": "Xóa đoạn này",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "Thêm một đoạn nữa của cạnh đã chọn, mỗi đoạn có góc, chiều cao và hướng uốn riêng"
|
||||
},
|
||||
"zh": {
|
||||
"Segments": "分段",
|
||||
"Split Edge": "分割边",
|
||||
"Remove this segment": "移除此分段",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "所选边的又一段,每段都有自己的角度、高度和折弯方向"
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
{
|
||||
"uk": {
|
||||
"Edit Holes": "Редагувати отвори",
|
||||
"Select the curves to divide first": "Спершу виберіть криві для поділу",
|
||||
"browser.canvas_locked": "Полотно заблоковано. Спершу розблокуйте його.",
|
||||
"cmd.model_body_features": "Перелічити операції тіла",
|
||||
"cmd.panel.focus.next": "Сфокусувати наступну панель",
|
||||
"cmd.panel.focus.previous": "Сфокусувати попередню панель",
|
||||
"cmd.panel.move.next_zone": "Перемістити панель до наступної зони",
|
||||
"cmd.panel.sash.down": "Змінити розмір роздільника панелей униз",
|
||||
"cmd.panel.sash.left": "Змінити розмір роздільника панелей ліворуч",
|
||||
"cmd.panel.sash.reset": "Скинути роздільник сфокусованої панелі",
|
||||
"cmd.panel.sash.right": "Змінити розмір роздільника панелей праворуч",
|
||||
"cmd.panel.sash.up": "Змінити розмір роздільника панелей угору",
|
||||
"cmd.panel.toggle": "Перемкнути сфокусовану панель",
|
||||
"cmd.pointcloud_reload": "Перезавантажити хмару точок",
|
||||
"cmd.sketch.replace": "Замінити ескіз",
|
||||
"cmd.sketch_point_divide": "Поділити криву",
|
||||
"cmd.ui.palette": "Пошук команд",
|
||||
"file_load.reloading_cloud": "Перезавантаження хмари точок",
|
||||
"help.sketch.point.divide": "Розміщує точки, що поділяють вибрані криві на рівні за довжиною частини. Точки залишаються на кожній кривій і зберігають свій крок, коли крива змінюється.",
|
||||
"hole_folder.applies_to": "Зміни застосовуються до {count} отворів у теці {folder}; кожен зберігає своє місце.",
|
||||
"nav.orbit_cursor_wrap.help": "Перетягування для обертання, що сягає краю виду, переносить курсор на протилежний край і продовжує обертання. Вимкнено: перетягування зупиняється на краю екрана. Не діє у Wayland і в браузері.",
|
||||
"nav.orbit_cursor_wrap.label": "Переносити курсор під час обертання",
|
||||
"parts.family.countersunk_socket_screw": "Гвинт із потайною головкою та внутрішнім шестигранником",
|
||||
"prefs.browser_body_features": "Операції під тілами",
|
||||
"prefs.browser_body_features_note": "Кожне тіло в браузері розгортається, показуючи операції часового ланцюжка, що його побудували, у порядку ланцюжка.",
|
||||
"prefs.design_tools.hole_group": "Групувати отвори, створені разом",
|
||||
"prefs.design_tools.hole_group_help": "Отвори, створені за один раз, опиняються в одній теці в історії, спершу закритій; відкрийте її, щоб редагувати отвір окремо.",
|
||||
"prefs.design_tools.hole_several": "Кілька отворів на одній грані",
|
||||
"prefs.design_tools.hole_several_help": "Вибір іншого місця на грані додає ще один отвір; вибір отвору видаляє його.",
|
||||
"prefs.history_folder_kind_icon": "Значок теки за її операціями",
|
||||
"prefs.history_folder_kind_icon_note": "Тека історії, усі операції якої одного типу, показує їхній значок.",
|
||||
"prefs.panel_layout.recovery": "Не вдалося відновити збережені компонування панелей. Збережені дані не втрачено; «Класичне» залишається доступним.",
|
||||
"prefs.shared_panel_layout": "Використовувати спільне компонування панелей",
|
||||
"prefs.shared_panel_layout_help": "Показувати наявні браузер, історію та асистента в переміщуваних панелях. Зміна набуде чинності після застосування налаштувань.",
|
||||
"prefs.sketch.escape_twice_finishes": "Подвійний Esc завершує ескіз",
|
||||
"prefs.sketch.escape_twice_finishes_note": "Два швидкі натискання Esc завершують ескіз. Вимкнено: Esc лише скасовує інструмент чи вибір, а ескіз завершує «Завершити ескіз».",
|
||||
"render.caustics_depth": "Глибина шляху каустики",
|
||||
"render.caustics_enable": "Каустика скла від точкових і спрямованих джерел світла",
|
||||
"render.caustics_help": "Кількість фотонів керує шумом і обсягом роботи. Радіус збирання обмінює чіткі деталі на плавнішу оцінку. CPU потребує непрямого освітлення.",
|
||||
"render.caustics_path_required": "Каустика на CPU потребує непрямого освітлення.",
|
||||
"render.caustics_photons": "Фотони",
|
||||
"render.caustics_radius": "Радіус збирання",
|
||||
"render.glass_abbe": "Число Аббе",
|
||||
"render.glass_dispersion": "Хроматична дисперсія",
|
||||
"render.glass_film": "Інтерференція тонкої плівки",
|
||||
"render.glass_film_ior": "IOR плівки",
|
||||
"render.glass_film_thickness": "Товщина плівки",
|
||||
"render.glass_model_enable": "Розширена модель скла",
|
||||
"render.glass_model_help": "Шорсткість скла розсіює промені, що проходять крізь нього. Дисперсія й колір плівки використовують три смуги довжин хвиль. Для шорстких листів потрібно вимкнути пряме пропускання тіней.",
|
||||
"render.glass_roughness": "Шорсткість скла",
|
||||
"render.gpu_job_shader_wait": "Підготовка шейдерів може тривати хвилини",
|
||||
"sketch.divide_hint": "Точки поділяють кожну криву на рівні за довжиною частини й зберігають їх, коли крива змінюється.",
|
||||
"ui.first_dimension_scales": "Перший розмір масштабує креслення",
|
||||
"ui.first_dimension_scales_tip": "Увімкнено: перший лінійний розмір ескізу масштабує креслення, яке він вимірює, тож форма зберігається. Вимкнено: розмір задає лише те, що вимірює.",
|
||||
"ui.heading_divide_curve": "ПОДІЛИТИ КРИВУ",
|
||||
"ui.heading_press_pull": "НАТИСНУТИ/ВИТЯГНУТИ",
|
||||
"ui.mesh_import_origin": "Перемістити до початку координат",
|
||||
"ui.mesh_import_origin_tip": "Центрувати сітку по X і Y, розмістивши її основу на Z = 0. Коли вимкнено, сітка зберігає координати, записані у файлі.",
|
||||
"ui.panel_layout.applied": "Застосовано «{name}» у робочій області «{workspace}»",
|
||||
"ui.panel_layout.cancel": "Скасувати",
|
||||
"ui.panel_layout.confirm_replace": "Замінити «{name}»?",
|
||||
"ui.panel_layout.copy": "Копіювати",
|
||||
"ui.panel_layout.current": "Поточне компонування",
|
||||
"ui.panel_layout.custom": "Власне",
|
||||
"ui.panel_layout.custom_hint": "Панелі переміщено після застосування: {name}.",
|
||||
"ui.panel_layout.details": "Подробиці",
|
||||
"ui.panel_layout.layout_workspace": "Робоча область компонування",
|
||||
"ui.panel_layout.page_defaults_hint": "Скидає налаштування цієї сторінки. Розташування панелей і збережені компонування залишаються без змін.",
|
||||
"ui.panel_layout.panel_layout": "Компонування панелей",
|
||||
"ui.panel_layout.panel_style": "Стиль панелей",
|
||||
"ui.panel_layout.replace": "Замінити компонування",
|
||||
"ui.panel_layout.replace_current": "Замінити поточним",
|
||||
"ui.panel_layout.replace_short": "Замінити",
|
||||
"ui.panel_layout.reset": "Скинути робочу область",
|
||||
"ui.panel_layout.reset_hint": "Повернути робочу область «{workspace}» до типового розташування. Збережені компонування залишаються без змін.",
|
||||
"ui.panel_layout.reset_short": "Скинути",
|
||||
"ui.panel_layout.restore_failed": "Не вдалося відновити ваше компонування",
|
||||
"ui.panel_layout.save": "Зберегти компонування",
|
||||
"ui.panel_layout.save_as": "Зберегти як",
|
||||
"ui.panel_layout.save_as_tile": "Зберегти як…",
|
||||
"ui.panel_layout.selected": "вибрано",
|
||||
"ui.panel_layout.suggested_name": "Компонування {n}",
|
||||
"ui.panel_layout.try_again": "Спробувати знову",
|
||||
"ui.panel_layout.validation.builtin": "Вбудовані компонування не можна змінювати",
|
||||
"ui.panel_layout.validation.duplicate": "Ця назва вже використовується",
|
||||
"ui.panel_layout.validation.empty": "Введіть назву",
|
||||
"ui.panel_layout.validation.full": "Збережено 64 з 64. Виберіть одне для заміни.",
|
||||
"ui.panel_layout.validation.invalid": "Використовуйте від 1 до 64 символів без керівних символів",
|
||||
"ui.panel_layout.workspace.classic": "Класичне",
|
||||
"ui.panel_layout.workspace.modelling": "Моделювання",
|
||||
"ui.panel_layout.workspace.render": "Рендеринг",
|
||||
"ui.panel_layout.workspace.review": "Огляд",
|
||||
"ui.panel_layout.workspace.sketch": "Ескіз",
|
||||
"ui.panel_layout.your_layout": "ваше компонування",
|
||||
"ui.point_cloud_reload": "Перезавантажити з файлу",
|
||||
"ui.project_references_construction": "Проєктувати посилання як допоміжну геометрію",
|
||||
"ui.project_references_construction_note": "«Проєктувати», «Перетин», «Включити 3D-геометрію» і ребра грані, які додає новий ескіз на грані, створюють допоміжну геометрію: посилання для креслення, не включені до профілів. Вони залишаються пов'язаними з моделлю.",
|
||||
"ui.replace_sketch.from_file": "З файлу проєкту…",
|
||||
"ui.replace_sketch.no_sketches": "У цьому проєкті немає ескізу, який можна взяти",
|
||||
"ui.segments": "Сегменти"
|
||||
}
|
||||
}
|
||||
+305
-289
File diff suppressed because it is too large
Load Diff
@@ -265,6 +265,7 @@
|
||||
"Edge": "Aresta",
|
||||
"Edges": "Arestas",
|
||||
"Edit": "Editar",
|
||||
"Edit Holes": "Editar furos",
|
||||
"Edit Profile Sketch": "Editar esboço do perfil",
|
||||
"Edit shortcuts": "Editar atalhos",
|
||||
"Enable rule": "Ativar regra",
|
||||
@@ -884,6 +885,7 @@
|
||||
"Variable Radius": "Raio variável",
|
||||
"Variable radius": "Raio variável",
|
||||
"Velocity": "Velocidade",
|
||||
"Vertical": "Vertical",
|
||||
"Vertices": "Vértices",
|
||||
"View": "Vista",
|
||||
"View navigator": "Navegador de vistas",
|
||||
@@ -976,6 +978,7 @@
|
||||
"browser.calibrate_click_a": "Clique na imagem para o ponto A ou digite suas coordenadas.",
|
||||
"browser.calibrate_click_b": "Clique na imagem para o ponto B ou digite suas coordenadas.",
|
||||
"browser.calibrate_title": "Calibrar: {name}",
|
||||
"browser.canvas_locked": "A tela está bloqueada. Desbloqueie-a primeiro.",
|
||||
"browser.capture_many": "{count} componentes foram movidos, mas suas posições não foram capturadas.",
|
||||
"browser.capture_note": "Capturar posição mantém a nova posição; Reverter posição restaura a anterior.",
|
||||
"browser.capture_one": "Um componente foi movido, mas sua posição não foi capturada.",
|
||||
@@ -1147,6 +1150,7 @@
|
||||
"cmd.file_save_mesh": "Salvar como malha",
|
||||
"cmd.file_send_to_slicer": "Enviar para o fatiador",
|
||||
"cmd.file_slicers": "Fatiadores instalados",
|
||||
"cmd.frame_end_cap": "Tampa de extremidade",
|
||||
"cmd.frame_member": "Membro estrutural",
|
||||
"cmd.frame_profile_insert": "Inserir perfil",
|
||||
"cmd.frame_profile_list": "Biblioteca de perfis",
|
||||
@@ -1205,6 +1209,7 @@
|
||||
"cmd.material_properties_directional": "Módulo de elasticidade direcional",
|
||||
"cmd.material_properties_validate": "Validar dados do material físico",
|
||||
"cmd.mesh_convert": "Converter malha",
|
||||
"cmd.model_body_features": "Listar características do corpo",
|
||||
"cmd.model_edges": "Listar arestas",
|
||||
"cmd.model_faces": "Listar faces",
|
||||
"cmd.model_threads": "Listar roscas",
|
||||
@@ -1233,8 +1238,11 @@
|
||||
"cmd.panel.dismiss": "Dispensar prévia do painel",
|
||||
"cmd.panel.float": "Desacoplar painel",
|
||||
"cmd.panel.focus": "Focar painel",
|
||||
"cmd.panel.focus.next": "Focar no próximo painel",
|
||||
"cmd.panel.focus.previous": "Focar no painel anterior",
|
||||
"cmd.panel.list": "Listar painéis",
|
||||
"cmd.panel.move": "Mover painel",
|
||||
"cmd.panel.move.next_zone": "Mover painel para a próxima zona",
|
||||
"cmd.panel.native_close": "Reacoplar seção de painel nativo",
|
||||
"cmd.panel.open": "Abrir painel",
|
||||
"cmd.panel.peek": "Espiar painel recolhido",
|
||||
@@ -1242,6 +1250,12 @@
|
||||
"cmd.panel.reset_pair": "Redefinir divisor do painel",
|
||||
"cmd.panel.resize": "Redimensionar seção do painel",
|
||||
"cmd.panel.resize_pair": "Redimensionar divisor do painel",
|
||||
"cmd.panel.sash.down": "Redimensionar divisor do painel para baixo",
|
||||
"cmd.panel.sash.left": "Redimensionar divisor do painel para a esquerda",
|
||||
"cmd.panel.sash.reset": "Redefinir divisor do painel focado",
|
||||
"cmd.panel.sash.right": "Redimensionar divisor do painel para a direita",
|
||||
"cmd.panel.sash.up": "Redimensionar divisor do painel para cima",
|
||||
"cmd.panel.toggle": "Alternar o painel focado",
|
||||
"cmd.parameters_add": "Adicionar parâmetro do usuário",
|
||||
"cmd.parameters_change": "Alterar parâmetros",
|
||||
"cmd.parameters_comment": "Comentar parâmetro",
|
||||
@@ -1365,6 +1379,7 @@
|
||||
"cmd.sketch.construction_line.tangent_external": "Tangente por um ponto externo",
|
||||
"cmd.sketch.construction_line.tangent_two": "Tangente comum",
|
||||
"cmd.sketch.construction_line.vertical": "Reta de construção vertical",
|
||||
"cmd.sketch.replace": "Substituir esboço",
|
||||
"cmd.sketch_arc3d": "Arco 3D",
|
||||
"cmd.sketch_arc_center_point": "Arco por ponto central",
|
||||
"cmd.sketch_arc_tangent": "Arco tangente",
|
||||
@@ -1496,6 +1511,7 @@
|
||||
"cmd.timeline_stop": "Parar histórico",
|
||||
"cmd.timeline_suppress": "Suprimir recurso",
|
||||
"cmd.ui.assistant": "Alternar assistente",
|
||||
"cmd.ui.palette": "Pesquisar comandos",
|
||||
"cmd.view.navigator": "Navegador de vistas personalizadas",
|
||||
"cmd.view.render_browser": "Navegador de renderização",
|
||||
"cmd.view.render_dock": "Mover dock de renderização",
|
||||
@@ -1609,6 +1625,7 @@
|
||||
"dialog.pattern_sketch_not_object": "Escolha corpos ou recursos: um esboço não é nenhum dos dois. Repita suas curvas com o Padrão ou Espelhar do próprio esboço, ou extrude-o primeiro.",
|
||||
"dialog.primitive_point_tip": "Um ponto que preenche X, Y e Z: clique aqui e depois clique em um vértice, aresta ou face do modelo, em um ponto de um esboço ou na origem.",
|
||||
"dialog.reference_edge_tip": "Uma aresta reta da face escolhida a partir da qual medir a distância abaixo: clique aqui e depois clique na aresta.",
|
||||
"dialog.right_click_pick": "Selecione {input} primeiro",
|
||||
"dialog.select": "↖ Selecionar",
|
||||
"dialog.selected_count": "↖ {count} selecionados",
|
||||
"dialog.selection_constraint": "Restrição {id}",
|
||||
@@ -1653,6 +1670,8 @@
|
||||
"dxf.tolerance": "Tolerância da curva",
|
||||
"dxf.tolerance_help": "Somente corpos visíveis. As curvas usam segmentos retos. Uma tolerância menor gera curvas mais finas e usa mais tempo e memória.",
|
||||
"each rail's curves must be in one sketch": "as curvas de cada trilho devem estar em um único esboço",
|
||||
"error.end_cap_faces": "Selecione pelo menos uma face de extremidade aberta de um membro",
|
||||
"error.end_cap_unresolved": "A extremidade {ends} desta tampa não está mais no modelo. Selecione as faces de extremidade novamente",
|
||||
"feature computation ended without a result": "o cálculo do recurso terminou sem resultado",
|
||||
"file.open.drawing_filter": "Projetos, arquivos CAD, malhas e desenhos",
|
||||
"file.open.portal_fallback.no_portal_service": "O seletor de arquivos que abriu não é o da área de trabalho: o serviço de portal da área de trabalho não está disponível.",
|
||||
@@ -1750,6 +1769,7 @@
|
||||
"help.file.send_to_slicer": "Salva os corpos selecionados como arquivo 3MF e o abre no fatiador que você escolher. Use para ir do modelo à impressão em um só passo.",
|
||||
"help.font_details": "A interface usa as fontes integradas do egui (Ubuntu Light e Hack, sob as licenças Ubuntu Font Licence e MIT/Bitstream Vera; Noto Emoji e a fonte de ícones emoji, sob OFL e MIT). O texto dos esboços usa Liberation Sans (SIL OFL 1.1). O pacote opcional de fontes da The Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), não está incluído nas compilações do SolidCraft.",
|
||||
"help.fonts": "Fontes",
|
||||
"help.frame.end_cap": "Fecha as extremidades abertas dos membros com placas no formato do contorno do perfil. Use para tampar tubos, cantoneiras e vigas, sobre a extremidade ou embutidas nela.",
|
||||
"help.frame.member": "Coloca um perfil, como um tubo ou um perfil extrudado de alumínio, ao longo das linhas de um esboço de estrutura, um membro por linha. Use para construir estruturas, racks e construções soldadas.",
|
||||
"help.inspect.accessibility": "Colore as faces que uma ferramenta alcança a partir de uma direção e as que ela não alcança. Use para verificar uma peça para usinagem ou moldagem por esse lado.",
|
||||
"help.inspect.center_of_mass": "Mostra o centro de massa dos corpos, de cada um e de todos juntos, com densidade uniforme. Use para verificar o equilíbrio e para onde uma peça vai tombar.",
|
||||
@@ -2015,6 +2035,7 @@
|
||||
"help.view.visual_style": "Muda como o modelo é desenhado: sombreado com ou sem arestas, aramado ou com arestas ocultas. Use aramado para ver o interior e sombreado para uma aparência limpa.",
|
||||
"history.sketch_under_constrained": "Subrestrito ({count} graus de liberdade)",
|
||||
"history.sketch_under_constrained_one": "Subrestrito ({count} grau de liberdade)",
|
||||
"hole_folder.applies_to": "As alterações se aplicam aos {count} furos em {folder}; cada um mantém seu lugar.",
|
||||
"hole_presets.confirm_delete": "Confirmar exclusão",
|
||||
"hole_presets.delete": "Excluir",
|
||||
"hole_presets.delete_prompt": "Excluir esta predefinição pessoal? Os furos existentes não mudam.",
|
||||
@@ -2417,6 +2438,7 @@
|
||||
"parts.dimension.width": "Largura",
|
||||
"parts.family.bearing": "Rolamento rígido de esferas (envoltória)",
|
||||
"parts.family.button_head_cap_screw": "Parafuso de cabeça abaulada com sextavado interno",
|
||||
"parts.family.countersunk_socket_screw": "Parafuso de cabeça cônica com sextavado interno",
|
||||
"parts.family.dowel_pin": "Pino paralelo (cavilha)",
|
||||
"parts.family.hex_bolt": "Parafuso de cabeça sextavada",
|
||||
"parts.family.hex_cap_screw_inch": "Parafuso de cabeça sextavada (polegada)",
|
||||
@@ -2515,6 +2537,8 @@
|
||||
"prefs.bottom_centre": "Inferior central",
|
||||
"prefs.bottom_right": "Inferior direito",
|
||||
"prefs.browser": "Navegador",
|
||||
"prefs.browser_body_features": "Características sob os corpos",
|
||||
"prefs.browser_body_features_note": "Cada corpo no navegador expande para mostrar as características da linha do tempo que o construíram, na ordem da linha do tempo.",
|
||||
"prefs.browser_components_open": "Componentes começam abertos",
|
||||
"prefs.browser_components_open_note": "Cada componente no navegador começa aberto, como antes, em vez de fechado até que você o abra.",
|
||||
"prefs.browser_eye_left": "Olho ao lado da seta de recolher",
|
||||
@@ -2555,7 +2579,11 @@
|
||||
"prefs.design_tools.degrees": "Graus",
|
||||
"prefs.design_tools.double_click_help": "Ou para editar um vinculado no local.",
|
||||
"prefs.design_tools.ghost": "Mostrar o lugar antigo das peças movidas como fantasma",
|
||||
"prefs.design_tools.hole_group": "Agrupar furos feitos juntos",
|
||||
"prefs.design_tools.hole_group_help": "Furos feitos de uma vez compartilham uma pasta no Histórico, fechada inicialmente; abra-a para editar um furo separadamente.",
|
||||
"prefs.design_tools.hole_moves_help": "Escolher a face novamente move o furo em vez de removê-lo.",
|
||||
"prefs.design_tools.hole_several": "Vários furos em uma face",
|
||||
"prefs.design_tools.hole_several_help": "Clicar em outro lugar na face adiciona outro furo; clicar em um furo o remove.",
|
||||
"prefs.design_tools.hole_snaps_help": "O meio de uma face e os centros de suas arestas circulares.",
|
||||
"prefs.design_tools.imported_files": "Arquivos importados",
|
||||
"prefs.design_tools.note": "Observação",
|
||||
@@ -2637,6 +2665,8 @@
|
||||
"prefs.history": "Histórico",
|
||||
"prefs.history_bar_groups": "Agrupar a barra de histórico em grupos",
|
||||
"prefs.history_bar_groups_note": "Em um histórico longo, uma sequência de recursos de um componente se agrupa em um único indicador, e as pastas de recursos começam recolhidas. Uma montagem STEP inserida vai para uma pasta Grupo. Desativado mostra cada recurso, começa com as pastas abertas e não cria pasta.",
|
||||
"prefs.history_folder_kind_icon": "Ícone da pasta baseado em suas características",
|
||||
"prefs.history_folder_kind_icon_note": "Uma pasta do Histórico cujas características são todas do mesmo tipo mostra o ícone delas.",
|
||||
"prefs.history_group_joints": "Agrupar juntas no Histórico",
|
||||
"prefs.history_group_joints_note": "Duas ou mais juntas aparecem como um único botão com sua contagem, e um clique mostra cada uma. Desativado mostra cada junta.",
|
||||
"prefs.history_origin_bodies": "Mostrar origem e corpos no topo",
|
||||
@@ -2742,6 +2772,7 @@
|
||||
"prefs.origin_plane_names": "Nomes dos planos da origem",
|
||||
"prefs.origin_plane_names_note": "Nomes mostrados no navegador, nas caixas de diálogo e nas listas. {top} é XY, {front} é XZ e {right} é YZ, com Z para cima. Comandos, scripts e projetos salvos mantêm XY, XZ e YZ.",
|
||||
"prefs.overall_speed": "Velocidade geral",
|
||||
"prefs.panel_layout.recovery": "Não foi possível restaurar os layouts de painéis salvos. Os dados salvos são mantidos; o estilo Clássico permanece disponível.",
|
||||
"prefs.parameter_list_rows": "Linhas da lista de parâmetros",
|
||||
"prefs.parameter_list_rows_tip": "O máximo de parâmetros que a seta para baixo lista em uma caixa de expressão vazia.",
|
||||
"prefs.persistent_ribbon_pressed": "Destacar comandos ativos da faixa de opções",
|
||||
@@ -2803,6 +2834,8 @@
|
||||
"prefs.remember_dialog_values.help": "Desativado por padrão. Quando ativado, depois que um comando dá certo, seus valores e opções seguros são reutilizados na próxima vez que você abrir o mesmo comando, até o SolidCraft fechar.",
|
||||
"prefs.render_legacy_image_defaults": "Usar os padrões anteriores da imagem de Renderizar",
|
||||
"prefs.render_legacy_image_defaults_help": "Manter o fluxo manual anterior: novas configurações usam rasterização em CPU, o ray tracing em CPU mantém amostragem fixa e você abre os resultados renderizados manualmente. Reenquadrar ao entrar em Renderizar, trocar de tomada sem restaurar as câmeras e usar o enquadramento e a navegação anteriores. Desativar o retorno automático da imagem ao vivo. As configurações salvas não mudam.",
|
||||
"prefs.render_legacy_memory_admission": "Usar verificações de memória de renderizações anteriores",
|
||||
"prefs.render_legacy_memory_admission_help": "Permitir renderizações nativas dentro dos orçamentos fixos de memória compartilhada e do host mesmo quando a estimativa excede a RAM disponível. Limites do dispositivo e verificações de alocação ainda se aplicam.",
|
||||
"prefs.render_previous_geometry_budget": "Usar o orçamento de geometria anterior da prévia de Renderizar",
|
||||
"prefs.render_previous_geometry_budget_help": "Restaurar o limite fixo de geometria anterior (512 MiB em desktop de 64 bits, 128 MiB nos demais) em vez do orçamento baseado no dispositivo.",
|
||||
"prefs.reports_saved": "{n} salvos",
|
||||
@@ -2829,6 +2862,8 @@
|
||||
"prefs.select_other_hidden": "Selecionar geometria oculta com Selecionar outro",
|
||||
"prefs.select_other_hidden_help": "Ativado: incluir corpos ocultos, esboços e arestas encobertas perto do ponteiro. Desativado: usar a lista original de geometria visível sob o ponteiro.",
|
||||
"prefs.selecting": "Seleção",
|
||||
"prefs.shared_panel_layout": "Usar layout de painel compartilhado",
|
||||
"prefs.shared_panel_layout_help": "Mostrar o Navegador, Histórico e Assistente existentes em painéis móveis. A alteração tem efeito quando as preferências são aplicadas.",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift só adiciona; Ctrl / Cmd alterna",
|
||||
"prefs.shift_add_note": "Ativado: Shift adiciona, Ctrl / Cmd alterna. Desativado (padrão): ambos alternam.",
|
||||
@@ -2848,9 +2883,13 @@
|
||||
"prefs.sketch.center_arc": "O arco pelo centro segue o cursor",
|
||||
"prefs.sketch.click_selects": "Clique seleciona",
|
||||
"prefs.sketch.conflict_colour": "Cor de conflito",
|
||||
"prefs.sketch.cursor_coordinates": "Mostrar as coordenadas do cursor em um esboço",
|
||||
"prefs.sketch.cursor_coordinates_note": "Ao lado do ponteiro, seu X e Y a partir da origem do esboço, também sem nenhuma ferramenta ativa. Desativado: só enquanto uma ferramenta posiciona um ponto.",
|
||||
"prefs.sketch.drawing": "Desenho",
|
||||
"prefs.sketch.ellipse_axes": "Desenhar elipses com seus eixos",
|
||||
"prefs.sketch.ellipse_axes_note": "Os eixos maior e menor como linhas de construção, para que os semieixos e eixos possam ser cotados. Desativado: apenas a elipse, e D nela dá o raio menor onde quer que o valor seja puxado, desenhado e rotulado R como antes.",
|
||||
"prefs.sketch.escape_twice_finishes": "Duplo Esc finaliza o esboço",
|
||||
"prefs.sketch.escape_twice_finishes_note": "Dois toques rápidos no Esc encerram o esboço. Desligado: Esc apenas cancela a ferramenta ou a seleção, e Finalizar Esboço encerra o esboço.",
|
||||
"prefs.sketch.exit_keep": "Manter",
|
||||
"prefs.sketch.exit_previous": "Voltar à vista anterior",
|
||||
"prefs.sketch.exit_unless_rotated": "A menos que girada",
|
||||
@@ -3193,8 +3232,10 @@
|
||||
"render.category_paint": "Tinta",
|
||||
"render.category_plastic": "Plástico",
|
||||
"render.category_wood": "Madeira",
|
||||
"render.caustics_area_lights": "Cáusticas de luzes de área",
|
||||
"render.caustics_depth": "Profundidade de caminho das cáusticas",
|
||||
"render.caustics_enable": "Cáusticas de vidro a partir de luzes pontuais e direcionais",
|
||||
"render.caustics_environment": "Cáusticas do ambiente",
|
||||
"render.caustics_help": "A contagem de fótons controla o ruído e o trabalho. O raio de coleta troca detalhe nítido por uma estimativa mais suave. A CPU exige Iluminação indireta.",
|
||||
"render.caustics_path_required": "As cáusticas em CPU exigem Iluminação indireta.",
|
||||
"render.caustics_photons": "Fótons",
|
||||
@@ -3411,6 +3452,12 @@
|
||||
"render.cpu_subsurface_denoise_reason": "O espalhamento subsuperficial em CPU precisa de Redução de ruído desativada. Suas configurações são mantidas.",
|
||||
"render.cpu_subsurface_help": "O espalhamento redireciona a luz dentro do Vidro fechado. Taxas positivas precisam de Iluminação indireta com Redução de ruído desativada. A taxa é de colisões por mm; 0 não adiciona espalhamento. Um viés de fase positivo favorece direções para a frente; negativo favorece para trás.",
|
||||
"render.cpu_summary": "Ray tracing em CPU · reflexos · HDR · luzes direcionais e pontuais",
|
||||
"render.cpu_threads": "CPU workers",
|
||||
"render.cpu_threads_auto": "Automático",
|
||||
"render.cpu_threads_custom": "Personalizado",
|
||||
"render.cpu_threads_help": "Automático usa CPU workers disponíveis. Um worker roda em série. Mais workers podem precisar de mais memória.",
|
||||
"render.cpu_threads_single": "Único",
|
||||
"render.cpu_threads_web": "Renderização no navegador usa um cooperative worker. A escolha de worker do desktop salva é preservada.",
|
||||
"render.cpu_transparent_help": "PNG transparente remove o fundo e mantém a cobertura das bordas. A opacidade de corpos e faces deve ficar em 100%.",
|
||||
"render.cpu_volume_enable_path": "Ativar Iluminação indireta",
|
||||
"render.cpu_volume_enable_path_plan": "Ray tracing em CPU · profundidade de caminho {depth} · {spp} amostras/pixel · semente {seed} · sombras traçadas. Mantém a atmosfera criada e o orçamento da imagem.",
|
||||
@@ -3419,6 +3466,40 @@
|
||||
"render.cpu_volume_method_incompatible": "Estas configurações de luz, amostragem ou atmosfera não podem ser transferidas para este método. Suas configurações são mantidas.",
|
||||
"render.cpu_volume_path_required": "Ative Iluminação indireta para usar a Atmosfera em CPU.",
|
||||
"render.cpu_warm_cool": "Quente e frio",
|
||||
"render.denoise_class_background": "Ignorado: fundo",
|
||||
"render.denoise_class_coverage": "Ignorado: cobertura parcial",
|
||||
"render.denoise_class_degenerate": "Ignorado: caminho degenerado",
|
||||
"render.denoise_class_depth": "Ignorado: limite de profundidade do caminho",
|
||||
"render.denoise_class_emitter": "Ignorado: emissor de luz",
|
||||
"render.denoise_class_exit": "Ignorado: saída incompatível",
|
||||
"render.denoise_class_identity": "Ignorado: limite de identidade do guia",
|
||||
"render.denoise_class_lens": "Ignorado: profundidade de campo",
|
||||
"render.denoise_class_material": "Ignorado: material não suportado",
|
||||
"render.denoise_class_nested": "Ignorado: meio aninhado",
|
||||
"render.denoise_class_optical": "Elegível: superfície refratada",
|
||||
"render.denoise_class_reflection": "Ignorado: ponto final reflexivo",
|
||||
"render.denoise_class_surface": "Elegível: superfície",
|
||||
"render.denoise_class_tir": "Ignorado: reflexão total interna",
|
||||
"render.denoise_class_transmission": "Ignorado: transmissão adicional",
|
||||
"render.denoise_class_unavailable": "Ignorado: sem guia",
|
||||
"render.denoise_class_volume": "Ignorado: espalhamento de volume",
|
||||
"render.denoise_diagnostics_counts": "Elegíveis: {eligible} · Ignorados: {skipped}",
|
||||
"render.denoise_diagnostics_enable": "Coletar diagnósticos de redução de ruído",
|
||||
"render.denoise_diagnostics_grid": "Contagens de pixels no tamanho interno {width} × {height}.",
|
||||
"render.denoise_diagnostics_help": "Coleta contagens de pixels elegíveis e ignorados mesmo quando a redução de ruído está desligada. As contagens usam o tamanho de renderização interno; a máscara usa o tamanho de saída.",
|
||||
"render.denoise_diagnostics_title": "Diagnósticos de redução de ruído",
|
||||
"render.denoise_export_mask": "Exportar máscara PNG",
|
||||
"render.denoise_firefly": "Suprimir pixels brilhantes isolados",
|
||||
"render.denoise_format_mask": "Máscara PNG",
|
||||
"render.denoise_mask_copy_help": "Exportar a máscara de redução de ruído como PNG, ou voltar à imagem renderizada para copiá-la.",
|
||||
"render.denoise_mask_unavailable": "Ative diagnósticos de redução de ruído e renderize uma imagem para inspecionar sua máscara.",
|
||||
"render.denoise_optical_filter": "Filtrar espelho e vidro",
|
||||
"render.denoise_optical_filter_help": "Filtrar luz refletida e transmitida elegível. Desligue para redução de ruído apenas em superfícies opacas.",
|
||||
"render.denoise_passes": "Passagens de filtro",
|
||||
"render.denoise_settings_help": "Mais passagens suavizam uma área maior. A intensidade controla quanto cada passagem aplica de filtro. Caminhos ópticos não suportados permanecem sem filtro.",
|
||||
"render.denoise_strength": "Intensidade da redução de ruído",
|
||||
"render.denoise_view_image": "Imagem renderizada",
|
||||
"render.denoise_view_mask": "Máscara de redução de ruído",
|
||||
"render.diag_bodies": "Corpos visíveis",
|
||||
"render.diag_job_details": "Detalhes do trabalho capturado",
|
||||
"render.diag_last_check": "Última pré-verificação",
|
||||
@@ -3624,6 +3705,7 @@
|
||||
"render.glass_model_help": "A rugosidade do vidro espalha os raios transmitidos. A dispersão e a cor da película usam três bandas de comprimento de onda. Chapas ásperas exigem sombras transmitidas retas desativadas.",
|
||||
"render.glass_roughness": "Rugosidade do vidro",
|
||||
"render.gpu_depth": "Profundidade máxima de caminho",
|
||||
"render.gpu_job_shader_wait": "Configuração do shader pode levar minutos",
|
||||
"render.gpu_options_help": "Amostras, profundidade, semente e exposição são salvas com esta configuração. Apenas o método de imagem ativo é salvo.",
|
||||
"render.gpu_path_crashed": "O SolidCraft fechou durante a configuração neste adaptador gráfico da última vez, muito provavelmente dentro do driver gráfico, então ele não é configurado de novo sozinho. Escolha ray tracing em CPU ou tente novamente (uma atualização do driver também tenta de novo).",
|
||||
"render.gpu_path_failed": "Path tracer em GPU indisponível",
|
||||
@@ -3972,6 +4054,8 @@
|
||||
"render.material_transient": "Substituições ópticas temporárias para esta aba de documento. Elas não são salvas no projeto, na configuração de renderização nem na biblioteca de materiais.",
|
||||
"render.material_v_up": "O V da textura aponta para cima na imagem",
|
||||
"render.material_weight": "Peso do verniz (0–1)",
|
||||
"render.metal_energy_compensation": "Recuperar reflectância de metal rugoso",
|
||||
"render.metal_energy_compensation_help": "Compensar luz perdida entre microfaceta de metal rugoso. Renderização CPU precisa de Iluminação indireta.",
|
||||
"render.method_cpu": "Ray tracing em CPU",
|
||||
"render.method_gpu": "Path tracing em GPU",
|
||||
"render.method_limit_raster": "A rasterização usa a prévia de estúdio opaca fixa. Selecione um método de ray tracing explícito para os controles ópticos suportados.",
|
||||
@@ -4100,6 +4184,8 @@
|
||||
"render.quality_denoise_on": "Redução de ruído: Ativada",
|
||||
"render.quality_draft": "Rascunho",
|
||||
"render.quality_high": "Alta",
|
||||
"render.quality_legacy_samples": "Valor salvo: {samples} spp. Novas seleções são limitadas a {maximum} spp.",
|
||||
"render.quality_preset_limit": "Esta predefinição excede o limite de seleção de 16384 spp. Escolha uma contagem de amostras até 16384.",
|
||||
"render.quality_projection_help": "Esta revisão altera apenas resolução, orçamento de amostras, profundidade de caminho, semente e redução de ruído. As outras configurações são mantidas; o orçamento não certifica a convergência.",
|
||||
"render.quality_review": "Revisar orçamento de amostragem",
|
||||
"render.quality_summary": "{width} × {height} · {samples} amostras · profundidade {depth} · semente {seed} · {denoise}",
|
||||
@@ -4247,6 +4333,7 @@
|
||||
"render.show_shots_label": "Mostrar faixa de tomadas",
|
||||
"render.size_4k": "4K",
|
||||
"render.size_4k_uhd": "4K UHD",
|
||||
"render.size_8k_uhd": "8K UHD",
|
||||
"render.size_custom": "Personalizado…",
|
||||
"render.size_full_hd": "Full HD",
|
||||
"render.size_hd": "HD",
|
||||
@@ -4409,6 +4496,11 @@
|
||||
"render.subsurface_enable": "Passeio aleatório de espalhamento interior",
|
||||
"render.subsurface_help": "Apenas dielétrico fechado. O espalhamento e a absorção RGB são coeficientes separados por mm. Os caminhos se espalham dentro da geometria real e depois refratam ou refletem no contorno. Desative a transmissão de sombra reta, a redução de ruído de superfície e o volume exterior; use um estrato de Fresnel. Não é um shader de difusão, uma grade de densidade nem um material medido. Meios densos podem precisar de mais amostras e profundidade de caminho.",
|
||||
"render.subsurface_rate": "Taxa de colisão de espalhamento",
|
||||
"render.supersampling": "Superamostragem",
|
||||
"render.supersampling_dimensions": "Renderiza {width} × {height} e reduz para {output_width} × {output_height}. Usa quatro vezes os pixels.",
|
||||
"render.supersampling_help": "Renderiza com o dobro da largura e altura, depois reduz em luz linear. O tamanho de saída permanece inalterado.",
|
||||
"render.supersampling_off": "Desligado",
|
||||
"render.supersampling_x2": "2×",
|
||||
"render.surface_import.author": "Autor",
|
||||
"render.surface_import.busy": "Importando imagem…",
|
||||
"render.surface_import.complete": "Escolha uma imagem e informe seu autor, fonte e licença.",
|
||||
@@ -4422,6 +4514,8 @@
|
||||
"render.surface_import.saved_cpu": "Salve os mapas para usá-los com a renderização em CPU.",
|
||||
"render.surface_import.source": "Fonte",
|
||||
"render.surface_import.title": "Importar imagem",
|
||||
"render.texture_filtering": "Filtrar detalhes de textura",
|
||||
"render.texture_filtering_help": "Usa níveis mip e filtragem anisotrópica para reduzir aliasing de textura sob minificação. Usa mais memória; desligado mantém a filtragem anterior.",
|
||||
"render.tone_aces_fitted": "ACES ajustado",
|
||||
"render.tone_reinhard": "Reinhard",
|
||||
"render.transmission_scope": "O vidro em GPU suporta meios disjuntos certificados. Meios aninhados irrestritos e um estimador de transmissão sem ruído não são fornecidos.",
|
||||
@@ -4652,6 +4746,10 @@
|
||||
"sketch_text.path_clear": "Tirar o texto da curva",
|
||||
"sketch_text.path_hint": "Uma curva do esboço que o texto segue: clique aqui e depois na curva",
|
||||
"sketch_text.use_font_file": "Usar o arquivo de fonte {path}",
|
||||
"sketch_text.valign_baseline": "Linha de base",
|
||||
"sketch_text.valign_bottom": "Base",
|
||||
"sketch_text.valign_middle": "Meio",
|
||||
"sketch_text.valign_top": "Topo",
|
||||
"solid": "sólido",
|
||||
"status.editing": "Editando {name}",
|
||||
"status.navigation": "Mapeamento do mouse: {mapping}",
|
||||
@@ -4987,6 +5085,7 @@
|
||||
"ui.agent_chat_setup_title": "Configurar um assistente",
|
||||
"ui.agent_chat_side": "Lado do chat com agente",
|
||||
"ui.agent_chat_signed_in": "conectado",
|
||||
"ui.agent_chat_snap_none_found": "Nenhum agente de programação encontrado. O pacote Snap é confinado, então não consegue ver nem iniciar os agentes de programação instalados neste computador. Para usá-los, instale o SolidCraft pelo pacote AppImage, .deb ou .rpm. Um agente que usa uma API compatível com OpenAI também funciona no pacote Snap: configure-o em Adicionar agente.",
|
||||
"ui.agent_chat_state_auth": "É preciso entrar",
|
||||
"ui.agent_chat_state_busy": "Trabalhando…",
|
||||
"ui.agent_chat_state_exited": "Agente parado",
|
||||
@@ -5362,6 +5461,17 @@
|
||||
"ui.ellipse": "Elipse",
|
||||
"ui.emboss_wrap_note": "Perfis de linhas ortogonais tangentes a uma parede cilíndrica suportada são envolvidos automaticamente. Escolha uma parede para definir um destino.",
|
||||
"ui.end": "Fim",
|
||||
"ui.end_cap.chamfer": "Chanfro dos cantos",
|
||||
"ui.end_cap.direction": "Direção",
|
||||
"ui.end_cap.faces": "Faces de extremidade",
|
||||
"ui.end_cap.inset": "Recuo",
|
||||
"ui.end_cap.inset_kind": "Recuo por",
|
||||
"ui.end_cap.inset_ratio": "Proporção de recuo",
|
||||
"ui.end_cap.inward": "Para dentro",
|
||||
"ui.end_cap.length": "Comprimento",
|
||||
"ui.end_cap.outward": "Para fora",
|
||||
"ui.end_cap.ratio": "Proporção da espessura",
|
||||
"ui.end_cap_title": "TAMPA DE EXTREMIDADE",
|
||||
"ui.end_radius": "Raio final",
|
||||
"ui.end_scale": "Escala final",
|
||||
"ui.ends": "Extremidades",
|
||||
@@ -5516,6 +5626,7 @@
|
||||
"ui.heading_plastic": "PLÁSTICO",
|
||||
"ui.heading_position": "POSIÇÃO",
|
||||
"ui.heading_prepare": "PREPARAR",
|
||||
"ui.heading_press_pull": "Puxar / Empurrar",
|
||||
"ui.heading_rectangular_pattern": "PADRÃO RETANGULAR",
|
||||
"ui.heading_revolve": "REVOLUÇÃO",
|
||||
"ui.heading_right": "DIREITA",
|
||||
@@ -5758,6 +5869,42 @@
|
||||
"ui.panel_host.surface": "Painel",
|
||||
"ui.panel_host.tab": "Aba do painel",
|
||||
"ui.panel_host.tabs": "Todas as abas",
|
||||
"ui.panel_layout.applied": "Aplicado {name} a {workspace}",
|
||||
"ui.panel_layout.cancel": "Cancelar",
|
||||
"ui.panel_layout.confirm_replace": "Substituir \"{name}\"?",
|
||||
"ui.panel_layout.copy": "Copiar",
|
||||
"ui.panel_layout.current": "Layout atual",
|
||||
"ui.panel_layout.custom": "Personalizado",
|
||||
"ui.panel_layout.custom_hint": "Painéis foram movidos desde {name}.",
|
||||
"ui.panel_layout.details": "Detalhes",
|
||||
"ui.panel_layout.layout_workspace": "Layout do espaço de trabalho",
|
||||
"ui.panel_layout.page_defaults_hint": "Redefine as configurações desta página. Arranjos de painéis e layouts salvos são mantidos.",
|
||||
"ui.panel_layout.panel_layout": "Layout de painéis",
|
||||
"ui.panel_layout.panel_style": "Estilo do painel",
|
||||
"ui.panel_layout.replace": "Substituir layout",
|
||||
"ui.panel_layout.replace_current": "Substituir pelo atual",
|
||||
"ui.panel_layout.replace_short": "Substituir",
|
||||
"ui.panel_layout.reset": "Redefinir espaço de trabalho",
|
||||
"ui.panel_layout.reset_hint": "Redefinir {workspace} para seu arranjo padrão. Layouts salvos são mantidos.",
|
||||
"ui.panel_layout.reset_short": "Redefinir",
|
||||
"ui.panel_layout.restore_failed": "Não foi possível restaurar seu layout",
|
||||
"ui.panel_layout.save": "Salvar layout",
|
||||
"ui.panel_layout.save_as": "Salvar como",
|
||||
"ui.panel_layout.save_as_tile": "Salvar como…",
|
||||
"ui.panel_layout.selected": "selecionado",
|
||||
"ui.panel_layout.suggested_name": "Layout {n}",
|
||||
"ui.panel_layout.try_again": "Tentar novamente",
|
||||
"ui.panel_layout.validation.builtin": "Layouts integrados não podem ser alterados",
|
||||
"ui.panel_layout.validation.duplicate": "Você já tem este nome",
|
||||
"ui.panel_layout.validation.empty": "Insira um nome",
|
||||
"ui.panel_layout.validation.full": "64 de 64 salvos. Escolha um para substituir.",
|
||||
"ui.panel_layout.validation.invalid": "Use 1–64 caracteres, sem caracteres de controle",
|
||||
"ui.panel_layout.workspace.classic": "Clássico",
|
||||
"ui.panel_layout.workspace.modelling": "Modelagem",
|
||||
"ui.panel_layout.workspace.render": "Renderização",
|
||||
"ui.panel_layout.workspace.review": "Revisão",
|
||||
"ui.panel_layout.workspace.sketch": "Esboço",
|
||||
"ui.panel_layout.your_layout": "seu layout",
|
||||
"ui.parallel": "Paralelo",
|
||||
"ui.parameters": "Parâmetros",
|
||||
"ui.part_size_needs_a_part": "Selecione uma peça padrão inserida (um parafuso, uma porca, uma arruela ou um pino) para alterar o tamanho. Para aumentar ou diminuir um corpo, use Escala.",
|
||||
@@ -5823,6 +5970,8 @@
|
||||
"ui.profiles": "Perfis",
|
||||
"ui.project": "Projetar",
|
||||
"ui.project_face_edges_sketch": "Projetar arestas da face em novos esboços",
|
||||
"ui.project_references_construction": "Projetar referências como geometria de construção",
|
||||
"ui.project_references_construction_note": "Projetar, Intersectar, Incluir Geometria 3D e as arestas da face de um novo esboço em uma face criam geometria de construção: referências para desenhar, deixadas fora dos perfis. Elas permanecem vinculadas ao modelo.",
|
||||
"ui.properties": "Propriedades",
|
||||
"ui.properties.copy_matrix": "Copiar matriz",
|
||||
"ui.properties.first_moments": "Primeiros momentos",
|
||||
@@ -5866,6 +6015,8 @@
|
||||
"ui.renderer": "Renderizador",
|
||||
"ui.repeat": "Repetir",
|
||||
"ui.repeat_nothing": "Ainda não há nada para repetir: inicie primeiro uma ferramenta ou caixa de diálogo.",
|
||||
"ui.replace_sketch.from_file": "De um Arquivo de Projeto…",
|
||||
"ui.replace_sketch.no_sketches": "Esse projeto não tem esboço para usar",
|
||||
"ui.replace_with_link_done": "As cópias agora são posicionamentos do projeto vinculado.",
|
||||
"ui.report_a_bug": "Relatar um bug",
|
||||
"ui.report_characters_left_one": "{count} caractere restante",
|
||||
@@ -5890,6 +6041,8 @@
|
||||
"ui.ribbon_pin_footer": "Os comandos fixados aparecem na faixa de opções. Passe o mouse sobre uma linha para fixar ou desafixar.",
|
||||
"ui.ribbon_workspace": "Espaço de trabalho",
|
||||
"ui.right": "Direita",
|
||||
"ui.right_click_confirms": "O clique direito confirma as entradas da caixa de diálogo",
|
||||
"ui.right_click_confirms_tip": "Com uma caixa de diálogo aberta, um clique direito na vista passa para a próxima entrada vazia e, na última, executa OK",
|
||||
"ui.save": "Salvar",
|
||||
"ui.save_as": "Salvar como",
|
||||
"ui.save_mesh_no_slicer_open": "Nenhum fatiador encontrado: escolha Personalizado… e selecione o seu programa fatiador",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Valoare",
|
||||
"Variable Radius": "Rază variabilă",
|
||||
"Velocity": "Viteză",
|
||||
"Vertical": "Vertical",
|
||||
"Vertices": "Vârfuri",
|
||||
"View navigator": "Navigator de vizualizare",
|
||||
"Volume": "Volum",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "EDITARE {title}",
|
||||
"dialog.no_shown_body": "Niciun corp afișat de modificat: afișați unul sau alegeți Corp nou",
|
||||
"dialog.pattern_sketch_not_object": "Alegeți corpuri sau operații: o schiță nu este niciuna dintre ele. Repetați curbele ei cu Matrice sau Oglindire din schiță, ori extrudați-o mai întâi.",
|
||||
"dialog.right_click_pick": "Selectați mai întâi {input}",
|
||||
"dialog.select": "↖ Selectează",
|
||||
"dialog.selected_count": "↖ {count} selectate",
|
||||
"dialog.selection_constraint": "Constrângerea {id}",
|
||||
@@ -3931,6 +3933,10 @@
|
||||
"sketch_text.path_clear": "Scoate textul de pe curbă",
|
||||
"sketch_text.path_hint": "O curbă a schiței pe care o urmează textul: faceți clic aici, apoi pe curbă",
|
||||
"sketch_text.use_font_file": "Folosește fișierul de font {path}",
|
||||
"sketch_text.valign_baseline": "Linie de bază",
|
||||
"sketch_text.valign_bottom": "Jos",
|
||||
"sketch_text.valign_middle": "Mijloc",
|
||||
"sketch_text.valign_top": "Sus",
|
||||
"solid": "solid",
|
||||
"status.editing": "Se editează {name}",
|
||||
"status.navigation": "Mapare mouse: {mapping}",
|
||||
@@ -5013,6 +5019,8 @@
|
||||
"ui.ribbon_pin_footer": "Comenzile fixate apar pe bandă. Treceți cursorul peste un rând pentru a-l fixa sau defixa.",
|
||||
"ui.ribbon_workspace": "Spațiu de lucru",
|
||||
"ui.right": "Dreapta",
|
||||
"ui.right_click_confirms": "Clicul dreapta confirmă intrările dialogului",
|
||||
"ui.right_click_confirms_tip": "Cu un dialog deschis, un clic dreapta în vedere trece la următoarea intrare goală, iar la ultima rulează OK",
|
||||
"ui.save": "Salvează",
|
||||
"ui.save_as": "Salvează ca",
|
||||
"ui.save_mesh_no_slicer_open": "Nu s-a găsit niciun slicer: alegeți Personalizat… și selectați programul dumneavoastră de slicing",
|
||||
|
||||
@@ -700,6 +700,7 @@
|
||||
"Value": "Значение",
|
||||
"Variable Radius": "Переменный радиус",
|
||||
"Velocity": "Скорость",
|
||||
"Vertical": "По вертикали",
|
||||
"Vertices": "Вершины",
|
||||
"View navigator": "Навигатор видов",
|
||||
"Volume": "Объём",
|
||||
@@ -1362,6 +1363,7 @@
|
||||
"dialog.edit_title": "ИЗМЕНИТЬ: {title}",
|
||||
"dialog.no_shown_body": "Нет отображаемого тела для изменения: покажите тело или выберите «Новое тело»",
|
||||
"dialog.pattern_sketch_not_object": "Выберите тела или операции: эскиз — ни то, ни другое. Повторите его кривые собственным инструментом «Массив» или «Зеркало» в эскизе либо сначала выдавите его.",
|
||||
"dialog.right_click_pick": "Сначала выберите {input}",
|
||||
"dialog.select": "↖ Выбрать",
|
||||
"dialog.selected_count": "↖ Выбрано: {count}",
|
||||
"dialog.selection_constraint": "Ограничение {id}",
|
||||
@@ -2343,6 +2345,8 @@
|
||||
"prefs.shortcuts": "Сочетания клавиш",
|
||||
"prefs.single_surface_analysis": "Использовать один анализ поверхности",
|
||||
"prefs.single_surface_analysis_help": "Если выключено, затенение поверхности и «Непрерывность» могут быть включены одновременно. Включение этого параметра оставляет последний запущенный или изменённый анализ.",
|
||||
"prefs.sketch.cursor_coordinates": "Показывать координаты курсора в эскизе",
|
||||
"prefs.sketch.cursor_coordinates_note": "Рядом с указателем его X и Y от начала координат эскиза, даже без активного инструмента. Выкл.: только пока инструмент ставит точку.",
|
||||
"prefs.sketch_align_points": "Выравнивать по другим точкам эскиза при рисовании",
|
||||
"prefs.sketch_align_points_note": "При рисовании точка выравнивается по горизонтали с одной точкой эскиза и по вертикали с другой одновременно, с пунктирной направляющей, и щелчок сохраняет оба выравнивания. Выкл.: только с предыдущей точкой, по одной оси за раз.",
|
||||
"prefs.sketch_construction_lines": "Расширенные инструменты вспомогательных прямых",
|
||||
@@ -3879,6 +3883,10 @@
|
||||
"sketch_text.path_clear": "Снять текст с кривой",
|
||||
"sketch_text.path_hint": "Кривая эскиза, вдоль которой идёт текст: щёлкните здесь, затем по кривой",
|
||||
"sketch_text.use_font_file": "Использовать файл шрифта {path}",
|
||||
"sketch_text.valign_baseline": "Базовая линия",
|
||||
"sketch_text.valign_bottom": "Низ",
|
||||
"sketch_text.valign_middle": "Середина",
|
||||
"sketch_text.valign_top": "Верх",
|
||||
"solid": "тело",
|
||||
"status.editing": "Изменение: {name}",
|
||||
"status.navigation": "Назначение кнопок мыши: {mapping}",
|
||||
@@ -4200,6 +4208,7 @@
|
||||
"ui.agent_chat_setup_title": "Настроить ассистента",
|
||||
"ui.agent_chat_side": "Сторона чата с агентом",
|
||||
"ui.agent_chat_signed_in": "вход выполнен",
|
||||
"ui.agent_chat_snap_none_found": "Кодирующий агент не найден. Пакет Snap работает в изолированной среде, поэтому не видит и не может запускать кодирующих агентов, установленных на этом компьютере. Чтобы пользоваться ими, установите SolidCraft из пакета AppImage, .deb или .rpm. Агент, использующий API, совместимый с OpenAI, работает и в пакете Snap: настройте его через «Добавить агент».",
|
||||
"ui.agent_chat_state_auth": "Требуется вход",
|
||||
"ui.agent_chat_state_busy": "Работает…",
|
||||
"ui.agent_chat_state_exited": "Агент остановлен",
|
||||
@@ -4366,7 +4375,9 @@
|
||||
"ui.browser_bodies_one": "{count} тело",
|
||||
"ui.browser_bodies_other": "{count} тел",
|
||||
"ui.browser_collapse": "Свернуть браузер",
|
||||
"ui.browser_collapse_below": "Свернуть вложенное",
|
||||
"ui.browser_expand": "Развернуть браузер",
|
||||
"ui.browser_expand_below": "Развернуть вложенное",
|
||||
"ui.browser_title": "Браузер",
|
||||
"ui.calibrate": "Калибровать",
|
||||
"ui.cancel": "Отмена",
|
||||
@@ -4393,6 +4404,7 @@
|
||||
"ui.collapse": "Свернуть",
|
||||
"ui.collinear": "Коллинеарность",
|
||||
"ui.colour_vision": "Цветовое зрение",
|
||||
"ui.colour_vision_bends": "Гибы",
|
||||
"ui.colour_vision_deutan": "Дейтан",
|
||||
"ui.colour_vision_deutan_tip": "При слабом или отсутствующем восприятии зелёного",
|
||||
"ui.colour_vision_failed": "Ошибка",
|
||||
@@ -4951,6 +4963,8 @@
|
||||
"ui.ribbon_pin_footer": "Закреплённые команды отображаются на ленте. Наведите курсор на строку, чтобы закрепить или открепить её.",
|
||||
"ui.ribbon_workspace": "Рабочая область",
|
||||
"ui.right": "Справа",
|
||||
"ui.right_click_confirms": "Правый щелчок подтверждает поля диалога",
|
||||
"ui.right_click_confirms_tip": "При открытом диалоге правый щелчок в виде переходит к следующему пустому полю, а на последнем выполняет OK",
|
||||
"ui.save": "Сохранить",
|
||||
"ui.save_as": "Сохранить как",
|
||||
"ui.save_mesh_no_slicer_open": "Слайсер не найден: выберите «Другая…» и укажите программу-слайсер",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Вредност",
|
||||
"Variable Radius": "Променљиви полупречник",
|
||||
"Velocity": "Брзина",
|
||||
"Vertical": "Вертикално",
|
||||
"Vertices": "Врхови",
|
||||
"View navigator": "Навигатор приказа",
|
||||
"Volume": "Запремина",
|
||||
@@ -3929,6 +3930,10 @@
|
||||
"sketch_text.path_clear": "Скини текст са његове криве",
|
||||
"sketch_text.path_hint": "Крива скице коју текст прати: кликните овде, а затим криву",
|
||||
"sketch_text.use_font_file": "Користи датотеку фонта {path}",
|
||||
"sketch_text.valign_baseline": "Основна линија",
|
||||
"sketch_text.valign_bottom": "Дно",
|
||||
"sketch_text.valign_middle": "Средина",
|
||||
"sketch_text.valign_top": "Врх",
|
||||
"solid": "пуно",
|
||||
"status.editing": "Измена: {name}",
|
||||
"status.navigation": "Мапирање миша: {mapping}",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Värde",
|
||||
"Variable Radius": "Variabel radie",
|
||||
"Velocity": "Hastighet",
|
||||
"Vertical": "Lodrät",
|
||||
"Vertices": "Hörn",
|
||||
"View navigator": "Vynavigator",
|
||||
"Volume": "Volym",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "REDIGERA {title}",
|
||||
"dialog.no_shown_body": "Ingen synlig kropp att ändra: visa en, eller välj Ny kropp",
|
||||
"dialog.pattern_sketch_not_object": "Välj kroppar eller funktioner: en skiss är ingetdera. Upprepa dess kurvor med skissens egna Mönster eller Spegla, eller extrudera den först.",
|
||||
"dialog.right_click_pick": "Markera {input} först",
|
||||
"dialog.select": "↖ Markera",
|
||||
"dialog.selected_count": "↖ {count} markerade",
|
||||
"dialog.selection_constraint": "Villkor {id}",
|
||||
@@ -3932,6 +3934,10 @@
|
||||
"sketch_text.path_clear": "Ta bort texten från dess kurva",
|
||||
"sketch_text.path_hint": "En kurva i skissen som texten följer: klicka här och sedan på kurvan",
|
||||
"sketch_text.use_font_file": "Använd teckensnittsfilen {path}",
|
||||
"sketch_text.valign_baseline": "Baslinje",
|
||||
"sketch_text.valign_bottom": "Nederkant",
|
||||
"sketch_text.valign_middle": "Mitten",
|
||||
"sketch_text.valign_top": "Överkant",
|
||||
"solid": "solid",
|
||||
"status.editing": "Redigerar {name}",
|
||||
"status.navigation": "Musmappning: {mapping}",
|
||||
@@ -5014,6 +5020,8 @@
|
||||
"ui.ribbon_pin_footer": "Fästa kommandon visas i menyfliken. Håll muspekaren över en rad för att fästa eller lossa den.",
|
||||
"ui.ribbon_workspace": "Arbetsyta",
|
||||
"ui.right": "Höger",
|
||||
"ui.right_click_confirms": "Högerklick bekräftar dialogens indata",
|
||||
"ui.right_click_confirms_tip": "Med en dialog öppen går ett högerklick i vyn vidare till nästa tomma indata, och vid den sista körs OK",
|
||||
"ui.save": "Spara",
|
||||
"ui.save_as": "Spara som",
|
||||
"ui.save_mesh_no_slicer_open": "Ingen slicer hittades: välj Egen… och ange ditt slicerprogram",
|
||||
|
||||
@@ -698,6 +698,7 @@
|
||||
"Value": "Değer",
|
||||
"Variable Radius": "Değişken yarıçap",
|
||||
"Velocity": "Hız",
|
||||
"Vertical": "Dikey",
|
||||
"Vertices": "Köşe noktaları",
|
||||
"View navigator": "Görünüm gezgini",
|
||||
"Volume": "Hacim",
|
||||
@@ -1369,6 +1370,7 @@
|
||||
"dialog.edit_title": "{title} düzenleniyor",
|
||||
"dialog.no_shown_body": "Değiştirilecek görünür gövde yok: bir gövdeyi gösterin ya da Yeni gövde seçin",
|
||||
"dialog.pattern_sketch_not_object": "Gövdeleri veya özellikleri seçin: eskiz bunlardan hiçbiri değildir. Eğrilerini eskizin kendi Dizi veya Aynala komutuyla tekrarlayın ya da önce ekstrüzyon yapın.",
|
||||
"dialog.right_click_pick": "Önce {input} seçin",
|
||||
"dialog.select": "↖ Seç",
|
||||
"dialog.selected_count": "↖ {count} seçildi",
|
||||
"dialog.selection_constraint": "Kısıtlama {id}",
|
||||
@@ -3931,6 +3933,10 @@
|
||||
"sketch_text.path_clear": "Metni eğriden ayır",
|
||||
"sketch_text.path_hint": "Metnin izleyeceği eskiz eğrisi: önce buraya, ardından eğriye tıklayın",
|
||||
"sketch_text.use_font_file": "{path} yazı tipi dosyasını kullan",
|
||||
"sketch_text.valign_baseline": "Taban çizgisi",
|
||||
"sketch_text.valign_bottom": "Alt",
|
||||
"sketch_text.valign_middle": "Orta",
|
||||
"sketch_text.valign_top": "Üst",
|
||||
"solid": "katı",
|
||||
"status.editing": "{name} düzenleniyor",
|
||||
"status.navigation": "Fare eşlemesi: {mapping}",
|
||||
@@ -4252,6 +4258,7 @@
|
||||
"ui.agent_chat_setup_title": "Asistan ayarla",
|
||||
"ui.agent_chat_side": "Ajan sohbeti konumu",
|
||||
"ui.agent_chat_signed_in": "oturum açık",
|
||||
"ui.agent_chat_snap_none_found": "Kodlama ajanı bulunamadı. Snap paketi yalıtılmış çalıştığı için bu bilgisayarda yüklü kodlama ajanlarını göremez ve başlatamaz. Bunları kullanmak için SolidCraft'ı bunun yerine AppImage, .deb veya .rpm paketinden yükleyin. OpenAI uyumlu API kullanan bir ajan Snap paketinde de çalışır: Ajan ekle ile ayarlayın.",
|
||||
"ui.agent_chat_state_auth": "Oturum açılması gerekiyor",
|
||||
"ui.agent_chat_state_busy": "Çalışıyor…",
|
||||
"ui.agent_chat_state_exited": "Ajan sonlandı",
|
||||
@@ -5013,6 +5020,8 @@
|
||||
"ui.ribbon_pin_footer": "Sabitlenen komutlar şeritte görünür. Sabitlemek veya kaldırmak için bir satırın üzerine gelin.",
|
||||
"ui.ribbon_workspace": "Çalışma alanı",
|
||||
"ui.right": "Sağ",
|
||||
"ui.right_click_confirms": "Sağ tıklama iletişim kutusu girişlerini onaylar",
|
||||
"ui.right_click_confirms_tip": "Bir iletişim kutusu açıkken görünümde sağ tıklama bir sonraki boş girişe geçer, sonuncusunda ise OK çalıştırır",
|
||||
"ui.save": "Kaydet",
|
||||
"ui.save_as": "Farklı kaydet",
|
||||
"ui.save_mesh_no_slicer_open": "Dilimleyici bulunamadı: Özel… seçin ve dilimleyici programınızı gösterin",
|
||||
|
||||
@@ -265,6 +265,7 @@
|
||||
"Edge": "Ребро",
|
||||
"Edges": "Ребра",
|
||||
"Edit": "Змінити",
|
||||
"Edit Holes": "Редагувати отвори",
|
||||
"Edit Profile Sketch": "Редагувати ескіз профілю",
|
||||
"Edit shortcuts": "Редагувати комбінації клавіш",
|
||||
"Enable rule": "Увімкнути правило",
|
||||
@@ -731,6 +732,7 @@
|
||||
"Select edges": "Виберіть ребра",
|
||||
"Select points of the sketch being edited": "Виберіть точки ескізу, що редагується",
|
||||
"Select the centre the pattern turns around first": "Спершу виберіть центр, навколо якого обертається масив",
|
||||
"Select the curves to divide first": "Спершу виберіть криві для поділу",
|
||||
"Select the curves to offset first": "Спершу виберіть криві для зсуву",
|
||||
"Select the mirror line": "Виберіть дзеркальну пряму",
|
||||
"Select the sketch curves or points to mirror first": "Спершу виберіть криві або точки ескізу, які треба віддзеркалити",
|
||||
@@ -883,6 +885,7 @@
|
||||
"Variable Radius": "Змінний радіус",
|
||||
"Variable radius": "Змінний радіус",
|
||||
"Velocity": "Швидкість",
|
||||
"Vertical": "По вертикалі",
|
||||
"Vertices": "Вершини",
|
||||
"View": "Вигляд",
|
||||
"View navigator": "Навігатор виду",
|
||||
@@ -936,6 +939,13 @@
|
||||
"ai.prefs.connect_apps_note": "Вимкнено: знову прибирає ці записи.\n\nПід час запуску SolidCraft додає себе як MCP-сервер до ШІ-застосунків, знайдених на цьому комп'ютері (OpenCode, Claude Desktop, Claude Code, Cursor, Codex, Gemini CLI, Copilot CLI, Windsurf, Zed, VS Code), щоб агент міг користуватися ним без жодного налаштування. Додається лише запис solidcraft або оновлюється його шлях; запис, який ви змінили, не чіпається, а файл спершу копіюється в резервну копію. Вимкнено: додані ним записи видаляються. Довідка > Підключити ШІ-асистентів… робить це вручну.",
|
||||
"ai.prefs.connect_at_start": "Під'єднувати останнього агента під час запуску",
|
||||
"ai.prefs.connect_at_start_note": "Під час кожного запуску SolidCraft у фоновому режимі запускає агента, якого ви під'єднували останнім (або типового), щоб він був готовий до розмови. Не діє, якщо SolidCraft запущено з --control. Якщо під'єднатися не вдається, Асистент показує «Не вдалося під'єднатися» та кнопку «Повторити».",
|
||||
"ai.prefs.control_failed": "Не вдалося запустити канал керування: {error}",
|
||||
"ai.prefs.control_from_launch": "Запущено з --control на порту {port} для цього запуску. Зміни тут набудуть чинності наступного разу, коли SolidCraft запуститься без --control.",
|
||||
"ai.prefs.control_listening": "Прослуховування на 127.0.0.1:{port}",
|
||||
"ai.prefs.control_not_listening": "Не прослуховується",
|
||||
"ai.prefs.control_port": "Порт",
|
||||
"ai.prefs.control_port_note": "Порт, до якого ШІ-агенти підключаються на цьому комп'ютері (127.0.0.1). 27878 — типовий: якщо його зайнято, береться наступний вільний. Будь-який інший порт використовується точно. Спрямуйте свій клієнт MCP на той самий порт, наприклад solidcraft-cli mcp --connect 127.0.0.1:7878.",
|
||||
"ai.prefs.control_port_taken": "Порт {port} зайнятий іншою програмою (або іншим вікном SolidCraft). Виберіть інший порт.",
|
||||
"ai.prefs.follow_camera": "Стежити за камерою",
|
||||
"ai.prefs.follow_camera_off": "Автоматичне стеження камери вимкнено.",
|
||||
"ai.prefs.follow_camera_on": "Камера повертається до ескізів, які створює агент.",
|
||||
@@ -975,6 +985,7 @@
|
||||
"browser.calibrate_click_a": "Клацніть зображення для точки A або введіть її координати.",
|
||||
"browser.calibrate_click_b": "Клацніть зображення для точки B або введіть її координати.",
|
||||
"browser.calibrate_title": "Калібрувати: {name}",
|
||||
"browser.canvas_locked": "Полотно заблоковано. Спершу розблокуйте його.",
|
||||
"browser.capture_many": "Компоненти ({count}) переміщено, але їхні положення не зафіксовано.",
|
||||
"browser.capture_note": "«Зафіксувати положення» зберігає нове положення; «Відновити положення» повертає попереднє.",
|
||||
"browser.capture_one": "Компонент переміщено, але його положення не зафіксовано.",
|
||||
@@ -1024,6 +1035,8 @@
|
||||
"cmd.appearance_pick_up": "Взяти вигляд",
|
||||
"cmd.appearance_replace": "Замінити вигляд",
|
||||
"cmd.assembly_bom": "Специфікація матеріалів",
|
||||
"cmd.assembly_constraint_create": "Обмежити",
|
||||
"cmd.assembly_constraint_edit": "Редагувати обмеження",
|
||||
"cmd.assembly_mass_properties": "Масові характеристики",
|
||||
"cmd.body.print_face": "Грань друку",
|
||||
"cmd.body_rename": "Перейменувати тіло",
|
||||
@@ -1083,7 +1096,10 @@
|
||||
"cmd.config_rule": "Правило конфігурації",
|
||||
"cmd.config_rules": "Правила конфігурації",
|
||||
"cmd.config_table": "Показати таблицю конфігурацій",
|
||||
"cmd.construct.axis": "Вісь",
|
||||
"cmd.construct.plane": "Площина",
|
||||
"cmd.construct.plane.axis_point": "Площина через вісь і точку",
|
||||
"cmd.construct.point": "Точка",
|
||||
"cmd.construct_axis_edge": "Вісь через ребро",
|
||||
"cmd.construct_axis_normal_to_face": "Вісь перпендикулярно до грані",
|
||||
"cmd.construct_axis_through_cylinder": "Вісь через циліндр/конус/тор",
|
||||
@@ -1204,6 +1220,7 @@
|
||||
"cmd.material_properties_directional": "Спрямований модуль пружності",
|
||||
"cmd.material_properties_validate": "Перевірити дані фізичного матеріалу",
|
||||
"cmd.mesh_convert": "Перетворити сітку",
|
||||
"cmd.model_body_features": "Перелічити операції тіла",
|
||||
"cmd.model_edges": "Список ребер",
|
||||
"cmd.model_faces": "Список граней",
|
||||
"cmd.model_threads": "Список різьб",
|
||||
@@ -1218,6 +1235,10 @@
|
||||
"cmd.motion_trace": "Траєкторія руху",
|
||||
"cmd.motion_trace_edit": "Змінити траєкторію руху",
|
||||
"cmd.motion_trace_keep": "Зберегти траєкторію руху",
|
||||
"cmd.note_add": "Додати примітку",
|
||||
"cmd.note_delete": "Видалити примітку",
|
||||
"cmd.note_list": "Список приміток",
|
||||
"cmd.note_update": "Редагувати примітку",
|
||||
"cmd.occurrence_align": "Вирівняти екземпляр",
|
||||
"cmd.occurrence_copy": "Вставити (екземпляр)",
|
||||
"cmd.occurrence_drag": "Перетягнути екземпляр",
|
||||
@@ -1232,8 +1253,11 @@
|
||||
"cmd.panel.dismiss": "Прибрати тимчасовий перегляд панелі",
|
||||
"cmd.panel.float": "Зробити панель плаваючою",
|
||||
"cmd.panel.focus": "Сфокусувати панель",
|
||||
"cmd.panel.focus.next": "Сфокусувати наступну панель",
|
||||
"cmd.panel.focus.previous": "Сфокусувати попередню панель",
|
||||
"cmd.panel.list": "Список панелей",
|
||||
"cmd.panel.move": "Перемістити панель",
|
||||
"cmd.panel.move.next_zone": "Перемістити панель до наступної зони",
|
||||
"cmd.panel.native_close": "Повернути рідний розділ панелі в док",
|
||||
"cmd.panel.open": "Відкрити панель",
|
||||
"cmd.panel.peek": "Тимчасово показати згорнуту панель",
|
||||
@@ -1241,6 +1265,12 @@
|
||||
"cmd.panel.reset_pair": "Скинути роздільник панелей",
|
||||
"cmd.panel.resize": "Змінити розмір розділу панелі",
|
||||
"cmd.panel.resize_pair": "Змінити розмір роздільника панелей",
|
||||
"cmd.panel.sash.down": "Змінити розмір роздільника панелей униз",
|
||||
"cmd.panel.sash.left": "Змінити розмір роздільника панелей ліворуч",
|
||||
"cmd.panel.sash.reset": "Скинути роздільник сфокусованої панелі",
|
||||
"cmd.panel.sash.right": "Змінити розмір роздільника панелей праворуч",
|
||||
"cmd.panel.sash.up": "Змінити розмір роздільника панелей угору",
|
||||
"cmd.panel.toggle": "Перемкнути сфокусовану панель",
|
||||
"cmd.parameters_add": "Додати користувацький параметр",
|
||||
"cmd.parameters_change": "Змінити параметри",
|
||||
"cmd.parameters_comment": "Коментувати параметр",
|
||||
@@ -1269,6 +1299,7 @@
|
||||
"cmd.pointcloud_edit": "Редагувати хмару точок",
|
||||
"cmd.pointcloud_insert": "Вставити хмару точок",
|
||||
"cmd.pointcloud_list": "Хмари точок",
|
||||
"cmd.pointcloud_reload": "Перезавантажити хмару точок",
|
||||
"cmd.render.coat.bind": "Зберегти прозоре покриття",
|
||||
"cmd.render.coat.unbind": "Прибрати прозоре покриття",
|
||||
"cmd.render.compare.divider": "Перемістити роздільник порівняння рендерів",
|
||||
@@ -1333,6 +1364,7 @@
|
||||
"cmd.render_start": "Рендеринг зображення",
|
||||
"cmd.render_status": "Перебіг рендерингу",
|
||||
"cmd.select_clear": "Зняти виділення",
|
||||
"cmd.selection_get": "Отримати виділення",
|
||||
"cmd.settings_profile_apply": "Застосувати профіль налаштувань",
|
||||
"cmd.settings_profile_delete": "Видалити профіль налаштувань",
|
||||
"cmd.settings_profile_export": "Експортувати профіль налаштувань",
|
||||
@@ -1363,6 +1395,7 @@
|
||||
"cmd.sketch.construction_line.tangent_external": "Дотична через зовнішню точку",
|
||||
"cmd.sketch.construction_line.tangent_two": "Спільна дотична",
|
||||
"cmd.sketch.construction_line.vertical": "Вертикальна допоміжна пряма",
|
||||
"cmd.sketch.replace": "Замінити ескіз",
|
||||
"cmd.sketch_arc3d": "3D-дуга",
|
||||
"cmd.sketch_arc_center_point": "Дуга за центром",
|
||||
"cmd.sketch_arc_tangent": "Дотична дуга",
|
||||
@@ -1420,6 +1453,7 @@
|
||||
"cmd.sketch_options": "Параметри палітри ескізу",
|
||||
"cmd.sketch_paste": "Вставити елементи ескізу",
|
||||
"cmd.sketch_point3d": "3D-точка",
|
||||
"cmd.sketch_point_divide": "Поділити криву",
|
||||
"cmd.sketch_polygon_circumscribed": "Описаний багатокутник",
|
||||
"cmd.sketch_polygon_edge": "Багатокутник за ребром",
|
||||
"cmd.sketch_polygon_inscribed": "Вписаний багатокутник",
|
||||
@@ -1493,6 +1527,7 @@
|
||||
"cmd.timeline_stop": "Зупинити історію",
|
||||
"cmd.timeline_suppress": "Придушити операцію",
|
||||
"cmd.ui.assistant": "Показати або приховати асистента",
|
||||
"cmd.ui.palette": "Пошук команд",
|
||||
"cmd.view.navigator": "Власний навігатор виду",
|
||||
"cmd.view.render_browser": "Браузер рендерингу",
|
||||
"cmd.view.render_dock": "Перемістити док рендерингу",
|
||||
@@ -1590,6 +1625,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}: посилання `{reference}` більше не існує в тому вигляді, у якому його вибрано; виберіть його знову",
|
||||
"dialog.bodies_count": "Тіл: {count}",
|
||||
"dialog.clearance_invalid": "зазор має бути довжиною 0 або більше",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "Обчислити",
|
||||
"dialog.compute_again": "Обчислити знову",
|
||||
"dialog.computing": "Обчислення… {seconds} с",
|
||||
@@ -1606,6 +1642,7 @@
|
||||
"dialog.pattern_sketch_not_object": "Виберіть тіла або операції: ескіз не є ні тим, ні іншим. Повторіть його криві власним інструментом «Масив» чи «Дзеркало» в ескізі або спершу видавіть його.",
|
||||
"dialog.primitive_point_tip": "Точка, що заповнює X, Y і Z: клацніть тут, потім клацніть вершину, ребро чи грань моделі, точку ескізу або початок координат.",
|
||||
"dialog.reference_edge_tip": "Пряме ребро вибраної грані, від якого вимірюється відстань нижче: клацніть тут, потім клацніть ребро.",
|
||||
"dialog.right_click_pick": "Спочатку виберіть {input}",
|
||||
"dialog.select": "↖ Вибрати",
|
||||
"dialog.selected_count": "↖ Вибрано: {count}",
|
||||
"dialog.selection_constraint": "Обмеження {id}",
|
||||
@@ -1661,6 +1698,7 @@
|
||||
"file_load.inserting": "Вставлення геометрії",
|
||||
"file_load.link_item": "{name} ({done} із {total})",
|
||||
"file_load.opened": "Відкрито {name}",
|
||||
"file_load.opened_behind": "Відкрито {name} у новій вкладці",
|
||||
"file_load.opened_in_tab": "Відкрито {name} у новій вкладці",
|
||||
"file_load.opening": "Відкриття проєкту",
|
||||
"file_load.preparing_thumbnail": "Підготовка мініатюри...",
|
||||
@@ -1670,6 +1708,7 @@
|
||||
"file_load.reading_percent": "Читання файлу... {percent}%",
|
||||
"file_load.rebuilding": "Перебудова елемента {done} із {total}",
|
||||
"file_load.recovering": "Відновлення проєкту",
|
||||
"file_load.reloading_cloud": "Перезавантаження хмари точок",
|
||||
"file_load.step_build": "Побудова моделі",
|
||||
"file_load.step_feature": "Операція {done} з {total}",
|
||||
"file_load.step_part": "Деталь {done} з {total}",
|
||||
@@ -1707,11 +1746,13 @@
|
||||
"help.config.table": "Показує таблицю конфігурацій: по одному рядку на варіант, по одному стовпцю на параметр чи операцію, а також чи проєкт досі відповідає активному рядку. Використовуйте, щоб переглянути варіанти проєкту.",
|
||||
"help.connect_note": "Перезапустіть кожного асистента, щоб завантажити сервер SolidCraft. Перед зміною кожен файл збережено як резервну копію .bak.",
|
||||
"help.connect_title": "Підключення ШІ-асистентів",
|
||||
"help.construct.axis": "Створює допоміжну вісь методом, який підказують ваші вибори: уздовж ребра чи прямої, крізь отвір або круглу грань, там, де перетинаються дві площини, через дві точки чи перпендикулярно до грані через точку. Використовуйте, коли ви знаєте опорні елементи, але не метод.",
|
||||
"help.construct.axis.edge": "Створює допоміжну вісь уздовж прямого ребра або прямої ескізу. Використовуйте як вісь для обертання, кругового масиву чи з'єднання.",
|
||||
"help.construct.axis.normal_to_face": "Створює допоміжну вісь через точку, перпендикулярну до грані. Використовуйте як вісь, що виходить прямо з поверхні.",
|
||||
"help.construct.axis.through_cylinder": "Створює допоміжну вісь через центр грані циліндра, конуса чи тора або кругового ребра. Використовуйте, щоб обертати чи розмножувати операції навколо круглої деталі.",
|
||||
"help.construct.axis.two_planes": "Створює допоміжну вісь там, де сходяться дві площини або плоскі грані. Використовуйте, коли потрібна вісь — лінія між двома гранями.",
|
||||
"help.construct.axis.two_points": "Створює допоміжну вісь через дві точки, вершини або точки ескізу. Використовуйте для осі, що проходить між двома відомими положеннями.",
|
||||
"help.construct.plane": "Створює допоміжну площину методом, який підказують ваші вибори: зі зміщенням від площини, через точку, між двома площинами, через прямі чи точки, дотично до криволінійної грані чи перпендикулярно до траєкторії. Використовуйте, коли ви знаєте опорні елементи, але не метод.",
|
||||
"help.construct.plane.along_path": "Створює допоміжну площину, перпендикулярну до ребра чи кривої, у вибраному місці вздовж неї. Використовуйте, щоб накреслити профіль для протягування або переріз траєкторії.",
|
||||
"help.construct.plane.at_angle": "Створює допоміжну площину, повернуту на кут від площини чи грані навколо осі або ребра. Використовуйте для похилих ескізів, наприклад косого кронштейна.",
|
||||
"help.construct.plane.axis_point": "Створює допоміжну площину, що містить вісь і точку поза цією віссю. Виберіть вісь початку координат або допоміжну вісь, пряме ребро чи пряму ескізу, потім вершину, точку ескізу чи допоміжну точку. Точка на осі не може задати єдину площину.",
|
||||
@@ -1721,6 +1762,7 @@
|
||||
"help.construct.plane.tangent": "Створює допоміжну площину, що дотикається до циліндра, конуса, кулі чи тора в точці. Використовуйте, щоб креслити на боці круглої деталі.",
|
||||
"help.construct.plane.three_points": "Створює допоміжну площину через три точки. Використовуйте для площини, заданої положеннями на моделі, наприклад трьома кутами.",
|
||||
"help.construct.plane.two_edges": "Створює допоміжну площину через два прямі ребра чи прямі, що лежать в одній площині. Використовуйте для площини через деталь, наприклад через два протилежні ребра.",
|
||||
"help.construct.point": "Створює допоміжну точку методом, який підказують ваші вибори: у вершині, у центрі кола чи кулі, уздовж ребра, там, де перетинаються дві прямі чи три площини, або там, де пряма перетинає площину. Використовуйте, коли ви знаєте опорні елементи, але не метод.",
|
||||
"help.construct.point.along_path": "Створює допоміжну точку в певному місці вздовж ребра чи кривої. Використовуйте як орієнтир на півшляху вздовж траєкторії.",
|
||||
"help.construct.point.center": "Створює допоміжну точку в центрі кругового ребра, кола чи дуги ескізу, кулі або тора. Використовуйте як орієнтир для отворів, осей і з'єднань.",
|
||||
"help.construct.point.edge_plane": "Створює допоміжну точку там, де ребро чи пряма проходить крізь площину або плоску грань. Використовуйте, щоб позначити, де траєкторія перетинає площину.",
|
||||
@@ -1909,6 +1951,7 @@
|
||||
"help.sketch.pattern.circular": "Копіює геометрію ескізу навколо центральної точки по повному колу або на заданий кут. Використовуйте для кіл розташування болтів, спиць і зубів.",
|
||||
"help.sketch.pattern.rectangular": "Копіює геометрію ескізу рядками й стовпцями із заданими проміжками. Використовуйте для сіток отворів, пазів чи вентиляційних прорізів.",
|
||||
"help.sketch.point": "Ставить точку ескізу. Використовуйте як орієнтир для розмірів, обмежень, центрів отворів або пізніших операцій.",
|
||||
"help.sketch.point.divide": "Розміщує точки, що поділяють вибрані криві на рівні за довжиною частини. Точки залишаються на кожній кривій і зберігають свій крок, коли крива змінюється.",
|
||||
"help.sketch.point3d": "Ставить точку в просторі за ввімкненого 3D-ескізу. Використовуйте як орієнтир для 3D-кривих і траєкторій.",
|
||||
"help.sketch.polygon.circumscribed": "Малює правильний багатокутник навколо кола, розмір якого задано від центра до середини сторони. Використовуйте, коли відомий розмір під ключ, як для шестигранної гайки.",
|
||||
"help.sketch.polygon.edge": "Малює правильний багатокутник за двома кінцями однієї сторони. Використовуйте, коли відомі довжина й положення сторони.",
|
||||
@@ -2010,6 +2053,7 @@
|
||||
"help.view.visual_style": "Перемикає спосіб відображення моделі: затінена з ребрами чи без них, каркас або з прихованими ребрами. Використовуйте каркас, щоб зазирнути всередину, а затінення — для чистого вигляду.",
|
||||
"history.sketch_under_constrained": "Ескіз має {count} ступенів вільності",
|
||||
"history.sketch_under_constrained_one": "Ескіз має {count} ступінь вільності",
|
||||
"hole_folder.applies_to": "Зміни застосовуються до {count} отворів у теці {folder}; кожен зберігає своє місце.",
|
||||
"hole_presets.confirm_delete": "Підтвердити видалення",
|
||||
"hole_presets.delete": "Видалити",
|
||||
"hole_presets.delete_prompt": "Видалити цей особистий набір? Наявні отвори не зміняться.",
|
||||
@@ -2261,8 +2305,12 @@
|
||||
"nav.hfss.help": "Alt+ліва панорамує, Shift+Alt+ліва масштабує, Ctrl+ліва з порожнього місця обертає",
|
||||
"nav.inventor.help": "Середня панорамує, Shift+середня обертає, Ctrl+середня масштабує, права обертає",
|
||||
"nav.maya.help": "Alt+ліва обертає, Alt+середня панорамує, Alt+права масштабує; середня також панорамує",
|
||||
"nav.maya_horizontal_zoom.help": "Alt+праве перетягування: праворуч — наближення, ліворуч — віддалення. Вимкніть, щоб повернути вертикальне масштабування перетягуванням.",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: горизонтальне масштабування перетягуванням",
|
||||
"nav.nx.help": "Середня обертає, Shift+середня панорамує (у NX — середня + права), Ctrl+середня масштабує (у NX — середня + ліва); права не рухає камеру",
|
||||
"nav.openscad.help": "Ліва обертає по порожньому місцю, Shift+ліва виділяє рамкою, геометрію ескізу перетягують для редагування; права або середня панорамує, Shift+права або Shift+середня масштабує",
|
||||
"nav.orbit_cursor_wrap.help": "Перетягування для обертання, що сягає краю виду, переносить курсор на протилежний край і продовжує обертання. Вимкнено: перетягування зупиняється на краю екрана. Не діє у Wayland і в браузері.",
|
||||
"nav.orbit_cursor_wrap.label": "Переносити курсор під час обертання",
|
||||
"nav.perspective.sketch": "Редагування ескізу використовує ортографічний вид. Завершіть ескіз, щоб увімкнути перспективу.",
|
||||
"nav.right_drag_orbits.help": "Перетягування правою кнопкою миші обертає вид",
|
||||
"nav.right_drag_orbits.label": "Обертання правою кнопкою",
|
||||
@@ -2389,6 +2437,16 @@
|
||||
"not a move": "це не переміщення",
|
||||
"not a number": "не число",
|
||||
"open a sketch first": "спершу відкрийте ескіз",
|
||||
"operations.cancel": "Скасувати {name}",
|
||||
"operations.cancelled": "{name} скасовано",
|
||||
"operations.cancelling": "Скасування…",
|
||||
"operations.cannot_cancel": "{name} не можна скасувати",
|
||||
"operations.feature": "Операція",
|
||||
"operations.feature_edit": "Редагувати операцію",
|
||||
"operations.meshing": "Завантаження деталей",
|
||||
"operations.queued": "У черзі",
|
||||
"operations.stopped": "Скасовано",
|
||||
"operations.waiting": "Готово",
|
||||
"parameters.apply_live": "Застосовувати кожну зміну, коли ви залишаєте її поле",
|
||||
"parameters.apply_live_tip": "Вимкнено: зміни чекають на «Застосувати» або OK, після чого проєкт один раз перебудовується для всіх. «Скасувати» чи Esc відкидає їх.",
|
||||
"parameters.held": "Змін, що чекають на «Застосувати»: {count}",
|
||||
@@ -2410,6 +2468,7 @@
|
||||
"parts.dimension.width": "Ширина",
|
||||
"parts.family.bearing": "Радіальний кульковий підшипник (габарит)",
|
||||
"parts.family.button_head_cap_screw": "Гвинт з циліндричною головкою та внутрішнім шестигранником",
|
||||
"parts.family.countersunk_socket_screw": "Гвинт із потайною головкою та внутрішнім шестигранником",
|
||||
"parts.family.dowel_pin": "Циліндричний штифт",
|
||||
"parts.family.hex_bolt": "Болт / гвинт із шестигранною головкою",
|
||||
"parts.family.hex_cap_screw_inch": "Гвинт із шестигранною головкою (дюймовий)",
|
||||
@@ -2476,6 +2535,7 @@
|
||||
"prefs.appearance.viewport_colours": "Кольори вікна перегляду",
|
||||
"prefs.appearance.viewport_logo": "Вікно перегляду та логотип",
|
||||
"prefs.applies_on_restart": "Застосовується після перезапуску",
|
||||
"prefs.assemblies": "Збірки",
|
||||
"prefs.assistant": "Асистент",
|
||||
"prefs.assistant_connecting": "Підключення",
|
||||
"prefs.assistant_follow_help": "У режимі «ескізи наведення» вид рухається за вказівником.",
|
||||
@@ -2508,6 +2568,8 @@
|
||||
"prefs.bottom_centre": "Внизу по центру",
|
||||
"prefs.bottom_right": "Внизу праворуч",
|
||||
"prefs.browser": "Браузер",
|
||||
"prefs.browser_body_features": "Операції під тілами",
|
||||
"prefs.browser_body_features_note": "Кожне тіло в браузері розгортається, показуючи операції часового ланцюжка, що його побудували, у порядку ланцюжка.",
|
||||
"prefs.browser_components_open": "Компоненти розгорнуті з початку",
|
||||
"prefs.browser_components_open_note": "Кожен компонент у браузері одразу розгорнутий, як раніше, а не згорнутий, доки ви його не розгорнете.",
|
||||
"prefs.browser_eye_left": "Око поруч зі стрілкою згортання",
|
||||
@@ -2526,6 +2588,10 @@
|
||||
"prefs.choose_font": "Вибрати файл шрифту…",
|
||||
"prefs.click": "Клацання",
|
||||
"prefs.command_dialog_values": "Діалоги команд",
|
||||
"prefs.constraint_glyph_size": "Розмір позначок обмежень",
|
||||
"prefs.constraint_glyph_size_note": "Наскільки великими малюються позначки обмежень та їхні літери чи піктограми в ескізі. 100% — звичайний розмір; позначки зберігають цей розмір на екрані за будь-якого масштабу.",
|
||||
"prefs.construct_menu_groups": "Групувати інструменти побудови за типом об'єкта",
|
||||
"prefs.construct_menu_groups_help": "Показувати заголовки «Площини», «Осі» та «Точки». Вимкнено: зберігається початковий порядок меню.",
|
||||
"prefs.contact_shading": "М'яке контактне затінення",
|
||||
"prefs.contact_shading_note": "М'яке затінення там, де деталі зближуються.",
|
||||
"prefs.context_menu": "Контекстне меню",
|
||||
@@ -2548,7 +2614,11 @@
|
||||
"prefs.design_tools.degrees": "Градуси",
|
||||
"prefs.design_tools.double_click_help": "Або редагувати пов'язаний компонент на місці.",
|
||||
"prefs.design_tools.ghost": "Показувати старе місце переміщених деталей як привид",
|
||||
"prefs.design_tools.hole_group": "Групувати отвори, створені разом",
|
||||
"prefs.design_tools.hole_group_help": "Отвори, створені за один раз, опиняються в одній теці в історії, спершу закритій; відкрийте її, щоб редагувати отвір окремо.",
|
||||
"prefs.design_tools.hole_moves_help": "Повторний вибір грані переміщує отвір, а не видаляє його.",
|
||||
"prefs.design_tools.hole_several": "Кілька отворів на одній грані",
|
||||
"prefs.design_tools.hole_several_help": "Вибір іншого місця на грані додає ще один отвір; вибір отвору видаляє його.",
|
||||
"prefs.design_tools.hole_snaps_help": "Середина грані та центри її круглих ребер.",
|
||||
"prefs.design_tools.imported_files": "Імпортовані файли",
|
||||
"prefs.design_tools.note": "Примітка",
|
||||
@@ -2557,6 +2627,8 @@
|
||||
"prefs.design_tools.rows": "Рядки",
|
||||
"prefs.devices": "3D-миша",
|
||||
"prefs.dialog_buttons": "Кнопки діалогу",
|
||||
"prefs.dialog_first_letter_buttons": "Кнопки діалогів реагують на першу літеру",
|
||||
"prefs.dialog_first_letter_buttons_help": "Коли діалог відкрито, натискання першої літери напису кнопки натискає її: O — OK, С — «Скасувати». Літера, що підходить до двох кнопок, нічого не робить, а сфокусоване текстове поле зберігає натискання. Вимкнено: натискання літер не діє на кнопки, як раніше.",
|
||||
"prefs.dialogs": "Діалоги",
|
||||
"prefs.dialogs_edge": "На краю виду",
|
||||
"prefs.dialogs_left_column": "У лівій колонці",
|
||||
@@ -2570,12 +2642,21 @@
|
||||
"prefs.dimension_values_window": "У вікні",
|
||||
"prefs.display": "Відображення",
|
||||
"prefs.edges": "Ребра та затінення",
|
||||
"prefs.export": "Експорт",
|
||||
"prefs.export_name": "Ім'я файлу експорту",
|
||||
"prefs.export_name.body": "Назва експортованого тіла (першого, якщо їх кілька)",
|
||||
"prefs.export_name.design": "Назва проєкту",
|
||||
"prefs.export_name_hint": "напр. {design}-{body}",
|
||||
"prefs.export_name_sample": "Під час експорту цього проєкту пропонується: {name}",
|
||||
"prefs.export_name_tip": "Ім'я файлу, яке пропонують «Файл» › «Експорт» і «Зберегти як сітку». Ці заповнювачі замінюються:\n{placeholders}\nНевстановлену властивість проєкту пропущено. Залиште поле порожнім, щоб пропонувати назву проєкту або, для сітки, назву тіла.",
|
||||
"prefs.extend": "Розширення",
|
||||
"prefs.extra_navigation": "Ctrl+перетягування лівою на порожньому місці обертає; утримуйте Space, щоб панорамувати.",
|
||||
"prefs.extrude_arrow_face_stops": "Стрілка видавлювання зупиняється на гранях",
|
||||
"prefs.extrude_arrow_face_stops_note": "Перетягування стрілки відстані видавлювання зупиняється на плоских гранях, паралельних профілю, наприклад на дальньому боці блока, який вирізають, і обводить цю грань. Вимкнено: стрілка рухається лише круглими кроками.",
|
||||
"prefs.extrude_view_isometric": "Повертати вид до ізометрії під час відкриття «Видавлювання»",
|
||||
"prefs.extrude_view_return": "Повертати попередній вид під час закриття «Видавлювання»",
|
||||
"prefs.file_operations_wait": "Чекати на відкриття файлів",
|
||||
"prefs.file_operations_wait_note": "Поки файл відкривається чи вставляється або зв'язки читаються знову, проєкт чекає за карткою з поступом файлу й кнопкою «Скасувати». Вимкнено: файл показується в панелі операцій, і ви можете працювати далі; вставлення відбувається, коли ви завершите поточну дію, а відкритий тим часом файл потрапляє в нову вкладку.",
|
||||
"prefs.follows_os": "Як у системі",
|
||||
"prefs.font": "Шрифт",
|
||||
"prefs.font_fallback": "Символи, яких немає у вибраному шрифті, беруться з вбудованого, тож жоден напис не показує порожній квадрат.",
|
||||
@@ -2630,6 +2711,8 @@
|
||||
"prefs.history": "Історія",
|
||||
"prefs.history_bar_groups": "Згортати панель історії в групи",
|
||||
"prefs.history_bar_groups_note": "У довгій історії послідовність операцій одного компонента згортається в одну кнопку, а теки операцій починаються згорнутими. Вставлена збірка STEP потрапляє в теку «Група». Вимкнено: показує кожну операцію, починає теки розгорнутими й не створює теки.",
|
||||
"prefs.history_folder_kind_icon": "Значок теки за її операціями",
|
||||
"prefs.history_folder_kind_icon_note": "Тека історії, усі операції якої одного типу, показує їхній значок.",
|
||||
"prefs.history_group_joints": "Групувати з’єднання в історії",
|
||||
"prefs.history_group_joints_note": "Два чи більше з’єднань показуються однією кнопкою з їхньою кількістю, а клацання показує кожне. Вимкнено: показує кожне з’єднання.",
|
||||
"prefs.history_origin_bodies": "Показувати початок координат і тіла вгорі",
|
||||
@@ -2655,6 +2738,8 @@
|
||||
"prefs.invert_curved_roll_arrows_note": "Дві вигнуті стрілки в куті куба обертають вид у площині екрана. Увімкнено: стрілка за годинниковою стрілкою обертає проти годинникової, а стрілка проти годинникової — за годинниковою. Вимкнено: кожна стрілка обертає вид у напрямку свого завитку.",
|
||||
"prefs.invert_navigator_arrows": "Інвертувати стрілки обертання куба виду",
|
||||
"prefs.invert_navigator_arrows_note": "Стрілки навколо куба обертають камеру в той бік, куди вказують, як у Fusion та Inventor: стрілка ліворуч вказує праворуч і повертає камеру праворуч. Вимк.: стрілка обертає куб у той бік, де вона розташована, тож ліва стрілка повертає камеру ліворуч. Вигнуті стрілки крену не змінюються.",
|
||||
"prefs.joint_drag_trackball": "Обертати деталі на кульовому з'єднанні під час перетягування, як трекболом",
|
||||
"prefs.joint_drag_trackball_help": "Перетягування деталі, яку утримує кульове з'єднання, обертає її найменшим поворотом навколо з'єднання, наче котиться куля розміром із деталь. Вимкнено: схоплена точка точно йде за вказівником, і деталь може також обертатися навколо неї.",
|
||||
"prefs.keep_unsaved_also_asks": "Усе одно запитувати під час закриття вкладки",
|
||||
"prefs.keep_unsaved_also_asks_tip": "Коли це вимкнено, вкладка закривається без вікна браузера, щойно копія кожного незбереженого проєкту актуальна.",
|
||||
"prefs.keep_unsaved_in_browser": "Зберігати незбережену роботу в цьому браузері",
|
||||
@@ -2730,11 +2815,14 @@
|
||||
"prefs.not_on_gpu": "не на цьому GPU",
|
||||
"prefs.on": "Увімкнено",
|
||||
"prefs.opaque": "Непрозорий",
|
||||
"prefs.operations_panel": "Показувати операції у виді",
|
||||
"prefs.operations_panel_note": "Тривалі операції (відкриття файлу, обчислення операції, команда агента) показуються в правому нижньому куті виду з поступом і кнопкою, що їх скасовує. Вимкнено: повідомлення «Обчислення», як раніше.",
|
||||
"prefs.orbit_snap": "Утримуйте Shift під час обертання, щоб прив'язатися до осі.",
|
||||
"prefs.orientation": "Орієнтація",
|
||||
"prefs.origin_plane_names": "Назви площин початку координат",
|
||||
"prefs.origin_plane_names_note": "Назви, що показуються в браузері, діалогах і списках. {top} — це XY, {front} — XZ, {right} — YZ, а Z спрямована вгору. Команди, скрипти й збережені проєкти зберігають XY, XZ і YZ.",
|
||||
"prefs.overall_speed": "Загальна швидкість",
|
||||
"prefs.panel_layout.recovery": "Не вдалося відновити збережені компонування панелей. Збережені дані не втрачено; «Класичне» залишається доступним.",
|
||||
"prefs.parameter_list_rows": "Рядків у списку параметрів",
|
||||
"prefs.parameter_list_rows_tip": "Скільки параметрів щонайбільше показує стрілка вниз у порожньому полі виразу.",
|
||||
"prefs.persistent_ribbon_pressed": "Підсвічувати активні команди стрічки",
|
||||
@@ -2796,6 +2884,8 @@
|
||||
"prefs.remember_dialog_values.help": "Типово вимкнено. Коли ввімкнено, після успішного виконання команди її безпечні значення й параметри повторно використовуються під час наступного відкриття тієї самої команди, доки SolidCraft не закриється.",
|
||||
"prefs.render_legacy_image_defaults": "Використовувати попередні типові налаштування зображення рендерингу",
|
||||
"prefs.render_legacy_image_defaults_help": "Зберігає попередній ручний робочий процес: нові налаштування використовують растеризацію на CPU, трасування променів на CPU зберігає фіксовану дискретизацію, а результати рендерингу відкриваються вручну. Під час входу в рендеринг виконується повторне вписування, кадри перемикаються без відновлення їхніх камер, використовується попереднє кадрування й навігація. Автоматичний зворотний зв’язок живого зображення вимкнено. Збережені налаштування не змінюються.",
|
||||
"prefs.render_legacy_memory_admission": "Використовувати попередні перевірки пам'яті рендерингу",
|
||||
"prefs.render_legacy_memory_admission_help": "Дозволяє нативний рендеринг у межах фіксованих бюджетів спільної пам'яті та пам'яті хоста, навіть коли оцінка перевищує доступну RAM. Обмеження пристрою й перевірки виділення пам'яті все одно діють.",
|
||||
"prefs.render_previous_geometry_budget": "Бюджет попередньої геометрії для візуалізації",
|
||||
"prefs.render_previous_geometry_budget_help": "Максимальний обсяг пам'яті для кешу геометрії попереднього стану",
|
||||
"prefs.reports_saved": "Збережено: {n}",
|
||||
@@ -2822,6 +2912,8 @@
|
||||
"prefs.select_other_hidden": "Вибирати приховану геометрію через «Вибрати інше»",
|
||||
"prefs.select_other_hidden_help": "Увімкнено: до списку входять приховані тіла, ескізи та затулені ребра поблизу вказівника. Вимкнено: використовується початковий список видимої геометрії під вказівником.",
|
||||
"prefs.selecting": "Вибір",
|
||||
"prefs.shared_panel_layout": "Використовувати спільне компонування панелей",
|
||||
"prefs.shared_panel_layout_help": "Показувати наявні браузер, історію та асистента в переміщуваних панелях. Зміна набуде чинності після застосування налаштувань.",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift лише додає; Ctrl / Cmd перемикає",
|
||||
"prefs.shift_add_note": "Увімкнено: Shift додає, Ctrl / Cmd перемикає. Вимкнено (типово): обидва перемикають.",
|
||||
@@ -2844,6 +2936,8 @@
|
||||
"prefs.sketch.drawing": "Креслення",
|
||||
"prefs.sketch.ellipse_axes": "Малювати еліпси з їхніми осями",
|
||||
"prefs.sketch.ellipse_axes_note": "Велика й мала осі як допоміжні лінії, тож півосі та осі можна позначати розмірами. Вимкнено: лише еліпс, а D на ньому задає його малий радіус, де б значення не тягнули; воно малюється й позначається R, як раніше.",
|
||||
"prefs.sketch.escape_twice_finishes": "Подвійний Esc завершує ескіз",
|
||||
"prefs.sketch.escape_twice_finishes_note": "Два швидкі натискання Esc завершують ескіз. Вимкнено: Esc лише скасовує інструмент чи вибір, а ескіз завершує «Завершити ескіз».",
|
||||
"prefs.sketch.exit_keep": "Зберегти",
|
||||
"prefs.sketch.exit_previous": "Повернутися до попереднього виду",
|
||||
"prefs.sketch.exit_unless_rotated": "Якщо не повернуто",
|
||||
@@ -3186,6 +3280,14 @@
|
||||
"render.category_paint": "Фарба",
|
||||
"render.category_plastic": "Пластик",
|
||||
"render.category_wood": "Дерево",
|
||||
"render.caustics_area_lights": "Каустика площинних джерел світла",
|
||||
"render.caustics_depth": "Глибина шляху каустики",
|
||||
"render.caustics_enable": "Каустика скла від точкових і спрямованих джерел світла",
|
||||
"render.caustics_environment": "Каустика середовища",
|
||||
"render.caustics_help": "Кількість фотонів керує шумом і обсягом роботи. Радіус збирання обмінює чіткі деталі на плавнішу оцінку. CPU потребує непрямого освітлення.",
|
||||
"render.caustics_path_required": "Каустика на CPU потребує непрямого освітлення.",
|
||||
"render.caustics_photons": "Фотони",
|
||||
"render.caustics_radius": "Радіус збирання",
|
||||
"render.check_glass_cpu": "CPU підтримує сертифіковані плоскі листи скла та паралелепіпеди, вирівняні за осями. Загальні замкнені сітки, вкладення й внутрішнє розсіювання потребують непрямого освітлення. Пропускання тіней крізь замкнене скло досі не підтримується.",
|
||||
"render.check_glass_gpu": "GPU підтримує сертифіковане неперетинне скло або явне сертифіковане вкладення. Вкладення потребує опуклих батьківських тіл, суворо вміщених дочірніх тіл і відсутності дотичних меж.",
|
||||
"render.check_media_remaining": "Шорстке скло, сітки густини, зміщення та спектральне перенесення досі недоступні.",
|
||||
@@ -3398,6 +3500,12 @@
|
||||
"render.cpu_subsurface_denoise_reason": "Підповерхневе розсіювання на CPU потребує вимкненого шумозаглушення. Ваші налаштування збережено.",
|
||||
"render.cpu_subsurface_help": "Розсіювання змінює напрямок світла всередині замкненого скла. Додатні швидкості потребують непрямого освітлення з вимкненим шумозаглушенням. Швидкість — це кількість зіткнень на mm; 0 не додає розсіювання. Додатний фазовий зсув сприяє напрямкам уперед; від'ємний — назад.",
|
||||
"render.cpu_summary": "Трасування променів на CPU · відбиття · HDR · напрямлене й точкове світло",
|
||||
"render.cpu_threads": "Робочі потоки CPU",
|
||||
"render.cpu_threads_auto": "Авто",
|
||||
"render.cpu_threads_custom": "Власна",
|
||||
"render.cpu_threads_help": "«Авто» використовує доступні робочі потоки CPU. Один потік працює послідовно. Більше потоків може потребувати більше пам'яті.",
|
||||
"render.cpu_threads_single": "Один",
|
||||
"render.cpu_threads_web": "Рендеринг у браузері використовує один кооперативний робочий потік. Вибір робочих потоків, збережений для настільного застосунку, не змінюється.",
|
||||
"render.cpu_transparent_help": "Прозорий PNG прибирає фон і зберігає покриття країв. Непрозорість тіл і граней має залишатися 100%.",
|
||||
"render.cpu_volume_enable_path": "Увімкнути непряме освітлення",
|
||||
"render.cpu_volume_enable_path_plan": "Трасування променів на CPU · глибина шляху {depth} · {spp} вибірок на піксель · початкове значення {seed} · трасовані тіні. Зберігає авторську атмосферу й бюджет зображення.",
|
||||
@@ -3406,6 +3514,40 @@
|
||||
"render.cpu_volume_method_incompatible": "Ці налаштування світла, дискретизації чи атмосфери не можна перенести на цей метод. Ваші налаштування збережено.",
|
||||
"render.cpu_volume_path_required": "Увімкніть непряме освітлення, щоб використовувати атмосферу на CPU.",
|
||||
"render.cpu_warm_cool": "Тепле й холодне",
|
||||
"render.denoise_class_background": "Пропущено: фон",
|
||||
"render.denoise_class_coverage": "Пропущено: часткове покриття",
|
||||
"render.denoise_class_degenerate": "Пропущено: вироджений шлях",
|
||||
"render.denoise_class_depth": "Пропущено: ліміт глибини шляху",
|
||||
"render.denoise_class_emitter": "Пропущено: джерело світла",
|
||||
"render.denoise_class_exit": "Пропущено: несумісний вихід",
|
||||
"render.denoise_class_identity": "Пропущено: ліміт ідентичності напрямних даних",
|
||||
"render.denoise_class_lens": "Пропущено: глибина різкості",
|
||||
"render.denoise_class_material": "Пропущено: непідтримуваний матеріал",
|
||||
"render.denoise_class_nested": "Пропущено: вкладене середовище",
|
||||
"render.denoise_class_optical": "Придатне: заломлена поверхня",
|
||||
"render.denoise_class_reflection": "Пропущено: відбивна кінцева точка",
|
||||
"render.denoise_class_surface": "Придатне: поверхня",
|
||||
"render.denoise_class_tir": "Пропущено: повне внутрішнє відбиття",
|
||||
"render.denoise_class_transmission": "Пропущено: подальше пропускання",
|
||||
"render.denoise_class_unavailable": "Пропущено: немає напрямних даних",
|
||||
"render.denoise_class_volume": "Пропущено: об'ємне розсіювання",
|
||||
"render.denoise_diagnostics_counts": "Придатні: {eligible} · Пропущені: {skipped}",
|
||||
"render.denoise_diagnostics_enable": "Збирати діагностику шумозаглушення",
|
||||
"render.denoise_diagnostics_grid": "Кількість пікселів у внутрішньому розмірі {width} × {height}.",
|
||||
"render.denoise_diagnostics_help": "Збирає кількість придатних і пропущених пікселів, навіть коли шумозаглушення вимкнено. Лічба використовує внутрішній розмір рендерингу, а маска — вихідний розмір.",
|
||||
"render.denoise_diagnostics_title": "Діагностика шумозаглушення",
|
||||
"render.denoise_export_mask": "Експортувати маску PNG",
|
||||
"render.denoise_firefly": "Пригнічувати ізольовані яскраві пікселі",
|
||||
"render.denoise_format_mask": "Маска PNG",
|
||||
"render.denoise_mask_copy_help": "Експортуйте маску шумозаглушення як PNG або поверніться до відрендереного зображення, щоб скопіювати його.",
|
||||
"render.denoise_mask_unavailable": "Увімкніть діагностику шумозаглушення й відрендерте зображення, щоб оглянути його маску.",
|
||||
"render.denoise_optical_filter": "Фільтрувати дзеркала й скло",
|
||||
"render.denoise_optical_filter_help": "Фільтрувати придатне відбите й пропущене світло. Вимкніть, щоб шумозаглушувати лише непрозорі поверхні.",
|
||||
"render.denoise_passes": "Проходи фільтрації",
|
||||
"render.denoise_settings_help": "Більше проходів згладжує ширшу область. Сила визначає, скільки фільтрації застосовує кожен прохід. Непідтримувані оптичні шляхи залишаються нефільтрованими.",
|
||||
"render.denoise_strength": "Сила шумозаглушення",
|
||||
"render.denoise_view_image": "Відрендерене зображення",
|
||||
"render.denoise_view_mask": "Маска шумозаглушення",
|
||||
"render.diag_bodies": "Видимі тіла",
|
||||
"render.diag_job_details": "Подробиці зафіксованого завдання",
|
||||
"render.diag_last_check": "Остання попередня перевірка",
|
||||
@@ -3538,6 +3680,7 @@
|
||||
"render.error_pbr_opacity": "непрозорий PBR вимагає непрозорості 1",
|
||||
"render.error_physical_glass": "вибраний рецепт не є фізичним склом",
|
||||
"render.error_preview_device": "для попереднього перегляду виробу потрібен установлений пристрій із буфером глибини",
|
||||
"render.error_product_placement": "недійсне розміщення виробу",
|
||||
"render.error_product_triangle": "недійсний трикутник виробу",
|
||||
"render.error_provisional_identity": "недійсний ідентифікатор проміжного рендерингу або кількість вибірок",
|
||||
"render.error_quality_bounds": "проєкція якості перевищує нативні межі",
|
||||
@@ -3602,7 +3745,16 @@
|
||||
"render.frame_tall": "9:16 · Вертикальний",
|
||||
"render.frame_thirds": "Третини",
|
||||
"render.frame_wide": "16:9 · Широкоекранний",
|
||||
"render.glass_abbe": "Число Аббе",
|
||||
"render.glass_dispersion": "Хроматична дисперсія",
|
||||
"render.glass_film": "Інтерференція тонкої плівки",
|
||||
"render.glass_film_ior": "IOR плівки",
|
||||
"render.glass_film_thickness": "Товщина плівки",
|
||||
"render.glass_model_enable": "Розширена модель скла",
|
||||
"render.glass_model_help": "Шорсткість скла розсіює промені, що проходять крізь нього. Дисперсія й колір плівки використовують три смуги довжин хвиль. Для шорстких листів потрібно вимкнути пряме пропускання тіней.",
|
||||
"render.glass_roughness": "Шорсткість скла",
|
||||
"render.gpu_depth": "Максимальна глибина шляху",
|
||||
"render.gpu_job_shader_wait": "Підготовка шейдерів може тривати хвилини",
|
||||
"render.gpu_options_help": "Вибірки, глибина, початкове значення та експозиція зберігаються разом із цим набором налаштувань. Зберігається лише активний метод зображення.",
|
||||
"render.gpu_path_crashed": "Минулого разу SolidCraft закрився під час налаштування на цьому графічному адаптері, найімовірніше всередині графічного драйвера, тому більше не налаштовує його сам. Виберіть трасування променів на CPU або спробуйте знову (оновлення драйвера також запускає нову спробу).",
|
||||
"render.gpu_path_failed": "Трасувальник шляхів GPU недоступний",
|
||||
@@ -3951,6 +4103,8 @@
|
||||
"render.material_transient": "Тимчасові оптичні перевизначення для цієї вкладки документа. Вони не зберігаються в проєкті, налаштуванні рендерингу чи бібліотеці матеріалів.",
|
||||
"render.material_v_up": "Вісь V текстури спрямована вгору на зображенні",
|
||||
"render.material_weight": "Вага покриття (0–1)",
|
||||
"render.metal_energy_compensation": "Відновлювати відбивну здатність шорсткого металу",
|
||||
"render.metal_energy_compensation_help": "Компенсує втрати світла між мікрогранями шорсткого металу. Рендеринг на CPU потребує непрямого освітлення.",
|
||||
"render.method_cpu": "Трасування променів на CPU",
|
||||
"render.method_gpu": "Трасування шляхів на GPU",
|
||||
"render.method_limit_raster": "Растр використовує фіксований непрозорий студійний перегляд. Виберіть явний метод трасування променів для підтримуваних оптичних параметрів.",
|
||||
@@ -4079,6 +4233,8 @@
|
||||
"render.quality_denoise_on": "Зменшення шуму: увімкнено",
|
||||
"render.quality_draft": "Чернетка",
|
||||
"render.quality_high": "Висока",
|
||||
"render.quality_legacy_samples": "Збережене значення: {samples} вибірок на піксель. Нові значення обмежено {maximum} вибірками на піксель.",
|
||||
"render.quality_preset_limit": "Цей пресет перевищує ліміт вибору 16384 вибірок на піксель. Виберіть кількість вибірок до 16384.",
|
||||
"render.quality_projection_help": "Шаблони Q містять майбутні вимоги. Ця дія проєктує лише підтримуваний бюджет PNG із фіксованою кількістю вибірок і явно пропускає адаптивну зупинку, необроблений лінійний вивід та незалежні обмеження пропускання.",
|
||||
"render.quality_review": "Переглянути бюджет вибірок",
|
||||
"render.quality_summary": "{width} × {height} · вибірок {samples} · глибина {depth} · початкове значення {seed} · {denoise}",
|
||||
@@ -4226,6 +4382,7 @@
|
||||
"render.show_shots_label": "Показати стрічку кадрів",
|
||||
"render.size_4k": "4K",
|
||||
"render.size_4k_uhd": "4K UHD",
|
||||
"render.size_8k_uhd": "8K UHD",
|
||||
"render.size_custom": "Власний…",
|
||||
"render.size_full_hd": "Full HD",
|
||||
"render.size_hd": "HD",
|
||||
@@ -4388,6 +4545,11 @@
|
||||
"render.subsurface_enable": "Випадкове блукання розсіювання всередині",
|
||||
"render.subsurface_help": "Лише для замкнених діелектриків. Розсіювання та поглинання RGB — окремі коефіцієнти на mm. Промені розсіюються всередині реальної геометрії, а на межі заломлюються або відбиваються. Вимкніть пряме пропускання тіней, шумозаглушення поверхні та зовнішній об'єм; використовуйте один шар Френеля. Це не шейдер дифузії, не сітка густини й не виміряний матеріал. Щільним середовищам може знадобитися більше вибірок і глибина шляху.",
|
||||
"render.subsurface_rate": "Частота зіткнень розсіювання",
|
||||
"render.supersampling": "Наддискретизація",
|
||||
"render.supersampling_dimensions": "Рендерить {width} × {height} і зменшує до {output_width} × {output_height}. Використовує вчетверо більше пікселів.",
|
||||
"render.supersampling_help": "Рендерить із подвійною шириною та висотою, потім зменшує в лінійному світлі. Вихідний розмір не змінюється.",
|
||||
"render.supersampling_off": "Вимкнено",
|
||||
"render.supersampling_x2": "2×",
|
||||
"render.surface_import.author": "Автор",
|
||||
"render.surface_import.busy": "Імпортування зображення…",
|
||||
"render.surface_import.complete": "Виберіть зображення та введіть його автора, джерело й ліцензію.",
|
||||
@@ -4401,6 +4563,8 @@
|
||||
"render.surface_import.saved_cpu": "Збережіть карти, щоб використовувати їх із рендерингом на CPU.",
|
||||
"render.surface_import.source": "Джерело",
|
||||
"render.surface_import.title": "Імпортувати зображення",
|
||||
"render.texture_filtering": "Фільтрувати деталі текстури",
|
||||
"render.texture_filtering_help": "Використовує mip-рівні й анізотропну фільтрацію, щоб зменшити аліасинг текстури під час мінімізації. Потребує більше пам'яті; вимкнено зберігає попередню фільтрацію.",
|
||||
"render.tone_aces_fitted": "ACES fitted",
|
||||
"render.tone_reinhard": "Reinhard",
|
||||
"render.transmission_scope": "Скло на GPU підтримує сертифіковані непересічні середовища. Необмежені вкладені середовища та безшумний оцінювач пропускання не надаються.",
|
||||
@@ -4570,6 +4734,7 @@
|
||||
"sketch.dimension_applied": "Розмір застосовано",
|
||||
"sketch.dimension_applied_defined": "Розмір застосовано; визначено параметр «{name}»",
|
||||
"sketch.dimension_applied_renamed": "Розмір застосовано; параметр перейменовано на «{name}»",
|
||||
"sketch.divide_hint": "Точки поділяють кожну криву на рівні за довжиною частини й зберігають їх, коли крива змінюється.",
|
||||
"sketch.dof_left": "Залишилося ступенів свободи: {count}",
|
||||
"sketch.dof_left_one": "Залишився {count} ступінь свободи",
|
||||
"sketch.draw_curves": "Малювати як {linetype}",
|
||||
@@ -4600,6 +4765,8 @@
|
||||
"sketch.hint.spline3d": "3D-сплайн: клацайте точки припасування в 3D; правою кнопкою або Esc, щоб завершити",
|
||||
"sketch.hint.trim": "Обрізати: клацніть частину кривої, яку треба прибрати, або протягніть по частинах, які треба прибрати",
|
||||
"sketch.make_selection": "Перетворити виділене на {linetype}",
|
||||
"sketch.move_released": "Переміщено: звільнено обмежень, що прив'язували його до нерухомого: {count} ({names}).",
|
||||
"sketch.move_released_one": "Переміщено: звільнено обмеження, що прив'язувало його до нерухомого: {count} ({names}).",
|
||||
"sketch.open_ends": "Відкритих: {count}",
|
||||
"sketch.status_conflict": "обмеження суперечать одне одному",
|
||||
"sketch.status_fully_constrained": "повністю обмежений",
|
||||
@@ -4630,6 +4797,10 @@
|
||||
"sketch_text.path_clear": "Зняти текст з його кривої",
|
||||
"sketch_text.path_hint": "Крива ескізу, якої дотримується текст: клацніть тут, а потім на кривій",
|
||||
"sketch_text.use_font_file": "Використати файл шрифту {path}",
|
||||
"sketch_text.valign_baseline": "Базова лінія",
|
||||
"sketch_text.valign_bottom": "Низ",
|
||||
"sketch_text.valign_middle": "Середина",
|
||||
"sketch_text.valign_top": "Верх",
|
||||
"solid": "суцільне",
|
||||
"status.editing": "Редагування: {name}",
|
||||
"status.navigation": "Призначення миші: {mapping}",
|
||||
@@ -4830,6 +5001,7 @@
|
||||
"ui.agent_chat_allow_once": "Дозволити один раз",
|
||||
"ui.agent_chat_allowed": "Дозволено",
|
||||
"ui.agent_chat_answered": "Відповідь: {option}",
|
||||
"ui.agent_chat_answered_in": "Відповідь за {time}",
|
||||
"ui.agent_chat_approval": "Дозволити агенту це зробити?",
|
||||
"ui.agent_chat_attach_selection": "Прикріпити виділення",
|
||||
"ui.agent_chat_attach_selection_tip": "Надіслати разом із повідомленням, що виділено в моделі (грані, ребра, операції, тіла), щоб агент розумів, що ви маєте на увазі",
|
||||
@@ -4871,6 +5043,7 @@
|
||||
"ui.agent_chat_dock_right": "Закріпити праворуч",
|
||||
"ui.agent_chat_drop_hint": "Перетягніть, щоб прикріпити до наступного повідомлення",
|
||||
"ui.agent_chat_edit": "Редагувати",
|
||||
"ui.agent_chat_ended_after": "Завершено за {time}",
|
||||
"ui.agent_chat_exited": "Агент зупинився.",
|
||||
"ui.agent_chat_failed_start": "Не вдалося запустити агента: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: CAD-файл імпортується в проєкт, а не читається",
|
||||
@@ -4908,6 +5081,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model} не може користуватися інструментами SolidCraft, тож лише спілкується в чаті. Виберіть модель з підтримкою інструментів.",
|
||||
"ui.agent_chat_model_rejected": "Агент не прийняв {model}: {error}",
|
||||
"ui.agent_chat_model_search": "Пошук моделей…",
|
||||
"ui.agent_chat_model_search_or_id": "Пошук або введіть будь-який ID моделі…",
|
||||
"ui.agent_chat_model_tip": "Модель, яку використовує агент. Ваш вибір запам'ятовується для цього агента.",
|
||||
"ui.agent_chat_models_failed": "Не вдалося отримати список моделей: {error}",
|
||||
"ui.agent_chat_models_heading": "Доступні моделі",
|
||||
@@ -4965,6 +5139,10 @@
|
||||
"ui.agent_chat_setup_title": "Налаштувати асистента",
|
||||
"ui.agent_chat_side": "Закріпити чат",
|
||||
"ui.agent_chat_signed_in": "виконано вхід",
|
||||
"ui.agent_chat_snap_none_found": "Агента для програмування не знайдено. Пакет Snap працює в ізольованому середовищі, тому не бачить і не може запускати агентів для програмування, установлених на цьому комп’ютері. Щоб користуватися ними, установіть SolidCraft з пакета AppImage, .deb або .rpm. Агент, що використовує API, сумісний з OpenAI, працює і в пакеті Snap: налаштуйте його через «Додати агента».",
|
||||
"ui.agent_chat_span_h": "{h} год {min} хв",
|
||||
"ui.agent_chat_span_min": "{n} хв",
|
||||
"ui.agent_chat_span_s": "{n} с",
|
||||
"ui.agent_chat_state_auth": "Потрібен вхід",
|
||||
"ui.agent_chat_state_busy": "Працює…",
|
||||
"ui.agent_chat_state_exited": "Агент зупинився",
|
||||
@@ -4975,6 +5153,10 @@
|
||||
"ui.agent_chat_stop": "Зупинити",
|
||||
"ui.agent_chat_stop_tip": "Зупинити агента й усе, що він запустив",
|
||||
"ui.agent_chat_stop_turn_tip": "Зупинити агента (Esc). Повідомлення в черзі залишаються в черзі.",
|
||||
"ui.agent_chat_thinking_for": "Міркування: {time}",
|
||||
"ui.agent_chat_tool_running_for": "триває {time}",
|
||||
"ui.agent_chat_transcript_assistant": "Асистент:",
|
||||
"ui.agent_chat_transcript_user": "Користувач:",
|
||||
"ui.agent_chat_turn_limit": "Змін на повідомлення",
|
||||
"ui.agent_chat_turn_unlimited": "Без обмежень",
|
||||
"ui.agent_chat_undo_changes": "Скасувати ці зміни",
|
||||
@@ -5131,7 +5313,9 @@
|
||||
"ui.browser_bodies_one": "{count} тіло",
|
||||
"ui.browser_bodies_other": "{count} тіл",
|
||||
"ui.browser_collapse": "Згорнути браузер",
|
||||
"ui.browser_collapse_below": "Згорнути вкладене",
|
||||
"ui.browser_expand": "Розгорнути браузер",
|
||||
"ui.browser_expand_below": "Розгорнути вкладене",
|
||||
"ui.browser_title": "Браузер",
|
||||
"ui.calibrate": "Калібрувати",
|
||||
"ui.cancel": "Скасувати",
|
||||
@@ -5190,14 +5374,24 @@
|
||||
"ui.conic_curve": "Конічна крива",
|
||||
"ui.constant": "Стала",
|
||||
"ui.constraints_conflict": "Конфлікт обмежень",
|
||||
"ui.construct_auto.chosen": "Вибрано за вашими опорними елементами. Виберіть інший опорний елемент або приберіть один, щоб змінити метод.",
|
||||
"ui.construct_auto.no_fit": "Виберіть інші опорні елементи: жоден метод не будує з цих.",
|
||||
"ui.construct_auto.pick": "Виберіть, з чого будувати: метод випливає з ваших виборів.",
|
||||
"ui.construct_auto.refs": "Опорні елементи",
|
||||
"ui.construct_auto.select": "Спершу виберіть опорні елементи для побудови",
|
||||
"ui.construct_axes": "Осі",
|
||||
"ui.construct_planes": "Площини",
|
||||
"ui.construct_points": "Точки",
|
||||
"ui.construction": "Конструкційна",
|
||||
"ui.construction.angle_hint": "Допоміжна пряма: клацніть точку, потім введіть кут або виберіть напрямок",
|
||||
"ui.construction.axis_hint": "Допоміжна пряма: клацніть точку або введіть її відстань від осі ескізу",
|
||||
"ui.construction.bisector_hint": "Бісектриса: виберіть дві прямі, що перетинаються, потім потрібний варіант",
|
||||
"ui.construction.common_hint": "Спільна дотична: виберіть два кола/дуги, потім потрібний варіант",
|
||||
"ui.construction.contact_hint": "Дотична: виберіть коло/дугу або відкритий сплайн/конічну криву, потім точку дотику (криві довільної форми: кінцеві точки)",
|
||||
"ui.construction.external_hint": "Дотична: виберіть коло або дугу, зовнішню точку, потім потрібний варіант",
|
||||
"ui.construction.free_hint": "Допоміжна пряма: клацніть дві точки; клацніть правою кнопкою, щоб почати знову",
|
||||
"ui.construction.normal_needs_length": "Нескінченна пряма завжди допоміжна: введіть довжину, щоб накреслити звичайну пряму",
|
||||
"ui.construction.parallel_hint": "Допоміжна пряма: виберіть пряму, потім клацніть або введіть зсув; клацніть правою кнопкою, щоб змінити опорний об'єкт",
|
||||
"ui.construction.point_hint": "Допоміжна пряма: клацніть точку, через яку вона проходить",
|
||||
"ui.construction.reference_hint": "Допоміжна пряма: виберіть пряму, потім точку; клацніть правою кнопкою, щоб змінити опорний об'єкт",
|
||||
"ui.construction.ribbon_label": "Доп. лінії",
|
||||
@@ -5419,6 +5613,8 @@
|
||||
"ui.fine": "Висока",
|
||||
"ui.finest": "Максимальна",
|
||||
"ui.finish_sketch": "Завершити ескіз",
|
||||
"ui.first_dimension_scales": "Перший розмір масштабує креслення",
|
||||
"ui.first_dimension_scales_tip": "Увімкнено: перший лінійний розмір ескізу масштабує креслення, яке він вимірює, тож форма зберігається. Вимкнено: розмір задає лише те, що вимірює.",
|
||||
"ui.fit": "Вписати",
|
||||
"ui.fix_unfix": "Закріпити/розкріпити",
|
||||
"ui.flat": "Плоска",
|
||||
@@ -5458,6 +5654,7 @@
|
||||
"ui.heading_custom_view_navigator": "ВЛАСНИЙ НАВІГАТОР ВИДУ",
|
||||
"ui.heading_cylinder": "ЦИЛІНДР",
|
||||
"ui.heading_design": "ПРОЄКТ",
|
||||
"ui.heading_divide_curve": "ПОДІЛИТИ КРИВУ",
|
||||
"ui.heading_draft": "УХИЛ",
|
||||
"ui.heading_edit": "РЕДАГУВАТИ",
|
||||
"ui.heading_equation_curve": "КРИВА ЗА РІВНЯННЯМ",
|
||||
@@ -5491,6 +5688,7 @@
|
||||
"ui.heading_plastic": "ПЛАСТИК",
|
||||
"ui.heading_position": "ПОЛОЖЕННЯ",
|
||||
"ui.heading_prepare": "ПІДГОТУВАТИ",
|
||||
"ui.heading_press_pull": "НАТИСНУТИ/ВИТЯГНУТИ",
|
||||
"ui.heading_rectangular_pattern": "ПРЯМОКУТНИЙ МАСИВ",
|
||||
"ui.heading_revolve": "ОБЕРТАННЯ",
|
||||
"ui.heading_right": "СПРАВА",
|
||||
@@ -5627,6 +5825,8 @@
|
||||
"ui.mesh_format_3mf": "3MF",
|
||||
"ui.mesh_format_3mf_tagged": "3MF з мітками граней",
|
||||
"ui.mesh_format_stl": "STL",
|
||||
"ui.mesh_import_origin": "Перемістити до початку координат",
|
||||
"ui.mesh_import_origin_tip": "Центрувати сітку по X і Y, розмістивши її основу на Z = 0. Коли вимкнено, сітка зберігає координати, записані у файлі.",
|
||||
"ui.minor_radius": "Малий радіус",
|
||||
"ui.mirror": "Дзеркало",
|
||||
"ui.mirror_line": "Вісь дзеркала",
|
||||
@@ -5731,6 +5931,42 @@
|
||||
"ui.panel_host.surface": "Панель",
|
||||
"ui.panel_host.tab": "Вкладка панелі",
|
||||
"ui.panel_host.tabs": "Усі вкладки",
|
||||
"ui.panel_layout.applied": "Застосовано «{name}» у робочій області «{workspace}»",
|
||||
"ui.panel_layout.cancel": "Скасувати",
|
||||
"ui.panel_layout.confirm_replace": "Замінити «{name}»?",
|
||||
"ui.panel_layout.copy": "Копіювати",
|
||||
"ui.panel_layout.current": "Поточне компонування",
|
||||
"ui.panel_layout.custom": "Власне",
|
||||
"ui.panel_layout.custom_hint": "Панелі переміщено після застосування: {name}.",
|
||||
"ui.panel_layout.details": "Подробиці",
|
||||
"ui.panel_layout.layout_workspace": "Робоча область компонування",
|
||||
"ui.panel_layout.page_defaults_hint": "Скидає налаштування цієї сторінки. Розташування панелей і збережені компонування залишаються без змін.",
|
||||
"ui.panel_layout.panel_layout": "Компонування панелей",
|
||||
"ui.panel_layout.panel_style": "Стиль панелей",
|
||||
"ui.panel_layout.replace": "Замінити компонування",
|
||||
"ui.panel_layout.replace_current": "Замінити поточним",
|
||||
"ui.panel_layout.replace_short": "Замінити",
|
||||
"ui.panel_layout.reset": "Скинути робочу область",
|
||||
"ui.panel_layout.reset_hint": "Повернути робочу область «{workspace}» до типового розташування. Збережені компонування залишаються без змін.",
|
||||
"ui.panel_layout.reset_short": "Скинути",
|
||||
"ui.panel_layout.restore_failed": "Не вдалося відновити ваше компонування",
|
||||
"ui.panel_layout.save": "Зберегти компонування",
|
||||
"ui.panel_layout.save_as": "Зберегти як",
|
||||
"ui.panel_layout.save_as_tile": "Зберегти як…",
|
||||
"ui.panel_layout.selected": "вибрано",
|
||||
"ui.panel_layout.suggested_name": "Компонування {n}",
|
||||
"ui.panel_layout.try_again": "Спробувати знову",
|
||||
"ui.panel_layout.validation.builtin": "Вбудовані компонування не можна змінювати",
|
||||
"ui.panel_layout.validation.duplicate": "Ця назва вже використовується",
|
||||
"ui.panel_layout.validation.empty": "Введіть назву",
|
||||
"ui.panel_layout.validation.full": "Збережено 64 з 64. Виберіть одне для заміни.",
|
||||
"ui.panel_layout.validation.invalid": "Використовуйте від 1 до 64 символів без керівних символів",
|
||||
"ui.panel_layout.workspace.classic": "Класичне",
|
||||
"ui.panel_layout.workspace.modelling": "Моделювання",
|
||||
"ui.panel_layout.workspace.render": "Рендеринг",
|
||||
"ui.panel_layout.workspace.review": "Огляд",
|
||||
"ui.panel_layout.workspace.sketch": "Ескіз",
|
||||
"ui.panel_layout.your_layout": "ваше компонування",
|
||||
"ui.parallel": "Паралельність",
|
||||
"ui.parameters": "Параметри",
|
||||
"ui.part_size_needs_a_part": "Виберіть вставлену стандартну деталь (гвинт, гайку, шайбу або штифт), щоб змінити її розмір. Щоб збільшити або зменшити тіло, скористайтеся «Масштаб».",
|
||||
@@ -5777,6 +6013,7 @@
|
||||
"ui.point_cloud_no_file_colors": "У файлі немає кольорів",
|
||||
"ui.point_cloud_pause": "Пауза",
|
||||
"ui.point_cloud_play": "Відтворити",
|
||||
"ui.point_cloud_reload": "Перезавантажити з файлу",
|
||||
"ui.point_cloud_single_color": "Один колір",
|
||||
"ui.point_cloud_size": "Розмір точки",
|
||||
"ui.point_cloud_units": "Одиниці файлу",
|
||||
@@ -5795,6 +6032,8 @@
|
||||
"ui.profiles": "Профілі",
|
||||
"ui.project": "Проєктувати",
|
||||
"ui.project_face_edges_sketch": "Проєктувати ребра граней у нові ескізи",
|
||||
"ui.project_references_construction": "Проєктувати посилання як допоміжну геометрію",
|
||||
"ui.project_references_construction_note": "«Проєктувати», «Перетин», «Включити 3D-геометрію» і ребра грані, які додає новий ескіз на грані, створюють допоміжну геометрію: посилання для креслення, не включені до профілів. Вони залишаються пов'язаними з моделлю.",
|
||||
"ui.properties": "Властивості",
|
||||
"ui.properties.copy_matrix": "Копіювати матрицю",
|
||||
"ui.properties.first_moments": "Перші моменти",
|
||||
@@ -5838,6 +6077,8 @@
|
||||
"ui.renderer": "Рендерер",
|
||||
"ui.repeat": "Повторити",
|
||||
"ui.repeat_nothing": "Поки що нічого повторювати: спершу запустіть інструмент або діалог.",
|
||||
"ui.replace_sketch.from_file": "З файлу проєкту…",
|
||||
"ui.replace_sketch.no_sketches": "У цьому проєкті немає ескізу, який можна взяти",
|
||||
"ui.replace_with_link_done": "Тепер копії — розміщення пов'язаного проєкту.",
|
||||
"ui.report_a_bug": "Повідомити про помилку",
|
||||
"ui.report_characters_left_one": "Залишився {count} символ",
|
||||
@@ -5862,6 +6103,8 @@
|
||||
"ui.ribbon_pin_footer": "Закріплені команди відображаються на стрічці. Наведіть курсор на рядок, щоб закріпити або відкріпити його.",
|
||||
"ui.ribbon_workspace": "Робоча область",
|
||||
"ui.right": "Справа",
|
||||
"ui.right_click_confirms": "Правий клік підтверджує поля діалогу",
|
||||
"ui.right_click_confirms_tip": "Коли діалог відкрито, правий клік у вигляді переходить до наступного порожнього поля, а на останньому виконує OK",
|
||||
"ui.save": "Зберегти",
|
||||
"ui.save_as": "Зберегти як",
|
||||
"ui.save_mesh_no_slicer_open": "Слайсер не знайдено: виберіть «Власний…» і вкажіть свою програму-слайсер",
|
||||
@@ -5873,6 +6116,7 @@
|
||||
"ui.second_rail": "Друга напрямна",
|
||||
"ui.section_analysis": "Аналіз перерізу",
|
||||
"ui.section_size": "Розмір перерізу",
|
||||
"ui.segments": "Сегменти",
|
||||
"ui.select": "Вибрати",
|
||||
"ui.selectOther": "Вибрати інше…",
|
||||
"ui.selectTangentChain": "Вибрати дотичний ланцюг",
|
||||
|
||||
@@ -247,6 +247,7 @@
|
||||
"Drag to move the hole; click to remove it": "Kéo để di chuyển lỗ; bấm để xóa",
|
||||
"Drag to move the rest across the model. It snaps to sketch points on the face.": "Kéo để di chuyển gờ đỡ trên mô hình. Gờ sẽ bắt dính vào các điểm phác thảo trên bề mặt.",
|
||||
"Drag to move the snap fit across the model. It snaps to sketch points on the face.": "Kéo để di chuyển khớp cài (snap fit) trên mô hình. Khớp sẽ bắt dính vào các điểm phác thảo trên bề mặt.",
|
||||
"Drag to place it on another face.": "Kéo để đặt nó lên một bề mặt khác.",
|
||||
"Drag to point the catch in another direction.": "Kéo để hướng lẫy cài sang hướng khác.",
|
||||
"Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.": "Kéo để xoay gờ đỡ theo từng bước 5°. Giữ phím Alt hoặc Ctrl để xoay tự do.",
|
||||
"Drive Joint": "Dẫn động khớp nối",
|
||||
@@ -513,6 +514,7 @@
|
||||
"Offset Y": "Độ lệch Y",
|
||||
"Offset Z": "Độ lệch Z",
|
||||
"On your computer": "Trên máy tính của bạn",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "Thêm một đoạn nữa của cạnh đã chọn, mỗi đoạn có góc, chiều cao và hướng uốn riêng",
|
||||
"Opacity": "Độ mờ đục",
|
||||
"Open GitHub": "Mở GitHub",
|
||||
"Open GitHub draft": "Mở bản nháp trên GitHub",
|
||||
@@ -634,6 +636,7 @@
|
||||
"Remove the track": "Xóa rãnh dẫn",
|
||||
"Remove this bend": "Xóa góc uốn này",
|
||||
"Remove this point": "Xóa điểm này",
|
||||
"Remove this segment": "Xóa đoạn này",
|
||||
"Rename Feature": "Đổi tên tính năng",
|
||||
"Rename Folder": "Đổi tên thư mục",
|
||||
"Render Stage": "Giai đoạn kết xuất",
|
||||
@@ -723,6 +726,7 @@
|
||||
"Section position": "Vị trí mặt cắt",
|
||||
"Sections": "Các mặt cắt",
|
||||
"Sections (one sketch each)": "Các mặt cắt (mỗi mặt cắt một phác thảo)",
|
||||
"Segments": "Đoạn",
|
||||
"Select Features": "Chọn tính năng",
|
||||
"Select Other": "Chọn đối tượng khác",
|
||||
"Select Other: hold the left button still on the model (or right-click › Select Other…) to list everything under the cursor; click again on the same spot to select the next thing there. Double-click the middle button to go Home (Preferences › Navigation).": "Chọn đối tượng khác: giữ nút chuột trái đứng yên trên mô hình (hoặc nhấp chuột phải › Chọn đối tượng khác…) để liệt kê mọi đối tượng dưới con trỏ; nhấp lại vào cùng vị trí đó để chọn đối tượng kế tiếp. Nhấp đúp chuột giữa để về Góc nhìn chuẩn (Tùy chọn cài đặt › Điều hướng).",
|
||||
@@ -772,6 +776,7 @@
|
||||
"Spacing must be a non-zero number": "Khoảng cách phải là một số khác 0",
|
||||
"Specialise": "Chuyên biệt hóa",
|
||||
"Speed": "Tốc độ",
|
||||
"Split Edge": "Chia cạnh",
|
||||
"Splitting tool": "Công cụ cắt chia",
|
||||
"Square": "Hình vuông",
|
||||
"Stainless Steel": "Thép không gỉ",
|
||||
@@ -885,6 +890,7 @@
|
||||
"Variable Radius": "Bán kính thay đổi",
|
||||
"Variable radius": "Bán kính thay đổi",
|
||||
"Velocity": "Vận tốc",
|
||||
"Vertical": "Dọc",
|
||||
"Vertices": "Các đỉnh",
|
||||
"View": "Xem",
|
||||
"View navigator": "Khối điều hướng góc nhìn",
|
||||
@@ -938,6 +944,13 @@
|
||||
"ai.prefs.connect_apps_note": "Tắt sẽ xóa các mục đã thêm.\n\nKhi SolidCraft khởi động, tự động thêm phần mềm dưới dạng MCP server vào các ứng dụng AI tìm thấy trên máy tính này (OpenCode, Claude Desktop, Claude Code, Cursor, Codex, Gemini CLI, Copilot CLI, Windsurf, Zed, VS Code) để AI agent có thể sử dụng ngay mà không cần cấu hình thủ công. Chỉ mục cấu hình solidcraft sẽ được thêm mới hoặc làm mới đường dẫn; các mục bạn tự tùy chỉnh sẽ được giữ nguyên và file được sao lưu .bak trước khi sửa. Tắt: các mục đã thêm sẽ được gỡ bỏ. Trợ giúp > Kết nối trợ lý ảo AI… để thực hiện thủ công.",
|
||||
"ai.prefs.connect_at_start": "Kết nối tác nhân gần nhất khi khởi động",
|
||||
"ai.prefs.connect_at_start_note": "Mỗi lần SolidCraft khởi động, chạy ngầm tác tử bạn kết nối gần nhất (hoặc tác tử mặc định) để sẵn sàng trò chuyện. Không áp dụng khi SolidCraft được khởi động với --control. Nếu không kết nối được, Trợ lý hiển thị “Kết nối thất bại” và nút “Thử lại”.",
|
||||
"ai.prefs.control_failed": "Không thể khởi động kênh điều khiển: {error}",
|
||||
"ai.prefs.control_from_launch": "Lần chạy này được khởi động với --control trên cổng {port}. Các thay đổi ở đây có hiệu lực vào lần tới SolidCraft khởi động mà không có --control.",
|
||||
"ai.prefs.control_listening": "Đang lắng nghe trên 127.0.0.1:{port}",
|
||||
"ai.prefs.control_not_listening": "Không lắng nghe",
|
||||
"ai.prefs.control_port": "Cổng",
|
||||
"ai.prefs.control_port_note": "Cổng mà các tác tử AI kết nối trên máy tính này (127.0.0.1). Mặc định là 27878: nếu cổng đang được dùng, cổng trống tiếp theo sẽ được dùng. Mọi cổng khác được dùng đúng như vậy. Hãy trỏ ứng dụng MCP của bạn đến cùng cổng, ví dụ solidcraft-cli mcp --connect 127.0.0.1:7878.",
|
||||
"ai.prefs.control_port_taken": "Cổng {port} đang được một chương trình khác (hoặc một cửa sổ SolidCraft khác) sử dụng. Hãy chọn cổng khác.",
|
||||
"ai.prefs.follow_camera": "Theo camera",
|
||||
"ai.prefs.follow_camera_off": "Tự động xoay camera theo phác thảo đang tắt.",
|
||||
"ai.prefs.follow_camera_on": "Camera sẽ tự động xoay vuông góc với phác thảo do agent tạo.",
|
||||
@@ -998,6 +1011,13 @@
|
||||
"browser.sketches_to_parts_not_on_face": "không nằm trên mặt của một chi tiết",
|
||||
"browser.sketches_to_parts_part_missing": "chi tiết của chúng không còn",
|
||||
"browser.sketches_to_parts_result": "Đã chuyển {moved} bản phác thảo vào chi tiết chứa chúng; {stayed} giữ nguyên: {why}",
|
||||
"browser.straighten_angle": "Hướng của cạnh",
|
||||
"browser.straighten_choose": "Chọn hướng cho cạnh (Ngang, Dọc hoặc một góc), rồi nhấn Làm thẳng.",
|
||||
"browser.straighten_click_a": "Nhấp vào ảnh tại một đầu của cạnh cần thẳng, hoặc nhập tọa độ của nó.",
|
||||
"browser.straighten_click_b": "Nhấp vào đầu kia của cạnh, hoặc nhập tọa độ của nó.",
|
||||
"browser.straighten_horizontal": "Ngang",
|
||||
"browser.straighten_title": "Làm thẳng: {name}",
|
||||
"browser.straighten_vertical": "Dọc",
|
||||
"browser.units": "Đơn vị: {units}",
|
||||
"cam.flat": "Bề mặt phẳng",
|
||||
"cam.follower": "Con đội cam",
|
||||
@@ -1027,6 +1047,8 @@
|
||||
"cmd.appearance_pick_up": "Lấy diện mạo",
|
||||
"cmd.appearance_replace": "Thay diện mạo",
|
||||
"cmd.assembly_bom": "Bảng kê vật tư (BOM)",
|
||||
"cmd.assembly_constraint_create": "Ràng buộc",
|
||||
"cmd.assembly_constraint_edit": "Sửa ràng buộc",
|
||||
"cmd.assembly_mass_properties": "Thuộc tính khối lượng",
|
||||
"cmd.body.print_face": "Mặt in",
|
||||
"cmd.body_rename": "Đổi tên thân khối",
|
||||
@@ -1045,6 +1067,7 @@
|
||||
"cmd.canvas_delete": "Xóa Canvas",
|
||||
"cmd.canvas_edit": "Chỉnh sửa hình ảnh Canvas",
|
||||
"cmd.canvas_insert": "Chèn hình ảnh Canvas",
|
||||
"cmd.canvas_straighten": "Làm thẳng hình ảnh Canvas",
|
||||
"cmd.canvas_to_sketch": "Phác thảo từ hình ảnh Canvas",
|
||||
"cmd.component_activate": "Kích hoạt cụm chi tiết",
|
||||
"cmd.component_break_link": "Ngắt liên kết cụm chi tiết",
|
||||
@@ -1086,7 +1109,10 @@
|
||||
"cmd.config_rule": "Quy tắc cấu hình",
|
||||
"cmd.config_rules": "Danh sách quy tắc cấu hình",
|
||||
"cmd.config_table": "Hiển thị bảng cấu hình",
|
||||
"cmd.construct.axis": "Trục",
|
||||
"cmd.construct.plane": "Mặt phẳng",
|
||||
"cmd.construct.plane.axis_point": "Mặt phẳng qua trục và điểm",
|
||||
"cmd.construct.point": "Điểm",
|
||||
"cmd.construct_axis_edge": "Trục đi qua cạnh",
|
||||
"cmd.construct_axis_normal_to_face": "Trục vuông góc với bề mặt",
|
||||
"cmd.construct_axis_through_cylinder": "Trục qua hình trụ/nón/xuyến",
|
||||
@@ -1149,6 +1175,7 @@
|
||||
"cmd.file_save_mesh": "Lưu dưới dạng lưới đa giác",
|
||||
"cmd.file_send_to_slicer": "Gửi sang phần mềm cắt lớp (Slicer)",
|
||||
"cmd.file_slicers": "Phần mềm cắt lớp đã cài đặt",
|
||||
"cmd.frame_end_cap": "Nắp đầu",
|
||||
"cmd.frame_member": "Phần tử khung kết cấu",
|
||||
"cmd.frame_profile_insert": "Chèn tiết diện",
|
||||
"cmd.frame_profile_list": "Thư viện tiết diện",
|
||||
@@ -1169,6 +1196,7 @@
|
||||
"cmd.inspect_isocurve": "Phân tích đường đẳng trị (Isocurve)",
|
||||
"cmd.inspect_minimum_radius": "Phân tích bán kính tối thiểu",
|
||||
"cmd.inspect_parameter_sweep": "Quét dải tham số",
|
||||
"cmd.inspect_parameter_variants": "So sánh các phương án tham số",
|
||||
"cmd.inspect_silhouette": "Phân tích đường bao bóng (Silhouette)",
|
||||
"cmd.inspect_zebra": "Phân tích sọc ngựa vằn (Zebra)",
|
||||
"cmd.joint_as_built": "Khớp nối theo vị trí hiện trạng",
|
||||
@@ -1222,6 +1250,10 @@
|
||||
"cmd.motion_trace": "Quỹ đạo chuyển động",
|
||||
"cmd.motion_trace_edit": "Chỉnh sửa quỹ đạo chuyển động",
|
||||
"cmd.motion_trace_keep": "Giữ lại đường quỹ đạo chuyển động",
|
||||
"cmd.note_add": "Thêm ghi chú",
|
||||
"cmd.note_delete": "Xóa ghi chú",
|
||||
"cmd.note_list": "Liệt kê ghi chú",
|
||||
"cmd.note_update": "Chỉnh sửa ghi chú",
|
||||
"cmd.occurrence_align": "Căn chỉnh bản thể",
|
||||
"cmd.occurrence_copy": "Dán (Bản thể)",
|
||||
"cmd.occurrence_drag": "Kéo chi tiết xuất hiện",
|
||||
@@ -1347,6 +1379,7 @@
|
||||
"cmd.render_start": "Bắt đầu kết xuất hình ảnh",
|
||||
"cmd.render_status": "Tiến độ kết xuất hình ảnh",
|
||||
"cmd.select_clear": "Hủy chọn tất cả",
|
||||
"cmd.selection_get": "Lấy vùng chọn",
|
||||
"cmd.settings_profile_apply": "Áp dụng hồ sơ cài đặt",
|
||||
"cmd.settings_profile_delete": "Xóa hồ sơ cài đặt",
|
||||
"cmd.settings_profile_export": "Xuất hồ sơ cài đặt",
|
||||
@@ -1510,6 +1543,7 @@
|
||||
"cmd.timeline_suppress": "Tạm nén tính năng",
|
||||
"cmd.ui.assistant": "Bật/tắt trợ lý",
|
||||
"cmd.ui.palette": "Tìm kiếm lệnh",
|
||||
"cmd.ui.toggle_visibility": "Hiển thị/Ẩn mục đã chọn",
|
||||
"cmd.view.navigator": "Khối điều hướng góc nhìn tùy chỉnh",
|
||||
"cmd.view.render_browser": "Trình duyệt kết xuất",
|
||||
"cmd.view.render_dock": "Di chuyển neo kết xuất",
|
||||
@@ -1567,6 +1601,7 @@
|
||||
"color.step_down": "Giảm một bước",
|
||||
"color.step_up": "Tăng một bước",
|
||||
"color.value": "Giá trị, độ sáng (phần trăm)",
|
||||
"component.error.ambiguous_name": "Nhiều thành phần có tên `{name}`. Hãy dùng ID thành phần dạng số: {ids}.",
|
||||
"config.column_filter_empty": "Không có cột phù hợp",
|
||||
"config.rule_parameter_columns": "Chỉ những tham số có cột trong bảng mới được liệt kê. Thêm cột bằng “Thêm cột” (+) để dùng tham số đó ở đây.",
|
||||
"config.rule_suppression_columns": "Chỉ những tính năng có cột “Bỏ kích hoạt (Suppress)” trong bảng mới được liệt kê. Thêm cột bằng “Thêm cột” (+) để điều khiển tính năng đó ở đây.",
|
||||
@@ -1607,6 +1642,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}: tham chiếu `{reference}` không còn tồn tại như khi được chọn; hãy chọn lại",
|
||||
"dialog.bodies_count": "{count} thân khối",
|
||||
"dialog.clearance_invalid": "khoảng cách an toàn phải có chiều dài từ 0 trở lên",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "Tính toán",
|
||||
"dialog.compute_again": "Tính toán lại",
|
||||
"dialog.computing": "Đang tính toán… {seconds} s",
|
||||
@@ -1619,10 +1655,12 @@
|
||||
"dialog.dimension_step_expression": "Chỉ số mới thay đổi theo bước; biểu thức giữ nguyên như đã nhập",
|
||||
"dialog.dimension_step_up": "Tăng {step}",
|
||||
"dialog.edit_title": "CHỈNH SỬA {title}",
|
||||
"dialog.hole_held_off_its_line": "Cạnh tham chiếu giữ lỗ này trên một đường thẳng ra khỏi mặt trước điểm đã chọn. Hãy chọn chỗ đường thẳng đi qua mặt, hoặc bỏ cạnh để di chuyển lỗ tự do.",
|
||||
"dialog.no_shown_body": "Không có thân khối đang hiển thị để thay đổi: hãy hiển thị một thân khối, hoặc chọn “Tạo mới Thân khối”",
|
||||
"dialog.pattern_sketch_not_object": "Hãy chọn thân khối hoặc tính năng: bản phác thảo không phải là cả hai. Lặp lại các đường cong của nó bằng Mảng hoặc Lấy đối xứng trong chính bản phác thảo, hoặc đùn khối nó trước.",
|
||||
"dialog.primitive_point_tip": "Một điểm điền vào X, Y và Z: nhấp vào đây, sau đó nhấp vào một đỉnh, cạnh hoặc bề mặt của mô hình, một điểm của bản phác thảo, hoặc gốc tọa độ.",
|
||||
"dialog.reference_edge_tip": "Một cạnh thẳng của bề mặt đã chọn, từ đó đo khoảng cách bên dưới: nhấp vào đây, sau đó nhấp vào cạnh.",
|
||||
"dialog.right_click_pick": "Chọn {input} trước",
|
||||
"dialog.select": "↖ Chọn",
|
||||
"dialog.selected_count": "↖ {count} đã chọn",
|
||||
"dialog.selection_constraint": "Ràng buộc {id}",
|
||||
@@ -1636,9 +1674,12 @@
|
||||
"document.changed_on_disk": "{name} đã thay đổi trên đĩa",
|
||||
"document.changed_on_disk_detail": "{name} đã bị thay đổi bởi chương trình hoặc máy tính khác kể từ khi bạn mở hoặc lưu lần cuối. Ghi đè sẽ thay thế các thay đổi đó bằng thay đổi của bạn; Lưu bản sao sẽ giữ lại cả hai.",
|
||||
"document.copy_name": "Bản sao {name}",
|
||||
"document.discard_row": "Bỏ thay đổi",
|
||||
"document.finish_save_prompt": "Hãy trả lời xong hộp thoại lưu trước khi mở thiết kế khác.",
|
||||
"document.newer_file": "Được lưu bằng phiên bản SolidCraft mới hơn (định dạng {format}, phiên bản này đọc được đến {reads}). Nếu thiếu gì, hãy cập nhật.",
|
||||
"document.newer_file_change": "Được lưu bằng phiên bản SolidCraft mới hơn (định dạng {format} với `{change}`, phiên bản này không biết). Nếu thiếu gì, hãy cập nhật.",
|
||||
"document.newer_file_not_read": "Không đọc được: {what}. Khi lưu, nội dung này vẫn được giữ lại.",
|
||||
"document.not_saved_yet": "Chưa lưu",
|
||||
"document.open_anyway": "Vẫn mở",
|
||||
"document.open_elsewhere": "{name} hiện đang được mở",
|
||||
"document.open_elsewhere_detail": "{name} đang được mở trong SolidCraft {app} trên {who}, mở lúc {when}. Nếu cả hai cùng lưu, một người sẽ mất phần công việc. Mở ở chế độ chỉ đọc để xem mà không ghi đè lên tệp.",
|
||||
@@ -1648,6 +1689,9 @@
|
||||
"document.read_only_save": "Thiết kế này được mở ở chế độ chỉ đọc: hãy lưu thành tệp mới",
|
||||
"document.save_changes": "Lưu các thay đổi đối với {name}?",
|
||||
"document.save_copy": "Lưu bản sao…",
|
||||
"document.save_many": "Lưu thay đổi cho {n} thiết kế?",
|
||||
"document.save_row": "Lưu",
|
||||
"document.save_selected": "Lưu mục đã chọn",
|
||||
"document.tab_unsaved_changes": "Thay đổi chưa lưu",
|
||||
"document.unsaved_changes": "{name} có các thay đổi chưa lưu. Nếu không lưu, các thay đổi sẽ bị mất.",
|
||||
"drive.rigid": "{joint} là khớp nối cứng: nó giữ cố định các chi tiết, nên không có gì để dẫn động. Để các chi tiết chuyển động, hãy đổi loại khớp nối trong “Chỉnh sửa khớp nối”: Revolute để xoay, Slider để trượt, Cylindrical cho cả hai.",
|
||||
@@ -1667,6 +1711,8 @@
|
||||
"dxf.tolerance": "Dung sai đường cong",
|
||||
"dxf.tolerance_help": "Chỉ áp dụng cho các thân khối và phác thảo hiển thị. Đường cong sử dụng các đoạn thẳng. Dung sai nhỏ hơn cho đường cong mịn hơn nhưng tốn nhiều thời gian và bộ nhớ hơn.",
|
||||
"each rail's curves must be in one sketch": "các đường cong của mỗi đường dẫn hướng phải nằm trong cùng một phác thảo",
|
||||
"error.end_cap_faces": "Chọn ít nhất một mặt đầu hở của một thanh khung",
|
||||
"error.end_cap_unresolved": "Đầu {ends} của nắp này không còn trên mô hình. Hãy chọn lại các mặt đầu",
|
||||
"feature computation ended without a result": "việc tính toán đặc trưng kết thúc mà không có kết quả",
|
||||
"file.open.drawing_filter": "Thiết kế, tệp CAD, lưới đa giác và bản vẽ",
|
||||
"file.open.portal_fallback.no_portal_service": "Bộ chọn tệp đã mở không phải của riêng desktop: dịch vụ chọn tệp của desktop không khả dụng.",
|
||||
@@ -1678,6 +1724,7 @@
|
||||
"file_load.inserting": "Đang chèn hình học",
|
||||
"file_load.link_item": "{name} ({done} trên {total})",
|
||||
"file_load.opened": "Đã mở {name}",
|
||||
"file_load.opened_behind": "Đã mở {name} trong thẻ mới",
|
||||
"file_load.opened_in_tab": "Đã mở {name} trong thẻ mới",
|
||||
"file_load.opening": "Đang mở thiết kế",
|
||||
"file_load.preparing_thumbnail": "Đang chuẩn bị ảnh thu nhỏ...",
|
||||
@@ -1725,11 +1772,13 @@
|
||||
"help.config.table": "Hiển thị bảng cấu hình: mỗi biến thể một hàng, mỗi tham số hoặc tính năng một cột, và cho biết thiết kế còn khớp với hàng đang kích hoạt hay không. Dùng để rà soát các biến thể của thiết kế.",
|
||||
"help.connect_note": "Khởi động lại từng trợ lý ảo để nạp SolidCraft server. Mỗi tập tin cấu hình đều đã được sao lưu thành .bak trước khi thay đổi.",
|
||||
"help.connect_title": "Kết nối trợ lý ảo AI",
|
||||
"help.construct.axis": "Tạo trục dựng theo phương pháp phù hợp với những gì bạn chọn: dọc theo cạnh hoặc đường, qua lỗ hoặc mặt tròn, nơi hai mặt phẳng giao nhau, qua hai điểm, hoặc vuông góc với mặt qua một điểm. Dùng khi bạn biết các tham chiếu nhưng không biết phương pháp.",
|
||||
"help.construct.axis.edge": "Tạo trục dựng hình dọc theo một cạnh thẳng hoặc đường phác thảo. Dùng làm trục cho Xoay tròn tạo khối, mảng tròn hoặc khớp nối.",
|
||||
"help.construct.axis.normal_to_face": "Tạo trục dựng hình đi qua một điểm và vuông góc với một mặt. Dùng làm trục nhô thẳng ra khỏi bề mặt.",
|
||||
"help.construct.axis.through_cylinder": "Tạo trục dựng hình đi qua tâm của mặt hình trụ, nón hoặc xuyến, hoặc của một cạnh tròn. Dùng để xoay hoặc tạo mảng các tính năng quanh một chi tiết tròn.",
|
||||
"help.construct.axis.two_planes": "Tạo trục dựng hình tại nơi hai mặt phẳng giao nhau. Dùng khi trục cần có chính là đường giao giữa hai mặt.",
|
||||
"help.construct.axis.two_points": "Tạo trục dựng hình đi qua hai điểm, đỉnh hoặc điểm phác thảo. Dùng cho trục chạy giữa hai vị trí đã biết.",
|
||||
"help.construct.plane": "Tạo mặt phẳng dựng theo phương pháp phù hợp với những gì bạn chọn: cách một mặt phẳng, qua một điểm, giữa hai mặt phẳng, qua các đường hoặc điểm, tiếp xúc với mặt cong, hoặc vuông góc với đường dẫn. Dùng khi bạn biết các tham chiếu nhưng không biết phương pháp.",
|
||||
"help.construct.plane.along_path": "Tạo mặt phẳng dựng hình vuông góc với một cạnh hoặc đường cong, tại một vị trí dọc theo nó. Dùng để phác thảo biên dạng cho Quét theo đường dẫn hoặc mặt cắt của đường dẫn.",
|
||||
"help.construct.plane.at_angle": "Tạo mặt phẳng dựng hình xoay một góc so với mặt phẳng hoặc mặt, quanh một trục hoặc cạnh. Dùng cho phác thảo nghiêng, chẳng hạn giá đỡ vát góc.",
|
||||
"help.construct.plane.axis_point": "Tạo mặt phẳng dựng chứa một trục và một điểm nằm ngoài trục đó. Chọn trục gốc, trục dựng, cạnh thẳng hoặc đường thẳng phác thảo, rồi chọn đỉnh, điểm phác thảo hoặc điểm dựng. Điểm nằm trên trục không xác định được một mặt phẳng duy nhất.",
|
||||
@@ -1739,6 +1788,7 @@
|
||||
"help.construct.plane.tangent": "Tạo mặt phẳng dựng hình tiếp xúc với hình trụ, nón, cầu hoặc xuyến tại một điểm. Dùng để phác thảo trên mặt bên của một chi tiết tròn.",
|
||||
"help.construct.plane.three_points": "Tạo mặt phẳng dựng hình đi qua ba điểm. Dùng cho mặt phẳng xác định bởi các vị trí trên mô hình, chẳng hạn ba góc.",
|
||||
"help.construct.plane.two_edges": "Tạo mặt phẳng dựng hình đi qua hai cạnh thẳng hoặc hai đường nằm trong cùng một mặt phẳng. Dùng cho mặt phẳng cắt ngang chi tiết, chẳng hạn qua hai cạnh đối diện.",
|
||||
"help.construct.point": "Tạo điểm dựng theo phương pháp phù hợp với những gì bạn chọn: tại đỉnh, tại tâm đường tròn hoặc mặt cầu, dọc theo cạnh, nơi hai đường hoặc ba mặt phẳng giao nhau, hoặc nơi một đường cắt mặt phẳng. Dùng khi bạn biết các tham chiếu nhưng không biết phương pháp.",
|
||||
"help.construct.point.along_path": "Tạo điểm dựng hình tại một vị trí dọc theo cạnh hoặc đường cong. Dùng làm điểm tham chiếu ở giữa đường dẫn.",
|
||||
"help.construct.point.center": "Tạo điểm dựng hình tại tâm của cạnh tròn, đường tròn hoặc cung phác thảo, hình cầu hoặc hình xuyến. Dùng làm điểm tham chiếu cho lỗ, trục và khớp nối.",
|
||||
"help.construct.point.edge_plane": "Tạo điểm dựng hình tại nơi một cạnh hoặc đường xuyên qua một mặt phẳng. Dùng để đánh dấu chỗ đường dẫn cắt qua mặt phẳng.",
|
||||
@@ -1764,6 +1814,7 @@
|
||||
"help.file.send_to_slicer": "Lưu các thân khối đã chọn thành tệp 3MF và mở trong phần mềm cắt lớp bạn chọn. Dùng để chuyển từ mô hình sang in chỉ trong một bước.",
|
||||
"help.font_details": "Giao diện sử dụng các phông chữ tích hợp của egui (Ubuntu Light và Hack, theo Ubuntu Font Licence và giấy phép MIT/Bitstream Vera; Noto Emoji và phông biểu tượng emoji, theo OFL và MIT). Văn bản phác thảo dùng Liberation Sans (SIL OFL 1.1). Gói phông chữ tùy chọn của Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), không được đóng gói kèm trong các bản dựng SolidCraft.",
|
||||
"help.fonts": "Phông chữ",
|
||||
"help.frame.end_cap": "Đóng các đầu hở của thanh khung bằng tấm có hình đường bao của tiết diện. Dùng để bịt ống, thép góc và dầm, đặt lên đầu hoặc lắp chìm vào đầu.",
|
||||
"help.frame.member": "Đặt một biên dạng, chẳng hạn ống hoặc nhôm định hình, dọc theo các đường của phác thảo khung, mỗi đường một phần tử. Dùng để dựng khung, giá đỡ và kết cấu hàn.",
|
||||
"help.inspect.accessibility": "Tô màu các mặt mà dụng cụ có thể tiếp cận từ một hướng và các mặt không tiếp cận được. Dùng để kiểm tra chi tiết có gia công hoặc ép khuôn được từ phía đó không.",
|
||||
"help.inspect.center_of_mass": "Hiển thị trọng tâm của các thân khối, từng thân riêng và tất cả cùng nhau, với giả định mật độ đồng đều. Dùng để kiểm tra cân bằng và chỗ chi tiết sẽ bị lật.",
|
||||
@@ -2240,6 +2291,9 @@
|
||||
"measure.at": "Tại",
|
||||
"measure.item": "Mục {number}",
|
||||
"measure.line_to_centre": "Từ đường đến tâm",
|
||||
"measure.perimeter": "Chu vi",
|
||||
"measure.perimeter_inner": "Chu vi trong",
|
||||
"measure.perimeter_outer": "Chu vi ngoài",
|
||||
"measure.quick_copied": "Đã sao chép số đo",
|
||||
"measure.quick_copy": "Nhấp để sao chép số đo",
|
||||
"measure.quick_edges": "{count} cạnh",
|
||||
@@ -2281,6 +2335,8 @@
|
||||
"nav.hfss.help": "Alt+kéo chuột trái để trượt, Shift+Alt+chuột trái để thu phóng, Ctrl+kéo chuột trái từ vùng trống để xoay",
|
||||
"nav.inventor.help": "Kéo chuột giữa để trượt, Shift + chuột giữa để xoay, Ctrl + chuột giữa để thu phóng, kéo chuột phải để xoay",
|
||||
"nav.maya.help": "Alt+kéo chuột trái để xoay, Alt+chuột giữa để trượt, Alt+chuột phải để thu phóng; kéo chuột giữa cũng trượt",
|
||||
"nav.maya_horizontal_zoom.help": "Alt+kéo chuột phải: kéo sang phải để phóng to, sang trái để thu nhỏ. Tắt để khôi phục thu phóng bằng cách kéo dọc.",
|
||||
"nav.maya_horizontal_zoom.label": "Maya: thu phóng bằng cách kéo ngang",
|
||||
"nav.nx.help": "Kéo chuột giữa để xoay, Shift+chuột giữa để kéo ngang (NX: giữa + phải), Ctrl+chuột giữa để thu phóng (NX: giữa + trái); kéo chuột phải không di chuyển camera",
|
||||
"nav.openscad.help": "Kéo chuột trái trên vùng trống để xoay, Shift + chuột trái để quét chọn vùng, kéo hình học phác thảo để chỉnh sửa; kéo chuột phải hoặc chuột giữa để trượt, Shift + kéo chuột phải hoặc chuột giữa để thu phóng",
|
||||
"nav.orbit_cursor_wrap.help": "Khi thao tác kéo để xoay chạm tới cạnh khung nhìn, con trỏ được chuyển sang cạnh đối diện và tiếp tục xoay. Khi tắt: thao tác kéo dừng lại ở cạnh màn hình. Không có tác dụng trên Wayland hoặc trên trình duyệt.",
|
||||
@@ -2411,6 +2467,16 @@
|
||||
"not a move": "không phải một phép di chuyển",
|
||||
"not a number": "không phải là số",
|
||||
"open a sketch first": "hãy mở một phác thảo trước",
|
||||
"operations.cancel": "Hủy {name}",
|
||||
"operations.cancelled": "Đã hủy {name}",
|
||||
"operations.cancelling": "Đang hủy…",
|
||||
"operations.cannot_cancel": "Không thể hủy {name}",
|
||||
"operations.feature": "Đặc trưng",
|
||||
"operations.feature_edit": "Sửa đặc trưng",
|
||||
"operations.meshing": "Đang tải chi tiết",
|
||||
"operations.queued": "Đang chờ",
|
||||
"operations.stopped": "Đã hủy",
|
||||
"operations.waiting": "Sẵn sàng",
|
||||
"parameters.apply_live": "Áp dụng mỗi thay đổi khi rời khỏi ô của nó",
|
||||
"parameters.apply_live_tip": "Tắt: các thay đổi chờ đến khi nhấn Áp dụng hoặc OK, rồi thiết kế được dựng lại một lần cho tất cả. Hủy hoặc Escape sẽ bỏ chúng.",
|
||||
"parameters.held": "{count} thay đổi đang chờ Áp dụng",
|
||||
@@ -2499,6 +2565,7 @@
|
||||
"prefs.appearance.viewport_colours": "Màu khung nhìn 3D",
|
||||
"prefs.appearance.viewport_logo": "Khung nhìn và logo",
|
||||
"prefs.applies_on_restart": "Áp dụng sau khi khởi động lại",
|
||||
"prefs.assemblies": "Cụm lắp ráp",
|
||||
"prefs.assistant": "Trợ lý",
|
||||
"prefs.assistant_connecting": "Kết nối",
|
||||
"prefs.assistant_follow_help": "Thao tác Look At trên bản phác di chuyển góc nhìn theo con trỏ.",
|
||||
@@ -2551,6 +2618,10 @@
|
||||
"prefs.choose_font": "Chọn tệp phông chữ…",
|
||||
"prefs.click": "Nhấp chuột",
|
||||
"prefs.command_dialog_values": "Hộp thoại lệnh",
|
||||
"prefs.constraint_glyph_size": "Kích thước biểu tượng ràng buộc",
|
||||
"prefs.constraint_glyph_size_note": "Kích thước vẽ biểu tượng ràng buộc cùng chữ cái hoặc biểu tượng bên trong trong bản phác. 100% là kích thước thông thường; biểu tượng giữ kích thước màn hình này ở mọi mức thu phóng.",
|
||||
"prefs.construct_menu_groups": "Nhóm công cụ dựng theo loại đối tượng",
|
||||
"prefs.construct_menu_groups_help": "Hiện tiêu đề Mặt phẳng, Trục và Điểm. Tắt để giữ thứ tự menu ban đầu.",
|
||||
"prefs.contact_shading": "Đổ bóng tiếp xúc mềm",
|
||||
"prefs.contact_shading_note": "Tạo bóng đổ mềm tại những vị trí các chi tiết tiếp giáp gần nhau.",
|
||||
"prefs.context_menu": "Menu ngữ cảnh",
|
||||
@@ -2586,6 +2657,8 @@
|
||||
"prefs.design_tools.rows": "Hàng",
|
||||
"prefs.devices": "Chuột 3D",
|
||||
"prefs.dialog_buttons": "Nút hộp thoại",
|
||||
"prefs.dialog_first_letter_buttons": "Nút trong hộp thoại trả lời chữ cái đầu của nhãn",
|
||||
"prefs.dialog_first_letter_buttons_help": "Khi một hộp thoại đang mở, gõ chữ cái đầu của nhãn một nút sẽ bấm nút đó: chữ H bấm nút Hủy bỏ, chẳng hạn. Một chữ khớp với hai nút không thực hiện gì, và trường văn bản đang tiêu điểm giữ lại phím gõ. Tắt: gõ phím không bấm nút, như trước đây.",
|
||||
"prefs.dialogs": "Hộp thoại",
|
||||
"prefs.dialogs_edge": "Ở cạnh khung nhìn",
|
||||
"prefs.dialogs_left_column": "Trong cột bên trái",
|
||||
@@ -2599,12 +2672,23 @@
|
||||
"prefs.dimension_values_window": "Trong một cửa sổ",
|
||||
"prefs.display": "Hiển thị",
|
||||
"prefs.edges": "Cạnh và đổ bóng",
|
||||
"prefs.export": "Xuất",
|
||||
"prefs.export_name": "Tên tệp khi xuất",
|
||||
"prefs.export_name.body": "Tên khối được xuất (khối đầu tiên nếu có nhiều)",
|
||||
"prefs.export_name.design": "Tên thiết kế",
|
||||
"prefs.export_name_hint": "vd. {design}-{body}",
|
||||
"prefs.export_name_sample": "Xuất thiết kế này sẽ đề xuất: {name}",
|
||||
"prefs.export_name_tip": "Tên tệp mà Tệp › Xuất tệp và Lưu dưới dạng lưới đa giác đề xuất. Các phần giữ chỗ này được thay thế:\n{placeholders}\nThuộc tính thiết kế chưa đặt sẽ bị bỏ qua. Để trống để đề xuất tên thiết kế, hoặc tên khối với lưới.",
|
||||
"prefs.extend": "Kéo dài",
|
||||
"prefs.extra_navigation": "Ctrl + kéo chuột trái trên vùng trống để xoay; giữ phím Cách (Space) để trượt góc nhìn.",
|
||||
"prefs.extrude_arrow_face_stops": "Mũi tên đùn dừng tại các mặt",
|
||||
"prefs.extrude_arrow_face_stops_note": "Khi kéo mũi tên khoảng cách của Đùn, nó dừng tại các mặt phẳng song song với biên dạng, chẳng hạn mặt bên kia của khối đang cắt, và tô viền mặt đó. Tắt: mũi tên chỉ di chuyển theo các bước tròn.",
|
||||
"prefs.extrude_view_isometric": "Xoay sang góc nhìn trục đo khi mở Đùn khối",
|
||||
"prefs.extrude_view_return": "Trở lại góc nhìn trước khi đóng Đùn khối",
|
||||
"prefs.file_operations_wait": "Chờ tệp mở xong",
|
||||
"prefs.file_operations_wait_note": "Khi một tệp đang mở, đang chèn hoặc các liên kết được đọc lại, thiết kế chờ sau một thẻ hiện tiến độ và nút Hủy. Tắt: tệp hiện trong bảng thao tác và bạn có thể tiếp tục làm việc; phần chèn được áp dụng khi bạn làm xong việc đang làm, và tệp mở trong lúc đó được đặt vào thẻ mới.",
|
||||
"prefs.fillet_legacy_radius": "Dùng giá trị mặc định bán kính Fillet trước đây",
|
||||
"prefs.fillet_legacy_radius.help": "Mặc định tắt. Khi bật: Solid Fillet mới bắt đầu với số 2 được đọc theo đơn vị của thiết kế (\"2 in\"), như trước; khi tắt: nó bắt đầu với bán kính mà công cụ được giao, 2 mm, hiển thị theo đơn vị của thiết kế (\"0.07874 in\").",
|
||||
"prefs.follows_os": "Theo hệ điều hành",
|
||||
"prefs.font": "Phông chữ",
|
||||
"prefs.font_fallback": "Các ký tự mà phông chữ đã chọn thiếu sẽ tự động dùng phông mặc định tích hợp, tránh tình trạng hiển thị ô vuông lỗi.",
|
||||
@@ -2628,6 +2712,17 @@
|
||||
"prefs.gesture_pan": "Trượt góc nhìn",
|
||||
"prefs.gesture_zoom": "Thu phóng",
|
||||
"prefs.graphics": "Đồ họa",
|
||||
"prefs.graphics_api": "API đồ họa",
|
||||
"prefs.graphics_api_auto": "Tự động",
|
||||
"prefs.graphics_api_help": "Chọn API đồ họa dùng để mở SolidCraft. Nếu lần khởi động tiếp theo không mở được cửa sổ, lựa chọn trước sẽ được khôi phục.",
|
||||
"prefs.graphics_api_override": "Một thiết lập ghi đè khi khởi chạy đang điều khiển API đồ họa. Lựa chọn đã lưu sẽ áp dụng khi mở SolidCraft bình thường.",
|
||||
"prefs.graphics_api_restart_note": "Áp dụng sau khi khởi động lại. Các thiết kế chưa lưu được xử lý trước khi đóng.",
|
||||
"prefs.graphics_api_restart_unavailable": "Khởi động lại SolidCraft để áp dụng API đồ họa đã lưu.",
|
||||
"prefs.graphics_api_running": "Hiện tại: {current}. Đã chọn cho lần khởi động tiếp theo: {selected}.",
|
||||
"prefs.graphics_api_save_failed": "Không thể lưu lựa chọn API đồ họa: {error}",
|
||||
"prefs.graphics_api_start_failed": "Không thể chuẩn bị API đồ họa đã chọn: {error}",
|
||||
"prefs.graphics_api_start_reverted": "Lần khởi động trước với {requested} không mở được cửa sổ. SolidCraft đã khôi phục {previous}.",
|
||||
"prefs.graphics_api_unavailable": "Có thể chọn API đồ họa trong ứng dụng máy tính.",
|
||||
"prefs.graphics_card": "Card đồ họa",
|
||||
"prefs.graphics_card_auto": "Tự động",
|
||||
"prefs.graphics_card_missing": "Card đồ họa đã lưu không khả dụng; chế độ Tự động đang được sử dụng.",
|
||||
@@ -2671,6 +2766,8 @@
|
||||
"prefs.history_sketches_in_order": "Theo thứ tự tạo",
|
||||
"prefs.history_sketches_note": "Khi tùy chọn Phác thảo được đặt thành Dưới tính năng tương ứng, cây Lịch sử ở bên trái sẽ liệt kê mỗi phác thảo thụt vào một cấp dưới tính năng đầu tiên được tạo từ nó (khi khung đủ rộng để hiển thị tên). Dòng thời gian ở cạnh dưới luôn giữ nguyên thứ tự tạo.",
|
||||
"prefs.history_sketches_under_feature": "Dưới tính năng tương ứng",
|
||||
"prefs.history_steps_component": "Bước Lịch sử theo cụm chi tiết",
|
||||
"prefs.history_steps_component_note": "Khi một cụm chi tiết đang kích hoạt hoặc được chọn, các điều khiển Lịch sử đi qua các tính năng của cụm đó, như dòng Lịch sử ở cạnh dưới hiển thị. Tắt: chúng đi qua mọi tính năng của thiết kế. Cây Lịch sử ở bên trái hoặc dưới cây thư mục luôn đi qua mọi tính năng.",
|
||||
"prefs.hold_stop_snapping": "Giữ để tạm dừng bắt dính",
|
||||
"prefs.home_fit_size": "Cỡ Home và Khớp",
|
||||
"prefs.home_fit_size_note": "Mô hình chiếm bao nhiêu phần khung nhìn khi Home, Khớp, một thiết kế vừa mở hoặc đổi góc nhìn bằng khối điều hướng đưa nó vào khung hình, dù tùy chọn bên dưới bật hay tắt. 100 %: lấp đầy khung nhìn giữa các bảng, la bàn và thanh điều hướng.",
|
||||
@@ -2686,6 +2783,8 @@
|
||||
"prefs.invert_curved_roll_arrows_note": "Hai mũi tên cong ở góc khối cuộn khung nhìn trong mặt phẳng màn hình. Khi bật: mũi tên theo chiều kim đồng hồ cuộn ngược chiều kim đồng hồ và ngược lại. Khi tắt: mỗi mũi tên cuộn khung nhìn theo chiều cong của nó.",
|
||||
"prefs.invert_navigator_arrows": "Đảo ngược mũi tên xoay của khối điều hướng",
|
||||
"prefs.invert_navigator_arrows_note": "Các mũi tên quanh khối xoay camera theo hướng mũi tên chỉ, như trong Fusion và Inventor: mũi tên bên trái chỉ sang phải và đưa camera sang phải. Khi tắt: mũi tên xoay khối về phía cạnh chứa nó, nên mũi tên bên trái đưa camera sang trái. Hai mũi tên cuộn cong không bị ảnh hưởng.",
|
||||
"prefs.joint_drag_trackball": "Xoay chi tiết trên khớp cầu như trackball khi kéo",
|
||||
"prefs.joint_drag_trackball_help": "Kéo một chi tiết do khớp cầu giữ sẽ xoay nó theo góc xoay nhỏ nhất quanh khớp, như lăn một quả bóng có kích thước bằng chi tiết. Tắt: điểm bạn nắm theo đúng con trỏ, và chi tiết có thể tự xoay quanh điểm đó.",
|
||||
"prefs.keep_unsaved_also_asks": "Vẫn hỏi khi đóng thẻ",
|
||||
"prefs.keep_unsaved_also_asks_tip": "Khi tắt, thẻ sẽ đóng mà không có hộp thoại của trình duyệt khi bản sao của mọi thiết kế chưa lưu đã được cập nhật.",
|
||||
"prefs.keep_unsaved_in_browser": "Giữ công việc chưa lưu trong trình duyệt này",
|
||||
@@ -2761,6 +2860,8 @@
|
||||
"prefs.not_on_gpu": "GPU này không hỗ trợ",
|
||||
"prefs.on": "Bật",
|
||||
"prefs.opaque": "Đậm đặc (không trong suốt)",
|
||||
"prefs.operations_panel": "Hiện các thao tác trong khung nhìn",
|
||||
"prefs.operations_panel_note": "Các thao tác dài (mở tệp, tính đặc trưng, lệnh của tác tử) hiện ở góc dưới bên phải khung nhìn cùng tiến độ và nút hủy. Tắt: thông báo Đang tính như trước.",
|
||||
"prefs.orbit_snap": "Giữ Shift khi xoay để bắt dính vào một trục tọa độ.",
|
||||
"prefs.orientation": "Hướng nhìn",
|
||||
"prefs.origin_plane_names": "Tên các mặt phẳng gốc",
|
||||
@@ -2841,6 +2942,8 @@
|
||||
"prefs.ribbon_tabs_only": "Chỉ hiện các thẻ của ribbon",
|
||||
"prefs.ribbon_tabs_only_note": "Ribbon thu gọn chỉ còn hàng thẻ. Bấm một thẻ sẽ hiện các bảng của nó đè lên khung nhìn cho đến khi một lệnh bắt đầu hoặc con trỏ rời khỏi chúng. Lệnh Chỉ các thẻ ribbon trong thẻ Xem, hoặc phím tắt của nó, bật tắt tùy chọn này.",
|
||||
"prefs.right_click": "Nhấp chuột phải",
|
||||
"prefs.save_prompt_one_at_a_time": "Hỏi riêng từng thiết kế chưa lưu khi đóng nhiều thiết kế",
|
||||
"prefs.save_prompt_one_at_a_time_help": "Hiển thị một hộp thoại lưu cho mỗi thiết kế chưa lưu thay vì một danh sách chung.",
|
||||
"prefs.saving": "Khởi động và lưu",
|
||||
"prefs.scale_note": "Cũng có thể dùng Ctrl + / Ctrl − trong cửa sổ. Các nút có kích thước 28 px ở mức 100%.",
|
||||
"prefs.scale_text": "Tỉ lệ và văn bản",
|
||||
@@ -2877,6 +2980,8 @@
|
||||
"prefs.sketch.center_arc": "Cung theo tâm đi theo con trỏ",
|
||||
"prefs.sketch.click_selects": "Nhấp để chọn",
|
||||
"prefs.sketch.conflict_colour": "Màu xung đột",
|
||||
"prefs.sketch.cursor_coordinates": "Hiển thị tọa độ con trỏ trong bản phác thảo",
|
||||
"prefs.sketch.cursor_coordinates_note": "Bên cạnh con trỏ, X và Y của nó tính từ gốc bản phác thảo, kể cả khi không có công cụ nào chạy. Tắt: chỉ khi một công cụ đang đặt điểm.",
|
||||
"prefs.sketch.drawing": "Vẽ",
|
||||
"prefs.sketch.ellipse_axes": "Vẽ hình elip kèm các trục",
|
||||
"prefs.sketch.ellipse_axes_note": "Trục lớn và trục nhỏ dưới dạng đường gióng dựng hình, để có thể ghi kích thước bán trục và trục. Tắt: chỉ vẽ hình elip, và D trên nó cho bán kính nhỏ dù kéo giá trị đến đâu, được vẽ và ghi nhãn R như trước.",
|
||||
@@ -2888,14 +2993,20 @@
|
||||
"prefs.sketch.faces_edges": "Mặt và cạnh",
|
||||
"prefs.sketch.hide_glyphs": "Ẩn ký hiệu khi thu nhỏ",
|
||||
"prefs.sketch.marks": "Dấu trong phác thảo",
|
||||
"prefs.sketch.max_points": "Phác thảo lớn nhất",
|
||||
"prefs.sketch.max_points_note": "Số điểm hoặc đường cong tối đa trong một phác thảo: mặc định 20000, tối đa 200000. Chèn tệp SVG và Chèn tệp DXF từ chối bản vẽ lớn hơn. Phác thảo lớn được giải và vẽ chậm hơn.",
|
||||
"prefs.sketch.max_points_unit": "điểm",
|
||||
"prefs.sketch.note": "Vẽ, bắt điểm và chọn.",
|
||||
"prefs.sketch.opening_closing": "Mở và đóng",
|
||||
"prefs.sketch.prefer_free_points": "Ưu tiên điểm di chuyển được khi chồng nhau",
|
||||
"prefs.sketch.project_options": "Hỏi tùy chọn Chiếu trước",
|
||||
"prefs.sketch.recent_snap": "Bắt vào giao điểm của hai đường dẫn",
|
||||
"prefs.sketch.select_3d_curve_points": "Chọn điểm trên đường cong phác thảo 3D",
|
||||
"prefs.sketch.select_3d_curve_points_help": "Hiển thị và chọn các điểm trên đường cong phác thảo 3D đã vẽ để làm tham chiếu dựng hình.",
|
||||
"prefs.sketch.select_other_hidden": "Chọn đối tượng khác bao gồm hình học bị ẩn",
|
||||
"prefs.sketch.shortcut_cycles_modes": "Nhấn lại phím tắt để đổi chế độ",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "Tắt: khởi động lại công cụ.",
|
||||
"prefs.sketch.snap_to_visible_grid": "Bắt vào giao điểm nhìn thấy của lưới",
|
||||
"prefs.sketch.snapping_guides": "Bắt điểm và đường dẫn",
|
||||
"prefs.sketch.state_icons": "Biểu tượng trạng thái",
|
||||
"prefs.sketch.tracking_guides": "Đường dẫn qua tâm và trung điểm",
|
||||
@@ -2923,6 +3034,7 @@
|
||||
"prefs.sketch_selection": "Phác thảo & chọn đối tượng",
|
||||
"prefs.sketch_selection_heading": "Phác thảo và lựa chọn",
|
||||
"prefs.sketch_selection_note": "Cách phác thảo bắt dính và cách nhấp chuột chọn đối tượng.",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "Một điểm trong phác thảo bắt vào giao điểm của các đường mà lưới vẽ khi con trỏ chỉ vào một giao điểm, và vào lưới mịn hơn giữa chúng trong trường hợp khác. Tắt: điểm chỉ bắt vào lưới mịn hơn, như trước.",
|
||||
"prefs.sketch_state_icons": "Biểu tượng bản phác theo màu trạng thái",
|
||||
"prefs.sketch_state_icons_note": "Trong Lịch sử và trình duyệt, biểu tượng của bản phác lấy màu trạng thái của nó (thiếu ràng buộc, ràng buộc đủ hoặc xung đột) và chú thích nêu trạng thái. Tắt: mọi bản phác có cùng biểu tượng.",
|
||||
"prefs.sketch_tab_always": "Luôn hiện thẻ Bản phác",
|
||||
@@ -3624,6 +3736,7 @@
|
||||
"render.error_pbr_opacity": "PBR đục yêu cầu độ đục 1",
|
||||
"render.error_physical_glass": "công thức đã chọn không phải kính vật lý",
|
||||
"render.error_preview_device": "xem trước sản phẩm cần thiết bị đã cài có bộ đệm độ sâu",
|
||||
"render.error_product_placement": "vị trí đặt sản phẩm không hợp lệ",
|
||||
"render.error_product_triangle": "tam giác sản phẩm không hợp lệ",
|
||||
"render.error_provisional_identity": "danh tính kết xuất tạm hoặc số mẫu không hợp lệ",
|
||||
"render.error_quality_bounds": "phép chiếu chất lượng vượt quá giới hạn gốc",
|
||||
@@ -3707,6 +3820,10 @@
|
||||
"render.gpu_path_retry": "Thử lại",
|
||||
"render.gpu_seed": "Hạt giống ngẫu nhiên",
|
||||
"render.gpu_unavailable": "Dò đường truyền tia GPU chưa sẵn sàng trên thiết bị này.",
|
||||
"render.graphics_api_restart_vulkan": "Khởi động lại với Vulkan",
|
||||
"render.graphics_api_restart_warning": "Đổi API đồ họa sẽ khởi động lại SolidCraft và yêu cầu lưu các thiết kế chưa lưu. Nếu API mới không mở được cửa sổ, lựa chọn trước sẽ được khôi phục ở lần khởi động tiếp theo.",
|
||||
"render.graphics_api_settings": "Cài đặt đồ họa",
|
||||
"render.graphics_api_vulkan_required": "Truy vết đường đi bằng GPU cần Vulkan trong phiên này. Khởi động lại với Vulkan hoặc tiếp tục dùng phương pháp tạo ảnh bằng CPU.",
|
||||
"render.ground_apply": "Khớp và lưu mặt sàn",
|
||||
"render.ground_gap": "Khe hở khoảng sáng rõ ràng",
|
||||
"render.ground_linear_rgb": "Độ phản xạ khuếch tán · RGB tuyến tính",
|
||||
@@ -4708,6 +4825,8 @@
|
||||
"sketch.hint.spline3d": "3D Spline: click fit points in 3D; right-click or Esc to finish",
|
||||
"sketch.hint.trim": "Trim: click the piece of a curve to remove, or drag across the pieces to remove",
|
||||
"sketch.make_selection": "Chuyển đổi vùng chọn sang {linetype}",
|
||||
"sketch.move_released": "Đã di chuyển: đã bỏ {count} ràng buộc nối nó với phần còn lại ({names}).",
|
||||
"sketch.move_released_one": "Đã di chuyển: đã bỏ {count} ràng buộc nối nó với phần còn lại ({names}).",
|
||||
"sketch.open_ends": "Đầu hở: {count}",
|
||||
"sketch.status_conflict": "ràng buộc xung đột",
|
||||
"sketch.status_fully_constrained": "ràng buộc hoàn toàn",
|
||||
@@ -4738,6 +4857,10 @@
|
||||
"sketch_text.path_clear": "Gỡ văn bản khỏi đường cong dẫn",
|
||||
"sketch_text.path_hint": "Đường cong phác thảo mà văn bản chạy theo: nhấp vào đây, sau đó chọn đường cong",
|
||||
"sketch_text.use_font_file": "Sử dụng tệp phông chữ {path}",
|
||||
"sketch_text.valign_baseline": "Đường cơ sở",
|
||||
"sketch_text.valign_bottom": "Dưới",
|
||||
"sketch_text.valign_middle": "Giữa",
|
||||
"sketch_text.valign_top": "Trên",
|
||||
"solid": "khối đặc",
|
||||
"status.editing": "Đang sửa {name}",
|
||||
"status.navigation": "Gán chức năng chuột: {mapping}",
|
||||
@@ -4938,6 +5061,7 @@
|
||||
"ui.agent_chat_allow_once": "Cho phép một lần",
|
||||
"ui.agent_chat_allowed": "Đã cho phép",
|
||||
"ui.agent_chat_answered": "Câu trả lời: {option}",
|
||||
"ui.agent_chat_answered_in": "Đã trả lời trong {time}",
|
||||
"ui.agent_chat_approval": "Cho phép AI thực hiện thao tác này?",
|
||||
"ui.agent_chat_attach_selection": "Đính kèm phần chọn",
|
||||
"ui.agent_chat_attach_selection_tip": "Gửi các đối tượng đang chọn trong mô hình (mặt, cạnh, tính năng, khối) kèm tin nhắn để trợ lý hiểu rõ đối tượng bạn muốn xử lý",
|
||||
@@ -4966,6 +5090,7 @@
|
||||
"ui.agent_chat_ctx_bodies": "Khối",
|
||||
"ui.agent_chat_ctx_elements": "Phần tử",
|
||||
"ui.agent_chat_ctx_features": "Tính năng",
|
||||
"ui.agent_chat_ctx_gone": "Không còn trong thiết kế: nó đã bị thay đổi hoặc xóa.",
|
||||
"ui.agent_chat_ctx_more": "+{n} mục khác",
|
||||
"ui.agent_chat_ctx_other": "Khác",
|
||||
"ui.agent_chat_custom_heading": "Mô hình tùy chỉnh",
|
||||
@@ -4979,6 +5104,7 @@
|
||||
"ui.agent_chat_dock_right": "Ghim sang bên phải",
|
||||
"ui.agent_chat_drop_hint": "Thả tệp vào đây để đính kèm vào tin nhắn tiếp theo",
|
||||
"ui.agent_chat_edit": "Chỉnh sửa",
|
||||
"ui.agent_chat_ended_after": "Đã dừng sau {time}",
|
||||
"ui.agent_chat_exited": "Tác tử đã dừng.",
|
||||
"ui.agent_chat_failed_start": "AI Agent không thể khởi động: {error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}: tệp CAD được nhập vào thiết kế, không đọc nội dung",
|
||||
@@ -5016,6 +5142,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model} không thể sử dụng các công cụ của SolidCraft nên chỉ có thể trò chuyện. Hãy chọn mô hình có hỗ trợ công cụ.",
|
||||
"ui.agent_chat_model_rejected": "Tác tử không chấp nhận {model}: {error}",
|
||||
"ui.agent_chat_model_search": "Tìm mô hình…",
|
||||
"ui.agent_chat_model_search_or_id": "Tìm, hoặc nhập mã mô hình bất kỳ…",
|
||||
"ui.agent_chat_model_tip": "Mô hình AI đang sử dụng. Lựa chọn của bạn sẽ được ghi nhớ cho Agent này.",
|
||||
"ui.agent_chat_models_failed": "Không thể lấy danh sách mô hình: {error}",
|
||||
"ui.agent_chat_models_heading": "Các mô hình có sẵn",
|
||||
@@ -5027,6 +5154,7 @@
|
||||
"ui.agent_chat_next_picture": "Ảnh kế tiếp",
|
||||
"ui.agent_chat_no_cli": "Không tìm thấy solidcraft-cli cạnh ứng dụng, vì vậy AI Agent không thể truy cập thiết kế.",
|
||||
"ui.agent_chat_no_control": "Điểm cuối trò chuyện của tác tử không thể khởi động, vì vậy AI Agent không thể truy cập thiết kế.",
|
||||
"ui.agent_chat_no_design_hint": "Tác tử đang chạy mà không có công cụ của SolidCraft, nên không thể đọc hay thay đổi thiết kế: không tìm thấy solidcraft-cli cạnh ứng dụng. Hãy cài SolidCraft có solidcraft-cli đi kèm (trên Windows: bản MSI hoặc bản zip di động), hoặc đặt SOLIDCRAFT_CLI thành đường dẫn của nó, rồi kết nối lại.",
|
||||
"ui.agent_chat_no_images": "AI Agent này không hỗ trợ tiếp nhận hình ảnh",
|
||||
"ui.agent_chat_no_picture": "Không có hình ảnh trong bộ nhớ tạm",
|
||||
"ui.agent_chat_no_tool_call": "Mô hình không sử dụng các công cụ của SolidCraft nên thiết kế không thay đổi. Hãy chọn mô hình hỗ trợ gọi công cụ; xem mục Mô hình cục bộ trong hướng dẫn trò chuyện AI.",
|
||||
@@ -5073,16 +5201,26 @@
|
||||
"ui.agent_chat_setup_title": "Thiết lập trợ lý",
|
||||
"ui.agent_chat_side": "Gắn khung trò chuyện",
|
||||
"ui.agent_chat_signed_in": "đã đăng nhập",
|
||||
"ui.agent_chat_snap_none_found": "Không tìm thấy tác tử lập trình nào. Gói Snap chạy trong môi trường bị giới hạn nên không thể thấy hay khởi động các tác tử lập trình được cài trên máy tính này. Để dùng chúng, hãy cài SolidCraft từ gói AppImage, .deb hoặc .rpm thay vào đó. Tác tử dùng API tương thích OpenAI vẫn hoạt động trong gói Snap: hãy thiết lập bằng Thêm AI Agent.",
|
||||
"ui.agent_chat_span_h": "{h} giờ {min} phút",
|
||||
"ui.agent_chat_span_min": "{n} phút",
|
||||
"ui.agent_chat_span_s": "{n} giây",
|
||||
"ui.agent_chat_state_auth": "Cần đăng nhập",
|
||||
"ui.agent_chat_state_busy": "Đang xử lý…",
|
||||
"ui.agent_chat_state_exited": "Tác tử đã dừng",
|
||||
"ui.agent_chat_state_failed": "Kết nối thất bại",
|
||||
"ui.agent_chat_state_no_design": "Không truy cập được thiết kế",
|
||||
"ui.agent_chat_state_off": "Chưa kết nối",
|
||||
"ui.agent_chat_state_ready": "Sẵn sàng",
|
||||
"ui.agent_chat_state_starting": "Đang khởi động…",
|
||||
"ui.agent_chat_stop": "Dừng",
|
||||
"ui.agent_chat_stop_tip": "Dừng tác tử và mọi tác vụ nó đã bắt đầu",
|
||||
"ui.agent_chat_stop_turn_tip": "Dừng tác tử (Esc). Tin nhắn trong hàng đợi vẫn được giữ nguyên.",
|
||||
"ui.agent_chat_thinking_for": "Đang suy nghĩ {time}",
|
||||
"ui.agent_chat_tool_running_for": "đang chạy {time}",
|
||||
"ui.agent_chat_tools_not_started": "Tác tử đang chạy mà không có công cụ của SolidCraft, nên không thể đọc hay thay đổi thiết kế: đã tìm thấy solidcraft-cli, nhưng công cụ của nó không khởi động được (lỗi trong cuộc trò chuyện cho biết lý do). Hãy kết nối lại; nếu vẫn xảy ra, hãy cài lại SolidCraft.",
|
||||
"ui.agent_chat_transcript_assistant": "Trợ lý:",
|
||||
"ui.agent_chat_transcript_user": "Người dùng:",
|
||||
"ui.agent_chat_turn_limit": "Số thay đổi tối đa mỗi tin nhắn",
|
||||
"ui.agent_chat_turn_unlimited": "Không giới hạn",
|
||||
"ui.agent_chat_undo_changes": "Hoàn tác các thay đổi này",
|
||||
@@ -5239,7 +5377,9 @@
|
||||
"ui.browser_bodies_one": "{count} thân khối",
|
||||
"ui.browser_bodies_other": "{count} thân khối",
|
||||
"ui.browser_collapse": "Thu gọn trình duyệt",
|
||||
"ui.browser_collapse_below": "Thu gọn bên dưới",
|
||||
"ui.browser_expand": "Mở rộng trình duyệt",
|
||||
"ui.browser_expand_below": "Mở rộng bên dưới",
|
||||
"ui.browser_title": "Trình duyệt",
|
||||
"ui.calibrate": "Hiệu chuẩn",
|
||||
"ui.cancel": "Hủy bỏ",
|
||||
@@ -5269,6 +5409,7 @@
|
||||
"ui.collapse": "Thu gọn",
|
||||
"ui.collinear": "Cùng đường thẳng",
|
||||
"ui.colour_vision": "Thị giác màu sắc",
|
||||
"ui.colour_vision_bends": "Các vị trí chấn",
|
||||
"ui.colour_vision_deutan": "Mù màu xanh lá (Deutan)",
|
||||
"ui.colour_vision_deutan_tip": "Dành cho người cảm nhận màu xanh lá yếu hoặc mất hẳn",
|
||||
"ui.colour_vision_failed": "Thất bại",
|
||||
@@ -5298,14 +5439,24 @@
|
||||
"ui.conic_curve": "Đường cong Conic",
|
||||
"ui.constant": "Hằng số",
|
||||
"ui.constraints_conflict": "Xung đột ràng buộc",
|
||||
"ui.construct_auto.chosen": "Đã chọn phương pháp theo lựa chọn của bạn. Chọn thêm hoặc bỏ một tham chiếu để đổi phương pháp.",
|
||||
"ui.construct_auto.no_fit": "Hãy chọn tham chiếu khác: không phương pháp nào dựng được từ các tham chiếu này.",
|
||||
"ui.construct_auto.pick": "Chọn những gì để dựng: phương pháp theo lựa chọn của bạn.",
|
||||
"ui.construct_auto.refs": "Tham chiếu",
|
||||
"ui.construct_auto.select": "Hãy chọn tham chiếu để dựng trước",
|
||||
"ui.construct_axes": "Các trục",
|
||||
"ui.construct_planes": "Các mặt phẳng",
|
||||
"ui.construct_points": "Các điểm",
|
||||
"ui.construction": "Đường gióng dựng hình",
|
||||
"ui.construction.angle_hint": "Đường dựng hình: nhấp một điểm rồi nhập góc hoặc chọn hướng",
|
||||
"ui.construction.axis_hint": "Đường dựng hình: nhấp một điểm, hoặc nhập khoảng cách tới trục phác thảo",
|
||||
"ui.construction.bisector_hint": "Phân giác: chọn hai đường thẳng giao nhau rồi chọn nghiệm mong muốn",
|
||||
"ui.construction.common_hint": "Tiếp tuyến chung: chọn hai đường tròn/cung rồi chọn nghiệm mong muốn",
|
||||
"ui.construction.contact_hint": "Tiếp tuyến: chọn đường tròn/cung hoặc spline/conic hở rồi chọn tiếp điểm (đường cong tự do: chỉ đầu mút)",
|
||||
"ui.construction.external_hint": "Tiếp tuyến: chọn đường tròn hoặc cung, điểm ngoài rồi chọn nghiệm mong muốn",
|
||||
"ui.construction.free_hint": "Đường dựng hình: nhấp hai điểm; nhấp chuột phải để bắt đầu lại",
|
||||
"ui.construction.normal_needs_length": "Đường vô hạn luôn là đường dựng hình: nhập chiều dài để vẽ đường thường",
|
||||
"ui.construction.parallel_hint": "Đường dựng hình: chọn đường thẳng, rồi nhấp hoặc nhập khoảng dời; nhấp chuột phải để đổi tham chiếu",
|
||||
"ui.construction.point_hint": "Đường dựng hình: nhấp điểm đi qua",
|
||||
"ui.construction.reference_hint": "Đường dựng hình: chọn đường thẳng rồi chọn điểm; nhấp chuột phải để đổi tham chiếu",
|
||||
"ui.construction.ribbon_label": "Đường phụ",
|
||||
@@ -5448,6 +5599,17 @@
|
||||
"ui.ellipse": "Hình elip",
|
||||
"ui.emboss_wrap_note": "Các biên dạng đường trực giao tiếp xúc với một hình trụ được hỗ trợ sẽ tự động quấn. Chọn một thành để chọn mục tiêu.",
|
||||
"ui.end": "Đầu",
|
||||
"ui.end_cap.chamfer": "Vát góc",
|
||||
"ui.end_cap.direction": "Hướng",
|
||||
"ui.end_cap.faces": "Mặt đầu",
|
||||
"ui.end_cap.inset": "Thụt vào",
|
||||
"ui.end_cap.inset_kind": "Thụt vào theo",
|
||||
"ui.end_cap.inset_ratio": "Tỉ lệ thụt vào",
|
||||
"ui.end_cap.inward": "Vào trong",
|
||||
"ui.end_cap.length": "Chiều dài",
|
||||
"ui.end_cap.outward": "Ra ngoài",
|
||||
"ui.end_cap.ratio": "Tỉ lệ theo độ dày",
|
||||
"ui.end_cap_title": "NẮP ĐẦU",
|
||||
"ui.end_radius": "Bán kính kết thúc",
|
||||
"ui.end_scale": "Tỷ lệ đầu cuối",
|
||||
"ui.ends": "Các đầu",
|
||||
@@ -5468,7 +5630,10 @@
|
||||
"ui.explode_needs_two_components": "Chế độ xem phân rã tách các cụm chi tiết ra xa nhau, nên thiết kế cần có từ hai cụm chi tiết trở lên (Tạo mới Cụm chi tiết, Chèn thiết kế vào cụm hoặc Tạo cụm chi tiết từ các thân khối)",
|
||||
"ui.exportDxf": "Xuất tệp DXF…",
|
||||
"ui.export_ellipsis_keymap": "Xuất tệp…",
|
||||
"ui.export_glb": "Xuất tệp GLB",
|
||||
"ui.export_keymap_tip": "Xuất phím tắt, danh sách S box yêu thích và thanh công cụ ra tệp",
|
||||
"ui.export_selects_only_body": "Chọn khối duy nhất khi xuất lưới",
|
||||
"ui.export_selects_only_body_tip": "Xuất tệp STL, Xuất tệp 3MF và Gửi sang phần mềm cắt lớp bắt đầu với khối của thiết kế đã được chọn khi thiết kế chỉ có một khối.",
|
||||
"ui.extend": "Kéo dài đường",
|
||||
"ui.extent": "Phạm vi",
|
||||
"ui.extent_type": "Kiểu giới hạn kéo dài",
|
||||
@@ -5528,6 +5693,8 @@
|
||||
"ui.finest": "Mịn nhất",
|
||||
"ui.finish_sketch": "Hoàn tất phác thảo",
|
||||
"ui.first_dimension_scales": "Kích thước đầu tiên co giãn bản vẽ",
|
||||
"ui.first_dimension_scales_about_origin": "Co giãn quanh gốc phác thảo",
|
||||
"ui.first_dimension_scales_about_origin_tip": "Bật: bản vẽ luôn phóng to hoặc thu nhỏ quanh gốc phác thảo, nên hình vẽ cách xa gốc sẽ di chuyển. Tắt: bản vẽ không gắn với gốc sẽ co giãn quanh tâm của chính nó và giữ nguyên vị trí.",
|
||||
"ui.first_dimension_scales_tip": "Bật: kích thước chiều dài đầu tiên của bản phác thảo co giãn toàn bộ hình mà nó đo, nên hình dạng được giữ nguyên. Tắt: kích thước chỉ đổi cỡ phần mà nó đo.",
|
||||
"ui.fit": "Vừa vặn (Fit)",
|
||||
"ui.fix_unfix": "Cố định/Uncố định",
|
||||
@@ -5950,6 +6117,7 @@
|
||||
"ui.project_references_construction_note": "Chiếu, Giao, Đưa vào hình học 3D và các cạnh bề mặt của phác thảo mới trên một bề mặt tạo ra đường dựng hình: tham chiếu để vẽ theo, không thuộc biên dạng. Chúng vẫn liên kết với mô hình.",
|
||||
"ui.properties": "Thuộc tính cơ lý",
|
||||
"ui.properties.copy_matrix": "Sao chép ma trận",
|
||||
"ui.properties.copy_value": "Nhấp để sao chép",
|
||||
"ui.properties.first_moments": "Mômen bậc nhất",
|
||||
"ui.properties.inertia": "Mômen quán tính",
|
||||
"ui.properties.inertia_note": "Quanh trọng tâm, theo các trục thế giới (g·{unit}²)",
|
||||
@@ -5962,6 +6130,7 @@
|
||||
"ui.properties.measuring_failed": "Phép đo đã dừng trước khi hoàn tất.",
|
||||
"ui.properties.principal_axis": "Trục chính {number}",
|
||||
"ui.properties.principal_moments": "Mômen quán tính chính",
|
||||
"ui.properties.value_copied": "Đã sao chép giá trị",
|
||||
"ui.pull_direction": "Hướng kéo",
|
||||
"ui.quality": "Chất lượng",
|
||||
"ui.quantity": "Số lượng",
|
||||
@@ -5982,11 +6151,14 @@
|
||||
"ui.relink_design_changed": "Cụm lắp ráp đã thay đổi trong lúc chọn nguồn. Hãy bắt đầu lại Liên kết lại nguồn.",
|
||||
"ui.relink_done": "Đã liên kết lại nguồn cho tất cả các thể hiện.",
|
||||
"ui.relink_not_linked": "Chi tiết này chưa được liên kết với thiết kế nguồn nào.",
|
||||
"ui.relink_one_done": "Đã liên kết lại nguồn cho thể hiện này.",
|
||||
"ui.relink_select_one": "Hãy chọn trước một chi tiết được liên kết hoặc một thể hiện của nó.",
|
||||
"ui.relink_source_all": "Liên kết lại nguồn (tất cả thể hiện)…",
|
||||
"ui.relink_source_one": "Liên kết lại nguồn…",
|
||||
"ui.removeFromQuickAccess": "Gỡ khỏi Truy cập nhanh",
|
||||
"ui.removeFromToolbar": "Xóa khỏi thanh công cụ",
|
||||
"ui.removeSection": "Xóa mặt cắt",
|
||||
"ui.renameSelectedBodies": "Đổi tên các thân khối đã chọn",
|
||||
"ui.render": "Kết xuất hình ảnh",
|
||||
"ui.renderer": "Trình kết xuất hình ảnh (Renderer)",
|
||||
"ui.repeat": "Lặp lại",
|
||||
@@ -6017,6 +6189,8 @@
|
||||
"ui.ribbon_pin_footer": "Các lệnh đã ghim hiển thị trên ruy-băng. Rê chuột lên một hàng để ghim hoặc bỏ ghim.",
|
||||
"ui.ribbon_workspace": "Không gian làm việc",
|
||||
"ui.right": "Phải (Hình chiếu cạnh)",
|
||||
"ui.right_click_confirms": "Nhấp chuột phải xác nhận đầu vào của hộp thoại",
|
||||
"ui.right_click_confirms_tip": "Khi hộp thoại đang mở, nhấp chuột phải trong khung nhìn chuyển sang đầu vào trống tiếp theo, và ở đầu vào cuối cùng sẽ chạy OK",
|
||||
"ui.save": "Lưu",
|
||||
"ui.save_as": "Lưu thành tệp mới",
|
||||
"ui.save_mesh_no_slicer_open": "Không tìm thấy phần mềm cắt lớp: chọn Tùy chỉnh… và chỉ định chương trình cắt lớp của bạn",
|
||||
@@ -6076,6 +6250,16 @@
|
||||
"ui.sketch_intersect_selection_filter": "Bộ lọc lựa chọn",
|
||||
"ui.sketch_keys_only": "Không dùng phím mô hình trong bản phác thảo",
|
||||
"ui.sketch_keys_only_tip": "Khi đang chỉnh sửa bản phác thảo, chỉ các phím phác thảo và các phím dùng được ở mọi nơi mới hoạt động; phím mô hình như E hoặc F không làm gì, nên một phím bấm nhầm không thể đóng một bản phác thảo nặng.",
|
||||
"ui.sketch_links_added_curve": "{command} đã thêm 1 đường cong vào bản phác thảo.",
|
||||
"ui.sketch_links_added_curves": "{command} đã thêm {count} đường cong vào bản phác thảo.",
|
||||
"ui.sketch_links_added_curves_and_points": "{command} đã thêm {curves} và {points} vào bản phác thảo.",
|
||||
"ui.sketch_links_added_point": "{command} đã thêm 1 điểm vào bản phác thảo.",
|
||||
"ui.sketch_links_added_points": "{command} đã thêm {count} điểm vào bản phác thảo.",
|
||||
"ui.sketch_links_curve_count": "{count} đường cong",
|
||||
"ui.sketch_links_curve_count_one": "1 đường cong",
|
||||
"ui.sketch_links_hidden": "Kết quả bị ẩn vì {option} đang tắt trong Tùy chọn phác thảo.",
|
||||
"ui.sketch_links_point_count": "{count} điểm",
|
||||
"ui.sketch_links_point_count_one": "1 điểm",
|
||||
"ui.sketch_modifiers": "Phím bổ trợ phác thảo",
|
||||
"ui.sketch_project_geometry": "Hình học",
|
||||
"ui.sketch_report.all_constrained": "Mọi thứ đã được ràng buộc hoàn toàn.",
|
||||
@@ -6115,6 +6299,7 @@
|
||||
"ui.step_values": "Thay đổi giá trị bằng mũi tên và con lăn",
|
||||
"ui.step_values_tip": "Phím lên/xuống và con lăn trên trường giá trị sẽ thay đổi số trong đó.",
|
||||
"ui.stitch_tolerance_hint": "chặt",
|
||||
"ui.straighten": "Làm thẳng",
|
||||
"ui.stretch": "Kéo giãn",
|
||||
"ui.supersampling": "Khử răng cưa SSAA",
|
||||
"ui.supersampling_adaptive": "Chỉ khi góc nhìn đứng yên",
|
||||
@@ -6188,6 +6373,8 @@
|
||||
"ui.view_angles_yaw": "Lệch",
|
||||
"ui.view_angles_zero": "Đặt {axis} về 0°",
|
||||
"ui.view_centre": "Tâm góc nhìn",
|
||||
"ui.view_compass_tip": "Nhìn từ {axis}. Bấm lần nữa để đảo ngược. Kéo để xoay góc nhìn.",
|
||||
"ui.view_compass_tip_snap": "Nhìn từ {axis}. Bấm lần nữa để đảo ngược. Kéo để xoay góc nhìn; giữ Shift để bắt dính.",
|
||||
"ui.viewport_status_clear": "Tắt {name}",
|
||||
"ui.viewport_status_clear_hint": "Tắt {name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} cạnh",
|
||||
|
||||
+1244
-212
File diff suppressed because it is too large
Load Diff
+214
-27
@@ -247,6 +247,7 @@
|
||||
"Drag to move the hole; click to remove it": "拖动以移动孔,单击以删除",
|
||||
"Drag to move the rest across the model. It snaps to sketch points on the face.": "拖动以在模型上移动垫块。它会吸附到面上的草图点。",
|
||||
"Drag to move the snap fit across the model. It snaps to sketch points on the face.": "拖动以在模型上移动卡扣。它会吸附到面上的草图点。",
|
||||
"Drag to place it on another face.": "拖动以将其放置到另一个面上。",
|
||||
"Drag to point the catch in another direction.": "拖动以将卡钩指向另一个方向。",
|
||||
"Drag to turn the rest in 5° steps. Hold Alt or Ctrl to turn it freely.": "拖动以 5° 为步长旋转垫块。按住 Alt 或 Ctrl 可自由旋转。",
|
||||
"Drive Joint": "驱动接头",
|
||||
@@ -513,6 +514,7 @@
|
||||
"Offset Y": "偏移 Y",
|
||||
"Offset Z": "偏移 Z",
|
||||
"On your computer": "在此计算机上",
|
||||
"One more stretch of the picked edge, each with its own angle, height and turns": "所选边的又一段,每段都有自己的角度、高度和折弯方向",
|
||||
"Opacity": "不透明度",
|
||||
"Open GitHub": "打开 GitHub",
|
||||
"Open GitHub draft": "打开 GitHub 草稿",
|
||||
@@ -634,6 +636,7 @@
|
||||
"Remove the track": "移除轨迹",
|
||||
"Remove this bend": "移除此折弯",
|
||||
"Remove this point": "移除此点",
|
||||
"Remove this segment": "移除此分段",
|
||||
"Rename Feature": "重命名特征",
|
||||
"Rename Folder": "重命名文件夹",
|
||||
"Render Stage": "渲染阶段",
|
||||
@@ -723,6 +726,7 @@
|
||||
"Section position": "截面位置",
|
||||
"Sections": "截面",
|
||||
"Sections (one sketch each)": "截面(每个一个草图)",
|
||||
"Segments": "分段",
|
||||
"Select Features": "选择特征",
|
||||
"Select Other": "选择其他",
|
||||
"Select Other: hold the left button still on the model (or right-click › Select Other…) to list everything under the cursor; click again on the same spot to select the next thing there. Double-click the middle button to go Home (Preferences › Navigation).": "“选择其他”:在模型上按住左键(或右键单击 › 选择其他…)列出光标下的所有对象;在同一位置再次单击可选择该处的下一个对象。双击中键转到主视图(首选项 › 导航)。",
|
||||
@@ -772,6 +776,7 @@
|
||||
"Spacing must be a non-zero number": "间距必须是非零数字",
|
||||
"Specialise": "专用操作",
|
||||
"Speed": "速度",
|
||||
"Split Edge": "分割边",
|
||||
"Splitting tool": "分割工具",
|
||||
"Square": "正方形",
|
||||
"Stainless Steel": "不锈钢",
|
||||
@@ -885,6 +890,7 @@
|
||||
"Variable Radius": "可变半径",
|
||||
"Variable radius": "可变半径",
|
||||
"Velocity": "速度",
|
||||
"Vertical": "垂直",
|
||||
"Vertices": "顶点",
|
||||
"View": "视图",
|
||||
"View navigator": "视图导航器",
|
||||
@@ -938,6 +944,13 @@
|
||||
"ai.prefs.connect_apps_note": "关闭后会移除已添加的条目。\n\nSolidCraft 启动时,会把自己作为 MCP 服务器添加到此电脑上找到的 AI 应用(OpenCode、Claude Desktop、Claude Code、Cursor、Codex、Gemini CLI、Copilot CLI、Windsurf、Zed、VS Code)。只添加或更新 solidcraft 条目;你修改过的条目不会被改动,文件会先备份。关闭后,会删除它添加的条目。",
|
||||
"ai.prefs.connect_at_start": "启动时连接上次使用的代理",
|
||||
"ai.prefs.connect_at_start_note": "每次启动 SolidCraft 时,在后台启动上次连接的智能体(或默认智能体),以便随时开始聊天。使用 --control 启动 SolidCraft 时不会这样做。如果无法连接,助手会显示“连接失败”和“重试”按钮。",
|
||||
"ai.prefs.control_failed": "控制通道无法启动:{error}",
|
||||
"ai.prefs.control_from_launch": "本次运行通过 --control 在端口 {port} 上启动。此处的更改将在下次不带 --control 启动 SolidCraft 时生效。",
|
||||
"ai.prefs.control_listening": "正在监听 127.0.0.1:{port}",
|
||||
"ai.prefs.control_not_listening": "未在监听",
|
||||
"ai.prefs.control_port": "端口",
|
||||
"ai.prefs.control_port_note": "AI 代理在本机上连接的端口 (127.0.0.1)。默认为 27878:若被占用,则使用下一个空闲端口。其他端口按原样使用。请让 MCP 客户端指向同一端口,例如 solidcraft-cli mcp --connect 127.0.0.1:7878。",
|
||||
"ai.prefs.control_port_taken": "端口 {port} 已被其他程序(或另一个 SolidCraft 窗口)占用。请选择其他端口。",
|
||||
"ai.prefs.follow_camera": "跟随相机",
|
||||
"ai.prefs.follow_camera_off": "相机自动跟随已关闭。",
|
||||
"ai.prefs.follow_camera_on": "相机将转向代理创建的草图。",
|
||||
@@ -998,6 +1011,13 @@
|
||||
"browser.sketches_to_parts_not_on_face": "不在零件的面上",
|
||||
"browser.sketches_to_parts_part_missing": "其零件已不存在",
|
||||
"browser.sketches_to_parts_result": "已将 {moved} 个草图移到其所在的零件;{stayed} 个保留原处:{why}",
|
||||
"browser.straighten_angle": "边的方向",
|
||||
"browser.straighten_choose": "选择边的方向(水平、垂直或角度),然后按“拉直”。",
|
||||
"browser.straighten_click_a": "在图像上单击应为直线的边的一端,或输入其坐标。",
|
||||
"browser.straighten_click_b": "单击该边的另一端,或输入其坐标。",
|
||||
"browser.straighten_horizontal": "水平",
|
||||
"browser.straighten_title": "拉直:{name}",
|
||||
"browser.straighten_vertical": "垂直",
|
||||
"browser.units": "单位: {units}",
|
||||
"cam.flat": "平底",
|
||||
"cam.follower": "从动件",
|
||||
@@ -1027,6 +1047,8 @@
|
||||
"cmd.appearance_pick_up": "拾取外观",
|
||||
"cmd.appearance_replace": "替换外观",
|
||||
"cmd.assembly_bom": "物料清单",
|
||||
"cmd.assembly_constraint_create": "约束",
|
||||
"cmd.assembly_constraint_edit": "编辑约束",
|
||||
"cmd.assembly_mass_properties": "质量属性",
|
||||
"cmd.body.print_face": "打印底面",
|
||||
"cmd.body_rename": "重命名实体",
|
||||
@@ -1045,6 +1067,7 @@
|
||||
"cmd.canvas_delete": "删除画布",
|
||||
"cmd.canvas_edit": "编辑画布",
|
||||
"cmd.canvas_insert": "画布",
|
||||
"cmd.canvas_straighten": "拉直画布",
|
||||
"cmd.canvas_to_sketch": "画布转草图",
|
||||
"cmd.component_activate": "激活组件",
|
||||
"cmd.component_break_link": "断开链接",
|
||||
@@ -1086,7 +1109,10 @@
|
||||
"cmd.config_rule": "配置规则",
|
||||
"cmd.config_rules": "配置规则",
|
||||
"cmd.config_table": "显示配置表",
|
||||
"cmd.construct.axis": "轴",
|
||||
"cmd.construct.plane": "平面",
|
||||
"cmd.construct.plane.axis_point": "通过轴和点的平面",
|
||||
"cmd.construct.point": "点",
|
||||
"cmd.construct_axis_edge": "过边的轴",
|
||||
"cmd.construct_axis_normal_to_face": "垂直于面的轴",
|
||||
"cmd.construct_axis_through_cylinder": "过圆柱/圆锥/圆环的轴",
|
||||
@@ -1149,6 +1175,7 @@
|
||||
"cmd.file_save_mesh": "另存为网格",
|
||||
"cmd.file_send_to_slicer": "发送到切片软件",
|
||||
"cmd.file_slicers": "已安装的切片软件",
|
||||
"cmd.frame_end_cap": "端盖",
|
||||
"cmd.frame_member": "框架构件",
|
||||
"cmd.frame_profile_insert": "插入型材",
|
||||
"cmd.frame_profile_list": "型材库",
|
||||
@@ -1169,6 +1196,7 @@
|
||||
"cmd.inspect_isocurve": "等参线分析",
|
||||
"cmd.inspect_minimum_radius": "最小半径分析",
|
||||
"cmd.inspect_parameter_sweep": "参数扫描",
|
||||
"cmd.inspect_parameter_variants": "比较参数方案",
|
||||
"cmd.inspect_silhouette": "轮廓",
|
||||
"cmd.inspect_zebra": "斑马纹分析",
|
||||
"cmd.joint_as_built": "现状接头",
|
||||
@@ -1222,6 +1250,10 @@
|
||||
"cmd.motion_trace": "运动轨迹",
|
||||
"cmd.motion_trace_edit": "编辑运动轨迹",
|
||||
"cmd.motion_trace_keep": "保留运动轨迹",
|
||||
"cmd.note_add": "添加备注",
|
||||
"cmd.note_delete": "删除备注",
|
||||
"cmd.note_list": "列出备注",
|
||||
"cmd.note_update": "编辑备注",
|
||||
"cmd.occurrence_align": "对齐实例",
|
||||
"cmd.occurrence_copy": "粘贴(实例)",
|
||||
"cmd.occurrence_drag": "拖动实例",
|
||||
@@ -1347,6 +1379,7 @@
|
||||
"cmd.render_start": "渲染图像",
|
||||
"cmd.render_status": "渲染进度",
|
||||
"cmd.select_clear": "清除选择",
|
||||
"cmd.selection_get": "获取选择",
|
||||
"cmd.settings_profile_apply": "应用设置配置文件",
|
||||
"cmd.settings_profile_delete": "删除设置配置文件",
|
||||
"cmd.settings_profile_export": "导出设置配置文件",
|
||||
@@ -1510,6 +1543,7 @@
|
||||
"cmd.timeline_suppress": "抑制特征",
|
||||
"cmd.ui.assistant": "切换助手显示",
|
||||
"cmd.ui.palette": "搜索命令",
|
||||
"cmd.ui.toggle_visibility": "显示/隐藏所选项",
|
||||
"cmd.view.navigator": "自定义视图导航器",
|
||||
"cmd.view.render_browser": "渲染浏览器",
|
||||
"cmd.view.render_dock": "移动渲染停靠面板",
|
||||
@@ -1567,6 +1601,7 @@
|
||||
"color.step_down": "减少一步",
|
||||
"color.step_up": "增加一步",
|
||||
"color.value": "明度(百分比)",
|
||||
"component.error.ambiguous_name": "多个组件名为 `{name}`。请使用数字组件 ID:{ids}。",
|
||||
"config.column_filter_empty": "没有匹配的列",
|
||||
"config.rule_parameter_columns": "此处仅列出在表中有列的参数。使用“添加列”(+) 添加一列,即可在此使用该参数。",
|
||||
"config.rule_suppression_columns": "此处仅列出在表中有“抑制”列的特征。使用“添加列”(+) 添加一列,即可在此控制该特征。",
|
||||
@@ -1607,6 +1642,7 @@
|
||||
"diagnostic.reselect_reference": "{feature}:引用 `{reference}` 已不再是选择时的样子;请重新选择",
|
||||
"dialog.bodies_count": "{count} 个实体",
|
||||
"dialog.clearance_invalid": "间隙必须是 0 或更大的长度",
|
||||
"dialog.component_origin": "{placement} · {item}",
|
||||
"dialog.compute": "计算",
|
||||
"dialog.compute_again": "重新计算",
|
||||
"dialog.computing": "正在计算… {seconds} 秒",
|
||||
@@ -1619,10 +1655,12 @@
|
||||
"dialog.dimension_step_expression": "只有数字可以增减;表达式保持不变",
|
||||
"dialog.dimension_step_up": "增加 {step}",
|
||||
"dialog.edit_title": "编辑 {title}",
|
||||
"dialog.hole_held_off_its_line": "参考边将此孔固定在一条直线上,该直线在所选点之前就离开了该面。请在直线经过该面的位置选取,或移除该边以自由移动孔。",
|
||||
"dialog.no_shown_body": "没有可更改的显示实体:请显示一个实体,或选择新建实体",
|
||||
"dialog.pattern_sketch_not_object": "请选择实体或特征:草图两者都不是。请用草图自身的阵列或镜像重复其曲线,或先将其拉伸。",
|
||||
"dialog.primitive_point_tip": "填入 X、Y、Z 的点:先单击此处,再单击模型的顶点、边或面、草图中的点,或原点。",
|
||||
"dialog.reference_edge_tip": "所选面上的一条直边,下方的距离从它量起:先单击此处,再单击该边。",
|
||||
"dialog.right_click_pick": "请先选择{input}",
|
||||
"dialog.select": "↖ 选择",
|
||||
"dialog.selected_count": "↖ 已选择 {count} 个",
|
||||
"dialog.selection_constraint": "约束 {id}",
|
||||
@@ -1636,9 +1674,12 @@
|
||||
"document.changed_on_disk": "{name} 已在磁盘上更改",
|
||||
"document.changed_on_disk_detail": "自您打开或上次保存 {name} 以来,它已被其他程序或计算机更改。覆盖会用您的更改替换这些更改;保存副本则两者都保留。",
|
||||
"document.copy_name": "{name} 副本",
|
||||
"document.discard_row": "放弃",
|
||||
"document.finish_save_prompt": "请先回答保存提示,再打开其他设计。",
|
||||
"document.newer_file": "由较新版本的 SolidCraft 保存(格式 {format},此版本最高可读取 {reads})。如有缺失,请更新。",
|
||||
"document.newer_file_change": "由较新版本的 SolidCraft 保存(格式 {format},包含此版本未知的 `{change}`)。如有缺失,请更新。",
|
||||
"document.newer_file_not_read": "未读取:{what}。保存时会保留它。",
|
||||
"document.not_saved_yet": "尚未保存",
|
||||
"document.open_anyway": "仍然打开",
|
||||
"document.open_elsewhere": "{name} 已被打开",
|
||||
"document.open_elsewhere_detail": "{name} 已在 {who} 上的 SolidCraft {app} 中打开({when}打开)。如果双方都保存,其中一方的工作会丢失。以只读方式打开即可查看而不会覆盖它。",
|
||||
@@ -1648,6 +1689,9 @@
|
||||
"document.read_only_save": "此设计以只读方式打开:请另存为新文件",
|
||||
"document.save_changes": "保存对 {name} 的更改?",
|
||||
"document.save_copy": "保存副本…",
|
||||
"document.save_many": "保存 {n} 个设计的更改?",
|
||||
"document.save_row": "保存",
|
||||
"document.save_selected": "保存所选项",
|
||||
"document.tab_unsaved_changes": "未保存的更改",
|
||||
"document.unsaved_changes": "{name} 有未保存的更改。如果不保存,将丢失这些更改。",
|
||||
"drive.rigid": "{joint} 是刚性接头:它把零件固定在原位,因此没有可驱动的运动。要让零件运动,请在“编辑接头”中更改其类型:旋转用 Revolute,滑动用 Slider,两者兼有用 Cylindrical。",
|
||||
@@ -1667,6 +1711,8 @@
|
||||
"dxf.tolerance": "曲线公差",
|
||||
"dxf.tolerance_help": "仅导出可见实体和显示的草图。曲线使用直线段近似。公差越小,曲线越精细,但需要更多时间和内存。",
|
||||
"each rail's curves must be in one sketch": "每条导轨的曲线必须位于同一个草图中",
|
||||
"error.end_cap_faces": "请至少选择一个框架构件的开放端面",
|
||||
"error.end_cap_unresolved": "此端盖的端 {ends} 已不在模型上。请重新选择端面",
|
||||
"feature computation ended without a result": "特征计算结束时没有返回结果",
|
||||
"file.open.drawing_filter": "设计、CAD 文件、网格和图纸",
|
||||
"file.open.portal_fallback.no_portal_service": "打开的文件选择器并非桌面自带:桌面的文件选择服务不可用。",
|
||||
@@ -1678,6 +1724,7 @@
|
||||
"file_load.inserting": "正在插入几何体",
|
||||
"file_load.link_item": "{name} ({done}/{total})",
|
||||
"file_load.opened": "已打开 {name}",
|
||||
"file_load.opened_behind": "已在新标签页中打开{name}",
|
||||
"file_load.opened_in_tab": "已在新标签页中打开 {name}",
|
||||
"file_load.opening": "正在打开设计",
|
||||
"file_load.preparing_thumbnail": "正在准备缩略图...",
|
||||
@@ -1725,11 +1772,13 @@
|
||||
"help.config.table": "显示配置表:每个变体一行,每个参数或特征一列,并指出设计是否仍与当前生效的行一致。用于检查设计的各个变体。",
|
||||
"help.connect_note": "请重启各个助手以加载 SolidCraft 服务器。每个被修改的文件都已备份为 .bak。",
|
||||
"help.connect_title": "连接 AI 助手",
|
||||
"help.construct.axis": "按所选对象对应的方法创建构造轴:沿边或直线、穿过孔或圆形面、两平面的交线、穿过两点,或过一点垂直于面。在已知参照但不想选择方法时使用。",
|
||||
"help.construct.axis.edge": "沿直边或草图线创建构造轴。用作旋转、圆周阵列或接头的轴。",
|
||||
"help.construct.axis.normal_to_face": "创建一条过某点、垂直于面的构造轴。用作从表面笔直伸出的轴。",
|
||||
"help.construct.axis.through_cylinder": "通过圆柱、圆锥或圆环面的中心,或圆形边的中心创建构造轴。用于绕圆形零件旋转或阵列特征。",
|
||||
"help.construct.axis.two_planes": "在两个平面或平整面相交处创建构造轴。用于所需的轴正是两个面之间的交线时。",
|
||||
"help.construct.axis.two_points": "通过两个点、顶点或草图点创建构造轴。用于连接两个已知位置的轴。",
|
||||
"help.construct.plane": "按所选对象对应的方法创建构造平面:偏移自平面、过一点、两平面之间、过直线或点、与曲面相切,或垂直于路径。在已知参照但不想选择方法时使用。",
|
||||
"help.construct.plane.along_path": "在边或曲线上的指定位置创建垂直于它的构造平面。用于为扫掠绘制轮廓,或绘制路径的截面。",
|
||||
"help.construct.plane.at_angle": "创建一个由平面或面绕轴或边旋转一定角度而成的构造平面。用于倾斜的草图,例如斜支架。",
|
||||
"help.construct.plane.axis_point": "创建包含一条轴和一个轴外点的构造平面。先选择原点轴、构造轴、直边或草图直线,再选择顶点、草图点或构造点。轴上的点无法确定唯一的平面。",
|
||||
@@ -1739,6 +1788,7 @@
|
||||
"help.construct.plane.tangent": "创建在某点与圆柱、圆锥、球或圆环相切的构造平面。用于在圆形零件的侧面绘制草图。",
|
||||
"help.construct.plane.three_points": "通过三个点创建构造平面。用于由模型上的位置(如三个角)确定的平面。",
|
||||
"help.construct.plane.two_edges": "通过位于同一平面内的两条直边或直线创建构造平面。用于穿过零件的平面,例如通过两条相对的边。",
|
||||
"help.construct.point": "按所选对象对应的方法创建构造点:在顶点、圆或球的中心、沿边、两直线或三个平面的交点,或直线与平面的交点。在已知参照但不想选择方法时使用。",
|
||||
"help.construct.point.along_path": "在边或曲线上的指定位置创建构造点。用作路径中途的参考。",
|
||||
"help.construct.point.center": "在圆形边、草图圆或圆弧、球或圆环的中心创建构造点。用作孔、轴和接头的参考。",
|
||||
"help.construct.point.edge_plane": "在边或直线穿过平面或平整面处创建构造点。用于标出路径与平面相交的位置。",
|
||||
@@ -1764,6 +1814,7 @@
|
||||
"help.file.send_to_slicer": "将选中的实体保存为 3MF 文件,并在所选的切片软件中打开。用于一步从模型进入打印。",
|
||||
"help.font_details": "界面使用 egui 的内置字体(Ubuntu Light 和 Hack,采用 Ubuntu Font Licence 和 MIT/Bitstream Vera 许可证;Noto Emoji 和表情图标字体,采用 OFL 和 MIT 许可证)。草图文本使用 Liberation Sans(SIL OFL 1.1)。The Crafting Apps 的可选字体包 craft-fonts(BIZ UDPGothic、Shippori Mincho、BIZ UDMincho、Noto Sans CJK SC、Noto Sans Arabic;SIL OFL 1.1)未随 SolidCraft 构建版本捆绑提供。",
|
||||
"help.fonts": "字体",
|
||||
"help.frame.end_cap": "用符合型材外形的板封闭框架构件的开放端。用于封住管材、角钢和梁的端部,可盖在端面上或嵌入端部。",
|
||||
"help.frame.member": "沿框架草图的线放置型材(如管材或铝型材),每条线一根构件。用于构建框架、货架和焊接结构。",
|
||||
"help.inspect.accessibility": "给刀具从某一方向能够到达和无法到达的面着色。用于检查零件从该方向加工或成型是否可行。",
|
||||
"help.inspect.center_of_mass": "在均匀密度下显示各实体单独以及整体的质心。用于检查平衡和零件的倾倒位置。",
|
||||
@@ -2240,6 +2291,9 @@
|
||||
"measure.at": "位置",
|
||||
"measure.item": "项目 {number}",
|
||||
"measure.line_to_centre": "线到圆心",
|
||||
"measure.perimeter": "周长",
|
||||
"measure.perimeter_inner": "内周长",
|
||||
"measure.perimeter_outer": "外周长",
|
||||
"measure.quick_copied": "已复制测量值",
|
||||
"measure.quick_copy": "点击复制测量值",
|
||||
"measure.quick_edges": "{count} 条边",
|
||||
@@ -2281,6 +2335,8 @@
|
||||
"nav.hfss.help": "Alt+左键拖动平移,Shift+Alt+左键拖动缩放,在空白处 Ctrl+左键拖动旋转",
|
||||
"nav.inventor.help": "中键拖动平移,Shift+中键拖动旋转,Ctrl+中键拖动缩放,右键拖动旋转",
|
||||
"nav.maya.help": "Alt+左键拖动旋转,Alt+中键拖动平移,Alt+右键拖动缩放;中键拖动也可平移",
|
||||
"nav.maya_horizontal_zoom.help": "Alt+右键拖动:向右放大,向左缩小。关闭此选项可恢复垂直拖动缩放。",
|
||||
"nav.maya_horizontal_zoom.label": "Maya:水平拖动缩放",
|
||||
"nav.nx.help": "中键拖动旋转,Shift+中键平移(对应 NX 的中键+右键),Ctrl+中键缩放(对应 NX 的中键+左键);右键拖动不旋转视图",
|
||||
"nav.openscad.help": "在空白处左键拖动旋转,Shift+左键拖动框选,拖动草图几何可编辑;右键或中键拖动平移,Shift+右键或 Shift+中键拖动缩放",
|
||||
"nav.orbit_cursor_wrap.help": "旋转拖动到达视图边缘时,光标移到对侧边缘并继续旋转。关闭时,拖动在屏幕边缘停止。在 Wayland 和浏览器中无效。",
|
||||
@@ -2411,6 +2467,16 @@
|
||||
"not a move": "不是移动",
|
||||
"not a number": "不是数字",
|
||||
"open a sketch first": "请先打开一个草图",
|
||||
"operations.cancel": "取消{name}",
|
||||
"operations.cancelled": "已取消{name}",
|
||||
"operations.cancelling": "正在取消…",
|
||||
"operations.cannot_cancel": "无法取消{name}",
|
||||
"operations.feature": "特征",
|
||||
"operations.feature_edit": "编辑特征",
|
||||
"operations.meshing": "正在加载零件",
|
||||
"operations.queued": "排队中",
|
||||
"operations.stopped": "已取消",
|
||||
"operations.waiting": "就绪",
|
||||
"parameters.apply_live": "离开字段时立即应用每项更改",
|
||||
"parameters.apply_live_tip": "关闭时:更改会等到“应用”或“确定”,然后设计只为所有更改重建一次。“取消”或 Esc 会放弃这些更改。",
|
||||
"parameters.held": "{count} 项更改等待应用",
|
||||
@@ -2499,6 +2565,7 @@
|
||||
"prefs.appearance.viewport_colours": "3D 视图颜色",
|
||||
"prefs.appearance.viewport_logo": "视口和徽标",
|
||||
"prefs.applies_on_restart": "重启后生效",
|
||||
"prefs.assemblies": "装配",
|
||||
"prefs.assistant": "助手",
|
||||
"prefs.assistant_connecting": "连接",
|
||||
"prefs.assistant_follow_help": "草图的Look At操作会使视图随指针移动。",
|
||||
@@ -2551,6 +2618,10 @@
|
||||
"prefs.choose_font": "选择字体文件…",
|
||||
"prefs.click": "单击",
|
||||
"prefs.command_dialog_values": "命令对话框",
|
||||
"prefs.constraint_glyph_size": "约束符号大小",
|
||||
"prefs.constraint_glyph_size_note": "草图中约束符号及其字母或图标的绘制大小。100% 为常规大小;任意缩放比例下符号都保持此屏幕大小。",
|
||||
"prefs.construct_menu_groups": "按实体类型分组构造工具",
|
||||
"prefs.construct_menu_groups_help": "显示平面、轴和点标题。关闭时保留原始菜单顺序。",
|
||||
"prefs.contact_shading": "柔和接触阴影",
|
||||
"prefs.contact_shading_note": "在零件相近处添加柔和阴影。",
|
||||
"prefs.context_menu": "上下文菜单",
|
||||
@@ -2586,6 +2657,8 @@
|
||||
"prefs.design_tools.rows": "行数",
|
||||
"prefs.devices": "3D 鼠标",
|
||||
"prefs.dialog_buttons": "对话框按钮",
|
||||
"prefs.dialog_first_letter_buttons": "对话框按钮响应其首字母",
|
||||
"prefs.dialog_first_letter_buttons_help": "打开对话框时,按下按钮标签的首字母即可触发该按钮:如“取”对应“取消”。一个字母若匹配两个按钮则不起作用,获得焦点的文本框保留按键输入。关闭时:按键不影响按钮,与以前相同。",
|
||||
"prefs.dialogs": "对话框",
|
||||
"prefs.dialogs_edge": "视图边缘",
|
||||
"prefs.dialogs_left_column": "左侧栏",
|
||||
@@ -2599,12 +2672,23 @@
|
||||
"prefs.dimension_values_window": "在窗口中",
|
||||
"prefs.display": "显示",
|
||||
"prefs.edges": "边缘与着色",
|
||||
"prefs.export": "导出",
|
||||
"prefs.export_name": "导出文件名",
|
||||
"prefs.export_name.body": "导出实体的名称(有多个时取第一个)",
|
||||
"prefs.export_name.design": "设计名称",
|
||||
"prefs.export_name_hint": "例如 {design}-{body}",
|
||||
"prefs.export_name_sample": "导出此设计时建议的名称:{name}",
|
||||
"prefs.export_name_tip": "文件 › 导出和另存为网格时建议的文件名。以下占位符会被替换:\n{placeholders}\n未设置的设计属性会被省略。留空则建议设计名称,网格则建议实体名称。",
|
||||
"prefs.extend": "扩展",
|
||||
"prefs.extra_navigation": "在空白处按住Ctrl并用鼠标左键拖动可旋转;按住空格键可平移。",
|
||||
"prefs.extrude_arrow_face_stops": "拉伸箭头停在面上",
|
||||
"prefs.extrude_arrow_face_stops_note": "拖动拉伸的距离箭头时,它会停在与轮廓平行的平面上(例如正在切除的块的另一侧),并勾勒出该面。关闭:箭头只按整数步长移动。",
|
||||
"prefs.extrude_view_isometric": "打开拉伸时转到等轴测视图",
|
||||
"prefs.extrude_view_return": "关闭拉伸时回到之前的视图",
|
||||
"prefs.file_operations_wait": "等待文件打开",
|
||||
"prefs.file_operations_wait_note": "打开或插入文件、重新读取链接时,设计会在显示进度和取消按钮的卡片后等待。关闭:文件显示在操作面板中,您可以继续工作;插入会在您完成当前操作后生效,期间打开的文件会放在新标签页中。",
|
||||
"prefs.fillet_legacy_radius": "使用之前的圆角半径默认值",
|
||||
"prefs.fillet_legacy_radius.help": "默认关闭。开启时:新的 Solid Fillet 以按设计单位读取的数字 2(\"2 in\")开始,与之前相同。关闭时:它以该工具自带的半径 2 mm 开始,并按设计的单位显示(\"0.07874 in\")。",
|
||||
"prefs.follows_os": "跟随操作系统",
|
||||
"prefs.font": "字体",
|
||||
"prefs.font_fallback": "所选字体缺少的字符会使用内置字体,避免标签显示为空方框。",
|
||||
@@ -2628,6 +2712,17 @@
|
||||
"prefs.gesture_pan": "平移",
|
||||
"prefs.gesture_zoom": "缩放",
|
||||
"prefs.graphics": "图形",
|
||||
"prefs.graphics_api": "图形 API",
|
||||
"prefs.graphics_api_auto": "自动",
|
||||
"prefs.graphics_api_help": "选择用于启动 SolidCraft 的图形 API。如果下次启动无法打开窗口,将恢复之前的选择。",
|
||||
"prefs.graphics_api_override": "启动覆盖设置正在控制图形 API。正常打开 SolidCraft 时将应用已保存的选择。",
|
||||
"prefs.graphics_api_restart_note": "重启后生效。关闭前会处理未保存的设计。",
|
||||
"prefs.graphics_api_restart_unavailable": "重启 SolidCraft 以应用已保存的图形 API。",
|
||||
"prefs.graphics_api_running": "当前:{current}。下次启动的选择:{selected}。",
|
||||
"prefs.graphics_api_save_failed": "无法保存图形 API 选择:{error}",
|
||||
"prefs.graphics_api_start_failed": "无法准备所选图形 API:{error}",
|
||||
"prefs.graphics_api_start_reverted": "上次使用 {requested} 启动时未能打开窗口。SolidCraft 已恢复为 {previous}。",
|
||||
"prefs.graphics_api_unavailable": "图形 API 选择功能可在桌面应用中使用。",
|
||||
"prefs.graphics_card": "显卡",
|
||||
"prefs.graphics_card_auto": "自动",
|
||||
"prefs.graphics_card_missing": "已保存的显卡不可用;将使用自动选择。",
|
||||
@@ -2671,6 +2766,8 @@
|
||||
"prefs.history_sketches_in_order": "按创建顺序",
|
||||
"prefs.history_sketches_note": "草图:选择“位于其特征下”后,左侧历史在宽度足以显示名称时,会将草图缩进一级,列在由其创建的第一个特征下。底部时间轴始终保持创建顺序。",
|
||||
"prefs.history_sketches_under_feature": "位于其特征下",
|
||||
"prefs.history_steps_component": "历史按组件逐步移动",
|
||||
"prefs.history_steps_component_note": "当某个组件处于活动或选中状态时,历史控件按底部历史的显示,只在该组件的特征之间移动。关闭后,它们在设计的所有特征之间移动。左侧或浏览器下方的历史始终在所有特征之间移动。",
|
||||
"prefs.hold_stop_snapping": "按住以停用吸附",
|
||||
"prefs.home_fit_size": "主视图与适配大小",
|
||||
"prefs.home_fit_size_note": "主视图、适配、打开的设计或视图导航器切换视图框住模型时,模型占视图的比例,与下方设置是否开启无关。100 %:填满面板、罗盘和导航栏之间的视图。",
|
||||
@@ -2686,6 +2783,8 @@
|
||||
"prefs.invert_curved_roll_arrows_note": "立方体角落的两个弯曲箭头在屏幕平面内翻滚视图。开启:顺时针箭头逆时针翻滚,逆时针箭头顺时针翻滚。关闭:每个箭头按其弯曲方向翻滚视图。",
|
||||
"prefs.invert_navigator_arrows": "反转视图立方体的旋转箭头",
|
||||
"prefs.invert_navigator_arrows_note": "立方体周围的箭头按箭头所指的方向转动相机,与 Fusion 和 Inventor 相同:左侧箭头指向右,相机向右转动。关闭:箭头把立方体转向它所在的那一面,因此左侧箭头使相机向左转动。弯曲的翻滚箭头不受影响。",
|
||||
"prefs.joint_drag_trackball": "拖动球关节上的零件时像轨迹球一样旋转",
|
||||
"prefs.joint_drag_trackball_help": "拖动由球关节固定的零件时,它绕关节以最小的转动旋转,就像滚动一个与零件同样大小的球。关闭:抓取的点精确跟随指针,零件还可能绕该点自旋。",
|
||||
"prefs.keep_unsaved_also_asks": "关闭标签页时仍然询问",
|
||||
"prefs.keep_unsaved_also_asks_tip": "关闭此项后,只要每个未保存设计的副本都是最新的,标签页就会直接关闭,不显示浏览器的提示框。",
|
||||
"prefs.keep_unsaved_in_browser": "在此浏览器中保留未保存的工作",
|
||||
@@ -2761,6 +2860,8 @@
|
||||
"prefs.not_on_gpu": "此 GPU 不支持",
|
||||
"prefs.on": "开启",
|
||||
"prefs.opaque": "不透明",
|
||||
"prefs.operations_panel": "在视图中显示操作",
|
||||
"prefs.operations_panel_note": "耗时的操作(打开文件、计算特征、智能体的命令)会连同进度和取消按钮显示在视图右下角。关闭:与以前一样显示“正在计算”提示。",
|
||||
"prefs.orbit_snap": "旋转时按住Shift可捕捉到坐标轴。",
|
||||
"prefs.orientation": "方向",
|
||||
"prefs.origin_plane_names": "原点平面名称",
|
||||
@@ -2841,6 +2942,8 @@
|
||||
"prefs.ribbon_tabs_only": "仅显示功能区的选项卡",
|
||||
"prefs.ribbon_tabs_only_note": "功能区折叠为选项卡行。单击选项卡会在视图上方显示其面板,直到命令开始或指针离开面板。“视图”选项卡中的“仅功能区选项卡”或其快捷键可切换此项。",
|
||||
"prefs.right_click": "右键单击",
|
||||
"prefs.save_prompt_one_at_a_time": "关闭多个设计时,逐个询问未保存的设计",
|
||||
"prefs.save_prompt_one_at_a_time_help": "对每个未保存的设计分别显示保存提示,而不是合并列表。",
|
||||
"prefs.saving": "启动和保存",
|
||||
"prefs.scale_note": "也可在窗口中使用 Ctrl + / Ctrl −。100% 时按钮高度为 28 像素。",
|
||||
"prefs.scale_text": "缩放与文字",
|
||||
@@ -2877,6 +2980,8 @@
|
||||
"prefs.sketch.center_arc": "圆心圆弧跟随光标",
|
||||
"prefs.sketch.click_selects": "单击选择",
|
||||
"prefs.sketch.conflict_colour": "冲突颜色",
|
||||
"prefs.sketch.cursor_coordinates": "在草图中显示光标坐标",
|
||||
"prefs.sketch.cursor_coordinates_note": "即使没有运行工具,也在指针旁显示其相对于草图原点的 X 和 Y。关闭:仅在工具放置点时显示。",
|
||||
"prefs.sketch.drawing": "绘制",
|
||||
"prefs.sketch.ellipse_axes": "绘制椭圆时带上轴线",
|
||||
"prefs.sketch.ellipse_axes_note": "将长轴和短轴绘制为构造线,以便标注半轴和轴。关闭:仅绘制椭圆,对其按 D 得到短半径,无论将数值拖到何处,都像以前一样绘制并标注 R。",
|
||||
@@ -2888,14 +2993,20 @@
|
||||
"prefs.sketch.faces_edges": "面和边",
|
||||
"prefs.sketch.hide_glyphs": "缩小时隐藏符号",
|
||||
"prefs.sketch.marks": "草图中的标记",
|
||||
"prefs.sketch.max_points": "最大草图",
|
||||
"prefs.sketch.max_points_note": "一个草图可容纳的点或曲线的最大数量:默认 20000,最多 200000。插入 SVG 和插入 DXF 会拒绝更大的图形。大型草图的求解和绘制会更慢。",
|
||||
"prefs.sketch.max_points_unit": "点",
|
||||
"prefs.sketch.note": "绘制、捕捉和选择。",
|
||||
"prefs.sketch.opening_closing": "打开和关闭",
|
||||
"prefs.sketch.prefer_free_points": "重叠时优先选择可移动点",
|
||||
"prefs.sketch.project_options": "先询问投影选项",
|
||||
"prefs.sketch.recent_snap": "捕捉两条辅助线的交点",
|
||||
"prefs.sketch.select_3d_curve_points": "选择 3D 草图曲线上的点",
|
||||
"prefs.sketch.select_3d_curve_points_help": "显示绘制的 3D 草图曲线上的点,并将其选作构造参照。",
|
||||
"prefs.sketch.select_other_hidden": "选择其他对象可选中隐藏几何体",
|
||||
"prefs.sketch.shortcut_cycles_modes": "再次按快捷键切换模式",
|
||||
"prefs.sketch.shortcut_cycles_modes_tip": "关闭时:重新启动工具。",
|
||||
"prefs.sketch.snap_to_visible_grid": "捕捉网格可见的交点",
|
||||
"prefs.sketch.snapping_guides": "捕捉和辅助线",
|
||||
"prefs.sketch.state_icons": "状态图标",
|
||||
"prefs.sketch.tracking_guides": "圆心和中点辅助线",
|
||||
@@ -2923,6 +3034,7 @@
|
||||
"prefs.sketch_selection": "草图与选择",
|
||||
"prefs.sketch_selection_heading": "草图和选择",
|
||||
"prefs.sketch_selection_note": "草图如何捕捉,以及单击如何选择。",
|
||||
"prefs.sketch_snap_to_visible_grid_note": "当指针指向网格绘制的线的交点时,草图中的点捕捉到该交点,否则捕捉到交点之间更细的网格。关闭:点只捕捉到更细的网格,与之前相同。",
|
||||
"prefs.sketch_state_icons": "以草图状态的颜色显示草图图标",
|
||||
"prefs.sketch_state_icons_note": "在历史和浏览器中,草图图标采用其状态(欠约束、完全约束或冲突)的颜色,工具提示会说明状态。关闭:所有草图使用相同的图标。",
|
||||
"prefs.sketch_tab_always": "始终显示草图选项卡",
|
||||
@@ -3624,6 +3736,7 @@
|
||||
"render.error_pbr_opacity": "不透明 PBR 要求不透明度为 1",
|
||||
"render.error_physical_glass": "所选配方不是物理玻璃",
|
||||
"render.error_preview_device": "产品预览需要带深度缓冲区的设备",
|
||||
"render.error_product_placement": "产品放置无效",
|
||||
"render.error_product_triangle": "产品三角形无效",
|
||||
"render.error_provisional_identity": "临时渲染标识或采样数无效",
|
||||
"render.error_quality_bounds": "质量映射超出原生限制",
|
||||
@@ -3707,6 +3820,10 @@
|
||||
"render.gpu_path_retry": "重试",
|
||||
"render.gpu_seed": "随机种子",
|
||||
"render.gpu_unavailable": "此设备上的 GPU 路径追踪尚未就绪。",
|
||||
"render.graphics_api_restart_vulkan": "使用 Vulkan 重启",
|
||||
"render.graphics_api_restart_warning": "更改图形 API 将重启 SolidCraft,并提示保存未保存的设计。如果新 API 无法打开窗口,下次启动时将恢复之前的选择。",
|
||||
"render.graphics_api_settings": "图形设置",
|
||||
"render.graphics_api_vulkan_required": "本次会话的 GPU 路径追踪需要 Vulkan。请使用 Vulkan 重启,或继续使用 CPU 图像方式。",
|
||||
"render.ground_apply": "适配并保存地面",
|
||||
"render.ground_gap": "明确的间隙",
|
||||
"render.ground_linear_rgb": "漫反射率 · 线性 RGB",
|
||||
@@ -4681,33 +4798,35 @@
|
||||
"sketch.dof_left": "剩余 {count} 个自由度",
|
||||
"sketch.dof_left_one": "剩余 {count} 个自由度",
|
||||
"sketch.draw_curves": "绘制为 {linetype}",
|
||||
"sketch.error.closed_curve_two_crossings": "a closed curve needs two crossings to trim",
|
||||
"sketch.error.nothing_to_break": "nothing to break here",
|
||||
"sketch.error.offset_fillet_chamfer": "`{id}` is an offset, and its corners follow its source curves: round or cut the source corners before offsetting, or break the offset association first",
|
||||
"sketch.error.offset_trim": "`{id}` is an offset, and its ends follow its source curves: edit the source curves instead, or break the offset association first",
|
||||
"sketch.hint.arc.center_point": "Arc: click center and start, go round either way and click the end, or type a signed sweep",
|
||||
"sketch.hint.arc.three_point": "Arc: click start, end, then a point on the arc",
|
||||
"sketch.hint.arc3d": "3D Arc: click start, end, then a point on the arc (points may leave the sketch plane)",
|
||||
"sketch.hint.break": "Break: click a curve where it should split",
|
||||
"sketch.hint.circle.center": "Circle: click the center, then a point on the circle",
|
||||
"sketch.hint.constraint.generic": "Constraint: pick the sketch entities",
|
||||
"sketch.hint.constraint.horizontal_vertical": "Horizontal/Vertical: pick a line, two points, or a point and a line; hold Shift to pick a line midpoint",
|
||||
"sketch.hint.constraint.midpoint": "MidPoint: pick a point and a line, or two lines to center the second on the first",
|
||||
"sketch.hint.dimension": "Dimension: pick one or two entities and type the value (or click to place it first); click a dimension to edit it; Enter applies",
|
||||
"sketch.hint.extend": "Extend: click a curve near the end to extend (Shift: click two curves to extend both to where they meet)",
|
||||
"sketch.hint.fallback": "Click in the sketch",
|
||||
"sketch.hint.line": "Line: click points; right-click or Esc to finish",
|
||||
"sketch.hint.line3d": "3D Line: click world points; right-click or Esc to finish (points may leave the sketch plane)",
|
||||
"sketch.hint.open_done": "Open done",
|
||||
"sketch.hint.point3d": "3D Point: click where a 3D point goes",
|
||||
"sketch.hint.rectangle.center": "Center rectangle: click the center, then a corner",
|
||||
"sketch.hint.rectangle.rounded": "Rounded rectangle: click two opposite corners (Tab to the radius box to type the corner radius)",
|
||||
"sketch.hint.rectangle.three_point": "3-point rectangle: click two points of one edge, then the width",
|
||||
"sketch.hint.rectangle.two_point": "Rectangle: click two opposite corners",
|
||||
"sketch.hint.slot": "Slot: click both ends, then the width",
|
||||
"sketch.hint.spline3d": "3D Spline: click fit points in 3D; right-click or Esc to finish",
|
||||
"sketch.hint.trim": "Trim: click the piece of a curve to remove, or drag across the pieces to remove",
|
||||
"sketch.error.closed_curve_two_crossings": "闭合曲线需要两个交点才能修剪",
|
||||
"sketch.error.nothing_to_break": "此处没有可断开的位置",
|
||||
"sketch.error.offset_fillet_chamfer": "`{id}` 是偏移曲线,其拐角跟随源曲线:请先对源曲线的拐角倒圆角或倒角再偏移,或先断开偏移关联",
|
||||
"sketch.error.offset_trim": "`{id}` 是偏移曲线,其端点跟随源曲线:请改为编辑源曲线,或先断开偏移关联",
|
||||
"sketch.hint.arc.center_point": "圆弧:单击圆心和起点,向任一方向转动后单击终点,或输入带符号的扫过角度",
|
||||
"sketch.hint.arc.three_point": "圆弧:依次单击起点、终点和圆弧上的一点",
|
||||
"sketch.hint.arc3d": "三维圆弧:依次单击起点、终点和圆弧上的一点(点可以离开草图平面)",
|
||||
"sketch.hint.break": "打断:在曲线要分开的位置单击",
|
||||
"sketch.hint.circle.center": "圆:单击圆心,再单击圆上一点",
|
||||
"sketch.hint.constraint.generic": "约束:选择草图图元",
|
||||
"sketch.hint.constraint.horizontal_vertical": "水平/竖直:选择一条直线、两个点,或一个点和一条直线;按住 Shift 可选取直线中点",
|
||||
"sketch.hint.constraint.midpoint": "中点:选择一个点和一条直线,或选择两条直线,使第二条的中点落在第一条上",
|
||||
"sketch.hint.dimension": "尺寸:选择一个或两个图元并输入数值(也可先单击放置尺寸);单击已有尺寸可编辑;按 Enter 应用",
|
||||
"sketch.hint.extend": "延伸:单击曲线靠近端点的位置进行延伸(Shift:依次单击两条曲线,将两者延伸到相交处)",
|
||||
"sketch.hint.fallback": "在草图中单击",
|
||||
"sketch.hint.line": "直线:依次单击各点;右键单击或按 Esc 结束",
|
||||
"sketch.hint.line3d": "三维直线:依次单击空间中的点;右键单击或按 Esc 结束(点可以离开草图平面)",
|
||||
"sketch.hint.open_done": "开放轮廓已完成",
|
||||
"sketch.hint.point3d": "三维点:单击三维点的位置",
|
||||
"sketch.hint.rectangle.center": "中心矩形:单击中心,再单击一个角点",
|
||||
"sketch.hint.rectangle.rounded": "圆角矩形:单击两个对角点(按 Tab 切换到半径框,输入圆角半径)",
|
||||
"sketch.hint.rectangle.three_point": "三点矩形:单击一条边的两个端点,再确定宽度",
|
||||
"sketch.hint.rectangle.two_point": "矩形:单击两个对角点",
|
||||
"sketch.hint.slot": "槽:单击两端,再确定宽度",
|
||||
"sketch.hint.spline3d": "三维样条曲线:在三维空间中单击拟合点;右键单击或按 Esc 结束",
|
||||
"sketch.hint.trim": "修剪:单击要删除的曲线段,或拖动划过要删除的各段",
|
||||
"sketch.make_selection": "将选择转换为 {linetype}",
|
||||
"sketch.move_released": "已移动:已解除 {count} 个将其与保留部分相连的约束({names})。",
|
||||
"sketch.move_released_one": "已移动:已解除 {count} 个将其与保留部分相连的约束({names})。",
|
||||
"sketch.open_ends": "开放 {count}",
|
||||
"sketch.status_conflict": "约束冲突",
|
||||
"sketch.status_fully_constrained": "完全约束",
|
||||
@@ -4738,6 +4857,10 @@
|
||||
"sketch_text.path_clear": "将文字移离其曲线",
|
||||
"sketch_text.path_hint": "文字所跟随的草图曲线:先单击此处,再选择曲线",
|
||||
"sketch_text.use_font_file": "使用字体文件 {path}",
|
||||
"sketch_text.valign_baseline": "基线",
|
||||
"sketch_text.valign_bottom": "底端",
|
||||
"sketch_text.valign_middle": "居中",
|
||||
"sketch_text.valign_top": "顶端",
|
||||
"solid": "实心",
|
||||
"status.editing": "正在编辑 {name}",
|
||||
"status.navigation": "鼠标映射:{mapping}",
|
||||
@@ -4938,6 +5061,7 @@
|
||||
"ui.agent_chat_allow_once": "仅允许一次",
|
||||
"ui.agent_chat_allowed": "已允许",
|
||||
"ui.agent_chat_answered": "回答:{option}",
|
||||
"ui.agent_chat_answered_in": "用时 {time} 完成回答",
|
||||
"ui.agent_chat_approval": "允许智能体执行此操作吗?",
|
||||
"ui.agent_chat_attach_selection": "附加选择",
|
||||
"ui.agent_chat_attach_selection_tip": "随消息发送模型中当前选中的内容(面、边、特征、实体),让智能体知道你指的是什么",
|
||||
@@ -4966,6 +5090,7 @@
|
||||
"ui.agent_chat_ctx_bodies": "实体",
|
||||
"ui.agent_chat_ctx_elements": "元素",
|
||||
"ui.agent_chat_ctx_features": "特征",
|
||||
"ui.agent_chat_ctx_gone": "已不在设计中:它被修改或删除了。",
|
||||
"ui.agent_chat_ctx_more": "另有 {n} 项",
|
||||
"ui.agent_chat_ctx_other": "其他",
|
||||
"ui.agent_chat_custom_heading": "自定义模型",
|
||||
@@ -4979,6 +5104,7 @@
|
||||
"ui.agent_chat_dock_right": "停靠在右侧",
|
||||
"ui.agent_chat_drop_hint": "拖放到此处,附加到下一条消息",
|
||||
"ui.agent_chat_edit": "编辑",
|
||||
"ui.agent_chat_ended_after": "{time} 后结束",
|
||||
"ui.agent_chat_exited": "智能体已停止。",
|
||||
"ui.agent_chat_failed_start": "智能体无法启动:{error}",
|
||||
"ui.agent_chat_file_cad_not_read": "{name}:CAD 文件会导入设计,而不是读取",
|
||||
@@ -5016,6 +5142,7 @@
|
||||
"ui.agent_chat_model_no_tools": "{model} 无法使用 SolidCraft 的工具,只能聊天。请选择支持工具的模型。",
|
||||
"ui.agent_chat_model_rejected": "智能体未接受 {model}:{error}",
|
||||
"ui.agent_chat_model_search": "搜索模型…",
|
||||
"ui.agent_chat_model_search_or_id": "搜索,或输入任意模型 ID…",
|
||||
"ui.agent_chat_model_tip": "智能体使用的模型。你的选择会为此智能体记住。",
|
||||
"ui.agent_chat_models_failed": "无法列出模型:{error}",
|
||||
"ui.agent_chat_models_heading": "可用模型",
|
||||
@@ -5027,6 +5154,7 @@
|
||||
"ui.agent_chat_next_picture": "下一张图片",
|
||||
"ui.agent_chat_no_cli": "在应用旁边未找到 solidcraft-cli,因此智能体无法访问设计。",
|
||||
"ui.agent_chat_no_control": "智能体聊天的端点未能启动,因此智能体无法访问设计。",
|
||||
"ui.agent_chat_no_design_hint": "代理在没有 SolidCraft 工具的情况下运行,因此无法读取或修改设计:在应用旁边找不到 solidcraft-cli。请安装附带 solidcraft-cli 的 SolidCraft(在 Windows 上为 MSI 或便携版 zip),或将 SOLIDCRAFT_CLI 设置为它的路径,然后重新连接。",
|
||||
"ui.agent_chat_no_images": "该智能体不接收图片",
|
||||
"ui.agent_chat_no_picture": "剪贴板上没有图片",
|
||||
"ui.agent_chat_no_tool_call": "模型没有使用 SolidCraft 的工具,因此设计没有更改。请选择支持工具调用的模型;参见智能体聊天指南中的“本地模型”。",
|
||||
@@ -5041,7 +5169,7 @@
|
||||
"ui.agent_chat_permission": "智能体请求运行:{title}",
|
||||
"ui.agent_chat_pick": "智能体",
|
||||
"ui.agent_chat_pick_context": "选择上下文",
|
||||
"ui.agent_chat_pick_context_tip": "在模型中选择要让智能体查看的面、边、特征和实体,然后点击确定",
|
||||
"ui.agent_chat_pick_context_tip": "在模型中选择面、边、特征和实体,然后点击确定:它们会作为标签放入消息中光标所在的位置(输入 @ 效果相同)",
|
||||
"ui.agent_chat_placeholder": "让智能体修改设计…",
|
||||
"ui.agent_chat_placeholder_busy": "输入消息,待智能体完成后发送(Ctrl+Enter:立即发送)",
|
||||
"ui.agent_chat_pop_out": "在独立窗口中打开(可移到另一个屏幕)",
|
||||
@@ -5073,16 +5201,26 @@
|
||||
"ui.agent_chat_setup_title": "设置助手",
|
||||
"ui.agent_chat_side": "停靠聊天",
|
||||
"ui.agent_chat_signed_in": "已登录",
|
||||
"ui.agent_chat_snap_none_found": "未找到编程代理。Snap 软件包运行在受限环境中,无法看到或启动此计算机上安装的编程代理。要使用它们,请改用 AppImage、.deb 或 .rpm 软件包安装 SolidCraft。使用 OpenAI 兼容 API 的代理在 Snap 软件包中同样可用:请通过“添加智能体”进行设置。",
|
||||
"ui.agent_chat_span_h": "{h} 小时 {min} 分钟",
|
||||
"ui.agent_chat_span_min": "{n} 分钟",
|
||||
"ui.agent_chat_span_s": "{n} 秒",
|
||||
"ui.agent_chat_state_auth": "需要登录",
|
||||
"ui.agent_chat_state_busy": "工作中…",
|
||||
"ui.agent_chat_state_exited": "智能体已停止",
|
||||
"ui.agent_chat_state_failed": "连接失败",
|
||||
"ui.agent_chat_state_no_design": "无法访问设计",
|
||||
"ui.agent_chat_state_off": "未连接",
|
||||
"ui.agent_chat_state_ready": "就绪",
|
||||
"ui.agent_chat_state_starting": "正在启动…",
|
||||
"ui.agent_chat_stop": "停止",
|
||||
"ui.agent_chat_stop_tip": "停止智能体及其启动的所有进程",
|
||||
"ui.agent_chat_stop_turn_tip": "停止智能体(Esc)。排队的消息仍保持排队。",
|
||||
"ui.agent_chat_thinking_for": "已思考 {time}",
|
||||
"ui.agent_chat_tool_running_for": "已运行 {time}",
|
||||
"ui.agent_chat_tools_not_started": "代理在没有 SolidCraft 工具的情况下运行,因此无法读取或修改设计:已找到 solidcraft-cli,但其工具未能启动(聊天中的错误信息说明了原因)。请重新连接;如果问题仍然出现,请重新安装 SolidCraft。",
|
||||
"ui.agent_chat_transcript_assistant": "助手:",
|
||||
"ui.agent_chat_transcript_user": "用户:",
|
||||
"ui.agent_chat_turn_limit": "每条消息的更改数",
|
||||
"ui.agent_chat_turn_unlimited": "不限",
|
||||
"ui.agent_chat_undo_changes": "撤销这些更改",
|
||||
@@ -5239,7 +5377,9 @@
|
||||
"ui.browser_bodies_one": "{count} 个实体",
|
||||
"ui.browser_bodies_other": "{count} 个实体",
|
||||
"ui.browser_collapse": "折叠浏览器",
|
||||
"ui.browser_collapse_below": "折叠下级",
|
||||
"ui.browser_expand": "展开浏览器",
|
||||
"ui.browser_expand_below": "展开下级",
|
||||
"ui.browser_title": "浏览器",
|
||||
"ui.calibrate": "校准",
|
||||
"ui.cancel": "取消",
|
||||
@@ -5269,6 +5409,7 @@
|
||||
"ui.collapse": "折叠",
|
||||
"ui.collinear": "共线",
|
||||
"ui.colour_vision": "色觉",
|
||||
"ui.colour_vision_bends": "折弯",
|
||||
"ui.colour_vision_deutan": "绿色觉异常(Deutan)",
|
||||
"ui.colour_vision_deutan_tip": "绿色感知较弱或缺失时使用",
|
||||
"ui.colour_vision_failed": "失败",
|
||||
@@ -5298,14 +5439,24 @@
|
||||
"ui.conic_curve": "圆锥曲线",
|
||||
"ui.constant": "恒定",
|
||||
"ui.constraints_conflict": "约束冲突",
|
||||
"ui.construct_auto.chosen": "已根据所选对象选定方法。添加或移除参照即可更换方法。",
|
||||
"ui.construct_auto.no_fit": "请选择其他参照:没有方法能由这些对象创建。",
|
||||
"ui.construct_auto.pick": "选择创建依据:方法由所选对象决定。",
|
||||
"ui.construct_auto.refs": "参照",
|
||||
"ui.construct_auto.select": "请先选择创建依据的参照",
|
||||
"ui.construct_axes": "轴",
|
||||
"ui.construct_planes": "平面",
|
||||
"ui.construct_points": "点",
|
||||
"ui.construction": "构造",
|
||||
"ui.construction.angle_hint": "构造直线:单击一点,然后输入角度或选择方向",
|
||||
"ui.construction.axis_hint": "构造直线:单击一点,或输入它到草图轴的距离",
|
||||
"ui.construction.bisector_hint": "角平分线:选择两条相交直线,再选择所需解",
|
||||
"ui.construction.common_hint": "公切线:选择两个圆/圆弧,再选择所需解",
|
||||
"ui.construction.contact_hint": "切线:先选圆/圆弧或开放样条曲线/圆锥曲线,再选接点(自由曲线仅支持端点)",
|
||||
"ui.construction.external_hint": "切线:依次选择圆或圆弧、外部点和所需解",
|
||||
"ui.construction.free_hint": "构造直线:单击两点;右键单击重新开始",
|
||||
"ui.construction.normal_needs_length": "无限直线始终是构造线:输入长度以绘制普通直线",
|
||||
"ui.construction.parallel_hint": "构造直线:先选直线,再单击或输入偏移;右键单击更换参照",
|
||||
"ui.construction.point_hint": "构造直线:单击要经过的点",
|
||||
"ui.construction.reference_hint": "构造直线:先选直线,再选一点;右键单击更换参照",
|
||||
"ui.construction.ribbon_label": "辅助线",
|
||||
@@ -5448,6 +5599,17 @@
|
||||
"ui.ellipse": "椭圆",
|
||||
"ui.emboss_wrap_note": "与受支持圆柱相切的正交线轮廓会自动缠绕。选择一个壁以指定目标。",
|
||||
"ui.end": "末端",
|
||||
"ui.end_cap.chamfer": "角部倒角",
|
||||
"ui.end_cap.direction": "方向",
|
||||
"ui.end_cap.faces": "端面",
|
||||
"ui.end_cap.inset": "内缩",
|
||||
"ui.end_cap.inset_kind": "内缩方式",
|
||||
"ui.end_cap.inset_ratio": "内缩比例",
|
||||
"ui.end_cap.inward": "向内",
|
||||
"ui.end_cap.length": "长度",
|
||||
"ui.end_cap.outward": "向外",
|
||||
"ui.end_cap.ratio": "厚度比例",
|
||||
"ui.end_cap_title": "端盖",
|
||||
"ui.end_radius": "结束半径",
|
||||
"ui.end_scale": "末端缩放",
|
||||
"ui.ends": "端部",
|
||||
@@ -5468,7 +5630,10 @@
|
||||
"ui.explode_needs_two_components": "爆炸图会将组件彼此分开,因此设计中需要两个或更多组件(新建组件、插入设计或由实体创建组件)",
|
||||
"ui.exportDxf": "导出 DXF…",
|
||||
"ui.export_ellipsis_keymap": "导出…",
|
||||
"ui.export_glb": "导出 GLB",
|
||||
"ui.export_keymap_tip": "将按键、S 框收藏和工具栏导出为文件",
|
||||
"ui.export_selects_only_body": "导出网格时选中唯一的实体",
|
||||
"ui.export_selects_only_body_tip": "设计只有一个实体时,导出 STL、导出 3MF 和发送到切片软件会在打开时选中该实体。",
|
||||
"ui.extend": "延伸",
|
||||
"ui.extent": "范围",
|
||||
"ui.extent_type": "延伸类型",
|
||||
@@ -5528,6 +5693,8 @@
|
||||
"ui.finest": "最精细",
|
||||
"ui.finish_sketch": "完成草图",
|
||||
"ui.first_dimension_scales": "第一个尺寸缩放整个图形",
|
||||
"ui.first_dimension_scales_about_origin": "以草图原点为中心缩放",
|
||||
"ui.first_dimension_scales_about_origin_tip": "开启:图形总是以草图原点为中心放大或缩小,因此远离原点绘制的形状会移动。关闭:未与原点关联的图形以其自身中心缩放,并保持在绘制的位置。",
|
||||
"ui.first_dimension_scales_tip": "开启:草图的第一个长度尺寸会缩放它所测量的图形,保持其形状不变。关闭:尺寸只改变所测量对象的大小。",
|
||||
"ui.fit": "适合",
|
||||
"ui.fix_unfix": "固定/取消固定",
|
||||
@@ -5950,6 +6117,7 @@
|
||||
"ui.project_references_construction_note": "投影、相交、包含三维几何以及在面上新建草图时投影的面边,都会生成构造几何:用于绘图参考,不计入轮廓。它们仍与模型保持关联。",
|
||||
"ui.properties": "属性",
|
||||
"ui.properties.copy_matrix": "复制矩阵",
|
||||
"ui.properties.copy_value": "点击复制",
|
||||
"ui.properties.first_moments": "一阶矩",
|
||||
"ui.properties.inertia": "转动惯量",
|
||||
"ui.properties.inertia_note": "相对质心,世界坐标轴 (g·{unit}²)",
|
||||
@@ -5962,6 +6130,7 @@
|
||||
"ui.properties.measuring_failed": "测量在完成前已停止。",
|
||||
"ui.properties.principal_axis": "主轴 {number}",
|
||||
"ui.properties.principal_moments": "主惯性矩",
|
||||
"ui.properties.value_copied": "已复制数值",
|
||||
"ui.pull_direction": "拔模方向",
|
||||
"ui.quality": "质量",
|
||||
"ui.quantity": "数量",
|
||||
@@ -5982,11 +6151,14 @@
|
||||
"ui.relink_design_changed": "选择源文件时装配已更改。请重新开始链接。",
|
||||
"ui.relink_done": "已为所有实例重新链接源文件。",
|
||||
"ui.relink_not_linked": "此组件未链接到源设计。",
|
||||
"ui.relink_one_done": "已为此实例重新链接源文件。",
|
||||
"ui.relink_select_one": "请先选择一个链接组件或其实例。",
|
||||
"ui.relink_source_all": "重新链接源文件(所有实例)…",
|
||||
"ui.relink_source_one": "重新链接源文件…",
|
||||
"ui.removeFromQuickAccess": "从快速访问中移除",
|
||||
"ui.removeFromToolbar": "从工具栏移除",
|
||||
"ui.removeSection": "移除剖面",
|
||||
"ui.renameSelectedBodies": "重命名所选实体",
|
||||
"ui.render": "渲染",
|
||||
"ui.renderer": "渲染器",
|
||||
"ui.repeat": "重复",
|
||||
@@ -6017,6 +6189,8 @@
|
||||
"ui.ribbon_pin_footer": "固定的命令显示在功能区中。将指针悬停在行上可固定或取消固定。",
|
||||
"ui.ribbon_workspace": "工作区",
|
||||
"ui.right": "右视",
|
||||
"ui.right_click_confirms": "右键确认对话框输入",
|
||||
"ui.right_click_confirms_tip": "对话框打开时,在视图中右键单击会转到下一个空输入,在最后一个输入上执行 OK",
|
||||
"ui.save": "保存",
|
||||
"ui.save_as": "另存为",
|
||||
"ui.save_mesh_no_slicer_open": "未找到切片软件:请选择“自定义…”并指定切片软件程序",
|
||||
@@ -6076,6 +6250,16 @@
|
||||
"ui.sketch_intersect_selection_filter": "选择过滤器",
|
||||
"ui.sketch_keys_only": "草图中不使用模型快捷键",
|
||||
"ui.sketch_keys_only_tip": "编辑草图时,只有草图快捷键和在任何地方都可用的快捷键会生效;E 或 F 等模型快捷键不起作用,因此误按的按键不会关闭复杂的草图。",
|
||||
"ui.sketch_links_added_curve": "{command} 已向草图添加 1 条曲线。",
|
||||
"ui.sketch_links_added_curves": "{command} 已向草图添加 {count} 条曲线。",
|
||||
"ui.sketch_links_added_curves_and_points": "{command} 已向草图添加{curves}和{points}。",
|
||||
"ui.sketch_links_added_point": "{command} 已向草图添加 1 个点。",
|
||||
"ui.sketch_links_added_points": "{command} 已向草图添加 {count} 个点。",
|
||||
"ui.sketch_links_curve_count": "{count} 条曲线",
|
||||
"ui.sketch_links_curve_count_one": "1 条曲线",
|
||||
"ui.sketch_links_hidden": "结果已隐藏,因为草图选项中的“{option}”已关闭。",
|
||||
"ui.sketch_links_point_count": "{count} 个点",
|
||||
"ui.sketch_links_point_count_one": "1 个点",
|
||||
"ui.sketch_modifiers": "草图修饰键",
|
||||
"ui.sketch_project_geometry": "几何体",
|
||||
"ui.sketch_report.all_constrained": "全部已完全约束。",
|
||||
@@ -6115,6 +6299,7 @@
|
||||
"ui.step_values": "使用箭头和滚轮调整数值",
|
||||
"ui.step_values_tip": "在数值字段上使用上/下箭头或滚轮可更改数值。",
|
||||
"ui.stitch_tolerance_hint": "严格",
|
||||
"ui.straighten": "拉直",
|
||||
"ui.stretch": "伸展",
|
||||
"ui.supersampling": "超级采样 (SSAA)",
|
||||
"ui.supersampling_adaptive": "仅在视图静止时",
|
||||
@@ -6188,6 +6373,8 @@
|
||||
"ui.view_angles_yaw": "偏航",
|
||||
"ui.view_angles_zero": "将{axis}设为 0°",
|
||||
"ui.view_centre": "视图中心",
|
||||
"ui.view_compass_tip": "从 {axis} 方向查看。再次单击可反向。拖动可环绕。",
|
||||
"ui.view_compass_tip_snap": "从 {axis} 方向查看。再次单击可反向。拖动可环绕;按住 Shift 可吸附。",
|
||||
"ui.viewport_status_clear": "关闭{name}",
|
||||
"ui.viewport_status_clear_hint": "关闭{name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} 条边",
|
||||
|
||||
@@ -23,7 +23,7 @@ from pathlib import Path
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
FONTS = HERE.parents[2] / "fonts"
|
||||
FONTS = HERE.parents[3] / "crates/look/fonts"
|
||||
LAYOUT = json.loads((HERE / "layout.json").read_text())
|
||||
W, H = LAYOUT["window"]
|
||||
ICON = LAYOUT["icon_size"]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
| assets/locales/lv.json | SolidCraft contributors | Original Latvian translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
|
||||
@@ -0,0 +1,118 @@
|
||||
//! Where a control request is, so the connection that sent it can cancel it (`control.cancel`,
|
||||
//! #1989): shared between the window, which moves it along, and the connection. Whoever changes
|
||||
//! it first wins.
|
||||
|
||||
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||
use std::sync::{Mutex, PoisonError};
|
||||
|
||||
/// A request's place in the app, and how to stop the work computing it.
|
||||
#[derive(Default)]
|
||||
pub struct Ticket {
|
||||
state: AtomicU8,
|
||||
/// It is an export computing on a copy, whose worker writes its file.
|
||||
writes_file: AtomicBool,
|
||||
/// Tells its worker to stop: set by the window when it hands the request to one.
|
||||
stopper: Mutex<Option<Box<dyn Fn() + Send + Sync>>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Ticket {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Ticket").field("state", &self.state).field("writes_file", &self.writes_file).finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
/// Waiting its turn (sent, or held behind another request).
|
||||
const WAITING: u8 = 0;
|
||||
/// Running on the window thread (or handed to something that can't stop it, such as the file
|
||||
/// loader).
|
||||
const RUNNING: u8 = 1;
|
||||
/// Computing off the window thread.
|
||||
const COMPUTING: u8 = 2;
|
||||
const CANCELLED: u8 = 3;
|
||||
|
||||
/// What [`Ticket::cancel`] did.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Cancel {
|
||||
/// It was waiting its turn: it will not run.
|
||||
Removed,
|
||||
/// It was computing off the window thread: it is answered as stopped and nothing of it is
|
||||
/// applied. An export's worker may still write its file.
|
||||
Stopped { writes_file: bool },
|
||||
/// It runs on the window thread: it will finish.
|
||||
Running,
|
||||
/// It was cancelled or stopped before.
|
||||
Already,
|
||||
}
|
||||
|
||||
impl Ticket {
|
||||
/// Cancel the request, unless it already runs on the window thread.
|
||||
pub fn cancel(&self) -> Cancel {
|
||||
let mut state = self.state.load(Ordering::Acquire);
|
||||
loop {
|
||||
let done = match state {
|
||||
WAITING => Cancel::Removed,
|
||||
COMPUTING => Cancel::Stopped { writes_file: self.writes_file.load(Ordering::Acquire) },
|
||||
CANCELLED => return Cancel::Already,
|
||||
_ => return Cancel::Running,
|
||||
};
|
||||
match self.state.compare_exchange(state, CANCELLED, Ordering::AcqRel, Ordering::Acquire) {
|
||||
Ok(_) => {
|
||||
self.stop_worker();
|
||||
return done;
|
||||
}
|
||||
Err(now) => state = now,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_cancelled(&self) -> bool {
|
||||
self.state.load(Ordering::Acquire) == CANCELLED
|
||||
}
|
||||
|
||||
/// The window takes the request to run it: false when it was cancelled.
|
||||
pub fn take(&self) -> bool {
|
||||
self.moves(WAITING, RUNNING)
|
||||
}
|
||||
|
||||
/// The work computing it stops on `stop` (a worker's own stop flag). Cancelled already, it is
|
||||
/// stopped at once.
|
||||
pub fn on_stop(&self, stop: impl Fn() + Send + Sync + 'static) {
|
||||
*self.stopper.lock().unwrap_or_else(PoisonError::into_inner) = Some(Box::new(stop));
|
||||
if self.is_cancelled() {
|
||||
self.stop_worker();
|
||||
}
|
||||
}
|
||||
|
||||
/// The window hands it to a worker (`writes_file`: an export on a copy).
|
||||
pub fn computing(&self, writes_file: bool) {
|
||||
self.writes_file.store(writes_file, Ordering::Release);
|
||||
let _ = self.moves(RUNNING, COMPUTING) || self.moves(WAITING, COMPUTING);
|
||||
}
|
||||
|
||||
/// Its worker is done and it runs on the window thread now (or it never left): false when it
|
||||
/// was cancelled meanwhile. Only the window moves it on from running, so running stays running.
|
||||
pub fn back(&self) -> bool {
|
||||
self.moves(COMPUTING, RUNNING) || self.state.load(Ordering::Acquire) == RUNNING
|
||||
}
|
||||
|
||||
/// Computed, but it waits its turn again (a file opening meanwhile): false when cancelled.
|
||||
pub fn wait_again(&self) -> bool {
|
||||
self.moves(COMPUTING, WAITING)
|
||||
}
|
||||
|
||||
/// The person at the app stopped it (Stop): its worker stops too.
|
||||
pub fn stop(&self) {
|
||||
self.state.store(CANCELLED, Ordering::Release);
|
||||
self.stop_worker();
|
||||
}
|
||||
|
||||
fn stop_worker(&self) {
|
||||
if let Some(stop) = self.stopper.lock().unwrap_or_else(PoisonError::into_inner).as_ref() {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
fn moves(&self, from: u8, to: u8) -> bool {
|
||||
self.state.compare_exchange(from, to, Ordering::AcqRel, Ordering::Acquire).is_ok()
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,12 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod auth;
|
||||
mod cancel;
|
||||
mod effect;
|
||||
mod request;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod server;
|
||||
|
||||
pub use cancel::{Cancel, Ticket};
|
||||
pub use effect::Effect;
|
||||
pub use request::{ControlRequest, ControlResponse, DOCUMENT_WATCH, DocumentWatch, Subscriber, cancelled_chat_response, chat_turn_cancelled};
|
||||
|
||||
@@ -18,12 +18,15 @@ pub struct ControlRequest {
|
||||
/// Chat requests already admitted by the gate may outlive a tab switch. This turn's
|
||||
/// validity follows them through queues, computation and cursor animation.
|
||||
pub chat_turn: Option<std::sync::Arc<std::sync::atomic::AtomicBool>>,
|
||||
/// Where the request is, shared with the connection that sent it so it can cancel it
|
||||
/// (`control.cancel`, #1989).
|
||||
pub ticket: std::sync::Arc<crate::Ticket>,
|
||||
}
|
||||
|
||||
impl ControlRequest {
|
||||
pub fn new(method: impl Into<String>, params: Value) -> (Self, std::sync::mpsc::Receiver<ControlResponse>) {
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
(Self { method: method.into(), params, reply: tx, started: Default::default(), chat_turn: None }, rx)
|
||||
(Self { method: method.into(), params, reply: tx, started: Default::default(), chat_turn: None, ticket: Default::default() }, rx)
|
||||
}
|
||||
|
||||
/// Answer a request whose agent chat turn has ended, and say so: such a request is not run.
|
||||
|
||||
+287
-11
@@ -14,6 +14,7 @@ use serde_json::{Value, json};
|
||||
|
||||
use crate::Effect;
|
||||
use crate::auth::tokens_match;
|
||||
use crate::cancel::{Cancel, Ticket};
|
||||
use crate::request::{ControlRequest, DOCUMENT_WATCH, DocumentWatch, Subscriber};
|
||||
|
||||
/// What the server needs to know of a request before it sends it to the window: how to name it
|
||||
@@ -94,28 +95,104 @@ impl Hub {
|
||||
/// on it). A listener that is not on a loopback address is refused: the channel never goes on
|
||||
/// the network.
|
||||
pub fn listen(self: &Arc<Self>, listener: TcpListener, token: String, requests: Sender<ControlRequest>, patient: bool) -> std::io::Result<()> {
|
||||
self.listen_stoppable(listener, token, requests, patient).map(drop)
|
||||
}
|
||||
|
||||
/// [`Hub::listen`], and a [`Stop`] that closes the listener and the connections it accepted
|
||||
/// (a channel turned off in the app's settings). Dropping the [`Stop`] leaves it serving.
|
||||
pub fn listen_stoppable(
|
||||
self: &Arc<Self>,
|
||||
listener: TcpListener,
|
||||
token: String,
|
||||
requests: Sender<ControlRequest>,
|
||||
patient: bool,
|
||||
) -> std::io::Result<Stop> {
|
||||
let addr = listener.local_addr()?;
|
||||
if !addr.ip().is_loopback() {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("the control channel listens on loopback only, not {addr}")));
|
||||
}
|
||||
let hub = Arc::clone(self);
|
||||
let token = Arc::new(token);
|
||||
let shared = Arc::new(Accepted::default());
|
||||
let (closed_tx, closed) = channel::<()>();
|
||||
let stop = Stop { addr, shared: Arc::clone(&shared), closed };
|
||||
std::thread::spawn(move || {
|
||||
// Dropped when this thread ends, with the listener: `Stop::stop` waits for that.
|
||||
let _closed = closed_tx;
|
||||
for stream in listener.incoming().flatten() {
|
||||
if shared.stopped.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
if hub.open.fetch_add(1, Ordering::Relaxed) >= MAX_CONNECTIONS {
|
||||
hub.open.fetch_sub(1, Ordering::Relaxed);
|
||||
let mut refused = stream;
|
||||
let _ = send(&mut refused, &json!({"ok": false, "error": "too many connections"}));
|
||||
continue;
|
||||
}
|
||||
let (hub, tx, token) = (Arc::clone(&hub), requests.clone(), Arc::clone(&token));
|
||||
let id = shared.next.fetch_add(1, Ordering::Relaxed);
|
||||
if let Ok(copy) = stream.try_clone() {
|
||||
shared.lock().push((id, copy));
|
||||
}
|
||||
// Stopped while this one was being accepted: it is closed with the rest.
|
||||
if shared.stopped.load(Ordering::SeqCst) {
|
||||
shared.close_all();
|
||||
}
|
||||
let (hub, tx, token, shared) = (Arc::clone(&hub), requests.clone(), Arc::clone(&token), Arc::clone(&shared));
|
||||
std::thread::spawn(move || {
|
||||
hub.serve(stream, &token, tx, patient);
|
||||
hub.open.fetch_sub(1, Ordering::Relaxed);
|
||||
shared.lock().retain(|(i, _)| *i != id);
|
||||
});
|
||||
}
|
||||
// A captured value drops after the body's locals, so without this `_closed` would tell
|
||||
// `Stop::stop` the port is free while the listener still holds it (#14752).
|
||||
drop(listener);
|
||||
});
|
||||
Ok(())
|
||||
Ok(stop)
|
||||
}
|
||||
}
|
||||
|
||||
/// The connections a stoppable listener accepted, so stopping it can close them too.
|
||||
#[derive(Default)]
|
||||
struct Accepted {
|
||||
stopped: AtomicBool,
|
||||
next: AtomicU64,
|
||||
streams: Mutex<Vec<(u64, TcpStream)>>,
|
||||
}
|
||||
|
||||
impl Accepted {
|
||||
fn lock(&self) -> MutexGuard<'_, Vec<(u64, TcpStream)>> {
|
||||
self.streams.lock().unwrap_or_else(PoisonError::into_inner)
|
||||
}
|
||||
|
||||
fn close_all(&self) {
|
||||
for (_, stream) in self.lock().drain(..) {
|
||||
let _ = stream.shutdown(std::net::Shutdown::Both);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stops a listener started with [`Hub::listen_stoppable`].
|
||||
pub struct Stop {
|
||||
addr: std::net::SocketAddr,
|
||||
shared: Arc<Accepted>,
|
||||
closed: Receiver<()>,
|
||||
}
|
||||
|
||||
impl Stop {
|
||||
/// The port the listener is on.
|
||||
pub fn port(&self) -> u16 {
|
||||
self.addr.port()
|
||||
}
|
||||
|
||||
/// Stop accepting, close the port and end every connection it accepted. Returns once the
|
||||
/// port is closed (at most a couple of seconds), so the same port can be bound again at once.
|
||||
pub fn stop(self) {
|
||||
self.shared.stopped.store(true, Ordering::SeqCst);
|
||||
// The listener waits in `accept`: a connection of our own wakes it to see the flag.
|
||||
let _ = TcpStream::connect_timeout(&self.addr, Duration::from_secs(1));
|
||||
let _ = self.closed.recv_timeout(Duration::from_secs(2));
|
||||
self.shared.close_all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,6 +354,62 @@ struct Pending {
|
||||
/// The request in messages ("`engine.execute` (solid.fillet)").
|
||||
what: String,
|
||||
reply: Receiver<Value>,
|
||||
/// Where it is in the app, to cancel it (`control.cancel`).
|
||||
job: Arc<Ticket>,
|
||||
}
|
||||
|
||||
/// `control.cancel {id?}`: cancel the request this connection still waits for (the one
|
||||
/// `control.pending` reports; `id`, when given, must name it). A connection can only cancel its
|
||||
/// own requests. Waiting its turn, it is removed; computing off the window thread, it is stopped
|
||||
/// as the app's Stop stops it. Either way nothing of it is applied and the connection is free.
|
||||
/// One that runs on the window thread can't be cancelled; one that finished is answered.
|
||||
fn cancel(pending: &mut Option<Pending>, late: Option<Value>, id: Option<&Value>, document: &str) -> Value {
|
||||
let id = id.filter(|v| !v.is_null());
|
||||
let mine = pending.as_ref().filter(|p| id.is_none_or(|id| *id == p.id));
|
||||
let Some(p) = mine else {
|
||||
return match id {
|
||||
None => json!({"ok": true, "result": {"cancelled": null, "note": "nothing to cancel: no request of this connection is running"}}),
|
||||
Some(id) => json!({"ok": false, "error": format!(
|
||||
"nothing to cancel: request {} is not running on this connection (a connection can only cancel its own requests)",
|
||||
id.to_string().chars().take(64).collect::<String>()
|
||||
)}),
|
||||
};
|
||||
};
|
||||
let (what, id) = (format!("request {} ({})", p.id, p.what), p.id.clone());
|
||||
let finished = |p: Pending, reply: Value| {
|
||||
json!({"ok": true, "result": {"cancelled": null, "pending": p.id, "method": p.method, "done": true, "reply": reply,
|
||||
"note": format!("nothing to cancel: {what} had already finished; its reply is here")}})
|
||||
};
|
||||
if let Some(reply) = late {
|
||||
return pending.take().map_or(Value::Null, |p| finished(p, reply));
|
||||
}
|
||||
let outcome = p.job.cancel();
|
||||
let note = match outcome {
|
||||
Cancel::Removed => format!("cancelled: {what} was still waiting its turn and will not run; nothing was applied"),
|
||||
Cancel::Stopped { writes_file: false } => format!("stopped: {what} was computing off the window thread; nothing was applied"),
|
||||
Cancel::Stopped { writes_file: true } => {
|
||||
format!("stopped: {what} was computing on a copy of the {document}, which is unchanged; its worker may still write the file")
|
||||
}
|
||||
Cancel::Already => format!("{what} was already cancelled or stopped; nothing of it was applied"),
|
||||
Cancel::Running => {
|
||||
// It may have just finished.
|
||||
if let Some(reply) = pending.as_ref().and_then(|p| p.reply.try_recv().ok()) {
|
||||
return pending.take().map_or(Value::Null, |p| finished(p, reply));
|
||||
}
|
||||
return json!({"ok": false, "cancellable": false, "error": format!(
|
||||
"cannot be cancelled: {what} already runs in the app (on its window thread, or as a file it opens) and will \
|
||||
still finish; ask `control.pending` for its result. Only a request still waiting its turn, or a change or \
|
||||
export computing off the window thread, can be cancelled"
|
||||
)});
|
||||
}
|
||||
};
|
||||
let method = pending.take().map(|p| p.method);
|
||||
let how = match outcome {
|
||||
Cancel::Removed => "removed",
|
||||
Cancel::Stopped { .. } => "stopped",
|
||||
_ => "already",
|
||||
};
|
||||
json!({"ok": true, "result": {"cancelled": id, "method": method, "outcome": how, "note": note}})
|
||||
}
|
||||
|
||||
/// Every request the app has been sent and not answered yet, from every connection, for
|
||||
@@ -311,7 +444,7 @@ impl Running {
|
||||
|
||||
/// List `req`, sent on `connection`, until the returned ticket is dropped; `command` and
|
||||
/// `steps` as the app's [`Protocol`] summarised it.
|
||||
fn add(self: &Arc<Self>, connection: u64, id: &Value, req: &ControlRequest, command: Option<&'static str>, steps: Option<usize>) -> Ticket {
|
||||
fn add(self: &Arc<Self>, connection: u64, id: &Value, req: &ControlRequest, command: Option<&'static str>, steps: Option<usize>) -> Listing {
|
||||
let key = self.keys.fetch_add(1, Ordering::Relaxed);
|
||||
// Ids and methods come from the client: only short ones are repeated to the others.
|
||||
let id = match id {
|
||||
@@ -322,7 +455,7 @@ impl Running {
|
||||
let method = req.method.chars().take(64).collect();
|
||||
let started = req.started.clone();
|
||||
self.lock().push(InFlight { key, connection, id, method, command, steps, since: Instant::now(), started });
|
||||
Ticket { running: Arc::clone(self), key }
|
||||
Listing { running: Arc::clone(self), key }
|
||||
}
|
||||
|
||||
/// The `control.running` result, as `asker`'s connection sees it.
|
||||
@@ -355,12 +488,12 @@ impl Running {
|
||||
}
|
||||
|
||||
/// A listed request; dropped when its reply arrives.
|
||||
struct Ticket {
|
||||
struct Listing {
|
||||
running: Arc<Running>,
|
||||
key: u64,
|
||||
}
|
||||
|
||||
impl Drop for Ticket {
|
||||
impl Drop for Listing {
|
||||
fn drop(&mut self) {
|
||||
let key = self.key;
|
||||
self.running.lock().retain(|e| e.key != key);
|
||||
@@ -369,7 +502,7 @@ impl Drop for Ticket {
|
||||
|
||||
/// The reply to a timed-out request, received on a thread of its own so the request stays listed
|
||||
/// until the app answers, also once its connection has closed (#3654).
|
||||
fn watch(reply: Receiver<Value>, ticket: Ticket) -> Receiver<Value> {
|
||||
fn watch(reply: Receiver<Value>, ticket: Listing) -> Receiver<Value> {
|
||||
let (late_tx, late_rx) = channel();
|
||||
// A small thread per timed-out request (each connection has at most one). If none can be
|
||||
// made, the reply is lost and `control.pending` says the app ended the request without one.
|
||||
@@ -395,11 +528,12 @@ pub fn timeout_message(what: &str, effect: Effect, document: &str) -> String {
|
||||
}
|
||||
Effect::WritesFile => format!(
|
||||
"timeout: {what} is still running in the app and will still write the file when it finishes (it was not cancelled: \
|
||||
don't send it again; the {document} does not change); ask `control.pending` for its result"
|
||||
don't send it again; the {document} does not change); ask `control.pending` for its result, or `control.cancel` to \
|
||||
cancel it"
|
||||
),
|
||||
Effect::Changes => format!(
|
||||
"timeout: {what} is still running in the app and will still apply when it finishes (it was not cancelled: don't send it \
|
||||
again); ask `control.pending` for its result"
|
||||
again); ask `control.pending` for its result, or `control.cancel` to cancel it"
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -597,6 +731,10 @@ impl Hub {
|
||||
json!({"ok": true, "result": running.result(connection)})
|
||||
} else if method == "control.capabilities" {
|
||||
json!({"ok": true, "result": self.protocol.capabilities()})
|
||||
} else if method == "control.cancel" {
|
||||
let r = cancel(&mut pending, late, params.get("id"), self.protocol.document());
|
||||
(self.wake)();
|
||||
r
|
||||
} else if method == "control.pending" {
|
||||
match (pending.take(), late) {
|
||||
(None, _) => json!({"ok": true, "result": {"pending": null}}),
|
||||
@@ -636,6 +774,7 @@ impl Hub {
|
||||
// answer on.
|
||||
joining = (method == "control.subscribe").then(|| documents.join());
|
||||
let (req, rrx) = ControlRequest::new(method.clone(), params);
|
||||
let job = Arc::clone(&req.ticket);
|
||||
let ticket = running.add(connection, &id, &req, command, steps);
|
||||
if tx.send(req).is_err() {
|
||||
break;
|
||||
@@ -645,7 +784,7 @@ impl Hub {
|
||||
Ok(r) => r,
|
||||
Err(_) => {
|
||||
let r = json!({"ok": false, "running": true, "error": timeout_message(&what, effect, self.protocol.document())});
|
||||
pending = Some(Pending { id: id.clone(), method, what, reply: watch(rrx, ticket) });
|
||||
pending = Some(Pending { id: id.clone(), method, what, reply: watch(rrx, ticket), job });
|
||||
r
|
||||
}
|
||||
}
|
||||
@@ -661,7 +800,7 @@ impl Hub {
|
||||
}
|
||||
};
|
||||
// Subscribed once the window named the design (not when it refused or timed out).
|
||||
let sent = match joining.and_then(|counted| document_of(&reply).map(|seen| (counted, seen))) {
|
||||
let sent = match joining.zip(document_of(&reply)) {
|
||||
Some((counted, seen)) => match Subscription::start(documents, self.protocol.change_event(), counted, &out, seen, &reply) {
|
||||
Some((subscription, sent)) => {
|
||||
events = Some(subscription);
|
||||
@@ -807,6 +946,104 @@ mod tests {
|
||||
assert!(l.contains("unauthorized"), "{l}");
|
||||
}
|
||||
|
||||
/// #1989: `control.cancel` cancels the connection's own outstanding request. One still
|
||||
/// waiting its turn is removed and never runs, and the connection is free at once; one that
|
||||
/// already runs in the app can't be, and says so; another connection's request is refused;
|
||||
/// with nothing outstanding there is nothing to cancel.
|
||||
#[test]
|
||||
fn control_cancel_cancels_only_this_connections_request() {
|
||||
let token = "0123456789abcdef0123456789abcdef";
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
let (tx, rx) = channel::<ControlRequest>();
|
||||
let (gate_tx, gate_rx) = channel::<()>();
|
||||
let ran = std::sync::Arc::new(std::sync::Mutex::new(Vec::<String>::new()));
|
||||
let seen = ran.clone();
|
||||
// A stand-in for the window thread: `queued` waits behind the others (never taken until
|
||||
// `slow` is done), `slow` runs until the gate opens.
|
||||
std::thread::spawn(move || {
|
||||
let mut held = Vec::new();
|
||||
for req in rx {
|
||||
if req.method == "queued" {
|
||||
held.push(req);
|
||||
continue;
|
||||
}
|
||||
if !req.ticket.take() {
|
||||
continue;
|
||||
}
|
||||
seen.lock().unwrap().push(req.method.clone());
|
||||
if req.method == "slow" {
|
||||
let _ = gate_rx.recv();
|
||||
}
|
||||
let _ = req.reply.send(json!({"ok": true, "result": req.method}));
|
||||
if req.method == "slow" {
|
||||
for req in held.drain(..) {
|
||||
if req.ticket.take() {
|
||||
seen.lock().unwrap().push(req.method.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let waits = Waits { short: Duration::from_millis(100), long: Duration::from_millis(100), token: TOKEN_WAIT };
|
||||
let hub = hub(waits, &DOCUMENT_WATCH);
|
||||
std::thread::spawn(move || {
|
||||
for stream in listener.incoming().flatten() {
|
||||
let (tx, hub) = (tx.clone(), Arc::clone(&hub));
|
||||
std::thread::spawn(move || hub.serve(stream, token, tx, false));
|
||||
}
|
||||
});
|
||||
let connect = || {
|
||||
let s = TcpStream::connect(addr).unwrap();
|
||||
s.set_read_timeout(Some(Duration::from_secs(10))).unwrap();
|
||||
let out = s.try_clone().unwrap();
|
||||
(out, BufReader::new(s))
|
||||
};
|
||||
let ask = |(out, lines): &mut (TcpStream, BufReader<TcpStream>), v: Value| -> Value {
|
||||
writeln!(out, "{v}").unwrap();
|
||||
let mut l = String::new();
|
||||
lines.read_line(&mut l).unwrap();
|
||||
serde_json::from_str(&l).unwrap()
|
||||
};
|
||||
let mut a = connect();
|
||||
let mut b = connect();
|
||||
let r = ask(&mut b, json!({"id": 1, "method": "control.cancel", "token": token}));
|
||||
assert!(r["ok"] == true && r["result"]["cancelled"].is_null(), "nothing to cancel: {r}");
|
||||
|
||||
// Waiting its turn: removed, never run, and the connection is free.
|
||||
let r = ask(&mut a, json!({"id": 1, "method": "queued", "token": token}));
|
||||
assert_eq!(r["running"], true, "{r}");
|
||||
let r = ask(&mut a, json!({"id": 2, "method": "control.cancel", "params": {"id": 1}}));
|
||||
assert_eq!((&r["ok"], &r["result"]["cancelled"], &r["result"]["outcome"]), (&json!(true), &json!(1), &json!("removed")), "{r}");
|
||||
assert!(r["result"]["note"].as_str().is_some_and(|n| n.contains("will not run")), "{r}");
|
||||
let r = ask(&mut a, json!({"id": 3, "method": "control.pending"}));
|
||||
assert_eq!(r["result"]["pending"], Value::Null, "{r}");
|
||||
|
||||
// Already running in the app: it can't be, and it still answers.
|
||||
let r = ask(&mut a, json!({"id": 4, "method": "slow"}));
|
||||
assert_eq!(r["running"], true, "{r}");
|
||||
let r = ask(&mut b, json!({"id": 2, "method": "control.cancel", "params": {"id": 4}}));
|
||||
assert!(r["ok"] == false && r["error"].as_str().is_some_and(|e| e.contains("its own requests")), "another connection's: {r}");
|
||||
let r = ask(&mut a, json!({"id": 5, "method": "control.cancel", "params": {"id": 99}}));
|
||||
assert!(r["ok"] == false && r["error"].as_str().is_some_and(|e| e.starts_with("nothing to cancel")), "{r}");
|
||||
let r = ask(&mut a, json!({"id": 6, "method": "control.cancel"}));
|
||||
assert!(r["ok"] == false && r["cancellable"] == false, "{r}");
|
||||
assert!(r["error"].as_str().is_some_and(|e| e.starts_with("cannot be cancelled") && e.contains("control.pending")), "{r}");
|
||||
gate_tx.send(()).unwrap();
|
||||
let deadline = Instant::now() + Duration::from_secs(10);
|
||||
let r = loop {
|
||||
let r = ask(&mut a, json!({"id": 7, "method": "control.pending"}));
|
||||
if r["result"]["done"] == true || Instant::now() > deadline {
|
||||
break r;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
};
|
||||
assert_eq!(r["result"]["reply"]["result"], "slow", "{r}");
|
||||
let r = ask(&mut a, json!({"id": 8, "method": "control.cancel"}));
|
||||
assert!(r["ok"] == true && r["result"]["cancelled"].is_null(), "{r}");
|
||||
assert_eq!(*ran.lock().unwrap(), ["slow"], "the cancelled request never ran");
|
||||
}
|
||||
|
||||
/// #1618: a request that outlasts its wait says it is still running; the connection keeps its
|
||||
/// reply for `control.pending`, and refuses other requests as `busy` until it lands, so none
|
||||
/// is queued to run unseen behind it.
|
||||
@@ -1154,4 +1391,43 @@ mod tests {
|
||||
assert_eq!(out.bytes.last(), Some(&b'\n'));
|
||||
assert_eq!(serde_json::from_slice::<Value>(&out.bytes).unwrap(), reply);
|
||||
}
|
||||
|
||||
/// A stopped listener frees its port at once and ends the connections it had, so a channel
|
||||
/// turned off in the settings leaves nothing listening and can be turned on again on the
|
||||
/// same port.
|
||||
#[test]
|
||||
fn a_stopped_listener_closes_its_port_and_its_connections() {
|
||||
use std::io::Read;
|
||||
let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap();
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
let (tx, _rx) = channel();
|
||||
let stop = hub(Waits::default(), &DOCUMENT_WATCH).listen_stoppable(listener, "0123456789abcdef0123456789abcdef".into(), tx, false).unwrap();
|
||||
assert_eq!(stop.port(), port);
|
||||
let mut client = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
||||
client.set_read_timeout(Some(Duration::from_secs(4))).unwrap();
|
||||
// Wait until the server holds the connection, so stopping has one to close.
|
||||
let held = Instant::now();
|
||||
while stop.shared.lock().is_empty() && held.elapsed() < Duration::from_secs(4) {
|
||||
std::thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
let started = Instant::now();
|
||||
stop.stop();
|
||||
let mut byte = [0u8; 1];
|
||||
match client.read(&mut byte) {
|
||||
Ok(n) => assert_eq!(n, 0, "the connection ends"),
|
||||
Err(e) => {
|
||||
assert!(!matches!(e.kind(), std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut), "the connection ends, not waits: {e}")
|
||||
}
|
||||
}
|
||||
assert!(started.elapsed() < Duration::from_secs(3), "before the token wait runs out");
|
||||
// The listener thread closes its socket when it notices the stop; on a loaded machine that can
|
||||
// take a moment after `stop()` returns. Wait for the port to be free, not for one instant.
|
||||
let freed = Instant::now();
|
||||
let mut bound = TcpListener::bind(("127.0.0.1", port));
|
||||
while bound.is_err() && freed.elapsed() < Duration::from_secs(2) {
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
bound = TcpListener::bind(("127.0.0.1", port));
|
||||
}
|
||||
assert!(bound.is_ok(), "the port is free again: {:?}", bound.err());
|
||||
}
|
||||
}
|
||||
|
||||
+120
-16
@@ -47,9 +47,41 @@ fn opaque() -> f64 {
|
||||
1.0
|
||||
}
|
||||
|
||||
/// The name a colour picked or typed in gets: no library entry's, no file's.
|
||||
pub const CUSTOM: &str = "Custom";
|
||||
|
||||
/// The name of a colour a file gave without a name: `Custom(R,G,B)` when it is opaque, else
|
||||
/// `Custom(R,G,B,opacity)`, the opacity to two decimals with at least one shown
|
||||
/// (`Custom(196,199,204)`, `Custom(210,226,240,0.35)`), so the same colour always reads the same.
|
||||
pub fn unnamed_colour(color: [u8; 3], opacity: f64) -> String {
|
||||
let hundredths = (if opacity.is_finite() { opacity.clamp(0.0, 1.0) } else { 1.0 } * 100.0).round() as u32;
|
||||
let [r, g, b] = color;
|
||||
if hundredths == 100 {
|
||||
return format!("{CUSTOM}({r},{g},{b})");
|
||||
}
|
||||
let mut fraction = format!("{:02}", hundredths % 100);
|
||||
if fraction.ends_with('0') {
|
||||
fraction.pop();
|
||||
}
|
||||
format!("{CUSTOM}({r},{g},{b},{}.{fraction})", hundredths / 100)
|
||||
}
|
||||
|
||||
impl Look {
|
||||
pub fn custom(color: [u8; 3], opacity: f64) -> Look {
|
||||
Look { name: "Custom".into(), color, opacity: opacity.clamp(0.0, 1.0), pbr: None }
|
||||
Look { name: CUSTOM.into(), color, opacity: opacity.clamp(0.0, 1.0), pbr: None }
|
||||
}
|
||||
|
||||
/// A colour read from a file: called what the file calls it, else [`unnamed_colour`].
|
||||
pub fn imported(color: [u8; 3], opacity: f64, name: Option<&str>) -> Look {
|
||||
let opacity = opacity.clamp(0.0, 1.0);
|
||||
let name = name.map_or_else(|| unnamed_colour(color, opacity), str::to_string);
|
||||
Look { name, color, opacity, pbr: None }
|
||||
}
|
||||
|
||||
/// The name to write with this look's colour in a file (a STEP `COLOUR_RGB` name): its own,
|
||||
/// unless it is the plain [`CUSTOM`], which says nothing.
|
||||
pub fn file_name(&self) -> Option<String> {
|
||||
(self.name != CUSTOM).then(|| self.name.clone()).and_then(|n| solidcraft_kernel::colour_name(&n))
|
||||
}
|
||||
pub fn opaque_surface(&self) -> crate::Result<Option<solidcraft_viewport::surface::OpaqueSurface>> {
|
||||
if self.pbr.is_some() && self.opacity != 1.0 {
|
||||
@@ -93,6 +125,10 @@ pub struct ImportedLook {
|
||||
pub color: Option<[f32; 3]>,
|
||||
pub opacity: Option<f32>,
|
||||
pub faces: BTreeMap<String, ([f32; 3], f32)>,
|
||||
/// The body colour's name in the file, if it had one.
|
||||
pub name: Option<String>,
|
||||
/// The names the file gives the faces' colours, by the same face names as `faces`.
|
||||
pub face_names: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl ImportedLook {
|
||||
@@ -102,14 +138,17 @@ impl ImportedLook {
|
||||
return b.imported.clone();
|
||||
}
|
||||
let names = crate::naming::face_names(b);
|
||||
let faces = b
|
||||
.body
|
||||
.paint()
|
||||
.map(|p| {
|
||||
p.faces.iter().filter_map(|f| names.get(f.face).map(|n| (crate::naming::strip_piece(n).to_string(), (f.color, f.opacity)))).collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
Some(std::sync::Arc::new(ImportedLook { color: b.body.color(), opacity: b.body.paint().map(|p| p.opacity), faces }))
|
||||
let named = |f: &solidcraft_kernel::FacePaint| names.get(f.face).map(|n| crate::naming::strip_piece(n).to_string());
|
||||
let painted = b.body.paint().map_or(&[][..], |p| p.faces.as_slice());
|
||||
let faces = painted.iter().filter_map(|f| named(f).map(|n| (n, (f.color, f.opacity)))).collect();
|
||||
let face_names = painted.iter().filter_map(|f| Some((named(f)?, f.name.clone()?))).collect();
|
||||
Some(std::sync::Arc::new(ImportedLook {
|
||||
color: b.body.color(),
|
||||
opacity: b.body.paint().map(|p| p.opacity),
|
||||
faces,
|
||||
name: b.body.paint().and_then(|p| p.name.clone()),
|
||||
face_names,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +356,11 @@ impl Document {
|
||||
pub fn model_display_look(&self, body: &crate::ModelBody) -> Option<Look> {
|
||||
self.model_body_look(body).or_else(|| {
|
||||
let color = body.body.color().or_else(|| body.imported.as_ref().and_then(|p| p.color))?;
|
||||
Some(Look::custom(color.map(|v| (v.clamp(0.0, 1.0) * 255.0).round() as u8), self.model_body_opacity(body)))
|
||||
let name = match body.body.color() {
|
||||
Some(_) => body.body.paint().and_then(|p| p.name.as_deref()),
|
||||
None => body.imported.as_ref().and_then(|p| p.name.as_deref()),
|
||||
};
|
||||
Some(Look::imported(color.map(|v| (v.clamp(0.0, 1.0) * 255.0).round() as u8), self.model_body_opacity(body), name))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -380,14 +423,17 @@ impl Document {
|
||||
Vec::new()
|
||||
} else {
|
||||
match b.body.paint() {
|
||||
Some(p) => p.faces.iter().map(|f| (f.face, Look::custom(f.color.map(to8), f.opacity as f64))).collect(),
|
||||
Some(p) => p.faces.iter().map(|f| (f.face, Look::imported(f.color.map(to8), f.opacity as f64, f.name.as_deref()))).collect(),
|
||||
// Carried from an earlier version of the body: by face name (worked out only here:
|
||||
// the viewport asks every body for its face colours on every change).
|
||||
None => match &b.imported {
|
||||
Some(imp) => crate::naming::face_names(b)
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, n)| imp.faces.get(crate::naming::strip_piece(n)).map(|(c, o)| (i, Look::custom(c.map(to8), *o as f64))))
|
||||
.filter_map(|(i, n)| {
|
||||
let n = crate::naming::strip_piece(n);
|
||||
imp.faces.get(n).map(|(c, o)| (i, Look::imported(c.map(to8), *o as f64, imp.face_names.get(n).map(String::as_str))))
|
||||
})
|
||||
.collect(),
|
||||
None => Vec::new(),
|
||||
},
|
||||
@@ -532,9 +578,9 @@ mod tests {
|
||||
.faces(0.01)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|face| solidcraft_kernel::FacePaint { face: face.index, color: [1., 0., 0.], opacity: 0.5 })
|
||||
.map(|face| solidcraft_kernel::FacePaint { face: face.index, color: [1., 0., 0.], opacity: 0.5, name: None })
|
||||
.collect();
|
||||
crate::ModelBody::new("Imported".into(), body.with_paint(Some(solidcraft_kernel::Paint { opacity: 1., faces })), 1)
|
||||
crate::ModelBody::new("Imported".into(), body.with_paint(Some(solidcraft_kernel::Paint { opacity: 1., faces, name: None })), 1)
|
||||
}
|
||||
|
||||
fn check_imported_appearance_precedence(body: &crate::ModelBody) {
|
||||
@@ -542,7 +588,7 @@ mod tests {
|
||||
let face_count = body.body.faces(0.01).unwrap().len();
|
||||
let imported = doc.face_colors(body);
|
||||
assert_eq!(imported.len(), face_count);
|
||||
assert!(imported.iter().all(|(_, look)| *look == Look::custom([255, 0, 0], 0.5)));
|
||||
assert!(imported.iter().all(|(_, look)| *look == Look::imported([255, 0, 0], 0.5, None)));
|
||||
|
||||
let body_look = Look::custom([0, 0, 255], 0.8);
|
||||
doc.appearances.bodies.insert(body.definition_name().into(), body_look.clone());
|
||||
@@ -565,7 +611,7 @@ mod tests {
|
||||
doc.appearances.bodies.clear();
|
||||
let restored = doc.face_colors(body);
|
||||
assert_eq!(restored.len(), face_count);
|
||||
assert!(restored.iter().all(|(face, look)| *look == if *face == 0 { face_look.clone() } else { Look::custom([255, 0, 0], 0.5) }));
|
||||
assert!(restored.iter().all(|(face, look)| *look == if *face == 0 { face_look.clone() } else { Look::imported([255, 0, 0], 0.5, None) }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -590,6 +636,64 @@ mod tests {
|
||||
assert!(faces.iter().all(|face| face.color == [1., 0., 0.] && face.opacity == 0.5));
|
||||
}
|
||||
|
||||
/// A colour a file names is called by that name; one it leaves unnamed by its values, the
|
||||
/// opacity to two decimals with at least one shown. A picked colour's plain name is not written
|
||||
/// to a file.
|
||||
#[test]
|
||||
fn imported_colours_are_called_by_their_file_name_or_their_values() {
|
||||
assert_eq!(unnamed_colour([196, 199, 204], 1.0), "Custom(196,199,204)");
|
||||
assert_eq!(unnamed_colour([210, 226, 240], 0.35), "Custom(210,226,240,0.35)");
|
||||
assert_eq!(unnamed_colour([90, 96, 104], 0.5), "Custom(90,96,104,0.5)");
|
||||
assert_eq!(unnamed_colour([0, 0, 0], 0.0), "Custom(0,0,0,0.0)");
|
||||
// A 32-bit file opacity reads as the number it was written as.
|
||||
assert_eq!(unnamed_colour([1, 2, 3], f64::from(0.35_f32)), "Custom(1,2,3,0.35)");
|
||||
assert_eq!(unnamed_colour([1, 2, 3], 0.995), "Custom(1,2,3)", "rounds to opaque");
|
||||
assert_eq!(unnamed_colour([1, 2, 3], 0.004), "Custom(1,2,3,0.0)");
|
||||
for hostile in [f64::NAN, f64::INFINITY, 7.0] {
|
||||
assert_eq!(unnamed_colour([1, 2, 3], hostile), "Custom(1,2,3)", "{hostile}");
|
||||
}
|
||||
assert_eq!(unnamed_colour([1, 2, 3], -3.0), "Custom(1,2,3,0.0)");
|
||||
let named = Look::imported([160, 160, 160], 1.0, Some("Steel - Satin"));
|
||||
assert_eq!((named.name.as_str(), named.color, named.opacity), ("Steel - Satin", [160, 160, 160], 1.0));
|
||||
assert_eq!(Look::imported([1, 2, 3], 2.0, None).opacity, 1.0);
|
||||
assert_eq!(named.file_name().as_deref(), Some("Steel - Satin"));
|
||||
assert_eq!(Look::imported([1, 2, 3], 1.0, None).file_name().as_deref(), Some("Custom(1,2,3)"));
|
||||
assert_eq!(Look::custom([1, 2, 3], 1.0).file_name(), None, "a picked colour's plain name says nothing");
|
||||
}
|
||||
|
||||
/// The names a file gives a body's colour and its faces' colours name the looks the body
|
||||
/// shows, still after a later feature rebuilds the body without its paint, and they are
|
||||
/// exported with the colours.
|
||||
#[test]
|
||||
fn imported_colour_names_name_the_looks_and_outlive_later_features() {
|
||||
let mut body = imported_box();
|
||||
let mut paint = body.body.paint().unwrap().clone();
|
||||
paint.name = Some("Body grey".into());
|
||||
paint.faces[0].name = Some("Accent".into());
|
||||
body.body = body.body.clone().with_color(Some([0.5, 0.5, 0.5])).with_paint(Some(paint));
|
||||
let doc = Document::default();
|
||||
let check = |body: &crate::ModelBody| {
|
||||
assert_eq!(doc.model_display_look(body).map(|l| l.name), Some("Body grey".into()));
|
||||
let faces = doc.face_colors(body);
|
||||
assert_eq!(faces.iter().find(|(face, _)| *face == 0).map(|(_, l)| l.name.as_str()), Some("Accent"));
|
||||
assert!(faces.iter().filter(|(face, _)| *face != 0).all(|(_, l)| l.name == "Custom(255,0,0,0.5)"), "{faces:?}");
|
||||
};
|
||||
check(&body);
|
||||
// A later feature's body carries the look by face name.
|
||||
let mut later = body.clone();
|
||||
later.imported = ImportedLook::of(&body);
|
||||
later.body = later.body.clone().with_color(None).with_paint(None);
|
||||
assert_eq!(later.imported.as_ref().and_then(|l| l.name.as_deref()), Some("Body grey"));
|
||||
check(&later);
|
||||
// Exported, the colours carry their names.
|
||||
let mut state = crate::ModelState::default();
|
||||
state.bodies.push(body);
|
||||
let painted = doc.painted(&state);
|
||||
let paint = painted.bodies[0].body.paint().unwrap();
|
||||
assert_eq!(paint.name.as_deref(), Some("Body grey"));
|
||||
assert_eq!(paint.faces.iter().find(|f| f.face == 0).and_then(|f| f.name.as_deref()), Some("Accent"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn body_appearance_overrides_imported_face_paint() {
|
||||
check_imported_appearance_precedence(&imported_box());
|
||||
|
||||
@@ -221,8 +221,8 @@ fn map_plane_ref(m: &Mat, p: &mut PlaneRef) {
|
||||
map_geo_ref(m, g);
|
||||
}
|
||||
}
|
||||
// Named origin planes and construction planes are the component's own.
|
||||
PlaneRef::Origin { .. } | PlaneRef::Construction { .. } => {}
|
||||
// Named origin planes, construction planes and placement datums are the component's own.
|
||||
PlaneRef::Origin { .. } | PlaneRef::Datum { .. } | PlaneRef::Construction { .. } => {}
|
||||
PlaneRef::Tangent { face, at, reference, .. } => {
|
||||
*at = apply_point(m, *at);
|
||||
map_geo_ref(m, face);
|
||||
|
||||
+65
-20
@@ -97,7 +97,14 @@ pub fn clone_expression(source: &str, parameters: &BTreeMap<String, String>) ->
|
||||
result
|
||||
}
|
||||
|
||||
fn remap_geo(g: &mut crate::construct::GeoRef, ids: &BTreeMap<u64, u64>, bodies: &BTreeMap<String, String>, depth: usize) -> crate::Result<()> {
|
||||
fn remap_geo(
|
||||
g: &mut crate::construct::GeoRef,
|
||||
ids: &BTreeMap<u64, u64>,
|
||||
bodies: &BTreeMap<String, String>,
|
||||
depth: usize,
|
||||
occurrences: &BTreeMap<u64, u64>,
|
||||
doc: &crate::Document,
|
||||
) -> crate::Result<()> {
|
||||
use crate::construct::GeoRef;
|
||||
if depth > 64 {
|
||||
return Err(crate::DocError::Invalid("clone plane reference depth exceeded".into()));
|
||||
@@ -114,29 +121,38 @@ fn remap_geo(g: &mut crate::construct::GeoRef, ids: &BTreeMap<u64, u64>, bodies:
|
||||
*n = remap_topology(n, ids, bodies);
|
||||
}
|
||||
}
|
||||
GeoRef::Plane { plane } => remap_plane(plane, ids, bodies, depth + 1)?,
|
||||
GeoRef::Plane { plane } => remap_plane(plane, ids, bodies, depth + 1, occurrences, doc)?,
|
||||
GeoRef::Datum { datum } => remap_datum_path(datum, occurrences, doc)?,
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remap_plane(p: &mut PlaneRef, ids: &BTreeMap<u64, u64>, bodies: &BTreeMap<String, String>, depth: usize) -> crate::Result<()> {
|
||||
fn remap_plane(
|
||||
p: &mut PlaneRef,
|
||||
ids: &BTreeMap<u64, u64>,
|
||||
bodies: &BTreeMap<String, String>,
|
||||
depth: usize,
|
||||
occurrences: &BTreeMap<u64, u64>,
|
||||
doc: &crate::Document,
|
||||
) -> crate::Result<()> {
|
||||
if depth > 64 {
|
||||
return Err(crate::DocError::Invalid("clone plane reference depth exceeded".into()));
|
||||
}
|
||||
match p {
|
||||
PlaneRef::Offset { base, .. } | PlaneRef::Flipped { base, .. } => remap_plane(base, ids, bodies, depth + 1)?,
|
||||
PlaneRef::Datum { datum } => remap_datum_path(datum, occurrences, doc)?,
|
||||
PlaneRef::Offset { base, .. } | PlaneRef::Flipped { base, .. } => remap_plane(base, ids, bodies, depth + 1, occurrences, doc)?,
|
||||
PlaneRef::ThroughPoint { base, point } => {
|
||||
remap_plane(base, ids, bodies, depth + 1)?;
|
||||
remap_geo(point, ids, bodies, depth + 1)?;
|
||||
remap_plane(base, ids, bodies, depth + 1, occurrences, doc)?;
|
||||
remap_geo(point, ids, bodies, depth + 1, occurrences, doc)?;
|
||||
}
|
||||
PlaneRef::AtAngle { base, line, pivot, .. } => {
|
||||
remap_plane(base, ids, bodies, depth + 1)?;
|
||||
remap_plane(base, ids, bodies, depth + 1, occurrences, doc)?;
|
||||
if let Some(g) = line {
|
||||
remap_geo(g, ids, bodies, depth + 1)?;
|
||||
remap_geo(g, ids, bodies, depth + 1, occurrences, doc)?;
|
||||
}
|
||||
if let Some(g) = pivot {
|
||||
remap_geo(g, ids, bodies, depth + 1)?;
|
||||
remap_geo(g, ids, bodies, depth + 1, occurrences, doc)?;
|
||||
}
|
||||
}
|
||||
PlaneRef::Face { name, anchor, .. } => {
|
||||
@@ -149,13 +165,28 @@ fn remap_plane(p: &mut PlaneRef, ids: &BTreeMap<u64, u64>, bodies: &BTreeMap<Str
|
||||
}
|
||||
_ => {
|
||||
for r in p.refs_mut() {
|
||||
remap_geo(r, ids, bodies, depth + 1)?;
|
||||
remap_geo(r, ids, bodies, depth + 1, occurrences, doc)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A datum reference names an exact placement by its complete occurrence path. A copy within one
|
||||
/// design rewrites the path to the copy's own walk (the copied subtree's source ancestors are not
|
||||
/// in the map); an empty occurrence map (a paste from another design) or a path that leaves the
|
||||
/// copied tree is refused - the reference could not follow, and a dangling one would resolve
|
||||
/// against whatever then sits at those ids.
|
||||
fn remap_datum_path(d: &mut crate::construct::DatumRef, occurrences: &BTreeMap<u64, u64>, doc: &crate::Document) -> crate::Result<()> {
|
||||
let last = d.path.last().copied().ok_or_else(|| crate::DocError::Invalid("a copied datum names no placement".into()))?;
|
||||
let new = occurrences
|
||||
.get(&last)
|
||||
.copied()
|
||||
.ok_or_else(|| crate::DocError::Invalid("the copied reference names a placement outside the copied tree".into()))?;
|
||||
d.path = doc.occurrence_path(new).ok_or_else(|| crate::DocError::Invalid("the copied placement's path is broken".into()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn remap_link(
|
||||
source: &mut solidcraft_sketch::LinkSource,
|
||||
ids: &BTreeMap<u64, u64>,
|
||||
@@ -204,6 +235,8 @@ impl crate::Feature {
|
||||
names: &BTreeMap<String, String>,
|
||||
bodies: &BTreeMap<String, String>,
|
||||
parameters: &BTreeMap<String, String>,
|
||||
occurrences: &BTreeMap<u64, u64>,
|
||||
doc: &crate::Document,
|
||||
) -> crate::Result<()> {
|
||||
use FeatureKind as K;
|
||||
match &self.kind {
|
||||
@@ -213,6 +246,11 @@ impl crate::Feature {
|
||||
checked_link(&link.source, 0)?;
|
||||
}
|
||||
}
|
||||
K::FrameEndCap { ends, .. } => {
|
||||
for end in ends {
|
||||
checked_plane(&end.plane, 0)?;
|
||||
}
|
||||
}
|
||||
K::ConstructionPlane { plane }
|
||||
| K::Split { plane, .. }
|
||||
| K::SplitFace { plane, .. }
|
||||
@@ -261,7 +299,7 @@ impl crate::Feature {
|
||||
self.kind.remap_bodies(bodies);
|
||||
match &mut self.kind {
|
||||
K::Sketch { plane, sketch } => {
|
||||
remap_plane(plane, ids, bodies, 0)?;
|
||||
remap_plane(plane, ids, bodies, 0, occurrences, doc)?;
|
||||
for c in &mut sketch.constraints {
|
||||
if let Some(n) = &mut c.param {
|
||||
mapped_name(n, parameters);
|
||||
@@ -283,28 +321,35 @@ impl crate::Feature {
|
||||
}
|
||||
}
|
||||
}
|
||||
K::FrameEndCap { ends, .. } => {
|
||||
for end in ends {
|
||||
remap_plane(&mut end.plane, ids, bodies, 0, occurrences, doc)?;
|
||||
}
|
||||
}
|
||||
K::ConstructionPlane { plane }
|
||||
| K::Split { plane, .. }
|
||||
| K::SplitFace { plane, .. }
|
||||
| K::Mirror { plane, .. }
|
||||
| K::SurfaceTrim { plane, .. } => remap_plane(plane, ids, bodies, 0)?,
|
||||
K::Draft { neutral, .. } => remap_plane(neutral, ids, bodies, 0)?,
|
||||
K::ReplaceFace { target, .. } => remap_plane(target, ids, bodies, 0)?,
|
||||
K::SurfaceExtend { up_to: Some(crate::ExtendTo::Plane(plane)), .. } => remap_plane(plane, ids, bodies, 0)?,
|
||||
K::Thread { up_to: Some(crate::ThreadLimit::Plane(plane)), .. } => remap_plane(plane, ids, bodies, 0)?,
|
||||
| K::SurfaceTrim { plane, .. } => remap_plane(plane, ids, bodies, 0, occurrences, doc)?,
|
||||
K::Draft { neutral, .. } => remap_plane(neutral, ids, bodies, 0, occurrences, doc)?,
|
||||
K::ReplaceFace { target, .. } => remap_plane(target, ids, bodies, 0, occurrences, doc)?,
|
||||
K::SurfaceExtend { up_to: Some(crate::ExtendTo::Plane(plane)), .. } => remap_plane(plane, ids, bodies, 0, occurrences, doc)?,
|
||||
K::Thread { up_to: Some(crate::ThreadLimit::Plane(plane)), .. } => remap_plane(plane, ids, bodies, 0, occurrences, doc)?,
|
||||
K::ConstructionAxis { def } => {
|
||||
for r in def.refs_mut() {
|
||||
remap_geo(r, ids, bodies, 0)?;
|
||||
remap_geo(r, ids, bodies, 0, occurrences, doc)?;
|
||||
}
|
||||
}
|
||||
K::ConstructionPoint { def } => {
|
||||
for r in def.refs_mut() {
|
||||
remap_geo(r, ids, bodies, 0)?;
|
||||
remap_geo(r, ids, bodies, 0, occurrences, doc)?;
|
||||
}
|
||||
}
|
||||
K::Revolve { axis: crate::AxisRef::Model { geo }, .. }
|
||||
| K::SurfaceRevolve { axis: crate::AxisRef::Model { geo }, .. }
|
||||
| K::Pattern { pattern: crate::PatternKind::Circular { axis_ref: Some(geo), .. }, .. } => remap_geo(geo, ids, bodies, 0)?,
|
||||
| K::Pattern { pattern: crate::PatternKind::Circular { axis_ref: Some(geo), .. }, .. } => {
|
||||
remap_geo(geo, ids, bodies, 0, occurrences, doc)?
|
||||
}
|
||||
// An Align frame's joint origin finds its faces and edges by name, as the feature's
|
||||
// own face names are found.
|
||||
K::Align { from_frame, to_frame, .. } => {
|
||||
@@ -407,7 +452,7 @@ mod clone_tests {
|
||||
value["name"] = json!("Copy");
|
||||
let mut feature: crate::Feature = serde_json::from_value(value).unwrap();
|
||||
let before = serde_json::to_string(&feature).unwrap();
|
||||
feature.remap_clone(&BTreeMap::new(), &names, &BTreeMap::new(), &BTreeMap::new()).unwrap();
|
||||
feature.remap_clone(&BTreeMap::new(), &names, &BTreeMap::new(), &BTreeMap::new(), &BTreeMap::new(), &crate::Document::default()).unwrap();
|
||||
assert_eq!(serde_json::to_string(&feature).unwrap(), before.replace("\"Old\"", "\"New\""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ impl Document {
|
||||
.assembly
|
||||
.joints
|
||||
.iter()
|
||||
.filter(|j| occurrences.contains(&j.a.occurrence) || occurrences.contains(&j.b.occurrence))
|
||||
.filter(|j| j.a.occurrences().chain(j.b.occurrences()).any(|o| occurrences.contains(&o)))
|
||||
.map(|j| j.id)
|
||||
.collect();
|
||||
for group in &mut self.timeline_groups {
|
||||
@@ -87,7 +87,7 @@ impl Document {
|
||||
let assembly = &mut self.assembly;
|
||||
assembly.joints.retain(|j| !joints.contains(&j.id));
|
||||
assembly.links.retain(|l| !joints.contains(&l.a) && !joints.contains(&l.b));
|
||||
assembly.origins.retain(|o| !occurrences.contains(&o.origin.occurrence));
|
||||
assembly.origins.retain(|o| !o.origin.occurrences().any(|o| occurrences.contains(&o)));
|
||||
for set in &mut assembly.contact_sets {
|
||||
set.occurrences.retain(|o| !occurrences.contains(o));
|
||||
}
|
||||
|
||||
+99
-12
@@ -38,6 +38,9 @@ pub enum Column {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ConfigRow {
|
||||
/// Fixed for the row's life, from the design's id counter ([`Document::allocate_id`]): a rename
|
||||
/// keeps it and no other row is ever given it, so what points at a row still finds it (#14750).
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
/// One cell per column: expression, suppression, material name or appearance look.
|
||||
pub cells: Vec<String>,
|
||||
@@ -64,10 +67,59 @@ pub fn suppression_cell(value: &str) -> Result<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A row of the table, by its id or by its name.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum RowKey<'a> {
|
||||
Id(u64),
|
||||
Name(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> RowKey<'a> {
|
||||
/// A row as a command or a file names it: a whole number is its id, text its name, so a row
|
||||
/// named `"17"` is not row 17. Anything else names no row.
|
||||
pub fn read(v: &'a serde_json::Value) -> Option<Self> {
|
||||
v.as_u64().map(RowKey::Id).or_else(|| v.as_str().map(RowKey::Name))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for RowKey<'a> {
|
||||
fn from(name: &'a str) -> Self {
|
||||
RowKey::Name(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for RowKey<'_> {
|
||||
fn from(id: u64) -> Self {
|
||||
RowKey::Id(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RowKey<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
RowKey::Id(id) => write!(f, "{id}"),
|
||||
RowKey::Name(name) => f.write_str(name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigTable {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.columns.is_empty() && self.rows.is_empty() && self.rules.is_empty()
|
||||
}
|
||||
|
||||
/// The row `key` names: the one with that id, or with that name.
|
||||
pub fn row(&self, key: RowKey<'_>) -> Option<&ConfigRow> {
|
||||
self.rows.iter().find(|r| match key {
|
||||
RowKey::Id(id) => r.id == id,
|
||||
RowKey::Name(name) => r.name == name,
|
||||
})
|
||||
}
|
||||
|
||||
/// The active row, when the table still has it.
|
||||
pub fn active_row(&self) -> Option<&ConfigRow> {
|
||||
self.row(RowKey::Name(self.active.as_deref()?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse an appearance cell. Empty/Default follows the body's material; named library looks
|
||||
@@ -164,13 +216,25 @@ impl Document {
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a row to the configuration table, with an id of its own; at most [`MAX_ROWS`] rows.
|
||||
pub fn add_configuration_row(&mut self, name: String, cells: Vec<String>) -> Result<u64> {
|
||||
if self.configs.rows.len() >= MAX_ROWS {
|
||||
return Err(DocError::Invalid("too many rows".into()));
|
||||
}
|
||||
let id = self.allocate_id()?;
|
||||
self.configs.rows.push(ConfigRow { id, name, cells });
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// Set the design to a row's values (all or nothing).
|
||||
pub fn apply_configuration(&mut self, row: &str) -> Result<()> {
|
||||
pub fn apply_configuration<'a>(&mut self, row: impl Into<RowKey<'a>>) -> Result<()> {
|
||||
self.apply_configuration_with_trace(row).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn apply_configuration_with_trace(&mut self, row: &str) -> Result<Vec<RuleTrace>> {
|
||||
let r = self.configs.rows.iter().find(|r| r.name == row).cloned().ok_or_else(|| DocError::Unknown(format!("configuration `{row}`")))?;
|
||||
pub fn apply_configuration_with_trace<'a>(&mut self, row: impl Into<RowKey<'a>>) -> Result<Vec<RuleTrace>> {
|
||||
let key = row.into();
|
||||
let r = self.configs.row(key).cloned().ok_or_else(|| DocError::Unknown(format!("configuration `{key}`")))?;
|
||||
let row = r.name.as_str();
|
||||
if self.configs.columns.len() > MAX_COLUMNS || self.configs.rows.len() > MAX_ROWS || r.cells.len() != self.configs.columns.len() {
|
||||
return Err(DocError::Invalid("configuration table exceeds limits or has incomplete rows".into()));
|
||||
}
|
||||
@@ -250,13 +314,13 @@ impl Document {
|
||||
|
||||
/// The active row's values all hold in the design.
|
||||
pub fn configuration_matches(&self) -> bool {
|
||||
let Some(r) = self.configs.active.as_ref().and_then(|a| self.configs.rows.iter().find(|r| r.name == *a)) else { return false };
|
||||
let Some(r) = self.configs.active_row() else { return false };
|
||||
if r.cells.len() != self.configs.columns.len() {
|
||||
return false;
|
||||
}
|
||||
if !self.configs.rules.is_empty() {
|
||||
let mut expected = self.clone();
|
||||
if expected.apply_configuration(&r.name).is_err() {
|
||||
if expected.apply_configuration(r.id).is_err() {
|
||||
return false;
|
||||
}
|
||||
return self.configs.columns.iter().all(|column| self.config_current(column) == expected.config_current(column));
|
||||
@@ -291,11 +355,11 @@ mod tests {
|
||||
d.set_param("a", "1 mm", None, None).unwrap();
|
||||
d.set_param("b", "a", None, None).unwrap();
|
||||
d.configs.columns = vec![Column::Param("a".into()), Column::Param("b".into())];
|
||||
d.configs.rows.push(ConfigRow { name: "Reordered".into(), cells: vec!["b".into(), "2 mm".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: 1, name: "Reordered".into(), cells: vec!["b".into(), "2 mm".into()] });
|
||||
d.apply_configuration("Reordered").unwrap();
|
||||
assert!(d.configuration_matches());
|
||||
assert_eq!(d.param_values().0["a"].v, 2.0);
|
||||
d.configs.rows.push(ConfigRow { name: "Cycle".into(), cells: vec!["b".into(), "a".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: 2, name: "Cycle".into(), cells: vec!["b".into(), "a".into()] });
|
||||
let before = d.clone();
|
||||
assert!(d.apply_configuration("Cycle").is_err());
|
||||
assert_eq!(d, before);
|
||||
@@ -323,28 +387,50 @@ mod tests {
|
||||
d.set_param("width", "10 mm", None, None).unwrap();
|
||||
d.params[0].expr = "1/".into();
|
||||
d.configs.columns = vec![Column::Param("width".into())];
|
||||
d.configs.rows.push(ConfigRow { name: "Default".into(), cells: vec!["1/".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: 3, name: "Default".into(), cells: vec!["1/".into()] });
|
||||
d.apply_configuration("Default").unwrap();
|
||||
assert!(d.configuration_matches());
|
||||
d.configs.rows.push(ConfigRow { name: "Different error".into(), cells: vec!["missing + 1".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: 4, name: "Different error".into(), cells: vec!["missing + 1".into()] });
|
||||
let before = d.clone();
|
||||
assert!(d.apply_configuration("Different error").is_err());
|
||||
assert_eq!(d, before);
|
||||
}
|
||||
|
||||
/// A row is found by its id or its name, and activating it by id names it active. A deleted
|
||||
/// row's id is never given out again (#14750).
|
||||
#[test]
|
||||
fn a_row_is_found_by_its_id_or_its_name() {
|
||||
let mut d = Document::new("A");
|
||||
d.set_param("w", "10 mm", None, None).unwrap();
|
||||
d.configs.columns.push(Column::Param("w".into()));
|
||||
let (small, large) = (d.allocate_id().unwrap(), d.allocate_id().unwrap());
|
||||
d.configs.rows.push(ConfigRow { id: small, name: "Small".into(), cells: vec!["10 mm".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: large, name: "Large".into(), cells: vec!["40 mm".into()] });
|
||||
assert_eq!(d.configs.row(RowKey::Id(large)).map(|r| r.name.as_str()), Some("Large"));
|
||||
assert_eq!(d.configs.row("Small".into()).map(|r| r.id), Some(small));
|
||||
d.apply_configuration(large).unwrap();
|
||||
assert_eq!((d.configs.active.as_deref(), d.configs.active_row().map(|r| r.id)), (Some("Large"), Some(large)));
|
||||
assert!(d.configuration_matches());
|
||||
d.configs.rows.retain(|r| r.id != large);
|
||||
assert!(d.configs.active_row().is_none() && !d.configuration_matches());
|
||||
assert!(d.allocate_id().unwrap() > large, "a deleted row's id is never given again");
|
||||
let gone = d.apply_configuration(large).unwrap_err().to_string();
|
||||
assert!(gone.contains(&format!("configuration `{large}`")), "{gone}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rows_switch_parameters() {
|
||||
let mut d = Document::new("A");
|
||||
d.set_param("w", "10 mm", None, None).unwrap();
|
||||
d.configs.columns.push(Column::Param("w".into()));
|
||||
d.configs.rows.push(ConfigRow { name: "Small".into(), cells: vec!["10 mm".into()] });
|
||||
d.configs.rows.push(ConfigRow { name: "Large".into(), cells: vec!["40 mm".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: 5, name: "Small".into(), cells: vec!["10 mm".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: 6, name: "Large".into(), cells: vec!["40 mm".into()] });
|
||||
d.apply_configuration("Large").unwrap();
|
||||
assert_eq!(d.config_current(&Column::Param("w".into())).as_deref(), Some("40 mm"));
|
||||
assert!(d.configuration_matches());
|
||||
d.set_param("w", "12 mm", None, None).unwrap();
|
||||
assert!(!d.configuration_matches());
|
||||
d.configs.rows.push(ConfigRow { name: "Bad".into(), cells: vec!["1/".into()] });
|
||||
d.configs.rows.push(ConfigRow { id: 7, name: "Bad".into(), cells: vec!["1/".into()] });
|
||||
let before = d.clone();
|
||||
assert!(d.apply_configuration("Bad").is_err());
|
||||
assert_eq!(d, before, "all or nothing");
|
||||
@@ -356,6 +442,7 @@ mod tests {
|
||||
d.set_param("width", "10 mm", None, None).unwrap();
|
||||
d.configs.columns = vec![Column::Param("width".into()), Column::Material("Body".into()), Column::Appearance("Body".into())];
|
||||
d.configs.rows.push(ConfigRow {
|
||||
id: 8,
|
||||
name: "Broken".into(),
|
||||
cells: vec!["20 mm".into(), "Steel".into(), r#"{"name":"Invalid","color":[1,2,3],"opacity":2}"#.into()],
|
||||
});
|
||||
|
||||
@@ -211,7 +211,7 @@ pub enum FaceCertificate {
|
||||
},
|
||||
/// A flat face known by its exact history name (the target's `name`, without piece
|
||||
/// numbers): what the kernel's face history says it came from, followed through every
|
||||
/// feature since (a cut wall `F5:side:l1`, a chamfer `F7:blend:…`, a pattern copy
|
||||
/// feature since (a cut wall `F5:side:l1`, a chamfer `F7:blend(…)`, a pattern copy
|
||||
/// `F4:top@F6.2`, a face a join merged from two features). Used where no construction
|
||||
/// certificate above names the face uniquely. Its plane is the face's exact current plane in
|
||||
/// the frame [`lineage_frame`] gives it. See docs/face-attachments.md.
|
||||
@@ -988,6 +988,7 @@ mod tests {
|
||||
sketch,
|
||||
report,
|
||||
profiles: Vec::new(),
|
||||
profiles_3d: Vec::new(),
|
||||
ends: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@ mod tests {
|
||||
}),
|
||||
],
|
||||
rows: vec![ConfigRow {
|
||||
id: 1,
|
||||
name: "Default".into(),
|
||||
cells: vec!["d1 * 2 + d2".into(), "4 mm".into(), "d1".into(), String::new(), String::new()],
|
||||
}],
|
||||
@@ -203,7 +204,7 @@ mod tests {
|
||||
certificate: None,
|
||||
}),
|
||||
],
|
||||
rows: vec![ConfigRow { name: "Default".into(), cells: vec!["2 mm".into(), String::new()] }],
|
||||
rows: vec![ConfigRow { id: 2, name: "Default".into(), cells: vec!["2 mm".into(), String::new()] }],
|
||||
..Default::default()
|
||||
};
|
||||
let original = table.clone();
|
||||
|
||||
@@ -529,7 +529,7 @@ mod tests {
|
||||
doc.set_param("width", "10 mm", None, None).unwrap();
|
||||
doc.set_param("depth", "5 mm", None, None).unwrap();
|
||||
doc.configs.columns = vec![Column::Param("width".into()), Column::Param("depth".into())];
|
||||
doc.configs.rows.push(ConfigRow { name: "Default".into(), cells: vec!["10 mm".into(), "5 mm".into()] });
|
||||
doc.configs.rows.push(ConfigRow { id: 1, name: "Default".into(), cells: vec!["10 mm".into(), "5 mm".into()] });
|
||||
doc
|
||||
}
|
||||
fn rule(id: &str, condition: RuleCondition, effect: RuleEffect) -> ConfigRule {
|
||||
@@ -730,7 +730,7 @@ mod tests {
|
||||
doc.rename_param(&width, "width").unwrap();
|
||||
doc.rename_param(&depth, "depth").unwrap();
|
||||
doc.configs.columns = vec![Column::Param("width".into()), Column::Param("depth".into())];
|
||||
doc.configs.rows.push(ConfigRow { name: "Default".into(), cells: vec!["10 mm".into(), "5 mm".into()] });
|
||||
doc.configs.rows.push(ConfigRow { id: 2, name: "Default".into(), cells: vec!["10 mm".into(), "5 mm".into()] });
|
||||
doc.units = "in".into();
|
||||
let mut first =
|
||||
rule("first", RuleCondition::Always, RuleEffect::DriveParameter { parameter: "width".into(), expression: "depth + 1".into() });
|
||||
|
||||
+177
-14
@@ -10,7 +10,7 @@ use solidcraft_geom::prelude::*;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solidcore_record::{Plane, Vec2, Vec3};
|
||||
use solidcore_record::{Plane, Vec3};
|
||||
use solidcraft_kernel::{self as kernel, FaceSurface};
|
||||
|
||||
use crate::eval::{ModelBody, ModelState};
|
||||
@@ -23,6 +23,9 @@ use crate::{DocError, Document, PlaneRef, Result};
|
||||
pub enum GeoRef {
|
||||
/// A fixed point.
|
||||
Point { p: Vec3 },
|
||||
/// An origin datum of an exact placement (its O point, an axis or a plane), found again on
|
||||
/// each evaluation, so it follows the component the way a named reference does.
|
||||
Datum { datum: DatumRef },
|
||||
/// The design origin.
|
||||
Origin,
|
||||
/// A body vertex: where the edges named `edges` meet (the end they share), else the one
|
||||
@@ -52,7 +55,7 @@ pub enum GeoRef {
|
||||
Axis { name: crate::FeatureName },
|
||||
/// A construction point feature, by name.
|
||||
ConstructPoint { name: crate::FeatureName },
|
||||
/// A sketch point (by sketch feature id and point id).
|
||||
/// A sketch point (by sketch feature id and point id), or a drawn wire node as `wire:index`.
|
||||
SketchPoint { sketch: u64, point: String },
|
||||
/// A sketch curve (by sketch feature id and curve id).
|
||||
SketchCurve { sketch: u64, curve: String },
|
||||
@@ -112,6 +115,129 @@ impl ConstructGeom {
|
||||
}
|
||||
}
|
||||
|
||||
/// One of the seven named items of a placement's Origin folder: the O point, the X, Y and Z
|
||||
/// axes, and the XY, XZ and YZ planes. Case-insensitive to parse; the `Plane::named` aliases
|
||||
/// (TOP/FRONT/RIGHT) stay root-only.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum DatumItem {
|
||||
O,
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
XY,
|
||||
XZ,
|
||||
YZ,
|
||||
}
|
||||
|
||||
impl DatumItem {
|
||||
/// The item's name as a key spells it.
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
DatumItem::O => "O",
|
||||
DatumItem::X => "X",
|
||||
DatumItem::Y => "Y",
|
||||
DatumItem::Z => "Z",
|
||||
DatumItem::XY => "XY",
|
||||
DatumItem::XZ => "XZ",
|
||||
DatumItem::YZ => "YZ",
|
||||
}
|
||||
}
|
||||
|
||||
/// Case-insensitive; the Plane::named aliases (TOP/FRONT/RIGHT) stay root-only.
|
||||
pub fn parse(name: &str) -> Option<Self> {
|
||||
Some(match name.to_ascii_uppercase().as_str() {
|
||||
"O" => DatumItem::O,
|
||||
"X" => DatumItem::X,
|
||||
"Y" => DatumItem::Y,
|
||||
"Z" => DatumItem::Z,
|
||||
"XY" => DatumItem::XY,
|
||||
"XZ" => DatumItem::XZ,
|
||||
"YZ" => DatumItem::YZ,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// The item in its component's own frame: O the point, X/Y/Z the axes, XY/XZ/YZ the planes.
|
||||
pub fn geom(self) -> ConstructGeom {
|
||||
match self {
|
||||
DatumItem::O => ConstructGeom::Point(Vec3::ZERO),
|
||||
DatumItem::X => ConstructGeom::Axis { origin: Vec3::ZERO, dir: Vec3::X },
|
||||
DatumItem::Y => ConstructGeom::Axis { origin: Vec3::ZERO, dir: Vec3::Y },
|
||||
DatumItem::Z => ConstructGeom::Axis { origin: Vec3::ZERO, dir: Vec3::Z },
|
||||
DatumItem::XY => ConstructGeom::Plane(Plane::XY),
|
||||
DatumItem::XZ => ConstructGeom::Plane(Plane::XZ),
|
||||
DatumItem::YZ => ConstructGeom::Plane(Plane::YZ),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An origin datum of an exact placement. The empty path is never a `DatumRef`: the root keeps
|
||||
/// `PlaneRef::Origin` and `GeoRef::Origin` as they are.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct DatumRef {
|
||||
/// The occurrence ids of the placement, root first.
|
||||
pub path: Vec<u64>,
|
||||
pub item: DatumItem,
|
||||
}
|
||||
|
||||
impl DatumRef {
|
||||
/// The datum's Browser key: `o:2/3/origin/XY`.
|
||||
pub fn key(&self) -> String {
|
||||
format!("o:{}/origin/{}", self.path.iter().map(|id| id.to_string()).collect::<Vec<_>>().join("/"), self.item.name())
|
||||
}
|
||||
|
||||
/// Strict: canonical non-zero decimal ids, depth at most 64, length at most 2048. Rejects
|
||||
/// `c0/origin`, `o:01/origin/X` and `o:0/origin/X`.
|
||||
pub fn parse_key(key: &str) -> Option<Self> {
|
||||
if key.len() > 2048 {
|
||||
return None;
|
||||
}
|
||||
let rest = key.strip_prefix("o:")?;
|
||||
let (ids, item) = rest.rsplit_once("/origin/")?;
|
||||
if ids.is_empty() || ids.split('/').count() > 64 {
|
||||
return None;
|
||||
}
|
||||
let path = ids.split('/').map(|id| id.parse::<u64>().ok().filter(|n| *n != 0 && n.to_string() == id)).collect::<Option<Vec<_>>>()?;
|
||||
Some(DatumRef { path, item: DatumItem::parse(item)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for DatumRef {
|
||||
/// Saved as its Browser key: `o:2/3/origin/XY`.
|
||||
fn serialize<S: serde::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
|
||||
s.serialize_str(&self.key())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for DatumRef {
|
||||
/// Reads a saved reference back from its Browser key: anything that is not a bounded
|
||||
/// datum key is a deserialize error, so an older release never mis-reads a newer design.
|
||||
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
|
||||
let key = String::deserialize(d)?;
|
||||
DatumRef::parse_key(&key).ok_or_else(|| serde::de::Error::custom(format!("not a datum key: `{key}`")))
|
||||
}
|
||||
}
|
||||
|
||||
/// An origin datum of an exact placement, resolved at evaluation time: the item in its own
|
||||
/// component's frame, placed by the placement's world frame. It follows the component on every
|
||||
/// evaluation, the way `PlaneRef::Face` re-finds its face.
|
||||
pub fn resolve_datum(doc: &Document, d: &DatumRef) -> Result<ConstructGeom> {
|
||||
Ok(d.item.geom().placed(&doc.placement_frame(&d.path)?))
|
||||
}
|
||||
|
||||
/// [`resolve_datum`] as the component `component` sees it: placed by the placements, then
|
||||
/// mapped back through that component's frame, since a feature evaluated in its own frame
|
||||
/// places what it reads into the world again through that frame (the world pass). The root
|
||||
/// (0) reads the world as it is.
|
||||
pub fn resolve_datum_in(doc: &Document, d: &DatumRef, component: u64) -> Result<ConstructGeom> {
|
||||
if component == 0 {
|
||||
return resolve_datum(doc, d);
|
||||
}
|
||||
let inverse =
|
||||
crate::mat_inverse(&doc.component_transform(component)).ok_or_else(|| DocError::Invalid("the component's placement is singular".into()))?;
|
||||
Ok(resolve_datum(doc, d)?.placed(&inverse))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Construct {
|
||||
pub feature: u64,
|
||||
@@ -133,6 +259,10 @@ pub(crate) struct Ctx<'a> {
|
||||
/// geometry resolves its sides through the document again, so the count has to continue
|
||||
/// across that hop; restarting it lets a plane that refers to itself recurse forever.
|
||||
pub depth: usize,
|
||||
/// The component the reading feature lives in: a datum it reads is found through the
|
||||
/// placements and mapped back into this frame ([`resolve_datum_in`]). The root (0) is
|
||||
/// the world.
|
||||
pub component: u64,
|
||||
}
|
||||
|
||||
fn bad(m: impl Into<String>) -> DocError {
|
||||
@@ -308,11 +438,6 @@ fn as_circle(pts: &[Vec3]) -> Option<(Vec3, Vec3, f64)> {
|
||||
.then_some((centre, unit, r))
|
||||
}
|
||||
|
||||
fn sketch_world(ctx: &Ctx, sketch: u64, q: Vec2) -> Result<Vec3> {
|
||||
let ss = ctx.st.sketch(sketch).ok_or_else(|| DocError::Unknown(format!("sketch {sketch}")))?;
|
||||
Ok(ss.plane.to_world(q))
|
||||
}
|
||||
|
||||
fn sketch_curve_points(ctx: &Ctx, sketch: u64, curve: &str) -> Result<Vec<Vec3>> {
|
||||
let ss = ctx.st.sketch(sketch).ok_or_else(|| DocError::Unknown(format!("sketch {sketch}")))?;
|
||||
if let Some(wire) = ss.sketch.wires.iter().find(|wire| wire.id == curve) {
|
||||
@@ -358,17 +483,30 @@ pub(crate) fn point(ctx: &Ctx, g: &GeoRef) -> Result<Vec3> {
|
||||
_ => Err(bad(format!("`{name}` is not a point"))),
|
||||
},
|
||||
GeoRef::SketchPoint { sketch, point } => {
|
||||
let ss = ctx.st.sketch(*sketch).ok_or_else(|| DocError::Unknown(format!("sketch {sketch}")))?;
|
||||
let q =
|
||||
ss.sketch.point_index(point).and_then(|i| ss.sketch.point(i)).ok_or_else(|| DocError::Unknown(format!("sketch point `{point}`")))?;
|
||||
sketch_world(ctx, *sketch, q)
|
||||
sketch_point_position(ctx.st, *sketch, point).ok_or_else(|| DocError::Unknown(format!("sketch point `{point}`")))
|
||||
}
|
||||
// A round edge or face: its centre.
|
||||
GeoRef::Edge { .. } | GeoRef::Face { .. } | GeoRef::SketchCurve { .. } => centre(ctx, g),
|
||||
GeoRef::Datum { datum } => match resolve_datum_in(ctx.doc, datum, ctx.component)? {
|
||||
ConstructGeom::Point(p) => Ok(p),
|
||||
_ => Err(bad("the datum is not a point (pick the O of a component)")),
|
||||
},
|
||||
_ => Err(bad("pick a point, vertex or sketch point")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a planar point or a drawn 3D wire's `wire:index` node in the evaluated state's frame.
|
||||
/// Wire coordinates have already been placed; applying the sketch plane again would move them twice.
|
||||
pub fn sketch_point_position(st: &ModelState, sketch: u64, point: &str) -> Option<Vec3> {
|
||||
let ss = st.sketch(sketch)?;
|
||||
if let Some(p) = ss.sketch.point_index(point).and_then(|i| ss.sketch.point(i)) {
|
||||
return Some(ss.plane.to_world(p));
|
||||
}
|
||||
let (wire, index) = point.rsplit_once(':')?;
|
||||
let index = index.parse::<usize>().ok()?;
|
||||
ss.sketch.wires.get(ss.sketch.wire_index(wire)?)?.fit.get(index).copied()
|
||||
}
|
||||
|
||||
/// An edge or face of the model as a line: along a straight edge, through the centre of a
|
||||
/// circular edge along its normal, or the axis of a cylinder, cone or torus face.
|
||||
fn model_line(st: &ModelState, g: &GeoRef) -> Result<(Vec3, Vec3)> {
|
||||
@@ -403,6 +541,23 @@ pub fn model_axis(st: &ModelState, g: &GeoRef) -> Result<(Vec3, Vec3)> {
|
||||
Ok((o, canonical_dir(d)))
|
||||
}
|
||||
|
||||
/// [`model_axis`] for references that may name a component's origin datum: the datum is placed
|
||||
/// through the document's placements ([`resolve_datum_in`], as the component `component` sees
|
||||
/// it), the rest as [`model_axis`] finds it in the model state. `None` for a datum asks for an
|
||||
/// evaluation.
|
||||
pub fn model_axis_in(doc: Option<&Document>, st: &ModelState, g: &GeoRef, component: u64) -> Result<(Vec3, Vec3)> {
|
||||
match g {
|
||||
GeoRef::Datum { datum } => {
|
||||
let doc = doc.ok_or_else(|| bad("this axis is built from a component's origin: evaluate first"))?;
|
||||
match resolve_datum_in(doc, datum, component)? {
|
||||
ConstructGeom::Axis { origin, dir } => Ok((origin, dir)),
|
||||
_ => Err(bad("the datum is not an axis (pick the X, Y or Z of a component)")),
|
||||
}
|
||||
}
|
||||
_ => model_axis(st, g),
|
||||
}
|
||||
}
|
||||
|
||||
/// `d` or `-d`, whichever has its largest component (the first of equal ones) positive: how
|
||||
/// [`model_axis`] orients an axis, for a preview of one to point the same way.
|
||||
pub fn canonical_dir(d: Vec3) -> Vec3 {
|
||||
@@ -417,6 +572,10 @@ pub fn canonical_dir(d: Vec3) -> Vec3 {
|
||||
/// A reference as a line (origin, unit direction).
|
||||
pub(crate) fn line(ctx: &Ctx, g: &GeoRef) -> Result<(Vec3, Vec3)> {
|
||||
match g {
|
||||
GeoRef::Datum { datum } => match resolve_datum_in(ctx.doc, datum, ctx.component)? {
|
||||
ConstructGeom::Axis { origin, dir } => Ok((origin, dir)),
|
||||
_ => Err(bad("the datum is not an axis (pick the X, Y or Z of a component)")),
|
||||
},
|
||||
GeoRef::Edge { .. } | GeoRef::Face { .. } => model_line(ctx.st, g),
|
||||
GeoRef::SketchCurve { sketch, curve } => {
|
||||
let pts = sketch_curve_points(ctx, *sketch, curve)?;
|
||||
@@ -442,7 +601,7 @@ pub(crate) fn line(ctx: &Ctx, g: &GeoRef) -> Result<(Vec3, Vec3)> {
|
||||
/// A reference as a plane.
|
||||
pub(crate) fn plane(ctx: &Ctx, g: &GeoRef) -> Result<Plane> {
|
||||
match g {
|
||||
GeoRef::Plane { plane } => ctx.doc.resolve_plane_in(ctx.vals, plane, ctx.depth + 1, Some(ctx.st)),
|
||||
GeoRef::Plane { plane } => ctx.doc.resolve_plane_in(ctx.vals, plane, ctx.depth + 1, ctx.component, Some(ctx.st)),
|
||||
GeoRef::Face { at, name } => {
|
||||
let (b, fi, q) = face_of(ctx.st, *at, name)?;
|
||||
match kernel::face_surface(&b.body, fi) {
|
||||
@@ -453,6 +612,10 @@ pub(crate) fn plane(ctx: &Ctx, g: &GeoRef) -> Result<Plane> {
|
||||
_ => Err(bad("the face is not planar")),
|
||||
}
|
||||
}
|
||||
GeoRef::Datum { datum } => match resolve_datum_in(ctx.doc, datum, ctx.component)? {
|
||||
ConstructGeom::Plane(p) => Ok(p),
|
||||
_ => Err(bad("the datum is not a plane (pick the XY, XZ or YZ of a component)")),
|
||||
},
|
||||
_ => Err(bad("pick a plane or planar face")),
|
||||
}
|
||||
}
|
||||
@@ -846,11 +1009,11 @@ pub(crate) fn resolve_geo_plane(ctx: &Ctx, p: &PlaneRef) -> Result<Plane> {
|
||||
Plane::from_normal(p, tan).ok_or_else(degenerate)
|
||||
}
|
||||
PlaneRef::ThroughPoint { base, point: at } => {
|
||||
let b = ctx.doc.resolve_plane_in(ctx.vals, base, ctx.depth + 1, Some(ctx.st))?;
|
||||
let b = ctx.doc.resolve_plane_in(ctx.vals, base, ctx.depth + 1, ctx.component, Some(ctx.st))?;
|
||||
let n = b.normal().normalized().ok_or_else(degenerate)?;
|
||||
Ok(Plane { origin: b.origin + n * (point(ctx, at)? - b.origin).dot(n), ..b })
|
||||
}
|
||||
_ => ctx.doc.resolve_plane_in(ctx.vals, p, ctx.depth + 1, Some(ctx.st)),
|
||||
_ => ctx.doc.resolve_plane_in(ctx.vals, p, ctx.depth + 1, ctx.component, Some(ctx.st)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+134
-23
@@ -45,6 +45,9 @@ pub enum PlaneRef {
|
||||
Origin { name: String },
|
||||
/// An explicit plane (e.g. picked from a planar face).
|
||||
Custom { plane: Plane },
|
||||
/// An origin datum of an exact placement (its XY, XZ or YZ), found again on each evaluation
|
||||
/// so it follows the component the way a named plane does.
|
||||
Datum { datum: crate::construct::DatumRef },
|
||||
/// An explicit plane whose origin is given as length expressions
|
||||
/// (`{origin: ["half", 0, 0], normal: [1, 0, 0]}`), so it follows parameter changes.
|
||||
Placed {
|
||||
@@ -540,31 +543,68 @@ impl EmbossFace {
|
||||
|
||||
/// Resolve one saved component path without expanding other occurrences.
|
||||
pub fn component_frame(doc: &Document, owner: u64, path: &[u64]) -> Result<crate::Mat> {
|
||||
if path.len() > 64 || doc.occurrences.len() > 100_000 {
|
||||
return Err(DocError::Invalid("selected cylinder path exceeds work limits".into()));
|
||||
let frame = doc.placement_frame(path)?;
|
||||
match path.split_last() {
|
||||
None => Ok(doc.component_transform(owner)),
|
||||
Some((last, _)) => {
|
||||
let component = doc.occurrences.iter().find(|o| o.id == *last).map(|o| o.component);
|
||||
if component == Some(owner) {
|
||||
Ok(frame)
|
||||
} else {
|
||||
Err(DocError::Invalid("selected cylinder path belongs to another component".into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Document {
|
||||
/// The world frame of one exact placement, without expanding every occurrence: the frame
|
||||
/// every origin datum of the placement resolves in ([`crate::construct::resolve_datum`]).
|
||||
/// The empty path is the root design frame. The shared walk of an exact placement (the
|
||||
/// Emboss selection's `component_frame` delegates to it): depth at most 64, non-zero
|
||||
/// canonical ids, no id repeated in a path, at most 100 000 occurrences.
|
||||
pub fn placement_frame(&self, path: &[u64]) -> Result<crate::Mat> {
|
||||
if path.len() > 64 || self.occurrences.len() > 100_000 {
|
||||
return Err(DocError::Invalid("the placement path exceeds work limits".into()));
|
||||
}
|
||||
let mut frame = crate::IDENTITY;
|
||||
let mut component = 0;
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for id in path {
|
||||
if *id == 0 || !seen.insert(*id) {
|
||||
return Err(DocError::Invalid("invalid selected cylinder path".into()));
|
||||
return Err(DocError::Invalid("invalid placement path".into()));
|
||||
}
|
||||
let occurrence = doc
|
||||
let occurrence = self
|
||||
.occurrences
|
||||
.iter()
|
||||
.find(|o| o.id == *id && o.parent == component)
|
||||
.ok_or_else(|| DocError::Invalid("selected cylinder placement no longer exists".into()))?;
|
||||
.ok_or_else(|| DocError::Invalid("the placement no longer exists".into()))?;
|
||||
frame = crate::mat_mul(&frame, &occurrence.transform);
|
||||
component = occurrence.component;
|
||||
}
|
||||
if path.is_empty() {
|
||||
frame = doc.component_transform(owner);
|
||||
} else if component != owner {
|
||||
return Err(DocError::Invalid("selected cylinder path belongs to another component".into()));
|
||||
}
|
||||
Ok(frame)
|
||||
}
|
||||
|
||||
/// The complete occurrence path of one occurrence, root first (the ids
|
||||
/// [`Self::placement_frame`] walks): the occurrence itself, then its ancestors, each stepped
|
||||
/// through its parent component's first occurrence, as `occurrence_world` reads a parent.
|
||||
/// `None` when the occurrence is missing or its chain is broken, cyclic or deeper than 64.
|
||||
pub fn occurrence_path(&self, occurrence: u64) -> Option<Vec<u64>> {
|
||||
let mut path = Vec::new();
|
||||
let mut cur = occurrence;
|
||||
while let Some(o) = self.occurrences.iter().find(|o| o.id == cur) {
|
||||
if path.len() >= 64 {
|
||||
return None;
|
||||
}
|
||||
path.insert(0, o.id);
|
||||
if o.parent == 0 {
|
||||
return Some(path);
|
||||
}
|
||||
cur = self.occurrence_of(o.parent)?.id;
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// One edge of an edge flange feature: a point on the sheet's edge and, where given, this
|
||||
@@ -979,6 +1019,12 @@ pub enum FeatureKind {
|
||||
/// part changes. `position` keeps where it was placed.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
references: Vec<HoleReference>,
|
||||
/// Holes at sketch points as older builds drilled them: a point inside a body moves back
|
||||
/// to the body's surface whatever plane the sketch lies on. Designs saved before #11538
|
||||
/// carry it, so their holes rebuild where they were; new holes leave it off, and Edit
|
||||
/// Hole keeps it.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
old_surface_start: bool,
|
||||
},
|
||||
/// A thread on a cylindrical face. Cosmetic by default (no geometry change; drawn and
|
||||
/// exported as an annotation); `modeled` cuts the real helical ISO profile into the face.
|
||||
@@ -993,6 +1039,10 @@ pub enum FeatureKind {
|
||||
length: Option<Expr>,
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
modeled: bool,
|
||||
/// Continuous flank faces for this feature. Missing in older designs: keep
|
||||
/// their half-turn faces and groove-before-chamfer order for saved references.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
continuous_flanks: bool,
|
||||
/// A point near the end of the face the thread starts at; `None`: the face's only free
|
||||
/// end (no material past it), or the end the pick at `face` lies near.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -1043,13 +1093,19 @@ pub enum FeatureKind {
|
||||
#[serde(default, skip_serializing_if = "RailFit::is_scale")]
|
||||
rail_fit: RailFit,
|
||||
},
|
||||
/// Sweep profiles along a chain of sketch curves.
|
||||
/// Sweep profiles along a chain of sketch curves, or along a chain of a body's edges.
|
||||
Sweep {
|
||||
sketch: SketchId,
|
||||
#[walk(profiles_of = sketch)]
|
||||
profiles: ProfileSel,
|
||||
path_sketch: SketchId,
|
||||
path: Vec<String>,
|
||||
/// The path on a body's edges, instead of the curves of `path_sketch` (#2216): the body
|
||||
/// and a point on each edge of the chain.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
path_body: Option<BodyName>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
path_edges: Vec<Position>,
|
||||
/// How the profile turns along the path (default: perpendicular to it).
|
||||
#[serde(default, skip_serializing_if = "SweepOrientation::is_perpendicular")]
|
||||
orientation: SweepOrientation,
|
||||
@@ -1190,6 +1246,25 @@ pub enum FeatureKind {
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
targets: Vec<BodyName>,
|
||||
},
|
||||
/// Plates closing open ends of frame members (#4003), one body per end, each the outside of
|
||||
/// the member's profile, optionally set in from its edge.
|
||||
FrameEndCap {
|
||||
ends: Vec<crate::end_cap::End>,
|
||||
#[walk(length = "Thickness")]
|
||||
thickness: Expr,
|
||||
/// The inset from the outline's edge as a length, or `ratio` of the thickness; neither:
|
||||
/// flush with the outside of the profile.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[walk(length = "Inset")]
|
||||
offset: Option<Expr>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[walk(unitless = "Inset Ratio")]
|
||||
ratio: Option<Expr>,
|
||||
#[walk(length = "Corner Chamfer")]
|
||||
chamfer: Expr,
|
||||
#[serde(default)]
|
||||
direction: crate::end_cap::Direction,
|
||||
},
|
||||
/// Structural members (#4003): one body per straight line of a frame sketch (2D sketch lines
|
||||
/// and 3D sketch lines), its cross-section the profile, square to the line from end to end.
|
||||
FrameMember {
|
||||
@@ -1641,6 +1716,10 @@ pub enum FeatureKind {
|
||||
#[serde(default = "all_profiles")]
|
||||
#[walk(profiles_of = sketch)]
|
||||
profiles: ProfileSel,
|
||||
/// Indices into the sketch's planar 3D loops (`sketch.inspect`'s `profiles_3d`): each is
|
||||
/// patched in the plane it lies in (#741).
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
profiles_3d: Vec<usize>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
body: Option<BodyName>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
@@ -1748,6 +1827,12 @@ pub enum FeatureKind {
|
||||
curves: Vec<String>,
|
||||
path_sketch: SketchId,
|
||||
path: Vec<String>,
|
||||
/// The path on a body's edges, instead of the curves of `path_sketch` (#2216): the body
|
||||
/// and a point on each edge of the chain.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
path_body: Option<BodyName>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
path_edges: Vec<Position>,
|
||||
/// How the profile turns along the path (default: perpendicular to it).
|
||||
#[serde(default, skip_serializing_if = "SweepOrientation::is_perpendicular")]
|
||||
orientation: SweepOrientation,
|
||||
@@ -2733,6 +2818,7 @@ impl FeatureKind {
|
||||
FeatureKind::SurfaceOffset { .. } => "OffsetSurfaceFeature",
|
||||
FeatureKind::BoundingSolid { .. } => "BoundingSolidFeature",
|
||||
FeatureKind::Pipe { .. } => "PipeFeature",
|
||||
FeatureKind::FrameEndCap { .. } => "EndCapFeature",
|
||||
FeatureKind::FrameMember { .. } => "FrameMemberFeature",
|
||||
FeatureKind::Emboss { .. } => "EmbossFeature",
|
||||
FeatureKind::Boss { .. } => "BossFeature",
|
||||
@@ -2815,6 +2901,7 @@ impl FeatureKind {
|
||||
FeatureKind::DeleteFace { .. } => "delete_face",
|
||||
FeatureKind::BoundingSolid { .. } => "bounding_solid",
|
||||
FeatureKind::Pipe { .. } => "pipe",
|
||||
FeatureKind::FrameEndCap { .. } => "frame_end_cap",
|
||||
FeatureKind::FrameMember { .. } => "frame_member",
|
||||
FeatureKind::Emboss { .. } => "emboss",
|
||||
FeatureKind::Rib { .. } => "rib",
|
||||
@@ -2899,6 +2986,7 @@ impl FeatureKind {
|
||||
"OffsetSurfaceFeature" => "surface_offset",
|
||||
"BoundingSolidFeature" => "bounding_solid",
|
||||
"PipeFeature" => "pipe",
|
||||
"EndCapFeature" => "frame_end_cap",
|
||||
"FrameMemberFeature" => "frame_member",
|
||||
"EmbossFeature" => "emboss",
|
||||
"BossFeature" => "boss",
|
||||
@@ -2982,6 +3070,7 @@ impl FeatureKind {
|
||||
FeatureKind::SurfaceOffset { .. } => "OffsetSurface",
|
||||
FeatureKind::BoundingSolid { .. } => "BoundingSolid",
|
||||
FeatureKind::Pipe { .. } => "Pipe",
|
||||
FeatureKind::FrameEndCap { .. } => "EndCap",
|
||||
FeatureKind::FrameMember { .. } => "Member",
|
||||
FeatureKind::Emboss { .. } => "Emboss",
|
||||
FeatureKind::Boss { .. } => "Boss",
|
||||
@@ -3328,6 +3417,9 @@ pub struct Document {
|
||||
/// Named views: saved cameras.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub named_views: Vec<NamedView>,
|
||||
/// Notes: text anchored to points in model space, drawn as screen-facing callouts (#1631).
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub notes: Vec<crate::notes::Note>,
|
||||
/// What was hidden when the design was saved. A session takes it from here when the design
|
||||
/// opens and keeps the live state itself (`browser.visibility`: saved, and undone like any
|
||||
/// other change), so a document in a session leaves this empty; the session puts it back when
|
||||
@@ -3357,6 +3449,9 @@ pub struct Visibility {
|
||||
/// The browser's Origin folder is hidden (`None`: the app's preference decides).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub origin_hidden: Option<bool>,
|
||||
/// Component Origin folders explicitly shown, by complete occurrence path. Hidden by default.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub shown_component_origins: Vec<Vec<u64>>,
|
||||
/// Finished sketches whose closed profiles are not shaded, by feature id.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub hidden_profiles: Vec<u64>,
|
||||
@@ -3384,6 +3479,7 @@ impl Visibility {
|
||||
&& self.shown_sketches.is_empty()
|
||||
&& self.hidden_joints.is_empty()
|
||||
&& self.origin_hidden.is_none()
|
||||
&& self.shown_component_origins.is_empty()
|
||||
&& self.hidden_profiles.is_empty()
|
||||
&& self.shown_dimensions.is_empty()
|
||||
&& self.locked_bodies.is_empty()
|
||||
@@ -3566,10 +3662,12 @@ impl Document {
|
||||
.chain(self.timeline_groups.iter().map(|g| g.id))
|
||||
.chain(self.canvases.iter().map(|c| c.id))
|
||||
.chain(self.point_clouds.iter().map(|c| c.id))
|
||||
.chain(self.notes.iter().map(|n| n.id))
|
||||
.chain(a.joints.iter().map(|j| j.id))
|
||||
.chain(a.contact_sets.iter().map(|c| c.id))
|
||||
.chain(a.studies.iter().map(|s| s.id))
|
||||
.chain(a.exploded.iter().map(|v| v.id))
|
||||
.chain(self.configs.rows.iter().map(|r| r.id))
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
let floor = largest.checked_add(1).ok_or_else(|| DocError::Invalid("too many items in the design".into()))?;
|
||||
@@ -3621,6 +3719,7 @@ impl Document {
|
||||
timeline_groups: Vec::new(),
|
||||
browser_order: Default::default(),
|
||||
named_views: Vec::new(),
|
||||
notes: Vec::new(),
|
||||
visibility: Visibility::default(),
|
||||
}
|
||||
}
|
||||
@@ -3824,10 +3923,14 @@ impl Document {
|
||||
for b in &mut st.bodies {
|
||||
let c = self.body_color(b);
|
||||
let face_colors = if authored_faces { self.face_colors(b) } else { self.imported_face_colors(b) };
|
||||
let faces: Vec<solidcraft_kernel::FacePaint> =
|
||||
face_colors.into_iter().map(|(face, l)| solidcraft_kernel::FacePaint { face, color: l.rgb(), opacity: l.opacity as f32 }).collect();
|
||||
let faces: Vec<solidcraft_kernel::FacePaint> = face_colors
|
||||
.into_iter()
|
||||
.map(|(face, l)| solidcraft_kernel::FacePaint { face, color: l.rgb(), opacity: l.opacity as f32, name: l.file_name() })
|
||||
.collect();
|
||||
let opacity = self.model_body_opacity(b) as f32;
|
||||
let paint = solidcraft_kernel::Paint { opacity, faces };
|
||||
// The look's name goes with its colour (a STEP `COLOUR_RGB` name), so it comes back on import.
|
||||
let name = c.and_then(|_| self.model_display_look(b)).and_then(|l| l.file_name());
|
||||
let paint = solidcraft_kernel::Paint { opacity, faces, name };
|
||||
if c != b.body.color() || b.body.paint() != Some(&paint) {
|
||||
b.body = b.body.clone().with_color(c).with_paint(Some(paint));
|
||||
}
|
||||
@@ -4512,18 +4615,22 @@ impl Document {
|
||||
expr::eval_with(e, &|n| vals.get(n).copied().ok_or_else(|| DocError::Expr(format!("unknown parameter `{n}`"))))?.to_kind(kind)
|
||||
}
|
||||
|
||||
/// Resolve a plane reference.
|
||||
/// Resolve a plane reference (in the world: the root's frame).
|
||||
pub fn resolve_plane(&self, vals: &std::collections::BTreeMap<String, expr::Value>, p: &PlaneRef, depth: usize) -> Result<Plane> {
|
||||
self.resolve_plane_in(vals, p, depth, None)
|
||||
self.resolve_plane_in(vals, p, depth, 0, None)
|
||||
}
|
||||
|
||||
/// Resolve a plane; planes built from model geometry (edges, faces, construction axes and
|
||||
/// points) need the model state `st`, and construction planes are read from it when given.
|
||||
/// `component` is the frame the plane is read for: a component origin datum resolves as
|
||||
/// that component sees it ([`crate::construct::resolve_datum_in`]), since a feature places
|
||||
/// what it read into the world again through its own frame. The root (0) is the world.
|
||||
pub fn resolve_plane_in(
|
||||
&self,
|
||||
vals: &std::collections::BTreeMap<String, expr::Value>,
|
||||
p: &PlaneRef,
|
||||
depth: usize,
|
||||
component: u64,
|
||||
st: Option<&crate::ModelState>,
|
||||
) -> Result<Plane> {
|
||||
if depth > 32 {
|
||||
@@ -4543,17 +4650,21 @@ impl Document {
|
||||
}
|
||||
Plane::new(o, *x_dir, *y_dir).ok_or_else(|| DocError::Invalid("degenerate plane".into()))
|
||||
}
|
||||
PlaneRef::Datum { datum } => match crate::construct::resolve_datum_in(self, datum, component)? {
|
||||
crate::construct::ConstructGeom::Plane(p) => Ok(p),
|
||||
_ => Err(DocError::Invalid("the datum is not a plane (pick the XY, XZ or YZ of a component)".into())),
|
||||
},
|
||||
PlaneRef::Offset { base, distance } => {
|
||||
let b = self.resolve_plane_in(vals, base, depth + 1, st)?;
|
||||
let b = self.resolve_plane_in(vals, base, depth + 1, component, st)?;
|
||||
Ok(b.offset(Self::eval_in(vals, distance, Kind::Length)?))
|
||||
}
|
||||
PlaneRef::AtAngle { base, axis_origin, axis_dir, angle, line, direction_only, pivot } => {
|
||||
let b = self.resolve_plane_in(vals, base, depth + 1, st)?;
|
||||
let b = self.resolve_plane_in(vals, base, depth + 1, component, st)?;
|
||||
let a = Self::eval_in(vals, angle, Kind::Angle)?;
|
||||
let (axis_origin, axis_dir) = match line {
|
||||
Some(g) => {
|
||||
let st = st.ok_or_else(|| DocError::Invalid("this plane is built from the model: evaluate first".into()))?;
|
||||
crate::construct::model_axis(st, g)?
|
||||
crate::construct::model_axis_in(Some(self), st, g, component)?
|
||||
}
|
||||
None => (*axis_origin, *axis_dir),
|
||||
};
|
||||
@@ -4566,7 +4677,7 @@ impl Document {
|
||||
let pivot = match pivot {
|
||||
Some(g) => {
|
||||
let st = st.ok_or_else(|| DocError::Invalid("this plane is built from the model: evaluate first".into()))?;
|
||||
crate::construct::point(&crate::construct::Ctx { doc: self, vals, st, depth }, g)?
|
||||
crate::construct::point(&crate::construct::Ctx { doc: self, vals, st, depth, component }, g)?
|
||||
}
|
||||
None => b.origin,
|
||||
};
|
||||
@@ -4581,7 +4692,7 @@ impl Document {
|
||||
let o = axis_origin + rot(b.origin - axis_origin);
|
||||
Plane::new(o, rot(b.x), rot(b.y)).ok_or_else(|| DocError::Invalid("degenerate plane".into()))
|
||||
}
|
||||
PlaneRef::Flipped { base, about_y } => Ok(self.resolve_plane_in(vals, base, depth + 1, st)?.flipped(*about_y)),
|
||||
PlaneRef::Flipped { base, about_y } => Ok(self.resolve_plane_in(vals, base, depth + 1, component, st)?.flipped(*about_y)),
|
||||
PlaneRef::Construction { feature } => {
|
||||
// Evaluated already: as it came out.
|
||||
if let Some(c) = st.and_then(|st| st.construct.iter().find(|c| c.feature == feature.0))
|
||||
@@ -4590,7 +4701,7 @@ impl Document {
|
||||
return Ok(*pl);
|
||||
}
|
||||
match self.feature(feature.0).map(|f| &f.kind) {
|
||||
Some(FeatureKind::ConstructionPlane { plane }) => self.resolve_plane_in(vals, plane, depth + 1, st),
|
||||
Some(FeatureKind::ConstructionPlane { plane }) => self.resolve_plane_in(vals, plane, depth + 1, component, st),
|
||||
// A name that could not be resolved when an older design opened keeps id 0,
|
||||
// which no feature has (#1134): the reference dangles, as it always did.
|
||||
_ => {
|
||||
@@ -4608,7 +4719,7 @@ impl Document {
|
||||
| PlaneRef::Perpendicular { .. }
|
||||
| PlaneRef::ThroughPoint { .. } => {
|
||||
let st = st.ok_or_else(|| DocError::Invalid("this plane is built from the model: evaluate first".into()))?;
|
||||
crate::construct::resolve_geo_plane(&crate::construct::Ctx { doc: self, vals, st, depth }, p)
|
||||
crate::construct::resolve_geo_plane(&crate::construct::Ctx { doc: self, vals, st, depth, component }, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,582 @@
|
||||
//! End caps (#4003): a plate closing the open end of a frame member, its outline the member
|
||||
//! profile's outer outline set in from the edge, built from existing extrude and boolean
|
||||
//! operations.
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::expr::{Kind, Value};
|
||||
use crate::{DocError, Document, Feature, FeatureKind, ModelBody, ModelState, PlaneRef, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solidcore_record::{Loop2, Plane, Region2, Seg2, Vec2};
|
||||
use solidcraft_geom::prelude::*;
|
||||
use solidcraft_kernel::{self as kernel, BoolOp};
|
||||
|
||||
/// Most end faces one end cap feature closes.
|
||||
pub const MAX_FACES: usize = 256;
|
||||
|
||||
/// The member a capped face belongs to: its feature and line, which outlive body renames.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, solidcraft_derive::Walk)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Member {
|
||||
pub feature: crate::FeatureId,
|
||||
pub line: String,
|
||||
}
|
||||
|
||||
/// One capped end: the member's planar end face and the member it belongs to.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, solidcraft_derive::Walk)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct End {
|
||||
pub plane: PlaneRef,
|
||||
pub member: Member,
|
||||
}
|
||||
|
||||
/// Which way the cap goes from the end face.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, solidcraft_derive::Walk)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Direction {
|
||||
/// Past the end: the frame gets longer by the thickness.
|
||||
#[default]
|
||||
Outward,
|
||||
/// Into the member, which is cut back by the thickness: the frame keeps its length.
|
||||
Inward,
|
||||
}
|
||||
|
||||
fn invalid(s: impl Into<String>) -> DocError {
|
||||
DocError::Invalid(s.into())
|
||||
}
|
||||
|
||||
/// The member that `plane`'s face belongs to; an error when it is no frame member's face.
|
||||
pub fn member(doc: &Document, st: &ModelState, plane: &PlaneRef) -> Result<Member> {
|
||||
let PlaneRef::Face { anchor: Some(anchor), .. } = plane else { return Err(invalid("an end cap needs a planar face picked on a frame member")) };
|
||||
let source = doc.feature(anchor.target.origin_feature).ok_or_else(|| invalid("the capped member's feature no longer exists"))?;
|
||||
let FeatureKind::FrameMember { names, .. } = &source.kind else { return Err(invalid("the face is not on a frame member")) };
|
||||
let ids = crate::frame::member_line_ids(st, &source.kind)?;
|
||||
let line = if source.body_names.is_empty() {
|
||||
ids.iter().find(|line| names.get(*line).is_some_and(|name| *name == anchor.target.body))
|
||||
} else {
|
||||
source.body_names.iter().position(|name| *name == anchor.target.body).and_then(|i| ids.get(i))
|
||||
}
|
||||
.ok_or_else(|| invalid("the face is no longer on the member it was picked on"))?;
|
||||
Ok(Member { feature: source.id.into(), line: line.clone() })
|
||||
}
|
||||
|
||||
fn length(v: f64, what: &str, min: f64) -> Result<f64> {
|
||||
if !v.is_finite() || v > 1e6 || v < min {
|
||||
return Err(invalid(format!("the end cap's {what} must be a length from {min} to 1e6 mm")));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
/// Most edges in an outline an end cap follows.
|
||||
const MAX_EDGES: usize = 4096;
|
||||
|
||||
/// Where a segment of the outline goes when it moves in: a line through a point along a unit
|
||||
/// direction, or a circle.
|
||||
#[derive(Clone, Copy)]
|
||||
enum Carrier {
|
||||
Line(Vec2, Vec2),
|
||||
Circle(Vec2, f64),
|
||||
}
|
||||
|
||||
/// The points where two carriers cross.
|
||||
fn crossings(c1: Carrier, c2: Carrier) -> Vec<Vec2> {
|
||||
match (c1, c2) {
|
||||
(Carrier::Line(p1, t1), Carrier::Line(p2, t2)) => {
|
||||
let den = t1.cross(t2);
|
||||
if den.abs() < 1e-9 { Vec::new() } else { vec![p1 + t1 * ((p2 - p1).cross(t2) / den)] }
|
||||
}
|
||||
(Carrier::Line(p, t), Carrier::Circle(c, r)) | (Carrier::Circle(c, r), Carrier::Line(p, t)) => {
|
||||
let foot = p + t * (c - p).dot(t);
|
||||
let h2 = r * r - (c - foot).dot(c - foot);
|
||||
if h2 < -1e-9 * r.max(1.0) {
|
||||
return Vec::new();
|
||||
}
|
||||
let h = h2.max(0.0).sqrt();
|
||||
vec![foot - t * h, foot + t * h]
|
||||
}
|
||||
(Carrier::Circle(c1, r1), Carrier::Circle(c2, r2)) => {
|
||||
let dd = c1.dist(c2);
|
||||
if dd < 1e-12 {
|
||||
return Vec::new();
|
||||
}
|
||||
let u = (c2 - c1) / dd;
|
||||
let along = (r1 * r1 - r2 * r2 + dd * dd) / (2.0 * dd);
|
||||
let h2 = r1 * r1 - along * along;
|
||||
if h2 < -1e-9 * r1.max(1.0) {
|
||||
return Vec::new();
|
||||
}
|
||||
let h = h2.max(0.0).sqrt();
|
||||
let foot = c1 + u * along;
|
||||
vec![foot - u.perp() * h, foot + u.perp() * h]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// How far `p` is from segment `s` (a line or an arc).
|
||||
fn distance(s: &Seg2, p: Vec2) -> f64 {
|
||||
match *s {
|
||||
Seg2::Line { a, b } => {
|
||||
let ab = b - a;
|
||||
let l2 = ab.dot(ab);
|
||||
let u = if l2 > 0.0 { ((p - a).dot(ab) / l2).clamp(0.0, 1.0) } else { 0.0 };
|
||||
p.dist(a + ab * u)
|
||||
}
|
||||
Seg2::Arc { center, radius, start, sweep } => {
|
||||
let tau = std::f64::consts::TAU;
|
||||
let rel = (p - center).angle() - start;
|
||||
let u = if sweep >= 0.0 { rel.rem_euclid(tau) } else { (-rel).rem_euclid(tau) };
|
||||
if u <= sweep.abs() { (p.dist(center) - radius).abs() } else { p.dist(s.start()).min(p.dist(s.end())) }
|
||||
}
|
||||
_ => p.dist(s.start()).min(p.dist(s.end())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Points along `s`: a few on a line, more on an arc.
|
||||
fn samples(s: &Seg2) -> Vec<Vec2> {
|
||||
let k = match *s {
|
||||
Seg2::Arc { sweep, .. } => ((sweep.abs() / (std::f64::consts::PI / 32.0)).ceil() as usize).clamp(2, 128),
|
||||
_ => 8,
|
||||
};
|
||||
(0..=k).map(|i| s.point_at(i as f64 / k as f64)).collect()
|
||||
}
|
||||
|
||||
/// Whether two straight pieces cross (touching at their ends does not count).
|
||||
fn pieces_cross(a: Vec2, b: Vec2, c: Vec2, d: Vec2) -> bool {
|
||||
let (o1, o2) = ((b - a).cross(c - a), (b - a).cross(d - a));
|
||||
let (o3, o4) = ((d - c).cross(a - c), (d - c).cross(b - c));
|
||||
let eps = 1e-12 * (1.0 + a.dist(b) + c.dist(d)).powi(2);
|
||||
o1 * o2 < -eps && o3 * o4 < -eps
|
||||
}
|
||||
|
||||
/// Whether `lp`'s edges cross one another.
|
||||
fn crosses_itself(lp: &Loop2) -> bool {
|
||||
let pts: Vec<Vec2> = lp
|
||||
.segs
|
||||
.iter()
|
||||
.flat_map(|s| {
|
||||
let mut v = samples(s);
|
||||
v.pop();
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
let n = pts.len();
|
||||
for i in 0..n {
|
||||
for j in i + 2..n {
|
||||
if i == 0 && j + 1 == n {
|
||||
continue;
|
||||
}
|
||||
let (Some(&a), Some(&b), Some(&c), Some(&d)) = (pts.get(i), pts.get((i + 1) % n), pts.get(j), pts.get((j + 1) % n)) else {
|
||||
continue;
|
||||
};
|
||||
if pieces_cross(a, b, c, d) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// `outline`, a counter-clockwise loop of lines and arcs, moved in by `d` all round: lines move
|
||||
/// along their inward normal, arcs that bulge out lose `d` of radius and arcs that curve in (the
|
||||
/// root of an angle or a beam) gain it. An arc that shrinks away leaves its neighbours meeting
|
||||
/// at a corner. Any shape works: round and rectangular tubes as well as angles, channels and
|
||||
/// beams. An inset more than half a wall somewhere (an angle's leg, a beam's web) is refused.
|
||||
pub(crate) fn inset(outline: &Loop2, d: f64) -> Result<Loop2> {
|
||||
let no_plate = || {
|
||||
invalid(format!(
|
||||
"an inset of {} mm leaves no plate inside the profile's outline (it is more than half a wall somewhere)",
|
||||
crate::frame::short(d)
|
||||
))
|
||||
};
|
||||
if !d.is_finite() || d < 0.0 {
|
||||
return Err(invalid("the end cap's inset must be a length of 0 or more"));
|
||||
}
|
||||
let segs = &outline.segs;
|
||||
let n = segs.len();
|
||||
if n == 0 || outline.signed_area() <= 0.0 {
|
||||
return Err(invalid("the profile's outline has no area"));
|
||||
}
|
||||
if n > MAX_EDGES {
|
||||
return Err(invalid(format!("end caps follow outlines of at most {MAX_EDGES} edges")));
|
||||
}
|
||||
// A full circle (arcs on one circle): its radius shrinks.
|
||||
if let Some(Seg2::Arc { center, radius, .. }) = segs.first().copied()
|
||||
&& segs
|
||||
.iter()
|
||||
.all(|s| matches!(*s, Seg2::Arc { center: c, radius: r, sweep, .. } if c.dist(center) < 1e-9 && (r - radius).abs() < 1e-9 && sweep > 0.0))
|
||||
{
|
||||
return if radius - d > 1e-6 { Ok(Loop2::circle(center, radius - d)) } else { Err(no_plate()) };
|
||||
}
|
||||
let mut carriers = Vec::with_capacity(n);
|
||||
for s in segs {
|
||||
carriers.push(match *s {
|
||||
Seg2::Line { a, b } => {
|
||||
let t = (b - a).normalized().ok_or_else(|| invalid("the profile's outline has an edge of no length"))?;
|
||||
Some(Carrier::Line(a + t.perp() * d, t))
|
||||
}
|
||||
// Counter-clockwise arcs bulge out and shrink; clockwise ones curve in and grow.
|
||||
Seg2::Arc { center, radius, sweep, .. } if sweep.abs() > 1e-12 && radius > 0.0 => {
|
||||
let r = radius - d * sweep.signum();
|
||||
(r > 1e-6).then_some(Carrier::Circle(center, r))
|
||||
}
|
||||
Seg2::Arc { .. } => return Err(invalid("the profile's outline has an arc of no length")),
|
||||
_ => return Err(invalid("end caps follow outlines of lines and arcs (a spline or conic outline is not supported)")),
|
||||
});
|
||||
}
|
||||
let kept: Vec<usize> = (0..n).filter(|i| carriers.get(*i).is_some_and(Option::is_some)).collect();
|
||||
let m = kept.len();
|
||||
if m < 2 {
|
||||
return Err(no_plate());
|
||||
}
|
||||
// Where kept segment `k` starts: after a smooth join, the old point moved in; otherwise (a
|
||||
// corner, or arcs shrunk away between) where it meets the previous kept segment, nearest the
|
||||
// corner it replaces.
|
||||
let mut starts = Vec::with_capacity(m);
|
||||
for (j, &k) in kept.iter().enumerate() {
|
||||
let p = kept.get((j + m - 1) % m).copied().ok_or_else(no_plate)?;
|
||||
let (Some(prev), Some(this)) = (segs.get(p), segs.get(k)) else { return Err(no_plate()) };
|
||||
let (tin, tout) = (prev.end_tangent(), this.start_tangent());
|
||||
if (p + 1) % n == k && tin.cross(tout).abs() < 1e-7 && tin.dot(tout) > 0.0 {
|
||||
starts.push(this.start() + tout.perp() * d);
|
||||
continue;
|
||||
}
|
||||
let (Some(Some(c1)), Some(Some(c2))) = (carriers.get(p).copied(), carriers.get(k).copied()) else { return Err(no_plate()) };
|
||||
let near = prev.end().lerp(this.start(), 0.5);
|
||||
let best = crossings(c1, c2).into_iter().min_by(|a, b| a.dist(near).total_cmp(&b.dist(near))).ok_or_else(no_plate)?;
|
||||
starts.push(best);
|
||||
}
|
||||
let mut out = Vec::with_capacity(m);
|
||||
for (j, &k) in kept.iter().enumerate() {
|
||||
let (Some(&a), Some(&b)) = (starts.get(j), starts.get((j + 1) % m)) else { return Err(no_plate()) };
|
||||
match (segs.get(k).copied(), carriers.get(k).copied()) {
|
||||
(Some(Seg2::Line { a: oa, b: ob }), _) => {
|
||||
if (b - a).dot(ob - oa) <= 1e-6 * oa.dist(ob) || a.dist(b) < 1e-6 {
|
||||
return Err(no_plate());
|
||||
}
|
||||
out.push(Seg2::Line { a, b });
|
||||
}
|
||||
(Some(Seg2::Arc { sweep, .. }), Some(Some(Carrier::Circle(center, r)))) => {
|
||||
let tau = std::f64::consts::TAU;
|
||||
let (s, e) = ((a - center).angle(), (b - center).angle());
|
||||
let sw = if sweep > 0.0 { (e - s).rem_euclid(tau) } else { -(s - e).rem_euclid(tau) };
|
||||
// An arc turned inside out shows as one sweeping most of the way round.
|
||||
if sw.abs() < 1e-9 || sw.abs() > sweep.abs() + std::f64::consts::FRAC_PI_2 {
|
||||
return Err(no_plate());
|
||||
}
|
||||
out.push(Seg2::Arc { center, radius: r, start: s, sweep: sw });
|
||||
}
|
||||
_ => return Err(no_plate()),
|
||||
}
|
||||
}
|
||||
let lp = Loop2 { segs: out };
|
||||
// Every point of the plate's edge is at least `d` from the profile's: closer means the inset
|
||||
// reached across a wall thinner than twice the inset.
|
||||
let tol = 1e-6 * (1.0 + d);
|
||||
let far_enough = lp.segs.iter().flat_map(samples).all(|q| segs.iter().map(|s| distance(s, q)).fold(f64::INFINITY, f64::min) >= d - tol);
|
||||
if !(lp.signed_area() > 1e-6) || !far_enough || crosses_itself(&lp) {
|
||||
return Err(no_plate());
|
||||
}
|
||||
Ok(lp)
|
||||
}
|
||||
|
||||
/// `outline` (as [`inset`] makes it) with every outside corner cut by a chamfer `c` long along
|
||||
/// each edge, measured from where the edges meet. A rounded corner is cut away whole, so `c`
|
||||
/// must be at least as long as its rounding. Inside corners (the root of an angle or a beam)
|
||||
/// stay as they are.
|
||||
pub(crate) fn chamfered(outline: &Loop2, c: f64) -> Result<Loop2> {
|
||||
if !c.is_finite() || c < 0.0 {
|
||||
return Err(invalid("the end cap's chamfer must be a length of 0 or more"));
|
||||
}
|
||||
if c == 0.0 {
|
||||
return Ok(outline.clone());
|
||||
}
|
||||
let segs = &outline.segs;
|
||||
let n = segs.len();
|
||||
let round = || invalid("a round end cap has no corners to chamfer (set the chamfer to 0)");
|
||||
// The lines in order from the first; an outline with none is round.
|
||||
let first = segs.iter().position(|s| matches!(s, Seg2::Line { .. })).ok_or_else(round)?;
|
||||
let lines: Vec<usize> = (0..n).map(|i| (first + i) % n).filter(|i| matches!(segs.get(*i), Some(Seg2::Line { .. }))).collect();
|
||||
let k = lines.len();
|
||||
if k < 2 {
|
||||
return Err(round());
|
||||
}
|
||||
let line = |i: usize| -> Result<(Vec2, Vec2, Vec2)> {
|
||||
match lines.get(i % k).and_then(|j| segs.get(*j)).copied() {
|
||||
Some(Seg2::Line { a, b }) => Ok((a, b, (b - a).normalized().ok_or_else(|| invalid("the end cap's outline has an edge of no length"))?)),
|
||||
_ => Err(invalid("the end cap's outline lost an edge")),
|
||||
}
|
||||
};
|
||||
// The segments between line `i` and the next line.
|
||||
let between = |i: usize| -> Vec<Seg2> {
|
||||
let (Some(&a), Some(&b)) = (lines.get(i % k), lines.get((i + 1) % k)) else { return Vec::new() };
|
||||
let count = (b + n - a - 1) % n;
|
||||
(1..=count).filter_map(|o| segs.get((a + o) % n).copied()).collect()
|
||||
};
|
||||
// Each line's corner at its end, where chamfered: an outside corner, sharp or rounded by arcs
|
||||
// that bulge out.
|
||||
let mut corners = Vec::with_capacity(k);
|
||||
for i in 0..k {
|
||||
let (a1, b1, t1) = line(i)?;
|
||||
let (a2, _, t2) = line(i + 1)?;
|
||||
let den = t1.cross(t2);
|
||||
let outside = den > 1e-9 && between(i).iter().all(|s| matches!(*s, Seg2::Arc { sweep, .. } if sweep > 0.0));
|
||||
if !outside {
|
||||
corners.push(None);
|
||||
continue;
|
||||
}
|
||||
let v = a1 + t1 * ((a2 - a1).cross(t2) / den);
|
||||
let setback = v.dist(b1).max(v.dist(a2));
|
||||
if c + 1e-9 < setback {
|
||||
return Err(invalid(format!(
|
||||
"the chamfer must be at least the corner rounding it cuts away ({} mm), or 0",
|
||||
crate::frame::short(setback)
|
||||
)));
|
||||
}
|
||||
corners.push(Some((v - t1 * c, v + t2 * c)));
|
||||
}
|
||||
if corners.iter().all(Option::is_none) {
|
||||
return Err(invalid("the end cap has no outside corners to chamfer (set the chamfer to 0)"));
|
||||
}
|
||||
let too_large = || invalid("the chamfer is too large for the end cap's edges");
|
||||
let mut out = Vec::with_capacity(2 * n);
|
||||
for i in 0..k {
|
||||
let (a, b, t) = line(i)?;
|
||||
let start = match corners.get((i + k - 1) % k) {
|
||||
Some(Some((_, s))) => *s,
|
||||
_ => a,
|
||||
};
|
||||
let end = match corners.get(i) {
|
||||
Some(Some((e, _))) => *e,
|
||||
_ => b,
|
||||
};
|
||||
if (end - start).dot(t) <= 1e-6 {
|
||||
return Err(too_large());
|
||||
}
|
||||
out.push(Seg2::Line { a: start, b: end });
|
||||
match corners.get(i) {
|
||||
Some(Some((e, s))) => out.push(Seg2::Line { a: *e, b: *s }),
|
||||
_ => out.extend(between(i)),
|
||||
}
|
||||
}
|
||||
let lp = Loop2 { segs: out };
|
||||
if !(lp.signed_area() > 1e-6) || crosses_itself(&lp) {
|
||||
return Err(too_large());
|
||||
}
|
||||
Ok(lp)
|
||||
}
|
||||
|
||||
/// A free body name for the cap on `member`: `<member> End Cap`, then `… (2)`, `… (3)`…
|
||||
fn cap_name(st: &mut ModelState, f: &Feature, k: usize, member: &str) -> String {
|
||||
if f.body_names.get(k).is_some_and(|n| !n.is_empty()) {
|
||||
return crate::eval::new_name(st, f, k);
|
||||
}
|
||||
let base = format!("{member} End Cap");
|
||||
// Not a name the design keeps for a suppressed feature or a rename (#4302, #4957): a cap
|
||||
// made while another is suppressed must not take that one's name. Nor one another end of
|
||||
// this cap has stored, which is built after this one when an end is added before it.
|
||||
let tries = st.bodies.len() + st.reserved_body_names.len() + f.body_names.len() + 2;
|
||||
(1..=tries)
|
||||
.map(|i| if i == 1 { base.clone() } else { format!("{base} ({i})") })
|
||||
.find(|n| st.body(n).is_none() && !st.reserved_body_names.contains(n) && !f.body_names.contains(n))
|
||||
.unwrap_or(base)
|
||||
}
|
||||
|
||||
/// A capped end, worked out before any body changes.
|
||||
struct Planned {
|
||||
body: String,
|
||||
plane: Plane,
|
||||
region: Region2,
|
||||
/// The cap's extent along the plane's normal, and the slab cut from an inward cap's member.
|
||||
cap: (f64, f64),
|
||||
cut: Option<(Region2, f64, f64)>,
|
||||
/// The cap's frame to the member body's own: the cap is authored in this feature's frame, the
|
||||
/// member is stored in its component's (moved by its body offset), and the cut is made there.
|
||||
to_member: crate::Mat,
|
||||
}
|
||||
|
||||
pub(crate) fn evaluate(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &mut ModelState) -> Result<()> {
|
||||
let FeatureKind::FrameEndCap { ends, thickness, offset, ratio, chamfer, direction } = &f.kind else {
|
||||
return Err(invalid("not an end cap"));
|
||||
};
|
||||
if ends.is_empty() {
|
||||
return Err(invalid("pick at least one open end face of a frame member"));
|
||||
}
|
||||
if ends.len() > MAX_FACES {
|
||||
return Err(invalid(format!("at most {MAX_FACES} end faces in one end cap feature")));
|
||||
}
|
||||
let t = length(crate::eval::val(vals, thickness, Kind::Length)?, "thickness", 0.01)?;
|
||||
let d = match (offset, ratio) {
|
||||
(Some(e), None) => length(crate::eval::val(vals, e, Kind::Length)?, "inset", 0.0)?,
|
||||
(None, Some(e)) => {
|
||||
let r = crate::eval::val(vals, e, Kind::Unitless)?;
|
||||
if !r.is_finite() || !(0.0..=1000.0).contains(&r) {
|
||||
return Err(invalid("the end cap's inset ratio must be from 0 to 1000 times the thickness"));
|
||||
}
|
||||
r * t
|
||||
}
|
||||
// Neither: flush with the outside of the profile.
|
||||
(None, None) => 0.0,
|
||||
_ => return Err(invalid("give the end cap's inset as either a length or a ratio of the thickness, not both")),
|
||||
};
|
||||
let c = length(crate::eval::val(vals, chamfer, Kind::Length)?, "chamfer", 0.0)?;
|
||||
let mut planned = Vec::with_capacity(ends.len());
|
||||
for end in ends {
|
||||
let PlaneRef::Face { anchor: Some(anchor), .. } = &end.plane else {
|
||||
return Err(invalid("an end cap needs a planar face picked on a frame member"));
|
||||
};
|
||||
if member(doc, st, &end.plane)? != end.member {
|
||||
return Err(invalid("the capped face is no longer on the member it was picked on"));
|
||||
}
|
||||
let face = doc.resolve_face_anchor(anchor, f.component, st).map_err(|e| invalid(format!("the capped end face: {e}")))?;
|
||||
let body = st.body(&anchor.target.body).ok_or_else(|| invalid("the capped member's body no longer exists"))?;
|
||||
let source = doc.feature(end.member.feature.0).ok_or_else(|| invalid("the capped member's feature no longer exists"))?;
|
||||
let (section, len, region) = crate::eval::frame_member::member_section(doc, vals, source, st, &end.member.line)?;
|
||||
let to_author = anchor.source_to_author(doc, f.component, body)?;
|
||||
let section = Plane::new(
|
||||
crate::apply_point(&to_author, section.origin),
|
||||
crate::apply_vector(&to_author, section.x),
|
||||
crate::apply_vector(&to_author, section.y),
|
||||
)
|
||||
.ok_or_else(|| invalid("the member's placement is degenerate"))?;
|
||||
let along = section.normal();
|
||||
let facing = face.normal().dot(along);
|
||||
if facing.abs() < 1.0 - 1e-7 {
|
||||
return Err(invalid("the picked face is not an end of the member (it is not square to the member's line)"));
|
||||
}
|
||||
let plane = Plane::new(section.origin + along * (face.origin - section.origin).dot(along), section.x, section.y)
|
||||
.ok_or_else(|| invalid("the end face's plane is degenerate"))?;
|
||||
// The same end, however it was picked (another point on its face, another anchor): the
|
||||
// same body with an earlier cap on this exact end plane.
|
||||
let same_end = |p: &Planned| {
|
||||
p.body == anchor.target.body && p.plane.origin.dist(plane.origin) < 1e-6 && p.plane.normal().dot(plane.normal()).abs() > 1.0 - 1e-9
|
||||
};
|
||||
if planned.iter().any(same_end) {
|
||||
return Err(invalid("an end face is picked twice"));
|
||||
}
|
||||
let outline = chamfered(&inset(&cap_outline(®ion.outer), d)?, c)?;
|
||||
let cap_region = Region2 { outer: outline, holes: Vec::new() };
|
||||
// Along the plane's normal: the member lies behind an end facing that way.
|
||||
let s = facing.signum();
|
||||
let (cap, cut) = match direction {
|
||||
Direction::Outward => (if s > 0.0 { (0.0, t) } else { (-t, 0.0) }, None),
|
||||
Direction::Inward => {
|
||||
if t >= len - 1e-3 {
|
||||
return Err(invalid(format!("an inward end cap {} mm thick needs a longer member", crate::frame::short(t))));
|
||||
}
|
||||
// A slab wider than the profile and past the end, so no face of it lies on the
|
||||
// member's.
|
||||
let bb = region.outer.polyline(1e-3).bounds();
|
||||
let m = 1.0 + 0.01 * (bb.max - bb.min).len();
|
||||
let (lo, hi) = (bb.min - Vec2::new(m, m), bb.max + Vec2::new(m, m));
|
||||
let slab = Region2 { outer: Loop2::polygon(&[lo, Vec2::new(hi.x, lo.y), hi, Vec2::new(lo.x, hi.y)]), holes: Vec::new() };
|
||||
let (a, b) = if s > 0.0 { (-t, m) } else { (-m, t) };
|
||||
(if s > 0.0 { (-t, 0.0) } else { (0.0, t) }, Some((slab, a, b)))
|
||||
}
|
||||
};
|
||||
let to_member = crate::mat_inverse(&to_author).ok_or_else(|| invalid("the member's placement is degenerate"))?;
|
||||
planned.push(Planned { body: anchor.target.body.clone(), plane, region: cap_region, cap, cut, to_member });
|
||||
}
|
||||
for (k, p) in planned.into_iter().enumerate() {
|
||||
if let Some((slab, a, b)) = &p.cut {
|
||||
let i = st.bodies.iter().position(|b| b.name == p.body).ok_or_else(|| invalid("the capped member's body no longer exists"))?;
|
||||
let mb = st.bodies.get(i).cloned().ok_or_else(|| invalid("the capped member's body no longer exists"))?;
|
||||
let at = Plane::new(
|
||||
crate::apply_point(&p.to_member, p.plane.origin),
|
||||
crate::apply_vector(&p.to_member, p.plane.x),
|
||||
crate::apply_vector(&p.to_member, p.plane.y),
|
||||
)
|
||||
.ok_or_else(|| invalid("the member's placement is degenerate"))?;
|
||||
let tool = one(kernel::extrude(&at, std::slice::from_ref(slab), *a, *b)?)?;
|
||||
let tool = crate::lineage::numbered_tool(tool);
|
||||
let cut = kernel::boolean(&mb.body, &tool.body, BoolOp::Cut)?
|
||||
.ok_or_else(|| invalid("cutting the member back for an inward end cap left nothing"))?;
|
||||
let cut = crate::lineage::Traced::step(cut, &[&mb.traced(), &tool]);
|
||||
if let Some(slot) = st.bodies.get_mut(i) {
|
||||
*slot = mb.remade(cut);
|
||||
}
|
||||
}
|
||||
let body = one(kernel::extrude(&p.plane, std::slice::from_ref(&p.region), p.cap.0, p.cap.1)?)?;
|
||||
let name = cap_name(st, f, k, &p.body);
|
||||
st.bodies.push(ModelBody::traced_new(name, crate::lineage::numbered_tool(body), f.id));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The outline an end cap is cut from: the outside of the profile. A closed section (a tube, a
|
||||
/// pipe, a bar) keeps its own outline. An open section that turns inward somewhere (an angle, a
|
||||
/// channel, a beam, an extrusion with slots) keeps the edges on its bounding rectangle and the
|
||||
/// rounds and chamfers turning between them, and bridges each inward stretch along the
|
||||
/// rectangle, so the plate closes the whole end with the profile's own outside corners.
|
||||
pub(crate) fn cap_outline(outer: &Loop2) -> Loop2 {
|
||||
let ring = outer.polyline(1e-3);
|
||||
let convex = ring.corners().all(|(p, c, n)| (*c - *p).cross(*n - *c) >= -1e-9);
|
||||
if convex {
|
||||
return outer.clone();
|
||||
}
|
||||
let bb = ring.bounds();
|
||||
let rect = Loop2::polygon(&[bb.min, Vec2::new(bb.max.x, bb.min.y), bb.max, Vec2::new(bb.min.x, bb.max.y)]);
|
||||
let tol = 1e-6 * (1.0 + bb.max.dist(bb.min));
|
||||
// How far a point is off each side of the rectangle (0 bottom, 1 right, 2 top, 3 left,
|
||||
// counter-clockwise); a line lies on a side when both its ends do.
|
||||
let off = |q: Vec2| [(q.y - bb.min.y).abs(), (q.x - bb.max.x).abs(), (q.y - bb.max.y).abs(), (q.x - bb.min.x).abs()];
|
||||
let on_side = |s: &Seg2| match *s {
|
||||
Seg2::Line { a, b } => (0..4).find(|i| off(a).get(*i).is_some_and(|e| *e < tol) && off(b).get(*i).is_some_and(|e| *e < tol)),
|
||||
_ => None,
|
||||
};
|
||||
let segs = &outer.segs;
|
||||
let n = segs.len();
|
||||
let sides: Vec<Option<usize>> = segs.iter().map(on_side).collect();
|
||||
let Some(first) = sides.iter().position(Option::is_some) else { return rect };
|
||||
let corner = |i: usize| [Vec2::new(bb.max.x, bb.min.y), bb.max, Vec2::new(bb.min.x, bb.max.y), bb.min].get(i % 4).copied();
|
||||
let mut out: Vec<Seg2> = Vec::with_capacity(n + 4);
|
||||
let mut i = first;
|
||||
for _ in 0..n {
|
||||
let (Some(&seg), Some(&Some(si))) = (segs.get(i), sides.get(i)) else { return rect };
|
||||
out.push(seg);
|
||||
// The stretch up to the next edge on the rectangle.
|
||||
let mut j = (i + 1) % n;
|
||||
let mut run = Vec::new();
|
||||
while sides.get(j).is_some_and(Option::is_none) {
|
||||
run.push(j);
|
||||
j = (j + 1) % n;
|
||||
}
|
||||
let (Some(&next), Some(&Some(sj))) = (segs.get(j), sides.get(j)) else { return rect };
|
||||
// Kept when it only turns outward from one side to the next: a round or a chamfer.
|
||||
let mut chain = vec![seg];
|
||||
chain.extend(run.iter().filter_map(|k| segs.get(*k).copied()));
|
||||
chain.push(next);
|
||||
let turns_out = chain.windows(2).all(|w| matches!(w, [a, b] if a.end_tangent().cross(b.start_tangent()) >= -1e-9))
|
||||
&& chain.iter().all(|s| !matches!(*s, Seg2::Arc { sweep, .. } if sweep < 0.0));
|
||||
if !run.is_empty() && turns_out && sj == (si + 1) % 4 {
|
||||
out.extend(run.iter().filter_map(|k| segs.get(*k).copied()));
|
||||
} else if !run.is_empty() || seg.end().dist(next.start()) > tol {
|
||||
// Along the rectangle from this side round to the next one's.
|
||||
let mut p = seg.end();
|
||||
let steps = (sj + 4 - si) % 4;
|
||||
let steps = if steps == 0 && (next.start() - p).dot(corner(si).unwrap_or(p) - p) < 0.0 { 4 } else { steps };
|
||||
for k in 0..steps {
|
||||
let Some(c) = corner(si + k) else { return rect };
|
||||
if p.dist(c) > tol {
|
||||
out.push(Seg2::Line { a: p, b: c });
|
||||
}
|
||||
p = c;
|
||||
}
|
||||
if p.dist(next.start()) > tol {
|
||||
out.push(Seg2::Line { a: p, b: next.start() });
|
||||
}
|
||||
}
|
||||
if j == first {
|
||||
break;
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
let lp = Loop2 { segs: out };
|
||||
if lp.signed_area() > 0.0 && lp.is_closed(tol) && !crosses_itself(&lp) { lp } else { rect }
|
||||
}
|
||||
|
||||
fn one(mut bodies: Vec<solidcraft_kernel::Body>) -> Result<solidcraft_kernel::Body> {
|
||||
let body = bodies.pop().ok_or_else(|| invalid("the end cap is not one solid"))?;
|
||||
if !bodies.is_empty() {
|
||||
return Err(invalid("the end cap is not one solid"));
|
||||
}
|
||||
Ok(body)
|
||||
}
|
||||
+2226
-539
File diff suppressed because it is too large
Load Diff
@@ -132,8 +132,8 @@ fn joint_face_measurements_are_shared_across_motion_samples_and_snap_kinds() {
|
||||
id: 100,
|
||||
name: "Pivot".into(),
|
||||
kind: JointKind::Revolute,
|
||||
a: JointOrigin { occurrence: 0, snap: Snap::Frame { origin: pick, z: Vec3::Z, x: Some(Vec3::X) } },
|
||||
b: JointOrigin { occurrence, snap: Snap::FaceCenter { pick, face: None, x: Some(XRef::Dir(Vec3::X)) } },
|
||||
a: JointOrigin::new(0, Snap::Frame { origin: pick, z: Vec3::Z, x: Some(Vec3::X) }),
|
||||
b: JointOrigin::new(occurrence, Snap::FaceCenter { pick, face: None, x: Some(XRef::Dir(Vec3::X)) }),
|
||||
values: vec![0.0],
|
||||
limits: Vec::new(),
|
||||
flip: true,
|
||||
@@ -141,6 +141,8 @@ fn joint_face_measurements_are_shared_across_motion_samples_and_snap_kinds() {
|
||||
angle: 0.0,
|
||||
suppressed: false,
|
||||
exprs: Default::default(),
|
||||
captured: None,
|
||||
constraint: None,
|
||||
});
|
||||
// One body supplies both old nearest-face snaps and persistent named-face snaps.
|
||||
// A scratch model shares its measurements, even though each sample changes the pose.
|
||||
@@ -181,7 +183,7 @@ fn joint_face_measurements_never_follow_a_replaced_body_or_stale_offset() {
|
||||
let mut doc = Document::new("replaced joint geometry");
|
||||
let mut state = ModelState::default();
|
||||
state.bodies.push(ModelBody::new("Pin".into(), kernel::cylinder(Vec3::ZERO, Vec3::Z, 2.0, 10.0).unwrap(), 0));
|
||||
let origin = JointOrigin { occurrence: 0, snap: Snap::FaceCenter { pick: Vec3::new(0.0, 0.0, 10.0), face: None, x: None } };
|
||||
let origin = JointOrigin::new(0, Snap::FaceCenter { pick: Vec3::new(0.0, 0.0, 10.0), face: None, x: None });
|
||||
let work = counted(|| {
|
||||
joints::resolve_origin(&doc, &state, &origin).unwrap();
|
||||
});
|
||||
@@ -210,7 +212,7 @@ fn an_edge_origin_measures_its_faces_once() {
|
||||
let mut state = ModelState::default();
|
||||
state.bodies.push(ModelBody::new("Block".into(), kernel::box_solid(Vec3::ZERO, Vec3::new(10.0, 10.0, 10.0)).unwrap(), 0));
|
||||
let pick = Vec3::new(5.0, 0.0, 10.0);
|
||||
let origin = JointOrigin { occurrence: 0, snap: Snap::Edge { pick, edge: None, face: None, corner: None, axis: None } };
|
||||
let origin = JointOrigin::new(0, Snap::Edge { pick, edge: None, face: None, corner: None, axis: None });
|
||||
let work = counted(|| {
|
||||
for _ in 0..8 {
|
||||
let frame = joints::resolve_origin(&doc, &state.clone(), &origin).unwrap();
|
||||
@@ -1412,6 +1414,7 @@ fn marking(p: Vec3) -> FeatureKind {
|
||||
chamfer_angle: None,
|
||||
chamfer_depth: None,
|
||||
steep_flank: Default::default(),
|
||||
continuous_flanks: false,
|
||||
old_auto_size: false,
|
||||
}
|
||||
}
|
||||
@@ -1453,6 +1456,7 @@ fn a_tap_marking_searches_only_the_bodies_near_it() {
|
||||
ease_out: None,
|
||||
to: None,
|
||||
references: Vec::new(),
|
||||
old_surface_start: false,
|
||||
};
|
||||
let (work, threads) = marking_work(&mut doc, hole);
|
||||
assert_eq!(work.cylinder_search, 1, "only the plate is searched");
|
||||
@@ -1570,6 +1574,7 @@ fn a_tapped_hole_reads_the_bodies_along_its_drill_line() {
|
||||
ease_out: None,
|
||||
to: None,
|
||||
references: Vec::new(),
|
||||
old_surface_start: false,
|
||||
};
|
||||
let (work, threads) = marking_work(&mut doc, hole);
|
||||
assert_eq!(work.tapped_wall, 3, "Plate, Below and Grazing are read");
|
||||
@@ -1999,3 +2004,71 @@ fn a_hole_classifies_the_faces_it_reads_not_every_face_of_the_design() {
|
||||
let side = super::hole_direction_at(&st, Vec3::new(252.0, 0.0, 5.0), &[]).unwrap();
|
||||
assert!((side - Vec3::new(-1.0, 0.0, 0.0)).len() < 1e-6, "into the side wall: {side:?}");
|
||||
}
|
||||
|
||||
/// A cut whose target name is taken by another component's sheet, while a body of the cut's own
|
||||
/// component was asked for that name, is refused before the sheet is machined (#12141).
|
||||
#[test]
|
||||
fn an_ambiguous_target_is_refused_before_a_sheet_is_machined() {
|
||||
let mut doc = Document::new("names");
|
||||
let linked = doc.add_component(Some("Encoder"), 0).unwrap();
|
||||
let local = doc.add_component(Some("Assembly"), 0).unwrap();
|
||||
flat_sheet(&mut doc, Vec2::new(0.0, 0.0), 40.0, 40.0);
|
||||
for f in doc.features.iter_mut() {
|
||||
f.component = linked;
|
||||
}
|
||||
let base = doc.features.last().unwrap().id;
|
||||
doc.feature_mut(base).unwrap().body_names = vec!["Plate".into()];
|
||||
let own = doc
|
||||
.add_feature(
|
||||
FeatureKind::Box {
|
||||
corner: point_expr(Vec3::new(100.0, 0.0, 0.0)),
|
||||
length: "10".into(),
|
||||
width: "10".into(),
|
||||
height: "2".into(),
|
||||
operation: Operation::NewBody,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
doc.feature_mut(own).unwrap().component = local;
|
||||
doc.feature_mut(own).unwrap().body_names = vec!["Plate".into()];
|
||||
let cut = doc
|
||||
.add_feature(
|
||||
FeatureKind::Box {
|
||||
corner: point_expr(Vec3::new(10.0, 10.0, -5.0)),
|
||||
length: "5".into(),
|
||||
width: "5".into(),
|
||||
height: "20".into(),
|
||||
operation: Operation::Cut,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
doc.feature_mut(cut).unwrap().component = local;
|
||||
doc.feature_mut(cut).unwrap().participants = vec!["Plate".into()];
|
||||
let mut model = Model::new();
|
||||
model.evaluate(&doc);
|
||||
let err = model.result(cut).and_then(|r| r.error.clone()).expect("the cut is refused");
|
||||
assert!(err.contains("ambiguous") && err.contains("`Encoder`"), "{err}");
|
||||
let st = model.state();
|
||||
let sheet = st.sheets.iter().find(|s| s.body == "Plate").expect("the linked sheet");
|
||||
assert!(sheet.holes.is_empty(), "the linked sheet is not machined");
|
||||
}
|
||||
|
||||
/// A hole's look at the material over its entry face (#10695) is best effort: when the kernel
|
||||
/// cannot build the run-on's column (here a column of no width), the hole keeps its full run-on
|
||||
/// and cuts nothing out of its tools, as before the check, instead of failing.
|
||||
#[test]
|
||||
fn a_hole_whose_run_on_column_cannot_be_built_keeps_its_run_on() {
|
||||
let mut state = ModelState::default();
|
||||
state.bodies.push(ModelBody::new("Over".into(), kernel::box_solid(Vec3::new(-5.0, -5.0, 0.5), Vec3::new(5.0, 5.0, 2.0)).unwrap(), 0));
|
||||
for reach in [0.0, f64::NAN] {
|
||||
let (top, near) = super::hole_run_on(&state, &Plane::XY, reach, 1.0);
|
||||
assert_eq!(top, 1.0, "reach {reach}");
|
||||
assert!(near.is_empty(), "reach {reach}");
|
||||
}
|
||||
// With a column, the body 0.5 over the face halves the run-on to its gap.
|
||||
let (top, near) = super::hole_run_on(&state, &Plane::XY, 3.0, 1.0);
|
||||
assert!((top - 0.25).abs() < 1e-6, "top {top}");
|
||||
assert!(near.is_empty());
|
||||
}
|
||||
|
||||
@@ -25,23 +25,10 @@ const STRAIGHT_TOL: f64 = 1e-3;
|
||||
/// Evaluate a `FrameMember` feature: one new body per line, each named
|
||||
/// ([`member_names`], or by position for a copy whose `body_names` were set).
|
||||
pub(super) fn evaluate(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &mut ModelState) -> Result<()> {
|
||||
let FeatureKind::FrameMember { path_sketch, lines, profile, anchor, angle, mirror, body_name, names } = &f.kind else {
|
||||
let FeatureKind::FrameMember { body_name, names, .. } = &f.kind else {
|
||||
return Err(DocError::Invalid("not a frame member feature".into()));
|
||||
};
|
||||
let ps = st.sketch(path_sketch.0).ok_or_else(|| DocError::Unknown(format!("sketch {path_sketch} (it must come earlier in the timeline)")))?;
|
||||
// The frame sketch in this feature's component frame: its plane, and its 3D lines.
|
||||
let mapped =
|
||||
if ps.sketch.wires.is_empty() { Cow::Owned(sketch_in_feature_frame(doc, ps, f.component)?) } else { path_in_frame(doc, ps, f.component)? };
|
||||
let segments = member_lines(mapped.as_ref(), lines)?;
|
||||
let (mut regions, description) = profile_regions(vals, st, profile)?;
|
||||
if *mirror {
|
||||
regions = regions.iter().map(frame::mirrored).collect();
|
||||
}
|
||||
let at = frame::anchor_point(®ions, *anchor);
|
||||
let turn = match angle {
|
||||
Some(e) => val(vals, e, Kind::Angle)?,
|
||||
None => 0.0,
|
||||
};
|
||||
let Layout { segments, regions, description, at, turn } = layout(doc, vals, f, st)?;
|
||||
let mut made = Vec::with_capacity(segments.len());
|
||||
for (id, a, b) in &segments {
|
||||
let (x, y) = frame::member_axes(*b - *a, turn).ok_or_else(|| DocError::Invalid(format!("line `{id}` has no length")))?;
|
||||
@@ -70,6 +57,54 @@ pub(super) fn evaluate(doc: &Document, vals: &BTreeMap<String, Value>, f: &Featu
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A member feature's lines (in its component frame), profile regions, default name, the
|
||||
/// profile point that sits on the lines and the profile's turn about them.
|
||||
struct Layout {
|
||||
segments: Vec<(String, Vec3, Vec3)>,
|
||||
regions: Vec<Region2>,
|
||||
description: String,
|
||||
at: Vec2,
|
||||
turn: f64,
|
||||
}
|
||||
|
||||
fn layout(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &ModelState) -> Result<Layout> {
|
||||
let FeatureKind::FrameMember { path_sketch, lines, profile, anchor, angle, mirror, .. } = &f.kind else {
|
||||
return Err(DocError::Invalid("not a frame member feature".into()));
|
||||
};
|
||||
let ps = st.sketch(path_sketch.0).ok_or_else(|| DocError::Unknown(format!("sketch {path_sketch} (it must come earlier in the timeline)")))?;
|
||||
// The frame sketch in this feature's component frame: its plane, and its 3D lines.
|
||||
let mapped =
|
||||
if ps.sketch.wires.is_empty() { Cow::Owned(sketch_in_feature_frame(doc, ps, f.component)?) } else { path_in_frame(doc, ps, f.component)? };
|
||||
let segments = member_lines(mapped.as_ref(), lines)?;
|
||||
let (mut regions, description) = profile_regions(vals, st, profile)?;
|
||||
if *mirror {
|
||||
regions = regions.iter().map(frame::mirrored).collect();
|
||||
}
|
||||
let at = frame::anchor_point(®ions, *anchor);
|
||||
let turn = match angle {
|
||||
Some(e) => val(vals, e, Kind::Angle)?,
|
||||
None => 0.0,
|
||||
};
|
||||
Ok(Layout { segments, regions, description, at, turn })
|
||||
}
|
||||
|
||||
/// The member of feature `f` on line `line`, as its body was made: the plane square to the line
|
||||
/// at its start (x × y along the line), its length, and its profile in that plane.
|
||||
pub(crate) fn member_section(
|
||||
doc: &Document,
|
||||
vals: &BTreeMap<String, Value>,
|
||||
f: &Feature,
|
||||
st: &ModelState,
|
||||
line: &str,
|
||||
) -> Result<(Plane, f64, Region2)> {
|
||||
let Layout { segments, regions, at, turn, .. } = layout(doc, vals, f, st)?;
|
||||
let (_, a, b) = segments.iter().find(|(id, _, _)| id == line).ok_or_else(|| DocError::Unknown(format!("line `{line}` of the member feature")))?;
|
||||
let (x, y) = frame::member_axes(*b - *a, turn).ok_or_else(|| DocError::Invalid(format!("line `{line}` has no length")))?;
|
||||
let plane = Plane::new(*a - x * at.x - y * at.y, x, y).ok_or_else(|| DocError::Invalid(format!("line `{line}`: no plane square to it")))?;
|
||||
let region = regions.into_iter().next().ok_or_else(|| DocError::Invalid("the member profile has no area".into()))?;
|
||||
Ok((plane, a.dist(*b), region))
|
||||
}
|
||||
|
||||
/// The body name of the member on each of `lines`: its own name from `pinned` (by line id) when no
|
||||
/// other body has it, else the first free one of `base`, `base (2)`, `base (3)`… that no line has
|
||||
/// pinned. A member therefore keeps its name when other lines are added, deleted or reordered.
|
||||
|
||||
@@ -79,7 +79,7 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
apply_op(doc, st, f, tools, Operation::Join, &[])
|
||||
}
|
||||
FeatureKind::ReplaceFace { faces, target, body } => {
|
||||
let tp = doc.resolve_plane_in(vals, target, 0, Some(st))?;
|
||||
let tp = doc.resolve_plane_in(vals, target, 0, f.component, Some(st))?;
|
||||
let tn = tp.normal();
|
||||
let i = body_at(st, body, &crate::plain(faces))?;
|
||||
let Some(mb) = st.bodies.get(i).cloned() else { return Err(DocError::Invalid("body".into())) };
|
||||
@@ -98,7 +98,7 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
}
|
||||
}
|
||||
if let Some(slot) = st.bodies.get_mut(i) {
|
||||
*slot = ModelBody::traced_new(mb.name, b, mb.feature);
|
||||
*slot = mb.remade(b);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -106,7 +106,7 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
// A plane on either side is worked out now, so the bodies follow it when it moves.
|
||||
let (mut from, mut from_normal) = (from.0, from_normal.and_then(|n| n.normalized()));
|
||||
if let Some(p) = from_plane {
|
||||
let pl = doc.resolve_plane_in(vals, p, 0, Some(&*st))?;
|
||||
let pl = doc.resolve_plane_in(vals, p, 0, f.component, Some(&*st))?;
|
||||
(from, from_normal) = (pl.origin, Some(pl.normal()));
|
||||
}
|
||||
// So is a frame (#6257): its origin and z, found again from the geometry.
|
||||
@@ -116,7 +116,7 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
}
|
||||
let target = match to_frame {
|
||||
Some(_) => None,
|
||||
None => to_plane.as_ref().map(|p| doc.resolve_plane_in(vals, p, 0, Some(&*st))).transpose()?,
|
||||
None => to_plane.as_ref().map(|p| doc.resolve_plane_in(vals, p, 0, f.component, Some(&*st))).transpose()?,
|
||||
};
|
||||
let (to, to_normal) = match (to_frame, &target) {
|
||||
(Some(fr), _) => fr.resolve(doc, st).map(|(o, z)| (o, Some(z)))?,
|
||||
@@ -2419,7 +2419,7 @@ pub(super) fn plastic_eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &F
|
||||
let edges = resolve_edges(&mb.body, &[position.0 + x * r0], &[], &mut warn)?;
|
||||
let nb = mb.traced().then(kernel::fillet(&mb.body, &edges, rf)?);
|
||||
if let Some(slot) = st.bodies.get_mut(i) {
|
||||
*slot = ModelBody::traced_new(mb.name, nb, mb.feature);
|
||||
*slot = mb.remade(nb);
|
||||
}
|
||||
}
|
||||
if let Some(hd) = hole_diameter {
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
//! SMLib's check of a feature's bodies beside the features after it.
|
||||
//!
|
||||
//! Under [`kernel::Validation::EachFeature`] a feature ends with SMLib's full check of the bodies
|
||||
//! it keeps, and the next feature used to wait for it: a third to a half of an evaluation went to
|
||||
//! those checks, on one core. [`Checks`] detaches each check from the bodies it reads
|
||||
//! ([`kernel::detach_kept`]) and runs it on a thread of its own while the evaluation goes on. What the features after it produce stands only once it passes: their
|
||||
//! cache entries are held until then, and a refusal takes the evaluation back to the refused
|
||||
//! feature, which then fails with the check's error and warnings, as it did when the check ran
|
||||
//! in line. The results are the same either way; only the time differs.
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use solidcraft_kernel as kernel;
|
||||
|
||||
use super::{CacheEntry, EvalCache, FeatureResult, KeptSlot, ModelBody, ModelState};
|
||||
|
||||
/// The evaluation's loop state just before a feature was evaluated: what a refusal of its check
|
||||
/// puts back before evaluating it again.
|
||||
pub(super) struct Saved {
|
||||
pub state: Arc<ModelState>,
|
||||
pub reserved: std::collections::BTreeSet<String>,
|
||||
pub out_len: usize,
|
||||
pub reuse: bool,
|
||||
pub prev_fp: u64,
|
||||
pub recomputed: usize,
|
||||
pub restored: usize,
|
||||
pub poses: HashMap<u64, u64>,
|
||||
pub moved: Vec<(u64, Vec<ModelBody>)>,
|
||||
pub failed: HashMap<u64, (String, String)>,
|
||||
pub rolled_results: HashMap<u64, (u64, FeatureResult)>,
|
||||
}
|
||||
|
||||
/// How a feature whose check refused its bodies ends: as the check in line ended it.
|
||||
#[derive(Clone)]
|
||||
pub(super) struct Failure {
|
||||
pub error: kernel::KernelError,
|
||||
pub warning: Option<String>,
|
||||
pub import_report: Option<Arc<kernel::ImportReport>>,
|
||||
pub repair: Option<Arc<kernel::RepairReport>>,
|
||||
pub ms: f64,
|
||||
}
|
||||
|
||||
/// A check that refused feature `index`'s bodies.
|
||||
pub(super) struct Refused {
|
||||
pub index: usize,
|
||||
pub saved: Saved,
|
||||
pub failure: Failure,
|
||||
}
|
||||
|
||||
struct Running {
|
||||
index: usize,
|
||||
saved: Saved,
|
||||
failure: Failure,
|
||||
done: std::thread::JoinHandle<kernel::Result<()>>,
|
||||
}
|
||||
|
||||
pub(super) struct Checks {
|
||||
on: bool,
|
||||
/// Most checks running at once: the cores beside the evaluation's own.
|
||||
most: usize,
|
||||
running: VecDeque<Running>,
|
||||
/// Cache entries of features evaluated after a check that is still running, in order.
|
||||
held: Vec<(usize, CacheEntry)>,
|
||||
/// Features whose check refused their bodies, to fail again as it did.
|
||||
refused: HashMap<usize, Failure>,
|
||||
}
|
||||
|
||||
impl Checks {
|
||||
pub fn new(validation: kernel::Validation) -> Checks {
|
||||
let cores = std::thread::available_parallelism().map_or(1, usize::from);
|
||||
Checks {
|
||||
on: validation == kernel::Validation::EachFeature && cores > 1,
|
||||
most: cores.saturating_sub(1).max(1),
|
||||
running: VecDeque::new(),
|
||||
held: Vec::new(),
|
||||
refused: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The check of the bodies `after` adds to `before`, detached from them so it can run beside
|
||||
/// the features after it ([`kernel::detach_kept`]); `None` when it runs in line.
|
||||
pub fn detach(&self, before: &ModelState, after: &ModelState) -> Option<Vec<(String, kernel::KeptCheck)>> {
|
||||
self.on.then(|| {
|
||||
after
|
||||
.bodies
|
||||
.iter()
|
||||
.filter(|b| !before.bodies.iter().any(|old| old.body.same_shape(&b.body)))
|
||||
.map(|b| (b.name.clone(), kernel::detach_kept(&b.body)))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// The failure feature `index` ends with, when its check refused it before.
|
||||
/// Whether feature `index`'s check refused its bodies, leaving the failure in place.
|
||||
pub fn refused_at(&self, index: usize) -> Option<&Failure> {
|
||||
self.refused.get(&index)
|
||||
}
|
||||
|
||||
pub fn refused(&mut self, index: usize) -> Option<Failure> {
|
||||
self.refused.remove(&index)
|
||||
}
|
||||
|
||||
/// Runs `check`, feature `index`'s check, on a thread of its own. `Err`: no thread could
|
||||
/// start, and this is the check's own result, made here.
|
||||
pub fn start(
|
||||
&mut self,
|
||||
index: usize,
|
||||
saved: Saved,
|
||||
failure: Failure,
|
||||
check: impl FnOnce() -> kernel::Result<()> + Send + 'static,
|
||||
) -> kernel::Result<()> {
|
||||
// Taken by whichever runs it: the thread, or this one when the thread cannot start.
|
||||
let shared = Arc::new(Mutex::new(Some(check)));
|
||||
let taken = shared.clone();
|
||||
let started = kernel::kernel_thread("feature-check").spawn(move || match taken.lock().ok().and_then(|mut c| c.take()) {
|
||||
Some(check) => check(),
|
||||
None => Ok(()),
|
||||
});
|
||||
match started {
|
||||
Ok(done) => {
|
||||
self.running.push_back(Running { index, saved, failure, done });
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => match shared.lock().ok().and_then(|mut c| c.take()) {
|
||||
Some(check) => check(),
|
||||
None => Ok(()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores the cache entry of feature `index` once no check before it, or of it, is running.
|
||||
pub fn store(&mut self, index: usize, entry: CacheEntry, cache: &Mutex<EvalCache>, kept: &KeptSlot) {
|
||||
if self.running.front().is_some_and(|r| r.index <= index) {
|
||||
self.held.push((index, entry));
|
||||
} else {
|
||||
entry.put(cache, kept);
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes the checks that ended (all of them with `wait`, or while too many run), in order:
|
||||
/// the first that refused, with what it puts back. Cache entries are stored as the checks
|
||||
/// before them pass.
|
||||
pub fn settle(&mut self, wait: bool, cache: &Mutex<EvalCache>, kept: &KeptSlot) -> Option<Refused> {
|
||||
while let Some(front) = self.running.front() {
|
||||
if !(wait || self.running.len() > self.most || front.done.is_finished()) {
|
||||
break;
|
||||
}
|
||||
let Some(r) = self.running.pop_front() else { break };
|
||||
let passed = match r.done.join() {
|
||||
Ok(check) => check,
|
||||
Err(_) => Err(kernel::KernelError::Internal(format!("{}: the check's thread stopped", r.index))),
|
||||
};
|
||||
if let Err(error) = passed {
|
||||
// What came after it was evaluated on bodies the check refuses: none of it stands.
|
||||
// The checks still running are left to end on their own.
|
||||
self.running.clear();
|
||||
self.held.retain(|(i, _)| *i < r.index);
|
||||
return Some(Refused { index: r.index, saved: r.saved, failure: Failure { error, ..r.failure } });
|
||||
}
|
||||
let upto = self.running.front().map_or(usize::MAX, |next| next.index);
|
||||
for (i, entry) in std::mem::take(&mut self.held) {
|
||||
if i < upto {
|
||||
entry.put(cache, kept);
|
||||
} else {
|
||||
self.held.push((i, entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Feature `index`'s check refused its bodies: it ends with `failure` when evaluated again.
|
||||
pub fn refuse(&mut self, index: usize, failure: Failure) {
|
||||
self.refused.insert(index, failure);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::CachedEval;
|
||||
use super::*;
|
||||
use kernel::KernelError;
|
||||
|
||||
fn saved() -> Saved {
|
||||
Saved {
|
||||
state: Arc::new(ModelState::default()),
|
||||
reserved: Default::default(),
|
||||
out_len: 0,
|
||||
reuse: false,
|
||||
prev_fp: 0,
|
||||
recomputed: 0,
|
||||
restored: 0,
|
||||
poses: HashMap::new(),
|
||||
moved: Vec::new(),
|
||||
failed: HashMap::new(),
|
||||
rolled_results: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn failure() -> Failure {
|
||||
Failure { error: KernelError::Failed(String::new()), warning: Some("kept".into()), import_report: None, repair: None, ms: 1.0 }
|
||||
}
|
||||
|
||||
fn entry(key: u64) -> CacheEntry {
|
||||
let whole = CachedEval { error: None, warning: None, import_report: None, repair: None, ms: 0.0, state: Arc::new(ModelState::default()) };
|
||||
CacheEntry { key, whole, bytes: 1, change: None }
|
||||
}
|
||||
|
||||
fn checks() -> Checks {
|
||||
Checks { on: true, most: 4, running: VecDeque::new(), held: Vec::new(), refused: HashMap::new() }
|
||||
}
|
||||
|
||||
/// A check that ends after the evaluation went on, with `r`.
|
||||
fn later(r: kernel::Result<()>) -> impl FnOnce() -> kernel::Result<()> + Send + 'static {
|
||||
move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(30));
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
/// Feature 1's check refuses its bodies while feature 0's passes: feature 0's result is
|
||||
/// stored, the results of features 1 and 2 (evaluated on the refused bodies) are not, and
|
||||
/// feature 1 ends with the check's error and the warnings it had.
|
||||
#[test]
|
||||
fn a_refused_check_takes_back_what_came_after_it() {
|
||||
let (cache, kept) = (Mutex::new(EvalCache::default()), KeptSlot(None));
|
||||
let mut c = checks();
|
||||
assert!(c.start(0, saved(), failure(), later(Ok(()))).is_ok());
|
||||
c.store(0, entry(10), &cache, &kept);
|
||||
assert!(c.start(1, saved(), failure(), later(Err(KernelError::Failed("refused".into())))).is_ok());
|
||||
c.store(1, entry(11), &cache, &kept);
|
||||
c.store(2, entry(12), &cache, &kept);
|
||||
assert!(cache.lock().unwrap().is_empty(), "held while the checks run");
|
||||
let refused = c.settle(true, &cache, &kept).expect("the second check refuses");
|
||||
assert_eq!(refused.index, 1);
|
||||
assert_eq!(refused.failure.error, KernelError::Failed("refused".into()));
|
||||
assert_eq!(refused.failure.warning.as_deref(), Some("kept"));
|
||||
{
|
||||
let m = cache.lock().unwrap();
|
||||
assert!(m.states.map.contains_key(&10) && !m.states.map.contains_key(&11) && !m.states.map.contains_key(&12));
|
||||
}
|
||||
c.refuse(1, refused.failure);
|
||||
assert!(c.refused(1).is_some() && c.refused(1).is_none());
|
||||
assert!(c.settle(true, &cache, &kept).is_none());
|
||||
}
|
||||
|
||||
/// With no check running a result is stored at once; once the checks pass, so is every
|
||||
/// result that waited for them.
|
||||
#[test]
|
||||
fn passed_checks_store_what_waited() {
|
||||
let (cache, kept) = (Mutex::new(EvalCache::default()), KeptSlot(None));
|
||||
let mut c = checks();
|
||||
c.store(0, entry(10), &cache, &kept);
|
||||
assert_eq!(cache.lock().unwrap().len(), 1);
|
||||
assert!(c.start(1, saved(), failure(), later(Ok(()))).is_ok());
|
||||
c.store(1, entry(11), &cache, &kept);
|
||||
c.store(2, entry(12), &cache, &kept);
|
||||
assert!(c.settle(true, &cache, &kept).is_none());
|
||||
assert_eq!(cache.lock().unwrap().len(), 3);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user