@things-factory/figure-service 10.1.215 → 10.1.222

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/figure-service",
3
- "version": "10.1.215",
3
+ "version": "10.1.222",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "@things-factory:registry": "https://registry.npmjs.org"
@@ -25,18 +25,18 @@
25
25
  "test:templates": "node --test scripts/templates.test.mts"
26
26
  },
27
27
  "dependencies": {
28
- "@hatiolab/figure-model": "^0.11.0",
28
+ "@hatiolab/figure-model": "^0.11.1",
29
29
  "@operato/typeorm-history": "^10.0.0",
30
- "@things-factory/ai-client-base": "^10.1.215",
31
- "@things-factory/attachment-base": "^10.1.215",
32
- "@things-factory/auth-base": "^10.1.215",
30
+ "@things-factory/ai-client-base": "^10.1.218",
31
+ "@things-factory/attachment-base": "^10.1.218",
32
+ "@things-factory/auth-base": "^10.1.218",
33
33
  "@things-factory/env": "^10.1.149",
34
- "@things-factory/setting-base": "^10.1.215",
34
+ "@things-factory/setting-base": "^10.1.218",
35
35
  "@things-factory/shell": "^10.1.208",
36
36
  "graphql-scalars": "^1.22.4",
37
37
  "graphql-upload": "^15.0.2",
38
38
  "jszip": "^3.10.1",
39
39
  "koa-router": "^7.4.0"
40
40
  },
41
- "gitHead": "7de5e80eb1f4e2e268746aee39f820e7563f454d"
41
+ "gitHead": "afdd6a9b1c8b440e39d4fec48bfbad1a0c02fccc"
42
42
  }
@@ -356,6 +356,7 @@ const SUBJECT: { [K in FigureProposalStep['kind']]: (step: StepOf<K>, base: Figu
356
356
  'scale-uniformly': () => undefined,
357
357
  'follow-size-in-proportion': () => undefined,
358
358
  'set-detail-level': () => undefined,
359
+ 'set-item': () => undefined,
359
360
  'add-design-input': () => undefined,
360
361
  'set-input-range': () => undefined,
361
362
  'publish-input': () => undefined,
@@ -312,6 +312,13 @@ describe('figure-format — 판을 알아보는 문', () => {
312
312
  for (const code of ['size-changed', 'motion-range-changed', 'contact-face-changed', 'public-input-gone', 'public-input-range-narrowed', 'public-input-added', 'state-input-joints-changed', 'joint-axis-changed', 'joint-motion-unit-changed', 'joint-child-changed', 'joint-list-unread', 'extension-gone', 'extension-changed', 'extension-added'])
313
313
  for (const dict of [KO, EN]) for (const field of ['message', 'why']) expect(dict[`figure.gate.contract.${code}.${field}`]).toBeTruthy()
314
314
  })
315
+ it('what a status port offers a template has its sentences in all six languages (ADR-0051 2.3)', () => {
316
+ const codes = ['status-port-gone', 'status-port-added', 'status-port-state-withdrawn', 'status-port-state-offered', 'status-port-state-mode-changed', 'status-port-group-withdrawn', 'status-port-group-offered']
317
+ for (const lang of ['ko', 'en', 'ja', 'zh', 'es', 'ms']) {
318
+ const dict = require(`../../../translations/${lang}.json`) as Record<string, string>
319
+ for (const code of codes) for (const field of ['message', 'why']) expect([lang, code, field, !!dict[`figure.gate.contract.${code}.${field}`]]).toEqual([lang, code, field, true])
320
+ }
321
+ })
315
322
  it('the data changes have their sentences under figure-model 0.6.6\'s codes, in all six languages', () => {
316
323
  /* 0.6.6 named them for data fields and bindings (data interface 2); a sentence under the old code is never found. */
317
324
  const codes = ['data-field-gone', 'data-field-kind-changed', 'data-field-narrowed', 'data-field-added', 'data-field-label-changed', 'data-field-default-changed', 'data-bindings-changed']
@@ -364,4 +371,42 @@ describe('figure-format — 판을 알아보는 문', () => {
364
371
  }
365
372
  })
366
373
  })
374
+
375
+ /* ADR-0155 amendment 2: a figure tagged as an item is told what it lacks for a seat, never refused. */
376
+ describe('a figure tagged as an item', () => {
377
+ const reel = () => {
378
+ let a = applyFigureAuthoring(createFigureAsset('Reel'), { kind: 'set-placement', placement: 'floor' })
379
+ a = addFigureBox(a, { id: 'body', size: { x: 760, y: 840, z: 840 }, position: { x: 0, y: 420, z: 0 } })
380
+ return applyFigureAuthoring(a, { kind: 'set-item', item: true })
381
+ }
382
+ const itemNotes = (asset: FigureAsset) =>
383
+ inspectSource(serializeFigureAsset(asset), null, undefined, 'REEL').findings.filter(f => f.code.startsWith('item-'))
384
+
385
+ it('with no mounting face and no size inputs is told both, and the release goes on', () => {
386
+ const found = itemNotes(reel())
387
+ expect(found.map(f => [f.code, f.blocking])).toEqual([['item-mounting-face-missing', false], ['item-size-inputs-missing', false]])
388
+ expect(found[0].message).toBe('This item names no mounting face.')
389
+ /* Said of the figure, never of a part: the panel lists `at` under the parts it touches. */
390
+ expect(found.map(f => f.at)).toEqual([undefined, undefined])
391
+ })
392
+ it('a figure that is no item is told nothing', () => {
393
+ expect(itemNotes(applyFigureAuthoring(reel(), { kind: 'set-item', item: false }))).toEqual([])
394
+ })
395
+ it('a tag that goes refuses the release; one that comes is said', () => {
396
+ const tagged = serializeFigureAsset(reel())
397
+ const untagged = serializeFigureAsset(applyFigureAuthoring(reel(), { kind: 'set-item', item: false }))
398
+ const gone = inspectSource(untagged, tagged, undefined, 'REEL').findings.find(f => f.code === 'item-gone')!
399
+ expect([gone.blocking, gone.message]).toEqual([true, 'The figure is no longer an item.'])
400
+ const added = inspectSource(tagged, untagged, undefined, 'REEL').findings.find(f => f.code === 'item-added')!
401
+ expect(added.blocking).toBe(false)
402
+ })
403
+ it('its sentences are in all six languages', () => {
404
+ const keys = ['item-mounting-face-missing', 'item-size-inputs-missing', 'item-also-holder'].flatMap(code => ['message', 'why', 'how'].map(field => `figure.gate.${code}.${field}`))
405
+ .concat(['item-gone', 'item-added'].flatMap(code => ['message', 'why'].map(field => `figure.gate.contract.${code}.${field}`)))
406
+ for (const lang of ['ko', 'en', 'ja', 'zh', 'es', 'ms']) {
407
+ const dict = require(`../../../translations/${lang}.json`) as Record<string, string>
408
+ for (const key of keys) expect([lang, key, !!dict[key]]).toEqual([lang, key, true])
409
+ }
410
+ })
411
+ })
367
412
  })
@@ -4,7 +4,7 @@
4
4
  * (`consumablePayloadOf`). The format is `figure-asset-1`, and the asset says so in its `version`; a source
5
5
  * that does not is refused by name, because a source the server cannot identify is one it must not save.
6
6
  */
7
- import { FIGURE_KERNEL_VERSION, compileFigureAsset, inspectFigureAsset, isPlaceholderType, parseFigureAsset, serializeFigureAsset, figureContractChanges, figureCostOf, figurePlaneGapOf, figureReleaseMetricsOf, figureScoreOf, figureTopViewOf, forgetRecordedInstanceSize, recordFigureInstanceSize } from '@hatiolab/figure-model'
7
+ import { FIGURE_KERNEL_VERSION, compileFigureAsset, inspectFigureAsset, isPlaceholderType, parseFigureAsset, serializeFigureAsset, figureContractChanges, figureCostOf, figureItemNotesOf, figurePlaneGapOf, figureReleaseMetricsOf, figureScoreOf, figureTopViewOf, forgetRecordedInstanceSize, recordFigureInstanceSize } from '@hatiolab/figure-model'
8
8
  import type { FigureAsset, FigureContractChange, FigureContractError, FigureReleaseMetrics, FigureTopView, FigureViolation } from '@hatiolab/figure-model'
9
9
 
10
10
  import type { FigureFinding } from './figure-type.js'
@@ -278,6 +278,7 @@ export function inspectSource(
278
278
  })
279
279
  }
280
280
  findings.push(...planeGapFindings(asset!, say))
281
+ findings.push(...itemFindings(asset!, say))
281
282
  if (releasedJson) findings.push(...figureContractFindings(asset!, releasedJson, say))
282
283
  findings.push(...appFindings({ asset: asset!, type: rowType, category: rowCategory, t }))
283
284
  return { blocked: findings.some(finding => finding.blocking), findings }
@@ -336,6 +337,37 @@ function planeGapFindings(asset: FigureAsset, say: Say): GateFinding[] {
336
337
  ]
337
338
  }
338
339
 
340
+ /*
341
+ Said, never refused (ADR-0155 amendment 2): what a figure tagged as an item lacks for a seat to show it as its author
342
+ expects, and whether it also holds. A figure may be an item without any of them.
343
+ */
344
+ const ITEM_ENGLISH = {
345
+ 'item-mounting-face-missing': {
346
+ message: 'This item names no mounting face.',
347
+ why: 'An item stands in its seat on the bottom of its body. Naming the face it stands on lets the release check that this face is at the bottom.',
348
+ how: 'Name its mounting face, or keep it if the bottom of its body is where it stands.'
349
+ },
350
+ 'item-size-inputs-missing': {
351
+ message: 'This item cannot be resized by a drawing.',
352
+ why: 'A seat gives an item its size. Without size inputs it grows in proportion and fills the seat along one side only.',
353
+ how: 'Let a drawing resize it if it should fill its seat; keep it if it should keep its proportions.'
354
+ },
355
+ 'item-also-holder': {
356
+ message: 'This item also holds things.',
357
+ why: 'A holder carried by another holder holding things of its own is not supported by scenes yet.',
358
+ how: 'Keep it if it is meant.'
359
+ }
360
+ } as const
361
+ function itemFindings(asset: FigureAsset, say: Say): GateFinding[] {
362
+ return figureItemNotesOf(asset).map(code => ({
363
+ code,
364
+ message: say(`figure.gate.${code}.message`, {}, ITEM_ENGLISH[code].message),
365
+ why: say(`figure.gate.${code}.why`, {}, ITEM_ENGLISH[code].why),
366
+ how: say(`figure.gate.${code}.how`, {}, ITEM_ENGLISH[code].how),
367
+ blocking: false
368
+ }))
369
+ }
370
+
339
371
  /**
340
372
  * The last release against this one — what the drawings that already hold this type lean on (ADR-0063 decision 3).
341
373
  *
@@ -489,6 +521,17 @@ function figureContractWording(change: FigureContractChange, say: Say): Pick<Gat
489
521
  message: say(key('message'), v, `The capability '${v.name}' is new.`),
490
522
  why: say(key('why'), {}, 'It adds what the figure can do. Placed instances stand as they are.')
491
523
  }
524
+ case 'item-gone':
525
+ return {
526
+ message: say(key('message'), v, 'The figure is no longer an item.'),
527
+ why: say(key('why'), {}, 'Item type tables draw their items with this figure. They lose its look.'),
528
+ ...gone
529
+ }
530
+ case 'item-added':
531
+ return {
532
+ message: say(key('message'), v, 'The figure is now an item.'),
533
+ why: say(key('why'), {}, 'Item type tables can draw their items with it. Placed instances stand as they are.')
534
+ }
492
535
  /* Said, never refused (ADR-0104): a consumer that pins a release reads these before it moves to this one. */
493
536
  case 'size-changed':
494
537
  return {
@@ -614,6 +657,45 @@ function figureContractWording(change: FigureContractChange, say: Say): Pick<Gat
614
657
  message: say(key('message'), v, `A change of clip in '${v.group}' now blends over ${v.after} s, not ${v.before} s.`),
615
658
  why: say(key('why'), {}, 'Only how a change of clip looks changes; which clip plays does not.')
616
659
  }
660
+ /* What a board's status templates lean on (ADR-0051 2.3): a port, the state inputs it offers, the group it selects a clip in. */
661
+ case 'status-port-gone':
662
+ return {
663
+ message: say(key('message'), v, `The status port '${v.port}' is gone.`),
664
+ why: say(key('why'), {}, 'A status template gives its codes a colour, an effect, values and a clip. After this release they show nothing on this figure.'),
665
+ ...gone
666
+ }
667
+ case 'status-port-added':
668
+ return {
669
+ message: say(key('message'), v, `There is a new status port '${v.port}'.`),
670
+ why: say(key('why'), {}, "Its codes show by the board's status template once the data gives them.")
671
+ }
672
+ case 'status-port-state-withdrawn':
673
+ return {
674
+ message: say(key('message'), v, `The status port '${v.port}' no longer offers '${v.input}'.`),
675
+ why: say(key('why'), {}, "A status template's value for it moves nothing after this release."),
676
+ ...gone
677
+ }
678
+ case 'status-port-state-offered':
679
+ return {
680
+ message: say(key('message'), v, `The status port '${v.port}' now offers '${v.input}'.`),
681
+ why: say(key('why'), {}, 'A status template can give it a value for each code.')
682
+ }
683
+ case 'status-port-state-mode-changed':
684
+ return {
685
+ message: say(key('message'), v, `The way the status port '${v.port}' gives '${v.input}' changed from ${v.before} to ${v.after}.`),
686
+ why: say(key('why'), {}, 'After this release the same code reaches that value another way.')
687
+ }
688
+ case 'status-port-group-withdrawn':
689
+ return {
690
+ message: say(key('message'), v, `The status port '${v.port}' no longer selects a clip in '${v.group}'.`),
691
+ why: say(key('why'), {}, "A status template's clip for it plays nothing after this release."),
692
+ ...gone
693
+ }
694
+ case 'status-port-group-offered':
695
+ return {
696
+ message: say(key('message'), v, `The status port '${v.port}' now selects a clip in '${v.group}'.`),
697
+ why: say(key('why'), {}, "A status template can choose the group's clip for each code.")
698
+ }
617
699
  /* The joints a controller drives (ADR-0107 decision 7): what writing a state input moves, compared release to release. */
618
700
  case 'state-input-joints-changed': {
619
701
  const after = v.after || say('figure.gate.contract.joints-none', {}, 'nothing')
@@ -55,6 +55,19 @@
55
55
  "figure.gate.contract.capability-gone.why": "Scenes attach behaviour by this name. Placed instances lose what it did.",
56
56
  "figure.gate.contract.capability-added.message": "The capability '{name}' is new.",
57
57
  "figure.gate.contract.capability-added.why": "It adds what the figure can do. Placed instances stand as they are.",
58
+ "figure.gate.contract.item-gone.message": "The figure is no longer an item.",
59
+ "figure.gate.contract.item-gone.why": "Item type tables draw their items with this figure. They lose its look.",
60
+ "figure.gate.contract.item-added.message": "The figure is now an item.",
61
+ "figure.gate.contract.item-added.why": "Item type tables can draw their items with it. Placed instances stand as they are.",
62
+ "figure.gate.item-mounting-face-missing.message": "This item names no mounting face.",
63
+ "figure.gate.item-mounting-face-missing.why": "An item stands in its seat on the bottom of its body. Naming the face it stands on lets the release check that this face is at the bottom.",
64
+ "figure.gate.item-mounting-face-missing.how": "Name its mounting face, or keep it if the bottom of its body is where it stands.",
65
+ "figure.gate.item-size-inputs-missing.message": "This item cannot be resized by a drawing.",
66
+ "figure.gate.item-size-inputs-missing.why": "A seat gives an item its size. Without size inputs it grows in proportion and fills the seat along one side only.",
67
+ "figure.gate.item-size-inputs-missing.how": "Let a drawing resize it if it should fill its seat; keep it if it should keep its proportions.",
68
+ "figure.gate.item-also-holder.message": "This item also holds things.",
69
+ "figure.gate.item-also-holder.why": "A holder carried by another holder holding things of its own is not supported by scenes yet.",
70
+ "figure.gate.item-also-holder.how": "Keep it if it is meant.",
58
71
  "figure.gate.contract.size-changed.message": "The figure's size changed: {before} → {after}.",
59
72
  "figure.gate.contract.size-changed.why": "A board gives the figure a box of this size. One that moves to this release sees its box change.",
60
73
  "figure.gate.contract.motion-range-changed.message": "The room the figure sweeps as it moves changed: {before} → {after}.",
@@ -143,6 +156,20 @@
143
156
  "figure.gate.contract.motion-group-added.why": "Placed instances play its default clip until a board or data chooses another.",
144
157
  "figure.gate.contract.motion-group-clip-added.message": "The motion group '{group}' now holds '{clip}'.",
145
158
  "figure.gate.contract.motion-group-clip-added.why": "It plays when a board or data chooses it.",
159
+ "figure.gate.contract.status-port-gone.message": "The status port '{port}' is gone.",
160
+ "figure.gate.contract.status-port-gone.why": "A status template gives its codes a colour, an effect, values and a clip. After this release they show nothing on this figure.",
161
+ "figure.gate.contract.status-port-added.message": "There is a new status port '{port}'.",
162
+ "figure.gate.contract.status-port-added.why": "Its codes show by the board's status template once the data gives them.",
163
+ "figure.gate.contract.status-port-state-withdrawn.message": "The status port '{port}' no longer offers '{input}'.",
164
+ "figure.gate.contract.status-port-state-withdrawn.why": "A status template's value for it moves nothing after this release.",
165
+ "figure.gate.contract.status-port-state-offered.message": "The status port '{port}' now offers '{input}'.",
166
+ "figure.gate.contract.status-port-state-offered.why": "A status template can give it a value for each code.",
167
+ "figure.gate.contract.status-port-state-mode-changed.message": "The way the status port '{port}' gives '{input}' changed from {before} to {after}.",
168
+ "figure.gate.contract.status-port-state-mode-changed.why": "After this release the same code reaches that value another way.",
169
+ "figure.gate.contract.status-port-group-withdrawn.message": "The status port '{port}' no longer selects a clip in '{group}'.",
170
+ "figure.gate.contract.status-port-group-withdrawn.why": "A status template's clip for it plays nothing after this release.",
171
+ "figure.gate.contract.status-port-group-offered.message": "The status port '{port}' now selects a clip in '{group}'.",
172
+ "figure.gate.contract.status-port-group-offered.why": "A status template can choose the group's clip for each code.",
146
173
  "figure.gate.contract.motion-group-default-changed.message": "The motion group '{group}' now starts with '{after}', not '{before}'.",
147
174
  "figure.gate.contract.motion-group-default-changed.why": "Placed instances with no choice of their own play the new default after this release.",
148
175
  "figure.gate.contract.motion-group-transition-changed.message": "A change of clip in '{group}' now blends over {after} s, not {before} s.",
@@ -55,6 +55,19 @@
55
55
  "figure.gate.contract.capability-gone.why": "Las escenas asocian comportamientos mediante este nombre. Las instancias colocadas pierden lo que hacía.",
56
56
  "figure.gate.contract.capability-added.message": "La capacidad '{name}' es nuevo.",
57
57
  "figure.gate.contract.capability-added.why": "Amplía lo que puede hacer la figura. Las instancias colocadas se quedan como están.",
58
+ "figure.gate.contract.item-gone.message": "La figura ya no es un artículo.",
59
+ "figure.gate.contract.item-gone.why": "Las tablas de tipos de artículo dibujan sus artículos con esta figura. Pierden su forma.",
60
+ "figure.gate.contract.item-added.message": "La figura ahora es un artículo.",
61
+ "figure.gate.contract.item-added.why": "Las tablas de tipos de artículo pueden dibujar sus artículos con ella. Las instancias colocadas se quedan como están.",
62
+ "figure.gate.item-mounting-face-missing.message": "Este artículo no nombra una cara de montaje.",
63
+ "figure.gate.item-mounting-face-missing.why": "Un artículo se apoya en su lugar sobre la base de su cuerpo. Nombrar la cara en la que se apoya permite que la publicación compruebe que esa cara está abajo.",
64
+ "figure.gate.item-mounting-face-missing.how": "Nombre su cara de montaje, o déjelo si se apoya sobre la base de su cuerpo.",
65
+ "figure.gate.item-size-inputs-missing.message": "Este artículo no puede cambiar de tamaño en un plano.",
66
+ "figure.gate.item-size-inputs-missing.why": "Un lugar da al artículo su tamaño. Sin entradas de tamaño crece en proporción y llena el lugar solo en un sentido.",
67
+ "figure.gate.item-size-inputs-missing.how": "Permita cambiar su tamaño en el plano si debe llenar su lugar; déjelo si debe mantener sus proporciones.",
68
+ "figure.gate.item-also-holder.message": "Este artículo también contiene cosas.",
69
+ "figure.gate.item-also-holder.why": "Las escenas aún no admiten que un contenedor llevado por otro contenga cosas propias.",
70
+ "figure.gate.item-also-holder.how": "Déjelo si es intencionado.",
58
71
  "figure.gate.contract.size-changed.message": "El tamaño de la figura cambió: {before} → {after}.",
59
72
  "figure.gate.contract.size-changed.why": "Un tablero le da a la figura una caja de este tamaño. Al pasar a esta versión, su caja cambia.",
60
73
  "figure.gate.contract.motion-range-changed.message": "El espacio que la figura recorre al moverse cambió: {before} → {after}.",
@@ -143,6 +156,20 @@
143
156
  "figure.gate.contract.motion-group-added.why": "Las instancias reproducen su clip predeterminado hasta que un tablero o datos elijan otro.",
144
157
  "figure.gate.contract.motion-group-clip-added.message": "El grupo '{group}' contiene ahora '{clip}'.",
145
158
  "figure.gate.contract.motion-group-clip-added.why": "Se reproduce cuando un tablero o datos lo eligen.",
159
+ "figure.gate.contract.status-port-gone.message": "El puerto de estado '{port}' ya no existe.",
160
+ "figure.gate.contract.status-port-gone.why": "Una plantilla de estado da a sus códigos un color, un efecto, valores y un clip. Tras esta publicación no muestran nada en esta figura.",
161
+ "figure.gate.contract.status-port-added.message": "Hay un puerto de estado nuevo: '{port}'.",
162
+ "figure.gate.contract.status-port-added.why": "Sus códigos se muestran según la plantilla de estado del tablero cuando los datos los dan.",
163
+ "figure.gate.contract.status-port-state-withdrawn.message": "El puerto de estado '{port}' ya no ofrece '{input}'.",
164
+ "figure.gate.contract.status-port-state-withdrawn.why": "El valor que una plantilla de estado le da no mueve nada tras esta publicación.",
165
+ "figure.gate.contract.status-port-state-offered.message": "El puerto de estado '{port}' ofrece ahora '{input}'.",
166
+ "figure.gate.contract.status-port-state-offered.why": "Una plantilla de estado puede darle un valor por código.",
167
+ "figure.gate.contract.status-port-state-mode-changed.message": "La forma en que el puerto de estado '{port}' da '{input}' cambió de {before} a {after}.",
168
+ "figure.gate.contract.status-port-state-mode-changed.why": "Tras esta publicación el mismo código llega a ese valor de otra manera.",
169
+ "figure.gate.contract.status-port-group-withdrawn.message": "El puerto de estado '{port}' ya no elige un clip en '{group}'.",
170
+ "figure.gate.contract.status-port-group-withdrawn.why": "El clip que una plantilla de estado le da no se reproduce tras esta publicación.",
171
+ "figure.gate.contract.status-port-group-offered.message": "El puerto de estado '{port}' elige ahora un clip en '{group}'.",
172
+ "figure.gate.contract.status-port-group-offered.why": "Una plantilla de estado puede elegir el clip del grupo por código.",
146
173
  "figure.gate.contract.motion-group-default-changed.message": "El grupo '{group}' empieza ahora con '{after}', no con '{before}'.",
147
174
  "figure.gate.contract.motion-group-default-changed.why": "Las instancias sin elección propia reproducen el nuevo predeterminado tras esta publicación.",
148
175
  "figure.gate.contract.motion-group-transition-changed.message": "El cambio de clip en '{group}' dura ahora {after} s, no {before} s.",
@@ -55,6 +55,19 @@
55
55
  "figure.gate.contract.capability-gone.why": "シーンはこの名前で動作を付けます。配置済みのインスタンスはその動作を失います。",
56
56
  "figure.gate.contract.capability-added.message": "'{name}' 能力が新しく追加されました。",
57
57
  "figure.gate.contract.capability-added.why": "Figure ができることが増えます。配置済みのインスタンスはそのままです。",
58
+ "figure.gate.contract.item-gone.message": "この Figure はアイテムではなくなりました。",
59
+ "figure.gate.contract.item-gone.why": "アイテムタイプ表がこの Figure でアイテムを描いています。その形を失います。",
60
+ "figure.gate.contract.item-added.message": "この Figure がアイテムになりました。",
61
+ "figure.gate.contract.item-added.why": "アイテムタイプ表がこの Figure でアイテムを描けます。配置済みのインスタンスはそのままです。",
62
+ "figure.gate.item-mounting-face-missing.message": "このアイテムは取付面を指定していません。",
63
+ "figure.gate.item-mounting-face-missing.why": "アイテムは場所で本体の最下部に立ちます。立つ面を取付面に指定すると、発行チェックがその面が最下部にあるか確認します。",
64
+ "figure.gate.item-mounting-face-missing.how": "取付面を指定してください。本体の最下部で立つのが正しければそのままにしてください。",
65
+ "figure.gate.item-size-inputs-missing.message": "このアイテムは図面でサイズを変えられません。",
66
+ "figure.gate.item-size-inputs-missing.why": "アイテムのサイズは置かれる場所が決めます。サイズ入力がないと比例で大きくなり、場所を一方向にしか満たしません。",
67
+ "figure.gate.item-size-inputs-missing.how": "場所を満たすべきなら「図面でサイズを変えられるようにする」を行ってください。比例を保つべきならそのままにしてください。",
68
+ "figure.gate.item-also-holder.message": "このアイテムは物も受け取ります。",
69
+ "figure.gate.item-also-holder.why": "別のホルダーに載ったホルダーが自分の物を受け取ることは、まだシーンが対応していません。",
70
+ "figure.gate.item-also-holder.how": "意図したものならそのままにしてください。",
58
71
  "figure.gate.contract.size-changed.message": "図形のサイズが変わりました: {before} → {after}。",
59
72
  "figure.gate.contract.size-changed.why": "ボードはこのサイズの箱で図形を置きます。このリリースに移ると箱が変わります。",
60
73
  "figure.gate.contract.motion-range-changed.message": "動くときに通る空間が変わりました: {before} → {after}。",
@@ -143,6 +156,20 @@
143
156
  "figure.gate.contract.motion-group-added.why": "ボードやデータが別のクリップを選ぶまで既定クリップを再生します。",
144
157
  "figure.gate.contract.motion-group-clip-added.message": "モーショングループ '{group}' に '{clip}' が入りました。",
145
158
  "figure.gate.contract.motion-group-clip-added.why": "ボードやデータが選ぶと再生します。",
159
+ "figure.gate.contract.status-port-gone.message": "ステータスポート '{port}' がなくなりました。",
160
+ "figure.gate.contract.status-port-gone.why": "ステータステンプレートはこのポートのコードごとに色・効果・値・クリップを与えます。このリリース以降、このフィギュアには何も表示されません。",
161
+ "figure.gate.contract.status-port-added.message": "ステータスポート '{port}' が追加されました。",
162
+ "figure.gate.contract.status-port-added.why": "データがコードを与えると、ボードのステータステンプレートどおりに表示されます。",
163
+ "figure.gate.contract.status-port-state-withdrawn.message": "ステータスポート '{port}' から入力 '{input}' が外れました。",
164
+ "figure.gate.contract.status-port-state-withdrawn.why": "ステータステンプレートがこの入力に与えた値は、このリリース以降何も動かしません。",
165
+ "figure.gate.contract.status-port-state-offered.message": "ステータスポート '{port}' が入力 '{input}' を公開しました。",
166
+ "figure.gate.contract.status-port-state-offered.why": "ステータステンプレートはコードごとにこの入力の値を与えられます。",
167
+ "figure.gate.contract.status-port-state-mode-changed.message": "ステータスポート '{port}' が '{input}' を与える方式が {before} から {after} に変わりました。",
168
+ "figure.gate.contract.status-port-state-mode-changed.why": "このリリース以降、同じコードでその値に至る様子が変わります。",
169
+ "figure.gate.contract.status-port-group-withdrawn.message": "ステータスポート '{port}' はモーショングループ '{group}' のクリップを選ばなくなりました。",
170
+ "figure.gate.contract.status-port-group-withdrawn.why": "ステータステンプレートがこのポートに与えたクリップは、このリリース以降再生されません。",
171
+ "figure.gate.contract.status-port-group-offered.message": "ステータスポート '{port}' がモーショングループ '{group}' のクリップを選びます。",
172
+ "figure.gate.contract.status-port-group-offered.why": "ステータステンプレートはコードごとにこのグループのクリップを選べます。",
146
173
  "figure.gate.contract.motion-group-default-changed.message": "モーショングループ '{group}' の既定クリップが '{before}' から '{after}' に変わりました。",
147
174
  "figure.gate.contract.motion-group-default-changed.why": "選択のないインスタンスは、このリリース以降新しい既定クリップを再生します。",
148
175
  "figure.gate.contract.motion-group-transition-changed.message": "'{group}' のクリップ切替時間が {before} 秒から {after} 秒に変わりました。",
@@ -55,6 +55,19 @@
55
55
  "figure.gate.contract.capability-gone.why": "씬이 이 이름으로 동작을 붙입니다. 놓인 인스턴스가 그 동작을 잃습니다.",
56
56
  "figure.gate.contract.capability-added.message": "'{name}' 능력이 새로 생겼습니다.",
57
57
  "figure.gate.contract.capability-added.why": "사용 가능한 기능이 추가됩니다. 기존 인스턴스의 상태는 유지됩니다.",
58
+ "figure.gate.contract.item-gone.message": "이 피규어는 더 이상 아이템이 아닙니다.",
59
+ "figure.gate.contract.item-gone.why": "아이템 타입 표가 이 피규어로 아이템을 그립니다. 그 모양을 잃습니다.",
60
+ "figure.gate.contract.item-added.message": "이 피규어가 이제 아이템입니다.",
61
+ "figure.gate.contract.item-added.why": "아이템 타입 표가 이 피규어로 아이템을 그릴 수 있습니다. 놓인 인스턴스는 그대로입니다.",
62
+ "figure.gate.item-mounting-face-missing.message": "이 아이템은 장착면을 정하지 않았습니다.",
63
+ "figure.gate.item-mounting-face-missing.why": "아이템은 자리에서 몸체 맨 아래로 섭니다. 서는 면을 장착면으로 정하면 발행 검사가 그 면이 맨 아래에 있는지 봅니다.",
64
+ "figure.gate.item-mounting-face-missing.how": "장착면을 정합니다. 몸체 맨 아래로 서는 것이 맞으면 그대로 둡니다.",
65
+ "figure.gate.item-size-inputs-missing.message": "이 아이템은 도면에서 크기를 바꿀 수 없습니다.",
66
+ "figure.gate.item-size-inputs-missing.why": "아이템의 크기는 앉는 자리가 줍니다. 크기 입력이 없으면 비례로 커져 자리를 한 방향으로만 채웁니다.",
67
+ "figure.gate.item-size-inputs-missing.how": "자리를 채워야 하면 「도면에서 크기를 바꿀 수 있게 하기」를 합니다. 비례를 지켜야 하면 그대로 둡니다.",
68
+ "figure.gate.item-also-holder.message": "이 아이템은 물건을 받기도 합니다.",
69
+ "figure.gate.item-also-holder.why": "다른 홀더에 실린 홀더가 자기 물건을 받는 것은 아직 장면이 지원하지 않습니다.",
70
+ "figure.gate.item-also-holder.how": "의도한 것이면 그대로 둡니다.",
58
71
  "figure.gate.contract.size-changed.message": "피규어의 크기가 바뀌었습니다: {before} → {after}.",
59
72
  "figure.gate.contract.size-changed.why": "보드는 이 크기의 상자로 피규어를 놓습니다. 이 발행본으로 옮기면 상자가 바뀝니다.",
60
73
  "figure.gate.contract.motion-range-changed.message": "움직일 때 쓸어 가는 공간이 바뀌었습니다: {before} → {after}.",
@@ -143,6 +156,20 @@
143
156
  "figure.gate.contract.motion-group-added.why": "보드나 데이터가 다른 클립을 선택 전까지 기본 클립을 재생합니다.",
144
157
  "figure.gate.contract.motion-group-clip-added.message": "'{group}' 동작 그룹에 '{clip}' 클립이 들어갔습니다.",
145
158
  "figure.gate.contract.motion-group-clip-added.why": "보드나 데이터가 선택하면 재생합니다.",
159
+ "figure.gate.contract.status-port-gone.message": "'{port}' 상태 포트가 없어졌습니다.",
160
+ "figure.gate.contract.status-port-gone.why": "상태 템플릿이 이 포트의 코드마다 색·효과·값·클립을 줍니다. 이 발행 뒤에는 이 피규어에 아무것도 보이지 않습니다.",
161
+ "figure.gate.contract.status-port-added.message": "'{port}' 상태 포트가 생겼습니다.",
162
+ "figure.gate.contract.status-port-added.why": "데이터가 코드를 주면 보드의 상태 템플릿대로 보입니다.",
163
+ "figure.gate.contract.status-port-state-withdrawn.message": "'{port}' 상태 포트에서 '{input}' 입력이 빠졌습니다.",
164
+ "figure.gate.contract.status-port-state-withdrawn.why": "상태 템플릿이 이 입력에 준 값은 이 발행 뒤에 아무것도 움직이지 않습니다.",
165
+ "figure.gate.contract.status-port-state-offered.message": "'{port}' 상태 포트가 '{input}' 입력을 내놓습니다.",
166
+ "figure.gate.contract.status-port-state-offered.why": "상태 템플릿이 코드마다 이 입력의 값을 줄 수 있습니다.",
167
+ "figure.gate.contract.status-port-state-mode-changed.message": "'{port}' 상태 포트가 '{input}' 값을 주는 방식이 {before} 에서 {after} 로 바뀌었습니다.",
168
+ "figure.gate.contract.status-port-state-mode-changed.why": "이 발행 뒤에는 같은 코드에서 그 값에 이르는 모습이 달라집니다.",
169
+ "figure.gate.contract.status-port-group-withdrawn.message": "'{port}' 상태 포트가 '{group}' 동작 그룹의 클립을 더 고르지 않습니다.",
170
+ "figure.gate.contract.status-port-group-withdrawn.why": "상태 템플릿이 이 포트에 준 클립은 이 발행 뒤에 재생되지 않습니다.",
171
+ "figure.gate.contract.status-port-group-offered.message": "'{port}' 상태 포트가 '{group}' 동작 그룹의 클립을 고릅니다.",
172
+ "figure.gate.contract.status-port-group-offered.why": "상태 템플릿이 코드마다 이 그룹의 클립을 고를 수 있습니다.",
146
173
  "figure.gate.contract.motion-group-default-changed.message": "'{group}' 동작 그룹의 기본 클립이 '{before}' 클립에서 '{after}' 클립으로 바뀌었습니다.",
147
174
  "figure.gate.contract.motion-group-default-changed.why": "선택이 없는 인스턴스는 이 발행 뒤에 새 기본 클립을 재생합니다.",
148
175
  "figure.gate.contract.motion-group-transition-changed.message": "'{group}' 동작 그룹에서 클립을 바꿀 때의 전환 시간이 {before}초에서 {after}초로 바뀌었습니다.",
@@ -55,6 +55,19 @@
55
55
  "figure.gate.contract.capability-gone.why": "Adegan melampirkan tingkah laku melalui nama ini. Instans yang diletakkan kehilangan apa yang dilakukannya.",
56
56
  "figure.gate.contract.capability-added.message": "Keupayaan '{name}' adalah baharu.",
57
57
  "figure.gate.contract.capability-added.why": "Ia menambah apa yang boleh dilakukan oleh figure. Instans yang diletakkan kekal seperti sedia ada.",
58
+ "figure.gate.contract.item-gone.message": "Figura ini bukan lagi item.",
59
+ "figure.gate.contract.item-gone.why": "Jadual jenis item melukis itemnya dengan figura ini. Ia kehilangan rupanya.",
60
+ "figure.gate.contract.item-added.message": "Figura ini kini item.",
61
+ "figure.gate.contract.item-added.why": "Jadual jenis item boleh melukis itemnya dengannya. Instans yang diletakkan kekal seperti sedia ada.",
62
+ "figure.gate.item-mounting-face-missing.message": "Item ini tidak menamakan muka pemasangan.",
63
+ "figure.gate.item-mounting-face-missing.why": "Item berdiri di tempatnya pada bahagian bawah badannya. Menamakan muka ia berdiri membolehkan semakan terbitan memastikan muka itu berada di bawah.",
64
+ "figure.gate.item-mounting-face-missing.how": "Namakan muka pemasangannya, atau kekalkan jika ia berdiri pada bahagian bawah badannya.",
65
+ "figure.gate.item-size-inputs-missing.message": "Item ini tidak boleh diubah saiz oleh lukisan.",
66
+ "figure.gate.item-size-inputs-missing.why": "Tempat memberi item saiznya. Tanpa input saiz ia membesar mengikut nisbah dan memenuhi tempat pada satu arah sahaja.",
67
+ "figure.gate.item-size-inputs-missing.how": "Benarkan lukisan mengubah saiznya jika ia patut memenuhi tempatnya; kekalkan jika ia patut mengekalkan nisbahnya.",
68
+ "figure.gate.item-also-holder.message": "Item ini juga memegang barang.",
69
+ "figure.gate.item-also-holder.why": "Pemegang yang dibawa oleh pemegang lain memegang barangnya sendiri belum disokong oleh adegan.",
70
+ "figure.gate.item-also-holder.how": "Kekalkan jika ia disengajakan.",
58
71
  "figure.gate.contract.size-changed.message": "Saiz rajah telah berubah: {before} → {after}.",
59
72
  "figure.gate.contract.size-changed.why": "Papan meletakkan rajah dalam kotak bersaiz ini. Selepas berpindah ke keluaran ini, kotaknya berubah.",
60
73
  "figure.gate.contract.motion-range-changed.message": "Ruang yang dilalui rajah semasa bergerak telah berubah: {before} → {after}.",
@@ -143,6 +156,20 @@
143
156
  "figure.gate.contract.motion-group-added.why": "Instans memainkan klip lalainya sehingga papan atau data memilih yang lain.",
144
157
  "figure.gate.contract.motion-group-clip-added.message": "Kumpulan gerakan '{group}' kini mengandungi '{clip}'.",
145
158
  "figure.gate.contract.motion-group-clip-added.why": "Ia dimainkan apabila papan atau data memilihnya.",
159
+ "figure.gate.contract.status-port-gone.message": "Port status '{port}' sudah tiada.",
160
+ "figure.gate.contract.status-port-gone.why": "Templat status memberi kod port ini warna, kesan, nilai dan klip. Selepas keluaran ini ia tidak menunjukkan apa-apa pada figura ini.",
161
+ "figure.gate.contract.status-port-added.message": "Ada port status baharu '{port}'.",
162
+ "figure.gate.contract.status-port-added.why": "Kodnya ditunjukkan mengikut templat status papan apabila data memberinya.",
163
+ "figure.gate.contract.status-port-state-withdrawn.message": "Port status '{port}' tidak lagi menawarkan '{input}'.",
164
+ "figure.gate.contract.status-port-state-withdrawn.why": "Nilai yang diberi templat status untuknya tidak menggerakkan apa-apa selepas keluaran ini.",
165
+ "figure.gate.contract.status-port-state-offered.message": "Port status '{port}' kini menawarkan '{input}'.",
166
+ "figure.gate.contract.status-port-state-offered.why": "Templat status boleh memberinya nilai bagi setiap kod.",
167
+ "figure.gate.contract.status-port-state-mode-changed.message": "Cara port status '{port}' memberi '{input}' berubah daripada {before} kepada {after}.",
168
+ "figure.gate.contract.status-port-state-mode-changed.why": "Selepas keluaran ini kod yang sama mencapai nilai itu dengan cara lain.",
169
+ "figure.gate.contract.status-port-group-withdrawn.message": "Port status '{port}' tidak lagi memilih klip dalam '{group}'.",
170
+ "figure.gate.contract.status-port-group-withdrawn.why": "Klip yang diberi templat status untuknya tidak dimainkan selepas keluaran ini.",
171
+ "figure.gate.contract.status-port-group-offered.message": "Port status '{port}' kini memilih klip dalam '{group}'.",
172
+ "figure.gate.contract.status-port-group-offered.why": "Templat status boleh memilih klip kumpulan itu bagi setiap kod.",
146
173
  "figure.gate.contract.motion-group-default-changed.message": "Kumpulan gerakan '{group}' kini bermula dengan '{after}', bukan '{before}'.",
147
174
  "figure.gate.contract.motion-group-default-changed.why": "Instans tanpa pilihan sendiri memainkan klip lalai baharu selepas keluaran ini.",
148
175
  "figure.gate.contract.motion-group-transition-changed.message": "Peralihan klip dalam '{group}' kini {after} s, bukan {before} s.",
@@ -55,6 +55,19 @@
55
55
  "figure.gate.contract.capability-gone.why": "场景按此名称附加行为。已放置的实例将失去该行为。",
56
56
  "figure.gate.contract.capability-added.message": "能力 '{name}' 是新增的。",
57
57
  "figure.gate.contract.capability-added.why": "它增加了图形能做的事。已放置的实例保持原样。",
58
+ "figure.gate.contract.item-gone.message": "该 Figure 不再是物品。",
59
+ "figure.gate.contract.item-gone.why": "物品类型表用该 Figure 绘制物品,将失去其外形。",
60
+ "figure.gate.contract.item-added.message": "该 Figure 现在是物品。",
61
+ "figure.gate.contract.item-added.why": "物品类型表可以用它绘制物品。已放置的实例保持原样。",
62
+ "figure.gate.item-mounting-face-missing.message": "该物品未指定安装面。",
63
+ "figure.gate.item-mounting-face-missing.why": "物品在位置上以本体底部站立。将站立的面指定为安装面后,发布检查会确认该面位于底部。",
64
+ "figure.gate.item-mounting-face-missing.how": "请指定安装面;如果本体底部就是站立面,则保持不变。",
65
+ "figure.gate.item-size-inputs-missing.message": "该物品不能在图纸上调整尺寸。",
66
+ "figure.gate.item-size-inputs-missing.why": "物品的尺寸由所在位置给出。没有尺寸输入时它按比例放大,只在一个方向上填满位置。",
67
+ "figure.gate.item-size-inputs-missing.how": "如需填满位置,请“允许在图纸上调整尺寸”;如需保持比例,则保持不变。",
68
+ "figure.gate.item-also-holder.message": "该物品也能放置物品。",
69
+ "figure.gate.item-also-holder.why": "被另一个容器承载的容器再承载自己的物品,场景暂不支持。",
70
+ "figure.gate.item-also-holder.how": "如果是有意为之,请保持不变。",
58
71
  "figure.gate.contract.size-changed.message": "图形的尺寸已更改: {before} → {after}。",
59
72
  "figure.gate.contract.size-changed.why": "看板按此尺寸的框放置图形。迁移到此版本后框会改变。",
60
73
  "figure.gate.contract.motion-range-changed.message": "运动时扫过的空间已更改: {before} → {after}。",
@@ -143,6 +156,20 @@
143
156
  "figure.gate.contract.motion-group-added.why": "在看板或数据选择其他片段之前,播放默认片段。",
144
157
  "figure.gate.contract.motion-group-clip-added.message": "动作组 '{group}' 现在包含 '{clip}'。",
145
158
  "figure.gate.contract.motion-group-clip-added.why": "看板或数据选择时播放。",
159
+ "figure.gate.contract.status-port-gone.message": "状态端口 '{port}' 已不存在。",
160
+ "figure.gate.contract.status-port-gone.why": "状态模板按代码为此端口提供颜色、效果、数值和片段。本次发布后,此图形上不再显示任何内容。",
161
+ "figure.gate.contract.status-port-added.message": "新增状态端口 '{port}'。",
162
+ "figure.gate.contract.status-port-added.why": "数据给出代码后,按看板的状态模板显示。",
163
+ "figure.gate.contract.status-port-state-withdrawn.message": "状态端口 '{port}' 不再公开输入 '{input}'。",
164
+ "figure.gate.contract.status-port-state-withdrawn.why": "本次发布后,状态模板为此输入给出的数值不再驱动任何内容。",
165
+ "figure.gate.contract.status-port-state-offered.message": "状态端口 '{port}' 现在公开输入 '{input}'。",
166
+ "figure.gate.contract.status-port-state-offered.why": "状态模板可以按代码为此输入给出数值。",
167
+ "figure.gate.contract.status-port-state-mode-changed.message": "状态端口 '{port}' 给出 '{input}' 的方式从 {before} 变为 {after}。",
168
+ "figure.gate.contract.status-port-state-mode-changed.why": "本次发布后,同一代码到达该值的方式会改变。",
169
+ "figure.gate.contract.status-port-group-withdrawn.message": "状态端口 '{port}' 不再选择动作组 '{group}' 的片段。",
170
+ "figure.gate.contract.status-port-group-withdrawn.why": "本次发布后,状态模板为此端口给出的片段不再播放。",
171
+ "figure.gate.contract.status-port-group-offered.message": "状态端口 '{port}' 现在选择动作组 '{group}' 的片段。",
172
+ "figure.gate.contract.status-port-group-offered.why": "状态模板可以按代码选择此组的片段。",
146
173
  "figure.gate.contract.motion-group-default-changed.message": "动作组 '{group}' 的默认片段从 '{before}' 改为 '{after}'。",
147
174
  "figure.gate.contract.motion-group-default-changed.why": "没有自身选择的实例在本次发布后播放新的默认片段。",
148
175
  "figure.gate.contract.motion-group-transition-changed.message": "'{group}' 中切换片段的过渡时间从 {before} 秒改为 {after} 秒。",