1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-08 04:20:07 +02:00

Compare commits

...

52 Commits

Author SHA1 Message Date
94abfe4b49 🐛 Fix crash bug (oops) 2024-10-31 22:51:49 +01:00
cef19243ee 🔧 Bump build 2024-10-31 21:59:42 +01:00
b319ecab59 👌 Move cut-off date to PHP 8.4 release day 2024-10-31 21:56:13 +01:00
a47b139d92 👌 Cleanup 2024-08-31 22:14:56 +02:00
e026ecf60d ♻️ Various extension list improvements (#274)
Installing and removing extensions now scrolls to the extension afterwards, and animates this. This is done to emphasise that the operation succeeded.
2024-08-31 15:57:08 +02:00
3c0a4a6142 🌐 Updated localization 2024-08-26 15:04:37 +02:00
87ebb20284 ♻️ Use alternate cell identifier for favorite 2024-08-25 16:21:16 +02:00
d60c26c9b2 UserDefaults-backed storage for Favorites 2024-08-25 14:35:11 +02:00
5c9c51f580 Mark domain as favorite (UI only)
Please note that this functionality is currently not persistent.
As such, reloading the domain list will reset any changes you have made.
2024-08-25 13:35:27 +02:00
0c320074da ♻️ Avoid using non-Sendable Timer 2024-08-06 14:15:37 +02:00
e3ea712a99 Ensure all tests run and pass 2024-07-16 18:38:56 +02:00
4db478ca64 👌 Update copyright information 2024-07-16 18:30:56 +02:00
3064a07d69 📦 Use NVAppUpdater and NVAlert packages 2024-07-16 18:29:11 +02:00
f3e1b4de6f 🚀 Version 7.0.4 2024-06-28 11:47:25 +02:00
a3226b632f 🐛 Restart PHP-FPM after managing extensions
This is done to prevent issues like #292.
2024-06-28 11:37:01 +02:00
652878d97f 👌 Remove unused WIP class 2024-06-28 11:14:20 +02:00
032610ad5c 🌐 Add localization for "Actions" 2024-06-28 11:12:55 +02:00
2c2627dc9f Add AppMenu class for easy access to main menu 2024-06-27 21:23:59 +02:00
62587bdf65 WIP: Add context menu to main menu 2024-06-11 18:53:55 +02:00
5e9dae78f5 🐛 Fix Bedrock project detection (#288) 2024-06-06 21:30:06 +02:00
949ba5b559 🔧 Build self-updater as part of main target
The self-updater is now a requirement for the main app to be able to be
built. You no longer need the existing binary. This makes it easier for
anyone to just try out the app locally and makes reproducible builds
also possible.

(This is done because the self-updater code will soon be moved to a
separate package, and I want to make this entire updater process
as simple as possible.)

In order to avoid the self-updater app from appearing as a product when
archiving a build, SKIP_INSTALL is set to true. This avoids a variety
of annoying issues including the archive appearing under "Other Items".
2024-05-31 23:54:42 +02:00
ce88f897ef 🌐 Added Chinese translations, credits
- Chinese translations contributed by @guanguans (via #285).
- Updated the credits so that all translators are now also listed
  separately, since the GitHub issue has been closed.
2024-05-02 10:24:47 +02:00
fa9b51aaab 🚀 Version 7.0.3 2024-04-10 13:07:58 +02:00
b8affad5ee 📝 Updated SECURITY.md 2024-04-10 13:07:30 +02:00
41e5f5b4c3 🔧 Bump build for EAP release 2024-04-09 12:33:55 +02:00
79f6a60a16 👌 Cleanup dependencies for site isolation 2024-04-03 14:50:05 +02:00
06bc4ddb9a 👌 Improve removing indirect dependency
Mind you, the interaction with the domain list controller also needs to
be abstracted away, but this is fine, for now.
2024-04-03 14:11:45 +02:00
bf728a24f0 👌 Fix PHP version suggestions in popover
- If your Valet installation supports using site isolation, that will
  be displayed as the suggestion. If not, the traditional "Switch to
  PHP" options will be available.

- Overflowing buttons have been fixed. Three columns are now used with
  a LazyVGrid, to prevent text from being unreadable.
2024-04-02 15:25:06 +02:00
b7cad3af62 👌 Fix Swift 5.10 concurrency warnings 2024-03-30 17:40:09 +01:00
4a3dee3c50 🚀 Version 7.0.2 2024-03-30 17:14:04 +01:00
9d5a0ed745 🔧 Xcode upgrade check 2024-03-20 13:46:56 +01:00
b3b509409a Fix test 2024-03-20 10:47:52 +01:00
4934f35d0b 🍱 Bump width of no results view 2024-03-19 14:23:19 +01:00
92e7418158 👌 Cleanup 2024-03-19 14:22:10 +01:00
52ea64db40 👌 Use base translation for no domain results 2024-03-19 14:20:34 +01:00
f66e9b7340 Add UnavailableContentView to domains 2024-03-19 14:10:08 +01:00
2bf28fe247 👌 Allow resizable windows 2024-03-16 00:32:05 +01:00
c6e4f785bc 🍱 Use PHP icon for phpman 2024-03-15 23:38:12 +01:00
94fe7df3bd 🍱 Custom button for "upgrade all" 2024-03-15 23:18:09 +01:00
f373621a4a 👌 Polish PHP installation management
- Make spinner view opaque to hide incorrect info
  when refreshing PHP installations
- Resolve each PHP installation to a Homebrew version
- Fix an issue where certain PHP upgrades don't show up

In this build, resolving PHP upgrades happens based on the formula name.

This avoids issues where available PHP version upgrades would *not* be
detected correctly (based on the installed version).
2024-03-15 22:09:59 +01:00
5104a865fb 🚀 Version 7.0.1 2024-02-12 18:28:45 +01:00
7b10973330 🔧 Bump build 2024-02-12 16:33:01 +01:00
bc208bddf9 👌 Notify if list of extensions is empty (#275) 2024-02-12 16:30:18 +01:00
321b4aaf8b 🐛 Fix extension detection on Intel (#275) 2024-02-12 15:26:48 +01:00
b26fc3bc4b 🚀 Version 7.0 2024-02-11 21:35:40 +01:00
f758c5d63a 👌 Cut off bottom of marketing screenshot 2024-02-10 16:18:58 +01:00
c7510d778d 🍱 Update marketing screenshot 2024-02-10 16:17:24 +01:00
7728a1125c 📝 Update README to reflect php = PHP 8.3 2024-01-09 21:00:06 +01:00
ff61d8c52e 🚀 Version 6.2.2 2023-11-24 23:30:12 +01:00
da41673855 Fix broken tests 2023-11-24 23:29:25 +01:00
5bda727981 🔧 Bump version 2023-11-24 22:58:04 +01:00
8790b30706 🚀 Version 6.2.1 2023-11-02 17:17:40 +01:00
91 changed files with 2089 additions and 890 deletions

View File

@ -14,6 +14,17 @@ It also automatically runs when you try to build the project. You'll get a warni
swiftlint --fix
```
## 📦 Swift Packages
Starting from PHP Monitor 7.1, the app now uses various first-party package dependencies.
The following package dependencies are in use:
* [`NVAppUpdater`](https://github.com/nicoverbruggen/NVAppUpdater)
* [`NVAlert`](https://github.com/nicoverbruggen/NVAlert)
You may need an internet connection to download these dependencies, or you can also clone the dependencies and include them manually.
## ⚙️ Preferences
You can find the persisted configuration file in `~/Library/Preferences/com.nicoverbruggen.phpmon.plist`
@ -33,17 +44,13 @@ defaults delete com.nicoverbruggen.phpmon && killall cfprefsd
If you'd like to build PHP Monitor yourself, you need:
* Xcode (usually the latest version)
* *PHP Monitor Self-Updater.app* in the `phpmon-updater` directory (You can build it yourself, it is included as a target OR copy the signed app so it is included w/ PHP Monitor)
* The contents of this repository
Once you have downloaded this repository, open `PHP Monitor.xcodeproj`, and you should be able to build the app for your system by pressing Cmd-R. This will create a debug build. (If Xcode complains about code signing, you can turn it off.)
**Important**: The updater now gets automatically built and included as part of the main target.
If you'd like to create a production build, choose "Any Mac" as the target and select Product > Archive.
### PHP Monitor Updater
Select the separate target and build. You can then copy the product to the `phpmon-updater` directory. The binary will be re-signed when distributing the main build.
## 🚀 Release procedure
1. Merge into `main`

View File

@ -53,7 +53,6 @@
C40175B92903108900763A68 /* ValetInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40175B72903108900763A68 /* ValetInteractor.swift */; };
C40175BA2903108900763A68 /* ValetInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40175B72903108900763A68 /* ValetInteractor.swift */; };
C40175BB2903108900763A68 /* ValetInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40175B72903108900763A68 /* ValetInteractor.swift */; };
C40508AF28ADA23D008FAC1F /* NoDomainResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40508AE28ADA23D008FAC1F /* NoDomainResultsView.swift */; };
C40508B128ADAB44008FAC1F /* NSMenuItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40508B028ADAB44008FAC1F /* NSMenuItemExtension.swift */; };
C405A4D024B9B9140062FAFA /* InternetAccessPolicy.strings in Resources */ = {isa = PBXBuildFile; fileRef = C405A4CE24B9B9130062FAFA /* InternetAccessPolicy.strings */; };
C405A4D124B9B9140062FAFA /* InternetAccessPolicy.plist in Resources */ = {isa = PBXBuildFile; fileRef = C405A4CF24B9B9140062FAFA /* InternetAccessPolicy.plist */; };
@ -65,11 +64,6 @@
C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */; };
C406A5F3298AD2CE00B5B85A /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C406A5F2298AD2CE00B5B85A /* main.swift */; };
C406A5F7298AD2CF00B5B85A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C406A5F6298AD2CF00B5B85A /* Assets.xcassets */; };
C406A602298AD50D00B5B85A /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C406A601298AD50D00B5B85A /* Updater.swift */; };
C4080FF627BD8C6400BF2C6B /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; };
C4080FF727BD8C6400BF2C6B /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; };
C4080FFA27BD956700BF2C6B /* BetterAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */; };
C4080FFB27BD956700BF2C6B /* BetterAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */; };
C409349D298EE8E900D25014 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C409349C298EE8E900D25014 /* AppUpdater.swift */; };
C409349E298EE8E900D25014 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C409349C298EE8E900D25014 /* AppUpdater.swift */; };
C409349F298EE8E900D25014 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C409349C298EE8E900D25014 /* AppUpdater.swift */; };
@ -176,6 +170,10 @@
C43A8A1A25D9CD1000591B77 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A1925D9CD1000591B77 /* Utility.swift */; };
C43A8A2025D9D1D700591B77 /* brew-formula.json in Resources */ = {isa = PBXBuildFile; fileRef = C43A8A1F25D9D1D700591B77 /* brew-formula.json */; };
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */; };
C43B8FD52BA9BAD3000C02BE /* UnavailableContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43B8FD42BA9BAD3000C02BE /* UnavailableContentView.swift */; };
C43B8FD62BA9C689000C02BE /* UnavailableContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43B8FD42BA9BAD3000C02BE /* UnavailableContentView.swift */; };
C43B8FD72BA9C689000C02BE /* UnavailableContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43B8FD42BA9BAD3000C02BE /* UnavailableContentView.swift */; };
C43B8FD82BA9C689000C02BE /* UnavailableContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43B8FD42BA9BAD3000C02BE /* UnavailableContentView.swift */; };
C43BCD4429FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */; };
C43BCD4529FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */; };
C43BCD4629FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */; };
@ -292,6 +290,10 @@
C469E700294CF7B200A82AB2 /* FakeValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C469E6FD294CF7B200A82AB2 /* FakeValetProxy.swift */; };
C469E701294CF7B200A82AB2 /* FakeValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C469E6FD294CF7B200A82AB2 /* FakeValetProxy.swift */; };
C469E706294CFDF700A82AB2 /* DomainsListTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C469E702294CFDF700A82AB2 /* DomainsListTest.swift */; };
C46DC7A42C7B55DC00F19D17 /* Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46DC7A32C7B55DC00F19D17 /* Favorites.swift */; };
C46DC7A52C7B5BC900F19D17 /* Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46DC7A32C7B55DC00F19D17 /* Favorites.swift */; };
C46DC7A62C7B5BC900F19D17 /* Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46DC7A32C7B55DC00F19D17 /* Favorites.swift */; };
C46DC7A72C7B5BCA00F19D17 /* Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46DC7A32C7B55DC00F19D17 /* Favorites.swift */; };
C46EBC4428DB95F0007ACC74 /* ShellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */; };
C46EBC4528DB95F0007ACC74 /* ShellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */; };
C46EBC4728DB9644007ACC74 /* RealShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46EBC4628DB9644007ACC74 /* RealShell.swift */; };
@ -302,6 +304,15 @@
C46FA9882822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA9872822EFDC00D78807 /* PhpConfigurationFile.swift */; };
C46FA9892822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA9872822EFDC00D78807 /* PhpConfigurationFile.swift */; };
C46FA98C2822F08F00D78807 /* PhpConfigurationFileTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA98A2822F08F00D78807 /* PhpConfigurationFileTest.swift */; };
C47014FC2C46D31B0069AAE7 /* NVAppUpdater in Frameworks */ = {isa = PBXBuildFile; productRef = C47014FB2C46D31B0069AAE7 /* NVAppUpdater */; };
C47014FF2C46D57C0069AAE7 /* NVAlert in Frameworks */ = {isa = PBXBuildFile; productRef = C47014FE2C46D57C0069AAE7 /* NVAlert */; };
C47015022C46D6910069AAE7 /* NVAlertExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47015012C46D6910069AAE7 /* NVAlertExtension.swift */; };
C47015032C46D7F00069AAE7 /* NVAlertExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47015012C46D6910069AAE7 /* NVAlertExtension.swift */; };
C47015042C46D7F00069AAE7 /* NVAlertExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47015012C46D6910069AAE7 /* NVAlertExtension.swift */; };
C47015052C46D7F10069AAE7 /* NVAlertExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47015012C46D6910069AAE7 /* NVAlertExtension.swift */; };
C47015072C46D8180069AAE7 /* NVAlert in Frameworks */ = {isa = PBXBuildFile; productRef = C47015062C46D8180069AAE7 /* NVAlert */; };
C470150B2C46D81E0069AAE7 /* NVAlert in Frameworks */ = {isa = PBXBuildFile; productRef = C470150A2C46D81E0069AAE7 /* NVAlert */; };
C470150D2C46D83E0069AAE7 /* NVAlert in Frameworks */ = {isa = PBXBuildFile; productRef = C470150C2C46D83E0069AAE7 /* NVAlert */; };
C4709CA228524B3400088BB8 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4709CA128524B3400088BB8 /* StatsView.swift */; };
C471E79328F9B21F0021E251 /* ActiveFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */; };
C471E79428F9B23B0021E251 /* FileSystemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900228F0E28800CE5E97 /* FileSystemProtocol.swift */; };
@ -389,10 +400,6 @@
C471E81828F9BAE80021E251 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA23E246C358E00944F05 /* StringExtension.swift */; };
C471E81928F9BAE80021E251 /* NSMenuItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40508B028ADAB44008FAC1F /* NSMenuItemExtension.swift */; };
C471E81A28F9BAE80021E251 /* TimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */; };
C471E81B28F9BB250021E251 /* BetterAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */; };
C471E81C28F9BB250021E251 /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; };
C471E81D28F9BB260021E251 /* BetterAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */; };
C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; };
C471E81F28F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; };
C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; };
C471E82128F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; };
@ -484,7 +491,6 @@
C471E88128F9BB650021E251 /* NoWarningsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C708C28AA7F7900E8D498 /* NoWarningsView.swift */; };
C471E88228F9BB650021E251 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E9D2BF2878B336008FFDAD /* OnboardingView.swift */; };
C471E88328F9BB650021E251 /* VersionPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */; };
C471E88428F9BB650021E251 /* NoDomainResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40508AE28ADA23D008FAC1F /* NoDomainResultsView.swift */; };
C471E88528F9BB650021E251 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B6091C2853AB9700C95265 /* ServicesView.swift */; };
C471E88628F9BB650021E251 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4709CA128524B3400088BB8 /* StatsView.swift */; };
C471E88728F9BB650021E251 /* SectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B609192853AAD300C95265 /* SectionHeaderView.swift */; };
@ -572,7 +578,6 @@
C471E8E428F9BB8F0021E251 /* NoWarningsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C708C28AA7F7900E8D498 /* NoWarningsView.swift */; };
C471E8E528F9BB8F0021E251 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E9D2BF2878B336008FFDAD /* OnboardingView.swift */; };
C471E8E628F9BB8F0021E251 /* VersionPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */; };
C471E8E728F9BB8F0021E251 /* NoDomainResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40508AE28ADA23D008FAC1F /* NoDomainResultsView.swift */; };
C471E8E828F9BB8F0021E251 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B6091C2853AB9700C95265 /* ServicesView.swift */; };
C471E8E928F9BB8F0021E251 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4709CA128524B3400088BB8 /* StatsView.swift */; };
C471E8EA28F9BB8F0021E251 /* SectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B609192853AAD300C95265 /* SectionHeaderView.swift */; };
@ -596,6 +601,10 @@
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; };
C481F79726164A78004FBCFF /* PreferencesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395826135DC100FB00FA /* PreferencesVC.swift */; };
C481F79A26164A7C004FBCFF /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395E2613607600FB00FA /* Preferences.swift */; };
C4821C5A2C2DEDE200357A68 /* AppMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4821C592C2DEDE200357A68 /* AppMenu.swift */; };
C4821C5B2C2DEDE200357A68 /* AppMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4821C592C2DEDE200357A68 /* AppMenu.swift */; };
C4821C5C2C2DEDE200357A68 /* AppMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4821C592C2DEDE200357A68 /* AppMenu.swift */; };
C4821C5D2C2DEDE200357A68 /* AppMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4821C592C2DEDE200357A68 /* AppMenu.swift */; };
C485706D28BF450900539B36 /* NSMenuItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40508B028ADAB44008FAC1F /* NSMenuItemExtension.swift */; };
C485706E28BF451C00539B36 /* OnboardingWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FACE82288F1F9700FC478F /* OnboardingWindowController.swift */; };
C485706F28BF452300539B36 /* PhpDoctorWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C422DDAC28A2DAC600CEAC97 /* PhpDoctorWindowController.swift */; };
@ -715,8 +724,6 @@
C4C3643A28AE4FCE00C0770E /* StatusMenu+Items.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3643828AE4FCE00C0770E /* StatusMenu+Items.swift */; };
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */; };
C4C3ED4327834C5200AB15D8 /* CustomPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */; };
C4C75F5A298C2D5700DFD82E /* LaunchControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C75F59298C2D5700DFD82E /* LaunchControl.swift */; };
C4C75F5C298C31C000DFD82E /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C75F5B298C31C000DFD82E /* Utility.swift */; };
C4C8900328F0E28800CE5E97 /* FileSystemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900228F0E28800CE5E97 /* FileSystemProtocol.swift */; };
C4C8900528F0E3D100CE5E97 /* RealFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900428F0E3D100CE5E97 /* RealFileSystem.swift */; };
C4C8900728F0E3EF00CE5E97 /* ActiveFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */; };
@ -750,10 +757,6 @@
C4D3660D29113F20006BD146 /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D3660A29113F20006BD146 /* System.swift */; };
C4D3660E29113F20006BD146 /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D3660A29113F20006BD146 /* System.swift */; };
C4D36611291140BE006BD146 /* TestableFileSystemTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D3660F291140BE006BD146 /* TestableFileSystemTest.swift */; };
C4D36615291160A1006BD146 /* WIP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36614291160A1006BD146 /* WIP.swift */; };
C4D36616291160A1006BD146 /* WIP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36614291160A1006BD146 /* WIP.swift */; };
C4D36617291160A1006BD146 /* WIP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36614291160A1006BD146 /* WIP.swift */; };
C4D36618291160A1006BD146 /* WIP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36614291160A1006BD146 /* WIP.swift */; };
C4D3661A291173EA006BD146 /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36619291173EA006BD146 /* DictionaryExtension.swift */; };
C4D3661B291173EA006BD146 /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36619291173EA006BD146 /* DictionaryExtension.swift */; };
C4D3661C291173EA006BD146 /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36619291173EA006BD146 /* DictionaryExtension.swift */; };
@ -819,8 +822,12 @@
C4E6840A2AF26B830023ED25 /* BrewTapFormulae.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E684082AF26B830023ED25 /* BrewTapFormulae.swift */; };
C4E6840B2AF26B830023ED25 /* BrewTapFormulae.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E684082AF26B830023ED25 /* BrewTapFormulae.swift */; };
C4E6840C2AF26B830023ED25 /* BrewTapFormulae.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E684082AF26B830023ED25 /* BrewTapFormulae.swift */; };
C4E91D142C0A7AAA00D69A31 /* PHP Monitor Self-Updater.app in Resources */ = {isa = PBXBuildFile; fileRef = C406A5F0298AD2CE00B5B85A /* PHP Monitor Self-Updater.app */; };
C4E9D2C02878B336008FFDAD /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E9D2BF2878B336008FFDAD /* OnboardingView.swift */; };
C4E9D90129CBA09E00BD28D4 /* PHP Monitor Self-Updater.app in Resources */ = {isa = PBXBuildFile; fileRef = C4E9D90029CBA09E00BD28D4 /* PHP Monitor Self-Updater.app */; };
C4EA3C472BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EA3C462BA4F947007B0BA7 /* CustomButtonStyles.swift */; };
C4EA3C482BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EA3C462BA4F947007B0BA7 /* CustomButtonStyles.swift */; };
C4EA3C492BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EA3C462BA4F947007B0BA7 /* CustomButtonStyles.swift */; };
C4EA3C4A2BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EA3C462BA4F947007B0BA7 /* CustomButtonStyles.swift */; };
C4EB53E528551F9B006F9937 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EB53E428551F9B006F9937 /* HeaderView.swift */; };
C4EB53E728553117006F9937 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EB53E628553117006F9937 /* ArrayExtension.swift */; };
C4EC1E73279DFCF40010F296 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; };
@ -890,6 +897,13 @@
remoteGlobalIDString = C41C1B3222B0097F00E7CF16;
remoteInfo = "PHP Monitor";
};
C4E91D122C0A7A9B00D69A31 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C41C1B2B22B0097F00E7CF16 /* Project object */;
proxyType = 1;
remoteGlobalIDString = C406A5EF298AD2CE00B5B85A;
remoteInfo = "PHP Monitor Self-Updater";
};
C4F7807E25D7F84B000DBC97 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C41C1B2B22B0097F00E7CF16 /* Project object */;
@ -924,7 +938,6 @@
54FCFD2C276C8D67004CE748 /* HotkeyPreferenceView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HotkeyPreferenceView.xib; sourceTree = "<group>"; };
54FCFD2F276C8DA4004CE748 /* HotkeyPreferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HotkeyPreferenceView.swift; sourceTree = "<group>"; };
C40175B72903108900763A68 /* ValetInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetInteractor.swift; sourceTree = "<group>"; };
C40508AE28ADA23D008FAC1F /* NoDomainResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoDomainResultsView.swift; sourceTree = "<group>"; };
C40508B028ADAB44008FAC1F /* NSMenuItemExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSMenuItemExtension.swift; sourceTree = "<group>"; };
C405A4CE24B9B9130062FAFA /* InternetAccessPolicy.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = InternetAccessPolicy.strings; sourceTree = "<group>"; };
C405A4CF24B9B9140062FAFA /* InternetAccessPolicy.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = InternetAccessPolicy.plist; sourceTree = "<group>"; };
@ -935,9 +948,6 @@
C406A5F2298AD2CE00B5B85A /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
C406A5F6298AD2CF00B5B85A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
C406A5FB298AD2CF00B5B85A /* phpmon-updater.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "phpmon-updater.entitlements"; sourceTree = "<group>"; };
C406A601298AD50D00B5B85A /* Updater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterAlert.swift; sourceTree = "<group>"; };
C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterAlertVC.swift; sourceTree = "<group>"; };
C409349C298EE8E900D25014 /* AppUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdater.swift; sourceTree = "<group>"; };
C40934A1298EEB2C00D25014 /* CaskFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskFile.swift; sourceTree = "<group>"; };
C40934A6298EEB8700D25014 /* phpmon-dev.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = "phpmon-dev.rb"; sourceTree = "<group>"; };
@ -998,6 +1008,7 @@
C43A8A1925D9CD1000591B77 /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = "<group>"; };
C43A8A1F25D9D1D700591B77 /* brew-formula.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "brew-formula.json"; sourceTree = "<group>"; };
C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewPackageTest.swift; sourceTree = "<group>"; };
C43B8FD42BA9BAD3000C02BE /* UnavailableContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnavailableContentView.swift; sourceTree = "<group>"; };
C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifyPhpVersionCommand.swift; sourceTree = "<group>"; };
C43FDBE829A932B0003D85EC /* PhpConfigChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpConfigChecker.swift; sourceTree = "<group>"; };
C44067F427E2582B0045BD4E /* DomainListNameCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListNameCell.swift; sourceTree = "<group>"; };
@ -1021,6 +1032,7 @@
C44F868D2835BD8D005C353A /* phpmon-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "phpmon-config.json"; sourceTree = "<group>"; };
C450C8C528C919EC002A2B4B /* PreferenceName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceName.swift; sourceTree = "<group>"; };
C451AFF52969E40F0078E617 /* HelpButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpButton.swift; sourceTree = "<group>"; };
C453874C2BE37FD6002B9C65 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
C4551656297AED18009B8466 /* ValetRcTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetRcTest.swift; sourceTree = "<group>"; };
C4551658297AED7D009B8466 /* valetrc.valid */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = valetrc.valid; sourceTree = "<group>"; };
C455165A297AEDB5009B8466 /* valetrc.broken */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = valetrc.broken; sourceTree = "<group>"; };
@ -1041,12 +1053,14 @@
C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListCellProtocol.swift; sourceTree = "<group>"; };
C469E6FD294CF7B200A82AB2 /* FakeValetProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeValetProxy.swift; sourceTree = "<group>"; };
C469E702294CFDF700A82AB2 /* DomainsListTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainsListTest.swift; sourceTree = "<group>"; };
C46DC7A32C7B55DC00F19D17 /* Favorites.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Favorites.swift; sourceTree = "<group>"; };
C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellProtocol.swift; sourceTree = "<group>"; };
C46EBC4628DB9644007ACC74 /* RealShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealShell.swift; sourceTree = "<group>"; };
C46EBC4928DB966A007ACC74 /* TestableShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableShell.swift; sourceTree = "<group>"; };
C46FA23E246C358E00944F05 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
C46FA9872822EFDC00D78807 /* PhpConfigurationFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpConfigurationFile.swift; sourceTree = "<group>"; };
C46FA98A2822F08F00D78807 /* PhpConfigurationFileTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpConfigurationFileTest.swift; sourceTree = "<group>"; };
C47015012C46D6910069AAE7 /* NVAlertExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NVAlertExtension.swift; sourceTree = "<group>"; };
C4709CA128524B3400088BB8 /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
C471E79228F9B1D30021E251 /* PHP Monitor.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "PHP Monitor.xctestplan"; sourceTree = "<group>"; };
C471E7AD28F9B4940021E251 /* Feature Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Feature Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
@ -1061,6 +1075,7 @@
C47DF1AE299D5A3B0007055D /* LoginItemManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginItemManager.swift; sourceTree = "<group>"; };
C4811D2322D70A4700B5F6B3 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
C4821C592C2DEDE200357A68 /* AppMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMenu.swift; sourceTree = "<group>"; };
C489E0BA2A220A4200323F5E /* FakeBrewFormulaeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeBrewFormulaeHandler.swift; sourceTree = "<group>"; };
C48D0C9225CC804200CC7490 /* XibLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XibLoadable.swift; sourceTree = "<group>"; };
C48D6C6F279CD2AC00F26D7E /* VersionNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionNumber.swift; sourceTree = "<group>"; };
@ -1106,8 +1121,6 @@
C4C3643828AE4FCE00C0770E /* StatusMenu+Items.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusMenu+Items.swift"; sourceTree = "<group>"; };
C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Startup.swift"; sourceTree = "<group>"; };
C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPrefs.swift; sourceTree = "<group>"; };
C4C75F59298C2D5700DFD82E /* LaunchControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchControl.swift; sourceTree = "<group>"; };
C4C75F5B298C31C000DFD82E /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = "<group>"; };
C4C8900228F0E28800CE5E97 /* FileSystemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSystemProtocol.swift; sourceTree = "<group>"; };
C4C8900428F0E3D100CE5E97 /* RealFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealFileSystem.swift; sourceTree = "<group>"; };
C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveFileSystem.swift; sourceTree = "<group>"; };
@ -1123,7 +1136,6 @@
C4D36600291132B7006BD146 /* ValetScanners.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetScanners.swift; sourceTree = "<group>"; };
C4D3660A29113F20006BD146 /* System.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = System.swift; sourceTree = "<group>"; };
C4D3660F291140BE006BD146 /* TestableFileSystemTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableFileSystemTest.swift; sourceTree = "<group>"; };
C4D36614291160A1006BD146 /* WIP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WIP.swift; sourceTree = "<group>"; };
C4D36619291173EA006BD146 /* DictionaryExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryExtension.swift; sourceTree = "<group>"; };
C4D4CB3629C109CF00DB9F93 /* InternalSwitcher+Valet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InternalSwitcher+Valet.swift"; sourceTree = "<group>"; };
C4D5576329C77CC5001A44CD /* PhpVersionManagerWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersionManagerWindowController.swift; sourceTree = "<group>"; };
@ -1152,7 +1164,7 @@
C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = "<group>"; };
C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = "<group>"; };
C4E9D2BF2878B336008FFDAD /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
C4E9D90029CBA09E00BD28D4 /* PHP Monitor Self-Updater.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = "PHP Monitor Self-Updater.app"; sourceTree = "<group>"; };
C4EA3C462BA4F947007B0BA7 /* CustomButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButtonStyles.swift; sourceTree = "<group>"; };
C4EB53E428551F9B006F9937 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = "<group>"; };
C4EB53E628553117006F9937 /* ArrayExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtension.swift; sourceTree = "<group>"; };
C4EC1E72279DFCF40010F296 /* Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Events.swift; sourceTree = "<group>"; };
@ -1185,6 +1197,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C47014FC2C46D31B0069AAE7 /* NVAppUpdater in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1192,6 +1205,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C47014FF2C46D57C0069AAE7 /* NVAlert in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1199,6 +1213,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C470150B2C46D81E0069AAE7 /* NVAlert in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1206,6 +1221,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C470150D2C46D83E0069AAE7 /* NVAlert in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1213,6 +1229,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C47015072C46D8180069AAE7 /* NVAlert in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1334,26 +1351,13 @@
C406A5F1298AD2CE00B5B85A /* phpmon-updater */ = {
isa = PBXGroup;
children = (
C4E9D90029CBA09E00BD28D4 /* PHP Monitor Self-Updater.app */,
C406A5F2298AD2CE00B5B85A /* main.swift */,
C406A601298AD50D00B5B85A /* Updater.swift */,
C4C75F5B298C31C000DFD82E /* Utility.swift */,
C4C75F59298C2D5700DFD82E /* LaunchControl.swift */,
C406A5F6298AD2CF00B5B85A /* Assets.xcassets */,
C406A5FB298AD2CF00B5B85A /* phpmon-updater.entitlements */,
);
path = "phpmon-updater";
sourceTree = "<group>";
};
C4080FF827BD955900BF2C6B /* Notice */ = {
isa = PBXGroup;
children = (
C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */,
C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */,
);
path = Notice;
sourceTree = "<group>";
};
C40C5C9E2846A42D00E28255 /* Presets */ = {
isa = PBXGroup;
children = (
@ -1456,7 +1460,6 @@
C41E181722CB61EB0072CF09 /* Domain */ = {
isa = PBXGroup;
children = (
C4080FF827BD955900BF2C6B /* Notice */,
C4AF9F6B275445D300D44ED0 /* Integrations */,
C4B13B1D25C4915000548C3A /* App */,
C4D9ADBD27761084007277F4 /* PHP */,
@ -1578,7 +1581,6 @@
C4D5576329C77CC5001A44CD /* PhpVersionManagerWindowController.swift */,
C43931C429C4BD610069165B /* PhpVersionManagerView.swift */,
C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */,
C48DDD0C29C75C9E00D032D9 /* BlockingOverlayView.swift */,
);
path = UI;
sourceTree = "<group>";
@ -1778,6 +1780,7 @@
isa = PBXGroup;
children = (
C44DFA852A67090A00B98ED5 /* UI */,
C46DC7A32C7B55DC00F19D17 /* Favorites.swift */,
);
path = "Domain List";
sourceTree = "<group>";
@ -1845,6 +1848,7 @@
C4F361602836BFD9003598CC /* MainMenu+Actions.swift */,
C47331A1247093B7009A0597 /* StatusMenu.swift */,
C4C3643828AE4FCE00C0770E /* StatusMenu+Items.swift */,
C4821C592C2DEDE200357A68 /* AppMenu.swift */,
);
path = Menu;
sourceTree = "<group>";
@ -1859,7 +1863,6 @@
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */,
C4B5635D276AB09000F12CCB /* VersionExtractor.swift */,
C4D3660A29113F20006BD146 /* System.swift */,
C4D36614291160A1006BD146 /* WIP.swift */,
C47DF1AE299D5A3B0007055D /* LoginItemManager.swift */,
C49EAA5129B12A5A00AB28FC /* Measurements.swift */,
);
@ -1963,6 +1966,9 @@
children = (
C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */,
C451AFF52969E40F0078E617 /* HelpButton.swift */,
C4EA3C462BA4F947007B0BA7 /* CustomButtonStyles.swift */,
C48DDD0C29C75C9E00D032D9 /* BlockingOverlayView.swift */,
C43B8FD42BA9BAD3000C02BE /* UnavailableContentView.swift */,
);
path = Common;
sourceTree = "<group>";
@ -1982,7 +1988,6 @@
isa = PBXGroup;
children = (
C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */,
C40508AE28ADA23D008FAC1F /* NoDomainResultsView.swift */,
);
path = Domains;
sourceTree = "<group>";
@ -2222,6 +2227,7 @@
C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */,
C4E2E84928FC1E70003B070C /* DataExtension.swift */,
C4D36619291173EA006BD146 /* DictionaryExtension.swift */,
C47015012C46D6910069AAE7 /* NVAlertExtension.swift */,
);
path = Extensions;
sourceTree = "<group>";
@ -2242,6 +2248,9 @@
dependencies = (
);
name = "PHP Monitor Self-Updater";
packageProductDependencies = (
C47014FB2C46D31B0069AAE7 /* NVAppUpdater */,
);
productName = "PHP Monitor Updater";
productReference = C406A5F0298AD2CE00B5B85A /* PHP Monitor Self-Updater.app */;
productType = "com.apple.product-type.application";
@ -2258,9 +2267,11 @@
buildRules = (
);
dependencies = (
C4E91D132C0A7A9B00D69A31 /* PBXTargetDependency */,
);
name = "PHP Monitor";
packageProductDependencies = (
C47014FE2C46D57C0069AAE7 /* NVAlert */,
);
productName = phpmon;
productReference = C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */;
@ -2280,6 +2291,9 @@
C471E7B228F9B4940021E251 /* PBXTargetDependency */,
);
name = "Feature Tests";
packageProductDependencies = (
C470150A2C46D81E0069AAE7 /* NVAlert */,
);
productName = "Feature Tests";
productReference = C471E7AD28F9B4940021E251 /* Feature Tests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
@ -2298,6 +2312,9 @@
C471E7C328F9B90F0021E251 /* PBXTargetDependency */,
);
name = "UI Tests";
packageProductDependencies = (
C470150C2C46D83E0069AAE7 /* NVAlert */,
);
productName = "UI Tests";
productReference = C471E7BC28F9B90F0021E251 /* UI Tests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
@ -2317,6 +2334,7 @@
);
name = "Unit Tests";
packageProductDependencies = (
C47015062C46D8180069AAE7 /* NVAlert */,
);
productName = "phpmon-tests";
productReference = C4F7807925D7F84B000DBC97 /* Unit Tests.xctest */;
@ -2330,7 +2348,7 @@
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1420;
LastUpgradeCheck = 1500;
LastUpgradeCheck = 1530;
ORGANIZATIONNAME = "Nico Verbruggen";
TargetAttributes = {
C406A5EF298AD2CE00B5B85A = {
@ -2363,9 +2381,12 @@
"pt-PT",
Base,
fr,
"zh-Hans",
);
mainGroup = C41C1B2A22B0097F00E7CF16;
packageReferences = (
C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */,
C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */,
);
productRefGroup = C41C1B3422B0097F00E7CF16 /* Products */;
projectDirPath = "";
@ -2393,7 +2414,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C4E9D90129CBA09E00BD28D4 /* PHP Monitor Self-Updater.app in Resources */,
C4E91D142C0A7AAA00D69A31 /* PHP Monitor Self-Updater.app in Resources */,
C41C1B3B22B0098000E7CF16 /* Assets.xcassets in Resources */,
C41C1B3E22B0098000E7CF16 /* Main.storyboard in Resources */,
C405A4D124B9B9140062FAFA /* InternetAccessPolicy.plist in Resources */,
@ -2493,10 +2514,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C4C75F5C298C31C000DFD82E /* Utility.swift in Sources */,
C490E3BC29BCA375006D2DE6 /* Measurements.swift in Sources */,
C406A602298AD50D00B5B85A /* Updater.swift in Sources */,
C4C75F5A298C2D5700DFD82E /* LaunchControl.swift in Sources */,
C41F3D08298AED0D0042ACBF /* System.swift in Sources */,
C406A5F3298AD2CE00B5B85A /* main.swift in Sources */,
);
@ -2537,12 +2555,12 @@
C48DDD0D29C75C9E00D032D9 /* BlockingOverlayView.swift in Sources */,
C45B91532956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
C41C708D28AA7F7900E8D498 /* NoWarningsView.swift in Sources */,
C4080FF627BD8C6400BF2C6B /* BetterAlert.swift in Sources */,
0309E6672B0D4B2F002AC007 /* BrewExtensionsObservable.swift in Sources */,
C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */,
C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */,
C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
C4E49DE728F764050026AC4E /* ActiveCommand.swift in Sources */,
C43B8FD52BA9BAD3000C02BE /* UnavailableContentView.swift in Sources */,
54FCFD30276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */,
C450C8C628C919EC002A2B4B /* PreferenceName.swift in Sources */,
C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */,
@ -2565,6 +2583,7 @@
031E2B692B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */,
C4AD38B228ECD9D300FA8D83 /* TestableFileSystem.swift in Sources */,
C4EB53E528551F9B006F9937 /* HeaderView.swift in Sources */,
C4EA3C472BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */,
C40FE737282ABA4F00A302C2 /* AppVersion.swift in Sources */,
C44A874828905BB000498BC4 /* ProgressVC.swift in Sources */,
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */,
@ -2663,18 +2682,17 @@
033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */,
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */,
C4D36615291160A1006BD146 /* WIP.swift in Sources */,
C485707028BF452300539B36 /* PhpDoctorWindowController.swift in Sources */,
C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */,
C40D725A2A018ACC0054A067 /* BusyStatus.swift in Sources */,
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
C4FACE83288F1F9700FC478F /* OnboardingWindowController.swift in Sources */,
C4415E8D2B0287E90035F520 /* BrewFormulaeObservable.swift in Sources */,
C4080FFA27BD956700BF2C6B /* BetterAlertVC.swift in Sources */,
C43FDBE929A932B0003D85EC /* PhpConfigChecker.swift in Sources */,
C4BF56AB2949381100379603 /* FakeValetInteractor.swift in Sources */,
C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */,
C451AFF62969E40F0078E617 /* HelpButton.swift in Sources */,
C46DC7A42C7B55DC00F19D17 /* Favorites.swift in Sources */,
54D9E0B627E4F51E003B9AD9 /* HotKey.swift in Sources */,
C4AFC4AE29C4F32F00BF4E0D /* BrewPhpFormula.swift in Sources */,
C4D936C927E3EB6100BD69FE /* PhpHelper.swift in Sources */,
@ -2682,8 +2700,8 @@
C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */,
54D9E0BA27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */,
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */,
C4821C5A2C2DEDE200357A68 /* AppMenu.swift in Sources */,
C42106662AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C40508AF28ADA23D008FAC1F /* NoDomainResultsView.swift in Sources */,
C4B79ECB29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
C40D725F2A018AE30054A067 /* BrewFormula+UI.swift in Sources */,
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */,
@ -2699,6 +2717,7 @@
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */,
C493084A279F331F009C240B /* AddSiteVC.swift in Sources */,
C4DEB7D427A5D60B00834718 /* Stats.swift in Sources */,
C47015022C46D6910069AAE7 /* NVAlertExtension.swift in Sources */,
C4E49DEA28F7643D0026AC4E /* CommandProtocol.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -2756,7 +2775,6 @@
C471E85428F9BB650021E251 /* StatusMenu.swift in Sources */,
C471E85528F9BB650021E251 /* StatusMenu+Items.swift in Sources */,
C471E85628F9BB650021E251 /* DomainListCellProtocol.swift in Sources */,
C4D36617291160A1006BD146 /* WIP.swift in Sources */,
C471E85728F9BB650021E251 /* DomainListTLSCell.swift in Sources */,
C471E85828F9BB650021E251 /* DomainListNameCell.swift in Sources */,
C4B79EBE29CA38DB00A483EE /* BrewCommand.swift in Sources */,
@ -2773,6 +2791,7 @@
C4E2E86628FC2F1B003B070C /* XCPMApplication.swift in Sources */,
C471E85F28F9BB650021E251 /* DomainListVC+Actions.swift in Sources */,
C4D5576629C77CC5001A44CD /* PhpVersionManagerWindowController.swift in Sources */,
C47015042C46D7F00069AAE7 /* NVAlertExtension.swift in Sources */,
C4ACE9E329F84EDD00110766 /* PhpGuard.swift in Sources */,
C471E86028F9BB650021E251 /* SelectionVC.swift in Sources */,
C471E86128F9BB650021E251 /* AddSiteVC.swift in Sources */,
@ -2801,6 +2820,7 @@
C471E86E28F9BB650021E251 /* MenuBarIcons.swift in Sources */,
C471E86F28F9BB650021E251 /* Stats.swift in Sources */,
C4CE7F9829683B43000102CF /* PhpVersionNumberCollection.swift in Sources */,
C4EA3C492BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */,
C471E87028F9BB650021E251 /* GlobalKeybindPreference.swift in Sources */,
C471E87228F9BB650021E251 /* CheckboxPreferenceView.swift in Sources */,
C471E87428F9BB650021E251 /* SelectPreferenceView.swift in Sources */,
@ -2817,7 +2837,6 @@
C471E88128F9BB650021E251 /* NoWarningsView.swift in Sources */,
C471E88228F9BB650021E251 /* OnboardingView.swift in Sources */,
C471E88328F9BB650021E251 /* VersionPopoverView.swift in Sources */,
C471E88428F9BB650021E251 /* NoDomainResultsView.swift in Sources */,
C4513F952B13E30C001AD760 /* BrewExtensionsObservable.swift in Sources */,
C471E88528F9BB650021E251 /* ServicesView.swift in Sources */,
C471E88628F9BB650021E251 /* StatsView.swift in Sources */,
@ -2834,11 +2853,13 @@
C471E88F28F9BB650021E251 /* ModifierFlagsExtension.swift in Sources */,
C456A0CD2AA6166F0080144F /* BytePhpPreference.swift in Sources */,
C471E7E928F9BAC20021E251 /* Paths.swift in Sources */,
C43B8FD72BA9C689000C02BE /* UnavailableContentView.swift in Sources */,
C45B91552956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
C471E7FE28F9BACE0021E251 /* HomebrewDecodable.swift in Sources */,
C4415E8F2B0287E90035F520 /* BrewFormulaeObservable.swift in Sources */,
C471E7D828F9BA8F0021E251 /* FileSystemProtocol.swift in Sources */,
C471E7F328F9BAC70021E251 /* PhpHelper.swift in Sources */,
C46DC7A62C7B5BC900F19D17 /* Favorites.swift in Sources */,
C471E7E728F9BAC20021E251 /* Constants.swift in Sources */,
C471E81628F9BAE80021E251 /* DateExtension.swift in Sources */,
C469E700294CF7B200A82AB2 /* FakeValetProxy.swift in Sources */,
@ -2863,7 +2884,6 @@
C471E82A28F9BB330021E251 /* ValetListable.swift in Sources */,
031E2B6B2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */,
C471E82728F9BB310021E251 /* BrewDiagnostics.swift in Sources */,
C471E81C28F9BB250021E251 /* BetterAlert.swift in Sources */,
C471E7DB28F9BA8F0021E251 /* RealShell.swift in Sources */,
C490E3B929BCA368006D2DE6 /* App+BrewWatch.swift in Sources */,
C471E7FF28F9BAD10021E251 /* Xdebug.swift in Sources */,
@ -2880,7 +2900,6 @@
C42106682AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C4B79EC829CA474200A483EE /* FakeCommand.swift in Sources */,
C471E7DE28F9BAA30021E251 /* CommandProtocol.swift in Sources */,
C471E81B28F9BB250021E251 /* BetterAlertVC.swift in Sources */,
C471E82928F9BB330021E251 /* Valet.swift in Sources */,
C471E80728F9BAD40021E251 /* PhpConfigurationFile.swift in Sources */,
C471E7D528F9BA8F0021E251 /* TestableConfigurations.swift in Sources */,
@ -2901,6 +2920,7 @@
C471E7D628F9BA8F0021E251 /* RealFileSystem.swift in Sources */,
C471E81728F9BAE80021E251 /* NSMenuExtension.swift in Sources */,
C40D725C2A018ACC0054A067 /* BusyStatus.swift in Sources */,
C4821C5C2C2DEDE200357A68 /* AppMenu.swift in Sources */,
C471E81328F9BAE80021E251 /* XibLoadable.swift in Sources */,
C4D3661C291173EA006BD146 /* DictionaryExtension.swift in Sources */,
C4B79ECD29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
@ -2966,6 +2986,7 @@
C471E8B828F9BB8F0021E251 /* StatusMenu+Items.swift in Sources */,
C471E8B928F9BB8F0021E251 /* DomainListCellProtocol.swift in Sources */,
C471E8BA28F9BB8F0021E251 /* DomainListTLSCell.swift in Sources */,
C43B8FD82BA9C689000C02BE /* UnavailableContentView.swift in Sources */,
C471E8BB28F9BB8F0021E251 /* DomainListNameCell.swift in Sources */,
C471E8BC28F9BB8F0021E251 /* DomainListPhpCell.swift in Sources */,
C471E8BD28F9BB8F0021E251 /* DomainListTypeCell.swift in Sources */,
@ -2978,7 +2999,7 @@
C471E8C128F9BB8F0021E251 /* DomainListVC+ContextMenu.swift in Sources */,
C4BF56AE2949381100379603 /* FakeValetInteractor.swift in Sources */,
C471E8C228F9BB8F0021E251 /* DomainListVC+Actions.swift in Sources */,
C4D36618291160A1006BD146 /* WIP.swift in Sources */,
C4821C5D2C2DEDE200357A68 /* AppMenu.swift in Sources */,
C471E8C328F9BB8F0021E251 /* SelectionVC.swift in Sources */,
C471E8C428F9BB8F0021E251 /* AddSiteVC.swift in Sources */,
C45B91562956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
@ -2986,10 +3007,12 @@
C471E8C628F9BB8F0021E251 /* PMTableView.swift in Sources */,
C471E8C728F9BB8F0021E251 /* Warning.swift in Sources */,
C471E8C828F9BB8F0021E251 /* WarningManager.swift in Sources */,
C46DC7A72C7B5BCA00F19D17 /* Favorites.swift in Sources */,
C471E8C928F9BB8F0021E251 /* PhpDoctorWindowController.swift in Sources */,
C41ADCEB2970CCC700120423 /* FSNotifier.swift in Sources */,
C471E8CA28F9BB8F0021E251 /* OnboardingWindowController.swift in Sources */,
C456A0C92AA614BD0080144F /* PhpPreference.swift in Sources */,
C4EA3C4A2BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */,
C4D4CB3A29C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */,
C471E8CB28F9BB8F0021E251 /* PreferencesWindowController.swift in Sources */,
C471E8CC28F9BB8F0021E251 /* PreferencesWindowController+Hotkey.swift in Sources */,
@ -3024,7 +3047,6 @@
C4B79EBF29CA38DB00A483EE /* BrewCommand.swift in Sources */,
C45D654F29F52F74004C28F9 /* BrewPermissionFixer.swift in Sources */,
C471E8E628F9BB8F0021E251 /* VersionPopoverView.swift in Sources */,
C471E8E728F9BB8F0021E251 /* NoDomainResultsView.swift in Sources */,
C471E8E828F9BB8F0021E251 /* ServicesView.swift in Sources */,
C4E2E85F28FC282B003B070C /* TestableConfiguration.swift in Sources */,
C471E8E928F9BB8F0021E251 /* StatsView.swift in Sources */,
@ -3034,6 +3056,7 @@
C456A0CE2AA6166F0080144F /* BytePhpPreference.swift in Sources */,
C4FD87A829AB9ABD0002D701 /* PhpConfigChecker.swift in Sources */,
C45B9151295608E300F4EC78 /* ValetServicesManager.swift in Sources */,
C47015032C46D7F00069AAE7 /* NVAlertExtension.swift in Sources */,
C471E8EC28F9BB8F0021E251 /* SwiftUIHelper.swift in Sources */,
C471E8EE28F9BB8F0021E251 /* HotKey.swift in Sources */,
C471E8EF28F9BB8F0021E251 /* HotKeysController.swift in Sources */,
@ -3074,7 +3097,6 @@
C4463FCF29804BCB007B93D5 /* RCFile.swift in Sources */,
C471E82C28F9BB340021E251 /* ValetListable.swift in Sources */,
C471E82828F9BB310021E251 /* BrewDiagnostics.swift in Sources */,
C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */,
C43BCD4729FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */,
C44E985F29B23EBF0059F773 /* UpdateCheckTest.swift in Sources */,
C4513F8E2B13E2E5001AD760 /* PhpExtensionManagerWindowController.swift in Sources */,
@ -3090,7 +3112,6 @@
C471E7DD28F9BAA30021E251 /* CommandProtocol.swift in Sources */,
C471E7D128F9BA630021E251 /* RealFileSystem.swift in Sources */,
033D459B2B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */,
C471E81D28F9BB260021E251 /* BetterAlertVC.swift in Sources */,
C471E82B28F9BB340021E251 /* Valet.swift in Sources */,
C471E80328F9BAD40021E251 /* PhpConfigurationFile.swift in Sources */,
C471E7C928F9BA2F0021E251 /* TestableConfigurations.swift in Sources */,
@ -3147,7 +3168,6 @@
C44A874928905BB000498BC4 /* ProgressVC.swift in Sources */,
C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */,
C485707528BF454F00539B36 /* StatsView.swift in Sources */,
C4080FFB27BD956700BF2C6B /* BetterAlertVC.swift in Sources */,
C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */,
54D9E0BB27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */,
C485707328BF454300539B36 /* OnboardingView.swift in Sources */,
@ -3180,6 +3200,7 @@
C4C0E8E327F88B13002D32A9 /* ValetDomainScanner.swift in Sources */,
C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */,
C4B5635F276AB09000F12CCB /* VersionExtractor.swift in Sources */,
C4821C5B2C2DEDE200357A68 /* AppMenu.swift in Sources */,
C463E381284930EE00422731 /* PresetHelper.swift in Sources */,
C441CC572AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
C4F520672AF03791006787F2 /* ExtensionEnumeratorTest.swift in Sources */,
@ -3194,6 +3215,7 @@
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */,
C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */,
C42106672AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C46DC7A52C7B5BC900F19D17 /* Favorites.swift in Sources */,
C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
C4FC21B128391F8E00D368BB /* MainMenu+Actions.swift in Sources */,
54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */,
@ -3239,13 +3261,11 @@
C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */,
C417DC75277614690015E6EE /* Helpers.swift in Sources */,
C469E6FF294CF7B200A82AB2 /* FakeValetProxy.swift in Sources */,
C4080FF727BD8C6400BF2C6B /* BetterAlert.swift in Sources */,
C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */,
5489625928313231004F647A /* CreatedFromFile.swift in Sources */,
C4513F932B13E2FB001AD760 /* PhpExtensionManagerView.swift in Sources */,
C471E79328F9B21F0021E251 /* ActiveFileSystem.swift in Sources */,
54D9E0B327E4F51E003B9AD9 /* HotKeysController.swift in Sources */,
C4D36616291160A1006BD146 /* WIP.swift in Sources */,
03E36FE828D9219000636F7F /* ActiveShell.swift in Sources */,
C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
C4E2E86528FC2F1B003B070C /* XCPMApplication.swift in Sources */,
@ -3253,6 +3273,7 @@
C489E0BC2A220A4200323F5E /* FakeBrewFormulaeHandler.swift in Sources */,
C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */,
C4B79ECC29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
C43B8FD62BA9C689000C02BE /* UnavailableContentView.swift in Sources */,
C4FD87AA29AB9ABD0002D701 /* PhpConfigChecker.swift in Sources */,
C485707D28BF45A200539B36 /* WarningView.swift in Sources */,
C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */,
@ -3272,6 +3293,7 @@
031E2B6A2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */,
C4998F0B2617633900B2526E /* PreferencesWindowController.swift in Sources */,
C485707228BF453800539B36 /* SwiftUIHelper.swift in Sources */,
C4EA3C482BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */,
C4F2E43B27530F750020E974 /* PhpInstallation.swift in Sources */,
C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */,
C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */,
@ -3296,6 +3318,7 @@
C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */,
C4C0E8E027F88AEB002D32A9 /* FakeDomainScanner.swift in Sources */,
C4463FCD29804BCB007B93D5 /* RCFile.swift in Sources */,
C47015052C46D7F10069AAE7 /* NVAlertExtension.swift in Sources */,
C409349E298EE8E900D25014 /* AppUpdater.swift in Sources */,
C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */,
C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */,
@ -3355,6 +3378,11 @@
target = C41C1B3222B0097F00E7CF16 /* PHP Monitor */;
targetProxy = C471E7C228F9B90F0021E251 /* PBXContainerItemProxy */;
};
C4E91D132C0A7A9B00D69A31 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C406A5EF298AD2CE00B5B85A /* PHP Monitor Self-Updater */;
targetProxy = C4E91D122C0A7A9B00D69A31 /* PBXContainerItemProxy */;
};
C4F7807F25D7F84B000DBC97 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C41C1B3222B0097F00E7CF16 /* PHP Monitor */;
@ -3380,6 +3408,7 @@
C4DD662A2A4A1B4E00D6A731 /* de */,
C4622F572A7593CB0016F8FB /* pt-PT */,
0336CAAF2B0D0CDA009A1034 /* fr */,
C453874C2BE37FD6002B9C65 /* zh-Hans */,
);
name = Localizable.strings;
sourceTree = "<group>";
@ -3406,16 +3435,17 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "PHP Monitor Self-Updater";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023-2024 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
@ -3440,16 +3470,17 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "PHP Monitor Self-Updater";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023-2024 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
@ -3474,16 +3505,17 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "PHP Monitor Self-Updater";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023-2024 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
@ -3508,16 +3540,17 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "PHP Monitor Self-Updater";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023-2024 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
@ -3655,7 +3688,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1422;
CURRENT_PROJECT_VERSION = 1516;
DEAD_CODE_STRIPPING = YES;
DEBUG = YES;
DEVELOPMENT_TEAM = 8M54J5J787;
@ -3668,7 +3701,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 7.0;
MARKETING_VERSION = 7.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -3686,7 +3719,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1422;
CURRENT_PROJECT_VERSION = 1516;
DEAD_CODE_STRIPPING = YES;
DEBUG = NO;
DEVELOPMENT_TEAM = 8M54J5J787;
@ -3699,7 +3732,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 7.0;
MARKETING_VERSION = 7.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -3927,7 +3960,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1422;
CURRENT_PROJECT_VERSION = 1516;
DEAD_CODE_STRIPPING = YES;
DEBUG = NO;
DEVELOPMENT_TEAM = 8M54J5J787;
@ -3940,7 +3973,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 7.0;
MARKETING_VERSION = 7.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) DEV";
@ -4044,7 +4077,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1422;
CURRENT_PROJECT_VERSION = 1516;
DEAD_CODE_STRIPPING = YES;
DEBUG = YES;
DEVELOPMENT_TEAM = 8M54J5J787;
@ -4057,7 +4090,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 7.0;
MARKETING_VERSION = 7.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) DEV";
@ -4161,7 +4194,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1422;
CURRENT_PROJECT_VERSION = 1516;
DEAD_CODE_STRIPPING = YES;
DEBUG = YES;
DEVELOPMENT_TEAM = 8M54J5J787;
@ -4174,7 +4207,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 7.0;
MARKETING_VERSION = 7.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) EAP";
@ -4202,16 +4235,17 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "PHP Monitor Self-Updater";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023-2024 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
@ -4343,7 +4377,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1422;
CURRENT_PROJECT_VERSION = 1516;
DEAD_CODE_STRIPPING = YES;
DEBUG = NO;
DEVELOPMENT_TEAM = 8M54J5J787;
@ -4356,7 +4390,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 7.0;
MARKETING_VERSION = 7.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) EAP";
@ -4384,16 +4418,17 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "PHP Monitor Self-Updater";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023-2024 Nico Verbruggen. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
@ -4582,6 +4617,53 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/nicoverbruggen/NVAppUpdater";
requirement = {
branch = main;
kind = branch;
};
};
C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/nicoverbruggen/NVAlert";
requirement = {
branch = main;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
C47014FB2C46D31B0069AAE7 /* NVAppUpdater */ = {
isa = XCSwiftPackageProductDependency;
package = C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */;
productName = NVAppUpdater;
};
C47014FE2C46D57C0069AAE7 /* NVAlert */ = {
isa = XCSwiftPackageProductDependency;
package = C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */;
productName = NVAlert;
};
C47015062C46D8180069AAE7 /* NVAlert */ = {
isa = XCSwiftPackageProductDependency;
package = C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */;
productName = NVAlert;
};
C470150A2C46D81E0069AAE7 /* NVAlert */ = {
isa = XCSwiftPackageProductDependency;
package = C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */;
productName = NVAlert;
};
C470150C2C46D83E0069AAE7 /* NVAlert */ = {
isa = XCSwiftPackageProductDependency;
package = C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */;
productName = NVAlert;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = C41C1B2B22B0097F00E7CF16 /* Project object */;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1540"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1540"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1540"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1540"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1540"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -4,19 +4,20 @@
Generally speaking, only the latest version of **PHP Monitor** is supported, except during transition periods (for example, when particular system requirements go up):
| Version | Apple Silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Recommended Valet Version |
| Version | Apple Silicon | Supported | Supported macOS | Minimum Deployment | Detected PHP Versions | Recommended Valet Version |
| ------- | ------------- | ------------------ | ----- | ----- | ----- | ----
| 6.2 | ✅ Universal binary | ✅ Yes | Monterey (12.4+)<br/>Ventura (13.0+)<br/>Sonoma (14.0) | macOS 12.4 | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.4 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.4 (w/ Valet 4.x)| 3.0 or higher recommended<br/> 2.16.2 minimum |
| 7.0 | ✅ Universal binary | ✅ Yes | Monterey (12.4+)<br/>Ventura (13.0+)<br/>Sonoma (14.0) | macOS 12.4+ | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.4 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.4 (w/ Valet 4.x)| 3.0 or higher recommended<br/> 2.16.2 minimum |
## Legacy versions
These versions of PHP Monitor are no longer supported, but if youre using an older computer with an older version of Homebrew, Valet or macOS, you might want to use one of these versions.
| Version | Apple Silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Minimum Required Valet Version |
| Version | Apple Silicon | Supported | Supported macOS | Minimum Deployment | Detected PHP Versions | Minimum Required Valet Version |
| ------- | ------------- | ------------------ | ----- | ----- | ----- | ----
| 6.1 | ✅ Universal binary | ❌ | Monterey (12.4+)<br/>Ventura (13.0+)<br/>Sonoma (14.0) | macOS 12.4 | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.4 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.4 (w/ Valet 4.x)| 3.0 or higher recommended<br/> 2.16.2 minimum |
| 6.0 | ✅ Universal binary | ❌ | Monterey (12.4+)<br/>Ventura (13.0+) | macOS 12.4 | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.2 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.2 (w/ Valet 4.x) | 3.0 or higher recommended<br/> 2.16.2 minimum |
| 5.8 | ✅ Universal binary | ❌ | Monterey (12.4+)<br/>Ventura (13.0+) | macOS 12.4 | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.2 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.2 (w/ Valet 4.x) | 3.0 or higher recommended<br/> 2.16.2 minimum |
| 6.2 | ✅ Universal binary | ❌ | Monterey (12.4+)<br/>Ventura (13.0+)<br/>Sonoma (14.0) | macOS 12.4+ | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.4 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.4 (w/ Valet 4.x)| 3.0 or higher recommended<br/> 2.16.2 minimum |
| 6.1 | ✅ Universal binary | ❌ | Monterey (12.4+)<br/>Ventura (13.0+)<br/>Sonoma (14.0) | macOS 12.4+ | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.4 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.4 (w/ Valet 4.x)| 3.0 or higher recommended<br/> 2.16.2 minimum |
| 6.0 | ✅ Universal binary | ❌ | Monterey (12.4+)<br/>Ventura (13.0+) | macOS 12.4+ | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.2 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.2 (w/ Valet 4.x) | 3.0 or higher recommended<br/> 2.16.2 minimum |
| 5.8 | ✅ Universal binary | ❌ | Monterey (12.4+)<br/>Ventura (13.0+) | macOS 12.4+ | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.2 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.2 (w/ Valet 4.x) | 3.0 or higher recommended<br/> 2.16.2 minimum |
| 5.7 | ✅ Universal binary | ❌ | Big Sur (11.0)<br/>Monterey (12.0)<br/>Ventura (13.0) | macOS 11+ | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.2 (w/ Valet 3.x)<br/>PHP 7.1-PHP 8.2 (w/ Valet 4.x) | 3.0 or higher recommended<br/> 2.16.2 minimum |
| 5.6 | ✅ Universal binary | ❌ | Big Sur (11.0)<br/>Monterey (12.0)<br/>Ventura (13.0) | macOS 11+ | PHP 5.6—PHP 8.2 (w/ Valet 2.x)<br/>PHP 7.0—PHP 8.2 (w/ Valet 3.x) | 3.0 recommended<br/> 2.16.2 minimum |
| 4.1 | ✅ Universal binary | ❌ | Big Sur (11.0)<br/>Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 | 2.16.2 |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 674 KiB

After

Width:  |  Height:  |  Size: 723 KiB

View File

@ -1,46 +0,0 @@
//
// LaunchControl.swift
// PHP Monitor Self-Updater
//
// Created by Nico Verbruggen on 02/02/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
class LaunchControl {
public static func smartRestart(priority: [String]) async {
for appPath in priority {
if FileManager.default.fileExists(atPath: appPath) {
let app = await LaunchControl.startApplication(at: appPath)
if app != nil {
return
}
}
}
}
public static func terminateApplications(bundleIds: [String]) async {
let runningApplications = NSWorkspace.shared.runningApplications
// Terminate all instances found
for id in bundleIds {
if let phpmon = runningApplications.first(where: {
(application) in return application.bundleIdentifier == id
}) {
phpmon.terminate()
}
}
}
public static func startApplication(at path: String) async -> NSRunningApplication? {
await withCheckedContinuation { continuation in
let url = NSURL(fileURLWithPath: path, isDirectory: true) as URL
let configuration = NSWorkspace.OpenConfiguration()
NSWorkspace.shared.openApplication(at: url, configuration: configuration) { phpmon, error in
continuation.resume(returning: phpmon)
}
}
}
}

View File

@ -1,162 +0,0 @@
//
// Updater.swift
// PHP Monitor Updater
//
// Created by Nico Verbruggen on 01/02/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Cocoa
class Updater: NSObject, NSApplicationDelegate {
var updaterDirectory: String = ""
var manifestPath: String = ""
var manifest: ReleaseManifest! = nil
func applicationDidFinishLaunching(_ aNotification: Notification) {
Task { await self.installUpdate() }
}
func installUpdate() async {
print("PHP MONITOR SELF-UPDATER by Nico Verbruggen")
print("===========================================")
self.updaterDirectory = "~/.config/phpmon/updater"
.replacingOccurrences(of: "~", with: NSHomeDirectory())
print("Updater directory set to: \(self.updaterDirectory)")
self.manifestPath = "\(updaterDirectory)/update.json"
// Fetch the manifest on the local filesystem
let manifest = await parseManifest()!
// Download the latest file
let zipPath = await download(manifest)
// Terminate all instances of PHP Monitor first
await LaunchControl.terminateApplications(bundleIds: [
"com.nicoverbruggen.phpmon.eap",
"com.nicoverbruggen.phpmon.dev",
"com.nicoverbruggen.phpmon"
])
// Install the app based on the zip
let appPath = await extractAndInstall(zipPath: zipPath)
// Restart PHP Monitor, this will also close the updater
_ = await LaunchControl.startApplication(at: appPath)
exit(1)
}
func applicationWillTerminate(_ aNotification: Notification) {
exit(1)
}
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return false
}
private func parseManifest() async -> ReleaseManifest? {
// Read out the correct information from the manifest JSON
print("Checking manifest file at \(manifestPath)...")
do {
let manifestText = try String(contentsOfFile: manifestPath)
manifest = try JSONDecoder().decode(ReleaseManifest.self, from: manifestText.data(using: .utf8)!)
return manifest
} catch {
print("Parsing the manifest failed (or the manifest file doesn't exist)!")
await Alert.show(description: "The manifest file for a potential update was not found. Please try searching for updates again in PHP Monitor.")
}
return nil
}
private func download(_ manifest: ReleaseManifest) async -> String {
// Remove all zips
system_quiet("rm -rf \(updaterDirectory)/*.zip")
// Download the file (and follow redirects + no output on failure)
system_quiet("cd \"\(updaterDirectory)\" && curl \(manifest.url) -fLO --max-time 20")
// Identify the downloaded file
let filename = system("cd \"\(updaterDirectory)\" && ls | grep .zip")
.trimmingCharacters(in: .whitespacesAndNewlines)
// Ensure the zip exists
if filename.isEmpty {
print("The update has not been downloaded. Sadly, that means that PHP Monitor cannot not updated!")
await Alert.show(description: "The update could not be downloaded, or the file was not correctly written to disk. \n\nPlease try again. \n\n(Note that the download will time-out after 20 seconds, so for slow connections it is recommended to manually download the update.)")
}
// Calculate the checksum for the downloaded file
let checksum = system("openssl dgst -sha256 \"\(updaterDirectory)/\(filename)\" | awk '{print $NF}'")
.trimmingCharacters(in: .whitespacesAndNewlines)
// Compare the checksums
print("""
Comparing checksums...
Expected SHA256: \(manifest.sha256)
Actual SHA256: \(checksum)
""")
// Make sure the checksum matches before we do anything with the file
if checksum != manifest.sha256 {
print("The checksums failed to match. Cancelling!")
await Alert.show(description: "The downloaded update failed checksum validation. Please try again. If this issue persists, there may be an issue with the server and I do not recommend upgrading.")
}
// Return the path to the zip
return "\(updaterDirectory)/\(filename)"
}
private func extractAndInstall(zipPath: String) async -> String {
// Remove the directory that will contain the extracted update
system_quiet("rm -rf \"\(updaterDirectory)/extracted\"")
// Recreate the directory where we will unzip the .app file
system_quiet("mkdir -p \"\(updaterDirectory)/extracted\"")
// Make sure the updater directory exists
var isDirectory: ObjCBool = true
if !FileManager.default.fileExists(atPath: "\(updaterDirectory)/extracted", isDirectory: &isDirectory) {
await Alert.show(description: "The updater directory is missing. The automatic updater will quit. Make sure that ` ~/.config/phpmon/updater` is writeable.")
}
// Unzip the file
system_quiet("unzip \"\(zipPath)\" -d \"\(updaterDirectory)/extracted\"")
// Find the .app file
let app = system("ls \"\(updaterDirectory)/extracted\" | grep .app")
.trimmingCharacters(in: .whitespacesAndNewlines)
print("Finished extracting: \(updaterDirectory)/extracted/\(app)")
// Make sure the file was extracted
if app.isEmpty {
await Alert.show(description: "The downloaded file could not be extracted. The automatic updater will quit. Make sure that ` ~/.config/phpmon/updater` is writeable.")
}
// Remove the original app
print("Removing \(app) before replacing...")
system_quiet("rm -rf \"/Applications/\(app)\"")
// Move the new app in place
system_quiet("mv \"\(updaterDirectory)/extracted/\(app)\" \"/Applications/\(app)\"")
// Remove the zip
system_quiet("rm \"\(zipPath)\"")
// Remove the manifest
system_quiet("rm \"\(manifestPath)\"")
// Write a file that is only written when we upgraded successfully
system_quiet("touch \"\(updaterDirectory)/upgrade.success\"")
// Return the new location of the app
return "/Applications/\(app)"
}
}

View File

@ -1,34 +0,0 @@
//
// Utility.swift
// PHP Monitor Self-Updater
//
// Created by Nico Verbruggen on 02/02/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
class Alert {
public static func show(description: String, shouldExit: Bool = true) async {
await withUnsafeContinuation { continuation in
DispatchQueue.main.async {
let alert = NSAlert()
alert.messageText = "The app could not be updated."
alert.informativeText = description
alert.addButton(withTitle: "OK")
alert.alertStyle = .critical
alert.runModal()
if shouldExit {
exit(0)
}
continuation.resume()
}
}
}
}
public struct ReleaseManifest: Codable {
let url: String
let sha256: String
}

View File

@ -7,8 +7,17 @@
//
import Cocoa
import NVAppUpdater
let app = NSApplication.shared
let delegate = Updater()
app.delegate = delegate
let delegate = SelfUpdater(
appName: "PHP Monitor",
bundleIdentifiers: [
"com.nicoverbruggen.phpmon.eap",
"com.nicoverbruggen.phpmon.dev",
"com.nicoverbruggen.phpmon"
],
selfUpdaterPath: "~/.config/phpmon/updater"
)
NSApplication.shared.delegate = delegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.172",
"green" : "0.182",
"red" : "0.182"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -24,7 +24,7 @@
"components" : {
"alpha" : "1.000",
"blue" : "0.988",
"green" : "0.723",
"green" : "0.444",
"red" : "0.277"
}
},

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.300",
"blue" : "0.180",
"green" : "0.841",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.300",
"blue" : "0.426",
"green" : "0.809",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,25 @@
{
"images" : [
{
"filename" : "php.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 24 24"><path d="M7.01 10.207h-.944l-.515 2.648h.838c.556 0 .97-.105 1.242-.314.272-.21.455-.559.55-1.049.092-.47.05-.802-.124-.995-.175-.193-.523-.29-1.047-.29zM12 5.688C5.373 5.688 0 8.514 0 12s5.373 6.313 12 6.313S24 15.486 24 12c0-3.486-5.373-6.312-12-6.312zm-3.26 7.451c-.261.25-.575.438-.917.551-.336.108-.765.164-1.285.164H5.357l-.327 1.681H3.652l1.23-6.326h2.65c.797 0 1.378.209 1.744.628.366.418.476 1.002.33 1.752a2.836 2.836 0 0 1-.305.847c-.143.255-.33.49-.561.703zm4.024.715.543-2.799c.063-.318.039-.536-.068-.651-.107-.116-.336-.174-.687-.174H11.46l-.704 3.625H9.388l1.23-6.327h1.367l-.327 1.682h1.218c.767 0 1.295.134 1.586.401s.378.7.263 1.299l-.572 2.944h-1.389zm7.597-2.265a2.782 2.782 0 0 1-.305.847c-.143.255-.33.49-.561.703a2.44 2.44 0 0 1-.917.551c-.336.108-.765.164-1.286.164h-1.18l-.327 1.682h-1.378l1.23-6.326h2.649c.797 0 1.378.209 1.744.628.366.417.477 1.001.331 1.751zm-2.595-1.382h-.943l-.516 2.648h.838c.557 0 .971-.105 1.242-.314.272-.21.455-.559.551-1.049.092-.47.049-.802-.125-.995s-.524-.29-1.047-.29z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -20,6 +20,11 @@ class Actions {
await brew("services restart \(HomebrewFormulae.php)", sudo: HomebrewFormulae.php.elevated)
}
public static func restartPhpFpm(version: String) async {
let formula = (version == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version)"
await brew("services restart \(formula)", sudo: HomebrewFormulae.php.elevated)
}
public static func restartNginx() async {
await brew("services restart \(HomebrewFormulae.nginx)", sudo: HomebrewFormulae.nginx.elevated)
}

View File

@ -30,7 +30,7 @@ struct Constants {
will be displayed to let them know that certain operations
will not work correctly and that they need to update their app.
*/
static let PhpFormulaeCutoffDate = "2024-11-01"
static let PhpFormulaeCutoffDate = "2024-11-30" // YYYY-MM-DD
/**
* The PHP versions that are considered pre-release versions.
@ -39,7 +39,8 @@ struct Constants {
*/
static var ExperimentalPhpVersions: Set<String> {
let releaseDates = [
"8.4": Date.fromString("2024-12-01") // PLACEHOLDER DATE
// "8.5": Date.fromString("2025-11-01"), // PLACEHOLDER DATE
"8.4": Date.fromString("2024-11-22"),
]
return Set(releaseDates
@ -54,6 +55,17 @@ struct Constants {
})
}
/**
The Homebrew services that should be automatically
detected and show up in the list of managed services.
*/
static let DetectedHomebrewServices: Set = [
"mailhog",
"mysql@",
"postgresql@",
"redis"
]
/**
* The PHP versions supported by this application.
* Any other PHP versions are considered invalid.
@ -61,8 +73,7 @@ struct Constants {
static let DetectedPhpVersions: Set = [
"5.6",
"7.0", "7.1", "7.2", "7.3", "7.4",
"8.0", "8.1", "8.2", "8.3",
"8.4"
"8.0", "8.1", "8.2", "8.3", "8.4"
]
/**
@ -78,14 +89,12 @@ struct Constants {
3: // Valet v3 dropped support for v5.6
[
"7.0", "7.1", "7.2", "7.3", "7.4",
"8.0", "8.1", "8.2",
"8.3", "8.4" // dev
"8.0", "8.1", "8.2", "8.3", "8.4"
],
4: // Valet v4 dropped support for v7.0
[
"7.1", "7.2", "7.3", "7.4",
"8.0", "8.1", "8.2",
"8.3", "8.4" // dev
"8.0", "8.1", "8.2", "8.3", "8.4"
]
]

View File

@ -45,7 +45,6 @@ func grepContains(file: String, query: String) async -> Bool {
/**
Attempts to introduce sleep for a particular duration. Use with caution.
Only intended for testing purposes.
*/
func delay(seconds: Double) async {
try! await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))

View File

@ -103,6 +103,10 @@ public class Paths {
}
public static var tapPath: String {
if shared.baseDir == .usr {
return "\(shared.baseDir.rawValue)/homebrew/Library/Taps"
}
return "\(shared.baseDir.rawValue)/Library/Taps"
}

View File

@ -8,6 +8,6 @@
import Foundation
protocol AlertableError {
public protocol AlertableError {
func getErrorMessageKey() -> String
}

View File

@ -0,0 +1,23 @@
//
// NVAlertExtension.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 16/07/2024.
// Copyright © 2024 Nico Verbruggen. All rights reserved.
//
import Foundation
import NVAlert
extension NVAlert {
/**
Shows the modal for a particular error.
*/
@MainActor public static func show(for error: Error & AlertableError) {
let key = error.getErrorMessageKey()
return NVAlert().withInformation(
title: "\(key).title".localized,
subtitle: "\(key).description".localized
).withPrimary(text: "generic.ok".localized).show()
}
}

View File

@ -29,6 +29,8 @@ class PMWindowController: NSWindowController, NSWindowDelegate {
App.shared.remove(window: windowName)
}
func windowDidResize(_ notification: Notification) {}
deinit {
Log.perf("deinit: \(String(describing: self)).\(#function)")
}

View File

@ -1,17 +0,0 @@
//
// WIP.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 01/11/2022.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
func todo(_ context: String = "") {
if !context.isEmpty {
fatalError("To be implemented: \(context)")
}
fatalError("To be implemented")
}

View File

@ -37,6 +37,7 @@ class PhpEnvironments {
from: brewPhpAlias.data(using: .utf8)!
).first!
PhpEnvironments.brewPhpAlias = self.homebrewPackage.version
Log.info("[BREW] On your system, the `php` formula means version \(homebrewPackage.version).")
// Check if that version actually corresponds to an older version

View File

@ -22,6 +22,16 @@ class PhpInstallation {
return self.iniFiles.flatMap({ $0.extensions })
}
var formulaName: String {
let version = self.versionNumber.short
if version == PhpEnvironments.brewPhpAlias {
return "php"
}
return "php@\(self.versionNumber.short)"
}
/**
In order to determine details about a PHP installation,
well simply run `php-config --version` in the relevant directory.

View File

@ -8,9 +8,6 @@
import Foundation
extension Process: @unchecked Sendable {}
extension Timer: @unchecked Sendable {}
class RealShell: ShellProtocol {
/**
The launch path of the terminal in question that is used.
@ -184,25 +181,26 @@ class RealShell: ShellProtocol {
}
return try await withCheckedThrowingContinuation({ continuation in
let timer = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { _ in
let task = Task {
try await Task.sleep(nanoseconds: timeout.nanoseconds)
// Only terminate if the process is still running
if process.isRunning {
process.terminationHandler = nil
process.terminate()
return continuation.resume(throwing: ShellError.timedOut)
continuation.resume(throwing: ShellError.timedOut)
}
}
process.terminationHandler = { [timer, output] process in
timer.invalidate()
process.terminationHandler = { [output] process in
task.cancel()
process.haltListening()
if !output.err.isEmpty {
return continuation.resume(returning: (process, .err(output.err)))
continuation.resume(returning: (process, .err(output.err)))
} else {
continuation.resume(returning: (process, .out(output.out)))
}
return continuation.resume(returning: (process, .out(output.out)))
}
process.launch()
@ -210,3 +208,9 @@ class RealShell: ShellProtocol {
})
}
}
extension TimeInterval {
var nanoseconds: UInt64 {
return UInt64(self * 1_000_000_000)
}
}

View File

@ -18,8 +18,15 @@
<p><b>Want to support further development of PHP Monitor?</b> You can <a href="https://phpmon.app/sponsor">financially support</a> the continued development of this app.</p>
<p><b>Get the latest on Twitter or Mastodon.</b> Give me a <a href="https://twitter.com/nicoverbruggen">follow on Twitter</a> or <a href="https://phpc.social/@nicoverbruggen">Mastodon</a> to learn about what's brewing and when new updates drop.</p>
<p><b>Special thanks</b> to all current and past <a href="https://github.com/sponsors/nicoverbruggen#sponsors"><b>sponsors</b></a> of PHP Monitor, who have helped to make further development of the app possible.</p>
<p><b>Made possible by these GitHub Sponsors</b>: @abdusfauzi, @abicons, @adrolli, @andresayej, @andyunleashed, @anzacorp, @argirisp, @AshPowell, @aurawindsurfing, @awsmug, @barrycarton, @BertvanHoekelen, @calebporzio, @caseyalee, @cgreuling, @cjcox17, @Diewy, @drfraker, @driftingly, @duellsy, @edalzell, @EYOND, @faithfm, @frankmichel, @gwleuverink, @hopkins385, @intrepidws, @jacksleight, @JacobBennett, @jasonvarga, @jeromegamez, @jimmyaldape, @jimmysawczuk, @joetannenbaum, @jolora, @joshuablum, @jpeinelt, @jreviews, @JustSteveKing, @Kajvdh, @KFoobar, @Laravel-Backpack, @leganz, @martinleveille, @mathiasonea, @matthewmnewman, @mcastillo1030, @megabubbletea, @mennen-online, @mike-healy, @mostafakram, @mpociot, @MrMicky-FR, @MrMooky, @murdercode, @nckrtl, @nhedger, @ninjaparade, @ozanuzer, @pepatel, @philbraun, @pickuse2013, @pk-informatics, @Plytas, @rderimay, @rickyjohnston, @rico, @RobertBoes, @runofthemill, @SahinU88, @sdebacker, @sdevore, @shadracnicholas, @simonhamp, @SRWieZ, @stefanbauer, @StriveMedia, @swilla, @Tailcode-Studio, @theutz, @ThomasEnssner, @tillkruss, @timothyrowan, @ttnppedr, @vincent-tarrit, @WheresMarco, @xPand4B, @xuandung38, @yeslandi89, @zackkatz, @zacksmash, @zaherg.<br/>(Some names have been omitted due to their sponsorships being private. Thank you all!)
<p><b>Made possible by these GitHub Sponsors</b>: @abdusfauzi, @abicons, @adrolli, @andresayej, @andyunleashed, @anzacorp, @argirisp, @AshPowell, @aurawindsurfing, @awsmug, @barrycarton, @BertvanHoekelen, @calebporzio, @caseyalee, @cgreuling, @cjcox17, @Diewy, @drfraker, @driftingly, @duellsy, @edalzell, @EYOND, @faithfm, @frankmichel, @gwleuverink, @hopkins385, @intrepidws, @jacksleight, @JacobBennett, @jasonvarga, @jeromegamez, @jimmyaldape, @jimmysawczuk, @joetannenbaum, @jolora, @joshuablum, @jpeinelt, @jreviews, @JustSteveKing, @Kajvdh, @KFoobar, @Laravel-Backpack, @leganz, @martinleveille, @mathiasonea, @matthewmnewman, @mcastillo1030, @megabubbletea, @mennen-online, @mike-healy, @mostafakram, @mpociot, @MrMicky-FR, @MrMooky, @murdercode, @nckrtl, @nhedger, @ninjaparade, @ozanuzer, @pepatel, @philbraun, @pickuse2013, @pk-informatics, @Plytas, @rderimay, @rickyjohnston, @rico, @RobertBoes, @runofthemill, @SahinU88, @sdebacker, @sdevore, @shadracnicholas, @simonhamp, @SRWieZ, @stefanbauer, @StriveMedia, @swilla, @Tailcode-Studio, @theutz, @ThomasEnssner, @tillkruss, @timothyrowan, @ttnppedr, @vincent-tarrit, @WheresMarco, @xPand4B, @xuandung38, @yeslandi89, @zackkatz, @zacksmash, @zaherg.<br/>(Some names have been omitted due to their sponsorships being private. Thank you all!)</p>
<p><b>Localization credits:</b></br>
&dash; English, Dutch</b> by @nicoverbruggen</br>
&dash; Vietnamese</b> by @xuandung38</br>
&dash; German</b> by @dsturm</br>
&dash; Portuguese</b> by @joseborges</br>
&dash; French</b> by @nhedger, @tplesnar</br>
&dash; Chinese</b> by @guanguans</br>
</p>
<br/>
</body>
</html>

View File

@ -89,6 +89,9 @@ class App {
/** List of detected (installed) applications that PHP Monitor can work with. */
var detectedApplications: [Application] = []
/** Favorites storage, which keeps track of favorited domains. */
var favorites = Favorites.shared
/** The warning manager, responsible for keeping track of warnings. */
var warnings = WarningManager.shared

View File

@ -23,12 +23,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
*/
let state: App
/**
The MainMenu singleton is responsible for rendering the
menu bar item and its menu, as well as its actions.
*/
let menu: MainMenu
/**
The paths singleton that determines where Homebrew is installed,
and where to look for binaries.
@ -96,7 +90,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
}
self.state = App.shared
self.menu = MainMenu.shared
self.paths = Paths.shared
self.valet = Valet.shared
self.brew = Brew.shared
@ -132,7 +125,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
setupNotifications()
Task { // Make sure the menu performs its initial checks
await menu.startup()
await MainMenu.shared.startup()
}
}

View File

@ -8,6 +8,7 @@
import Foundation
import Cocoa
import NVAlert
class AppUpdater {
var caskFile: CaskFile!
@ -72,7 +73,7 @@ class AppUpdater {
: "brew upgrade phpmon"
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "updater.alerts.newer_version_available.title"
.localized(latestVersionOnline.humanReadable),
subtitle: "updater.alerts.newer_version_available.subtitle"
@ -112,7 +113,7 @@ class AppUpdater {
public func presentNoNewerVersionAvailableAlert() {
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "updater.alerts.is_latest_version.title".localized,
subtitle: "updater.alerts.is_latest_version.subtitle".localized(App.shortVersion),
description: ""
@ -124,7 +125,7 @@ class AppUpdater {
public func presentCouldNotRetrieveUpdate() {
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "updater.alerts.cannot_check_for_update.title".localized,
subtitle: "updater.alerts.cannot_check_for_update.subtitle".localized,
description: "updater.alerts.cannot_check_for_update.description".localized(

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22155"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22690"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Search Toolbar Item" minToolsVersion="12.0" minSystemVersion="11.0"/>
@ -63,6 +63,13 @@
<action selector="focusSearchField:" target="Voe-Tx-rLC" id="O8j-1B-hll"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bPr-YU-lg4"/>
<menuItem title="actions" enabled="NO" id="cAS-FU-WUA" userLabel="actions" customClass="LocalizedMenuItem" customModule="PHP_Monitor" customModuleProvider="target">
<modifierMask key="keyEquivalentModifierMask"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="localizationKey" value="mm_actions"/>
</userDefinedRuntimeAttributes>
</menuItem>
</items>
</menu>
</menuItem>
@ -508,10 +515,10 @@
</objects>
<point key="canvasLocation" x="-374" y="2267"/>
</scene>
<!--Better AlertVC-->
<!--AlertVC-->
<scene sceneID="y9E-bB-wIG">
<objects>
<viewController storyboardIdentifier="noticeVC" id="hkw-9V-NxP" customClass="BetterAlertVC" customModule="PHP_Monitor" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="noticeVC" id="hkw-9V-NxP" customClass="NVAlertVC" customModule="PHP_Monitor" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="UPH-hV-Naz">
<rect key="frame" x="0.0" y="0.0" width="500" height="212"/>
<autoresizingMask key="autoresizingMask"/>
@ -819,14 +826,21 @@ Gw
<rect key="frame" x="0.0" y="0.0" width="626" height="309"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<progressIndicator maxValue="100" displayedWhenStopped="NO" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="ZiS-Gq-TLQ">
<rect key="frame" x="298" y="150" width="30" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="XK3-AR-Oc0"/>
<constraint firstAttribute="height" constant="30" id="lfW-dB-Eu3"/>
</constraints>
</progressIndicator>
<scrollView borderType="none" horizontalLineScroll="54" horizontalPageScroll="10" verticalLineScroll="54" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p0j-eB-I2i">
<rect key="frame" x="0.0" y="0.0" width="626" height="309"/>
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="6IL-DW-37w">
<rect key="frame" x="0.0" y="0.0" width="626" height="309"/>
<rect key="frame" x="0.0" y="0.0" width="611" height="294"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" multipleSelection="NO" autosaveName="phpmon-sitelist-columns" rowHeight="54" headerView="xUg-Mq-OSh" viewBased="YES" id="cp3-34-pQj" customClass="PMTableView" customModule="PHP_Monitor" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="626" height="281"/>
<rect key="frame" x="0.0" y="0.0" width="611" height="266"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="17" height="0.0"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -916,6 +930,50 @@ Gw
<outlet property="labelSiteName" destination="XJL-Uw-frD" id="f0t-vd-W68"/>
</connections>
</tableCellView>
<tableCellView identifier="domainListNameCellFavorited" wantsLayer="YES" id="Byb-te-u65" customClass="DomainListNameCell" customModule="PHP_Monitor" customModuleProvider="target">
<rect key="frame" x="69" y="54" width="200" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="aot-FJ-HIk">
<rect key="frame" x="33" y="26" width="145" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="my-domain-name.test" id="LHu-UF-QlC">
<font key="font" metaFont="systemSemibold" size="13"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="GNH-l8-oki">
<rect key="frame" x="33" y="12" width="75" height="14"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="~/path/to/site" id="LNw-Ju-0Ot">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="3Wp-DX-An9">
<rect key="frame" x="5" y="4" width="20" height="47"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="Q76-fI-lkW">
<imageReference key="image" image="star.circle.fill" catalog="system" symbolScale="large"/>
</imageCell>
<color key="contentTintColor" name="AccentColor"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="3Wp-DX-An9" firstAttribute="leading" secondItem="Byb-te-u65" secondAttribute="leading" constant="5" id="CTd-ON-loK"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="aot-FJ-HIk" secondAttribute="trailing" constant="20" symbolic="YES" id="Csc-Dy-H4K"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="GNH-l8-oki" secondAttribute="trailing" constant="20" symbolic="YES" id="H10-MG-hCG"/>
<constraint firstItem="GNH-l8-oki" firstAttribute="leading" secondItem="aot-FJ-HIk" secondAttribute="leading" id="Hk0-x3-RyN"/>
<constraint firstItem="3Wp-DX-An9" firstAttribute="top" secondItem="Byb-te-u65" secondAttribute="top" constant="9" id="erH-dR-K7S"/>
<constraint firstItem="aot-FJ-HIk" firstAttribute="top" secondItem="Byb-te-u65" secondAttribute="top" constant="12" id="ktI-fg-qaX"/>
<constraint firstAttribute="bottom" secondItem="3Wp-DX-An9" secondAttribute="bottom" constant="9" id="uyc-26-gZb"/>
<constraint firstItem="aot-FJ-HIk" firstAttribute="leading" secondItem="Byb-te-u65" secondAttribute="leading" constant="35" id="vXE-jj-lLF"/>
<constraint firstItem="GNH-l8-oki" firstAttribute="top" secondItem="aot-FJ-HIk" secondAttribute="bottom" id="wSX-fR-O7a"/>
</constraints>
<connections>
<outlet property="labelPathName" destination="GNH-l8-oki" id="GC1-TA-lIk"/>
<outlet property="labelSiteName" destination="aot-FJ-HIk" id="HdZ-Rh-ua6"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="ENVIRONMENT" width="100" minWidth="100" maxWidth="150" id="hzb-XI-Out">
@ -1073,28 +1131,30 @@ Gw
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="620" id="iRQ-sz-oyv"/>
</constraints>
<scroller key="horizontalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="TDE-ff-DQT">
<rect key="frame" x="0.0" y="293" width="626" height="16"/>
<rect key="frame" x="0.0" y="294" width="611" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="wFn-93-f10">
<rect key="frame" x="610" y="28" width="16" height="281"/>
<rect key="frame" x="611" y="28" width="15" height="266"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" wantsLayer="YES" id="xUg-Mq-OSh">
<rect key="frame" x="0.0" y="0.0" width="626" height="28"/>
<rect key="frame" x="0.0" y="0.0" width="611" height="28"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<progressIndicator maxValue="100" displayedWhenStopped="NO" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="ZiS-Gq-TLQ">
<rect key="frame" x="298" y="150" width="30" height="30"/>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="wcV-ed-8Bv">
<rect key="frame" x="113" y="5" width="400" height="300"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="XK3-AR-Oc0"/>
<constraint firstAttribute="height" constant="30" id="lfW-dB-Eu3"/>
<constraint firstAttribute="width" constant="400" id="HCo-LG-x3N"/>
<constraint firstAttribute="height" constant="300" id="Xpi-Rl-xmb"/>
</constraints>
</progressIndicator>
</customView>
</subviews>
<constraints>
<constraint firstItem="p0j-eB-I2i" firstAttribute="leading" secondItem="rIZ-4U-bhj" secondAttribute="leading" id="2Tx-yb-xrv"/>
<constraint firstItem="wcV-ed-8Bv" firstAttribute="centerX" secondItem="rIZ-4U-bhj" secondAttribute="centerX" id="DPz-kQ-aP0"/>
<constraint firstItem="wcV-ed-8Bv" firstAttribute="centerY" secondItem="rIZ-4U-bhj" secondAttribute="centerY" id="HCW-zJ-gSY"/>
<constraint firstItem="p0j-eB-I2i" firstAttribute="top" secondItem="rIZ-4U-bhj" secondAttribute="top" id="Pst-5A-dI0"/>
<constraint firstAttribute="bottom" secondItem="p0j-eB-I2i" secondAttribute="bottom" id="QEw-5m-u1s"/>
<constraint firstItem="ZiS-Gq-TLQ" firstAttribute="centerY" secondItem="rIZ-4U-bhj" secondAttribute="centerY" constant="-10" id="XqX-Tf-8ck"/>
@ -1103,13 +1163,14 @@ Gw
</constraints>
</view>
<connections>
<outlet property="noResultsView" destination="wcV-ed-8Bv" id="K3s-fb-1aN"/>
<outlet property="progressIndicator" destination="ZiS-Gq-TLQ" id="Ylb-Vk-uub"/>
<outlet property="tableView" destination="cp3-34-pQj" id="sdw-Ac-27X"/>
</connections>
</viewController>
<customObject id="HgD-aB-bQb" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="323" y="723"/>
<point key="canvasLocation" x="323" y="722.5"/>
</scene>
<!--Add ProxyVC-->
<scene sceneID="g8z-pE-RL9">
@ -1486,6 +1547,10 @@ Gw
<image name="Lock" width="30" height="30"/>
<image name="arrow.clockwise" catalog="system" width="14" height="16"/>
<image name="plus" catalog="system" width="14" height="13"/>
<image name="star.circle.fill" catalog="system" width="20" height="20"/>
<namedColor name="AccentColor">
<color red="0.0" green="0.46000000000000002" blue="0.89000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="IconColorGreen">
<color red="0.24699999392032623" green="0.69700002670288086" blue="0.50099998712539673" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>

View File

@ -8,6 +8,7 @@
import Foundation
import Cocoa
import NVAlert
class ValetServicesManager: ServicesManager {
override init() {
@ -131,7 +132,7 @@ class ValetServicesManager: ServicesManager {
Log.err("The service '\(named)' is now reporting an error.")
guard let errorLogPath = after.error_log_path else {
return BetterAlert().withInformation(
return NVAlert().withInformation(
title: "alert.service_error.title".localized(named),
subtitle: "alert.service_error.subtitle.no_error_log".localized(named),
description: "alert.service_error.extra".localized
@ -140,7 +141,7 @@ class ValetServicesManager: ServicesManager {
.show()
}
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.service_error.title".localized(named),
subtitle: "alert.service_error.subtitle.error_log".localized(named),
description: "alert.service_error.extra".localized

View File

@ -7,6 +7,7 @@
import Foundation
import AppKit
import NVAlert
class Startup {
@ -55,7 +56,7 @@ class Startup {
*/
@MainActor private func showAlert(for check: EnvironmentCheck) {
if check.requiresAppRestart {
BetterAlert()
NVAlert()
.withInformation(
title: check.titleText,
subtitle: check.subtitleText,
@ -66,7 +67,7 @@ class Startup {
}).show()
}
BetterAlert()
NVAlert()
.withInformation(
title: check.titleText,
subtitle: check.subtitleText,

View File

@ -7,6 +7,7 @@
//
import Foundation
import NVAlert
@MainActor class ComposerWindow {
private var shouldNotify: Bool! = nil
@ -109,7 +110,7 @@ import Foundation
// MARK: Alert
private func presentMissingAlert() {
BetterAlert()
NVAlert()
.withInformation(
title: "alert.composer_missing.title".localized,
subtitle: "alert.composer_missing.subtitle".localized,

View File

@ -22,7 +22,7 @@ struct ProjectTypeDetection {
This list is checked first to see if a project dependency can be mapped to a certain project type.
*/
public static let SpecificDependencyList = [
"roots/bedrock": "Bedrock",
"roots/bedrock-autoloader": "Bedrock",
"cakephp/app": "CakePHP",
"craftcms/craft": "Craft",
"drupal/core": "Drupal",

View File

@ -7,6 +7,7 @@
//
import Foundation
import NVAlert
class BrewDiagnostics {
/**
@ -183,7 +184,7 @@ class BrewDiagnostics {
*/
private static func presentAlertAboutConflict() {
Task { @MainActor in
BetterAlert()
NVAlert()
.withInformation(
title: "alert.php_alias_conflict.title".localized,
subtitle: "alert.php_alias_conflict.info".localized

View File

@ -44,14 +44,13 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
}
return Brew.phpVersionFormulae.map { (version, formula) in
let fullVersion = PhpEnvironments.shared.cachedPhpInstallations[version]?
.versionNumber.text
var fullVersion: String?
var upgradeVersion: String?
if let version = fullVersion {
if let install = PhpEnvironments.shared.cachedPhpInstallations[version] {
fullVersion = install.versionNumber.text
upgradeVersion = outdated?.first(where: { formula in
return formula.installed_versions.contains(version)
return formula.name == install.formulaName
})?.current_version
}

View File

@ -61,6 +61,11 @@ class InstallPhpExtensionCommand: BrewCommand {
// Reload and restart PHP versions
onProgress(.create(value: 0.95, title: self.getCommandTitle(), description: "phpman.steps.reloading".localized))
// Restart PHP-FPM
if let installed = self.installing.first {
await Actions.restartPhpFpm(version: installed.phpVersion)
}
// Check which version of PHP are now installed
await PhpEnvironments.detectPhpVersions()

View File

@ -61,6 +61,8 @@ class RemovePhpExtensionCommand: BrewCommand {
await PhpEnvironments.detectPhpVersions()
await Actions.restartPhpFpm(version: phpExtension.phpVersion)
await MainMenu.shared.refreshActiveInstallation()
onProgress(.create(value: 1, title: getCommandTitle(), description: "phpman.steps.success".localized))

View File

@ -24,4 +24,6 @@ protocol ValetListable {
func getListableUrl() -> URL?
func getListableFavorited() -> Bool
}

View File

@ -14,6 +14,11 @@ class ValetProxy: ValetListable {
var target: String
var secured: Bool = false
var favorited: Bool = false
var favoriteSignature: String {
"proxy:domain:\(domain).\(tld)|target:\(target)"
}
init(domain: String, target: String, secure: Bool, tld: String) {
self.domain = domain
self.tld = tld
@ -28,6 +33,8 @@ class ValetProxy: ValetListable {
secure: false,
tld: configuration.tld
)
self.favorited = Favorites.shared.contains(domain: self.domain)
self.determineSecured()
}
@ -61,12 +68,21 @@ class ValetProxy: ValetListable {
return URL(string: "\(self.secured ? "https://" : "http://")\(self.domain).\(self.tld)")
}
func getListableFavorited() -> Bool {
return self.favorited
}
// MARK: - Interactions
func determineSecured() {
self.secured = FileSystem.fileExists("~/.config/valet/Certificates/\(self.domain).\(self.tld).key")
}
func toggleFavorite() {
self.favorited.toggle()
Favorites.shared.toggle(domain: self.favoriteSignature)
}
func toggleSecure() async throws {
try await ValetInteractor.shared.toggleSecure(proxy: self)
}

View File

@ -61,6 +61,11 @@ class ValetSite: ValetListable {
?? "???"
}
var favorited: Bool = false
var favoriteSignature: String {
"site:domain:\(name).\(tld)|path:\(absolutePath)"
}
init(
name: String,
tld: String,
@ -75,6 +80,7 @@ class ValetSite: ValetListable {
self.secured = false
if makeDeterminations {
self.favorited = Favorites.shared.contains(domain: favoriteSignature)
determineSecured()
determineIsolated()
determineComposerPhpVersion()
@ -305,12 +311,21 @@ class ValetSite: ValetListable {
return URL(string: "\(self.secured ? "https://" : "http://")\(self.name).\(Valet.shared.config.tld)")
}
func getListableFavorited() -> Bool {
return self.favorited
}
// MARK: - Interactions
func toggleSecure() async throws {
try await ValetInteractor.shared.toggleSecure(site: self)
}
func toggleFavorite() {
self.favorited.toggle()
Favorites.shared.toggle(domain: self.favoriteSignature)
}
func isolate(version: String) async throws {
try await ValetInteractor.shared.isolate(site: self, version: version)
}

View File

@ -7,6 +7,7 @@
//
import Foundation
import NVAlert
extension Valet {
@ -16,7 +17,7 @@ extension Valet {
public func notifyAboutUnsupportedTLD() {
if Valet.shared.config.tld != "test" && Preferences.isEnabled(.warnAboutNonStandardTLD) {
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.warnings.tld_issue.title".localized,
subtitle: "alert.warnings.tld_issue.subtitle".localized,
description: "alert.warnings.tld_issue.description".localized
@ -33,7 +34,7 @@ extension Valet {
public func notifyAboutOutdatedValetVersion(_ version: VersionNumber) {
Task { @MainActor in
BetterAlert()
NVAlert()
.withInformation(
title: "alert.min_valet_version.title".localized,
subtitle: "alert.min_valet_version.info".localized(
@ -60,7 +61,7 @@ extension Valet {
}
Task { @MainActor in
BetterAlert()
NVAlert()
.withInformation(
title: "alert.php_fpm_broken.title".localized,
subtitle: "alert.php_fpm_broken.info".localized,

View File

@ -0,0 +1,41 @@
//
// AppMenu.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 27/06/2024.
// Copyright © 2024 Nico Verbruggen. All rights reserved.
//
import Cocoa
class AppMenu {
// MARK: - Main Menu
static var appMenu: NSMenu? {
return NSApplication.shared.mainMenu?.items[0].submenu
}
static var sitesMenu: NSMenu? {
return NSApplication.shared.mainMenu?.items[1].submenu
}
static var editMenu: NSMenu? {
return NSApplication.shared.mainMenu?.items[2].submenu
}
static var windowMenu: NSMenu? {
return NSApplication.shared.mainMenu?.items[3].submenu
}
static var helpMenu: NSMenu? {
return NSApplication.shared.mainMenu?.items[4].submenu
}
// MARK: - Submenu
static var actionsMenu: NSMenuItem? {
return sitesMenu?.items.last
}
}

View File

@ -7,6 +7,7 @@
//
import Cocoa
import NVAlert
extension MainMenu {
@ -20,7 +21,7 @@ extension MainMenu {
@MainActor @objc func displayUnlinkedInfo() {
Task { @MainActor in
BetterAlert()
NVAlert()
.withInformation(
title: "phpman.unlinked.title".localized,
subtitle: "phpman.unlinked.desc".localized,
@ -32,7 +33,7 @@ extension MainMenu {
}
@MainActor @objc func fixHomebrewPermissions() {
if !BetterAlert()
if !NVAlert()
.withInformation(
title: "alert.fix_homebrew_permissions.title".localized,
subtitle: "alert.fix_homebrew_permissions.subtitle".localized,
@ -47,7 +48,7 @@ extension MainMenu {
asyncExecution {
try Actions.fixHomebrewPermissions()
} success: {
BetterAlert()
NVAlert()
.withInformation(
title: "alert.fix_homebrew_permissions_done.title".localized,
subtitle: "alert.fix_homebrew_permissions_done.subtitle".localized,
@ -56,7 +57,7 @@ extension MainMenu {
.withPrimary(text: "generic.ok".localized)
.show()
} failure: { error in
BetterAlert.show(for: error as! HomebrewPermissionError)
NVAlert.show(for: error as! HomebrewPermissionError)
}
}
@ -175,7 +176,7 @@ extension MainMenu {
return
}
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.revert_description.title".localized,
subtitle: "alert.revert_description.subtitle".localized(
preset.textDescription
@ -196,7 +197,7 @@ extension MainMenu {
}
@MainActor @objc func showPresetHelp() {
BetterAlert().withInformation(
NVAlert().withInformation(
title: "preset_help_title".localized,
subtitle: "preset_help_info".localized,
description: "preset_help_desc".localized
@ -263,7 +264,7 @@ extension MainMenu {
Task { MainMenu.shared.switchToPhpVersion(version) }
} else {
Task {
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.php_switch_unavailable.title".localized,
subtitle: "alert.php_switch_unavailable.subtitle".localized(version)
).withPrimary(

View File

@ -8,6 +8,7 @@
import Foundation
import AppKit
import NVAlert
extension MainMenu {
@ -19,7 +20,7 @@ extension MainMenu {
return
}
if !BetterAlert()
if !NVAlert()
.withInformation(
title: "alert.fix_my_valet.title".localized,
subtitle: "alert.fix_my_valet.info".localized(PhpEnvironments.brewPhpAlias)
@ -43,7 +44,7 @@ extension MainMenu {
}
@MainActor private func presentAlertForMissingFormula() {
BetterAlert()
NVAlert()
.withInformation(
title: "alert.php_formula_missing.title".localized,
subtitle: "alert.php_formula_missing.info".localized
@ -53,7 +54,7 @@ extension MainMenu {
}
@MainActor private func presentAlertForSameVersion() {
BetterAlert()
NVAlert()
.withInformation(
title: "alert.fix_my_valet_done.title".localized,
subtitle: "alert.fix_my_valet_done.subtitle".localized,
@ -64,7 +65,7 @@ extension MainMenu {
}
@MainActor private func presentAlertForDifferentVersion(version: String) {
BetterAlert()
NVAlert()
.withInformation(
title: "alert.fix_my_valet_done.title".localized,
subtitle: "alert.fix_my_valet_done.subtitle".localized,

View File

@ -7,6 +7,7 @@
//
import Cocoa
import NVAlert
extension MainMenu {
/**
@ -143,7 +144,7 @@ extension MainMenu {
*/
private func onEnvironmentFail() async {
Task { @MainActor [self] in
BetterAlert()
NVAlert()
.withInformation(
title: "alert.cannot_start.title".localized,
subtitle: "alert.cannot_start.subtitle".localized,

View File

@ -7,6 +7,7 @@
//
import Foundation
import NVAlert
extension MainMenu {
@ -75,7 +76,7 @@ extension MainMenu {
}
@MainActor private func suggestFixMyValet(failed version: String) {
let outcome = BetterAlert()
let outcome = NVAlert()
.withInformation(
title: "alert.php_switch_failed.title".localized(version),
subtitle: "alert.php_switch_failed.info".localized(version),
@ -90,7 +91,7 @@ extension MainMenu {
}
@MainActor private func suggestFixMyComposer() {
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.global_composer_platform_issues.title".localized,
subtitle: "alert.global_composer_platform_issues.subtitle".localized,
description: "alert.global_composer_platform_issues.desc".localized

View File

@ -6,6 +6,7 @@
//
import Cocoa
import NVAlert
@MainActor
class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate {
@ -120,7 +121,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
@objc func showIncompatiblePhpVersionsAlert() {
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "startup.unsupported_versions_explanation.title".localized,
subtitle: "startup.unsupported_versions_explanation.subtitle".localized(
PhpEnvironments.shared.incompatiblePhpVersions
@ -185,7 +186,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
@objc func openLiteModeInfo() {
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "lite_mode_explanation.title".localized,
subtitle: "lite_mode_explanation.subtitle".localized,
description: "lite_mode_explanation.description".localized

View File

@ -242,7 +242,7 @@ extension StatusMenu {
addLoadedPresets()
}
private func addEmptyPresetHelp() {
@MainActor private func addEmptyPresetHelp() {
addItem(NSMenuItem(title: "mi_presets_title".localized, submenu: [
NSMenuItem(title: "mi_no_presets".localized),
NSMenuItem.separator(),
@ -251,7 +251,7 @@ extension StatusMenu {
], target: MainMenu.shared))
}
private func addLoadedPresets() {
@MainActor private func addLoadedPresets() {
addItem(NSMenuItem(title: "mi_presets_title".localized, submenu: [
NSMenuItem.separator(),
HeaderView.asMenuItem(text: "mi_apply_presets_title".localized)
@ -266,7 +266,7 @@ extension StatusMenu {
// MARK: - Xdebug
func addXdebugMenuItem() {
@MainActor func addXdebugMenuItem() {
if !Xdebug.enabled {
addItem(NSMenuItem.separator())
return
@ -286,7 +286,7 @@ extension StatusMenu {
// MARK: - PHP Doctor
func addPhpDoctorMenuItem() {
@MainActor func addPhpDoctorMenuItem() {
if !Preferences.isEnabled(.showPhpDoctorSuggestions) ||
!WarningManager.shared.hasWarnings() {
return
@ -302,7 +302,7 @@ extension StatusMenu {
// MARK: - First Aid & Services
func addFirstAidAndServicesMenuItems() {
@MainActor func addFirstAidAndServicesMenuItems() {
let services = NSMenuItem(title: "mi_other".localized)
var items: [NSMenuItem] = [
@ -359,7 +359,7 @@ extension StatusMenu {
// MARK: - Other helper methods to generate menu items
func addExtensionItem(_ phpExtension: PhpExtension, _ shortcutKey: Int) {
@MainActor func addExtensionItem(_ phpExtension: PhpExtension, _ shortcutKey: Int) {
let keyEquivalent = shortcutKey < 9 ? "\(shortcutKey)" : ""
let menuItem = ExtensionMenuItem(

View File

@ -1,122 +0,0 @@
//
// Notice.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 16/02/2022.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
@MainActor
class BetterAlert {
var windowController: NSWindowController!
var noticeVC: BetterAlertVC {
return self.windowController.contentViewController as! BetterAlertVC
}
init() {
let storyboard = NSStoryboard(name: "Main", bundle: nil)
self.windowController = storyboard.instantiateController(
withIdentifier: "noticeWindow"
) as? NSWindowController
}
public static func make() -> BetterAlert {
return BetterAlert()
}
public func withPrimary(
text: String,
action: @MainActor @escaping (BetterAlertVC) -> Void = { vc in
vc.close(with: .alertFirstButtonReturn)
}
) -> Self {
self.noticeVC.buttonPrimary.title = text
self.noticeVC.actionPrimary = action
return self
}
public func withSecondary(
text: String,
action: (@MainActor (BetterAlertVC) -> Void)? = { vc in
vc.close(with: .alertSecondButtonReturn)
}
) -> Self {
self.noticeVC.buttonSecondary.title = text
self.noticeVC.actionSecondary = action
return self
}
public func withTertiary(
text: String = "",
action: (@MainActor (BetterAlertVC) -> Void)? = nil
) -> Self {
if text == "" {
self.noticeVC.buttonTertiary.bezelStyle = .helpButton
}
self.noticeVC.buttonTertiary.title = text
self.noticeVC.actionTertiary = action
return self
}
public func withInformation(
title: String,
subtitle: String,
description: String = ""
) -> Self {
self.noticeVC.labelTitle.stringValue = title
self.noticeVC.labelSubtitle.stringValue = subtitle
self.noticeVC.labelDescription.stringValue = description
// If the description is missing, handle the excess space and change the top margin
if description == "" {
self.noticeVC.labelDescription.isHidden = true
self.noticeVC.primaryButtonTopMargin.constant = 0
}
return self
}
/**
Shows the modal and returns a ModalResponse.
If you wish to simply show the alert and disregard the outcome, use `show`.
*/
@MainActor public func runModal() -> NSApplication.ModalResponse {
if !Thread.isMainThread {
fatalError("You should always present alerts on the main thread!")
}
NSApp.activate(ignoringOtherApps: true)
windowController.window?.makeKeyAndOrderFront(nil)
windowController.window?.setCenterPosition(offsetY: 70)
return NSApplication.shared.runModal(for: windowController.window!)
}
/** Shows the modal and returns true if the user pressed the primary button. */
@MainActor public func didSelectPrimary() -> Bool {
return self.runModal() == .alertFirstButtonReturn
}
/**
Shows the modal and does not return anything.
*/
@MainActor public func show() {
_ = self.runModal()
}
/**
Shows the modal for a particular error.
*/
@MainActor public static func show(for error: Error & AlertableError) {
let key = error.getErrorMessageKey()
return BetterAlert().withInformation(
title: "\(key).title".localized,
subtitle: "\(key).description".localized
).withPrimary(text: "generic.ok".localized).show()
}
}

View File

@ -1,77 +0,0 @@
//
// NoticeVC.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 16/02/2022.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
class BetterAlertVC: NSViewController {
// MARK: - Outlets
@IBOutlet weak var labelTitle: NSTextField!
@IBOutlet weak var labelSubtitle: NSTextField!
@IBOutlet weak var labelDescription: NSTextField!
@IBOutlet weak var buttonPrimary: NSButton!
@IBOutlet weak var buttonSecondary: NSButton!
@IBOutlet weak var buttonTertiary: NSButton!
var actionPrimary: (@MainActor (BetterAlertVC) -> Void) = { _ in }
var actionSecondary: (@MainActor (BetterAlertVC) -> Void)?
var actionTertiary: (@MainActor (BetterAlertVC) -> Void)?
@IBOutlet weak var imageView: NSImageView!
@IBOutlet weak var primaryButtonTopMargin: NSLayoutConstraint!
// MARK: - Lifecycle
override func viewWillAppear() {
imageView.image = NSApp.applicationIconImage
if actionSecondary == nil {
buttonSecondary.isHidden = true
}
if actionTertiary == nil {
buttonTertiary.isHidden = true
}
}
override func viewDidAppear() {
view.window?.makeFirstResponder(buttonPrimary)
}
deinit {
// Log.perf("deinit: \(String(describing: self)).\(#function)")
}
// MARK: Outlet Actions
@IBAction func primaryButtonAction(_ sender: Any) {
self.actionPrimary(self)
}
@IBAction func secondaryButtonAction(_ sender: Any) {
if self.actionSecondary != nil {
self.actionSecondary!(self)
} else {
self.close(with: .alertSecondButtonReturn)
}
}
@IBAction func tertiaryButtonAction(_ sender: Any) {
if self.actionTertiary != nil {
self.actionTertiary!(self)
}
}
@MainActor public func close(with code: NSApplication.ModalResponse) {
self.view.window?.close()
NSApplication.shared.stopModal(withCode: code)
}
}

View File

@ -7,6 +7,7 @@
//
import Foundation
import NVAlert
class PhpGuard {
@ -43,7 +44,7 @@ class PhpGuard {
Log.info("PHP Guard noticed a different PHP version. An alert will be displayed!")
Task { @MainActor in
BetterAlert()
NVAlert()
.withInformation(
title: "startup.version_mismatch.title".localized,
subtitle: "startup.version_mismatch.subtitle".localized(

View File

@ -28,6 +28,10 @@ class Preferences {
environmentVariables: [:]
)
if isRunningSwiftUIPreview {
return
}
Task { await loadCustomPreferences() }
}

View File

@ -8,6 +8,7 @@
import Foundation
import Cocoa
import NVAlert
class Stats {
@ -123,7 +124,7 @@ class Stats {
}
Task { @MainActor in
let donate = BetterAlert()
let donate = NVAlert()
.withInformation(
title: "startup.sponsor_encouragement.title".localized,
subtitle: "startup.sponsor_encouragement.subtitle".localized,

View File

@ -7,6 +7,7 @@
//
import Foundation
import NVAlert
struct Preset: Codable, Equatable {
let name: String
@ -139,7 +140,7 @@ struct Preset: Codable, Equatable {
return true
} else {
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.php_switch_unavailable.title".localized,
subtitle: "alert.php_switch_unavailable.subtitle".localized(version!),
description: "alert.php_switch_unavailable.info".localized(

View File

@ -29,7 +29,7 @@ struct BlockingOverlayView<Content: View>: View {
var body: some View {
ZStack(alignment: .center) {
content().opacity(isBlocking ? 0.2 : 1)
content().opacity(isBlocking ? 0 : 1)
if isBlocking {
VStack {
ActivityIndicator()
@ -44,7 +44,8 @@ struct BlockingOverlayView<Content: View>: View {
.padding(.top, -4)
}.padding(60)
}
}.background(Color.white)
}
.background(Color.spinnerBackground)
.disabled(isBlocking)
}
}

View File

@ -0,0 +1,36 @@
//
// CustomButtonStyles.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 15/03/2024.
// Copyright © 2024 Nico Verbruggen. All rights reserved.
//
import SwiftUI
public struct CustomButtonStyle: ButtonStyle {
@Environment(\.isEnabled) var isEnabled
public func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding(.vertical, 4)
.padding(.horizontal, 8)
.foregroundStyle(.white)
.background(.statusColorBlue, in: .rect(cornerRadius: 8, style: .continuous))
.opacity({
if configuration.isPressed {
return 0.4
}
if !isEnabled {
return 0.2
}
return 1.0
}())
}
}
extension ButtonStyle where Self == CustomButtonStyle {
static var custom: CustomButtonStyle { .init() }
}

View File

@ -0,0 +1,67 @@
//
// NoDomainsView.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 19/03/2024.
// Copyright © 2024 Nico Verbruggen. All rights reserved.
//
import SwiftUI
struct UnavailableContentView: View {
var title: String
var description: String
var icon: String
var button: String?
var action: (() -> Void)?
init(
title: String,
description: String,
icon: String,
button: String? = nil,
action: (() -> Void)? = nil
) {
self.title = title
self.description = description
self.icon = icon
self.button = button
self.action = action
}
var body: some View {
Group {
VStack(spacing: 15) {
Image(systemName: self.icon)
.resizable()
.frame(width: 48, height: 48)
.foregroundColor(Color.appPrimary)
.padding(.bottom, 10)
Text(self.title)
.font(.system(size: 18, weight: .bold))
Text(self.description)
.foregroundStyle(Color.secondary)
.multilineTextAlignment(.center)
if self.button != nil {
Button(self.button!) {
self.action!()
}.buttonStyle(.custom)
}
}
}
.padding(30)
.frame(maxWidth: 400)
}
}
#Preview {
UnavailableContentView(
title: "domain_list.domains_empty.title".localized,
description: "domain_list.domains_empty.desc".localized,
icon: "globe",
button: "domain_list.domains_empty.button".localized,
action: {}
)
}

View File

@ -1,35 +0,0 @@
//
// NoDomainResults.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 15/08/2022.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import SwiftUI
struct NoDomainResults: View {
@State var searching: Bool = false
var body: some View {
VStack(alignment: .center, spacing: 15) {
Image(systemName: searching ? "magnifyingglass.circle.fill" : "questionmark.circle.fill")
.resizable()
.renderingMode(.template)
.frame(width: 24, height: 24)
VStack(alignment: .center) {
Text(
searching
? "domain_list.no_domains_for_search_query".localizedForSwiftUI
: "domain_list.no_domains".localizedForSwiftUI
)
}
}
.frame(minWidth: 0, maxWidth: .infinity)
.padding(25)
}
}
#Preview {
NoDomainResults()
}

View File

@ -14,8 +14,16 @@ struct VersionPopoverView: View {
@State var validPhpVersions: [VersionNumber]
@State var prefersIsolationSuggestions: Bool
@State var parent: NSPopover!
let rows = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
VStack(alignment: .leading, spacing: 10) {
Text(getTitleText())
@ -32,14 +40,29 @@ struct VersionPopoverView: View {
message: "alert.php_suggestions".localized,
color: Color("AppColor")
)
HStack {
ForEach(validPhpVersions, id: \.self) { version in
Button("site_link.switch_to_php".localized(version.short), action: {
MainMenu.shared.switchToPhpVersion(version.short)
parent?.close()
})
}
}.padding(EdgeInsets(top: 10, leading: 0, bottom: 0, trailing: 0))
if prefersIsolationSuggestions {
// SITE ISOLATION (preferred)
LazyVGrid(columns: self.rows, alignment: .leading, spacing: 5, content: {
ForEach(validPhpVersions, id: \.self) { version in
Button("site_link.isolate_php".localized(version.short), action: {
App.shared.domainListWindowController?.contentVC
.isolateSite(site: site, version: version.short)
parent?.close()
}).padding(EdgeInsets(top: 3, leading: 0, bottom: 3, trailing: 0))
}
}).padding(EdgeInsets(top: 5, leading: 0, bottom: 0, trailing: 0))
} else {
// GLOBAL SWITCHER
LazyVGrid(columns: self.rows, alignment: .leading, spacing: 5, content: {
ForEach(validPhpVersions, id: \.self) { version in
Button("site_link.switch_to_php".localized(version.short), action: {
MainMenu.shared.switchToPhpVersion(version.short)
parent?.close()
}).padding(EdgeInsets(top: 3, leading: 0, bottom: 3, trailing: 0))
}
}).padding(EdgeInsets(top: 5, leading: 0, bottom: 0, trailing: 0))
}
}
} else {
if site.preferredPhpVersionSource == .unknown {
@ -137,6 +160,7 @@ struct DisclaimerView: View {
constraint: ""
),
validPhpVersions: [],
prefersIsolationSuggestions: false,
parent: nil
)
}
@ -152,6 +176,7 @@ struct DisclaimerView: View {
constraint: "^8.1"
),
validPhpVersions: [],
prefersIsolationSuggestions: false,
parent: nil
)
}
@ -168,6 +193,7 @@ struct DisclaimerView: View {
isolated: "8.0"
),
validPhpVersions: [],
prefersIsolationSuggestions: false,
parent: nil
)
}
@ -184,6 +210,7 @@ struct DisclaimerView: View {
isolated: "7.4"
),
validPhpVersions: [],
prefersIsolationSuggestions: false,
parent: nil
)
}
@ -200,8 +227,12 @@ struct DisclaimerView: View {
),
validPhpVersions: [
VersionNumber(major: 8, minor: 0, patch: 0),
VersionNumber(major: 8, minor: 1, patch: 0)
VersionNumber(major: 8, minor: 1, patch: 0),
VersionNumber(major: 8, minor: 2, patch: 0),
VersionNumber(major: 8, minor: 3, patch: 0),
VersionNumber(major: 8, minor: 4, patch: 0)
],
prefersIsolationSuggestions: true,
parent: nil
)
}

View File

@ -8,6 +8,7 @@
import Foundation
import SwiftUI
import NVAlert
struct ServicesView: View {
@ -81,7 +82,7 @@ struct ServicesView: View {
: "key_service_not_running"
// Show an alert with more information
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.\(type).title".localized,
subtitle: "alert.\(type).subtitle".localized,
description: "alert.\(type).desc".localized
@ -116,7 +117,7 @@ struct ServiceView: View {
if service.status == .missing {
Button {
Task { @MainActor in
BetterAlert().withInformation(
NVAlert().withInformation(
title: "alert.warnings.service_missing.title".localized,
subtitle: "alert.warnings.service_missing.subtitle".localized,
description: "alert.warnings.service_missing.description".localized

View File

@ -40,7 +40,7 @@
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019-2023 Nico Verbruggen. All rights reserved.</string>
<string>Copyright © 2019-2024 Nico Verbruggen. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>

View File

@ -0,0 +1,38 @@
//
// Favorites.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 25/08/2024.
// Copyright © 2024 Nico Verbruggen. All rights reserved.
//
import Foundation
class Favorites {
static var shared: Favorites = Favorites()
var items: [String]
init() {
if let items = UserDefaults.standard.array(forKey: "user_favorites") as? [String] {
self.items = items
} else {
self.items = []
}
}
public func contains(domain: String) -> Bool {
return self.items.contains(domain)
}
public func toggle(domain: String) {
if let index = items.firstIndex(of: domain) {
items.remove(at: index)
} else {
items.append(domain)
}
UserDefaults.standard.setValue(items, forKey: "user_favorites")
UserDefaults.standard.synchronize()
}
}

View File

@ -10,6 +10,7 @@ import Cocoa
import AppKit
protocol DomainListCellProtocol {
static func getCellIdentifier(for domain: ValetListable) -> String
func populateCell(with site: ValetSite)
func populateCell(with proxy: ValetProxy)
}

View File

@ -10,10 +10,12 @@ import Cocoa
import AppKit
class DomainListKindCell: NSTableCellView, DomainListCellProtocol {
static let reusableName = "domainListKindCell"
@IBOutlet weak var imageViewType: NSImageView!
static func getCellIdentifier(for domain: ValetListable) -> String {
return "domainListKindCell"
}
func populateCell(with site: ValetSite) {
// If the `aliasPath` is nil, we're dealing with a parked site (otherwise: linked).
imageViewType.image = site.aliasPath == nil

View File

@ -10,11 +10,13 @@ import Cocoa
import AppKit
class DomainListNameCell: NSTableCellView, DomainListCellProtocol {
static let reusableName = "domainListNameCell"
@IBOutlet weak var labelSiteName: NSTextField!
@IBOutlet weak var labelPathName: NSTextField!
static func getCellIdentifier(for domain: ValetListable) -> String {
return domain.getListableFavorited() ? "domainListNameCellFavorited" : "domainListNameCell"
}
func populateCell(with site: ValetSite) {
labelSiteName.stringValue = "\(site.name).\(site.tld)"
labelPathName.stringValue = site.absolutePathRelative

View File

@ -11,13 +11,15 @@ import AppKit
import SwiftUI
class DomainListPhpCell: NSTableCellView, DomainListCellProtocol {
static let reusableName = "domainListPhpCell"
var site: ValetSite?
@IBOutlet weak var buttonPhpVersion: NSButton!
@IBOutlet weak var imageViewPhpVersionOK: NSImageView!
static func getCellIdentifier(for domain: ValetListable) -> String {
return "domainListPhpCell"
}
func populateCell(with site: ValetSite) {
self.site = site
@ -70,7 +72,12 @@ class DomainListPhpCell: NSTableCellView, DomainListCellProtocol {
let button = self.buttonPhpVersion!
let popover = NSPopover()
let view = VersionPopoverView(site: site, validPhpVersions: validPhpSuggestions, parent: popover)
let view = VersionPopoverView(
site: site,
validPhpVersions: validPhpSuggestions,
prefersIsolationSuggestions: Valet.enabled(feature: .isolatedSites),
parent: popover
)
popover.contentViewController = NSHostingController(rootView: view)
popover.behavior = .transient

View File

@ -10,10 +10,12 @@ import Cocoa
import AppKit
class DomainListTLSCell: NSTableCellView, DomainListCellProtocol {
static let reusableName = "domainListTLSCell"
@IBOutlet weak var imageViewLock: NSImageView!
static func getCellIdentifier(for domain: ValetListable) -> String {
return "domainListTLSCell"
}
func populateCell(with site: ValetSite) {
imageViewLock.contentTintColor = site.secured
? NSColor(named: "IconColorGreen")

View File

@ -10,11 +10,13 @@ import Cocoa
import AppKit
class DomainListTypeCell: NSTableCellView, DomainListCellProtocol {
static let reusableName = "domainListTypeCell"
@IBOutlet weak var labelDriver: NSTextField!
@IBOutlet weak var labelPhpVersion: NSTextField!
static func getCellIdentifier(for domain: ValetListable) -> String {
return "domainListTypeCell"
}
func populateCell(with site: ValetSite) {
labelDriver.stringValue = site.driver ?? "driver.not_detected".localized

View File

@ -8,6 +8,7 @@
import Foundation
import Cocoa
import NVAlert
extension DomainListVC {
@ -17,7 +18,7 @@ extension DomainListVC {
}
guard let url = selected.getListableUrl() else {
BetterAlert()
NVAlert()
.withInformation(
title: "domain_list.alert.invalid_folder_name".localized,
subtitle: "domain_list.alert.invalid_folder_name_desc".localized
@ -66,6 +67,14 @@ extension DomainListVC {
// MARK: - Interactions with `valet` or terminal
@objc func toggleFavorite() {
guard let selected = self.selected else {
return
}
Task { await toggleFavorite(domain: selected) }
}
@objc func toggleSecure() {
if selected is ValetSite {
Task { await toggleSecure(site: selected as! ValetSite) }
@ -93,6 +102,22 @@ extension DomainListVC {
}
}
func toggleFavorite(domain: any ValetListable) async {
waitAndExecute {
do {
if let site = domain as? ValetSite {
site.toggleFavorite()
}
if let proxy = domain as? ValetProxy {
proxy.toggleFavorite()
}
// Reload the entire table as the sorting may be affected
self.reloadTable()
}
}
}
func toggleSecure(site: ValetSite) async {
waitAndExecute {
do {
@ -126,17 +151,17 @@ extension DomainListVC {
}
}
@objc func isolateSite(sender: PhpMenuItem) {
guard let site = selectedSite else {
return
}
public func isolateSite(site: ValetSite, version: String) {
waitAndExecute {
do {
// Instruct Valet to isolate a given PHP version
try await site.isolate(version: sender.version)
// Reload the UI
self.reloadSelectedRow()
try await site.isolate(version: version)
// Reload the UI if it's the same site
if self.selectedSite?.absolutePath == site.absolutePath {
self.reloadSelectedRow()
} else {
await self.reloadDomains()
}
} catch {
// Notify the user about a failed command
let error = error as! ValetInteractionError
@ -145,7 +170,15 @@ extension DomainListVC {
}
}
@objc func removeIsolatedSite() {
@objc func isolateSiteViaMenuItem(sender: PhpMenuItem) {
guard let site = selectedSite else {
return
}
self.isolateSite(site: site, version: sender.version)
}
@objc func removeIsolatedSiteViaMenuItem() {
guard let site = selectedSite else {
return
}
@ -241,7 +274,7 @@ extension DomainListVC {
}
private func notifyAboutUsingIsolatedPhpVersionInTerminal(version: VersionNumber) {
BetterAlert()
NVAlert()
.withInformation(
title: "domain_list.alerts_isolated_php_terminal.title".localized(version.short),
subtitle: "domain_list.alerts_isolated_php_terminal.subtitle".localized(
@ -255,7 +288,7 @@ extension DomainListVC {
}
private func notifyAboutFailedSecureStatus(command: String) {
BetterAlert()
NVAlert()
.withInformation(
title: "domain_list.alerts_status_not_changed.title".localized,
subtitle: "domain_list.alerts_status_not_changed.desc".localized(command)
@ -265,7 +298,7 @@ extension DomainListVC {
}
private func notifyAboutFailedSiteIsolation(command: String) {
BetterAlert()
NVAlert()
.withInformation(
title: "domain_list.alerts_isolation_failed.title".localized,
subtitle: "domain_list.alerts_isolation_failed.subtitle".localized,

View File

@ -13,22 +13,31 @@ extension DomainListVC {
internal func reloadContextMenu() {
guard let selected = selected else {
tableView.menu = nil
AppMenu.actionsMenu?.title = "mm_actions".localized
AppMenu.actionsMenu?.submenu = nil
AppMenu.actionsMenu?.isEnabled = false
return
}
if let selected = selected as? ValetSite {
addMenuItemsForSite(selected)
tableView.menu = addMenuItemsForSite(selected)
AppMenu.actionsMenu?.title = "mm_actions".localized + " (\(selected.name).\(selected.tld))"
AppMenu.actionsMenu?.submenu = tableView.menu
AppMenu.actionsMenu?.isEnabled = true
return
}
if let selected = selected as? ValetProxy {
addMenuItemsForProxy(selected)
tableView.menu = addMenuItemsForProxy(selected)
AppMenu.actionsMenu?.title = "mm_actions".localized + " (\(selected.domain).\(selected.tld))"
AppMenu.actionsMenu?.submenu = tableView.menu
AppMenu.actionsMenu?.isEnabled = true
return
}
}
// MARK: - Menu Items for Site
private func addMenuItemsForSite(_ site: ValetSite) {
private func addMenuItemsForSite(_ site: ValetSite) -> NSMenu? {
let menu = NSMenu()
addSystemApps(to: menu)
@ -56,10 +65,11 @@ extension DomainListVC {
menu.addItem(HeaderView.asMenuItem(text: "domain_list.actions".localized))
addToggleFavorite(to: menu, favorited: site.favorited)
addToggleSecure(to: menu, secured: site.secured)
addUnlink(to: menu, with: site)
tableView.menu = menu
return menu
}
private func addSystemApps(to menu: NSMenu) {
@ -121,7 +131,7 @@ extension DomainListVC {
for version in PhpEnvironments.shared.availablePhpVersions.reversed() {
let item = PhpMenuItem(
title: "domain_list.always_use_php".localized(version),
action: #selector(self.isolateSite),
action: #selector(self.isolateSiteViaMenuItem),
keyEquivalent: ""
)
if site.servingPhpVersion == version && site.isolatedPhpVersion != nil {
@ -137,7 +147,7 @@ extension DomainListVC {
items.append(NSMenuItem.separator())
items.append(NSMenuItem(
title: "domain_list.remove_isolation".localized,
action: #selector(self.removeIsolatedSite)
action: #selector(self.removeIsolatedSiteViaMenuItem)
))
}
@ -163,6 +173,16 @@ extension DomainListVC {
)
}
private func addToggleFavorite(to menu: NSMenu, favorited: Bool) {
menu.addItem(
withTitle: favorited
? "domain_list.unfavorite".localized
: "domain_list.favorite".localized,
action: #selector(toggleFavorite),
keyEquivalent: ""
)
}
private func addMenuItemsForExtensions(to menu: NSMenu, for extensions: [PhpExtension], version: String) {
var items: [NSMenuItem] = [
NSMenuItem(title: "domain_list.applies_to".localized(version))
@ -187,13 +207,14 @@ extension DomainListVC {
// MARK: - Menu Items for Proxy
private func addMenuItemsForProxy(_ proxy: ValetProxy) {
private func addMenuItemsForProxy(_ proxy: ValetProxy) -> NSMenu {
let menu = NSMenu()
addOpenProxyInBrowser(to: menu)
addSeparator(to: menu)
addToggleFavorite(to: menu, favorited: proxy.favorited)
addToggleSecure(to: menu, secured: proxy.secured)
addRemoveProxy(to: menu)
tableView.menu = menu
return menu
}
private func addOpenProxyInBrowser(to menu: NSMenu) {

View File

@ -8,12 +8,14 @@
import Cocoa
import Carbon
import SwiftUI
class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
// MARK: - Outlets
@IBOutlet weak var tableView: PMTableView!
@IBOutlet weak var noResultsView: NSView!
@IBOutlet weak var progressIndicator: NSProgressIndicator!
// MARK: - Variables
@ -93,6 +95,8 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
override func viewDidLoad() {
tableView.doubleAction = #selector(self.doubleClicked(sender:))
addNoResultsView()
let mapping = [
"SECURE": "domain_list.columns.secure",
"DOMAIN": "domain_list.columns.domain",
@ -115,6 +119,25 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
}
}
private func addNoResultsView() {
let child = NSHostingController(
rootView: UnavailableContentView(
title: "domain_list.domains_empty.title".localized,
description: "domain_list.domains_empty.desc".localized,
icon: "globe",
button: "domain_list.domains_empty.button".localized,
action: {
App.shared.domainListWindowController?
.pressedAddLink(nil)
}
)
.frame(width: 400, height: 300)
).view
self.noResultsView.addSubview(child)
child.frame = self.noResultsView.bounds
}
// MARK: - Async Operations
/**
@ -132,6 +155,7 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
tableView.alphaValue = 0.3
tableView.isEnabled = false
tableView.selectRowIndexes([], byExtendingSelection: true)
noResultsView.isHidden = true
}
/**
@ -142,6 +166,7 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
progressIndicator.stopAnimation(nil)
tableView.alphaValue = 1.0
tableView.isEnabled = true
updateNoResultsView()
}
/**
@ -196,7 +221,9 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
default: break
}
self.domains = descriptor.ascending ? sorted.reversed() : sorted
sorted = descriptor.ascending ? sorted.reversed() : sorted
self.domains = sorted.sorted { $0.getListableFavorited() && !$1.getListableFavorited() }
}
func addedNewSite(name: String, secureAfterLinking: Bool) async {
@ -236,16 +263,17 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let mapping: [String: String] = [
"TLS": DomainListTLSCell.reusableName,
"DOMAIN": DomainListNameCell.reusableName,
"ENVIRONMENT": DomainListPhpCell.reusableName,
"KIND": DomainListKindCell.reusableName,
"TYPE": DomainListTypeCell.reusableName
let mapping: [String: DomainListCellProtocol.Type] = [
"TLS": DomainListTLSCell.self,
"DOMAIN": DomainListNameCell.self,
"ENVIRONMENT": DomainListPhpCell.self,
"KIND": DomainListKindCell.self,
"TYPE": DomainListTypeCell.self
]
let columnName = tableColumn!.identifier.rawValue
let identifier = NSUserInterfaceItemIdentifier(rawValue: mapping[columnName]!)
guard let cellType = mapping[columnName] else { return nil }
let identifier = NSUserInterfaceItemIdentifier(rawValue: cellType.getCellIdentifier(for: domains[row]))
guard let userCell = tableView.makeView(withIdentifier: identifier, owner: self)
as? DomainListCellProtocol else { return nil }
@ -282,9 +310,14 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
Task { @MainActor in
self.tableView.reloadData()
updateNoResultsView()
}
}
func updateNoResultsView() {
self.noResultsView.isHidden = !domains.isEmpty
}
func searchedFor(text: String) {
lastSearchedFor = text

View File

@ -27,13 +27,14 @@ extension PhpExtensionManagerView {
)
}
public func install(_ ext: BrewPhpExtension) {
public func install(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
Task {
await self.runCommand(InstallPhpExtensionCommand(install: [ext]))
onCompletion()
}
}
public func confirmUninstall(_ ext: BrewPhpExtension) {
public func confirmUninstall(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
Alert.confirm(
onWindow: App.shared.phpExtensionManagerWindowController!.window!,
messageText: "phpextman.warnings.removal.title".localized(ext.name),
@ -45,6 +46,7 @@ extension PhpExtensionManagerView {
onFirstButtonPressed: {
Task {
await self.runCommand(RemovePhpExtensionCommand(remove: ext))
onCompletion()
}
}
)

View File

@ -12,7 +12,9 @@ import SwiftUI
struct PhpExtensionManagerView: View {
@ObservedObject var manager: BrewExtensionsObservable
@ObservedObject var status: BusyStatus
@State var searchText: String
@State private var highlightedExtension: String?
init() {
self.searchText = ""
@ -22,11 +24,22 @@ struct PhpExtensionManagerView: View {
self.status.busy = false
}
var availablePhpVersions: [String] {
if isRunningSwiftUIPreview {
return [manager.phpVersion]
}
return PhpEnvironments.shared.availablePhpVersions
}
var filteredExtensions: [BrewPhpExtension] {
guard !searchText.isEmpty else {
return manager.extensions
return manager.extensions.sorted { $0.isInstalled && !$1.isInstalled }
}
return manager.extensions.filter { $0.name.contains(searchText) }
return manager.extensions
.filter { $0.name.contains(searchText) }
.sorted { $0.isInstalled && !$1.isInstalled }
}
var body: some View {
@ -48,25 +61,41 @@ struct PhpExtensionManagerView: View {
title: self.status.title,
text: self.status.description
) {
List(Array(self.filteredExtensions.enumerated()), id: \.1.name) { (_, ext) in
listContent(for: ext)
.padding(.vertical, 8)
.padding(.horizontal, 8)
ScrollViewReader { proxy in
List(Array(self.filteredExtensions.enumerated()), id: \.1.name) { (_, ext) in
listContent(for: ext, proxy: proxy)
}
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
.searchable(text: $searchText)
.onChange(of: manager.phpVersion, perform: { _ in
if let ext = self.filteredExtensions.first {
proxy.scrollTo(ext.name)
}
})
}
}
}
.frame(minWidth: 600, minHeight: 600)
.onAppear {
Task {
await delay(seconds: 1)
if self.manager.extensions.isEmpty {
self.presentErrorAlert(
title: "phpextman.errors.not_found.title".localized,
description: "phpextman.errors.not_found.desc".localized,
button: "generic.ok".localized
)
}
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
.searchable(text: $searchText)
}
}
.frame(width: 600, height: 600)
}
// MARK: View Variables
private var phpVersionPicker: some View {
Picker("",
selection: $manager.phpVersion) {
ForEach(PhpEnvironments.shared.availablePhpVersions, id: \.self) {
Picker("", selection: $manager.phpVersion) {
ForEach(self.availablePhpVersions, id: \.self) {
Text("PHP \($0)")
.tag($0)
.font(.system(size: 12))
@ -135,17 +164,16 @@ struct PhpExtensionManagerView: View {
}
}
private func listContent(for ext: BrewPhpExtension) -> some View {
private func listContent(for ext: BrewPhpExtension, proxy: ScrollViewProxy) -> some View {
HStack(alignment: .center, spacing: 7.0) {
VStack(alignment: .center, spacing: 0) {
HStack {
HStack {
Image(systemName: ext.isInstalled || ext.hasAlternativeInstall
? "puzzlepiece.extension.fill"
: "puzzlepiece.extension")
.resizable()
.frame(width: 24, height: 20)
.foregroundColor(ext.hasAlternativeInstall ? Color.gray : Color.blue)
? "puzzlepiece.extension.fill" : "puzzlepiece.extension")
.resizable()
.frame(width: 24, height: 20)
.foregroundColor(ext.hasAlternativeInstall ? Color.gray : Color.blue)
}.frame(width: 36, height: 24)
VStack(alignment: .leading, spacing: 5) {
@ -172,19 +200,41 @@ struct PhpExtensionManagerView: View {
HStack {
if ext.isInstalled {
Button("phpman.buttons.uninstall".localizedForSwiftUI, role: .destructive) {
self.confirmUninstall(ext)
}.disabled(ext.firstDependent(in: self.manager.extensions) != nil)
self.confirmUninstall(ext, onCompletion: {
scrollAndAnimate(ext, proxy)
})
}
.disabled(ext.firstDependent(in: self.manager.extensions) != nil)
} else {
Button("phpman.buttons.install".localizedForSwiftUI) {
self.install(ext)
self.install(ext, onCompletion: {
scrollAndAnimate(ext, proxy)
})
}.disabled(ext.hasAlternativeInstall)
}
}
}
.padding(.vertical, 8)
.padding(.horizontal, 8)
.background(highlightedExtension == ext.name ? Color.accentColor.opacity(0.3) : Color.clear)
.cornerRadius(8)
.animation(.easeInOut(duration: 0.5), value: highlightedExtension)
}
private func scrollAndAnimate(_ ext: BrewPhpExtension, _ proxy: ScrollViewProxy) {
withAnimation {
highlightedExtension = ext.name
proxy.scrollTo(ext.name, anchor: .top)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
withAnimation {
highlightedExtension = nil
}
}
}
}
#Preview {
PhpExtensionManagerView()
.frame(width: 600, height: 600)
PhpExtensionManagerView().frame(width: 600, height: 600)
}

View File

@ -1,5 +1,5 @@
//
// PhpVersionManagerWindowController.swift
// PhpExtensionManagerWindowController.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 13/11/2023.
@ -28,7 +28,7 @@ class PhpExtensionManagerWindowController: PMWindowController {
guard let window = windowController.window else { return }
window.title = "phpextman.window.title".localized
window.styleMask = [.titled, .closable, .miniaturizable]
window.styleMask = [.titled, .closable, .miniaturizable, .resizable]
window.titlebarAppearsTransparent = false
window.delegate = delegate ?? windowController
window.contentView = NSHostingView(rootView: windowController.view)

View File

@ -94,6 +94,8 @@ struct PhpVersionManagerView: View {
VStack {
header.padding(10)
Divider()
if self.hasUpdates {
hasUpdatesView
} else {
@ -134,16 +136,17 @@ struct PhpVersionManagerView: View {
.listStyle(PlainListStyle())
}
}
}.frame(width: 600, height: 600)
}
.frame(minWidth: 600, minHeight: 600)
}
// MARK: View Variables
private var header: some View {
HStack(alignment: .center, spacing: 15) {
Image(systemName: "arrow.down.to.line.circle.fill")
Image.init(.php)
.resizable()
.frame(width: 40, height: 40)
.frame(width: 50, height: 50)
.foregroundColor(Color.blue)
.padding(12)
VStack(alignment: .leading, spacing: 5) {
@ -160,44 +163,43 @@ struct PhpVersionManagerView: View {
private var hasUpdatesView: some View {
Group {
Divider()
HStack(alignment: .center, spacing: 15) {
Text("phpman.has_updates.description".localizedForSwiftUI)
.foregroundColor(.gray)
.font(.system(size: 11))
Button("phpman.has_updates.button".localizedForSwiftUI, action: {
Button(action: {
Task { await self.upgradeAll(self.formulae.upgradeable) }
}, label: {
Label("phpman.has_updates.button".localizedForSwiftUI,
systemImage: "arrowshape.up.circle.fill")
})
.buttonStyle(.custom)
.focusable(false)
.disabled(self.status.busy)
}
.padding(10)
}
.background(.statusColorYellowTranslucent)
.cornerRadius(5)
}
private var noUpdatesView: some View {
Group {
Divider()
HStack(alignment: .center, spacing: 15) {
Button {
Task { await self.reload() }
} label: {
Image(systemName: "arrow.clockwise")
.buttonStyle(.automatic)
.controlSize(.large)
}
.focusable(false)
.disabled(self.status.busy)
Text("phpman.refresh.button.description".localizedForSwiftUI)
.foregroundColor(.gray)
.font(.system(size: 11))
HStack(alignment: .center, spacing: 15) {
Button {
Task { await self.reload() }
} label: {
Image(systemName: "arrow.clockwise")
.buttonStyle(.automatic)
.controlSize(.large)
}
.padding(10)
.focusable(false)
.disabled(self.status.busy)
Text("phpman.refresh.button.description".localizedForSwiftUI)
.foregroundColor(.gray)
.font(.system(size: 11))
}
.padding(10)
}
private var prereleaseBadge: some View {
@ -205,7 +207,7 @@ struct PhpVersionManagerView: View {
.font(.system(size: 9))
.padding(.horizontal, 5)
.padding(.vertical, 1)
.background(Color.appPrimary)
.background(Color.statusColorBlue)
.foregroundColor(Color.white)
.clipShape(Capsule())
.fixedSize(horizontal: true, vertical: true)

View File

@ -30,7 +30,7 @@ class PhpVersionManagerWindowController: PMWindowController {
guard let window = windowController.window else { return }
window.title = ""
window.styleMask = [.titled, .closable, .miniaturizable]
window.styleMask = [.titled, .closable, .miniaturizable, .resizable]
window.titlebarAppearsTransparent = true
window.delegate = delegate ?? windowController
window.contentView = NSHostingView(rootView: windowController.view)

View File

@ -85,6 +85,8 @@
"mi_xdebug_actions" = "Aktionen";
"mi_xdebug_disable_all" = "Alle Modi deaktivieren";
"mm_actions" = "Aktionen";
// PHPEXTMAN
"phpextman.window.title" = "Erweiterungen";
@ -105,6 +107,12 @@
"phpextman.list.status.dependent" = "Sie können diese nicht deinstallieren, bevor Sie %@ deinstallieren.";
"phpextman.list.status.can_manage" = "Diese Erweiterung ist installiert und kann von PHP Monitor verwaltet werden.";
"phpextman.errors.not_found.title" = "Oh oh. Keine Erweiterungen gefunden!";
"phpextman.errors.not_found.desc" = "Das sollte eigentlich nicht passieren. Sie müssen möglicherweise den folgenden Befehl in Ihrem Terminal ausführen:
`brew tap shivammathur/extensions`
und PHP Monitor neu starten, damit die Erweiterungen sichtbar werden. Wenn das Problem nach Ausführen des Befehls und Neustart von PHP Monitor weiterhin besteht, ziehen Sie bitte in Erwägung, ein Issue auf GitHub zu eröffnen.";
// PHPMAN
@ -128,7 +136,7 @@
"phpman.refresh.button" = "Aktualisierungen suchen";
"phpman.refresh.button.description" = "Sie können auf die Schaltfläche Aktualisieren klicken, um zu prüfen, ob Aktualisierungen für die installierten PHP-Versionen verfügbar sind.";
"phpman.has_updates.description" = "Ein oder mehrere Aktualisierungen sind verfügbar. (Bitte beachten Sie, dass PHP Monitor PHP-Versionen immer im Ganzen installiert oder aktualisiert, so dass Sie immer alle Installationen auf einmal aktualisieren).";
"phpman.has_updates.description" = "**Ein oder mehrere Aktualisierungen sind verfügbar.** Bitte beachten Sie, dass PHP Monitor PHP-Versionen immer im Ganzen installiert oder aktualisiert, so dass Sie immer alle Installationen auf einmal aktualisieren.";
"phpman.has_updates.button" = "Alle aktualisieren";
"phpman.warnings.unsupported.title" = "Ihre Version von Homebrew kann Probleme verursachen";
@ -293,6 +301,8 @@ Möglicherweise werden Sie während des Deinstallationsvorgangs nach Ihrem Passw
"domain_list.always_use_php" = "Immer PHP %@ verwenden";
"domain_list.isolation_unavailable" = "Isolierung wird nicht unterstützt (in Valet 2)";
"domain_list.favorite" = "Als Favorit markieren";
"domain_list.unfavorite" = "Aus den Favoriten entfernen";
"domain_list.actions" = "Aktionen";
"domain_list.unlink" = "Ordner-Link aufheben";
"domain_list.secure" = "Domain sichern";
@ -608,7 +618,7 @@ Sie können dies tun, indem Sie `composer global update` in Ihrem Terminal ausf
// STARTUP
/// 0. Architecture mismatch
// 0. Architecture mismatch
"alert.homebrew_missing.title" = "PHP Monitor kann nicht starten!";
"alert.homebrew_missing.subtitle" = "Eine funktionierende Homebrew-Binärdatei konnte nicht am üblichen Ort gefunden werden. Bitte starten Sie die Anwendung neu, nachdem Sie dieses Problem behoben haben.";
@ -616,32 +626,32 @@ Sie können dies tun, indem Sie `composer global update` in Ihrem Terminal ausf
"alert.homebrew_missing.quit" = "Schließen";
/// PHP binary not found
// PHP binary not found
"startup.errors.php_binary.title" = "PHP ist nicht korrekt installiert";
"startup.errors.php_binary.subtitle" = "Sie müssen PHP über Homebrew installieren. Die App wird nicht richtig funktionieren, bis Sie dieses Problem behoben haben.";
"startup.errors.php_binary.desc" = "Normalerweise wird dieses Problem durch das Ausführen von `brew link php` in Ihrem Terminal gelöst.\n\n Um herauszufinden, was falsch ist, können Sie versuchen, `which php` in Ihrem Terminal auszuführen, es sollte `%@` zurückgeben.";
/// PHP not found in /usr/local/opt or /opt/homebrew/opt
// PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "PHP ist nicht korrekt installiert";
"startup.errors.php_opt.subtitle" = "Der PHP-Alias wurde in `%@` nicht gefunden. Die Anwendung wird nicht korrekt funktionieren, bis Sie dieses Problem behoben haben.";
"startup.errors.php_opt.desc" = "Wenn Sie bereits die `php` Formel installiert haben, müssen Sie eventuell `brew install php` ausführen, damit PHP Monitor diese Installation erkennt.";
/// PHP binary is broken
// PHP binary is broken
"startup.errors.dyld_library.title" = "PHP ist installiert, scheint aber defekt zu sein";
"startup.errors.dyld_library.subtitle" = "Wenn PHP Monitor versucht, Befehle auszuführen, gelingt es ihm nicht richtig. Dies ist normalerweise ein Hinweis auf eine fehlerhafte PHP-Installation.";
"startup.errors.dyld_library.desc" = "Das Ausführen von `brew reinstall php && brew link php` in Ihrem Terminal kann dieses Problem lösen, also versuchen Sie es bitte.";
/// Valet is not installed
// Valet is not installed
"startup.errors.valet_executable.title" = "Laravel Valet ist nicht korrekt installiert";
"startup.errors.valet_executable.subtitle" = "Sie müssen Valet mit Composer installieren. Die App wird nicht richtig funktionieren, bis Sie dieses Problem behoben haben.";
"startup.errors.valet_executable.desc" = "Wenn Sie Laravel Valet noch nicht installiert haben, tun Sie dies bitte zuerst. Wenn Sie es installiert haben, aber trotzdem diese Meldung sehen, dann versuchen Sie, `which valet` im Terminal auszuführen, es sollte zurückgegeben werden: `%@`.";
/// Valet configuration file missing or broken
// Valet configuration file missing or broken
"startup.errors.valet_json_invalid.title" = "Laravel Valet-Konfigurationsdatei ungültig oder fehlt";
"startup.errors.valet_json_invalid.subtitle" = "PHP Monitor muss in der Lage sein, die Konfigurationsdatei zu lesen. Es scheint, dass die Datei falsch formatiert ist oder fehlt. Bitte überprüfen Sie, ob sie existiert und korrekt formatiert ist.";
"startup.errors.valet_json_invalid.desc" = "Sie finden die Datei unter `~/.config/valet/config.json`. Wenn Laravel Valet die Konfigurationsdatei nicht parsen kann, wird die JSON-Datei durch die Ausführung eines beliebigen `valet`-Befehls normalerweise automatisch korrigiert. Versuchen Sie, `valet --version` auszuführen, um die Datei automatisch zu korrigieren.";
/// Valet version not readable
// Valet version not readable
"startup.errors.valet_version_unknown.title" = "Ihre Valet-Version konnte nicht gelesen werden";
"startup.errors.valet_version_unknown.subtitle" = "Das Auslesen der Ausgabe von `valet --version` ist fehlgeschlagen. Stellen Sie sicher, dass Ihre Valet-Installation funktioniert und aktuell ist.";
"startup.errors.valet_version_unknown.desc" = "Versuchen Sie, `valet --version` in einem Terminal auszuführen, um herauszufinden, was los ist.";
@ -657,27 +667,27 @@ Wenn Sie diese Meldung sehen, aber nicht wissen, warum dieser Ordner verschwunde
"startup.errors.valet_version_not_supported.subtitle" = "Sie verwenden eine Version von Valet, die derzeit nicht unterstützt wird. PHP Monitor funktioniert derzeit mit Valet v2, v3 und v4. Um Probleme auf Ihrem System zu vermeiden, kann PHP Monitor nicht gestartet werden.";
"startup.errors.valet_version_not_supported.desc" = "Sie müssen eine Version von Valet installieren, die mit PHP Monitor kompatibel ist, oder Sie müssen ein Upgrade auf eine neuere Version von PHP Monitor durchführen, die möglicherweise die Kompatibilität mit dieser Version von Valet beinhaltet (weitere Informationen finden Sie in den aktuellen Release Notes).";
/// Brew & sudoers
// Brew & sudoers
"startup.errors.sudoers_brew.title" = "Brew wurde nicht zu sudoers.d hinzugefügt";
"startup.errors.sudoers_brew.subtitle" = "Sie müssen `sudo valet trust` ausführen, um sicherzustellen, dass Valet Dienste starten und stoppen kann, ohne jedes Mal sudo verwenden zu müssen. Die Anwendung wird nicht richtig funktionieren, bis Sie dieses Problem behoben haben.";
"startup.errors.sudoers_brew.desc" = "Wenn Sie diesen Fehler immer wieder sehen, kann es sein, dass PHP Monitor die Datei nicht validieren kann. Dies lässt sich in der Regel wie folgt beheben: `sudo chmod +r /private/etc/sudoers.d/brew`.";
/// Valet & sudoers
// Valet & sudoers
"startup.errors.sudoers_valet.title" = "Valet wurde nicht zu sudoers.d hinzugefügt";
"startup.errors.sudoers_valet.subtitle" = "Sie müssen `sudo valet trust` ausführen, um sicherzustellen, dass Valet Dienste starten und stoppen kann, ohne jedes Mal sudo verwenden zu müssen. Die Anwendung wird nicht richtig funktionieren, bis Sie dieses Problem behoben haben. Wenn Sie dies bereits getan haben, führen Sie bitte `sudo valet trust` erneut aus.";
"startup.errors.sudoers_valet.desc" = "Wenn Sie diesen Fehler immer wieder sehen, kann es sein, dass PHP Monitor die Datei nicht validieren kann. Dies lässt sich in der Regel wie folgt beheben: `sudo chmod +r /private/etc/sudoers.d/valet`.";
/// Platform issue detected
// Platform issue detected
"startup.errors.global_composer_platform_issues.title" = "PHP Monitor und Valet funktionieren nicht richtig: Composer meldet ein Problem mit Ihrer Plattform";
"startup.errors.global_composer_platform_issues.subtitle" = "Bitte befolgen Sie die folgenden empfohlenen Schritte, um dieses Problem in Zukunft zu vermeiden:\n\n1. Führen Sie `composer global update` aus.\n2. Starten Sie PHP Monitor neu. (Es sollte wieder funktionieren.)\n3. Wechseln Sie zur ältesten PHP-Version, die Sie installiert haben.\n4. Führen Sie `composer global update` erneut aus.";
"startup.errors.global_composer_platform_issues.desc" = "Sie können in den Einstellungen die Option \"Globale Abhängigkeiten automatisch aktualisieren\" aktivieren. Dadurch werden Ihre globalen Composer-Abhängigkeiten bei jeder Änderung der PHP-Version aktualisiert, was nicht ideal ist, wenn Sie nicht ständig Zugang zum Internet haben. Valet funktioniert derzeit nicht mit den installierten Abhängigkeiten. Normalerweise wird dies durch eine Versionsabweichung verursacht: d.h. installierte Abhängigkeiten für eine neuere Version von PHP als die derzeit aktive Version.";
/// Cannot retrieve services
// Cannot retrieve services
"startup.errors.services_json_error.title" = "Status der Dienste kann nicht ermittelt werden";
"startup.errors.services_json_error.subtitle" = "PHP Monitor fragt normalerweise `brew` mit dem folgenden Befehl ab, um zu testen, ob die Dienste abgerufen werden können: `sudo brew services info nginx --json`.\nPHP Monitor konnte diese Antwort nicht interpretieren.";
"startup.errors.services_json_error.desc" = "Dies kann passieren, wenn Ihre Homebrew-Installation veraltet ist. In diesem Fall gibt Homebrew noch kein JSON zurück. Sie können dies normalerweise beheben, indem Sie `brew update` oder `brew tap homebrew/services` ausführen. Sie können auch versuchen, `sudo brew services info nginx --json` in einem Terminal Ihrer Wahl auszuführen.";
/// Issue with `which` alias
// Issue with `which` alias
"startup.errors.which_alias_issue.title" = "Es wurde ein Konfigurationsproblem festgestellt";
"startup.errors.which_alias_issue.subtitle" = "Es scheint, dass es eine Datei in `/usr/local/bin/which` gibt. Diese wird normalerweise von NodeJS eingerichtet, aber `node` ist nicht im PATH in `/usr/local/bin`. Um dies zu beheben, lesen Sie weiter.";
"startup.errors.which_alias_issue.desc" = "Sie müssen einen Symlink von `node` in das Verzeichnis `/usr/local/bin` setzen, um sicherzustellen, dass PHP Monitor erfolgreich starten kann. Für weitere Informationen siehe: https://github.com/nicoverbruggen/phpmon/issues/174";

View File

@ -85,6 +85,8 @@
"mi_xdebug_actions" = "Actions";
"mi_xdebug_disable_all" = "Disable All Modes";
"mm_actions" = "Actions";
// CONFMAN
"confman.title" = "PHP Configuration Editor";
@ -118,7 +120,14 @@
"phpextman.list.status.external" = "This extension is already installed via another source, and cannot be managed.";
"phpextman.list.status.installable" = "This extension can be installed.";
"phpextman.list.status.dependent" = "You cannot uninstall this before uninstalling %@.";
"phpextman.list.status.can_manage" = "This extension is installed and can be managed by PHP Monitor.";
"phpextman.list.status.can_manage" = "This extension is installed and managed by PHP Monitor.";
"phpextman.errors.not_found.title" = "Uh oh. No extensions discovered!";
"phpextman.errors.not_found.desc" = "This is not supposed to happen. You may need to run the following command in your terminal:
`brew tap shivammathur/extensions`
and restart PHP Monitor for extensions to become visible. If the problem persists after running the command and restarting PHP Monitor, please consider opening an issue on GitHub.";
// PHPMAN
@ -151,7 +160,7 @@
"phpman.refresh.button" = "Search for Updates";
"phpman.refresh.button.description" = "You can press the refresh button to check if any updates are available to installed PHP versions.";
"phpman.has_updates.description" = "One or more updates are available. (Please note that PHP Monitor will always install or update PHP versions in bulk, so you will always upgrade all installations at once.)";
"phpman.has_updates.description" = "**One or more updates are available.** PHP Monitor will always install or update PHP versions in bulk, so you will always upgrade all installations at once.";
"phpman.has_updates.button" = "Upgrade All";
"phpman.warnings.outdated.title" = "This version of PHP Monitor is outdated";
@ -232,8 +241,9 @@ You may be asked for your password during the uninstallation process if file per
"domain_list.title" = "Domains";
"domain_list.subtitle" = "";
"domain_list.no_domains" = "You have not set up any domains or proxies yet.";
"domain_list.no_domains_for_search_query" = "There are no results for your search query.";
"domain_list.domains_empty.title" = "No domains available.";
"domain_list.domains_empty.desc" = "No domains were found for this search query or you haven't linked any domains yet.";
"domain_list.domains_empty.button" = "Add domain...";
"domain_list.tooltips.isolated" = "This domain is isolated and using PHP %@ instead of the globally linked PHP.";
"domain_list.tooltips.checkmark" = "This domain is being served with a version of PHP that is compatible with this requirement (PHP %@). Click on the PHP version next to this checkmark to find out more information about how this requirement was determined.";
@ -254,6 +264,7 @@ You may be asked for your password during the uninstallation process if file per
"domain_list.confirm_unlink_desc" = "No files will be removed. You can always link the folder again by clicking on the + button and selecting the original folder.";
"site_link.close" = "Close";
"site_link.switch_to_php" = "Switch to PHP %@";
"site_link.isolate_php" = "Isolate PHP %@";
"domain_list.confirm_unproxy" = "Are you sure you want to remove the proxy '%@'?";
"domain_list.confirm_unproxy_desc" = "You can always recreate proxy the again by clicking on the + button.";
@ -319,6 +330,8 @@ You may be asked for your password during the uninstallation process if file per
"domain_list.always_use_php" = "Always use PHP %@";
"domain_list.isolation_unavailable" = "Isolation Not Supported (in Valet 2)";
"domain_list.favorite" = "Favorite Domain";
"domain_list.unfavorite" = "Unfavorite Domain";
"domain_list.actions" = "Actions";
"domain_list.unlink" = "Unlink Directory";
"domain_list.secure" = "Secure Domain";
@ -634,7 +647,7 @@ You can do this by running `composer global update` in your terminal. After that
// STARTUP
/// 0. Architecture mismatch
// 0. Architecture mismatch
"alert.homebrew_missing.title" = "PHP Monitor cannot start!";
"alert.homebrew_missing.subtitle" = "A working Homebrew binary could not be found in the usual location. Please restart the app after fixing this issue.";
@ -642,32 +655,32 @@ You can do this by running `composer global update` in your terminal. After that
"alert.homebrew_missing.quit" = "Quit";
/// PHP binary not found
// PHP binary not found
"startup.errors.php_binary.title" = "PHP is not correctly installed";
"startup.errors.php_binary.subtitle" = "You must install PHP via Homebrew. The app will not work correctly until you resolve this issue.";
"startup.errors.php_binary.desc" = "Usually running `brew link php` in your Terminal will resolve this issue.\n\nTo diagnose what is wrong, you can try running `which php` in your Terminal, it should return `%@`.";
/// PHP not found in /usr/local/opt or /opt/homebrew/opt
// PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "PHP is not correctly installed";
"startup.errors.php_opt.subtitle" = "The PHP alias was not found in `%@`. The app will not work correctly until you resolve this issue.";
"startup.errors.php_opt.desc" = "If you already have the `php` formula installed, you may need to run `brew install php` in order for PHP Monitor to detect this installation.";
/// PHP binary is broken
// PHP binary is broken
"startup.errors.dyld_library.title" = "PHP is installed, but appears to be broken";
"startup.errors.dyld_library.subtitle" = "When PHP Monitor is attempting to run commands, it is failing to do so correctly. This is usually an indicator of a broken PHP installation.";
"startup.errors.dyld_library.desc" = "Running `brew reinstall php && brew link php` in your Terminal may resolve this issue, so please give that a try.";
/// Valet is not installed
// Valet is not installed
"startup.errors.valet_executable.title" = "Laravel Valet is not correctly installed";
"startup.errors.valet_executable.subtitle" = "You must install Valet with Composer. The app will not work correctly until you resolve this issue.";
"startup.errors.valet_executable.desc" = "If you haven't installed Laravel Valet yet, please do so first. If you have it installed but are seeing this message anyway, then try running `which valet` in Terminal, it should return: `%@`.";
/// Valet configuration file missing or broken
// Valet configuration file missing or broken
"startup.errors.valet_json_invalid.title" = "Laravel Valet configuration file invalid or missing";
"startup.errors.valet_json_invalid.subtitle" = "PHP Monitor needs to be able to read the configuration file. It appears the file is malformed or missing. Please check that it exists and is formatted correctly.";
"startup.errors.valet_json_invalid.desc" = "You can find the file at `~/.config/valet/config.json`. If Laravel Valet cannot parse the configuration file, running any `valet` command will usually automatically fix the JSON file. Try running `valet --version` to automatically fix the file.";
/// Valet version not readable
// Valet version not readable
"startup.errors.valet_version_unknown.title" = "Your Valet version could not be read";
"startup.errors.valet_version_unknown.subtitle" = "Parsing the output of `valet --version` failed. Make sure your Valet installation works and is up-to-date.";
"startup.errors.valet_version_unknown.desc" = "Try running `valet --version` in a terminal to find out what's going on.";
@ -683,32 +696,32 @@ If you are seeing this message but are confused why this folder has gone missing
"startup.errors.valet_version_not_supported.subtitle" = "You are running a version of Valet that is currently not supported. PHP Monitor currently works with Valet v2, v3 and v4. In order to avoid causing issues on your system, PHP Monitor cannot start.";
"startup.errors.valet_version_not_supported.desc" = "You must install a version of Valet that is compatible with PHP Monitor, or you may need to upgrade to a newer version of PHP Monitor which may include compatibility for this version of Valet (consult the latest release notes for more info).";
/// Brew & sudoers
// Brew & sudoers
"startup.errors.sudoers_brew.title" = "Brew has not been added to sudoers.d";
"startup.errors.sudoers_brew.subtitle" = "You must run `sudo valet trust` to ensure Valet can start and stop services without having to use sudo every time. The app will not work correctly until you resolve this issue.";
"startup.errors.sudoers_brew.desc" = "If you keep seeing this error, it is possible that there is a permission issue where PHP Monitor cannot validate the file, which can usually be resolved by running: `sudo chmod +r /private/etc/sudoers.d/brew`";
/// Valet & sudoers
// Valet & sudoers
"startup.errors.sudoers_valet.title" = "Valet has not been added to sudoers.d";
"startup.errors.sudoers_valet.subtitle" = "You must run `sudo valet trust` to ensure Valet can start and stop services without having to use sudo every time. The app will not work correctly until you resolve this issue. If you did this before, please run `sudo valet trust` again.";
"startup.errors.sudoers_valet.desc" = "If you keep seeing this error, it is possible that there is a permission issue where PHP Monitor cannot validate the file, which can usually be resolved by running: `sudo chmod +r /private/etc/sudoers.d/valet`";
/// Platform issue detected
// Platform issue detected
"startup.errors.global_composer_platform_issues.title" = "PHP Monitor and Valet cannot work correctly: Composer is reporting an issue with your platform";
"startup.errors.global_composer_platform_issues.subtitle" = "Please follow these recommended steps to avoid seeing this issue in the future:\n\n1. Run `composer global update`.\n2. Restart PHP Monitor. (It should work again.)\n3. Switch to the oldest PHP version you have installed.\n4. Run `composer global update` again.";
"startup.errors.global_composer_platform_issues.desc" = "You can go to Preferences and check the 'Automatically update global dependencies' option. This will update your global Composer dependencies whenever you change PHP versions, so this may not be ideal if you may not have constant access to the internet.\n\nTo find out exactly what's going wrong, try running `valet --version`. Valet is currently not functional with the installed dependencies. Usually this is caused by a version mismatch: i.e. installed dependencies for a newer version of PHP than the version that is currently active.";
/// Cannot retrieve services
// Cannot retrieve services
"startup.errors.services_json_error.title" = "Cannot determine services status";
"startup.errors.services_json_error.subtitle" = "PHP Monitor usually queries `brew` using the following command to test if the services can be retrieved: `sudo brew services info nginx --json`.\n\nPHP Monitor could not interpret this response.";
"startup.errors.services_json_error.desc" = "This can happen if your Homebrew installation is out of date, in which case Homebrew won't return JSON yet. You can usually fix this by running `brew update` or `brew tap homebrew/services`. You can also try running `sudo brew services info nginx --json` in your terminal of choice.";
/// Issue with `which` alias
// Issue with `which` alias
"startup.errors.which_alias_issue.title" = "A configuration issue was detected";
"startup.errors.which_alias_issue.subtitle" = "It appears that there's a file in `/usr/local/bin/which`. This is usually set up by NodeJS, but `node` isn't in the PATH in `/usr/local/bin`. To fix this, keep reading.";
"startup.errors.which_alias_issue.desc" = "You will need to symlink `node` into the `/usr/local/bin` directory to make sure PHP Monitor can start successfully. For more info, see: https://github.com/nicoverbruggen/phpmon/issues/174";
/// Laravel Herd conflicts
// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Laravel Herd appears to be running";
"startup.errors.herd_running.subtitle" = "It seems that Laravel Herd is currently running. Herd's built-in Valet setup may conflict with your regular Valet installation, so please quit Herd before continuing. (You can perfectly mix usage of Herd and regular Valet but you shouldn't run both at the same time.)";
"startup.errors.herd_running.desc" = "You may also find that the `php` alias by Herd added to your $PATH may prevent `php` aliasing of PHP Monitor from working, so keep that in mind. You can check out `~/.zshrc` and see what Herd has added to your $PATH.";
@ -738,7 +751,7 @@ Valet might break if you link these PHP versions so PHP Monitor won't let you sw
"startup.sponsor_encouragement.learn_more" = "Learn More";
"startup.sponsor_encouragement.skip" = "No Thanks";
// ERROR MESSAGES (based on AlertableError)
// ERROR MESSAGES
"alert.errors.homebrew_permissions.applescript_returned_nil.title" = "Restore Homebrew Permissions has been cancelled.";
"alert.errors.homebrew_permissions.applescript_returned_nil.description" = "The outcome of the script that is executed to adjust the permissions returned nil, which usually means that you did not grant administrative permissions to PHP Monitor.\n\nIf you clicked on Cancel during the authentication prompt, this is normal. If you did actually authenticate and you are still seeing this message, something probably went wrong.";

View File

@ -85,6 +85,8 @@
"mi_xdebug_actions" = "Actions";
"mi_xdebug_disable_all" = "Désactiver tous les modes";
"mm_actions" = "Actions";
// CONFMAN
"confman.title" = "Éditeur de configuration PHP";
@ -120,6 +122,14 @@
"phpextman.list.status.dependent" = "Vous ne pouvez pas désinstaller ceci avant de désinstaller %@.";
"phpextman.list.status.can_manage" = "Cette extension est installée et peut être gérée par PHP Monitor.";
"phpextman.errors.not_found.title" = "Oh là là. Aucune extension découverte !";
"phpextman.errors.not_found.desc" = "Ceci n'est pas censé se produire. Vous devrez peut-être exécuter la commande suivante dans votre terminal :
`brew tap shivammathur/extensions`
et redémarrer PHP Monitor pour que les extensions deviennent visibles. Si le problème persiste après avoir exécuté la commande et redémarré PHP Monitor, veuillez envisager d'ouvrir un problème sur GitHub.";
// PHPMAN
"phpman.busy.title" = "Vérification des mises à jour en cours !";
@ -142,7 +152,7 @@
"phpman.refresh.button" = "Rechercher des mises à jour";
"phpman.refresh.button.description" = "Vous pouvez appuyer sur le bouton de rafraîchissement pour vérifier si des mises à jour sont disponibles pour les versions de PHP installées.";
"phpman.has_updates.description" = "Une ou plusieurs mises à jour sont disponibles. (Veuillez noter que PHP Monitor installera ou mettra toujours à jour les versions de PHP en bloc, vous mettrez donc à jour toutes les installations en une seule fois.)";
"phpman.has_updates.description" = "**Une ou plusieurs mises à jour sont disponibles.** PHP Monitor installera ou mettra toujours à jour les versions de PHP en bloc, vous mettrez donc à jour toutes les installations en une seule fois.";
"phpman.has_updates.button" = "Tout mettre à jour";
"phpman.warnings.unsupported.title" = "Votre version de Homebrew peut causer des problèmes";
@ -307,6 +317,8 @@ Il se peut que vous deviez saisir votre mot de passe pendant le processus de dé
"domain_list.always_use_php" = "Tojours utiliser PHP %@";
"domain_list.isolation_unavailable" = "Isolement non pris en charge (dans Valet 2)";
"domain_list.favorite" = "Marquer comme favori";
"domain_list.unfavorite" = "Démarquer des favoris";
"domain_list.actions" = "Actions";
"domain_list.unlink" = "Supprimer le Lien vers le Dossier";
"domain_list.secure" = "Sécuriser le Domaine";
@ -619,7 +631,7 @@ Vous pouvez mettre à jour en executant `composer global update` dans votre term
// STARTUP
/// 0. Architecture mismatch
// 0. Architecture mismatch
"alert.homebrew_missing.title" = "Le PHP Monitor ne peut pas démarrer !";
"alert.homebrew_missing.subtitle" = "Un binaire Homebrew fonctionnel n'a pas pu être trouvé à l'emplacement standard. Veuillez redémarrer l'application après avoir résolu ce problème.";
@ -627,32 +639,32 @@ Vous pouvez mettre à jour en executant `composer global update` dans votre term
"alert.homebrew_missing.quit" = "Quitter";
/// PHP binary not found
// PHP binary not found
"startup.errors.php_binary.title" = "PHP n'est pas correctement installé";
"startup.errors.php_binary.subtitle" = "Vous devez installer PHP via Homebrew. L'application ne fonctionnera pas correctement tant que vous n'aurez pas résolu ce problème.";
"startup.errors.php_binary.desc" = "Généralement, l'exécution de `brew link php` dans votre Terminal résoudra ce problème.\n\nPour diagnostiquer ce qui ne va pas, vous pouvez essayer de lancer `which php` dans votre Terminal, il devrait retourner `%@`.";
/// PHP not found in /usr/local/opt or /opt/homebrew/opt
// PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "PHP n'est pas correctement installé";
"startup.errors.php_opt.subtitle" = "L'alias PHP n'a pas été trouvé dans `%@`. L'application ne fonctionnera pas correctement tant que vous n'aurez pas résolu ce problème.";
"startup.errors.php_opt.desc" = "Si vous avez déjà installé la formule `php`, vous pouvez avoir besoin de lancer `brew install php` pour que PHP Monitor détecte cette installation.";
/// PHP binary is broken
// PHP binary is broken
"startup.errors.dyld_library.title" = "PHP est installé, mais ne fonctionne manifestement pas.";
"startup.errors.dyld_library.subtitle" = "Lorsque le PHP Monitor tente d'exécuter des commandes, il ne parvient pas à le faire correctement. C'est généralement un indicateur d'une installation PHP défectueuse.";
"startup.errors.dyld_library.desc" = "Lancer `brew reinstall php && brew link php` dans votre Terminal peut résoudre ce problème, veuillez donc essayer.";
/// Valet is not installed
// Valet is not installed
"startup.errors.valet_executable.title" = "Laravel Valet n'est pas correctement installé";
"startup.errors.valet_executable.subtitle" = "Vous devez installer Valet avec Composer. L'application ne fonctionnera pas correctement tant que vous n'aurez pas résolu ce problème.";
"startup.errors.valet_executable.desc" = "Si vous n'avez pas encore installé Laravel Valet, faites-le d'abord. Si vous l'avez installé mais que vous voyez quand même ce message, essayez de lancer `which valet` dans Terminal, il devrait retourner : `%@`.";
/// Valet configuration file missing or broken
// Valet configuration file missing or broken
"startup.errors.valet_json_invalid.title" = "Fichier de configuration de Laravel Valet invalide ou manquant";
"startup.errors.valet_json_invalid.subtitle" = "PHP Monitor doit pouvoir lire le fichier de configuration. Il semble que le fichier soit malformé ou manquant. Veuillez vérifier qu'il existe et qu'il est correctement formaté.";
"startup.errors.valet_json_invalid.desc" = "Vous pouvez trouver le fichier à `~/.config/valet/config.json`. Si Laravel Valet ne peut pas analyser le fichier de configuration, l'exécution de n'importe quelle commande `valet` corrigera automatiquement le fichier JSON. Essayez d'exécuter `valet --version` pour corriger automatiquement le fichier.";
/// Valet version not readable
// Valet version not readable
"startup.errors.valet_version_unknown.title" = "La version de votre Valet n'a pu être lue";
"startup.errors.valet_version_unknown.subtitle" = "L'analyse de la réponse de `valet --version` a échoué. Assurez-vous que votre installation de Valet fonctionne et qu'elle est à jour.";
"startup.errors.valet_version_unknown.desc" = "Essayez de lancer `valet --version` dans un terminal pour savoir ce qui se passe.";
@ -668,32 +680,32 @@ Si vous voyez ce message mais que vous ne savez pas pourquoi ce dossier a dispar
"startup.errors.valet_version_not_supported.subtitle" = "Vous utilisez une version de Valet qui n'est pas supportée actuellement. PHP Monitor fonctionne actuellement avec Valet v2, v3 et v4. Afin d'éviter de causer des problèmes sur votre système, PHP Monitor ne peut pas démarrer.";
"startup.errors.valet_version_not_supported.desc" = "Vous devez installer une version de Valet qui est compatible avec PHP Monitor, ou vous pouvez avoir besoin de mettre à jour vers une version plus récente de PHP Monitor qui peut inclure la compatibilité avec cette version de Valet (consultez les dernières notes de version pour plus d'informations).";
/// Brew & sudoers
// Brew & sudoers
"startup.errors.sudoers_brew.title" = "Brew n'a pas été ajouté à sudoers.d";
"startup.errors.sudoers_brew.subtitle" = "Vous devez exécuter `sudo valet trust` pour vous assurer que Valet peut démarrer et arrêter les services sans avoir à utiliser sudo à chaque fois. L'application ne fonctionnera pas correctement tant que vous n'aurez pas résolu ce problème.";
"startup.errors.sudoers_brew.desc" = "Si vous continuez à voir cette erreur, il est possible qu'il y ait un problème de permission où PHP Monitor ne peut pas valider le fichier, ce qui peut généralement être résolu en exécutant : `sudo chmod +r /private/etc/sudoers.d/brew`";
/// Valet & sudoers
// Valet & sudoers
"startup.errors.sudoers_valet.title" = "Valet n'a pas été ajouté à sudoers.d";
"startup.errors.sudoers_valet.subtitle" = "Vous devez exécuter `sudo valet trust` pour vous assurer que Valet peut démarrer et arrêter les services sans avoir à utiliser sudo à chaque fois. L'application ne fonctionnera pas correctement tant que vous n'aurez pas résolu ce problème. Si vous l'avez déjà fait, exécutez à nouveau `sudo valet trust`.";
"startup.errors.sudoers_valet.desc" = "Si vous continuez à voir cette erreur, il est possible qu'il y ait un problème de permission où PHP Monitor ne peut pas valider le fichier, ce qui peut généralement être résolu en exécutant : `sudo chmod +r /private/etc/sudoers.d/valet`";
/// Platform issue detected
// Platform issue detected
"startup.errors.global_composer_platform_issues.title" = "PHP Monitor et Valet ne peuvent pas fonctionner correctement : Composer signale un problème avec votre plateforme";
"startup.errors.global_composer_platform_issues.subtitle" = "Veuillez suivre les étapes suivantes pour éviter ce problème à l'avenir :\n\n1. Exécuter `composer global update`.\n2. Redémarrer PHP Monitor. (Il devrait fonctionner à nouveau.)\n3. Passez à la version la plus ancienne de PHP que vous avez installée.\n4. Exécutez à nouveau `composer global update`.";
"startup.errors.global_composer_platform_issues.desc" = "Vous pouvez aller dans Préférences et cocher l'option 'Mettre à jour automatiquement les dépendances globales'. Cela mettra à jour les dépendances globales de Composer à chaque fois que vous changerez de version de PHP, ce qui n'est pas idéal si vous n'avez pas un accès constant à internet.\n\nPour savoir exactement ce qui ne va pas, essayez de lancer `valet --version`. Valet n'est actuellement pas fonctionnel avec les dépendances installées. Habituellement, cela est dû à une incompatibilité de version : c'est-à-dire que les dépendances installées correspondent à une version de PHP plus récente que la version actuellement active.";
/// Cannot retrieve services
// Cannot retrieve services
"startup.errors.services_json_error.title" = "Impossible de déterminer l'état des services";
"startup.errors.services_json_error.subtitle" = "PHP Monitor interroge habituellement `brew` en utilisant la commande suivante pour tester si les services peuvent être récupérés : `sudo brew services info nginx --json`.\n\n Le moniteur PHP n'a pas pu interpréter cette réponse.";
"startup.errors.services_json_error.desc" = "Cela peut arriver si votre installation Homebrew n'est pas à jour, auquel cas Homebrew ne renverra pas encore de JSON. Vous pouvez généralement corriger cela en lançant `brew update` ou `brew tap homebrew/services`. Vous pouvez aussi essayer de lancer `sudo brew services info nginx --json` dans le terminal de votre choix.";
/// Issue with `which` alias
// Issue with `which` alias
"startup.errors.which_alias_issue.title" = "Un problème de configuration a été détecté";
"startup.errors.which_alias_issue.subtitle" = "Il semble qu'il y ait un fichier dans `/usr/local/bin/which`. Ceci est généralement mis en place par NodeJS, mais `node` n'est pas dans le PATH de `/usr/local/bin`. Pour corriger cela, continuez à lire.";
"startup.errors.which_alias_issue.desc" = "Vous devrez faire un lien symbolique entre `node` et le répertoire `/usr/local/bin` pour vous assurer que PHP Monitor peut démarrer avec succès. Pour plus d'informations, voir : https://github.com/nicoverbruggen/phpmon/issues/174";
/// Laravel Herd conflicts
// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Laravel Herd semble être lancé";
"startup.errors.herd_running.subtitle" = "Il semble que Laravel Herd soit en cours d'exécution. La configuration de Valet intégrée à Herd peut entrer en conflit avec votre installation habituelle de Valet, veuillez donc quitter Herd avant de continuer. (Vous pouvez parfaitement mélanger l'utilisation de Herd et de Valet mais vous ne devez pas utiliser les deux en même temps).";
"startup.errors.herd_running.desc" = "Vous pouvez également constater que l'alias `php` ajouté par Herd à votre $PATH peut empêcher l'alias `php` de PHP Monitor de fonctionner, alors gardez cela à l'esprit. Vous pouvez vérifier `~/.zshrc` et voir ce que Herd a ajouté à votre $PATH.";

View File

@ -86,6 +86,8 @@
"mi_xdebug_actions" = "Acties";
"mi_xdebug_disable_all" = "Alle modes uitschakelen";
"mm_actions" = "Acties";
// PHPEXTMAN
"phpextman.window.title" = "Extensies";
@ -106,6 +108,13 @@
"phpextman.list.status.dependent" = "U kunt dit niet deïnstalleren voordat u %@ deïnstalleert.";
"phpextman.list.status.can_manage" = "Deze extensie is geïnstalleerd en kan worden beheerd door PHP Monitor.";
"phpextman.errors.not_found.title" = "Oeps. Geen extensies gevonden!";
"phpextman.errors.not_found.desc" = "Dit zou niet moeten gebeuren. Mogelijk moet je het volgende commando in je terminal uitvoeren:
`brew tap shivammathur/extensions`
en PHP Monitor herstarten om de extensies zichtbaar te maken. Als het probleem zich blijft voordoen na het uitvoeren van het commando en het herstarten van PHP Monitor, overweeg dan om een issue te openen op GitHub.";
// PHPMAN
"phpman.busy.title" = "Bezig met zoeken naar updates!";
@ -128,7 +137,7 @@
"phpman.refresh.button" = "Zoek naar updates";
"phpman.refresh.button.description" = "Je kunt op de vernieuwen-knop drukken om te controleren of er updates beschikbaar zijn voor geïnstalleerde PHP-versies.";
"phpman.has_updates.description" = "Er zijn één of meer updates beschikbaar. (Houd er rekening mee dat PHP Monitor altijd PHP-versies in bulk installeert of bijwerkt, dus u zult altijd alle installaties tegelijk upgraden.)";
"phpman.has_updates.description" = "**Er zijn één of meer updates beschikbaar.** PHP Monitor werkt alle versies in één keer bij, hou hier rekening mee.";
"phpman.has_updates.button" = "Alles bijwerken";
"phpman.warnings.unsupported.title" = "Uw versie van Homebrew kan problemen veroorzaken";
@ -293,6 +302,8 @@ Tijdens het verwijderingsproces kan u worden gevraagd om uw wachtwoord indien de
"domain_list.always_use_php" = "Altijd PHP %@ gebruiken";
"domain_list.isolation_unavailable" = "Isolatie wordt niet ondersteund (in Valet 2)";
"domain_list.favorite" = "Markeren als favoriet";
"domain_list.unfavorite" = "Verwijderen uit favorieten";
"domain_list.actions" = "Acties";
"domain_list.unlink" = "Link verwijderen";
"domain_list.secure" = "Domein beveiligen";
@ -608,38 +619,38 @@ U kunt dit doen door `composer global update` uit te voeren in uw terminal. Voer
// STARTUP
/// Architecture mismatch
// Architecture mismatch
"alert.homebrew_missing.title" = "PHP Monitor kan niet starten!";
"alert.homebrew_missing.subtitle" = "Er kon geen werkende Homebrew-binair worden gevonden op de gebruikelijke locatie. Start de app opnieuw nadat u dit probleem hebt verholpen.";
"alert.homebrew_missing.info" = "U gebruikt PHP Monitor met de volgende architectuur: %@. Hierdoor wordt verwacht dat er een werkende Homebrew binary gevonden wordt in `%@`, maar deze is niet gevonden. Daarom kan PHP Monitor niet werken.\n\nAls u Homebrew nog niet hebt geïnstalleerd, doe dit dan nu. Als u gebruikmaakt van Apple Silicon, zorg er dan voor dat uw Homebrew en PHP Monitor dezelfde architectuur gebruiken door Rosetta in of uit te schakelen waar nodig.";
"alert.homebrew_missing.quit" = "Afsluiten";
/// PHP binary not found
// PHP binary not found
"startup.errors.php_binary.title" = "PHP is niet correct geïnstalleerd";
"startup.errors.php_binary.subtitle" = "U moet PHP installeren via Homebrew. De app werkt niet correct totdat u dit probleem oplost.";
"startup.errors.php_binary.desc" = "Meestal lost u dit probleem op door `brew link php` uit te voeren in uw Terminal.\n\nOm te achterhalen wat er mis is, kunt u proberen `which php` uit te voeren in uw Terminal. Het zou `%@` moeten retourneren.";
/// PHP not found in /usr/local/opt or /opt/homebrew/opt
// PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "PHP is niet correct geïnstalleerd";
"startup.errors.php_opt.subtitle" = "De PHP-alias is niet gevonden in `%@`. De app werkt niet correct totdat u dit probleem oplost.";
"startup.errors.php_opt.desc" = "Als u de `php` formule al hebt geïnstalleerd, moet u mogelijk `brew install php` uitvoeren zodat PHP Monitor deze installatie kan detecteren.";
/// PHP binary is broken
// PHP binary is broken
"startup.errors.dyld_library.title" = "PHP is geïnstalleerd, maar lijkt defect te zijn";
"startup.errors.dyld_library.subtitle" = "Bij het uitvoeren van opdrachten slaagt PHP Monitor er niet in om dit correct te doen. Dit is meestal een indicatie van een defecte PHP-installatie.";
"startup.errors.dyld_library.desc" = "Het opnieuw installeren van PHP met `brew reinstall php && brew link php` in uw Terminal kan dit probleem verhelpen, dus probeer dat eens.";
/// Valet is not installed
// Valet is not installed
"startup.errors.valet_executable.title" = "Laravel Valet is niet correct geïnstalleerd";
"startup.errors.valet_executable.subtitle" = "U moet Valet installeren met Composer. De app werkt niet correct totdat u dit probleem oplost.";
"startup.errors.valet_executable.desc" = "Als u Laravel Valet nog niet hebt geïnstalleerd, doe dit dan eerst. Als u het al hebt geïnstalleerd maar toch dit bericht ziet, probeer dan `which valet` uit te voeren in Terminal. Het zou `%@` moeten retourneren.";
/// Valet configuration file missing or broken
// Valet configuration file missing or broken
"startup.errors.valet_json_invalid.title" = "Laravel Valet configuratiebestand ongeldig of ontbreekt";
"startup.errors.valet_json_invalid.subtitle" = "PHP Monitor moet in staat zijn om het configuratiebestand te lezen. Het lijkt erop dat het bestand onjuist is opgemaakt of ontbreekt. Controleer of het bestaat en correct is opgemaakt.";
"startup.errors.valet_json_invalid.desc" = "U kunt het bestand vinden op `~/.config/valet/config.json`. Als Laravel Valet het configuratiebestand niet kan parsen, zal het uitvoeren van een `valet`-opdracht meestal automatisch het JSON-bestand herstellen. Probeer `valet --version` uit te voeren om het bestand automatisch te herstellen.";
/// Valet version not readable
// Valet version not readable
"startup.errors.valet_version_unknown.title" = "Kan uw Valet-versie niet lezen";
"startup.errors.valet_version_unknown.subtitle" = "Het parsen van de uitvoer van `valet --version` is mislukt. Zorg ervoor dat uw Valet-installatie werkt en up-to-date is.";
"startup.errors.valet_version_unknown.desc" = "Probeer `valet --version` uit te voeren in een terminal om erachter te komen wat er aan de hand is.";
@ -655,32 +666,32 @@ Als u dit bericht ziet, maar verward bent waarom deze map ontbreekt, wilt u moge
"startup.errors.valet_version_not_supported.subtitle" = "U gebruikt een versie van Valet die momenteel niet wordt ondersteund. PHP Monitor werkt momenteel met Valet v2, v3 en v4. Om problemen op uw systeem te voorkomen, kan PHP Monitor niet starten.";
"startup.errors.valet_version_not_supported.desc" = "U moet een versie van Valet installeren die compatibel is met PHP Monitor, of u moet mogelijk upgraden naar een nieuwere versie van PHP Monitor die compatibiliteit biedt met deze versie van Valet (raadpleeg de nieuwste release-opmerkingen voor meer informatie).";
/// Brew & sudoers
// Brew & sudoers
"startup.errors.sudoers_brew.title" = "Brew is niet toegevoegd aan sudoers.d";
"startup.errors.sudoers_brew.subtitle" = "U moet `sudo valet trust` uitvoeren om ervoor te zorgen dat Valet services kan starten en stoppen zonder telkens sudo te hoeven gebruiken. De app werkt niet correct totdat u dit probleem oplost.";
"startup.errors.sudoers_brew.desc" = "Als u deze fout blijft zien, is het mogelijk dat er een machtigingsprobleem is waarbij PHP Monitor het bestand niet kan valideren. Dit kan meestal worden opgelost door `sudo chmod +r /private/etc/sudoers.d/brew` uit te voeren";
/// Valet & sudoers
// Valet & sudoers
"startup.errors.sudoers_valet.title" = "Valet is niet toegevoegd aan sudoers.d";
"startup.errors.sudoers_valet.subtitle" = "U moet `sudo valet trust` uitvoeren om ervoor te zorgen dat Valet services kan starten en stoppen zonder telkens sudo te hoeven gebruiken. De app werkt niet correct totdat u dit probleem oplost. Als u dit al eerder hebt gedaan, voer dan `sudo valet trust` opnieuw uit.";
"startup.errors.sudoers_valet.desc" = "Als u deze fout blijft zien, is het mogelijk dat er een machtigingsprobleem is waarbij PHP Monitor het bestand niet kan valideren. Dit kan meestal worden opgelost door `sudo chmod +r /private/etc/sudoers.d/valet` uit te voeren";
/// Platform issue detected
// Platform issue detected
"startup.errors.global_composer_platform_issues.title" = "PHP Monitor en Valet kunnen niet correct werken: Composer meldt een probleem met uw platform";
"startup.errors.global_composer_platform_issues.subtitle" = "Volg deze aanbevolen stappen om dit probleem in de toekomst te voorkomen:\n\n1. Voer `composer global update` uit.\n2. Start PHP Monitor opnieuw op. (Het zou weer moeten werken.)\n3. Schakel over naar de oudste geïnstalleerde versie van PHP.\n4. Voer opnieuw `composer global update` uit.";
"startup.errors.global_composer_platform_issues.desc" = "U kunt naar Voorkeuren gaan en de optie 'Automatisch globale afhankelijkheden bijwerken' controleren. Hiermee worden uw globale Composer-afhankelijkheden bijgewerkt wanneer u PHP-versies wijzigt, dus dit is mogelijk niet ideaal als u mogelijk geen constante toegang tot internet heeft.\n\nOm erachter te komen wat er precies misgaat, probeer `valet --version` uit te voeren. Valet is momenteel niet functioneel met de geïnstalleerde afhankelijkheden. Dit wordt meestal veroorzaakt door een versieverschil: bijvoorbeeld geïnstalleerde afhankelijkheden voor een nieuwere versie van PHP dan de momenteel actieve versie.";
/// Cannot retrieve services
// Cannot retrieve services
"startup.errors.services_json_error.title" = "Kan de status van services niet bepalen";
"startup.errors.services_json_error.subtitle" = "PHP Monitor maakt meestal gebruik van de volgende opdracht om `brew` te raadplegen en te controleren of de services kunnen worden opgehaald: `sudo brew services info nginx --json`.\n\nPHP Monitor kon deze reactie niet interpreteren.";
"startup.errors.services_json_error.desc" = "Dit kan gebeuren als uw Homebrew-installatie verouderd is, waardoor Homebrew nog geen JSON retourneert. U kunt dit meestal oplossen door `brew update` of `brew tap homebrew/services` uit te voeren. U kunt ook proberen `sudo brew services info nginx --json` uit te voeren in uw terminal naar keuze.";
/// Issue with `which` alias
// Issue with `which` alias
"startup.errors.which_alias_issue.title" = "Er is een configuratieprobleem gedetecteerd";
"startup.errors.which_alias_issue.subtitle" = "Het lijkt erop dat er een bestand is in `/usr/local/bin/which`. Dit wordt meestal ingesteld door NodeJS, maar `node` staat niet in de PATH in `/usr/local/bin`. Om dit op te lossen, gaat u verder met lezen.";
"startup.errors.which_alias_issue.desc" = "U moet `node` symbolisch koppelen aan de `/usr/local/bin`-directory om ervoor te zorgen dat PHP Monitor succesvol kan starten. Voor meer informatie, zie: https://github.com/nicoverbruggen/phpmon/issues/174";
/// Laravel Herd conflicts
// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Laravel Herd lijkt actief te zijn";
"startup.errors.herd_running.subtitle" = "Het lijkt erop dat Laravel Herd momenteel actief is. De ingebouwde Valet-configuratie van Herd kan conflicteren met je reguliere Valet-installatie, dus sluit Herd af voordat je verdergaat. (Je kunt perfect gebruik maken van zowel Herd als reguliere Valet, maar je moet ze niet tegelijkertijd uitvoeren.)";
"startup.errors.herd_running.desc" = "Je kan ook merken dat de `php`-alias die Herd aan je $PATH heeft toegevoegd, niet werkt met de aliases van PHP Monitor, dus hou daar rekening mee. Je kunt `~/.zshrc` bekijken om te zien wat Herd aan je $PATH heeft toegevoegd.";

View File

@ -85,6 +85,8 @@
"mi_xdebug_actions" = "Ações";
"mi_xdebug_disable_all" = "Desativar todos os modos";
"mm_actions" = "Ações";
// PHPEXTMAN
"phpextman.window.title" = "Extensões";
@ -105,6 +107,13 @@
"phpextman.list.status.dependent" = "Você não pode desinstalar isso antes de desinstalar %@.";
"phpextman.list.status.can_manage" = "Esta extensão está instalada e pode ser gerenciada pelo PHP Monitor.";
"phpextman.errors.not_found.title" = "Uh oh. Nenhuma extensão descoberta!";
"phpextman.errors.not_found.desc" = "Isto não deveria acontecer. Pode ser necessário executar o seguinte comando no seu terminal:
`brew tap shivammathur/extensions`
e reiniciar o PHP Monitor para que as extensões se tornem visíveis. Se o problema persistir após executar o comando e reiniciar o PHP Monitor, por favor considere abrir um problema no GitHub.";
// PHPMAN
"phpman.busy.title" = "Procurando atualizações!";
@ -127,7 +136,7 @@
"phpman.refresh.button" = "Procurar atualizações";
"phpman.refresh.button.description" = "Você pode premir o botão de atualização para verificar se há atualizações disponíveis para as versões do PHP instaladas.";
"phpman.has_updates.description" = "Estão disponiveis uma ou mais atualizações. (Por favor, tenha em conta que o PHP Monitor instalará ou atualizará as versões do PHP em bloco, ou seja, atualizará todas as instalações PHP de uma só vez.)";
"phpman.has_updates.description" = "**Estão disponiveis uma ou mais atualizações.** Por favor, tenha em conta que o PHP Monitor instalará ou atualizará as versões do PHP em bloco, ou seja, atualizará todas as instalações PHP de uma só vez.";
"phpman.has_updates.button" = "Atualizar tudo";
"phpman.warnings.unsupported.title" = "A versão instalada do Homebrew pode causar problemas";
@ -293,6 +302,8 @@ Poderá ser-lhe solicitada a sua palavra-passe durante o processo de desinstala
"domain_list.always_use_php" = "Usar sempre PHP %@";
"domain_list.isolation_unavailable" = "Isolamento não suportado (no Laravel Valet 2)";
"domain_list.favorite" = "Marcar como favorito";
"domain_list.unfavorite" = "Desmarcar do favoritado";
"domain_list.actions" = "Ações";
"domain_list.unlink" = "Desvincular diretoria";
"domain_list.secure" = "Domínio seguro";
@ -607,7 +618,7 @@ Pode faze-lo executando `composer global update` no seu Terminal. Depois disso,
// STARTUP
/// 0. Architecture mismatch
// 0. Architecture mismatch
"alert.homebrew_missing.title" = "PHP Monitor não pode iniciar!";
"alert.homebrew_missing.subtitle" = "Não foi encontrado um executável do Homebrew da diretoria por defeito. Reinicie a aplicação depois de corrigir o problema.";
@ -615,32 +626,32 @@ Pode faze-lo executando `composer global update` no seu Terminal. Depois disso,
"alert.homebrew_missing.quit" = "Sair";
/// PHP binary not found
// PHP binary not found
"startup.errors.php_binary.title" = "O PHP não está instalado corretamente";
"startup.errors.php_binary.subtitle" = "Deve instalar o PHP através do Homebrew. Esta aplicação não funcionará corretamente até que resolva este problema.";
"startup.errors.php_binary.desc" = "Normalmente, executar `brew link php` no seu Terminal resolve este problema.\n\nPara diagnosticar o que está errado, pode tentar executar `which php` no seu Terminal, que deverá mostrar `%@`.";
/// PHP not found in /usr/local/opt or /opt/homebrew/opt
// PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "O PHP não está instalado corretamente";
"startup.errors.php_opt.subtitle" = "O alias do PHP não foi encontrado em `%@`. Esta aplicação não funcionará corretamente até que resolva este problema.";
"startup.errors.php_opt.desc" = "Se já possui a fórmula `php` instalada, pode ser necessário executar `brew install php` para que o PHP Monitor detecte a instalação.";
/// PHP binary is broken
// PHP binary is broken
"startup.errors.dyld_library.title" = "O PHP está instalado, mas parece estar incorretamente instalado";
"startup.errors.dyld_library.subtitle" = "Quando o PHP Monitor tenta executar comandos, falha. Isto geralmente é um indicador de uma instalação do PHP incorretamente instalado.";
"startup.errors.dyld_library.desc" = "Executar `brew reinstall php && brew link php` no seu Terminal pode resolver este problema, pelo que deve tentar executar este comando.";
/// Valet is not installed
// Valet is not installed
"startup.errors.valet_executable.title" = "Laravel Valet não está instalado corretamente";
"startup.errors.valet_executable.subtitle" = "Deve instalar o Laravel Valet com o Composer. Esta aplicação não funcionará corretamente até que resolva este problema.";
"startup.errors.valet_executable.desc" = "Se ainda não instalou o Laravel Valet, faça-o agora. Se já instalou, tente executar `which valet` no seu Terminal, que deverá mostrar: `%@`.";
/// Valet configuration file missing or broken
// Valet configuration file missing or broken
"startup.errors.valet_json_invalid.title" = "ficheiro de configuração Laravel Valet inválido ou inexistente";
"startup.errors.valet_json_invalid.subtitle" = "O PHP Monitor precisa de ler o ficheiro de configuração. Parece que o ficheiro está malformado ou inexistente. Por favor, verifique se o ficheiro existe e se está formatado corretamente.";
"startup.errors.valet_json_invalid.desc" = "Pode encontrar o ficheiro em `~/.config/valet/config.json`. Se o Laravel Valet não puder analisar o ficheiro de configuração, execute um comando `valet` qualquer que geralmente corrigirá automaticamente o ficheiro JSON. Tente executar `valet --version` para corrigir automaticamente o ficheiro.";
/// Valet version not readable
// Valet version not readable
"startup.errors.valet_version_unknown.title" = "A versão Laravel Valet não pôde ser obtida";
"startup.errors.valet_version_unknown.subtitle" = "A análise do output de `valet --version` falhou. Certifique-se de que a instalação do Laravel Valet funciona e está atualizada.";
"startup.errors.valet_version_unknown.desc" = "Tente executar `valet --version` no seu Terminal para descobrir o motivo do problema.";
@ -656,27 +667,27 @@ Se ainda vê esta mensagem, e não percebe porque a diretoria desapareceu, conv
"startup.errors.valet_version_not_supported.subtitle" = "Está a executar uma versão do Laravel Valet que não é compatível de momento. O PHP Monitor atualmente funciona apenas com Laravel Valet v2, v3 e v4. Para evitar problemas no seu sistema, o PHP Monitor não pode ser iniciado.";
"startup.errors.valet_version_not_supported.desc" = "Deve instalar uma versão do Laravel Valet que seja compatível com o PHP Monitor, ou pode ser necessário atualizar para uma versão mais recente do PHP Monitor que pode incluir compatibilidade para esta versão do Laravel Valet (consulte as notas de versão mais recentes para obter mais informações).";
/// Brew & sudoers
// Brew & sudoers
"startup.errors.sudoers_brew.title" = "Brew não foi adicionado a sudoers.d";
"startup.errors.sudoers_brew.subtitle" = "Deve executar `sudo valet trust` no seu Terminal para garantir que o Laravel Valet pode iniciar e parar os serviços sem ter que usar sempre o sudo. Esta aplicação não funcionará corretamente até que resolva este problema.";
"startup.errors.sudoers_brew.desc" = "Se continuar a ver este erro, é possível que haja um problema de permissão em que o PHP Monitor não pode validar o ficheiro, o que normalmente pode ser resolvido executando no seu Terminal: `sudo chmod +r /private/etc/sudoers.d/brew`";
/// Valet & sudoers
// Valet & sudoers
"startup.errors.sudoers_valet.title" = "Laravel Valet não foi adicionado a sudoers.d";
"startup.errors.sudoers_valet.subtitle" = "Você deve executar `sudo valet trust` para garantir que o Laravel Valet possa iniciar e parar os serviços sem ter que usar o sudo todas as vezes. Esta aplicação não funcionará corretamente até que você resolva este problema. Mesmo que já tenha feito isto antes, experimente executar novamente no seu Terminal `sudo valet trust`.";
"startup.errors.sudoers_valet.desc" = "Se continuar a ver este erro, é possível que haja um problema de permissão em que o PHP Monitor não pode validar o ficheiro, que normalmente pode ser resolvido executando no seu Terminal: `sudo chmod +r /private/etc/sudoers.d/valet`";
/// Platform issue detected
// Platform issue detected
"startup.errors.global_composer_platform_issues.title" = "O PHP Monitor e o Laravel Valet não funcionam corretamente: o Composer reporta um problema com sua plataforma";
"startup.errors.global_composer_platform_issues.subtitle" = "Siga estes passos recomendados para evitar este problema de futuro:\n\n1. Execute a `atualização global do compositor`.\n2. Reinicie o PHP Monitor. (Deve funcionar novamente.)\n3. Mude para a versão mais antiga do PHP que instalou.\n4. Execute a `atualização global do compositor` novamente.";
"startup.errors.global_composer_platform_issues.desc" = "Pode ir a Preferências e marcar a opção 'Atualizar dependências globais automaticamente'. Isto atualizará as suas dependências globais do Composer sempre que alterar versões do PHP, portanto, no entanto, pode não ser a solução ideal se não tiver acesso à Internet.\n\nPara descobrir exatamente o que está errado, tente executar no seu Terminal `valet --version`. O Laravel Valet não está a funcionar com as dependências instaladas. Normalmente, isso é provocado por uma incompatibilidade de versão: ou seja, dependências instaladas para uma versão mais recente do PHP do que a versão que está vinculada no momento.";
/// Cannot retrieve services
// Cannot retrieve services
"startup.errors.services_json_error.title" = "Não é possível determinar o status dos serviços";
"startup.errors.services_json_error.subtitle" = "O PHP Monitor geralmente usar o `brew` usando o seguinte comando para testar se os serviços podem ser recuperados: `sudo brew services info nginx --json`.\n\nO PHP Monitor não pôde interpretar a resposta do `brew`.";
"startup.errors.services_json_error.desc" = "Isto pode acontecer se a instalação do Homebrew estiver desatualizada, e o Homebrew ainda não retornar JSON. Geralmente, pode corrigir isto executando no seu Terminal `brew update` ou `brew tap homebrew/services`. Também pode tentar executar no seu Terminal `sudo brew services info nginx --json`.";
/// Issue with `which` alias
// Issue with `which` alias
"startup.errors.which_alias_issue.title" = "Foi detectado um problema de configuração";
"startup.errors.which_alias_issue.subtitle" = "Parece que há um ficheiro em `/usr/local/bin/which`. Isto geralmente é configurado pelo NodeJS, mas `node` não está no PATH em `/usr/local/bin`. Para corrigir isto, continue a ler.";
"startup.errors.which_alias_issue.desc" = "Precisará vincular `node` à diretoria `/usr/local/bin` para garantir que o PHP Monitor possa iniciar com sucesso. Para mais informações, consulte: https://github.com/nicoverbruggen/phpmon/issues/174";

View File

@ -85,6 +85,8 @@
"mi_xdebug_actions" = "Hành động";
"mi_xdebug_disable_all" = "Tắt Tất cả Chế độ";
"mm_actions" = "Hành động";
// PHPEXTMAN
"phpextman.window.title" = "Tiện ích mở rộng";
@ -105,6 +107,13 @@
"phpextman.list.status.dependent" = "Bạn không thể gỡ cài đặt điều này trước khi gỡ cài đặt %@.";
"phpextman.list.status.can_manage" = "Tiện ích mở rộng này đã được cài đặt và có thể được quản lý bởi PHP Monitor.";
"phpextman.errors.not_found.title" = "Ồ. Không phát hiện thấy tiện ích mở rộng nào!";
"phpextman.errors.not_found.desc" = "Điều này không nên xảy ra. Bạn có thể cần chạy lệnh sau trong terminal của mình:
`brew tap shivammathur/extensions`
và khởi động lại PHP Monitor để các tiện ích mở rộng trở nên hiển thị. Nếu vấn đề vẫn tiếp diễn sau khi chạy lệnh và khởi động lại PHP Monitor, xin hãy xem xét mở một vấn đề trên GitHub.";
// PHPMAN
"phpman.busy.title" = "Đang kiểm tra cập nhật!";
@ -127,7 +136,7 @@
"phpman.refresh.button" = "Tìm kiếm Cập nhật";
"phpman.refresh.button.description" = "Bạn có thể nhấn nút làm mới để kiểm tra xem có sẵn các cập nhật cho các phiên bản PHP đã cài đặt.";
"phpman.has_updates.description" = "Một hoặc nhiều cập nhật có sẵn. (Vui lòng lưu ý rằng PHP Monitor sẽ luôn cài đặt hoặc cập nhật các phiên bản PHP theo lô, vì vậy bạn sẽ luôn nâng cấp tất cả các cài đặt cùng một lúc.)";
"phpman.has_updates.description" = "**Một hoặc nhiều cập nhật có sẵn.** Vui lòng lưu ý rằng PHP Monitor sẽ luôn cài đặt hoặc cập nhật các phiên bản PHP theo lô, vì vậy bạn sẽ luôn nâng cấp tất cả các cài đặt cùng một lúc.";
"phpman.has_updates.button" = "Nâng cấp Tất cả";
"phpman.warnings.unsupported.title" = "Phiên bản Homebrew của bạn có thể gây ra vấn đề";
@ -283,6 +292,8 @@ Bạn có thể được yêu cầu nhập mật khẩu của mình trong quá t
"domain_list.always_use_php" = "Luôn sử dụng PHP %@";
"domain_list.isolation_unavailable" = "Không hỗ trợ cô lập (trong Valet 2)";
"domain_list.favorite" = "Điểm yêu thích";
"domain_list.unfavorite" = "Bỏ khỏi điểm yêu thích";
"domain_list.actions" = "Hành động";
"domain_list.unlink" = "Hủy liên kết Thư mục";
"domain_list.secure" = "Bảo mật Tên miền";
@ -600,7 +611,7 @@ Bạn có thể làm điều này bằng cách chạy `composer global update` t
// STARTUP
/// 0. Architecture mismatch
// 0. Architecture mismatch
"alert.homebrew_missing.title" = "PHP Monitor không thể khởi động!";
"alert.homebrew_missing.subtitle" = "Không tìm thấy binary Homebrew hoạt động ở vị trí thông thường. Vui lòng khởi động lại ứng dụng sau khi khắc phục vấn đề này.";
@ -608,32 +619,32 @@ Bạn có thể làm điều này bằng cách chạy `composer global update` t
"alert.homebrew_missing.quit" = "Thoát";
/// PHP binary not found
// PHP binary not found
"startup.errors.php_binary.title" = "PHP chưa được cài đặt đúng cách";
"startup.errors.php_binary.subtitle" = "Bạn phải cài đặt PHP qua Homebrew. Ứng dụng sẽ không hoạt động chính xác cho đến khi bạn giải quyết vấn đề này.";
"startup.errors.php_binary.desc" = "Thường thì chạy `brew link php` trong Terminal của bạn sẽ giải quyết vấn đề này.\n\nĐể chẩn đoán lỗi, bạn có thể thử chạy `which php` trong Terminal của bạn, nó sẽ trả về `%@`.";
/// PHP not found in /usr/local/opt or /opt/homebrew/opt
// PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "PHP chưa được cài đặt đúng cách";
"startup.errors.php_opt.subtitle" = "Bí danh PHP không được tìm thấy ở `%@`. Ứng dụng sẽ không hoạt động chính xác cho đến khi bạn giải quyết vấn đề này.";
"startup.errors.php_opt.desc" = "Nếu bạn đã cài đặt công thức `php`, bạn có thể cần chạy `brew install php` để PHP Monitor nhận ra cài đặt này.";
/// PHP binary is broken
// PHP binary is broken
"startup.errors.dyld_library.title" = "PHP đã được cài đặt, nhưng có vẻ bị lỗi";
"startup.errors.dyld_library.subtitle" = "Khi PHP Monitor cố gắng chạy các lệnh, nó không thể chạy chúng chính xác. Điều này thường là một dấu hiệu của một cài đặt PHP bị lỗi.";
"startup.errors.dyld_library.desc" = "Chạy `brew reinstall php && brew link php` trong Terminal của bạn có thể giải quyết vấn đề này, vì vậy hãy thử điều đó.";
/// Valet is not installed
// Valet is not installed
"startup.errors.valet_executable.title" = "Laravel Valet chưa được cài đặt đúng cách";
"startup.errors.valet_executable.subtitle" = "Bạn phải cài đặt Valet với Composer. Ứng dụng sẽ không hoạt động chính xác cho đến khi bạn giải quyết vấn đề này.";
"startup.errors.valet_executable.desc" = "Nếu bạn chưa cài đặt Laravel Valet, hãy cài đặt trước. Nếu bạn đã cài đặt, nhưng vẫn nhìn thấy thông báo này, thì hãy thử chạy `which valet` trong Terminal, nó sẽ trả về: `%@`.";
/// Valet configuration file missing or broken
// Valet configuration file missing or broken
"startup.errors.valet_json_invalid.title" = "Tệp cấu hình Laravel Valet không hợp lệ hoặc bị thiếu";
"startup.errors.valet_json_invalid.subtitle" = "PHP Monitor cần có thể đọc tệp cấu hình. Dường như tệp đã bị lỗi hoặc bị thiếu. Vui lòng kiểm tra xem nó tồn tại và được định dạng đúng.";
"startup.errors.valet_json_invalid.desc" = "Bạn có thể tìm thấy tệp tại `~/.config/valet/config.json`. Nếu Laravel Valet không thể phân tích cú pháp tệp cấu hình, chạy bất kỳ lệnh `valet` nào thường sẽ tự động sửa tệp JSON. Thử chạy `valet -- version` để tự động sửa file.";
/// Valet version not readable
// Valet version not readable
"startup.errors.valet_version_unknown.title" = "Phiên bản Valet của bạn không thể đọc được";
"startup.errors.valet_version_unknown.subtitle" = "Phân tích kết quả của `valet --version` đã thất bại. Hãy đảm bảo cài đặt Valet của bạn hoạt động và được cập nhật.";
"startup.errors.valet_version_unknown.desc" = "Thử chạy `valet --version` trong terminal để tìm hiểu điều gì đang xảy ra.";
@ -649,32 +660,32 @@ Nếu bạn nhìn thấy thông báo này nhưng bối rối vì thư mục này
"startup.errors.valet_version_not_supported.subtitle" = "Bạn đang chạy một phiên bản của Valet hiện không được hỗ trợ. PHP Monitor hiện tại hoạt động với Valet v2, v3 và v4. Để tránh gây ra sự cố trên hệ thống của bạn, PHP Monitor không thể khởi động.";
"startup.errors.valet_version_not_supported.desc" = "Bạn phải cài đặt một phiên bản của Valet tương thích với PHP Monitor, hoặc bạn có thể cần nâng cấp lên phiên bản mới hơn của PHP Monitor có thể bao gồm tính năng tương thích cho phiên bản này của Valet (xem thông tin chi tiết về các bản phát hành mới nhất để biết thêm thông tin).";
/// Brew & sudoers
// Brew & sudoers
"startup.errors.sudoers_brew.title" = "Brew chưa được thêm vào sudoers.d";
"startup.errors.sudoers_brew.subtitle" = "Bạn phải chạy lệnh `sudo valet trust` để đảm bảo Valet có thể bắt đầu và dừng dịch vụ mà không cần phải sử dụng sudo mỗi lần. Ứng dụng sẽ không hoạt động chính xác cho đến khi bạn giải quyết vấn đề này.";
"startup.errors.sudoers_brew.desc" = "Nếu bạn tiếp tục nhìn thấy lỗi này, có thể có vấn đề về quyền truy cập mà PHP Monitor không thể xác minh tệp, điều này thường có thể giải quyết bằng cách chạy: `sudo chmod +r /private/etc/sudoers.d/brew`";
/// Valet & sudoers
// Valet & sudoers
"startup.errors.sudoers_valet.title" = "Valet chưa được thêm vào sudoers.d";
"startup.errors.sudoers_valet.subtitle" = "Bạn phải chạy lệnh `sudo valet trust` để đảm bảo Valet có thể bắt đầu và dừng dịch vụ mà không cần phải sử dụng sudo mỗi lần. Ứng dụng sẽ không hoạt động chính xác cho đến khi bạn giải quyết vấn đề này. Nếu bạn đã làm điều này trước đó, hãy chạy lại lệnh `sudo valet trust`.";
"startup.errors.sudoers_valet.desc" = "Nếu bạn tiếp tục nhìn thấy lỗi này, có thể có vấn đề về quyền truy cập mà PHP Monitor không thể xác minh tệp, điều này thường có thể giải quyết bằng cách chạy: `sudo chmod +r /private/etc/sudoers.d/valet`";
/// Platform issue detected
// Platform issue detected
"startup.errors.global_composer_platform_issues.title" = "PHP Monitor và Valet không thể hoạt động chính xác: Composer báo cáo vấn đề với nền tảng của bạn";
"startup.errors.global_composer_platform_issues.subtitle" = "Vui lòng làm theo những bước khuyến nghị sau để tránh gặp vấn đề này trong tương lai:\n\n1. Chạy lệnh `composer global update`.\n2. Khởi động lại PHP Monitor. (Nó sẽ hoạt động lại).\n3. Chuyển sang phiên bản PHP cũ nhất mà bạn đã cài đặt.\n4. Chạy lại lệnh `composer global update`.";
"startup.errors.global_composer_platform_issues.desc" = "Bạn có thể vào Tùy chọn và kiểm tra tùy chọn 'Tự động cập nhật các phụ thuộc toàn cầu'. Điều này sẽ cập nhật các phụ thuộc Composer toàn cầu của bạn mỗi khi bạn thay đổi phiên bản PHP, vì vậy điều này có thể không lý tưởng nếu bạn không có quyền truy cập internet liên tục.\n\nĐể biết chính xác điều gì đang sai, hãy thử chạy `valet --version`. Hiện tại, Valet không hoạt động với các phụ thuộc đã cài đặt. Thông thường điều này được gây ra bởi sự không phù hợp của phiên bản: ví dụ như các phụ thuộc đã cài đặt cho một phiên bản PHP mới hơn phiên bản hiện tại đang hoạt động.";
/// Cannot retrieve services
// Cannot retrieve services
"startup.errors.services_json_error.title" = "Không thể xác định trạng thái dịch vụ";
"startup.errors.services_json_error.subtitle" = "PHP Monitor thường sử dụng lệnh sau để kiểm tra liệu các dịch vụ có thể được truy xuất hay không: `sudo brew services info nginx --json`.\n\nPHP Monitor không thể giải thích được câu trả lời này.";
"startup.errors.services_json_error.desc" = "Điều này có thể xảy ra nếu cài đặt Homebrew của bạn đã lỗi thời, trong trường hợp đó Homebrew sẽ không trở lại JSON. Bạn có thể khắc phục điều này bằng cách chạy `brew update` hoặc `brew tap homebrew/services`. Bạn cũng có thể thử chạy `sudo brew services info nginx --json` trong bất kỳ terminal nào bạn muốn.";
/// Issue with `which` alias
// Issue with `which` alias
"startup.errors.which_alias_issue.title" = "Phát hiện vấn đề cấu hình";
"startup.errors.which_alias_issue.subtitle" = "Dường như có một tệp trong `/usr/local/bin/which`. Điều này thường được thiết lập bởi NodeJS, nhưng `node` không có trong PATH trong `/usr/local/bin`. Để khắc phục điều này, hãy đọc tiếp.";
"startup.errors.which_alias_issue.desc" = "Bạn sẽ cần tạo liên kết tượng trưng cho `node` vào thư mục `/usr/local/bin` để đảm bảo PHP Monitor có thể khởi động thành công. Để biết thêm thông tin, xem: https://github.com/nicoverbruggen/phpmon/issues/174";
/// Laravel Herd conflicts
// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Có vẻ như Laravel Herd đang chạy";
"startup.errors.herd_running.subtitle" = "Có vẻ như Laravel Herd hiện đang chạy. Cài đặt Valet tích hợp của Herd có thể xung đột với cài đặt Valet thông thường của bạn, vì vậy hãy thoát Herd trước khi tiếp tục. (Bạn có thể hoàn toàn kết hợp sử dụng Herd và Valet thông thường nhưng bạn không nên chạy cả hai cùng một lúc.)";
"startup.errors.herd_running.desc" = "Bạn cũng có thể thấy rằng bí danh `php` mà Herd thêm vào $PATH của bạn có thể ngăn chặn việc đặt bí danh `php` cho PHP Monitor hoạt động, vì vậy hãy lưu ý điều đó. Bạn có thể kiểm tra tệp `~/.zshrc` và xem Herd đã thêm gì vào $PATH của bạn.";

View File

@ -0,0 +1,866 @@
// MENU ITEMS (MI)
"mi_busy" = "PHP Monitor 正忙着...";
"mi_unsure" = "我们不确定您正在运行的 PHP 版本";
"mi_php_version" = "全局版本PHP";
"mi_php_switch" = "切换到 PHP";
"mi_php_unsupported" = "未显示某些已安装的 PHP 版本";
"mi_php_broken_1" = "哦!看来您的 PHP 安装已损坏...";
"mi_php_broken_2" = "尝试在终端运行 `php -v`";
"mi_php_broken_3" = "您也可以尝试切换到另一个版本";
"mi_php_broken_4" = "运行 `brew reinstall php`(或同等版本)可能会有帮助";
"mi_no_php_linked" = "未链接 PHP 版本!";
"mi_fix_php_link" = "自动修复...";
"mi_no_php_linked_explain" = "这是什么?";
"mi_php_version_manager" = "管理 PHP 安装...";
"mi_php_ext_manager" = "管理 PHP 扩展...";
"mi_php_config_manager" = "PHP 配置编辑器...";
"mi_manage_limits" = "管理限制...";
"mi_diagnostics" = "诊断";
"mi_active_services" = "活动服务";
"mi_restart_php_fpm" = "重启服务php";
"mi_restart_nginx" = "重启服务nginx";
"mi_restart_dnsmasq" = "重启服务dnsmasq";
"mi_manage_services" = "管理服务";
"mi_restart_valet_services" = "重启 Valet 服务";
"mi_stop_valet_services" = "停止 Valet 服务";
"mi_fix_my_valet" = "修复我的 Valet...";
"mi_fix_my_valet_tooltip" = "您的 Valet 安装有问题?试试 PHP Monitor 的自动修复功能,它能让您立即恢复正常运行!";
"mi_fix_brew_permissions" = "恢复 Homebrew 权限...";
"mi_fix_brew_permissions_tooltip" = "运行 `brew upgrade` 时遇到权限问题PHP Monitor 来帮忙!";
"mi_php_refresh" = "刷新信息";
"mi_configuration" = "PHP 配置";
"mi_limits" = "限制配置";
"mi_memory_limit" = "内存限制";
"mi_post_max_size" = "最大 POST";
"mi_upload_max_filesize" = "最大上传";
"mi_manual_actions" = "手动操作";
"mi_services" = "服务";
"mi_other" = "急救与服务";
"mi_first_aid" = "急救";
"mi_xdebug_mode" = "管理 Xdebug";
"mi_composer" = "Composer";
"mi_valet_config" = "定位 Valet 文件夹(.config/valet)";
"mi_php_config" = "定位 PHP 配置文件(php.ini)";
"mi_phpmon_config" = "定位 PHP Monitor 文件夹(.config/phpmon)";
"mi_global_composer" = "定位全局 Composer 文件(.composer)";
"mi_phpinfo" = "显示当前配置(phpinfo)";
"mi_update_global_composer" = "更新全局 Composer 依赖...";
"mi_detected_extensions" = "检测到的扩展";
"mi_no_extensions_detected" = "未检测到其他扩展";
"mi_php_doctor" = "PHP Doctor";
"mi_fa_php_doctor" = "打开 PHP Doctor...";
"mi_recommendations_count" = "%i 个被检测到的问题!";
"mi_view_recommendations" = "查看建议...";
"mi_valet" = "Laravel Valet";
"mi_domain_list" = "查看域名列表...";
"mi_preferences" = "首选项...";
"mi_donate" = "捐赠...";
"mi_check_for_updates" = "检查更新...";
"mi_lite_mode" = "关于单机模式...";
"mi_quit" = "退出 PHP Monitor";
"mi_about" = "关于 PHP Monitor";
"mi_presets_title" = "配置预设";
"mi_apply_presets_title" = "应用配置预设";
"mi_revert_to_prev_config" = "还原到先前配置...";
"mi_profiles_loaded" = "从配置文件加载 %i 配置文件";
"mi_no_presets" = "无可用预设";
"mi_set_up_presets" = "了解有关预设的更多信息...";
"mi_view_onboarding" = "打开 Welcome Tour...";
"mi_xdebug_available_modes" = "可用模式";
"mi_xdebug_actions" = "操作";
"mi_xdebug_disable_all" = "禁用所有模式";
"mm_actions" = "操作";
// CONFMAN
"confman.title" = "PHP 配置编辑器";
"confman.description" = "该功能可让您轻松定制 PHP 安装的配置。\n请注意您所做的任何更改都会立即自动应用。";
"confman.byte_limit.unlimited" = "允许无限制使用";
"php_ini.memory_limit.title" = "内存限制";
"php_ini.memory_limit.description" = "设置允许脚本分配的最大内存字节数。这有助于防止编写不当的脚本占用服务器上的所有可用内存";
"php_ini.post_max_size.title" = "POST 最大大小";
"php_ini.post_max_size.description" = "设置允许的帖子数据最大大小。此设置也会影响文件上传。要上传大文件,该值必须大于上传最大大小。一般来说,内存限制应大于 POST 最大大小";
"php_ini.file_uploads.title" = "文件上传";
"php_ini.file_uploads.description" = "启用或完全禁用文件上传。建议保持开启。";
"php_ini.upload_max_filesize.title" = "上传最大文件大小";
"php_ini.upload_max_filesize.description" = "上传文件的最大大小。POST 最大文件大小必须大于此值";
// PHPEXTMAN
"phpextman.window.title" = "扩展";
"phpextman.description" = "**PHP 扩展管理器**让您只需点击按钮即可管理不同的 PHP 扩展。由于使用的是 Homebrew因此无需使用 `pecl` 即时编译扩展。";
"phpextman.disclaimer" = "某些扩展可能需要安装其他依赖项,但一般来说,安装扩展应该比安装 PHP 版本快得多";
"phpextman.warnings.removal.title" = "卸载扩展 `%@`";
"phpextman.warnings.removal.desc" = "扩展及其唯一的配置文件将被删除。此 PHP 安装将不再使用扩展的功能。您确定吗?
(如果扩展使用非标准文件名启用,则不会被移除。因此,如果不想删除.ini 文件,最好将其重命名为其他文件名。在这种情况下,扩展名只会在清理过程中被禁用)";
"phpextman.warnings.removal.button" = "卸载";
"phpextman.list.showing_count" = "当前显示 %@ 扩展名:";
"phpextman.list.depends_on" = "依赖于:";
"phpextman.list.status.external" = "此扩展已通过其他来源安装,无法管理";
"phpextman.list.status.installable" = "可以安装此扩展";
"phpextman.list.status.dependent" = "在卸载 %@ 之前无法卸载此扩展。";
"phpextman.list.status.can_manage" = "该扩展已安装,可由 PHP Monitor 管理";
"phpextman.errors.not_found.title" = "啊哦。未发现扩展!";
"phpextman.errors.not_found.desc" = "不应该出现这种情况。您可能需要在终端运行以下命令:
`brew tap shivammathur/extensions` 并重启 PHP Monitor。
并重新启动 PHP Monitor 使扩展名可见。如果运行该命令并重启 PHP Monitor 后问题仍然存在,请考虑在 GitHub 上提交问题 ";
// PHPMAN
"phpman.busy.title" = "检查更新!";
"phpman.busy.description.outdated" = "检查任何 PHP 版本是否过时...";
"phpman.version.broken" = "此版本似乎已损坏,您可以尝试修复";
"phpman.version.has_update" = "已安装 %@ 版本,%@ 可用";
"phpman.version.installed" = "当前已安装 %@ 版本";
"phpman.version.available_for_installation" = "此版本可以安装";
"phpman.version.automatic_upgrade" = "此版本将通过升级旧版本自动安装";
"phpman.buttons.uninstall" = "卸载";
"phpman.buttons.install" = "安装";
"phpman.buttons.update" = "更新";
"phpman.buttons.repair" = "修复";
"phpman.version.prerelease" = "预发布";
"phpman.steps.installing" = "安装 %@";
"phpman.steps.removing" = "移除 %@";
"phpman.steps.reloading" = "重载 PHP 版本...";
"phpman.steps.preparing" = "PHP Monitor 正在准备 Homebrew...";
"phpman.steps.wait" = "请稍候...";
"phpman.steps.completed" = "操作已完成!";
"phpman.steps.success" = "操作成功";
"phpman.steps.failure" = "命令未能正确运行";
"phpman.title" = "PHP 版本管理器";
"phpman.description" = "**PHP 版本管理器**可让您通过 Homebrew 安装、升级和删除不同的 PHP 版本,而无需在终端运行命令。";
"phpman.disclaimer" = "请注意,安装或升级 PHP 版本可能会导致其他 Homebrew 软件包也被升级。大多数安装步骤通常需要一些时间,所以请耐心等待 Homebrew 完成工作";
"phpman.refresh.button" = "搜索更新";
"phpman.refresh.button.description" = "您可以点按刷新按钮来检查已安装的 PHP 版本是否有更新";
"phpman.has_updates.description" = "**有一个或多个更新可用。**PHP Monitor 总是会批量安装或更新 PHP 版本,因此您总是可以一次性升级所有安装的版本";
"phpman.has_updates.button" = "全部升级";
"phpman.warnings.outdated.title" = "此版本的 PHP Monitor 已过期";
"phpman.warnings.outdated.desc" = "自该版本 PHP Monitor 创建以来Homebrew Formula 极有可能已更改。我强烈建议在使用版本管理器安装、删除或升级 PHP 版本之前更新应用程序";
"phpman.warnings.unsupported.title" = "您的 Homebrew 版本可能会导致问题";
"phpman.warnings.unsupported.desc" = "没有禁用任何功能,但某些命令可能无法按预期运行。您当前运行的是 Homebrew %@。
目前Homebrew 4 是 PHP 版本管理器唯一支持的版本。如果您运行的是更新版本的 Homebrew您可能需要检查是否有更新版本的 PHP Monitor 可用 ";
"phpman.warnings.removal.title" = "您确定要卸载 %@";
"phpman.warnings.removal.desc" = "请注意,配置文件不会被删除,因此如果需要,稍后重新安装应该很容易。
如果文件权限不允许简单删除,卸载过程中可能会要求您提供密码 ";
"phpman.warnings.removal.button" = "卸载";
"phpman.failures.install.title" = "安装失败!";
"phpman.failures.install.desc" = "不幸的是,由于某些原因,操作返回了错误代码。您可能会发现 Formula 已被正确安装或升级。遗憾的是,我对此无能为力。请在此处查看来自 Homebrew 的最后几条信息,以了解发生了什么:
%@";
"phpman.action_prevented_busy.title" = "PHP Monitor 当前正忙。";
"phpman.action_prevented_busy.desc" = "PHP Monitor 当前正在执行类似在 PHP 版本间切换的操作。为确保您的系统不会崩溃,您需要等到 PHP Monitor 准备就绪后再尝试此操作。";
"phpman.uninstall_prevented.title" = "您无法通过 PHP Monitor 卸载当前活动的 PHP 版本。";
"phpman.uninstall_prevented.desc" = "为了防止 PHP Monitor 出现问题和进一步崩溃,无法通过此用户界面卸载当前链接的 PHP 版本。请注意,如果卸载当前链接的 PHP 版本PHP Monitor 可能会崩溃。";
"phpman.failures.uninstall.title" = "卸载失败!";
"phpman.failures.uninstall.desc" = "很不幸,自动卸载失败。您可以手动尝试运行此命令:`%@` 并找出问题所在。完成后记得重启 PHP Monitor(或按刷新按钮)";
"phpman.unlinked.title" = "您系统上安装的所有 PHP 版本当前都没有链接。";
"phpman.unlinked.desc" = "您当前可能还安装了某些版本的 PHP但目前没有链接到任何版本的 PHP";
"phpman.unlinked.detail" = "如果没有链接任何 PHP 版本,系统上就无法访问 `php` 二进制文件,如果不明确地将其作为 PATH 的一部分,就无法运行任何 PHP 脚本。您可以让 PHP Monitor 自动解决这个问题(在主菜单中选择自动修复),或者运行 `brew link php --force` 自行修复。";
"phpman.operations.repairing" = "修复安装...";
"phpman.operations.updating" = "安装更新...";
"phpman.operations.installing" = "安装 %@...";
"phpman.steps.fetching" = "获取...";
"phpman.steps.downloading" = "下载软件包数据...";
"phpman.steps.installing" = "安装某些软件包数据...";
"phpman.steps.pouring" = "浇注... 这可能需要一段时间...";
"phpman.steps.summary" = "某些软件包已完成安装...";
"phpman.services.loading" = "正在加载...";
"phpman.services.not_installed" = "关键服务未安装";
"phpman.services.error" = "关键服务报告错误状态";
"phpman.services.inactive" = "关键服务未运行";
"phpman.services.all_ok" = "所有 Valet 服务均正常";
// LITE MODE
"lite_mode_explanation.title" = "您当前正以独立模式运行 PHP Monitor";
"lite_mode_explanation.subtitle" = "PHP Monitor 有一些附加功能,如果你恰好是 Laravel Valet 的用户就可以使用这些功能。目前PHP Monitor 无法检测到您的系统中正在安装 Valet因此这些功能不可用。";
"lite_mode_explanation.description" = "如需了解更多信息,我建议查看 README(可在 GitHub 上获取),其中将解释安装 Valet 所需的步骤,以及如何使 PHP Monitor 在安装 Valet 后正常运行。安装 Laravel Valet 后,需要重启 PHP Monitor它才会脱离独立模式";
// GENERIC
"generic.ok" = "确定";
"generic.cancel" = "取消";
"generic.retry" = "重试";
"generic.notice" = "通知";
// PRESET LOADING
"preset_help_title" = "使用配置预设";
"preset_help_info" = "您可以在 config.json 文件中设置配置预设,该文件位于 ~/.config/phpmon/config.json。这些预设可以一次性应用选定的配置值。这是一项强大的功能但目前需要手动设置";
"preset_help_desc" = "重启 PHP Monitor 后,将加载文件中找到的所有预设。如果没有预设出现,则可能是文件无法正确解析。\n\n您可以点击此提示中的问号转到 GitHub 上的 FAQ在那里您可以找到有关此功能的更多信息包括一个示例文件。";
// MENU ITEMS (if window is open)
"mm_add_folder_as_link" = "将文件夹添加为链接...";
"mm_reload_domain_list" = "重新载入域名列表";
"mm_find_in_domain_list" = "在域名列表中搜索";
// SITE LIST
"domain_list.title" = "域名";
"domain_list.subtitle" = "";
"domain_list.domains_empty.title" = "无可用域名";
"domain_list.domains_empty.desc" = "此搜索查询未找到任何域名或您尚未链接任何域名";
"domain_list.domains_empty.button" = "添加域名...";
"domain_list.tooltips.isolated" = "此域名已被隔离,并使用 PHP %@ 代替全局链接的 PHP";
"domain_list.tooltips.checkmark" = "此域名使用的 PHP 版本与此要求(PHP %@)兼容。单击该复选标记旁边的 PHP 版本,了解有关如何确定该要求的更多信息。";
"domain_list.alerts_isolation_failed.title" = "糟糕!网站隔离未应用";
"domain_list.alerts_isolation_failed.subtitle" = "在尝试更改此站点的隔离状态时出了问题。如果这是您的默认站点但没有链接,我建议您在设置隔离之前手动链接该站点。";
"domain_list.alerts_isolation_failed.desc" = "要找出出错的原因,可以尝试在终端中手动运行命令:%@";
"domain_list.alerts_status_not_changed.title" = "哎呀SSL 状态未更改";
"domain_list.alerts_status_not_changed.desc" = "出错了。请尝试在终端中手动运行命令:%@";
"domain_list.alerts_status_changed.title" = "SSL 状态已更改";
"domain_list.alerts_status_changed.desc" = "域名 `%@` 现在是 %@";
"domain_list.alerts_status_secure" = "安全";
"domain_list.alerts_status_unsecure" = "不安全";
"domain_list.confirm_unlink" = "您确定要解除 `%@` 的链接吗?";
"domain_list.confirm_unlink_desc" = "不会删除任何文件。您可以随时点击 + 按钮并选择原始文件夹,重新链接该文件夹。";
"site_link.close" = "关闭";
"site_link.switch_too_php" = "切换到 PHP %@";
"site_link.isolate_php" = "隔离 PHP %@";
"domain_list.confirm_unproxy" = "您确定要移除代理 `%@` 吗?";
"domain_list.confirm_unproxy_desc" = "您可以随时点击 + 按钮重新创建代理";
"domain_list.columns.secure" = "TLS";
"domain_list.columns.domain" = "域名";
"domain_list.columns.active" = "Active";
"domain_list.columns.kind" = "种类";
"domain_list.columns.project_type" = "项目类型";
"domain_list.extensions" = "切换扩展";
"domain_list.applies_to" = "适用于 PHP %@";
// CHOOSE WHAT TO ADD
"selection.title" = "您想设置什么样的域名?";
"selection.description" = "链接用于直接为项目提供服务。如果你有一个包含代码的 Laravel、Symfony、WordPress 等文件夹,你需要创建一个链接,并选择代码所在的文件夹。\n\n如果需要代理可以将容器等代理到特定域名。 例如,这在与 Docker 结合使用时非常有用。";
"selection.create_link" = "创建链接";
"selection.create_proxy" = "创建代理";
"selection.cancel" = "取消";
// ADD PROXY TO DOMAINS LIST
"domain_list.add.set_up_proxy" = "设置代理";
"domain_list.add.proxy_subject" = "代理主机(必须包括协议和端口)";
"domain_list.add.domain_name" = "域名";
"domain_list.add.create_proxy" = "创建代理";
"domain_list.add.proxy_available" = "%@ 将被代理并可通过:%@://%@.%@";
"domain_list.add.proxy_https_warning" = "%@ 将被代理并可通过以下方式获得: %@://%@.%@.
(!)重要提示:在该域名的 nginx 配置文件中手动添加 `proxy_ssl_verify off;` 之前,该代理可能无法工作。建议使用不安全的域名作为代理主体。";
// ADD SITE TO DOMAINS LIST
"domain_list.add.link_folder" = "链接文件夹";
"domain_list.add.domain_name_placeholder" = "在此输入域名";
"domain_list.add.secure_after_creation" = "创建后 secure %@.%@";
"domain_list.add.secure_description" = "确保域名安全需要管理权限";
"domain_list.add.create_link" = "创建链接";
"domain_list.add.cancel" = "取消";
"domain_list.add.folder_available" = "本网站将通过以下 URL 提供: %@://%@.%@";
"domain_list.add.empty_fields" = "一个或多个字段为空。请填写所有必填字段";
"domain_list.add.errors.empty" = "您必须输入域名";
"domain_list.add.errors.empty_proxy" = "您必须输入要代理的内容";
"domain_list.add.errors.subject_invalid" = "您输入的主题无效";
"domain_list.add.errors.already_exists" = "该名称的链接已经存在";
// ADD SITE ERROR: FOLDER MISSING SINCE SELECTION
"domain_list.alert.folder_missing.desc" = "您选择的文件夹似乎已不存在。您要取消添加此文件夹吗?如果您移动了文件夹,可以将其放回去再试一次。";
"domain_list.alert.folder_missing.title" = "文件夹丢失!";
"domain_list.alert.folder_missing.cancel" = "取消链接";
"domain_list.alert.folder_missing.return" = "确定";
"domain_list.add.modal_description" = "首先,选择要链接的文件夹";
// SITE LIST ACTIONS
"domain_list.isolate" = "切换 PHP 版本";
"domain_list.site_isolation" = "站点隔离";
"domain_list.remove_isolation" = "删除隔离";
"domain_list.always_use_php" = "始终使用 PHP %@";
"domain_list.isolation_unavailable" = "不支持隔离(在 Valet 2 中)";
"domain_list.favorite" = "添加到收藏";
"domain_list.unfavorite" = "从收藏中移除";
"domain_list.actions" = "操作";
"domain_list.unlink" = "取消链接目录";
"domain_list.secure" = "安全域名";
"domain_list.unsecure" = "不安全域名";
"domain_list.open_in" = "用 %@ 打开";
"domain_list.open_in_finder" = "在 Finder 中打开";
"domain_list.open_in_browser" = "在浏览器中打开";
"domain_list.open_in_terminal" = "在终端中打开";
"domain_list.detected_apps" = "检测到的应用程序";
"domain_list.system_apps" = "系统应用程序";
"domain_list.unproxy" = "移除代理";
"domain_list.use_in_terminal" = "在终端中打开 PHP %@";
"domain_list.alerts_isolated_php_terminal.title" = "您可以在特定终端中使用 PHP %@";
"domain_list.alerts_isolated_php_terminal.subtitle" = "遗憾的是PHP Monitor 无法为您打开终端(并键入相应的命令)。要使用这个特定版本的 PHP您必须手动获取辅助脚本的源代码。为此您可以在选择的终端中键入以下内容
pm%@
这将源化由 PHP Monitor 生成的辅助脚本,并在该特定终端启用 PHP %@。
这对其他终端没有影响,只对正在使用它的特定终端会话有影响。(例如,如果您在终端应用程序中有多个选项卡,其他选项卡和窗口不受影响)";
"domain_list.alerts_isolated_php_terminal.desc" = "如果这不起作用,您可以通过 PHP Monitor 中的急救与服务菜单检查 PHP Doctor。有关此功能的更多信息也可以在 GitHub(PHP Monitor 软件仓库的维基站点)上找到。加入此警告是为了提高此功能的可见性。";
"domain_list.warning.spaces" = "警告!该网站的文件夹中有一个空格。\n无法通过浏览器访问该网站。";
"domain_list.alert.invalid_folder_name" = "文件夹名称无效";
"domain_list.alert.invalid_folder_name_desc" = "该文件夹无法解析为有效的 URL。这通常是因为文件夹名称中有一个空格。请重命名文件夹重新加载网站列表然后再试一次。";
"domain_list.columns.tls" = "TLS";
"domain_list.columns.domain" = "域名";
"domain_list.columns.php" = "PHP";
"domain_list.columns.type" = "类型";
"domain_list.columns.kind" = "种类";
// DRIVERS
"driver.not_detected" = "其他";
// PRESET
"preset.extension" = "%i 扩展";
"preset.extensions" = "%i 扩展";
"preset.preference" = "%i 偏好";
"preset.preferences" = "%i 偏好";
// EDITORS
"editors.alert.try_again" = "再试一次";
"editors.alert.cancel" = "取消";
// PREFERENCES
"prefs.title" = "PHP Monitor";
"prefs.subtitle" = "首选项";
"prefs.close" = "关闭";
"prefs.tabs.general" = "常规";
"prefs.tabs.appearance" = "外观";
"prefs.tabs.visibility" = "可见性";
"prefs.tabs.notifications" = "通知";
"prefs.global_shortcut" = "全局快捷方式:";
"prefs.dynamic_icon" = "动态图标:";
"prefs.dynamic_icon" = "图标类型:";
"prefs.info_density" = "信息密度:";
"prefs.services" = "服务:";
"prefs.switcher" = "切换器:";
"prefs.php_doctor" = "PHP Doctor:";
"prefs.integrations" = "集成:";
"prefs.updates" = "更新:";
"prefs.notifications" = "通知:";
"prefs.warnings" = "警告:";
"prefs.menu_contents" = "菜单功能:";
"prefs.startup" = "启动:";
"prefs.auto_start_desc" = "登录 Mac 时自动启动 PHP Monitor";
"prefs.auto_start_title" = "登录时启动 PHP Monitor";
"prefs.icon_options.php" = "显示 PHP 图标";
"prefs.icon_options.elephant" = "显示大象图标";
"prefs.icon_options.none" = "不显示图标";
"prefs.icon_options_desc" = "该选项决定在当前链接的 PHP 版本的版本号旁边显示哪个图标。如果动态图标选项已被禁用,该选项将不起作用";
"prefs.auto_restart_services_title" = "自动重启 PHP-FPM";
"prefs.auto_restart_services_desc" = "选中后,在选中或取消选中扩展时将自动重启 PHP-FPM。启用后速度稍慢但会立即将扩展变更应用于您服务的所有网站无需手动重启 PHP-FPM";
"prefs.dynamic_icon_title" = "在菜单栏中显示动态图标";
"prefs.dynamic_icon_desc" = "如果不选中此复选框,卡车图标将始终可见。如果选中,它将显示当前链接的 PHP 版本的主要版本号";
"prefs.display_full_php_version" = "在任何地方都显示完整的 PHP 版本";
"prefs.display_full_php_version_desc" = "显示完整版本,而不是菜单栏和下拉菜单中显示的主要版本。(这在较小的显示屏上可能不可取,因此默认禁用)";
"prefs.auto_composer_update_title" = "自动更新全局依赖";
"prefs.auto_composer_update_desc" = "选中后,当您在不同 PHP 版本之间切换时,将自动要求 Composer 运行 `composer global update`。您将能看到正在进行的更改,或者如果此操作失败。";
"prefs.open_protocol_title" = "允许第三方集成";
"prefs.open_protocol_desc" = "选中后,将允许与第三方工具(如 Alfred、Raycast)进行交互。如果禁用此选项PHP Monitor 仍将接收命令,但不会对其采取行动";
"prefs.automatic_update_check_title" = "自动检查更新";
"prefs.automatic_update_check_desc" = "选中后PHP Monitor 将自动检查是否有更新版本,并在有更新版本时通知您";
"prefs.php_doctor_suggestions_title" = "始终显示建议";
"prefs.php_doctor_suggestions_desc" = "如果取消选中此项PHP Monitor 的菜单中将不会显示 PHP Doctor 的建议。请记住如果没有建议PHP Doctor 就不会出现。";
"prefs.shortcut_set" = "设置全局快捷方式";
"prefs.shortcut_listening" = "<按键监听>";
"prefs.shortcut_clear" = "清除";
"prefs.shortcut_desc" = "如果设置了快捷键组合,则无论您身在何处,都可以通过按下所选组合键来切换 PHP Monitor。(按空格键取消快捷键选择)";
"prefs.notify_about_version_change_desc" = "当活动 PHP 版本发生变化时显示通知";
"prefs.notify_about_version_change" = "通知 PHP 版本切换";
"prefs.notify_about_php_fpm_change_desc" = "每当活动的 PHP-FPM 进程因配置更改而重新启动时显示通知";
"prefs.notify_about_php_fpm_change" = "通知 PHP-FPM 重启";
"prefs.notify_about_services_desc" = "在任何 Homebrew 服务(由 Valet 安装和配置)重新启动或停止时显示通知";
"prefs.notify_about_services" = "通知服务状态";
"prefs.notify_about_presets_desc" = "每当成功应用或恢复预设时显示通知";
"prefs.notify_about_presets" = "通知已应用的预设";
"prefs.notify_about_secure_status_desc" = "域名已安全或未安全时显示通知";
"prefs.notify_about_secure_status" = "通知安全/不安全状态";
"prefs.notify_about_composer_success_desc" = "当全局 Composer 配置更新成功时显示通知";
"prefs.notify_about_composer_success" = "通知全局 Composer 更新";
"prefs.warn_about_non_standard_tld_desc" = "如果您使用非标准顶级域名,您可能不希望重复收到相关通知";
"prefs.warn_about_non_standard_tld" = "警告非标准 TLD";
"prefs.display_global_version_switcher_desc" = "如果禁用,将无法通过主菜单更改全局链接的 PHP 版本";
"prefs.display_global_version_switcher" = "PHP 切换器";
"prefs.display_services_manager_desc" = "如果禁用,将无法查看、启动或停止单个服务。(如果有任何服务被禁用,您将无法轻易察觉)";
"prefs.display_services_manager" = "服务管理器";
"prefs.display_valet_integration_desc" = "如果禁用,您将无法找到 Valet 主文件夹或打开域名列表";
"prefs.display_valet_integration" = "Valet 集成";
"prefs.display_php_config_finder_desc" = "如果禁用,您将无法轻松找到 PHP 配置文件和/或生成 phpinfo()转储";
"prefs.display_php_config_finder" = "PHP 配置查找器";
"prefs.display_composer_toolkit_desc" = "如果禁用,将无法通过主菜单调用 Composer。切换首选项后自动更新 Composer 不受此更改影响。";
"prefs.display_composer_toolkit" = "Composer Toolkit";
"prefs.display_limits_widget_desc" = "如果禁用,将无法在主菜单中看到限制小工具(内存、POST、上传)";
"prefs.display_limits_widget" = "限制小工具";
"prefs.display_extensions_desc" = "如果禁用,将无法通过主菜单轻松切换扩展名";
"prefs.display_extensions" = "扩展";
"prefs.display_presets_desc" = "如果禁用,将无法应用或恢复 PHP 配置预设";
"prefs.display_presets" = "预设";
"prefs.display_misc_desc" = "如果禁用,将无法访问急救与服务菜单";
"prefs.display_misc" = "急救与服务菜单";
// NOTIFICATIONS
"notification.version_changed_title" = "PHP %@ 已激活";
"notification.version_changed_desc" = "PHP Monitor 已切换到 PHP %@";
"notification.php_fpm_restarted" = "PHP-FPM 自动重新启动";
"notification.php_fpm_restarted_desc" = "您切换了扩展,因此 PHP-FPM 自动重启";
"notification.services_stopped" = "Valet 服务已停止";
"notification.services_stopped_desc" = "所有服务已成功停止";
"notification.services_restarted" = "Valet 服务已重新启动";
"notification.services_restarted_desc" = "所有服务已成功重启";
"notification.preset_applied_title" = "已应用预设";
"notification.preset_applied_desc" = "预设 `%@` 已成功应用";
"notification.preset_reverted_title" = "预设已恢复";
"notification.preset_reverted_desc" = "您上次应用的预设已被撤销。您之前的配置现已激活";
"notification.phpmon_updated.title" = "PHP Monitor 已更新!";
"notification.phpmon_updated.desc" = "您现在运行的是 PHP Monitor v%@。感谢您保持更新!";
"notification.phpmon_updated_dev.desc" = "PHP Monitor v%@ (build %@)已安装并激活";
// Composer Update
"alert.composer_missing.title" = "未找到 Composer";
"alert.composer_missing.subtitle" = "PHP Monitor 无法找到 Composer。请确保已安装 Composer 并重试。";
"alert.composer_missing.desc" = "PHP Monitor 假定 Composer 位于以下任一位置:
- `/usr/local/bin/composer`.
- `/opt/homebrew/bin/composer` 中。
请确保您已将 Composer 安装在其中一个位置,如果您已将 Composer 安装在其他位置,请创建一个符号链接。";
"alert.composer_progress.title" = "正在更新全局依赖...";
"alert.composer_progress.info" = "您可以在下面的终端输出中看到进度";
"alert.composer_failure.title" = "出错了!";
"alert.composer_failure.info" = "您的全局 Composer 依赖项无法更新。
您可以在下面的终端输出中找到更多信息。
你必须使用您自己的终端应用程序手动解决这个问题(这只是向您显示输出结果)。";
"alert.composer_success.title" = "Composer 已完成更新!";
"alert.composer_success.info" = "您的全局 Composer 依赖项已成功更新";
// Composer Version
"alert.composer_php_isolated.desc" = "该站点已被隔离,这意味着 Valet 将专门为该站点提供 PHP %@。全局版本目前为 PHP %@。";
"alert.composer_php_requirement.title" = "`%@` 需要 PHP %@";
"alert.composer_php_requirement.unable_to_determine" = "无法确定 PHP 需求";
"alert.composer_php_requirement.type.unknown" = "PHP Monitor 无法确定此域名需要哪个版本的 PHP。如果项目目录中有 `composer.json` 或 `.valetphprc` 文件,则可以确定限制条件。";
"alert.composer_php_requirement.type.require" = "在网站列表最后一次刷新时,通过检查 `composer.json` 文件中的 `require` 字段确定了所需的 PHP 版本";
"alert.composer_php_requirement.type.platform" = "上次刷新站点列表时,通过检查 `composer.json` 文件中的 `platform` 字段确定了所需的 PHP 版本";
"alert.composer_php_requirement.type.valetphprc" = "通过检查项目目录中的 `.valetphprc` 文件确定了所需的 PHP 版本。";
"alert.composer_php_requirement.type.valetrc" = "通过检查项目目录中的 `.valetrc` 文件确定了所需的 PHP 版本";
"alert.unable_to_determine_is_fine" = "如果您的项目很简单,可能没有指定的 PHP 版本作为要求。在这种情况下,您可以忽略此警告。";
"alert.php_version_ideal" = "当前活动的 PHP 版本是该网站的理想版本";
"alert.php_version_incorrect" = "当前活动的 PHP 版本与此站点所需的约束设置不匹配";
"alert.php_suggestions" = "可能有其他更接近约束条件的 PHP 版本";
// Suggest Fix My Valet
"alert.php_switch_failed.title" = "切换到 PHP %@ 似乎失败了";
"alert.php_switch_failed.info" = "PHP Monitor 检测到 PHP %@ 在完成切换程序后没有激活。您可以尝试运行 `Fix My Valet` 并在运行后重新切换。您想试试这个修复方法吗?";
"alert.php_switch_failed.desc" = "首先,如果您还没有尝试过 `Fix My Valet`,您应该试试。如果在此之后 PHP Monitor 仍然无法更改活动的 PHP 版本,则可能需要升级 Valet 和系统中的 Homebrew 软件包。您可以通过运行 `brew update && brew upgrade` 和运行 `composer global update && valet install` 来升级 Valet";
"alert.php_switch_failed.confirm" = "是的,运行 `Fix My Valet`";
"alert.php_switch_failed.cancel" = "不运行";
// PHP Formula Missing
"alert.php_formula_missing.title" = "哎呀Fix My Valet 必须安装 `php` Formula...";
"alert.php_formula_missing.info" = "看来您没有安装 `php` Formula导致 PHP Monitor 无法运行 Fix My Valet。请使用 `brew install php` 安装,重启 PHP Monitor 并重试。";
// Fix My Valet Started
"alert.fix_my_valet.title" = "有问题Fix My Valet 已准备就绪!";
"alert.fix_my_valet.info" = "这可能需要一段时间。请耐心等待。\n\n完成后所有其他服务都将停止PHP %@ 将被链接。一旦这项操作完成,您就可以切换到所需的 PHP 版本了。\n\n(一旦 Fix My Valet 服务完成,您将收到另一条提醒。)";
"alert.fix_my_valet.ok" = "继续";
"alert.fix_my_valet.cancel" = "中止";
// Fix My Valet Done
"alert.fix_my_valet_done.title" = "Fix My Valet 已完成操作";
"alert.fix_my_valet_done.subtitle" = "已停止所有相应的服务并重新启动了正确的服务,最新版本的 PHP 现在应该处于活动状态。您现在可以尝试切换到另一个版本的 PHP。";
"alert.fix_my_valet_done.stay" = "停留在 PHP %@";
"alert.fix_my_valet_done.switch_back" = "切换回 PHP %@";
"alert.fix_my_valet_done.desc" = "如果访问网站仍然无法正常工作,您可以尝试再次运行 `valet install`,这可以修复 502 问题(网关错误)。如果 Valet 已损坏且无法运行 `valet install`,您可能需要运行 `composer global update`。如果您遇到其他问题,请查阅 GitHub 上的 FAQ";
// Restore Homebrew Permissions
"alert.fix_homebrew_permissions.title" = "关于 `恢复Homebrew权限`";
"alert.fix_homebrew_permissions.subtitle" = "创建此功能是为了让您可以在没有权限问题的情况下运行 `brew upgrade` 或 `brew cleanup`。\n\n(应用此修复后,您将收到通知。)";
"alert.fix_homebrew_permissions.desc" = "这将需要管理权限,因为由于 Valet 服务以根用户身份运行PHP Monitor 将恢复您对当前由 `root` 用户拥有的文件和文件夹的所有权";
"alert.fix_homebrew_permissions.ok" = "恢复权限";
"alert.fix_homebrew_permissions.cancel" = "取消";
"alert.fix_homebrew_permissions_done.title" = "已恢复 Valet 依赖项的所有文件和文件夹权限";
"alert.fix_homebrew_permissions_done.subtitle" = "因此Valet 的所有服务目前都不再运行。您现在可以与 Homebrew 互动,但您的 Valet 站点将无法使用,因为所有服务都已禁用。";
"alert.fix_homebrew_permissions_done.desc" = "当您完成 Homebrew 的操作后(例如在运行 `brew upgrade` 之后),如果您希望 Valet 重新运行,您应该重启 PHP Monitor 并选择 `Restart Valet Services`。建议每次使用 `brew upgrade` 升级 PHP 版本时都重启 PHP Monitor否则可能会出错";
// PHP FPM Broken
"alert.php_fpm_broken.title" = "您的 PHP-FPM 配置没有指向 Valet 套接字!";
"alert.php_fpm_broken.info" = "PHP Monitor 已确定您的 PHP-FPM 配置存在问题。如果您访问通过 Valet 链接的网站,这将导致 `502 Bad Gateway` 响应";
"alert.php_fpm_broken.description" = "如果已经有一段时间了,你通常可以通过运行 `valet install` 来解决这个问题,它可以更新你的 PHP-FPM 配置.\n\n如果你看到这个消息而你正在尝试运行一个预发布版本的 PHP有可能是 Valet 还不支持这个预发布版本的 PHP.\n\n你可能需要将你安装的 Laravel Valet 升级到至少 v3.1.11,之后你应该运行 `valet install`。更多信息请点击https://phpmon.app/prerelease-php";
// PHP Monitor Cannot Start
"alert.cannot_start.title" = "由于您的系统配置问题PHP Monitor 无法启动";
"alert.cannot_start.subtitle" = "刚才通知您的问题导致 PHP Monitor 无法正常运行";
"alert.cannot_start.description" = "您可能不需要退出 PHP Monitor 并重新启动它。如果您已解决问题(或不记得具体问题是什么)可以点击重试PHP Monitor 将重试启动检查";
"alert.cannot_start.close" = "退出";
"alert.cannot_start.retry" = "重试";
// PHP alias issue
"alert.php_alias_conflict.title" = "检测到 Homebrew 的 `php` Formula 别名冲突";
"alert.php_alias_conflict.info" = "PHP Monitor 在您的 Homebrew 设置中检测到了相互冲突的 `php` 别名,这两个别名都已被检测到安装";
"alert.min_valet_version.title" = "安装的 Valet 版本不符合最低版本要求。PHP Monitor 可能无法按预期运行!";
"alert.min_valet_version.info" = "您当前正在运行 Valet %@。
为优化对最新版本 PHP 的支持和正确的版本切换,建议您更新到 %@版本,这是该版本 PHP Monitor 的最低要求。
在终端运行 `composer global update` 即可。然后,再次运行 `valet install`。为获得最佳效果,请重新启动 PHP Monitor。在此问题解决之前PHP Monitor 可能无法正常运行。";
// Preset text description
"alert.preset_description.switcher_version" = "切换到 PHP %@.\n\n";
"alert.preset_description.applying_extensions" = "应用以下扩展:\n";
"alert.preset_description.applying_config" = "应用以下配置值:\n";
"alert.preset_description.enabled" = "启用";
"alert.preset_description.disabled" = "禁用";
"alert.preset_description.empty" = "(空)";
// PHP version unavailable
"alert.php_switch_unavailable.title" = "不支持的 PHP 版本";
"alert.php_switch_unavailable.subtitle" = "PHP Monitor 无法切换到 PHP %@,因为它可能未安装或不可用。已取消应用此预设。";
"alert.php_switch_unavailable.info" = "请确保已安装 PHP %@,并可在下拉菜单中切换到它。目前支持的版本包括 PHP %@.";
"alert.php_switch_unavailable.ok" = "确定";
// Service error
"alert.service_error.title" = "服务 `%@` 报告错误!";
"alert.service_error.subtitle.error_log" = "这意味着服务 `%@` 没有运行。这可能导致 Valet 无法正常工作。不过,该服务有一个相关的日志文件,您可能需要检查一下。";
"alert.service_error.subtitle.no_error_log" = "这意味着服务 `%@` 没有运行。这可能会妨碍 Valet 正常工作。不幸的是,该服务没有相关日志文件。";
"alert.service_error.extra" = "您可能还希望遵循常见的故障排除步骤。要了解更多信息,请点击 PHP Monitor 中服务部分的 `?` 按钮";
"alert.service_error.button.show_log" = "查看错误日志";
"alert.service_error.button.close" = "关闭";
// Composer issues
"alert.global_composer_platform_issues.title" = "Composer 检测到您的平台存在问题";
"alert.global_composer_platform_issues.subtitle" = "您切换到的 PHP 版本对于您安装的全局 Composer 依赖项来说太旧。这些依赖项需要更新。";
"alert.global_composer_platform_issues.desc" = "防止将来发生此问题的最简单方法是切换到已安装的最旧 PHP 版本,并再次运行 `composer global update`。\另外,你也可以在偏好设置中选择 `自动更新全局依赖` 选项来避免这个问题。如果你在尝试更新全局依赖之后仍然看到这个消息,你可能需要查看一下你的全局 composer 配置文件,它位于 `~/.composer/composer.json`";
"alert.global_composer_platform_issues.buttons.update" = "更新全局依赖";
"alert.global_composer_platform_issues.buttons.quit" = "退出 PHP Monitor";
// Revert
"alert.revert_description.title" = "还原配置?";
"alert.revert_description.subtitle" = "PHP Monitor 可以还原到之前激活的配置。以下是将应用的配置: \n\n%@";
"alert.revert_description.ok" = "恢复";
"alert.revert_description.cancel" = "取消";
// STARTUP
// 0. Architecture mismatch
"alert.homebrew_missing.title" = "PHP Monitor 无法启动!";
"alert.homebrew_missing.subtitle" = "无法在常规位置找到可用的 Homebrew 二进制文件。请在修复此问题后重新启动应用程序。";
"alert.homebrew_missing.info" = "您正在使用以下架构运行 PHP Monitor%@。因此,我们希望在 `%@` 中找到一个可运行的 Homebrew 二进制文件,但却没有找到。如果您还没有安装 Homebrew请安装。如果您使用的是 Apple Silicon请确保您的 Homebrew 和 PHP Monitor 使用相同的架构,必要时启用或禁用 Rosetta";
"alert.homebrew_missing.quit" = "退出";
// PHP binary not found
"startup.errors.php_binary.title" = "PHP 未正确安装";
"startup.errors.php_binary.subtitle" = "您必须通过 Homebrew 安装 PHP。在解决此问题之前应用程序将无法正常运行";
"startup.errors.php_binary.desc" = "通常在终端运行 `brew link php` 可以解决这个问题";
// PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "PHP 未正确安装";
"startup.errors.php_opt.subtitle" = "在 `%@` 中找不到 PHP 别名。在您解决此问题之前,应用程序将无法正常运行";
"startup.errors.php_opt.desc" = "如果您已经安装了 `php` Formula则可能需要运行 `brew install php` 才能使 PHP Monitor 检测到该安装";
// PHP binary is broken
"startup.errors.dyld_library.title" = "PHP 已安装,但似乎已损坏";
"startup.errors.dyld_library.subtitle" = "PHP Monitor 尝试运行命令时,未能正确执行。这通常表明 PHP 安装已损坏";
"startup.errors.dyld_library.desc" = "在终端运行 `brew reinstall php && brew link php` 可能会解决此问题,因此请尝试一下";
// Valet is not installed
"startup.errors.valet_executable.title" = "Laravel Valet 未正确安装";
"startup.errors.valet_executable.subtitle" = "您必须使用 Composer 安装 Valet。在解决此问题之前应用程序将无法正常运行。";
"startup.errors.valet_executable.desc" = "如果您尚未安装 Laravel Valet请先安装。如果你已经安装但还是看到了这条信息那么请尝试在终端运行 `which valet`,它应该会返回:`%@`.";
// Valet configuration file missing or broken
"startup.errors.valet_json_invalid.title" = "Laravel Valet 配置文件无效或丢失";
"startup.errors.valet_json_invalid.subtitle" = "PHP Monitor 需要能够读取配置文件。文件似乎畸形或丢失。请检查该文件是否存在,格式是否正确。";
"startup.errors.valet_json_invalid.desc" = "您可以在 `~/.config/valet/config.json` 找到该文件。如果 Laravel Valet 无法解析配置文件,运行 `valet` 命令通常会自动修复 JSON 文件。尝试运行 `valet --version` 来自动修复文件";
// Valet version not readable
"startup.errors.valet_version_unknown.title" = "无法读取您的 Valet 版本";
"startup.errors.valet_version_unknown.subtitle" = "解析 `valet --version` 输出失败。请确保您的 Valet 安装正常运行且为最新版本。";
"startup.errors.valet_version_unknown.desc" = "尝试在终端中运行 `valet --version` 以找出问题所在";
"startup.errors.valet_not_installed.title" = "您的 Valet 配置目录丢失";
"startup.errors.valet_not_installed.subtitle" = "缺少所需目录 `~/.config/valet`。这通常意味着您忘记了运行 `valet install`.";
"startup.errors.valet_not_installed.desc" = "假设你已经通过 Composer 安装了 Valet请运行 `valet install` 来完成 Laravel Valet 的设置。
如果你看到此消息,但不明白为什么这个文件夹不见了,那么你可能想调查一下它消失的原因--它不应该就这样消失,这意味着你的 Valet 安装被破坏了。";
// Valet version too new or old
"startup.errors.valet_version_not_supported.title" = "不支持此 Valet 版本";
"startup.errors.valet_version_not_supported.subtitle" = "您运行的 Valet 版本目前不受支持。PHP Monitor 目前适用于 Valet v2、v3 和 v4。为了避免给您的系统带来问题PHP Monitor 无法启动";
"startup.errors.valet_version_not_supported.desc" = "您必须安装与 PHP Monitor 兼容的 Valet 版本,或者您可能需要升级到较新版本的 PHP Monitor该版本可能包含对该 Valet 版本的兼容性(更多信息请查阅最新发布说明)";
// Brew & sudoers
"startup.errors.sudoers_brew.title" = "Brew 没有被添加到 sudoers.d";
"startup.errors.sudoers_brew.subtitle" = "您必须运行 `sudo valet trust` 以确保 Valet 可以启动和停止服务,而无需每次都使用 sudo。在您解决此问题之前应用程序将无法正常工作。";
"startup.errors.sudoers_brew.desc" = "如果您一直看到此错误则可能存在权限问题PHP Monitor 无法验证该文件,通常可通过运行:`sudo chmod +r /private/etc/sudoers.d/brew` 解决该问题";
// Valet & sudoers
"startup.errors.sudoers_valet.title" = "Valet 尚未添加到 sudoers.d";
"startup.errors.sudoers_valet.subtitle" = "您必须运行 `sudo valet trust` 以确保 Valet 可以启动和停止服务,而无需每次都使用 sudo。在您解决此问题之前应用程序将无法正常运行。如果您之前执行过此操作请再次运行 `sudo valet trust`。";
"startup.errors.sudoers_valet.desc" = "如果一直看到此错误则可能存在权限问题PHP Monitor 无法验证文件,通常可通过运行:`sudo chmod +r /private/etc/sudoers.d/valet` 解决";
// Platform issue detected
"startup.errors.global_composer_platform_issues.title" = "PHP Monitor 和 Valet 无法正常工作Composer 报告您的平台存在问题";
"startup.errors.global_composer_platform_issues.subtitle" = "请按照以下建议步骤操作,以避免将来出现此问题:\n\n1. 运行 `composer global update`.\n2. 重新启动 PHP Monitor。(它应该可以重新工作。)\n3. 切换到已安装的最早的 PHP 版本。再次运行 `composer global update`";
"startup.errors.global_composer_platform_issues.desc" = "您可以进入首选项并选中 `自动更新全局依赖` 选项。这将在您更改 PHP 版本时更新您的全局 Composer 依赖项,因此,如果您不能持续访问互联网,这可能不是最理想的选择。要找出确切的问题所在,请尝试运行 `valet --version`。Valet 目前无法使用已安装的依赖项。通常这是由于版本不匹配造成的:即安装的 PHP 依赖版本比当前激活的版本要新";
// Cannot retrieve services
"startup.errors.services_json_error.title" = "无法确定服务状态";
"startup.errors.services_json_error.subtitle" = "PHP Monitor 通常使用以下命令查询 `brew` 以测试是否可以检索服务:`sudo brew services info nginx --json`.\n\nPHP Monitor 无法解释此响应。";
"startup.errors.services_json_error.desc" = "如果您的 Homebrew 安装过时可能会出现这种情况在这种情况下Homebrew 还不会返回 JSON。通常可以通过运行 `brew update` 或 `brew tap homebrew/services` 来解决这个问题。你也可以尝试在终端运行 `sudo brew services info nginx --json`";
// Issue with `which` alias
"startup.errors.which_alias_issue.title" = "检测到配置问题";
"startup.errors.which_alias_issue.subtitle" = "`/usr/local/bin/which` 中似乎有一个文件。这通常是由 NodeJS 设置的,但 `/usr/local/bin` 的 PATH 中没有 `node`。要解决这个问题,请继续阅读";
"startup.errors.which_alias_issue.desc" = "您需要将 `node` 链接到 `/usr/local/bin` 目录,以确保 PHP Monitor 能够成功启动。更多信息请参见https://github.com/nicoverbruggen/phpmon/issues/174";
// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Laravel Herd 似乎正在运行";
"startup.errors.herd_running.subtitle" = "Laravel Herd 似乎正在运行。Herd 的内置 Valet 设置可能与您的常规 Valet 安装冲突,因此请在继续之前退出 Herd。(你完全可以混合使用 Herd 和常规 Valet但不应同时运行两者)";
"startup.errors.herd_running.desc" = "你可能还会发现Herd 添加到 $PATH 的 `php` 别名可能会阻止 PHP Monitor 的 `php` 别名生效,所以请记住这一点。您可以查看 `~/.zshrc` 并了解 Herd 在您的 $PATH 中添加了什么。";
// Warning about a different PHP version linked than last time
"startup.version_mismatch.title" = "您的活动 PHP 版本已更改";
"startup.version_mismatch.subtitle" = "自 PHP Monitor 上次激活以来,您链接的 PHP 版本已更改为 PHP %@。您想切换回 PHP %@,还是继续使用当前版本?";
"startup.version_mismatch.desc" = "PHP Monitor 会跟踪全局链接的 PHP 版本。全局版本可能由于其他程序或 Homebrew 升级后链接了不同的 Formula 而发生变化";
"startup.version_mismatch.button_switch_back" = "切换回 PHP %@";
"startup.version_mismatch.button_stay" = "继续使用 PHP %@";
// Warning about unsupported PHP versions
"startup.unsupported_versions_explanation.title" = "检测到 Valet 不支持的 PHP 安装!";
"startup.unsupported_versions_explanation.subtitle" = "您的系统中安装了以下 PHP 版本,但该版本的 Valet 不支持这些版本。
%@
如果链接这些 PHP 版本Valet 可能会崩溃,因此 PHP Monitor 不会让您切换到这些版本。";
"startup.unsupported_versions_explanation.desc" = " 如果您需要旧版本的 PHP 支持,您可能需要降级到旧版本的 Valet。否则最好卸载任何不使用的过时版本。也可能是 Valet 的版本太旧。只有在重启 PHP Monitor 后,此消息才会被删除。";
// Sponsor encouragement
"startup.sponsor_encouragement.title" = "如果 PHP Monitor 对您或贵公司有用,请考虑留下小费";
"startup.sponsor_encouragement.subtitle" = "100%透明:我计划保持 PHP Monitor 的开源和免费。您的支持使这一决定变得非常容易。";
"startup.sponsor_encouragement.desc" = "如果您已经捐赠,那么您就是应用程序能够获得所有这些更新的原因。在这种情况下,这是给您的感谢信息。感谢您的支持。";
"startup.sponsor_encouragement.accept" = "立即赞助";
"startup.sponsor_encouragement.learn_more" = "了解更多信息";
"startup.sponsor_encouragement.skip" = "不,谢谢";
// ERROR MESSAGES
"alert.errors.homebrew_permissions.applescript_returned_nil.title" = "恢复 Homebrew 权限已被取消。";
"alert.errors.homebrew_permissions.applescript_returned_nil.description" = "为调整权限而执行的脚本的结果返回为零,这通常意味着您没有授予 PHP Monitor 管理权限。如果您确实进行了身份验证,但仍看到此消息,则可能出了问题。";
"alert.key_service_not_running.title" = "由于所需的 Homebrew 服务存在问题Valet 目前无法正常工作";
"alert.key_service_not_running.subtitle" = "Valet 要正常工作,至少需要三个关键服务正常运行。
PHP Monitor 报告说情况并非如此。您可以尝试按下受影响服务下方菜单中带有 `X` 的按钮来(重新)启动当前处于非活动状态的服务,从而解决这个问题。";
"alert.key_service_not_running.desc" = "如果点击服务下方的按钮不起作用(即旋转器出现,但一段时间后仍为 `X`),您可能需要运行 `Fix My Valet`。您可以通过菜单 `急救与服务` > `修复我的 Valet...` 进行操作。
另外,也可以在终端中使用 `valet stop` 和 `valet start`,这也可以解决问题(作为修复我的 Valet 的替代方法)。
如需进一步调试,您可以查看 GitHub 问题跟踪器,其他用户可能也遇到过类似问题。作为开发人员,我将尽力确保每个问题都能得到解答:)";
"alert.key_service_has_error.title" = "由于所需的 Homebrew 服务存在问题Valet 目前无法正常工作";
"alert.key_service_has_error.subtitle" = "Valet 要正常工作,至少需要三个关键服务正常运行。
PHP Monitor 报告说情况并非如此。其中一个受影响的服务似乎正在报告错误状态,因此我建议点击 `E`。
PHP Monitor 将尝试重新启动服务,如果失败(很有可能),它将提供日志文件(如果存在),其中可能包含有助于调试问题的其他信息。";
"alert.key_service_has_error.desc" = "不幸的是,如果服务报错,通常是由于配置状态无效,这可能难以调试。
常见故障排除提示
· 首先尝试重启服务并检查日志文件(如果存在)。您可以点击 `E` 按钮让 PHP Monitor 来做这件事。
· PHP如果看到的是错误状态可能是 PHP 的配置出现了问题。确保 Homebrew 安装中的.ini 文件没有问题,并且不存在套接字冲突。
· nginx如果出现错误状态则可能是网站配置错误(通常会在错误日志中指出)。你可能需要检查 Valet 的 nginx 文件夹。
· dnsmasq如果出现错误状态可能是 dnsmasq 配置文件损坏(通常位于 ~/.config/valet/dnsmasq.d)";
// CHECK FOR UPDATES
"updater.alerts.newer_version_available.title" = "PHP Monitor v%@ 现已可用!";
"updater.alerts.newer_version_available.subtitle" = "强烈建议将 PHP Monitor 保持更新,因为新版本通常会修复漏洞并包含支持最新版本 Valet 和 PHP 的修正";
"updater.installation_source.brew" = "安装 PHP Monitor 更新的推荐方法是直接按 `Install Update`(安装更新)。由于你使用 Homebrew 安装应用程序,你也可以通过终端运行 `%@` 进行升级,但不推荐这样做";
"updater.installation_source.direct" = "向 PHP Monitor 安装更新的推荐方法是直接按 `安装更新`";
"updater.alerts.buttons.release_notes" = "查看版本说明";
"updater.alerts.is_latest_version.title" = "PHP Monitor 是最新版本!";
"updater.alerts.is_latest_version.subtitle" = "当前安装的版本(v%@)是最新的";
"updater.alerts.cannot_check_for_update.title" = "PHP Monitor 无法确定是否有更新的版本";
"updater.alerts.cannot_check_for_update.subtitle" = "您可能没有连接到互联网、正在阻塞流量或 GitHub 出现故障,不允许您检查更新。如果您一直看到此消息,可能需要手动检查发布页面。";
"updater.alerts.cannot_check_for_update.description" = "当前安装的版本是:%@。您可以点击左侧的按钮进入最新版本列表(在 GitHub 上)";
"updater.alerts.buttons.releases_on_github" = "查看版本";
"updater.alerts.buttons.install" = "安装更新";
"updater.alerts.buttons.dismiss" = "解除";
// WARNINGS ABOUT NON-DEFAULT TLD
"alert.warnings.tld_issue.title" = "您没有使用 `.test` 作为 Valet 的顶级域名";
"alert.warnings.tld_issue.subtitle" = "使用非默认顶级域名可能无法正常工作,并且不受官方支持";
"alert.warnings.tld_issue.description" = "PHP Monitor 仍将正常运行,但可能会出现一些问题:应用程序可能无法正确显示哪些域名已被安全保护。为获得最佳效果,请转到 Valet 配置文件(Valet 目录中的 config.json)并将 TLD 改回 `test`。";
"alert.do_not_tell_again" = "不要再告诉我";
// WARNINGS
"warnings.limits_error.title" = "PHP Monitor 无法检索限制";
"warnings.limits_error.steps" = "尝试在终端运行 `php -v`";
"warnings.title" = "PHP Doctor";
"warnings.description" = "**PHP Doctor** 将对您的活动系统配置提出改进建议";
"warnings.disclaimer" = "您可以选择隐藏偏好设置中 PHP Monitor 菜单中的所有建议,但建议您处理所有可操作的项目";
"warnings.refresh.button" = "再次扫描";
"warnings.refresh.button.description" = "修复问题后按下此按钮。这将导致 PHP Monitor 重新评估您的环境。如果问题确实已修复,建议应该会消失。";
"warnings.helper_permissions.title" = "PHP Monitor 的助手当前不可用";
"warnings.helper_permissions.description" = "PHP Monitor 自带各种辅助脚本。使用这些脚本可以轻松调用特定版本的 PHP而无需切换链接的 PHP 版本";
"warnings.helper_permissions.unavailable" = "然而,这些辅助脚本可能*不可用*,因为 PHP Monitor 目前无法创建或更新所需的符号链接";
"warnings.helper_permissions.symlink" = "如果不想让 `/usr/local/bin` 可写,可以将 PHP Monitor 的辅助目录添加到 `PATH` 变量中,这样警告就会消失。(点击**了解更多**了解如何解决这个问题)";
"warnings.arm_compatibility.title" = "您在 Apple Silicon 上使用 Rosetta 运行 PHP Monitor这意味着您的 PHP 环境也是通过 Rosetta 运行的";
"warnings.arm_compatibility.description" = "您似乎正在运行与 ARM 兼容的 macOS 版本,但您目前正在使用 Rosetta 运行 PHP Monitor。虽然这可以正常工作但建议您使用本机版本的 Homebrew";
"warnings.files_missing.title" = "您的 PHP 安装缺少所需的重要配置文件";
"warnings.files_missing.description" = "安装 PHP 后应存在以下关键配置文件:
- %@
当缺少类似文件时,应切换到与这些文件相关的 PHP 版本:这可能会解决问题。如果还不能解决问题,建议再次通过 Homebrew 重新安装相应的 PHP 版本,这样就可以恢复丢失的配置文件。配置文件缺失可能是出现 `502 Bad Gateway` 错误的原因,即使运行了 Fix My Valet(如果使用 Valet)也是如此。";
"warnings.none" = "现在没有可用的建议。您可以放心使用!";
// ONBOARDING
"onboarding.title" = "Welcome Tour";
"onboarding.welcome" = "欢迎来到 PHP Monitor!";
"onboarding.explore" = "您现在可以访问 PHP Monitor 的全部功能。您可以在此页面了解更多有关 PHP Monitor 所提供功能的信息";
"onboarding.explore.lite" = "您现在可以访问 PHP Monitor 最重要的功能。
请注意,由于 Laravel Valet 未激活,某些功能(下面灰色部分)目前不可用。";
"onboarding.tour.menu_bar.title" = "菜单栏中的强大功能";
"onboarding.tour.menu_bar" = "PHP Monitor 位于您的菜单栏中。通过该菜单,您可以访问 PHP Monitor 的大部分关键功能,包括切换全局链接的 PHP 版本、查找配置文件、安装不同的 PHP 版本等。";
"onboarding.tour.faq_hint" = "**有问题吗?**我建议您查看 GitHub 上的 [README](https://github.com/nicoverbruggen/phpmon/blob/main/README.md):其中包含全面的常见问题解答,包含各种技巧和常见问题及答案。";
"onboarding.tour.services.title" = "管理 Homebrew 服务";
"onboarding.tour.services" = "点击菜单栏项目后,您可以根据复选标记或叉号一目了然地查看所有 Homebrew 服务是否都已启动和运行。您还可以点击某项服务快速切换。";
"onboarding.tour.domains.title" = "管理域名";
"onboarding.tour.domains" = "通过菜单栏项目打开 `域名列表` 窗口,可以查看链接和停放的域名,以及活动的 nginx 代理";
"onboarding.tour.isolation.title" = "隔离域名";
"onboarding.tour.isolation" = "如果安装了 Valet 3 或更新版本,甚至可以通过右键单击域名窗口中的指定域名来使用域名隔离。这样,您就可以为该域名选择一个特定的 PHP 版本,而且只能在该域名使用。";
"onboarding.tour.feature_unavailable" = "此功能目前不可用,需要安装 Laravel Valet。";
"onboarding.tour.once" = "您只能看到一次 Welcome Tour。您可以稍后通过菜单栏图标(可在 `急救与服务` 下的菜单中找到)重新打开 Welcome Tour。";
"onboarding.tour.close" = "关闭 Tour";
// LANGUAGE CHOICE
"prefs.language" = "语言:";
"prefs.language_options_desc" = "选择不同的语言与 PHP Monitor 一起使用。要完全应用此更改,必须重新启动应用程序";
"alert.language_changed.title" = "您必须重新启动 PHP Monitor";
"alert.language_changed.subtitle" = "您刚刚更改了 PHP Monitor 的显示语言。菜单将立即使用正确的语言,但您可能需要重新启动应用程序,以使整个应用程序中的所有文本都应用您的新语言选择";

View File

@ -90,16 +90,17 @@ final class MainMenuTest: UITestCase {
// Should display loader
assertExists(app.staticTexts["phpman.busy.title".localized], 1)
// After loading, should display PHP 8.2
// After loading, should display PHP 8.2 and PHP 8.3
assertExists(app.staticTexts["PHP 8.2"], 5)
assertExists(app.staticTexts["PHP 8.3"])
// Should also display pre-release version
assertExists(app.staticTexts["PHP 8.3"])
assertExists(app.staticTexts["PHP 8.4"])
assertExists(app.staticTexts["phpman.version.prerelease".localized.uppercased()])
assertExists(app.staticTexts["phpman.version.available_for_installation".localized])
// But not PHP 8.4 (yet)
assertNotExists(app.staticTexts["PHP 8.4"])
// But not PHP 8.5 (yet)
assertNotExists(app.staticTexts["PHP 8.5"])
// Also, PHP 8.2 should have an update available
assertExists(app.staticTexts["phpman.version.has_update".localized(

View File

@ -51,7 +51,7 @@ final class UpdateCheckTest: UITestCase {
let app = launch(openMenu: false, with: configuration)
// Expect to see the content of the appropriate alert box
assertExists(app.staticTexts["updater.alerts.newer_version_available.title".localized("99.0.0 (9999)")], 2)
assertExists(app.staticTexts["updater.alerts.newer_version_available.title".localized("99.0.0 (9999)")], 3.0)
assertExists(app.buttons["updater.alerts.buttons.install".localized])
assertExists(app.buttons["updater.alerts.buttons.dismiss".localized])
}

View File

@ -28,6 +28,8 @@ class HomebrewUpgradableTest: XCTestCase {
: .instant("/opt/homebrew/etc/php/7.4/conf.d/php-memory-limits.ini")
])
// This config file assumes our PHP alias (`php`) is v8.2
PhpEnvironments.brewPhpAlias = "8.2"
let env = PhpEnvironments.shared
env.cachedPhpInstallations = [
"8.1": PhpInstallation("8.1.16"),