@chance722/dsh-inbox 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -40,7 +40,7 @@ window.__ModuleLoader__.load({
40
40
  name: () => name
41
41
  });
42
42
  module.exports = __toCommonJS(index_exports);
43
- var import_react7 = __toESM(require("react"), 1);
43
+ var import_react8 = __toESM(require("react"), 1);
44
44
 
45
45
  // node_modules/.pnpm/lucide-react@1.47.0_react@18.3.1/node_modules/lucide-react/dist/esm/createLucideIcon.mjs
46
46
  var import_react3 = require("react");
@@ -673,53 +673,635 @@ window.__ModuleLoader__.load({
673
673
  var PANEL_ID = "inbox";
674
674
 
675
675
  // src/client/card.tsx
676
- var import_react5 = require("react");
676
+ var import_react6 = require("react");
677
677
 
678
678
  // src/client/dock.tsx
679
- var import_react4 = __toESM(require("react"), 1);
679
+ var import_react5 = __toESM(require("react"), 1);
680
680
 
681
- // src/shared/vocabulary.ts
682
- var CATEGORIES = [
683
- "idea",
684
- "article",
685
- "media",
686
- "image",
687
- "document",
688
- "secret",
689
- "other"
690
- ];
691
- var CATEGORY_LABELS = {
692
- idea: "\u7075\u611F/\u5F85\u529E",
693
- article: "\u6587\u7AE0",
694
- media: "\u89C6\u9891/\u97F3\u9891",
695
- image: "\u56FE\u7247",
696
- document: "\u8BC1\u4EF6",
697
- secret: "\u5BC6\u94A5/\u8D26\u5BC6",
698
- other: "\u5176\u5B83"
699
- };
700
- var KIND_LABELS = {
701
- text: "\u6587\u672C",
702
- link: "\u94FE\u63A5",
703
- image: "\u56FE\u7247",
704
- file: "\u6587\u4EF6"
705
- };
706
- var CATEGORY_SOURCE_LABELS = {
707
- rule: "\u89C4\u5219\u5224\u5B9A",
708
- model: "\u6A21\u578B\u5224\u5B9A",
709
- user: "\u624B\u52A8\u5224\u5B9A"
681
+ // src/client/i18n.ts
682
+ var import_react4 = require("react");
683
+
684
+ // src/client/messages.ts
685
+ var zh = {
686
+ // The record heading, shared by the list, the cards and the dock.
687
+ "heading.untitled": "\uFF08\u65E0\u6807\u9898\uFF09",
688
+ "heading.credential": "\u5BC6\u94A5 / \u8D26\u5BC6",
689
+ "heading.tooltip": "{name}\uFF08{note}\uFF09",
690
+ // Record kinds and categories, as the *panel* says them. The host keeps its
691
+ // own Chinese labels in `src/shared/vocabulary.ts` for the model and for the
692
+ // readable copy it writes to the cloud; these are the reader's language.
693
+ "kind.text": "\u6587\u672C",
694
+ "kind.link": "\u94FE\u63A5",
695
+ "kind.image": "\u56FE\u7247",
696
+ "kind.file": "\u6587\u4EF6",
697
+ "category.idea": "\u7075\u611F/\u5F85\u529E",
698
+ "category.article": "\u6587\u7AE0",
699
+ "category.media": "\u89C6\u9891/\u97F3\u9891",
700
+ "category.image": "\u56FE\u7247",
701
+ "category.document": "\u8BC1\u4EF6",
702
+ "category.secret": "\u5BC6\u94A5/\u8D26\u5BC6",
703
+ "category.other": "\u5176\u5B83",
704
+ "source.rule": "\u89C4\u5219\u5224\u5B9A",
705
+ "source.model": "\u6A21\u578B\u5224\u5B9A",
706
+ "source.user": "\u624B\u52A8\u5224\u5B9A",
707
+ "source.rule.hint": "\u672C\u5730\u89C4\u5219\u6309\u94FE\u63A5\u3001\u6587\u672C\u3001\u56FE\u7247\u7684\u5F62\u72B6\u5224\u7684\uFF0C\u6CA1\u6709\u8054\u7F51",
708
+ "source.model.hint": "\u89C4\u5219\u5224\u4E0D\u51FA\u6765\u624D\u4EA4\u7ED9\u6A21\u578B\u5224\u7684\uFF1B\u4F60\u8BF4\u7684\u8BDD\u6C38\u8FDC\u4F18\u5148\uFF0C\u968F\u65F6\u53EF\u4EE5\u6539",
709
+ "source.user.hint": "\u4F60\u81EA\u5DF1\u9009\u7684\u7C7B\u76EE\uFF0C\u89C4\u5219\u548C\u6A21\u578B\u90FD\u4E0D\u4F1A\u8986\u76D6\u5B83",
710
+ // Why a link has no fetched title (these reach the panel as `linkTitleError`).
711
+ "link.noTitle": "\u90A3\u4E2A\u9875\u9762\u91CC\u6CA1\u6709\u6807\u9898\uFF08\u6709\u4E9B\u7AD9\u70B9\u5BF9\u975E\u6D4F\u89C8\u5668\u7684\u8BF7\u6C42\u53EA\u56DE\u7A7A\u58F3\u9875\uFF0C\u6BD4\u5982\u5FAE\u4FE1\uFF09",
712
+ "link.http": "\u5BF9\u65B9\u8FD4\u56DE HTTP {status}",
713
+ "link.notHtml": "\u90A3\u4E2A\u5730\u5740\u4E0D\u662F\u7F51\u9875",
714
+ "link.unreachable": "\u8BF7\u6C42\u6CA1\u6210\u529F\uFF08\u7F51\u7EDC\u4E0D\u901A\u6216\u5BF9\u65B9\u62D2\u7EDD\uFF09",
715
+ "link.unknown": "\u539F\u56E0\u4E0D\u660E",
716
+ // Chrome above the list.
717
+ "app.settings": "\u8BBE\u7F6E",
718
+ "app.manual": "\u4F7F\u7528\u624B\u518C",
719
+ "app.counts": " \xB7 \u5171 {total} \u6761 \xB7 \u5F85\u770B {watch} \u6761 \xB7 \u56DE\u6536\u7AD9 {deleted} \u6761",
720
+ "app.refresh": "\u5237\u65B0",
721
+ "app.refreshing": "\u5237\u65B0\u4E2D\u2026",
722
+ "app.loading": "\u8BFB\u53D6\u4E2D\u2026",
723
+ "app.saving": "\u5904\u7406\u4E2D\u2026",
724
+ "app.filter": "\u7B5B\u9009",
725
+ "app.store": "\u5B58\u5165\u4ED3\u5E93",
726
+ "app.pickFile": "\u9009\u62E9\u6587\u4EF6",
727
+ "app.close": "\u5173\u95ED",
728
+ "app.remove": "\u79FB\u9664 {name}",
729
+ "app.prevPage": "\u4E0A\u4E00\u9875",
730
+ "app.nextPage": "\u4E0B\u4E00\u9875",
731
+ "pager.of": "\u7B2C {page} / {pages} \u9875",
732
+ "app.category": "\u7C7B\u76EE",
733
+ "app.tag": "\u6807\u7B7E",
734
+ "app.emptyBox": "\u8FD8\u6CA1\u4E1C\u897F\u53EF\u5B58\uFF1A\u7C98\u4E00\u6BB5\u6587\u5B57\u3001\u4E00\u4E2A\u94FE\u63A5\uFF0C\u6216\u8005\u628A\u56FE\u7247\u62D6\u8FDB\u6765",
735
+ "app.detail": "\u8BB0\u5F55\u8BE6\u60C5",
736
+ "app.noMatches": "\u6CA1\u6709\u5339\u914D\u7684\u8BB0\u5F55\u3002",
737
+ "app.binEmpty": "\u56DE\u6536\u7AD9\u662F\u7A7A\u7684\u3002",
738
+ "app.matches": "{count} \u6761\u5339\u914D",
739
+ "app.attachments": "{count} \u4E2A\u9644\u4EF6",
740
+ "app.failedCount": "\u5931\u8D25 {count}",
741
+ "app.pickOne": "\u9009\u5DE6\u8FB9\u4E00\u6761\u770B\u770B\u8BE6\u60C5\u3002",
742
+ "app.unnamedFile": "\uFF08\u672A\u547D\u540D\uFF09",
743
+ // The capture box and the search box.
744
+ "capture.placeholder": "\u7C98\u8D34\u6587\u5B57\u3001\u94FE\u63A5\uFF0C\u6216\u628A\u56FE\u7247/\u6587\u4EF6\u62D6\u5230\u8FD9\u91CC\uFF08Ctrl+Enter \u5B58\u5165\uFF09",
745
+ "search.placeholder": "\u641C\u6807\u9898\u3001\u6B63\u6587\u3001\u94FE\u63A5\u3001\u5907\u6CE8\u2026",
746
+ "modes.label": "\u5217\u8868\u6A21\u5F0F",
747
+ "modes.titleOf": "\u5217\u8868\u6A21\u5F0F\uFF1A{label}",
748
+ "modes.grid": "\u7F51\u683C",
749
+ "modes.compact": "\u7D27\u51D1",
750
+ // Filters.
751
+ "filter.all": "\u5168\u90E8",
752
+ "filter.watch": "\u5F85\u770B",
753
+ "filter.bin": "\u56DE\u6536\u7AD9",
754
+ "filter.clearBin": "\u6E05\u7A7A\u56DE\u6536\u7AD9",
755
+ "filter.untagAll": "\u628A\u6807\u7B7E\u300C{tag}\u300D\u4ECE\u6240\u6709\u8BB0\u5F55\u4E0A\u79FB\u9664\uFF08\u8BB0\u5F55\u672C\u8EAB\u4E0D\u5220\uFF09",
756
+ // The detail pane.
757
+ "detail.name": "\u540D\u79F0",
758
+ "detail.nameTitle": "\u5217\u8868\u3001\u5361\u7247\u548C\u5BF9\u8BDD\u5361\u7247\u663E\u793A\u8FD9\u4E2A\u540D\u5B57\uFF1B\u7559\u7A7A\u5219\u7528\u6587\u4EF6\u540D\u6216\u5907\u6CE8\u515C\u5E95",
759
+ "detail.namePlaceholder": "\u540D\u79F0\uFF0C\u5982\uFF1A\u8EAB\u4EFD\u8BC1\u6B63\u9762\uFF08\u7559\u7A7A\u5219\u7528\u6587\u4EF6\u540D\u515C\u5E95\uFF09",
760
+ "detail.note": "\u5907\u6CE8",
761
+ "detail.noteTitle": "\u4F60\u5199\u7684\u6C38\u8FDC\u4F18\u5148\u4E8E\u6A21\u578B\u7684\u5224\u65AD",
762
+ "detail.notePlaceholder": "\u5907\u6CE8\uFF0C\u5982\uFF1A\u8EAB\u4EFD\u8BC1\u7167 / \u5F85\u770B\u89C6\u9891 / \u8FD9\u4E2A key \u662F\u6D4B\u8BD5\u73AF\u5883\u7684\uFF08\u6CA1\u8D77\u540D\u5B57\u65F6\uFF0C\u5B83\u4F1A\u9876\u4E0A\u5F53\u5217\u8868\u91CC\u7684\u540D\u5B57\uFF09",
763
+ "detail.tagsPlaceholder": "\u8F93\u5165\u6807\u7B7E\uFF0C\u5982\uFF1A\u524D\u7AEF, \u62A5\u9500\uFF08\u9017\u53F7\u5206\u9694\uFF09",
764
+ "detail.save": "\u4FDD\u5B58\u4EE5\u4E0A",
765
+ "detail.watch": "\u6807\u4E3A\u5F85\u770B",
766
+ "detail.unwatch": "\u53D6\u6D88\u5F85\u770B",
767
+ "detail.restore": "\u6062\u590D",
768
+ "detail.delete": "\u5220\u9664",
769
+ "detail.removeTag": "\u4ECE\u8FD9\u6761\u8BB0\u5F55\u4E0A\u79FB\u9664\u300C{tag}\u300D",
770
+ "detail.updated": " \xB7 \u66F4\u65B0 {when}",
771
+ "detail.sealedNote": "\u8FD9\u6761\u8D26\u5BC6\u7684\u6B63\u6587\u662F\u5BC6\u6587\uFF0C\u73B0\u5728\u89E3\u4E0D\u5F00\u3002\u5230\u300C\u8BBE\u7F6E \u2192 \u8D26\u5BC6\u52A0\u5BC6\u300D\u89E3\u9501\uFF08\u6216\u5148\u8BBE\u4E00\u4E2A\u4E3B\u5BC6\u7801\uFF09\u5C31\u80FD\u770B\u5230\u3002",
772
+ "detail.titleMissed": "\u6CA1\u6293\u5230\u9875\u9762\u6807\u9898\uFF1A{reason}\u3002\u53EF\u4EE5\u81EA\u5DF1\u8D77\u4E2A\u540D\u5B57\u3002",
773
+ "detail.play": "\u64AD\u653E",
774
+ "detail.zoom": "\u653E\u5927\u67E5\u770B",
775
+ "detail.playInBrowser": "\u5728\u6D4F\u89C8\u5668\u91CC\u64AD\u653E",
776
+ "detail.openInBrowser": "\u5728\u6D4F\u89C8\u5668\u6253\u5F00",
777
+ "detail.zoomInPanel": "\u5728\u9762\u677F\u91CC\u653E\u5927",
778
+ "detail.foreign": "\u8FD9\u6761\u662F\u5916\u7AD9\u7684\u5185\u5BB9",
779
+ "detail.foreignBody": "\u9762\u677F\u4E0D\u5185\u5D4C\u522B\u4EBA\u7684\u64AD\u653E\u5668\uFF0C\u6240\u4EE5\u5728\u6D4F\u89C8\u5668\u91CC\u6253\u5F00\u2014\u2014\u90A3\u91CC\u624D\u662F\u5927\u5C4F\u3002",
780
+ // Settings: credentials and remote.
781
+ "settings.secrets": "\u8D26\u5BC6\u52A0\u5BC6",
782
+ "settings.secretsBody": "\u8D26\u5BC6\u6B63\u6587\u4EE5\u5BC6\u6587\u5199\u76D8\uFF1B\u4E3B\u5BC6\u7801\u548C\u5BC6\u94A5\u90FD\u4E0D\u843D\u76D8\uFF0C\u91CD\u542F\u540E\u8981\u91CD\u65B0\u89E3\u9501\u3002\u5BC6\u7801\u5FD8\u4E86\u5C31\u89E3\u4E0D\u5F00\uFF0C\u6CA1\u6709\u627E\u56DE\u3002",
783
+ "settings.masterPassword": "\u4E3B\u5BC6\u7801",
784
+ "settings.masterPasswordSet": "\u8F93\u5165\u4E3B\u5BC6\u7801",
785
+ "settings.masterPasswordNew": "\u8BBE\u4E00\u4E2A\u4E3B\u5BC6\u7801",
786
+ "settings.unlock": "\u89E3\u9501",
787
+ "settings.lock": "\u9501\u5B9A",
788
+ "settings.setOrChange": "\u8BBE\u7F6E / \u66F4\u6362",
789
+ "settings.unlocked": "\u5DF2\u89E3\u9501",
790
+ "settings.locked": "\u5DF2\u9501\u5B9A",
791
+ "settings.lockedNote": "\u5DF2\u9501\u5B9A\uFF1A\u8D26\u5BC6\u6B63\u6587\u4E0D\u53EF\u8BFB\uFF0C\u76F4\u5230\u518D\u6B21\u89E3\u9501",
792
+ "settings.noPassword": "\u8FD8\u6CA1\u8BBE\u4E3B\u5BC6\u7801",
793
+ "settings.passwordJustSet": "\u4E3B\u5BC6\u7801\u5DF2\u8BBE\u7F6E\uFF0C\u8D26\u5BC6\u4ECE\u6B64\u52A0\u5BC6\u843D\u76D8",
794
+ "settings.passwordSealed": "\u4E3B\u5BC6\u7801\u5DF2\u8BBE\u7F6E\uFF0C\u53E6\u6709 {count} \u6761\u65E7\u8BB0\u5F55\u5DF2\u4ECE\u660E\u6587\u6539\u4E3A\u5BC6\u6587",
795
+ "settings.ingest": "\u8FDC\u7AEF\u5165\u5E93",
796
+ "settings.ingestOnly": "\u53EA\u505A\u5355\u5411\uFF1A\u8FDC\u7AEF\u5F80\u91CC\u6254\uFF0C\u672C\u673A\u62C9\u4E0B\u6765\u5165\u5E93\u3002\u5BC6\u7801\u8D70 dsh \u7684\u51ED\u8BC1\u5E93\uFF0C\u4E0D\u5199\u8FDB\u914D\u7F6E\u3002",
797
+ "settings.protocol": "\u534F\u8BAE",
798
+ "settings.protocolHint": "\u6362\u534F\u8BAE\u540E\u8BB0\u5F97\u70B9\u4FDD\u5B58",
799
+ "settings.endpoint": "\u63A5\u5165\u70B9",
800
+ "settings.endpointPlaceholder": "s3.cstcloud.cn\uFF08\u4E0D\u5199\u534F\u8BAE\u9ED8\u8BA4 https\uFF09",
801
+ "settings.region": "\u533A\u57DF",
802
+ "settings.bucketAddress": "\u5730\u5740",
803
+ "settings.bucketDir": "\u76EE\u5F55",
804
+ "settings.dirS3.lead": "\u76EE\u5F55\u90A3\u4E00\u680F\u540C\u65F6\u662F S3 \u7684 key \u524D\u7F00\uFF08\u9ED8\u8BA4 ",
805
+ "settings.dirS3.mid": "\uFF0C\u4F1A\u8F6C\u6210 ",
806
+ "settings.dirS3.tail": "\uFF09\u3002",
807
+ "settings.clientId": "\u5BA2\u6237\u7AEF\u6807\u8BC6",
808
+ "settings.clientIdS3": "\u7559\u7A7A\u5373 dsh-inbox\uFF1B\u6709\u4E9B\u7F51\u5173\u6309\u5B83\u8BA4\u4EBA\uFF0C\u586B\u6210\u8FD9\u4E2A AccessKey \u7ED1\u5B9A\u7684\u5E94\u7528\u540D",
809
+ "settings.clientIdWebdav": "\u7559\u7A7A\u5373 dsh-inbox\uFF1B\u6709\u4E9B\u7F51\u5173\u6309\u5B83\u8BA4\u4EBA\uFF0C\u586B\u6210\u8FD9\u4E2A WebDAV \u8D26\u53F7\u7ED1\u5B9A\u7684\u5E94\u7528\u540D",
810
+ "settings.username": "\u7528\u6237\u540D",
811
+ "settings.password": "\u5BC6\u7801",
812
+ "settings.passwordStored": "\u5DF2\u5B58\uFF08\u7559\u7A7A\u5219\u4E0D\u6539\uFF09",
813
+ "settings.passwordStore": "\u5B58\u5728 dsh \u7684\u51ED\u8BC1\u5E93\u91CC",
814
+ "settings.signature": "\u7B7E\u540D",
815
+ "settings.signatureV2": "v2\uFF08\u8001\u7F51\u5173\u591A\u534A\u8981\u8FD9\u4E2A\uFF09",
816
+ "settings.save": "\u4FDD\u5B58",
817
+ "settings.probe": "\u81EA\u68C0",
818
+ "settings.details": "\u8BE6\u60C5\uFF08{count} \u6B21\u8BF7\u6C42\uFF09",
819
+ "settings.noServiceBody": "\u8FD9\u4E2A\u7EC4\u5408\u91CC\u6CA1\u6709\u8BBE\u7F6E\u670D\u52A1\uFF0C\u5730\u5740\u6539\u4E0D\u4E86\u2014\u2014\u4F60\u591A\u534A\u5728\u7528 headless \u5F62\u6001\u5F00\u53D1\u3002",
820
+ "settings.bucketHint": "\u522B\u7684\u8BBE\u5907\u5F80\u8FD9\u91CC\u6254\u4E1C\u897F",
821
+ // Notices (the one-line status under the toolbar).
822
+ "notice.listFailed": "\u8BFB\u53D6\u5217\u8868\u5931\u8D25\uFF1A{reason}",
823
+ "notice.listUnreadable": "\u8BFB\u53D6\u5217\u8868\u5931\u8D25\uFF1A\u5BBF\u4E3B\u8FD4\u56DE\u7684\u5185\u5BB9\u770B\u4E0D\u61C2",
824
+ "notice.detailFailed": "\u8BFB\u53D6\u8BE6\u60C5\u5931\u8D25\uFF1A{reason}",
825
+ "notice.responseUnreadable": "\u5BBF\u4E3B\u8FD4\u56DE\u4E86\u770B\u4E0D\u61C2\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09",
826
+ "notice.captureEmpty": "\u8FD8\u6CA1\u4E1C\u897F\u53EF\u5B58\uFF1A\u7C98\u4E00\u6BB5\u6587\u5B57\u3001\u4E00\u4E2A\u94FE\u63A5\uFF0C\u6216\u8005\u628A\u56FE\u7247\u62D6\u8FDB\u6765",
827
+ "notice.captureFailed": "\u6CA1\u5B58\u8FDB\u53BB\uFF1A{reason}",
828
+ "notice.saved": "\u5DF2\u5B58\u5165 {count} \u6761",
829
+ "notice.merged": "\u5408\u5E76 {count} \u6761\u91CD\u590D\u9879",
830
+ "notice.restored": "\u4ECE\u56DE\u6536\u7AD9\u53D6\u56DE {count} \u6761",
831
+ "notice.settingsSaved": "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58",
832
+ "notice.settingsUnreadable": "\u8BFB\u4E0D\u5230\u8BBE\u7F6E\uFF1A{reason}",
833
+ "notice.settingsFailed": "\u6CA1\u5B58\u4E0A\uFF1A{reason}",
834
+ "notice.probeFailed": "\u81EA\u68C0\u5931\u8D25\uFF1A{reason}",
835
+ "notice.probeDone": "\u81EA\u68C0\u7ED3\u679C\u89C1\u4E0B\u65B9",
836
+ "notice.syncing": "\u540C\u6B65\u4E2D\u2026",
837
+ "notice.pushFailed": "\u63A8\u9001\u5931\u8D25\uFF1A{reason}",
838
+ "notice.pullFailed": "\u62C9\u53D6\u5931\u8D25\uFF1A{reason}",
839
+ "notice.tagRemoved": "\u6807\u7B7E\u300C{tag}\u300D\u5DF2\u79FB\u9664",
840
+ "notice.tagRemoveFailed": "\u5220\u6807\u7B7E\u5931\u8D25\uFF1A{reason}",
841
+ "notice.purgeFailed": "\u6E05\u7A7A\u5931\u8D25\uFF1A{reason}",
842
+ "notice.purgeNoRemote": "\uFF08\u6CA1\u914D\u8FDC\u7AEF\uFF09",
843
+ "notice.purgeRemote": "\uFF0C\u4E91\u7AEF\u5220\u4E86 {count} \u4E2A\u5BF9\u8C61",
844
+ "notice.purgeDone": "\u5DF2\u6E05\u7A7A {count} \u6761{remote}{failure}",
845
+ "notice.purgeFailedAtRemote": " \xB7 \u4E91\u7AEF\u6709\u5931\u8D25\uFF1A{reason}",
846
+ "confirm.untag": "\u628A\u6807\u7B7E\u300C{tag}\u300D\u4ECE {count} \u6761\u8BB0\u5F55\u4E0A\u79FB\u9664\uFF1F\u8BB0\u5F55\u672C\u8EAB\u4E0D\u4F1A\u88AB\u5220\u9664\u3002",
847
+ "confirm.purge": "\u6E05\u7A7A\u56DE\u6536\u7AD9\u4F1A\u771F\u7684\u5220\u6389\u8FD9\u4E9B\u8BB0\u5F55\uFF1A\u672C\u673A\u8BB0\u5F55\u3001\u4EE5\u53CA\u4E91\u76D8\u4E0A\u5BF9\u5E94\u7684\u540C\u6B65\u5BF9\u8C61\uFF08\u8BB0\u5F55 JSON/\u6587\u672C\u3001\u53EA\u88AB\u8FD9\u4E9B\u8BB0\u5F55\u5F15\u7528\u7684\u9644\u4EF6\uFF09\u3002\u4E0D\u80FD\u64A4\u9500\u3002dsh \u9644\u4EF6\u4ED3\u5E93\u91CC\u7684\u539F\u59CB\u5B57\u8282\u4ECD\u7136\u7559\u7740\u3002\u7EE7\u7EED\uFF1F",
848
+ // Sync lines (push/pull status).
849
+ "sync.pushUnconfigured": "\u63A8\u9001\uFF1A\u8FD8\u6CA1\u914D\u7F6E\u8FDC\u7AEF",
850
+ "sync.pushFailed": "\u63A8\u9001\u5931\u8D25\uFF1A{reason}",
851
+ "sync.pushUnknown": "\u672A\u77E5\u539F\u56E0",
852
+ "sync.pushUpToDate": "\u63A8\u9001\uFF1A\u6CA1\u6709\u65B0\u5185\u5BB9\uFF08{count} \u6761\u5DF2\u662F\u6700\u65B0\uFF09",
853
+ "sync.pushDone": "\u63A8\u9001\uFF1A{records} \u6761\u8BB0\u5F55 / {attachments} \u4E2A\u9644\u4EF6",
854
+ "sync.pushPartial": "{head} \xB7 \u90E8\u5206\u5931\u8D25\uFF1A{reason}",
855
+ "sync.pullNoAddress": "\u8FD8\u6CA1\u914D\u7F6E\u5730\u5740",
856
+ "sync.pullFailed": "\u62C9\u53D6\u5931\u8D25\uFF1A{reason}",
857
+ "sync.pullNothingNew": "\u4E91\u7AEF\u7684\u8BB0\u5F55\u6CA1\u6709\u65B0\u7684",
858
+ "sync.pullMerged": "\u4ECE\u4E91\u7AEF\u5408\u5E76 {count} \u6761{attachments}",
859
+ "sync.pullAttachments": " / {count} \u4E2A\u9644\u4EF6",
860
+ "sync.pullDone": "\u62C9\u53D6\u5B8C\u6210\uFF1A\u8FDC\u7AEF\u5217\u51FA {listed} \u9879\uFF0C\u65B0\u5165\u5E93 {pulled} \u6761\uFF0C\u8DF3\u8FC7 {skipped} \u6761{tail}",
861
+ "sync.pullFailedCount": " \xB7 \u5931\u8D25 {count} \u6761",
862
+ "sync.thisPage": " \xB7 \u672C\u9875 {count} \u6761",
863
+ "settings.status": "{settings} \xB7 {webdav} \xB7 {s3}",
864
+ "settings.statusOn": "\u8BBE\u7F6E\u670D\u52A1\u5728",
865
+ "settings.statusOff": "\u6CA1\u6709\u8BBE\u7F6E\u670D\u52A1",
866
+ "settings.statusWebdavSet": "WebDAV \u5BC6\u7801\u5DF2\u5B58",
867
+ "settings.statusWebdavUnset": "\u8FD8\u6CA1\u5B58 WebDAV \u5BC6\u7801",
868
+ "settings.statusS3Set": "S3 \u5BC6\u94A5\u5DF2\u5B58",
869
+ "settings.statusS3Unset": "\u8FD8\u6CA1\u5B58 S3 \u5BC6\u94A5",
870
+ // Conversation cards.
871
+ "card.openThis": "\u5728\u53F3\u4FA7\u300C\u4ED3\u5E93\u300D\u91CC\u6253\u5F00\u8FD9\u6761",
872
+ "card.searchTitle": "\u{1F5C2} dsh-inbox \xB7 \u641C\u7D22\u4ED3\u5E93",
873
+ "card.getTitle": "\u{1F5C2} dsh-inbox \xB7 \u6253\u5F00\u8BB0\u5F55",
874
+ "card.error": " \xB7 \u51FA\u9519",
875
+ "card.open": "\u6253\u5F00",
876
+ "card.pending": "\uFF08\u8FD9\u6761\u8C03\u7528\u8FD8\u6CA1\u6709\u7ED3\u679C\uFF09",
877
+ // The dock beside the conversation.
878
+ "dock.title": "\u4ED3\u5E93",
879
+ "dock.description": "\u628A inbox \u653E\u5728\u5BF9\u8BDD\u65C1\u8FB9\uFF0C\u968F\u624B\u770B",
880
+ "dock.recent": "\u6700\u8FD1 {count} \u6761",
881
+ "dock.watch": " \xB7 \u5F85\u770B",
882
+ "dock.back": "\u56DE\u5230\u6700\u8FD1\u8BB0\u5F55",
883
+ "dock.backShort": "\u8FD4\u56DE\u6700\u8FD1",
884
+ "dock.note": "\u5907\u6CE8\uFF1A",
885
+ "dock.unavailable": "\u8BFB\u4E0D\u5230\u4ED3\u5E93\uFF0C\u53BB\u5DE6\u4FA7\u300C{panel}\u300D\u9762\u677F\u770B\u770B\u3002",
886
+ "dock.hint": "\u8FD9\u91CC\u662F\u968F\u624B\u770B\u3002\u6539\u7C7B\u76EE\u3001\u5220\u8BB0\u5F55\u3001\u5165\u5E93\u8BBE\u7F6E\u5728\u5DE6\u4FA7\u300C{panel}\u300D\u9762\u677F\u91CC\u3002",
887
+ "dock.gone": "\u8BFB\u4E0D\u5230\u8FD9\u6761\u8BB0\u5F55\uFF0C\u5B83\u53EF\u80FD\u5DF2\u7ECF\u88AB\u5220\u6389\u4E86\u3002",
888
+ "dock.editHint": "\u6539\u7C7B\u76EE\u3001\u6539\u5907\u6CE8\u3001\u5220\u9664\u90FD\u5728\u5DE6\u4FA7\u300C{panel}\u300D\u9762\u677F\u91CC\u3002",
889
+ // The manual, section by section.
890
+ "manual.title": "\u4F7F\u7528\u624B\u518C",
891
+ "manual.titleInline": "dsh-inbox \u600E\u4E48\u7528",
892
+ "manual.lead": "\u4E09\u5206\u949F\u770B\u5B8C",
893
+ "manual.separator": "\uFF1A",
894
+ "manual.1.title": "1. \u5F80\u91CC\u5B58",
895
+ "manual.1.panel.label": "\u9762\u677F",
896
+ "manual.1.panel.body": "\u7C98\u8D34\u6587\u5B57/\u94FE\u63A5\u3001\u62D6\u8FDB\u56FE\u7247\u6587\u4EF6\uFF0C\u6216\u70B9\u300C\u9009\u62E9\u6587\u4EF6\u2026\u300D\uFF0C\u7136\u540E\u300C\u5B58\u5165\u4ED3\u5E93\u300D\uFF08Ctrl+Enter \u4E5F\u884C\uFF09\u3002",
897
+ "manual.1.chat.label": "\u5BF9\u8BDD\u91CC",
898
+ "manual.1.chat.lead": "\u8F93\u5165 ",
899
+ "manual.1.chat.code": "/inbox \u6587\u5B57\u6216\u94FE\u63A5",
900
+ "manual.1.chat.tail": "\uFF0C\u56FE\u7247\u76F4\u63A5\u9644\u5728\u8F93\u5165\u6846\u4E0A\uFF1B\u4E0D\u53D1\u7ED9\u6A21\u578B\u3002",
901
+ "manual.1.repeat.label": "\u91CD\u590D",
902
+ "manual.1.repeat.body": "\u540C\u4E00\u6837\u4E1C\u897F\u518D\u5B58\u4E00\u6B21\u4E0D\u4F1A\u65B0\u589E\uFF0C\u4F1A\u5E76\u8FDB\u539F\u8BB0\u5F55\uFF1B\u5982\u679C\u5B83\u4E4B\u524D\u5728\u56DE\u6536\u7AD9\uFF0C\u4F1A\u987A\u624B\u53D6\u56DE\u6765\u3002",
903
+ "manual.2.title": "2. \u600E\u4E48\u7FFB\u3001\u600E\u4E48\u6539",
904
+ "manual.2.filter.label": "\u7B5B\u9009",
905
+ "manual.2.filter.body": "\u5DE6\u4FA7\u300C\u5168\u90E8 / \u5F85\u770B / \u56DE\u6536\u7AD9\u300D\u4E0E\u7C7B\u76EE\u3001\u6807\u7B7E\u4E92\u65A5\uFF1B\u300C\u5F85\u770B\u300D\u662F\u4F60\u81EA\u5DF1\u6253\u7684\u6807\u8BB0\uFF0C\u65B0\u8BB0\u5F55\u4E0D\u5E26\u4EFB\u4F55\u6807\u8BB0\u3002",
906
+ "manual.2.list.label": "\u5217\u8868",
907
+ "manual.2.list.body": "\u4E24\u79CD\u5BC6\u5EA6\uFF08\u4E24\u5217 / \u7D27\u51D1\uFF09\u968F\u624B\u5207\uFF0C\u4F1A\u8BB0\u4F4F\uFF1B\u4E0A\u9762\u641C\u7D22\u6846\u641C\u6807\u9898\u3001\u6B63\u6587\u3001\u94FE\u63A5\u3001\u5907\u6CE8\u3002",
908
+ "manual.2.detail.label": "\u8BE6\u60C5",
909
+ "manual.2.detail.body": "\u53F3\u8FB9\u4E00\u680F\u53EF\u4EE5\u6539\u540D\u79F0\u3001\u7C7B\u76EE\u3001\u5907\u6CE8\u3001\u6807\u7B7E\uFF0C\u4E5F\u80FD\u6807\u5F85\u770B\u3001\u5220\u9664\u3001\u6062\u590D\u3002",
910
+ "manual.3.title": "3. \u5217\u8868\u91CC\u663E\u793A\u7684\u540D\u5B57\u662F\u54EA\u513F\u6765\u7684",
911
+ "manual.3.order.label": "\u987A\u5E8F",
912
+ "manual.3.order.body": "\u4F60\u8D77\u7684\u540D\u79F0 \u2192 \u6293\u6765\u7684\u9875\u9762\u6807\u9898 \u2192 \u94FE\u63A5/\u6B63\u6587/\u6587\u4EF6\u540D \u2192 \u5907\u6CE8\uFF08\u6700\u540E\u515C\u5E95\uFF09\u3002",
913
+ "manual.3.icon.label": "\u7C7B\u76EE\u56FE\u6807",
914
+ "manual.3.icon.tail": " \u5404\u6709\u56FE\u6807\uFF1B\u5BC6\u94A5/\u8D26\u5BC6\u662F\u94A5\u5319\uFF0C\u4E00\u773C\u80FD\u8BA4\u51FA\u6765\u3002",
915
+ "manual.3.who.label": "\u8C01\u5224\u7684",
916
+ "manual.3.who.lead": "\u7C7B\u76EE\u65C1\u7684\u6807\u7B7E\u5206\u4E09\u79CD\uFF1A",
917
+ "manual.3.who.tail": "\uFF08\u4F60\u9009\u8FC7\u7684\u7C7B\u76EE\uFF0C\u89C4\u5219\u548C\u6A21\u578B\u90FD\u4E0D\u4F1A\u8986\u76D6\uFF09\u3002",
918
+ "manual.4.title": "4. \u5BC6\u94A5\u4E0E\u8D26\u5BC6",
919
+ "manual.4.password.label": "\u5148\u8BBE\u4E3B\u5BC6\u7801",
920
+ "manual.4.password.body": "\u8BBE\u7F6E \u2192 \u8D26\u5BC6\u52A0\u5BC6\u3002\u8BBE\u4E86\u4E4B\u540E\uFF0C\u8D26\u5BC6\u6B63\u6587\u4EE5\u5BC6\u6587\u5199\u76D8\uFF1B\u6CA1\u8BBE\u7684\u65F6\u5019\uFF0C\u8D26\u5BC6\u4E0D\u4F1A\u88AB\u5B58\u8FDB\u53BB\uFF08\u5B81\u53EF\u4E0D\u5B58\uFF0C\u4E5F\u4E0D\u5199\u660E\u6587\uFF09\u3002",
921
+ "manual.4.unlock.label": "\u6BCF\u6B21\u91CD\u542F\u8981\u89E3\u9501",
922
+ "manual.4.unlock.body": "\u4E3B\u5BC6\u7801\u548C\u5BC6\u94A5\u90FD\u4E0D\u843D\u76D8\uFF0C\u6240\u4EE5\u670D\u52A1\u4E00\u91CD\u542F\u5C31\u8981\u5728\u540C\u4E00\u4E2A\u5730\u65B9\u89E3\u9501\u4E00\u6B21\uFF1B\u5BC6\u7801\u5FD8\u4E86\u5C31\u89E3\u4E0D\u5F00\uFF0C\u6CA1\u6709\u627E\u56DE\u3002",
923
+ "manual.4.never.label": "\u6C38\u4E0D\u5916\u663E",
924
+ "manual.4.never.body": "\u5217\u8868\u91CC\u53EA\u663E\u793A\u4F60\u8D77\u7684\u540D\u5B57\uFF1B\u5BF9\u8BDD\u91CC\u53EA\u56DE\u4E00\u53E5\u300C\u660E\u6587\u4E0D\u4F1A\u901A\u8FC7\u5BF9\u8BDD\u8F93\u51FA\u300D\uFF1B\u53D1\u7ED9\u6A21\u578B\u7684\u5206\u7C7B\u8BF7\u6C42\u5148\u8131\u654F\u3002",
925
+ "manual.5.title": "5. \u540C\u6B65\uFF08\u672C\u673A \u2194 \u4E91\u76D8\uFF09",
926
+ "manual.5.auto.label": "\u81EA\u52A8",
927
+ "manual.5.auto.body": "\u5165\u5E93/\u6539\u52A8\u540E\u51E0\u79D2\u81EA\u52A8\u63A8\u9001\u4E00\u6B21\uFF08\u9632\u6296\uFF0C\u8FDE\u7740\u5B58\u4E94\u6761\u53EA\u4F1A\u63A8\u4E00\u6B21\uFF09\u3002",
928
+ "manual.5.manual.label": "\u624B\u52A8",
929
+ "manual.5.manual.body": "\u53F3\u4E0A\u89D2\u300C\u5237\u65B0\u300D= \u4E00\u6B21\u5B8C\u6574\u540C\u6B65\uFF1A\u5148\u63A8\u672C\u673A\u6539\u52A8\uFF0C\u518D\u62C9\u522B\u4EBA\u7684\uFF0C\u7136\u540E\u91CD\u8BFB\u5217\u8868\u3002",
930
+ "manual.5.delete.label": "\u5220\u9664",
931
+ "manual.5.delete.body": "\u9762\u677F\u91CC\u7684\u300C\u5220\u9664\u300D\u53EA\u662F\u628A\u5B83\u653E\u8FDB\u56DE\u6536\u7AD9\uFF08\u522B\u7684\u8BBE\u5907\u4E5F\u4F1A\u77E5\u9053\u5B83\u88AB\u5220\u4E86\uFF0C\u4E0D\u4F1A\u53C8\u88AB\u62C9\u56DE\u6765\uFF09\uFF1B\u300C\u6E05\u7A7A\u56DE\u6536\u7AD9\u300D\u624D\u662F\u771F\u5220\uFF0C\u4E91\u7AEF\u90A3\u4EFD\u4E5F\u4F1A\u4E00\u8D77\u5220\u3002",
932
+ "manual.5.conflict.label": "\u51B2\u7A81",
933
+ "manual.5.conflict.body": "\u591A\u8BBE\u5907\u6539\u540C\u4E00\u6761\u6309\u65F6\u95F4\u540E\u5199\u8D62\uFF0C\u4E0D\u7559\u51B2\u7A81\u526F\u672C\u3002\u4E0A\u4E91\u7684\u5BC6\u6587\u53EA\u6709\u8D26\u5BC6\u6B63\u6587\uFF0C\u5176\u4F59\u662F\u660E\u6587 \u2014\u2014 \u6876\u52A1\u5FC5\u8981\u6709\u8BBF\u95EE\u63A7\u5236\u3002",
934
+ "manual.6.title": "6. \u5728\u5BF9\u8BDD\u91CC\u53D6\u56DE\u6765",
935
+ "manual.6.query.label": "\u67E5",
936
+ "manual.6.query.body": "\u5728\u5BF9\u8BDD\u91CC\u76F4\u63A5\u95EE\uFF1A\u300C\u6211\u7684\u6536\u4EF6\u7BB1\u91CC\u6709\u54EA\u4E9B\u8FD8\u6CA1\u770B\u7684\u94FE\u63A5\uFF1F\u300D\u52A9\u624B\u4F1A\u53BB\u4ED3\u5E93\u91CC\u627E\uFF0C \u6700\u591A\u5217 10 \u6761\uFF0C\u5E76\u544A\u8BC9\u4F60\u8FD8\u5269\u51E0\u6761\u3002\u53EB\u5B83\u300C\u6536\u4EF6\u7BB1\u300D\u300C\u4ED3\u5E93\u300D\u300C\u4E2A\u4EBA\u4ED3\u5E93\u300D\u8FD8\u662F\u300Cinbox\u300D\u90FD\u8BA4\u3002",
937
+ "manual.6.get.label": "\u53D6",
938
+ "manual.6.get.body": "\u63A5\u7740\u8BF4\u300C\u6253\u5F00\u7B2C 3 \u6761\u300D\uFF0C\u52A9\u624B\u5C31\u628A\u90A3\u6761\u62FF\u56DE\u6765\uFF1A\u6B63\u6587\uFF08\u6700\u591A 1000 \u5B57\uFF09\u3001\u94FE\u63A5\u3001\u5907\u6CE8\u3001\u6807\u7B7E\u3001\u9644\u4EF6\u4FE1\u606F\u3002",
939
+ "manual.6.refuse.label": "\u4E24\u6761\u786C\u62D2\u7EDD",
940
+ "manual.6.refuse.body": "\u8D26\u5BC6\u6C38\u4E0D\u56DE\u660E\u6587\uFF1B\u56FE\u7247\u9ED8\u8BA4\u53EA\u56DE\u4E00\u4E2A\u6807\u8BB0\uFF0C\u7531\u754C\u9762\u5728\u672C\u673A\u753B\u51FA\u6765\u3002\u60F3\u8BA9\u52A9\u624B\u4EB2\u773C\u770B\u56FE\uFF08\u6BD4\u5982\u300C\u8FD9\u5F20\u662F\u4EC0\u4E48\u7801\u300D\uFF09\uFF0C \u76F4\u63A5\u8BF4\u300C\u5E2E\u6211\u770B\u8FD9\u5F20\u56FE\u300D\u2014\u2014\u90A3\u4E00\u6B21\u624D\u4F1A\u628A\u8FD9\u5F20\u56FE\u53D1\u7ED9\u5B83\u3002",
941
+ "manual.6.tools.label": "\u52A9\u624B\u8BF4\u4E0D\u8BA4\u8BC6\u8FD9\u4E2A\u4ED3\u5E93",
942
+ "manual.6.tools.body": "\u8BF4\u660E\u8FD9\u4E2A\u4F1A\u8BDD\u6CA1\u5E26\u4E0A\u6536\u4EF6\u7BB1\u63D2\u4EF6\u3002\u65B0\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u518D\u95EE\u4E00\u6B21\u5373\u53EF\u2014\u2014\u9762\u677F\u80FD\u7528\u3001\u52A9\u624B\u770B\u4E0D\u5230\uFF0C \u8FD9\u4E24\u4EF6\u4E8B\u662F\u5206\u5F00\u7684\u3002",
943
+ "manual.7.title": "7. \u51FA\u95EE\u9898\u5148\u770B\u8FD9\u91CC",
944
+ "manual.7.title.label": "\u94FE\u63A5\u6CA1\u540D\u5B57",
945
+ "manual.7.title.body": "\u6B63\u5E38\uFF1A\u6709\u4E9B\u7AD9\u70B9\uFF08\u5982\u5FAE\u4FE1\uFF09\u5BF9\u975E\u6D4F\u89C8\u5668\u8BF7\u6C42\u53EA\u56DE\u7A7A\u58F3\u9875\uFF0C\u6293\u4E0D\u5230\u6807\u9898\uFF1B\u70B9\u8FDB\u8BE6\u60C5\u81EA\u5DF1\u8D77\u4E2A\u540D\u5B57\u5373\u53EF\u3002",
946
+ "manual.7.zero.label": "\u4E91\u76D8\u91CC\u6709 0 \u5B57\u8282\u76EE\u5F55",
947
+ "manual.7.zero.body": "\u4E91\u76D8\u81EA\u5DF1\u5EFA\u7684\u5360\u4F4D\u5BF9\u8C61\uFF0C\u4E0D\u662F\u63D2\u4EF6\u5199\u7684\uFF0C\u53EF\u4EE5\u5FFD\u7565\u3002",
948
+ "manual.7.sync.label": "\u540C\u6B65\u4E0D\u5BF9",
949
+ "manual.7.sync.body": "\u8BBE\u7F6E\u91CC\u70B9\u300C\u81EA\u68C0\u300D\uFF1A\u4F1A\u544A\u8BC9\u4F60\u901A\u9053\u901A\u4E0D\u901A\u3001\u54EA\u79CD\u7B7E\u540D\u53EF\u7528\uFF1B\u8BA4\u8BC1\u88AB\u62D2\u901A\u5E38\u662F\u300C\u5BA2\u6237\u7AEF\u6807\u8BC6\u300D\u4E0E AccessKey \u7ED1\u5B9A\u7684\u5E94\u7528\u4E0D\u4E00\u81F4\u3002"
710
950
  };
711
- var CATEGORY_SOURCE_HINTS = {
712
- rule: "\u672C\u5730\u89C4\u5219\u6309\u94FE\u63A5\u3001\u6587\u672C\u3001\u56FE\u7247\u7684\u5F62\u72B6\u5224\u7684\uFF0C\u6CA1\u6709\u8054\u7F51",
713
- model: "\u89C4\u5219\u5224\u4E0D\u51FA\u6765\u624D\u4EA4\u7ED9\u6A21\u578B\u5224\u7684\uFF1B\u4F60\u8BF4\u7684\u8BDD\u6C38\u8FDC\u4F18\u5148\uFF0C\u968F\u65F6\u53EF\u4EE5\u6539",
714
- user: "\u4F60\u81EA\u5DF1\u9009\u7684\u7C7B\u76EE\uFF0C\u89C4\u5219\u548C\u6A21\u578B\u90FD\u4E0D\u4F1A\u8986\u76D6\u5B83"
951
+ var en = {
952
+ "heading.untitled": "(untitled)",
953
+ "heading.credential": "Credential",
954
+ "heading.tooltip": "{name} ({note})",
955
+ "kind.text": "Text",
956
+ "kind.link": "Link",
957
+ "kind.image": "Image",
958
+ "kind.file": "File",
959
+ "category.idea": "Idea/todo",
960
+ "category.article": "Article",
961
+ "category.media": "Video/audio",
962
+ "category.image": "Image",
963
+ "category.document": "ID document",
964
+ "category.secret": "Credential",
965
+ "category.other": "Other",
966
+ "source.rule": "by rule",
967
+ "source.model": "by model",
968
+ "source.user": "by you",
969
+ "source.rule.hint": "the local rules judged this from the shape of the link, text or image \u2014 no network was used",
970
+ "source.model.hint": "the rules could not decide, so the model did; what you say always wins and can be changed any time",
971
+ "source.user.hint": "the category you chose yourself \u2014 neither the rules nor the model will overwrite it",
972
+ "link.noTitle": "that page has no title (some sites answer non-browser requests with an empty shell \u2014 WeChat does)",
973
+ "link.http": "the other side answered HTTP {status}",
974
+ "link.notHtml": "that address is not a web page",
975
+ "link.unreachable": "the request did not go through (no network, or refused)",
976
+ "link.unknown": "no clear reason",
977
+ "app.settings": "Settings",
978
+ "app.manual": "Manual",
979
+ "app.counts": " \xB7 {total} total \xB7 {watch} to read \xB7 {deleted} in the bin",
980
+ "app.refresh": "Refresh",
981
+ "app.refreshing": "Refreshing\u2026",
982
+ "app.loading": "Loading\u2026",
983
+ "app.saving": "Saving\u2026",
984
+ "app.filter": "Filter",
985
+ "app.store": "Save to vault",
986
+ "app.pickFile": "Choose a file",
987
+ "app.close": "Close",
988
+ "app.remove": "Remove {name}",
989
+ "app.prevPage": "Previous",
990
+ "app.nextPage": "Next",
991
+ "pager.of": "page {page} / {pages}",
992
+ "app.category": "Category",
993
+ "app.tag": "Tag",
994
+ "app.emptyBox": "Nothing to save yet: paste some text or a link, or drop an image in",
995
+ "app.detail": "Record",
996
+ "app.noMatches": "Nothing matches.",
997
+ "app.binEmpty": "The bin is empty.",
998
+ "app.matches": "{count} matching",
999
+ "app.attachments": "{count} attachment(s)",
1000
+ "app.failedCount": "{count} failed",
1001
+ "app.pickOne": "Pick a record on the left to see it here.",
1002
+ "app.unnamedFile": "(unnamed)",
1003
+ "capture.placeholder": "Paste text or a link, or drop an image/file here (Ctrl+Enter to save)",
1004
+ "search.placeholder": "Search title, text, link, note\u2026",
1005
+ "modes.label": "List density",
1006
+ "modes.titleOf": "List density: {label}",
1007
+ "modes.grid": "Grid",
1008
+ "modes.compact": "Compact",
1009
+ "filter.all": "All",
1010
+ "filter.watch": "To read",
1011
+ "filter.bin": "Bin",
1012
+ "filter.clearBin": "Empty the bin",
1013
+ "filter.untagAll": "Remove the tag \u201C{tag}\u201D from every record (the records stay)",
1014
+ "detail.name": "Name",
1015
+ "detail.nameTitle": "The name the list, the cards and the conversation show; empty falls back to the file name or the note",
1016
+ "detail.namePlaceholder": "Name, e.g. ID card front (empty falls back to the file name)",
1017
+ "detail.note": "Note",
1018
+ "detail.noteTitle": "What you write always outranks what the model guessed",
1019
+ "detail.notePlaceholder": "Note, e.g. ID photo / video to watch / this key is for staging (when there is no name, it becomes the row\u2019s name)",
1020
+ "detail.tagsPlaceholder": "Tags, e.g. frontend, expenses (comma separated)",
1021
+ "detail.save": "Save",
1022
+ "detail.watch": "Mark to read",
1023
+ "detail.unwatch": "Unmark",
1024
+ "detail.restore": "Restore",
1025
+ "detail.delete": "Delete",
1026
+ "detail.removeTag": "Remove \u201C{tag}\u201D from this record",
1027
+ "detail.updated": " \xB7 updated {when}",
1028
+ "detail.sealedNote": "This credential\u2019s body is ciphertext and cannot be read right now. Unlock it under Settings \u2192 Credential encryption (or set a master password first).",
1029
+ "detail.titleMissed": "No page title was fetched: {reason}. You can give it a name yourself.",
1030
+ "detail.play": "Play",
1031
+ "detail.zoom": "Zoom in",
1032
+ "detail.playInBrowser": "Play in the browser",
1033
+ "detail.openInBrowser": "Open in the browser",
1034
+ "detail.zoomInPanel": "Zoom in here",
1035
+ "detail.foreign": "This one lives on another site",
1036
+ "detail.foreignBody": "the panel does not embed other people\u2019s players, so open it in the browser \u2014 that is where the big screen is.",
1037
+ "settings.secrets": "Credential encryption",
1038
+ "settings.secretsBody": "Credential bodies are written to disk as ciphertext; neither the master password nor its key is ever written down, so every restart locks it again. A forgotten password cannot be recovered.",
1039
+ "settings.masterPassword": "Master password",
1040
+ "settings.masterPasswordSet": "Enter the master password",
1041
+ "settings.masterPasswordNew": "Set a master password",
1042
+ "settings.unlock": "Unlock",
1043
+ "settings.lock": "Lock",
1044
+ "settings.setOrChange": "Set / Change",
1045
+ "settings.unlocked": "Unlocked",
1046
+ "settings.locked": "Locked",
1047
+ "settings.lockedNote": "Locked: credential bodies stay unreadable until you unlock again",
1048
+ "settings.noPassword": "No master password yet",
1049
+ "settings.passwordJustSet": "Master password set \u2014 credentials are now encrypted at rest",
1050
+ "settings.passwordSealed": "Master password set, and {count} old records went from plain text to ciphertext",
1051
+ "settings.ingest": "Drop folder",
1052
+ "settings.ingestOnly": "One way only: other devices drop files there, this machine pulls them in. The password lives in dsh\u2019s credential store, not in the config.",
1053
+ "settings.protocol": "Protocol",
1054
+ "settings.protocolHint": "save after switching protocol",
1055
+ "settings.endpoint": "Endpoint",
1056
+ "settings.endpointPlaceholder": "s3.cstcloud.cn (https assumed)",
1057
+ "settings.region": "Region",
1058
+ "settings.bucketAddress": "Address",
1059
+ "settings.bucketDir": "Directory",
1060
+ "settings.dirS3.lead": "the directory is also the key prefix for S3 (default ",
1061
+ "settings.dirS3.mid": ", which becomes ",
1062
+ "settings.dirS3.tail": ").",
1063
+ "settings.clientId": "Client identity",
1064
+ "settings.clientIdS3": "empty means dsh-inbox; some gateways identify callers by it \u2014 use the application this AccessKey is bound to",
1065
+ "settings.clientIdWebdav": "empty means dsh-inbox; some gateways identify callers by it \u2014 use the application this WebDAV account is bound to",
1066
+ "settings.username": "Username",
1067
+ "settings.password": "Password",
1068
+ "settings.passwordStored": "stored (leave empty to keep it)",
1069
+ "settings.passwordStore": "kept in dsh\u2019s credential store",
1070
+ "settings.signature": "Signature",
1071
+ "settings.signatureV2": "v2 (what older gateways usually want)",
1072
+ "settings.save": "Save",
1073
+ "settings.probe": "Test",
1074
+ "settings.details": "Details ({count} requests)",
1075
+ "settings.noServiceBody": "this composition has no settings service, so the address cannot be changed \u2014 you are most likely running the headless shape.",
1076
+ "settings.bucketHint": "other devices drop things here",
1077
+ "notice.listFailed": "Could not read the list: {reason}",
1078
+ "notice.listUnreadable": "Could not read the list: the host answered with something we cannot read",
1079
+ "notice.detailFailed": "Could not read the record: {reason}",
1080
+ "notice.responseUnreadable": "The host answered with something we cannot read (HTTP {status})",
1081
+ "notice.captureEmpty": "Nothing to save yet: paste some text or a link, or drop an image in",
1082
+ "notice.captureFailed": "Not saved: {reason}",
1083
+ "notice.saved": "Saved {count}",
1084
+ "notice.merged": "Merged {count} duplicate(s)",
1085
+ "notice.restored": "Restored {count} from the bin",
1086
+ "notice.settingsSaved": "Settings saved",
1087
+ "notice.settingsUnreadable": "Could not read the settings: {reason}",
1088
+ "notice.settingsFailed": "Not saved: {reason}",
1089
+ "notice.probeFailed": "Test failed: {reason}",
1090
+ "notice.probeDone": "The test result is below",
1091
+ "notice.syncing": "Syncing\u2026",
1092
+ "notice.pushFailed": "Push failed: {reason}",
1093
+ "notice.pullFailed": "Pull failed: {reason}",
1094
+ "notice.tagRemoved": "Tag \u201C{tag}\u201D removed",
1095
+ "notice.tagRemoveFailed": "Could not remove the tag: {reason}",
1096
+ "notice.purgeFailed": "Could not empty the bin: {reason}",
1097
+ "notice.purgeNoRemote": " (no remote configured)",
1098
+ "notice.purgeRemote": ", {count} object(s) deleted in the cloud",
1099
+ "notice.purgeDone": "Emptied {count}{remote}{failure}",
1100
+ "notice.purgeFailedAtRemote": " \xB7 the cloud had failures: {reason}",
1101
+ "confirm.untag": "Remove the tag \u201C{tag}\u201D from {count} record(s)? The records themselves stay.",
1102
+ "confirm.purge": "Emptying the bin really deletes these records: the local ones and the matching objects in the cloud (record JSON/text, plus any attachment only they referenced). It cannot be undone. The original bytes in dsh\u2019s attachment store stay. Continue?",
1103
+ "sync.pushUnconfigured": "Push: no remote configured yet",
1104
+ "sync.pushFailed": "Push failed: {reason}",
1105
+ "sync.pushUnknown": "unknown reason",
1106
+ "sync.pushUpToDate": "Push: nothing new ({count} already current)",
1107
+ "sync.pushDone": "Push: {records} records / {attachments} attachment(s)",
1108
+ "sync.pushPartial": "{head} \xB7 partly failed: {reason}",
1109
+ "sync.pullNoAddress": "No address configured yet",
1110
+ "sync.pullFailed": "Pull failed: {reason}",
1111
+ "sync.pullNothingNew": "Nothing new in the cloud",
1112
+ "sync.pullMerged": "Merged {count} from the cloud{attachments}",
1113
+ "sync.pullAttachments": " / {count} attachment(s)",
1114
+ "sync.pullDone": "Pull done: {listed} listed remotely, {pulled} filed, {skipped} skipped{tail}",
1115
+ "sync.pullFailedCount": " \xB7 {count} failed",
1116
+ "sync.thisPage": " \xB7 {count} on this page",
1117
+ "settings.status": "{settings} \xB7 {webdav} \xB7 {s3}",
1118
+ "settings.statusOn": "settings service present",
1119
+ "settings.statusOff": "no settings service",
1120
+ "settings.statusWebdavSet": "WebDAV password stored",
1121
+ "settings.statusWebdavUnset": "no WebDAV password yet",
1122
+ "settings.statusS3Set": "S3 secret stored",
1123
+ "settings.statusS3Unset": "no S3 secret yet",
1124
+ "card.openThis": "Open this in \u4ED3\u5E93 on the right",
1125
+ "card.searchTitle": "\u{1F5C2} dsh-inbox \xB7 vault search",
1126
+ "card.getTitle": "\u{1F5C2} dsh-inbox \xB7 record",
1127
+ "card.error": " \xB7 failed",
1128
+ "card.open": "Open",
1129
+ "card.pending": "(this call has no result yet)",
1130
+ "dock.title": "Vault",
1131
+ "dock.description": "The inbox, next to the conversation",
1132
+ "dock.recent": "Latest {count}",
1133
+ "dock.watch": " \xB7 to read",
1134
+ "dock.back": "Back to the latest",
1135
+ "dock.backShort": "Back",
1136
+ "dock.note": "Note: ",
1137
+ "dock.unavailable": "Could not read the vault \u2014 look at the \u201C{panel}\u201D panel on the left.",
1138
+ "dock.hint": "This is just a glance. Change the category, delete records or set up the drop folder in the \u201C{panel}\u201D panel on the left.",
1139
+ "dock.gone": "Could not read this record; it may have been deleted.",
1140
+ "dock.editHint": "Changing the category, the note or deleting all happen in the \u201C{panel}\u201D panel on the left.",
1141
+ "manual.title": "Manual",
1142
+ "manual.titleInline": "How to use dsh-inbox",
1143
+ "manual.lead": "a three-minute read",
1144
+ "manual.separator": ": ",
1145
+ "manual.1.title": "1. Getting things in",
1146
+ "manual.1.panel.label": "Panel",
1147
+ "manual.1.panel.body": "Paste text or a link, drop in images or files, or press \u201CChoose a file\u2026\u201D and then \u201CSave to vault\u201D (Ctrl+Enter works too).",
1148
+ "manual.1.chat.label": "In the conversation",
1149
+ "manual.1.chat.lead": "type ",
1150
+ "manual.1.chat.code": "/inbox text or a link",
1151
+ "manual.1.chat.tail": ", attach images straight onto the composer; nothing is sent to the model.",
1152
+ "manual.1.repeat.label": "Repeats",
1153
+ "manual.1.repeat.body": "Saving the same thing twice does not add a row \u2014 it joins the record it already has, and pulls it out of the bin if that is where it was.",
1154
+ "manual.2.title": "2. Browsing and editing",
1155
+ "manual.2.filter.label": "Filters",
1156
+ "manual.2.filter.body": "\u201CAll / To read / Bin\u201D on the left exclude categories and tags; \u201CTo read\u201D is your own flag, and new records carry none.",
1157
+ "manual.2.list.label": "List",
1158
+ "manual.2.list.body": "Two densities (grid / compact) switch with a click and are remembered; the search box covers title, text, link and note.",
1159
+ "manual.2.detail.label": "Record",
1160
+ "manual.2.detail.body": "The right-hand pane edits the name, category, note and tags, and can flag, delete or restore.",
1161
+ "manual.3.title": "3. Where a row\u2019s name comes from",
1162
+ "manual.3.order.label": "Order",
1163
+ "manual.3.order.body": "the name you typed \u2192 the fetched page title \u2192 the link/text/file name \u2192 the note (the last resort).",
1164
+ "manual.3.icon.label": "Glyphs",
1165
+ "manual.3.icon.tail": " each have their own glyph; a credential is a key, recognisable at a glance.",
1166
+ "manual.3.who.label": "Who judged it",
1167
+ "manual.3.who.lead": "the badge beside the category comes in three kinds: ",
1168
+ "manual.3.who.tail": " (a category you chose is never overwritten by rules or the model).",
1169
+ "manual.4.title": "4. Credentials",
1170
+ "manual.4.password.label": "Set a master password first",
1171
+ "manual.4.password.body": "Settings \u2192 Credential encryption. Once set, credential bodies are ciphertext on disk; without one they are refused (better not to store it than to store it in the clear).",
1172
+ "manual.4.unlock.label": "Every restart locks it",
1173
+ "manual.4.unlock.body": "neither the password nor its key is written down, so a restart needs one unlock in the same place; a forgotten password cannot be recovered.",
1174
+ "manual.4.never.label": "Never shown",
1175
+ "manual.4.never.body": "the list shows only the name you gave it; a conversation gets a one-line refusal; classification requests are redacted first.",
1176
+ "manual.5.title": "5. Sync (this machine \u2194 the cloud)",
1177
+ "manual.5.auto.label": "Automatic",
1178
+ "manual.5.auto.body": "a few seconds after a capture or an edit a push goes out (debounced \u2014 five quick saves push once).",
1179
+ "manual.5.manual.label": "Manual",
1180
+ "manual.5.manual.body": "\u201CRefresh\u201D in the top right is a full sync: push local changes, pull the others, then re-read the list.",
1181
+ "manual.5.delete.label": "Deleting",
1182
+ "manual.5.delete.body": "\u201CDelete\u201D in the panel only moves a record to the bin (other devices learn it is gone instead of pushing it back); emptying the bin is the real delete, and the cloud copy goes with it.",
1183
+ "manual.5.conflict.label": "Conflicts",
1184
+ "manual.5.conflict.body": "two devices editing one record: the later write wins, no conflict copies. Only credential bodies travel encrypted \u2014 everything else is plain text up there, so the bucket needs access control.",
1185
+ "manual.6.title": "6. Getting things back in the conversation",
1186
+ "manual.6.query.label": "Ask",
1187
+ "manual.6.query.body": "just ask: \u201Cwhich links in my inbox haven\u2019t I read yet?\u201D The assistant searches the vault, lists at most 10, and tells you how many are left. \u6536\u4EF6\u7BB1 / \u4ED3\u5E93 / inbox all mean the same shelf.",
1188
+ "manual.6.get.label": "Fetch",
1189
+ "manual.6.get.body": "then say \u201Copen number 3\u201D and it comes back: text (up to 1000 characters), link, note, tags and attachment facts.",
1190
+ "manual.6.refuse.label": "Two hard refusals",
1191
+ "manual.6.refuse.body": "a credential never comes back in clear text, and an image comes back as a marker the UI draws locally. To have the assistant look at a picture (say, \u201Cwhat is this code?\u201D), ask it to \u2014 that one call sends that one image.",
1192
+ "manual.6.tools.label": "The assistant says it does not know this vault",
1193
+ "manual.6.tools.body": "this session was not started with the inbox plugin. Open a new session and ask again \u2014 the panel working and the assistant seeing the tools are two different things.",
1194
+ "manual.7.title": "7. When something looks wrong",
1195
+ "manual.7.title.label": "A link has no name",
1196
+ "manual.7.title.body": "normal: some sites (WeChat among them) serve non-browser requests an empty shell page with no title. Open the record and name it yourself.",
1197
+ "manual.7.zero.label": "A 0-byte directory in the cloud",
1198
+ "manual.7.zero.body": "a placeholder the cloud drive made itself, not something the plugin wrote \u2014 ignore it.",
1199
+ "manual.7.sync.label": "Sync looks wrong",
1200
+ "manual.7.sync.body": "press \u201CTest\u201D in Settings: it says whether the channel works and which signature shape is accepted. An authentication refusal usually means the client identity does not match the application the AccessKey is bound to."
715
1201
  };
1202
+ var MESSAGES = { zh, en };
1203
+
1204
+ // src/client/i18n.ts
1205
+ var MESSAGES_NS = "dsh-inbox";
1206
+ var service;
1207
+ var bound;
1208
+ var observed;
1209
+ var revision = 0;
1210
+ var listeners = /* @__PURE__ */ new Set();
1211
+ function notify() {
1212
+ revision += 1;
1213
+ for (const listener of listeners) listener();
1214
+ }
1215
+ function subscribeToLocale(listener) {
1216
+ listeners.add(listener);
1217
+ return () => {
1218
+ listeners.delete(listener);
1219
+ };
1220
+ }
1221
+ function localeRevision() {
1222
+ return revision;
1223
+ }
1224
+ function useLocaleRevision() {
1225
+ return (0, import_react4.useSyncExternalStore)(subscribeToLocale, localeRevision, localeRevision);
1226
+ }
1227
+ function resolveLanguage(tag) {
1228
+ return tag !== void 0 && tag.toLowerCase().startsWith("zh") ? "zh" : "en";
1229
+ }
1230
+ function documentLanguage() {
1231
+ if (typeof document === "undefined") return void 0;
1232
+ const tag = document.documentElement?.getAttribute("lang");
1233
+ return typeof tag === "string" && tag.length > 0 ? tag : void 0;
1234
+ }
1235
+ function browserLanguage() {
1236
+ if (typeof navigator === "undefined") return void 0;
1237
+ const preferred = navigator.languages?.[0] ?? navigator.language;
1238
+ return typeof preferred === "string" && preferred.length > 0 ? preferred : void 0;
1239
+ }
1240
+ function activeLanguage() {
1241
+ return resolveLanguage(observed ?? documentLanguage() ?? browserLanguage());
1242
+ }
1243
+ function fill(text, params) {
1244
+ return text.replace(
1245
+ /\{(\w+)\}/g,
1246
+ (whole, name2) => name2 in params ? String(params[name2]) : whole
1247
+ );
1248
+ }
1249
+ function t(key, params) {
1250
+ const text = bound?.(key) ?? MESSAGES[activeLanguage()][key] ?? MESSAGES.en[key] ?? key;
1251
+ return params === void 0 ? text : fill(text, params);
1252
+ }
1253
+ function kindLabel(kind) {
1254
+ return t(`kind.${kind}`);
1255
+ }
1256
+ function categoryLabel(category) {
1257
+ return t(`category.${category}`);
1258
+ }
1259
+ function sourceLabel(source) {
1260
+ return t(`source.${source}`);
1261
+ }
1262
+ function sourceHint(source) {
1263
+ return t(`source.${source}.hint`);
1264
+ }
1265
+ function observeDocument() {
1266
+ observed = documentLanguage();
1267
+ if (typeof MutationObserver === "undefined" || typeof document === "undefined") return () => {
1268
+ };
1269
+ const observer = new MutationObserver(() => {
1270
+ const next = documentLanguage();
1271
+ if (next === observed) return;
1272
+ observed = next;
1273
+ notify();
1274
+ });
1275
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] });
1276
+ return () => {
1277
+ observer.disconnect();
1278
+ };
1279
+ }
1280
+ function installLocale(ctx) {
1281
+ const locale = ctx.get("locale");
1282
+ if (locale === void 0) {
1283
+ ctx.effect(() => observeDocument(), "dsh-inbox: follow <html lang>");
1284
+ return;
1285
+ }
1286
+ service = locale;
1287
+ ctx.effect(() => locale.register(MESSAGES_NS, "zh", MESSAGES.zh), "dsh-inbox: zh dictionary");
1288
+ ctx.effect(() => locale.register(MESSAGES_NS, "en", MESSAGES.en), "dsh-inbox: en dictionary");
1289
+ bound = locale.bind(MESSAGES_NS);
1290
+ observed = locale.getSnapshot().active;
1291
+ ctx.effect(
1292
+ () => locale.subscribe(() => {
1293
+ observed = locale.getSnapshot().active;
1294
+ notify();
1295
+ }),
1296
+ "dsh-inbox: language changes"
1297
+ );
1298
+ }
716
1299
 
717
1300
  // src/client/heading.ts
718
1301
  var NOTE_IN_HEADING_CHARS = 24;
719
1302
  function isSecret(entry) {
720
1303
  return entry.category === "secret";
721
1304
  }
722
- var UNTITLED = "\uFF08\u65E0\u6807\u9898\uFF09";
723
1305
  function firstFilled(...values) {
724
1306
  return values.find((value) => value !== void 0 && value.trim().length > 0);
725
1307
  }
@@ -737,7 +1319,7 @@ window.__ModuleLoader__.load({
737
1319
  if (title !== void 0) return title;
738
1320
  const own = ownName(entry);
739
1321
  if (own !== void 0) return own;
740
- return noteLine(entry.note, noteChars) || (isSecret(entry) ? "\u5BC6\u94A5 / \u8D26\u5BC6" : UNTITLED);
1322
+ return noteLine(entry.note, noteChars) || (isSecret(entry) ? t("heading.credential") : t("heading.untitled"));
741
1323
  }
742
1324
  function headingOf(entry) {
743
1325
  return build(entry, NOTE_IN_HEADING_CHARS);
@@ -745,7 +1327,7 @@ window.__ModuleLoader__.load({
745
1327
  function headingTooltipOf(entry) {
746
1328
  const name2 = build(entry, Number.MAX_SAFE_INTEGER);
747
1329
  const note = noteLine(entry.note, Number.MAX_SAFE_INTEGER);
748
- return note.length === 0 || note === name2 ? name2 : `${name2}\uFF08${note}\uFF09`;
1330
+ return note.length === 0 || note === name2 ? name2 : t("heading.tooltip", { name: name2, note });
749
1331
  }
750
1332
 
751
1333
  // src/client/dock.tsx
@@ -757,10 +1339,10 @@ window.__ModuleLoader__.load({
757
1339
  function dockFocusOf(info) {
758
1340
  const navigation = info?.tab?.navigation;
759
1341
  const wanted = navigation?.params?.id;
760
- const revision = navigation?.revision;
1342
+ const revision2 = navigation?.revision;
761
1343
  return {
762
1344
  ...typeof wanted === "string" && wanted.length > 0 ? { id: wanted } : {},
763
- revision: typeof revision === "number" ? revision : 0
1345
+ revision: typeof revision2 === "number" ? revision2 : 0
764
1346
  };
765
1347
  }
766
1348
  function registerInboxDock(ctx) {
@@ -772,9 +1354,9 @@ window.__ModuleLoader__.load({
772
1354
  tabs.register({
773
1355
  id: DOCK_TAB_ID,
774
1356
  kind: DOCK_KIND,
775
- title: () => "\u4ED3\u5E93",
1357
+ title: () => t("dock.title"),
776
1358
  guide: [
777
- { order: 20, title: () => "\u4ED3\u5E93", description: () => "\u628A inbox \u653E\u5728\u5BF9\u8BDD\u65C1\u8FB9\uFF0C\u968F\u624B\u770B" }
1359
+ { order: 20, title: () => t("dock.title"), description: () => t("dock.description") }
778
1360
  ]
779
1361
  });
780
1362
  slots.inject(
@@ -793,14 +1375,15 @@ window.__ModuleLoader__.load({
793
1375
  });
794
1376
  }
795
1377
  function InboxDock(props) {
1378
+ useLocaleRevision();
796
1379
  const info = (props?.useTabInfo ?? props?.hooks?.tabInfo)?.();
797
- const { id: focused, revision } = dockFocusOf(info);
798
- return focused === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DockList, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DockRecord, { id: focused, revision });
1380
+ const { id: focused, revision: revision2 } = dockFocusOf(info);
1381
+ return focused === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DockList, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DockRecord, { id: focused, revision: revision2 });
799
1382
  }
800
1383
  function DockList() {
801
- const [entries, setEntries] = import_react4.default.useState();
802
- const [failed, setFailed] = import_react4.default.useState(false);
803
- import_react4.default.useEffect(() => {
1384
+ const [entries, setEntries] = import_react5.default.useState();
1385
+ const [failed, setFailed] = import_react5.default.useState(false);
1386
+ import_react5.default.useEffect(() => {
804
1387
  let live = true;
805
1388
  void (async () => {
806
1389
  try {
@@ -822,8 +1405,8 @@ window.__ModuleLoader__.load({
822
1405
  };
823
1406
  }, []);
824
1407
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "10px 12px", fontSize: 13 }, children: [
825
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { opacity: 0.6, marginBottom: 8 }, children: entries === void 0 ? "\u8BFB\u53D6\u4E2D\u2026" : `\u6700\u8FD1 ${String(entries.length)} \u6761` }),
826
- failed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.7 }, children: "\u8BFB\u4E0D\u5230\u4ED3\u5E93\uFF0C\u53BB\u5DE6\u4FA7\u300CInbox\u300D\u9762\u677F\u770B\u770B\u3002" }),
1408
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { opacity: 0.6, marginBottom: 8 }, children: entries === void 0 ? t("app.loading") : t("dock.recent", { count: entries.length }) }),
1409
+ failed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.7 }, children: t("dock.unavailable", { panel: "Inbox" }) }),
827
1410
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 6 }, children: entries?.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
828
1411
  "li",
829
1412
  {
@@ -836,22 +1419,22 @@ window.__ModuleLoader__.load({
836
1419
  children: [
837
1420
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { overflowWrap: "anywhere" }, children: headingOf(entry) }),
838
1421
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 12, opacity: 0.6, marginTop: 2 }, children: [
839
- KIND_LABELS[entry.kind],
1422
+ kindLabel(entry.kind),
840
1423
  " \xB7 ",
841
- CATEGORY_LABELS[entry.category],
842
- entry.watchLater ? " \xB7 \u5F85\u770B" : ""
1424
+ categoryLabel(entry.category),
1425
+ entry.watchLater ? t("dock.watch") : ""
843
1426
  ] })
844
1427
  ]
845
1428
  },
846
1429
  entry.id
847
1430
  )) }),
848
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.6, marginTop: 10 }, children: "\u8FD9\u91CC\u662F\u968F\u624B\u770B\u3002\u6539\u7C7B\u76EE\u3001\u5220\u8BB0\u5F55\u3001\u5165\u5E93\u8BBE\u7F6E\u5728\u5DE6\u4FA7\u300CInbox\u300D\u9762\u677F\u91CC\u3002" })
1431
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.6, marginTop: 10 }, children: t("dock.hint", { panel: "Inbox" }) })
849
1432
  ] });
850
1433
  }
851
- function DockRecord({ id, revision }) {
852
- const [entry, setEntry] = import_react4.default.useState();
853
- const [failed, setFailed] = import_react4.default.useState(false);
854
- import_react4.default.useEffect(() => {
1434
+ function DockRecord({ id, revision: revision2 }) {
1435
+ const [entry, setEntry] = import_react5.default.useState();
1436
+ const [failed, setFailed] = import_react5.default.useState(false);
1437
+ import_react5.default.useEffect(() => {
855
1438
  let live = true;
856
1439
  setEntry(void 0);
857
1440
  setFailed(false);
@@ -873,17 +1456,17 @@ window.__ModuleLoader__.load({
873
1456
  return () => {
874
1457
  live = false;
875
1458
  };
876
- }, [id, revision]);
1459
+ }, [id, revision2]);
877
1460
  const clause = { margin: "6px 0 0", overflowWrap: "anywhere" };
878
1461
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "10px 12px", fontSize: 13 }, children: [
879
1462
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }, children: [
880
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { style: { minWidth: 0, overflowWrap: "anywhere" }, children: "\u4ED3\u5E93" }),
1463
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { style: { minWidth: 0, overflowWrap: "anywhere" }, children: t("dock.title") }),
881
1464
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
882
1465
  "button",
883
1466
  {
884
1467
  type: "button",
885
1468
  onClick: () => openVaultDock?.(),
886
- title: "\u56DE\u5230\u6700\u8FD1\u8BB0\u5F55",
1469
+ title: t("dock.back"),
887
1470
  style: {
888
1471
  marginLeft: "auto",
889
1472
  font: "inherit",
@@ -895,23 +1478,23 @@ window.__ModuleLoader__.load({
895
1478
  color: "inherit",
896
1479
  cursor: "pointer"
897
1480
  },
898
- children: "\u8FD4\u56DE\u6700\u8FD1"
1481
+ children: t("dock.backShort")
899
1482
  }
900
1483
  )
901
1484
  ] }),
902
- failed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.7 }, children: "\u8BFB\u4E0D\u5230\u8FD9\u6761\u8BB0\u5F55\uFF0C\u5B83\u53EF\u80FD\u5DF2\u7ECF\u88AB\u5220\u6389\u4E86\u3002" }),
903
- entry === void 0 && !failed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.6 }, children: "\u8BFB\u53D6\u4E2D\u2026" }),
1485
+ failed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.7 }, children: t("dock.gone") }),
1486
+ entry === void 0 && !failed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.6 }, children: t("app.loading") }),
904
1487
  entry !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
905
1488
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { overflowWrap: "anywhere", fontWeight: 500 }, children: headingOf(entry) }),
906
1489
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 12, opacity: 0.6, marginTop: 2 }, children: [
907
- KIND_LABELS[entry.kind],
1490
+ kindLabel(entry.kind),
908
1491
  " \xB7 ",
909
- CATEGORY_LABELS[entry.category],
910
- entry.watchLater ? " \xB7 \u5F85\u770B" : "",
1492
+ categoryLabel(entry.category),
1493
+ entry.watchLater ? t("dock.watch") : "",
911
1494
  ` \xB7 ${new Date(entry.createdAt).toLocaleString()}`
912
1495
  ] }),
913
1496
  entry.note !== void 0 && entry.note.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: clause, children: [
914
- "\u5907\u6CE8\uFF1A",
1497
+ t("dock.note"),
915
1498
  entry.note
916
1499
  ] }),
917
1500
  entry.url !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: clause, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: entry.url, target: "_blank", rel: "noreferrer", children: entry.url }) }),
@@ -943,7 +1526,7 @@ window.__ModuleLoader__.load({
943
1526
  children: entry.text
944
1527
  }
945
1528
  ),
946
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.6, marginTop: 10 }, children: "\u6539\u7C7B\u76EE\u3001\u6539\u5907\u6CE8\u3001\u5220\u9664\u90FD\u5728\u5DE6\u4FA7\u300CInbox\u300D\u9762\u677F\u91CC\u3002" })
1529
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { opacity: 0.6, marginTop: 10 }, children: t("dock.editHint", { panel: "Inbox" }) })
947
1530
  ] })
948
1531
  ] });
949
1532
  }
@@ -966,11 +1549,11 @@ window.__ModuleLoader__.load({
966
1549
  }
967
1550
  function RecordLink({ id }) {
968
1551
  if (openVaultDock === void 0) return null;
969
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1552
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
970
1553
  "button",
971
1554
  {
972
1555
  type: "button",
973
- title: "\u5728\u53F3\u4FA7\u300C\u4ED3\u5E93\u300D\u91CC\u6253\u5F00\u8FD9\u6761",
1556
+ title: t("card.openThis"),
974
1557
  onClick: () => openVaultDock?.(id),
975
1558
  style: {
976
1559
  font: "inherit",
@@ -982,7 +1565,10 @@ window.__ModuleLoader__.load({
982
1565
  color: "inherit",
983
1566
  cursor: "pointer"
984
1567
  },
985
- children: "\u6253\u5F00 \u2197"
1568
+ children: [
1569
+ t("card.open"),
1570
+ " \u2197"
1571
+ ]
986
1572
  }
987
1573
  );
988
1574
  }
@@ -1062,6 +1648,7 @@ window.__ModuleLoader__.load({
1062
1648
  return nodes;
1063
1649
  }
1064
1650
  function InboxToolCard({ toolName, block }) {
1651
+ useLocaleRevision();
1065
1652
  const text = resultText(block);
1066
1653
  const isError = block.isError === true;
1067
1654
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
@@ -1076,10 +1663,10 @@ window.__ModuleLoader__.load({
1076
1663
  },
1077
1664
  children: [
1078
1665
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { opacity: 0.65, marginBottom: 6 }, children: [
1079
- toolName === "inbox_search" ? "\u{1F5C2} dsh-inbox \xB7 \u641C\u7D22\u4ED3\u5E93" : "\u{1F5C2} dsh-inbox \xB7 \u6253\u5F00\u8BB0\u5F55",
1080
- isError ? " \xB7 \u51FA\u9519" : ""
1666
+ toolName === "inbox_search" ? t("card.searchTitle") : t("card.getTitle"),
1667
+ isError ? t("card.error") : ""
1081
1668
  ] }),
1082
- text === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { opacity: 0.6 }, children: "\uFF08\u8FD9\u6761\u8C03\u7528\u8FD8\u6CA1\u6709\u7ED3\u679C\uFF09" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { whiteSpace: "pre-wrap" }, children: render(text) })
1669
+ text === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { opacity: 0.6 }, children: t("card.pending") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { whiteSpace: "pre-wrap" }, children: render(text) })
1083
1670
  ]
1084
1671
  }
1085
1672
  );
@@ -1094,7 +1681,21 @@ window.__ModuleLoader__.load({
1094
1681
  }
1095
1682
 
1096
1683
  // src/client/manual.tsx
1097
- var import_react6 = require("react");
1684
+ var import_react7 = require("react");
1685
+
1686
+ // src/shared/vocabulary.ts
1687
+ var CATEGORIES = [
1688
+ "idea",
1689
+ "article",
1690
+ "media",
1691
+ "image",
1692
+ "document",
1693
+ "secret",
1694
+ "other"
1695
+ ];
1696
+ var CATEGORY_SOURCES = ["rule", "model", "user"];
1697
+
1698
+ // src/client/manual.tsx
1098
1699
  var import_jsx_runtime3 = require("react/jsx-runtime");
1099
1700
  function Section({
1100
1701
  title,
@@ -1108,16 +1709,17 @@ window.__ModuleLoader__.load({
1108
1709
  function Line({ label, children }) {
1109
1710
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { style: { margin: 0 }, children: [
1110
1711
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { style: { fontWeight: 600 }, children: label }),
1111
- label.length === 0 ? "" : "\uFF1A",
1712
+ label.length === 0 ? "" : t("manual.separator"),
1112
1713
  children
1113
1714
  ] });
1114
1715
  }
1115
1716
  function ManualDialog({ onClose }) {
1717
+ useLocaleRevision();
1116
1718
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1117
1719
  "div",
1118
1720
  {
1119
1721
  role: "dialog",
1120
- "aria-label": "\u4F7F\u7528\u624B\u518C",
1722
+ "aria-label": t("manual.title"),
1121
1723
  style: {
1122
1724
  position: "fixed",
1123
1725
  inset: 0,
@@ -1167,8 +1769,8 @@ window.__ModuleLoader__.load({
1167
1769
  borderBottom: "1px solid color-mix(in srgb, currentColor 12%, transparent)"
1168
1770
  },
1169
1771
  children: [
1170
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { style: { fontSize: 16 }, children: "dsh-inbox \u600E\u4E48\u7528" }),
1171
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { opacity: 0.6, fontSize: 12 }, children: "\u4E09\u5206\u949F\u770B\u5B8C" }),
1772
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { style: { fontSize: 16 }, children: t("manual.titleInline") }),
1773
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { opacity: 0.6, fontSize: 12 }, children: t("manual.lead") }),
1172
1774
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1173
1775
  "button",
1174
1776
  {
@@ -1184,7 +1786,7 @@ window.__ModuleLoader__.load({
1184
1786
  color: "inherit",
1185
1787
  cursor: "pointer"
1186
1788
  },
1187
- children: "\u5173\u95ED"
1789
+ children: t("app.close")
1188
1790
  }
1189
1791
  )
1190
1792
  ]
@@ -1202,53 +1804,53 @@ window.__ModuleLoader__.load({
1202
1804
  minHeight: 0
1203
1805
  },
1204
1806
  children: [
1205
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: "1. \u5F80\u91CC\u5B58", children: [
1206
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u9762\u677F", children: "\u7C98\u8D34\u6587\u5B57/\u94FE\u63A5\u3001\u62D6\u8FDB\u56FE\u7247\u6587\u4EF6\uFF0C\u6216\u70B9\u300C\u9009\u62E9\u6587\u4EF6\u2026\u300D\uFF0C\u7136\u540E\u300C\u5B58\u5165\u4ED3\u5E93\u300D\uFF08Ctrl+Enter \u4E5F\u884C\uFF09\u3002" }),
1207
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Line, { label: "\u5BF9\u8BDD\u91CC", children: [
1208
- "\u8F93\u5165 ",
1209
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: "/inbox \u6587\u5B57\u6216\u94FE\u63A5" }),
1210
- "\uFF0C\u56FE\u7247\u76F4\u63A5\u9644\u5728\u8F93\u5165\u6846\u4E0A\uFF1B\u4E0D\u53D1\u7ED9\u6A21\u578B\u3002"
1807
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: t("manual.1.title"), children: [
1808
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.1.panel.label"), children: t("manual.1.panel.body") }),
1809
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Line, { label: t("manual.1.chat.label"), children: [
1810
+ t("manual.1.chat.lead"),
1811
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: t("manual.1.chat.code") }),
1812
+ t("manual.1.chat.tail")
1211
1813
  ] }),
1212
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u91CD\u590D", children: "\u540C\u4E00\u6837\u4E1C\u897F\u518D\u5B58\u4E00\u6B21\u4E0D\u4F1A\u65B0\u589E\uFF0C\u4F1A\u5E76\u8FDB\u539F\u8BB0\u5F55\uFF1B\u5982\u679C\u5B83\u4E4B\u524D\u5728\u56DE\u6536\u7AD9\uFF0C\u4F1A\u987A\u624B\u53D6\u56DE\u6765\u3002" })
1814
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.1.repeat.label"), children: t("manual.1.repeat.body") })
1213
1815
  ] }),
1214
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: "2. \u600E\u4E48\u7FFB\u3001\u600E\u4E48\u6539", children: [
1215
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u7B5B\u9009", children: "\u5DE6\u4FA7\u300C\u5168\u90E8 / \u5F85\u770B / \u56DE\u6536\u7AD9\u300D\u4E0E\u7C7B\u76EE\u3001\u6807\u7B7E\u4E92\u65A5\uFF1B\u300C\u5F85\u770B\u300D\u662F\u4F60\u81EA\u5DF1\u6253\u7684\u6807\u8BB0\uFF0C\u65B0\u8BB0\u5F55\u4E0D\u5E26\u4EFB\u4F55\u6807\u8BB0\u3002" }),
1216
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u5217\u8868", children: "\u4E24\u79CD\u5BC6\u5EA6\uFF08\u4E24\u5217 / \u7D27\u51D1\uFF09\u968F\u624B\u5207\uFF0C\u4F1A\u8BB0\u4F4F\uFF1B\u4E0A\u9762\u641C\u7D22\u6846\u641C\u6807\u9898\u3001\u6B63\u6587\u3001\u94FE\u63A5\u3001\u5907\u6CE8\u3002" }),
1217
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u8BE6\u60C5", children: "\u53F3\u8FB9\u4E00\u680F\u53EF\u4EE5\u6539\u540D\u79F0\u3001\u7C7B\u76EE\u3001\u5907\u6CE8\u3001\u6807\u7B7E\uFF0C\u4E5F\u80FD\u6807\u5F85\u770B\u3001\u5220\u9664\u3001\u6062\u590D\u3002" })
1816
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: t("manual.2.title"), children: [
1817
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.2.filter.label"), children: t("manual.2.filter.body") }),
1818
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.2.list.label"), children: t("manual.2.list.body") }),
1819
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.2.detail.label"), children: t("manual.2.detail.body") })
1218
1820
  ] }),
1219
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: "3. \u5217\u8868\u91CC\u663E\u793A\u7684\u540D\u5B57\u662F\u54EA\u513F\u6765\u7684", children: [
1220
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u987A\u5E8F", children: "\u4F60\u8D77\u7684\u540D\u79F0 \u2192 \u6293\u6765\u7684\u9875\u9762\u6807\u9898 \u2192 \u94FE\u63A5/\u6B63\u6587/\u6587\u4EF6\u540D \u2192 \u5907\u6CE8\uFF08\u6700\u540E\u515C\u5E95\uFF09\u3002" }),
1221
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Line, { label: "\u7C7B\u76EE\u56FE\u6807", children: [
1222
- Object.values(CATEGORY_LABELS).join(" / "),
1223
- " \u5404\u6709\u56FE\u6807\uFF1B\u5BC6\u94A5/\u8D26\u5BC6\u662F\u94A5\u5319\uFF0C\u4E00\u773C\u80FD\u8BA4\u51FA\u6765\u3002"
1821
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: t("manual.3.title"), children: [
1822
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.3.order.label"), children: t("manual.3.order.body") }),
1823
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Line, { label: t("manual.3.icon.label"), children: [
1824
+ CATEGORIES.map((category) => categoryLabel(category)).join(" / "),
1825
+ t("manual.3.icon.tail")
1224
1826
  ] }),
1225
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Line, { label: "\u8C01\u5224\u7684", children: [
1226
- "\u7C7B\u76EE\u65C1\u7684\u6807\u7B7E\u5206\u4E09\u79CD\uFF1A",
1227
- Object.values(CATEGORY_SOURCE_LABELS).join(" / "),
1228
- "\uFF08\u4F60\u9009\u8FC7\u7684\u7C7B\u76EE\uFF0C\u89C4\u5219\u548C\u6A21\u578B\u90FD\u4E0D\u4F1A\u8986\u76D6\uFF09\u3002"
1827
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Line, { label: t("manual.3.who.label"), children: [
1828
+ t("manual.3.who.lead"),
1829
+ CATEGORY_SOURCES.map((source) => sourceLabel(source)).join(" / "),
1830
+ t("manual.3.who.tail")
1229
1831
  ] })
1230
1832
  ] }),
1231
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: "4. \u5BC6\u94A5\u4E0E\u8D26\u5BC6", children: [
1232
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u5148\u8BBE\u4E3B\u5BC6\u7801", children: "\u8BBE\u7F6E \u2192 \u8D26\u5BC6\u52A0\u5BC6\u3002\u8BBE\u4E86\u4E4B\u540E\uFF0C\u8D26\u5BC6\u6B63\u6587\u4EE5\u5BC6\u6587\u5199\u76D8\uFF1B\u6CA1\u8BBE\u7684\u65F6\u5019\uFF0C\u8D26\u5BC6\u4E0D\u4F1A\u88AB\u5B58\u8FDB\u53BB\uFF08\u5B81\u53EF\u4E0D\u5B58\uFF0C\u4E5F\u4E0D\u5199\u660E\u6587\uFF09\u3002" }),
1233
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u6BCF\u6B21\u91CD\u542F\u8981\u89E3\u9501", children: "\u4E3B\u5BC6\u7801\u548C\u5BC6\u94A5\u90FD\u4E0D\u843D\u76D8\uFF0C\u6240\u4EE5\u670D\u52A1\u4E00\u91CD\u542F\u5C31\u8981\u5728\u540C\u4E00\u4E2A\u5730\u65B9\u89E3\u9501\u4E00\u6B21\uFF1B\u5BC6\u7801\u5FD8\u4E86\u5C31\u89E3\u4E0D\u5F00\uFF0C\u6CA1\u6709\u627E\u56DE\u3002" }),
1234
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u6C38\u4E0D\u5916\u663E", children: "\u5217\u8868\u91CC\u53EA\u663E\u793A\u4F60\u8D77\u7684\u540D\u5B57\uFF1B\u5BF9\u8BDD\u91CC\u53EA\u56DE\u4E00\u53E5\u300C\u660E\u6587\u4E0D\u4F1A\u901A\u8FC7\u5BF9\u8BDD\u8F93\u51FA\u300D\uFF1B\u53D1\u7ED9\u6A21\u578B\u7684\u5206\u7C7B\u8BF7\u6C42\u5148\u8131\u654F\u3002" })
1833
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: t("manual.4.title"), children: [
1834
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.4.password.label"), children: t("manual.4.password.body") }),
1835
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.4.unlock.label"), children: t("manual.4.unlock.body") }),
1836
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.4.never.label"), children: t("manual.4.never.body") })
1235
1837
  ] }),
1236
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: "5. \u540C\u6B65\uFF08\u672C\u673A \u2194 \u4E91\u76D8\uFF09", children: [
1237
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u81EA\u52A8", children: "\u5165\u5E93/\u6539\u52A8\u540E\u51E0\u79D2\u81EA\u52A8\u63A8\u9001\u4E00\u6B21\uFF08\u9632\u6296\uFF0C\u8FDE\u7740\u5B58\u4E94\u6761\u53EA\u4F1A\u63A8\u4E00\u6B21\uFF09\u3002" }),
1238
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u624B\u52A8", children: "\u53F3\u4E0A\u89D2\u300C\u5237\u65B0\u300D= \u4E00\u6B21\u5B8C\u6574\u540C\u6B65\uFF1A\u5148\u63A8\u672C\u673A\u6539\u52A8\uFF0C\u518D\u62C9\u522B\u4EBA\u7684\uFF0C\u7136\u540E\u91CD\u8BFB\u5217\u8868\u3002" }),
1239
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u5220\u9664", children: "\u9762\u677F\u91CC\u7684\u300C\u5220\u9664\u300D\u53EA\u662F\u628A\u5B83\u653E\u8FDB\u56DE\u6536\u7AD9\uFF08\u522B\u7684\u8BBE\u5907\u4E5F\u4F1A\u77E5\u9053\u5B83\u88AB\u5220\u4E86\uFF0C\u4E0D\u4F1A\u53C8\u88AB\u62C9\u56DE\u6765\uFF09\uFF1B \u300C\u6E05\u7A7A\u56DE\u6536\u7AD9\u300D\u624D\u662F\u771F\u5220\uFF0C\u4E91\u7AEF\u90A3\u4EFD\u4E5F\u4F1A\u4E00\u8D77\u5220\u3002" }),
1240
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u51B2\u7A81", children: "\u591A\u8BBE\u5907\u6539\u540C\u4E00\u6761\u6309\u65F6\u95F4\u540E\u5199\u8D62\uFF0C\u4E0D\u7559\u51B2\u7A81\u526F\u672C\u3002\u4E0A\u4E91\u7684\u5BC6\u6587\u53EA\u6709\u8D26\u5BC6\u6B63\u6587\uFF0C\u5176\u4F59\u662F\u660E\u6587\u2014\u2014\u6876\u52A1\u5FC5\u8981\u6709\u8BBF\u95EE\u63A7\u5236\u3002" })
1838
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: t("manual.5.title"), children: [
1839
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.5.auto.label"), children: t("manual.5.auto.body") }),
1840
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.5.manual.label"), children: t("manual.5.manual.body") }),
1841
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.5.delete.label"), children: t("manual.5.delete.body") }),
1842
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.5.conflict.label"), children: t("manual.5.conflict.body") })
1241
1843
  ] }),
1242
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: "6. \u5728\u5BF9\u8BDD\u91CC\u53D6\u56DE\u6765", children: [
1243
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u67E5", children: "\u5728\u5BF9\u8BDD\u91CC\u76F4\u63A5\u95EE\uFF1A\u300C\u6211\u7684\u6536\u4EF6\u7BB1\u91CC\u6709\u54EA\u4E9B\u8FD8\u6CA1\u770B\u7684\u94FE\u63A5\uFF1F\u300D\u52A9\u624B\u4F1A\u53BB\u4ED3\u5E93\u91CC\u627E\uFF0C \u6700\u591A\u5217 10 \u6761\uFF0C\u5E76\u544A\u8BC9\u4F60\u8FD8\u5269\u51E0\u6761\u3002\u53EB\u5B83\u300C\u6536\u4EF6\u7BB1\u300D\u300C\u4ED3\u5E93\u300D\u300C\u4E2A\u4EBA\u4ED3\u5E93\u300D\u8FD8\u662F\u300Cinbox\u300D\u90FD\u8BA4\u3002" }),
1244
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u53D6", children: "\u63A5\u7740\u8BF4\u300C\u6253\u5F00\u7B2C 3 \u6761\u300D\uFF0C\u52A9\u624B\u5C31\u628A\u90A3\u6761\u62FF\u56DE\u6765\uFF1A\u6B63\u6587\uFF08\u6700\u591A 1000 \u5B57\uFF09\u3001\u94FE\u63A5\u3001\u5907\u6CE8\u3001\u6807\u7B7E\u3001\u9644\u4EF6\u4FE1\u606F\u3002" }),
1245
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u4E24\u6761\u786C\u62D2\u7EDD", children: "\u8D26\u5BC6\u6C38\u4E0D\u56DE\u660E\u6587\uFF1B\u56FE\u7247\u9ED8\u8BA4\u53EA\u56DE\u4E00\u4E2A\u6807\u8BB0\uFF0C\u7531\u754C\u9762\u5728\u672C\u673A\u753B\u51FA\u6765\u3002\u60F3\u8BA9\u52A9\u624B\u4EB2\u773C\u770B\u56FE\uFF08\u6BD4\u5982\u300C\u8FD9\u5F20\u662F\u4EC0\u4E48\u7801\u300D\uFF09\uFF0C \u76F4\u63A5\u8BF4\u300C\u5E2E\u6211\u770B\u8FD9\u5F20\u56FE\u300D\u2014\u2014\u90A3\u4E00\u6B21\u624D\u4F1A\u628A\u8FD9\u5F20\u56FE\u53D1\u7ED9\u5B83\u3002" }),
1246
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u52A9\u624B\u8BF4\u4E0D\u8BA4\u8BC6\u8FD9\u4E2A\u4ED3\u5E93", children: "\u8BF4\u660E\u8FD9\u4E2A\u4F1A\u8BDD\u6CA1\u5E26\u4E0A\u6536\u4EF6\u7BB1\u63D2\u4EF6\u3002\u65B0\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u518D\u95EE\u4E00\u6B21\u5373\u53EF\u2014\u2014\u9762\u677F\u80FD\u7528\u3001\u52A9\u624B\u770B\u4E0D\u5230\uFF0C \u8FD9\u4E24\u4EF6\u4E8B\u662F\u5206\u5F00\u7684\u3002" })
1844
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: t("manual.6.title"), children: [
1845
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.6.query.label"), children: t("manual.6.query.body") }),
1846
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.6.get.label"), children: t("manual.6.get.body") }),
1847
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.6.refuse.label"), children: t("manual.6.refuse.body") }),
1848
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.6.tools.label"), children: t("manual.6.tools.body") })
1247
1849
  ] }),
1248
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: "7. \u51FA\u95EE\u9898\u5148\u770B\u8FD9\u91CC", children: [
1249
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u94FE\u63A5\u6CA1\u540D\u5B57", children: "\u6B63\u5E38\uFF1A\u6709\u4E9B\u7AD9\u70B9\uFF08\u5982\u5FAE\u4FE1\uFF09\u5BF9\u975E\u6D4F\u89C8\u5668\u8BF7\u6C42\u53EA\u56DE\u7A7A\u58F3\u9875\uFF0C\u6293\u4E0D\u5230\u6807\u9898\uFF1B\u70B9\u8FDB\u8BE6\u60C5\u81EA\u5DF1\u8D77\u4E2A\u540D\u5B57\u5373\u53EF\u3002" }),
1250
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u4E91\u76D8\u91CC\u6709 0 \u5B57\u8282\u76EE\u5F55", children: "\u4E91\u76D8\u81EA\u5DF1\u5EFA\u7684\u5360\u4F4D\u5BF9\u8C61\uFF0C\u4E0D\u662F\u63D2\u4EF6\u5199\u7684\uFF0C\u53EF\u4EE5\u5FFD\u7565\u3002" }),
1251
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: "\u540C\u6B65\u4E0D\u5BF9", children: "\u8BBE\u7F6E\u91CC\u70B9\u300C\u81EA\u68C0\u300D\uFF1A\u4F1A\u544A\u8BC9\u4F60\u901A\u9053\u901A\u4E0D\u901A\u3001\u54EA\u79CD\u7B7E\u540D\u53EF\u7528\uFF1B\u8BA4\u8BC1\u88AB\u62D2\u901A\u5E38\u662F\u300C\u5BA2\u6237\u7AEF\u6807\u8BC6\u300D\u4E0E AccessKey \u7ED1\u5B9A\u7684\u5E94\u7528\u4E0D\u4E00\u81F4\u3002" })
1850
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { title: t("manual.7.title"), children: [
1851
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.7.title.label"), children: t("manual.7.title.body") }),
1852
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.7.zero.label"), children: t("manual.7.zero.body") }),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { label: t("manual.7.sync.label"), children: t("manual.7.sync.body") })
1252
1854
  ] })
1253
1855
  ]
1254
1856
  }
@@ -1294,6 +1896,7 @@ window.__ModuleLoader__.load({
1294
1896
  function apply(ctx) {
1295
1897
  const slots = ctx.get("slots");
1296
1898
  if (slots === void 0) return;
1899
+ installLocale(ctx);
1297
1900
  slots.inject(
1298
1901
  "sidebar.panellist",
1299
1902
  () => slots.register(
@@ -1374,12 +1977,12 @@ window.__ModuleLoader__.load({
1374
1977
  var CONTROL_HEIGHT = "calc(1.6em + 12px)";
1375
1978
  function titleFailureText(code) {
1376
1979
  if (code === "no-title") {
1377
- return "\u90A3\u4E2A\u9875\u9762\u91CC\u6CA1\u6709\u6807\u9898\uFF08\u6709\u4E9B\u7AD9\u70B9\u5BF9\u975E\u6D4F\u89C8\u5668\u7684\u8BF7\u6C42\u53EA\u56DE\u7A7A\u58F3\u9875\uFF0C\u6BD4\u5982\u5FAE\u4FE1\uFF09";
1980
+ return t("link.noTitle");
1378
1981
  }
1379
- if (code.startsWith("http:")) return `\u5BF9\u65B9\u8FD4\u56DE HTTP ${code.slice("http:".length)}`;
1380
- if (code.startsWith("not-html:")) return "\u90A3\u4E2A\u5730\u5740\u4E0D\u662F\u7F51\u9875";
1381
- if (code.startsWith("network:")) return "\u8BF7\u6C42\u6CA1\u6210\u529F\uFF08\u7F51\u7EDC\u4E0D\u901A\u6216\u5BF9\u65B9\u62D2\u7EDD\uFF09";
1382
- return "\u539F\u56E0\u4E0D\u660E";
1982
+ if (code.startsWith("http:")) return t("link.http", { status: code.slice("http:".length) });
1983
+ if (code.startsWith("not-html:")) return t("link.notHtml");
1984
+ if (code.startsWith("network:")) return t("link.unreachable");
1985
+ return t("link.unknown");
1383
1986
  }
1384
1987
  var paneRowStyle = { flex: "none" };
1385
1988
  var selectStyle = {
@@ -1477,31 +2080,32 @@ window.__ModuleLoader__.load({
1477
2080
  padding: "5px 8px"
1478
2081
  };
1479
2082
  function InboxPanel() {
1480
- const [text, setText] = import_react7.default.useState("");
1481
- const [staged, setStaged] = import_react7.default.useState([]);
1482
- const [notice, setNotice] = import_react7.default.useState();
1483
- const [busy, setBusy] = import_react7.default.useState(false);
1484
- const [dragging, setDragging] = import_react7.default.useState(false);
1485
- const picker = import_react7.default.useRef(null);
1486
- const [scope, setScope] = import_react7.default.useState("live");
1487
- const [watchOnly, setWatchOnly] = import_react7.default.useState(false);
1488
- const [category, setCategory] = import_react7.default.useState();
1489
- const [tag, setTag] = import_react7.default.useState();
1490
- const [search, setSearch] = import_react7.default.useState("");
1491
- const [query, setQuery] = import_react7.default.useState("");
1492
- const [list, setList] = import_react7.default.useState();
1493
- const [selectedId, setSelectedId] = import_react7.default.useState();
1494
- const [detail, setDetail] = import_react7.default.useState();
1495
- const [settingsOpen, setSettingsOpen] = import_react7.default.useState(false);
1496
- const [manualOpen, setManualOpen] = import_react7.default.useState(false);
1497
- const [listMode, setListMode] = import_react7.default.useState("grid");
1498
- const [page, setPage] = import_react7.default.useState(0);
1499
- const [zoom, setZoom] = import_react7.default.useState();
1500
- const [panelWidth, setPanelWidth] = import_react7.default.useState(1200);
1501
- const [railOpen, setRailOpen] = import_react7.default.useState(false);
1502
- const panelRef = import_react7.default.useRef(null);
1503
- const [scheme, setScheme] = import_react7.default.useState(() => schemeOf(null));
1504
- import_react7.default.useEffect(() => {
2083
+ useLocaleRevision();
2084
+ const [text, setText] = import_react8.default.useState("");
2085
+ const [staged, setStaged] = import_react8.default.useState([]);
2086
+ const [notice, setNotice] = import_react8.default.useState();
2087
+ const [busy, setBusy] = import_react8.default.useState(false);
2088
+ const [dragging, setDragging] = import_react8.default.useState(false);
2089
+ const picker = import_react8.default.useRef(null);
2090
+ const [scope, setScope] = import_react8.default.useState("live");
2091
+ const [watchOnly, setWatchOnly] = import_react8.default.useState(false);
2092
+ const [category, setCategory] = import_react8.default.useState();
2093
+ const [tag, setTag] = import_react8.default.useState();
2094
+ const [search, setSearch] = import_react8.default.useState("");
2095
+ const [query, setQuery] = import_react8.default.useState("");
2096
+ const [list, setList] = import_react8.default.useState();
2097
+ const [selectedId, setSelectedId] = import_react8.default.useState();
2098
+ const [detail, setDetail] = import_react8.default.useState();
2099
+ const [settingsOpen, setSettingsOpen] = import_react8.default.useState(false);
2100
+ const [manualOpen, setManualOpen] = import_react8.default.useState(false);
2101
+ const [listMode, setListMode] = import_react8.default.useState("grid");
2102
+ const [page, setPage] = import_react8.default.useState(0);
2103
+ const [zoom, setZoom] = import_react8.default.useState();
2104
+ const [panelWidth, setPanelWidth] = import_react8.default.useState(1200);
2105
+ const [railOpen, setRailOpen] = import_react8.default.useState(false);
2106
+ const panelRef = import_react8.default.useRef(null);
2107
+ const [scheme, setScheme] = import_react8.default.useState(() => schemeOf(null));
2108
+ import_react8.default.useEffect(() => {
1505
2109
  const element = panelRef.current;
1506
2110
  if (element === null || typeof ResizeObserver === "undefined") return;
1507
2111
  const observer = new ResizeObserver((entries) => {
@@ -1510,7 +2114,7 @@ window.__ModuleLoader__.load({
1510
2114
  observer.observe(element);
1511
2115
  return () => observer.disconnect();
1512
2116
  }, []);
1513
- import_react7.default.useEffect(() => {
2117
+ import_react8.default.useEffect(() => {
1514
2118
  const read = () => setScheme(schemeOf(panelRef.current));
1515
2119
  read();
1516
2120
  if (typeof MutationObserver === "undefined") return;
@@ -1526,7 +2130,7 @@ window.__ModuleLoader__.load({
1526
2130
  }, []);
1527
2131
  const narrow = panelWidth < 960;
1528
2132
  const hairline = "color-mix(in srgb, currentColor 12%, transparent)";
1529
- const call = import_react7.default.useCallback(
2133
+ const call = import_react8.default.useCallback(
1530
2134
  async (endpoint, payload) => {
1531
2135
  try {
1532
2136
  const response = await fetch(`${INBOX_API_PREFIX}/${endpoint}`, {
@@ -1540,7 +2144,7 @@ window.__ModuleLoader__.load({
1540
2144
  ok: false,
1541
2145
  error: {
1542
2146
  code: "inbox/malformed-answer",
1543
- message: `\u5BBF\u4E3B\u8FD4\u56DE\u4E86\u770B\u4E0D\u61C2\u7684\u54CD\u5E94\uFF08HTTP ${String(response.status)}\uFF09`,
2147
+ message: t("notice.responseUnreadable", { status: response.status }),
1544
2148
  details: {}
1545
2149
  }
1546
2150
  };
@@ -1559,7 +2163,7 @@ window.__ModuleLoader__.load({
1559
2163
  },
1560
2164
  []
1561
2165
  );
1562
- const refresh = import_react7.default.useCallback(
2166
+ const refresh = import_react8.default.useCallback(
1563
2167
  async (keepSelection = true) => {
1564
2168
  const result = await call(INBOX_ENDPOINT_LIST, {
1565
2169
  scope,
@@ -1571,12 +2175,12 @@ window.__ModuleLoader__.load({
1571
2175
  offset: page * PAGE_SIZE
1572
2176
  });
1573
2177
  if (!result.ok) {
1574
- setNotice(`\u8BFB\u53D6\u5217\u8868\u5931\u8D25\uFF1A${result.error.message}`);
2178
+ setNotice(t("notice.listFailed", { reason: result.error.message }));
1575
2179
  return;
1576
2180
  }
1577
2181
  const next = result.value;
1578
2182
  if (!Array.isArray(next.entries)) {
1579
- setNotice("\u8BFB\u53D6\u5217\u8868\u5931\u8D25\uFF1A\u5BBF\u4E3B\u8FD4\u56DE\u7684\u5185\u5BB9\u770B\u4E0D\u61C2");
2183
+ setNotice(t("notice.listUnreadable"));
1580
2184
  return;
1581
2185
  }
1582
2186
  setList(next);
@@ -1587,16 +2191,16 @@ window.__ModuleLoader__.load({
1587
2191
  },
1588
2192
  [call, category, page, query, scope, selectedId, tag, watchOnly]
1589
2193
  );
1590
- import_react7.default.useEffect(() => {
2194
+ import_react8.default.useEffect(() => {
1591
2195
  void refresh();
1592
2196
  }, [refresh]);
1593
- import_react7.default.useEffect(() => {
2197
+ import_react8.default.useEffect(() => {
1594
2198
  refreshRef.current = refresh;
1595
2199
  }, [refresh]);
1596
- import_react7.default.useEffect(() => {
2200
+ import_react8.default.useEffect(() => {
1597
2201
  setPage(0);
1598
2202
  }, [scope, watchOnly, category, tag, query]);
1599
- import_react7.default.useEffect(() => {
2203
+ import_react8.default.useEffect(() => {
1600
2204
  const onKey = (event) => {
1601
2205
  if (event.key !== "Escape") return;
1602
2206
  setZoom(void 0);
@@ -1605,14 +2209,14 @@ window.__ModuleLoader__.load({
1605
2209
  window.addEventListener("keydown", onKey);
1606
2210
  return () => window.removeEventListener("keydown", onKey);
1607
2211
  }, []);
1608
- import_react7.default.useEffect(() => {
2212
+ import_react8.default.useEffect(() => {
1609
2213
  if (notice === void 0 || notice.length === 0) return;
1610
2214
  const timer = window.setTimeout(() => setNotice(void 0), 4e3);
1611
2215
  return () => window.clearTimeout(timer);
1612
2216
  }, [notice]);
1613
- const refreshRef = import_react7.default.useRef(async () => {
2217
+ const refreshRef = import_react8.default.useRef(async () => {
1614
2218
  });
1615
- import_react7.default.useEffect(() => {
2219
+ import_react8.default.useEffect(() => {
1616
2220
  void (async () => {
1617
2221
  const answer = await call(INBOX_ENDPOINT_UI, { action: "read" });
1618
2222
  if (!answer.ok) return;
@@ -1620,39 +2224,39 @@ window.__ModuleLoader__.load({
1620
2224
  if (UI_LIST_MODES.includes(prefs.listMode)) setListMode(prefs.listMode);
1621
2225
  })();
1622
2226
  }, [call]);
1623
- const chooseListMode = import_react7.default.useCallback(
2227
+ const chooseListMode = import_react8.default.useCallback(
1624
2228
  (mode) => {
1625
2229
  setListMode(mode);
1626
2230
  void call(INBOX_ENDPOINT_UI, { action: "save", listMode: mode });
1627
2231
  },
1628
2232
  [call]
1629
2233
  );
1630
- const refreshAll = import_react7.default.useCallback(async () => {
2234
+ const refreshAll = import_react8.default.useCallback(async () => {
1631
2235
  setBusy(true);
1632
- setNotice("\u540C\u6B65\u4E2D\u2026");
2236
+ setNotice(t("notice.syncing"));
1633
2237
  try {
1634
2238
  const pushed = await call(INBOX_ENDPOINT_PUSH, {});
1635
- const pushLine = pushed.ok ? describePush(pushed.value) : `\u63A8\u9001\u5931\u8D25\uFF1A${pushed.error.message}`;
2239
+ const pushLine = pushed.ok ? describePush(pushed.value) : t("notice.pushFailed", { reason: pushed.error.message });
1636
2240
  const pulled = await call(INBOX_ENDPOINT_PULL, {});
1637
2241
  let suffix = "";
1638
2242
  if (pulled.ok) {
1639
2243
  const result = pulled.value;
1640
2244
  suffix = ` \xB7 ${describePull(result)}`;
1641
2245
  } else {
1642
- suffix = ` \xB7 \u62C9\u53D6\u5931\u8D25\uFF1A${pulled.error.message}`;
2246
+ suffix = ` \xB7 ${t("notice.pullFailed", { reason: pulled.error.message })}`;
1643
2247
  }
1644
2248
  await refresh();
1645
2249
  const total = list?.matched;
1646
2250
  setNotice(
1647
- `${pushLine}${suffix}${total === void 0 ? "" : ` \xB7 \u672C\u9875 ${String(total)} \u6761`}`
2251
+ `${pushLine}${suffix}${total === void 0 ? "" : t("sync.thisPage", { count: total })}`
1648
2252
  );
1649
2253
  } finally {
1650
2254
  setBusy(false);
1651
2255
  }
1652
2256
  }, [call, list?.matched, refresh]);
1653
- const removeTagEverywhere = import_react7.default.useCallback(
2257
+ const removeTagEverywhere = import_react8.default.useCallback(
1654
2258
  async (name2, count) => {
1655
- if (!window.confirm(`\u628A\u6807\u7B7E\u300C${name2}\u300D\u4ECE ${String(count)} \u6761\u8BB0\u5F55\u4E0A\u79FB\u9664\uFF1F\u8BB0\u5F55\u672C\u8EAB\u4E0D\u4F1A\u88AB\u5220\u9664\u3002`))
2259
+ if (!window.confirm(t("confirm.untag", { tag: name2, count })))
1656
2260
  return;
1657
2261
  setBusy(true);
1658
2262
  try {
@@ -1661,28 +2265,28 @@ window.__ModuleLoader__.load({
1661
2265
  tag: name2
1662
2266
  });
1663
2267
  if (!result.ok) {
1664
- setNotice(`\u5220\u6807\u7B7E\u5931\u8D25\uFF1A${result.error.message}`);
2268
+ setNotice(t("notice.tagRemoveFailed", { reason: result.error.message }));
1665
2269
  return;
1666
2270
  }
1667
2271
  setTag(void 0);
1668
2272
  await refresh(false);
1669
- setNotice(`\u6807\u7B7E\u300C${name2}\u300D\u5DF2\u79FB\u9664`);
2273
+ setNotice(t("notice.tagRemoved", { tag: name2 }));
1670
2274
  } finally {
1671
2275
  setBusy(false);
1672
2276
  }
1673
2277
  },
1674
2278
  [call, refresh]
1675
2279
  );
1676
- import_react7.default.useEffect(() => {
2280
+ import_react8.default.useEffect(() => {
1677
2281
  const timer = window.setTimeout(() => setQuery(search), 250);
1678
2282
  return () => window.clearTimeout(timer);
1679
2283
  }, [search]);
1680
- const openDetail = import_react7.default.useCallback(
2284
+ const openDetail = import_react8.default.useCallback(
1681
2285
  async (id) => {
1682
2286
  setSelectedId(id);
1683
2287
  const result = await call(INBOX_ENDPOINT_DETAIL, { id });
1684
2288
  if (!result.ok) {
1685
- setNotice(`\u8BFB\u53D6\u8BE6\u60C5\u5931\u8D25\uFF1A${result.error.message}`);
2289
+ setNotice(t("notice.detailFailed", { reason: result.error.message }));
1686
2290
  setDetail(void 0);
1687
2291
  return;
1688
2292
  }
@@ -1690,7 +2294,7 @@ window.__ModuleLoader__.load({
1690
2294
  },
1691
2295
  [call]
1692
2296
  );
1693
- const mutate = import_react7.default.useCallback(
2297
+ const mutate = import_react8.default.useCallback(
1694
2298
  async (endpoint, payload, { dropSelection = false } = {}) => {
1695
2299
  setBusy(true);
1696
2300
  try {
@@ -1714,18 +2318,22 @@ window.__ModuleLoader__.load({
1714
2318
  },
1715
2319
  [call, openDetail, refresh, selectedId]
1716
2320
  );
1717
- const purge = import_react7.default.useCallback(async () => {
2321
+ const purge = import_react8.default.useCallback(async () => {
1718
2322
  setBusy(true);
1719
2323
  try {
1720
2324
  const result = await call(INBOX_ENDPOINT_PURGE, {});
1721
2325
  if (!result.ok) {
1722
- setNotice(`\u6E05\u7A7A\u5931\u8D25\uFF1A${result.error.message}`);
2326
+ setNotice(t("notice.purgeFailed", { reason: result.error.message }));
1723
2327
  return;
1724
2328
  }
1725
2329
  const value = result.value;
1726
- const remote = value.remoteSkipped === true ? "\uFF08\u6CA1\u914D\u8FDC\u7AEF\uFF09" : value.remoteRemoved === void 0 ? "" : `\uFF0C\u4E91\u7AEF\u5220\u4E86 ${String(value.remoteRemoved)} \u4E2A\u5BF9\u8C61`;
2330
+ const remote = value.remoteSkipped === true ? t("notice.purgeNoRemote") : value.remoteRemoved === void 0 ? "" : t("notice.purgeRemote", { count: value.remoteRemoved });
1727
2331
  setNotice(
1728
- `\u5DF2\u6E05\u7A7A ${String(value.removed)} \u6761${remote}${value.reason === void 0 ? "" : ` \xB7 \u4E91\u7AEF\u6709\u5931\u8D25\uFF1A${value.reason}`}`
2332
+ t("notice.purgeDone", {
2333
+ count: value.removed,
2334
+ remote,
2335
+ failure: value.reason === void 0 ? "" : t("notice.purgeFailedAtRemote", { reason: value.reason })
2336
+ })
1729
2337
  );
1730
2338
  setSelectedId(void 0);
1731
2339
  setDetail(void 0);
@@ -1740,7 +2348,7 @@ window.__ModuleLoader__.load({
1740
2348
  const isImage = INBOX_IMAGE_TYPES.includes(file.type);
1741
2349
  next.push({
1742
2350
  id: `${file.name}:${file.size}:${file.lastModified}:${next.length}`,
1743
- name: file.name.length === 0 ? "\uFF08\u672A\u547D\u540D\uFF09" : file.name,
2351
+ name: file.name.length === 0 ? t("app.unnamedFile") : file.name,
1744
2352
  slot: isImage ? "image" : "file",
1745
2353
  bytes: file.size,
1746
2354
  file,
@@ -1768,7 +2376,7 @@ window.__ModuleLoader__.load({
1768
2376
  if (busy) return;
1769
2377
  const trimmed = text.trim();
1770
2378
  if (trimmed.length === 0 && staged.length === 0) {
1771
- setNotice("\u8FD8\u6CA1\u4E1C\u897F\u53EF\u5B58\uFF1A\u7C98\u4E00\u6BB5\u6587\u5B57\u3001\u4E00\u4E2A\u94FE\u63A5\uFF0C\u6216\u8005\u628A\u56FE\u7247\u62D6\u8FDB\u6765");
2379
+ setNotice(t("notice.captureEmpty"));
1772
2380
  return;
1773
2381
  }
1774
2382
  setBusy(true);
@@ -1790,7 +2398,7 @@ window.__ModuleLoader__.load({
1790
2398
  }
1791
2399
  const result = await call(INBOX_ENDPOINT_CAPTURE, { text: trimmed, images, files });
1792
2400
  if (!result.ok) {
1793
- setNotice(`\u6CA1\u5B58\u8FDB\u53BB\uFF1A${result.error.message}`);
2401
+ setNotice(t("notice.captureFailed", { reason: result.error.message }));
1794
2402
  return;
1795
2403
  }
1796
2404
  setNotice(describe(result.value));
@@ -1820,16 +2428,16 @@ window.__ModuleLoader__.load({
1820
2428
  const pageCount = Math.max(1, Math.ceil((list?.matched ?? 0) / PAGE_SIZE));
1821
2429
  const listTitle = (() => {
1822
2430
  const parts = [];
1823
- if (scope === "bin") parts.push("\u56DE\u6536\u7AD9");
2431
+ if (scope === "bin") parts.push(t("filter.bin"));
1824
2432
  else {
1825
- if (category !== void 0) parts.push(CATEGORY_LABELS[category]);
1826
- if (watchOnly) parts.push("\u5F85\u770B");
2433
+ if (category !== void 0) parts.push(categoryLabel(category));
2434
+ if (watchOnly) parts.push(t("filter.watch"));
1827
2435
  }
1828
2436
  if (tag !== void 0) parts.push(`#${tag}`);
1829
- return parts.length === 0 ? "\u5168\u90E8" : parts.join(" \xB7 ");
2437
+ return parts.length === 0 ? t("filter.all") : parts.join(" \xB7 ");
1830
2438
  })();
1831
2439
  const zoomKind = zoom?.mime?.startsWith("video/") === true ? "video" : zoom?.mime?.startsWith("audio/") === true ? "audio" : "image";
1832
- const openEntryPreview = import_react7.default.useCallback((entry) => {
2440
+ const openEntryPreview = import_react8.default.useCallback((entry) => {
1833
2441
  if (entry.previewId !== void 0) {
1834
2442
  setZoom({
1835
2443
  src: attachmentUrl(entry.previewId),
@@ -1846,7 +2454,7 @@ window.__ModuleLoader__.load({
1846
2454
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { style: { margin: "0 0 4px" }, children: "dsh-inbox" }),
1847
2455
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: { margin: 0, opacity: 0.7 }, children: [
1848
2456
  PACKAGE_NAME,
1849
- list === void 0 ? "" : ` \xB7 \u5171 ${String(list.total)} \u6761 \xB7 \u5F85\u770B ${String(list.watchLater)} \u6761 \xB7 \u56DE\u6536\u7AD9 ${String(list.deleted)} \u6761`
2457
+ list === void 0 ? "" : t("app.counts", { total: list.total, watch: list.watchLater, deleted: list.deleted })
1850
2458
  ] })
1851
2459
  ] }),
1852
2460
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -1855,7 +2463,7 @@ window.__ModuleLoader__.load({
1855
2463
  type: "button",
1856
2464
  style: { ...buttonStyle, marginLeft: "auto" },
1857
2465
  onClick: () => setManualOpen(true),
1858
- children: "\u4F7F\u7528\u624B\u518C"
2466
+ children: t("app.manual")
1859
2467
  }
1860
2468
  ),
1861
2469
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -1867,7 +2475,8 @@ window.__ModuleLoader__.load({
1867
2475
  onClick: () => setSettingsOpen((open) => !open),
1868
2476
  children: [
1869
2477
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Settings2, { size: 14 }),
1870
- " \u8BBE\u7F6E"
2478
+ " ",
2479
+ t("app.settings")
1871
2480
  ]
1872
2481
  }
1873
2482
  )
@@ -1876,7 +2485,7 @@ window.__ModuleLoader__.load({
1876
2485
  "div",
1877
2486
  {
1878
2487
  role: "dialog",
1879
- "aria-label": "\u8BBE\u7F6E",
2488
+ "aria-label": t("app.settings"),
1880
2489
  style: {
1881
2490
  position: "fixed",
1882
2491
  inset: 0,
@@ -1902,7 +2511,7 @@ window.__ModuleLoader__.load({
1902
2511
  "div",
1903
2512
  {
1904
2513
  role: "dialog",
1905
- "aria-label": "\u653E\u5927\u67E5\u770B",
2514
+ "aria-label": t("detail.zoom"),
1906
2515
  style: {
1907
2516
  position: "fixed",
1908
2517
  inset: 0,
@@ -1966,8 +2575,8 @@ window.__ModuleLoader__.load({
1966
2575
  alignItems: "flex-start"
1967
2576
  },
1968
2577
  children: [
1969
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u8FD9\u6761\u662F\u5916\u7AD9\u7684\u5185\u5BB9" }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.75 }, children: "\u9762\u677F\u4E0D\u5185\u5D4C\u522B\u4EBA\u7684\u64AD\u653E\u5668\uFF0C\u6240\u4EE5\u5728\u6D4F\u89C8\u5668\u91CC\u6253\u5F00\u2014\u2014\u90A3\u91CC\u624D\u662F\u5927\u5C4F\u3002" }),
2578
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("detail.foreign") }),
2579
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.75 }, children: t("detail.foreignBody") }),
1971
2580
  zoom.href !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1972
2581
  "a",
1973
2582
  {
@@ -1977,7 +2586,8 @@ window.__ModuleLoader__.load({
1977
2586
  style: { ...primaryStyle, textDecoration: "none" },
1978
2587
  children: [
1979
2588
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExternalLink, { size: 14 }),
1980
- " \u5728\u6D4F\u89C8\u5668\u91CC\u64AD\u653E"
2589
+ " ",
2590
+ t("detail.playInBrowser")
1981
2591
  ]
1982
2592
  }
1983
2593
  )
@@ -1995,13 +2605,15 @@ window.__ModuleLoader__.load({
1995
2605
  style: { color: "inherit", display: "inline-flex", alignItems: "center", gap: 4 },
1996
2606
  children: [
1997
2607
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExternalLink, { size: 13 }),
1998
- " \u5728\u6D4F\u89C8\u5668\u6253\u5F00"
2608
+ " ",
2609
+ t("detail.openInBrowser")
1999
2610
  ]
2000
2611
  }
2001
2612
  ),
2002
2613
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", style: buttonStyle, onClick: () => setZoom(void 0), children: [
2003
2614
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(X, { size: 13 }),
2004
- " \u5173\u95ED"
2615
+ " ",
2616
+ t("app.close")
2005
2617
  ] })
2006
2618
  ] })
2007
2619
  ]
@@ -2029,7 +2641,7 @@ window.__ModuleLoader__.load({
2029
2641
  onChange: (event) => setText(event.target.value),
2030
2642
  onPaste,
2031
2643
  onKeyDown,
2032
- placeholder: "\u7C98\u8D34\u6587\u5B57\u3001\u94FE\u63A5\uFF0C\u6216\u628A\u56FE\u7247/\u6587\u4EF6\u62D6\u5230\u8FD9\u91CC\uFF08Ctrl+Enter \u5B58\u5165\uFF09",
2644
+ placeholder: t("capture.placeholder"),
2033
2645
  rows: 3,
2034
2646
  style: {
2035
2647
  width: "100%",
@@ -2085,7 +2697,7 @@ window.__ModuleLoader__.load({
2085
2697
  "button",
2086
2698
  {
2087
2699
  type: "button",
2088
- "aria-label": `\u79FB\u9664 ${entry.name}`,
2700
+ "aria-label": t("app.remove", { name: entry.name }),
2089
2701
  onClick: () => setStaged((current) => current.filter((item) => item.id !== entry.id)),
2090
2702
  style: { ...buttonStyle, padding: "0 6px", border: "none", opacity: 0.6 },
2091
2703
  children: "\xD7"
@@ -2111,17 +2723,20 @@ window.__ModuleLoader__.load({
2111
2723
  }
2112
2724
  }
2113
2725
  ),
2114
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2726
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2115
2727
  "button",
2116
2728
  {
2117
2729
  type: "button",
2118
2730
  style: buttonStyle,
2119
2731
  disabled: busy,
2120
2732
  onClick: () => picker.current?.click(),
2121
- children: "\u9009\u62E9\u6587\u4EF6\u2026"
2733
+ children: [
2734
+ t("app.pickFile"),
2735
+ "\u2026"
2736
+ ]
2122
2737
  }
2123
2738
  ),
2124
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: buttonStyle, disabled: busy, onClick: () => void submit(), children: busy ? "\u5904\u7406\u4E2D\u2026" : "\u5B58\u5165\u4ED3\u5E93" })
2739
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: buttonStyle, disabled: busy, onClick: () => void submit(), children: busy ? t("app.saving") : t("app.store") })
2125
2740
  ] })
2126
2741
  ]
2127
2742
  }
@@ -2170,7 +2785,8 @@ window.__ModuleLoader__.load({
2170
2785
  onClick: () => setRailOpen((open) => !open),
2171
2786
  children: [
2172
2787
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Layers, { size: 13 }),
2173
- " \u7B5B\u9009"
2788
+ " ",
2789
+ t("app.filter")
2174
2790
  ]
2175
2791
  }
2176
2792
  ),
@@ -2179,7 +2795,7 @@ window.__ModuleLoader__.load({
2179
2795
  {
2180
2796
  value: search,
2181
2797
  onChange: (event) => setSearch(event.target.value),
2182
- placeholder: "\u641C\u6807\u9898\u3001\u6B63\u6587\u3001\u94FE\u63A5\u3001\u5907\u6CE8\u2026",
2798
+ placeholder: t("search.placeholder"),
2183
2799
  style: {
2184
2800
  ...inputStyle,
2185
2801
  flex: 1,
@@ -2196,7 +2812,7 @@ window.__ModuleLoader__.load({
2196
2812
  "span",
2197
2813
  {
2198
2814
  role: "group",
2199
- "aria-label": "\u5217\u8868\u6A21\u5F0F",
2815
+ "aria-label": t("modes.label"),
2200
2816
  style: {
2201
2817
  display: "inline-flex",
2202
2818
  border: "1px solid color-mix(in srgb, currentColor 15%, transparent)",
@@ -2209,7 +2825,7 @@ window.__ModuleLoader__.load({
2209
2825
  "button",
2210
2826
  {
2211
2827
  type: "button",
2212
- title: `\u5217\u8868\u6A21\u5F0F\uFF1A${mode.label}`,
2828
+ title: t("modes.titleOf", { label: mode.label }),
2213
2829
  "aria-pressed": listMode === mode.id,
2214
2830
  onClick: () => chooseListMode(mode.id),
2215
2831
  style: {
@@ -2243,7 +2859,7 @@ window.__ModuleLoader__.load({
2243
2859
  children: [
2244
2860
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RefreshCw, { size: 13 }),
2245
2861
  " ",
2246
- busy ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0"
2862
+ busy ? t("app.refreshing") : t("app.refresh")
2247
2863
  ]
2248
2864
  }
2249
2865
  )
@@ -2268,7 +2884,7 @@ window.__ModuleLoader__.load({
2268
2884
  (!narrow || railOpen) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2269
2885
  "nav",
2270
2886
  {
2271
- "aria-label": "\u7B5B\u9009",
2887
+ "aria-label": t("app.filter"),
2272
2888
  style: {
2273
2889
  ...cardStyle,
2274
2890
  display: "flex",
@@ -2282,7 +2898,7 @@ window.__ModuleLoader__.load({
2282
2898
  {
2283
2899
  active: scope === "live" && !watchOnly && category === void 0,
2284
2900
  icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Inbox, { size: 15 }),
2285
- label: "\u5168\u90E8",
2901
+ label: t("filter.all"),
2286
2902
  ...list === void 0 ? {} : { count: list.total },
2287
2903
  onClick: () => {
2288
2904
  setScope("live");
@@ -2296,7 +2912,7 @@ window.__ModuleLoader__.load({
2296
2912
  {
2297
2913
  active: scope === "live" && watchOnly,
2298
2914
  icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Circle, { size: 15 }),
2299
- label: "\u5F85\u770B",
2915
+ label: t("filter.watch"),
2300
2916
  ...list === void 0 ? {} : { count: list.watchLater },
2301
2917
  onClick: () => {
2302
2918
  setScope("live");
@@ -2310,7 +2926,7 @@ window.__ModuleLoader__.load({
2310
2926
  {
2311
2927
  active: scope === "bin",
2312
2928
  icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Trash, { size: 15 }),
2313
- label: "\u56DE\u6536\u7AD9",
2929
+ label: t("filter.bin"),
2314
2930
  ...list === void 0 ? {} : { count: list.deleted },
2315
2931
  onClick: () => {
2316
2932
  setScope("bin");
@@ -2319,7 +2935,7 @@ window.__ModuleLoader__.load({
2319
2935
  }
2320
2936
  }
2321
2937
  ),
2322
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { margin: "8px 0 4px", padding: "0 9px", fontSize: 11, opacity: 0.6 }, children: "\u7C7B\u76EE" }),
2938
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { margin: "8px 0 4px", padding: "0 9px", fontSize: 11, opacity: 0.6 }, children: t("app.category") }),
2323
2939
  CATEGORIES.map((value) => {
2324
2940
  const count = list?.categories.find((facet) => facet.value === value)?.count;
2325
2941
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -2327,7 +2943,7 @@ window.__ModuleLoader__.load({
2327
2943
  {
2328
2944
  active: category === value,
2329
2945
  icon: categoryGlyph(value, 15),
2330
- label: CATEGORY_LABELS[value],
2946
+ label: categoryLabel(value),
2331
2947
  ...list === void 0 ? {} : { count: count ?? 0 },
2332
2948
  onClick: () => {
2333
2949
  setCategory(category === value ? void 0 : value);
@@ -2339,7 +2955,7 @@ window.__ModuleLoader__.load({
2339
2955
  );
2340
2956
  }),
2341
2957
  list !== void 0 && list.tags.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2342
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { margin: "8px 0 4px", padding: "0 9px", fontSize: 11, opacity: 0.6 }, children: "\u6807\u7B7E" }),
2958
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { margin: "8px 0 4px", padding: "0 9px", fontSize: 11, opacity: 0.6 }, children: t("app.tag") }),
2343
2959
  list.tags.map((facet) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 2 }, children: [
2344
2960
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2345
2961
  RailRow,
@@ -2355,7 +2971,7 @@ window.__ModuleLoader__.load({
2355
2971
  "button",
2356
2972
  {
2357
2973
  type: "button",
2358
- title: `\u628A\u6807\u7B7E\u300C${facet.value}\u300D\u4ECE\u6240\u6709\u8BB0\u5F55\u4E0A\u79FB\u9664\uFF08\u8BB0\u5F55\u672C\u8EAB\u4E0D\u5220\uFF09`,
2974
+ title: t("filter.untagAll", { tag: facet.value }),
2359
2975
  onClick: () => void removeTagEverywhere(facet.value, facet.count),
2360
2976
  style: { ...buttonStyle, border: "none", padding: "4px 5px", opacity: 0.6 },
2361
2977
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(X, { size: 12 })
@@ -2397,22 +3013,23 @@ window.__ModuleLoader__.load({
2397
3013
  disabled: busy,
2398
3014
  onClick: () => {
2399
3015
  if (!window.confirm(
2400
- "\u6E05\u7A7A\u56DE\u6536\u7AD9\u4F1A\u771F\u7684\u5220\u6389\u8FD9\u4E9B\u8BB0\u5F55\uFF1A\u672C\u673A\u8BB0\u5F55\u3001\u4EE5\u53CA\u4E91\u76D8\u4E0A\u5BF9\u5E94\u7684\u540C\u6B65\u5BF9\u8C61\uFF08\u8BB0\u5F55 JSON/\u6587\u672C\u3001\u53EA\u88AB\u8FD9\u4E9B\u8BB0\u5F55\u5F15\u7528\u7684\u9644\u4EF6\uFF09\u3002\u4E0D\u80FD\u64A4\u9500\u3002dsh \u9644\u4EF6\u4ED3\u5E93\u91CC\u7684\u539F\u59CB\u5B57\u8282\u4ECD\u7136\u7559\u7740\u3002\u7EE7\u7EED\uFF1F"
3016
+ t("confirm.purge")
2401
3017
  ))
2402
3018
  return;
2403
3019
  void purge();
2404
3020
  },
2405
3021
  children: [
2406
3022
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Trash, { size: 13 }),
2407
- " \u6E05\u7A7A\u56DE\u6536\u7AD9"
3023
+ " ",
3024
+ t("filter.clearBin")
2408
3025
  ]
2409
3026
  }
2410
3027
  )
2411
3028
  ]
2412
3029
  }
2413
3030
  ),
2414
- (list === void 0 || list.matched > 0) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { textAlign: "right", fontSize: 12, opacity: 0.6, marginBottom: 6 }, children: list === void 0 ? "\u8BFB\u53D6\u4E2D\u2026" : `${String(list.matched)} \u6761\u5339\u914D` }),
2415
- list?.entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "8px 0 0", opacity: 0.7 }, children: scope === "bin" ? "\u56DE\u6536\u7AD9\u662F\u7A7A\u7684\u3002" : "\u6CA1\u6709\u5339\u914D\u7684\u8BB0\u5F55\u3002" }),
3031
+ (list === void 0 || list.matched > 0) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { textAlign: "right", fontSize: 12, opacity: 0.6, marginBottom: 6 }, children: list === void 0 ? t("app.loading") : t("app.matches", { count: list.matched }) }),
3032
+ list?.entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "8px 0 0", opacity: 0.7 }, children: scope === "bin" ? t("app.binEmpty") : t("app.noMatches") }),
2416
3033
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2417
3034
  "div",
2418
3035
  {
@@ -2457,13 +3074,7 @@ window.__ModuleLoader__.load({
2457
3074
  fontSize: 12
2458
3075
  },
2459
3076
  children: [
2460
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
2461
- "\u7B2C ",
2462
- String(page + 1),
2463
- " / ",
2464
- String(pageCount),
2465
- " \u9875"
2466
- ] }),
3077
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("pager.of", { page: page + 1, pages: pageCount }) }),
2467
3078
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { marginLeft: "auto" } }),
2468
3079
  page > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2469
3080
  "button",
@@ -2473,7 +3084,8 @@ window.__ModuleLoader__.load({
2473
3084
  onClick: () => setPage((current) => Math.max(0, current - 1)),
2474
3085
  children: [
2475
3086
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronLeft, { size: 13 }),
2476
- " \u4E0A\u4E00\u9875"
3087
+ " ",
3088
+ t("app.prevPage")
2477
3089
  ]
2478
3090
  }
2479
3091
  ),
@@ -2484,7 +3096,8 @@ window.__ModuleLoader__.load({
2484
3096
  style: pagerButtonStyle,
2485
3097
  onClick: () => setPage((current) => current + 1),
2486
3098
  children: [
2487
- "\u4E0B\u4E00\u9875 ",
3099
+ t("app.nextPage"),
3100
+ " ",
2488
3101
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronRight, { size: 13 })
2489
3102
  ]
2490
3103
  }
@@ -2499,7 +3112,7 @@ window.__ModuleLoader__.load({
2499
3112
  "div",
2500
3113
  {
2501
3114
  role: "dialog",
2502
- "aria-label": "\u8BB0\u5F55\u8BE6\u60C5",
3115
+ "aria-label": t("app.detail"),
2503
3116
  style: {
2504
3117
  position: "fixed",
2505
3118
  left: 12,
@@ -2531,7 +3144,8 @@ window.__ModuleLoader__.load({
2531
3144
  },
2532
3145
  children: [
2533
3146
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(X, { size: 13 }),
2534
- " \u5173\u95ED"
3147
+ " ",
3148
+ t("app.close")
2535
3149
  ]
2536
3150
  }
2537
3151
  ) }),
@@ -2568,7 +3182,7 @@ window.__ModuleLoader__.load({
2568
3182
  flexDirection: "column",
2569
3183
  minHeight: 0
2570
3184
  },
2571
- children: detail === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, opacity: 0.7 }, children: "\u9009\u5DE6\u8FB9\u4E00\u6761\u770B\u770B\u8BE6\u60C5\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3185
+ children: detail === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, opacity: 0.7 }, children: t("app.pickOne") }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2572
3186
  EntryPane,
2573
3187
  {
2574
3188
  detail,
@@ -2588,28 +3202,34 @@ window.__ModuleLoader__.load({
2588
3202
  ] });
2589
3203
  }
2590
3204
  function describePush(result) {
2591
- if (result.status === "unconfigured") return `\u63A8\u9001\uFF1A${result.reason ?? "\u8FD8\u6CA1\u914D\u7F6E\u8FDC\u7AEF"}`;
2592
- if (result.status === "failed") return `\u63A8\u9001\u5931\u8D25\uFF1A${result.reason ?? "\u672A\u77E5\u539F\u56E0"}`;
2593
- const head = result.pushed === 0 && result.attachments === 0 ? `\u63A8\u9001\uFF1A\u6CA1\u6709\u65B0\u5185\u5BB9\uFF08${String(result.skipped)} \u6761\u5DF2\u662F\u6700\u65B0\uFF09` : `\u63A8\u9001\uFF1A${String(result.pushed)} \u6761\u8BB0\u5F55 / ${String(result.attachments)} \u4E2A\u9644\u4EF6`;
2594
- return result.status === "partial" ? `${head} \xB7 \u90E8\u5206\u5931\u8D25\uFF1A${result.reason ?? ""}` : head;
3205
+ if (result.status === "unconfigured") return t("sync.pushUnconfigured");
3206
+ if (result.status === "failed") return t("sync.pushFailed", { reason: result.reason ?? t("sync.pushUnknown") });
3207
+ const head = result.pushed === 0 && result.attachments === 0 ? t("sync.pushUpToDate", { count: result.skipped }) : t("sync.pushDone", { records: result.pushed, attachments: result.attachments });
3208
+ return result.status === "partial" ? t("sync.pushPartial", { head, reason: result.reason ?? "" }) : head;
2595
3209
  }
2596
3210
  function describePull(result) {
2597
- if (result.status === "unconfigured") return result.reason ?? "\u8FD8\u6CA1\u914D\u7F6E\u5730\u5740";
2598
- if (result.status === "failed") return `\u62C9\u53D6\u5931\u8D25\uFF1A${result.reason ?? "\u672A\u77E5\u539F\u56E0"}`;
3211
+ if (result.status === "unconfigured") return result.reason ?? t("sync.pullNoAddress");
3212
+ if (result.status === "failed") return t("sync.pullFailed", { reason: result.reason ?? t("sync.pushUnknown") });
2599
3213
  const merged = result.merged ?? 0;
2600
3214
  const attachments = result.attachments ?? 0;
2601
- const syncPart = merged === 0 && attachments === 0 ? "\u4E91\u7AEF\u7684\u8BB0\u5F55\u6CA1\u6709\u65B0\u7684" : `\u4ECE\u4E91\u7AEF\u5408\u5E76 ${String(merged)} \u6761${attachments === 0 ? "" : ` / ${String(attachments)} \u4E2A\u9644\u4EF6`}`;
3215
+ const syncPart = merged === 0 && attachments === 0 ? t("sync.pullNothingNew") : t("sync.pullMerged", {
3216
+ count: merged,
3217
+ attachments: attachments === 0 ? "" : t("sync.pullAttachments", { count: attachments })
3218
+ });
2602
3219
  if (result.pulled === 0 && result.skipped === 0 && result.failed === 0) return syncPart;
2603
- return `\u62C9\u53D6\u5B8C\u6210\uFF1A\u8FDC\u7AEF\u5217\u51FA ${String(result.listed)} \u9879\uFF0C\u65B0\u5165\u5E93 ${String(result.pulled)} \u6761\uFF0C\u8DF3\u8FC7 ${String(
2604
- result.skipped
2605
- )} \u6761 \xB7 ${syncPart}${result.failed > 0 ? ` \xB7 \u5931\u8D25 ${String(result.failed)} \u6761` : ""}`;
3220
+ return t("sync.pullDone", {
3221
+ listed: result.listed,
3222
+ pulled: result.pulled,
3223
+ skipped: result.skipped,
3224
+ tail: `${syncPart}${result.failed > 0 ? t("sync.pullFailedCount", { count: result.failed }) : ""}`
3225
+ });
2606
3226
  }
2607
3227
  function EncryptionSettings({ call }) {
2608
- const [status, setStatus] = import_react7.default.useState();
2609
- const [password, setPassword] = import_react7.default.useState("");
2610
- const [notice, setNotice] = import_react7.default.useState();
2611
- const [busy, setBusy] = import_react7.default.useState(false);
2612
- const send = import_react7.default.useCallback(
3228
+ const [status, setStatus] = import_react8.default.useState();
3229
+ const [password, setPassword] = import_react8.default.useState("");
3230
+ const [notice, setNotice] = import_react8.default.useState();
3231
+ const [busy, setBusy] = import_react8.default.useState(false);
3232
+ const send = import_react8.default.useCallback(
2613
3233
  async (action) => {
2614
3234
  setBusy(true);
2615
3235
  try {
@@ -2625,7 +3245,7 @@ window.__ModuleLoader__.load({
2625
3245
  setStatus(next);
2626
3246
  setPassword("");
2627
3247
  setNotice(
2628
- action === "set" ? next.sealed === void 0 || next.sealed === 0 ? "\u4E3B\u5BC6\u7801\u5DF2\u8BBE\u7F6E\uFF0C\u8D26\u5BC6\u4ECE\u6B64\u52A0\u5BC6\u843D\u76D8" : `\u4E3B\u5BC6\u7801\u5DF2\u8BBE\u7F6E\uFF0C\u53E6\u6709 ${String(next.sealed)} \u6761\u65E7\u8BB0\u5F55\u5DF2\u4ECE\u660E\u6587\u6539\u4E3A\u5BC6\u6587` : action === "unlock" ? "\u5DF2\u89E3\u9501" : action === "lock" ? "\u5DF2\u9501\u5B9A\uFF1A\u8D26\u5BC6\u6B63\u6587\u4E0D\u53EF\u8BFB\uFF0C\u76F4\u5230\u518D\u6B21\u89E3\u9501" : void 0
3248
+ action === "set" ? next.sealed === void 0 || next.sealed === 0 ? t("settings.passwordJustSet") : t("settings.passwordSealed", { count: next.sealed }) : action === "unlock" ? t("settings.unlocked") : action === "lock" ? t("settings.lockedNote") : void 0
2629
3249
  );
2630
3250
  } finally {
2631
3251
  setBusy(false);
@@ -2633,15 +3253,15 @@ window.__ModuleLoader__.load({
2633
3253
  },
2634
3254
  [call, password]
2635
3255
  );
2636
- import_react7.default.useEffect(() => {
3256
+ import_react8.default.useEffect(() => {
2637
3257
  void send("status");
2638
3258
  }, []);
2639
3259
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { style: { ...cardStyle, marginBottom: 12 }, children: [
2640
3260
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }, children: [
2641
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u8D26\u5BC6\u52A0\u5BC6" }),
2642
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, fontSize: 12 }, children: status === void 0 ? "\u8BFB\u53D6\u4E2D\u2026" : status.unlocked ? "\u5DF2\u89E3\u9501" : status.configured ? "\u5DF2\u9501\u5B9A" : "\u8FD8\u6CA1\u8BBE\u4E3B\u5BC6\u7801" })
3261
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("settings.secrets") }),
3262
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, fontSize: 12 }, children: status === void 0 ? t("app.loading") : status.unlocked ? t("settings.unlocked") : status.configured ? t("settings.locked") : t("settings.noPassword") })
2643
3263
  ] }),
2644
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "0 0 8px", opacity: 0.7, fontSize: 12 }, children: "\u8D26\u5BC6\u6B63\u6587\u4EE5\u5BC6\u6587\u5199\u76D8\uFF1B\u4E3B\u5BC6\u7801\u548C\u5BC6\u94A5\u90FD\u4E0D\u843D\u76D8\uFF0C**\u91CD\u542F\u540E\u8981\u91CD\u65B0\u89E3\u9501**\u3002\u5BC6\u7801\u5FD8\u4E86\u5C31\u89E3\u4E0D\u5F00\uFF0C\u6CA1\u6709\u627E\u56DE\u3002" }),
3264
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "0 0 8px", opacity: 0.7, fontSize: 12 }, children: t("settings.secretsBody") }),
2645
3265
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2646
3266
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2647
3267
  "input",
@@ -2651,8 +3271,8 @@ window.__ModuleLoader__.load({
2651
3271
  disabled: busy,
2652
3272
  autoComplete: "new-password",
2653
3273
  onChange: (event) => setPassword(event.target.value),
2654
- "aria-label": "\u4E3B\u5BC6\u7801",
2655
- placeholder: status?.configured === true ? "\u8F93\u5165\u4E3B\u5BC6\u7801" : "\u8BBE\u4E00\u4E2A\u4E3B\u5BC6\u7801",
3274
+ "aria-label": t("settings.masterPassword"),
3275
+ placeholder: status?.configured === true ? t("settings.masterPasswordSet") : t("settings.masterPasswordNew"),
2656
3276
  style: { ...inputStyle, flex: 1, minWidth: 160 }
2657
3277
  }
2658
3278
  ),
@@ -2663,7 +3283,7 @@ window.__ModuleLoader__.load({
2663
3283
  style: { ...buttonStyle, height: CONTROL_HEIGHT, boxSizing: "border-box" },
2664
3284
  disabled: busy || password.length === 0,
2665
3285
  onClick: () => void send("set"),
2666
- children: "\u8BBE\u7F6E / \u66F4\u6362"
3286
+ children: t("settings.setOrChange")
2667
3287
  }
2668
3288
  ),
2669
3289
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -2673,7 +3293,7 @@ window.__ModuleLoader__.load({
2673
3293
  style: { ...buttonStyle, height: CONTROL_HEIGHT, boxSizing: "border-box" },
2674
3294
  disabled: busy || password.length === 0 || status?.configured !== true,
2675
3295
  onClick: () => void send("unlock"),
2676
- children: "\u89E3\u9501"
3296
+ children: t("settings.unlock")
2677
3297
  }
2678
3298
  ),
2679
3299
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -2683,7 +3303,7 @@ window.__ModuleLoader__.load({
2683
3303
  style: { ...buttonStyle, height: CONTROL_HEIGHT, boxSizing: "border-box" },
2684
3304
  disabled: busy || status?.unlocked !== true,
2685
3305
  onClick: () => void send("lock"),
2686
- children: "\u9501\u5B9A"
3306
+ children: t("settings.lock")
2687
3307
  }
2688
3308
  )
2689
3309
  ] }),
@@ -2694,27 +3314,27 @@ window.__ModuleLoader__.load({
2694
3314
  call,
2695
3315
  onClose
2696
3316
  }) {
2697
- const [status, setStatus] = import_react7.default.useState();
2698
- const [baseUrl, setBaseUrl] = import_react7.default.useState("");
2699
- const [directory, setDirectory] = import_react7.default.useState("/inbox");
2700
- const [username, setUsername] = import_react7.default.useState("");
2701
- const [password, setPassword] = import_react7.default.useState("");
2702
- const [protocol, setProtocol] = import_react7.default.useState("webdav");
2703
- const [endpoint, setEndpoint] = import_react7.default.useState("");
2704
- const [bucket, setBucket] = import_react7.default.useState("");
2705
- const [region, setRegion] = import_react7.default.useState("us-east-1");
2706
- const [signatureVersion, setSignatureVersion] = import_react7.default.useState("v4");
2707
- const [accessKeyId, setAccessKeyId] = import_react7.default.useState("");
2708
- const [s3UserAgent, setS3UserAgent] = import_react7.default.useState("");
2709
- const [webdavUserAgent, setWebdavUserAgent] = import_react7.default.useState("");
2710
- const [accessKeySecret, setAccessKeySecret] = import_react7.default.useState("");
2711
- const [probe, setProbe] = import_react7.default.useState();
2712
- const [notice, setNotice] = import_react7.default.useState();
2713
- const [busy, setBusy] = import_react7.default.useState(false);
2714
- const read = import_react7.default.useCallback(async () => {
3317
+ const [status, setStatus] = import_react8.default.useState();
3318
+ const [baseUrl, setBaseUrl] = import_react8.default.useState("");
3319
+ const [directory, setDirectory] = import_react8.default.useState("/inbox");
3320
+ const [username, setUsername] = import_react8.default.useState("");
3321
+ const [password, setPassword] = import_react8.default.useState("");
3322
+ const [protocol, setProtocol] = import_react8.default.useState("webdav");
3323
+ const [endpoint, setEndpoint] = import_react8.default.useState("");
3324
+ const [bucket, setBucket] = import_react8.default.useState("");
3325
+ const [region, setRegion] = import_react8.default.useState("us-east-1");
3326
+ const [signatureVersion, setSignatureVersion] = import_react8.default.useState("v4");
3327
+ const [accessKeyId, setAccessKeyId] = import_react8.default.useState("");
3328
+ const [s3UserAgent, setS3UserAgent] = import_react8.default.useState("");
3329
+ const [webdavUserAgent, setWebdavUserAgent] = import_react8.default.useState("");
3330
+ const [accessKeySecret, setAccessKeySecret] = import_react8.default.useState("");
3331
+ const [probe, setProbe] = import_react8.default.useState();
3332
+ const [notice, setNotice] = import_react8.default.useState();
3333
+ const [busy, setBusy] = import_react8.default.useState(false);
3334
+ const read = import_react8.default.useCallback(async () => {
2715
3335
  const result = await call(INBOX_ENDPOINT_WEBDAV, { action: "read" });
2716
3336
  if (!result.ok) {
2717
- setNotice(`\u8BFB\u4E0D\u5230\u8BBE\u7F6E\uFF1A${result.error.message}`);
3337
+ setNotice(t("notice.settingsUnreadable", { reason: result.error.message }));
2718
3338
  return;
2719
3339
  }
2720
3340
  const next = result.value;
@@ -2733,7 +3353,7 @@ window.__ModuleLoader__.load({
2733
3353
  setPassword("");
2734
3354
  setAccessKeySecret("");
2735
3355
  }, [call]);
2736
- import_react7.default.useEffect(() => {
3356
+ import_react8.default.useEffect(() => {
2737
3357
  void read();
2738
3358
  }, [read]);
2739
3359
  const userAgent = protocol === "s3" ? s3UserAgent : webdavUserAgent;
@@ -2763,13 +3383,13 @@ window.__ModuleLoader__.load({
2763
3383
  };
2764
3384
  const result = await call(INBOX_ENDPOINT_WEBDAV, request);
2765
3385
  if (!result.ok) {
2766
- setNotice(`\u6CA1\u5B58\u4E0A\uFF1A${result.error.message}`);
3386
+ setNotice(t("notice.settingsFailed", { reason: result.error.message }));
2767
3387
  return;
2768
3388
  }
2769
3389
  setStatus(result.value);
2770
3390
  setPassword("");
2771
3391
  setAccessKeySecret("");
2772
- setNotice("\u8BBE\u7F6E\u5DF2\u4FDD\u5B58");
3392
+ setNotice(t("notice.settingsSaved"));
2773
3393
  } finally {
2774
3394
  setBusy(false);
2775
3395
  }
@@ -2780,24 +3400,28 @@ window.__ModuleLoader__.load({
2780
3400
  try {
2781
3401
  const result = await call(INBOX_ENDPOINT_PROBE, {});
2782
3402
  if (!result.ok) {
2783
- setNotice(`\u81EA\u68C0\u5931\u8D25\uFF1A${result.error.message}`);
3403
+ setNotice(t("notice.probeFailed", { reason: result.error.message }));
2784
3404
  return;
2785
3405
  }
2786
3406
  setProbe(result.value);
2787
- setNotice("\u81EA\u68C0\u7ED3\u679C\u89C1\u4E0B\u65B9");
3407
+ setNotice(t("notice.probeDone"));
2788
3408
  } finally {
2789
3409
  setBusy(false);
2790
3410
  }
2791
3411
  };
2792
3412
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { style: { ...cardStyle, display: "flex", flexDirection: "column", gap: 8 }, children: [
2793
3413
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "baseline", gap: 10 }, children: [
2794
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "\u8FDC\u7AEF\u5165\u5E93" }),
2795
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.65 }, children: status === void 0 ? "\u8BFB\u53D6\u4E2D\u2026" : `${status.settingsAvailable ? "\u8BBE\u7F6E\u670D\u52A1\u5728" : "\u6CA1\u6709\u8BBE\u7F6E\u670D\u52A1"} \xB7 ${status.passwordSet ? "WebDAV \u5BC6\u7801\u5DF2\u5B58" : "\u8FD8\u6CA1\u5B58 WebDAV \u5BC6\u7801"} \xB7 ${status.secretSet ? "S3 \u5BC6\u94A5\u5DF2\u5B58" : "\u8FD8\u6CA1\u5B58 S3 \u5BC6\u94A5"}` }),
2796
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: { ...buttonStyle, marginLeft: "auto" }, onClick: onClose, children: "\u5173\u95ED" })
3414
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("settings.ingest") }),
3415
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.65 }, children: status === void 0 ? t("app.loading") : t("settings.status", {
3416
+ settings: status.settingsAvailable ? t("settings.statusOn") : t("settings.statusOff"),
3417
+ webdav: status.passwordSet ? t("settings.statusWebdavSet") : t("settings.statusWebdavUnset"),
3418
+ s3: status.secretSet ? t("settings.statusS3Set") : t("settings.statusS3Unset")
3419
+ }) }),
3420
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: { ...buttonStyle, marginLeft: "auto" }, onClick: onClose, children: t("app.close") })
2797
3421
  ] }),
2798
- status !== void 0 && !status.settingsAvailable && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, opacity: 0.75 }, children: "\u8FD9\u4E2A\u7EC4\u5408\u91CC\u6CA1\u6709\u8BBE\u7F6E\u670D\u52A1\uFF0C\u5730\u5740\u6539\u4E0D\u4E86\u2014\u2014\u4F60\u591A\u534A\u5728\u7528 headless \u5F62\u6001\u5F00\u53D1\u3002" }),
3422
+ status !== void 0 && !status.settingsAvailable && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, opacity: 0.75 }, children: t("settings.noServiceBody") }),
2799
3423
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2800
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u534F\u8BAE" }),
3424
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.protocol") }),
2801
3425
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2802
3426
  SelectBox,
2803
3427
  {
@@ -2810,24 +3434,24 @@ window.__ModuleLoader__.load({
2810
3434
  onChange: (next) => setProtocol(next === "s3" ? "s3" : "webdav")
2811
3435
  }
2812
3436
  ),
2813
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.6 }, children: "\u6362\u534F\u8BAE\u540E\u8BB0\u5F97\u70B9\u4FDD\u5B58" })
3437
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.6 }, children: t("settings.protocolHint") })
2814
3438
  ] }),
2815
3439
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2816
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u5BA2\u6237\u7AEF\u6807\u8BC6" }),
3440
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.clientId") }),
2817
3441
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2818
3442
  "input",
2819
3443
  {
2820
3444
  value: userAgent,
2821
3445
  disabled: busy,
2822
3446
  onChange: (event) => setUserAgent(event.target.value),
2823
- placeholder: protocol === "s3" ? "\u7559\u7A7A\u5373 dsh-inbox\uFF1B\u6709\u4E9B\u7F51\u5173\u6309\u5B83\u8BA4\u4EBA\uFF0C\u586B\u6210\u8FD9\u4E2A AccessKey \u7ED1\u5B9A\u7684\u5E94\u7528\u540D" : "\u7559\u7A7A\u5373 dsh-inbox\uFF1B\u6709\u4E9B\u7F51\u5173\u6309\u5B83\u8BA4\u4EBA\uFF0C\u586B\u6210\u8FD9\u4E2A WebDAV \u8D26\u53F7\u7ED1\u5B9A\u7684\u5E94\u7528\u540D",
3447
+ placeholder: protocol === "s3" ? t("settings.clientIdS3") : t("settings.clientIdWebdav"),
2824
3448
  style: { ...inputStyle, flex: 1 }
2825
3449
  }
2826
3450
  )
2827
3451
  ] }),
2828
3452
  protocol === "webdav" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2829
3453
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2830
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u5730\u5740" }),
3454
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.bucketAddress") }),
2831
3455
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2832
3456
  "input",
2833
3457
  {
@@ -2840,7 +3464,7 @@ window.__ModuleLoader__.load({
2840
3464
  )
2841
3465
  ] }),
2842
3466
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2843
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u76EE\u5F55" }),
3467
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.bucketDir") }),
2844
3468
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2845
3469
  "input",
2846
3470
  {
@@ -2851,10 +3475,10 @@ window.__ModuleLoader__.load({
2851
3475
  style: { ...inputStyle, flex: 1 }
2852
3476
  }
2853
3477
  ),
2854
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.6 }, children: "\u522B\u7684\u8BBE\u5907\u5F80\u8FD9\u91CC\u6254\u4E1C\u897F" })
3478
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.6 }, children: t("settings.bucketHint") })
2855
3479
  ] }),
2856
3480
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2857
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u7528\u6237\u540D" }),
3481
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.username") }),
2858
3482
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2859
3483
  "input",
2860
3484
  {
@@ -2866,7 +3490,7 @@ window.__ModuleLoader__.load({
2866
3490
  )
2867
3491
  ] }),
2868
3492
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2869
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u5BC6\u7801" }),
3493
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.password") }),
2870
3494
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2871
3495
  "input",
2872
3496
  {
@@ -2874,21 +3498,21 @@ window.__ModuleLoader__.load({
2874
3498
  value: password,
2875
3499
  disabled: busy || status?.credentialsAvailable === false,
2876
3500
  onChange: (event) => setPassword(event.target.value),
2877
- placeholder: status?.passwordSet === true ? "\u5DF2\u5B58\uFF08\u7559\u7A7A\u5219\u4E0D\u6539\uFF09" : "\u5B58\u5728 dsh \u7684\u51ED\u8BC1\u5E93\u91CC",
3501
+ placeholder: status?.passwordSet === true ? t("settings.passwordStored") : t("settings.passwordStore"),
2878
3502
  style: { ...inputStyle, flex: 1 }
2879
3503
  }
2880
3504
  )
2881
3505
  ] })
2882
3506
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2883
3507
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2884
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u63A5\u5165\u70B9" }),
3508
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.endpoint") }),
2885
3509
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2886
3510
  "input",
2887
3511
  {
2888
3512
  value: endpoint,
2889
3513
  disabled: busy,
2890
3514
  onChange: (event) => setEndpoint(event.target.value),
2891
- placeholder: "s3.cstcloud.cn\uFF08\u4E0D\u5199\u534F\u8BAE\u9ED8\u8BA4 https\uFF09",
3515
+ placeholder: t("settings.endpointPlaceholder"),
2892
3516
  style: { ...inputStyle, flex: 1 }
2893
3517
  }
2894
3518
  )
@@ -2906,20 +3530,20 @@ window.__ModuleLoader__.load({
2906
3530
  )
2907
3531
  ] }),
2908
3532
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2909
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: "\u7B7E\u540D" }),
3533
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 64 }, children: t("settings.signature") }),
2910
3534
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2911
3535
  SelectBox,
2912
3536
  {
2913
3537
  value: signatureVersion,
2914
3538
  options: [
2915
3539
  ["v4", "v4"],
2916
- ["v2", "v2\uFF08\u8001\u7F51\u5173\u591A\u534A\u8981\u8FD9\u4E2A\uFF09"]
3540
+ ["v2", t("settings.signatureV2")]
2917
3541
  ],
2918
3542
  disabled: busy,
2919
3543
  onChange: setSignatureVersion
2920
3544
  }
2921
3545
  ),
2922
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 40 }, children: "\u533A\u57DF" }),
3546
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.7, minWidth: 40 }, children: t("settings.region") }),
2923
3547
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2924
3548
  "input",
2925
3549
  {
@@ -2952,22 +3576,22 @@ window.__ModuleLoader__.load({
2952
3576
  value: accessKeySecret,
2953
3577
  disabled: busy || status?.credentialsAvailable === false,
2954
3578
  onChange: (event) => setAccessKeySecret(event.target.value),
2955
- placeholder: status?.secretSet === true ? "\u5DF2\u5B58\uFF08\u7559\u7A7A\u5219\u4E0D\u6539\uFF09" : "\u5B58\u5728 dsh \u7684\u51ED\u8BC1\u5E93\u91CC",
3579
+ placeholder: status?.secretSet === true ? t("settings.passwordStored") : t("settings.passwordStore"),
2956
3580
  style: { ...inputStyle, flex: 1 }
2957
3581
  }
2958
3582
  )
2959
3583
  ] }),
2960
3584
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: { margin: 0, opacity: 0.6 }, children: [
2961
- "\u76EE\u5F55\u90A3\u4E00\u680F\u540C\u65F6\u662F S3 \u7684 key \u524D\u7F00\uFF08\u9ED8\u8BA4 ",
3585
+ t("settings.dirS3.lead"),
2962
3586
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { children: "/inbox" }),
2963
- "\uFF0C\u4F1A\u8F6C\u6210 ",
3587
+ t("settings.dirS3.mid"),
2964
3588
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { children: "inbox/" }),
2965
- "\uFF09\u3002"
3589
+ t("settings.dirS3.tail")
2966
3590
  ] })
2967
3591
  ] }),
2968
3592
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }, children: [
2969
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: buttonStyle, disabled: busy, onClick: () => void save(), children: "\u4FDD\u5B58" }),
2970
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: buttonStyle, disabled: busy, onClick: () => void selfTest(), children: "\u81EA\u68C0" }),
3593
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: buttonStyle, disabled: busy, onClick: () => void save(), children: t("settings.save") }),
3594
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: buttonStyle, disabled: busy, onClick: () => void selfTest(), children: t("settings.probe") }),
2971
3595
  detailNotice(notice)
2972
3596
  ] }),
2973
3597
  probe !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { margin: 0, display: "flex", flexDirection: "column", gap: 6 }, children: [
@@ -2987,11 +3611,7 @@ window.__ModuleLoader__.load({
2987
3611
  ),
2988
3612
  verdict.hint !== void 0 && verdict.hint.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, opacity: 0.7 }, children: verdict.hint }),
2989
3613
  probe.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("details", { children: [
2990
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("summary", { style: { cursor: "pointer", opacity: 0.7, fontSize: 12 }, children: [
2991
- "\u8BE6\u60C5\uFF08",
2992
- probe.length,
2993
- " \u6B21\u8BF7\u6C42\uFF09"
2994
- ] }),
3614
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("summary", { style: { cursor: "pointer", opacity: 0.7, fontSize: 12 }, children: t("settings.details", { count: probe.length }) }),
2995
3615
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2996
3616
  "pre",
2997
3617
  {
@@ -3012,15 +3632,15 @@ window.__ModuleLoader__.load({
3012
3632
  )
3013
3633
  ] })
3014
3634
  ] }),
3015
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, opacity: 0.6 }, children: "\u53EA\u505A\u5355\u5411\uFF1A\u8FDC\u7AEF\u5F80\u91CC\u6254\uFF0C\u672C\u673A\u62C9\u4E0B\u6765\u5165\u5E93\u3002\u5BC6\u7801\u8D70 dsh \u7684\u51ED\u8BC1\u5E93\uFF0C\u4E0D\u5199\u8FDB\u914D\u7F6E\u3002" })
3635
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, opacity: 0.6 }, children: t("settings.ingestOnly") })
3016
3636
  ] });
3017
3637
  }
3018
3638
  function detailNotice(notice) {
3019
3639
  return notice === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.8 }, children: notice });
3020
3640
  }
3021
3641
  var LIST_MODES = [
3022
- { id: "grid", label: "\u7F51\u683C", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LayoutGrid, { size: 14 }) },
3023
- { id: "compact", label: "\u7D27\u51D1", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Layers, { size: 14 }) }
3642
+ { id: "grid", label: t("modes.grid"), icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LayoutGrid, { size: 14 }) },
3643
+ { id: "compact", label: t("modes.compact"), icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Layers, { size: 14 }) }
3024
3644
  ];
3025
3645
  function categoryGlyph(category, size) {
3026
3646
  switch (category) {
@@ -3054,7 +3674,7 @@ window.__ModuleLoader__.load({
3054
3674
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3055
3675
  "span",
3056
3676
  {
3057
- title: CATEGORY_SOURCE_HINTS[source],
3677
+ title: sourceHint(source),
3058
3678
  style: {
3059
3679
  flex: "none",
3060
3680
  display: "inline-flex",
@@ -3077,7 +3697,7 @@ window.__ModuleLoader__.load({
3077
3697
  color: tint
3078
3698
  }
3079
3699
  },
3080
- children: CATEGORY_SOURCE_LABELS[source]
3700
+ children: sourceLabel(source)
3081
3701
  }
3082
3702
  );
3083
3703
  }
@@ -3154,7 +3774,7 @@ window.__ModuleLoader__.load({
3154
3774
  "button",
3155
3775
  {
3156
3776
  type: "button",
3157
- title: previewKind === void 0 ? "\u5728\u6D4F\u89C8\u5668\u91CC\u64AD\u653E" : "\u5728\u9762\u677F\u91CC\u653E\u5927",
3777
+ title: previewKind === void 0 ? t("detail.playInBrowser") : t("detail.zoomInPanel"),
3158
3778
  onClick: (event) => {
3159
3779
  event.stopPropagation();
3160
3780
  onPreview();
@@ -3297,7 +3917,8 @@ window.__ModuleLoader__.load({
3297
3917
  },
3298
3918
  children: [
3299
3919
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Bookmark, { size: 11 }),
3300
- " \u5F85\u770B"
3920
+ " ",
3921
+ t("filter.watch")
3301
3922
  ]
3302
3923
  }
3303
3924
  )
@@ -3334,7 +3955,7 @@ window.__ModuleLoader__.load({
3334
3955
  opacity: 0.6
3335
3956
  },
3336
3957
  children: [
3337
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: CATEGORY_LABELS[entry.category] }),
3958
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: categoryLabel(entry.category) }),
3338
3959
  entry.platform !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
3339
3960
  "\xB7 ",
3340
3961
  entry.platform
@@ -3342,9 +3963,13 @@ window.__ModuleLoader__.load({
3342
3963
  entry.attachmentCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
3343
3964
  "\xB7 ",
3344
3965
  entry.attachmentCount,
3345
- " \u9644\u4EF6"
3966
+ " ",
3967
+ t("app.tag")
3968
+ ] }),
3969
+ entry.deletedAt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { color: "salmon" }, children: [
3970
+ "\xB7 ",
3971
+ t("filter.bin")
3346
3972
  ] }),
3347
- entry.deletedAt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "salmon" }, children: "\xB7 \u5DF2\u5220" }),
3348
3973
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { flex: "none" }, children: [
3349
3974
  "\xB7 ",
3350
3975
  new Date(entry.createdAt).toLocaleDateString()
@@ -3373,10 +3998,10 @@ window.__ModuleLoader__.load({
3373
3998
  onRestore,
3374
3999
  onZoom
3375
4000
  }) {
3376
- const [note, setNote] = import_react7.default.useState(detail.note ?? "");
3377
- const [title, setTitle] = import_react7.default.useState(detail.title ?? "");
3378
- const [tags, setTags] = import_react7.default.useState(detail.tags.join(", "));
3379
- import_react7.default.useEffect(() => {
4001
+ const [note, setNote] = import_react8.default.useState(detail.note ?? "");
4002
+ const [title, setTitle] = import_react8.default.useState(detail.title ?? "");
4003
+ const [tags, setTags] = import_react8.default.useState(detail.tags.join(", "));
4004
+ import_react8.default.useEffect(() => {
3380
4005
  setNote(detail.note ?? "");
3381
4006
  setTitle(detail.title ?? "");
3382
4007
  setTags(detail.tags.join(", "));
@@ -3426,8 +4051,8 @@ window.__ModuleLoader__.load({
3426
4051
  flexWrap: "wrap"
3427
4052
  },
3428
4053
  children: [
3429
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: KIND_LABELS[detail.kind] }),
3430
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.6 }, children: CATEGORY_LABELS[detail.category] }),
4054
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: kindLabel(detail.kind) }),
4055
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.6 }, children: categoryLabel(detail.category) }),
3431
4056
  detail.categorySource !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SourceBadge, { source: detail.categorySource }),
3432
4057
  detail.platform !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { opacity: 0.6 }, children: detail.platform })
3433
4058
  ]
@@ -3459,7 +4084,7 @@ window.__ModuleLoader__.load({
3459
4084
  children: detail.text
3460
4085
  }
3461
4086
  ),
3462
- detail.text === void 0 && detail.category === "secret" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { ...paneRowStyle, margin: 0, opacity: 0.75 }, children: "\u8FD9\u6761\u8D26\u5BC6\u7684\u6B63\u6587\u662F\u5BC6\u6587\uFF0C\u73B0\u5728\u89E3\u4E0D\u5F00\u3002\u5230\u300C\u8BBE\u7F6E \u2192 \u8D26\u5BC6\u52A0\u5BC6\u300D\u89E3\u9501\uFF08\u6216\u5148\u8BBE\u4E00\u4E2A\u4E3B\u5BC6\u7801\uFF09\u5C31\u80FD\u770B\u5230\u3002" }),
4087
+ detail.text === void 0 && detail.category === "secret" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { ...paneRowStyle, margin: 0, opacity: 0.75 }, children: t("detail.sealedNote") }),
3463
4088
  detail.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3464
4089
  "div",
3465
4090
  {
@@ -3503,7 +4128,7 @@ window.__ModuleLoader__.load({
3503
4128
  "button",
3504
4129
  {
3505
4130
  type: "button",
3506
- title: playable ? "\u64AD\u653E" : "\u653E\u5927\u67E5\u770B",
4131
+ title: playable ? t("detail.play") : t("detail.zoom"),
3507
4132
  onClick: () => onZoom({ src, mime: attachment.mime, label: caption }),
3508
4133
  style: {
3509
4134
  padding: 0,
@@ -3562,24 +4187,20 @@ window.__ModuleLoader__.load({
3562
4187
  disabled: busy,
3563
4188
  maxLength: MAX_TITLE_CHARS,
3564
4189
  onChange: (event) => setTitle(event.target.value),
3565
- "aria-label": "\u540D\u79F0",
3566
- title: "\u5217\u8868\u3001\u5361\u7247\u548C\u5BF9\u8BDD\u5361\u7247\u663E\u793A\u8FD9\u4E2A\u540D\u5B57\uFF1B\u7559\u7A7A\u5219\u7528\u6587\u4EF6\u540D\u6216\u5907\u6CE8\u515C\u5E95",
3567
- placeholder: "\u540D\u79F0\uFF0C\u5982\uFF1A\u8EAB\u4EFD\u8BC1\u6B63\u9762\uFF08\u7559\u7A7A\u5219\u7528\u6587\u4EF6\u540D\u515C\u5E95\uFF09",
4190
+ "aria-label": t("detail.name"),
4191
+ title: t("detail.nameTitle"),
4192
+ placeholder: t("detail.namePlaceholder"),
3568
4193
  style: { ...paneRowStyle, ...inputStyle, width: "100%", boxSizing: "border-box" }
3569
4194
  }
3570
4195
  ),
3571
- detail.title === void 0 && detail.linkTitle === void 0 && detail.linkTitleError !== void 0 && detail.kind === "link" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: { ...paneRowStyle, margin: 0, fontSize: 12, opacity: 0.6 }, children: [
3572
- "\u6CA1\u6293\u5230\u9875\u9762\u6807\u9898\uFF1A",
3573
- titleFailureText(detail.linkTitleError),
3574
- "\u3002\u53EF\u4EE5\u81EA\u5DF1\u8D77\u4E2A\u540D\u5B57\u3002"
3575
- ] }),
4196
+ detail.title === void 0 && detail.linkTitle === void 0 && detail.linkTitleError !== void 0 && detail.kind === "link" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { ...paneRowStyle, margin: 0, fontSize: 12, opacity: 0.6 }, children: t("detail.titleMissed", { reason: titleFailureText(detail.linkTitleError) }) }),
3576
4197
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3577
4198
  SelectBox,
3578
4199
  {
3579
4200
  block: true,
3580
- label: "\u7C7B\u76EE",
4201
+ label: t("app.category"),
3581
4202
  value: detail.category,
3582
- options: CATEGORIES.map((value) => [value, CATEGORY_LABELS[value]]),
4203
+ options: CATEGORIES.map((value) => [value, categoryLabel(value)]),
3583
4204
  disabled: busy,
3584
4205
  onChange: (next) => void onUpdate({ category: next })
3585
4206
  }
@@ -3591,9 +4212,9 @@ window.__ModuleLoader__.load({
3591
4212
  disabled: busy,
3592
4213
  onChange: (event) => setNote(event.target.value),
3593
4214
  rows: 2,
3594
- "aria-label": "\u5907\u6CE8",
3595
- title: "\u4F60\u5199\u7684\u6C38\u8FDC\u4F18\u5148\u4E8E\u6A21\u578B\u7684\u5224\u65AD",
3596
- placeholder: "\u5907\u6CE8\uFF0C\u5982\uFF1A\u8EAB\u4EFD\u8BC1\u7167 / \u5F85\u770B\u89C6\u9891 / \u8FD9\u4E2A key \u662F\u6D4B\u8BD5\u73AF\u5883\u7684\uFF08\u6CA1\u8D77\u540D\u5B57\u65F6\uFF0C\u5B83\u4F1A\u9876\u4E0A\u5F53\u5217\u8868\u91CC\u7684\u540D\u5B57\uFF09",
4215
+ "aria-label": t("detail.note"),
4216
+ title: t("detail.noteTitle"),
4217
+ placeholder: t("detail.notePlaceholder"),
3597
4218
  style: {
3598
4219
  ...paneRowStyle,
3599
4220
  ...inputStyle,
@@ -3636,7 +4257,7 @@ window.__ModuleLoader__.load({
3636
4257
  "button",
3637
4258
  {
3638
4259
  type: "button",
3639
- title: `\u4ECE\u8FD9\u6761\u8BB0\u5F55\u4E0A\u79FB\u9664\u300C${value}\u300D`,
4260
+ title: t("detail.removeTag", { tag: value }),
3640
4261
  style: { ...actionStyle, padding: "2px 6px", gap: 2 },
3641
4262
  onClick: () => void onUpdate({ tags: detail.tags.filter((tag) => tag !== value) }),
3642
4263
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(X, { size: 11 })
@@ -3654,8 +4275,8 @@ window.__ModuleLoader__.load({
3654
4275
  value: tags,
3655
4276
  disabled: busy,
3656
4277
  onChange: (event) => setTags(event.target.value),
3657
- "aria-label": "\u6807\u7B7E",
3658
- placeholder: "\u8F93\u5165\u6807\u7B7E\uFF0C\u5982\uFF1A\u524D\u7AEF, \u62A5\u9500\uFF08\u9017\u53F7\u5206\u9694\uFF09",
4278
+ "aria-label": t("app.tag"),
4279
+ placeholder: t("detail.tagsPlaceholder"),
3659
4280
  style: { ...paneRowStyle, ...inputStyle, width: "100%", boxSizing: "border-box" }
3660
4281
  }
3661
4282
  ),
@@ -3673,7 +4294,7 @@ window.__ModuleLoader__.load({
3673
4294
  }),
3674
4295
  children: [
3675
4296
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Check, { size: 14 }),
3676
- "\u4FDD\u5B58\u4EE5\u4E0A"
4297
+ t("detail.save")
3677
4298
  ]
3678
4299
  }
3679
4300
  ),
@@ -3686,7 +4307,7 @@ window.__ModuleLoader__.load({
3686
4307
  onClick: () => void onUpdate({ watchLater: detail.watchLater !== true }),
3687
4308
  children: [
3688
4309
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Bookmark, { size: 14 }),
3689
- detail.watchLater === true ? "\u53D6\u6D88\u5F85\u770B" : "\u6807\u4E3A\u5F85\u770B"
4310
+ detail.watchLater === true ? t("detail.unwatch") : t("detail.watch")
3690
4311
  ]
3691
4312
  }
3692
4313
  ),
@@ -3699,7 +4320,8 @@ window.__ModuleLoader__.load({
3699
4320
  onClick: () => void onRestore(),
3700
4321
  children: [
3701
4322
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RotateCcw, { size: 14 }),
3702
- " \u6062\u590D"
4323
+ " ",
4324
+ t("detail.restore")
3703
4325
  ]
3704
4326
  }
3705
4327
  ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -3711,7 +4333,8 @@ window.__ModuleLoader__.load({
3711
4333
  onClick: () => void onDelete(),
3712
4334
  children: [
3713
4335
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Trash, { size: 14 }),
3714
- " \u5220\u9664"
4336
+ " ",
4337
+ t("detail.delete")
3715
4338
  ]
3716
4339
  }
3717
4340
  )
@@ -3732,9 +4355,10 @@ window.__ModuleLoader__.load({
3732
4355
  overflowWrap: "anywhere"
3733
4356
  },
3734
4357
  children: [
3735
- "\u5B58\u5165 ",
4358
+ t("app.store"),
4359
+ " ",
3736
4360
  new Date(detail.createdAt).toLocaleString(),
3737
- detail.updatedAt === detail.createdAt ? "" : ` \xB7 \u66F4\u65B0 ${new Date(detail.updatedAt).toLocaleString()}`
4361
+ detail.updatedAt === detail.createdAt ? "" : t("detail.updated", { when: new Date(detail.updatedAt).toLocaleString() })
3738
4362
  ]
3739
4363
  }
3740
4364
  )
@@ -3743,10 +4367,10 @@ window.__ModuleLoader__.load({
3743
4367
  }
3744
4368
  function describe(summary) {
3745
4369
  const parts = [];
3746
- if (summary.stored > 0) parts.push(`\u5DF2\u5B58\u5165 ${summary.stored} \u6761`);
4370
+ if (summary.stored > 0) parts.push(t("notice.saved", { count: summary.stored }));
3747
4371
  const repeats = summary.merged - summary.restored;
3748
- if (repeats > 0) parts.push(`\u5408\u5E76 ${repeats} \u6761\u91CD\u590D\u9879`);
3749
- if (summary.restored > 0) parts.push(`\u4ECE\u56DE\u6536\u7AD9\u53D6\u56DE ${summary.restored} \u6761`);
4372
+ if (repeats > 0) parts.push(t("notice.merged", { count: repeats }));
4373
+ if (summary.restored > 0) parts.push(t("notice.restored", { count: summary.restored }));
3750
4374
  return parts.join("\uFF0C");
3751
4375
  }
3752
4376
  function isRpcResult(value) {