@things-factory/shell 10.1.205 → 10.1.208
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/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +1 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/reversibility/reversibility.d.ts +1 -1
- package/dist-server/reversibility/reversibility.js +1 -1
- package/dist-server/reversibility/reversibility.js.map +1 -1
- package/dist-server/row-ties/index.d.ts +1 -0
- package/dist-server/row-ties/index.js +5 -0
- package/dist-server/row-ties/index.js.map +1 -0
- package/dist-server/row-ties/row-ties.d.ts +32 -0
- package/dist-server/row-ties/row-ties.js +66 -0
- package/dist-server/row-ties/row-ties.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/utils/condition-builder.js +7 -19
- package/dist-server/utils/condition-builder.js.map +1 -1
- package/dist-server/utils/get-query-builder-from-list-params.js +4 -14
- package/dist-server/utils/get-query-builder-from-list-params.js.map +1 -1
- package/dist-server/utils/membership-clause.d.ts +19 -0
- package/dist-server/utils/membership-clause.js +30 -0
- package/dist-server/utils/membership-clause.js.map +1 -0
- package/package.json +2 -2
- package/tests/empty-membership.test.ts +117 -0
- package/tests/row-ties.test.ts +144 -0
- package/translations/en.json +12 -0
- package/translations/es.json +12 -0
- package/translations/ja.json +12 -0
- package/translations/ko.json +12 -0
- package/translations/ms.json +12 -0
- package/translations/zh.json +12 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import 'reflect-metadata'
|
|
2
|
+
import { Column, DataSource, DeleteDateColumn, Entity, ManyToOne, OneToOne, JoinColumn, PrimaryGeneratedColumn } from 'typeorm'
|
|
3
|
+
import { HistoryOriginalIdColumn } from '@operato/typeorm-history'
|
|
4
|
+
|
|
5
|
+
import { refuseTiedRows, registerKindTie } from '../server/row-ties/row-ties.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A ledger row is not deleted while another row is tied to it (2026-10-23).
|
|
9
|
+
*
|
|
10
|
+
* What this splits: a live row naming it by a key (many-to-one and owning one-to-one) or by kind and id against the
|
|
11
|
+
* rows that are not ties - a version a history table keeps, a row deleted together with it, a row already deleted.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
@Entity()
|
|
15
|
+
class Loan {
|
|
16
|
+
@PrimaryGeneratedColumn('uuid')
|
|
17
|
+
id!: string
|
|
18
|
+
|
|
19
|
+
/* A loan refinanced from another names it. */
|
|
20
|
+
@ManyToOne(() => Loan, { nullable: true })
|
|
21
|
+
refinancedFrom?: Loan
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Entity()
|
|
25
|
+
class Repayment {
|
|
26
|
+
@PrimaryGeneratedColumn('uuid')
|
|
27
|
+
id!: string
|
|
28
|
+
|
|
29
|
+
@ManyToOne(() => Loan, { nullable: true })
|
|
30
|
+
loan?: Loan
|
|
31
|
+
|
|
32
|
+
@DeleteDateColumn()
|
|
33
|
+
deletedAt?: Date
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Entity()
|
|
37
|
+
class Collateral {
|
|
38
|
+
@PrimaryGeneratedColumn('uuid')
|
|
39
|
+
id!: string
|
|
40
|
+
|
|
41
|
+
@OneToOne(() => Loan, { nullable: true })
|
|
42
|
+
@JoinColumn()
|
|
43
|
+
loan?: Loan
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Entity()
|
|
47
|
+
class RepaymentHistory {
|
|
48
|
+
@PrimaryGeneratedColumn('uuid')
|
|
49
|
+
id!: string
|
|
50
|
+
|
|
51
|
+
@HistoryOriginalIdColumn({ type: 'text' })
|
|
52
|
+
originalId!: string
|
|
53
|
+
|
|
54
|
+
@ManyToOne(() => Loan, { nullable: true })
|
|
55
|
+
loan?: Loan
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Entity()
|
|
59
|
+
class Settlement {
|
|
60
|
+
@PrimaryGeneratedColumn('uuid')
|
|
61
|
+
id!: string
|
|
62
|
+
|
|
63
|
+
@Column({ type: 'text' })
|
|
64
|
+
targetType!: string
|
|
65
|
+
|
|
66
|
+
@Column({ type: 'text' })
|
|
67
|
+
targetId!: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
registerKindTie(Settlement, { kind: 'targetType', id: 'targetId' })
|
|
71
|
+
|
|
72
|
+
let db: DataSource
|
|
73
|
+
|
|
74
|
+
beforeAll(async () => {
|
|
75
|
+
db = await new DataSource({
|
|
76
|
+
type: 'sqlite',
|
|
77
|
+
database: ':memory:',
|
|
78
|
+
synchronize: true,
|
|
79
|
+
entities: [Loan, Repayment, Collateral, RepaymentHistory, Settlement]
|
|
80
|
+
}).initialize()
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
afterAll(async () => {
|
|
84
|
+
await db?.destroy()
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const loan = (over: Partial<Loan> = {}) => db.getRepository(Loan).save({ ...over })
|
|
88
|
+
const refusal = async (call: Promise<unknown>) => {
|
|
89
|
+
try {
|
|
90
|
+
await call
|
|
91
|
+
} catch (e: any) {
|
|
92
|
+
return { code: e.code, ...e.params }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
describe('refuseTiedRows', () => {
|
|
97
|
+
it('refuses a row a live row names by a key, and says what and how many', async () => {
|
|
98
|
+
const one = await loan()
|
|
99
|
+
await db.getRepository(Repayment).save([{ loan: one }, { loan: one }])
|
|
100
|
+
expect(await refusal(refuseTiedRows(db.manager, Loan, [one.id]))).toEqual({ code: 'row-tied', kind: 'Repayment', count: 2 })
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('refuses a row an owning one-to-one names', async () => {
|
|
104
|
+
const one = await loan()
|
|
105
|
+
await db.getRepository(Collateral).save({ loan: one })
|
|
106
|
+
expect(await refusal(refuseTiedRows(db.manager, Loan, [one.id]))).toEqual({ code: 'row-tied', kind: 'Collateral', count: 1 })
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('refuses a row a declared ledger names by kind and id', async () => {
|
|
110
|
+
const one = await loan()
|
|
111
|
+
await db.getRepository(Settlement).save({ targetType: 'Loan', targetId: one.id })
|
|
112
|
+
expect(await refusal(refuseTiedRows(db.manager, Loan, [one.id]))).toEqual({ code: 'row-tied', kind: 'Settlement', count: 1 })
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('a kind tie counts only its own kind', async () => {
|
|
116
|
+
const one = await loan()
|
|
117
|
+
await db.getRepository(Settlement).save({ targetType: 'Repayment', targetId: one.id })
|
|
118
|
+
await expect(refuseTiedRows(db.manager, Loan, [one.id])).resolves.toBeUndefined()
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('does not count a version a history table keeps', async () => {
|
|
122
|
+
const one = await loan()
|
|
123
|
+
await db.getRepository(RepaymentHistory).save({ originalId: one.id, loan: one })
|
|
124
|
+
await expect(refuseTiedRows(db.manager, Loan, [one.id])).resolves.toBeUndefined()
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('does not count a row already deleted', async () => {
|
|
128
|
+
const one = await loan()
|
|
129
|
+
const repayment = await db.getRepository(Repayment).save({ loan: one })
|
|
130
|
+
await db.getRepository(Repayment).softDelete(repayment.id)
|
|
131
|
+
await expect(refuseTiedRows(db.manager, Loan, [one.id])).resolves.toBeUndefined()
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('does not count a row of the same delete, but does one left behind', async () => {
|
|
135
|
+
const old = await loan()
|
|
136
|
+
const next = await loan({ refinancedFrom: old })
|
|
137
|
+
await expect(refuseTiedRows(db.manager, Loan, [old.id, next.id])).resolves.toBeUndefined()
|
|
138
|
+
expect(await refusal(refuseTiedRows(db.manager, Loan, [old.id]))).toEqual({ code: 'row-tied', kind: 'Loan', count: 1 })
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('a kind tie is declared once', () => {
|
|
142
|
+
expect(() => registerKindTie(Settlement, { kind: 'targetType', id: 'targetId' })).toThrow(/twice/)
|
|
143
|
+
})
|
|
144
|
+
})
|
package/translations/en.json
CHANGED
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"text.draft": "draft",
|
|
134
134
|
"text.entity360-not-yet": "there is no 360 for this kind yet.",
|
|
135
135
|
"text.entity360-none": "none",
|
|
136
|
+
"text.shown-of-total": "showing {shown} of {total}",
|
|
136
137
|
"text.entity360-forbidden": "you may not see this",
|
|
137
138
|
"text.entity360-failed": "could not be read",
|
|
138
139
|
"text.error": "error",
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
"label.import": "import",
|
|
173
174
|
"error.address-not-allowed": "this site does not accept connections from where you are. ask its administrator.",
|
|
174
175
|
"error.database-failed": "The server could not process this. Tell your administrator.",
|
|
176
|
+
"error.row-tied": "{count} $t(label.row-tie-{kind}, {\"defaultValue\": \"{kind}\"}) record(s) are tied to this row, so it cannot be deleted. Unlink or delete them first.",
|
|
175
177
|
"button.undo": "undo",
|
|
176
178
|
"button.redo": "redo",
|
|
177
179
|
"button.fit-view": "fit to view",
|
|
@@ -180,10 +182,20 @@
|
|
|
180
182
|
"button.hide-end-pane": "hide the right pane",
|
|
181
183
|
"button.show-end-pane": "show the right pane",
|
|
182
184
|
"title.unsaved-draft": "there is an unsaved edit",
|
|
185
|
+
"title.id-lens": "find by number",
|
|
183
186
|
"text.unsaved-draft-kept": "what you changed {minutes} minutes ago is still kept in this browser.",
|
|
184
187
|
"text.unsaved-draft-behind": "it has been saved again since then. saving will tell you about the conflict.",
|
|
188
|
+
"text.id-lens-searching": "searching",
|
|
189
|
+
"text.id-lens-choose": "{count} matches for {value} - choose one",
|
|
190
|
+
"text.id-lens-forbidden": "Not searched - you may not view: {kinds}",
|
|
191
|
+
"text.id-lens-failed": "Could not read {kind}",
|
|
192
|
+
"text.id-lens-none": "Nothing is numbered {value}.",
|
|
185
193
|
"button.resume-editing": "resume editing",
|
|
186
194
|
"button.discard": "discard",
|
|
195
|
+
"button.find": "find",
|
|
196
|
+
"button.scan": "scan",
|
|
197
|
+
"button.retry": "retry",
|
|
198
|
+
"button.scan-with-camera": "scan with camera",
|
|
187
199
|
"figure.label.motion": "Motion",
|
|
188
200
|
"figure.text.preview-needs-a-part": "add a part to see how it looks placed on a drawing.",
|
|
189
201
|
"error.timezone-required": "The $t(term.domain) has no timezone. Set it in $t(term.domain) management."
|
package/translations/es.json
CHANGED
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"text.draft": "borrador",
|
|
134
134
|
"text.entity360-not-yet": "todavía no hay vista 360 para este tipo.",
|
|
135
135
|
"text.entity360-none": "ninguno",
|
|
136
|
+
"text.shown-of-total": "se muestran {shown} de {total}",
|
|
136
137
|
"text.entity360-forbidden": "no tiene permiso para ver esto",
|
|
137
138
|
"text.entity360-failed": "no se pudo leer",
|
|
138
139
|
"text.error": "error",
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
"label.import": "importar",
|
|
173
174
|
"error.address-not-allowed": "este sitio no acepta conexiones desde su ubicación actual. consulte a su administrador.",
|
|
174
175
|
"error.database-failed": "El servidor no pudo procesar esto. Avise a su administrador.",
|
|
176
|
+
"error.row-tied": "Hay {count} registro(s) de $t(label.row-tie-{kind}, {\"defaultValue\": \"{kind}\"}) vinculados a esta fila, por lo que no se puede eliminar. Desvincúlelos o elimínelos primero.",
|
|
175
177
|
"button.undo": "deshacer",
|
|
176
178
|
"button.redo": "rehacer",
|
|
177
179
|
"button.fit-view": "ajustar a la vista",
|
|
@@ -180,10 +182,20 @@
|
|
|
180
182
|
"button.hide-end-pane": "ocultar el panel derecho",
|
|
181
183
|
"button.show-end-pane": "mostrar el panel derecho",
|
|
182
184
|
"title.unsaved-draft": "hay una edición sin guardar",
|
|
185
|
+
"title.id-lens": "buscar por número",
|
|
183
186
|
"text.unsaved-draft-kept": "los cambios que hizo hace {minutes} minutos siguen guardados en este navegador.",
|
|
184
187
|
"text.unsaved-draft-behind": "desde entonces se ha vuelto a guardar. al guardar se le avisará del conflicto.",
|
|
188
|
+
"text.id-lens-searching": "buscando",
|
|
189
|
+
"text.id-lens-choose": "{count} coincidencias para {value}; elija una",
|
|
190
|
+
"text.id-lens-forbidden": "No se buscó; no tiene permiso para ver: {kinds}",
|
|
191
|
+
"text.id-lens-failed": "No se pudo leer {kind}",
|
|
192
|
+
"text.id-lens-none": "No hay nada con el número {value}.",
|
|
185
193
|
"button.resume-editing": "reanudar edición",
|
|
186
194
|
"button.discard": "descartar",
|
|
195
|
+
"button.find": "buscar",
|
|
196
|
+
"button.scan": "escanear",
|
|
197
|
+
"button.retry": "reintentar",
|
|
198
|
+
"button.scan-with-camera": "escanear con la cámara",
|
|
187
199
|
"figure.label.motion": "Movimiento",
|
|
188
200
|
"figure.text.preview-needs-a-part": "añada una pieza para ver cómo se ve colocada en un plano.",
|
|
189
201
|
"error.timezone-required": "El dominio no tiene zona horaria. Configúrela en la gestión de dominios."
|
package/translations/ja.json
CHANGED
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"text.draft": "ドラフト保存",
|
|
134
134
|
"text.entity360-not-yet": "この種類の 360 はまだありません。",
|
|
135
135
|
"text.entity360-none": "なし",
|
|
136
|
+
"text.shown-of-total": "{total} 件中 {shown} 件を表示",
|
|
136
137
|
"text.entity360-forbidden": "閲覧できません",
|
|
137
138
|
"text.entity360-failed": "読み込めませんでした",
|
|
138
139
|
"text.error": "エラー",
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
"label.import": "インポート",
|
|
173
174
|
"error.address-not-allowed": "この事業所は現在の場所からの接続を受け付けていません。事業所の管理者にお問い合わせください。",
|
|
174
175
|
"error.database-failed": "サーバーで処理できませんでした。管理者にお知らせください。",
|
|
176
|
+
"error.row-tied": "$t(label.row-tie-{kind}, {\"defaultValue\": \"{kind}\"}) {count}件がこの行につながっているため削除できません。先に連結を解除するか、その行を削除してください。",
|
|
175
177
|
"button.undo": "元に戻す",
|
|
176
178
|
"button.redo": "やり直す",
|
|
177
179
|
"button.fit-view": "画面に合わせる",
|
|
@@ -180,10 +182,20 @@
|
|
|
180
182
|
"button.hide-end-pane": "右のパネルを閉じる",
|
|
181
183
|
"button.show-end-pane": "右のパネルを開く",
|
|
182
184
|
"title.unsaved-draft": "保存していない編集があります",
|
|
185
|
+
"title.id-lens": "番号で検索",
|
|
183
186
|
"text.unsaved-draft-kept": "{minutes}分前に変更した内容がこのブラウザに残っています。",
|
|
184
187
|
"text.unsaved-draft-behind": "その後、再び保存されています。保存するときに競合をお知らせします。",
|
|
188
|
+
"text.id-lens-searching": "検索中",
|
|
189
|
+
"text.id-lens-choose": "{value} に一致する対象が {count} 件あります。1 件を選んでください",
|
|
190
|
+
"text.id-lens-forbidden": "閲覧権限がないため検索していません: {kinds}",
|
|
191
|
+
"text.id-lens-failed": "{kind} を読み込めませんでした",
|
|
192
|
+
"text.id-lens-none": "番号 {value} の対象はありません。",
|
|
185
193
|
"button.resume-editing": "編集を続ける",
|
|
186
194
|
"button.discard": "破棄",
|
|
195
|
+
"button.find": "検索",
|
|
196
|
+
"button.scan": "スキャン",
|
|
197
|
+
"button.retry": "再試行",
|
|
198
|
+
"button.scan-with-camera": "カメラでスキャン",
|
|
187
199
|
"figure.label.motion": "Motion",
|
|
188
200
|
"figure.text.preview-needs-a-part": "部品を追加すると、図面に置いたときの姿が表示されます。",
|
|
189
201
|
"error.timezone-required": "事業所のタイムゾーンが設定されていません。事業所管理でタイムゾーンを設定してください。"
|
package/translations/ko.json
CHANGED
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"text.draft": "초안저장",
|
|
134
134
|
"text.entity360-not-yet": "이 종류의 360 은 아직 없습니다.",
|
|
135
135
|
"text.entity360-none": "없음",
|
|
136
|
+
"text.shown-of-total": "{total}건 중 {shown}건 표시",
|
|
136
137
|
"text.entity360-forbidden": "볼 수 없음",
|
|
137
138
|
"text.entity360-failed": "읽지 못함",
|
|
138
139
|
"text.error": "오류",
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
"label.import": "가져오기",
|
|
173
174
|
"error.address-not-allowed": "이 사업장은 지금 계신 곳에서의 접속을 받지 않습니다. 사업장 관리자에게 문의하십시오.",
|
|
174
175
|
"error.database-failed": "서버에서 처리하지 못했습니다. 관리자에게 알려 주세요.",
|
|
176
|
+
"error.row-tied": "$t(label.row-tie-{kind}, {\"defaultValue\": \"{kind}\"}) {count}건이 이 행에 이어져 있어 삭제할 수 없습니다. 그 연결을 먼저 끊거나 그 행을 먼저 지워야 합니다.",
|
|
175
177
|
"button.undo": "되돌리기",
|
|
176
178
|
"button.redo": "다시 실행",
|
|
177
179
|
"button.fit-view": "화면에 맞추기",
|
|
@@ -180,10 +182,20 @@
|
|
|
180
182
|
"button.hide-end-pane": "오른쪽 판 접기",
|
|
181
183
|
"button.show-end-pane": "오른쪽 판 펼치기",
|
|
182
184
|
"title.unsaved-draft": "저장하지 않은 편집이 있습니다",
|
|
185
|
+
"title.id-lens": "번호로 찾기",
|
|
183
186
|
"text.unsaved-draft-kept": "{minutes}분 전에 수정한 내용이 이 브라우저에 남아 있습니다.",
|
|
184
187
|
"text.unsaved-draft-behind": "그 뒤에 다시 저장되었습니다. 저장할 때 충돌을 알려 드립니다.",
|
|
188
|
+
"text.id-lens-searching": "찾는 중",
|
|
189
|
+
"text.id-lens-choose": "검색어 {value}와 일치하는 대상이 {count}개입니다. 하나를 선택하십시오.",
|
|
190
|
+
"text.id-lens-forbidden": "볼 권한이 없어 찾지 않았습니다: {kinds}",
|
|
191
|
+
"text.id-lens-failed": "{kind} 정보를 불러오지 못했습니다.",
|
|
192
|
+
"text.id-lens-none": "번호가 {value} 인 대상이 없습니다.",
|
|
185
193
|
"button.resume-editing": "이어서 편집",
|
|
186
194
|
"button.discard": "버리기",
|
|
195
|
+
"button.find": "찾기",
|
|
196
|
+
"button.scan": "스캔",
|
|
197
|
+
"button.retry": "다시 시도",
|
|
198
|
+
"button.scan-with-camera": "카메라로 스캔",
|
|
187
199
|
"figure.label.motion": "움직임",
|
|
188
200
|
"figure.text.preview-needs-a-part": "부품을 추가하면 도면에 놓았을 때의 모습이 표시됩니다.",
|
|
189
201
|
"error.timezone-required": "$t(term.domain) 시간대가 정해지지 않았습니다. $t(term.domain) 관리에서 시간대를 정하세요."
|
package/translations/ms.json
CHANGED
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"text.draft": "draf",
|
|
134
134
|
"text.entity360-not-yet": "belum ada 360 untuk jenis ini.",
|
|
135
135
|
"text.entity360-none": "tiada",
|
|
136
|
+
"text.shown-of-total": "menunjukkan {shown} daripada {total}",
|
|
136
137
|
"text.entity360-forbidden": "anda tidak boleh melihat ini",
|
|
137
138
|
"text.entity360-failed": "tidak dapat dibaca",
|
|
138
139
|
"text.error": "Ralat",
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
"label.import": "import",
|
|
173
174
|
"error.address-not-allowed": "tapak ini tidak menerima sambungan dari lokasi anda. sila hubungi pentadbirnya.",
|
|
174
175
|
"error.database-failed": "Pelayan tidak dapat memproses ini. Sila maklumkan kepada pentadbir anda.",
|
|
176
|
+
"error.row-tied": "{count} rekod $t(label.row-tie-{kind}, {\"defaultValue\": \"{kind}\"}) terikat pada baris ini, jadi ia tidak boleh dipadam. Nyahpautkan atau padamkannya dahulu.",
|
|
175
177
|
"button.undo": "buat asal",
|
|
176
178
|
"button.redo": "buat semula",
|
|
177
179
|
"button.fit-view": "muat ke paparan",
|
|
@@ -180,10 +182,20 @@
|
|
|
180
182
|
"button.hide-end-pane": "sembunyikan panel kanan",
|
|
181
183
|
"button.show-end-pane": "tunjukkan panel kanan",
|
|
182
184
|
"title.unsaved-draft": "ada suntingan yang belum disimpan",
|
|
185
|
+
"title.id-lens": "cari mengikut nombor",
|
|
183
186
|
"text.unsaved-draft-kept": "perubahan yang anda buat {minutes} minit lalu masih disimpan dalam pelayar ini.",
|
|
184
187
|
"text.unsaved-draft-behind": "ia telah disimpan semula sejak itu. semasa menyimpan, anda akan dimaklumkan tentang konflik.",
|
|
188
|
+
"text.id-lens-searching": "mencari",
|
|
189
|
+
"text.id-lens-choose": "{count} padanan untuk {value} - pilih satu",
|
|
190
|
+
"text.id-lens-forbidden": "Tidak dicari - anda tidak boleh melihat: {kinds}",
|
|
191
|
+
"text.id-lens-failed": "Tidak dapat membaca {kind}",
|
|
192
|
+
"text.id-lens-none": "Tiada apa-apa bernombor {value}.",
|
|
185
193
|
"button.resume-editing": "sambung menyunting",
|
|
186
194
|
"button.discard": "buang",
|
|
195
|
+
"button.find": "cari",
|
|
196
|
+
"button.scan": "imbas",
|
|
197
|
+
"button.retry": "cuba lagi",
|
|
198
|
+
"button.scan-with-camera": "imbas dengan kamera",
|
|
187
199
|
"figure.label.motion": "Motion",
|
|
188
200
|
"figure.text.preview-needs-a-part": "tambah bahagian untuk melihat rupanya apabila diletakkan pada lukisan.",
|
|
189
201
|
"error.timezone-required": "Domain tiada zon waktu. Tetapkannya dalam pengurusan domain."
|
package/translations/zh.json
CHANGED
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"text.draft": "草稿",
|
|
134
134
|
"text.entity360-not-yet": "此类暂无 360 视图。",
|
|
135
135
|
"text.entity360-none": "无",
|
|
136
|
+
"text.shown-of-total": "显示 {total} 个中的 {shown} 个",
|
|
136
137
|
"text.entity360-forbidden": "无权查看",
|
|
137
138
|
"text.entity360-failed": "无法读取",
|
|
138
139
|
"text.error": "错误",
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
"label.import": "导入",
|
|
173
174
|
"error.address-not-allowed": "此站点不接受来自您当前位置的连接。请联系站点管理员。",
|
|
174
175
|
"error.database-failed": "服务器无法处理此请求。请告知管理员。",
|
|
176
|
+
"error.row-tied": "有 {count} 条$t(label.row-tie-{kind}, {\"defaultValue\": \"{kind}\"})与此行关联,无法删除。请先解除关联或删除这些记录。",
|
|
175
177
|
"button.undo": "撤销",
|
|
176
178
|
"button.redo": "重做",
|
|
177
179
|
"button.fit-view": "适应视图",
|
|
@@ -180,10 +182,20 @@
|
|
|
180
182
|
"button.hide-end-pane": "收起右侧面板",
|
|
181
183
|
"button.show-end-pane": "展开右侧面板",
|
|
182
184
|
"title.unsaved-draft": "有未保存的编辑",
|
|
185
|
+
"title.id-lens": "按编号查找",
|
|
183
186
|
"text.unsaved-draft-kept": "您 {minutes} 分钟前所做的更改仍保留在此浏览器中。",
|
|
184
187
|
"text.unsaved-draft-behind": "此后已被再次保存。保存时会提示冲突。",
|
|
188
|
+
"text.id-lens-searching": "正在查找",
|
|
189
|
+
"text.id-lens-choose": "与 {value} 匹配的对象有 {count} 个,请选择一个",
|
|
190
|
+
"text.id-lens-forbidden": "无查看权限,未查找: {kinds}",
|
|
191
|
+
"text.id-lens-failed": "无法读取{kind}",
|
|
192
|
+
"text.id-lens-none": "没有编号为 {value} 的对象。",
|
|
185
193
|
"button.resume-editing": "继续编辑",
|
|
186
194
|
"button.discard": "放弃",
|
|
195
|
+
"button.find": "查找",
|
|
196
|
+
"button.scan": "扫描",
|
|
197
|
+
"button.retry": "重试",
|
|
198
|
+
"button.scan-with-camera": "用摄像头扫描",
|
|
187
199
|
"figure.label.motion": "Motion",
|
|
188
200
|
"figure.text.preview-needs-a-part": "添加部件后会显示放置到图面上的效果。",
|
|
189
201
|
"error.timezone-required": "尚未设置单位时区。请在单位管理中设置时区。"
|