@cardenelabs/cdl 0.57.1 → 0.59.0
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/CHANGELOG.md +46 -1
- package/dist/index.cjs +600 -247
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +601 -249
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +597 -247
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +598 -248
- package/dist/react.js.map +1 -1
- package/dist/{render-Cp41meYv.d.cts → render-DpwY2hzM.d.cts} +39 -1
- package/dist/{render-Cp41meYv.d.ts → render-DpwY2hzM.d.ts} +39 -1
- package/package.json +1 -1
- package/src/builder.ts +7 -0
- package/src/index.ts +6 -0
- package/src/kinds/shape-blockchain.tsx +40 -22
- package/src/kinds/shape-commerce.tsx +24 -12
- package/src/kinds/shape-finance.tsx +25 -17
- package/src/kinds/shape-software.tsx +30 -11
- package/src/lang.ts +392 -0
- package/src/layout.ts +4 -0
- package/src/render/interactive-panel.tsx +183 -111
- package/src/render/nodes.tsx +18 -14
- package/src/render/stage.tsx +2 -0
- package/src/types.ts +15 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { JSX } from "react";
|
|
2
2
|
import type { LaidNode } from "../types";
|
|
3
|
+
import { 字引きを作る, type CdlLang } from "../lang";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Shape-driven software 6 kinds (CAR-1111 Phase 2-B)。
|
|
@@ -38,6 +39,8 @@ import type { LaidNode } from "../types";
|
|
|
38
39
|
type ShapeProps = {
|
|
39
40
|
node: LaidNode;
|
|
40
41
|
active: boolean;
|
|
42
|
+
/** 描画側の固定の字の言語 (#847)。 渡さない呼び方は英語で描く */
|
|
43
|
+
lang?: CdlLang;
|
|
41
44
|
};
|
|
42
45
|
|
|
43
46
|
const commonFrame = (active: boolean) => ({
|
|
@@ -53,6 +56,19 @@ const DESCENT = 0.25;
|
|
|
53
56
|
// SVG の字幅は描く前に測れず、 getBBox も描いた後にしか使えないため送り幅で見積もる。
|
|
54
57
|
// 手元の等幅書体は 0.55-0.61 なので、 0.62 なら実寸を下回らず収めた行が実際にはみ出さない。
|
|
55
58
|
const MONO_ADVANCE = 0.62;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 等幅の書体で描く字の桁数。 和文 (U+2E80 以降) は 2 桁、それ以外は 1 桁で数える (#847)。
|
|
62
|
+
*
|
|
63
|
+
* 字数 (`length`) で数えると、日本語の辞書で描く字 (`進行中` / `→ 12 個を 1.8 秒で出力`) を
|
|
64
|
+
* 半分の幅に見積もり、縮める倍率が効かずに箱からはみ出す。 英語の辞書の字はすべて U+2E80 より
|
|
65
|
+
* 前にあり (`→` も含む)、字数と同じ値になるので、英語の図の見え方は変わらない。
|
|
66
|
+
*/
|
|
67
|
+
function 等幅の桁(s: string): number {
|
|
68
|
+
let 桁 = 0;
|
|
69
|
+
for (const c of s) 桁 += (c.codePointAt(0) ?? 0) >= 0x2e80 ? 2 : 1;
|
|
70
|
+
return 桁;
|
|
71
|
+
}
|
|
56
72
|
// 説明は名前が 16 の時に従来の 11 となり、 名前を縮めた時も同じ比で追随する。
|
|
57
73
|
const LABEL_SUB_RATIO = 11 / 16;
|
|
58
74
|
// 肩書は名前が 16 の時に従来の 12 となり、 名前を縮めた時も同じ比で追随する。
|
|
@@ -187,7 +203,8 @@ export function ShapeWindowNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
187
203
|
}
|
|
188
204
|
|
|
189
205
|
/** shape-terminal = 端末 (黒地 + macOS 風 top bar + prompt 3 行 + typing cursor) */
|
|
190
|
-
export function ShapeTerminalNode({ node, active }: ShapeProps): JSX.Element {
|
|
206
|
+
export function ShapeTerminalNode({ node, active, lang }: ShapeProps): JSX.Element {
|
|
207
|
+
const 字引 = 字引きを作る(lang);
|
|
191
208
|
const frame = commonFrame(active);
|
|
192
209
|
const 線 = frame.strokeWidth / 2;
|
|
193
210
|
const x = node.cx - node.w / 2 + 線;
|
|
@@ -209,11 +226,11 @@ export function ShapeTerminalNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
209
226
|
{ 左: 16, 字: 12.5, 色: "#7cd88f", 文: "$" },
|
|
210
227
|
{ 左: 30, 字: 12.5, 色: "#e6edf3", 文: "pnpm build" },
|
|
211
228
|
],
|
|
212
|
-
[{ 左: 16, 字: 12, 色: "#8b95a5", 文: "
|
|
229
|
+
[{ 左: 16, 字: 12, 色: "#8b95a5", 文: 字引("terminal.output") }],
|
|
213
230
|
[{ 左: 16, 字: 12.5, 色: "#7cd88f", 文: "$" }],
|
|
214
231
|
];
|
|
215
232
|
// 中身は自分の座標で描くため、 本体に入る倍率を出せるよう最長行から自然幅を求める。
|
|
216
|
-
const 自然幅 = Math.max(...行.flat().map((
|
|
233
|
+
const 自然幅 = Math.max(...行.flat().map((c) => c.左 + 等幅の桁(c.文) * MONO_ADVANCE * c.字)) + 余白;
|
|
217
234
|
// 最終行とカーソルまで入る自然高を使い、 縦にも同じ倍率を適用できるようにする。
|
|
218
235
|
const 自然高 = 帯 + 先頭 + 行間 * (行.length - 1) + Math.max(カーソル.下, 12.5 * DESCENT);
|
|
219
236
|
// 縦横を同じ倍率で縮めて比を保ち、 幅 300・高さ 200 では 1 のまま従来値を保つ。
|
|
@@ -317,7 +334,8 @@ export function ShapeTerminalNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
317
334
|
}
|
|
318
335
|
|
|
319
336
|
/** shape-code-block = code editor (tab + gutter + 4 syntax-colored stub lines) */
|
|
320
|
-
export function ShapeCodeBlockNode({ node, active }: ShapeProps): JSX.Element {
|
|
337
|
+
export function ShapeCodeBlockNode({ node, active, lang }: ShapeProps): JSX.Element {
|
|
338
|
+
const 字引 = 字引きを作る(lang);
|
|
321
339
|
const frame = commonFrame(active);
|
|
322
340
|
const 線 = frame.strokeWidth / 2;
|
|
323
341
|
const x = node.cx - node.w / 2 + 線;
|
|
@@ -410,7 +428,7 @@ export function ShapeCodeBlockNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
410
428
|
textAnchor="middle"
|
|
411
429
|
fill="#e6edf3"
|
|
412
430
|
>
|
|
413
|
-
|
|
431
|
+
{字引("codeBlock.fileName")}
|
|
414
432
|
</text>
|
|
415
433
|
<circle cx={x + tabW - 丸} cy={y + tabH / 2} r={3 * 倍} fill="#7cd88f" stroke="none" />
|
|
416
434
|
<path
|
|
@@ -483,7 +501,8 @@ export function ShapeCodeBlockNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
483
501
|
}
|
|
484
502
|
|
|
485
503
|
/** shape-kanban-card = kanban ticket (top color bar + 3 stub line) */
|
|
486
|
-
export function ShapeKanbanCardNode({ node, active }: ShapeProps): JSX.Element {
|
|
504
|
+
export function ShapeKanbanCardNode({ node, active, lang }: ShapeProps): JSX.Element {
|
|
505
|
+
const 字引 = 字引きを作る(lang);
|
|
487
506
|
const frame = commonFrame(active);
|
|
488
507
|
const 線 = frame.strokeWidth / 2;
|
|
489
508
|
// 影は札を右下へずらして重ねるため、 ずらす分と枠線を札の寸法から先に引く。
|
|
@@ -496,7 +515,7 @@ export function ShapeKanbanCardNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
496
515
|
const 左右余白 = 14;
|
|
497
516
|
const 上段隙間 = 8;
|
|
498
517
|
const 優先帯高 = 10;
|
|
499
|
-
const ID文 = "
|
|
518
|
+
const ID文 = 字引("kanbanCard.id");
|
|
500
519
|
const ID基準 = 30;
|
|
501
520
|
const ID字 = 11;
|
|
502
521
|
const ID字間 = 1;
|
|
@@ -516,7 +535,7 @@ export function ShapeKanbanCardNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
516
535
|
const 下帯 = FOOTER下 - AVATAR中心Y + AVATAR半径 + AVATAR枠 / 2 + 帯間余白;
|
|
517
536
|
const 中帯 = 名前字 * ASCENT + 名前字 * 説明基準比 + 名前字 * 説明字比 * DESCENT;
|
|
518
537
|
const 自然高 = 上帯 + 中帯 + 下帯;
|
|
519
|
-
const ID幅 = ID
|
|
538
|
+
const ID幅 = 等幅の桁(ID文) * MONO_ADVANCE * ID字 + ID字間 * [...ID文].length;
|
|
520
539
|
const 自然幅 = 左右余白 + ID幅 + 上段隙間 + PILL幅 + 左右余白;
|
|
521
540
|
// 札の中身だけを縦横同率で縮め、 入る札では 1 のまま従来の大きさを保つ。
|
|
522
541
|
const 倍 = Math.min(1, w / 自然幅, h / 自然高);
|
|
@@ -594,7 +613,7 @@ export function ShapeKanbanCardNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
594
613
|
fill="#5a4a1a"
|
|
595
614
|
fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace"
|
|
596
615
|
>
|
|
597
|
-
|
|
616
|
+
{字引("kanbanCard.status")}
|
|
598
617
|
</text>
|
|
599
618
|
{/* タスク名 = title (中央上、 大きく太字) */}
|
|
600
619
|
<text
|
|
@@ -616,7 +635,7 @@ export function ShapeKanbanCardNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
616
635
|
textAnchor="middle"
|
|
617
636
|
fill="var(--cdl-text-dim, #5a6270)"
|
|
618
637
|
>
|
|
619
|
-
|
|
638
|
+
{字引("kanbanCard.task")}
|
|
620
639
|
</text>
|
|
621
640
|
{/* footer = 2 avatars 左 + due date 右 */}
|
|
622
641
|
<g transform={`translate(${x + 左右余白 * 倍}, ${footY})`}>
|
|
@@ -668,7 +687,7 @@ export function ShapeKanbanCardNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
668
687
|
textAnchor="end"
|
|
669
688
|
fill="var(--cdl-text-dim, #5a6270)"
|
|
670
689
|
>
|
|
671
|
-
|
|
690
|
+
{字引("kanbanCard.due")}
|
|
672
691
|
</text>
|
|
673
692
|
</>
|
|
674
693
|
)}
|
package/src/lang.ts
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 描画側が書く固定の字の言語 (#847)。
|
|
3
|
+
*
|
|
4
|
+
* 書き手が何を渡しても描かれる字 (形の看板 / 絵の中の見本の値 / 行の名前) を 1 つの辞書に集め、
|
|
5
|
+
* 図の `lang` で引き替える。 書き手の字 (`title` / `subtitle` / 行 / 札) はこの辞書を通らない。
|
|
6
|
+
*
|
|
7
|
+
* **既定は英語**。 字を直接日本語へ書き換えると、英語で使う人の図まで変わり、戻す口も無い。
|
|
8
|
+
* 指定の無い図は変更前と同じ字で描く。
|
|
9
|
+
*
|
|
10
|
+
* **JSX を持たない module に置く**。 型の定義 (`types.ts`) と配置 (`layout.ts`) からも読むため、
|
|
11
|
+
* ここから React を引き込むと字の幅を測る検査の読込みが重くなる (`kinds/text-width.ts` の注記と同じ)。
|
|
12
|
+
*
|
|
13
|
+
* 言語は `CdlStage` → `CdlNodeView` → 形の部品へ引数 (`lang`) で届く。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** 図の言語。 書かない図は `"en"` で描く */
|
|
17
|
+
export type CdlLang = "en" | "ja";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 記法から届いた値を言語に直す。 型の外の値 (記法の文字列の書き損じ等) は既定の `"en"` に落とす。
|
|
21
|
+
*
|
|
22
|
+
* 落とす先を英語にするのは、指定の無い図と同じ見え方になるため。 書き損じで一部の字だけ
|
|
23
|
+
* 日本語になる形は作らない。
|
|
24
|
+
*/
|
|
25
|
+
export function resolveLang(value: unknown): CdlLang {
|
|
26
|
+
return value === "ja" ? "ja" : "en";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 英語の辞書。 鍵の一覧の出どころで、値は変更前に描いていた字そのもの。
|
|
31
|
+
*
|
|
32
|
+
* 鍵は `形.役割` の形にする。 同じ字でも役割が違えば別の鍵にする (訳が分かれうるため)。
|
|
33
|
+
*/
|
|
34
|
+
const en = {
|
|
35
|
+
/** `shape-terminal` の 2 行目 (命令の出力) */
|
|
36
|
+
"terminal.output": "→ 12 chunks in 1.8s",
|
|
37
|
+
/** `shape-code-block` の札の file 名 */
|
|
38
|
+
"codeBlock.fileName": "utils.ts",
|
|
39
|
+
/** `shape-kanban-card` の課題の番号 */
|
|
40
|
+
"kanbanCard.id": "CAR-1111",
|
|
41
|
+
/** `shape-kanban-card` の状態の札 */
|
|
42
|
+
"kanbanCard.status": "IN PROG",
|
|
43
|
+
/** `shape-kanban-card` の題の下の説明 */
|
|
44
|
+
"kanbanCard.task": "shape-driven kind 実装",
|
|
45
|
+
/** `shape-kanban-card` の期日 */
|
|
46
|
+
"kanbanCard.due": "Jul 10",
|
|
47
|
+
/** `shape-smart-contract` の契約の本文の 1 行 */
|
|
48
|
+
"smartContract.call": "function execute()",
|
|
49
|
+
/** `shape-blockchain-block` の題を渡さない時の見出し */
|
|
50
|
+
"blockchainBlock.title": "Block #421,873",
|
|
51
|
+
/** `shape-blockchain-block` の 1 行目の名前 (塊を識別する値) */
|
|
52
|
+
"blockchainBlock.hash": "hash",
|
|
53
|
+
/** `shape-blockchain-block` の 2 行目の名前 (1 つ前の塊の識別値) */
|
|
54
|
+
"blockchainBlock.prev": "prev",
|
|
55
|
+
/** `shape-blockchain-block` の 3 行目の名前 (取引をまとめた木の根) */
|
|
56
|
+
"blockchainBlock.merkle": "merkle",
|
|
57
|
+
/** `shape-blockchain-block` の 4 行目の名前 (採掘で試した値) */
|
|
58
|
+
"blockchainBlock.nonce": "nonce",
|
|
59
|
+
/** `shape-blockchain-block` の 5 行目の名前 (取引の件数) */
|
|
60
|
+
"blockchainBlock.tx": "tx",
|
|
61
|
+
/** `shape-blockchain-block` の 5 行目の値 */
|
|
62
|
+
"blockchainBlock.txCount": "142 tx",
|
|
63
|
+
/** `shape-rpc-node` の稼働の札 */
|
|
64
|
+
"rpcNode.status": "RPC ONLINE",
|
|
65
|
+
/** `shape-trust-bank` の看板 */
|
|
66
|
+
"trustBank.sign": "TRUST",
|
|
67
|
+
/** `shape-payment-provider` の看板 */
|
|
68
|
+
"paymentProvider.sign": "PAY",
|
|
69
|
+
/** `shape-payment-provider` の状態の札 */
|
|
70
|
+
"paymentProvider.status": "PROCESSING",
|
|
71
|
+
/** `shape-brokerage` の株価の帯 */
|
|
72
|
+
"brokerage.ticker": "▲NKY 38,240 ▲AAPL 194",
|
|
73
|
+
/** `shape-brokerage` の看板 */
|
|
74
|
+
"brokerage.sign": "$ SECURITIES",
|
|
75
|
+
/** `shape-exchange` の看板 */
|
|
76
|
+
"exchange.sign": "EXCHANGE",
|
|
77
|
+
/** `shape-exchange` の看板の下の札 */
|
|
78
|
+
"exchange.sub": "clearing",
|
|
79
|
+
/** `shape-atm` の天井の看板 */
|
|
80
|
+
"atm.sign": "ATM CORNER",
|
|
81
|
+
/** `shape-atm` の画面の案内 */
|
|
82
|
+
"atm.screen": "SELECT AMOUNT",
|
|
83
|
+
/** `shape-atm` の決める鍵 */
|
|
84
|
+
"atm.ok": "OK",
|
|
85
|
+
/** `shape-atm` のカードを入れる口の札 */
|
|
86
|
+
"atm.cardSlot": "CARD SLOT",
|
|
87
|
+
/** `shape-storefront` の看板 */
|
|
88
|
+
"storefront.sign": "SHOP",
|
|
89
|
+
/** `shape-storefront` の扉の札 */
|
|
90
|
+
"storefront.open": "OPEN",
|
|
91
|
+
/** `shape-warehouse` の看板 */
|
|
92
|
+
"warehouse.sign": "WAREHOUSE",
|
|
93
|
+
/** `shape-api-gateway` の看板 */
|
|
94
|
+
"apiGateway.sign": "API GATEWAY",
|
|
95
|
+
/** `shape-api-gateway` の 3 行目の要求の種類 */
|
|
96
|
+
"apiGateway.delete": "DEL",
|
|
97
|
+
/** `shape-api-gateway` の 1 行目の宛先 */
|
|
98
|
+
"apiGateway.users": "/users",
|
|
99
|
+
/** `shape-api-gateway` の 2 行目の宛先 */
|
|
100
|
+
"apiGateway.orders": "/orders",
|
|
101
|
+
/** `shape-api-gateway` の 3 行目の宛先 */
|
|
102
|
+
"apiGateway.session": "/session",
|
|
103
|
+
|
|
104
|
+
// 読み出し (`readout.*`) と入力欄の固定の字 (#849)。
|
|
105
|
+
// `{名前}` は描く時に値を差し込む位置 (`字を差し込む`)。 語順が言語で変わるので、位置ごと辞書に持つ
|
|
106
|
+
|
|
107
|
+
/** 配列を描く読み出しで、値が空の時の字 */
|
|
108
|
+
"readout.empty": "empty",
|
|
109
|
+
/** `sparkline` で点がまだ無い時の字 */
|
|
110
|
+
"readout.sparkline.waiting": "waiting",
|
|
111
|
+
/** 時の流れの入力欄の速さ */
|
|
112
|
+
"input.timeline.speed": "{speed}x",
|
|
113
|
+
/** 時の流れの入力欄の経過と長さ (秒) */
|
|
114
|
+
"input.timeline.time": "{t}s / {d}s",
|
|
115
|
+
/** `sequence-timeline` の点の見出し */
|
|
116
|
+
"readout.sequenceTimeline.title": "{name}: t={t}",
|
|
117
|
+
/** `bubble-chart` の泡の見出し */
|
|
118
|
+
"readout.bubbleChart.title": "({x}, {y}) r={r}",
|
|
119
|
+
/** `calendar-heatmap` の升目の見出し (`i` は 0 から) */
|
|
120
|
+
"readout.calendarHeatmap.title": "day {i}: {v}",
|
|
121
|
+
/** `candlestick` の足の見出し (始値 / 高値 / 安値 / 終値) */
|
|
122
|
+
"readout.candlestick.title": "O:{o} H:{h} L:{l} C:{c}",
|
|
123
|
+
/** `slope` の左の目盛 */
|
|
124
|
+
"readout.slope.before": "before",
|
|
125
|
+
/** `slope` の右の目盛 */
|
|
126
|
+
"readout.slope.after": "after",
|
|
127
|
+
/** `bullet-chart` の実績の見出し */
|
|
128
|
+
"readout.bulletChart.actual": "actual: {v}",
|
|
129
|
+
/** `bullet-chart` の目標の見出し */
|
|
130
|
+
"readout.bulletChart.target": "target: {v}",
|
|
131
|
+
/** `rating` の塗った星の見出し */
|
|
132
|
+
"readout.rating.full": "full",
|
|
133
|
+
/** `rating` の半分塗った星の見出し */
|
|
134
|
+
"readout.rating.half": "half",
|
|
135
|
+
/** `rating` の塗っていない星の見出し */
|
|
136
|
+
"readout.rating.empty": "empty",
|
|
137
|
+
/** `price-tag` の割引額 */
|
|
138
|
+
"readout.priceTag.save": "You save {amount}",
|
|
139
|
+
/** `confidence-meter` の低い帯の名前 */
|
|
140
|
+
"readout.confidence.low": "low",
|
|
141
|
+
/** `confidence-meter` の中ほどの帯の名前 */
|
|
142
|
+
"readout.confidence.mid": "mid",
|
|
143
|
+
/** `confidence-meter` の高い帯の名前 */
|
|
144
|
+
"readout.confidence.high": "high",
|
|
145
|
+
/** 並べきれなかった件数 (`user-stack` / `kanban-board` / `user-presence`) */
|
|
146
|
+
"readout.more": "+{n} more",
|
|
147
|
+
/** `video-card` の再生数 */
|
|
148
|
+
"readout.videoCard.views": "{v} views",
|
|
149
|
+
/** `attendance-grid` の角の見出し */
|
|
150
|
+
"readout.attendance.corner": "day",
|
|
151
|
+
/** `calendar-month` の曜日 (日曜) */
|
|
152
|
+
"readout.weekday.0": "Sun",
|
|
153
|
+
/** `calendar-month` の曜日 (月曜) */
|
|
154
|
+
"readout.weekday.1": "Mon",
|
|
155
|
+
/** `calendar-month` の曜日 (火曜) */
|
|
156
|
+
"readout.weekday.2": "Tue",
|
|
157
|
+
/** `calendar-month` の曜日 (水曜) */
|
|
158
|
+
"readout.weekday.3": "Wed",
|
|
159
|
+
/** `calendar-month` の曜日 (木曜) */
|
|
160
|
+
"readout.weekday.4": "Thu",
|
|
161
|
+
/** `calendar-month` の曜日 (金曜) */
|
|
162
|
+
"readout.weekday.5": "Fri",
|
|
163
|
+
/** `calendar-month` の曜日 (土曜) */
|
|
164
|
+
"readout.weekday.6": "Sat",
|
|
165
|
+
/** `rating-thumb` の賛成の割合と票数 */
|
|
166
|
+
"readout.ratingThumb.summary": "{pct}% up · {total} votes",
|
|
167
|
+
/** `kpi-trend-tile` の前の期間の値 */
|
|
168
|
+
"readout.kpiTrend.prev": "prev {v}",
|
|
169
|
+
/** `quick-poll-emoji` の票の合計 */
|
|
170
|
+
"readout.poll.total": "total {n}",
|
|
171
|
+
/** `thread-summary` の参加者の数 */
|
|
172
|
+
"readout.thread.participants": "{n} participants",
|
|
173
|
+
/** `thread-summary` の最後に書いた人 */
|
|
174
|
+
"readout.thread.last": "last: {name}",
|
|
175
|
+
/** `read-receipt` の送信した段 */
|
|
176
|
+
"readout.readReceipt.sent": "sent",
|
|
177
|
+
/** `read-receipt` の相手に届いた段 */
|
|
178
|
+
"readout.readReceipt.delivered": "delivered",
|
|
179
|
+
/** `read-receipt` の読まれた段 */
|
|
180
|
+
"readout.readReceipt.read": "read",
|
|
181
|
+
/** `password-strength` の段階 0 */
|
|
182
|
+
"readout.password.0": "too weak",
|
|
183
|
+
/** `password-strength` の段階 1 */
|
|
184
|
+
"readout.password.1": "weak",
|
|
185
|
+
/** `password-strength` の段階 2 */
|
|
186
|
+
"readout.password.2": "fair",
|
|
187
|
+
/** `password-strength` の段階 3 */
|
|
188
|
+
"readout.password.3": "good",
|
|
189
|
+
/** `password-strength` の段階 4 */
|
|
190
|
+
"readout.password.4": "strong",
|
|
191
|
+
/** `file-dropzone` で取り込んだ後の字 */
|
|
192
|
+
"readout.dropzone.uploaded": "uploaded",
|
|
193
|
+
/** `file-dropzone` の空の時の 1 行目 */
|
|
194
|
+
"readout.dropzone.drop": "⬆ Drop file here",
|
|
195
|
+
/** `file-dropzone` の空の時の 2 行目 */
|
|
196
|
+
"readout.dropzone.browse": "or click to browse",
|
|
197
|
+
/** `log-stream` の重さ 0 (調べるための詳細) */
|
|
198
|
+
"readout.log.0": "DBG",
|
|
199
|
+
/** `log-stream` の重さ 1 (知らせ) */
|
|
200
|
+
"readout.log.1": "INF",
|
|
201
|
+
/** `log-stream` の重さ 2 (警告) */
|
|
202
|
+
"readout.log.2": "WRN",
|
|
203
|
+
/** `log-stream` の重さ 3 (異常) */
|
|
204
|
+
"readout.log.3": "ERR",
|
|
205
|
+
/** `cart-summary` の点数 */
|
|
206
|
+
"readout.cart.items": "Items",
|
|
207
|
+
/** `cart-summary` の小計 */
|
|
208
|
+
"readout.cart.subtotal": "Subtotal",
|
|
209
|
+
/** `cart-summary` の送料 */
|
|
210
|
+
"readout.cart.shipping": "Shipping",
|
|
211
|
+
/** `cart-summary` の合計 */
|
|
212
|
+
"readout.cart.total": "Total",
|
|
213
|
+
/** `pricing-tier` で名前が空の時の名前 */
|
|
214
|
+
"readout.pricing.plan": "Plan",
|
|
215
|
+
/** `pricing-tier` の価格の後ろ */
|
|
216
|
+
"readout.pricing.perMonth": "per month",
|
|
217
|
+
/** `pricing-tier` の押す札 */
|
|
218
|
+
"readout.pricing.get": "Get {name}",
|
|
219
|
+
/** `coupon-code` で番号が空の時の字 */
|
|
220
|
+
"readout.coupon.placeholder": "ENTER CODE",
|
|
221
|
+
/** `coupon-code` の割引の割合 */
|
|
222
|
+
"readout.coupon.off": "-{pct}% off",
|
|
223
|
+
/** `coupon-code` の押す札 */
|
|
224
|
+
"readout.coupon.apply": "Apply",
|
|
225
|
+
/** `article-preview` の書いた人 */
|
|
226
|
+
"readout.article.by": "by {author}",
|
|
227
|
+
/** `priority-badge` の高い優先度の表示 (値は `high` / `2` で読む) */
|
|
228
|
+
"readout.priority.high": "HIGH",
|
|
229
|
+
/** `priority-badge` の中ほどの優先度の表示 */
|
|
230
|
+
"readout.priority.med": "MED",
|
|
231
|
+
/** `priority-badge` の低い優先度の表示 (値は `low` / `0` で読む) */
|
|
232
|
+
"readout.priority.low": "LOW",
|
|
233
|
+
/** `kanban-board` の列の見出し (値は `todo` で読む) */
|
|
234
|
+
"readout.kanban.todo": "Todo",
|
|
235
|
+
/** `kanban-board` の列の見出し (値は `inprogress` で読む) */
|
|
236
|
+
"readout.kanban.inprogress": "In Progress",
|
|
237
|
+
/** `kanban-board` の列の見出し (値は `done` で読む) */
|
|
238
|
+
"readout.kanban.done": "Done",
|
|
239
|
+
/** `traffic-light` の赤の灯の見出し (値は `red` で読む) */
|
|
240
|
+
"readout.trafficLight.red": "red",
|
|
241
|
+
/** `traffic-light` の黄の灯の見出し (値は `yellow` / `amber` で読む) */
|
|
242
|
+
"readout.trafficLight.yellow": "yellow",
|
|
243
|
+
/** `traffic-light` の緑の灯の見出し (値は `green` で読む) */
|
|
244
|
+
"readout.trafficLight.green": "green",
|
|
245
|
+
} as const;
|
|
246
|
+
|
|
247
|
+
/** 辞書の鍵 */
|
|
248
|
+
export type CdlTextKey = keyof typeof en;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 日本語の辞書。 型を `en` の鍵と同じにし、訳の抜けと余分な鍵を型で落とす。
|
|
252
|
+
*
|
|
253
|
+
* 製品名と定着した略語 (`API` / `ATM` / `RPC`) と、要求の種類の綴り (`DELETE`) は英字のまま残す。
|
|
254
|
+
* 日本語の文でもこの綴りで書くため。
|
|
255
|
+
*/
|
|
256
|
+
const ja: Record<CdlTextKey, string> = {
|
|
257
|
+
"terminal.output": "→ 1.8 秒で完了",
|
|
258
|
+
"codeBlock.fileName": "共通.ts",
|
|
259
|
+
"kanbanCard.id": "#1111",
|
|
260
|
+
"kanbanCard.status": "進行中",
|
|
261
|
+
"kanbanCard.task": "形を実装",
|
|
262
|
+
"kanbanCard.due": "7/10",
|
|
263
|
+
"smartContract.call": "自動で実行する",
|
|
264
|
+
"blockchainBlock.title": "ブロック #421,873",
|
|
265
|
+
"blockchainBlock.hash": "ハッシュ",
|
|
266
|
+
"blockchainBlock.prev": "直前",
|
|
267
|
+
"blockchainBlock.merkle": "木の根",
|
|
268
|
+
"blockchainBlock.nonce": "ノンス",
|
|
269
|
+
"blockchainBlock.tx": "取引",
|
|
270
|
+
"blockchainBlock.txCount": "142 件",
|
|
271
|
+
"rpcNode.status": "RPC 稼働中",
|
|
272
|
+
"trustBank.sign": "信託",
|
|
273
|
+
"paymentProvider.sign": "決済",
|
|
274
|
+
"paymentProvider.status": "処理中",
|
|
275
|
+
"brokerage.ticker": "▲日経 38,240 ▲東証 2,710",
|
|
276
|
+
"brokerage.sign": "¥ 証券",
|
|
277
|
+
"exchange.sign": "取引所",
|
|
278
|
+
"exchange.sub": "清算",
|
|
279
|
+
"atm.sign": "ATM コーナー",
|
|
280
|
+
"atm.screen": "金額を選択",
|
|
281
|
+
"atm.ok": "確定",
|
|
282
|
+
"atm.cardSlot": "カード挿入口",
|
|
283
|
+
"storefront.sign": "商店",
|
|
284
|
+
"storefront.open": "営業",
|
|
285
|
+
"warehouse.sign": "倉庫",
|
|
286
|
+
"apiGateway.sign": "API 入口",
|
|
287
|
+
"apiGateway.delete": "DELETE",
|
|
288
|
+
"apiGateway.users": "/利用者",
|
|
289
|
+
"apiGateway.orders": "/注文",
|
|
290
|
+
"apiGateway.session": "/接続",
|
|
291
|
+
|
|
292
|
+
"readout.empty": "なし",
|
|
293
|
+
"readout.sparkline.waiting": "待機中",
|
|
294
|
+
"input.timeline.speed": "{speed}倍",
|
|
295
|
+
"input.timeline.time": "{t}秒 / {d}秒",
|
|
296
|
+
"readout.sequenceTimeline.title": "{name}: 時刻 {t}",
|
|
297
|
+
"readout.bubbleChart.title": "({x}, {y}) 半径 {r}",
|
|
298
|
+
"readout.calendarHeatmap.title": "{i} 日目: {v}",
|
|
299
|
+
"readout.candlestick.title": "始 {o} 高 {h} 安 {l} 終 {c}",
|
|
300
|
+
"readout.slope.before": "前",
|
|
301
|
+
"readout.slope.after": "後",
|
|
302
|
+
"readout.bulletChart.actual": "実績: {v}",
|
|
303
|
+
"readout.bulletChart.target": "目標: {v}",
|
|
304
|
+
"readout.rating.full": "満",
|
|
305
|
+
"readout.rating.half": "半分",
|
|
306
|
+
"readout.rating.empty": "空",
|
|
307
|
+
"readout.priceTag.save": "{amount} お得",
|
|
308
|
+
"readout.confidence.low": "低",
|
|
309
|
+
"readout.confidence.mid": "中",
|
|
310
|
+
"readout.confidence.high": "高",
|
|
311
|
+
"readout.more": "ほか {n}",
|
|
312
|
+
"readout.videoCard.views": "{v} 回視聴",
|
|
313
|
+
"readout.attendance.corner": "日",
|
|
314
|
+
"readout.weekday.0": "日",
|
|
315
|
+
"readout.weekday.1": "月",
|
|
316
|
+
"readout.weekday.2": "火",
|
|
317
|
+
"readout.weekday.3": "水",
|
|
318
|
+
"readout.weekday.4": "木",
|
|
319
|
+
"readout.weekday.5": "金",
|
|
320
|
+
"readout.weekday.6": "土",
|
|
321
|
+
"readout.ratingThumb.summary": "賛成 {pct}% · {total} 票",
|
|
322
|
+
"readout.kpiTrend.prev": "前回 {v}",
|
|
323
|
+
"readout.poll.total": "合計 {n}",
|
|
324
|
+
"readout.thread.participants": "{n} 人",
|
|
325
|
+
"readout.thread.last": "最後: {name}",
|
|
326
|
+
"readout.readReceipt.sent": "送信済み",
|
|
327
|
+
"readout.readReceipt.delivered": "配信済み",
|
|
328
|
+
"readout.readReceipt.read": "既読",
|
|
329
|
+
"readout.password.0": "弱すぎる",
|
|
330
|
+
"readout.password.1": "弱い",
|
|
331
|
+
"readout.password.2": "普通",
|
|
332
|
+
"readout.password.3": "良い",
|
|
333
|
+
"readout.password.4": "強い",
|
|
334
|
+
"readout.dropzone.uploaded": "取り込み済み",
|
|
335
|
+
"readout.dropzone.drop": "⬆ ここにファイルを置く",
|
|
336
|
+
"readout.dropzone.browse": "または押して選ぶ",
|
|
337
|
+
"readout.log.0": "詳細",
|
|
338
|
+
"readout.log.1": "情報",
|
|
339
|
+
"readout.log.2": "警告",
|
|
340
|
+
"readout.log.3": "異常",
|
|
341
|
+
"readout.cart.items": "点数",
|
|
342
|
+
"readout.cart.subtotal": "小計",
|
|
343
|
+
"readout.cart.shipping": "送料",
|
|
344
|
+
"readout.cart.total": "合計",
|
|
345
|
+
"readout.pricing.plan": "プラン",
|
|
346
|
+
"readout.pricing.perMonth": "月額",
|
|
347
|
+
"readout.pricing.get": "{name}を選ぶ",
|
|
348
|
+
"readout.coupon.placeholder": "コードを入力",
|
|
349
|
+
"readout.coupon.off": "-{pct}% 引き",
|
|
350
|
+
"readout.coupon.apply": "適用",
|
|
351
|
+
"readout.article.by": "文: {author}",
|
|
352
|
+
"readout.priority.high": "高",
|
|
353
|
+
"readout.priority.med": "中",
|
|
354
|
+
"readout.priority.low": "低",
|
|
355
|
+
"readout.kanban.todo": "未着手",
|
|
356
|
+
"readout.kanban.inprogress": "進行中",
|
|
357
|
+
"readout.kanban.done": "完了",
|
|
358
|
+
"readout.trafficLight.red": "赤",
|
|
359
|
+
"readout.trafficLight.yellow": "黄",
|
|
360
|
+
"readout.trafficLight.green": "緑",
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/** 言語ごとの辞書。 検査が鍵の一致を実行時にも確かめるため公開する */
|
|
364
|
+
export const CDL_TEXT: Readonly<Record<CdlLang, Readonly<Record<CdlTextKey, string>>>> = { en, ja };
|
|
365
|
+
|
|
366
|
+
/** 言語と鍵から描く字を引く */
|
|
367
|
+
export function cdlText(lang: CdlLang, key: CdlTextKey): string {
|
|
368
|
+
return CDL_TEXT[lang][key];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* 部品が受け取った言語で辞書を引く関数を返す。 言語を渡さない呼び方は英語で引く。
|
|
373
|
+
*
|
|
374
|
+
* **部品へは引数で渡す** (React の文脈で届けない)。 形の部品は検査から関数として直接呼ばれており
|
|
375
|
+
* (`描く({ node, active })`)、文脈を読む hook はその呼び方で使えない。
|
|
376
|
+
*/
|
|
377
|
+
export function 字引きを作る(lang: CdlLang | undefined): (key: CdlTextKey) => string {
|
|
378
|
+
const 言語 = lang ?? "en";
|
|
379
|
+
return (key) => CDL_TEXT[言語][key];
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* 辞書の字の `{名前}` に値を差し込む (#849)。
|
|
384
|
+
*
|
|
385
|
+
* **差し込む位置を辞書に持たせる**。 `+3 more` と `ほか 3` のように、値の前後に来る語が言語で
|
|
386
|
+
* 変わるため、字を前後に分けて持つと語順を表せない。
|
|
387
|
+
*
|
|
388
|
+
* 渡されなかった名前は `{名前}` のまま残す (黙って空にすると、差し込み忘れが画面で見えなくなる)。
|
|
389
|
+
*/
|
|
390
|
+
export function 字を差し込む(template: string, values: Readonly<Record<string, string | number>>): string {
|
|
391
|
+
return template.replace(/\{(\w+)\}/g, (whole, name: string) => (name in values ? String(values[name]) : whole));
|
|
392
|
+
}
|
package/src/layout.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CdlDiagram, LaidDiagram } from "./types";
|
|
2
|
+
import { resolveLang } from "./lang";
|
|
2
3
|
import {
|
|
3
4
|
CLEARANCE_LABEL_LABEL,
|
|
4
5
|
CLEARANCE_NODE_LABEL,
|
|
@@ -422,6 +423,9 @@ export function layout(diag: CdlDiagram): LaidDiagram {
|
|
|
422
423
|
// **遮断はここだけに置く**。 描画は必ず組み立てを通り、組み立て API も `er` も
|
|
423
424
|
// 素通しにしてある。 上流にも置くと、どの入力でも通らない分岐が残る
|
|
424
425
|
...(diag.palette ? { palette: diag.palette } : {}),
|
|
426
|
+
// 描画側の固定の字の言語 (#847)。 既定 (`en`) と型の外の値は持たせない = 配置の結果の形を
|
|
427
|
+
// 変更前と揃え、記法の書き損じで一部の字だけ日本語になる形を作らない
|
|
428
|
+
...(resolveLang(diag.lang) === "ja" ? { lang: "ja" as const } : {}),
|
|
425
429
|
// 種類も配色と同じく空の目印を出さない。 遮断をここに揃えると手書きの図にも効く
|
|
426
430
|
...(diag.type ? { type: diag.type } : {}),
|
|
427
431
|
bboxes,
|