@stapel/workspaces-react 0.17.0 → 0.19.1

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.
Files changed (123) hide show
  1. package/CHANGELOG.md +218 -0
  2. package/README.md +39 -8
  3. package/dist/api/generated/schema.d.ts +187 -60
  4. package/dist/api/generated/schema.d.ts.map +1 -1
  5. package/dist/default/ActiveWorkspace.d.ts +43 -0
  6. package/dist/default/ActiveWorkspace.d.ts.map +1 -0
  7. package/dist/default/ActiveWorkspace.js +33 -0
  8. package/dist/default/ActiveWorkspace.js.map +1 -0
  9. package/dist/default/AuditTrailPane.d.ts +12 -0
  10. package/dist/default/AuditTrailPane.d.ts.map +1 -0
  11. package/dist/default/AuditTrailPane.js +154 -0
  12. package/dist/default/AuditTrailPane.js.map +1 -0
  13. package/dist/default/InvitationsPane.d.ts +19 -0
  14. package/dist/default/InvitationsPane.d.ts.map +1 -0
  15. package/dist/default/InvitationsPane.js +217 -0
  16. package/dist/default/InvitationsPane.js.map +1 -0
  17. package/dist/default/InviteAcceptPage.d.ts +7 -0
  18. package/dist/default/InviteAcceptPage.d.ts.map +1 -1
  19. package/dist/default/InviteAcceptPage.js +74 -38
  20. package/dist/default/InviteAcceptPage.js.map +1 -1
  21. package/dist/default/MembersManager.d.ts +12 -4
  22. package/dist/default/MembersManager.d.ts.map +1 -1
  23. package/dist/default/MembersManager.js +320 -84
  24. package/dist/default/MembersManager.js.map +1 -1
  25. package/dist/default/RoleSelectField.d.ts +64 -0
  26. package/dist/default/RoleSelectField.d.ts.map +1 -0
  27. package/dist/default/RoleSelectField.js +78 -0
  28. package/dist/default/RoleSelectField.js.map +1 -0
  29. package/dist/default/WorkspaceSettings.d.ts +7 -1
  30. package/dist/default/WorkspaceSettings.d.ts.map +1 -1
  31. package/dist/default/WorkspaceSettings.js +203 -45
  32. package/dist/default/WorkspaceSettings.js.map +1 -1
  33. package/dist/default/WorkspacesPage.d.ts +13 -0
  34. package/dist/default/WorkspacesPage.d.ts.map +1 -0
  35. package/dist/default/WorkspacesPage.js +109 -0
  36. package/dist/default/WorkspacesPage.js.map +1 -0
  37. package/dist/default/index.d.ts +28 -7
  38. package/dist/default/index.d.ts.map +1 -1
  39. package/dist/default/index.js +24 -7
  40. package/dist/default/index.js.map +1 -1
  41. package/dist/default/parts.d.ts +104 -0
  42. package/dist/default/parts.d.ts.map +1 -0
  43. package/dist/default/parts.js +143 -0
  44. package/dist/default/parts.js.map +1 -0
  45. package/dist/headless/Members.d.ts +59 -14
  46. package/dist/headless/Members.d.ts.map +1 -1
  47. package/dist/headless/Members.js +35 -10
  48. package/dist/headless/Members.js.map +1 -1
  49. package/dist/headless/RoleSelect.d.ts +9 -3
  50. package/dist/headless/RoleSelect.d.ts.map +1 -1
  51. package/dist/headless/RoleSelect.js +3 -2
  52. package/dist/headless/RoleSelect.js.map +1 -1
  53. package/dist/i18n/es.d.ts +11 -12
  54. package/dist/i18n/es.d.ts.map +1 -1
  55. package/dist/i18n/es.js +267 -14
  56. package/dist/i18n/es.js.map +1 -1
  57. package/dist/i18n/generated/errors.es.gen.d.ts.map +1 -1
  58. package/dist/i18n/generated/errors.es.gen.js +5 -0
  59. package/dist/i18n/generated/errors.es.gen.js.map +1 -1
  60. package/dist/i18n/generated/errors.gen.d.ts +30 -0
  61. package/dist/i18n/generated/errors.gen.d.ts.map +1 -1
  62. package/dist/i18n/generated/errors.gen.js +15 -0
  63. package/dist/i18n/generated/errors.gen.js.map +1 -1
  64. package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -1
  65. package/dist/i18n/generated/errors.ru.gen.js +5 -0
  66. package/dist/i18n/generated/errors.ru.gen.js.map +1 -1
  67. package/dist/i18n/keys.d.ts +209 -1
  68. package/dist/i18n/keys.d.ts.map +1 -1
  69. package/dist/i18n/keys.js +410 -4
  70. package/dist/i18n/keys.js.map +1 -1
  71. package/dist/i18n/ru.d.ts +7 -2
  72. package/dist/i18n/ru.d.ts.map +1 -1
  73. package/dist/i18n/ru.js +209 -4
  74. package/dist/i18n/ru.js.map +1 -1
  75. package/dist/index.d.ts +1 -1
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +1 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/model/format.d.ts +56 -0
  80. package/dist/model/format.d.ts.map +1 -0
  81. package/dist/model/format.js +125 -0
  82. package/dist/model/format.js.map +1 -0
  83. package/dist/model/selection.d.ts +15 -0
  84. package/dist/model/selection.d.ts.map +1 -1
  85. package/dist/model/selection.js +18 -1
  86. package/dist/model/selection.js.map +1 -1
  87. package/dist/nav/manifest.d.ts +45 -0
  88. package/dist/nav/manifest.d.ts.map +1 -0
  89. package/dist/nav/manifest.js +77 -0
  90. package/dist/nav/manifest.js.map +1 -0
  91. package/llms.txt +11 -10
  92. package/manifest.json +281 -69
  93. package/package.json +18 -12
  94. package/src/analytics/generated/events.json +1 -1
  95. package/src/api/generated/schema.ts +187 -60
  96. package/src/default/ActiveWorkspace.tsx +97 -0
  97. package/src/default/AuditTrailPane.tsx +309 -0
  98. package/src/default/InvitationsPane.tsx +501 -0
  99. package/src/default/InviteAcceptPage.tsx +187 -90
  100. package/src/default/MembersManager.tsx +832 -222
  101. package/src/default/RoleSelectField.tsx +187 -0
  102. package/src/default/WorkspaceSettings.tsx +540 -125
  103. package/src/default/WorkspacesPage.tsx +394 -0
  104. package/src/default/index.ts +28 -7
  105. package/src/default/parts.tsx +315 -0
  106. package/src/headless/Members.tsx +84 -16
  107. package/src/headless/RoleSelect.tsx +12 -5
  108. package/src/i18n/es.ts +326 -14
  109. package/src/i18n/generated/errors.es.gen.ts +5 -0
  110. package/src/i18n/generated/errors.gen.ts +15 -0
  111. package/src/i18n/generated/errors.json +37 -0
  112. package/src/i18n/generated/errors.ru.gen.ts +5 -0
  113. package/src/i18n/keys.ts +462 -5
  114. package/src/i18n/ru.ts +259 -5
  115. package/src/index.ts +1 -0
  116. package/src/model/format.ts +158 -0
  117. package/src/model/selection.tsx +19 -1
  118. package/src/nav/manifest.ts +120 -0
  119. package/dist/default/ErrorAlert.d.ts +0 -8
  120. package/dist/default/ErrorAlert.d.ts.map +0 -1
  121. package/dist/default/ErrorAlert.js +0 -30
  122. package/dist/default/ErrorAlert.js.map +0 -1
  123. package/src/default/ErrorAlert.tsx +0 -47
package/src/i18n/es.ts CHANGED
@@ -14,32 +14,344 @@ export { workspacesErrorBundleEs } from "./generated/errors.es.gen.js";
14
14
  * COVERAGE IS DECLARED, NOT DISCOVERED. This bundle carries the GENERATED
15
15
  * backend error texts (from stapel-workspaces's `translations/errors.es.json`
16
16
  * catalog — `pnpm gen:errors`), complete over the error registry by
17
- * construction: the generator fails on a gap and the Record type fails
18
- * compilation on drift. The pair-owned UI keys (`WORKSPACES_I18N_KEYS`) are NOT
19
- * translated to Spanish yet and deliberately fall back to their English text
20
- * through the en floor that {@link registerWorkspacesI18nEs} registers underneath.
21
- * So a Spanish-speaking user reads Spanish error messages and English UI copy —
22
- * never a raw key. That state is asserted in `test/i18nEs.test.ts`; whoever
23
- * adds hand-written Spanish UI copy flips those assertions deliberately.
17
+ * construction, AND hand-written Spanish for every pair-owned UI key. It used
18
+ * to carry exactly one UI string and fall back to English for the other 72,
19
+ * which meant a Spanish reader got Spanish error messages inside an English
20
+ * screen; the 2026-08-24 wave closed that. `registerWorkspacesI18nEs` still
21
+ * registers the en floor underneath, so a key added tomorrow degrades to
22
+ * English rather than to a raw key.
24
23
  *
25
- * Adding that copy later is additive and host-invisible: this const and the
26
- * `./i18n/es` subpath keep their names and shapes when it lands.
24
+ * PLURALS. Spanish takes the same two CLDR categories as English
25
+ * (`one`/`other`), so a `*.count` family ships both plus the flat fallback.
27
26
  */
28
27
  export const workspacesI18nBundleEs: I18nDictionary = {
29
28
  // Backend error codes — generated es texts (coverage by construction).
30
29
  ...workspacesErrorBundleEs,
31
30
 
32
- // No hand-written Spanish UI copy yet — see COVERAGE above. Pair-owned keys
33
- // resolve through the en floor until it exists.
31
+ // workspaces-react UI (hand-written es mirror of the en copy in keys.ts)
32
+ "workspaces.error.unknown": "Algo ha fallado. Inténtelo de nuevo.",
33
+ "workspaces.retry": "Reintentar",
34
+ "workspaces.dialog.close": "Cerrar",
35
+ "workspaces.cancel": "Cancelar",
36
+ "workspaces.pager.prev": "Anterior",
37
+ "workspaces.pager.next": "Siguiente",
38
+ "workspaces.pager.position": "Página {page}",
39
+ "workspaces.list.loading": "Cargando espacios de trabajo…",
40
+ "workspaces.list.empty": "Todavía no hay espacios de trabajo.",
41
+ "workspaces.list.load_failed":
42
+ "No hemos podido cargar sus espacios de trabajo. Es un fallo nuestro, no una señal de que no tenga ninguno.",
43
+ "workspaces.list.create": "Crear espacio de trabajo",
44
+ "workspaces.list.creating": "Creando…",
45
+ "workspaces.members.loading": "Cargando miembros…",
46
+ "workspaces.members.empty": "Todavía no hay miembros.",
47
+ "workspaces.members.load_failed": "No hemos podido cargar la lista de miembros.",
48
+ "workspaces.roles.load_failed":
49
+ "No hemos podido cargar la lista de roles, así que ahora no se pueden cambiar. Esto no significa que el espacio de trabajo no tenga roles.",
50
+ "workspaces.roles.empty":
51
+ "Esta instalación no define ningún rol, así que no hay nada que elegir.",
52
+ "workspaces.members.invite": "Invitar",
53
+ "workspaces.members.inviting": "Enviando invitaciones…",
54
+ "workspaces.members.update_role": "Cambiar el rol",
55
+ "workspaces.members.remove": "Quitar",
56
+ "workspaces.accept.accept": "Aceptar la invitación",
57
+ "workspaces.accept.accepting": "Aceptando…",
58
+ "workspaces.accept.accepted": "Se ha unido al espacio de trabajo.",
59
+ "workspaces.settings.title": "Espacio de trabajo",
60
+ "workspaces.settings.subtitle": "Nombre y ajustes generales.",
61
+ "workspaces.settings.field.name": "Nombre del espacio de trabajo",
62
+ "workspaces.settings.field.slug": "Identificador en la URL",
63
+ "workspaces.settings.field.type": "Tipo",
64
+ "workspaces.settings.type.personal": "Personal",
65
+ "workspaces.settings.type.work": "De trabajo",
66
+ "workspaces.settings.save": "Guardar los cambios",
67
+ "workspaces.settings.blocked.cannot_manage":
68
+ "Su rol no puede cambiar los ajustes de este espacio de trabajo.",
69
+ "workspaces.settings.blocked.name_required": "Escriba un nombre para el espacio de trabajo.",
70
+ "workspaces.settings.blocked.unchanged": "Todavía no ha cambiado nada.",
71
+ "workspaces.settings.saving": "Guardando…",
72
+ "workspaces.settings.danger_zone.title": "Zona de riesgo",
73
+ "workspaces.settings.danger_zone.delete": "Eliminar el espacio de trabajo",
74
+ "workspaces.settings.danger_zone.delete_confirm":
75
+ "¿Eliminar este espacio de trabajo? No se puede deshacer.",
76
+ "workspaces.settings.danger_zone.delete_confirm_body":
77
+ "Todos pierden el acceso de inmediato. Lo que otros servicios guarden de este espacio sigue sus propias reglas de retención.",
78
+ "workspaces.settings.danger_zone.blocked": "Este espacio de trabajo no se puede eliminar.",
79
+ "workspaces.settings.security.title": "Seguridad",
80
+ "workspaces.settings.security.subtitle":
81
+ "Reglas que debe cumplir todo el mundo en este espacio de trabajo.",
82
+ "workspaces.settings.security.require_mfa": "Exigir autenticación en dos pasos",
83
+ "workspaces.settings.security.require_mfa_hint":
84
+ "Los miembros sin un segundo factor confirmado no entran hasta que añadan uno.",
85
+ "workspaces.settings.security.policies_label":
86
+ "Pasos del primer inicio de sesión para las cuentas que cree este espacio",
87
+ "workspaces.settings.security.policies_hint":
88
+ "Son exigencias independientes, no alternativas: una organización puede pedir las dos.",
89
+ "workspaces.settings.security.policy.password_change": "Cambiar la contraseña",
90
+ "workspaces.settings.security.policy.mfa_enroll": "Configurar la autenticación en dos pasos",
91
+ "workspaces.settings.security.save": "Guardar los ajustes de seguridad",
92
+ "workspaces.settings.security.saving": "Guardando…",
93
+ "workspaces.settings.security.blocked.capability":
94
+ "Su rol no puede cambiar los ajustes de seguridad.",
95
+ "workspaces.settings.security.step_up_notice":
96
+ "Le pediremos que confirme su identidad antes de guardar.",
97
+ "workspaces.settings.security.mfa.status_title": "Cumplimiento",
98
+ "workspaces.settings.security.mfa.state_label": "Estado",
99
+ "workspaces.settings.security.mfa.state.pending": "Esperando la primera comprobación",
100
+ "workspaces.settings.security.mfa.state.enforcing": "Comprobando a los miembros",
101
+ "workspaces.settings.security.mfa.state.enforced": "En vigor",
102
+ "workspaces.settings.security.mfa.state.failed": "La última comprobación falló",
103
+ "workspaces.settings.security.mfa.state.other": "Estado desconocido ({state})",
104
+ "workspaces.settings.security.mfa.checked_count": "Miembros comprobados: {count}",
105
+ "workspaces.settings.security.mfa.checked_count.one": "{count} miembro comprobado",
106
+ "workspaces.settings.security.mfa.checked_count.other": "{count} miembros comprobados",
107
+ "workspaces.settings.security.mfa.noncompliant_count":
108
+ "Suspendidos por no tener segundo factor: {count}",
109
+ "workspaces.settings.security.mfa.noncompliant_count.one":
110
+ "{count} miembro suspendido por no tener segundo factor",
111
+ "workspaces.settings.security.mfa.noncompliant_count.other":
112
+ "{count} miembros suspendidos por no tener segundo factor",
113
+ "workspaces.settings.security.mfa.unverified_count": "Sin verificar todavía: {count}",
114
+ "workspaces.settings.security.mfa.unverified_count.one": "{count} miembro sin verificar todavía",
115
+ "workspaces.settings.security.mfa.unverified_count.other":
116
+ "{count} miembros sin verificar todavía",
117
+ "workspaces.settings.security.mfa.attempts_count": "Comprobaciones hechas: {count}",
118
+ "workspaces.settings.security.mfa.attempts_count.one": "{count} comprobación hecha",
119
+ "workspaces.settings.security.mfa.attempts_count.other": "{count} comprobaciones hechas",
120
+ "workspaces.settings.security.mfa.last_attempt": "Última comprobación {date}",
121
+ "workspaces.settings.security.mfa.completed_at": "Cobertura completa desde {date}",
122
+ "workspaces.settings.security.mfa.last_error": "Último error: {error}",
123
+ "workspaces.settings.security.mfa.unverified_hint":
124
+ "Mientras la política esté activa, los miembros sin verificar no entran. Pídales que añadan un segundo factor: la cifra de arriba tiene que llegar a cero.",
125
+ "workspaces.settings.security.mfa.off":
126
+ "En este espacio de trabajo no se exige la autenticación en dos pasos.",
127
+ "workspaces.settings.security.mfa.no_status_yet":
128
+ "Aquí se exige la autenticación en dos pasos. Todavía no se ha hecho ninguna comprobación, así que no hay nadie confirmado.",
129
+ "workspaces.members.title": "Miembros",
130
+ "workspaces.members.subtitle": "Gestione quién tiene acceso a este espacio de trabajo.",
131
+ "workspaces.members.count": "Miembros: {count}",
132
+ "workspaces.members.count.one": "{count} miembro",
133
+ "workspaces.members.count.other": "{count} miembros",
134
+ "workspaces.members.joined": "Se unió el {date}",
135
+ "workspaces.members.last_seen": "Visto {date}",
136
+ "workspaces.members.last_seen_never": "Aún no ha abierto este espacio de trabajo",
137
+ "workspaces.members.search_placeholder": "Buscar por nombre o correo",
138
+ "workspaces.members.role_picker_label": "Rol de {member}",
139
+ "workspaces.members.blocked.read_only":
140
+ "Puede ver quién está aquí, pero no cambiarlo.",
141
+ "workspaces.members.mfa_label": "Dos pasos",
142
+ "workspaces.members.mfa.compliant": "confirmado",
143
+ "workspaces.members.mfa.noncompliant": "sin configurar",
144
+ "workspaces.members.mfa.unknown": "sin comprobar",
145
+ "workspaces.members.suspended": "Suspendido",
146
+ "workspaces.members.suspended.no_mfa":
147
+ "Suspendido hasta que se confirme un segundo factor.",
148
+ "workspaces.members.provisioned": "Creado por un administrador",
149
+ "workspaces.members.invite_dialog.title": "Invitar a miembros",
150
+ "workspaces.members.invite_dialog.emails_label": "Correos",
151
+ "workspaces.members.invite_dialog.emails_placeholder": "Escriba un correo y pulse Intro",
152
+ "workspaces.members.invite_dialog.role_label": "Rol",
153
+ "workspaces.members.invite_dialog.name_label": "Nombre (opcional)",
154
+ "workspaces.members.invite_dialog.name_placeholder": "Se muestra hasta que elijan el suyo",
155
+ "workspaces.members.invite_dialog.submit": "Enviar las invitaciones",
156
+ "workspaces.members.invite_dialog.blocked.no_emails":
157
+ "Escriba al menos una dirección de correo.",
158
+ "workspaces.members.invite_dialog.blocked.bad_email":
159
+ "{email} no es una dirección de correo.",
160
+ "workspaces.members.remove_confirm": "¿Quitar a este miembro?",
161
+ "workspaces.members.remove_confirm_body":
162
+ "{member} pierde el acceso al espacio de trabajo de inmediato. Podrá volver a invitarle más adelante.",
163
+ "workspaces.members.remove.blocked.last_owner":
164
+ "Es el único propietario del espacio de trabajo. Dé antes el rol de propietario a otra persona.",
165
+ "workspaces.members.remove.blocked.self":
166
+ "Este es usted. Pida a otro propietario o administrador que le quite del espacio de trabajo.",
167
+ "workspaces.members.reset_password": "Restablecer la contraseña",
168
+ "workspaces.members.reset_password.blocked.self":
169
+ "Este es usted. Cambie su propia contraseña en los ajustes de su cuenta — esto actúa sobre la cuenta de otra persona.",
170
+ "workspaces.members.reset_password_dialog.title":
171
+ "¿Restablecer la contraseña de {member}?",
172
+ "workspaces.members.reset_password_dialog.body":
173
+ "Su contraseña actual deja de funcionar de inmediato y se le avisa de que ha sido usted. La carta nunca lleva la nueva contraseña.",
174
+ "workspaces.members.reset_password_dialog.step_up":
175
+ "Le pediremos que confirme su identidad antes de continuar.",
176
+ "workspaces.members.reset_password_dialog.submit": "Restablecer la contraseña",
177
+ "workspaces.members.reset_password_dialog.done":
178
+ "{member} ya tiene una contraseña nueva.",
179
+ "workspaces.members.reset_password_dialog.generated": "Contraseña de un solo uso",
180
+ "workspaces.members.reset_password_dialog.generated_hint":
181
+ "Se muestra una vez y nunca más. Entréguela por un canal de confianza; la persona elegirá la suya al iniciar sesión por primera vez.",
182
+ "workspaces.members.reset_password_dialog.not_notified":
183
+ "No había ningún canal para avisarle, así que dígaselo usted.",
184
+ "workspaces.members.rename": "Cambiar el nombre",
185
+ "workspaces.members.rename_dialog.title": "Corregir el nombre",
186
+ "workspaces.members.rename_dialog.label": "Nombre visible",
187
+ "workspaces.members.rename_dialog.placeholder": "Déjelo vacío para quitar el nombre",
188
+ "workspaces.members.rename_dialog.hint":
189
+ "Es el nombre de esa persona en todo el producto, no una nota guardada en este espacio.",
190
+ "workspaces.members.rename_dialog.submit": "Guardar el nombre",
191
+ "workspaces.members.rename_dialog.blocked.unchanged": "Cambie antes el nombre.",
192
+ "workspaces.members.role.owner": "Propietario",
193
+ "workspaces.members.role.admin": "Administrador",
194
+ "workspaces.members.role.member": "Miembro",
195
+ "workspaces.members.role.viewer": "Observador",
196
+
197
+ // Role registry labels (builtin four; clients merge their own roles)
198
+ "workspaces.role.owner": "Propietario",
199
+ "workspaces.role.admin": "Administrador",
200
+ "workspaces.role.member": "Miembro",
201
+ "workspaces.role.viewer": "Observador",
202
+ "workspaces.role.rank_caption": "Rango {rank}",
203
+
204
+ // Workspaces page
205
+ "workspaces.page.title": "Espacios de trabajo",
206
+ "workspaces.page.subtitle": "Todos los espacios de trabajo a los que pertenece.",
207
+ "workspaces.list.count": "Espacios de trabajo: {count}",
208
+ "workspaces.list.count.one": "{count} espacio de trabajo",
209
+ "workspaces.list.count.other": "{count} espacios de trabajo",
210
+ "workspaces.list.member_count": "Miembros: {count}",
211
+ "workspaces.list.member_count.one": "{count} miembro",
212
+ "workspaces.list.member_count.other": "{count} miembros",
213
+ "workspaces.list.owner_line": "Propiedad de {owner}",
214
+ "workspaces.list.your_role": "Su rol",
215
+ "workspaces.list.open": "Abrir",
216
+ "workspaces.list.preferred": "Principal",
217
+ "workspaces.list.set_preferred": "Hacer principal",
218
+ "workspaces.list.clear_preferred": "Quitar como principal",
219
+ "workspaces.list.empty_hint":
220
+ "Cree uno para invitar a otras personas y tener el trabajo en un sitio.",
221
+ "workspaces.list.guest_notice":
222
+ "Está aquí como invitado. Un invitado abre lo que le han enviado, pero no pertenece a ningún espacio de trabajo.",
223
+ "workspaces.list.instance_closed":
224
+ "Pida una invitación a quien administra esta instalación.",
225
+ "workspaces.list.create_dialog.title": "Nuevo espacio de trabajo",
226
+ "workspaces.list.create_dialog.name_label": "Nombre",
227
+ "workspaces.list.create_dialog.name_placeholder": "por ejemplo, Acme Ingeniería",
228
+ "workspaces.list.create_dialog.submit": "Crear espacio de trabajo",
229
+ "workspaces.list.create_dialog.blocked.no_name": "Escriba un nombre.",
230
+ "workspaces.list.blocked.create_policy":
231
+ "En esta instalación solo su propietario puede crear espacios de trabajo.",
232
+
233
+ // Invitation administration
234
+ "workspaces.invitations.title": "Invitaciones",
235
+ "workspaces.invitations.subtitle": "A quién se ha invitado y quién no se ha unido todavía.",
236
+ "workspaces.invitations.count": "Invitaciones: {count}",
237
+ "workspaces.invitations.count.one": "{count} invitación",
238
+ "workspaces.invitations.count.other": "{count} invitaciones",
239
+ "workspaces.invitations.empty": "Nadie está esperando una invitación.",
240
+ "workspaces.invitations.expires_label": "Caduca",
241
+ "workspaces.invitations.sent_label": "Último envío",
242
+ "workspaces.invitations.sent_never": "Todavía no se ha enviado ninguna carta",
243
+ "workspaces.invitations.search_placeholder": "Buscar por correo",
244
+ "workspaces.invitations.filter_label": "Mostrar",
245
+ "workspaces.invitations.filter.pending": "En espera",
246
+ "workspaces.invitations.filter.never_accepted": "Nunca aceptadas",
247
+ "workspaces.invitations.filter.all": "Todas",
248
+ "workspaces.invitations.status.pending": "En espera",
249
+ "workspaces.invitations.status.accepted": "Aceptada",
250
+ "workspaces.invitations.status.declined": "Rechazada",
251
+ "workspaces.invitations.status.revoked": "Retirada",
252
+ "workspaces.invitations.status.expired": "Caducada",
253
+ "workspaces.invitations.resend": "Reenviar",
254
+ "workspaces.invitations.resend_confirm": "¿Enviar la invitación otra vez?",
255
+ "workspaces.invitations.resend_confirm_body":
256
+ "Sale un enlace nuevo hacia {email} y el anterior deja de funcionar.",
257
+ "workspaces.invitations.revoke": "Retirar",
258
+ "workspaces.invitations.revoke_confirm": "¿Retirar esta invitación?",
259
+ "workspaces.invitations.revoke_confirm_body":
260
+ "El enlace hacia {email} deja de funcionar. No se avisa a nadie; podrá invitarle de nuevo más adelante.",
261
+ "workspaces.invitations.rename": "Cambiar el nombre",
262
+ "workspaces.invitations.rename_dialog.title": "Corregir el nombre de la persona invitada",
263
+ "workspaces.invitations.blocked.terminal":
264
+ "Esta invitación ya se aceptó, se rechazó, se retiró o caducó.",
265
+ "workspaces.invitations.blocked.resend_terminal":
266
+ "Solo se puede reenviar una invitación en espera o caducada.",
267
+ "workspaces.invitations.blocked.row_closed":
268
+ "Esta invitación está cerrada: ya no queda nada que hacer con ella.",
269
+ "workspaces.invitations.blocked.row_resend_only":
270
+ "Esta invitación ha caducado. Lo único que queda es volver a enviarla.",
271
+
272
+ // Membership history
273
+ "workspaces.audit.title": "Historial de miembros",
274
+ "workspaces.audit.subtitle":
275
+ "Quién dejó entrar a cada persona, quién la sacó y cuándo.",
276
+ "workspaces.audit.empty": "Aquí todavía no ha pasado nada.",
277
+ "workspaces.audit.filter_label": "Evento",
278
+ "workspaces.audit.filter.all": "Todos los eventos",
279
+ "workspaces.audit.actor_unknown": "El sistema",
280
+ "workspaces.audit.by": "por {actor}",
281
+ "workspaces.audit.role_line": "Rol: {role}",
282
+ "workspaces.audit.action.invitation_created": "Invitación enviada",
283
+ "workspaces.audit.action.invitation_accepted": "Invitación aceptada",
284
+ "workspaces.audit.action.invitation_revoked": "Invitación retirada",
285
+ "workspaces.audit.action.invitation_declined": "Invitación rechazada",
286
+ "workspaces.audit.action.account_created_by_invitation":
287
+ "Cuenta creada a partir de una invitación",
288
+ "workspaces.audit.action.member_joined": "Se unió al espacio de trabajo",
289
+ "workspaces.audit.action.member_provisioned": "Añadido por un administrador",
290
+ "workspaces.audit.action.member_removed": "Retirado del espacio de trabajo",
291
+ "workspaces.audit.action.member_role_changed": "Rol cambiado",
292
+ "workspaces.audit.action.member_suspended": "Acceso suspendido",
293
+ "workspaces.audit.action.member_unsuspended": "Acceso restablecido",
294
+ "workspaces.audit.action.deleted": "Espacio de trabajo eliminado",
295
+
296
+ // Invite accept flow (org-program §B4)
297
+ "workspaces.invite.loading": "Cargando la invitación…",
298
+ "workspaces.invite.acceptTitle": "Unirse a {workspace}",
299
+ "workspaces.invite.roleLine": "Le han invitado como {role}.",
300
+ "workspaces.invite.emailLine": "Invitación para {email}",
301
+ "workspaces.invite.joinCta": "Unirse al espacio de trabajo",
302
+ "workspaces.invite.declineCta": "Rechazar",
303
+ "workspaces.invite.declineConfirm": "¿Rechazar esta invitación?",
304
+ "workspaces.invite.declineConfirmBody":
305
+ "Se avisa al espacio de trabajo de su negativa y el enlace deja de funcionar. Si cambia de idea, pida otra invitación.",
306
+ "workspaces.invite.accepted": "Se ha unido a {workspace}.",
307
+ "workspaces.invite.declined": "Invitación rechazada.",
308
+ "workspaces.invite.unavailable.expired": "Esta invitación ha caducado. Pida una nueva.",
309
+ "workspaces.invite.unavailable.revoked": "Esta invitación fue retirada.",
310
+ "workspaces.invite.unavailable.accepted": "Esta invitación ya se ha usado.",
311
+ "workspaces.invite.unavailable.declined": "Esta invitación fue rechazada.",
312
+ "workspaces.invite.unavailable.next_step":
313
+ "Pida a un administrador de {workspace} que le envíe una invitación nueva.",
314
+ "workspaces.invite.exitCta": "Ir a sus espacios de trabajo",
315
+ "workspaces.invite.wrongAccount": "Esta invitación es para otra cuenta",
316
+ "workspaces.invite.wrongAccountHint":
317
+ "Ha entrado como {email}, pero la invitación se envió a {invited}. Cambie de cuenta para continuar.",
318
+ "workspaces.invite.switchAccountCta": "Cambiar de cuenta",
319
+ "workspaces.invite.loginTitle": "Inicie sesión para aceptar la invitación",
320
+ "workspaces.invite.newUserHint":
321
+ "Crearemos una cuenta verificada para {email}: sin contraseña ni confirmación por correo.",
322
+ "workspaces.invite.createAccountCta": "Crear la cuenta y continuar",
323
+ "workspaces.invite.claiming": "Creando su cuenta…",
324
+ "workspaces.invite.exchanging": "Iniciando su sesión…",
325
+ "workspaces.invite.exchangeFailed": "No hemos podido terminar el inicio de sesión.",
326
+ "workspaces.invite.retryCta": "Inténtelo de nuevo",
327
+ "workspaces.invite.basicDataTitle": "Configure su perfil",
328
+ "workspaces.invite.basicDataContinueCta": "Continuar",
329
+ "workspaces.invite.blocked.busy": "Terminando el paso que ya está en marcha…",
330
+
331
+ // A workspace-scoped screen with no active workspace
332
+ "workspaces.active.choose.title": "Elija un espacio de trabajo",
333
+ "workspaces.active.choose.hint":
334
+ "Esta pantalla gestiona un espacio de trabajo cada vez. Elija uno en la página Espacios de trabajo y vuelva.",
335
+ "workspaces.active.none.title": "Todavía no pertenece a ningún espacio de trabajo",
336
+ "workspaces.active.none.hint":
337
+ "Cree uno o pida a un propietario que le invite — entonces habrá algo que gestionar aquí.",
338
+
339
+ // Nav manifest labels
340
+ "workspaces.nav.workspaces": "Espacios de trabajo",
341
+ "workspaces.nav.settings": "Espacio de trabajo",
342
+ "workspaces.nav.members": "Miembros",
343
+ "workspaces.nav.invitations": "Invitaciones",
344
+ "workspaces.nav.audit": "Historial",
345
+ "workspaces.nav.invite": "Invitación",
34
346
  };
35
347
 
36
348
  /**
37
349
  * Register the pair's `es` locale into a core i18n engine (call once at
38
350
  * startup, after {@link registerWorkspacesI18n}). Layers per the merge-priority
39
351
  * convention (i18n-shipping.md §3): the en floor is registered UNDER the es
40
- * texts inside the `es` locale, so any key the es bundle does not carry —
41
- * today, every pair-owned UI key — degrades to its English text rather than to
42
- * a raw key. A host bundle registered after this call overrides both.
352
+ * texts inside the `es` locale, so any key the es bundle does not carry
353
+ * degrades to its English text rather than to a raw key. A host bundle
354
+ * registered after this call overrides both.
43
355
  */
44
356
  export function registerWorkspacesI18nEs(engine: I18nEngine): void {
45
357
  engine.registerBundle("es", workspacesI18nBundleEn);
@@ -68,17 +68,22 @@ export const workspacesErrorBundleEs: Record<WorkspacesErrorCode, string> = {
68
68
  "error.408.request_timeout": "Tiempo de espera de la solicitud agotado",
69
69
  "error.409.conflict": "El recurso ya existe",
70
70
  "error.409.email_already_registered": "Ya existe una cuenta con este correo electrónico: inicia sesión en su lugar",
71
+ "error.409.workspace_is_instance_default": "Este es el espacio de trabajo predeterminado de la instancia y no se puede eliminar; primero indica otro",
72
+ "error.409.workspace_is_personal": "Un espacio de trabajo personal no se puede eliminar en esta instancia: se vuelve a crear la próxima vez que inicies sesión",
71
73
  "error.410.gone": "El recurso se ha eliminado permanentemente",
72
74
  "error.413.payload_too_large": "El cuerpo de la solicitud es demasiado grande",
73
75
  "error.415.unsupported_media_type": "Tipo de contenido no compatible",
74
76
  "error.422.unprocessable_entity": "Entidad no procesable",
75
77
  "error.423.locked": "El recurso está bloqueado",
76
78
  "error.423.verification_locked": "Demasiados intentos fallidos — verificación bloqueada",
79
+ "error.429.invitation_grant_pending": "El enlace de acceso de esta invitación sigue siendo válido; puedes solicitar otro en {retry_after} segundos",
77
80
  "error.429.invitation_resend_cooldown": "Esta invitación se envió por correo hace poco; puedes volver a enviarla en {retry_after} segundos",
78
81
  "error.429.rate_limit": "Demasiados intentos. Inténtalo de nuevo en {retry_after_minutes} minutos.",
79
82
  "error.429.too_many_requests": "Demasiadas solicitudes. Inténtalo de nuevo más tarde.",
80
83
  "error.500.internal": "Algo salió mal",
81
84
  "error.503.auth_unavailable": "El servicio de autenticación no está disponible; inténtalo de nuevo más tarde",
85
+ "error.503.billing_unavailable": "El servicio de facturación no está disponible; inténtalo de nuevo más tarde",
86
+ "error.503.mandate_unavailable": "No se puede verificar el mandato del espacio de trabajo",
82
87
  "error.503.profiles_not_configured": "Este despliegue no tiene configurado un servicio de perfiles, por lo que aquí no se puede escribir un nombre para mostrar",
83
88
  "error.503.profiles_unavailable": "El servicio de perfiles no está disponible; inténtalo de nuevo más tarde",
84
89
  };
@@ -91,17 +91,22 @@ export const WORKSPACES_ERRORS = {
91
91
  "error.408.request_timeout": { status: 408, params: [], remediation: "retry", en: "Request timeout" },
92
92
  "error.409.conflict": { status: 409, params: [], remediation: "fix_input", en: "Resource already exists" },
93
93
  "error.409.email_already_registered": { status: 409, params: [], remediation: "reauthenticate", en: "An account with this email already exists — log in instead" },
94
+ "error.409.workspace_is_instance_default": { status: 409, params: [], remediation: "fix_input", en: "This is the instance's default workspace and cannot be deleted; point the instance at another workspace first" },
95
+ "error.409.workspace_is_personal": { status: 409, params: [], remediation: "fix_input", en: "A personal workspace cannot be deleted on this instance — it is recreated the next time you sign in" },
94
96
  "error.410.gone": { status: 410, params: [], remediation: "retry", en: "Resource has been permanently removed" },
95
97
  "error.413.payload_too_large": { status: 413, params: [], remediation: "retry", en: "Request body is too large" },
96
98
  "error.415.unsupported_media_type": { status: 415, params: [], remediation: "retry", en: "Unsupported media type" },
97
99
  "error.422.unprocessable_entity": { status: 422, params: [], remediation: "wait_and_retry", en: "Unprocessable entity" },
98
100
  "error.423.locked": { status: 423, params: [], remediation: "wait_and_retry", en: "Resource is locked" },
99
101
  "error.423.verification_locked": { status: 423, params: [], remediation: "wait_and_retry", en: "Too many failed attempts — verification locked" },
102
+ "error.429.invitation_grant_pending": { status: 429, params: ["retry_after"], remediation: "wait_and_retry", en: "A sign-in link for this invitation is still valid; you can request another one in {retry_after} seconds" },
100
103
  "error.429.invitation_resend_cooldown": { status: 429, params: ["retry_after"], remediation: "wait_and_retry", en: "This invitation was emailed recently; you can send it again in {retry_after} seconds" },
101
104
  "error.429.rate_limit": { status: 429, params: ["retry_after_minutes"], remediation: "wait_and_retry", en: "Too many attempts. Try again in {retry_after_minutes} minutes." },
102
105
  "error.429.too_many_requests": { status: 429, params: [], remediation: "wait_and_retry", en: "Too many requests. Please try again later." },
103
106
  "error.500.internal": { status: 500, params: [], remediation: "contact_support", en: "Something went wrong" },
104
107
  "error.503.auth_unavailable": { status: 503, params: [], remediation: "wait_and_retry", en: "The authentication service is unavailable; try again later" },
108
+ "error.503.billing_unavailable": { status: 503, params: [], remediation: "wait_and_retry", en: "The billing service is unavailable; try again later" },
109
+ "error.503.mandate_unavailable": { status: 503, params: [], remediation: "retry", en: "Cannot verify workspace mandate right now" },
105
110
  "error.503.profiles_not_configured": { status: 503, params: [], remediation: "contact_support", en: "This deployment has no profiles service configured, so a display name cannot be written here" },
106
111
  "error.503.profiles_unavailable": { status: 503, params: [], remediation: "wait_and_retry", en: "The profiles service is unavailable; try again later" },
107
112
  } as const;
@@ -166,17 +171,22 @@ export const WORKSPACES_ERROR_CODES: readonly WorkspacesErrorCode[] = [
166
171
  "error.408.request_timeout",
167
172
  "error.409.conflict",
168
173
  "error.409.email_already_registered",
174
+ "error.409.workspace_is_instance_default",
175
+ "error.409.workspace_is_personal",
169
176
  "error.410.gone",
170
177
  "error.413.payload_too_large",
171
178
  "error.415.unsupported_media_type",
172
179
  "error.422.unprocessable_entity",
173
180
  "error.423.locked",
174
181
  "error.423.verification_locked",
182
+ "error.429.invitation_grant_pending",
175
183
  "error.429.invitation_resend_cooldown",
176
184
  "error.429.rate_limit",
177
185
  "error.429.too_many_requests",
178
186
  "error.500.internal",
179
187
  "error.503.auth_unavailable",
188
+ "error.503.billing_unavailable",
189
+ "error.503.mandate_unavailable",
180
190
  "error.503.profiles_not_configured",
181
191
  "error.503.profiles_unavailable",
182
192
  ];
@@ -243,17 +253,22 @@ export const workspacesErrorBundleEn: Record<WorkspacesErrorCode, string> = {
243
253
  "error.408.request_timeout": "Request timeout",
244
254
  "error.409.conflict": "Resource already exists",
245
255
  "error.409.email_already_registered": "An account with this email already exists — log in instead",
256
+ "error.409.workspace_is_instance_default": "This is the instance's default workspace and cannot be deleted; point the instance at another workspace first",
257
+ "error.409.workspace_is_personal": "A personal workspace cannot be deleted on this instance — it is recreated the next time you sign in",
246
258
  "error.410.gone": "Resource has been permanently removed",
247
259
  "error.413.payload_too_large": "Request body is too large",
248
260
  "error.415.unsupported_media_type": "Unsupported media type",
249
261
  "error.422.unprocessable_entity": "Unprocessable entity",
250
262
  "error.423.locked": "Resource is locked",
251
263
  "error.423.verification_locked": "Too many failed attempts — verification locked",
264
+ "error.429.invitation_grant_pending": "A sign-in link for this invitation is still valid; you can request another one in {retry_after} seconds",
252
265
  "error.429.invitation_resend_cooldown": "This invitation was emailed recently; you can send it again in {retry_after} seconds",
253
266
  "error.429.rate_limit": "Too many attempts. Try again in {retry_after_minutes} minutes.",
254
267
  "error.429.too_many_requests": "Too many requests. Please try again later.",
255
268
  "error.500.internal": "Something went wrong",
256
269
  "error.503.auth_unavailable": "The authentication service is unavailable; try again later",
270
+ "error.503.billing_unavailable": "The billing service is unavailable; try again later",
271
+ "error.503.mandate_unavailable": "Cannot verify workspace mandate right now",
257
272
  "error.503.profiles_not_configured": "This deployment has no profiles service configured, so a display name cannot be written here",
258
273
  "error.503.profiles_unavailable": "The profiles service is unavailable; try again later",
259
274
  };
@@ -425,6 +425,20 @@
425
425
  "remediation": "reauthenticate",
426
426
  "en": "An account with this email already exists — log in instead"
427
427
  },
428
+ {
429
+ "code": "error.409.workspace_is_instance_default",
430
+ "status": 409,
431
+ "params": [],
432
+ "remediation": "fix_input",
433
+ "en": "This is the instance's default workspace and cannot be deleted; point the instance at another workspace first"
434
+ },
435
+ {
436
+ "code": "error.409.workspace_is_personal",
437
+ "status": 409,
438
+ "params": [],
439
+ "remediation": "fix_input",
440
+ "en": "A personal workspace cannot be deleted on this instance — it is recreated the next time you sign in"
441
+ },
428
442
  {
429
443
  "code": "error.410.gone",
430
444
  "status": 410,
@@ -467,6 +481,15 @@
467
481
  "remediation": "wait_and_retry",
468
482
  "en": "Too many failed attempts — verification locked"
469
483
  },
484
+ {
485
+ "code": "error.429.invitation_grant_pending",
486
+ "status": 429,
487
+ "params": [
488
+ "retry_after"
489
+ ],
490
+ "remediation": "wait_and_retry",
491
+ "en": "A sign-in link for this invitation is still valid; you can request another one in {retry_after} seconds"
492
+ },
470
493
  {
471
494
  "code": "error.429.invitation_resend_cooldown",
472
495
  "status": 429,
@@ -506,6 +529,20 @@
506
529
  "remediation": "wait_and_retry",
507
530
  "en": "The authentication service is unavailable; try again later"
508
531
  },
532
+ {
533
+ "code": "error.503.billing_unavailable",
534
+ "status": 503,
535
+ "params": [],
536
+ "remediation": "wait_and_retry",
537
+ "en": "The billing service is unavailable; try again later"
538
+ },
539
+ {
540
+ "code": "error.503.mandate_unavailable",
541
+ "status": 503,
542
+ "params": [],
543
+ "remediation": "retry",
544
+ "en": "Cannot verify workspace mandate right now"
545
+ },
509
546
  {
510
547
  "code": "error.503.profiles_not_configured",
511
548
  "status": 503,
@@ -68,17 +68,22 @@ export const workspacesErrorBundleRu: Record<WorkspacesErrorCode, string> = {
68
68
  "error.408.request_timeout": "Время ожидания запроса истекло",
69
69
  "error.409.conflict": "Ресурс уже существует",
70
70
  "error.409.email_already_registered": "Аккаунт с этим email уже существует — войдите в него",
71
+ "error.409.workspace_is_instance_default": "Это рабочее пространство по умолчанию для сервера, его нельзя удалить — сначала укажите другое",
72
+ "error.409.workspace_is_personal": "Личное рабочее пространство нельзя удалить на этом сервере — оно создаётся заново при следующем входе",
71
73
  "error.410.gone": "Ресурс был безвозвратно удалён",
72
74
  "error.413.payload_too_large": "Тело запроса слишком большое",
73
75
  "error.415.unsupported_media_type": "Неподдерживаемый тип данных",
74
76
  "error.422.unprocessable_entity": "Невозможно обработать данные запроса",
75
77
  "error.423.locked": "Ресурс заблокирован",
76
78
  "error.423.verification_locked": "Слишком много неудачных попыток — подтверждение заблокировано",
79
+ "error.429.invitation_grant_pending": "Ссылка для входа по этому приглашению ещё действует; запросить новую можно через {retry_after} с",
77
80
  "error.429.invitation_resend_cooldown": "Это приглашение недавно отправлялось; отправить снова можно через {retry_after} с",
78
81
  "error.429.rate_limit": "Слишком много попыток. Повторите попытку через {retry_after_minutes} мин.",
79
82
  "error.429.too_many_requests": "Слишком много запросов. Пожалуйста, повторите попытку позже.",
80
83
  "error.500.internal": "Что-то пошло не так",
81
84
  "error.503.auth_unavailable": "Сервис аутентификации недоступен; повторите попытку позже",
85
+ "error.503.billing_unavailable": "Сервис биллинга недоступен; повторите попытку позже",
86
+ "error.503.mandate_unavailable": "Не удалось проверить доступ к рабочему пространству",
82
87
  "error.503.profiles_not_configured": "В этой инсталляции не настроен сервис профилей — отображаемое имя здесь записать нельзя",
83
88
  "error.503.profiles_unavailable": "Сервис профилей недоступен; повторите попытку позже",
84
89
  };