diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index cff97ab..3e3c67d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -12,6 +12,7 @@ jobs: id-token: write contents: write attestations: write + actions: read timeout-minutes: 10 steps: - uses: actions/checkout@v5 @@ -36,20 +37,27 @@ jobs: sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Config/Config.xcconfig - name: Build run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive - - name: Create ZIP + - name: Move to Artifact Folder + run: mkdir Artifact; cp -r Archive.xcarchive/Products/Applications/Secretive.app Artifact + - name: Upload App to Artifacts + id: upload + uses: actions/upload-artifact@v4 + with: + name: Secretive + path: Artifact + - name: Download Zipped Artifact + id: download + env: + ZIP_ID: ${{ steps.upload.outputs.artifact-id }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip + curl -L -H "Authorization: Bearer $GITHUB_TOKEN" -L \ + https://api.github.com/repos/maxgoedjen/secretive/actions/artifacts/$ZIP_ID/zip > Secretive.zip - name: Notarize env: APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip - - name: Upload App to Artifacts - id: upload - uses: actions/upload-artifact@v4 - with: - name: Secretive.zip - path: Secretive.zip - name: Attest id: attest uses: actions/attest-build-provenance@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a3d42e..ba5b220 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,6 +32,7 @@ jobs: id-token: write contents: write attestations: write + actions: read runs-on: macos-26 timeout-minutes: 10 steps: @@ -58,33 +59,40 @@ jobs: sed -i '' -e "s/GITHUB_BUILD_URL/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Config/Config.xcconfig - name: Build run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive - - name: Create ZIP - run: | - ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip - - name: Notarize - env: - APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} - APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} - run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip + - name: Move to Artifact Folder + run: mkdir Artifact; cp -r Archive.xcarchive/Products/Applications/Secretive.app Artifact - name: Upload App to Artifacts id: upload uses: actions/upload-artifact@v4 with: name: Secretive.zip - path: Secretive.zip + path: Artifact + - name: Download Zipped Artifact + id: download + env: + ZIP_ID: ${{ steps.upload.outputs.artifact-id }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + curl -L -H "Authorization: Bearer $GITHUB_TOKEN" -L \ + https://api.github.com/repos/maxgoedjen/secretive/actions/artifacts/$ZIP_ID/zip > Secretive.zip + - name: Notarize + env: + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip - name: Attest id: attest uses: actions/attest-build-provenance@v2 with: subject-path: "Secretive.zip" - name: Create Release - run: | - sed -i.tmp "s/RUN_ID/$RUN_ID/g" .github/templates/release.md - sed -i.tmp "s/ATTESTATION_ID/$ATTESTATION_ID/g" .github/templates/release.md - gh release create $TAG_NAME -d -F .github/templates/release.md - gh release upload $TAG_NAME Secretive.zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG_NAME: ${{ github.ref }} RUN_ID: ${{ github.run_id }} ATTESTATION_ID: ${{ steps.attest.outputs.attestation-id }} + run: | + sed -i.tmp "s/RUN_ID/$RUN_ID/g" .github/templates/release.md + sed -i.tmp "s/ATTESTATION_ID/$ATTESTATION_ID/g" .github/templates/release.md + gh release create $TAG_NAME -d -F .github/templates/release.md + gh release upload $TAG_NAME Secretive.zip diff --git a/Sources/Packages/Resources/Localizable.xcstrings b/Sources/Packages/Resources/Localizable.xcstrings index aca6a13..3513013 100644 --- a/Sources/Packages/Resources/Localizable.xcstrings +++ b/Sources/Packages/Resources/Localizable.xcstrings @@ -93,13 +93,13 @@ "value" : "" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "" @@ -278,13 +278,13 @@ "value" : "**%1$@** (%2$@)" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "**%1$@** (%2$@)" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "**%1$@** (%2$@)" @@ -430,8 +430,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "Build Log" + "state" : "translated", + "value" : "Journal de version" } }, "he" : { @@ -464,13 +464,13 @@ "value" : "빌드 로그" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Build Log" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Build Log" @@ -538,14 +538,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Build Log" + "state" : "translated", + "value" : "构建日志" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Build Log" + "state" : "translated", + "value" : "構建日誌" } } } @@ -615,8 +615,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "About Secretive" + "state" : "translated", + "value" : "A propos" } }, "he" : { @@ -649,13 +649,13 @@ "value" : "Secretive에 대해서" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "About Secretive" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "About Secretive" @@ -724,13 +724,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关于 Secretive" + "value" : "关于Secretive" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "About Secretive" + "state" : "translated", + "value" : "關於Secretive" } } } @@ -800,8 +800,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive is Open Source and MIT Licensed" + "state" : "translated", + "value" : "Secretive est Open Source et sous licence MIT" } }, "he" : { @@ -834,13 +834,13 @@ "value" : "Secretive는 오픈 소스이며 MIT 라이선스입니다" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive is Open Source and MIT Licensed" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive is Open Source and MIT Licensed" @@ -908,14 +908,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive is Open Source and MIT Licensed" + "state" : "translated", + "value" : "Secretive是开源软件并以MIT协议授权" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive is Open Source and MIT Licensed" + "state" : "translated", + "value" : "Secretive是開源軟體並以MIT協議授權" } } } @@ -985,8 +985,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "Special thanks our [Contributors](%1$(contributorsLink)@) and [Sponsors](%2$(sponsorsLink)@)" + "state" : "translated", + "value" : "Remerciements spéciaux à nos [Contributeurs](%1$(contributorsLink)@) et [Mécène](%2$(sponsorsLink)@)" } }, "he" : { @@ -1019,13 +1019,13 @@ "value" : "[기여자](%1$(contributorsLink)@)와 [후원자](%2$(sponsorsLink)@)에게 특별히 감사드립니다" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Special thanks our [Contributors](%1$(contributorsLink)@) and [Sponsors](%2$(sponsorsLink)@)" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Special thanks our [Contributors](%1$(contributorsLink)@) and [Sponsors](%2$(sponsorsLink)@)" @@ -1093,14 +1093,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Special thanks our [Contributors](%1$(contributorsLink)@) and [Sponsors](%2$(sponsorsLink)@)" + "state" : "translated", + "value" : "特别感谢我们的[贡献者](%1$(contributorsLink)@)和[赞助者](%2$(sponsorsLink)@)" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Special thanks our [Contributors](%1$(contributorsLink)@) and [Sponsors](%2$(sponsorsLink)@)" + "state" : "translated", + "value" : "特別感謝我們的[貢獻者](%1$(contributorsLink)@)和[贊助者](%2$(sponsorsLink)@)" } } } @@ -1170,8 +1170,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "View on GitHub" + "state" : "translated", + "value" : "Voir sur GitHub" } }, "he" : { @@ -1204,13 +1204,13 @@ "value" : "GitHub에서 보기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "View on GitHub" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "View on GitHub" @@ -1278,14 +1278,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "View on GitHub" + "state" : "translated", + "value" : "在GitHub上查看" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "View on GitHub" + "state" : "translated", + "value" : "在GitHub上檢視" } } } @@ -1389,13 +1389,13 @@ "value" : "Secretive에서 SecretAgent를 실행할 수 없습니다. Mac을 재시작해 보시고, 그래도 문제가 해결되지 않으면 GitHub에 문제를 제출해 주세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive was unable to get SecretAgent to launch. Please try restarting your Mac, and if that doesn't work, file an issue on GitHub." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive was unable to get SecretAgent to launch. Please try restarting your Mac, and if that doesn't work, file an issue on GitHub." @@ -1463,14 +1463,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive was unable to get SecretAgent to launch. Please try restarting your Mac, and if that doesn't work, file an issue on GitHub." + "state" : "translated", + "value" : "Secretive无法启动SecretAgent。请尝试重启Mac,如果没有效果,请在GitHub上提交一个issue。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive was unable to get SecretAgent to launch. Please try restarting your Mac, and if that doesn't work, file an issue on GitHub." + "state" : "translated", + "value" : "Secretive無法啟動SecretAgent。請嘗試重啟Mac,如果沒有效果,請在GitHub上提交一個issue。" } } } @@ -1574,13 +1574,13 @@ "value" : "에이전트 비활성화" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Disable Agent" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Disable Agent" @@ -1648,14 +1648,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Disable Agent" + "state" : "translated", + "value" : "禁用Agent" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Disable Agent" + "state" : "translated", + "value" : "禁用Agent" } } } @@ -1759,13 +1759,13 @@ "value" : "에이전트 재시작" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Restart Agent" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Restart Agent" @@ -1833,14 +1833,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Restart Agent" + "state" : "translated", + "value" : "重启Agent" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Restart Agent" + "state" : "translated", + "value" : "重啟Agent" } } } @@ -1944,13 +1944,13 @@ "value" : "실행 시각" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Running Since" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Running Since" @@ -2018,14 +2018,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Running Since" + "state" : "translated", + "value" : "运行时间始于" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Running Since" + "state" : "translated", + "value" : "執行時間始於" } } } @@ -2129,13 +2129,13 @@ "value" : "소켓 경로" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Socket Path" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Socket Path" @@ -2203,14 +2203,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Socket Path" + "state" : "translated", + "value" : "Socket路径" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Socket Path" + "state" : "translated", + "value" : "Socket路徑" } } } @@ -2314,13 +2314,13 @@ "value" : "에이전트 시작" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Start Agent" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Start Agent" @@ -2388,14 +2388,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Start Agent" + "state" : "translated", + "value" : "启动Agent" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Start Agent" + "state" : "translated", + "value" : "啟動Agent" } } } @@ -2499,13 +2499,13 @@ "value" : "에이전트 시작중" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Starting Agent" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Starting Agent" @@ -2573,14 +2573,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Starting Agent" + "state" : "translated", + "value" : "Agent启动中" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Starting Agent" + "state" : "translated", + "value" : "Agent啟動中" } } } @@ -2684,13 +2684,13 @@ "value" : "버전" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Version" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Version" @@ -2758,14 +2758,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Version" + "state" : "translated", + "value" : "版本" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Version" + "state" : "translated", + "value" : "版本" } } } @@ -2869,13 +2869,13 @@ "value" : "SecretAgent는 백그라운드에서 실행되어 요청에 서명하는 프로세스이므로 Secretive를 항상 열어 둘 필요는 없습니다.\n\n**Secretive 에이전트가 설치되어 실행 중이어야 Secretive가 제대로 작동합니다.**" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**Secretive will not be able to function properly unless the agent is installed and running.**" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**Secretive will not be able to function properly unless the agent is installed and running.**" @@ -2943,14 +2943,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**Secretive will not be able to function properly unless the agent is installed and running.**" + "state" : "translated", + "value" : "SecretAgent是个在后台处理签名请求的进程,让您无需将Secretive一直保持在前台。\n\n**需要安装并运行Agent,否则Secretive无法正常工作。**" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**Secretive will not be able to function properly unless the agent is installed and running.**" + "state" : "translated", + "value" : "SecretAgent是個在後台處理簽名請求的行程,讓您無需將Secretive一直保持在前台。\n\n**需要安裝並執行Agent,否則Secretive無法正常工作。**" } } } @@ -3054,13 +3054,13 @@ "value" : "Agent가 실행되고 있지 않음" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Agent Is Not Running" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Agent Is Not Running" @@ -3129,13 +3129,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "SecretAgent尚未运行" + "value" : "Agent尚未运行" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Agent Is Not Running" + "state" : "translated", + "value" : "Agent尚未執行" } } } @@ -3200,7 +3200,7 @@ "fi" : { "stringUnit" : { "state" : "translated", - "value" : "SecretAgent on taustaprosessi joka allekirjoittaa pyyntöjä, joten Secretiveä ei tarvitse pitää käynnissä koko aikaa.\u2028\u2028**Voit sulkea Secretiven, ja kaikki toimii yhä.**" + "value" : "SecretAgent on taustaprosessi joka allekirjoittaa pyyntöjä, joten Secretiveä ei tarvitse pitää käynnissä koko aikaa.

**Voit sulkea Secretiven, ja kaikki toimii yhä.**" } }, "fr" : { @@ -3239,13 +3239,13 @@ "value" : "SecretAgent는 요청에 서명하기 위해 백그라운드에서 실행되는 프로세스이므로 Secretive를 항상 열어 둘 필요가 없습니다.\n\n**Secretive를 닫아도 모든 것이 계속 작동합니다.**" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**You can close Secretive, and everything will still keep working.**" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**You can close Secretive, and everything will still keep working.**" @@ -3314,13 +3314,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "SecretAgent是一个在后台进行请求处理的服务,所以您可以不用让Secretive 一直保持前台运行。 \n\n\n**您可以关闭 Secretive,所有服务都将正常运行。**\n\n\n" + "value" : "SecretAgent是个在后台处理签名请求的进程,让您无需将Secretive一直保持在前台。\n\n**您可以关闭Secretive,所有服务都将正常运行。**" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**You can close Secretive, and everything will still keep working.**" + "state" : "translated", + "value" : "SecretAgent是個在後台處理簽名請求的行程,讓您無需將Secretive一直保持在前台。\n\n**您可以關閉Secretive,所有服務都將正常執行。**" } } } @@ -3424,13 +3424,13 @@ "value" : "Secret Agent가 실행 중입니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secret Agent is Running" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secret Agent is Running" @@ -3499,13 +3499,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "SecretAgent运行中" + "value" : "Secret Agent运行中" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secret Agent is Running" + "state" : "translated", + "value" : "Secret Agent執行中" } } } @@ -3609,13 +3609,13 @@ "value" : "Agent가 실행중" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Agent is Running" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Agent is Running" @@ -3689,8 +3689,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Agent is Running" + "state" : "translated", + "value" : "Agent執行中" } } } @@ -3794,13 +3794,13 @@ "value" : "Secret Agent 경로" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secret Agent Location" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secret Agent Location" @@ -3868,14 +3868,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Secret Agent Location" + "state" : "translated", + "value" : "Secret Agent的位置" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secret Agent Location" + "state" : "translated", + "value" : "Secret Agent的位置" } } } @@ -3979,13 +3979,13 @@ "value" : "도움말" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Help" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Help" @@ -4059,8 +4059,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Help" + "state" : "translated", + "value" : "幫助" } } } @@ -4164,13 +4164,13 @@ "value" : "새 비밀" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "New Secret" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "New Secret" @@ -4244,8 +4244,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "New Secret" + "state" : "translated", + "value" : "新建Secret" } } } @@ -4315,8 +4315,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "Later" + "state" : "translated", + "value" : "Plus tard" } }, "he" : { @@ -4349,13 +4349,13 @@ "value" : "나중에" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Later" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Later" @@ -4423,14 +4423,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Later" + "state" : "translated", + "value" : "稍后" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Later" + "state" : "translated", + "value" : "稍後" } } } @@ -4534,13 +4534,13 @@ "value" : "Secretive가 제대로 작동하려면 Applications 폴더에 있어야 합니다. 이동한 후 다시 실행해 주세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive needs to be in your Applications folder to work properly. Please move it and relaunch." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive needs to be in your Applications folder to work properly. Please move it and relaunch." @@ -4609,13 +4609,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Secretive 需要在应用程序文件夹中才能保持正常运行。请移动Secretive并重启" + "value" : "Secretive需要在“应用程序”文件夹中才能正常运行。请移动并重新启动Secretive。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive needs to be in your Applications folder to work properly. Please move it and relaunch." + "state" : "translated", + "value" : "Secretive需要在「應用程式」資料夾中才能正常執行。請移動並重新啟動Secretive。" } } } @@ -4685,8 +4685,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "Quit" + "state" : "translated", + "value" : "Quitter" } }, "he" : { @@ -4719,13 +4719,13 @@ "value" : "종료" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Quit" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Quit" @@ -4793,14 +4793,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Quit" + "state" : "translated", + "value" : "退出" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Quit" + "state" : "translated", + "value" : "退出" } } } @@ -4904,13 +4904,13 @@ "value" : "Secretive가 Applications 폴더에 없음" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive Is Not in Applications Folder" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive Is Not in Applications Folder" @@ -4979,13 +4979,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Secretive 不在系统应用文件夹中" + "value" : "Secretive不在“应用程序”文件夹中" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive Is Not in Applications Folder" + "state" : "translated", + "value" : "Secretive不在「應用程式」資料夾中" } } } @@ -5090,13 +5090,13 @@ "value" : "비밀 “%1$(secretName)@”를 %2$(duration)@ 동안 잠금 해제" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "unlock secret “%1$(secretName)@” for %2$(duration)@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "unlock secret “%1$(secretName)@” for %2$(duration)@" @@ -5165,13 +5165,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "解锁密钥串 “%1$(secretName)@” 给 %2$(duration)@" + "value" : "解锁密钥串“%1$(secretName)@”%2$(duration)@" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "unlock secret “%1$(secretName)@” for %2$(duration)@" + "state" : "translated", + "value" : "解鎖Secret「%1$(secretName)@」%2$(duration)@" } } } @@ -5276,13 +5276,13 @@ "value" : "거부" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Deny" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Deny" @@ -5356,8 +5356,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Deny" + "state" : "translated", + "value" : "拒絕" } } } @@ -5462,13 +5462,13 @@ "value" : "비밀 “%2$(secretName)@”를 사용해서 “%1$(appName)@”의 요청에 서명" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "sign a request from “%1$(appName)@” using secret “%2$(secretName)@”" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "sign a request from “%1$(appName)@” using secret “%2$(secretName)@”" @@ -5537,13 +5537,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用密钥串 “%2$(secretName)@” 认证 “%1$(appName)@” " + "value" : "用密钥串“%2$(secretName)@”认证来自“%1$(appName)@”的请求" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "sign a request from “%1$(appName)@” using secret “%2$(secretName)@”" + "state" : "translated", + "value" : "用Secret「%2$(secretName)@」認證来自「%1$(appName)@」的请求" } } } @@ -5647,13 +5647,13 @@ "value" : "복사하기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Click to Copy" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Click to Copy" @@ -5727,8 +5727,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Click to Copy" + "state" : "translated", + "value" : "點選以拷貝" } } } @@ -5832,13 +5832,13 @@ "value" : "복사됨" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Copied" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Copied" @@ -5912,8 +5912,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Copied" + "state" : "translated", + "value" : "已拷貝" } } } @@ -6017,13 +6017,13 @@ "value" : "고급" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Advanced" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Advanced" @@ -6091,14 +6091,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Advanced" + "state" : "translated", + "value" : "高级选项" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Advanced" + "state" : "translated", + "value" : "高階選項" } } } @@ -6202,13 +6202,13 @@ "value" : "새로운 지문을 추가하는 등 생체 인식 설정을 _어떤 식으로든_ 변경하면 이 키에 더 이상 접근할 수 없습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If you change your biometric settings in _any way_, including adding a new fingerprint, this key will no longer be accessible." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If you change your biometric settings in _any way_, including adding a new fingerprint, this key will no longer be accessible." @@ -6276,14 +6276,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "If you change your biometric settings in _any way_, including adding a new fingerprint, this key will no longer be accessible." + "state" : "translated", + "value" : "如果您以_任何方式_更改生物识别设置,包括新增指纹,此密钥将不再可用。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If you change your biometric settings in _any way_, including adding a new fingerprint, this key will no longer be accessible." + "state" : "translated", + "value" : "如果您以_任何方式_更改生物識別設定,包括新增指紋,此金鑰將不再可用。" } } } @@ -6387,13 +6387,13 @@ "value" : "취소" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Cancel" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Cancel" @@ -6462,13 +6462,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "返回" + "value" : "取消" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Cancel" + "state" : "translated", + "value" : "取消" } } } @@ -6572,13 +6572,13 @@ "value" : "생성" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Create" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Create" @@ -6652,8 +6652,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Create" + "state" : "translated", + "value" : "建立" } } } @@ -6757,13 +6757,13 @@ "value" : "공개 키 끝에 표시되는 정보입니다. 보통 이메일 주소입니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "This shows at the end of your public key. It’s usually an email address." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "This shows at the end of your public key. It’s usually an email address." @@ -6837,8 +6837,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "This shows at the end of your public key. It’s usually an email address." + "state" : "translated", + "value" : "會顯示在公鑰末尾。通常為電郵地址。" } } } @@ -6942,13 +6942,13 @@ "value" : "키 속성" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Key Attribution" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Key Attribution" @@ -7022,8 +7022,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Key Attribution" + "state" : "translated", + "value" : "金鑰歸屬" } } } @@ -7127,13 +7127,13 @@ "value" : "키 유형" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Key Type" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Key Type" @@ -7201,14 +7201,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Key Type" + "state" : "translated", + "value" : "密钥类型" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Key Type" + "state" : "translated", + "value" : "金鑰型別" } } } @@ -7278,8 +7278,8 @@ }, "fr" : { "stringUnit" : { - "state" : "new", - "value" : "Unavailable on this version of macOS" + "state" : "translated", + "value" : "Indisponible sur cette version de macOS" } }, "he" : { @@ -7312,13 +7312,13 @@ "value" : "이 버전의 macOS에서는 사용할 수 없습니다" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Unavailable on this version of macOS" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Unavailable on this version of macOS" @@ -7386,14 +7386,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Unavailable on this version of macOS" + "state" : "translated", + "value" : "在当前版本的macOS上不可用" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Unavailable on this version of macOS" + "state" : "translated", + "value" : "在當前版本的macOS上不可用" } } } @@ -7497,13 +7497,13 @@ "value" : "경고: ML-DSA 키는 매우 최신 버전이므로 아직 많은 서버에서 지원되지 않습니다. 이 키를 사용할 서버가 ML-DSA 키를 허용하는지 확인하세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Warning: ML-DSA keys are very new, and not supported by many servers yet. Please verify the server you'll be using this key for accepts ML-DSA keys." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Warning: ML-DSA keys are very new, and not supported by many servers yet. Please verify the server you'll be using this key for accepts ML-DSA keys." @@ -7571,14 +7571,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Warning: ML-DSA keys are very new, and not supported by many servers yet. Please verify the server you'll be using this key for accepts ML-DSA keys." + "state" : "translated", + "value" : "警告:ML-DSA密钥非常新,许多服务器尚不支持。 请验证您将使用此密钥的服务器能接受ML-DSA密钥。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Warning: ML-DSA keys are very new, and not supported by many servers yet. Please verify the server you'll be using this key for accepts ML-DSA keys." + "state" : "translated", + "value" : "警告:ML-DSA金鑰非常新,許多伺服器尚不支援。 請驗證您將使用此金鑰的伺服器能接受ML-DSA金鑰。" } } } @@ -7682,13 +7682,13 @@ "value" : "이름" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Name" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Name" @@ -7762,8 +7762,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Name" + "state" : "translated", + "value" : "名稱" } } } @@ -7867,13 +7867,13 @@ "value" : "쉿" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Shhhhh" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Shhhhh" @@ -7947,8 +7947,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Shhhhh" + "state" : "translated", + "value" : "某某" } } } @@ -8052,13 +8052,13 @@ "value" : "Mac이 잠금 해제되어 있는 동안에는 인증이 필요하지 않지만 비밀이 사용되면 알림을 받게 됩니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "No authentication is required while your Mac is unlocked, but you will be notified when a secret is used." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "No authentication is required while your Mac is unlocked, but you will be notified when a secret is used." @@ -8127,13 +8127,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "当您的Mac 解锁时不需要任何验证,但您会收到一条密钥串被使用的通知" + "value" : "当Mac已解锁时无需验证,但密钥串被使用时会通知您。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "No authentication is required while your Mac is unlocked, but you will be notified when a secret is used." + "state" : "translated", + "value" : "當Mac已解鎖時無需驗證,但Secret被使用时會通知您。" } } } @@ -8237,13 +8237,13 @@ "value" : "알림" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Notify" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Notify" @@ -8317,8 +8317,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Notify" + "state" : "translated", + "value" : "通知" } } } @@ -8422,13 +8422,13 @@ "value" : "보호 수준" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Protection Level" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Protection Level" @@ -8496,14 +8496,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Protection Level" + "state" : "translated", + "value" : "保护级别" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Protection Level" + "state" : "translated", + "value" : "保護級別" } } } @@ -8607,13 +8607,13 @@ "value" : "현재의 생체 인식 정보들를 사용하여 인증을 요구합니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Require authentication with current set of biometrics." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Require authentication with current set of biometrics." @@ -8681,14 +8681,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Require authentication with current set of biometrics." + "state" : "translated", + "value" : "需要用当前的生物识别特征集来认证。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Require authentication with current set of biometrics." + "state" : "translated", + "value" : "需要用當前的生物識別特徵集來認證。" } } } @@ -8792,13 +8792,13 @@ "value" : "현재 생체 인식들" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Current Biometrics" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Current Biometrics" @@ -8866,14 +8866,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Current Biometrics" + "state" : "translated", + "value" : "当前的生物识别" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Current Biometrics" + "state" : "translated", + "value" : "當前的生物識別" } } } @@ -8977,13 +8977,13 @@ "value" : "매번 사용하기 전에 Touch ID, Apple Watch 또는 비밀번호를 사용하여 인증해야 합니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "You will be required to authenticate using Touch ID, Apple Watch, or password before each use." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "You will be required to authenticate using Touch ID, Apple Watch, or password before each use." @@ -9052,13 +9052,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "您在每次使用时都会被要求使用Touch ID 、Apple Watch 或密码进行验证。" + "value" : "每次使用前都会要求您使用触控ID、Apple Watch或密码进行验证。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "You will be required to authenticate using Touch ID, Apple Watch, or password before each use." + "state" : "translated", + "value" : "每次使用前都會要求您使用Touch ID、Apple Watch或密碼進行認證。" } } } @@ -9162,13 +9162,13 @@ "value" : "인증 요구" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Require Authentication" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Require Authentication" @@ -9242,8 +9242,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Require Authentication" + "state" : "translated", + "value" : "需要驗證" } } } @@ -9347,13 +9347,13 @@ "value" : "새 비밀 생성" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Create a New Secret" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Create a New Secret" @@ -9427,8 +9427,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Create a New Secret" + "state" : "translated", + "value" : "建立新Secret" } } } @@ -9532,13 +9532,13 @@ "value" : "삭제하지 않기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Don't Delete" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Don't Delete" @@ -9612,8 +9612,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Don't Delete" + "state" : "translated", + "value" : "禁止刪除" } } } @@ -9717,13 +9717,13 @@ "value" : "삭제" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Delete" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Delete" @@ -9797,8 +9797,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Delete" + "state" : "translated", + "value" : "刪除" } } } @@ -9902,13 +9902,13 @@ "value" : "%1$(secretName)@를 삭제하면 복구할 수 없습니다. 확인하려면 “%2$(confirmSecretName)@”를 입력하세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If you delete %1$(secretName)@, you will not be able to recover it. Type “%2$(confirmSecretName)@” to confirm." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If you delete %1$(secretName)@, you will not be able to recover it. Type “%2$(confirmSecretName)@” to confirm." @@ -9977,13 +9977,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "如果您删除 %1$(secretName)@ ,您将没有任何方式恢复它。输入 “%2$(confirmSecretName)@” 以确认。" + "value" : "如果删除%1$(secretName)@,您将无法恢复它。输入 “%2$(confirmSecretName)@”以确认。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If you delete %1$(secretName)@, you will not be able to recover it. Type “%2$(confirmSecretName)@” to confirm." + "state" : "translated", + "value" : "如果刪除%1$(secretName)@,您將無法恢復它。輸入“%2$(confirmSecretName)@”以確認。" } } } @@ -10087,13 +10087,13 @@ "value" : "%1$(secretName)@를 지우겠습니까?" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Delete %1$(secretName)@?" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Delete %1$(secretName)@?" @@ -10162,13 +10162,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "删除 %1$(secretName)@ 吗?" + "value" : "删除“%1$(secretName)@”吗?" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Delete %1$(secretName)@?" + "state" : "translated", + "value" : "刪除「%1$(secretName)@」嗎?" } } } @@ -10272,13 +10272,13 @@ "value" : "취소" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Cancel" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Cancel" @@ -10352,8 +10352,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Cancel" + "state" : "translated", + "value" : "取消" } } } @@ -10457,13 +10457,13 @@ "value" : "이름 변경" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Save" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Save" @@ -10532,13 +10532,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名" + "value" : "保存" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Save" + "state" : "translated", + "value" : "儲存" } } } @@ -10642,13 +10642,13 @@ "value" : "여기를 클릭해서 새로운 비밀 만들기." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Create a new one by clicking here." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Create a new one by clicking here." @@ -10722,8 +10722,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Create a new one by clicking here." + "state" : "translated", + "value" : "點選這裡建立一個新的Secret。" } } } @@ -10827,13 +10827,13 @@ "value" : "비밀이 없음" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "No Secrets" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "No Secrets" @@ -10907,8 +10907,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "No Secrets" + "state" : "translated", + "value" : "沒有Secret" } } } @@ -11012,13 +11012,13 @@ "value" : "최근에 macOS를 업데이트하신 것 같습니다. 업데이트 후 Secure Enclave가 이상한 상태로 전환되는 경우가 있는데, Mac을 재부팅해야 다시 작동할 수 있습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "It looks like you may have recently updated macOS. Sometimes this puts the Secure Enclave into a weird state, and you might need to reboot your Mac before things start working again." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "It looks like you may have recently updated macOS. Sometimes this puts the Secure Enclave into a weird state, and you might need to reboot your Mac before things start working again." @@ -11086,14 +11086,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "It looks like you may have recently updated macOS. Sometimes this puts the Secure Enclave into a weird state, and you might need to reboot your Mac before things start working again." + "state" : "translated", + "value" : "看起来您最近可能更新了macOS。 有时这会使安全隔区状态异常,可能需要重启Mac才能恢复正常。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "It looks like you may have recently updated macOS. Sometimes this puts the Secure Enclave into a weird state, and you might need to reboot your Mac before things start working again." + "state" : "translated", + "value" : "看起來您最近可能更新了macOS。 有時這會使安全隔離區狀態異常,可能需要重啟Mac才能恢復正常。" } } } @@ -11197,13 +11197,13 @@ "value" : "Secret이 사라졌나요?" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Missing Secrets?" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Missing Secrets?" @@ -11271,14 +11271,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Missing Secrets?" + "state" : "translated", + "value" : "密钥串不见了?" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Missing Secrets?" + "state" : "translated", + "value" : "Secret不見了?" } } } @@ -11382,13 +11382,13 @@ "value" : "스마트 카드의 관리 도구를 사용하여 비밀을 생성하세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Use your Smart Card's management tool to create a secret." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Use your Smart Card's management tool to create a secret." @@ -11457,13 +11457,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用您的智能卡管理工具创建一个新的密钥串" + "value" : "使用您的智能卡管理工具创建一个新的密钥串。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Use your Smart Card's management tool to create a secret." + "state" : "translated", + "value" : "使用您的智慧卡管理工具建立一個新的Secret。" } } } @@ -11567,13 +11567,13 @@ "value" : "Secretive는 EC256, EC384, RSA1024 및 RSA2048 키를 지원합니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive supports EC256, EC384, and RSA2048 keys." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive supports EC256, EC384, and RSA2048 keys." @@ -11642,13 +11642,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Secretive 支持 EC256, EC384, RSA1024, 和RSA2048." + "value" : "Secretive支持EC256、EC384、RSA2048密钥。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive supports EC256, EC384, and RSA2048 keys." + "state" : "translated", + "value" : "Secretive支援EC256、EC384、RSA2048金鑰。" } } } @@ -11752,13 +11752,13 @@ "value" : "비밀이 없음" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "No Secrets" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "No Secrets" @@ -11832,8 +11832,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "No Secrets" + "state" : "translated", + "value" : "沒有Secret" } } } @@ -11930,13 +11930,13 @@ "value" : "export SSH_AUTH_SOCK=%@" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "export SSH_AUTH_SOCK=%@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "export SSH_AUTH_SOCK=%@" @@ -12109,13 +12109,13 @@ "value" : "Host *\n\tIdentityAgent %@" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Host *\n\tIdentityAgent %@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Host *\n\tIdentityAgent %@" @@ -12295,13 +12295,13 @@ "value" : "이것을 추가하세요:" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Add This:" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Add This:" @@ -12375,8 +12375,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Add This:" + "state" : "translated", + "value" : "新增這些內容:" } } } @@ -12480,13 +12480,13 @@ "value" : "앱들" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Apps" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Apps" @@ -12560,8 +12560,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Apps" + "state" : "translated", + "value" : "應用" } } } @@ -12665,13 +12665,13 @@ "value" : "GitHub에는 커뮤니티에서 관리하는 앱 관련 지침 목록이 있습니다. 찾고 있는 앱이 지원되지 않는 경우, 이슈를 생성하시면 커뮤니티에서 도움을 드릴 수 있습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "There's a community-maintained list of instructions for apps on GitHub. If the app you're looking for isn't supported, create an issue and the community may be able to help." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "There's a community-maintained list of instructions for apps on GitHub. If the app you're looking for isn't supported, create an issue and the community may be able to help." @@ -12740,13 +12740,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "GitHub 上有份由社区维护的清单介绍如何配置应用。若尚不支持你要找的应用,请创建一个 issue,社区或许能提供帮助。" + "value" : "GitHub上有份由社区维护的清单介绍如何配置应用。若尚不支持您要找的应用,请创建一个issue,社区或许能提供帮助。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "There's a community-maintained list of instructions for apps on GitHub. If the app you're looking for isn't supported, create an issue and the community may be able to help." + "state" : "translated", + "value" : "GitHub上有份由社群維護的清單介紹如何配置應用。若尚不支援您要找的應用,請建立一個issue,社群或許能提供幫助。" } } } @@ -12850,13 +12850,13 @@ "value" : "GitHub에는 커뮤니티에서 관리하는 셸 지침 목록이 있습니다. 찾고 있는 셸이 지원되지 않는 경우, 이슈를 생성하면 커뮤니티에서 도움을 드릴 수 있습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "There's a community-maintained list of shell instructions on GitHub. If the shell you're looking for isn't supported, create an issue and the community may be able to help." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "There's a community-maintained list of shell instructions on GitHub. If the shell you're looking for isn't supported, create an issue and the community may be able to help." @@ -12925,13 +12925,47 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "GitHub 上有份由社区维护的清单介绍如何配置 shell。若尚不支持你要找的 shell,请创建一个 issue,社区或许能提供帮助。" + "value" : "GitHub上有份由社区维护的清单介绍如何配置shell。若尚不支持您要找的shell,请创建一个issue,社区或许能提供帮助。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "There's a community-maintained list of shell instructions on GitHub. If the shell you're looking for isn't supported, create an issue and the community may be able to help." + "state" : "translated", + "value" : "GitHub上有份由社群維護的清單介紹如何配置shell。若尚不支援您要找的shell,請建立一個issue,社群或許能提供幫助。" + } + } + } + }, + "integrations_configure_using_email_placeholder" : { + "comment" : "Only “your_email” can be (optionally) localized. “example.com” should remain as-is.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "your_email@example.com" + } + } + } + }, + "integrations_configure_using_email_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The email address you set when you configured git (visible in gitconfig)." + } + } + } + }, + "integrations_configure_using_email_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email Address" } } } @@ -13035,13 +13069,13 @@ "value" : "이 작업을 구성하기 전에 Secret을 만들어야 합니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "You'll need to create a Secret before configuring this action." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "You'll need to create a Secret before configuring this action." @@ -13109,14 +13143,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "You'll need to create a Secret before configuring this action." + "state" : "translated", + "value" : "在配置此操作前,您需要先创建一个密钥串。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "You'll need to create a Secret before configuring this action." + "state" : "translated", + "value" : "在配置此操作前,您需要先建立一個Secret。" } } } @@ -13220,13 +13254,13 @@ "value" : "Secret을 사용하여 구성" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Configure Using Secret" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Configure Using Secret" @@ -13294,14 +13328,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Configure Using Secret" + "state" : "translated", + "value" : "用密钥串来配置" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Configure Using Secret" + "state" : "translated", + "value" : "用Secret來配置" } } } @@ -13405,13 +13439,13 @@ "value" : "비밀이 없음" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "No Secret" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "No Secret" @@ -13479,14 +13513,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "No Secret" + "state" : "translated", + "value" : "没有密钥串" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "No Secret" + "state" : "translated", + "value" : "沒有Secret" } } } @@ -13590,13 +13624,13 @@ "value" : "비밀" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secret" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secret" @@ -13664,13 +13698,13 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Secret" + "state" : "translated", + "value" : "密钥串" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", + "state" : "translated", "value" : "Secret" } } @@ -13775,13 +13809,13 @@ "value" : "여러 도구를 구성할 수 있으며, 일반적으로 서로 간섭하지 않습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "You can configure more than one tool, they generally won't interfere with each other." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "You can configure more than one tool, they generally won't interfere with each other." @@ -13849,14 +13883,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "You can configure more than one tool, they generally won't interfere with each other." + "state" : "translated", + "value" : "您可以配置多个工具,它们通常不会相互干扰。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "You can configure more than one tool, they generally won't interfere with each other." + "state" : "translated", + "value" : "您可以配置多個工具,它們通常不會相互干擾。" } } } @@ -13960,13 +13994,13 @@ "value" : "처음 시작하기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Getting Started" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Getting Started" @@ -14034,14 +14068,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Getting Started" + "state" : "translated", + "value" : "入门指南" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Getting Started" + "state" : "translated", + "value" : "入門指南" } } } @@ -14145,13 +14179,13 @@ "value" : "통합" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Integrations" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Integrations" @@ -14219,14 +14253,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Integrations" + "state" : "translated", + "value" : "第三方集成" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Integrations" + "state" : "translated", + "value" : "第三方整合" } } } @@ -14330,13 +14364,13 @@ "value" : "Git 커밋에 서명하려면 Git 서명을 설정하세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If you're trying to sign your git commits, set up Git Signing." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If you're trying to sign your git commits, set up Git Signing." @@ -14404,14 +14438,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "If you're trying to sign your git commits, set up Git Signing." + "state" : "translated", + "value" : "如果您打算签署git提交,请配置“Git签名”。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If you're trying to sign your git commits, set up Git Signing." + "state" : "translated", + "value" : "如果您打算簽署git提交,請配置「Git簽名」。" } } } @@ -14515,13 +14549,13 @@ "value" : "Secretive를 사용하기 위해 명령줄에서 실행되는 모든 것을 구성하려는 경우 셸을 구성하세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If you're trying to configure anything your command line runs to use Secretive, configure your shell." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If you're trying to configure anything your command line runs to use Secretive, configure your shell." @@ -14589,14 +14623,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "If you're trying to configure anything your command line runs to use Secretive, configure your shell." + "state" : "translated", + "value" : "如果您打算让命令行运行的任何命令使用Secretive,请配置“Shell”。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If you're trying to configure anything your command line runs to use Secretive, configure your shell." + "state" : "translated", + "value" : "如果您打算讓命令列執行的任何命令使用Secretive,請配置「Shell」。" } } } @@ -14700,13 +14734,13 @@ "value" : "어떤 셸을 사용하는지 모르고 변경하지 않은 경우, 아마도 `%(shellName)@`를 사용하고 있을 것입니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If you don't known what shell you use and haven't changed it, you're probably using `%(shellName)@`." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If you don't known what shell you use and haven't changed it, you're probably using `%(shellName)@`." @@ -14774,14 +14808,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "If you don't known what shell you use and haven't changed it, you're probably using `%(shellName)@`." + "state" : "translated", + "value" : "如果您不知道自己在用哪个shell且未曾更改它,您大概在用`%(shellName)@`。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If you don't known what shell you use and haven't changed it, you're probably using `%(shellName)@`." + "state" : "translated", + "value" : "如果您不知道自己在用哪個shell且未曾更改它,您大概在用`%(shellName)@`。" } } } @@ -14885,13 +14919,13 @@ "value" : "SSH 서버로 인증하거나 SSH를 통해 GitHub와 같은 서비스로 인증하려는 경우 SSH 클라이언트를 구성하세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If you're trying to authenticate with an SSH server or authenticating with a service like GitHub over SSH, configure your SSH client." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If you're trying to authenticate with an SSH server or authenticating with a service like GitHub over SSH, configure your SSH client." @@ -14959,14 +14993,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "If you're trying to authenticate with an SSH server or authenticating with a service like GitHub over SSH, configure your SSH client." + "state" : "translated", + "value" : "如果您打算为SSH服务器配置身份认证或通过SSH与GitHub之类的服务认证身份,请配置SSH客户端。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If you're trying to authenticate with an SSH server or authenticating with a service like GitHub over SSH, configure your SSH client." + "state" : "translated", + "value" : "如果您打算為SSH伺服器配置身份認證或透過SSH與GitHub之類的服務認證身份,請配置SSH客戶端。" } } } @@ -15070,13 +15104,13 @@ "value" : "Secretive를 위한 도구 구성" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Configuring Tools for Secretive" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Configuring Tools for Secretive" @@ -15144,14 +15178,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Configuring Tools for Secretive" + "state" : "translated", + "value" : "为Secretive配置工具" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Configuring Tools for Secretive" + "state" : "translated", + "value" : "為Secretive配置工具" } } } @@ -15255,13 +15289,13 @@ "value" : "대부분의 도구는 디스크의 `~/.ssh`에서 SSH 키를 찾으려고 합니다. Secretive를 사용하려면 해당 도구가 Secretive와 통신하도록 설정해야 합니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Most tools will try and look for SSH keys on disk in `~/.ssh`. To use Secretive, we need to configure those tools to talk to Secretive instead." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Most tools will try and look for SSH keys on disk in `~/.ssh`. To use Secretive, we need to configure those tools to talk to Secretive instead." @@ -15330,13 +15364,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "多数工具会在 `~/.ssh` 中尝试并查找磁盘上的 SSH 密钥。要使用 Secretive,我们需要配置这些工具来与 Secretive 通信。" + "value" : "多数工具会尝试在`~/.ssh`中查找磁盘上的SSH密钥。要使用Secretive,我们需要配置这些工具来与Secretive通信。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Most tools will try and look for SSH keys on disk in `~/.ssh`. To use Secretive, we need to configure those tools to talk to Secretive instead." + "state" : "translated", + "value" : "多數工具會嘗試在`~/.ssh`中查詢磁碟上的SSH金鑰。要使用Secretive,我們需要配置這些工具來與Secretive通訊。" } } } @@ -15440,13 +15474,13 @@ "value" : "무엇을 구성해야 할까요?" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "What Should I Configure?" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "What Should I Configure?" @@ -15520,8 +15554,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "What Should I Configure?" + "state" : "translated", + "value" : "我應該配置什麼?" } } } @@ -15625,13 +15659,13 @@ "value" : "~/.gitallowedsigners가 존재하지 않을 수 있습니다. 직접 만들어야 합니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "~/.gitallowedsigners probably does not exist. You'll need to create it." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "~/.gitallowedsigners probably does not exist. You'll need to create it." @@ -15700,13 +15734,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "~/.gitallowedsigners 可能不存在。你需要创建它。" + "value" : "~/.gitallowedsigners 可能不存在。您需要创建它。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "~/.gitallowedsigners probably does not exist. You'll need to create it." + "state" : "translated", + "value" : "~/.gitallowedsigners 可能不存在。您需要建立它。" } } } @@ -15810,13 +15844,13 @@ "value" : "[user]\n signingkey = %1$(publicKeyPathPlaceholder)@\n[commit]\n gpgsign = true\n[gpg]\n format = ssh\n[gpg \"ssh\"]\n allowedSignersFile = ~/.gitallowedsigners" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "[user]\n signingkey = %1$(publicKeyPathPlaceholder)@\n[commit]\n gpgsign = true\n[gpg]\n format = ssh\n[gpg \"ssh\"]\n allowedSignersFile = ~/.gitallowedsigners" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "[user]\n signingkey = %1$(publicKeyPathPlaceholder)@\n[commit]\n gpgsign = true\n[gpg]\n format = ssh\n[gpg \"ssh\"]\n allowedSignersFile = ~/.gitallowedsigners" @@ -15996,13 +16030,13 @@ "value" : "통합…" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Integrations…" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Integrations…" @@ -16076,8 +16110,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Integrations…" + "state" : "translated", + "value" : "第三方整合…" } } } @@ -16181,13 +16215,13 @@ "value" : "기타" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Other" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Other" @@ -16261,8 +16295,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Other" + "state" : "translated", + "value" : "其他" } } } @@ -16366,13 +16400,13 @@ "value" : "이외의 셸" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "other" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "other" @@ -16446,8 +16480,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "other" + "state" : "translated", + "value" : "其他" } } } @@ -16551,13 +16585,13 @@ "value" : "설정 파일" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Configuration File" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Configuration File" @@ -16631,8 +16665,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Configuration File" + "state" : "translated", + "value" : "配置檔案" } } } @@ -16736,13 +16770,13 @@ "value" : "Shell" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Shell" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Shell" @@ -16816,7 +16850,7 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", + "state" : "translated", "value" : "Shell" } } @@ -16921,13 +16955,13 @@ "value" : "SSH가 특정 호스트에 대해 특정 키를 사용하도록 설정할 수 있습니다. 자세한 내용은 웹 문서를 참조하세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "You can tell SSH to use a specific key for a given host. See the web documentation for more details." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "You can tell SSH to use a specific key for a given host. See the web documentation for more details." @@ -16996,13 +17030,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "你可以让 SSH 为指定的主机使用特定密钥。详情请参阅在线文档。" + "value" : "您可以让SSH为指定的主机使用特定密钥。详情请参阅在线文档。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "You can tell SSH to use a specific key for a given host. See the web documentation for more details." + "state" : "translated", + "value" : "您可以讓SSH為指定的主機使用特定金鑰。詳情請參閱線上手冊。" } } } @@ -17106,13 +17140,13 @@ "value" : "시스템" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "System" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "System" @@ -17186,8 +17220,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "System" + "state" : "translated", + "value" : "系統" } } } @@ -17291,13 +17325,13 @@ "value" : "bash" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "bash" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "bash" @@ -17477,13 +17511,13 @@ "value" : "fish" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "fish" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "fish" @@ -17663,13 +17697,13 @@ "value" : "Git 서명" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Git Signing" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Git Signing" @@ -17738,13 +17772,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Git 签名" + "value" : "Git签名" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Git Signing" + "state" : "translated", + "value" : "Git簽名" } } } @@ -17848,13 +17882,13 @@ "value" : "SSH" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "SSH" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "SSH" @@ -18034,13 +18068,13 @@ "value" : "zsh" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "zsh" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "zsh" @@ -18220,13 +18254,13 @@ "value" : "GitHub에서 보기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "View on GitHub" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "View on GitHub" @@ -18295,13 +18329,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在 GitHub 上查看" + "value" : "在GitHub上查看" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "View on GitHub" + "state" : "translated", + "value" : "在GitHub上檢視" } } } @@ -18405,13 +18439,13 @@ "value" : "웹에서 문서 보기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "View Documentation on Web" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "View Documentation on Web" @@ -18485,8 +18519,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "View Documentation on Web" + "state" : "translated", + "value" : "檢視線上手冊" } } } @@ -18590,13 +18624,13 @@ "value" : "섹션(예: [user])이 이미 있는 경우 기존 섹션에 항목을 추가하기만 하면 됩니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If any section (like [user]) already exists, just add the entries in the existing section." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If any section (like [user]) already exists, just add the entries in the existing section." @@ -18670,8 +18704,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If any section (like [user]) already exists, just add the entries in the existing section." + "state" : "translated", + "value" : "如果某小節(比如 [user])已存在,只需在現有小節中新增條目。" } } } @@ -18775,13 +18809,13 @@ "value" : "Mac에 Secure Enclave가 없고 호환되는 스마트 카드가 삽입되어 있지 않습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Your Mac doesn't have a Secure Enclave, and there's not a compatible Smart Card inserted." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Your Mac doesn't have a Secure Enclave, and there's not a compatible Smart Card inserted." @@ -18850,13 +18884,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "您的Mac 没有安全隔区,同时也没有插入兼容的智能卡。" + "value" : "您的Mac没有安全隔区,也没有插入兼容的智能卡。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Your Mac doesn't have a Secure Enclave, and there's not a compatible Smart Card inserted." + "state" : "translated", + "value" : "您的Mac沒有安全隔離區,也沒有插入相容的智慧卡。" } } } @@ -18960,13 +18994,13 @@ "value" : "보안 저장소를 사용할 수 없음" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "No Secure Storage Available" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "No Secure Storage Available" @@ -19035,13 +19069,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "没有可用的密钥存储区" + "value" : "没有可用的安全存储区" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "No Secure Storage Available" + "state" : "translated", + "value" : "沒有可用的安全儲存區" } } } @@ -19145,13 +19179,13 @@ "value" : "Mac에 하나를 추가하고 싶다면 YubiKey 5 시리즈가 좋습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "If you're looking to add one to your Mac, the YubiKey 5 Series are great." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "If you're looking to add one to your Mac, the YubiKey 5 Series are great." @@ -19220,13 +19254,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "如果您想为您的Mac添加一个物理密钥, YubiKey 5 系列是一个不错的选择。" + "value" : "如果您想为Mac添加一个智能卡, YubiKey 5系列是个不错的选择。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "If you're looking to add one to your Mac, the YubiKey 5 Series are great." + "state" : "translated", + "value" : "如果您想為Mac新增一個智慧卡,YubiKey 5系列是個不錯的選擇。" } } } @@ -19331,13 +19365,13 @@ "value" : "잠금 해제 상태로 유지" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Leave Unlocked" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Leave Unlocked" @@ -19411,8 +19445,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Leave Unlocked" + "state" : "translated", + "value" : "保持解鎖" } } } @@ -19517,13 +19551,13 @@ "value" : "잠금 해제하지 않음" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Do Not Unlock" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Do Not Unlock" @@ -19597,8 +19631,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Do Not Unlock" + "state" : "translated", + "value" : "不要解鎖" } } } @@ -19702,13 +19736,13 @@ "value" : "Finder에서 보기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Reveal in Finder" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Reveal in Finder" @@ -19777,13 +19811,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在“访达”中查看" + "value" : "在访达中查看" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Reveal in Finder" + "state" : "translated", + "value" : "在Finder中檢視" } } } @@ -19887,13 +19921,13 @@ "value" : "MD5 지문" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "MD5 Fingerprint" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "MD5 Fingerprint" @@ -19962,13 +19996,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "MD5 指纹" + "value" : "MD5指纹" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "MD5 Fingerprint" + "state" : "translated", + "value" : "MD5指紋" } } } @@ -20072,13 +20106,13 @@ "value" : "공개 키" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Public Key" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Public Key" @@ -20152,8 +20186,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Public Key" + "state" : "translated", + "value" : "公鑰" } } } @@ -20257,13 +20291,13 @@ "value" : "공개 키 경로" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Public Key Path" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Public Key Path" @@ -20337,8 +20371,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Public Key Path" + "state" : "translated", + "value" : "公鑰路徑" } } } @@ -20442,13 +20476,13 @@ "value" : "SHA256 지문" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "SHA256 Fingerprint" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "SHA256 Fingerprint" @@ -20517,13 +20551,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "SHA256 指纹" + "value" : "SHA256指纹" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "SHA256 Fingerprint" + "state" : "translated", + "value" : "SHA256指紋" } } } @@ -20627,13 +20661,13 @@ "value" : "삭제" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Delete" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Delete" @@ -20707,8 +20741,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Delete" + "state" : "translated", + "value" : "刪除" } } } @@ -20812,13 +20846,13 @@ "value" : "이름 변경" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Edit" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Edit" @@ -20887,13 +20921,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名" + "value" : "编辑" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Edit" + "state" : "translated", + "value" : "編輯" } } } @@ -20997,13 +21031,13 @@ "value" : "Secure Enclave" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secure Enclave" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secure Enclave" @@ -21077,8 +21111,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secure Enclave" + "state" : "translated", + "value" : "安全隔離區" } } } @@ -21175,13 +21209,13 @@ "value" : "set -x SSH_AUTH_SOCK %@" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "set -x SSH_AUTH_SOCK %@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "set -x SSH_AUTH_SOCK %@" @@ -21361,13 +21395,13 @@ "value" : "이 도우미 앱은 **Secret Agent**이라고 하며 활성 상태 보기에서 수시로 볼 수 있습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "This helper app is called **Secret Agent** and you may see it in Activity Manager from time to time." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "This helper app is called **Secret Agent** and you may see it in Activity Manager from time to time." @@ -21436,13 +21470,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "帮助文件叫做 *Secret Agent*, 之后您会经常在活动监视器中看见它。" + "value" : "这个辅助程序叫做**Secret Agent**, 之后您会时不时在活动监视器中看见它。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "This helper app is called **Secret Agent** and you may see it in Activity Manager from time to time." + "state" : "translated", + "value" : "這個輔助程式叫做**Secret Agent**,之後您會時不時在活動監視器中看見它。" } } } @@ -21546,13 +21580,13 @@ "value" : "Secretive가 제대로 작동하려면 도우미 앱을 설치해야 합니다. 백그라운드에서 SSH 클라이언트의 요청에 서명하므로 기본 Secretive 앱을 열어 둘 필요가 없습니다." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive needs to set up a helper app to work properly. It will sign requests from SSH clients in the background, so you don't need to keep the main Secretive app open." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive needs to set up a helper app to work properly. It will sign requests from SSH clients in the background, so you don't need to keep the main Secretive app open." @@ -21621,13 +21655,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Secretive 需要帮助文件来正常工作。 它会在后台识别SSH 请求, 这样您就不需要在前台一直保持Secretive 开启了。" + "value" : "Secretive需要设置一个辅助程序才能正常工作。它会在后台处理SSH客户端的签名请求,这样您就不需要在前台一直保持Secretive开启了。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive needs to set up a helper app to work properly. It will sign requests from SSH clients in the background, so you don't need to keep the main Secretive app open." + "state" : "translated", + "value" : "Secretive需要設定一個輔助程式才能正常工作。它會在後台處理SSH客戶端的簽名請求,這樣您就不需要在前臺一直保持Secretive開啟了。" } } } @@ -21731,13 +21765,13 @@ "value" : "설치" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Install" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Install" @@ -21811,8 +21845,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Install" + "state" : "translated", + "value" : "安裝" } } } @@ -21916,13 +21950,13 @@ "value" : "Agent 설치" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Setup Agent" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Setup Agent" @@ -21991,13 +22025,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "设置" + "value" : "设置Agent" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Setup Agent" + "state" : "translated", + "value" : "設定Agent" } } } @@ -22101,13 +22135,13 @@ "value" : "완료" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Done" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Done" @@ -22181,8 +22215,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Done" + "state" : "translated", + "value" : "完成" } } } @@ -22286,13 +22320,13 @@ "value" : "설정" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Configure" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Configure" @@ -22366,8 +22400,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Configure" + "state" : "translated", + "value" : "配置" } } } @@ -22471,13 +22505,13 @@ "value" : "Secretive와 대화하는 방법을 사용하는 도구를 알려주세요." } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Tell the tools you use how to talk to Secretive." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Tell the tools you use how to talk to Secretive." @@ -22546,13 +22580,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "让你用的工具知晓如何与 Secretive 通信。" + "value" : "让您用的工具知道如何与Secretive通信。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Tell the tools you use how to talk to Secretive." + "state" : "translated", + "value" : "讓您用的工具知道如何與Secretive通訊。" } } } @@ -22656,13 +22690,13 @@ "value" : "통합 설정" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Configure Integrations" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Configure Integrations" @@ -22736,8 +22770,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Configure Integrations" + "state" : "translated", + "value" : "配置第三方整合" } } } @@ -22841,13 +22875,13 @@ "value" : "Secretive는 주기적으로 GitHub를 확인하여 새 릴리스가 있는지 확인합니다. GitHub에 대한 네트워크 요청이 표시되는 이유입니다. " } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive will periodically check with GitHub to see if there's a new release. If you see any network requests to GitHub, that's why." } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive will periodically check with GitHub to see if there's a new release. If you see any network requests to GitHub, that's why." @@ -22916,13 +22950,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Secretive 需要使用GitHub 检查更新。这就是为什么您会看见来自GitHub 的网络流量。" + "value" : "Secretive会定期访问GitHub来检查更新。这就是为什么您会看见发往GitHub的网络请求。" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Secretive will periodically check with GitHub to see if there's a new release. If you see any network requests to GitHub, that's why." + "state" : "translated", + "value" : "Secretive會定期訪問GitHub來檢查更新。這就是為什麼您會看見發往GitHub的網路請求。" } } } @@ -23026,13 +23060,13 @@ "value" : "확인" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "OK" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "OK" @@ -23100,14 +23134,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "OK" + "state" : "translated", + "value" : "好的" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "OK" + "state" : "translated", + "value" : "好的" } } } @@ -23211,13 +23245,13 @@ "value" : "업데이트" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Updates" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Updates" @@ -23291,8 +23325,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Updates" + "state" : "translated", + "value" : "更新" } } } @@ -23396,13 +23430,13 @@ "value" : "완료됨" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Done" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Done" @@ -23470,14 +23504,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Done" + "state" : "translated", + "value" : "已完成" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Done" + "state" : "translated", + "value" : "已完成" } } } @@ -23582,13 +23616,13 @@ "value" : "비밀 %1$(secretName)@ 사용됨" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Using secret %1$(secretName)@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Using secret %1$(secretName)@" @@ -23662,8 +23696,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Using secret %1$(secretName)@" + "state" : "translated", + "value" : "使用Secret「%1$(secretName)@」" } } } @@ -23768,13 +23802,13 @@ "value" : "%1$(appName)@에서 서명 요청" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Signed Request from %1$(appName)@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Signed Request from %1$(appName)@" @@ -23843,13 +23877,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "已认证来自 %1$(appName)@ 的请求" + "value" : "已认证来自“%1$(appName)@”的请求" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Signed Request from %1$(appName)@" + "state" : "translated", + "value" : "已認證來自「%1$(appName)@」的請求" } } } @@ -23953,13 +23987,13 @@ "value" : "스마트 카드" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Smart Card" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Smart Card" @@ -24033,8 +24067,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Smart Card" + "state" : "translated", + "value" : "智慧卡" } } } @@ -24138,13 +24172,13 @@ "value" : "무명" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Unnamed" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Unnamed" @@ -24218,8 +24252,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Unnamed" + "state" : "translated", + "value" : "未命名" } } } @@ -24323,13 +24357,13 @@ "value" : "치명적 보안 업데이트 필요" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Critical Security Update Required" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Critical Security Update Required" @@ -24403,8 +24437,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Critical Security Update Required" + "state" : "translated", + "value" : "需要重要安全更新" } } } @@ -24508,13 +24542,13 @@ "value" : "무시하기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Ignore" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Ignore" @@ -24588,8 +24622,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Ignore" + "state" : "translated", + "value" : "忽略" } } } @@ -24693,13 +24727,13 @@ "value" : "사용가능한 업데이트" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Update Available" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Update Available" @@ -24768,13 +24802,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "更新可用" + "value" : "有可用更新" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Update Available" + "state" : "translated", + "value" : "有可用更新" } } } @@ -24879,13 +24913,13 @@ "value" : "무시" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Ignore" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Ignore" @@ -24959,8 +24993,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Ignore" + "state" : "translated", + "value" : "忽略" } } } @@ -25065,13 +25099,13 @@ "value" : "업데이트" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Update" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Update" @@ -25145,8 +25179,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Update" + "state" : "translated", + "value" : "更新" } } } @@ -25251,13 +25285,13 @@ "value" : "치명적 보안 업데이트 - %1$(updateName)@" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Critical Security Update - %1$(updateName)@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Critical Security Update - %1$(updateName)@" @@ -25331,8 +25365,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Critical Security Update - %1$(updateName)@" + "state" : "translated", + "value" : "重要安全更新 - %1$(updateName)@" } } } @@ -25437,13 +25471,13 @@ "value" : "클릭해서 업데이트 하기" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Click to Update" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Click to Update" @@ -25517,8 +25551,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Click to Update" + "state" : "translated", + "value" : "點選以更新" } } } @@ -25623,13 +25657,13 @@ "value" : "사용 가능한 업데이트 - %1$(updateName)@" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Update Available - %1$(updateName)@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Update Available - %1$(updateName)@" @@ -25698,13 +25732,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "更新可用 - %1$(updateName)@" + "value" : "有可用更新 - %1$(updateName)@" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Update Available - %1$(updateName)@" + "state" : "translated", + "value" : "有可用更新 - %1$(updateName)@" } } } @@ -25808,13 +25842,13 @@ "value" : "릴리즈 노트" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Release Notes" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Release Notes" @@ -25888,8 +25922,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Release Notes" + "state" : "translated", + "value" : "發行說明" } } } @@ -25993,13 +26027,13 @@ "value" : "테스트 빌드" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Test Build" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Test Build" @@ -26073,8 +26107,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Test Build" + "state" : "translated", + "value" : "測試版本" } } } @@ -26178,13 +26212,13 @@ "value" : "업데이트" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Update" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Update" @@ -26258,8 +26292,8 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Update" + "state" : "translated", + "value" : "更新" } } } @@ -26363,13 +26397,13 @@ "value" : "Secretive %1$(updateName)@" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Secretive %1$(updateName)@" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Secretive %1$(updateName)@" @@ -26437,13 +26471,13 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", + "state" : "translated", "value" : "Secretive %1$(updateName)@" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", + "state" : "translated", "value" : "Secretive %1$(updateName)@" } } @@ -26548,13 +26582,13 @@ "value" : "최신 Nightly Build 다운로드" } }, - "nl" : { + "nb" : { "stringUnit" : { "state" : "new", "value" : "Download Latest Nightly Build" } }, - "no" : { + "nl" : { "stringUnit" : { "state" : "new", "value" : "Download Latest Nightly Build" @@ -26622,14 +26656,14 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Download Latest Nightly Build" + "state" : "translated", + "value" : "下载最新的每日构建版本" } }, "zh-Hant" : { "stringUnit" : { - "state" : "new", - "value" : "Download Latest Nightly Build" + "state" : "translated", + "value" : "下載最新的每日構建版本" } } } diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift index fbd739e..83ce175 100644 --- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift +++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift @@ -47,6 +47,7 @@ extension Agent { logger.debug("Agent returned \(SSHAgent.Response.agentSignResponse.debugDescription)") case .unknown(let value): logger.error("Agent received unknown request of type \(value).") + throw UnhandledRequestError() default: logger.debug("Agent received valid request of type \(request.debugDescription), but not currently supported.") throw UnhandledRequestError() diff --git a/Sources/Secretive.xcodeproj/project.pbxproj b/Sources/Secretive.xcodeproj/project.pbxproj index 44f5ca0..89cb503 100644 --- a/Sources/Secretive.xcodeproj/project.pbxproj +++ b/Sources/Secretive.xcodeproj/project.pbxproj @@ -32,7 +32,6 @@ 504788F62E68206F00B4556F /* GettingStartedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788F52E68206F00B4556F /* GettingStartedView.swift */; }; 504789232E697DD300B4556F /* BoxBackgroundStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504789222E697DD300B4556F /* BoxBackgroundStyle.swift */; }; 50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; }; - 50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; }; 50617D8323FCE48E0099B055 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* App.swift */; }; 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; }; 50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8923FCE48E0099B055 /* Preview Assets.xcassets */; }; @@ -194,7 +193,6 @@ 504788F52E68206F00B4556F /* GettingStartedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GettingStartedView.swift; sourceTree = ""; }; 504789222E697DD300B4556F /* BoxBackgroundStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxBackgroundStyle.swift; sourceTree = ""; }; 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustUpdatedChecker.swift; sourceTree = ""; }; - 50571E0424393D1500F76F6C /* LaunchAgentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAgentController.swift; sourceTree = ""; }; 5059933F2E7A3B5B0092CFFA /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/Main.storyboard; sourceTree = ""; }; 50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50617D8223FCE48E0099B055 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; @@ -448,7 +446,6 @@ 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */, 5091D2BB25183B830049FD9B /* ApplicationDirectoryController.swift */, 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */, - 50571E0424393D1500F76F6C /* LaunchAgentController.swift */, ); path = Controllers; sourceTree = ""; @@ -707,7 +704,6 @@ 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */, 50AE97002E5C1A420018C710 /* IntegrationsView.swift in Sources */, 50153E20250AFCB200525160 /* UpdateView.swift in Sources */, - 50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */, 5066A6C82516FE6E004B5A36 /* CopyableView.swift in Sources */, 50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */, 50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */, diff --git a/Sources/Secretive/App.swift b/Sources/Secretive/App.swift index 4c3dff1..ea2f156 100644 --- a/Sources/Secretive/App.swift +++ b/Sources/Secretive/App.swift @@ -7,7 +7,7 @@ import Brief @main struct Secretive: App { - @Environment(\.agentStatusChecker) var agentStatusChecker + @Environment(\.agentLaunchController) var agentLaunchController @Environment(\.justUpdatedChecker) var justUpdatedChecker @SceneBuilder var body: some Scene { @@ -15,14 +15,16 @@ struct Secretive: App { ContentView() .environment(EnvironmentValues._secretStoreList) .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in - @AppStorage("defaultsHasRunSetup") var hasRunSetup = false - guard hasRunSetup else { return } - agentStatusChecker.check() - if agentStatusChecker.running && justUpdatedChecker.justUpdatedBuild { - // Relaunch the agent, since it'll be running from earlier update still - reinstallAgent() - } else if !agentStatusChecker.running && !agentStatusChecker.developmentBuild { - forceLaunchAgent() + Task { + @AppStorage("defaultsHasRunSetup") var hasRunSetup = false + @AppStorage("explicitlyDisabled") var explicitlyDisabled = false + guard hasRunSetup && !explicitlyDisabled else { return } + agentLaunchController.check() + guard !agentLaunchController.developmentBuild else { return } + if justUpdatedChecker.justUpdatedBuild || !agentLaunchController.running { + // Relaunch the agent, since it'll be running from earlier update still + try await agentLaunchController.forceLaunch() + } } } } @@ -79,30 +81,6 @@ extension Secretive { } -extension Secretive { - - private func reinstallAgent() { - Task { - _ = await LaunchAgentController().install() - try? await Task.sleep(for: .seconds(1)) - agentStatusChecker.check() - if !agentStatusChecker.running { - forceLaunchAgent() - } - } - } - - private func forceLaunchAgent() { - // We've run setup, we didn't just update, launchd is just not doing it's thing. - // Force a launch directly. - Task { - _ = await LaunchAgentController().forceLaunch() - agentStatusChecker.check() - } - } - -} - private enum Constants { static let helpURL = URL(string: "https://github.com/maxgoedjen/secretive/blob/main/FAQ.md")! } @@ -121,8 +99,8 @@ extension EnvironmentValues { return list }() - private static let _agentStatusChecker = AgentStatusChecker() - @Entry var agentStatusChecker: any AgentStatusCheckerProtocol = _agentStatusChecker + private static let _agentLaunchController = AgentLaunchController() + @Entry var agentLaunchController: any AgentLaunchControllerProtocol = _agentLaunchController private static let _updater: any UpdaterProtocol = { @AppStorage("defaultsHasRunSetup") var hasRunSetup = false return Updater(checkOnLaunch: hasRunSetup) diff --git a/Sources/Secretive/Controllers/AgentStatusChecker.swift b/Sources/Secretive/Controllers/AgentStatusChecker.swift index b7327a6..4cb4620 100644 --- a/Sources/Secretive/Controllers/AgentStatusChecker.swift +++ b/Sources/Secretive/Controllers/AgentStatusChecker.swift @@ -2,18 +2,25 @@ import Foundation import AppKit import SecretKit import Observation +import OSLog +import ServiceManagement -@MainActor protocol AgentStatusCheckerProtocol: Observable, Sendable { +@MainActor protocol AgentLaunchControllerProtocol: Observable, Sendable { var running: Bool { get } var developmentBuild: Bool { get } var process: NSRunningApplication? { get } func check() + func install() async throws + func uninstall() async throws + func forceLaunch() async throws } -@Observable @MainActor final class AgentStatusChecker: AgentStatusCheckerProtocol { +@Observable @MainActor final class AgentLaunchController: AgentLaunchControllerProtocol { var running: Bool = false var process: NSRunningApplication? = nil + private let logger = Logger(subsystem: "com.maxgoedjen.secretive", category: "LaunchAgentController") + private let service = SMAppService.loginItem(identifier: Bundle.agentBundleID) nonisolated init() { Task { @MainActor in @@ -33,7 +40,7 @@ import Observation // The process corresponding to this instance of Secretive var instanceSecretAgentProcess: NSRunningApplication? { - // FIXME: CHECK VERSION + // TODO: CHECK VERSION let agents = allSecretAgentProcesses for agent in agents { guard let url = agent.bundleURL else { continue } @@ -49,6 +56,47 @@ import Observation Bundle.main.bundleURL.isXcodeURL } + func install() async throws { + logger.debug("Installing agent") + try? await service.unregister() + // This is definitely a bit of a "seems to work better" thing but: + // Seems to more reliably hit if these are on separate runloops, otherwise it seems like it sometimes doesn't kill old + // and start new? + try await Task.sleep(for: .seconds(1)) + try service.register() + try await Task.sleep(for: .seconds(1)) + check() + } + + func uninstall() async throws { + logger.debug("Uninstalling agent") + try await Task.sleep(for: .seconds(1)) + try await service.unregister() + try await Task.sleep(for: .seconds(1)) + check() + } + + func forceLaunch() async throws { + logger.debug("Agent is not running, attempting to force launch by reinstalling") + try await install() + if running { + logger.debug("Agent successfully force launched by reinstalling") + return + } + logger.debug("Agent is not running, attempting to force launch by launching directly") + let url = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LoginItems/SecretAgent.app") + let config = NSWorkspace.OpenConfiguration() + config.activates = false + do { + try await NSWorkspace.shared.openApplication(at: url, configuration: config) + logger.debug("Agent force launched") + try await Task.sleep(for: .seconds(1)) + } catch { + logger.error("Error force launching \(error.localizedDescription)") + } + check() + } + } extension URL { diff --git a/Sources/Secretive/Controllers/LaunchAgentController.swift b/Sources/Secretive/Controllers/LaunchAgentController.swift deleted file mode 100644 index 308c381..0000000 --- a/Sources/Secretive/Controllers/LaunchAgentController.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Foundation -import ServiceManagement -import AppKit -import OSLog -import SecretKit - -struct LaunchAgentController { - - private let logger = Logger(subsystem: "com.maxgoedjen.secretive", category: "LaunchAgentController") - - func install() async -> Bool { - logger.debug("Installing agent") - _ = setEnabled(false) - // This is definitely a bit of a "seems to work better" thing but: - // Seems to more reliably hit if these are on separate runloops, otherwise it seems like it sometimes doesn't kill old - // and start new? - try? await Task.sleep(for: .seconds(1)) - let result = await MainActor.run { - setEnabled(true) - } - try? await Task.sleep(for: .seconds(1)) - return result - } - - func uninstall() async -> Bool { - logger.debug("Uninstalling agent") - try? await Task.sleep(for: .seconds(1)) - let result = await MainActor.run { - setEnabled(false) - } - try? await Task.sleep(for: .seconds(1)) - return result - } - - func forceLaunch() async -> Bool { - logger.debug("Agent is not running, attempting to force launch") - let url = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LoginItems/SecretAgent.app") - let config = NSWorkspace.OpenConfiguration() - config.activates = false - do { - try await NSWorkspace.shared.openApplication(at: url, configuration: config) - logger.debug("Agent force launched") - try? await Task.sleep(for: .seconds(1)) - return true - } catch { - logger.error("Error force launching \(error.localizedDescription)") - return false - } - } - - private func setEnabled(_ enabled: Bool) -> Bool { - let service = SMAppService.loginItem(identifier: Bundle.agentBundleID) - do { - if enabled { - try service.register() - } else { - try service.unregister() - } - return true - } catch { - return false - } - } - -} diff --git a/Sources/Secretive/Preview Content/PreviewAgentStatusChecker.swift b/Sources/Secretive/Preview Content/PreviewAgentStatusChecker.swift index e9799e9..97df864 100644 --- a/Sources/Secretive/Preview Content/PreviewAgentStatusChecker.swift +++ b/Sources/Secretive/Preview Content/PreviewAgentStatusChecker.swift @@ -1,7 +1,7 @@ import Foundation import AppKit -class PreviewAgentStatusChecker: AgentStatusCheckerProtocol { +class PreviewAgentLaunchController: AgentLaunchControllerProtocol { let running: Bool let process: NSRunningApplication? @@ -15,4 +15,13 @@ class PreviewAgentStatusChecker: AgentStatusCheckerProtocol { func check() { } + func install() async throws { + } + + func uninstall() async throws { + } + + func forceLaunch() async throws { + } + } diff --git a/Sources/Secretive/Views/Configuration/SetupView.swift b/Sources/Secretive/Views/Configuration/SetupView.swift index df55855..7616b56 100644 --- a/Sources/Secretive/Views/Configuration/SetupView.swift +++ b/Sources/Secretive/Views/Configuration/SetupView.swift @@ -3,6 +3,7 @@ import SwiftUI struct SetupView: View { @Environment(\.dismiss) private var dismiss + @Environment(\.agentLaunchController) private var agentLaunchController @Binding var setupComplete: Bool @State var showingIntegrations = false @@ -31,7 +32,7 @@ struct SetupView: View { ) { installed = true Task { - await LaunchAgentController().install() + try? await agentLaunchController.install() } } } diff --git a/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift b/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift index d23679a..8696e06 100644 --- a/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift +++ b/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift @@ -10,6 +10,7 @@ struct ToolConfigurationView: View { @State var creating = false @State var selectedSecret: AnySecret? + @State var email = "" init(selectedInstruction: ConfigurationFileInstructions) { self.selectedInstruction = selectedInstruction @@ -48,6 +49,12 @@ struct ToolConfigurationView: View { .tag(secret) } } + TextField(text: $email, prompt: Text(.integrationsConfigureUsingEmailPlaceholder)) { + Text(.integrationsConfigureUsingEmailTitle) + Text(.integrationsConfigureUsingEmailSubtitle) + .font(.subheadline) + .foregroundStyle(.secondary) + } } header: { Text(.integrationsConfigureUsingSecretHeader) } @@ -60,7 +67,7 @@ struct ToolConfigurationView: View { Section { ConfigurationItemView(title: .integrationsPathTitle, value: stepGroup.path, action: .revealInFinder(stepGroup.path)) ForEach(stepGroup.steps, id: \.self.key) { step in - ConfigurationItemView(title: .integrationsAddThisTitle, action: .copy(String(localized: step))) { + ConfigurationItemView(title: .integrationsAddThisTitle, action: .copy(placeholdersReplaced(text: String(localized: step)))) { HStack { Text(placeholdersReplaced(text: String(localized: step))) .padding(8) @@ -102,9 +109,11 @@ struct ToolConfigurationView: View { func placeholdersReplaced(text: String) -> String { guard let selectedSecret else { return text } let writer = OpenSSHPublicKeyWriter() + let gitAllowedSignersString = [email.isEmpty ? String(localized: .integrationsConfigureUsingEmailPlaceholder) : email, writer.openSSHString(secret: selectedSecret)] + .joined(separator: " ") let fileController = PublicKeyFileStoreController(homeDirectory: URL.agentHomeURL) return text - .replacingOccurrences(of: Instructions.Constants.publicKeyPlaceholder, with: writer.openSSHString(secret: selectedSecret)) + .replacingOccurrences(of: Instructions.Constants.publicKeyPlaceholder, with: gitAllowedSignersString) .replacingOccurrences(of: Instructions.Constants.publicKeyPathPlaceholder, with: fileController.publicKeyPath(for: selectedSecret)) } diff --git a/Sources/Secretive/Views/Views/AgentStatusView.swift b/Sources/Secretive/Views/Views/AgentStatusView.swift index 50b50c9..43c69a1 100644 --- a/Sources/Secretive/Views/Views/AgentStatusView.swift +++ b/Sources/Secretive/Views/Views/AgentStatusView.swift @@ -2,10 +2,10 @@ import SwiftUI struct AgentStatusView: View { - @Environment(\.agentStatusChecker) private var agentStatusChecker: any AgentStatusCheckerProtocol + @Environment(\.agentLaunchController) private var agentLaunchController: any AgentLaunchControllerProtocol var body: some View { - if agentStatusChecker.running { + if agentLaunchController.running { AgentRunningView() } else { AgentNotRunningView() @@ -14,12 +14,13 @@ struct AgentStatusView: View { } struct AgentRunningView: View { - @Environment(\.agentStatusChecker) private var agentStatusChecker: any AgentStatusCheckerProtocol + @Environment(\.agentLaunchController) private var agentLaunchController: any AgentLaunchControllerProtocol + @AppStorage("explicitlyDisabled") var explicitlyDisabled = false var body: some View { Form { Section { - if let process = agentStatusChecker.process { + if let process = agentLaunchController.process { ConfigurationItemView( title: .agentDetailsLocationTitle, value: process.bundleURL!.path(), @@ -53,19 +54,14 @@ struct AgentRunningView: View { Menu(.agentDetailsRestartAgentButton) { Button(.agentDetailsDisableAgentButton) { Task { - _ = await LaunchAgentController() + explicitlyDisabled = true + try? await agentLaunchController .uninstall() - agentStatusChecker.check() } } } primaryAction: { Task { - let controller = LaunchAgentController() - let installed = await controller.install() - if !installed { - _ = await controller.forceLaunch() - } - agentStatusChecker.check() + try? await agentLaunchController.forceLaunch() } } } @@ -82,9 +78,10 @@ struct AgentRunningView: View { struct AgentNotRunningView: View { - @Environment(\.agentStatusChecker) private var agentStatusChecker: any AgentStatusCheckerProtocol + @Environment(\.agentLaunchController) private var agentLaunchController @State var triedRestart = false @State var loading = false + @AppStorage("explicitlyDisabled") var explicitlyDisabled = false var body: some View { Form { @@ -100,18 +97,14 @@ struct AgentNotRunningView: View { if !triedRestart { Spacer() Button { + explicitlyDisabled = false guard !loading else { return } loading = true Task { - let controller = LaunchAgentController() - let installed = await controller.install() - if !installed { - _ = await controller.forceLaunch() - } - agentStatusChecker.check() + try await agentLaunchController.forceLaunch() loading = false - if !agentStatusChecker.running { + if !agentLaunchController.running { triedRestart = true } } @@ -145,9 +138,9 @@ struct AgentNotRunningView: View { //#Preview { // AgentStatusView() -// .environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: false)) +// .environment(\.agentLaunchController, PreviewAgentLaunchController(running: false)) //} //#Preview { // AgentStatusView() -// .environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: true, process: .current)) +// .environment(\.agentLaunchController, PreviewAgentLaunchController(running: true, process: .current)) //} diff --git a/Sources/Secretive/Views/Views/ContentView.swift b/Sources/Secretive/Views/Views/ContentView.swift index 7c395df..c44f0da 100644 --- a/Sources/Secretive/Views/Views/ContentView.swift +++ b/Sources/Secretive/Views/Views/ContentView.swift @@ -14,7 +14,7 @@ struct ContentView: View { @Environment(\.openWindow) private var openWindow @Environment(\.secretStoreList) private var storeList @Environment(\.updater) private var updater - @Environment(\.agentStatusChecker) private var agentStatusChecker + @Environment(\.agentLaunchController) private var agentLaunchController @AppStorage("defaultsHasRunSetup") private var hasRunSetup = false @State private var showingCreation = false @@ -127,7 +127,7 @@ extension ContentView { showingAgentInfo = true }, label: { HStack { - if agentStatusChecker.running { + if agentLaunchController.running { Text(.agentRunningNoticeTitle) .font(.headline) .foregroundColor(colorScheme == .light ? Color(white: 0.3) : .white) @@ -145,8 +145,8 @@ extension ContentView { }) .buttonStyle( ToolbarStatusButtonStyle( - lightColor: agentStatusChecker.running ? .black.opacity(0.05) : .red.opacity(0.75), - darkColor: agentStatusChecker.running ? .white.opacity(0.05) : .red.opacity(0.5), + lightColor: agentLaunchController.running ? .black.opacity(0.05) : .red.opacity(0.75), + darkColor: agentLaunchController.running ? .white.opacity(0.05) : .red.opacity(0.5), ) ) .popover(isPresented: $showingAgentInfo, attachmentAnchor: attachmentAnchor, arrowEdge: .bottom) {