@object-ui/i18n 16.0.0 → 17.1.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.
@@ -89,9 +89,14 @@ const en = {
89
89
  package: 'Package',
90
90
  },
91
91
  actions: {
92
+ decisionOutput: {
93
+ help: 'Handed to the flow as a decision output.',
94
+ helpMultiValue: 'Handed to the flow as a decision output. Comma-separate multiple values.',
95
+ },
92
96
  resultDialog: {
93
97
  defaultTitle: 'Save this value now',
94
98
  acknowledge: 'I have saved this',
99
+ copyAll: 'Copy all',
95
100
  },
96
101
  },
97
102
  validation: {
@@ -108,6 +113,8 @@ const en = {
108
113
  type: '{{field}} must be a valid {{type}}',
109
114
  },
110
115
  form: {
116
+ noPermissionToSave: "You don't have permission to save this record.",
117
+ submitFailed: 'Could not save. Please try again.',
111
118
  addItem: 'Add item',
112
119
  removeItem: 'Remove item',
113
120
  fieldRequired: 'This field is required',
@@ -119,11 +126,13 @@ const en = {
119
126
  discardMessage: 'You have unsaved changes. If you close this form now, your edits will be lost.',
120
127
  keepEditing: 'Keep editing',
121
128
  discard: 'Discard',
129
+ conflictTitle: 'Save conflict',
130
+ conflictMessage: 'This record was changed by someone else while you were editing. Overwriting will replace their changes with yours.',
131
+ conflictLatestVersion: 'Their save: {{time}}',
132
+ conflictOverwrite: 'Overwrite',
122
133
  stepOf: 'Step {{current}} of {{total}}',
123
134
  createTitle: 'Create {{object}}',
124
135
  editTitle: 'Edit {{object}}',
125
- createDescription: 'Add a new {{object}} to your database.',
126
- editDescription: 'Update details for {{object}}',
127
136
  saveRecord: 'Save',
128
137
  create: 'Create',
129
138
  update: 'Update',
@@ -135,11 +144,67 @@ const en = {
135
144
  relativeDate: {
136
145
  overdue: 'Overdue {{count}}d',
137
146
  },
147
+ file: {
148
+ dragDropHere: 'Drag & drop files here',
149
+ dropFilesHere: 'Drop files here',
150
+ browseHint: 'or click to browse',
151
+ browseHintCamera: 'or click to browse • use the camera button below',
152
+ takePhoto: 'Take photo',
153
+ takeSelfie: 'Take selfie',
154
+ cameraCapture: 'Camera capture',
155
+ uploading: 'Uploading…',
156
+ uploadingPct: 'Uploading… ({{pct}}%)',
157
+ fileFallback: 'File',
158
+ upload: 'Upload',
159
+ remove: 'Remove {{name}}',
160
+ exceedsMaxSize: '"{{name}}" exceeds max size ({{max}} MB)',
161
+ uploadFailed: 'Failed to upload "{{name}}": {{error}}',
162
+ },
163
+ image: {
164
+ upload: 'Upload image',
165
+ addMore: 'Add more images',
166
+ uploading: 'Uploading…',
167
+ imageAlt: 'Image {{index}}',
168
+ crop: 'Crop image {{index}}',
169
+ remove: 'Remove image {{index}}',
170
+ enlarge: 'Enlarge {{name}}',
171
+ preview: 'Image preview',
172
+ previous: 'Previous image',
173
+ next: 'Next image',
174
+ counter: '{{current}} / {{total}}',
175
+ },
138
176
  richText: {
139
177
  format: 'Format: {{format}}',
140
178
  basicEditorHint: 'Rich text editor (basic)',
141
179
  placeholder: 'Enter text...',
142
180
  },
181
+ objectRef: {
182
+ loading: 'Loading objects…',
183
+ placeholder: 'Select an object',
184
+ search: 'Search objects…',
185
+ empty: 'No objects found',
186
+ },
187
+ recipient: {
188
+ selectTypeFirst: 'Select a recipient type first.',
189
+ loading: 'Loading…',
190
+ search: 'Search…',
191
+ empty: 'No matches',
192
+ select: 'Select a recipient',
193
+ selectUser: 'Select a user',
194
+ selectTeam: 'Select a team',
195
+ selectBusinessUnit: 'Select a business unit',
196
+ selectPosition: 'Select a position',
197
+ selectUnitAndSubordinates: 'Select a business unit',
198
+ },
199
+ filterCondition: {
200
+ selectObjectFirst: 'Select an object first.',
201
+ noCriteria: 'No criteria — this rule shares nothing',
202
+ criteriaRequired: 'Add at least one condition. A rule with no criteria would share every record, so it cannot be saved.',
203
+ invalidJson: 'Invalid JSON — the rule will match no records until fixed.',
204
+ jsonOnly: 'This criteria can only be edited as JSON',
205
+ editAsJson: 'Edit as JSON',
206
+ useVisualBuilder: 'Use visual builder',
207
+ },
143
208
  },
144
209
  table: {
145
210
  rowsPerPage: 'Rows per page',
@@ -214,9 +279,12 @@ const en = {
214
279
  previewDescription: 'Review data before importing.',
215
280
  dragDrop: 'Drag & drop a CSV or Excel file here, or click to browse',
216
281
  browseFiles: 'Browse Files',
282
+ downloadTemplate: 'Download template',
283
+ downloadTemplateHint: 'Get a CSV with the right columns (required fields marked *).',
284
+ templateFileName: '{{object}}-import-template',
217
285
  parsing: 'Parsing…',
218
286
  pasteHint: 'or paste (Ctrl/⌘+V) rows copied from Excel or Google Sheets',
219
- legacyXls: "Legacy .xls files aren't supported — please re-save as .xlsx.",
287
+ legacyXls: 'Legacy .xls files aren\'t supported — please re-save as .xlsx.',
220
288
  unsupportedFile: 'Unsupported file type. Use CSV, TSV, or Excel (.xlsx).',
221
289
  parseFailed: 'Could not read this file. Please check the format and try again.',
222
290
  fileNeedsHeader: 'File must contain a header row and at least one data row.',
@@ -237,6 +305,13 @@ const en = {
237
305
  csvColumn: 'Column',
238
306
  mapsTo: 'Maps To',
239
307
  typeMismatch: 'Looks like {{type}}',
308
+ autoMatched: 'Auto-matched',
309
+ autoMatchedSummary: 'Auto-matched {{count}} column(s) — review and adjust below.',
310
+ confidence: {
311
+ high: 'High confidence',
312
+ medium: 'Medium confidence',
313
+ low: 'Low confidence',
314
+ },
240
315
  type: {
241
316
  number: 'Number',
242
317
  boolean: 'Boolean',
@@ -254,25 +329,96 @@ const en = {
254
329
  clickToFix: '— click a highlighted cell to fix it inline.',
255
330
  showingRows: 'Showing {{shown}} of {{total}} rows',
256
331
  importing: 'Importing… {{progress}}%',
332
+ asyncQueued: 'Queued — preparing to import…',
333
+ asyncProcessing: 'Importing {{processed}} of {{total}} rows… {{progress}}%',
334
+ asyncLargeHint: 'This file is large, so it will be imported in the background.',
335
+ largeSampleNotice: 'Previewing the first {{shown}} of {{total}} rows.',
336
+ cancelImport: 'Cancel import',
337
+ importCancelled: 'Import cancelled',
338
+ resultsTruncated: 'Showing the first {{count}} row results (of {{total}}).',
257
339
  importComplete: 'Import Complete',
258
340
  imported: '{{count}} imported',
341
+ createdCount: '{{count}} created',
342
+ updatedCount: '{{count}} updated',
259
343
  skippedCount: '{{count}} skipped',
260
344
  moreErrors: '…and {{count}} more errors',
345
+ downloadFailed: 'Download failed rows',
346
+ options: 'Import options',
347
+ writeMode: 'When a row matches an existing record',
348
+ writeModeOpt: {
349
+ insert: 'Always create new',
350
+ update: 'Update existing (skip if no match)',
351
+ upsert: 'Update if matched, else create',
352
+ },
353
+ matchFields: 'Match on',
354
+ matchFieldsPlaceholder: 'Choose match field(s)…',
355
+ matchFieldsHint: 'Rows are matched to existing records by these field(s).',
356
+ needMatchFields: 'Select at least one field to match on.',
357
+ matchOnlyField: '(match only)',
358
+ optCreateOptions: 'Keep unknown option values',
359
+ optRunAutomations: 'Run automations & triggers',
360
+ optTreatHistorical: 'Import as historical data',
361
+ optTreatHistoricalHint: '(import completed records as-is — skip state-machine checks and keep their original timestamps & author instead of stamping now)',
362
+ optSkipBlankKey: 'Skip rows with a blank match value',
363
+ optBackground: 'Import in the background',
364
+ optBackgroundHint: '(runs as an undoable job)',
365
+ validate: 'Validate data',
366
+ validating: 'Validating…',
367
+ validateHint: 'Check every row against the server before importing.',
368
+ validatePassed: 'All {{ok}} rows are valid.',
369
+ validateFailed: '{{ok}} valid, {{errors}} with errors.',
370
+ errorRowPrefix: 'Row {{row}}: ',
371
+ referenceNotFound: 'No matching record for "{{value}}"',
372
+ referenceAmbiguous: '"{{value}}" matches more than one record — use a unique value or the record id',
373
+ invalidBoolean: '"{{value}}" is not a valid true/false value',
374
+ invalidNumber: '"{{value}}" is not a valid number',
375
+ invalidDate: '"{{value}}" is not a valid date',
376
+ invalidOption: '"{{value}}" is not one of the allowed options',
377
+ requiredValue: 'This field is required',
378
+ matchAmbiguous: 'Matches more than one existing record — use a unique value or the record id',
379
+ history: 'History',
380
+ historyBack: 'Back to import',
381
+ historyDescription: 'Recent imports for this object.',
382
+ historyHint: 'Background import jobs, newest first.',
383
+ historyRefresh: 'Refresh',
384
+ historyLoading: 'Loading…',
385
+ historyEmpty: 'No imports yet.',
386
+ historyUnsupported: 'Import history isn’t available for this data source.',
387
+ historyColStatus: 'Status',
388
+ historyColRows: 'Rows',
389
+ historyColResult: 'Result',
390
+ historyColTime: 'When',
391
+ errorCount: '{{count}} errors',
392
+ undoImport: 'Undo import',
393
+ undoing: 'Undoing…',
394
+ undoConfirm: 'Undo this import? Records it created will be deleted and records it updated will be restored to their previous values.',
395
+ reverted: 'Undone',
396
+ jobStatus: {
397
+ pending: 'Pending',
398
+ running: 'Running',
399
+ succeeded: 'Succeeded',
400
+ failed: 'Failed',
401
+ cancelled: 'Cancelled',
402
+ },
261
403
  cancel: 'Cancel',
262
404
  back: 'Back',
263
405
  next: 'Next',
264
406
  close: 'Close',
265
407
  importNRows: 'Import {{count}} Rows',
266
408
  importingProgress: 'Importing…',
267
- requiredMark: '*',
268
409
  required: 'Required',
269
410
  invalidType: 'Invalid {{type}}',
270
- legacyReferenceBlocked: 'Import blocked: {{fields}} are relation fields that need the server import route to resolve names into record IDs, and this connection doesn\u2019t support it. Importing them as plain text would corrupt the data. Upgrade the backend/client, or unmap these columns and import them separately.',
411
+ legacyReferenceBlocked: 'Import blocked: {{fields}} are relation fields that need the server import route to resolve names into record IDs, and this connection doesn’t support it. Importing them as plain text would corrupt the data. Upgrade the backend/client, or unmap these columns and import them separately.',
412
+ missingRequiredHint: 'Can’t continue — required field(s) not mapped: {{fields}}. Add a matching column to your file, or go back and upload one that includes it.',
413
+ legacyFallbackNotice: 'Imported via a compatibility fallback: this connection doesn’t support the server import route, so values were saved as text without server-side type coercion. Upgrade the backend/client for full import support (type coercion and relation lookups).',
414
+ notAllowed: 'This object is not open for import.',
415
+ requiredMark: '*',
271
416
  },
272
417
  bulk: {
273
418
  confirmDefault: 'This will apply to {{count}} record(s).',
274
419
  overLimit: 'Selection ({{count}}) exceeds the action limit ({{limit}}). Reduce the selection to proceed.',
275
420
  affectedRecords: 'Affected records ({{count}}):',
421
+ skippedIneligible: '{{count}} selected record(s) are not eligible for this action and will be skipped.',
276
422
  rowFallback: 'Row {{index}}',
277
423
  andMore: '\u2026 and {{count}} more',
278
424
  processed: '{{count}} / {{total}} processed',
@@ -317,6 +463,8 @@ const en = {
317
463
  filterRecords: 'Filter Records',
318
464
  sort: 'Sort',
319
465
  sortRecords: 'Sort Records',
466
+ sortByIdSuffix: '(by ID)',
467
+ sortRelationalHint: 'Columns that link to another record are not listed: they can only be sorted by the stored ID, not by the name shown in the cell. To sort by that name, add a formula field holding it.',
320
468
  group: 'Group',
321
469
  groupBy: 'Group By',
322
470
  export: 'Export',
@@ -335,6 +483,12 @@ const en = {
335
483
  noMatchesMessage: 'No records match your current filters or search. Try adjusting or clearing them.',
336
484
  loadErrorTitle: 'Couldn\u2019t load records',
337
485
  loadErrorMessage: 'Something went wrong while loading this data. Check your connection and try again.',
486
+ loadErrorForbiddenTitle: 'You don\u2019t have access',
487
+ loadErrorForbiddenMessage: 'You don\u2019t have permission to view these records. Contact your administrator if you think you should have access.',
488
+ loadErrorUnauthorizedTitle: 'Sign in required',
489
+ loadErrorUnauthorizedMessage: 'Your session has expired or you are signed out. Sign in again to view these records.',
490
+ loadErrorRejectedTitle: 'This view’s query was rejected',
491
+ loadErrorRejectedMessage: 'The server could not process this view’s filter or query options. Clearing the filters usually fixes it; if the view is saved this way, an administrator needs to correct it.',
338
492
  retry: 'Retry',
339
493
  managedBy: {
340
494
  system: {
@@ -386,6 +540,11 @@ const en = {
386
540
  title: 'Managed by the platform',
387
541
  body: 'Rows here are created automatically when actions run on the source record. The list below is a read-only monitoring surface — row-level actions (Approve, Recall, Resend, …) live on each row.',
388
542
  },
543
+ systemWritable: {
544
+ short: 'Platform schema',
545
+ title: 'Platform-defined, admin-writable',
546
+ body: "This object's schema is defined by the platform, but its rows are yours to create and edit here. Who may write is governed by delegated administration and record-level security, not by this badge.",
547
+ },
389
548
  appendOnly: {
390
549
  short: 'Read-only · Audit log',
391
550
  title: 'Read-only historical record',
@@ -405,6 +564,7 @@ const en = {
405
564
  deleteColumn: 'Delete column',
406
565
  noCards: 'No cards',
407
566
  cardTitlePlaceholder: 'Enter card title...',
567
+ uncategorized: 'Uncategorized',
408
568
  },
409
569
  timeline: {
410
570
  bucket: {
@@ -473,14 +633,6 @@ const en = {
473
633
  removeDependency: 'Remove dependency',
474
634
  noCandidates: 'No available tasks',
475
635
  searchTasks: 'Search tasks…',
476
- qrcode: 'Mobile QR code',
477
- },
478
- qr: {
479
- title: 'Open on mobile',
480
- hint: 'Scan with a phone to open the details',
481
- copy: 'Copy link',
482
- copied: 'Copied',
483
- close: 'Close',
484
636
  },
485
637
  delete: {
486
638
  title: 'Delete this task?',
@@ -504,6 +656,14 @@ const en = {
504
656
  confirm: 'Auto-reschedule',
505
657
  cancel: 'Keep as is',
506
658
  },
659
+ autoScheduleDlg: {
660
+ title: 'Auto-schedule',
661
+ body: 'Shift {count} task(s) later to satisfy dependency links?',
662
+ skipped: '{count} locked task(s) also violate links and were skipped.',
663
+ confirm: 'Apply',
664
+ cancel: 'Cancel',
665
+ none: 'All dependencies satisfied — nothing to reschedule.',
666
+ },
507
667
  resource: {
508
668
  header: 'Resource',
509
669
  peak: 'Peak',
@@ -556,9 +716,15 @@ const en = {
556
716
  editInlineHint: 'Double-click to edit',
557
717
  lockedByApproval: 'Locked for approval',
558
718
  lockedTooltip: 'This record has a pending approval request; editing is locked',
719
+ writeStrippedTitle: 'Some fields were not saved',
720
+ writeStrippedReadonly: 'Read-only, so it was not saved: {{fields}}',
721
+ writeStrippedByState: "Not editable in this record's current state, so it was not saved: {{fields}}",
722
+ approvalPendingEditable: 'In approval · editable',
723
+ approvalPendingTooltip: 'This record has a pending approval request; this step still allows editing',
559
724
  cancelApproval: 'Recall approval',
560
725
  cancelApprovalInFlight: 'Recalling…',
561
726
  cancelApprovalTooltip: 'Recall the pending approval request to unlock this record',
727
+ cancelApprovalTooltipUnlocked: 'Recall the pending approval request',
562
728
  cancelApprovalFailed: 'Failed to recall approval',
563
729
  cancelApprovalUnavailable: 'Recalling approvals is not supported on this data source',
564
730
  linkCopied: 'Link copied to clipboard',
@@ -645,6 +811,18 @@ const en = {
645
811
  attachmentCount: '{{count}} attachment',
646
812
  attachmentCountPlural: '{{count}} attachments',
647
813
  removeAttachment: 'Remove attachment',
814
+ // Record Attachments panel (enable.files, objectstack#4358)
815
+ attachments: 'Attachments',
816
+ uploadAttachment: 'Upload',
817
+ loadingAttachments: 'Loading attachments…',
818
+ noAttachments: 'No attachments yet. Upload a file to get started.',
819
+ downloadAttachment: 'Download',
820
+ deleteAttachment: 'Delete attachment',
821
+ attachmentDeleteDenied: 'Only the uploader or someone who can edit this record may delete this attachment.',
822
+ attachmentParentAccessDenied: "You don't have access to attach files to this record.",
823
+ attachmentDownloadDenied: "You don't have access to download this attachment.",
824
+ attachmentAuthRequired: 'Please sign in to download this attachment.',
825
+ attachmentPermissionDenied: "You don't have permission to do that.",
648
826
  // Diff
649
827
  unifiedDiff: 'Unified diff',
650
828
  sideBySideDiff: 'Side-by-side diff',
@@ -1068,6 +1246,7 @@ const en = {
1068
1246
  navTypeGroup: 'Group',
1069
1247
  navTypeSeparator: 'Separator',
1070
1248
  navTypeAction: 'Action',
1249
+ navTypeComponent: 'Component',
1071
1250
  navEditIcon: 'Edit icon',
1072
1251
  navToggleVisible: 'Toggle visibility',
1073
1252
  navHidden: 'Hidden',
@@ -1184,6 +1363,24 @@ const en = {
1184
1363
  dragToReorder: 'Drag to reorder',
1185
1364
  favorites: 'Favorites',
1186
1365
  },
1366
+ settingsHub: {
1367
+ title: 'Settings',
1368
+ subtitle: 'Configure your workspace, integrations, and feature flags.',
1369
+ loadError: 'Failed to load settings',
1370
+ empty: 'No settings registered. Plugins can register settings manifests via the SettingsService.',
1371
+ settingsCount: '{{n}} settings',
1372
+ beta: 'Beta',
1373
+ // Section headers, keyed by the manifest `category` value. Unknown
1374
+ // (plugin-authored) categories fall back to the literal category string.
1375
+ categories: {
1376
+ Workspace: 'Workspace',
1377
+ Communication: 'Communication',
1378
+ Security: 'Security',
1379
+ Infrastructure: 'Infrastructure',
1380
+ Beta: 'Beta',
1381
+ Other: 'Other',
1382
+ },
1383
+ },
1187
1384
  loadingSteps: {
1188
1385
  connecting: 'Connecting to data source',
1189
1386
  loadingConfig: 'Loading configuration',
@@ -1342,6 +1539,26 @@ const en = {
1342
1539
  planApproveMessage: 'Looks good — build it as proposed.',
1343
1540
  planApproveDefaultsMessage: 'Build it with your best assumptions; use sensible defaults for the open questions.',
1344
1541
  planAnswerMessage: 'For "{{question}}", go with: {{option}}.',
1542
+ changesTitle: 'Confirm changes',
1543
+ changesConfirmed: 'Confirmed',
1544
+ changesConfirm: 'Confirm',
1545
+ changesConfirmHint: 'Reply to confirm or adjust this change.',
1546
+ // Wording is load-bearing: this is SENT to the agent and must satisfy the
1547
+ // cloud confirm gate's English clause `apply (this|the) change`
1548
+ // (service-ai-studio confirm-gate.ts APPROVAL_RE). "apply what you just
1549
+ // proposed" did NOT match, so the button was inert. Singular "the change"
1550
+ // so it still matches if the gate ever adds a word boundary.
1551
+ changesConfirmMessage: 'Confirm — apply the change you just proposed.',
1552
+ changeVerb: {
1553
+ createObject: 'Create object',
1554
+ addField: 'Add field',
1555
+ modifyField: 'Modify field',
1556
+ deleteField: 'Delete field',
1557
+ createMetadata: 'Create',
1558
+ updateMetadata: 'Modify',
1559
+ createSeed: 'Generate sample data',
1560
+ createPackage: 'Create app package',
1561
+ },
1345
1562
  justNow: 'just now',
1346
1563
  minutesAgo: '{{count}}m ago',
1347
1564
  hoursAgo: '{{count}}h ago',
@@ -1404,14 +1621,16 @@ const en = {
1404
1621
  identityImport: {
1405
1622
  policyTitle: 'Sign-in setup for imported users',
1406
1623
  policy: {
1407
- none: 'No password (recommended)',
1624
+ auto: 'Automatic (recommended)',
1408
1625
  invite: 'Send invitations',
1409
1626
  temporary: 'Temporary passwords',
1627
+ none: 'No password (identity only)',
1410
1628
  },
1411
1629
  policyHint: {
1630
+ auto: 'Reachable users get an invitation (email or SMS); anyone we can\'t reach gets a one-time password, shown ONCE on the result screen. Works with or without an email/SMS service.',
1631
+ invite: 'Every created user gets a set-your-password email (or an invitation SMS for phone-only rows). Requires a configured email/SMS service — unreachable rows fail.',
1632
+ temporary: 'For deployments without email/SMS: every created user gets a one-time password, shown ONCE on the result screen. First sign-in forces a change.',
1412
1633
  none: 'Users first sign in with a phone OTP, magic link, or password-reset link, then set their own password.',
1413
- invite: 'Each created user gets a set-your-password email (or an invitation SMS for phone-only rows). Requires a configured email/SMS service.',
1414
- temporary: 'For deployments without email/SMS: each created user gets a one-time password, shown ONCE on the result screen. First sign-in forces a change.',
1415
1634
  },
1416
1635
  passwordsNote: 'Temporary passwords — shown once, never stored. Save them now; each user must change theirs at first sign-in.',
1417
1636
  passwordsMore: 'More entries omitted — use the download.',
@@ -1514,6 +1733,10 @@ const en = {
1514
1733
  parentField: 'Parent field',
1515
1734
  parentFieldHelp: 'The field pointing to the parent record (same object) that defines the hierarchy. Only self-referencing fields qualify.',
1516
1735
  newView: 'New View',
1736
+ viewName: 'Name',
1737
+ viewNameHelp: 'Machine key (snake_case). Auto-filled from the title — edit if you like.',
1738
+ viewNameRequired: 'Enter a key (lowercase letters, numbers, underscore). Not auto-filled for non-Latin titles.',
1739
+ viewNameInvalid: 'Use lowercase letters, numbers and underscores; start with a letter or underscore.',
1517
1740
  typeOptions: 'Type Options',
1518
1741
  groupByField: 'Group by field',
1519
1742
  groupByFieldHelp: 'The kanban groups records into columns by this field\'s values.',
@@ -1774,6 +1997,59 @@ const en = {
1774
1997
  shell: {
1775
1998
  tenantHostHint: 'You are signing in to this workspace',
1776
1999
  },
2000
+ // These were previously supplied only as inline `defaultValue:` args at the
2001
+ // SetPasswordPage call sites, so `zh` was the only pack that could carry a
2002
+ // translation. Owning them here makes the page translatable everywhere.
2003
+ setPassword: {
2004
+ title: 'Set a recovery password',
2005
+ description: 'You signed in via single sign-on. Set a local password so you can still sign in to this environment directly if SSO ever becomes unavailable.',
2006
+ email: 'Email',
2007
+ newPassword: 'New password',
2008
+ confirmPassword: 'Confirm password',
2009
+ submit: 'Set password',
2010
+ submitting: 'Saving…',
2011
+ success: 'Local password set',
2012
+ failed: 'Could not set password',
2013
+ passwordsMismatch: 'Passwords do not match',
2014
+ noSession: 'Your session has expired.',
2015
+ backToSignIn: 'Sign in again',
2016
+ },
2017
+ layout: {
2018
+ headline: 'Build powerful business applications, faster.',
2019
+ subhead: 'The universal platform for enterprise data management, workflows, and analytics.',
2020
+ },
2021
+ // ADR-0069 full-screen remediation gate. A user hitting this cannot reach
2022
+ // the rest of the app until they finish, so it must read in their language.
2023
+ remediation: {
2024
+ signOut: 'Sign out instead',
2025
+ password: {
2026
+ title: 'Your password has expired',
2027
+ fallbackMessage: 'Please set a new password to continue.',
2028
+ current: 'Current password',
2029
+ next: 'New password',
2030
+ confirm: 'Confirm new password',
2031
+ submit: 'Change password & continue',
2032
+ submitting: 'Updating…',
2033
+ mismatch: 'New passwords do not match.',
2034
+ failed: 'Could not change password.',
2035
+ },
2036
+ mfa: {
2037
+ title: 'Set up two-factor authentication',
2038
+ fallbackMessage: 'Your organization requires an authenticator app to continue.',
2039
+ confirmPassword: 'Confirm your password',
2040
+ continue: 'Continue',
2041
+ preparing: 'Preparing…',
2042
+ enrollFailed: 'Could not start enrollment.',
2043
+ scanTitle: 'Scan with your authenticator',
2044
+ scanBody: 'Scan this QR code with Google Authenticator, 1Password, Authy, etc., then enter the 6-digit code.',
2045
+ backupTitle: 'Save your backup codes',
2046
+ backupBody: 'Store these somewhere safe — each can be used once if you lose your device.',
2047
+ codeLabel: '6-digit code',
2048
+ verify: 'Verify & continue',
2049
+ verifying: 'Verifying…',
2050
+ invalidCode: 'Invalid code. Try again.',
2051
+ },
2052
+ },
1777
2053
  },
1778
2054
  profile: {
1779
2055
  title: 'Profile',
@@ -1869,6 +2145,7 @@ const en = {
1869
2145
  offline: 'Offline',
1870
2146
  usersOnline: 'Users currently online',
1871
2147
  switchView: 'Switch view',
2148
+ switchObject: 'Switch Object',
1872
2149
  connection: {
1873
2150
  connected: 'Connected',
1874
2151
  connecting: 'Connecting...',
@@ -1888,6 +2165,14 @@ const en = {
1888
2165
  subtitle: 'Your workspace dashboard',
1889
2166
  nav: 'Home',
1890
2167
  allApps: 'All Applications',
2168
+ yourApps: 'Your apps',
2169
+ showMoreApps: 'More',
2170
+ showLess: 'Show less',
2171
+ continueEmpty: 'Items you open will show up here.',
2172
+ actionCenter: {
2173
+ title: 'Needs your attention',
2174
+ empty: "You're all caught up",
2175
+ },
1891
2176
  greetingMorning: 'Good morning',
1892
2177
  greetingAfternoon: 'Good afternoon',
1893
2178
  greetingEvening: 'Good evening',
@@ -2107,10 +2392,11 @@ const en = {
2107
2392
  description: 'Please provide the required information to continue.',
2108
2393
  selectPlaceholder: 'Select {{label}}',
2109
2394
  requiredError: '{{label}} is required',
2110
- lookupPlaceholder: 'Paste the {{label}} record id (UUID)',
2111
- lookupHelpText: 'Enter the record id of the referenced object. A picker is coming soon.',
2395
+ lookupPlaceholder: 'Record id for {{label}}',
2396
+ lookupHelpText: 'No reference object is configured for this parameter, so the record picker is unavailable. Enter a record id, or ask an administrator to fix the action parameter.',
2112
2397
  cancel: 'Cancel',
2113
2398
  confirm: 'Confirm',
2399
+ uploading: 'Uploading…',
2114
2400
  defaultActionTitle: 'Action',
2115
2401
  ok: 'OK',
2116
2402
  },
@@ -2195,6 +2481,10 @@ const en = {
2195
2481
  filterAll: 'All',
2196
2482
  markAllRead: 'Mark all read',
2197
2483
  viewAll: 'View all notifications',
2484
+ groupCount: '{{count}} notifications',
2485
+ groupUnread: '{{count}} unread',
2486
+ groupMarkRead: 'Mark read',
2487
+ groupMarkReadTitle: 'Mark all of this type read',
2198
2488
  approvalsPending: '{{count}} pending approvals',
2199
2489
  viewApprovals: 'View approvals',
2200
2490
  noPendingApprovals: 'No pending approvals',
@@ -2307,6 +2597,93 @@ const en = {
2307
2597
  done: 'Done — hide it',
2308
2598
  },
2309
2599
  },
2600
+ excelImport: {
2601
+ noImportableFields: 'That object has no importable fields.',
2602
+ schemaReadFailed: 'Could not read the object schema.',
2603
+ imported: 'Imported {{count}} row(s) into {{object}}.',
2604
+ importFrom: 'Import the real rows from',
2605
+ into: 'into',
2606
+ opening: 'Opening…',
2607
+ importAction: 'Import',
2608
+ dismiss: 'Dismiss',
2609
+ },
2610
+ cloudOnboarding: {
2611
+ hintCreate: 'Spin up your first environment — a private workspace with its own URL, database, and plan. Building happens inside it.',
2612
+ hintReady: 'Your production environment is ready. Open it to build and run your apps — that all happens inside the environment.',
2613
+ createEnvironment: 'Create your environment',
2614
+ openProduction: 'Open Production',
2615
+ manageEnvironments: 'Manage environments',
2616
+ },
2617
+ aiModelStatus: {
2618
+ summary: 'Build / Ask uses {{conversational}} ({{conversationalSource}}); structured uses {{structured}} ({{structuredSource}}).',
2619
+ summaryRouting: 'Routing policy: free plans → {{free}}, paid plans → {{paid}}.',
2620
+ modelUnknown: 'unknown',
2621
+ sourceUnknown: 'not reported by the adapter',
2622
+ rowConversational: 'Build / Ask model',
2623
+ rowStructured: 'Structured (blueprint / seed)',
2624
+ rowReasoning: 'Reasoning effort',
2625
+ readFailed: 'Couldn\'t read the effective AI model. This environment may not run an AI service, or you may lack the ai:read permission.',
2626
+ readFailedWithStatus: 'Couldn\'t read the effective AI model (HTTP {{status}}). This environment may not run an AI service, or you may lack the ai:read permission.',
2627
+ overridesInEffect: 'Overrides in effect: ',
2628
+ noOverrides: 'none — running the deployed code defaults.',
2629
+ adapter: 'Adapter: ',
2630
+ sourceCodeDefault: 'code default (no env override)',
2631
+ sourceInherits: 'same as build/ask',
2632
+ sourcePinned: 'pinned by {{source}}',
2633
+ },
2634
+ chatbotError: {
2635
+ title: 'Response failed',
2636
+ fallbackDetail: 'Something went wrong. Please try again.',
2637
+ details: 'Details',
2638
+ hide: 'Hide',
2639
+ retry: 'Retry',
2640
+ },
2641
+ chatbotQuota: {
2642
+ title: 'Upgrade needed',
2643
+ fallbackMessage: 'You have reached your AI quota.',
2644
+ buyCredits: 'Buy a credit pack',
2645
+ upgradePlan: 'Upgrade plan',
2646
+ },
2647
+ environment: {
2648
+ addEnvironment: 'Add environment',
2649
+ setUpProduction: 'Set up your production environment',
2650
+ addDevelopment: 'Add development environment',
2651
+ },
2652
+ cloudConnection: {
2653
+ checking: 'Checking connection…',
2654
+ retry: 'Try again',
2655
+ errors: {
2656
+ expired: 'The request expired before it was approved. Start again.',
2657
+ bindFailed: 'Binding failed.',
2658
+ deviceCodeFailed: 'Device code request failed.',
2659
+ },
2660
+ waiting: {
2661
+ popupOpened: 'Approve the connection in the window that just opened — this page updates by itself.',
2662
+ polling: 'Waiting for approval in the cloud console…',
2663
+ openApproval: 'Open the approval page',
2664
+ copy: 'Copy',
2665
+ copied: 'Copied',
2666
+ codePrefilled: 'The code is pre-filled on the approval page.',
2667
+ openItHere: 'Window did not appear? Open it here',
2668
+ cancel: 'Cancel',
2669
+ },
2670
+ bound: {
2671
+ title: 'Connected to ObjectStack Cloud',
2672
+ runtime: 'Runtime',
2673
+ organization: 'Organization',
2674
+ approvedBy: 'Approved by',
2675
+ runtimeId: 'Runtime ID',
2676
+ environment: 'Environment',
2677
+ since: 'Since',
2678
+ privatePackages: 'Your organization\'s private packages now appear in the Marketplace under “Your organization”.',
2679
+ disconnect: 'Disconnect',
2680
+ },
2681
+ unbound: {
2682
+ title: 'Not connected',
2683
+ body: 'Connect this runtime to an ObjectStack control plane to browse your organization\'s private packages and install them here. Approval is a single click in your cloud account — no ids or credentials are typed into this page.',
2684
+ connect: 'Connect',
2685
+ },
2686
+ },
2310
2687
  marketplace: {
2311
2688
  title: 'App Marketplace',
2312
2689
  subtitle: 'Browse approved apps published to the ObjectStack catalog. Click an app to view details and install it into one of your environments.',
@@ -2442,6 +2819,14 @@ const en = {
2442
2819
  yearsAgo: '{{count}}y ago',
2443
2820
  },
2444
2821
  },
2822
+ approvals: {
2823
+ approve: 'Approve',
2824
+ reject: 'Reject',
2825
+ comment: 'Comment (optional)',
2826
+ approveSuccess: 'Approved',
2827
+ rejectSuccess: 'Rejected',
2828
+ rejectConfirm: 'Reject this approval request?',
2829
+ },
2445
2830
  approvalsInbox: {
2446
2831
  loadMore: 'Load more',
2447
2832
  loadingMore: 'Loading…',
@@ -2466,13 +2851,28 @@ const en = {
2466
2851
  slaRemaining: 'SLA {{dur}} left',
2467
2852
  slaOverdue: 'SLA overdue {{dur}}',
2468
2853
  actReassign: 'Reassigned',
2854
+ reassignFromTo: 'from {{from}} to {{to}}',
2469
2855
  actRemind: 'Reminder sent',
2470
2856
  actRequestInfo: 'Requested more info',
2471
2857
  actComment: 'Commented',
2472
2858
  stepProgress: 'Approval steps',
2473
2859
  prevRequest: 'Previous',
2474
2860
  nextRequest: 'Next',
2475
- positionOf: '{{index}} of {{total}}',
2861
+ positionOf: 'Request {{index}} of {{total}}',
2862
+ progressApprovals: 'Approvals — {{got}} of {{need}}',
2863
+ progressGroups: 'Sign-off progress — {{got}} of {{need}} groups',
2864
+ progressEligible: '{{count}} eligible approver(s)',
2865
+ progressBar: 'Decision progress',
2866
+ declaredActions: 'Actions',
2867
+ attachmentChip: 'Attachment',
2868
+ attachmentOpenFailed: 'Could not open the attachment — please try again',
2869
+ approveOneTitle: 'Approve "{{title}}"?',
2870
+ approveOneBody: 'This approves the request with your identity. To add a comment or attachment, open the request instead.',
2871
+ flowOrigin: 'Flow-initiated',
2872
+ sortBy: 'Sort',
2873
+ sortRecent: 'Newest first',
2874
+ sortOldest: 'Oldest first',
2875
+ sortAmount: 'Amount (high→low)',
2476
2876
  quickPhrase1: 'Approved — meets requirements.',
2477
2877
  quickPhrase2: 'Approved with conditions — please monitor execution.',
2478
2878
  quickPhrase3: 'Please add supporting material and resubmit.',