fix(remote): let a WSL machine restart its server, and call it "server" in zh (#417)

* fix(remote): let a WSL machine restart its server, and call it "server" in zh

The machine menu offered "restart server" only when `target.is_ssh()`, so a
WSL distro's row had just "new workspace" and "disconnect" — and the router
refused the action for anything but SSH, even though `restart_wsl_daemon`
had been sitting in `install/wsl.rs` unused since it was written. A distro's
server is installed and launched from this computer exactly like an SSH one;
only the transport differs.

- `RemoteTarget::hosts_our_server()` replaces `is_ssh()` as the gate in the
  sidebar menu and in `restart_window_daemon`. A `--stdio` workspace still
  has nothing to restart: it is whatever program the user named.
- The router grows WSL arms for both actions — `RestartServer` relaunches
  the distro's daemon, `ReplaceServer` (new `replace_wsl_server`) publishes
  the bundled binary first. The mismatch dialog's "update server" used to be
  a dead end on WSL for the same reason.
- `AppRestartServerNotSsh` is now `AppRestartServerNoServer`: the message no
  longer talks about SSH, since the only machine it can fire for is a local
  `--stdio` one.

The Chinese table called tty7's server 服务器 / 服务器端 / 后台服务; it now
says `server`, the way it already keeps `shell`, `pane` and `agent` in
English. The macOS Services menu keeps its 服务.

* fix(i18n): keep 服务器 where it means the SSH host, and test the new gate

The sweep that renamed tty7's own server to `server` in the Chinese table
also caught two SSH settings where 服务器 was never tty7's server: the
host-key description talks about the key of each machine being connected
to, and the banner switch suppresses the login banner sshd prints. Written
as `server` both now read as if tty7 ran something there, which is exactly
the confusion the rest of the sweep removes. Put the Chinese word back in
those two.

`hosts_our_server()` is the gate the whole change hangs on and nothing
exercised it, while the test next door still asserted under the name
"only SSH machines have a server to restart" — the rule this branch
retires. Name that test after what it actually checks, the transport, and
add one for the new predicate. It matches on the variants rather than
negating a single one, so a transport added later has to say for itself
whether we can restart what is on the far end.

---------

Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
This commit is contained in:
l0ng-ai
2026-08-09 01:04:25 +08:00
committed by GitHub
co-authored by l0ng-ai
parent a6eccc6937
commit 8b7215f0d8
9 changed files with 153 additions and 69 deletions
+48 -2
View File
@@ -162,6 +162,20 @@ impl RemoteTarget {
}
}
/// Whether the far end is served by a tty7 daemon this computer installed
/// and can therefore restart. SSH machines and WSL distros both are; a
/// `--stdio` program is whatever the user named, and stopping it is its
/// workspace's business.
pub fn hosts_our_server(&self) -> bool {
match self {
RemoteTarget::Profile { .. }
| RemoteTarget::Alias { .. }
| RemoteTarget::Direct { .. }
| RemoteTarget::Wsl { .. } => true,
RemoteTarget::LocalStdio { .. } => false,
}
}
pub fn host_id(&self) -> crate::host::HostId {
crate::host::HostId::from_connection_key(&self.connection_key())
}
@@ -491,7 +505,7 @@ mod tests {
}
#[test]
fn only_ssh_machines_have_a_server_to_restart() {
fn only_ssh_machines_are_reached_over_ssh() {
assert!(
RemoteTarget::Profile {
id: uuid::Uuid::nil()
@@ -510,7 +524,7 @@ mod tests {
distro: "Ubuntu".into()
}
.is_ssh(),
"a distribution's server is started by this client"
"a distribution is reached through wsl.exe, not a connection"
);
assert!(
!RemoteTarget::LocalStdio {
@@ -522,6 +536,38 @@ mod tests {
);
}
#[test]
fn every_machine_but_a_stdio_one_has_a_server_to_restart() {
assert!(
RemoteTarget::Profile {
id: uuid::Uuid::nil()
}
.hosts_our_server()
);
assert!(
RemoteTarget::Alias {
alias: "devbox".into()
}
.hosts_our_server()
);
assert!(RemoteTarget::direct("me", "box.local", 22).hosts_our_server());
assert!(
RemoteTarget::Wsl {
distro: "Ubuntu".into()
}
.hosts_our_server(),
"a distribution's server is installed and launched from here, like an SSH one"
);
assert!(
!RemoteTarget::LocalStdio {
program: "tty7-server".into(),
args: vec!["--stdio".into()],
}
.hosts_our_server(),
"a stdio program is whatever the user named, not a daemon of ours"
);
}
#[test]
fn direct_targets_normalize_and_reuse_the_quick_connect_parser() {
assert_eq!(
@@ -603,6 +603,20 @@ pub fn restart_wsl_daemon(distro: &str) -> io::Result<()> {
Ok(())
}
/// Restart the distro's daemon after making sure the binary it launches is this
/// build's. The bundled server is already on this computer, so unlike SSH there
/// is nothing to download — the copy is the whole install.
pub fn replace_wsl_server(distro: &str) -> io::Result<()> {
validate_distro(distro)?;
let ops = WslRemoteOps::new(distro);
let source = BundledServerBinary::discover();
let confirm = install_confirm();
let lock = install_lock(distro);
let _held = lock.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
Installer::with_source(&ops, &source, confirm.as_ref(), host_label(distro)).replace()?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
+37 -13
View File
@@ -718,8 +718,25 @@ async fn restart_server(
.restart_remote_server(spec, setup)
.await
}
// A distro's server is installed and launched from here too, so both
// moves mean the same thing they do over SSH — only the transport is
// different.
(RouteTarget::Wsl { distro }, RouteAction::ReplaceServer) => {
let distro = distro.clone();
setup
.blocking(move || crate::daemon::install::wsl::replace_wsl_server(&distro))
.await??;
Ok(())
}
(RouteTarget::Wsl { distro }, _) => {
let distro = distro.clone();
setup
.blocking(move || crate::daemon::install::wsl::restart_wsl_daemon(&distro))
.await??;
Ok(())
}
_ => Err(anyhow::anyhow!(
"restarting tty7's server is only supported for SSH machines, not {}",
"restarting tty7's server is only supported for machines it serves, not {}",
header.describe()
)),
}
@@ -1233,19 +1250,22 @@ mod tests {
assert!(forwarded.performed(RouteAction::Forward));
}
/// SSH and WSL machines both run a daemon this side installed, so both can
/// be restarted. A `--stdio` program is whatever the user named — there is
/// no daemon of ours behind it to stop.
#[tokio::test]
async fn a_restart_is_refused_for_a_machine_that_has_no_remote_daemon() {
for header in [
RouteHeader::local_stdio("cat", &[]).restart_server(),
RouteHeader::wsl("Ubuntu-22.04").restart_server(),
] {
let describe = header.describe();
let setup = RouteSetup::unattended(header.channel);
let Err(err) = perform(&header, &setup).await else {
panic!("a restart must be refused for {describe}");
};
assert!(err.to_string().contains("only supported for SSH"), "{err}");
}
let header = RouteHeader::local_stdio("cat", &[]).restart_server();
let describe = header.describe();
let setup = RouteSetup::unattended(header.channel);
let Err(err) = perform(&header, &setup).await else {
panic!("a restart must be refused for {describe}");
};
assert!(
err.to_string()
.contains("only supported for machines it serves"),
"{err}"
);
}
#[test]
@@ -1259,7 +1279,11 @@ mod tests {
let mut client = client;
let err = RouteAck::read(&mut client).expect_err("a `cat` has no daemon to restart");
assert!(err.to_string().contains("only supported for SSH"), "{err}");
assert!(
err.to_string()
.contains("only supported for machines it serves"),
"{err}"
);
assert!(routed.join().unwrap().is_err());
}
+2 -2
View File
@@ -1160,9 +1160,9 @@ impl Tty7App {
};
let target = remote.target.clone();
let label = crate::ui::remote_connect::label_for(&target, cx);
if !target.is_ssh() {
if !target.hosts_our_server() {
window.push_notification(
t_fmt(L10nKey::AppRestartServerNotSsh, &[("label", &label)]),
t_fmt(L10nKey::AppRestartServerNoServer, &[("label", &label)]),
cx,
);
return;
+2 -2
View File
@@ -1120,8 +1120,8 @@ pub fn translate_en(key: L10nKey) -> &'static str {
"The server holding your shells predates the version handshake, so this app can't tell what it speaks.\n\nQuit: nothing changes — the server and your shells keep running.\nRestart: tabs come back with fresh shells, and anything running now is killed."
}
L10nKey::AppRestart => "Restart",
L10nKey::AppRestartServerNotSsh => {
"tty7 can only restart the server on machines it reaches over SSH. {label} is served from this computer — stop its workspace instead."
L10nKey::AppRestartServerNoServer => {
"tty7 has no server of its own to restart on {label} — it is a program this computer runs over --stdio. Stop its workspace instead."
}
L10nKey::AppRestartServerBody => {
"This stops every running shell on this computer — anything still running in them will be terminated. Your tabs and layout are kept and reopened with fresh shells."
+2 -2
View File
@@ -1155,8 +1155,8 @@ pub fn translate_ja(key: L10nKey) -> Option<&'static str> {
"サーバーはバージョン照合より前のもので、何を話すか分かりません。\n\n終了:何も変わりません。サーバーもシェルも動き続けます。\n再起動:タブは新しいシェルで戻り、いま実行中のものは終了します"
}
L10nKey::AppRestart => "再起動",
L10nKey::AppRestartServerNotSsh => {
"tty7 は SSH で到達できるマシン上のサーバーしか再起動できません。{label} はこのコンピュータで実行されています。代わりにそのワークスペースを止めてください"
L10nKey::AppRestartServerNoServer => {
"{label} には再起動できる tty7 自身のサーバーがありません。これはこのコンピュータが --stdio で実行しているプログラムです。代わりにそのワークスペースを止めてください"
}
L10nKey::AppRestartServerBody => {
"このコンピュータで実行中のすべてのシェルが停止します。タブとレイアウトは保持され、新しいシェルで開きます"
+2 -2
View File
@@ -929,7 +929,7 @@ pub enum L10nKey {
AppRestartServerDialectNewerDetail,
AppRestartServerOldDetail,
AppRestart,
AppRestartServerNotSsh,
AppRestartServerNoServer,
AppRestartServerBody,
AppWorktreeRemoveDetailDirty,
AppWorktreeRemoveDetailClean,
@@ -1956,7 +1956,7 @@ mod tests {
L10nKey::AppRestartServerDialectNewerDetail,
L10nKey::AppRestartServerOldDetail,
L10nKey::AppRestart,
L10nKey::AppRestartServerNotSsh,
L10nKey::AppRestartServerNoServer,
L10nKey::AppRestartServerBody,
L10nKey::AppWorktreeRemoveDetailDirty,
L10nKey::AppWorktreeRemoveDetailClean,
+45 -45
View File
@@ -24,7 +24,7 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::HomeSplitRight => "向右分屏",
L10nKey::HomeSplitDown => "向下分屏",
L10nKey::HomeSettings => "设置…",
L10nKey::TrayQuitStopServer => "退出并停止服务器",
L10nKey::TrayQuitStopServer => "退出并停止 server",
L10nKey::Reconnect => "重新连接",
L10nKey::None => "无。",
L10nKey::TryAgain => "重试",
@@ -47,9 +47,9 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::RememberKeychain => "记住(钥匙串)",
L10nKey::Cancel => "取消",
L10nKey::Close => "关闭",
L10nKey::QuitStopServerTitle => "退出并停止服务器",
L10nKey::QuitStopServerTitle => "退出并停止 server",
L10nKey::QuitStopServerBody => {
"这会退出 tty7 并停止后台服务器,所有仍在运行的 shell 都会被终止。你的标签页和布局会被保留,下次启动时以全新的 shell 重新打开。(普通退出会保持 shell 运行。)"
"这会退出 tty7 并停止后台 server,所有仍在运行的 shell 都会被终止。你的标签页和布局会被保留,下次启动时以全新的 shell 重新打开。(普通退出会保持 shell 运行。)"
}
L10nKey::QuitAndStop => "退出并停止",
L10nKey::CloseSshConnectionTitle => "关闭这个 SSH 连接?",
@@ -435,17 +435,17 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
}
L10nKey::SettingsUpdateChannelStable => "Stable",
L10nKey::SettingsUpdateChannelNightly => "Nightly",
L10nKey::SettingsDaemonStale => "后台服务仍运行在 {build}。",
L10nKey::SettingsDaemonStale => "后台 server 仍运行在 {build}。",
L10nKey::SettingsDaemonStaleDesc => {
"tty7 是原地升级的,界面已经是新版本,但各个 pane 仍由旧版本的后台服务托管。重启服务才能用上新版本,代价是 pane 里正在跑的进程全部结束——shell、agent、SSH 会话都算。不急,挑个 pane 空闲的时候再重启。"
"tty7 是原地升级的,界面已经是新版本,但各个 pane 仍由旧版本的后台 server 托管。重启 server 才能用上新版本,代价是 pane 里正在跑的进程全部结束——shell、agent、SSH 会话都算。不急,挑个 pane 空闲的时候再重启。"
}
L10nKey::SettingsDaemonStaleRestart => "重启服务",
L10nKey::SettingsDaemonStaleRestart => "重启 server",
L10nKey::UpdateDialogTitle => "有可用更新",
L10nKey::UpdateDialogDetail => {
"tty7 {version} 已发布,你现在是 {current}。安装会重启应用;后台服务不动,pane 里开着的东西都还在。"
"tty7 {version} 已发布,你现在是 {current}。安装会重启应用;后台 server 不动,pane 里开着的东西都还在。"
}
L10nKey::UpdateDialogDetailWindows => {
"tty7 {version} 已发布,你现在是 {current}。安装会重启应用和后台服务:pane 里正在运行的进程会被结束,标签页和布局会以全新的 shell 恢复。"
"tty7 {version} 已发布,你现在是 {current}。安装会重启应用和后台 server:pane 里正在运行的进程会被结束,标签页和布局会以全新的 shell 恢复。"
}
L10nKey::UpdateDialogDetailManual => "tty7 {version} 已发布,你现在是 {current}。{hint}",
L10nKey::UpdateDialogCannotSelfUpdate => "这份安装无法自行更新。",
@@ -484,11 +484,11 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
"启动时将自带的 `tty7` 命令加入 PATH,让脚本和编码 agent 可在任意终端驱动 tty7。在 tty7 窗格内两种情况都可用。如果你自己构建或安装了 `tty7` 且不希望被遮蔽,请关闭此选项。下次启动时生效。"
}
L10nKey::SettingsInstallCliOnPath => "将 `tty7` 命令安装到 PATH",
L10nKey::SettingsServer => "服务器",
L10nKey::SettingsServer => "Server",
L10nKey::SettingsServerDesc => {
"重启在后台维持 shell 运行的服务器。这会结束这台计算机上所有正在运行的 shell;你的标签页和布局会以全新的 shell 重新打开。"
"重启在后台维持 shell 运行的 server。这会结束这台计算机上所有正在运行的 shell;你的标签页和布局会以全新的 shell 重新打开。"
}
L10nKey::SettingsRestartServer => "重启服务器",
L10nKey::SettingsRestartServer => "重启 server",
L10nKey::SettingsAppHttpProxy => "更新代理",
L10nKey::SettingsAppHttpProxyDesc => {
"仅用于 tty7 自身的更新检查和下载,不影响面板中运行的程序。留空则跟随系统代理。"
@@ -683,7 +683,7 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::SwitcherNoMatch => "没有匹配的工作区或机器。",
L10nKey::AddSshHost => "添加 SSH 主机…",
L10nKey::ClickForNewWindow => "点击打开新窗口",
L10nKey::RestartServer => "重启服务器",
L10nKey::RestartServer => "重启 server",
L10nKey::OtherMachines => "其他机器",
L10nKey::Ok => "确定",
L10nKey::SftpNoTransfers => "还没有传输任务。",
@@ -857,26 +857,26 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
SSH ~/.ssh/config "
}
L10nKey::RemoteThisComputer => "本机",
L10nKey::RemoteRestartTitle => "重启 \"{machine}\" 上的 tty7 服务器",
L10nKey::RemoteRestartTitle => "重启 \"{machine}\" 上的 tty7 server",
L10nKey::RemoteRestartBody => {
"这将停止 {machine} 上的所有 shell——其中仍在运行的任何内容都会被终止,\
shell shell "
}
L10nKey::RemoteReplaceBody => {
"tty7 会在 {machine} 上安装匹配的服务器端并启动它。\n\
"tty7 会在 {machine} 上安装匹配的 server 并启动它。\n\
\n\
{machine} "
}
L10nKey::RemoteRestartFailedTitle => "\"{machine}\" 上的 tty7 服务器未被重启",
L10nKey::RemoteRestartFailedTitle => "\"{machine}\" 上的 tty7 server 未被重启",
L10nKey::RemoteRestartFailedBody => {
"{error}\n\
\n\
"
server"
}
L10nKey::RemoteHostUnreachable => "无法连接到 {machine}{error}",
L10nKey::RemoteInstallTitle => "\"{machine}\" 上安装 tty7 服务器",
L10nKey::RemoteInstallTitle => "\"{machine}\" 上安装 tty7 server",
L10nKey::RemoteInstallDetail => {
"tty7 会将其服务器二进制文件写入 {machine},以便本机可以在那里托管\
"tty7 会将其 server 二进制文件写入 {machine},以便本机可以在那里托管\
{machine} 使 sudo\n\
\n\
{path_label}\u{2003}{path}\n\
@@ -894,50 +894,50 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::RemoteInstallShaLabel => "SHA-256",
L10nKey::RemoteInstallSilentUpgrades => "此后在该机器上的升级将静默安装。",
L10nKey::RemoteInstallBytes => "字节",
L10nKey::RemoteMismatchTitle => "更新 \"{machine}\" 上的 tty7 服务器端",
L10nKey::RemoteMismatchTitle => "更新 \"{machine}\" 上的 tty7 server",
L10nKey::RemoteMismatchDetail => {
"{machine} 正在使用 {running} 提供 tty7 会话,该版本使用的协议无法被\
{wanted}tty7 \
{wanted}tty7 server\
\n\
\n\
{replace_server}\u{2003} {wanted} \n\
{cancel}\u{2003} {machine} "
}
L10nKey::RemoteMismatchReplaceServer => "更新服务器端",
L10nKey::RemoteMismatchReplaceServer => "更新 server",
L10nKey::RemoteMismatchUnknownBuild => "未知构建",
L10nKey::RemoteMismatchUnknownBuildFromExe => "未知构建(来自 {exe}",
L10nKey::RemoteServerOutdated => {
"{machine} 上的 tty7 服务器端太旧({build}),当前这份 tty7 连不上它。\
"{machine} 上的 tty7 server 太旧({build}),当前这份 tty7 连不上它。\
"
}
L10nKey::RemoteServerTooNew => {
"{machine} 上的 tty7 服务器端{build})比当前这份 tty7 还新。\
tty7"
"{machine} 上的 tty7 server{build})比当前这份 tty7 还新。\
tty7 server "
}
L10nKey::RemoteDaemonStartFailed => "无法启动 tty7 本地服务器{error}",
L10nKey::RemoteDaemonUnreachable => "无法连接到 tty7 本地服务器{error}",
L10nKey::RemoteDaemonStartFailed => "无法启动 tty7 本地 server{error}",
L10nKey::RemoteDaemonUnreachable => "无法连接到 tty7 本地 server{error}",
L10nKey::RemoteDaemonTooOld => {
"此机器上的 tty7 守护进程版本较旧,无法重启 {machine} 上的服务器\
"此机器上的 tty7 守护进程版本较旧,无法重启 {machine} 上的 server\
退 tty7"
}
L10nKey::RemoteProfileMissing => "该已保存的 SSH 主机配置已不存在",
L10nKey::RemoteAliasMissing => "`{alias}` 已不再位于 ~/.ssh/config 中",
L10nKey::RemoteWslNoSsh => "WSL 工作区没有 SSH 连接",
L10nKey::RemoteLocalStdioNoSsh => "本地 --stdio 工作区没有 SSH 连接",
L10nKey::RemoteHostNotTty7 => "{machine} 已响应,但并非作为 tty7 服务器{error}",
L10nKey::RemoteHostNotTty7 => "{machine} 已响应,但并非作为 tty7 server{error}",
L10nKey::RemoteWorkspaceListFailed => "已连接到 {machine},但其工作区列表获取失败:{error}",
L10nKey::RemoteServerRestartFailed => "无法重启 {machine} 上的 tty7 服务器{error}",
L10nKey::RemoteServerRestartFailed => "无法重启 {machine} 上的 tty7 server{error}",
L10nKey::RemoteNoRouteToHost => "tty7 已无法到达 {machine}",
L10nKey::RemoteMachineTreeUnexpectedReply => "服务器用 {reply} 回复了机器树请求",
L10nKey::RemoteMachineTreeUnexpectedReply => "server 用 {reply} 回复了机器树请求",
L10nKey::RemoteMismatchVersionFromExe => "{version}(来自 {exe}",
L10nKey::AppNoRunningCodingAgent => {
"未找到运行中的编码 agent——请先在某个窗格中启动一个(claude、codex 等)。"
}
L10nKey::SwitcherThisComputer => "本机",
L10nKey::SwitcherRestartingServer => "正在重启 tty7 服务器",
L10nKey::SwitcherDownloadingServerWithTotal => "正在下载 tty7 服务器… {done} / {total}",
L10nKey::SwitcherDownloadingServerNoTotal => "正在下载 tty7 服务器… {done}",
L10nKey::SwitcherCopyingServer => "正在复制 tty7 服务器… {done} / {total}",
L10nKey::SwitcherRestartingServer => "正在重启 tty7 server",
L10nKey::SwitcherDownloadingServerWithTotal => "正在下载 tty7 server… {done} / {total}",
L10nKey::SwitcherDownloadingServerNoTotal => "正在下载 tty7 server… {done}",
L10nKey::SwitcherCopyingServer => "正在复制 tty7 server… {done} / {total}",
L10nKey::SwitcherThisWindow => "当前窗口",
L10nKey::SwitcherOpen => "已打开",
L10nKey::SwitcherDisconnect => "断开连接",
@@ -961,7 +961,7 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::SshPromptSubmit => "提交",
L10nKey::HostOpsError => "{context}{error}",
L10nKey::TreeWindowOpenedEmpty => {
"这个窗口的服务器没有交出标签页,所以窗口是空的。什么都没丢,它一响应就会回来。如果一直不回来,在命令面板里执行「重启服务器」。"
"这个窗口的 server 没有交出标签页,所以窗口是空的。什么都没丢,它一响应就会回来。如果一直不回来,在命令面板里执行「重启 server」。"
}
L10nKey::CmdGroupTabsPanes => "标签页与窗格",
L10nKey::CmdGroupWorkspaces => "工作区",
@@ -1046,29 +1046,29 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::CmdDocumentation => "文档",
L10nKey::CmdJoinDiscord => "加入 Discord",
L10nKey::CmdReportIssue => "报告问题…",
L10nKey::CmdRestartServer => "重启服务器",
L10nKey::CmdRestartServer => "重启 server",
L10nKey::CmdRestartServerSubtitle => "结束所有运行中的 shell;保留布局",
L10nKey::CmdQuitTty7 => "退出 tty7",
L10nKey::CmdQuitTty7Subtitle => "shell 保持运行",
L10nKey::CmdQuickConnect => "连接到 \"{target}\"",
L10nKey::CmdQuickConnectSaveProfile => "\"{target}\" 保存为主机配置…",
L10nKey::CmdRecent => "最近使用",
L10nKey::AppRestartServerTitle => "重启服务器",
L10nKey::AppRestartServerTitle => "重启 server",
L10nKey::AppRestartServerMismatchDetail => {
"服务器是 v{build},协议 {protocol};此应用使用 {ours}。两者无法对话,标签页取不出来。\n\n退出:什么都不变,服务器和 shell 继续运行。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
"server 是 v{build},协议 {protocol};此应用使用 {ours}。两者无法对话,标签页取不出来。\n\n退出:什么都不变,server 和 shell 继续运行。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
}
L10nKey::AppRestartServerDialectDetail => {
"服务器是 v{build}control 方言 v{dialect},而此应用使用 v{ours}。它交不出标签页,所以每个窗口都开成空的。\n\n退出:什么都不变,服务器和 shell 继续运行。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
"server 是 v{build}control 方言 v{dialect},而此应用使用 v{ours}。它交不出标签页,所以每个窗口都开成空的。\n\n退出:什么都不变,server 和 shell 继续运行。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
}
L10nKey::AppRestartServerDialectNewerDetail => {
"服务器是 v{build}control 方言 v{dialect},而此应用使用 v{ours}。它交不出标签页,所以每个窗口都开成空的。\n\n退出并装上更新的构建:真正的解法,shell 全都还在。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
"server 是 v{build}control 方言 v{dialect},而此应用使用 v{ours}。它交不出标签页,所以每个窗口都开成空的。\n\n退出并装上更新的构建:真正的解法,shell 全都还在。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
}
L10nKey::AppRestartServerOldDetail => {
"服务器早于版本握手,此应用无从得知它说的是什么。\n\n退出:什么都不变,服务器和 shell 继续运行。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
"server 早于版本握手,此应用无从得知它说的是什么。\n\n退出:什么都不变,server 和 shell 继续运行。\n重启:标签页带全新 shell 回来,现在跑着的东西会被杀掉。"
}
L10nKey::AppRestart => "重启",
L10nKey::AppRestartServerNotSsh => {
"tty7 只能重启通过 SSH 连接的机器上的服务器。{label} 由本机提供服务——请改为停止其工作区。"
L10nKey::AppRestartServerNoServer => {
"{label} 上没有 tty7 自己的 server 可重启——它是本机通过 --stdio 运行的程序。请改为停止其工作区。"
}
L10nKey::AppRestartServerBody => {
"这会停止本机上所有正在运行的 shell——其中仍在运行的任何内容都会被终止。你的标签页和布局会被保留,并以全新的 shell 重新打开。"
@@ -1126,7 +1126,7 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::AppKeybindingDisplacedNote => {
"{action} 占用了原属于 {previous} 的快捷键,{previous} 现在没有快捷键了。"
}
L10nKey::AppLocalServerName => "本地服务器",
L10nKey::AppLocalServerName => "本地 server",
L10nKey::AppSshParseUnbalancedQuotes => "SSH 命令中的引号不匹配",
L10nKey::AppSshParseNoRemoteCommands => "此处不支持远程命令",
L10nKey::AppSshParseFlagNeedsValue => "-{flag} 需要一个值",
@@ -1206,7 +1206,7 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
L10nKey::AppMenuKeyboardShortcuts => "键盘快捷键",
L10nKey::AppMenuJoinDiscord => "加入 Discord",
L10nKey::AppMenuReportIssue => "报告问题…",
L10nKey::AppMenuRestartServer => "重启服务器",
L10nKey::AppMenuRestartServer => "重启 server",
L10nKey::WindowUntitled => "未命名",
L10nKey::TrayShowTty7 => "显示 tty7",
L10nKey::TrayNotifications => "通知",
+1 -1
View File
@@ -2242,7 +2242,7 @@ fn group_menu(
return menu;
};
let connected = group.link == Link::Connected;
let restartable = target.is_ssh();
let restartable = target.hosts_our_server();
let (label, for_restart) = (group.label.clone(), target.clone());
let menu = menu.separator().item(
PopupMenuItem::new(t(L10nKey::SwitcherDisconnect))