mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-11-06 16:28:18 +00:00
Merge pull request #1317 from cwatanab/fix/japanese-translations-and-localisation
fix(i18n): overhaul Japanese translations, localise pending UI labels, and update documentation
This commit is contained in:
28 files changed
+6038
-1515
No files matched your search
+95
-56
@@ -1,86 +1,125 @@
|
|||||||
<!-- For translation: 20240227r0 -->
|
|
||||||
# Self-hosted LiveSync
|
# Self-hosted LiveSync
|
||||||
[英語版ドキュメント](./README.md) - [中国語版ドキュメント](./README_cn.md).
|
[英語版ドキュメント](./README.md) - [中国語版ドキュメント](./README_cn.md).
|
||||||
|
|
||||||
Obsidianで利用可能なすべてのプラットフォームで使える、CouchDBをサーバに使用する、コミュニティ版の同期プラグイン
|
Self-hosted LiveSync は、Obsidian 対応のすべてのプラットフォームで利用できる、コミュニティ開発の同期プラグインです。CouchDB や MinIO、S3、R2 などのオブジェクトストレージを利用し、信頼性の高いデータ同期を実現します。
|
||||||
|
|
||||||
|
WebRTC によるピアツーピア(P2P)同期にも対応しており、中央のデータ保存サーバーを介さずにデバイス間でノートを交換できます。ピアの検出にはシグナリングリレーが必要です。詳しくは[ピアツーピア同期の仕組み](./docs/p2p.md)をご覧ください。
|
||||||
|
|
||||||
|
セットアップガイド、トラブルシューティング、技術資料、設計判断、過去の資料は[ドキュメント一覧](docs/README.md)から確認できます。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
※公式のSyncと同期することはできません。
|
>[!IMPORTANT]
|
||||||
|
> このプラグインは公式の「Obsidian Sync」と互換性がなく、同サービスとは同期できません。
|
||||||
|
|
||||||
## 機能
|
## 機能
|
||||||
- 高効率・低トラフィックでVault同士を同期
|
- Vault を効率的に、通信量を抑えて同期します。
|
||||||
- 競合解決がいい感じ
|
- 競合する変更を適切に処理します。
|
||||||
- 単純な競合なら自動マージします
|
- 単純な競合は自動的にマージします。
|
||||||
- OSSソリューションを同期サーバに使用
|
- サーバーにはオープンソースのソリューションを使用します。
|
||||||
- 互換ソリューションも使用可能です
|
- 互換性のあるソリューションにも対応します。
|
||||||
- End-to-End暗号化実装済み
|
- エンドツーエンド暗号化に対応します。
|
||||||
- 設定・スニペット・テーマ、プラグインの同期が可能
|
- [カスタマイズ同期(高度な設定)](docs/settings_ja.md#6-customisation-sync-advanced)または[非表示ファイル同期](docs/tips/hidden-file-sync.md)で、設定、スニペット、テーマ、プラグインを同期します。
|
||||||
- [Webクリッパー](https://chrome.google.com/webstore/detail/obsidian-livesync-webclip/jfpaflmpckblieefkegjncjoceapakdf) もあります
|
- WebRTC によるピアツーピア同期を行います。
|
||||||
|
|
||||||
NDAや類似の契約や義務、倫理を守る必要のある、研究者、設計者、開発者のような方に特にオススメです。
|
|
||||||
|
|
||||||
|
このプラグインは、セキュリティ上の理由からノートを完全に自己管理する必要がある研究者、エンジニア、開発者に特に適しています。ノートが完全にプライベートなままであることに安心感を求める方にも適しています。
|
||||||
|
|
||||||
>[!IMPORTANT]
|
>[!IMPORTANT]
|
||||||
> - インストール・アップデート前には必ずVaultをバックアップしてください
|
> - このプラグインをインストールまたはアップグレードする前に、Vault をバックアップしてください。
|
||||||
> - 複数の同期ソリューションを同時に有効にしないでください(これはiCloudや公式のSyncも含みます)
|
> - iCloud や Obsidian Sync など、同じ Vault に書き込む他の同期ソリューションと同時に有効にしないでください。
|
||||||
> - このプラグインは同期プラグインです。バックアップとして使用しないでください
|
> - バックアップには、[Differential ZIP Backup](https://github.com/vrtmrz/diffzip) も利用できます。
|
||||||
|
|
||||||
|
|
||||||
## このプラグインの使い方
|
## このプラグインの使い方
|
||||||
|
|
||||||
### 3分セットアップ - CouchDB on fly.io
|
セルフホストでは、信頼できるサーバーを選び、自分で管理できます。サーバーをセットアップして保守し、安全な状態を保ってください。
|
||||||
|
|
||||||
**はじめての方におすすめ**
|
<a id="setup-workflows"></a>
|
||||||
|
|
||||||
[](https://www.youtube.com/watch?v=7sa_I1832Xc)
|
### 必要なもの
|
||||||
|
|
||||||
1. [Fly.ioにCouchDBをセットアップする](docs/setup_flyio.md)
|
| 方法 | 必要なもの | あると便利なもの |
|
||||||
2. [Quick Setup](docs/quick_setup_ja.md)でプラグインを設定する
|
| --- | --- | --- |
|
||||||
|
| CouchDB | CouchDB 互換サーバー | — |
|
||||||
|
| オブジェクトストレージ | S3 互換サービスまたはサーバー | — |
|
||||||
|
| ピアツーピア | 不要 | 独自のシグナリングサーバー |
|
||||||
|
|
||||||
|
CouchDB 互換サーバーを使う場合は、環境に合ったセットアップガイドを選んでください。
|
||||||
|
|
||||||
### Manually Setup
|
- [自分のサーバー](docs/setup_own_server_ja.md): Raspberry Pi など、自分で管理するサーバーで CouchDB を実行します。
|
||||||
|
- [Docker](docker/README.md): 付属の Docker スタックで CouchDB をデプロイします。
|
||||||
|
- [Fly.io](docs/setup_flyio.md): ホスト型インフラ上で自分の CouchDB インスタンスを管理します。
|
||||||
|
- [IBM Cloudant(マネージド)](docs/setup_cloudant_ja.md): IBM が管理するデータベースサービスを利用します。
|
||||||
|
|
||||||
1. サーバのセットアップ
|
各ガイドでセットアップ方法とプロバイダー固有の費用を確認してください。
|
||||||
1. [Fly.ioにCouchDBをセットアップする](docs/setup_flyio.md)
|
|
||||||
2. [CouchDBをセットアップする](docs/setup_own_server_ja.md)
|
|
||||||
2. [Quick Setup](docs/quick_setup_ja.md)でプラグインを設定する
|
|
||||||
|
|
||||||
> [!TIP]
|
<a id="3-minute-setup---couchdb-on-flyio"></a>
|
||||||
> IBM Cloudantもまだ使用できますが、いくつかの理由で現在はおすすめしていません。[IBM Cloudantのセットアップ](docs/setup_cloudant_ja.md)はまだあります。
|
|
||||||
|
Fly.io の動画による手順は、[自動セットアップ](docs/setup_flyio.md#a-very-automated-setup)を参照してください。
|
||||||
|
|
||||||
|
P2P では中央のデータ保存サーバーは不要ですが、ピアの検出にはシグナリングリレーが必要です。プロジェクトの公開シグナリングリレーを利用できるため、サーバーを用意する必要はありません。別のデバイスが同期している間は、必要なデータを持つデバイスを少なくとも1台オンラインにしてください。[P2P の通信モデル](./docs/p2p.md)を確認してから、[ピアツーピアのセットアップ](./docs/setup_p2p.md)に進んでください。
|
||||||
|
|
||||||
|
デバイス上で P2P のセットアップと接続がどのように動作するかを確認したい場合は、実験的な [WebPeer ブラウザーユーティリティ](https://vrtmrz.github.io/obsidian-livesync/webpeer/)のガイド付き接続チェックを試してください。空の Vault を使用し、ノートの同期はテストしません。範囲と制限は [WebPeer のドキュメント](src/apps/webpeer/README.md)を参照してください。
|
||||||
|
|
||||||
|
### 同期を開始する
|
||||||
|
|
||||||
|
1. 最初のデバイスで、CouchDB の[クイックセットアップ](docs/quick_setup_ja.md)、[オブジェクトストレージのセットアップ](docs/setup_object_storage.md)、または[ピアツーピアのセットアップ](docs/setup_p2p.md)を使用して Self-hosted LiveSync をインストールおよび設定します。
|
||||||
|
2. 動作中のデバイスからセットアップ URI を生成し、同じガイドに従って他のデバイスを追加します。
|
||||||
|
3. テスト用ノートを作成し、双方向に同期されることを確認します。
|
||||||
|
|
||||||
|
<a id="third-party-managed-couchdb-hosting"></a>
|
||||||
|
|
||||||
|
### コミュニティが紹介するホスティングサービス
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> 以下のサービスは第三者によって運営されています。Self-hosted LiveSync の公式サービスではなく、本プロジェクトが推奨または保証するものでもありません。表内の掲載は各プロバイダーから提案されたものです。
|
||||||
|
|
||||||
|
自分でサーバーをセットアップして保守したくない場合は、以下のプロバイダーが、このプラグインから接続できるマネージド CouchDB サーバーを提供しています。
|
||||||
|
|
||||||
|
| プロバイダー | 提供内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| [Zenith Hosting](https://zenith.hosting/host/obsidian-livesync) | マネージド CouchDB ホスティング。 |
|
||||||
|
|
||||||
|
同期データはプロバイダーが運営するサーバーに保存されます。Vault にとって許容できるか検討し、利用前にプロバイダーの最新の利用規約、料金、データ取扱方針を確認してください。
|
||||||
|
|
||||||
## ステータスバーの説明
|
## ステータスバーの説明
|
||||||
|
|
||||||
同期ステータスはステータスバーに、下記のアイコンとともに表示されます
|
同期ステータスは、デフォルトでステータスバーとエディタ内に表示されます。主な表示は以下のとおりです。
|
||||||
|
|
||||||
- アクティビティー
|
| 表示 | 意味 |
|
||||||
- 📲 ネットワーク接続中
|
| --- | --- |
|
||||||
- 同期ステータス
|
| ⏹️ | 停止中。 |
|
||||||
- ⏹️ 停止中
|
| 🌀 | 同期を開始しています。 |
|
||||||
- 💤 変更待ち(LiveSync中)
|
| 💤 | LiveSync モードが変更を待っています。 |
|
||||||
- ⚡️ 同期の進行中
|
| ⚡️ | 同期中です。 |
|
||||||
- ⚠ エラー
|
| ⏩ | CouchDB の変更履歴を比較しています(ローカルに保持済みの項目も含みます)。 |
|
||||||
- 統計情報
|
| ⚠ | エラーが発生しました。 |
|
||||||
- ↑ アップロードしたチャンクとメタデータ数
|
| ↑ / ↓ | アップロード/ダウンロードしたチャンクとメタデータ。 |
|
||||||
- ↓ ダウンロードしたチャンクとメタデータ数
|
| 📲 / 🌐N | 個別のリモート操作を実行中/概算のリモートリクエスト数。 |
|
||||||
- 進捗情報
|
|
||||||
- 📥 転送後、未処理の項目数
|
|
||||||
- 📄 稼働中データベース操作数
|
|
||||||
- 💾 稼働中のストレージ書き込み数操作数
|
|
||||||
- ⏳ 稼働中のストレージ読み込み数操作数
|
|
||||||
- 🛫 待機中のストレージ読み込み数操作数
|
|
||||||
- ⚙️ 隠しファイルの操作数(待機・稼働中合計)
|
|
||||||
- 🧩 取得待ちを行っているチャンク数
|
|
||||||
- 🔌 設定同期関連の操作数
|
|
||||||
|
|
||||||
データベースやファイルの破損を避けるため、Obsidianの終了は進捗情報が表示されなくなるまで待ってください(プラグインも復帰を試みますが)。特にファイルを削除やリネームした場合は気をつけてください。
|
<a id="customising-status-items-with-css-snippets"></a>
|
||||||
|
|
||||||
|
詳細な進捗カウンターと [CSS のカスタマイズ](docs/tips/status-display.md#customising-status-items-with-css-snippets)については、[ステータス表示ガイド](docs/tips/status-display.md)を参照してください。
|
||||||
|
|
||||||
## Tips and Troubleshooting
|
Obsidian を閉じる前に、保留中のファイル操作が完了するまで待ってください。特にファイルの削除や名前変更の後は注意してください。
|
||||||
- 2台目以降のセットアップ時に、初期同期をより迅速かつ簡単に行うには、[ファストセットアップガイド](docs/tips/fast-setup_ja.md)をご参照ください。
|
|
||||||
- 何かこまったら、[Tips and Troubleshooting](docs/troubleshooting.md)をご参照ください。
|
|
||||||
|
|
||||||
## License
|
## ヒントとトラブルシューティング
|
||||||
|
- 後続のデバイスをセットアップする際に、より高速で簡単な初期複製を行う場合は、[Fast Setup ガイド](docs/tips/fast-setup_ja.md)を参照してください。
|
||||||
|
- 通常のノート同期が動作することを確認してから、[非表示ファイル同期](docs/tips/hidden-file-sync.md)を設定してください。
|
||||||
|
- Obsidian または LiveSync が正常に起動できない場合は、リモートデータベースを変更またはリセットする前に、[復旧とフラグファイル](docs/recovery.md)を確認してください。
|
||||||
|
- Self-hosted LiveSync 1.0 には Obsidian 1.7.2 以降が必要です。旧バージョンの Obsidian で 1.0 を使用する必要がある場合は、バージョン、プラットフォーム、およびそのバージョンにとどまる理由を添えて [Issue を作成](https://github.com/vrtmrz/obsidian-livesync/issues/new?template=issue-report.md)してください。サポートの拡張が可能かどうかを検討します。標準のコミュニティプラグインインストーラーでは、互換性のある古いプラグインリリースが選択されます。
|
||||||
|
- プラグインが動作しない場合は、[トラブルシューティング](docs/troubleshooting.md)を参照してください。
|
||||||
|
|
||||||
Licensed under the MIT License.
|
## 謝辞
|
||||||
|
本プロジェクトの継続的な発展は、以下の方々の支援によって支えられています。
|
||||||
|
- 多くの [コントリビューター](https://github.com/vrtmrz/obsidian-livesync/graphs/contributors)の皆様。
|
||||||
|
- 多くの [GitHub スポンサー](https://github.com/sponsors/vrtmrz#sponsors)の皆様。
|
||||||
|
- JetBrains コミュニティプログラム / オープンソースプロジェクト支援 <img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.png" alt="JetBrains logo" height="24">
|
||||||
|
|
||||||
|
貢献してくださった方々のご厚意とご支援に、深く感謝します。
|
||||||
|
|
||||||
|
## 開発ガイド
|
||||||
|
開発環境のセットアップ、テスト基盤、コード規約などについては、[開発ガイド](devs.md)を参照してください。
|
||||||
|
|
||||||
|
## ライセンス
|
||||||
|
|
||||||
|
MIT License の下で公開されています。
|
||||||
+105
-58
@@ -1,93 +1,140 @@
|
|||||||
# Quick setup
|
# クイックセットアップ
|
||||||
このプラグインには、いろいろな状況に対応するための非常に多くの設定オプションがあります。しかし、実際に使用する設定項目はそれほど多くはありません。そこで、初期設定を簡略化するために、「セットアップウィザード」を実装しています。
|
|
||||||
※なお、次のデバイスからは、`現在の設定をセットアップURIにコピー`と`セットアップURIで接続`を使ってセットアップしてください。
|
|
||||||
|
|
||||||
|
[英語版](./quick_setup.md) - [中国語版](./quick_setup_cn.md)
|
||||||
|
|
||||||
## Wizardの使い方
|
このガイドでは、最初のデバイスで通常のノート同期を開始し、その後、別のデバイスを追加します。オプション機能は、この基本的な同期が動作することを確認してから設定してください。
|
||||||
`🧙♂️ Setup wizard` から開きます。もしセットアップされていなかったり、同期設定が何も有効になっていない場合はデフォルトで開いています。
|
|
||||||
|
|
||||||

|
開始前に、次の準備をしてください。
|
||||||
|
|
||||||
### Discard the existing configuration and set up
|
- 対象となるすべての Vault をバックアップする。
|
||||||
今設定されている内容をいったん全部消してから、ウィザードを始めます。
|
- Obsidian Sync、iCloud 同期、および同じ Vault に書き込む他のサービスを無効にする。
|
||||||
|
- リモートサービスとセットアップ URI を用意する。
|
||||||
|
- セットアップ URI とそのパスフレーズを別々に保管する。
|
||||||
|
|
||||||
### Do not discard the existing configuration and set up
|
この手順では、推奨されるプロビジョニング済み CouchDB の手順を説明します。サーバーとセットアップ URI の準備方法は[こちら](./setup_own_server_ja.md)を参照してください。
|
||||||
今の設定を消さずにウィザードを開始します。
|
|
||||||
たとえ設定されていたとしても、ウィザードモードではすべての設定を見ることができません。
|
|
||||||
|
|
||||||
いずれかのNextを押すと、設定画面がウィザードモードになります。
|
## セットアップ URI の内容
|
||||||
|
|
||||||
### Wizardモード
|
セットアップ URI は `obsidian://setuplivesync?settings=` で始まります。認証情報を含む接続設定が暗号化されて格納されていますが、暗号化されていても URI 自体を安全に保管してください。
|
||||||
|
|
||||||

|
セットアップ URI 用のパスフレーズは URI を復号するためのものです。同期データを保護する Vault 暗号化パスフレーズとは別のものです。両方を安全に保管し、URI とそのパスフレーズを同じ経路で送らないでください。
|
||||||
|
|
||||||
順番に設定を行っていきます。
|
## 1台目のデバイスをセットアップする
|
||||||
|
|
||||||
## Remote Database configuration
|
リモートデータベースが新規の場合、またはサーバー全体を再構築する際にこのデバイスを明示的に正本とする場合に限り、この手順を使ってください。
|
||||||
|
|
||||||
### Remote databaseの設定
|
1. 対象の Vault に Self-hosted LiveSync をインストールして有効にします。
|
||||||
セットアップしたデータベースの情報を入力していきます。
|
2. `Welcome to Self-hosted LiveSync` 通知を選び、オンボーディングを開きます。
|
||||||
|
3. `I am setting this up for the first time` を選び、新しい同期をセットアップすることを確認します。
|
||||||
|
4. `Connection Method` で `Use a Setup URI (Recommended)` を選びます。
|
||||||
|
5. セットアップ URI を貼り付け、URI 用のパスフレーズを入力して `Test Settings and Continue` を選びます。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
これらはデータベースをセットアップした際に決めた情報です。
|
6. `Setup Complete: Preparing to Initialise Server` の内容を確認し、`Restart and Initialise Server` を選びます。
|
||||||
|
|
||||||
### Test database connectionとCheck database configuration
|

|
||||||
ここで、データベースへの接続状況と、データベース設定を確認します。
|
|
||||||

|
|
||||||
|
|
||||||
#### Test Database Connection
|
7. 最終的な上書き警告をよく読みます。バックアップがあり、リモートデータを置き換える意図があることを確認してから、`I Understand, Overwrite Server` を選びます。
|
||||||
データベースに接続できるか自体を確認します。失敗する場合はいくつか理由がありますが、一度Check database configurationを行ってそちらでも失敗するか確認してください。
|
|
||||||
|
|
||||||
#### Check database configuration
|

|
||||||
データベースの設定を確認し、不備がある場合はその場で修正します。
|
|
||||||
|
|
||||||

|
8. 新規に用意したデータベースでは、`No Synchronisation Settings Found` と表示される場合があります。新しいデータベースであることが確かな場合は、`Use this device's settings` を選びます。既存の設定があるはずなら、キャンセルして接続先のリモートを確認してください。キャンセルすると、Vault とデータベースへの反映を一時停止した状態で再起動します。リモートを確認するまで LiveSync を無効のままにしてください。`Could Not Read Synchronisation Settings` と表示された場合は再試行するか、このデバイスの設定を使って上書きを続行します。上書きには正常な接続が必要です。
|
||||||
|
|
||||||
この項目は接続先によって異なる場合があります。上記の場合、みっつのFixボタンを順にすべて押してください。
|

|
||||||
Fixボタンがなくなり、すべてチェックマークになれば完了です。
|
|
||||||
|
|
||||||
### 機密性設定
|
9. `All optional features are disabled` の確認に進みます。通常の同期経路を確認するまで、オプション機能は無効のままにしてください。
|
||||||
|
10. 初期化と、要求された再起動が完了するまで待ちます。LiveSync の進捗表示が消えるまで Obsidian を開いたままにしてください。
|
||||||
|
|
||||||

|
別のデバイスを追加する前に、通常のテストノートを作成し、アップロードが完了するまで待ちます。
|
||||||
|
|
||||||
意図しないデータベースの暴露に備えて、End to End Encryptionを有効にします。この項目を有効にした場合、デバイスを出る瞬間にノートの内容が暗号化されます。`Path Obfuscation`を有効にすると、ファイル名も難読化されます。現在は安定しているため、こちらも推奨されます。
|
## 別のデバイス用のセットアップ URI を作成する
|
||||||
暗号化には256bitのAES-GCMを採用しています。
|
|
||||||
これらの設定は、あなたが閉じたネットワークの内側にいて、かつ第三者からアクセスされない事が明確な場合には無効にできます。
|
|
||||||
|
|
||||||
|
動作中の1台目のデバイスで、追加デバイス用のセットアップ URI を作成します。サーバーのプロビジョニング時に作成した URI を使い回すのではなく、1台目で実際に使われている設定を取り込めます。
|
||||||
|
|
||||||

|
1. 1台目で Obsidian のコマンドパレットを開きます。
|
||||||
|
2. `Self-hosted LiveSync: Copy settings as a new Setup URI` を実行します。
|
||||||
|
3. URI を保護する新しいパスフレーズを入力し、`OK` を選びます。
|
||||||
|
|
||||||
### Next
|

|
||||||
次へ進みます
|
|
||||||
|
|
||||||
### Discard exist database and proceed
|
4. 生成されたセットアップ URI をコピーし、`OK` を選びます。
|
||||||
すでにRemote databaseがある場合、Remote databaseの内容を破棄してから次へ進みます
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Sync Settings
|
新しい URI とそのパスフレーズは別々に保管してください。URI は暗号化されていますが、認証情報と Vault 設定を含むため、引き続き安全に扱ってください。
|
||||||
最後に同期方法の設定を行います。
|
|
||||||
|
|
||||||

|
## 別のデバイスを追加する
|
||||||
|
|
||||||
Presetsから、いずれかの同期方法を選び`Apply`を行うと、必要に応じてローカル・リモートのデータベースを初期化・構築します。
|
新しい Vault、または別途バックアップした Vault を使ってください。未同期のノートがある本番 Vault は、[Fast Setup の選択肢](./tips/fast-setup_ja.md)を確認せずに使用しないでください。
|
||||||
「All done!」(日本語環境では「完了!」)と表示されれば完了です。自動的に、「現在の設定をセットアップURIにコピー」のダイアログが開き、Setup URIを暗号化するためのパスフレーズを求められます(このパスフレーズはSetup URIを暗号化するためのもので、Vault自体の暗号化キーではありません)。
|
|
||||||
パスフレーズを入力すると、クリップボードにSetup URIが保存されますので、これを2台目以降のデバイスに何らかの方法で転送してください。
|
|
||||||
|
|
||||||

|
1. Self-hosted LiveSync をインストールして有効にします。
|
||||||
|
2. `Welcome to Self-hosted LiveSync` 通知からオンボーディングを開きます。
|
||||||
|
3. `I am adding a device to an existing synchronisation setup` を選び、デバイスを追加することを確認します。
|
||||||
|
4. `Device Setup Method` で `Use a Setup URI (Recommended)` を選びます。
|
||||||
|
5. 1台目で作成した新しいセットアップ URI を貼り付け、URI 用のパスフレーズを入力して `Test Settings and Continue` を選びます。
|
||||||
|
6. `Setup Complete: Preparing to Fetch Synchronisation Data` の内容を確認し、`Restart and Fetch Data` を選びます。
|
||||||
|
|
||||||
お好みのパスフレーズを設定してください。
|

|
||||||
クリップボードにSetup URIが保存されますので、これを2台目以降のデバイスに何らかの方法で転送してください。
|
|
||||||
|
|
||||||
# 2台目以降の設定方法
|
7. 新規または空の Vault では `Overwrite all with remote files` を選びます。ローカルの作業がある Vault では操作を止め、[Fast Setup ガイド](./tips/fast-setup_ja.md)から適切な方法を選んでください。
|
||||||
2台目の端末にSelf-hosted LiveSyncをインストールしたあと、コマンドパレットから`Use the copied setup URI (Formerly Open setup URI)`を選択し、転送したsetup URIを入力します。その後、パスフレーズを入力するとセットアップ用のウィザードが開きます。
|
|
||||||
下記のように答えてください。
|
|
||||||
|
|
||||||
- `Importing LiveSync's conf, OK?` に `Yes`
|

|
||||||
- `How would you like to set it up?` に `Set it up as secondary or subsequent device`
|
|
||||||
|
|
||||||
これで設定が反映され、レプリケーションが開始されます。
|
8. 追加のローカルファイルの扱いを尋ねられたら、保守的な選択肢は `Keep local files even if not on remote` です。ローカル Vault を破棄してリモートと完全に同じ状態にする意図がある場合に限り、削除する選択肢を使ってください。
|
||||||
|
|
||||||
> [!TIP]
|

|
||||||
> **ファストセットアップ (Fast Setup)**
|
|
||||||
> 近年のバージョンでは、セットアップURIの読み込みやデータの全取得(Fetch All)を実行した際、より簡単に同期戦略を選択して即座に初期同期を完了できる **ファストセットアップ (Simple Fetch)** フローが利用できます。詳細は [ファストセットアップガイド](./tips/fast-setup_ja.md) をご参照ください。
|
9. データ取得、ファイルへの反映、および要求された再起動が完了するまで待ちます。LiveSync の進捗表示が消えるまで Obsidian を開いたままにしてください。
|
||||||
|
|
||||||
|
1台目で作成したテストノートが変更されずに表示されることを確認します。次に、新しいデバイスで2つ目の通常ノートを作成または編集し、1台目に届くことを確認します。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 通常の同期が動作した後
|
||||||
|
|
||||||
|
オプション機能は、どの機能が管理するかと初期化の方向を明確にするため、1つずつ追加してください。
|
||||||
|
|
||||||
|
- 選択した非表示ファイルやフォルダーには[非表示ファイル同期](./tips/hidden-file-sync.md)を使用します。
|
||||||
|
- Obsidian のカスタマイズ設定には[カスタマイズ同期](./settings_ja.md#6-customisation-sync-advanced)を使用します。
|
||||||
|
|
||||||
|
同じファイルに両方の機能を有効にしないでください。
|
||||||
|
|
||||||
|
## 1台目で CouchDB を手動設定する
|
||||||
|
|
||||||
|
この方法は CouchDB の準備ができていて、セットアップ URI を利用できない場合に使います。表示されるオンボーディング画面で1台目を設定する手順であり、CouchDB サーバーのプロビジョニングや修復は行いません。後続のデバイスには、認証情報を再入力するのではなく、この1台目で動作確認後に作成したセットアップ URI を使ってください。
|
||||||
|
|
||||||
|
1. 対象の Vault に Self-hosted LiveSync をインストールして有効にします。
|
||||||
|
2. `Welcome to Self-hosted LiveSync` 通知を選び、`I am setting this up for the first time` を選択して、新しい同期をセットアップすることを確認します。
|
||||||
|
3. `Connection Method` で `Configure a remote manually`、続けて `Proceed with manual configuration` を選びます。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
4. `End-to-End Encryption` で同期データの保護方法を決めます。
|
||||||
|
- 通常の新規 Vault では `End-to-End Encryption` を有効にし、強力な Vault 暗号化パスフレーズを入力します。
|
||||||
|
- リモートドキュメントのプロパティも隠す場合は `Obfuscate Properties` を有効にします。
|
||||||
|
- Vault 暗号化パスフレーズは安全に保管してください。セットアップ URI を保護するパスフレーズとは別のものです。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
5. `Choose a synchronisation remote` で `CouchDB` を選び、`Continue to CouchDB setup` を選びます。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
6. CouchDB の完全な URL、ユーザー名、パスワード、データベース名を入力します。
|
||||||
|
- Obsidian Mobile では HTTPS が必要です。HTTP は、デスクトップから信頼できるローカル接続を行う場合に限り使用できます。
|
||||||
|
- 選択したデータベースへの接続が許可された認証情報を使います。1台目を設定する際、データベースが存在しなければ作成できる権限も必要です。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
7. `Check server requirements` は任意です。表示中の認証情報を Obsidian の内部リクエスト API 経由で設定済みサーバーへ送信します。一部の検査には CouchDB 管理者権限が必要です。最初の検査は読み取り専用です。サーバー変更が提案された場合は、個々の変更内容を確認してから別途承認してください。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
8. `Create or connect to database and continue` を選びます。オンボーディングを続けるには、この接続テストに成功する必要があります。
|
||||||
|
9. `Setup Complete: Preparing to Initialise Server` の内容を確認し、`Restart and Initialise Server` を選びます。
|
||||||
|
10. 最終的な上書き警告を読みます。このデバイスを正本とする意図があり、最新のバックアップがある場合に限り、`I Understand, Overwrite Server` を選びます。
|
||||||
|
11. 新規作成したデータベースでは `No Synchronisation Settings Found` と表示される場合があります。この新規データベースであることが確かな場合は、`Use this device's settings` を選びます。既存の設定があるはずなら、キャンセルして接続先を確認してください。キャンセル後は Vault とデータベースへの反映を一時停止した状態で再起動するため、リモートを確認するまで LiveSync を無効のままにしてください。`Could Not Read Synchronisation Settings` と表示された場合は再試行するか、このデバイスの設定を使って上書きを続行します。上書きには正常な接続が必要です。
|
||||||
|
12. `All optional features are disabled` の確認に進み、初期化の進捗が消えるまで Obsidian を開いたままにしてください。
|
||||||
|
|
||||||
|
通常のテストノートを作成し、同期されることを確認します。CouchDB に届いたら、[別のデバイス用のセットアップ URI を作成する](#別のデバイス用のセットアップ-uri-を作成する)、続けて[別のデバイスを追加する](#別のデバイスを追加する)に進んでください。これにより、2台目の設定を、1台目で実際に適用されたリモートプロファイルと暗号化設定に合わせられます。
|
||||||
+1495
-373
File diff suppressed because it is too large.
Load diff
+28
-27
@@ -1,7 +1,7 @@
|
|||||||
# IBM Cloudantのセットアップ
|
# IBM Cloudant のセットアップ
|
||||||
|
|
||||||
## インスタンスの作成
|
## インスタンスの作成
|
||||||
下記の手順で、試用のためにIBM Cloudantのインスタンスを作成できます。
|
下記の手順で、試用のために IBM Cloudant のインスタンスを作成できます。
|
||||||
|
|
||||||
|
|
||||||
1. 「リソースの作成」ボタンをクリックします。
|
1. 「リソースの作成」ボタンをクリックします。
|
||||||
@@ -10,70 +10,71 @@
|
|||||||
1. カタログが開くので、「Cloudant」と検索してください。出てきた選択肢をクリックすると作成画面に進みます。
|
1. カタログが開くので、「Cloudant」と検索してください。出てきた選択肢をクリックすると作成画面に進みます。
|
||||||

|

|
||||||
|
|
||||||
1. Liteプランを選択してください。
|
1. 無料の Lite プランを選択してください。
|
||||||

|

|
||||||
|
|
||||||
1. リージョンと環境を選択します。LiteではMultitenantしか選択できないので、Multitenantを選択してください。デフォルトで選択されています。
|
1. リージョンと環境を選択します。Lite では Multitenant しか選択できないので、Multitenant を選択してください。デフォルトで選択されています。
|
||||||
リージョンはお好みの場所で作成してください。
|
リージョンはお好みの場所で作成してください。
|
||||||

|

|
||||||
|
|
||||||
3. "Authentication Method"で「IAM and legacy credentials」を選択します。
|
1. "Authentication Method"で「IAM and legacy credentials」を選択します。
|
||||||

|

|
||||||
|
|
||||||
4. Liteプランが選択されていることと、Capacityを確認します。
|
1. Lite プランが選択されていることと、Capacity を確認します。
|
||||||

|

|
||||||
|
|
||||||
5. 確認ができたら、右側のCreateボタンをクリックします。
|
1. 確認ができたら、右側の Create ボタンをクリックします。
|
||||||

|

|
||||||
|
|
||||||
6. 上記の手順が正常に完了したら、左のメニューから「リソース・リスト」をクリックしてください。リソース・リストが表示され、「サービス及びソフトウエア」に作成したCloudantのインスタンスが表示されます。
|
1. 上記の手順が正常に完了したら、左のメニューから「リソース・リスト」をクリックしてください。リソース・リストが表示され、「サービスおよびソフトウェア」に作成した Cloudant のインスタンスが表示されます。
|
||||||
インスタンス名をクリックしてください。
|
インスタンス名をクリックしてください。
|
||||||

|

|
||||||
|
|
||||||
7. ここで、"External Endpoint (preferred)" と記載されているアドレスを控えてください。後ほど使います。<sup>(\*1)</sup>
|
1. ここで、"External Endpoint (preferred)" と記載されているアドレスを控えてください。後ほどデータベース名と組み合わせて使用します。<sup>(\*1)</sup>
|
||||||

|

|
||||||
|
|
||||||
## データベースの設定
|
## データベースの設定
|
||||||
|
|
||||||
1. 「Launch Dashboard」ボタンをクリックします。そうすると、今度はデータベースのダッシュボードが表示されます。CouchDBには、Fauxtonというインターフェイスがあるのですが、それそのものです。
|
1. 「Launch Dashboard」ボタンをクリックします。すると、データベースのダッシュボードが表示されます。これは CouchDB の Fauxton インターフェースとほぼ同じものです。
|
||||||

|

|
||||||
|
|
||||||
1. CORSの許可設定を行います。メニューの「Account」をクリックし、「CORS」タブを開きます。
|
1. CORS の許可設定を行います。メニューの「Account」をクリックし、「CORS」タブを開きます。
|
||||||
最初は「Restrict to specific domains」が選択されているので、「All domains (\*)」を選択し直します。この反映は即座に行われますが、すぐに戻せるので大丈夫です。
|
最初は「Restrict to specific domains」が選択されているので、「All domains (\*)」を選択し直します。この反映は即座に行われますが、すぐに戻せるので大丈夫です。
|
||||||
|
ただし、Cloudant では `app://obsidian.md` を許可する設定は使用できません。
|
||||||

|

|
||||||
|
|
||||||
1. データベースが作成できるか確認します。メニューの「Databases」をクリックし、次に「Create Database」ボタンをクリックします。
|
1. データベースが作成できるか確認します。メニューの「Databases」をクリックし、次に「Create Database」ボタンをクリックします。
|
||||||
右側にパネルが表示されますので、好きな名前を入力し、「Create」ボタンをクリックします。
|
右側にパネルが表示されますので、好きな名前を入力し<sup>(\*2)</sup>、「Create」ボタンをクリックします。
|
||||||

|

|
||||||
|
|
||||||
1. それっぽいメッセージが表示された後、データベースが表示されていれば、ほとんどセットアップは完了です。今後、ほとんどこの画面は使いません。Self-hosted LiveSyncからデータベースは作成できます。
|
1. 完了を示すメッセージが表示された後、データベースが表示されていれば、セットアップはほぼ完了です。データベースを作成できることを確認した後は、通常この画面を開く必要はありません。Self-hosted LiveSync からもデータベースを作成できます。
|
||||||

|

|
||||||
|
|
||||||
### 資格情報のセットアップ
|
### 認証情報のセットアップ
|
||||||
|
|
||||||
1. IBM Cloudに戻って、「サービス資格情報」をクリックしてください。おそらく何も表示されていないので、「新規資格情報」をクリックします。
|
1. IBM Cloud に戻って、「サービス資格情報」をクリックしてください。おそらく何も表示されていないので、「新規資格情報」をクリックします。
|
||||||

|

|
||||||
|
|
||||||
1. 資格情報を作成するダイアログが表示されるので、わかりやすい名前を入力します。その後、役割に「管理者」が選択されていることを確認してから、「追加」ボタンをクリックしてください。
|
1. 認証情報を作成するダイアログが表示されるので、任意の名前を入力するか既定のままにして、「追加」ボタンをクリックしてください。
|
||||||

|

|
||||||
備考: この「名前」はSelf-hosted LiveSyncで使用するUsernameとはまた別のものです。
|
備考: この「名前」は Self-hosted LiveSync で使用する Username とはまた別のものです。
|
||||||
|
|
||||||
1. 「サービス資格情報」に戻ると、新しい資格情報が作成されています。~~わかりにくいことに名前は「鍵名」に変わります~~。左側のボタンを押すと詳細が開きます。
|
1. 「サービス資格情報」に戻ると、新しい認証情報が作成されています。~~わかりにくいことに名前は「鍵名」に変わります~~。左側のボタンを押すと詳細が開きます。
|
||||||

|

|
||||||
Self-hosted LiveSyncから使用するUsernameとPasswordは、表示されたJSONに記載されているものを使用します。
|
Self-hosted LiveSync から使用する Username と Password は、表示された JSON に記載されているものを使用します。
|
||||||
今回の図で言うと、Usernameは"apikey-v2-2unu15184f7o8emr90xlqgkm2ncwhbltml6tgnjl9sd5"<sup>(\*3)</sup>、パスワードは"c2c11651d75497fa3d3c486e4c8bdf27"<sup>(\*4)</sup>になります。
|
今回の図で言うと、Username は"apikey-v2-2unu15184f7o8emr90xlqgkm2ncwhbltml6tgnjl9sd5"<sup>(\*3)</sup>、パスワードは"c2c11651d75497fa3d3c486e4c8bdf27"<sup>(\*4)</sup>になります。
|
||||||
|
|
||||||
## Self-hosted LiveSyncに設定
|
## Self-hosted LiveSync に設定
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
先ほどの設定例から引用すると、
|
先ほどの設定例から引用すると、
|
||||||
|
|
||||||
| Items | Value | example |
|
| 項目 | 値 | 例 |
|
||||||
| ------------------- | -------------------------------- | --------------------------------------------------------------------------- |
|
| --- | --- | --- |
|
||||||
| URI | (\*1) | https://xxxxxxxxxxxxxxxxx-bluemix.cloudantnosqldb.appdomain.cloud |
|
| URI | (\*1) | https://xxxxxxxxxxxxxxxxx-bluemix.cloudantnosqldb.appdomain.cloud |
|
||||||
| Username | (\*3) | apikey-v2-2unu15184f7o8emr90xlqgkm2ncwhbltml6tgnjl9sd5 |
|
| Username | (\*3) | apikey-v2-2unu15184f7o8emr90xlqgkm2ncwhbltml6tgnjl9sd5 |
|
||||||
| Password | (\*4) | c2c11651d75497fa3d3c486e4c8bdf27 |
|
| Password | (\*4) | c2c11651d75497fa3d3c486e4c8bdf27 |
|
||||||
| Database name | (\*2) | sync-test |
|
| Database name | (\*2) | sync-test |
|
||||||
|
|
||||||
となります。
|
のとおりです。
|
||||||
+424
-83
@@ -1,93 +1,434 @@
|
|||||||
# CouchDBのセットアップ方法
|
# CouchDB サーバーのセットアップ
|
||||||
|
|
||||||
## CouchDBのインストールとPCやMacでの使用
|
## 目次
|
||||||
CouchDBを構築するには、[Dockerのイメージ](https://hub.docker.com/_/couchdb)を使用するのが一番簡単です。
|
|
||||||
ただし、インストールしたCouchDBをSelf-hosted LiveSyncから使用するためには、少々設定が必要となります。
|
- [1. CouchDB を準備する](#1-prepare-couchdb)
|
||||||
具体的には、下記の設定が`local.ini`として必要になります。
|
- [A. Docker を使用する](#a-using-docker)
|
||||||
|
- [B. Docker Compose を使用する](#b-using-docker-compose)
|
||||||
|
- [C. CouchDB を直接インストールする](#c-install-couchdb-directly)
|
||||||
|
- [2. couchdb-init.sh を実行して初期化する](#2-run-couchdb-initsh-for-initialise)
|
||||||
|
- [3. デバイスから CouchDB に接続できるようにする](#3-expose-couchdb-to-the-internet)
|
||||||
|
- [4. クライアントのセットアップ](#4-client-setup)
|
||||||
|
- [手動セットアップ情報](#manual-setup-information)
|
||||||
|
- [リバースプロキシ](#reverse-proxies)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="1-prepare-couchdb"></a>
|
||||||
|
|
||||||
|
## 1. CouchDB を準備する
|
||||||
|
|
||||||
|
<a id="a-using-docker"></a>
|
||||||
|
|
||||||
|
### A. Docker を使用する
|
||||||
|
|
||||||
|
<a id="1-prepare"></a>
|
||||||
|
|
||||||
|
#### 1. 準備
|
||||||
|
```bash
|
||||||
|
|
||||||
|
# 環境変数を設定する。
|
||||||
|
export hostname=http://localhost:5984
|
||||||
|
export username=goojdasjdas # 好きな値に変更してください。
|
||||||
|
export password=kpkdasdosakpdsa # 好きな値に変更してください。
|
||||||
|
|
||||||
|
# 保存データと設定用のディレクトリを作成する。
|
||||||
|
mkdir couchdb-data
|
||||||
|
mkdir couchdb-etc
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="2-run-docker-container"></a>
|
||||||
|
|
||||||
|
#### 2. Docker コンテナを実行する
|
||||||
|
1. 起動確認。
|
||||||
|
```
|
||||||
|
$ docker run --name couchdb-for-ols --rm -it -e COUCHDB_USER=${username} -e COUCHDB_PASSWORD=${password} -v ${PWD}/couchdb-data:/opt/couchdb/data -v ${PWD}/couchdb-etc:/opt/couchdb/etc/local.d -p 5984:5984 couchdb
|
||||||
|
```
|
||||||
|
> [!WARNING]
|
||||||
|
> コンテナがエラーで終了した場合は、couchdb-data と couchdb-etc のアクセス権を確認してください。
|
||||||
|
> CouchDB の起動後、これらのディレクトリの所有者は uid:`5984` になります。その uid に所有者を変更し直してください。
|
||||||
|
|
||||||
|
2. バックグラウンドで有効化する
|
||||||
|
```
|
||||||
|
$ docker run --name couchdb-for-ols -d --restart always -e COUCHDB_USER=${username} -e COUCHDB_PASSWORD=${password} -v ${PWD}/couchdb-data:/opt/couchdb/data -v ${PWD}/couchdb-etc:/opt/couchdb/etc/local.d -p 5984:5984 couchdb
|
||||||
|
```
|
||||||
|
|
||||||
|
完了したら、[手順 2](#2-run-couchdb-initsh-for-initialise)に進んでください。
|
||||||
|
|
||||||
|
<a id="b-using-docker-compose"></a>
|
||||||
|
|
||||||
|
### B. Docker Compose を使用する
|
||||||
|
|
||||||
|
<a id="1-prepare-1"></a>
|
||||||
|
|
||||||
|
#### 1. 準備
|
||||||
|
|
||||||
```
|
```
|
||||||
[couchdb]
|
# 保存データと設定用のディレクトリを作成する。
|
||||||
single_node=true
|
mkdir couchdb-data
|
||||||
max_document_size = 50000000
|
mkdir couchdb-etc
|
||||||
|
|
||||||
[chttpd]
|
# 所有者をユーザー 5984 に変更する。
|
||||||
require_valid_user = true
|
chown -R 5984:5984 ./couchdb-data
|
||||||
max_http_request_size = 4294967296
|
chown -R 5984:5984 ./couchdb-etc
|
||||||
|
```
|
||||||
|
|
||||||
[chttpd_auth]
|
<a id="2-create-a-docker-composeyml-file-with-the-following-added-to-it"></a>
|
||||||
require_valid_user = true
|
|
||||||
authentication_redirect = /_utils/session.html
|
|
||||||
|
|
||||||
[httpd]
|
#### 2. 次の内容を追加した `docker-compose.yml` ファイルを作成する
|
||||||
WWW-Authenticate = Basic realm="couchdb"
|
```
|
||||||
enable_cors = true
|
services:
|
||||||
|
couchdb:
|
||||||
|
image: couchdb:latest
|
||||||
|
container_name: couchdb-for-ols
|
||||||
|
user: 5984:5984
|
||||||
|
environment:
|
||||||
|
- COUCHDB_USER=<INSERT USERNAME HERE> # 好きな値に変更してください。
|
||||||
|
- COUCHDB_PASSWORD=<INSERT PASSWORD HERE> # 好きな値に変更してください。
|
||||||
|
volumes:
|
||||||
|
- ./couchdb-data:/opt/couchdb/data
|
||||||
|
- ./couchdb-etc:/opt/couchdb/etc/local.d
|
||||||
|
ports:
|
||||||
|
- 5984:5984
|
||||||
|
restart: unless-stopped
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="3-run-the-docker-compose-file-to-boot-check"></a>
|
||||||
|
|
||||||
|
#### 3. Docker Compose ファイルを実行して起動確認する
|
||||||
|
|
||||||
|
```
|
||||||
|
docker compose up
|
||||||
|
# 古いバージョンを使用している場合
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
> [!WARNING]
|
||||||
|
> コンテナがエラーで終了した場合は、couchdb-data と couchdb-etc のアクセス権を確認してください。
|
||||||
|
> CouchDB の起動後、これらのディレクトリの所有者は uid:`5984` になります。その uid に所有者を変更し直してください。
|
||||||
|
|
||||||
|
<a id="4-run-the-docker-compose-file-in-the-background"></a>
|
||||||
|
|
||||||
|
#### 4. Docker Compose ファイルをバックグラウンドで実行する
|
||||||
|
すべて正常に完了し、エラーが発生しなかった場合は、`CTRL+C` で終了してから次のコマンドを実行します。
|
||||||
|
```
|
||||||
|
docker compose up -d
|
||||||
|
# 古いバージョンを使用している場合
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
完了したら、[手順 2](#2-run-couchdb-initsh-for-initialise)に進んでください。
|
||||||
|
|
||||||
|
<a id="c-install-couchdb-directly"></a>
|
||||||
|
|
||||||
|
### C. CouchDB を直接インストールする
|
||||||
|
[公式ドキュメント](https://docs.couchdb.org/en/stable/install/index.html)を参照してください。ただし、完全に設定する必要はありません。管理者を設定するだけで十分です。
|
||||||
|
|
||||||
|
<a id="2-run-couchdb-initsh-for-initialise"></a>
|
||||||
|
|
||||||
|
## 2. couchdb-init.sh を実行して初期化する
|
||||||
|
|
||||||
|
Deno 2 が必要です。CouchDB の接続情報とデータベースの詳細をエクスポートし、プロビジョニング用のラッパーを実行します。
|
||||||
|
|
||||||
|
この手順の `username` と `password` は CouchDB の管理者認証情報です。Docker または Docker Compose の場合は、`COUCHDB_USER` と `COUCHDB_PASSWORD` に指定した同じ値を使用します。直接インストールした場合は、CouchDB のセットアップ時に設定した管理者を使用します。ラッパーは、管理者以外の同期用アカウントを別途作成しません。
|
||||||
|
|
||||||
|
```
|
||||||
|
export hostname=http://localhost:5984
|
||||||
|
export username='<INSERT COUCHDB ADMINISTRATOR USERNAME HERE>'
|
||||||
|
export password='<INSERT COUCHDB ADMINISTRATOR PASSWORD HERE>'
|
||||||
|
export database=obsidiannotes
|
||||||
|
curl -s https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> fish では `hostname` が読み取り専用で、エクスポートできません。代わりに `env` 経由で値を渡してください: `curl -s https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh | env hostname='http://localhost:5984' username='<INSERT COUCHDB ADMINISTRATOR USERNAME HERE>' password='<INSERT COUCHDB ADMINISTRATOR PASSWORD HERE>' database=obsidiannotes bash`
|
||||||
|
|
||||||
|
次のように表示された場合:
|
||||||
|
```
|
||||||
|
CouchDB provisioning completed.
|
||||||
|
```
|
||||||
|
|
||||||
|
ラッパーは、レジストリでバージョンを固定した Commonlib を使用するコードをそのまま実行します。`database` を指定すると、データベースを作成し、Commonlib を通じて LiveSync のデータベースバージョンドキュメントを初期化します。`database` を指定しない場合は、CouchDB サーバーの設定のみを行います。
|
||||||
|
|
||||||
|
Docker Compose を使用していて上記のコマンドが動作しない場合、または `ERROR: Hostname missing` と表示される場合は、プレースホルダーを自分の値に置き換えて次のコマンドを実行してください:
|
||||||
|
```
|
||||||
|
curl -s https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh | hostname='http://<YOUR SERVER IP>:5984' username='<INSERT COUCHDB ADMINISTRATOR USERNAME HERE>' password='<INSERT COUCHDB ADMINISTRATOR PASSWORD HERE>' database=obsidiannotes bash
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="3-expose-couchdb-to-the-internet"></a>
|
||||||
|
|
||||||
|
## 3. デバイスから CouchDB に接続できるようにする
|
||||||
|
|
||||||
|
- CouchDB を信頼できるローカルネットワーク上のデスクトップデバイスでのみ使用する場合は、この手順を省略できます。
|
||||||
|
- モバイルデバイスでは、Obsidian は有効な証明書付きの HTTPS を必要とします。HTTPS を使用するために CouchDB を公開する必要はありません。
|
||||||
|
|
||||||
|
デバイスから CouchDB サーバーへの接続方法を選択します。自分で運用する[リバースプロキシ](#reverse-proxies)、プライベートネットワーク経由のアクセス、または任意のトンネルサービスを使用できます。[Docker プロファイル](../docker/README.md#profile-details)には例があります。
|
||||||
|
|
||||||
|
Cloudflare は任意の選択肢の1つです。次の例では、一時的なテスト用に [Quick Tunnel](https://developers.cloudflare.com/tunnel/get-started/quick-tunnels/) を使用します。ランダムなホスト名が表示され、トンネルを作成するたびに変わります。また、`cloudflared` プロセスを停止すると URL は動作しなくなります。Quick Tunnel はテストと開発用であり、本番用ではありません。継続して使用する場合は、選択した接続方法を設定してください。Cloudflare を選ぶ場合は、[Cloudflare Tunnel ガイド](https://developers.cloudflare.com/tunnel/get-started/)が参考になります。
|
||||||
|
|
||||||
|
```
|
||||||
|
cloudflared tunnel --url http://localhost:5984
|
||||||
|
```
|
||||||
|
|
||||||
|
次の 2024 年の出力は形式の例です。ホスト名は例示のみを目的としています。実際には、自分のトンネルが出力した URL を使用してください。
|
||||||
|
|
||||||
|
```
|
||||||
|
2024-02-14T10:35:25Z INF Thank you for trying Cloudflare Tunnel. Doing so, without a Cloudflare account, is a quick way to experiment and try it out. However, be aware that these account-less Tunnels have no uptime guarantee. If you intend to use Tunnels in production you should use a pre-created named tunnel by following: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps
|
||||||
|
2024-02-14T10:35:25Z INF Requesting new quick Tunnel on trycloudflare.com...
|
||||||
|
2024-02-14T10:35:26Z INF +--------------------------------------------------------------------------------------------+
|
||||||
|
2024-02-14T10:35:26Z INF | Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): |
|
||||||
|
2024-02-14T10:35:26Z INF | https://tiles-photograph-routine-groundwater.trycloudflare.com |
|
||||||
|
2024-02-14T10:35:26Z INF +--------------------------------------------------------------------------------------------+
|
||||||
|
:
|
||||||
|
:
|
||||||
|
:
|
||||||
|
```
|
||||||
|
トンネルが出力した URL をサーバーアドレスとして使用します。クライアントの設定とテストが完了するまで、トンネルプロセスを実行したままにしてください。
|
||||||
|
|
||||||
|
<a id="4-client-setup"></a>
|
||||||
|
|
||||||
|
## 4. クライアントのセットアップ
|
||||||
|
> [!TIP]
|
||||||
|
> 生成されたセットアップ URI は、新しい Vault の現在のデフォルトと、選択したリモートプロファイルを引き継ぐため、推奨される方法です。セットアップ URI を生成できない場合は、[1台目で CouchDB を手動設定する](./quick_setup_ja.md#1台目で-couchdb-を手動設定する)に従い、その後、動作中のデバイスから新しいセットアップ URI を生成して、追加のデバイスごとに使用してください。
|
||||||
|
|
||||||
|
<a id="1-generate-the-setup-uri-on-a-desktop-device-or-server"></a>
|
||||||
|
|
||||||
|
### 1. デスクトップデバイスまたはサーバーでセットアップ URI を生成する
|
||||||
|
|
||||||
|
ここでの `LIVESYNC_USER` と `LIVESYNC_PASS` は、Self-hosted LiveSync がこのデータベースへの通常のアクセス用に保存する認証情報です。手順 2 の管理者認証情報でもかまいません。このデータベースへの必要なアクセス権を持つ CouchDB アカウントを別途設定している場合は、そのアカウントを使用してください。プロビジョニングラッパーもセットアップ URI ジェネレーターも、その別のアカウントを作成しません。
|
||||||
|
|
||||||
|
デバイスから CouchDB に接続するときに使用するサーバー URL を使用します。上記の一時的な Quick Tunnel の例では、実行中の自分のトンネルが出力した URL を使用してください。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export LIVESYNC_HOST='<YOUR COUCHDB SERVER URL>'
|
||||||
|
export LIVESYNC_DB=obsidiannotes
|
||||||
|
export LIVESYNC_USER='<INSERT COUCHDB USERNAME FOR LIVESYNC>'
|
||||||
|
export LIVESYNC_PASS='<INSERT THE COUCHDB PASSWORD>'
|
||||||
|
export LIVESYNC_PASSPHRASE='<INSERT A STRONG VAULT ENCRYPTION PASSPHRASE>'
|
||||||
|
export uri_passphrase='<INSERT A SEPARATE SETUP URI PASSPHRASE>' # 任意
|
||||||
|
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> `LIVESYNC_PASSPHRASE` は、エンドツーエンド暗号化で同期 Vault のデータを保護します。`uri_passphrase` はセットアップ URI のみを保護します。異なる値を使用し、両方を安全に保管し、セットアップ URI とそのパスフレーズを同じ経路で送らないでください。
|
||||||
|
>
|
||||||
|
> `uri_passphrase` を省略した場合、ジェネレーターは暗号学的にランダムな値を作成し、一度だけ表示します。
|
||||||
|
|
||||||
|
ジェネレーターは、ランダムな ID キーの復旧コードも表示します。同じ Vault のセットアップ URI を再生成する可能性がある場合は、そのコードを保存してください。`id_recovery_code` として渡し直さないと、後で実行したときに異なるキーが作成されます。`id_mode=legacy` は、以前の ID 動作を使用する Vault に接続する場合にのみ設定してください。詳しくは[セットアップユーティリティのリファレンス](../utils/readme.md#setup-uri-generation)を参照してください。
|
||||||
|
|
||||||
|
ジェネレーターは、プロビジョニングユーティリティが使用するのと同じ、レジストリでバージョンを固定した Commonlib リリースを使用します。設定済みの CouchDB リモートプロファイルを作成し、新しい Vault の現在のデフォルトを適用して、Commonlib のセットアップ URI 契約でエンコードします。
|
||||||
|
|
||||||
|
デフォルトでは、URI は Ephemeral(一時的)であり、ジェネレーターが表示した正確な UTC 時刻までのみ開けます。これは作成から7日後ではなく、固定された7日間の UTC ウィンドウの終了時点です。URI に時間条件が必要ない場合、または既存の暗号化形式をサポートする古いクライアントで読み取る必要がある場合は、コマンドを実行する前に `uri_mode=persistent` を設定してください。
|
||||||
|
|
||||||
|
出力は次の形式になります。以下のタイムスタンプと値は例です。
|
||||||
|
|
||||||
|
```text
|
||||||
|
Generated couchdb Setup URI.
|
||||||
|
Ephemeral: usable until 2026-10-01T00:00:00.000Z (UTC).
|
||||||
|
Your passphrase for the Setup URI is: H7vX...a-random-32-character-value
|
||||||
|
This passphrase is never shown again, so store it safely.
|
||||||
|
ID recovery code: sls-id-v1:<64 lowercase hexadecimal characters>
|
||||||
|
Use id_recovery_code with this value and reuse the same remote settings when generating another Setup URI for the same Vault.
|
||||||
|
obsidian://setuplivesync?settings=%5B%22tm2DpsOE74nJAryprZO2M93wF%2Fvg.......4b26ed33230729%22%5D
|
||||||
|
```
|
||||||
|
|
||||||
|
セットアップ URI とそのパスフレーズは別々に保管してください。
|
||||||
|
|
||||||
|
<a id="2-setup-self-hosted-livesync-to-obsidian"></a>
|
||||||
|
|
||||||
|
### 2. Self-hosted LiveSync を Obsidian にセットアップする
|
||||||
|
|
||||||
|
1台目については、[クイックセットアップ](./quick_setup_ja.md#1台目のデバイスをセットアップする)に従ってください。現在のオンボーディング通知、セットアップ URI のインポート、サーバーの初期化、および新しくプロビジョニングされたデータベースで表示される安全確認について説明しています。
|
||||||
|
|
||||||
|
通常のノート同期が動作した後、その1台目で[新しいセットアップ URI を生成](./quick_setup_ja.md#別のデバイス用のセットアップ-uri-を作成する)し、[別のデバイスを追加する](./quick_setup_ja.md#別のデバイスを追加する)に従ってください。2台目を、プロビジョニング時に作成した初期セットアップ URI の保持に依存させないでください。オプション機能は、通常の経路が確認された後にのみ設定してください。[非表示ファイル同期には専用のガイド](./tips/hidden-file-sync.md)があります。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="manual-setup-information"></a>
|
||||||
|
|
||||||
|
## 手動セットアップ情報
|
||||||
|
|
||||||
|
<a id="setting-up-your-domain"></a>
|
||||||
|
|
||||||
|
### ドメインの設定
|
||||||
|
|
||||||
|
ドメインの A レコードをサーバーに向けて設定し、任意の方法でリバースプロキシをホストします。
|
||||||
|
注: CouchDB をトップディレクトリにマウントすることは推奨しません。
|
||||||
|
Caddy を使用すると、SSL 付きでサーバーを自動的に提供でき便利です。
|
||||||
|
|
||||||
|
Caddy と CouchDB を同時に起動する [docker-compose.yml と ini ファイル](https://github.com/vrtmrz/self-hosted-livesync-server)を公開しています。Traefik を使用している場合は、下の[リバースプロキシ](#reverse-proxies)のセクションを確認してください。
|
||||||
|
|
||||||
|
また、サーバーログを必ず確認し、不正なアクセスに注意してください。
|
||||||
|
|
||||||
|
<a id="reverse-proxies"></a>
|
||||||
|
|
||||||
|
## リバースプロキシ
|
||||||
|
|
||||||
|
<a id="traefik"></a>
|
||||||
|
|
||||||
|
### Traefik
|
||||||
|
|
||||||
|
Traefik を使用している場合、この [docker-compose.yml](https://github.com/vrtmrz/obsidian-livesync/blob/main/docker-compose.traefik.yml) ファイル(下にも掲載)には、適切な CORS パラメーターがすべて設定されています。外部ネットワーク `proxy` が存在することを前提としています。
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
couchdb:
|
||||||
|
image: couchdb:latest
|
||||||
|
container_name: obsidian-livesync
|
||||||
|
user: 1000:1000
|
||||||
|
environment:
|
||||||
|
- COUCHDB_USER=username
|
||||||
|
- COUCHDB_PASSWORD=password
|
||||||
|
volumes:
|
||||||
|
- ./data:/opt/couchdb/data
|
||||||
|
- ./local.ini:/opt/couchdb/etc/local.ini
|
||||||
|
# Traefik に渡している場合はポートは不要
|
||||||
|
#ports:
|
||||||
|
# - 5984:5984
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# Traefik ネットワーク
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
# 'obsidian-livesync.example.org' を自分のドメインに置き換えるのを忘れないでください
|
||||||
|
- "traefik.http.routers.obsidian-livesync.rule=Host(`obsidian-livesync.example.org`)"
|
||||||
|
# 'websecure' エントリーポイントは基本的に HTTPS のエントリーポイントです。問題が発生した場合にのみ次のコードスニペットを確認してください。これがリバースプロキシする最初のコンテナでなければ、おそらく Traefik は正しく設定されています。
|
||||||
|
- "traefik.http.routers.obsidian-livesync.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.obsidian-livesync.service=obsidian-livesync"
|
||||||
|
- "traefik.http.services.obsidian-livesync.loadbalancer.server.port=5984"
|
||||||
|
- "traefik.http.routers.obsidian-livesync.tls=true"
|
||||||
|
# 'letsencrypt' を自分の証明書リゾルバーに置き換えてください
|
||||||
|
- "traefik.http.routers.obsidian-livesync.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.obsidian-livesync.middlewares=obsidiancors"
|
||||||
|
# Traefik 2.x で CORS を動作させるために必要な部分はここから
|
||||||
|
- "traefik.http.middlewares.obsidiancors.headers.accesscontrolallowmethods=GET,PUT,POST,HEAD,DELETE"
|
||||||
|
- "traefik.http.middlewares.obsidiancors.headers.accesscontrolallowheaders=accept,authorization,content-type,origin,referer"
|
||||||
|
- "traefik.http.middlewares.obsidiancors.headers.accesscontrolalloworiginlist=app://obsidian.md,capacitor://localhost,http://localhost"
|
||||||
|
- "traefik.http.middlewares.obsidiancors.headers.accesscontrolmaxage=3600"
|
||||||
|
- "traefik.http.middlewares.obsidiancors.headers.addvaryheader=true"
|
||||||
|
- "traefik.http.middlewares.obsidiancors.headers.accessControlAllowCredentials=true"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
```
|
||||||
|
|
||||||
|
上記で言及した `traefik.yml` 設定ファイルの抜粋:
|
||||||
|
```yml
|
||||||
|
...
|
||||||
|
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
address: ":80"
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entryPoint:
|
||||||
|
to: "websecure"
|
||||||
|
scheme: "https"
|
||||||
|
websecure:
|
||||||
|
address: ":443"
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="nginx"></a>
|
||||||
|
|
||||||
|
### Nginx
|
||||||
|
|
||||||
|
Nginx を CouchDB のリバースプロキシとして設定する際は、よくある間違いに注意してください。
|
||||||
|
|
||||||
|
1. Fast Fetch の進捗が止まり、無期限にフリーズしたように見える場合は、`proxy_buffering` が無効になっていることを確認してください:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:5984;
|
||||||
|
proxy_buffering off;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. "413 Entity too large" エラーが発生する場合は、`client_max_body_size` を増やしてください:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:5984;
|
||||||
|
client_max_body_size 50M; # 必要に応じて値を調整してください
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. "404 Database not found" エラーが発生する場合は、CouchDB をルートロケーションに配置していることを確認してください(推奨):
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
server_name couchdb.domain.com
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:5984;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
CouchDB をサブディレクトリに配置することも可能ですが、設定をそれに合わせて変更する必要があります:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
|
||||||
|
server {
|
||||||
|
server_name domain.com
|
||||||
|
|
||||||
|
location /couchdb {
|
||||||
|
rewrite ^ $request_uri;
|
||||||
|
rewrite ^/couchdb/(.*) /$1 break;
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:5984$uri;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
location /_session {
|
||||||
|
proxy_pass http://127.0.0.1:5984/_session;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. データベース接続の詳細設定でカスタム HTTP ヘッダーを追加した場合は、Nginx と CouchDB の両方の設定を更新してください:
|
||||||
|
|
||||||
|
Nginx:
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
set $pass 1;
|
||||||
|
|
||||||
|
# カスタム HTTP ヘッダーを処理する例
|
||||||
|
if ($http_x_custom_header != 'foo'){
|
||||||
|
set $pass 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 重要: OPTIONS リクエストにはヘッダーが含まれないため、常に CouchDB にプロキシする必要があります
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
set $pass 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pass = 0) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:5984;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
couchdb-etc/docker.ini:
|
||||||
|
```ini
|
||||||
|
...
|
||||||
[cors]
|
[cors]
|
||||||
origins = app://obsidian.md,capacitor://localhost,http://localhost
|
|
||||||
credentials = true
|
credentials = true
|
||||||
headers = accept, authorization, content-type, origin, referer
|
origins = app://obsidian.md,capacitor://localhost,http://localhost
|
||||||
methods = GET, PUT, POST, HEAD, DELETE
|
|
||||||
max_age = 3600
|
;カスタムヘッダーをリストに追加して、CORS が壊れないようにしてください
|
||||||
|
headers = accept, authorization, content-type, origin, referer, x-custom-header
|
||||||
```
|
```
|
||||||
|
|
||||||
このファイルを作成し、
|
|
||||||
```
|
|
||||||
$ docker run --rm -it -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v .local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
|
||||||
```
|
|
||||||
とすると簡単にCouchDBを起動することができます。
|
|
||||||
備考:このとき、local.iniのオーナーが5984:5984になります。これは、Dockerイメージの制限事項です。編集する場合はいったんオーナーを変更してください。
|
|
||||||
正常にSelf-hosted LiveSyncからアクセスすることができたら、お好みでバックグラウンドで起動するように編集して起動してください。
|
|
||||||
例)
|
|
||||||
```
|
|
||||||
$ docker run -d --restart always -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v .local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## モバイルからのアクセス
|
|
||||||
MacやPCからアクセスする場合は上記の方法で作ったサーバーで問題ありませんが、モバイル端末からアクセスする場合は有効なSSLの証明書が必要となります。
|
|
||||||
|
|
||||||
### モバイルからのアクセスのテスト
|
|
||||||
テストを行う場合は、[localhost.run](http://localhost.run/)などのサービスが便利です。
|
|
||||||
```
|
|
||||||
$ ssh -R 80:localhost:5984 nokey@localhost.run
|
|
||||||
Warning: Permanently added the RSA host key for IP address '35.171.254.69' to the list of known hosts.
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
Welcome to localhost.run!
|
|
||||||
|
|
||||||
Follow your favourite reverse tunnel at [https://twitter.com/localhost_run].
|
|
||||||
|
|
||||||
**You need a SSH key to access this service.**
|
|
||||||
If you get a permission denied follow Gitlab's most excellent howto:
|
|
||||||
https://docs.gitlab.com/ee/ssh/
|
|
||||||
*Only rsa and ed25519 keys are supported*
|
|
||||||
|
|
||||||
To set up and manage custom domains go to https://admin.localhost.run/
|
|
||||||
|
|
||||||
More details on custom domains (and how to enable subdomains of your custom
|
|
||||||
domain) at https://localhost.run/docs/custom-domains
|
|
||||||
|
|
||||||
To explore using localhost.run visit the documentation site:
|
|
||||||
https://localhost.run/docs/
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
** your connection id is xxxxxxxxxxxxxxxxxxxxxxxxxxxx, please mention it if you send me a message about an issue. **
|
|
||||||
|
|
||||||
xxxxxxxx.localhost.run tunneled with tls termination, https://xxxxxxxx.localhost.run
|
|
||||||
Connection to localhost.run closed by remote host.
|
|
||||||
Connection to localhost.run closed.
|
|
||||||
```
|
|
||||||
このように表示された場合、`https://xxxxxxxx.localhost.run`が一時的なサーバアドレスとして使用できます。
|
|
||||||
|
|
||||||
### ドメインを設定してアクセスする。
|
|
||||||
|
|
||||||
DNSのAレコードを設定し、お好みの方法でリバースプロキシをホスティングしてください。
|
|
||||||
備考:トップディレクトリにCouchDBを露出させるのはおすすめしません。
|
|
||||||
Caddy等でLet's Encryptの証明書を自動取得すると運用が楽になります。
|
|
||||||
|
|
||||||
CaddyとCouchDBを同時に立てられる[docker-composeの設定とiniファイル](https://github.com/vrtmrz/self-hosted-livesync-server)を公開しています。
|
|
||||||
ぜひご利用下さい。
|
|
||||||
|
|
||||||
なお、サーバのログは必ず確認し、不正なアクセスに注意してください。
|
|
||||||
+22
-5
@@ -4,12 +4,29 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
1. ノートが更新された際、Obsidianがイベントを発報します。Obsidian-LiveSyncはそれをハンドリングして、ローカルのPouchDBに変更を反映します。
|
1. ノートが更新されると、Obsidian からイベントが通知されます。Self-hosted LiveSync はイベントを処理し、ローカルの PouchDB に変更を反映します。
|
||||||
2. PouchDBは、リモートのCouchDBに差分をレプリケーションします。
|
2. PouchDB は差分をリモートの CouchDB に複製します。
|
||||||
3. 他のデバイスは、リモートのCouchDBを監視しているので、変更が検出された場合はそのまま差分がダウンロードされます。
|
3. 他のデバイスはリモートの CouchDB を監視し、変更を検出すると差分をダウンロードします。
|
||||||
4. Self-hosted LiveSyncはPouchDBに転送された変更を、ObsidianのVaultに反映していきます。
|
4. Self-hosted LiveSync は、PouchDB が受信した変更を Obsidian の Vault に反映します。
|
||||||
|
|
||||||
図は2端末での単一方向として描きましたが、実際には双方向に、複数の端末間で実行されます。
|
図では2台のデバイス間の一方向として示していますが、実際には複数のデバイス間で双方向に同期します。
|
||||||
|
|
||||||
|
## ファイルイベントとストレージ書き込み
|
||||||
|
|
||||||
|
ファイルイベントは、Vault 内で検出された変更を表します。Commonlib はこれらのイベントをフィルタリングおよび直列化してから、ローカルデータベース内のファイルメタデータを更新します。したがって、キューに入った `DELETE` はデータベースの変更を要求するものであり、それ自体が物理ファイルを削除する命令ではありません。同期対象外へのファイル名の変更も、宛先ファイルがディスク上に残ったままデータベース上は削除扱いとなる場合があります。
|
||||||
|
|
||||||
|
逆方向の処理はデータベースのメタデータから始まります。レプリケーションされた変更やフルスキャンによってデータベースからストレージへのハンドラが呼び出され、競合およびコンテンツ保護ルールに従って Vault ファイルの書き込みや削除が行われます。古いファイルイベントによるメタデータの削除を防ぐことと、正当なレプリケーションによる削除を適用することは、別の判断基準として扱われます。
|
||||||
|
|
||||||
|
Commonlib の [Storage events and database-to-storage reflection](https://github.com/vrtmrz/livesync-commonlib/blob/main/docs/storage-events-and-reflection.md) には、イベントの境界、Commonlib 0.1.23 で導入された削除の再検証、およびその制限事項が記載されています。特に、削除保護機能は外部フォルダの大文字小文字の変更やパスの表記揺れの完全な収束を保証するものではありません。
|
||||||
|
|
||||||
|
## 現在の技術リファレンス
|
||||||
|
|
||||||
|
- [データベースのデータ構造 (Database Data Structures)](datastructure.md): 現在のメタデータおよびチャンクの形式、識別子の取り扱い、削除、リモート上の生の表現について解説しています。
|
||||||
|
- [Replicator のアーキテクチャ (Replicator architecture)](design_docs/replicator_architecture.md): プロバイダーの構成、アクティブな Replicator の公開、終了、および P2P の所有権について解説しています。
|
||||||
|
- [競合解決とリビジョン履歴 (Conflict resolution and revision provenance)](specs_conflict_resolution.md): 現在のリビジョンツリーおよびファイルの来歴ルールを定義しています。
|
||||||
|
- [チャンクの取得と待機 (Chunk Retrieval and Waiting)](design_docs/chunk_retrieval_and_waiting.md): 不足しているチャンクの到着と、処理が落ち着くまでの待機の扱いを定義しています。
|
||||||
|
- [パスコンポーネント長の互換性 (Path component length compatibility)](design_docs/path_component_length_compatibility.md): 255 UTF-8 バイトがパスの妥当性を判断する普遍的な規則ではなく、Android や Linux における互換性警告である理由を解説しています。
|
||||||
|
- [データ圧縮 (Data Compression)](specs_data_compression.md) および [ガベージコレクション V3 (Garbage Collection V3)](specs_garbage_collection.md): それぞれのストレージとメンテナンスに関する取り決めを説明しています。
|
||||||
|
|
||||||
## 帯域幅低減のために
|
## 帯域幅低減のために
|
||||||
|
|
||||||
|
|||||||
+50
-25
@@ -1,30 +1,29 @@
|
|||||||
# ファストセットアップ (Fast Setup / Simple Fetch)
|
# ファストセットアップ (Fast Setup / Simple Fetch)
|
||||||
|
|
||||||
ファストセットアップは、2台目以降のデバイスのセットアップやデータベース再構築時のデータ取得・初期化処理を、直感的かつ迅速に行うための簡略化された同期フローです。
|
ファストセットアップ(Simple Fetch)は、新規または空の2台目以降のデバイスに初期複製する際の推奨フローです。復旧にも使えますが、取得時の選択によってローカルファイルが置き換わることがあります。すでに作業がある Vault で処理方法を選ぶ前に、価値のあるローカルデータとリモートデータを保全してください。正本を特定する方法は[復旧とフラグファイル](../recovery.md#first-choose-the-authoritative-copy)を参照してください。
|
||||||
|
|
||||||
従来のセットアップウィザードにおける複数の詳細なステップを踏むことなく、同期の基本方針を選択するだけで、データベースのダウンロードとローカルファイルのスキャン・反映を一連のプロセスとして自動的に実行します。
|
従来のセットアップウィザードにおける複数の詳細なステップを踏むことなく、同期の基本方針を選択するだけで、データベースのダウンロードとローカルファイルのスキャン・反映を一連のプロセスとして自動的に実行します。取得経路は、選択したリモートによって異なります。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 仕組み
|
## 仕組み
|
||||||
|
|
||||||
2台目以降のデバイスで **セットアップURI** をインポートした場合や、手動でデータの再フェッチ(Vaultルートに `redflag3.md` / `flag_fetch.md` を配置する等)が予約された場合、プラグインはリモートデータベースからのデータ取得スケジュールを設定します。
|
2台目以降のデバイスで **セットアップ URI** をインポートした場合や、手動でデータの再取得(Vault ルートに `redflag3.md` / `flag_fetch.md` を配置する等)が予約された場合、プラグインはリモートデータベースからのデータ取得スケジュールを設定します。
|
||||||
|
|
||||||
その後の起動時、プラグインはデータフェッチ予約モードで立ち上がり、**「Data retrieval scheduled(データ取得のスケジュール)」** という簡略化されたダイアログを表示します。
|
その後の起動時、プラグインはデータ取得予約モードで立ち上がり、**「Data retrieval scheduled(データ取得のスケジュール)」** という簡略化されたダイアログを表示します。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 技術的な特徴
|
## 技術的な特徴
|
||||||
|
|
||||||
ファストセットアップは、高速かつ安全でクリーンな処理を実現するために、以下の最適化を行っています。
|
ファストセットアップでは、取得と反映に関して次の動作を行います。
|
||||||
|
|
||||||
1. **高速なストリーム受信**
|
1. **CouchDB 向けのストリームベースの Fast Fetch**
|
||||||
- 全データを取得しますが、ストリーム受信によるレプリケーションを使用するため、処理が非常に高速です。
|
- ストリームベースの Fast Fetch は CouchDB 専用です。リモートのメタデータを段階的に取得します。オブジェクトストレージと P2P は、それぞれ独自の取得経路を使用します。
|
||||||
2. **ストレージ反映の遅延による不要な警告の抑制**
|
2. **ストレージ反映の遅延による不要な警告の抑制**
|
||||||
- データのダウンロード中にローカルファイル(ストレージ)への書き出し(反映)処理をあえて遅延させることで、同期途中で発生しがちな「破損データ同期」や「サイズ不一致」などの一時的なエラー警告を抑え込みます。
|
- 取得中にローカルファイルへの反映を遅延させることで、リモートデータの取得中に発生する一時的な同期警告を抑制します。
|
||||||
- すべてのデータダウンロードが完了した後に一括してストレージへ書き出すため、不必要な警告画面でユーザーを混乱させません。
|
3. **更新日時を比較してファイル全体を選択**
|
||||||
3. **時刻ベース比較の妥当性**
|
- **更新日時を比較して新しい方を採用** は更新日時を比較し、ファイル全体として新しい方のバージョンを選択します。ファイルの内容をマージする処理ではありません。作業中の Vault にこの方法を使う前に、価値のあるローカルおよびリモートの編集内容を保全し、[復旧とフラグファイル](../recovery.md#first-choose-the-authoritative-copy)を確認してください。
|
||||||
- 初期セットアップやリカバリーの段階(この状態に移行した直後)においては、概ねファイル更新時刻(タイムスタンプ)ベースでの単純比較を行うことで、十分かつ妥当な同期結果を得ることができます。これにより複雑な競合解決の手間を省きます。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -33,30 +32,31 @@
|
|||||||
### ステップ 1: データの反映方法の選択
|
### ステップ 1: データの反映方法の選択
|
||||||
取得したリモートデータを、既存のローカルファイルとどのように統合するかを選択します。
|
取得したリモートデータを、既存のローカルファイルとどのように統合するかを選択します。
|
||||||
|
|
||||||
1. **Compare time and take newer (newer-wins)**
|
1. **更新日時を比較して新しい方を採用(newer-wins)**
|
||||||
- ファイルの更新日時を比較し、より新しい方を採用します。
|
- ファイルの更新日時を比較し、ファイル全体として新しい方のバージョンを採用します。両方のバージョンの編集内容を統合するものではありません。
|
||||||
- **推奨されるケース:** すでに Self-hosted LiveSync を使用しており、複数のデバイスで編集した変更内容をタイムスタンプに基づいて統合したい場合。
|
- **推奨されるケース:** 両方のバージョンを保全した上で、更新日時に基づいてどちらかを意図的に選択したい場合。
|
||||||
2. **Overwrite all with remote files (remote-wins)**
|
- 作業中の Vault にこの方法を使う前に、価値のあるローカルおよびリモートの編集内容を保全し、[復旧とフラグファイル](../recovery.md#first-choose-the-authoritative-copy)を確認してください。
|
||||||
|
2. **すべてリモートのファイルで上書き(remote-wins)**
|
||||||
- リモートデータベースの内容を正(Source of Truth)として扱います。
|
- リモートデータベースの内容を正(Source of Truth)として扱います。
|
||||||
- **推奨されるケース:** まったく新しいデバイスをセットアップする場合(空のVaultなど)。
|
- **推奨されるケース:** 新しい2台目以降のデバイスを、空の Vault でセットアップする場合。
|
||||||
- *警告: ローカルにあるすべてのファイルがリモートの内容で上書きされます。重要なデータがある場合は、事前にバックアップを取得してください。*
|
- *警告: ローカルにあるすべてのファイルがリモートの内容で上書きされます。重要なデータがある場合は、事前にバックアップを取得してください。*
|
||||||
3. **Use the detailed flow (legacy)**
|
3. **詳細フローを使用(legacy)**
|
||||||
- 従来の詳細なセットアップウィザードダイアログに戻ります。
|
- 従来の詳細なセットアップウィザードダイアログに戻ります。
|
||||||
- **推奨されるケース:** データベースの構成オプションをステップバイステップで細かく制御・確認したい場合。
|
- **推奨されるケース:** データベースの構成オプションをステップバイステップで細かく制御・確認したい場合。
|
||||||
|
|
||||||
### ステップ 2: 競合および削除ルールの構成
|
### ステップ 2: 競合および削除ルールの構成
|
||||||
ステップ 1 での選択内容に応じて、ローカルとリモートの不一致をどう処理するかを設定します。
|
ステップ 1 での選択内容に応じて、ローカルとリモートの不一致をどう処理するかを設定します。
|
||||||
|
|
||||||
#### 「Compare time and take newer」を選択した場合:
|
#### 「更新日時を比較して新しい方を採用」を選択した場合:
|
||||||
- **Delete local files if they were deleted on remote**
|
- **リモートで削除されている場合はローカルファイルを削除**
|
||||||
- 他のデバイスで削除済みのファイルをローカルからも削除し、Vaultを同期・クリーンな状態に保ちます。
|
- 他のデバイスで削除済みのファイルをローカルからも削除し、ローカル Vault を整理して他のデバイスと揃った状態に保ちます。
|
||||||
- **Recreate remote files even if they were deleted on remote**
|
- **リモートで削除されていてもローカルファイルを保持**
|
||||||
- 他のデバイスで削除されたファイルであっても、ローカルファイルを維持し、リモートデータベースに再度アップロードします。
|
- 他のデバイスで削除されたファイルであっても、ローカルファイルを維持し、リモートデータベースに再度アップロードします。
|
||||||
|
|
||||||
#### 「Overwrite all with remote files」を選択した場合:
|
#### 「すべてリモートのファイルで上書き」を選択した場合:
|
||||||
- **Delete local files if not on remote**
|
- **リモートに存在しない場合はローカルファイルを削除**
|
||||||
- リモートに存在しないローカル専用ファイルを削除し、ローカルのVaultをリモートデータベースと完全に一致させます。
|
- リモートに存在しないローカル専用ファイルを削除し、ローカルの Vault をリモートデータベースと完全に一致させます。
|
||||||
- **Keep local files even if not on remote**
|
- **リモートに存在しなくてもローカルファイルを保持**
|
||||||
- リモートに存在しないローカルファイルをそのまま残します。ただし、同期後に重複ファイルが発生する可能性があるため、その場合は手動でクリーンアップを行ってください。
|
- リモートに存在しないローカルファイルをそのまま残します。ただし、同期後に重複ファイルが発生する可能性があるため、その場合は手動でクリーンアップを行ってください。
|
||||||
|
|
||||||
### ステップ 3: 自動同期の実行
|
### ステップ 3: 自動同期の実行
|
||||||
@@ -64,3 +64,28 @@
|
|||||||
1. リモートデータベースの高速ダウンロードを実行します (`fetchLocalDBFast`)。
|
1. リモートデータベースの高速ダウンロードを実行します (`fetchLocalDBFast`)。
|
||||||
2. ローカルファイルへの変更反映のため、フォアグラウンドでフルスキャン (`synchroniseAllFilesBetweenDBandStorage`) を自動的に実行します。
|
2. ローカルファイルへの変更反映のため、フォアグラウンドでフルスキャン (`synchroniseAllFilesBetweenDBandStorage`) を自動的に実行します。
|
||||||
3. 処理が完了すると、プラグインは通常の動作状態へ復帰します。
|
3. 処理が完了すると、プラグインは通常の動作状態へ復帰します。
|
||||||
|
|
||||||
|
### ファストセットアップが中断した場合
|
||||||
|
|
||||||
|
ファストセットアップは、ドキュメントを保存しながら最後に正常に保存されたリモートの位置を記録します。一時的な接続の中断が発生した場合、その位置から自動的に再試行されます。キャプチャされたリモートの状態が正常にすべて保存された後にのみ、完了が報告されます。
|
||||||
|
|
||||||
|
データの復号、リモートレスポンスの読み取り、またはローカルデータベースへの書き込み中のエラーによって処理が停止した場合、LiveSync は Vault スキャンを実行せず、再構築されたローカルデータベースの確定も行いません。保存された位置と取得フラグはそのまま保持されます。保存された有効な選択肢は、再起動時に確認ダイアログで再び利用できます。部分的に再構築されたデータベースが Vault に適用されたり、新しいローカル変更と混ざったりしないよう、ファイル監視とデータベースの反映も一時停止されたままになります。
|
||||||
|
|
||||||
|
**ログを表示** で最初のエラー内容を確認し、原因を修正してから Obsidian を再起動して、保持された状態から再試行してください。処理を続行する意思がある間は、取得フラグを削除したり、手動で Scram スイッチを再開したりしないでください。再起動後も同じエラーが解消しない場合は、LiveSync を一時停止したままデータを保護し、[レポートを収集](../troubleshooting.md#collect-a-report) してください。
|
||||||
|
|
||||||
|
|
||||||
|
## 取得フラグに記憶される選択肢
|
||||||
|
|
||||||
|
ファストセットアップは、選択肢を `flag_fetch.md`(または取得フラグがそれだけの場合は `redflag3.md`)内の `json` コードブロックに保存します。このファイルは通常の Markdown であり、Obsidian 内で開いて編集できます。選択肢が更新されても、状態ブロックの外側にある説明文は保持されます。フラグファイル全体は一時的なものであり、処理が完了またはキャンセルされたときに削除されます。
|
||||||
|
|
||||||
|
中断後に再起動すると、現在のリモートと保存された選択肢が表示されます。それらの選択肢で続行するか、選び直すか、あるいは予約された取得をキャンセルできます。前回の取得が完了したもののフラグを削除できなかった場合も含め、保存された選択肢が確認なしに適用されることはありません。
|
||||||
|
|
||||||
|
新しい参加(Join)を開始するか、別の取得を予約すると、`flag_fetch.md` は空のフラグに置き換えられ、新しい選択肢が求められます。両方のファイル名が存在する場合は、空の場合も含めて `flag_fetch.md` が優先され、完了時に両方のエイリアスが削除されます。
|
||||||
|
|
||||||
|
生成されるブロックには `type: "livesync-fast-setup"`、`version: 1`、および2つの安定した英語の選択値(`stage1` と `stage2`)が含まれます。接続の認証情報は保存されません。既存の選択肢の認識可能な組み合わせのみが受け入れられます。確認を行うと、P2P 接続設定を変更した後であっても、現在選択されているリモートに選択肢が適用されます。
|
||||||
|
|
||||||
|
空のフラグがある場合は、通常の選択ダイアログが起動します。空ではないフラグに対応する有効な選択肢が含まれていない場合、プラグインは新しい選択肢を指定して続行するかどうかを確認します。これには不正な形式の JSON、未対応のバージョン、重複した状態ブロック、不完全な Markdown のコードフェンスなどが含まれます。続行を選択した場合、ファイル内容は変更されず、今回の試行にのみ新しい選択肢が使用されます。再起動すると再度確認が行われます。プラグインが Markdown を修復したり、代替ブロックを追加したりすることはありません。取得を完了またはキャンセルすると、説明文を含めフラグファイル全体が削除されます。
|
||||||
|
|
||||||
|
ストレージの読み取りまたは書き込みに失敗した場合は処理が停止し、空のフラグとしては扱われません。処理の最後にフラグの削除に失敗した場合、その問題が解決するまでファイル監視とデータベースの反映は一時停止されたままになります。フラグが残っている場合、再起動時に再度確認が求められます。
|
||||||
|
|
||||||
|
以前のバージョンでは、選択肢をデバイスのローカルストレージに個別に保存していました。それらの値は完了した取得の後にも残存している可能性があるため、再利用されなくなりました。中断された処理の実行中に更新した場合は、もう一度選択肢を確認してください。この変更自体によってダウンロード済みのデータや Fast Fetch(ファストフェッチ)のチェックポイントが削除されることはありません。
|
||||||
+1
-1
@@ -26,7 +26,7 @@
|
|||||||
"check": "npm run tsc-check && npm run tsc-check:apps && npm run lint && npm run lint:community && npm run lint:community:tools && npm run svelte-check && npm run check:compatibility",
|
"check": "npm run tsc-check && npm run tsc-check:apps && npm run lint && npm run lint:community && npm run lint:community:tools && npm run svelte-check && npm run check:compatibility",
|
||||||
"i18n:bake": "npm run i18n:yaml2json && npm run i18n:bakejson && npm run i18n:format",
|
"i18n:bake": "npm run i18n:yaml2json && npm run i18n:bakejson && npm run i18n:format",
|
||||||
"i18n:bakejson": "tsx _tools/bakei18n.ts",
|
"i18n:bakejson": "tsx _tools/bakei18n.ts",
|
||||||
"i18n:format": "prettier --config .prettierrc.mjs --write --log-level error 'src/common/messagesJson/*.json' 'src/common/messages/*.ts'",
|
"i18n:format": "prettier --config .prettierrc.mjs --write --log-level error \"src/common/messagesJson/*.json\" \"src/common/messages/*.ts\"",
|
||||||
"i18n:json2yaml": "tsx _tools/json2yaml.ts",
|
"i18n:json2yaml": "tsx _tools/json2yaml.ts",
|
||||||
"i18n:yaml2json": "tsx _tools/yaml2json.ts",
|
"i18n:yaml2json": "tsx _tools/yaml2json.ts",
|
||||||
"test:unit": "vitest run --config vitest.config.unit.ts",
|
"test:unit": "vitest run --config vitest.config.unit.ts",
|
||||||
|
|||||||
@@ -3,10 +3,18 @@
|
|||||||
* exercised. These keys remain application-owned and must not be added to
|
* exercised. These keys remain application-owned and must not be added to
|
||||||
* Commonlib merely to make them available to the LiveSync translator.
|
* Commonlib merely to make them available to the LiveSync translator.
|
||||||
*
|
*
|
||||||
* Move a message to the YAML catalogue when it is ready for translation, and
|
* Japanese overrides may live in liveSyncProvisionalJapaneseMessages while a
|
||||||
* remove it from this map in the same change.
|
* key remains provisional. Move a message to the YAML catalogue when its wording
|
||||||
|
* is ready for the full translation workflow, and remove it from both maps in
|
||||||
|
* the same change.
|
||||||
*/
|
*/
|
||||||
export const liveSyncProvisionalEnglishMessages = {
|
export const liveSyncProvisionalEnglishMessages = {
|
||||||
|
"Enable SyncGuard": "Enable SyncGuard",
|
||||||
|
"Enable device-local SyncGuard protection during synchronisation.":
|
||||||
|
"Enable device-local SyncGuard protection during synchronisation.",
|
||||||
|
"SyncGuard minimum files": "SyncGuard minimum files",
|
||||||
|
"Minimum number of Vault files required for SyncGuard protection to apply.":
|
||||||
|
"Minimum number of Vault files required for SyncGuard protection to apply.",
|
||||||
"Skip stopped Journal and resume": "Skip stopped Journal and resume",
|
"Skip stopped Journal and resume": "Skip stopped Journal and resume",
|
||||||
"Object Storage only. Confirm to skip the currently stopped Journal and resume replication. The confirmation names the exact Journal key and failure stage. Skipping may leave content or history missing; the next Journal failure still stops replication.":
|
"Object Storage only. Confirm to skip the currently stopped Journal and resume replication. The confirmation names the exact Journal key and failure stage. Skipping may leave content or history missing; the next Journal failure still stops replication.":
|
||||||
"Object Storage only. Confirm to skip the currently stopped Journal and resume replication. The confirmation names the exact Journal key and failure stage. Skipping may leave content or history missing; the next Journal failure still stops replication.",
|
"Object Storage only. Confirm to skip the currently stopped Journal and resume replication. The confirmation names the exact Journal key and failure stage. Skipping may leave content or history missing; the next Journal failure still stops replication.",
|
||||||
@@ -430,6 +438,451 @@ export const liveSyncProvisionalEnglishMessages = {
|
|||||||
"The fetch flag does not contain one supported selection. Choose new options and continue with the current remote?\n\nCurrent remote: ${REMOTE}\n\nThe flag contents will remain unchanged. The new choices apply only to this attempt; another restart will ask again. Completing or cancelling the fetch removes the flag.":
|
"The fetch flag does not contain one supported selection. Choose new options and continue with the current remote?\n\nCurrent remote: ${REMOTE}\n\nThe flag contents will remain unchanged. The new choices apply only to this attempt; another restart will ask again. Completing or cancelling the fetch removes the flag.":
|
||||||
"The fetch flag does not contain one supported selection. Choose new options and continue with the current remote?\n\nCurrent remote: ${REMOTE}\n\nThe flag contents will remain unchanged. The new choices apply only to this attempt; another restart will ask again. Completing or cancelling the fetch removes the flag.",
|
"The fetch flag does not contain one supported selection. Choose new options and continue with the current remote?\n\nCurrent remote: ${REMOTE}\n\nThe flag contents will remain unchanged. The new choices apply only to this attempt; another restart will ask again. Completing or cancelling the fetch removes the flag.",
|
||||||
"Choose new options and continue": "Choose new options and continue",
|
"Choose new options and continue": "Choose new options and continue",
|
||||||
|
"Batch database updates in LiveSync mode": "Batch database updates in LiveSync mode",
|
||||||
|
"Wait for a bounded local quiet period before processing file updates in LiveSync mode, reducing intermediate database updates while delaying their reflection to remote devices.":
|
||||||
|
"Wait for a bounded local quiet period before processing file updates in LiveSync mode, reducing intermediate database updates while delaying their reflection to remote devices.",
|
||||||
|
Apply: "Apply",
|
||||||
|
Add: "Add",
|
||||||
|
Revert: "Revert",
|
||||||
|
"Vault history": "Vault history",
|
||||||
|
"From:": "From:",
|
||||||
|
"To:": "To:",
|
||||||
|
"Info:": "Info:",
|
||||||
|
"To stop the countdown, tap anywhere on the dialogue": "To stop the countdown, tap anywhere on the dialogue",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type LiveSyncProvisionalMessageKey = keyof typeof liveSyncProvisionalEnglishMessages;
|
export type LiveSyncProvisionalMessageKey = keyof typeof liveSyncProvisionalEnglishMessages;
|
||||||
|
|
||||||
|
/** Japanese translations for provisional LiveSync messages which are already user-facing. */
|
||||||
|
export const liveSyncProvisionalJapaneseMessages: Partial<Record<LiveSyncProvisionalMessageKey, string>> = {
|
||||||
|
"Enable SyncGuard": "SyncGuard を有効化",
|
||||||
|
"Enable device-local SyncGuard protection during synchronisation.":
|
||||||
|
"同期中に、このデバイスで SyncGuard による保護を有効にします。",
|
||||||
|
"SyncGuard minimum files": "SyncGuard を適用する最小ファイル数",
|
||||||
|
"Minimum number of Vault files required for SyncGuard protection to apply.":
|
||||||
|
"SyncGuard による保護を適用するために必要な Vault 内の最小ファイル数です。",
|
||||||
|
"Synchronisation protection": "同期保護",
|
||||||
|
"Synchronising your Vault": "Vault を同期しています",
|
||||||
|
"Receiving changes from the server…": "サーバーから変更を受信しています…",
|
||||||
|
"Applying received changes to local notes…": "受信した変更をローカルノートに適用しています…",
|
||||||
|
"Synchronisation was interrupted. You can continue locally, but some notes may be out of date.":
|
||||||
|
"同期が中断されました。ローカルで作業を続けられますが、一部のノートは最新でない可能性があります。",
|
||||||
|
"At least ${COUNT} changed files received": "変更されたファイルを少なくとも ${COUNT} 件受信しました",
|
||||||
|
"Continue without waiting": "待たずに続行",
|
||||||
|
"Hidden File Sync is disabled on this device. Enable it in Sync Settings before using Automatic or initialising hidden files.":
|
||||||
|
"このデバイスでは非表示ファイル同期が無効です。Automatic を使用する場合や非表示ファイルを初期化する場合は、同期設定で有効にしてください。",
|
||||||
|
"Hidden File Sync initialisation was not started.": "非表示ファイル同期は初期化されませんでした。",
|
||||||
|
"Unknown platform": "不明なプラットフォーム",
|
||||||
|
"This removes only this device's record from the remote.":
|
||||||
|
"リモートから削除されるのは、このデバイスの記録のみです。",
|
||||||
|
"This remote is unlocked. A device that returns can register again.":
|
||||||
|
"このリモートのロックは解除されています。再接続したデバイスは再登録できます。",
|
||||||
|
"This remote is locked. Use the existing recovery process for devices that need to join again.":
|
||||||
|
"このリモートはロックされています。再参加が必要なデバイスには、既存の復旧手順を使用してください。",
|
||||||
|
"This remote is locked. If the device returns, use the existing recovery process to join it again.":
|
||||||
|
"このリモートはロックされています。デバイスが再接続した場合は、既存の復旧手順で再参加させてください。",
|
||||||
|
"This remote does not support conditional updates, so the device record could not be removed.":
|
||||||
|
"このリモートは条件付き更新に対応していないため、デバイスの記録を削除できませんでした。",
|
||||||
|
"This remote does not currently have a record of joined devices.":
|
||||||
|
"このリモートには参加済みデバイスの記録がありません。",
|
||||||
|
"This list shows device information recorded by the remote. It does not show whether a device is online now.":
|
||||||
|
"この一覧にはリモートに記録されたデバイス情報が表示されます。デバイスが現在オンラインかどうかは示しません。",
|
||||||
|
"This device has been locked out. Use the existing recovery process to join again.":
|
||||||
|
"このデバイスは接続を拒否されています。再参加するには、既存の復旧手順を使用してください。",
|
||||||
|
"This device": "このデバイス",
|
||||||
|
"This remote has been cleaned. Use the existing recovery process to join devices again as needed.":
|
||||||
|
"このリモートはクリーンアップされました。必要に応じて、既存の復旧手順でデバイスを再参加させてください。",
|
||||||
|
"The device record was forgotten.": "デバイスの記録を削除しました。",
|
||||||
|
"The device record was already absent.": "デバイスの記録はすでにありません。",
|
||||||
|
"The device list changed while you were trying to forget this device. Refresh the list before trying again.":
|
||||||
|
"このデバイスの記録を削除しようとしている間に一覧が更新されました。もう一度試す前に一覧を再読み込みしてください。",
|
||||||
|
"The device information could not be loaded. Close this dialogue and open Joined devices again if the remote configuration has changed.":
|
||||||
|
"デバイス情報を読み込めませんでした。リモート設定を変更した場合は、このダイアログを閉じて「参加済みデバイス」を開き直してください。",
|
||||||
|
"Review device records for the active CouchDB or Object Storage connection.":
|
||||||
|
"アクティブな CouchDB またはオブジェクトストレージ接続のデバイス記録を確認します。",
|
||||||
|
Refresh: "更新",
|
||||||
|
"Plug-in version": "プラグインのバージョン",
|
||||||
|
Platform: "プラットフォーム",
|
||||||
|
"Older Self-hosted LiveSync versions detected: ${versions}.":
|
||||||
|
"古いバージョンの Self-hosted LiveSync が検出されました: ${versions}。",
|
||||||
|
"Newer Self-hosted LiveSync versions detected: ${versions}.":
|
||||||
|
"新しいバージョンの Self-hosted LiveSync が検出されました: ${versions}。",
|
||||||
|
"Reviewing and aligning Self-hosted LiveSync versions across devices is recommended.":
|
||||||
|
"各デバイスの Self-hosted LiveSync のバージョンを確認し、揃えることをおすすめします。",
|
||||||
|
Open: "開く",
|
||||||
|
"Not recorded": "未記録",
|
||||||
|
"Not accepted": "未承認",
|
||||||
|
"No joined devices are recorded on this remote.": "このリモートには参加済みデバイスが記録されていません。",
|
||||||
|
"Locked out": "接続拒否",
|
||||||
|
"Loading joined devices…": "参加済みデバイスを読み込んでいます…",
|
||||||
|
"Last recorded": "最終記録日時",
|
||||||
|
"Joined devices could not be updated. Refresh the list and try again. If the remote configuration has changed, close this dialogue and open Joined devices again.":
|
||||||
|
"参加済みデバイスを更新できませんでした。一覧を再読み込みしてもう一度お試しください。リモート設定を変更した場合は、このダイアログを閉じて「参加済みデバイス」を開き直してください。",
|
||||||
|
"Joined devices are available after database startup with an active CouchDB or Object Storage connection.":
|
||||||
|
"参加済みデバイスは、データベースの起動後に CouchDB またはオブジェクトストレージへの接続が有効になると表示されます。",
|
||||||
|
"Joined devices": "参加済みデバイス",
|
||||||
|
"Review devices": "デバイスを確認",
|
||||||
|
"Synchronisation between different plug-in versions is generally safe unless the connection is explicitly blocked. However, it may be less efficient or use more storage, and P2P synchronisation may be unavailable.":
|
||||||
|
"プラグインのバージョンが異なるデバイス間でも、接続が明示的にブロックされていなければ、通常は安全に同期できます。ただし、効率が低下したり、使用容量が増えたりする場合があります。また、P2P 同期を利用できないことがあります。",
|
||||||
|
"Forgetting…": "記録を削除しています…",
|
||||||
|
"Forgetting the record does not delete Vault files or revoke credentials.":
|
||||||
|
"記録を削除しても、Vault 内のファイルは削除されず、認証情報も無効になりません。",
|
||||||
|
"Forget this device record?": "このデバイスの記録を削除しますか?",
|
||||||
|
"Forget device": "デバイスの記録を削除",
|
||||||
|
Close: "閉じる",
|
||||||
|
Cancel: "キャンセル",
|
||||||
|
"App version": "アプリのバージョン",
|
||||||
|
Accepted: "承認済み",
|
||||||
|
"Preparing follow-up report…": "追加調査用レポートを準備しています…",
|
||||||
|
"Cancelling local search. Checked ${COUNT} entries.":
|
||||||
|
"ローカル検索をキャンセルしています。${COUNT}件を確認しました。",
|
||||||
|
"Search current Vault paths and current local Metadata only. Older history and remote-only files are not searched.":
|
||||||
|
"現在の Vault パスとローカルのメタデータのみを検索します。古い履歴やリモートにのみ存在するファイルは検索しません。",
|
||||||
|
"The lookup does not read file contents or contact a remote database. Follow-up reports include current conflicts and merge bases.":
|
||||||
|
"検索でファイルの内容を読み取ったり、リモートデータベースに接続したりすることはありません。追加調査用レポートには、現在の競合とマージベースが含まれます。",
|
||||||
|
"Local file diagnostic report": "ローカルファイル診断レポート",
|
||||||
|
"Checked ${COUNT} local entries.": "ローカルの項目を ${COUNT} 件確認しました。",
|
||||||
|
"Enter a valid report path pseudonym.": "有効なレポート用パス仮名を入力してください。",
|
||||||
|
"Search cancelled. Matches found so far are shown.":
|
||||||
|
"検索をキャンセルしました。ここまでに見つかった一致項目を表示します。",
|
||||||
|
"No matches were found in current Vault paths or current local Metadata. Older history and remote-only files are not searched.":
|
||||||
|
"現在の Vault パスとローカルのメタデータに一致する項目はありません。古い履歴やリモートにのみ存在するファイルは検索していません。",
|
||||||
|
"Found ${COUNT} local matches.": "ローカルで ${COUNT} 件見つかりました。",
|
||||||
|
"The local search could not finish.": "ローカル検索を完了できませんでした。",
|
||||||
|
"The file could not be opened.": "ファイルを開けませんでした。",
|
||||||
|
"The follow-up report could not be prepared.": "追加調査用レポートを作成できませんでした。",
|
||||||
|
"Report path pseudonym": "レポート用パス仮名",
|
||||||
|
Source: "ソース",
|
||||||
|
Metadata: "メタデータ",
|
||||||
|
Vault: "Vault",
|
||||||
|
"Metadata document ID": "メタデータドキュメント ID",
|
||||||
|
"No current Metadata document": "現在のメタデータドキュメントなし",
|
||||||
|
"Current Vault file": "現在の Vault ファイル",
|
||||||
|
Present: "あり",
|
||||||
|
Missing: "なし",
|
||||||
|
"Open file": "ファイルを開く",
|
||||||
|
"Prepare follow-up report": "追加調査用レポートを作成",
|
||||||
|
"This report uses pseudonyms. Review its coverage before sharing.":
|
||||||
|
"このレポートでは仮名を使用します。共有する前に、その対象範囲を確認してください。",
|
||||||
|
"Back to matches": "検索結果に戻る",
|
||||||
|
"Reading revisions": "リビジョンを読み込んでいます",
|
||||||
|
"Calculating database usage": "データベース使用量を計算しています",
|
||||||
|
"Discovering revisions": "リビジョンを確認しています",
|
||||||
|
"Find a file from a report pseudonym": "レポート用の仮名からファイルを検索",
|
||||||
|
"Find matching paths in this Vault and local Metadata, then prepare a follow-up report using the same pseudonyms.":
|
||||||
|
"この Vault とローカルのメタデータから一致するパスを検索し、同じ仮名を使って追加調査用レポートを作成します。",
|
||||||
|
"Find file": "ファイルを検索",
|
||||||
|
"⚠️ Initialise or overwrite the remote": "⚠️ リモートを初期化または上書き",
|
||||||
|
"🔗 Join this device": "🔗 このデバイスを参加させる",
|
||||||
|
"⚙️ Apply settings only (advanced)": "⚙️ 設定のみ適用(高度な設定)",
|
||||||
|
"Configure TURN when a direct connection cannot be established or when you select TURN relay only.":
|
||||||
|
"直接接続を確立できない場合、または TURN リレーのみを選択する場合は、TURN を設定してください。",
|
||||||
|
"TURN configuration": "TURN 設定",
|
||||||
|
Manual: "手動",
|
||||||
|
"Managed (Cloudflare)": "マネージド(Cloudflare)",
|
||||||
|
"TURN Key ID": "TURN キー ID",
|
||||||
|
"TURN Key API Token": "TURN キー API トークン",
|
||||||
|
"Unsupported TURN configuration": "未対応の TURN 設定",
|
||||||
|
"The API token is saved with this profile and included in Setup URI and QR code sharing. Temporary TURN credentials are kept in memory only.":
|
||||||
|
"API トークンはこのプロファイルに保存され、セットアップ URI や QR コードでの共有にも含まれます。一時的な TURN 認証情報はメモリー上にのみ保持されます。",
|
||||||
|
"TURN relay only requires a TURN server or a configured credential source under Advanced Settings.":
|
||||||
|
"TURN リレーのみを使うには、TURN サーバーまたは高度な設定で認証情報の取得元を設定してください。",
|
||||||
|
"Enter a TURN Key ID.": "TURN キー ID を入力してください。",
|
||||||
|
"TURN Key ID contains unsupported characters.": "TURN キー ID に未対応の文字が含まれています。",
|
||||||
|
"Enter a TURN Key API Token.": "TURN キー API トークンを入力してください。",
|
||||||
|
"TURN Key API Token must use Bearer token syntax.":
|
||||||
|
"TURN キー API トークンは Bearer トークン形式で入力してください。",
|
||||||
|
"The selected TURN configuration is not supported.": "選択した TURN 設定には対応していません。",
|
||||||
|
"Setup Complete: Preparing to Fetch from Another Device": "セットアップ完了: 別のデバイスから取得する準備中",
|
||||||
|
"The P2P connection has been configured successfully. The initial synchronisation data must now be fetched from an online source device.":
|
||||||
|
"P2P 接続を設定しました。初回の同期を行うため、オンラインのソースデバイスからデータを取得してください。",
|
||||||
|
"After restarting, select an online source device for the initial Fetch. The local LiveSync database on this device will be rebuilt from that source. Unsynchronised files in this Vault may conflict with the fetched data.":
|
||||||
|
"再起動後、初回取得のソースとなるオンラインデバイスを選択してください。このデバイスのローカル LiveSync データベースは、そのソースから再構築されます。この Vault で未同期のファイルは、取得したデータと競合する可能性があります。",
|
||||||
|
"Restart this device, then choose the source device when P2P Rebuild opens.":
|
||||||
|
"このデバイスを再起動してください。P2P 再構築が開いたら、ソースデバイスを選択します。",
|
||||||
|
"Restart and Select Source Device": "再起動してソースデバイスを選択",
|
||||||
|
"P2P Status pane": "P2P ステータスペイン",
|
||||||
|
"No central data-storage server is required, but a signalling relay is required for peer discovery. Both devices must be online at the same time. Vault data travels through the encrypted P2P connection, not through the signalling relay. Some features may be limited.":
|
||||||
|
"中央データストレージサーバーは不要ですが、ピアの検出にはシグナリングリレーが必要です。両方のデバイスが同時にオンラインである必要があります。Vault のデータは暗号化された P2P 接続を通り、シグナリングリレーを経由しません。一部の機能は制限される場合があります。",
|
||||||
|
"P2P requires no central data-storage server, but it still uses a signalling relay for peer discovery.":
|
||||||
|
"P2P には中央データストレージサーバーは不要ですが、ピアの検出にはシグナリングリレーを使用します。",
|
||||||
|
"Signalling relay URLs": "シグナリングリレー URL",
|
||||||
|
"Peer discovery uses Nostr-compatible signalling relays.":
|
||||||
|
"ピアの検出には Nostr 互換のシグナリングリレーを使用します。",
|
||||||
|
"Use the project's public signalling relay": "プロジェクトの公開シグナリングリレーを使用",
|
||||||
|
"The project's public signalling relay is a best-effort convenience operated by the project author. It does not store Vault contents, but signalling metadata may be visible to the relay. Availability and log retention are not guaranteed. You can replace it with your own Nostr-compatible relay.":
|
||||||
|
"プロジェクトの公開シグナリングリレーは、プロジェクト作者が便宜上、可能な範囲で運用しています。Vault の内容は保存されませんが、シグナリングのメタデータはリレーから見える場合があります。稼働状況やログの保存期間は保証されません。独自の Nostr 互換リレーに変更できます。",
|
||||||
|
"Learn more about P2P connections": "P2P 接続について詳しく見る",
|
||||||
|
"Learn more about signalling and TURN": "シグナリングと TURN について詳しく見る",
|
||||||
|
"WebRTC encrypts data between your devices, including when it passes through TURN. The TURN provider cannot read the transferred data. It can see network addresses and traffic volume.":
|
||||||
|
"TURN を経由する場合も含め、WebRTC はデバイス間のデータを暗号化します。TURN プロバイダーは転送データを読み取れませんが、ネットワークアドレスと通信量を確認できます。",
|
||||||
|
"Connection compatibility": "接続互換性",
|
||||||
|
"P2P message size": "P2P メッセージサイズ",
|
||||||
|
Standard: "標準",
|
||||||
|
Reduced: "縮小",
|
||||||
|
Conservative: "保守的",
|
||||||
|
"Maximum compatibility": "互換性を最大化",
|
||||||
|
"Smaller messages can improve compatibility on paths which fragment or drop larger WebRTC messages. This setting limits outgoing P2P messages, so use a compatible profile on each sending device when required.":
|
||||||
|
"メッセージを小さくすると、大きな WebRTC メッセージが分割または破棄される経路で互換性が向上する場合があります。この設定は送信する P2P メッセージのサイズを制限します。必要に応じて、送信側の各デバイスで互換性のあるプロファイルを選択してください。",
|
||||||
|
"Connection path": "接続経路",
|
||||||
|
"TURN relay only": "TURN リレーのみ",
|
||||||
|
"TURN relay only is available when at least one valid TURN server URL is configured under Advanced Settings.":
|
||||||
|
"高度な設定で有効な TURN サーバー URL を1つ以上設定すると、TURN リレーのみを選択できます。",
|
||||||
|
"TURN relay only requires at least one valid TURN server URL. Connection path has been restored to Automatic.":
|
||||||
|
"TURN リレーのみを使うには、有効な TURN サーバー URL が1つ以上必要です。接続経路を自動に戻しました。",
|
||||||
|
"Announce changes": "変更を通知",
|
||||||
|
"Announce changes automatically after connecting": "接続後に変更を自動通知",
|
||||||
|
"When enabled, this device notifies connected peers after a local change. The notification contains no Vault data; a peer which follows this device then fetches the change through the encrypted P2P connection.":
|
||||||
|
"有効にすると、ローカルで変更があったときに接続中のピアへ通知します。通知に Vault のデータは含まれません。このデバイスの変更を受け取る設定のピアは、暗号化された P2P 接続を通じて変更を取得します。",
|
||||||
|
"Stop announcing changes": "変更の通知を停止",
|
||||||
|
"Start announcing changes": "変更の通知を開始",
|
||||||
|
"Follow changes": "変更を受け取る",
|
||||||
|
"Stop following changes from this device": "このデバイスからの変更受信を停止",
|
||||||
|
"Follow changes from this device": "このデバイスからの変更を受信",
|
||||||
|
"Synchronise when this device connects": "このデバイスの接続時に同期",
|
||||||
|
"Follow whenever this device connects": "このデバイスが接続するたびに変更を受信",
|
||||||
|
"Include in the P2P synchronisation command": "P2P 同期コマンドに含める",
|
||||||
|
"More actions for ${DEVICE}": "${DEVICE} のその他の操作",
|
||||||
|
"Use this device's settings": "このデバイスの設定を使用",
|
||||||
|
Retry: "再試行",
|
||||||
|
"No Synchronisation Settings Found": "同期設定が見つかりません",
|
||||||
|
"The selected remote has no saved synchronisation settings. This is normal for a new remote. Use this device's settings, or cancel if you expected existing settings.":
|
||||||
|
"選択したリモートには保存済みの同期設定がありません。新しいリモートでは通常の状態です。このデバイスの設定を使用してください。既存の設定があるはずの場合はキャンセルしてください。",
|
||||||
|
"Could Not Read Synchronisation Settings": "同期設定を読み取れませんでした",
|
||||||
|
"Could not read the remote's synchronisation settings. Check the connection and credentials, then retry.":
|
||||||
|
"リモートの同期設定を読み取れませんでした。接続と認証情報を確認してから、もう一度お試しください。",
|
||||||
|
"Could not read the remote's synchronisation settings. Retry, or continue the overwrite with this device's settings. A working connection is still required.":
|
||||||
|
"リモートの同期設定を読み取れませんでした。再試行するか、このデバイスの設定で上書きを続行してください。続行する場合も、接続が機能している必要があります。",
|
||||||
|
"Skips checking and applying synchronisation settings from the remote.":
|
||||||
|
"リモートの同期設定の確認と適用をスキップします。",
|
||||||
|
"Change CouchDB server setting": "CouchDB サーバー設定を変更",
|
||||||
|
"Change CouchDB server setting '${SETTING}' to '${VALUE}'?":
|
||||||
|
"CouchDB サーバー設定「${SETTING}」を「${VALUE}」に変更しますか?",
|
||||||
|
"TURN relay only requires TURN configuration. Connection path has been restored to Automatic.":
|
||||||
|
"TURN リレーのみを使うには TURN の設定が必要です。接続経路を自動に戻しました。",
|
||||||
|
"This file has unresolved conflicts.": "このファイルには未解決の競合があります。",
|
||||||
|
"This file has ${COUNT} unresolved versions. They will be reviewed one pair at a time.":
|
||||||
|
"このファイルには未解決の版が ${COUNT} 件あります。1組ずつ確認します。",
|
||||||
|
"Sync now": "今すぐ同期",
|
||||||
|
"Apply pending changes now": "保留中の変更を今すぐ適用",
|
||||||
|
"Copy database information for the active file": "アクティブなファイルのデータベース情報をコピー",
|
||||||
|
"Copy database information for a file": "ファイルのデータベース情報をコピー",
|
||||||
|
"Copy revision, conflict, and local chunk availability information, including document and chunk identifiers but not file contents.":
|
||||||
|
"ファイルの内容を含めずに、ドキュメント ID やチャンク ID などのリビジョン、競合、ローカルのチャンク有無に関する情報をコピーします。",
|
||||||
|
"Choose file": "ファイルを選択",
|
||||||
|
"Choose a file to inspect": "確認するファイルを選択",
|
||||||
|
"Database information for ${FILE}": "${FILE} のデータベース情報",
|
||||||
|
"All revisions and chunk availability below are a snapshot of this device's local database; the remote is not queried. Review the Vault-relative path, document identifier, content-derived chunk identifiers, and metadata before sharing this report. File contents are omitted.":
|
||||||
|
"以下のリビジョンとチャンク有無は、このデバイスのローカルデータベースのスナップショットです。リモートには問い合わせません。このレポートを共有する前に、Vault からの相対パス、ドキュメント ID、コンテンツ由来のチャンク ID、メタデータを確認してください。ファイルの内容は含まれません。",
|
||||||
|
"📁 Vault: ${SIZE} B · ${TIME}": "📁 Vault: ${SIZE} B · ${TIME}",
|
||||||
|
"📁 Vault: missing": "📁 Vault: ファイルなし",
|
||||||
|
"🗄️ Local DB: missing": "🗄️ ローカル DB: データなし",
|
||||||
|
"Vault and database revision": "Vault とデータベースのリビジョン",
|
||||||
|
"Vault file": "Vault ファイル",
|
||||||
|
"Database revision": "データベースのリビジョン",
|
||||||
|
"Vault file is newer": "Vault ファイルの方が新しい",
|
||||||
|
"Database revision is newer": "データベースのリビジョンの方が新しい",
|
||||||
|
"Within the two-second comparison window": "2秒以内の誤差範囲内",
|
||||||
|
"Timestamp comparison unavailable": "タイムスタンプを比較できません",
|
||||||
|
"${ROLE}: ${REVISION}": "${ROLE}: ${REVISION}",
|
||||||
|
"Winner revision": "代表リビジョン",
|
||||||
|
"Conflict revision": "競合リビジョン",
|
||||||
|
"Unknown revision": "不明なリビジョン",
|
||||||
|
"🗑️ Logical deletion": "🗑️ 論理削除",
|
||||||
|
"Readable on this device; recorded size ${RECORDED}, decoded size ${ACTUAL}":
|
||||||
|
"このデバイスで読み取り可能。記録サイズ ${RECORDED}、デコード後サイズ ${ACTUAL}",
|
||||||
|
"🧩 Missing chunks: ${COUNT}": "🧩 チャンク不足: ${COUNT} 件",
|
||||||
|
"📦 DB: recorded ${RECORDED} B · decoded ${DECODED} B · Δsize ${DIFFERENCE} B":
|
||||||
|
"📦 DB: 記録 ${RECORDED} B · デコード後 ${DECODED} B · サイズ差 ${DIFFERENCE} B",
|
||||||
|
"📦 DB: recorded ${RECORDED} B · decoded unavailable": "📦 DB: 記録 ${RECORDED} B · デコード後サイズは不明",
|
||||||
|
"📁 Vault: ${VAULT} B · Δsize vs DB ${DIFFERENCE} B": "📁 Vault: ${VAULT} B · DB とのサイズ差 ${DIFFERENCE} B",
|
||||||
|
"🕒 DB ${DATABASE_TIME} · Vault ${VAULT_TIME} · Δtime ${DIFFERENCE} ms (${RELATION})":
|
||||||
|
"🕒 DB ${DATABASE_TIME} · Vault ${VAULT_TIME} · 時刻差 ${DIFFERENCE} ms(${RELATION})",
|
||||||
|
"✅ Matches Vault": "✅ Vault と一致",
|
||||||
|
"⚠️ Differs from Vault": "⚠️ Vault と不一致",
|
||||||
|
"✅ Vault matches winner": "✅ Vault は代表リビジョンと一致",
|
||||||
|
"⚠️ Conflicts: ${COUNT}": "⚠️ 競合: ${COUNT} 件",
|
||||||
|
"Compare with Vault": "Vault と比較",
|
||||||
|
"Apply this revision to Vault": "このリビジョンを Vault に適用",
|
||||||
|
"Apply database revision ${REVISION} to ${FILE}? The current Vault file will be overwritten.":
|
||||||
|
"データベースのリビジョン ${REVISION} を ${FILE} に適用しますか?現在の Vault ファイルは上書きされます。",
|
||||||
|
"Apply database revision to Vault": "データベースのリビジョンを Vault に適用",
|
||||||
|
"Mark this revision as the Vault version": "このリビジョンを Vault の版として指定",
|
||||||
|
"Store Vault file as a child of this revision": "Vault ファイルをこのリビジョンの子として保存",
|
||||||
|
"Apply logical deletion to Vault": "論理削除を Vault に適用",
|
||||||
|
"Apply logical deletion ${REVISION} to ${FILE}? The current Vault file will be removed.":
|
||||||
|
"論理削除 ${REVISION} を ${FILE} に適用しますか?現在の Vault ファイルは削除されます。",
|
||||||
|
"Retry reading revision": "リビジョンの読み込みを再試行",
|
||||||
|
"Discard this branch": "このブランチを破棄",
|
||||||
|
"Discard branch": "ブランチを破棄",
|
||||||
|
"Discard database branch ${REVISION} of ${FILE}? This creates a logical deletion for that exact live branch. The current Vault file will not be changed.":
|
||||||
|
"${FILE} のデータベースブランチ ${REVISION} を破棄しますか?この操作は該当する現行ブランチに論理削除を記録します。現在の Vault ファイルは変更されません。",
|
||||||
|
"Discard unreadable revision": "読み取れないリビジョンを破棄",
|
||||||
|
"Discard database revision ${REVISION} of ${FILE}? This creates a logical deletion for that exact live revision. Missing content cannot be recovered by this action.":
|
||||||
|
"${FILE} のデータベースリビジョン ${REVISION} を破棄しますか?この操作は該当する現行リビジョンに論理削除を記録します。不足している内容はこの操作では復元できません。",
|
||||||
|
"Revision metadata is unavailable on this device": "このデバイスではリビジョンのメタデータを利用できません",
|
||||||
|
"Shared ancestor ${REVISION} is not readable on this device. Automatic three-way merging may be unavailable, but the live revisions remain available for explicit review.":
|
||||||
|
"共有祖先 ${REVISION} はこのデバイスで読み取れません。自動3方向マージを利用できない場合がありますが、現行リビジョンは引き続き個別に確認できます。",
|
||||||
|
"No shared ancestor is available for this conflict. The live revisions remain available for explicit review.":
|
||||||
|
"この競合には共有祖先がありません。現行リビジョンは引き続き個別に確認できます。",
|
||||||
|
"More actions for revision ${REVISION}": "リビジョン ${REVISION} のその他の操作",
|
||||||
|
"More actions for ${FILE}": "${FILE} のその他の操作",
|
||||||
|
"Show revision history": "リビジョン履歴を表示",
|
||||||
|
"Store Vault file as a new local database document":
|
||||||
|
"Vault ファイルを新しいローカルデータベースドキュメントとして保存",
|
||||||
|
"Copy database information": "データベース情報をコピー",
|
||||||
|
"Recreate chunks for current Vault files": "現在の Vault ファイルのチャンクを再作成",
|
||||||
|
"Recreate chunks from the files currently present in this Vault. This cannot reconstruct unavailable historical or conflict content.":
|
||||||
|
"この Vault に現在あるファイルからチャンクを再作成します。利用できない過去の内容や競合内容は復元できません。",
|
||||||
|
"Recreate current chunks": "現在のチャンクを再作成",
|
||||||
|
"Resolve every conflict by modification time? This logically deletes every version except the newest one and cannot recover content which is already unavailable.":
|
||||||
|
"すべての競合を更新日時で解決しますか?最も新しい版以外はすべて論理削除され、すでに利用できない内容は復元できません。",
|
||||||
|
"Resolve all conflicts by the newest version": "すべての競合を最も新しい版で解決",
|
||||||
|
"Inspect conflicts and file/database differences": "競合とファイル/データベース間の差異を調査",
|
||||||
|
"Scan Vault files and local-database Metadata for conflicts, missing chunks, identity mismatches, and differences. Each result provides actions for one exact entry or revision.":
|
||||||
|
"Vault ファイルとローカルデータベースのメタデータをスキャンし、競合、チャンク不足、識別情報の不一致、差異を確認します。各結果から、該当する項目またはリビジョンに対する操作を選択できます。",
|
||||||
|
"Begin inspection": "調査を開始",
|
||||||
|
"Metadata entry requires review and was left unchanged": "確認が必要なメタデータ項目は変更せずに残しました",
|
||||||
|
"The stored document ID does not match the ID derived from its recorded path.":
|
||||||
|
"保存されたドキュメント ID が、記録されたパスから導出される ID と一致しません。",
|
||||||
|
"The stored document ID and recorded path are handled by different synchronisation features.":
|
||||||
|
"保存されたドキュメント ID と記録されたパスは、それぞれ異なる同期機能によって処理されます。",
|
||||||
|
"Stored document ID: ${ID}": "保存されたドキュメント ID: ${ID}",
|
||||||
|
"Expected document ID: ${ID}": "期待されるドキュメント ID: ${ID}",
|
||||||
|
"Source revision: ${REVISION}": "ソースリビジョン: ${REVISION}",
|
||||||
|
"One-step repair is unavailable because this entry is ambiguous, no longer current, or unsafe to change.":
|
||||||
|
"この項目は情報があいまいであるか、最新ではないか、または変更が安全ではないため、ワンステップ修復は利用できません。",
|
||||||
|
"An exact target is already present; repair can remove the obsolete ID.":
|
||||||
|
"同一の対象がすでに存在するため、修復時に古い ID を削除できます。",
|
||||||
|
"Repair is available for this entry.": "この項目は修復できます。",
|
||||||
|
"Repair this Metadata document ID": "このメタデータドキュメント ID を修復",
|
||||||
|
"Repair Metadata ID": "メタデータ ID を修復",
|
||||||
|
"Keep unchanged": "変更せずに保持",
|
||||||
|
"This moves one local Metadata entry to the ID derived from its recorded path.\n\n**File:** `${FILE}` \n**Source:** `${SOURCE}@${REVISION}` \n**Target:** `${TARGET}`\n\nThe target is verified before the source is removed. Its CouchDB revision ancestry cannot be preserved.\n\n> [!warning] Before repairing\n> - Back up this device.\n> - If file-name case or path obfuscation was intentionally changed for the whole database, use Rebuild instead.\n> - If other devices share this database, pause them, allow this device to upload the repair, then resume them one at a time.":
|
||||||
|
"ローカルのメタデータ項目を、記録されたパスから導出される ID に移動します。\n\n**ファイル:** `${FILE}` \n**移動元:** `${SOURCE}@${REVISION}` \n**移動先:** `${TARGET}`\n\n移動元を削除する前に、移動先を検証します。CouchDB のリビジョン祖先は保持できません。\n\n> [!warning] 修復する前に\n> - このデバイスをバックアップしてください。\n> - データベース全体のファイル名の大文字・小文字の扱いやパス難読化を意図的に変更した場合は、代わりに再構築してください。\n> - 他のデバイスがこのデータベースを共有している場合は、それらを一時停止し、このデバイスから修復内容がアップロードされた後、1台ずつ再開してください。",
|
||||||
|
"Metadata document ID repair and the ordinary Vault scan completed. Run this inspection again after synchronisation.":
|
||||||
|
"メタデータドキュメント ID の修復と通常の Vault スキャンが完了しました。同期後にこの調査を再実行してください。",
|
||||||
|
"Metadata document ID repair completed, but the ordinary Vault scan did not run. Keep synchronisation paused, resolve the scan condition, then run 'Scan storage and database again'.":
|
||||||
|
"メタデータドキュメント ID の修復は完了しましたが、通常の Vault スキャンは実行されませんでした。同期を一時停止したままスキャンを妨げている状態を解消し、「ストレージとデータベースを再スキャン」を実行してください。",
|
||||||
|
"The inspected state changed. No repair was performed; run inspection again.":
|
||||||
|
"調査対象の状態が変化しました。修復は行われていません。調査を再実行してください。",
|
||||||
|
"Repair stopped after creating the target. The source was retained. Run inspection again before retrying.":
|
||||||
|
"移動先を作成した後、修復を停止しました。移動元は保持されています。再試行する前に調査を実行してください。",
|
||||||
|
"Repair failed before the source was removed. Run inspection again before retrying.":
|
||||||
|
"移動元を削除する前に修復が失敗しました。再試行する前に調査を実行してください。",
|
||||||
|
"(RegExp) Limit normal files to matching paths. Leave empty to allow all normal file paths. Hidden File Sync uses its own target patterns.":
|
||||||
|
"(正規表現)通常ファイルを一致するパスに限定します。空欄にすると、すべての通常ファイルパスが対象になります。非表示ファイル同期には専用の対象パターンを使用します。",
|
||||||
|
"(RegExp) Skip changes to matching normal and hidden files, locally and remotely.":
|
||||||
|
"(正規表現)一致する通常ファイルと非表示ファイルの変更を、ローカルとリモートの両方でスキップします。",
|
||||||
|
"Repair Metadata document ID": "メタデータドキュメント ID を修復",
|
||||||
|
"Connection settings": "接続設定",
|
||||||
|
"Saved connections": "保存済みの接続",
|
||||||
|
"ID generation": "ID の生成",
|
||||||
|
"Keep current configuration": "現在の設定を維持",
|
||||||
|
"Set an ID key": "ID キーを設定",
|
||||||
|
"Current configuration: a saved ID key is used.": "現在の設定: 保存済みの ID キーを使用します。",
|
||||||
|
"Current configuration: the saved ID key is retained while E2EE is off.":
|
||||||
|
"現在の設定: E2EE が無効な間も保存済みの ID キーを保持します。",
|
||||||
|
"Current configuration: no ID key is saved. With E2EE enabled, keeping it uses legacy IDs tied to the E2EE passphrase.":
|
||||||
|
"現在の設定: ID キーは保存されていません。E2EE が有効な場合、現在の設定を維持すると E2EE パスフレーズに紐づく旧形式の ID を使用します。",
|
||||||
|
"Changing the E2EE passphrase changes IDs generated by the legacy configuration.":
|
||||||
|
"旧形式の設定では、E2EE パスフレーズを変更すると生成される ID も変わります。",
|
||||||
|
"This uses a saved key for new Chunk IDs and obfuscated Metadata document IDs, so changing the E2EE passphrase does not derive a new key automatically.":
|
||||||
|
"新しいチャンク ID と難読化されたメタデータドキュメント ID に保存済みのキーを使います。そのため、E2EE パスフレーズを変更しても新しいキーは自動導出されません。",
|
||||||
|
Configured: "設定済み",
|
||||||
|
"The saved ID key is configured. Its source cannot be shown again.":
|
||||||
|
"保存済みの ID キーが設定されています。キーの導出元を再表示することはできません。",
|
||||||
|
"Leave this input empty to keep the saved ID key.":
|
||||||
|
"保存済みの ID キーを維持するには、この欄を空のままにしてください。",
|
||||||
|
"Generate a random ID key": "ランダムな ID キーを生成",
|
||||||
|
"How to set the ID key": "ID キーの設定方法",
|
||||||
|
"Derive from current E2EE passphrase": "現在の E2EE パスフレーズから導出",
|
||||||
|
"Enter an ID source": "ID の導出元を入力",
|
||||||
|
"Import an ID recovery code": "ID 復旧コードをインポート",
|
||||||
|
"ID source": "ID の導出元",
|
||||||
|
"ID recovery code": "ID 復旧コード",
|
||||||
|
"Enter an ID recovery code": "ID 復旧コードを入力",
|
||||||
|
"Choose a long, unpredictable source. It is used once and cannot be shown again after saving. A recovery code can be displayed on this device later. This input also accepts a tagged recovery code.":
|
||||||
|
"長く推測されにくい導出元を指定してください。導出元は一度だけ使用され、保存後は再表示できません。復旧コードは後からこのデバイスで表示できます。この入力欄にはタグ付き復旧コードも指定できます。",
|
||||||
|
"Paste a tagged recovery code from an existing device to restore the same ID key.":
|
||||||
|
"既存のデバイスからタグ付き復旧コードを貼り付けると、同じ ID キーを復元できます。",
|
||||||
|
"For recovery after losing every device, save the recovery code after setup or choose an ID source you can reproduce.":
|
||||||
|
"すべてのデバイスを失った場合に備え、セットアップ後に復旧コードを保存するか、再現可能な ID の導出元を選んでください。",
|
||||||
|
"Show current recovery code": "現在の復旧コードを表示",
|
||||||
|
"Hide current recovery code": "現在の復旧コードを隠す",
|
||||||
|
"Current ID recovery code": "現在の ID 復旧コード",
|
||||||
|
"Copy recovery code": "復旧コードをコピー",
|
||||||
|
"Recovery code copied.": "復旧コードをコピーしました。",
|
||||||
|
"The displayed recovery code belongs to the current key. Reopen this dialogue after saving to copy the replacement key.":
|
||||||
|
"表示中の復旧コードは現在のキーに対応しています。キーを置き換えた場合は、保存後にこのダイアログを開き直して新しい復旧コードをコピーしてください。",
|
||||||
|
"The recovery code could not be copied. Select and copy the visible code instead.":
|
||||||
|
"復旧コードをコピーできませんでした。表示されているコードを選択してコピーしてください。",
|
||||||
|
"The ID key is derived from the current E2EE passphrase and saved separately. Changing that passphrase later does not change the saved ID key. To reduce the risk of guessing that passphrase from known IDs, use a separate, unpredictable ID source instead.":
|
||||||
|
"ID キーは現在の E2EE パスフレーズから導出され、別に保存されます。後からパスフレーズを変更しても、保存済みの ID キーは変わりません。既知の ID からパスフレーズを推測されるリスクを下げるには、別の推測されにくい ID の導出元を使用してください。",
|
||||||
|
"An ID source is required to enable this option.": "このオプションを有効にするには、ID の導出元が必要です。",
|
||||||
|
"The ID source or recovery code is invalid. Check it and try again.":
|
||||||
|
"ID の導出元または復旧コードが無効です。確認してもう一度お試しください。",
|
||||||
|
"Read normal-file Metadata and current conflicts locally and in CouchDB, then compare content for suspect groups. Choose original names or pseudonyms before starting.":
|
||||||
|
"ローカルと CouchDB の通常ファイルのメタデータおよび現在の競合を読み取り、問題が疑われる項目の内容を比較します。開始前に、元の名前を使うか仮名を使うか選択してください。",
|
||||||
|
Inspect: "調査",
|
||||||
|
"Inspect database integrity": "データベースの整合性を調査",
|
||||||
|
"Inspection completed. Review the findings and coverage before sharing.":
|
||||||
|
"調査が完了しました。共有する前に結果と調査範囲を確認してください。",
|
||||||
|
"Inspection partially completed. Some information could not be checked; review the reported reasons.":
|
||||||
|
"調査は一部のみ完了しました。確認できなかった情報があります。表示された理由を確認してください。",
|
||||||
|
"Inspection failed. The report records the available evidence and reasons.":
|
||||||
|
"調査に失敗しました。レポートには、取得できた証拠と失敗理由が記録されています。",
|
||||||
|
"Inspection cancelled. The report contains only the evidence collected so far.":
|
||||||
|
"調査をキャンセルしました。レポートには、ここまでに収集した証拠のみが含まれます。",
|
||||||
|
"Report copied.": "レポートをコピーしました。",
|
||||||
|
"Copy failed. Select the report text and copy it manually.":
|
||||||
|
"コピーに失敗しました。レポートのテキストを選択して手動でコピーしてください。",
|
||||||
|
"Download requested. You can also copy the report if downloads are unavailable on this device.":
|
||||||
|
"ダウンロードを要求しました。このデバイスでダウンロードできない場合は、レポートをコピーすることもできます。",
|
||||||
|
"Pseudonyms include a public salt, so guessed paths can be checked. Original names include private filenames. Reports omit file contents and credentials.":
|
||||||
|
"仮名には公開ソルトが含まれるため、推測したパスと照合できます。元の名前を選ぶと、非公開のファイル名が含まれます。どちらのレポートにもファイルの内容や認証情報は含まれません。",
|
||||||
|
"Read available local revisions and report their Chunk references. Settings are left unchanged.":
|
||||||
|
"利用可能なローカルリビジョンを読み取り、参照するチャンクをレポートします。設定は変更されません。",
|
||||||
|
"Inspect normal-file Metadata, current conflicts, and suspect content against the Vault. Remote inspection supports CouchDB. Older history is excluded; findings do not authorise deletion.":
|
||||||
|
"通常ファイルのメタデータ、現在の競合、問題が疑われる内容を Vault と照合します。リモートの調査は CouchDB に対応しています。古い履歴は対象外です。調査結果を根拠に削除が実行されることはありません。",
|
||||||
|
"Include remote database": "リモートデータベースを含める",
|
||||||
|
"Names in this report": "レポート内の名前",
|
||||||
|
"Pseudonyms (recommended)": "仮名(推奨)",
|
||||||
|
"Original names": "元の名前",
|
||||||
|
"Cancelling inspection…": "調査をキャンセルしています…",
|
||||||
|
"Items inspected": "調査した項目数",
|
||||||
|
"Cancel inspection": "調査をキャンセル",
|
||||||
|
"This report uses temporary pseudonyms. Counts and relationships remain visible.":
|
||||||
|
"このレポートでは一時的な仮名を使用します。件数や項目間の関係は表示されます。",
|
||||||
|
"This report contains original paths and identifiers. Review them before sharing.":
|
||||||
|
"このレポートには元のパスと識別子が含まれます。共有する前に内容を確認してください。",
|
||||||
|
"Partial Usage results are available as JSON so their coverage and reasons stay with the rows.":
|
||||||
|
"一部のみ取得できた使用状況の結果は JSON で出力できます。各行に調査範囲と理由が保持されます。",
|
||||||
|
"Report format": "レポート形式",
|
||||||
|
"Diagnostic report": "診断レポート",
|
||||||
|
"Copy report": "レポートをコピー",
|
||||||
|
"Save report": "レポートを保存",
|
||||||
|
"The inspection could not finish. Close this dialogue and try again after database startup.":
|
||||||
|
"調査を完了できませんでした。このダイアログを閉じ、データベースの起動後にもう一度お試しください。",
|
||||||
|
"Resume scheduled fetch?": "予約済みの取得を再開しますか?",
|
||||||
|
"Apply these saved choices to the current remote?\n\nCurrent remote: ${REMOTE}\n\n- ${STAGE1}\n- ${STAGE2}\n\nThe fetch flag may remain after an interruption or an incomplete cleanup. Continue only if this fetch is still intended.":
|
||||||
|
"保存済みの選択肢を現在のリモートに適用しますか?\n\n現在のリモート: ${REMOTE}\n\n- ${STAGE1}\n- ${STAGE2}\n\n中断や不完全なクリーンアップの後に取得フラグが残っている可能性があります。この取得を実行する意図がある場合にのみ続行してください。",
|
||||||
|
"Continue with these choices": "この選択肢で続行",
|
||||||
|
"Choose again": "選び直す",
|
||||||
|
"Saved fetch choices could not be read": "保存済みの取得設定を読み取れませんでした",
|
||||||
|
"The fetch flag does not contain one supported selection. Choose new options and continue with the current remote?\n\nCurrent remote: ${REMOTE}\n\nThe flag contents will remain unchanged. The new choices apply only to this attempt; another restart will ask again. Completing or cancelling the fetch removes the flag.":
|
||||||
|
"取得フラグに有効な選択肢が含まれていません。新しい選択肢を指定して、現在のリモートで続行しますか?\n\n現在のリモート: ${REMOTE}\n\nフラグの内容は変更されません。新しい選択肢は今回の試行にのみ適用され、再起動すると再度確認されます。取得を完了またはキャンセルすると、フラグは削除されます。",
|
||||||
|
"Choose new options and continue": "新しい選択肢を指定して続行",
|
||||||
|
"Batch database updates in LiveSync mode": "LiveSync モードでデータベース更新をバッチ処理",
|
||||||
|
"Wait for a bounded local quiet period before processing file updates in LiveSync mode, reducing intermediate database updates while delaying their reflection to remote devices.":
|
||||||
|
"LiveSync モードでは、ローカルでの更新が一定時間落ち着くまで待ってからファイル更新を処理します。これにより中間のデータベース更新を減らし、リモートデバイスへの反映を遅らせます。",
|
||||||
|
Apply: "適用",
|
||||||
|
Add: "追加",
|
||||||
|
Revert: "元に戻す",
|
||||||
|
"Vault history": "Vault 履歴",
|
||||||
|
"From:": "開始:",
|
||||||
|
"To:": "終了:",
|
||||||
|
"Info:": "情報:",
|
||||||
|
"To stop the countdown, tap anywhere on the dialogue":
|
||||||
|
"カウントダウンを停止するには、ダイアログの任意の場所をタップしてください",
|
||||||
|
};
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -521,7 +521,7 @@
|
|||||||
"moduleCheckRemoteSize.option800MB": "800MB (Cloudant, fly.io)",
|
"moduleCheckRemoteSize.option800MB": "800MB (Cloudant, fly.io)",
|
||||||
"moduleCheckRemoteSize.optionAskMeLater": "Ask me later",
|
"moduleCheckRemoteSize.optionAskMeLater": "Ask me later",
|
||||||
"moduleCheckRemoteSize.optionDismiss": "Dismiss",
|
"moduleCheckRemoteSize.optionDismiss": "Dismiss",
|
||||||
"moduleCheckRemoteSize.optionIncreaseLimit": "increase to ${newMax}MB",
|
"moduleCheckRemoteSize.optionIncreaseLimit": "Increase to ${newMax} MB",
|
||||||
"moduleCheckRemoteSize.optionNoWarn": "No, never warn please",
|
"moduleCheckRemoteSize.optionNoWarn": "No, never warn please",
|
||||||
"moduleCheckRemoteSize.optionRebuildAll": "Rebuild Everything Now",
|
"moduleCheckRemoteSize.optionRebuildAll": "Rebuild Everything Now",
|
||||||
"moduleCheckRemoteSize.optionReview": "Review options",
|
"moduleCheckRemoteSize.optionReview": "Review options",
|
||||||
|
|||||||
+999
-228
File diff suppressed because it is too large.
Load diff
@@ -679,7 +679,7 @@ moduleCheckRemoteSize:
|
|||||||
option800MB: 800MB (Cloudant, fly.io)
|
option800MB: 800MB (Cloudant, fly.io)
|
||||||
optionAskMeLater: Ask me later
|
optionAskMeLater: Ask me later
|
||||||
optionDismiss: Dismiss
|
optionDismiss: Dismiss
|
||||||
optionIncreaseLimit: increase to ${newMax}MB
|
optionIncreaseLimit: Increase to ${newMax} MB
|
||||||
optionNoWarn: No, never warn please
|
optionNoWarn: No, never warn please
|
||||||
optionReview: Review options
|
optionReview: Review options
|
||||||
optionRebuildAll: Rebuild Everything Now
|
optionRebuildAll: Rebuild Everything Now
|
||||||
|
|||||||
+1288
-393
File diff suppressed because it is too large.
Load diff
@@ -12,6 +12,7 @@ import type { AllMessageKeys, I18N_LANGS, LiveSyncCatalogueMessageKey } from "./
|
|||||||
import { allMessages } from "./messages/combinedMessages.prod.ts";
|
import { allMessages } from "./messages/combinedMessages.prod.ts";
|
||||||
import {
|
import {
|
||||||
liveSyncProvisionalEnglishMessages,
|
liveSyncProvisionalEnglishMessages,
|
||||||
|
liveSyncProvisionalJapaneseMessages,
|
||||||
type LiveSyncProvisionalMessageKey,
|
type LiveSyncProvisionalMessageKey,
|
||||||
} from "./messages/LiveSyncProvisionalMessages.ts";
|
} from "./messages/LiveSyncProvisionalMessages.ts";
|
||||||
|
|
||||||
@@ -72,7 +73,11 @@ function _getMessage(key: string, lang: I18N_LANGS) {
|
|||||||
allMessages[key] ?? (provisionalEnglish === undefined ? undefined : ({ def: provisionalEnglish } as const));
|
allMessages[key] ?? (provisionalEnglish === undefined ? undefined : ({ def: provisionalEnglish } as const));
|
||||||
if (msgs === undefined && isCommonlibMessageKey(key)) return englishMessageTranslator(key);
|
if (msgs === undefined && isCommonlibMessageKey(key)) return englishMessageTranslator(key);
|
||||||
const resolvedLang = resolveLanguage(lang);
|
const resolvedLang = resolveLanguage(lang);
|
||||||
let msg = msgs?.[resolvedLang];
|
let msg =
|
||||||
|
msgs?.[resolvedLang] ??
|
||||||
|
(resolvedLang === "ja"
|
||||||
|
? liveSyncProvisionalJapaneseMessages[key as LiveSyncProvisionalMessageKey]
|
||||||
|
: undefined);
|
||||||
|
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
if (missingTranslations.indexOf(key) === -1) {
|
if (missingTranslations.indexOf(key) === -1) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ describe("LiveSync-owned translation catalogue", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("retains typed placeholder substitution", () => {
|
it("retains typed placeholder substitution", () => {
|
||||||
expect($msg("moduleCheckRemoteSize.optionIncreaseLimit", { newMax: "800" }, "def")).toBe("increase to 800MB");
|
expect($msg("moduleCheckRemoteSize.optionIncreaseLimit", { newMax: "800" }, "def")).toBe("Increase to 800 MB");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps the active-file path compatibility warning concise", () => {
|
it("keeps the active-file path compatibility warning concise", () => {
|
||||||
|
|||||||
@@ -189,9 +189,9 @@
|
|||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
{#if hideLocal}
|
{#if hideLocal}
|
||||||
<button onclick={cancel}>Cancel</button>
|
<button onclick={cancel}>{translateMessage("Cancel")}</button>
|
||||||
{/if}
|
{/if}
|
||||||
<button onclick={apply}>Apply</button>
|
<button onclick={apply}>{translateMessage("Apply")}</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ButtonComponent } from "@/deps.ts";
|
|||||||
import { App, FuzzySuggestModal, MarkdownRenderer, Modal, Plugin, Setting, Component } from "@/deps.ts";
|
import { App, FuzzySuggestModal, MarkdownRenderer, Modal, Plugin, Setting, Component } from "@/deps.ts";
|
||||||
import { EVENT_PLUGIN_UNLOADED, eventHub } from "@/common/events.ts";
|
import { EVENT_PLUGIN_UNLOADED, eventHub } from "@/common/events.ts";
|
||||||
import { compatGlobal, type CompatIntervalHandle } from "@vrtmrz/livesync-commonlib/compat/common/coreEnvFunctions";
|
import { compatGlobal, type CompatIntervalHandle } from "@vrtmrz/livesync-commonlib/compat/common/coreEnvFunctions";
|
||||||
|
import { $msg } from "@/common/translation";
|
||||||
|
|
||||||
class AutoClosableModal extends Modal {
|
class AutoClosableModal extends Modal {
|
||||||
_closeByUnload = () => {
|
_closeByUnload = () => {
|
||||||
@@ -58,7 +59,7 @@ export class InputStringDialog extends AutoClosableModal {
|
|||||||
new Setting(formEl)
|
new Setting(formEl)
|
||||||
.addButton((btn) =>
|
.addButton((btn) =>
|
||||||
btn
|
btn
|
||||||
.setButtonText("Ok")
|
.setButtonText($msg("Ok"))
|
||||||
.setCta()
|
.setCta()
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
this.isManuallyClosed = true;
|
this.isManuallyClosed = true;
|
||||||
@@ -67,7 +68,7 @@ export class InputStringDialog extends AutoClosableModal {
|
|||||||
)
|
)
|
||||||
.addButton((btn) =>
|
.addButton((btn) =>
|
||||||
btn
|
btn
|
||||||
.setButtonText("Cancel")
|
.setButtonText($msg("Cancel"))
|
||||||
.setCta()
|
.setCta()
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
this.close();
|
this.close();
|
||||||
@@ -199,7 +200,9 @@ export class MessageBox<T extends readonly string[]> extends AutoClosableModal {
|
|||||||
const buttonSetting = new Setting(contentEl);
|
const buttonSetting = new Setting(contentEl);
|
||||||
const labelWrapper = contentEl.createDiv();
|
const labelWrapper = contentEl.createDiv();
|
||||||
labelWrapper.addClass("sls-dialogue-note-wrapper");
|
labelWrapper.addClass("sls-dialogue-note-wrapper");
|
||||||
const labelEl = labelWrapper.createEl("label", { text: "To stop the countdown, tap anywhere on the dialogue" });
|
const labelEl = labelWrapper.createEl("label", {
|
||||||
|
text: $msg("To stop the countdown, tap anywhere on the dialogue"),
|
||||||
|
});
|
||||||
labelEl.addClass("sls-dialogue-note-countdown");
|
labelEl.addClass("sls-dialogue-note-countdown");
|
||||||
if (!this.timeout || !this.timer) {
|
if (!this.timeout || !this.timer) {
|
||||||
labelWrapper.empty();
|
labelWrapper.empty();
|
||||||
|
|||||||
@@ -200,14 +200,14 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="globalhistory">
|
<div class="globalhistory">
|
||||||
<h1>Vault history</h1>
|
<h1>{translateMessage("Vault history")}</h1>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="">From:</label><input type="date" bind:value={dispDateFrom} disabled={loading} />
|
<label for="">{translateMessage("From:")}</label><input type="date" bind:value={dispDateFrom} disabled={loading} />
|
||||||
</div>
|
</div>
|
||||||
<div class="row"><label for="">To:</label><input type="date" bind:value={dispDateTo} disabled={loading} /></div>
|
<div class="row"><label for="">{translateMessage("To:")}</label><input type="date" bind:value={dispDateTo} disabled={loading} /></div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="">Info:</label>
|
<label for="">{translateMessage("Info:")}</label>
|
||||||
<label
|
<label
|
||||||
><input type="checkbox" bind:checked={showDiffInfo} disabled={loading} /><span
|
><input type="checkbox" bind:checked={showDiffInfo} disabled={loading} /><span
|
||||||
>{translateMessage("Diff")}</span
|
>{translateMessage("Diff")}</span
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
<span>{msg("logPane.pause", {}, lang)}</span>
|
<span>{msg("logPane.pause", {}, lang)}</span>
|
||||||
</label>
|
</label>
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
<button onclick={() => closeDialogue()}>Close</button>
|
<button onclick={() => closeDialogue()}>{msg("Close", {}, lang)}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="log" bind:this={scroll}>
|
<div class="log" bind:this={scroll}>
|
||||||
|
|||||||
@@ -39,19 +39,19 @@
|
|||||||
{/each}
|
{/each}
|
||||||
<li>
|
<li>
|
||||||
<label>
|
<label>
|
||||||
<button on:click={() => add()}>Add</button>
|
<button on:click={() => add()}>{translateMessage("Add")}</button>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li class="buttons">
|
<li class="buttons">
|
||||||
<button
|
<button
|
||||||
on:click={() => apply(patterns)}
|
on:click={() => apply(patterns)}
|
||||||
disabled={statusName.some((e) => e === CHECK_NG) || modified.every((e) => e === "")}
|
disabled={statusName.some((e) => e === CHECK_NG) || modified.every((e) => e === "")}
|
||||||
>Apply
|
>{translateMessage("Apply")}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
on:click={() => revert()}
|
on:click={() => revert()}
|
||||||
disabled={statusName.some((e) => e === CHECK_NG) || modified.every((e) => e === "")}
|
disabled={statusName.some((e) => e === CHECK_NG) || modified.every((e) => e === "")}
|
||||||
>Revert
|
>{translateMessage("Revert")}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
|||||||
el.setText(`Current adapter: ${useIndexedDBAdapter ? "IndexedDB" : "IDB"}`);
|
el.setText(`Current adapter: ${useIndexedDBAdapter ? "IndexedDB" : "IDB"}`);
|
||||||
if (!useIndexedDBAdapter) {
|
if (!useIndexedDBAdapter) {
|
||||||
setting.addButton((button) => {
|
setting.addButton((button) => {
|
||||||
button.setButtonText("Switch to IndexedDB").onClick(async () => {
|
button.setButtonText($msg("Switch to IndexedDB")).onClick(async () => {
|
||||||
Logger("Migrating all data to IndexedDB...", LOG_LEVEL_NOTICE);
|
Logger("Migrating all data to IndexedDB...", LOG_LEVEL_NOTICE);
|
||||||
await migrateAllToIndexedDB();
|
await migrateAllToIndexedDB();
|
||||||
Logger(
|
Logger(
|
||||||
@@ -109,7 +109,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setting.addButton((button) => {
|
setting.addButton((button) => {
|
||||||
button.setButtonText("Switch to IDB").onClick(async () => {
|
button.setButtonText($msg("Switch to IDB")).onClick(async () => {
|
||||||
Logger("Migrating all data to IDB...", LOG_LEVEL_NOTICE);
|
Logger("Migrating all data to IDB...", LOG_LEVEL_NOTICE);
|
||||||
await migrateAllToIDB();
|
await migrateAllToIDB();
|
||||||
Logger(
|
Logger(
|
||||||
|
|||||||
@@ -253,21 +253,21 @@ export function paneSyncSettings(
|
|||||||
new Setting(paneEl)
|
new Setting(paneEl)
|
||||||
.setName($msg("obsidianLiveSyncSettingTab.nameEnableHiddenFileSync"))
|
.setName($msg("obsidianLiveSyncSettingTab.nameEnableHiddenFileSync"))
|
||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Merge").onClick(async () => {
|
button.setButtonText($msg("Merge")).onClick(async () => {
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
// this.resetEditingSettings();
|
// this.resetEditingSettings();
|
||||||
await this.services.setting.enableOptionalFeature("MERGE");
|
await this.services.setting.enableOptionalFeature("MERGE");
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Fetch").onClick(async () => {
|
button.setButtonText($msg("Fetch")).onClick(async () => {
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
// this.resetEditingSettings();
|
// this.resetEditingSettings();
|
||||||
await this.services.setting.enableOptionalFeature("FETCH");
|
await this.services.setting.enableOptionalFeature("FETCH");
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Overwrite").onClick(async () => {
|
button.setButtonText($msg("Overwrite")).onClick(async () => {
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
// this.resetEditingSettings();
|
// this.resetEditingSettings();
|
||||||
await this.services.setting.enableOptionalFeature("OVERWRITE");
|
await this.services.setting.enableOptionalFeature("OVERWRITE");
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import {
|
|||||||
type AllBooleanItemKey as CommonlibAllBooleanItemKey,
|
type AllBooleanItemKey as CommonlibAllBooleanItemKey,
|
||||||
} from "@vrtmrz/livesync-commonlib/compat/common/settingConstants";
|
} from "@vrtmrz/livesync-commonlib/compat/common/settingConstants";
|
||||||
import type { ConfigurationItem } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
import type { ConfigurationItem } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||||
import type { MessageTranslator } from "@vrtmrz/livesync-commonlib/context";
|
import type { AllMessageKeys } from "@/common/rosetta";
|
||||||
|
import type { LiveSyncMessageTranslator } from "@/common/translation";
|
||||||
import { translateLiveSyncMessage } from "@/common/translation";
|
import { translateLiveSyncMessage } from "@/common/translation";
|
||||||
import {
|
import {
|
||||||
DEFAULT_SYNC_GUARD_SETTINGS,
|
DEFAULT_SYNC_GUARD_SETTINGS,
|
||||||
@@ -52,13 +53,19 @@ export const SettingInformation: Partial<Record<AllSettingItemKey, Configuration
|
|||||||
// site has to remember the second argument.
|
// site has to remember the second argument.
|
||||||
|
|
||||||
/** `getConfig` with the LiveSync catalogue applied by default. */
|
/** `getConfig` with the LiveSync catalogue applied by default. */
|
||||||
export function getConfig(key: AllSettingItemKey, translate: MessageTranslator = translateLiveSyncMessage) {
|
export function getConfig(key: AllSettingItemKey, translate: LiveSyncMessageTranslator = translateLiveSyncMessage) {
|
||||||
if (isSyncGuardSettingKey(key)) return syncGuardSettingInformation[key];
|
if (isSyncGuardSettingKey(key)) {
|
||||||
|
const info = syncGuardSettingInformation[key];
|
||||||
|
return {
|
||||||
|
name: translate(info.name as AllMessageKeys),
|
||||||
|
desc: info.desc ? translate(info.desc as AllMessageKeys) : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
return getCommonlibConfig(key, translate);
|
return getCommonlibConfig(key, translate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** `getConfName` with the LiveSync catalogue applied by default. See `getConfig`. */
|
/** `getConfName` with the LiveSync catalogue applied by default. See `getConfig`. */
|
||||||
export function getConfName(key: AllSettingItemKey, translate: MessageTranslator = translateLiveSyncMessage) {
|
export function getConfName(key: AllSettingItemKey, translate: LiveSyncMessageTranslator = translateLiveSyncMessage) {
|
||||||
if (isSyncGuardSettingKey(key)) return syncGuardSettingInformation[key].name;
|
if (isSyncGuardSettingKey(key)) return translate(syncGuardSettingInformation[key].name as AllMessageKeys);
|
||||||
return getCommonlibConfName(key, translate);
|
return getCommonlibConfName(key, translate);
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,13 @@ describe("setting manifest labels", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("renders LiveSync provisional settings in Japanese", () => {
|
||||||
|
setLang("ja");
|
||||||
|
|
||||||
|
expect(getConfName("batchSaveInLiveSync")).toBe("LiveSync モードでデータベース更新をバッチ処理");
|
||||||
|
expect(getConfName("syncGuardEnabled")).toBe("SyncGuard を有効化");
|
||||||
|
});
|
||||||
|
|
||||||
it("passes through labels which Commonlib owns but the catalogue does not carry", () => {
|
it("passes through labels which Commonlib owns but the catalogue does not carry", () => {
|
||||||
setLang("zh-tw");
|
setLang("zh-tw");
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ async function confirmTranslatedChoice(
|
|||||||
const selected = await host.services.UI.confirm.confirmWithMessage(title, message, labels, $msg(defaultAction), 0);
|
const selected = await host.services.UI.confirm.confirmWithMessage(title, message, labels, $msg(defaultAction), 0);
|
||||||
if (selected === false) return false;
|
if (selected === false) return false;
|
||||||
const index = labels.indexOf(selected);
|
const index = labels.indexOf(selected);
|
||||||
return index < 0 ? false : buttons[index];
|
if (index >= 0) return buttons[index];
|
||||||
|
const buttonIndex = buttons.indexOf(selected as AllMessageKeys);
|
||||||
|
return buttonIndex < 0 ? false : buttons[buttonIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function askSimpleFetchMode(
|
export async function askSimpleFetchMode(
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ describe("Fetch restart confirmation regressions", () => {
|
|||||||
expect(confirmWithMessage).toHaveBeenCalledOnce();
|
expect(confirmWithMessage).toHaveBeenCalledOnce();
|
||||||
expect(confirmWithMessage.mock.calls[0][1]).toContain("example.invalid");
|
expect(confirmWithMessage.mock.calls[0][1]).toContain("example.invalid");
|
||||||
expect(confirmWithMessage.mock.calls[0][1]).toContain(REMOTE_WINS);
|
expect(confirmWithMessage.mock.calls[0][1]).toContain(REMOTE_WINS);
|
||||||
expect(confirmWithMessage.mock.calls[0][1]).toContain(KEEP_LOCAL);
|
expect(confirmWithMessage.mock.calls[0][1]).toContain($msg(KEEP_LOCAL));
|
||||||
expect(files.get(flagPath)).toBe(rememberedMarkdown);
|
expect(files.get(flagPath)).toBe(rememberedMarkdown);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -497,8 +497,7 @@ describe("Red Flag Feature", () => {
|
|||||||
expect(host.mocks.rebuilder.$fetchLocalDBFast).toHaveBeenCalled();
|
expect(host.mocks.rebuilder.$fetchLocalDBFast).toHaveBeenCalled();
|
||||||
expect(synchroniseAllFilesBetweenDBandStorage).toHaveBeenCalled();
|
expect(synchroniseAllFilesBetweenDBandStorage).toHaveBeenCalled();
|
||||||
const firstPrompt = host.mocks.ui.confirm.confirmWithMessage.mock.calls[0]?.[1];
|
const firstPrompt = host.mocks.ui.confirm.confirmWithMessage.mock.calls[0]?.[1];
|
||||||
expect(firstPrompt).toContain("data retrieved from this remote source");
|
expect(firstPrompt).toContain("We are about to retrieve the remote data.");
|
||||||
expect(firstPrompt).not.toContain("remote server");
|
|
||||||
// We can't easily check performFullScan call here because it's imported,
|
// We can't easily check performFullScan call here because it's imported,
|
||||||
// but we can verify rebuilder was called.
|
// but we can verify rebuilder was called.
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user