@things-factory/figure-ui 10.1.158 → 10.1.160
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 +38 -0
- package/client/harness-theme/brand.css +21 -25
- package/client/index.ts +1 -0
- package/client/modeller/figure-clips.ts +17 -8
- package/client/modeller/figure-links.ts +21 -6
- package/client/modeller/figure-preview.ts +21 -7
- package/client/modeller/links.ts +13 -0
- package/client/setting-let/figure-namespace-setting-let.ts +84 -0
- package/dist-client/graphql/index.d.ts +13 -0
- package/dist-client/graphql/index.js +24 -0
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/harness-theme/brand.css +21 -25
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +1 -0
- package/dist-client/index.js.map +1 -1
- package/dist-client/modeller/figure-clips.js +26 -18
- package/dist-client/modeller/figure-clips.js.map +1 -1
- package/dist-client/modeller/figure-links.js +21 -7
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-preview.js +21 -7
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/links.d.ts +13 -0
- package/dist-client/modeller/links.js +11 -0
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/setting-let/figure-namespace-setting-let.d.ts +18 -0
- package/dist-client/setting-let/figure-namespace-setting-let.js +93 -0
- package/dist-client/setting-let/figure-namespace-setting-let.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -4
- package/test/brand-palette.test.ts +41 -6
- package/test/data-motion.test.ts +3 -0
- package/test/harness-serve.test.ts +49 -0
- package/test/links.test.ts +29 -0
- package/translations/en.json +8 -1
- package/translations/es.json +8 -1
- package/translations/ja.json +8 -1
- package/translations/ko.json +8 -1
- package/translations/ms.json +8 -1
- package/translations/zh.json +8 -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.160",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"@things-factory:registry": "https://registry.npmjs.org"
|
|
@@ -41,10 +41,11 @@
|
|
|
41
41
|
"@operato/slot-layout-editor": "^10.29.25",
|
|
42
42
|
"@operato/styles": "^10.0.0",
|
|
43
43
|
"@operato/utils": "^10.0.0",
|
|
44
|
-
"@things-factory/ai-assistant": "^10.1.
|
|
45
|
-
"@things-factory/figure-service": "^10.1.
|
|
44
|
+
"@things-factory/ai-assistant": "^10.1.160",
|
|
45
|
+
"@things-factory/figure-service": "^10.1.160",
|
|
46
46
|
"@things-factory/figure-viewer": "^10.1.155",
|
|
47
|
+
"@things-factory/setting-base": "^10.1.159",
|
|
47
48
|
"three": "^0.185.1"
|
|
48
49
|
},
|
|
49
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "b5e86be374e8b913a3f2b8459b6001e8f44e345b"
|
|
50
51
|
}
|
|
@@ -25,13 +25,17 @@ const HERE = import.meta.dirname
|
|
|
25
25
|
const FOLDER = 'harness-theme'
|
|
26
26
|
const BRAND = join(HERE, '..', 'client', FOLDER, 'brand.css')
|
|
27
27
|
const THEMES = ['light.css', 'dark.css'].map(f => join(HERE, '..', 'client', FOLDER, f))
|
|
28
|
-
/** 저작 하네스
|
|
29
|
-
const HARNESSES = ['
|
|
28
|
+
/** 저작 하네스 — 앱의 모델러 페이지를 그대로 세우는 것 하나다(옛 V2 픽스처 페이지는 2026-10-13 에 지웠다). */
|
|
29
|
+
const HARNESSES = ['real-modeller.mjs'].map(f =>
|
|
30
30
|
join(HERE, '..', '..', '..', 'test', 'browser', f)
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
const read = (path: string) => readFileSync(path, 'utf8')
|
|
34
34
|
|
|
35
|
+
/** brand.css 가 들여오는 teal — operato-suite 의 틀. 하네스의 `/pkg/` 처럼 저장소 안 경로로 읽는다. */
|
|
36
|
+
const TEAL_IMPORT = /@import url\('(\.\.\/\.\.\/\.\.\/operato-suite\/client\/frames\/teal\.css)'\);/
|
|
37
|
+
const TEAL = join(HERE, '..', 'client', FOLDER, '../../../operato-suite/client/frames/teal.css')
|
|
38
|
+
|
|
35
39
|
/** `--이름: 값;` 을 모은다. 한 줄에 여러 개 붙어 있어도 잡는다. */
|
|
36
40
|
function definitions(css: string): Map<string, string[]> {
|
|
37
41
|
const found = new Map<string, string[]>()
|
|
@@ -69,6 +73,37 @@ function colorOf(css: string, name: string): string {
|
|
|
69
73
|
return value
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
/**
|
|
77
|
+
* 브랜드 이름의 실제 색. brand.css 는 `var(--teal-on-*)` 로 suite 를 가리키므로 그 값을 따라가
|
|
78
|
+
* 6자리 hex 로 돌려준다.
|
|
79
|
+
*/
|
|
80
|
+
function brandColor(name: string): string {
|
|
81
|
+
const value = definitions(read(BRAND)).get(name)?.[0]
|
|
82
|
+
const teal = /^var\((--teal-on-(?:light|dark))\)$/.exec(value ?? '')
|
|
83
|
+
|
|
84
|
+
assert.ok(teal, `${name} 이 suite 의 teal 이름을 읽지 않는다: ${value}`)
|
|
85
|
+
|
|
86
|
+
const literal = definitions(read(TEAL)).get(teal[1]!)?.[0] ?? ''
|
|
87
|
+
const rgb = /^rgb\((\d+) (\d+) (\d+)\)$/.exec(literal)
|
|
88
|
+
|
|
89
|
+
assert.ok(rgb, `suite 의 ${teal[1]} 를 읽을 수 없다: ${literal}`)
|
|
90
|
+
return '#' + [rgb[1], rgb[2], rgb[3]].map(v => Number(v).toString(16).padStart(2, '0')).join('')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
test('teal 값은 operato-suite 에만 있다 — brand.css 는 들여와 이름만 잇는다', () => {
|
|
94
|
+
/*
|
|
95
|
+
* operato-figure · operato-twin 의 앱 화면이 읽는 teal 과 하네스의 teal 이 사본으로 따로 살았다
|
|
96
|
+
* (2026-10-13 까지). 이제 brand.css 는 suite 의 `frames/teal.css` 를 들여오고 값을 적지 않는다.
|
|
97
|
+
*/
|
|
98
|
+
const brand = read(BRAND)
|
|
99
|
+
|
|
100
|
+
assert.match(brand, TEAL_IMPORT, 'brand.css 가 suite 의 teal 틀을 들여오지 않는다')
|
|
101
|
+
assert.ok(existsSync(TEAL), `들여오는 자리에 teal 틀이 없다: ${TEAL}`)
|
|
102
|
+
|
|
103
|
+
const literals = [...brand.replace(/\/\*[\s\S]*?\*\//g, ' ').matchAll(/#[0-9a-f]{3,8}\b|rgba?\(/gi)].map(m => m[0])
|
|
104
|
+
assert.deepEqual(literals, [], `brand.css 가 색을 직접 적는다: ${literals.join(' · ')}`)
|
|
105
|
+
})
|
|
106
|
+
|
|
72
107
|
test('브랜드 색의 정본이 있다 — 없으면 아래 테스트가 다 통과해 버린다', () => {
|
|
73
108
|
const brand = definitions(read(BRAND))
|
|
74
109
|
|
|
@@ -168,7 +203,7 @@ test('산출물에 소스에 없는 css 가 없다 — copyfiles 는 지운 것
|
|
|
168
203
|
옮긴 자리를 하네스가 가리키지 않으면 하네스는 스타일시트 없이 뜬다 — 오류 없이 무채색 화면이
|
|
169
204
|
되고, 아래 대비 시험들은 **어느 화면에도 없는 값**을 재게 된다.
|
|
170
205
|
*/
|
|
171
|
-
test('
|
|
206
|
+
test('하네스가 옮긴 팔레트를 가리킨다 — 밝은 것과 어두운 것 모두', () => {
|
|
172
207
|
for (const path of HARNESSES) {
|
|
173
208
|
const html = read(path)
|
|
174
209
|
|
|
@@ -189,14 +224,14 @@ test('밝은 면과 어두운 면을 함께 든다 — 한쪽만 있으면 어
|
|
|
189
224
|
})
|
|
190
225
|
|
|
191
226
|
test('브랜드 색 위의 흰 글자가 읽힌다 — 작은 글자 기준 4.5', () => {
|
|
192
|
-
const figure =
|
|
227
|
+
const figure = brandColor('--figure-brand')
|
|
193
228
|
const measured = contrast(figure, '#ffffff')
|
|
194
229
|
|
|
195
230
|
assert.ok(measured >= 4.5, `${figure} 위 흰 글자 대비가 ${measured.toFixed(2)} 다`)
|
|
196
231
|
})
|
|
197
232
|
|
|
198
233
|
test('어두운 면 위의 브랜드 색이 읽힌다 — 그쪽은 -2 가 맡는다', () => {
|
|
199
|
-
const bright =
|
|
234
|
+
const bright = brandColor('--figure-brand-2')
|
|
200
235
|
const surface = colorOf(read(THEMES[1]!), '--md-sys-color-surface')
|
|
201
236
|
const measured = contrast(bright, surface)
|
|
202
237
|
|
|
@@ -207,7 +242,7 @@ test('밝은 쪽 값을 어두운 면에 쓰지 않는다 — 이름이 뜻이
|
|
|
207
242
|
/*
|
|
208
243
|
* `--figure-brand` 를 어두운 면에 그대로 쓰면 대비 1.6 이라 사라진다. 그 실수를 잡는다.
|
|
209
244
|
*/
|
|
210
|
-
const figure =
|
|
245
|
+
const figure = brandColor('--figure-brand')
|
|
211
246
|
const darkSurface = colorOf(read(THEMES[1]!), '--md-sys-color-surface')
|
|
212
247
|
|
|
213
248
|
assert.ok(
|
package/test/data-motion.test.ts
CHANGED
|
@@ -116,6 +116,9 @@ test('데이터 탭 · 클립 패널 · 미리보기의 배선과 문구', () =>
|
|
|
116
116
|
assert.match(preview, /tellInstances\('motion'/)
|
|
117
117
|
const clips = read('../client/modeller/figure-clips.ts')
|
|
118
118
|
assert.match(clips, /kind: 'remove-driver', state: track\.state, clip: clip\.name/)
|
|
119
|
+
/* A key's value is shown to three decimals: a slider's 14.399999999999999 is not what a person typed. */
|
|
120
|
+
assert.match(clips, /value: current === undefined \? '' : shown\(current\)/)
|
|
121
|
+
assert.match(clips, /\$\{key\.seconds\}s → \$\{shown\(key\.value\)\}/)
|
|
119
122
|
const keys = [read('../client/modeller/figure-data-panel.ts'), clips, read('../client/modeller/refusals.ts')].flatMap(src => [...src.matchAll(/'(figure\.[a-z.-]*[a-z])'/g)].map(m => m[1]!))
|
|
120
123
|
/* Keys made from a value: each value the kernel can give has its words. */
|
|
121
124
|
const made = [
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
|
+
import test from 'node:test'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 저작 하네스(`test/browser/serve-modeller.mjs`)가 서고, 표본이 모델러에서 열린다.
|
|
8
|
+
*
|
|
9
|
+
* import map 이 꾸러미의 `exports` 하위 경로를 따른다.
|
|
10
|
+
*
|
|
11
|
+
* 하네스(`test/browser/serve.mjs`)는 `name/` 접두 하나만 두고 있었다. 그래서
|
|
12
|
+
* `@operato/popup/ox-popup-actions.js` 처럼 들이는 이름과 파일 자리(`dist/src/...`)가 다른 모듈이
|
|
13
|
+
* 패키지 맨 위에서 찾아져 404 가 되었고, 그것을 무는 모델러가 하네스에서 통째로 안 떴다(2026-10-13).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const SERVE = join(import.meta.dirname, '..', '..', '..', 'test', 'browser', 'serve.mjs')
|
|
17
|
+
const REAL = join(import.meta.dirname, '..', '..', '..', 'test', 'browser', 'real-modeller.mjs')
|
|
18
|
+
|
|
19
|
+
test('exports 의 하위 경로가 그 파일 자리로 간다', async () => {
|
|
20
|
+
const { buildImportMap } = await import(pathToFileURL(SERVE).href)
|
|
21
|
+
const { imports } = buildImportMap()
|
|
22
|
+
|
|
23
|
+
assert.equal(imports['@operato/popup/ox-popup-actions.js'], '/nm/@operato/popup/dist/src/ox-popup-actions.js')
|
|
24
|
+
assert.equal(imports['@operato/styles/action-heights.js'], '/nm/@operato/styles/dist/src/action-heights.js')
|
|
25
|
+
assert.equal(imports['@operato/popup/'], '/nm/@operato/popup/', 'the prefix stays for paths exports does not name')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('표본은 모두 지금의 자산 형식이라 모델러가 연다', async () => {
|
|
29
|
+
/*
|
|
30
|
+
* 손으로 쓴 옛 부품 형식 표본은 figure-model 이 `ASSET_SCHEMA: asset: missing version` 으로 거절해
|
|
31
|
+
* 하나도 열리지 않았다(2026-10-13). 이제 저장소의 V3 자산(시험 고정물 · 레시피 기본 모델)을 그대로 읽는다.
|
|
32
|
+
*/
|
|
33
|
+
const { currentSamples } = await import(pathToFileURL(REAL).href)
|
|
34
|
+
const { parseFigureAsset } = await import('@hatiolab/figure-model')
|
|
35
|
+
const samples = currentSamples()
|
|
36
|
+
const refused: string[] = []
|
|
37
|
+
|
|
38
|
+
for (const sample of samples) {
|
|
39
|
+
try {
|
|
40
|
+
parseFigureAsset(JSON.stringify(sample.source))
|
|
41
|
+
} catch (error) {
|
|
42
|
+
refused.push(`${sample.key}: ${(error as Error).message}`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
assert.ok(samples.length > 10, `표본이 ${samples.length} 개뿐이다`)
|
|
47
|
+
assert.equal(new Set(samples.map(s => s.key)).size, samples.length, '표본 키가 겹친다')
|
|
48
|
+
assert.deepEqual(refused, [])
|
|
49
|
+
})
|
package/test/links.test.ts
CHANGED
|
@@ -645,6 +645,35 @@ test('붙이기 칸은 부품 제 붙임으로 열린다 — 가운데로 붙은
|
|
|
645
645
|
assert.ok(!ownFacesOf(asset, 'roller', true).includes('centre'), 'on the floor, by a face only')
|
|
646
646
|
})
|
|
647
647
|
|
|
648
|
+
test('a worked-out gap is kept by the fastening form: opening it on the part moves nothing (the robot dog, the forklift, 2026-10-13)', async () => {
|
|
649
|
+
const { fastenGapOf } = await import('../client/modeller/links.ts')
|
|
650
|
+
const { compileFigureAsset, robotDogFigure } = await import('@hatiolab/figure-model')
|
|
651
|
+
const posesOf = (asset: FigureAsset) =>
|
|
652
|
+
Object.fromEntries((compileFigureAsset(asset).evaluate().geometry as unknown as Array<{ id: string; pose?: { t: number[] } }>).map(g => [g.id, g.pose?.t.map(v => Math.round(v * 1000) / 1000)]))
|
|
653
|
+
/* What the form sends when nothing in it is changed: the attach it would make of the part's own fastening. */
|
|
654
|
+
const reattach = (asset: FigureAsset, part: string, form: Parameters<typeof fastenGapOf>[0]) =>
|
|
655
|
+
applyFigureAuthoring(asset, { kind: 'attach', part, face: 'bottom', to: { plane: 'mounting-plane' }, ...fastenGapOf(form), twist: 0, replace: true } as never)
|
|
656
|
+
|
|
657
|
+
const dog = robotDogFigure().asset
|
|
658
|
+
const body = fasteningOf(revisionOf(dog), 'body')!
|
|
659
|
+
assert.deepEqual(body.gapKept, dog.joints!.find(j => j.id === 'body')!.origin!.gap, 'the sum of the leg lengths, as written')
|
|
660
|
+
assert.deepEqual(posesOf(reattach(dog, 'body', body)), posesOf(dog), 'the body and everything hung from it stay where they stand')
|
|
661
|
+
/* The defect it replaces: read as the number 0, the body dropped to the floor and its legs below it. */
|
|
662
|
+
assert.notDeepEqual(posesOf(reattach(dog, 'body', { gap: body.gap })), posesOf(dog))
|
|
663
|
+
|
|
664
|
+
/* A gap that is a share of the instance height, as the forklift's is. */
|
|
665
|
+
let lift = addFigureBox(createFigureAsset('Lift'), { id: 'body', size: { x: 1000, y: 800, z: 600 }, position: { x: 0, y: 500, z: 0 } })
|
|
666
|
+
lift.document.model.inputs.push({ id: 'size.y', unit: 'mm', min: 100, max: 20000, role: 'design' } as never)
|
|
667
|
+
lift.designInputs['size.y'] = 1800
|
|
668
|
+
lift = applyFigureAuthoring(lift, { kind: 'attach', part: 'body', face: 'bottom', to: { plane: 'mounting-plane' }, gap: { from: { of: 'instance', axis: 'y' }, times: 0.05 } } as never)
|
|
669
|
+
const kept = fasteningOf(revisionOf(lift), 'body')!
|
|
670
|
+
assert.deepEqual(kept.gapKept, { from: { of: 'instance', axis: 'y' }, times: 0.05 })
|
|
671
|
+
assert.deepEqual(posesOf(reattach(lift, 'body', kept)), posesOf(lift))
|
|
672
|
+
/* A number typed in the form is a number again. */
|
|
673
|
+
assert.deepEqual(fastenGapOf({ gap: 20 }), { gap: 20 })
|
|
674
|
+
assert.deepEqual(fastenGapOf({ gap: 0 }), {})
|
|
675
|
+
})
|
|
676
|
+
|
|
648
677
|
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 () => {
|
|
649
678
|
const { motionFormOf, motionJoint, motionOf } = await import('../client/modeller/links.ts')
|
|
650
679
|
const { palletizerRobotFigure } = await import('@hatiolab/figure-model')
|
package/translations/en.json
CHANGED
|
@@ -555,6 +555,7 @@
|
|
|
555
555
|
"figure.label.fasten-detail": "Details",
|
|
556
556
|
"figure.label.facing": "How faces meet",
|
|
557
557
|
"figure.text.fasten-summary-gap": "gap {mm} mm",
|
|
558
|
+
"figure.text.fasten-summary-gap-worked-out": "gap worked out by a formula",
|
|
558
559
|
"figure.text.fasten-summary-twist": "twist {degrees}°",
|
|
559
560
|
"figure.label.gap": "gap (mm)",
|
|
560
561
|
"figure.label.align": "within the face",
|
|
@@ -829,6 +830,7 @@
|
|
|
829
830
|
"figure.text.resize-move": "(moves {mm} mm on {axis})",
|
|
830
831
|
"figure.text.held-by-rule": "A rule places this part.",
|
|
831
832
|
"figure.text.held-on-plane": "{face} kept on the {place} (gap {gap} mm)",
|
|
833
|
+
"figure.text.held-on-plane-worked-out": "{face} kept on the {place} (gap worked out by a formula)",
|
|
832
834
|
"figure.text.held-on-part": "Attached by its {face} to the {otherFace} of {other}",
|
|
833
835
|
"figure.button.open-fastening": "Open attachment settings",
|
|
834
836
|
"figure.button.detach-held": "Detach",
|
|
@@ -1108,5 +1110,10 @@
|
|
|
1108
1110
|
"figure.text.motion-setting-speed-out-of-range": "The speed of {group} is 0 to 3.",
|
|
1109
1111
|
"figure.text.motion-setting-group-selection-required": "Choose which clip of {group} plays.",
|
|
1110
1112
|
"figure.text.motion-key-outside-range": "The key {value} of {input} is outside {min} to {max}; a grouped clip keys inside the range.",
|
|
1111
|
-
"figure.label.tab-short-data": "Data"
|
|
1113
|
+
"figure.label.tab-short-data": "Data",
|
|
1114
|
+
"figure.title.namespace-setting": "Figure namespace",
|
|
1115
|
+
"figure.label.namespace": "Namespace",
|
|
1116
|
+
"figure.text.namespace-fixed": "Figures have been made under this namespace, so it cannot change.",
|
|
1117
|
+
"figure.text.namespace-empty-takes-subdomain": "Left empty, the subdomain {subdomain} is used. It cannot change once a figure is made.",
|
|
1118
|
+
"figure.text.namespace-subdomain-unusable": "The subdomain {subdomain} cannot be a namespace. Enter one, for example hatiolab.com."
|
|
1112
1119
|
}
|
package/translations/es.json
CHANGED
|
@@ -555,6 +555,7 @@
|
|
|
555
555
|
"figure.label.fasten-detail": "Detalles",
|
|
556
556
|
"figure.label.facing": "Cómo se unen las caras",
|
|
557
557
|
"figure.text.fasten-summary-gap": "separación {mm} mm",
|
|
558
|
+
"figure.text.fasten-summary-gap-worked-out": "separación calculada por una fórmula",
|
|
558
559
|
"figure.text.fasten-summary-twist": "torsión {degrees}°",
|
|
559
560
|
"figure.label.gap": "separación (mm)",
|
|
560
561
|
"figure.label.align": "dentro de la cara",
|
|
@@ -829,6 +830,7 @@
|
|
|
829
830
|
"figure.text.resize-move": "(se mueve {mm} mm en {axis})",
|
|
830
831
|
"figure.text.held-by-rule": "Una regla coloca esta pieza.",
|
|
831
832
|
"figure.text.held-on-plane": "{face} mantenida en {place} (separación {gap} mm)",
|
|
833
|
+
"figure.text.held-on-plane-worked-out": "{face} mantenida en {place} (separación calculada por una fórmula)",
|
|
832
834
|
"figure.text.held-on-part": "Unida por su {face} a {otherFace} de {other}",
|
|
833
835
|
"figure.button.open-fastening": "Abrir la configuración de unión",
|
|
834
836
|
"figure.button.detach-held": "Separar",
|
|
@@ -1108,5 +1110,10 @@
|
|
|
1108
1110
|
"figure.text.motion-setting-speed-out-of-range": "La velocidad de {group} es de 0 a 3.",
|
|
1109
1111
|
"figure.text.motion-setting-group-selection-required": "Elija qué clip de {group} se reproduce.",
|
|
1110
1112
|
"figure.text.motion-key-outside-range": "La clave {value} de {input} está fuera de {min} a {max}; un clip de grupo usa claves dentro del rango.",
|
|
1111
|
-
"figure.label.tab-short-data": "Datos"
|
|
1113
|
+
"figure.label.tab-short-data": "Datos",
|
|
1114
|
+
"figure.title.namespace-setting": "Namespace de Figure",
|
|
1115
|
+
"figure.label.namespace": "Namespace",
|
|
1116
|
+
"figure.text.namespace-fixed": "Ya hay figuras creadas con este namespace, por lo que no puede cambiar.",
|
|
1117
|
+
"figure.text.namespace-empty-takes-subdomain": "Si se deja vacío, se usa el subdominio {subdomain}. No puede cambiar una vez creada una figura.",
|
|
1118
|
+
"figure.text.namespace-subdomain-unusable": "El subdominio {subdomain} no puede ser un namespace. Escriba uno, por ejemplo hatiolab.com."
|
|
1112
1119
|
}
|
package/translations/ja.json
CHANGED
|
@@ -555,6 +555,7 @@
|
|
|
555
555
|
"figure.label.fasten-detail": "詳細",
|
|
556
556
|
"figure.label.facing": "接し方",
|
|
557
557
|
"figure.text.fasten-summary-gap": "間隔 {mm} mm",
|
|
558
|
+
"figure.text.fasten-summary-gap-worked-out": "間隔は式で決まる",
|
|
558
559
|
"figure.text.fasten-summary-twist": "ひねり {degrees}°",
|
|
559
560
|
"figure.label.gap": "gap (mm)",
|
|
560
561
|
"figure.label.align": "within the face",
|
|
@@ -829,6 +830,7 @@
|
|
|
829
830
|
"figure.text.resize-move": "({axis} {mm} mm 移動)",
|
|
830
831
|
"figure.text.held-by-rule": "規則がこの部品の位置を決めます。",
|
|
831
832
|
"figure.text.held-on-plane": "{face}を{place}に保持中 (間隔 {gap} mm)",
|
|
833
|
+
"figure.text.held-on-plane-worked-out": "{face}を{place}に保持中 (間隔は式で決まる)",
|
|
832
834
|
"figure.text.held-on-part": "{other}の{otherFace}に{face}で取り付け",
|
|
833
835
|
"figure.button.open-fastening": "取り付け設定を開く",
|
|
834
836
|
"figure.button.detach-held": "取り付けを外す",
|
|
@@ -1108,5 +1110,10 @@
|
|
|
1108
1110
|
"figure.text.motion-setting-speed-out-of-range": "{group} の速度は 0 ~ 3 です。",
|
|
1109
1111
|
"figure.text.motion-setting-group-selection-required": "{group} で再生するクリップを選びます。",
|
|
1110
1112
|
"figure.text.motion-key-outside-range": "{input} のキー {value} が範囲 {min} ~ {max} の外です。グループのクリップは範囲内のキーだけを使います。",
|
|
1111
|
-
"figure.label.tab-short-data": "データ"
|
|
1113
|
+
"figure.label.tab-short-data": "データ",
|
|
1114
|
+
"figure.title.namespace-setting": "Figure 名前空間",
|
|
1115
|
+
"figure.label.namespace": "名前空間",
|
|
1116
|
+
"figure.text.namespace-fixed": "この名前空間で Figure を作成済みのため変更できません。",
|
|
1117
|
+
"figure.text.namespace-empty-takes-subdomain": "空欄ならサブドメイン {subdomain} を使います。Figure を作成すると変更できません。",
|
|
1118
|
+
"figure.text.namespace-subdomain-unusable": "サブドメイン {subdomain} は名前空間に使えません。例: hatiolab.com"
|
|
1112
1119
|
}
|
package/translations/ko.json
CHANGED
|
@@ -555,6 +555,7 @@
|
|
|
555
555
|
"figure.label.fasten-detail": "세부",
|
|
556
556
|
"figure.label.facing": "닿는 방식",
|
|
557
557
|
"figure.text.fasten-summary-gap": "간격 {mm} mm",
|
|
558
|
+
"figure.text.fasten-summary-gap-worked-out": "간격은 식으로 정해짐",
|
|
558
559
|
"figure.text.fasten-summary-twist": "비틀기 {degrees}°",
|
|
559
560
|
"figure.label.gap": "간격 (mm)",
|
|
560
561
|
"figure.label.align": "면 안 위치",
|
|
@@ -829,6 +830,7 @@
|
|
|
829
830
|
"figure.text.resize-move": "({axis} {mm} mm 이동)",
|
|
830
831
|
"figure.text.held-by-rule": "규칙이 이 부품의 자리를 정합니다.",
|
|
831
832
|
"figure.text.held-on-plane": "{face}을 {place}에 유지 중 (간격 {gap} mm)",
|
|
833
|
+
"figure.text.held-on-plane-worked-out": "{face}을 {place}에 유지 중 (간격은 식으로 정해짐)",
|
|
832
834
|
"figure.text.held-on-part": "{other}의 {otherFace}에 {face}으로 붙어 있음",
|
|
833
835
|
"figure.button.open-fastening": "붙임 설정 열기",
|
|
834
836
|
"figure.button.detach-held": "붙임 풀기",
|
|
@@ -1108,5 +1110,10 @@
|
|
|
1108
1110
|
"figure.text.motion-setting-speed-out-of-range": "{group} 그룹의 배속은 0 ~ 3입니다.",
|
|
1109
1111
|
"figure.text.motion-setting-group-selection-required": "{group} 그룹에서 재생할 클립을 고릅니다.",
|
|
1110
1112
|
"figure.text.motion-key-outside-range": "{input} 조작값의 키 {value} 값이 범위 {min} ~ {max} 밖입니다. 그룹의 클립은 범위 안의 키만 씁니다.",
|
|
1111
|
-
"figure.label.tab-short-data": "데이터"
|
|
1113
|
+
"figure.label.tab-short-data": "데이터",
|
|
1114
|
+
"figure.title.namespace-setting": "Figure 이름공간",
|
|
1115
|
+
"figure.label.namespace": "이름공간",
|
|
1116
|
+
"figure.text.namespace-fixed": "이 이름공간으로 Figure를 만들어서 바꿀 수 없습니다.",
|
|
1117
|
+
"figure.text.namespace-empty-takes-subdomain": "비워 두면 서브도메인 {subdomain} 값을 씁니다. Figure를 만들고 나면 바꿀 수 없습니다.",
|
|
1118
|
+
"figure.text.namespace-subdomain-unusable": "서브도메인 {subdomain} 값은 이름공간으로 쓸 수 없습니다. 예: hatiolab.com"
|
|
1112
1119
|
}
|
package/translations/ms.json
CHANGED
|
@@ -555,6 +555,7 @@
|
|
|
555
555
|
"figure.label.fasten-detail": "Butiran",
|
|
556
556
|
"figure.label.facing": "Cara muka bertemu",
|
|
557
557
|
"figure.text.fasten-summary-gap": "jarak {mm} mm",
|
|
558
|
+
"figure.text.fasten-summary-gap-worked-out": "jarak ditentukan oleh formula",
|
|
558
559
|
"figure.text.fasten-summary-twist": "pulasan {degrees}°",
|
|
559
560
|
"figure.label.gap": "gap (mm)",
|
|
560
561
|
"figure.label.align": "within the face",
|
|
@@ -829,6 +830,7 @@
|
|
|
829
830
|
"figure.text.resize-move": "(bergerak {mm} mm pada {axis})",
|
|
830
831
|
"figure.text.held-by-rule": "Satu peraturan meletakkan bahagian ini.",
|
|
831
832
|
"figure.text.held-on-plane": "{face} dikekalkan pada {place} (jarak {gap} mm)",
|
|
833
|
+
"figure.text.held-on-plane-worked-out": "{face} dikekalkan pada {place} (jarak ditentukan oleh formula)",
|
|
832
834
|
"figure.text.held-on-part": "Dilekatkan dengan {face} pada {otherFace} {other}",
|
|
833
835
|
"figure.button.open-fastening": "Buka tetapan lekatan",
|
|
834
836
|
"figure.button.detach-held": "Tanggalkan",
|
|
@@ -1108,5 +1110,10 @@
|
|
|
1108
1110
|
"figure.text.motion-setting-speed-out-of-range": "Kelajuan {group} ialah 0 hingga 3.",
|
|
1109
1111
|
"figure.text.motion-setting-group-selection-required": "Pilih klip {group} yang dimainkan.",
|
|
1110
1112
|
"figure.text.motion-key-outside-range": "Kunci {value} bagi {input} di luar {min} hingga {max}; klip berkumpulan mesti dalam julat.",
|
|
1111
|
-
"figure.label.tab-short-data": "Data"
|
|
1113
|
+
"figure.label.tab-short-data": "Data",
|
|
1114
|
+
"figure.title.namespace-setting": "Namespace Figure",
|
|
1115
|
+
"figure.label.namespace": "Namespace",
|
|
1116
|
+
"figure.text.namespace-fixed": "Figure telah dibuat di bawah namespace ini, jadi ia tidak boleh diubah.",
|
|
1117
|
+
"figure.text.namespace-empty-takes-subdomain": "Jika dibiarkan kosong, subdomain {subdomain} digunakan. Ia tidak boleh diubah selepas figure dibuat.",
|
|
1118
|
+
"figure.text.namespace-subdomain-unusable": "Subdomain {subdomain} tidak boleh menjadi namespace. Masukkan satu, contohnya hatiolab.com."
|
|
1112
1119
|
}
|
package/translations/zh.json
CHANGED
|
@@ -555,6 +555,7 @@
|
|
|
555
555
|
"figure.label.fasten-detail": "详细",
|
|
556
556
|
"figure.label.facing": "接触方式",
|
|
557
557
|
"figure.text.fasten-summary-gap": "间距 {mm} mm",
|
|
558
|
+
"figure.text.fasten-summary-gap-worked-out": "间距由公式决定",
|
|
558
559
|
"figure.text.fasten-summary-twist": "扭转 {degrees}°",
|
|
559
560
|
"figure.label.gap": "gap (mm)",
|
|
560
561
|
"figure.label.align": "within the face",
|
|
@@ -829,6 +830,7 @@
|
|
|
829
830
|
"figure.text.resize-move": "({axis} 方向移动 {mm} mm)",
|
|
830
831
|
"figure.text.held-by-rule": "由规则决定此部件的位置。",
|
|
831
832
|
"figure.text.held-on-plane": "{face}保持在{place}上(间距 {gap} mm)",
|
|
833
|
+
"figure.text.held-on-plane-worked-out": "{face}保持在{place}上(间距由公式决定)",
|
|
832
834
|
"figure.text.held-on-part": "以{face}附着在{other}的{otherFace}上",
|
|
833
835
|
"figure.button.open-fastening": "打开附着设置",
|
|
834
836
|
"figure.button.detach-held": "解除附着",
|
|
@@ -1108,5 +1110,10 @@
|
|
|
1108
1110
|
"figure.text.motion-setting-speed-out-of-range": "{group} 的倍速为 0 ~ 3。",
|
|
1109
1111
|
"figure.text.motion-setting-group-selection-required": "请选择 {group} 播放的片段。",
|
|
1110
1112
|
"figure.text.motion-key-outside-range": "{input} 的关键帧 {value} 超出 {min} ~ {max};组内片段只能在范围内设关键帧。",
|
|
1111
|
-
"figure.label.tab-short-data": "数据"
|
|
1113
|
+
"figure.label.tab-short-data": "数据",
|
|
1114
|
+
"figure.title.namespace-setting": "Figure 命名空间",
|
|
1115
|
+
"figure.label.namespace": "命名空间",
|
|
1116
|
+
"figure.text.namespace-fixed": "已用此命名空间创建 Figure,无法更改。",
|
|
1117
|
+
"figure.text.namespace-empty-takes-subdomain": "留空则使用子域名 {subdomain}。创建 Figure 后无法更改。",
|
|
1118
|
+
"figure.text.namespace-subdomain-unusable": "子域名 {subdomain} 不能用作命名空间。例如 hatiolab.com"
|
|
1112
1119
|
}
|