@aiquants/auth-react-router 0.11.0 → 0.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/auth-react-router",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "React Router v7 / v8 auth adapter for @aiquants/auth-core: Google OAuth strategy factory (remix-auth), cookie session storage with DI test backdoor, a loader guard that authenticates at most once per request (token refresh + photo cache), auth route handlers, and a <GoogleForm> login button.",
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -67,7 +67,7 @@
67
67
  "tsup": "^8.5.1",
68
68
  "typescript": "^5.9.3",
69
69
  "vitest": "^4.1.8",
70
- "@aiquants/auth-core": "0.3.0"
70
+ "@aiquants/auth-core": "0.5.0"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "react": ">=18",
@@ -75,7 +75,7 @@
75
75
  "react-router": "^7.0.0 || ^8.0.0",
76
76
  "remix-auth": "^4.0.0",
77
77
  "remix-auth-oauth2": "^3.0.0",
78
- "@aiquants/auth-core": "^0.3.0"
78
+ "@aiquants/auth-core": "^0.5.0"
79
79
  },
80
80
  "engines": {
81
81
  "node": ">=18.0.0",
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @module admin/format
3
+ * @description Text helpers shared by the shell and the views.
4
+ * シェルとビューが共有する文言整形の補助。
5
+ *
6
+ * 数や名前を JSX で連結すると語順が英語に固定され、日付を実行環境任せで整形すると
7
+ * サーバーとブラウザで別の文字列になる (水和が壊れる)。どちらもラベル側の宣言に従わせる。
8
+ */
9
+ import type { UserAdminLabels } from "./labels"
10
+
11
+ /**
12
+ * Substitutes `{key}` placeholders in a label template.
13
+ * ラベルの雛形に含まれる `{key}` を差し替える処理。
14
+ *
15
+ * @param template Label text containing `{key}` placeholders. `{key}` を含むラベル文言。
16
+ * @param values Replacement values by key. キーごとの差し替え値。
17
+ * @returns The filled text. 差し替え済みの文言。
18
+ */
19
+ export function fill(template: string, values: Record<string, string | number>): string {
20
+ return Object.entries(values).reduce((text, [key, value]) => text.replaceAll(`{${key}}`, String(value)), template)
21
+ }
22
+
23
+ /**
24
+ * Formats an ISO timestamp with the locale the labels declare, not the runtime's.
25
+ * ISO 時刻を、実行環境ではなく **ラベルが宣言したロケール** で整形する処理。
26
+ *
27
+ * @param iso ISO 8601 timestamp. ISO 8601 の時刻。
28
+ * @param labels Resolved label set carrying locale and time zone. ロケールと時間帯を持つラベル。
29
+ * @returns Formatted text. 整形済みの文言。
30
+ */
31
+ export function formatDateTime(iso: string, labels: UserAdminLabels): string {
32
+ return new Intl.DateTimeFormat(labels.locale, { timeZone: labels.timeZone, dateStyle: "medium", timeStyle: "short" }).format(new Date(iso))
33
+ }
@@ -10,60 +10,123 @@
10
10
 
11
11
  export type UserAdminLabels = {
12
12
  title: string
13
+ /**
14
+ * BCP 47 locale used to format dates. 日付整形に使う BCP 47 ロケール。
15
+ *
16
+ * 実行環境任せにするとサーバーとブラウザで別の文字列になり、水和が壊れる。
17
+ */
18
+ locale: string
19
+ /** IANA time zone used to format dates. 日付整形に使う IANA タイムゾーン。 */
20
+ timeZone: string
21
+ /**
22
+ * Strings shared by more than one view. 複数のビューが共有する文言。
23
+ *
24
+ * ビューごとに同じ語を持たせると、ある画面の「削除」だけを言い換えることが **できなく
25
+ * なる** (実装がどのビューのキーを読んでいるかは呼び出し側から見えない)。共有する語は
26
+ * ここ 1 か所に置く。
27
+ */
28
+ common: {
29
+ add: string
30
+ create: string
31
+ edit: string
32
+ delete: string
33
+ save: string
34
+ cancel: string
35
+ actions: string
36
+ status: string
37
+ id: string
38
+ /** 変更不能な供給元 (環境変数など) 由来の行に出す表示。 */
39
+ readOnly: string
40
+ /** 上流所有のグループに出す編集不可の表示。 */
41
+ managedUpstream: string
42
+ /** `#{id}` の表示。記号の位置は言語で変わる。 */
43
+ idTemplate: string
44
+ /** 値が無いことの表示 (説明欄など)。 */
45
+ none: string
46
+ }
47
+ /** アクションが拒否・失敗したときの文言。 */
48
+ errors: {
49
+ /**
50
+ * Shown when the actor lacks permission for the attempted operation.
51
+ * 操作の権限が無いときに出す文言。
52
+ *
53
+ * ガードの例外メッセージをそのまま返してはならない。テナント ID・アプリキー・
54
+ * 拒否理由といった内部の語彙が、権限を持たない相手にそのまま渡る。
55
+ */
56
+ forbidden: string
57
+ }
13
58
  /** シェル (タブ枠) の見出し。 */
14
59
  heading: string
60
+ /** シェルが描く自己権限バッジの文言。 */
61
+ permissions: {
62
+ label: string
63
+ canWrite: string
64
+ canRead: string
65
+ none: string
66
+ /** 未結線・取得失敗・付与ゼロのいずれも「不明」であり、許可ではない。 */
67
+ unknown: string
68
+ }
15
69
  tabs: {
16
70
  users: string
17
71
  groups: string
18
72
  groupMembers: string
19
73
  allowlist: string
74
+ directory: string
20
75
  }
21
76
  usersView: {
22
77
  title: string
23
78
  searchPlaceholder: string
79
+ /** 検索欄の読み上げ名。プレースホルダは入力すると消えるため名前にならない。 */
80
+ searchLabel: string
24
81
  addUser: string
25
82
  editUser: string
26
- id: string
27
83
  displayName: string
28
84
  email: string
29
- status: string
30
85
  active: string
31
86
  inactive: string
32
- actions: string
33
- edit: string
34
87
  activate: string
35
88
  deactivate: string
89
+ /** 行ごとの読み上げ名。`{user}` を利用者名へ置換する。 */
90
+ editUserAria: string
91
+ activateAria: string
92
+ deactivateAria: string
93
+ /** 無効化はサインインを止める。確認を取る。 */
94
+ confirmDeactivate: string
36
95
  empty: string
37
- save: string
38
- cancel: string
39
96
  }
40
97
  groupsView: {
98
+ /** 検索語に一致しないときの説明。空状態と混ぜると「消えた」と誤読される。 */
99
+ emptyFiltered: string
41
100
  title: string
42
101
  searchPlaceholder: string
102
+ searchLabel: string
43
103
  addGroup: string
44
104
  editGroup: string
45
- id: string
46
105
  groupKey: string
47
106
  name: string
48
107
  description: string
49
- memberCount: string
50
- status: string
51
- actions: string
52
- edit: string
53
- delete: string
108
+ /** 所属人数。`{count}` を人数へ置換する。 */
109
+ memberCountTemplate: string
54
110
  confirmDelete: string
55
111
  noDescription: string
56
112
  groupKeyPlaceholder: string
57
113
  namePlaceholder: string
58
114
  empty: string
59
- save: string
60
- cancel: string
61
115
  }
62
116
  groupMembersView: {
117
+ title: string
63
118
  selectGroup: string
64
119
  selectPrompt: string
65
120
  actionAdd: string
66
121
  actionRemove: string
122
+ /** 行ごとの読み上げ名。`{user}` を利用者名へ置換する。 */
123
+ actionAddAria: string
124
+ actionRemoveAria: string
125
+ /** 上流所有グループで編集を出さない理由。押せない理由を書かないと故障に見える。 */
126
+ upstreamNotice: string
127
+ /** 見出し。`{group}` をグループ名へ置換する。語順が言語で変わるため位置指定にする。 */
128
+ membersOfTemplate: string
129
+ groupKeyLabel: string
67
130
  }
68
131
  allowlistView: {
69
132
  title: string
@@ -80,30 +143,26 @@ export type UserAdminLabels = {
80
143
  /** 対象列の見出し。パターンとグループが混在するため「パターン」ではない。 */
81
144
  target: string
82
145
  description: string
83
- actions: string
84
- /** 変更不能な供給元 (環境変数など) 由来の行に出す表示。 */
85
- readOnly: string
86
146
  /** 配備全体が所有する行 (環境変数由来) の所有者表示。 */
87
147
  deploymentOwner: string
88
- delete: string
148
+ /** 許可の取り消しはサインインを止める。確認を取る。 */
149
+ confirmDelete: string
150
+ /** 行ごとの読み上げ名。`{target}` を対象へ置換する。 */
151
+ deleteAria: string
89
152
  empty: string
90
- save: string
91
- cancel: string
92
153
  }
93
154
  directoryView: {
94
155
  title: string
95
156
  /** 出所列。ローカル管理か、どの上流かを示す。 */
96
157
  source: string
97
158
  localSource: string
98
- /** 上流所有のグループに出す編集不可の表示。 */
99
- managedUpstream: string
100
159
  membershipMode: string
101
160
  directMode: string
102
161
  transitiveMode: string
103
162
  lastSynced: string
104
163
  neverSynced: string
105
- /** 上流に居るがローカルユーザーへ解決できていない人数。 */
106
- unresolved: string
164
+ /** 上流に居るがローカルユーザーへ解決できていない人数。`{count}` を人数へ置換する。 */
165
+ unresolvedTemplate: string
107
166
  syncPaused: string
108
167
  syncEnabled: string
109
168
  syncNow: string
@@ -111,10 +170,53 @@ export type UserAdminLabels = {
111
170
  /** 同期が滞っていることの警告。停止はセキュリティ事象である。 */
112
171
  staleWarning: string
113
172
  disabledWarning: string
173
+ /** 停止件数。`{paused}` / `{total}` を件数へ置換する。 */
174
+ pausedTemplate: string
175
+ /** 失敗したグループの列挙。`{groups}` を名前の並びへ置換する。 */
176
+ erroredTemplate: string
177
+ /** 失敗理由付きの 1 件。`{group}` / `{reason}`。 */
178
+ erroredItemTemplate: string
179
+ /** 列挙の区切り。言語で変わる。 */
180
+ listSeparator: string
181
+ /** 滞留警告に添える最終成功時刻。`{at}`。 */
182
+ oldestSyncedTemplate: string
183
+ /** 未処理の同期要求。`{count}`。 */
184
+ pendingTemplate: string
185
+ /** 連携先が 1 つも残っていないときの説明。 */
186
+ nothingToLink: string
187
+ /** 未結線の配備で操作を出さない理由。 */
188
+ notWiredNotice: string
189
+ /** 行ごとの読み上げ名。`{group}` をグループ名へ置換する。 */
190
+ syncNowAria: string
191
+ pauseAria: string
192
+ resumeAria: string
193
+ allowGroupAria: string
194
+ disallowGroupAria: string
195
+ unlinkAria: string
196
+ /** グループ単位のサインイン許可を外す確認。 */
197
+ confirmDisallow: string
114
198
  link: string
115
199
  unlink: string
116
200
  externalKey: string
117
201
  empty: string
202
+ /** 直近の同期が失敗したグループの見出し。件数だけでは何が起きたか判らない。 */
203
+ erroredWarning: string
204
+ /** 同期有効なリンクのうち最も古い成功時刻。滞留の実際の深さを示す。 */
205
+ oldestSyncedAt: string
206
+ /** 連携するグループを選ぶ欄。 */
207
+ selectGroup: string
208
+ /** 上流グループのアドレス入力。 */
209
+ externalKeyPlaceholder: string
210
+ /** 連携解除の確認。台帳と許可設定が消える。 */
211
+ confirmUnlink: string
212
+ /** 同期の一時停止・再開。 */
213
+ pause: string
214
+ resume: string
215
+ /** 許可グループに加える / 外す。 */
216
+ allowGroup: string
217
+ disallowGroup: string
218
+ /** グループ名と鍵の併記。`{name}` / `{key}`。 */
219
+ groupOptionTemplate: string
118
220
  }
119
221
  }
120
222
 
@@ -124,63 +226,91 @@ export type UserAdminLabels = {
124
226
  */
125
227
  export const defaultUserAdminLabels: UserAdminLabels = {
126
228
  title: "Users & Groups",
127
- heading: "👤 User administration",
229
+ locale: "en-US",
230
+ timeZone: "UTC",
231
+ heading: "\u{1F464} User administration",
232
+ common: {
233
+ add: "Add",
234
+ create: "Create",
235
+ edit: "Edit",
236
+ delete: "Delete",
237
+ save: "Save",
238
+ cancel: "Cancel",
239
+ actions: "Actions",
240
+ status: "Status",
241
+ id: "ID",
242
+ readOnly: "Read-only",
243
+ managedUpstream: "Managed upstream",
244
+ idTemplate: "#{id}",
245
+ none: "-",
246
+ },
247
+ errors: {
248
+ forbidden: "You do not have permission for this operation.",
249
+ },
250
+ permissions: {
251
+ label: "Your permissions:",
252
+ canWrite: "Editable",
253
+ canRead: "Read only",
254
+ none: "No access",
255
+ unknown: "Unknown",
256
+ },
128
257
  tabs: {
129
- users: "👤 Users",
130
- groups: "👥 Groups",
131
- groupMembers: "🔗 Members",
132
- allowlist: "✉️ Allowlist",
258
+ users: "\u{1F464} Users",
259
+ groups: "\u{1F465} Groups",
260
+ groupMembers: "\u{1F517} Members",
261
+ allowlist: "\u2709\uFE0F Allowlist",
262
+ directory: "\u{1F504} Directory",
133
263
  },
134
264
  usersView: {
135
265
  title: "Users",
136
266
  searchPlaceholder: "Search by name or email...",
137
- addUser: "+ Add user",
267
+ searchLabel: "Search users",
268
+ addUser: "\uFF0B Add user",
138
269
  editUser: "Edit user",
139
- id: "ID",
140
270
  displayName: "Name",
141
271
  email: "Email",
142
- status: "Status",
143
272
  active: "Active",
144
273
  inactive: "Inactive",
145
- actions: "Actions",
146
- edit: "Edit",
147
274
  activate: "Activate",
148
275
  deactivate: "Deactivate",
276
+ editUserAria: "Edit {user}",
277
+ activateAria: "Activate {user}",
278
+ deactivateAria: "Deactivate {user}",
279
+ confirmDeactivate: "Deactivate this user? They will no longer be able to sign in.",
149
280
  empty: "No matching users",
150
- save: "Save",
151
- cancel: "Cancel",
152
281
  },
153
282
  groupsView: {
283
+ emptyFiltered: "No group matches this search",
154
284
  title: "Groups",
155
285
  searchPlaceholder: "Search by group name or key...",
156
- addGroup: "+ Add group",
286
+ searchLabel: "Search groups",
287
+ addGroup: "\uFF0B Add group",
157
288
  editGroup: "Edit group",
158
- id: "ID",
159
289
  groupKey: "Group key",
160
290
  name: "Name",
161
291
  description: "Description",
162
- memberCount: "Members",
163
- status: "Status",
164
- actions: "Actions",
165
- edit: "Edit",
166
- delete: "Delete",
292
+ memberCountTemplate: "{count} members",
167
293
  confirmDelete: "Delete this group?",
168
294
  noDescription: "No description",
169
295
  groupKeyPlaceholder: "e.g. dev-team",
170
296
  namePlaceholder: "e.g. Development team",
171
297
  empty: "No groups registered",
172
- save: "Save",
173
- cancel: "Cancel",
174
298
  },
175
299
  groupMembersView: {
300
+ title: "Group members",
176
301
  selectGroup: "Select a group",
177
302
  selectPrompt: "Select a group to manage its members",
178
303
  actionAdd: "Add",
179
304
  actionRemove: "Remove",
305
+ actionAddAria: "Add {user} to this group",
306
+ actionRemoveAria: "Remove {user} from this group",
307
+ upstreamNotice: "Membership of this group is owned by the upstream directory. Edit it there \u2014 a local change would be reverted at the next synchronization.",
308
+ membersOfTemplate: "Members of {group}",
309
+ groupKeyLabel: "Group key",
180
310
  },
181
311
  allowlistView: {
182
312
  title: "Sign-in allowlist",
183
- addEntry: "+ Add pattern",
313
+ addEntry: "\uFF0B Add pattern",
184
314
  pattern: "Pattern (e.g. @example.com or user@example.com)",
185
315
  type: "Type",
186
316
  emailType: "Exact email match",
@@ -190,35 +320,56 @@ export const defaultUserAdminLabels: UserAdminLabels = {
190
320
  groupTypeShort: "Group",
191
321
  target: "Target",
192
322
  description: "Description",
193
- actions: "Actions",
194
- readOnly: "Read-only",
195
323
  deploymentOwner: "Deployment-wide",
196
- delete: "Delete",
324
+ confirmDelete: "Remove this allowlist entry? Anyone who could sign in only through it will be locked out.",
325
+ deleteAria: "Remove the allowlist entry for {target}",
197
326
  empty: "No allowlist entries registered",
198
- save: "Add",
199
- cancel: "Cancel",
200
327
  },
201
328
  directoryView: {
202
329
  title: "Directory synchronization",
203
330
  source: "Source",
204
331
  localSource: "Local",
205
- managedUpstream: "Managed upstream",
206
332
  membershipMode: "Membership",
207
333
  directMode: "Direct only",
208
334
  transitiveMode: "Nested expanded",
209
335
  lastSynced: "Last synced",
210
336
  neverSynced: "Never",
211
- unresolved: "unresolved",
337
+ unresolvedTemplate: "{count} unresolved",
212
338
  syncPaused: "Paused",
213
339
  syncEnabled: "Active",
214
340
  syncNow: "Sync now",
215
341
  syncQueued: "Queued",
216
342
  staleWarning: "Synchronization is overdue. Until it runs, people removed upstream keep their access.",
217
343
  disabledWarning: "Directory synchronization is not wired for this deployment. Existing memberships remain in force and are no longer being refreshed.",
344
+ pausedTemplate: "{paused} of {total} links are paused",
345
+ erroredTemplate: "Last synchronization failed for {groups}",
346
+ erroredItemTemplate: "{group}: {reason}",
347
+ listSeparator: ", ",
348
+ oldestSyncedTemplate: "oldest successful sync: {at}",
349
+ pendingTemplate: "{count} sync requests are queued",
350
+ nothingToLink: "Every group is already linked to a directory.",
351
+ notWiredNotice: "Directory synchronization is not wired for this deployment, so links cannot be created or changed here.",
352
+ syncNowAria: "Synchronize {group} now",
353
+ pauseAria: "Pause synchronization of {group}",
354
+ resumeAria: "Resume synchronization of {group}",
355
+ allowGroupAria: "Allow members of {group} to sign in",
356
+ disallowGroupAria: "Stop allowing members of {group} to sign in",
357
+ unlinkAria: "Unlink {group} from the directory",
358
+ confirmDisallow: "Stop allowing this group to sign in? Anyone who could sign in only through it will be locked out.",
218
359
  link: "Link to a directory group",
219
360
  unlink: "Unlink",
220
361
  externalKey: "Upstream group",
221
362
  empty: "No groups are linked to a directory",
363
+ erroredWarning: "Last synchronization failed for",
364
+ oldestSyncedAt: "Oldest successful sync",
365
+ selectGroup: "Group to link",
366
+ externalKeyPlaceholder: "e.g. dev-team@example.com",
367
+ confirmUnlink: "Unlink this group? Its member ledger and group-based sign-in permission are removed.",
368
+ pause: "Pause",
369
+ resume: "Resume",
370
+ allowGroup: "Allow sign-in",
371
+ disallowGroup: "Stop allowing sign-in",
372
+ groupOptionTemplate: "{name} ({key})",
222
373
  },
223
374
  }
224
375
 
@@ -228,108 +379,162 @@ export const defaultUserAdminLabels: UserAdminLabels = {
228
379
  */
229
380
  export const jaUserAdminLabels: UserAdminLabels = {
230
381
  title: "ユーザー・グループ管理",
231
- heading: "👤 ユーザー管理",
382
+ locale: "ja-JP",
383
+ timeZone: "Asia/Tokyo",
384
+ heading: "\u{1F464} ユーザー管理",
385
+ common: {
386
+ add: "追加",
387
+ create: "作成",
388
+ edit: "編集",
389
+ delete: "削除",
390
+ save: "保存",
391
+ cancel: "キャンセル",
392
+ actions: "操作",
393
+ status: "状態",
394
+ id: "ID",
395
+ readOnly: "変更不可",
396
+ managedUpstream: "上流が所有",
397
+ idTemplate: "#{id}",
398
+ none: "-",
399
+ },
400
+ errors: {
401
+ forbidden: "この操作を行う権限がありません。",
402
+ },
403
+ permissions: {
404
+ label: "あなたの権限:",
405
+ canWrite: "編集可",
406
+ canRead: "閲覧のみ",
407
+ none: "権限なし",
408
+ unknown: "権限不明",
409
+ },
232
410
  tabs: {
233
- users: "👤 ユーザー一覧",
234
- groups: "👥 ユーザーグループ",
235
- groupMembers: "🔗 グループメンバー",
236
- allowlist: "✉️ アクセス許可リスト",
411
+ users: "\u{1F464} ユーザー一覧",
412
+ groups: "\u{1F465} ユーザーグループ",
413
+ groupMembers: "\u{1F517} グループメンバー",
414
+ allowlist: "\u2709\uFE0F アクセス許可リスト",
415
+ directory: "\u{1F504} ディレクトリ連携",
237
416
  },
238
417
  usersView: {
239
418
  title: "ユーザー管理",
240
419
  searchPlaceholder: "表示名や Email で検索...",
241
- addUser: "+ ユーザー追加",
242
- editUser: "ユーザーの編集",
243
- id: "ID",
420
+ searchLabel: "ユーザーを検索",
421
+ addUser: "\uFF0B ユーザー追加",
422
+ editUser: "ユーザー編集",
244
423
  displayName: "表示名",
245
- email: "メールアドレス",
246
- status: "ステータス",
424
+ email: "Email",
247
425
  active: "有効",
248
426
  inactive: "無効",
249
- actions: "操作",
250
- edit: "編集",
251
427
  activate: "有効化",
252
428
  deactivate: "無効化",
429
+ editUserAria: "{user} を編集",
430
+ activateAria: "{user} を有効化",
431
+ deactivateAria: "{user} を無効化",
432
+ confirmDeactivate: "このユーザーを無効化しますか? 以後サインインできなくなります。",
253
433
  empty: "該当するユーザーが見つかりません",
254
- save: "保存",
255
- cancel: "キャンセル",
256
434
  },
257
435
  groupsView: {
436
+ emptyFiltered: "検索条件に一致するグループはありません",
258
437
  title: "ユーザーグループ管理",
259
438
  searchPlaceholder: "グループ名やキーで検索...",
260
- addGroup: "+ グループ作成",
261
- editGroup: "グループの編集",
262
- id: "ID",
439
+ searchLabel: "グループを検索",
440
+ addGroup: "\uFF0B グループ追加",
441
+ editGroup: "グループ編集",
263
442
  groupKey: "グループキー",
264
- name: "グループ名",
443
+ name: "名称",
265
444
  description: "説明",
266
- memberCount: "メンバー数",
267
- status: "ステータス",
268
- actions: "操作",
269
- edit: "編集",
270
- delete: "削除",
271
- confirmDelete: "このグループを削除してもよろしいですか?",
445
+ memberCountTemplate: "所属 {count} 名",
446
+ confirmDelete: "このグループを削除しますか?",
272
447
  noDescription: "説明なし",
273
448
  groupKeyPlaceholder: "例: dev-team",
274
449
  namePlaceholder: "例: 開発チーム",
275
- empty: "グループが登録されていません",
276
- save: "保存",
277
- cancel: "キャンセル",
450
+ empty: "ユーザーグループが登録されていません",
278
451
  },
279
452
  groupMembersView: {
453
+ title: "グループメンバー管理",
280
454
  selectGroup: "グループ選択",
281
455
  selectPrompt: "グループを選択してください",
282
456
  actionAdd: "追加",
283
457
  actionRemove: "除外",
458
+ actionAddAria: "{user} をこのグループへ追加",
459
+ actionRemoveAria: "{user} をこのグループから除外",
460
+ upstreamNotice: "このグループの所属は上流ディレクトリが所有しています。変更は上流で行ってください (ここで変えても次の同期で元に戻ります)。",
461
+ membersOfTemplate: "{group} の所属メンバー",
462
+ groupKeyLabel: "グループキー",
284
463
  },
285
464
  allowlistView: {
286
- title: "アクセス許可リスト (Allowlist)",
287
- addEntry: "+ 許可パターン追加",
465
+ title: "サインイン許可リスト",
466
+ addEntry: "\uFF0B パターン追加",
288
467
  pattern: "パターン (例: @example.com または user@example.com)",
289
468
  type: "種別",
290
469
  emailType: "メールアドレス完全一致",
291
470
  domainType: "ドメイン一致",
292
- emailTypeShort: "Email 完全一致",
293
- domainTypeShort: "ドメイン一致",
471
+ emailTypeShort: "メール",
472
+ domainTypeShort: "ドメイン",
294
473
  groupTypeShort: "グループ",
295
474
  target: "対象",
296
475
  description: "説明 / 備考",
297
- actions: "操作",
298
- readOnly: "変更不可",
299
476
  deploymentOwner: "配備共通",
300
- delete: "削除",
477
+ confirmDelete: "この許可を削除しますか? これでしかサインインできない人はログインできなくなります。",
478
+ deleteAria: "{target} の許可を削除",
301
479
  empty: "アロワリストエントリが登録されていません",
302
- save: "登録",
303
- cancel: "キャンセル",
304
480
  },
305
481
  directoryView: {
306
482
  title: "ディレクトリ同期",
307
483
  source: "出所",
308
484
  localSource: "ローカル管理",
309
- managedUpstream: "上流が所有",
310
485
  membershipMode: "所属の展開",
311
486
  directMode: "直接所属のみ",
312
487
  transitiveMode: "入れ子を展開",
313
488
  lastSynced: "最終同期",
314
489
  neverSynced: "未実行",
315
- unresolved: "件 未解決",
490
+ unresolvedTemplate: "{count} 件が未解決",
316
491
  syncPaused: "停止中",
317
492
  syncEnabled: "有効",
318
493
  syncNow: "今すぐ同期",
319
494
  syncQueued: "同期を要求しました",
320
495
  staleWarning: "同期が滞っています。実行されるまで、上流から外れた人のアクセスは残り続けます。",
321
496
  disabledWarning: "この配備ではディレクトリ同期が結線されていません。既存の所属はそのまま有効で、更新だけが止まっています。",
497
+ pausedTemplate: "連携 {total} 件のうち {paused} 件が停止中",
498
+ erroredTemplate: "直近の同期に失敗したグループ: {groups}",
499
+ erroredItemTemplate: "{group}: {reason}",
500
+ listSeparator: " / ",
501
+ oldestSyncedTemplate: "最も古い同期成功: {at}",
502
+ pendingTemplate: "{count} 件の同期要求が未処理",
503
+ nothingToLink: "すべてのグループが既にディレクトリと連携しています。",
504
+ notWiredNotice: "この配備ではディレクトリ同期が結線されていないため、ここから連携の作成・変更はできません。",
505
+ syncNowAria: "{group} を今すぐ同期",
506
+ pauseAria: "{group} の同期を一時停止",
507
+ resumeAria: "{group} の同期を再開",
508
+ allowGroupAria: "{group} のメンバーのサインインを許可",
509
+ disallowGroupAria: "{group} のメンバーのサインイン許可を外す",
510
+ unlinkAria: "{group} のディレクトリ連携を解除",
511
+ confirmDisallow: "このグループのサインイン許可を外しますか? これでしかサインインできない人はログインできなくなります。",
322
512
  link: "ディレクトリのグループと連携する",
323
513
  unlink: "連携を解除",
324
514
  externalKey: "上流グループ",
325
515
  empty: "ディレクトリと連携しているグループはありません",
516
+ erroredWarning: "直近の同期に失敗したグループ",
517
+ oldestSyncedAt: "最も古い同期成功",
518
+ selectGroup: "連携するグループ",
519
+ externalKeyPlaceholder: "例: dev-team@example.com",
520
+ confirmUnlink: "このグループの連携を解除しますか? メンバー台帳とグループ単位のサインイン許可が失われます。",
521
+ pause: "一時停止",
522
+ resume: "再開",
523
+ allowGroup: "サインインを許可",
524
+ disallowGroup: "サインイン許可を外す",
525
+ groupOptionTemplate: "{name} ({key})",
326
526
  },
327
527
  }
328
528
 
329
529
  /** セクション単位の部分上書き。 */
330
530
  export type PartialUserAdminLabels = {
331
531
  title?: string
532
+ locale?: string
533
+ timeZone?: string
534
+ common?: Partial<UserAdminLabels["common"]>
535
+ errors?: Partial<UserAdminLabels["errors"]>
332
536
  heading?: string
537
+ permissions?: Partial<UserAdminLabels["permissions"]>
333
538
  tabs?: Partial<UserAdminLabels["tabs"]>
334
539
  usersView?: Partial<UserAdminLabels["usersView"]>
335
540
  groupsView?: Partial<UserAdminLabels["groupsView"]>
@@ -347,7 +552,12 @@ export function resolveUserAdminLabels(over?: PartialUserAdminLabels): UserAdmin
347
552
  if (!over) return d
348
553
  return {
349
554
  title: over.title ?? d.title,
555
+ locale: over.locale ?? d.locale,
556
+ timeZone: over.timeZone ?? d.timeZone,
350
557
  heading: over.heading ?? d.heading,
558
+ common: { ...d.common, ...over.common },
559
+ errors: { ...d.errors, ...over.errors },
560
+ permissions: { ...d.permissions, ...over.permissions },
351
561
  tabs: { ...d.tabs, ...over.tabs },
352
562
  usersView: { ...d.usersView, ...over.usersView },
353
563
  groupsView: { ...d.groupsView, ...over.groupsView },