@things-factory/figure-ui 10.1.115 → 10.1.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/graphql/index.ts +6 -1
- package/client/modeller/editor.ts +3 -9
- package/client/modeller/figure-links.ts +20 -7
- package/client/modeller/joint-drag.ts +3 -3
- package/client/modeller/links.ts +28 -11
- package/client/modeller/recipes.ts +6 -1
- package/client/pages/figure-list-page.ts +4 -4
- package/client/types.ts +1 -1
- package/client/viewparts/detail-motion.ts +11 -0
- package/client/viewparts/figure-asset-viewer.ts +177 -0
- package/client/viewparts/figure-detail-dock.ts +187 -0
- package/dist-client/graphql/index.d.ts +5 -0
- package/dist-client/graphql/index.js +5 -1
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +3 -2
- package/dist-client/modeller/editor.js +3 -9
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-links.js +35 -22
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/joint-drag.js +3 -3
- package/dist-client/modeller/joint-drag.js.map +1 -1
- package/dist-client/modeller/links.d.ts +18 -3
- package/dist-client/modeller/links.js +21 -10
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/recipes.js +5 -1
- package/dist-client/modeller/recipes.js.map +1 -1
- package/dist-client/pages/figure-list-page.d.ts +2 -3
- package/dist-client/pages/figure-list-page.js +4 -4
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types.d.ts +1 -1
- package/dist-client/types.js.map +1 -1
- package/dist-client/viewparts/detail-motion.d.ts +6 -0
- package/dist-client/viewparts/detail-motion.js +9 -0
- package/dist-client/viewparts/detail-motion.js.map +1 -0
- package/dist-client/viewparts/figure-asset-viewer.d.ts +31 -0
- package/dist-client/viewparts/figure-asset-viewer.js +198 -0
- package/dist-client/viewparts/figure-asset-viewer.js.map +1 -0
- package/dist-client/viewparts/figure-detail-dock.d.ts +36 -0
- package/dist-client/viewparts/figure-detail-dock.js +224 -0
- package/dist-client/viewparts/figure-detail-dock.js.map +1 -0
- package/package.json +6 -6
- package/test/browser/detail-page.js +34 -0
- package/test/browser/serve-detail.mjs +10 -0
- package/test/detail-motion.test.ts +26 -0
- package/test/links.test.ts +20 -1
- package/test/modeller-route.test.ts +4 -2
- package/test/verdict.test.ts +3 -1
- package/translations/en.json +19 -1
- package/translations/ja.json +19 -1
- package/translations/ko.json +19 -1
- package/translations/ms.json +19 -1
- package/translations/zh.json +19 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/figure-ui",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.116",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"@things-factory:registry": "https://registry.npmjs.org"
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"clean": "npm run clean:server && npm run clean:client"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@hatiolab/figure-model": "^0.2
|
|
31
|
-
"@hatiolab/things-scene": "^10.1.
|
|
30
|
+
"@hatiolab/figure-model": "^0.3.2",
|
|
31
|
+
"@hatiolab/things-scene": "^10.1.71",
|
|
32
32
|
"@material/web": "^2.0.0",
|
|
33
33
|
"@operato/data-grist": "^10.0.0",
|
|
34
34
|
"@operato/graphql": "^10.0.0",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"@operato/shell": "^10.0.0",
|
|
41
41
|
"@operato/styles": "^10.0.0",
|
|
42
42
|
"@operato/utils": "^10.0.0",
|
|
43
|
-
"@things-factory/ai-assistant": "^10.1.
|
|
44
|
-
"@things-factory/figure-service": "^10.1.
|
|
43
|
+
"@things-factory/ai-assistant": "^10.1.116",
|
|
44
|
+
"@things-factory/figure-service": "^10.1.116",
|
|
45
45
|
"three": "^0.185.1"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "49fa935cc703be70200eef4d29f473de98f871ce"
|
|
48
48
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* Isolated product detail: fixtures are in memory, never saved to the running app. */
|
|
2
|
+
import 'figure-ui-client/viewparts/figure-detail-dock.js'
|
|
3
|
+
import { i18next } from '@operato/i18n'
|
|
4
|
+
import { addFigureBox, createFigureAsset, editFigurePart, applyFigureAuthoring, serializeFigureAsset } from '@hatiolab/figure-model'
|
|
5
|
+
|
|
6
|
+
async function start() {
|
|
7
|
+
i18next.addResourceBundle('ko', 'translations', await fetch('/ko.json').then(r => r.json()), true, true)
|
|
8
|
+
await i18next.changeLanguage('ko')
|
|
9
|
+
let asset = addFigureBox(createFigureAsset('클립 시험'), { id: 'block', size: { x: 100, y: 100, z: 100 }, position: { x: 0, y: 50, z: 0 } })
|
|
10
|
+
asset = applyFigureAuthoring(asset, { kind: 'set-joint', joint: {
|
|
11
|
+
id: 'block', type: 'prismatic', body0: { plane: 'mounting-plane' }, body1: { part: 'block', face: 'bottom' }, axis: 'X', lowerLimit: 0, upperLimit: 200, state: { id: 'shift', start: 0 }
|
|
12
|
+
} })
|
|
13
|
+
asset = editFigurePart(asset, { kind: 'set-driver', state: 'shift', clip: 'cycle', duration: 4, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 200 }, { seconds: 4, value: 0 }] })
|
|
14
|
+
const source = serializeFigureAsset(asset)
|
|
15
|
+
const dock = document.createElement('figure-detail-dock')
|
|
16
|
+
let fail = true
|
|
17
|
+
dock.load = async id => {
|
|
18
|
+
if (id === 'retry' && fail) { fail = false; throw Error('test connection failure') }
|
|
19
|
+
if (id === 'slow') await new Promise(done => setTimeout(done, 1200))
|
|
20
|
+
return { saved: { id, name: id === 'slow' ? '늦은 이전 모델' : '클립 시험', type: 'DETAIL_TEST', state: 'draft', source }, released: id === 'invalid' ? { version: 1, source: 'broken json' } : undefined }
|
|
21
|
+
}
|
|
22
|
+
const controls = document.createElement('nav')
|
|
23
|
+
for (const [label, id] of [['클립 모델 열기','motion'],['연결 오류 시험','retry'],['깨진 발행판 시험','invalid'],['느린 모델 열기','slow']]) {
|
|
24
|
+
const button = document.createElement('button'); button.textContent = label
|
|
25
|
+
button.onclick = () => void dock.show(id); controls.append(button)
|
|
26
|
+
}
|
|
27
|
+
document.body.append(controls,dock)
|
|
28
|
+
await dock.show('motion')
|
|
29
|
+
const original = document.createElement('output'); original.setAttribute('aria-label','원본 보존')
|
|
30
|
+
const check = document.createElement('button'); check.textContent='원본 확인'
|
|
31
|
+
check.onclick=()=>original.textContent=serializeFigureAsset(asset)===source?'원본 그대로':'원본 변경됨'
|
|
32
|
+
controls.append(check,original)
|
|
33
|
+
}
|
|
34
|
+
start()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createServer } from 'node:http'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { dirname, resolve } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { buildPage } from './build.mjs'
|
|
6
|
+
const here=dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
const bundle=await buildPage('detail-page.js')
|
|
8
|
+
const html=`<!doctype html><html><head><meta charset="utf-8"><title>Figure 상세 검증</title><link rel="stylesheet" href="/theme.css"><style>body{margin:0;font-family:sans-serif;display:flex;height:100vh}nav{flex:1;padding:24px;display:flex;flex-direction:column;gap:12px}nav button{padding:12px}figure-detail-dock{position:static!important;height:100%!important}output{display:block}</style></head><body><script type="module" src="/page.js"></script></body></html>`
|
|
9
|
+
const routes={ '/page.js':[bundle,'text/javascript'], '/ko.json':[resolve(here,'../../translations/ko.json'),'application/json'], '/theme.css':[resolve(here,'../../client/harness-theme/light.css'),'text/css'] }
|
|
10
|
+
createServer((req,res)=>{const match=routes[req.url];res.writeHead(200,{'Content-Type':match?.[1]??'text/html; charset=utf-8'});res.end(match?readFileSync(match[0]):html)}).listen(3394,'127.0.0.1',()=>console.log('Detail fixture: http://localhost:3394'))
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { addFigureBox, createFigureAsset, editFigurePart, serializeFigureAsset } from '@hatiolab/figure-model'
|
|
4
|
+
import { moving } from './joints.ts'
|
|
5
|
+
import { clipForControl, parametersForClip } from '../client/viewparts/detail-motion.ts'
|
|
6
|
+
|
|
7
|
+
function machine() {
|
|
8
|
+
let asset = addFigureBox(createFigureAsset('Motion probe'), { id: 'block', size: { x: 100, y: 100, z: 100 }, position: { x: 0, y: 50, z: 0 } })
|
|
9
|
+
asset = moving(asset, 'block', { kind: 'slide', axis: 'x', id: 'shift', min: 0, max: 200, start: 0 })
|
|
10
|
+
return editFigurePart(asset, { kind: 'set-driver', state: 'shift', clip: 'cycle', duration: 4, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 200 }, { seconds: 4, value: 0 }] })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
test('playing a clip releases manual values that would mask its drivers, retaining unrelated controls and the source', () => {
|
|
14
|
+
const asset = machine()
|
|
15
|
+
const source = serializeFigureAsset(asset)
|
|
16
|
+
const values = { shift: 75, other: 42 }
|
|
17
|
+
assert.deepEqual(parametersForClip(asset, values, 'cycle'), { other: 42 })
|
|
18
|
+
assert.deepEqual(values, { shift: 75, other: 42 })
|
|
19
|
+
assert.equal(serializeFigureAsset(asset), source)
|
|
20
|
+
assert.equal(clipForControl(asset, 'shift'), 'cycle')
|
|
21
|
+
assert.equal(clipForControl(asset, 'other'), undefined)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('choosing a different clip cannot clear another clip’s manual control', () => {
|
|
25
|
+
assert.deepEqual(parametersForClip(machine(), { shift: 75 }, 'other'), { shift: 75 })
|
|
26
|
+
})
|
package/test/links.test.ts
CHANGED
|
@@ -371,7 +371,7 @@ test('따라 움직이는 관절 — 같은 방식으로 움직이고 제 조작
|
|
|
371
371
|
assert.equal(x('left', 40) - x('left', 0), 40)
|
|
372
372
|
assert.equal(x('right', 40) - x('right', 0), -40, '오른손은 거울로 따라 닫힌다')
|
|
373
373
|
const { motionOf } = await import('../client/modeller/links.ts')
|
|
374
|
-
assert.deepEqual(motionOf(asset, 'right')?.follows, { joint: 'left', multiplier: -1 }, '화면은 무엇을 따르는지 읽는다')
|
|
374
|
+
assert.deepEqual(motionOf(asset, 'right')?.follows, { sum: [{ joint: 'left', multiplier: -1 }], offset: 0 }, '화면은 무엇을 따르는지 읽는다')
|
|
375
375
|
})
|
|
376
376
|
|
|
377
377
|
test('면은 도형이 정한다 — 문틀(portal)은 바깥 여섯에 개구부 셋, 공은 없음, 원뿔대는 위아래뿐 (2026-09-25)', async () => {
|
|
@@ -661,3 +661,22 @@ test('붙이기 칸은 부품 제 붙임으로 열린다 — 가운데로 붙은
|
|
|
661
661
|
assert.ok(panel.includes('fasteningOf(this.asset, this.partId)'), '부품을 고르면 제 붙임으로 연다')
|
|
662
662
|
assert.ok(panel.includes("...(f.toPlane ? [] : (['centre'] as const))"), '내 면에 가운데가 있다')
|
|
663
663
|
})
|
|
664
|
+
|
|
665
|
+
test('a follower of several leaders and a stroke that is a sum of lengths are written back unchanged by the motion form (ADR-0107)', async () => {
|
|
666
|
+
const { motionFormOf, motionJoint, motionOf } = await import('../client/modeller/links.ts')
|
|
667
|
+
const { palletizerRobotFigure } = await import('@hatiolab/figure-model')
|
|
668
|
+
const { asset } = palletizerRobotFigure()
|
|
669
|
+
const wrist = asset.joints!.find(j => j.id === 'wrist')!
|
|
670
|
+
const form = motionFormOf(wrist)
|
|
671
|
+
assert.equal(form.follow, '', 'no single leader to pick')
|
|
672
|
+
assert.deepEqual(form.followSum, [{ joint: 'j2', multiplier: -1 }, { joint: 'j3', multiplier: -1 }])
|
|
673
|
+
const saved = motionJoint(wrist, { ...form, axis: form.axis }, 'wrist')
|
|
674
|
+
assert.deepEqual(saved.mimic, { sum: [{ joint: 'j2', multiplier: -1 }, { joint: 'j3', multiplier: -1 }] }, 'saving the form keeps the follower a follower')
|
|
675
|
+
assert.equal(saved.state, undefined, 'and gives it no control of its own')
|
|
676
|
+
assert.deepEqual(motionOf(asset, 'wrist')?.follows, { sum: [{ joint: 'j2', multiplier: -1 }, { joint: 'j3', multiplier: -1 }], offset: 0 })
|
|
677
|
+
|
|
678
|
+
const reach = { ...wrist, id: 'reach', type: 'prismatic' as const, mimic: undefined, axis: 'X' as const, travel: { sum: [{ from: { of: 'part' as const, part: 'base', axis: 'x' as const } }, { from: { of: 'part' as const, part: 'turret', axis: 'x' as const }, times: 0.5 }] } }
|
|
679
|
+
const slide = motionFormOf(reach)
|
|
680
|
+
assert.equal(slide.travel, '')
|
|
681
|
+
assert.deepEqual(motionJoint(reach, slide, 'wrist').travel, reach.travel, 'saving keeps the summed stroke')
|
|
682
|
+
})
|
|
@@ -23,9 +23,11 @@ test('one modeller page at one address: the route and the shell table agree', ()
|
|
|
23
23
|
assert.equal(config.match(/tagname: 'figure-modeller-page', page: 'figure-modeller'/g)?.length, 1)
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
test('the catalogue opens
|
|
26
|
+
test('the catalogue opens details first; editing is an explicit action in the detail dock', () => {
|
|
27
27
|
const list = read('../client/pages/figure-list-page.ts')
|
|
28
|
-
assert.match(list, /
|
|
28
|
+
assert.match(list, /openFigureDetail\(record\)/)
|
|
29
|
+
const detail = read('../client/viewparts/figure-detail-dock.ts')
|
|
30
|
+
assert.match(detail, /navigate\(modellerPathOf\(saved\)\)/)
|
|
29
31
|
})
|
|
30
32
|
|
|
31
33
|
test('reloading or closing the tab with unsaved work asks first — the shell does not ask canDeactivate then (09-26)', () => {
|
package/test/verdict.test.ts
CHANGED
|
@@ -12,7 +12,7 @@ import assert from 'node:assert/strict'
|
|
|
12
12
|
import { readFileSync } from 'node:fs'
|
|
13
13
|
import { fileURLToPath } from 'node:url'
|
|
14
14
|
|
|
15
|
-
import { addFigureBox, createFigureAsset, figureCostOf } from '@hatiolab/figure-model'
|
|
15
|
+
import { addFigureBox, createFigureAsset, editFigurePart, figureCostOf } from '@hatiolab/figure-model'
|
|
16
16
|
|
|
17
17
|
import { capacityFrom, SCENE_BUDGET } from '../client/modeller/scene-budget.ts'
|
|
18
18
|
|
|
@@ -25,6 +25,8 @@ test('개수는 목록 카드와 같은 셈이다 — 원가를 같은 capacityF
|
|
|
25
25
|
let asset = createFigureAsset('Probe')
|
|
26
26
|
asset = addFigureBox(asset, { id: 'a', size: { x: 100, y: 100, z: 100 }, position: { x: 0, y: 50, z: 0 } })
|
|
27
27
|
asset = addFigureBox(asset, { id: 'b', size: { x: 100, y: 100, z: 100 }, position: { x: 200, y: 50, z: 0 } })
|
|
28
|
+
// The kernel batches static parts with the same material. Use two colours to test two draw groups.
|
|
29
|
+
asset = editFigurePart(asset, { kind: 'set-material', target: 'b', material: { token: 'palette.accent' }, palette: { 'palette.accent': '#f28c28' } })
|
|
28
30
|
const cost = figureCostOf(asset)
|
|
29
31
|
|
|
30
32
|
assert.equal(cost.groups, 2, '전제: 그려지는 부품 둘이 묶음 둘')
|
package/translations/en.json
CHANGED
|
@@ -965,5 +965,23 @@
|
|
|
965
965
|
"figure.label.face-mapping-choose": "Choose",
|
|
966
966
|
"figure.label.face-mapping-detach": "Let go (stays where it is)",
|
|
967
967
|
"figure.button.face-mapping-cancel": "Cancel",
|
|
968
|
-
"figure.button.face-mapping-apply": "Move and apply"
|
|
968
|
+
"figure.button.face-mapping-apply": "Move and apply",
|
|
969
|
+
"figure.title.detail": "Figure details",
|
|
970
|
+
"figure.text.detail-loading": "Loading model…",
|
|
971
|
+
"figure.button.detail-retry": "Retry",
|
|
972
|
+
"figure.text.detail-load-failed": "Could not load the model. Check your connection and access, then retry.",
|
|
973
|
+
"figure.text.detail-no-source": "No saved model is available.",
|
|
974
|
+
"figure.text.detail-invalid-source": "This model format could not be read. Open the editor to inspect it.",
|
|
975
|
+
"figure.label.detail-source": "Model to view",
|
|
976
|
+
"figure.label.detail-released": "Released version {version}",
|
|
977
|
+
"figure.label.detail-saved": "Saved model",
|
|
978
|
+
"figure.text.detail-unreleased": "Not released yet. Showing the saved draft.",
|
|
979
|
+
"figure.button.detail-edit": "Open editor",
|
|
980
|
+
"figure.label.detail-size": "Placement size",
|
|
981
|
+
"figure.button.detail-reset": "Reset size and pose",
|
|
982
|
+
"figure.text.detail-transient": "Try sizes and motion here. The saved model stays unchanged.",
|
|
983
|
+
"figure.text.detail-no-motion": "No motion is defined.",
|
|
984
|
+
"figure.text.detail-playing": "Playing",
|
|
985
|
+
"figure.label.detail-summary": "Drawing cost of the selected model",
|
|
986
|
+
"figure.text.detail-paused": "Paused"
|
|
969
987
|
}
|
package/translations/ja.json
CHANGED
|
@@ -965,5 +965,23 @@
|
|
|
965
965
|
"figure.label.face-mapping-choose": "移動先",
|
|
966
966
|
"figure.label.face-mapping-detach": "外しておく(今の位置のまま)",
|
|
967
967
|
"figure.button.face-mapping-cancel": "やめる",
|
|
968
|
-
"figure.button.face-mapping-apply": "移して適用"
|
|
968
|
+
"figure.button.face-mapping-apply": "移して適用",
|
|
969
|
+
"figure.title.detail": "Figure の詳細",
|
|
970
|
+
"figure.text.detail-loading": "モデルを読み込み中…",
|
|
971
|
+
"figure.button.detail-retry": "再試行",
|
|
972
|
+
"figure.text.detail-load-failed": "モデルを読み込めませんでした。接続とアクセス権を確認して再試行してください。",
|
|
973
|
+
"figure.text.detail-no-source": "保存されたモデルがありません。",
|
|
974
|
+
"figure.text.detail-invalid-source": "このモデルの形式を読み取れません。編集画面で確認してください。",
|
|
975
|
+
"figure.label.detail-source": "表示するモデル",
|
|
976
|
+
"figure.label.detail-released": "公開版 {version}",
|
|
977
|
+
"figure.label.detail-saved": "保存版",
|
|
978
|
+
"figure.text.detail-unreleased": "まだ公開されていません。保存された下書きを表示します。",
|
|
979
|
+
"figure.button.detail-edit": "編集画面を開く",
|
|
980
|
+
"figure.label.detail-size": "配置サイズ",
|
|
981
|
+
"figure.button.detail-reset": "基準サイズと姿勢に戻す",
|
|
982
|
+
"figure.text.detail-transient": "サイズと動きはここでのみ試します。保存されたモデルは変更されません。",
|
|
983
|
+
"figure.text.detail-no-motion": "登録された動きがありません。",
|
|
984
|
+
"figure.text.detail-playing": "再生中",
|
|
985
|
+
"figure.label.detail-summary": "選択したモデルの描画コスト",
|
|
986
|
+
"figure.text.detail-paused": "一時停止"
|
|
969
987
|
}
|
package/translations/ko.json
CHANGED
|
@@ -965,5 +965,23 @@
|
|
|
965
965
|
"figure.label.face-mapping-choose": "옮길 곳",
|
|
966
966
|
"figure.label.face-mapping-detach": "떼어 두기(지금 자리에 그대로)",
|
|
967
967
|
"figure.button.face-mapping-cancel": "그만두기",
|
|
968
|
-
"figure.button.face-mapping-apply": "옮기고 적용"
|
|
968
|
+
"figure.button.face-mapping-apply": "옮기고 적용",
|
|
969
|
+
"figure.title.detail": "Figure 상세",
|
|
970
|
+
"figure.text.detail-loading": "모델을 불러오는 중…",
|
|
971
|
+
"figure.button.detail-retry": "다시 시도",
|
|
972
|
+
"figure.text.detail-load-failed": "모델을 불러오지 못했습니다. 연결과 접근 권한을 확인하고 다시 시도하세요.",
|
|
973
|
+
"figure.text.detail-no-source": "저장된 모델이 없습니다.",
|
|
974
|
+
"figure.text.detail-invalid-source": "이 모델의 형식을 읽을 수 없습니다. 편집 화면에서 확인하세요.",
|
|
975
|
+
"figure.label.detail-source": "보는 모델",
|
|
976
|
+
"figure.label.detail-released": "발행판 {version}",
|
|
977
|
+
"figure.label.detail-saved": "저장본",
|
|
978
|
+
"figure.text.detail-unreleased": "아직 발행되지 않았습니다. 저장된 초안을 보여줍니다.",
|
|
979
|
+
"figure.button.detail-edit": "편집 화면 열기",
|
|
980
|
+
"figure.label.detail-size": "배치 크기",
|
|
981
|
+
"figure.button.detail-reset": "기준 크기와 자세로",
|
|
982
|
+
"figure.text.detail-transient": "크기와 움직임은 여기서만 시험합니다. 저장된 모델은 바뀌지 않습니다.",
|
|
983
|
+
"figure.text.detail-no-motion": "등록된 움직임이 없습니다.",
|
|
984
|
+
"figure.text.detail-playing": "재생 중",
|
|
985
|
+
"figure.label.detail-summary": "선택한 모델의 그리기 비용",
|
|
986
|
+
"figure.text.detail-paused": "일시정지"
|
|
969
987
|
}
|
package/translations/ms.json
CHANGED
|
@@ -965,5 +965,23 @@
|
|
|
965
965
|
"figure.label.face-mapping-choose": "Pilih",
|
|
966
966
|
"figure.label.face-mapping-detach": "Lepaskan (kekal di tempatnya)",
|
|
967
967
|
"figure.button.face-mapping-cancel": "Batal",
|
|
968
|
-
"figure.button.face-mapping-apply": "Alih dan guna"
|
|
968
|
+
"figure.button.face-mapping-apply": "Alih dan guna",
|
|
969
|
+
"figure.title.detail": "Butiran Figure",
|
|
970
|
+
"figure.text.detail-loading": "Memuatkan model…",
|
|
971
|
+
"figure.button.detail-retry": "Cuba lagi",
|
|
972
|
+
"figure.text.detail-load-failed": "Model tidak dapat dimuatkan. Semak sambungan dan hak akses, kemudian cuba lagi.",
|
|
973
|
+
"figure.text.detail-no-source": "Tiada model yang disimpan.",
|
|
974
|
+
"figure.text.detail-invalid-source": "Format model ini tidak dapat dibaca. Semak dalam editor.",
|
|
975
|
+
"figure.label.detail-source": "Model untuk dilihat",
|
|
976
|
+
"figure.label.detail-released": "Versi terbitan {version}",
|
|
977
|
+
"figure.label.detail-saved": "Versi disimpan",
|
|
978
|
+
"figure.text.detail-unreleased": "Belum diterbitkan. Draf yang disimpan dipaparkan.",
|
|
979
|
+
"figure.button.detail-edit": "Buka editor",
|
|
980
|
+
"figure.label.detail-size": "Saiz penempatan",
|
|
981
|
+
"figure.button.detail-reset": "Pulihkan saiz dan posisi asal",
|
|
982
|
+
"figure.text.detail-transient": "Saiz dan gerakan hanya diuji di sini. Model yang disimpan tidak berubah.",
|
|
983
|
+
"figure.text.detail-no-motion": "Tiada gerakan didaftarkan.",
|
|
984
|
+
"figure.text.detail-playing": "Sedang dimainkan",
|
|
985
|
+
"figure.label.detail-summary": "Kos lukisan model yang dipilih",
|
|
986
|
+
"figure.text.detail-paused": "Dijeda"
|
|
969
987
|
}
|
package/translations/zh.json
CHANGED
|
@@ -965,5 +965,23 @@
|
|
|
965
965
|
"figure.label.face-mapping-choose": "去处",
|
|
966
966
|
"figure.label.face-mapping-detach": "解除连接(保持原位)",
|
|
967
967
|
"figure.button.face-mapping-cancel": "取消",
|
|
968
|
-
"figure.button.face-mapping-apply": "移动并应用"
|
|
968
|
+
"figure.button.face-mapping-apply": "移动并应用",
|
|
969
|
+
"figure.title.detail": "Figure 详情",
|
|
970
|
+
"figure.text.detail-loading": "正在加载模型…",
|
|
971
|
+
"figure.button.detail-retry": "重试",
|
|
972
|
+
"figure.text.detail-load-failed": "无法加载模型。请检查连接和访问权限后重试。",
|
|
973
|
+
"figure.text.detail-no-source": "没有已保存的模型。",
|
|
974
|
+
"figure.text.detail-invalid-source": "无法读取此模型的格式。请在编辑页面检查。",
|
|
975
|
+
"figure.label.detail-source": "查看模型",
|
|
976
|
+
"figure.label.detail-released": "发布版 {version}",
|
|
977
|
+
"figure.label.detail-saved": "已保存版本",
|
|
978
|
+
"figure.text.detail-unreleased": "尚未发布。显示已保存的草稿。",
|
|
979
|
+
"figure.button.detail-edit": "打开编辑页面",
|
|
980
|
+
"figure.label.detail-size": "放置尺寸",
|
|
981
|
+
"figure.button.detail-reset": "恢复基准尺寸与姿态",
|
|
982
|
+
"figure.text.detail-transient": "尺寸和动作仅在此处试用,不会修改已保存的模型。",
|
|
983
|
+
"figure.text.detail-no-motion": "没有已注册的动作。",
|
|
984
|
+
"figure.text.detail-playing": "播放中",
|
|
985
|
+
"figure.label.detail-summary": "所选模型的绘制成本",
|
|
986
|
+
"figure.text.detail-paused": "已暂停"
|
|
969
987
|
}
|