@brftech/filex-core 0.39.1 → 0.41.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.
Files changed (125) hide show
  1. package/README.md +32 -25
  2. package/dist/ArchiveViewer-BNqukFg8.js +124 -0
  3. package/dist/ArchiveViewer-BNqukFg8.js.map +1 -0
  4. package/dist/CsvViewer-ii_-MgmG.js +141 -0
  5. package/dist/CsvViewer-ii_-MgmG.js.map +1 -0
  6. package/dist/{DrawioViewer-BNALOB04.js → DrawioViewer-B2tuu4rX.js} +48 -42
  7. package/dist/DrawioViewer-B2tuu4rX.js.map +1 -0
  8. package/dist/EpubViewer-p4B8iiWb.js +163 -0
  9. package/dist/EpubViewer-p4B8iiWb.js.map +1 -0
  10. package/dist/IpynbViewer-D_qYRJhu.js +184 -0
  11. package/dist/IpynbViewer-D_qYRJhu.js.map +1 -0
  12. package/dist/MermaidViewer-3ZkfNM8v.js +137 -0
  13. package/dist/MermaidViewer-3ZkfNM8v.js.map +1 -0
  14. package/dist/PsdViewer-CuV-OPSd.js +122 -0
  15. package/dist/PsdViewer-CuV-OPSd.js.map +1 -0
  16. package/dist/TiffViewer-BLeoF4Be.js +142 -0
  17. package/dist/TiffViewer-BLeoF4Be.js.map +1 -0
  18. package/dist/Viewer3D-DHhhU76E.js +75 -0
  19. package/dist/Viewer3D-DHhhU76E.js.map +1 -0
  20. package/dist/filex-core.js +217 -20077
  21. package/dist/filex-core.js.map +1 -1
  22. package/dist/filex-core.umd.cjs +61 -62
  23. package/dist/filex-core.umd.cjs.map +1 -1
  24. package/dist/index-BraG7Cz4.js +26664 -0
  25. package/dist/index-BraG7Cz4.js.map +1 -0
  26. package/dist/index.d.ts +4276 -851
  27. package/dist/style.css +1 -1
  28. package/package.json +1 -1
  29. package/src/FileExplorer.vue +2170 -492
  30. package/src/components/AdvancedSearch.vue +870 -0
  31. package/src/components/Breadcrumb.vue +191 -19
  32. package/src/components/CommandPalette.vue +66 -22
  33. package/src/components/ConnectionsPanel.vue +6 -2
  34. package/src/components/ContextMenu.vue +57 -2
  35. package/src/components/EncryptedFolderModal.vue +31 -25
  36. package/src/components/FilePane.vue +939 -0
  37. package/src/components/FilterBar.vue +568 -72
  38. package/src/components/GalleryView.vue +162 -30
  39. package/src/components/GridView.vue +322 -58
  40. package/src/components/HomeView.vue +331 -0
  41. package/src/components/InspectorPanel.vue +296 -53
  42. package/src/components/ListView.vue +1158 -167
  43. package/src/components/NFSExportsPanel.vue +7 -4
  44. package/src/components/OnboardingTour.vue +156 -33
  45. package/src/components/QuickLook.vue +34 -5
  46. package/src/components/RecentlyOpened.vue +17 -2
  47. package/src/components/S3KeysPanel.vue +7 -4
  48. package/src/components/SSHKeysPanel.vue +7 -4
  49. package/src/components/ShortcutSettings.vue +43 -2
  50. package/src/components/ShortcutsHelp.vue +4 -1
  51. package/src/components/SideNav.vue +206 -140
  52. package/src/components/StorageFields.vue +19 -1
  53. package/src/components/TabBar.vue +87 -1
  54. package/src/components/TagPicker.vue +77 -6
  55. package/src/components/ThemeGallery.vue +13 -198
  56. package/src/components/ThemePalette.vue +244 -0
  57. package/src/components/TimeZoneDialog.vue +127 -0
  58. package/src/components/TimeZonePicker.vue +696 -0
  59. package/src/components/TokensPanel.vue +16 -4
  60. package/src/components/Toolbar.vue +965 -469
  61. package/src/components/ViewSwitcher.vue +9 -4
  62. package/src/composables/useConnections.ts +35 -4
  63. package/src/composables/useExplorerTimeZone.ts +85 -0
  64. package/src/composables/useFileApi.ts +53 -4
  65. package/src/composables/useKeyboardShortcuts.ts +122 -0
  66. package/src/composables/useLocale.ts +365 -25
  67. package/src/index.ts +182 -3
  68. package/src/lib/actionIcons.ts +330 -0
  69. package/src/lib/advSearch.ts +162 -0
  70. package/src/lib/dateGroups.ts +197 -0
  71. package/src/lib/destinationTree.ts +235 -0
  72. package/src/lib/downloadSelection.ts +154 -0
  73. package/src/lib/fileFilters.ts +319 -12
  74. package/src/lib/fileIcons.ts +299 -5
  75. package/src/lib/filePreview.ts +605 -0
  76. package/src/lib/listing.ts +72 -0
  77. package/src/lib/shareTtl.ts +11 -1
  78. package/src/lib/sortOrder.ts +459 -0
  79. package/src/lib/themes.ts +152 -23
  80. package/src/lib/timezone.ts +456 -0
  81. package/src/lib/uiProfile.ts +82 -0
  82. package/src/lib/viewPrefs.ts +1036 -0
  83. package/src/locales/en.ts +432 -25
  84. package/src/locales/tr.ts +425 -25
  85. package/src/modals/ConvertModal.vue +23 -3
  86. package/src/modals/DestinationPickerModal.vue +341 -0
  87. package/src/modals/Modal.vue +18 -4
  88. package/src/modals/NewDocumentModal.vue +525 -0
  89. package/src/modals/NewFolderModal.vue +15 -9
  90. package/src/modals/PermissionsModal.vue +543 -473
  91. package/src/modals/PreviewModal.vue +516 -156
  92. package/src/styles/base.css +5435 -8
  93. package/src/styles/variables.css +140 -60
  94. package/src/types/Connections.ts +9 -0
  95. package/src/types/ExplorerConfig.ts +144 -39
  96. package/src/types/FileNode.ts +28 -0
  97. package/src/viewers/ArchiveViewer.vue +46 -8
  98. package/src/viewers/CsvViewer.vue +19 -2
  99. package/src/viewers/DrawioViewer.vue +12 -1
  100. package/src/viewers/EpubViewer.vue +50 -6
  101. package/src/viewers/IpynbViewer.vue +19 -2
  102. package/src/viewers/MermaidViewer.vue +20 -3
  103. package/src/viewers/PdfViewer.vue +24 -4
  104. package/src/viewers/PsdViewer.vue +28 -4
  105. package/src/viewers/TiffViewer.vue +19 -2
  106. package/src/viewers/Viewer3D.vue +36 -2
  107. package/dist/ArchiveViewer-Cdfv9LFC.js +0 -99
  108. package/dist/ArchiveViewer-Cdfv9LFC.js.map +0 -1
  109. package/dist/CsvViewer-CqWeV8VO.js +0 -131
  110. package/dist/CsvViewer-CqWeV8VO.js.map +0 -1
  111. package/dist/DrawioViewer-BNALOB04.js.map +0 -1
  112. package/dist/EpubViewer-BPmlImG7.js +0 -145
  113. package/dist/EpubViewer-BPmlImG7.js.map +0 -1
  114. package/dist/IpynbViewer-CDlQmuCV.js +0 -175
  115. package/dist/IpynbViewer-CDlQmuCV.js.map +0 -1
  116. package/dist/MermaidViewer-sfZWdR-d.js +0 -127
  117. package/dist/MermaidViewer-sfZWdR-d.js.map +0 -1
  118. package/dist/PsdViewer-DwuySZsb.js +0 -112
  119. package/dist/PsdViewer-DwuySZsb.js.map +0 -1
  120. package/dist/TiffViewer-BDQ3d3CQ.js +0 -132
  121. package/dist/TiffViewer-BDQ3d3CQ.js.map +0 -1
  122. package/dist/Viewer3D-CJJJgkuv.js +0 -60
  123. package/dist/Viewer3D-CJJJgkuv.js.map +0 -1
  124. package/src/components/SecondaryPane.vue +0 -447
  125. package/src/modals/ShareModal.vue +0 -139
package/src/locales/en.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /** English UI strings. */
2
2
  export const en: Record<string, string> = {
3
- 'toolbar.new_folder': 'New Folder',
3
+ 'toolbar.new_folder': 'New folder',
4
4
  'toolbar.upload': 'Upload',
5
5
  'toolbar.search': 'Search',
6
6
  'toolbar.search.placeholder': 'Search by name or tag:…',
@@ -39,10 +39,11 @@ export const en: Record<string, string> = {
39
39
  'ctx.paste': 'Paste',
40
40
  'ctx.info': 'Info',
41
41
  'ctx.duplicate': 'Duplicate',
42
- 'ctx.new_file': 'New File',
42
+ 'ctx.new_file': 'New file',
43
43
 
44
44
  'modal.delete.title': 'Delete?',
45
- 'modal.delete.message': '{count} item(s) will be moved to trash.',
45
+ 'modal.delete.message': '{count} items will be moved to trash.',
46
+ 'modal.delete.message_one': '1 item will be moved to trash.',
46
47
  'modal.delete.confirm': 'Move to Trash',
47
48
  'modal.delete.cancel': 'Cancel',
48
49
 
@@ -50,7 +51,7 @@ export const en: Record<string, string> = {
50
51
  'modal.rename.save': 'Save',
51
52
  'modal.rename.cancel': 'Cancel',
52
53
 
53
- 'modal.newfolder.title': 'New Folder',
54
+ 'modal.newfolder.title': 'New folder',
54
55
  'modal.newfolder.placeholder': 'Folder name',
55
56
  'modal.newfolder.create': 'Create',
56
57
  'modal.newfolder.cancel': 'Cancel',
@@ -96,10 +97,11 @@ export const en: Record<string, string> = {
96
97
  'unit.mb': 'MB',
97
98
  'unit.gb': 'GB',
98
99
  'unit.tb': 'TB',
100
+ 'unit.pb': 'PB',
99
101
 
100
102
  'breadcrumb.root': 'Root',
101
- 'breadcrumb.copy_path': 'Copy Path',
102
- 'breadcrumb.go_to_path': 'Go To Path',
103
+ 'breadcrumb.copy_path': 'Copy path',
104
+ 'breadcrumb.go_to_path': 'Go to path',
103
105
  'breadcrumb.path_placeholder': 'fileman/foo/bar',
104
106
 
105
107
  'ops.copy': 'Copying',
@@ -110,9 +112,13 @@ export const en: Record<string, string> = {
110
112
  'ops.error': 'error',
111
113
 
112
114
  'node.trash': 'Trash',
115
+ /* gorunum:v1 — the singular kind, printed under a folder's name on a card
116
+ * and beside it in the list. The plural section heading is a different
117
+ * string on purpose. */
118
+ 'node.folder': 'Folder',
113
119
 
114
120
  // ——— Rich viewer chrome ———
115
- 'viewer.open_in_new_tab': 'Open in New Tab',
121
+ 'viewer.open_in_new_tab': 'Open in new tab',
116
122
  'viewer.loading': 'Loading…',
117
123
  'viewer.failed_to_load': 'Failed to load file',
118
124
  'viewer.peer_not_installed': 'Optional viewer library is not installed. Install the peer dependency or use the download button.',
@@ -150,6 +156,7 @@ export const en: Record<string, string> = {
150
156
  'viewer.epub_next': 'Next',
151
157
  'viewer.drawio.disabled': 'diagrams.net embed is not configured for this filex instance — operator must wire FILEX_DRAWIO_URL to enable the editor.',
152
158
  'viewer.archive.entries': '{n} files',
159
+ 'viewer.archive.entries_one': '1 file',
153
160
  'viewer.archive.empty': 'Archive is empty.',
154
161
  'viewer.archive.error': 'Could not read archive contents.',
155
162
  'viewer.name': 'Name',
@@ -217,7 +224,10 @@ export const en: Record<string, string> = {
217
224
  'toast.cut_ready': 'Cut — ready to paste',
218
225
  'toast.copy_ready': 'Copied — ready to paste',
219
226
  'toast.same_folder_cut': 'Cannot cut into the same folder',
220
- 'toast.restored': '{n} item(s) restored',
227
+ 'toast.restored': '{n} items restored',
228
+ 'toast.restored_one': '1 item restored',
229
+ 'toast.restore_taken': '{n} items were not restored: something already has their names. Rename what is there, then restore again.',
230
+ 'toast.restore_taken_one': '“{name}” was not restored: something already has that name. Rename what is there, then restore again.',
221
231
  'toast.delete_queued': 'Delete queued',
222
232
  'toast.trash_retention': 'Items in the trash are removed automatically once the retention window ends. Permanent deletion is done from the admin panel.',
223
233
  'dropzone.hint': 'Drop files here',
@@ -226,7 +236,9 @@ export const en: Record<string, string> = {
226
236
  'viewer.pdf_inline_failed': 'Your browser could not display this PDF inline.',
227
237
  'viewer.too_large': 'File is too large (>1 MB).',
228
238
  'viewer.csv_rows': '{n} rows',
239
+ 'viewer.csv_rows_one': '1 row',
229
240
  'presence.others': '{n} people',
241
+ 'presence.others_one': '1 person',
230
242
  'conn.offline': 'No live connection — changes may be delayed',
231
243
  'conn.tooltip': 'Live connection to the server is unavailable; the list refreshes periodically. This notice disappears once the connection is back.',
232
244
 
@@ -253,8 +265,25 @@ export const en: Record<string, string> = {
253
265
  'star.failed': 'Could not change the star',
254
266
  'shortcuts.inspector': 'Toggle details panel',
255
267
  'inspector.title': 'Details',
268
+ 'inspector.copy_name': 'Copy name',
269
+ 'inspector.items': '{n} items',
270
+ 'inspector.items_one': '1 item',
271
+ 'inspector.type': 'Type',
272
+ 'inspector.select_hint': 'Select an item to see its details.',
273
+ /* pane:p1 — the panel HOLDS the last selected thing (owner's ruling,
274
+ 2026-09-13), so it can be describing an item in the half of a split
275
+ window nobody is looking at. This line says which one and where. */
276
+ 'inspector.held': 'Last selected — in {where}',
256
277
  'inspector.close': 'Close',
257
278
  'inspector.section.general': 'General',
279
+ 'inspector.section.tags': 'Tags',
280
+ /* etiket:t1 — TagPicker's own chrome. It printed these three in English
281
+ regardless of the catalogue until 2026-09-13; `tags.open` is the chip's new
282
+ "show me everything with this tag". */
283
+ 'tags.open': 'Open tag: {tag}',
284
+ 'tags.add': '+ Add tag',
285
+ 'tags.name': 'Tag name',
286
+ 'tags.remove': 'Remove tag',
258
287
  'inspector.section.versions': 'Versions',
259
288
  'inspector.section.permissions': 'Permissions',
260
289
  'inspector.section.shares': 'Shares',
@@ -263,11 +292,14 @@ export const en: Record<string, string> = {
263
292
  'inspector.modified': 'Modified',
264
293
  'inspector.mime': 'MIME type',
265
294
  'inspector.etag': 'ETag',
295
+ 'inspector.nodeId': 'Node ID',
266
296
  'inspector.copy': 'Copy',
267
297
  'inspector.copied': 'Copied',
268
298
  'inspector.error': 'Could not load',
269
299
  'inspector.items_summary': '{n} items, {size} total',
300
+ 'inspector.items_summary_one': '1 item, {size} total',
270
301
  'inspector.folder_items': '{n} items',
302
+ 'inspector.folder_items_one': '1 item',
271
303
  'inspector.versions.empty': 'No version history',
272
304
  'inspector.versions.v': 'Version {n}',
273
305
  'inspector.versions.restore': 'Restore',
@@ -306,6 +338,18 @@ export const en: Record<string, string> = {
306
338
  'theme.name.contrast': 'High Contrast',
307
339
  'theme.name.gray': 'Soft Gray',
308
340
  'theme.name.terminal': 'Terminal Green',
341
+ /* === zaman:z3 — the time-zone picker (embed dialog + web settings) === */
342
+ 'tz.menu': 'Time zone',
343
+ 'tz.title': 'Time zone',
344
+ 'tz.label': 'Show dates in',
345
+ 'tz.search': 'Search a city, country or offset — try "Istanbul" or "GMT+3"',
346
+ 'tz.default.device': "Use this device's zone ({zone})",
347
+ 'tz.default.account': "Use the account's zone ({zone})",
348
+ 'tz.default.host': "Use this site's default ({zone})",
349
+ 'tz.no_match': 'No zone matches “{query}”. Try a city, a country, or an offset like GMT+3.',
350
+ 'tz.more': '{n} more — keep typing to narrow the list.',
351
+ 'tz.hint': 'Saved in this browser only. Every date is stored as one moment in time and shown on the clock you pick here.',
352
+ 'tz.now': 'Right now in {zone}: {time}',
309
353
  /* === wiring:c2 — customizable shortcuts + quick look === */
310
354
  'shortcuts.quicklook': 'Quick look',
311
355
  'shortcuts.customize': 'Customize',
@@ -330,6 +374,7 @@ export const en: Record<string, string> = {
330
374
  /* === wiring:c3 — operations center === */
331
375
  'opc.title': 'Operations',
332
376
  'opc.aria_badge': '{n} operations — toggle operations center',
377
+ 'opc.aria_badge_one': '1 operation — toggle operations center',
333
378
  'opc.close': 'Close',
334
379
  'opc.active': 'In progress',
335
380
  'opc.history': 'History',
@@ -358,24 +403,34 @@ export const en: Record<string, string> = {
358
403
  'tour.next': 'Next',
359
404
  'tour.done': 'Done',
360
405
  'tour.progress': '{n} / {m}',
361
- 'tour.step.nav.title': 'Storages & folders',
406
+ 'tour.step.nav.title': 'Storages & views',
362
407
  'tour.step.nav.desc':
363
- 'Your current location lives here. Click any crumb to jump back to parent folders or the storage root.',
364
- 'tour.step.upload.title': 'Upload files',
365
- 'tour.step.upload.desc':
366
- 'Pick files with this button — or simply drag & drop them anywhere in the window.',
408
+ 'Home, Shared with me, Recent, Starred and Trash are always in this panel, with your storages and connections underneath. The button in the top-left corner collapses it to a rail and brings it back.',
409
+ 'tour.step.nav.desc_closed':
410
+ 'This button opens the navigation panel: Home, Shared with me, Recent, Starred and Trash, with your storages and connections underneath.',
411
+ 'tour.step.new.title': 'Add something',
412
+ 'tour.step.new.desc':
413
+ 'Everything new starts here — upload from this device, create a folder, or ask somebody else for a file. Dropping files onto the window uploads them as well.',
414
+ 'tour.step.new.desc_fab':
415
+ 'This button uploads files from this device. Dropping files onto the window works as well.',
367
416
  'tour.step.search.title': 'Search',
368
417
  'tour.step.search.desc':
369
- 'This box searches the whole storage by name — separators and one typo are forgiven, so "invoice 2026" finds invoice_2026.pdf. Add tag:invoice to filter by tag. The {palette} command palette also runs commands.',
418
+ 'This field searches the whole storage by name — separators and one typo are forgiven, so "invoice 2026" finds invoice_2026.pdf. Add tag:invoice to filter by tag. The sliders button opens advanced search, and {palette} opens the command palette, which runs commands too.',
419
+ 'tour.step.crumb.title': 'Where you are',
420
+ 'tour.step.crumb.desc':
421
+ 'This trail is the address of the folder on screen. Click any step to go back up, and the chevron beside the last one lists the folders inside it.',
422
+ 'tour.step.filters.title': 'Narrow the list',
423
+ 'tour.step.filters.desc':
424
+ 'Type, People, Modified and Size filter the folder you are in, the box beside them matches names as you type, and the control at the end of the row sorts.',
370
425
  'tour.step.view.title': 'Switch views',
371
426
  'tour.step.view.desc':
372
- 'Toggle between the list and grid layout; your choice is remembered.',
373
- 'tour.step.share.title': 'Sharing',
374
- 'tour.step.share.desc':
375
- 'Right-click any file and use "Share / Permissions" to create a link with an optional PIN and expiry.',
427
+ 'Change how this folder is drawn; your choice is remembered.',
428
+ 'tour.step.details.title': 'Details & sharing',
429
+ 'tour.step.details.desc':
430
+ 'Select a file and open this panel for its details, its activity and its share links. For the full menu, right-click the file or use the button at the end of its row — "Share / Permissions" there creates a link with an optional PIN and expiry.',
376
431
  'tour.step.help.title': 'Shortcuts',
377
432
  'tour.step.help.desc':
378
- 'Press {help} for the shortcut cheat-sheet and {palette} for the command palette. Replay this tour any time via "Restart the tour" in the menu.',
433
+ 'Press {help} for the shortcut cheat-sheet and {palette} for the command palette. Theme and "Restart the tour" are in the "More actions" menu at the top right; your account and sign-out are behind the avatar beside it.',
379
434
  'error.hint': 'This may be a temporary network or server problem. Please try again.',
380
435
  'error.details': 'Technical details',
381
436
  'col.star': 'Star',
@@ -395,6 +450,24 @@ export const en: Record<string, string> = {
395
450
  'shortcuts.tab_close': 'Close tab',
396
451
  'shortcuts.tab_next': 'Next tab',
397
452
  'shortcuts.tab_prev': 'Previous tab',
453
+ /* tus:t1 — the menu verbs */
454
+ 'shortcuts.new_folder': 'New folder',
455
+ 'shortcuts.upload': 'Upload files',
456
+ 'shortcuts.refresh': 'Refresh the listing',
457
+ 'shortcuts.download': 'Download',
458
+ 'shortcuts.preview': 'Preview',
459
+ 'shortcuts.share': 'Share / permissions',
460
+ 'shortcuts.tags': 'Tags',
461
+ 'shortcuts.convert': 'Convert',
462
+ 'shortcuts.open_tab': 'Open in a new tab',
463
+ 'shortcuts.copy_path': 'Copy path',
464
+ 'shortcuts.copy_id': 'Copy id',
465
+ 'shortcuts.restore': 'Restore from trash',
466
+ 'shortcuts.settings.reserved':
467
+ 'is taken by the browser before the page sees it, so it would do nothing here. Pick another key.',
468
+ 'shortcuts.settings.reserved_badge': 'Desktop app only',
469
+ 'shortcuts.settings.reserved_title':
470
+ 'The browser handles this combination itself. It fires in the desktop app and in an installed PWA, not in a browser tab.',
398
471
  'cmd.tab_new': 'Open a new tab',
399
472
  'cmd.split_toggle': 'Toggle split view',
400
473
  'split.pane': 'Secondary pane',
@@ -403,6 +476,7 @@ export const en: Record<string, string> = {
403
476
  'split.retry': 'Retry',
404
477
  'split.copy_queued': 'Copy queued',
405
478
  'split.move_queued': 'Move queued',
479
+ 'toast.move_kept_both': 'Move queued. A name was already taken there, so that item will be kept beside the existing one with “-copy” added. This move cannot be undone.',
406
480
  'split.cross_copy': 'Different storages — copy queued instead',
407
481
  'dragout.downloading': 'Downloading into the folder you dropped on…',
408
482
  'dragout.not_found': 'Could not find where it was dropped — a drop onto an application (rather than a folder) cannot be filled in',
@@ -424,8 +498,9 @@ export const en: Record<string, string> = {
424
498
  /* wiring:e2 — end-to-end encrypted folders */
425
499
  'e2e.create.title': 'Create encrypted folder',
426
500
  'e2e.create.option': 'Create encrypted folder…',
427
- 'e2e.create.pw_placeholder': 'Folder password (min 8 characters)',
428
- 'e2e.create.pw2_placeholder': 'Repeat the password',
501
+ 'e2e.create.pw_label': 'Folder password',
502
+ 'e2e.create.pw_placeholder': 'At least 8 characters',
503
+ 'e2e.create.pw2_label': 'Repeat the password',
429
504
  'e2e.create.warn_title': 'NO WAY BACK',
430
505
  'e2e.create.warn_body':
431
506
  'Files in this folder can only be opened with this password or the recovery key shown once when the folder is created. The password is NEVER stored on the server, and filex keeps no copy of the recovery key either. Lose both and the contents are gone for good.',
@@ -446,6 +521,10 @@ export const en: Record<string, string> = {
446
521
  'e2e.locked.busy': 'Verifying…',
447
522
  'e2e.unlock.wrong': 'Wrong password.',
448
523
  'e2e.unlock.marker_missing': 'Could not read the key file (.filex-e2e.json).',
524
+ /* ikon:emoji — the listing marker's accessible name. The row used to print
525
+ a 🔒 and nothing else; the padlock that replaced it is aria-hidden inside
526
+ the tile, so the span that carries it says this instead. */
527
+ 'e2e.badge': 'Encrypted folder',
449
528
  'e2e.strip.label': 'Encrypted folder — unlocked',
450
529
  'e2e.strip.lock': 'Lock',
451
530
  'e2e.locked_toast': 'Folder locked',
@@ -556,7 +635,8 @@ export const en: Record<string, string> = {
556
635
  'conn.denied.unreachable': 'The server did not answer: {error}',
557
636
  'conn.denied.guideHint': 'You do not need administrator rights to connect your own computer to the storages you can already see.',
558
637
  'conn.denied.guideCta': 'Show me how to connect',
559
- 'conn.list.count': '{n} storage(s)',
638
+ 'conn.list.count': '{n} storages',
639
+ 'conn.list.count_one': '1 storage',
560
640
  'conn.list.add': 'Add a storage',
561
641
  'conn.list.empty': 'No storage is configured yet. Add one and the files show up in the explorer.',
562
642
  'conn.list.edit': 'Edit',
@@ -575,7 +655,8 @@ export const en: Record<string, string> = {
575
655
  'conn.form.enabled': 'Enabled',
576
656
  'conn.form.test': 'Test connection',
577
657
  'conn.form.testing': 'Testing…',
578
- 'conn.form.testOk': 'Connected. {count} item(s) at the root.',
658
+ 'conn.form.testOk': 'Connected. {count} items at the root.',
659
+ 'conn.form.testOk_one': 'Connected. 1 item at the root.',
579
660
  'conn.form.testFail': 'Could not connect: {error}',
580
661
  'conn.form.save': 'Save',
581
662
  'conn.form.saving': 'Saving…',
@@ -950,6 +1031,8 @@ export const en: Record<string, string> = {
950
1031
  'sidenav.title': 'Navigation',
951
1032
  'sidenav.views': 'Views',
952
1033
  'sidenav.storages': 'Storages',
1034
+ 'sidenav.home': 'Home',
1035
+ 'sidenav.myfiles': 'My files',
953
1036
  'sidenav.recent': 'Recent',
954
1037
  'sidenav.starred': 'Starred',
955
1038
  'sidenav.shared': 'Shared with me',
@@ -957,8 +1040,22 @@ export const en: Record<string, string> = {
957
1040
  'sidenav.collapse': 'Collapse navigation',
958
1041
  'sidenav.expand': 'Expand navigation',
959
1042
  'sidenav.close': 'Close navigation',
1043
+ // ⚠ `open`/`close` are the DRAWER's pair, `expand`/`collapse` the docked
1044
+ // panel's, and they are not interchangeable — see the note on
1045
+ // `navToggleLabel` in Toolbar.vue. Below 560px the panel is a drawer over
1046
+ // the listing: it is not narrowed to a rail, it is not on screen at all, so
1047
+ // "expand" would promise a width change to something that has no width.
1048
+ 'sidenav.open': 'Open navigation',
960
1049
  'sidenav.storage.shared': 'Shared',
961
- 'toolbar.nav': 'Navigation',
1050
+ // ⚠ `toolbar.nav` is GONE, and nothing replaced it. It was the one label on
1051
+ // the panel's collapse control, first as the noun "Navigation" — which names
1052
+ // the panel and never says the button does anything to it, so the owner
1053
+ // could not find how to collapse the panel (2026-09-13: "yan menüyü kısıp
1054
+ // açabilir olalım ya bence") — and then as the static stopgap "Show or hide
1055
+ // navigation". The four `sidenav.*` verbs above are the real fix: the label
1056
+ // is bound to `navOpen`, so it says *collapse* when it will collapse and
1057
+ // *expand* when it will expand.
1058
+ 'node.home': 'Home',
962
1059
  'node.recent': 'Recent',
963
1060
  'node.starred': 'Starred',
964
1061
  'node.shared': 'Shared with me',
@@ -987,17 +1084,57 @@ export const en: Record<string, string> = {
987
1084
  'conn.tokens.capNote': 'Your account and its permissions are the ceiling — asking for more than you have is refused, not granted.',
988
1085
  /* === /gezinti:g1 === */
989
1086
 
990
- /* === surucu:d1 — the Drive shell (uiProfile: 'drive', GitHub #14) ===== */
1087
+ /* === surucu:d1 — the shell (GitHub #14); every profile, no longer a
1088
+ `uiProfile: 'drive'` opt-in === */
991
1089
  'drive.new': 'New',
992
1090
  'drive.new.upload': 'Upload files',
993
1091
  'drive.new.folder': 'New folder',
994
1092
  'drive.new.request': 'Request files',
1093
+ 'drive.new.document': 'New document',
1094
+
1095
+ /* === belge:n1 — "New document": the picker under + New =================
1096
+ Type names are NOT listed here. A tile reads its words from
1097
+ lib/fileIcons `typeLabelFor`, the same table the listing's Type column
1098
+ uses, so ".docx" is called the same thing in both places and a new type
1099
+ needs no string at all. Only this dialog's own chrome lives below. */
1100
+ 'newdoc.title': 'New document',
1101
+ 'newdoc.type.label': 'Document type',
1102
+ 'newdoc.group.document': 'Documents',
1103
+ 'newdoc.group.text': 'Text and code',
1104
+ 'newdoc.group.diagram': 'Diagrams',
1105
+ 'newdoc.withheld.onlyoffice': 'Office documents need a document server (OnlyOffice), which is not configured here.',
1106
+ 'newdoc.withheld.drawio': 'Diagrams need a drawio service, which is not configured here.',
1107
+ 'newdoc.empty.title': 'No document types are available',
1108
+ 'newdoc.empty.body': 'This server did not offer any type this app can create.',
1109
+ 'newdoc.empty.blocked': 'Every type this server can create needs an editor service that is not configured here.',
1110
+ 'newdoc.name': 'Name',
1111
+ 'newdoc.name.placeholder': 'Document name',
1112
+ 'newdoc.untitled': 'Untitled',
1113
+ 'newdoc.err.slash': 'A name cannot contain a slash.',
1114
+ 'newdoc.err.exists': '{name} is already here. Choose another name.',
1115
+ 'newdoc.location': 'Location',
1116
+ 'newdoc.location.none': 'Choose a folder',
1117
+ 'newdoc.location.change': 'Change',
1118
+ 'newdoc.location.noaccess': 'You cannot save into this folder.',
1119
+ 'newdoc.create': 'Create',
1120
+ 'newdoc.creating': 'Creating…',
1121
+ 'newdoc.cancel': 'Cancel',
995
1122
  'drive.search.placeholder': 'Search in {scope}',
996
1123
  'drive.search.placeholder_all': 'Search your files',
997
1124
  'drive.search.hint_title': 'Search everywhere and run commands ({combo})',
998
1125
  'drive.storage.used': '{used} of {total} used',
999
1126
  'drive.storage.used_unlimited': '{used} used',
1000
1127
  'drive.storage.label': 'Storage',
1128
+ /* === gorunum:v3-shell — the Home view (the overview, inside the shell) ==
1129
+ * The section headings are `sidenav.storages` / `sidenav.recent` /
1130
+ * `sidenav.starred` and the two empty states are `empty.recent.*` /
1131
+ * `empty.starred.*`, on purpose: the block headed "Recent" on Home and the
1132
+ * panel row labelled "Recent" beside it are the same thing, and a second
1133
+ * string for it is how the two drift apart one translation at a time. Only
1134
+ * what exists nowhere else is below. */
1135
+ 'home.title': 'Home',
1136
+ 'home.storages.empty': 'No storages yet',
1137
+ 'home.storages.hint': 'A storage is a drive filex reads and writes — an administrator adds them.',
1001
1138
  'drive.section.folders': 'Folders',
1002
1139
  'drive.section.files': 'Files',
1003
1140
  'filter.aria': 'Filters',
@@ -1025,6 +1162,12 @@ export const en: Record<string, string> = {
1025
1162
  'filter.size.1to10': '1 - 10 MB',
1026
1163
  'filter.size.10to100': '10 - 100 MB',
1027
1164
  'filter.size.gt100': 'Over 100 MB',
1165
+ /* surucu:d1-actions — the ⋮ menu at the end of the filter row. Only its own
1166
+ NAME is new: every row inside it reuses the string that verb already has
1167
+ (`toolbar.new_folder`, `toolbar.upload`, `ctx.paste`, `shortcuts.select_all`,
1168
+ `selection.clear`), because a menu that renames a command is a menu the
1169
+ reader has to learn twice. */
1170
+ 'filter.actions': 'Listing actions',
1028
1171
  'filter.clear': 'Clear filters',
1029
1172
  'filter.empty.title': 'Nothing here matches those filters',
1030
1173
  'filter.empty.hint': 'Clear a filter, or search everywhere with the field above.',
@@ -1058,4 +1201,268 @@ export const en: Record<string, string> = {
1058
1201
  'convert.unsupported_input': 'This file type has no source format the converter can read.',
1059
1202
  'convert.converting': 'Converting…',
1060
1203
  'convert.convert': 'Convert',
1204
+ /* === gorunum:v1-chrome — the filter row's name box === */
1205
+ 'filter.find': 'Filter in this folder…',
1206
+ /* surucu:d1-scope — the same box where the rows are not a folder's contents.
1207
+ It has to say what it narrows: at the drive list "this folder" names
1208
+ nothing, and on Home it would name three blocks at once. */
1209
+ 'filter.find.storages': 'Filter storages…',
1210
+ 'filter.find.home': 'Filter Home…',
1211
+ /* === gorunum:v1-viewer — the full-bleed overlay's own chrome === */
1212
+ 'viewer.share': 'Share',
1213
+ 'viewer.nav_prev': 'Previous file',
1214
+ 'viewer.nav_next': 'Next file',
1215
+ /* The counter in the top bar's meta line: "246.3 KB • Sep 9, 2026 • 1 of 9". */
1216
+ 'viewer.counter': '{i} of {n}',
1217
+ 'viewer.zoom_reset': 'Reset zoom',
1218
+ 'viewer.fullscreen': 'Full screen',
1219
+ 'viewer.exit_fullscreen': 'Exit full screen',
1220
+ 'viewer.md_placeholder': '# Markdown here…',
1221
+ /* === gorunum:v1-selbar — the selection bar that replaces the filter row === */
1222
+ 'selection.count': '{n} selected',
1223
+ 'selection.clear': 'Clear selection',
1224
+ /* === gorunum:v1-preview — the kind, said in words ======================
1225
+ The Type column used to print the extension in caps. These are what it
1226
+ prints instead; the table that picks one is in `lib/fileIcons.ts`
1227
+ (`typeLabelKey`), so this list and that one are the only two places a
1228
+ kind is named. Anything unmapped still falls back to the uppercased
1229
+ extension — these names improve on that fallback, they do not replace
1230
+ it. `Folder` is NOT here: it is `node.folder`, which the grid card's
1231
+ caption already prints. */
1232
+ 'ftype.typescript': 'TypeScript',
1233
+ 'ftype.javascript': 'JavaScript',
1234
+ 'ftype.vue': 'Vue component',
1235
+ 'ftype.python': 'Python',
1236
+ 'ftype.go': 'Go',
1237
+ 'ftype.rust': 'Rust',
1238
+ 'ftype.php': 'PHP',
1239
+ 'ftype.ruby': 'Ruby',
1240
+ 'ftype.java': 'Java',
1241
+ 'ftype.kotlin': 'Kotlin',
1242
+ 'ftype.swift': 'Swift',
1243
+ 'ftype.c': 'C source',
1244
+ 'ftype.cpp': 'C++ source',
1245
+ 'ftype.csharp': 'C# source',
1246
+ 'ftype.stylesheet': 'Stylesheet',
1247
+ 'ftype.html': 'HTML document',
1248
+ 'ftype.json': 'JSON data',
1249
+ 'ftype.yaml': 'YAML',
1250
+ 'ftype.xml': 'XML',
1251
+ 'ftype.toml': 'TOML',
1252
+ 'ftype.sql': 'SQL',
1253
+ 'ftype.shell': 'Shell script',
1254
+ 'ftype.powershell': 'PowerShell script',
1255
+ 'ftype.markdown': 'Markdown',
1256
+ 'ftype.plaintext': 'Plain text',
1257
+ 'ftype.log': 'Log file',
1258
+ 'ftype.config': 'Configuration',
1259
+ 'ftype.sheet': 'Spreadsheet',
1260
+ 'ftype.figma': 'Figma design',
1261
+ 'ftype.design': 'Design file',
1262
+ 'ftype.image': 'Image',
1263
+ 'ftype.video': 'Video',
1264
+ 'ftype.audio': 'Audio',
1265
+ 'ftype.pdf': 'PDF document',
1266
+ 'ftype.document': 'Document',
1267
+ 'ftype.slides': 'Presentation',
1268
+ 'ftype.archive': 'Archive',
1269
+ 'ftype.code': 'Code',
1270
+ /* === gorunum:v1-advsearch — the Advanced search dialog ==================
1271
+ * Two `filter.*` keys are added here rather than beside their siblings
1272
+ * because they are new members of shared unions the dialog introduced
1273
+ * (`modified: 'around'`, `size: 'range'`); the filter row never selects
1274
+ * them, but `chipLabel` would print the raw key if one ever reached it. */
1275
+ 'filter.modified.around': 'Around a date',
1276
+ 'filter.size.range': 'Custom range',
1277
+
1278
+ 'advsearch.open': 'Advanced search',
1279
+ 'advsearch.title': 'Advanced search',
1280
+ 'advsearch.subtitle': 'Find files by name, content, path, or tags.',
1281
+ 'advsearch.close': 'Close',
1282
+ 'advsearch.content.heading': 'Content search',
1283
+ 'advsearch.viewall': 'View all results',
1284
+ 'advsearch.where.any_short': 'Anywhere',
1285
+ 'advsearch.where.here_short': 'Only here',
1286
+ 'advsearch.where.skip_short': 'Skip this',
1287
+ 'advsearch.server.legend': 'What the server searches',
1288
+ 'advsearch.client.legend': 'Narrow the results that come back',
1289
+ 'advsearch.query.label': 'Words',
1290
+ 'advsearch.query.placeholder': 'Part of a name, or words inside a file',
1291
+ 'advsearch.scope.label': 'Look in',
1292
+ 'advsearch.scope.name': 'Names and paths',
1293
+ 'advsearch.scope.content': 'File contents',
1294
+ 'advsearch.scope.all': 'Both',
1295
+ 'advsearch.scope.hint':
1296
+ 'Contents are searched from the index, which covers text-like files up to 200 KB.',
1297
+ 'advsearch.people.name_only':
1298
+ 'Owner is read off the rows that come back, and only a name search returns rows that carry one.',
1299
+ 'advsearch.scope.name_only':
1300
+ 'Only names and paths here: a content hit reaches the explorer without the drive it came from, so content search is offered on single-storage deployments only.',
1301
+ 'advsearch.tags.label': 'Tags',
1302
+ 'advsearch.tags.placeholder': 'invoice, quarterly report',
1303
+ 'advsearch.tags.exclude': 'Without tags',
1304
+ 'advsearch.tags.exclude_placeholder': 'archive',
1305
+ 'advsearch.tags.hint':
1306
+ 'Separate with commas. Tags narrow: several tags means files carrying all of them, and a tag nobody has applied returns nothing.',
1307
+ 'advsearch.where.label': 'Folder',
1308
+ 'advsearch.where.any': 'Anywhere in this storage',
1309
+ 'advsearch.where.here': 'Only in {folder}',
1310
+ 'advsearch.where.skip': 'Everywhere except {folder}',
1311
+ 'advsearch.around.label': 'Within',
1312
+ 'advsearch.around.date': 'Date and time',
1313
+ 'advsearch.around.h1': '1 hour',
1314
+ 'advsearch.around.d1': '1 day',
1315
+ 'advsearch.around.w1': '1 week',
1316
+ 'advsearch.size.range_label': 'Between',
1317
+ 'advsearch.size.from': 'From',
1318
+ 'advsearch.size.to': 'To',
1319
+ 'advsearch.count.idle': 'Type something, or pick a tag.',
1320
+ 'advsearch.count.counting': 'Counting…',
1321
+ 'advsearch.count.result': '{n} matching items',
1322
+ 'advsearch.count.capped': '{n} matching items in the first page of hits',
1323
+ 'advsearch.count.result_one': '1 matching item',
1324
+ 'advsearch.count.capped_one': '1 matching item in the first page of hits',
1325
+ 'advsearch.count.error': 'The count could not be run.',
1326
+ 'advsearch.count.cost':
1327
+ 'The count runs this search. Type, owner, date, size and folder are applied to the rows that come back, not by the server.',
1328
+ 'advsearch.wire': 'Sent as',
1329
+ 'advsearch.reset': 'Reset',
1330
+ 'advsearch.cancel': 'Cancel',
1331
+ 'advsearch.submit': 'Search',
1332
+
1333
+ /* === gorunum:v2-topbar — the page bar is gone; the explorer's own header
1334
+ and breadcrumb row carry what it used to. === */
1335
+ 'breadcrumb.subfolders': 'Subfolders',
1336
+ 'breadcrumb.subfolders.empty': 'No subfolders here',
1337
+ 'header.admin': 'Admin panel',
1338
+ 'header.settings': 'Settings',
1339
+ 'header.signout': 'Sign out',
1340
+ 'ai.assistant': 'AI assistant',
1341
+ 'ai.soon': 'Coming soon',
1342
+ 'ai.assistant.soon': 'AI assistant — coming soon',
1343
+
1344
+ /* gorunum:v2-share — the Share / Permissions dialog's own chrome. The
1345
+ controls inside it keep the strings they already had; these are the new
1346
+ shell: the title, the one switch, the sentence that says who can open the
1347
+ item right now, and the three named sections it all folds into. */
1348
+ 'access.title': 'Share "{name}"',
1349
+ 'access.close': 'Close',
1350
+ 'access.done': 'Done',
1351
+ 'access.copy': 'Copy',
1352
+ 'access.copied': 'Copied',
1353
+ 'access.link.switch': 'Link sharing',
1354
+ 'access.who.private': 'Only people with access can open it.',
1355
+ 'access.who.link': 'Anyone with the link can open it.',
1356
+ 'access.who.pin': 'Anyone with the link and the PIN can open it.',
1357
+ 'access.who.existing': 'Link sharing is on — {n} links already exist.',
1358
+ 'access.who.existing_one': 'Link sharing is on — 1 link already exists.',
1359
+ 'access.section.link': 'Link options',
1360
+ 'access.section.people': 'People with access',
1361
+ 'access.section.drop': 'Request files',
1362
+ 'access.sum.pin_on': 'PIN on',
1363
+ 'access.sum.pin_off': 'No PIN',
1364
+ 'access.sum.people': '{n} people',
1365
+ 'access.sum.people_one': '1 person',
1366
+ 'access.sum.people_none': 'No one yet',
1367
+ 'access.sum.drop': '{n} upload links',
1368
+ 'access.sum.drop_one': '1 upload link',
1369
+ 'access.sum.drop_none': 'No upload link',
1370
+ /* Ownership — the Owner column and the People chip. "System" is the honest
1371
+ word for a row nobody put here through filex (the scanner found it, or it
1372
+ was written straight into the bucket); it is a real answer, not a blank. */
1373
+ 'col.owner': 'Owner',
1374
+ 'owner.you': 'You',
1375
+ 'owner.system': 'System',
1376
+ 'owner.unknown': 'Unknown',
1377
+ 'owner.external': 'Uploaded through an upload link',
1378
+ 'owner.last_actor': 'Last changed by {who}',
1379
+ 'filter.people': 'People',
1380
+ 'filter.people.any': 'Anyone',
1381
+ 'filter.people.me': 'You',
1382
+ 'filter.people.system': 'System',
1383
+ 'filter.people.someone': 'Someone else',
1384
+ /* surucu:d1-sort — the listing sort control at the trailing edge of the
1385
+ filter row. The four key names are `col.*`: the menu offers exactly the
1386
+ words the list view's own column headers carry, so the two controls that
1387
+ drive one sort cannot name it differently. */
1388
+ 'sort.by': 'Sort by',
1389
+ 'sort.asc': 'Ascending',
1390
+ 'sort.desc': 'Descending',
1391
+ /* The order a SEARCH RESULT is in. It is not a fifth sort key — it is what
1392
+ the control prints instead of a key while the rows on screen were ranked
1393
+ by the server, so the button stops claiming a sort it is not performing.
1394
+ `_why` is the reason the control is closed, and the owner asked for the
1395
+ reason to be written rather than for the control to go quietly inert. */
1396
+ 'sort.relevance': 'Relevance',
1397
+ 'sort.relevance_why':
1398
+ 'Search results are listed by how well they match. Your sort comes back when you leave the search.',
1399
+ /* === tablo:t1 — the table's own configuration ==========================
1400
+ Column widths and visibility are a preference about YOUR SCREEN; the view
1401
+ a folder opens in is a fact about the FOLDER. Both are set from here, and
1402
+ `folder_hint` is the rule in one sentence, written where the person who is
1403
+ about to be surprised by it can read it. */
1404
+ 'col.location': 'Location',
1405
+ 'cols.menu': 'Column options',
1406
+ 'cols.title': 'Columns',
1407
+ 'cols.resize': 'Resize {col}',
1408
+ 'cols.move_left': 'Move {col} left',
1409
+ 'cols.move_right': 'Move {col} right',
1410
+ 'cols.reset': 'Reset columns',
1411
+ 'cols.folder_title': 'Folder view',
1412
+ 'cols.folder_hint':
1413
+ 'Folders you set up keep their own view. Your last choice is the default everywhere else.',
1414
+ 'cols.forget_folder': "Forget this folder's view",
1415
+ 'cols.apply_all': 'Apply to all folders ({count} remembered)',
1416
+ /* === tablo:t1 — the trash banner ======================================
1417
+ ⚠ `retention` is only used when the deployment has TOLD us the number
1418
+ (GET /api/admin/protection). Everywhere else `retention_unknown` says the
1419
+ same thing without naming a period we cannot verify: a banner that states
1420
+ the wrong retention is worse than no banner, because people act on it. */
1421
+ 'trash.retention': 'Items in the trash are permanently deleted after {days} days.',
1422
+ 'trash.retention_one': 'Items in the trash are permanently deleted after 1 day.',
1423
+ 'trash.retention_unknown':
1424
+ 'Items in the trash are permanently deleted after a retention period set by your administrator.',
1425
+ 'trash.empty_action': 'Empty trash',
1426
+ 'trash.empty_confirm_title': 'Empty the trash?',
1427
+ 'trash.empty_confirm_body_one': 'This permanently deletes 1 item ({size}). It cannot be undone.',
1428
+ 'trash.empty_confirm_body':
1429
+ 'This permanently deletes {count} items ({size}). It cannot be undone.',
1430
+ 'trash.empty_confirm_body_nosize_one': 'This permanently deletes 1 item. It cannot be undone.',
1431
+ 'trash.empty_confirm_body_nosize': 'This permanently deletes {count} items. It cannot be undone.',
1432
+ 'trash.emptied': 'Trash emptied',
1433
+ 'empty.trash.hint': 'Files you delete land here first, so you can put them back.',
1434
+
1435
+ /* tasi:m1 — the destination picker (modals/DestinationPickerModal.vue) and
1436
+ the two selection verbs built on it. */
1437
+ 'destpicker.title.move': 'Move to',
1438
+ 'destpicker.title.copy': 'Copy to',
1439
+ 'destpicker.title.choose': 'Choose a folder',
1440
+ 'destpicker.confirm.move': 'Move here',
1441
+ 'destpicker.confirm.copy': 'Copy here',
1442
+ 'destpicker.confirm.choose': 'Choose this folder',
1443
+ 'destpicker.cancel': 'Cancel',
1444
+ 'destpicker.up': 'Up one level',
1445
+ 'destpicker.crumbs': 'Location',
1446
+ 'destpicker.drives': 'Drives',
1447
+ 'destpicker.loading': 'Loading…',
1448
+ 'destpicker.empty': 'No subfolders here',
1449
+ 'destpicker.unreadable': 'This folder cannot be opened.',
1450
+ 'destpicker.readonly': 'Read-only',
1451
+ 'destpicker.readonly_here': 'You cannot write into this folder.',
1452
+ 'destpicker.pick_a_drive': 'Open a storage to choose a folder inside it.',
1453
+ 'destpicker.target': 'Destination: {name}',
1454
+ 'destpicker.tag.blocked': 'Not allowed',
1455
+ 'destpicker.blocked.self': 'A folder cannot be moved into itself.',
1456
+ 'destpicker.blocked.descendant': 'A folder cannot be moved into one of its own subfolders.',
1457
+
1458
+ 'ctx.move_to': 'Move to…',
1459
+ 'ctx.copy_to': 'Copy to…',
1460
+ 'ctx.access.one_only': 'Sharing works on one item at a time.',
1461
+
1462
+ 'toast.archive.preparing': 'Preparing the archive…',
1463
+ 'toast.archive.started': 'Downloading {name} ({count} files)',
1464
+ 'toast.archive.started_one': 'Downloading {name} (1 file)',
1465
+ 'toast.archive.empty': 'Nothing to download — the selection contains no readable file.',
1466
+ 'toast.moved_to': 'Moved to {name}',
1467
+ 'toast.copied_to': 'Copy to {name} queued',
1061
1468
  };