diff --git a/apps/android/app/src/main/AndroidManifest.xml b/apps/android/app/src/main/AndroidManifest.xml index ff5d4b2c..e39e142f 100644 --- a/apps/android/app/src/main/AndroidManifest.xml +++ b/apps/android/app/src/main/AndroidManifest.xml @@ -6,11 +6,12 @@ - + android:supportsRtl="false" android:usesCleartextTraffic="false"> open("https://crossdesk.cn"));updateLink.setGravity(Gravity.START|Gravity.CENTER_VERTICAL);updateLink.setPadding(ui.dp(8),ui.dp(12),0,ui.dp(12));updateRow.addView(updateLink,new LinearLayout.LayoutParams(0,-2,1));version.addView(updateRow); updateStatus=ui.text("",13,false);updateStatus.setPadding(ui.dp(16),ui.dp(8),ui.dp(16),ui.dp(8));version.addView(updateStatus); - checkButton=ui.action("检查更新",BLUE,activity::checkAppUpdates);version.addView(checkButton);renderUpdates();ui.gap(content,28); + checkButton=ui.action(L10n.tr("检查更新"),BLUE,activity::checkAppUpdates);version.addView(checkButton);renderUpdates();ui.gap(content,28); if(catalog==null){unavailable(content);return;} LinearLayout links=activity.section(content,""); - activity.link(links,"软件许可","",()->component(catalog.find("crossdesk"),this::show));ui.divider(links); - activity.link(links,"开源组件","",this::components);ui.divider(links); - activity.link(links,"源码与构建说明","",this::source); - activity.footer(content,"许可与版权声明可离线查阅。"); + activity.link(links,L10n.tr("软件许可"),"",()->component(catalog.find("crossdesk"),this::show));ui.divider(links); + activity.link(links,L10n.tr("开源组件"),"",this::components);ui.divider(links); + activity.link(links,L10n.tr("源码与构建说明"),"",this::source); + activity.footer(content,L10n.tr("许可与版权声明可离线查阅。")); } private String applicationVersion(){ return activity.applicationVersion(); @@ -45,11 +45,11 @@ final class AboutPages { void renderUpdates(){ if(updateStatus==null)return; updateRow.setVisibility(updates.updateAvailable()?View.VISIBLE:View.GONE); - updateLink.setText("新版本可用:v"+updates.availableVersion); - String status=!activity.hasNetworkConsent()?"完成隐私授权后可检查更新":switch(updates.status){ - case CHECKING -> "正在检查更新…"; - case UP_TO_DATE -> "当前已是最新版本"; - case FAILED -> "检查失败,请稍后重试"; + updateLink.setText(L10n.format("新版本可用:v{0}",updates.availableVersion)); + String status=!activity.hasNetworkConsent()?L10n.tr("完成隐私授权后可检查更新"):switch(updates.status){ + case CHECKING -> L10n.tr("正在检查更新…"); + case UP_TO_DATE -> L10n.tr("当前已是最新版本"); + case FAILED -> L10n.tr("检查失败,请稍后重试"); default -> ""; }; updateStatus.setText(status);updateStatus.setVisibility(status.isEmpty()?View.GONE:View.VISIBLE); @@ -58,11 +58,11 @@ final class AboutPages { checkButton.setAlpha(checkButton.isEnabled()?1f:.5f); } private void components(){ - LinearLayout content=activity.formPage("open-source","开源组件",this::show); - LinearLayout notice=activity.section(content,"OpenFEC 告知"); - paragraph(notice,"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。",SECONDARY); + LinearLayout content=activity.formPage("open-source",L10n.tr("开源组件"),this::show); + LinearLayout notice=activity.section(content,L10n.tr("OpenFEC 告知")); + paragraph(notice,L10n.tr("本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。"),SECONDARY); ui.divider(notice);paragraph(notice,"(c) Copyright 2009 - 2012 INRIA - All rights reserved",INK);ui.divider(notice); - activity.link(notice,"OpenFEC 许可与源码","",()->component(catalog.find("openfec"),this::components));ui.gap(content,28); + activity.link(notice,L10n.tr("OpenFEC 许可与源码"),"",()->component(catalog.find("openfec"),this::components));ui.gap(content,28); LinearLayout list=activity.section(content,"");boolean first=true; for(LicenseCatalog.Component item:catalog.components){ if(item.id.equals("crossdesk")||item.id.equals("openfec"))continue; @@ -73,41 +73,41 @@ final class AboutPages { row.addView(labels,new LinearLayout.LayoutParams(0,-2,1));TextView chevron=ui.text(" ›",23,false);chevron.setTextColor(0xFFB7B7BD);row.addView(chevron); row.setContentDescription(item.name+","+item.license);row.setClickable(true);row.setFocusable(true);row.setOnClickListener(v->component(item,this::components));list.addView(row); } - activity.footer(content,"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。"); + activity.footer(content,L10n.tr("各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。")); } private void component(LicenseCatalog.Component item,Runnable back){ LinearLayout content=activity.formPage("license:"+item.id,item.name,back);LinearLayout info=activity.section(content,""); String version=item.id.equals("crossdesk")?applicationVersion():item.version.length()==40?item.version.substring(0,12):item.version; - value(info,"版本",version);ui.divider(info);value(info,"许可",item.license);ui.divider(info); - external(info,"查看源码",item.sourceURL); + value(info,L10n.tr("版本"),version);ui.divider(info);value(info,L10n.tr("许可"),item.license);ui.divider(info); + external(info,L10n.tr("查看源码"),item.sourceURL); if(!item.buildDocuments.isEmpty()||!item.buildSourceURL.isEmpty()){ ui.divider(info); - if(!item.buildDocuments.isEmpty())activity.link(info,"构建配方与项目补丁","",()->buildSources(item,back)); - else external(info,"构建配方与项目补丁",item.buildSourceURL); + if(!item.buildDocuments.isEmpty())activity.link(info,L10n.tr("构建配方与项目补丁"),"",()->buildSources(item,back)); + else external(info,L10n.tr("构建配方与项目补丁"),item.buildSourceURL); } - ui.gap(content,16);LinearLayout docs=activity.section(content,"许可与版权声明"); + ui.gap(content,16);LinearLayout docs=activity.section(content,L10n.tr("许可与版权声明")); for(int i=0;i0)ui.divider(docs);LicenseCatalog.Document document=item.documents.get(i); activity.link(docs,item.documentTitle(document),"",()->document(item.documentTitle(document),document,()->component(item,back))); } } private void source(){ - LinearLayout content=activity.formPage("source","源码与构建说明",this::show); - LinearLayout info=activity.section(content,"本版本源码与构建说明"); - if(catalog.source==null){paragraph(info,"本版本源码信息暂不可用。",SECONDARY);ui.divider(info);external(info,"项目主页","https://github.com/kunkundi/crossdesk");return;} + LinearLayout content=activity.formPage("source",L10n.tr("源码与构建说明"),this::show); + LinearLayout info=activity.section(content,L10n.tr("本版本源码与构建说明")); + if(catalog.source==null){paragraph(info,L10n.tr("本版本源码信息暂不可用。"),SECONDARY);ui.divider(info);external(info,L10n.tr("项目主页"),"https://github.com/kunkundi/crossdesk");return;} String revision=catalog.source.optString("revision","");String tag=catalog.source.isNull("tag")?"":catalog.source.optString("tag",""); - value(info,"源码版本",tag.isEmpty()?revision.substring(0,Math.min(12,revision.length())):tag);ui.divider(info); - if(catalog.source.optBoolean("isModified")){paragraph(info,"开发版本包含尚未发布的修改,以下链接为基础版本源码。",SECONDARY);ui.divider(info);} - external(info,"查看源码",catalog.source.optString("sourceURL",catalog.find("crossdesk").sourceURL));ui.divider(info); + value(info,L10n.tr("源码版本"),tag.isEmpty()?revision.substring(0,Math.min(12,revision.length())):tag);ui.divider(info); + if(catalog.source.optBoolean("isModified")){paragraph(info,L10n.tr("开发版本包含尚未发布的修改,以下链接为基础版本源码。"),SECONDARY);ui.divider(info);} + external(info,L10n.tr("查看源码"),catalog.source.optString("sourceURL",catalog.find("crossdesk").sourceURL));ui.divider(info); try{ List documents=LicenseCatalog.documents(catalog.source.optJSONArray("buildDocuments")); - if(!documents.isEmpty())actionLink(info,"构建说明",()->document("构建说明",documents.get(0),this::source)); - else external(info,"构建说明",catalog.source.optString("buildInstructionsURL","https://github.com/kunkundi/crossdesk")); - }catch(org.json.JSONException error){paragraph(info,"本版本源码信息暂不可用。",SECONDARY);} + if(!documents.isEmpty())actionLink(info,L10n.tr("构建说明"),()->document(L10n.tr("构建说明"),documents.get(0),this::source)); + else external(info,L10n.tr("构建说明"),catalog.source.optString("buildInstructionsURL","https://github.com/kunkundi/crossdesk")); + }catch(org.json.JSONException error){paragraph(info,L10n.tr("本版本源码信息暂不可用。"),SECONDARY);} } private void buildSources(LicenseCatalog.Component item,Runnable back){ - LinearLayout content=activity.formPage("build:"+item.id,"构建配方与项目补丁",()->component(item,back)); - if(!item.buildSourceURL.isEmpty()){LinearLayout upstream=activity.section(content,"");external(upstream,"查看源码",item.buildSourceURL);ui.gap(content,28);} + LinearLayout content=activity.formPage("build:"+item.id,L10n.tr("构建配方与项目补丁"),()->component(item,back)); + if(!item.buildSourceURL.isEmpty()){LinearLayout upstream=activity.section(content,"");external(upstream,L10n.tr("查看源码"),item.buildSourceURL);ui.gap(content,28);} LinearLayout docs=activity.section(content,""); for(int i=0;i0)ui.divider(docs);LicenseCatalog.Document document=item.buildDocuments.get(i); @@ -129,10 +129,10 @@ final class AboutPages { private void actionLink(LinearLayout parent,String title,Runnable action){TextView link=ui.action(title,BLUE,action);link.setTypeface(android.graphics.Typeface.DEFAULT);link.setGravity(Gravity.START|Gravity.CENTER_VERTICAL);link.setPadding(ui.dp(16),ui.dp(12),ui.dp(16),ui.dp(12));parent.addView(link);} private void open(String url){ Uri uri=Uri.parse(url);if(!"https".equals(uri.getScheme())&&!"http".equals(uri.getScheme()))return; - try{activity.startActivity(new Intent(Intent.ACTION_VIEW,uri).addCategory(Intent.CATEGORY_BROWSABLE));}catch(ActivityNotFoundException error){Toast.makeText(activity,"未找到可打开链接的浏览器",Toast.LENGTH_SHORT).show();} + try{activity.startActivity(new Intent(Intent.ACTION_VIEW,uri).addCategory(Intent.CATEGORY_BROWSABLE));}catch(ActivityNotFoundException error){Toast.makeText(activity,L10n.tr("未找到可打开链接的浏览器"),Toast.LENGTH_SHORT).show();} } private void unavailable(LinearLayout content){ content.setGravity(Gravity.CENTER);ui.gap(content,32);TextView icon=ui.text("▤",36,false);icon.setTextColor(SECONDARY);content.addView(icon);ui.gap(content,12); - content.addView(ui.text("无法读取开源许可",17,true));TextView message=ui.text("应用中的许可文件缺失或损坏,请重新安装应用。",14,false);message.setGravity(Gravity.CENTER);message.setTextColor(SECONDARY);content.addView(message); + content.addView(ui.text(L10n.tr("无法读取开源许可"),17,true));TextView message=ui.text(L10n.tr("应用中的许可文件缺失或损坏,请重新安装应用。"),14,false);message.setGravity(Gravity.CENTER);message.setTextColor(SECONDARY);content.addView(message); } } diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/AnnouncementView.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/AnnouncementView.java index fa30b9ff..4db7020b 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/AnnouncementView.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/AnnouncementView.java @@ -51,15 +51,15 @@ final class AnnouncementView extends ScrollView { TextView text=ui.text(value,14,false);text.setTextColor(color);text.setLineSpacing(ui.dp(3),1);return text; } private void renderList(){ - if(inbox.deleteFailed){content.addView(message("无法删除这条公告,请重试。",RED));ui.gap(content,12);} + if(inbox.deleteFailed){content.addView(message(L10n.tr("无法删除这条公告,请重试。"),RED));ui.gap(content,12);} if(!inbox.isConnected()){ - content.addView(message("连接服务器后可获取最新公告。",SECONDARY)); - content.addView(ui.action("连接服务器",BLUE,authorize));ui.gap(content,8); + content.addView(message(L10n.tr("连接服务器后可获取最新公告。"),SECONDARY)); + content.addView(ui.action(L10n.tr("连接服务器"),BLUE,authorize));ui.gap(content,8); }else if(inbox.failed){ - LinearLayout error=ui.row();error.addView(message("公告加载失败,请重试。",SECONDARY),new LinearLayout.LayoutParams(0,-2,1)); - error.addView(ui.action("重试",BLUE,inbox::refresh),ui.size(64,48));content.addView(error);ui.gap(content,8); + LinearLayout error=ui.row();error.addView(message(L10n.tr("公告加载失败,请重试。"),SECONDARY),new LinearLayout.LayoutParams(0,-2,1)); + error.addView(ui.action(L10n.tr("重试"),BLUE,inbox::refresh),ui.size(64,48));content.addView(error);ui.gap(content,8); } - countLabel=ui.text("共 "+inbox.total+" 条 · "+inbox.unread+" 条未读",13,false); + countLabel=ui.text(L10n.format("共 {0} 条 · {1} 条未读",inbox.total,inbox.unread),13,false); countLabel.setTextColor(SECONDARY);countLabel.setPadding(ui.dp(16),ui.dp(8),0,ui.dp(8));content.addView(countLabel); LinearLayout card=ui.column();ui.card(card,12);content.addView(card); for(AnnouncementInbox.Item item:inbox.items){ @@ -69,11 +69,11 @@ final class AnnouncementView extends ScrollView { if(inbox.loading){ LinearLayout loading=ui.row();loading.setGravity(Gravity.CENTER);loading.setPadding(0,ui.dp(18),0,ui.dp(18)); ProgressBar spinner=new ProgressBar(getContext());spinner.setIndeterminateTintList(ColorStateList.valueOf(BLUE));loading.addView(spinner,ui.size(20,20)); - TextView label=message("加载中…",SECONDARY);label.setPadding(ui.dp(10),0,0,0);loading.addView(label);card.addView(loading); + TextView label=message(L10n.tr("加载中…"),SECONDARY);label.setPadding(ui.dp(10),0,0,0);loading.addView(label);card.addView(loading); }else if(inbox.items.size()open.accept(item));row.setOnLongClickListener(v->{confirmDelete(item);return true;}); return new SwipeRow(row,()->confirmDelete(item)); } private void confirmDelete(AnnouncementInbox.Item item){ if(deleteDialog!=null)deleteDialog.dismiss(); - deleteDialog=new AlertDialog.Builder(getContext()).setTitle("删除公告").setMessage("删除这条公告?") - .setNegativeButton("取消",null).setPositiveButton("删除",(dialog,which)->inbox.dismiss(item)).show(); + deleteDialog=new AlertDialog.Builder(getContext()).setTitle(L10n.tr("删除公告")).setMessage(L10n.tr("删除这条公告?")) + .setNegativeButton(L10n.tr("取消"),null).setPositiveButton(L10n.tr("删除"),(dialog,which)->inbox.dismiss(item)).show(); } private void renderDetail(){ AnnouncementInbox.Item item=inbox.find(id,revision); - if(item==null){content.addView(message("这条公告已更新或删除,请返回公告列表查看。",SECONDARY));return;} + if(item==null){content.addView(message(L10n.tr("这条公告已更新或删除,请返回公告列表查看。"),SECONDARY));return;} content.addView(ui.text(item.title,22,true));ui.gap(content,16); - TextView date=ui.text(date(item)+" · "+(item.read?"已读":"未读"),12,false);date.setTextColor(SECONDARY);content.addView(date);ui.gap(content,16); + TextView date=ui.text(date(item)+" · "+(item.read?L10n.tr("已读"):L10n.tr("未读")),12,false);date.setTextColor(SECONDARY);content.addView(date);ui.gap(content,16); if(inbox.readSaveFailed){ - content.addView(message("无法保存本地阅读状态,请重试。",RED)); - content.addView(ui.action("重试保存阅读状态",BLUE,()->inbox.markRead(item)));ui.gap(content,16); + content.addView(message(L10n.tr("无法保存本地阅读状态,请重试。"),RED)); + content.addView(ui.action(L10n.tr("重试保存阅读状态"),BLUE,()->inbox.markRead(item)));ui.gap(content,16); } TextView body=ui.text("",17,false);body.setText(AnnouncementText.format(item.body));body.setTextIsSelectable(true); body.setMovementMethod(LinkMovementMethod.getInstance());body.setLinksClickable(true);body.setLinkTextColor(BLUE);body.setLineSpacing(ui.dp(4),1); @@ -127,7 +127,7 @@ final class AnnouncementView extends ScrollView { trackPull(event); if(!pulling)return super.onTouchEvent(event); boolean reached=event.getY()-downY>=ui.dp(72); - if(event.getActionMasked()==MotionEvent.ACTION_MOVE&&countLabel!=null)countLabel.setText(reached?"松开刷新":"下拉刷新"); + if(event.getActionMasked()==MotionEvent.ACTION_MOVE&&countLabel!=null)countLabel.setText(reached?L10n.tr("松开刷新"):L10n.tr("下拉刷新")); if(event.getActionMasked()==MotionEvent.ACTION_UP||event.getActionMasked()==MotionEvent.ACTION_CANCEL){ pulling=false;if(reached&&event.getActionMasked()==MotionEvent.ACTION_UP)inbox.refresh();else render(); } @@ -142,7 +142,7 @@ final class AnnouncementView extends ScrollView { private boolean dragging; SwipeRow(View front,Runnable delete){ super(ui.context);this.front=front;setClipChildren(true); - remove=ui.action("删除",Color.WHITE,delete);remove.setBackgroundColor(RED); + remove=ui.action(L10n.tr("删除"),Color.WHITE,delete);remove.setBackgroundColor(RED); remove.setVisibility(INVISIBLE); remove.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);remove.setFocusable(false); addView(remove,new FrameLayout.LayoutParams(ui.dp(76),-1,Gravity.END));addView(front,new FrameLayout.LayoutParams(-1,-2)); diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/BackgroundSession.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/BackgroundSession.java index 1d7ebf75..618147bc 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/BackgroundSession.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/BackgroundSession.java @@ -46,7 +46,7 @@ final class BackgroundSession implements NativeSession.Listener { if (listener != null) listener.ended(reason); } @Override public void ended(String reason) { finish(reason); } - @Override public void passwordRejected() { finish("远端访问密码已失效,请重新连接"); } + @Override public void passwordRejected() { finish(L10n.tr("远端访问密码已失效,请重新连接")); } @Override public void connected() { /* Already connected before the service takes ownership. */ } @Override public void status(String message) { if (view != null) view.status(message); } @Override public void signaling(int state, String id) { @@ -75,8 +75,8 @@ final class BackgroundSession implements NativeSession.Listener { @Override public void statistics(RemoteNetworkStatistics.Snapshot value) { if (view != null) view.statistics(value); } @Override public void fileTransfer(String name, double progress, boolean sending, File received) { if (received != null) receivedFile = received; - fileStatus = progress < 0 ? name + " 传输失败" : (sending ? "发送 " : "接收 ") + name - + (progress >= 1 ? " · 已完成" : " · " + (int)(progress * 100) + "%"); + fileStatus = progress < 0 ? L10n.format("{0} 传输失败", name) : (sending ? L10n.tr("发送 ") : L10n.tr("接收 ")) + name + + (progress >= 1 ? L10n.tr(" · 已完成") : " · " + (int)(progress * 100) + "%"); if (view != null) view.fileTransfer(name, progress, sending, received); } @Override public void controlFeedback(String text) { if (view != null) view.controlFeedback(text); } diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/CrossDeskApplication.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/CrossDeskApplication.java new file mode 100644 index 00000000..0575d0f8 --- /dev/null +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/CrossDeskApplication.java @@ -0,0 +1,11 @@ +package cn.crossdesk.mobile; + +import android.app.Application; + +/** Initialize localization before any activity, background service or model. */ +public final class CrossDeskApplication extends Application { + @Override public void onCreate() { + super.onCreate(); + L10n.initialize(this); + } +} diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/L10n.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/L10n.java new file mode 100644 index 00000000..2a0e947b --- /dev/null +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/L10n.java @@ -0,0 +1,33 @@ +package cn.crossdesk.mobile; + +import android.content.Context; +import java.util.Locale; + +/** Native resource lookup; never translates remote content, file names or protocol data. */ +final class L10n { + private static volatile Context application; + static void initialize(Context context) { application = context.getApplicationContext(); } + static String tr(String key) { + Context context = application; + Integer id = LocalizationKeys.IDS.get(key); + return context == null || id == null ? key : context.getString(id); + } + static String format(String key, Object... args) { + java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("\\{(\\d+)\\}").matcher(tr(key)); + StringBuffer result = new StringBuffer(); + while (matcher.find()) { + int index = Integer.parseInt(matcher.group(1)); + String value = index < args.length ? String.valueOf(args[index]) : matcher.group(); + matcher.appendReplacement(result, java.util.regex.Matcher.quoteReplacement(value)); + } + matcher.appendTail(result); + return result.toString(); + } + static boolean isChinese() { + Context context = application; + Locale locale = context == null ? Locale.getDefault() + : context.getResources().getConfiguration().getLocales().get(0); + return locale.getLanguage().equals("zh"); + } + private L10n() {} +} diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/LicenseCatalog.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/LicenseCatalog.java index d03115dc..6b1d0147 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/LicenseCatalog.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/LicenseCatalog.java @@ -28,9 +28,9 @@ final class LicenseCatalog { if(documents.isEmpty())throw new JSONException("Missing documents"); } String documentTitle(Document document){ - if(document.title.equals("Source copyright and license notices"))return "版权与许可声明"; - if(document.title.equals("apps/android/licenses/OPEN_SOURCE_NOTICE.txt"))return "开源软件权利说明"; - if(id.equals("crossdesk")&&document.title.equals("LICENSE"))return "GNU GPL 第 3 版"; + if(document.title.equals("Source copyright and license notices"))return L10n.tr("版权与许可声明"); + if(document.title.equals("apps/android/licenses/OPEN_SOURCE_NOTICE.txt"))return L10n.tr("开源软件权利说明"); + if(id.equals("crossdesk")&&document.title.equals("LICENSE"))return L10n.tr("GNU GPL 第 3 版"); return document.title; } } diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/LocalizationKeys.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/LocalizationKeys.java new file mode 100644 index 00000000..3f7f3bb7 --- /dev/null +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/LocalizationKeys.java @@ -0,0 +1,316 @@ +package cn.crossdesk.mobile; + +import java.util.HashMap; +import java.util.Map; + +/** Generated resource keys; text and locale selection live in Android resources. */ +final class LocalizationKeys { + static final Map IDS = new HashMap<>(); + static { + IDS.put(" · 已完成", R.string.text_58b6df1059088699); + IDS.put(" 传输失败", R.string.text_53af552fb3af7f6e); + IDS.put(" 台设备", R.string.text_23ebae95d26dfe5e); + IDS.put(" 条 · ", R.string.text_a7f4dfd234a43b16); + IDS.put(" 条未读", R.string.text_2c894057fc526576); + IDS.put("CrossDesk 远程连接", R.string.text_d0ac753c6681e578); + IDS.put("GNU GPL 第 3 版", R.string.text_0991c6fc1de4ffd6); + IDS.put("OpenFEC 告知", R.string.text_5ae7dc4079223967); + IDS.put("OpenFEC 许可与源码", R.string.text_69ad29820a259526); + IDS.put("P2P 直连", R.string.text_63ae4a0c7a448d21); + IDS.put("SRTP 已启用", R.string.text_70cae3c6aad8e152); + IDS.put("TURN 中继", R.string.text_ef813fec7d6d8a3b); + IDS.put("{0} 传输失败", R.string.text_ebede975edd52aee); + IDS.put("{0} 台设备", R.string.text_b3ffb6e982ecf5df); + IDS.put("{0} 条未读", R.string.text_fc66a78b9e27fecf); + IDS.put("{0},接收 {1},发送 {2},丢包率 {3}", R.string.text_dcb59cdcf66150a1); + IDS.put("● 已连接", R.string.text_01965b3249458d01); + IDS.put("下拉刷新", R.string.text_eb4236fe6a926a5a); + IDS.put("丢包率", R.string.text_37772187ab854191); + IDS.put("中", R.string.text_a567bdaa11367f26); + IDS.put("优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。", R.string.text_e6ff95a9fe6acc7f); + IDS.put("低", R.string.text_aa9e366f68d3d097); + IDS.put("使用自定义服务器", R.string.text_f03d03eb35e3330c); + IDS.put("保存密码", R.string.text_2e9f4819e064ce12); + IDS.put("保存收到的文件", R.string.text_10019cef593819ed); + IDS.put("保存远程画面预览", R.string.text_3bcdcd330bb3044c); + IDS.put("保存远程画面预览?", R.string.text_0f197074373e38fd); + IDS.put("信令连接中断,请重新连接", R.string.text_71ca53f95a8484da); + IDS.put("公告加载失败,请重试。", R.string.text_789f22a8b1b34797); + IDS.put("公告详情", R.string.text_00554b17c432937e); + IDS.put("共 ", R.string.text_2428420e407fe2e8); + IDS.put("共 {0} 条 · {1} 条未读", R.string.text_d977c7568cc5201e); + IDS.put("关于", R.string.text_52d25a9e30ba94f1); + IDS.put("关于 CrossDesk", R.string.text_459c1e980c1c8ce2); + IDS.put("关于,有新版本", R.string.text_390a95b65eb33052); + IDS.put("关闭", R.string.text_3fd47edce45b3603); + IDS.put("关闭控制栏", R.string.text_56a18c93e12fdc4e); + IDS.put("关闭隐私屏", R.string.text_4eb0565cc4658d7f); + IDS.put("兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。", R.string.text_7d466b69be42fc43); + IDS.put("分辨率", R.string.text_b92421822c213c2b); + IDS.put("删除", R.string.text_2f9daa828907b93f); + IDS.put("删除公告", R.string.text_0e46cdb3442edfba); + IDS.put("删除记录", R.string.text_f2cf9101bb2d8816); + IDS.put("删除这条公告?", R.string.text_d087671ca7df7f0f); + IDS.put("刷新公告", R.string.text_33e7584cd5c252d7); + IDS.put("剪贴板", R.string.text_8c10e2c1728ddf8e); + IDS.put("加载中…", R.string.text_4927a53bcc886afb); + IDS.put("加载更多", R.string.text_af90a08fec8ee28d); + IDS.put("升级提示", R.string.text_a739f24a9fd8a5d9); + IDS.put("原生连接初始化失败", R.string.text_861521c9e107c648); + IDS.put("发送", R.string.text_edecf0ae6e5144f9); + IDS.put("发送 ", R.string.text_43b7b60867ca51e7); + IDS.put("发送后,在远程键盘中点击“粘贴”。接收的远端文本可手动复制到本机。", R.string.text_da7df5a5543c4ba1); + IDS.put("发送文件", R.string.text_e7281fbca7af369c); + IDS.put("发送文本", R.string.text_ce6c02d19022e016); + IDS.put("取消", R.string.text_2cd0f3be8738a86c); + IDS.put("取消连接", R.string.text_3687f953cfe85fb8); + IDS.put("各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。", R.string.text_72814b15a6fa152c); + IDS.put("合计", R.string.text_e009c148d1890dac); + IDS.put("同意并继续", R.string.text_81c92013219dd115); + IDS.put("后台保持连接,点按返回远程桌面", R.string.text_409696774c9998ce); + IDS.put("后台保活未能启动,请保持应用在前台", R.string.text_dcb8d4e2e6973912); + IDS.put("后台保活未能启动,请保持应用在前台后重新连接", R.string.text_d96a21463557171d); + IDS.put("后台连接已结束,请重新连接", R.string.text_952f7300de0a7bd9); + IDS.put("后台连接服务已停止,请重新连接", R.string.text_da904f715e1cff87); + IDS.put("后续连接仍会保存新的预览图。", R.string.text_0812359e18082071); + IDS.put("在线", R.string.text_b9086662b1df1f20); + IDS.put("填写主机名或 IPv4 地址,不含协议和路径", R.string.text_39f2f444a042643e); + IDS.put("声音", R.string.text_473400815c0f687d); + IDS.put("复制远端文本", R.string.text_ab5ca1fab212f4ca); + IDS.put("始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。", R.string.text_c92269b2039e7aa3); + IDS.put("媒体加密", R.string.text_7ff73de85ec16d15); + IDS.put("字母数字", R.string.text_22dc6217af77bc37); + IDS.put("安全存储或证书初始化失败,请重试或清除应用数据", R.string.text_9ca1cdaf831182e3); + IDS.put("完成", R.string.text_c0b3fbff51ccc40b); + IDS.put("完成隐私授权后可检查更新", R.string.text_678328f6f02881c7); + IDS.put("完成隐私授权后登记本机身份", R.string.text_c4361f9abdba4882); + IDS.put("密码保存失败,本次连接仍可使用", R.string.text_c29b888e357d727d); + IDS.put("密码将加密保存在本机 Android Keystore 中", R.string.text_3f31300a23afb390); + IDS.put("对端 ID", R.string.text_8d3b052c4c67acda); + IDS.put("对端 ID ", R.string.text_0512084e130984bc); + IDS.put("对端 ID {0}", R.string.text_c5147d65960196b0); + IDS.put("将删除本机保存的所有远程预览图,保留连接记录和密码。", R.string.text_882b705d31ac7e2a); + IDS.put("屏幕方向", R.string.text_60cc99cc0013972e); + IDS.put("展开远程控制菜单", R.string.text_9e7294d264afecb7); + IDS.put("已从通知断开远程连接", R.string.text_9343612ee473edd6); + IDS.put("已保存密码", R.string.text_9d32476fe83aef60); + IDS.put("已保存密码无法读取,请重新输入", R.string.text_1cbd391383283924); + IDS.put("已保存的密码未能保留,请重新输入一次", R.string.text_6792b9f341380c68); + IDS.put("已发送 Ctrl+Alt+Del", R.string.text_74d3f0927d465047); + IDS.put("已启用后台保活,切换应用可继续保持连接", R.string.text_c28d86acbedba3b6); + IDS.put("已启用后台保活,可从连接通知返回或断开", R.string.text_506409ec08cb2a79); + IDS.put("已授权", R.string.text_521e65ffc7d0ff2d); + IDS.put("已读", R.string.text_efdd1a47e4beb2f9); + IDS.put("已连接 ", R.string.text_1f672b9b18d18e87); + IDS.put("已连接服务器", R.string.text_9c05d9d7fa1b0abd); + IDS.put("帧率", R.string.text_f9404bf335bc14cf); + IDS.put("帧率优先", R.string.text_9ae0c69e26db1d6a); + IDS.put("平衡", R.string.text_df544e46aa4d5c17); + IDS.put("应用中的许可文件缺失或损坏,请重新安装应用。", R.string.text_3362e8fa7f65cc2f); + IDS.put("开发版本包含尚未发布的修改,以下链接为基础版本源码。", R.string.text_3f2904435942cc0f); + IDS.put("开启保存", R.string.text_4338afaad52ea445); + IDS.put("开启隐私屏", R.string.text_c8bb8255390df3b6); + IDS.put("开源组件", R.string.text_c6ecaca362ae1c80); + IDS.put("开源软件权利说明", R.string.text_6099db946bdb5ee4); + IDS.put("当前已是最新版本", R.string.text_6e86570183c3cdd0); + IDS.put("当前远端不支持直接输入此文本,请使用支持文本输入的被控端版本,或通过剪贴板发送", R.string.text_24a52788cf474bf6); + IDS.put("成功连接后,这里会显示最近的远程设备。", R.string.text_33f25b500697a7d9); + IDS.put("我已阅读并同意《隐私政策》", R.string.text_70341256d7317e7d); + IDS.put("所选文件(无法读取或空间不足)", R.string.text_85c4c8fda0461f35); + IDS.put("找不到该设备 ID", R.string.text_9b58c9ff5f6a856f); + IDS.put("指令发送失败,请重试", R.string.text_97b7b18df07b9787); + IDS.put("指令已发送,等待电脑确认…", R.string.text_cb782027ca5986c7); + IDS.put("授权状态", R.string.text_3ca40a586103f6b7); + IDS.put("接收", R.string.text_6e684586884ebee6); + IDS.put("接收 ", R.string.text_84ae92e54e3078aa); + IDS.put("控制端解码器", R.string.text_d16488b987723161); + IDS.put("撤回", R.string.text_6b58198955259066); + IDS.put("撤回后将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。", R.string.text_c52e42ee856825db); + IDS.put("撤回联网授权", R.string.text_61f4788032ec596b); + IDS.put("撤回联网授权?", R.string.text_e736e419008ac10a); + IDS.put("收起远程控制菜单", R.string.text_73431dcf0afb7a65); + IDS.put("收起键盘", R.string.text_d826c4ece4dd4031); + IDS.put("收起鼠标", R.string.text_6e9a457c0c3c34ed); + IDS.put("数据", R.string.text_5440f7424f2865bf); + IDS.put("文件保存失败,请重试", R.string.text_94244f41d0a41378); + IDS.put("文件已保存", R.string.text_2553a785fef2a405); + IDS.put("文件选择已超时,会话已结束", R.string.text_d573b3f9a810ea04); + IDS.put("文本超过 128 KB", R.string.text_985a5c380be49f4f); + IDS.put("断开", R.string.text_f33ac04eece6a6a6); + IDS.put("断开后将返回首页", R.string.text_09b1395f50589327); + IDS.put("断开远程连接?", R.string.text_a73c0680db0d2e06); + IDS.put("断开连接", R.string.text_a33f3804768e68ee); + IDS.put("新版本", R.string.text_47ceaf502c5a05d6); + IDS.put("新版本可用:v", R.string.text_78823e6cf1a8afe5); + IDS.put("新版本可用:v{0}", R.string.text_b7e58b67fa8f7e78); + IDS.put("无未读公告", R.string.text_ef23787ec32c5588); + IDS.put("无法保存本地阅读状态,请重试。", R.string.text_dca2c418ac967366); + IDS.put("无法删除这条公告,请重试。", R.string.text_5c92da76360056cc); + IDS.put("无法发起远程连接", R.string.text_615709dd3129313c); + IDS.put("无法读取开源许可", R.string.text_a5c4f4ad79a640ae); + IDS.put("显示器", R.string.text_1a13ea5910a0c5e6); + IDS.put("显示密码", R.string.text_ffe21a671190323e); + IDS.put("暂不同意", R.string.text_a94460e8a04f04c5); + IDS.put("暂无公告", R.string.text_6d9a7758610a2432); + IDS.put("最近连接", R.string.text_0b290c6600d92f43); + IDS.put("服务器", R.string.text_2388cbc6a486af9f); + IDS.put("服务器 TLS 证书校验失败", R.string.text_dfe408e686175095); + IDS.put("服务器地址", R.string.text_d3716cc5a2f5a810); + IDS.put("服务器登录失败,请检查服务器地址和网络", R.string.text_2a9608d4465d0f70); + IDS.put("服务器端口", R.string.text_d270868960e68629); + IDS.put("服务器连接超时,请检查服务器地址和网络", R.string.text_7a4e4a6a1b479a52); + IDS.put("未启用", R.string.text_f95ea7f4c063eea7); + IDS.put("未找到可打开链接的浏览器", R.string.text_c8f7ed6f2186fb98); + IDS.put("未授权", R.string.text_94bc3d40defef3e9); + IDS.put("未读", R.string.text_4d0680f9efaef147); + IDS.put("未连接服务器 · 点击重试", R.string.text_d1fcb66a323a16f5); + IDS.put("本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", R.string.text_7eea7966c0b746c5); + IDS.put("本机 ID ", R.string.text_c611b4e50b0dbc08); + IDS.put("本机 ID {0}", R.string.text_97d10220f08dd7fc); + IDS.put("本版本源码与构建说明", R.string.text_91f15d505770d7a0); + IDS.put("本版本源码信息暂不可用。", R.string.text_5b2c8ca2c5a87241); + IDS.put("松开刷新", R.string.text_f0e274aa130e08a2); + IDS.put("构建说明", R.string.text_47077144715b7074); + IDS.put("构建配方与项目补丁", R.string.text_837ab2d0b2f4cb98); + IDS.put("查看源码", R.string.text_921c3b62f1f7d6f4); + IDS.put("检查失败,请稍后重试", R.string.text_fdd1059f10c4b979); + IDS.put("检查更新", R.string.text_7f68ebad19ba6bcd); + IDS.put("正在关闭隐私屏…", R.string.text_4f4d1e704e38c161); + IDS.put("正在建立安全连接…", R.string.text_2a05f6fbd3f4436e); + IDS.put("正在开启隐私屏…", R.string.text_0da575e3c92de73a); + IDS.put("正在检查更新…", R.string.text_91834aebecabcbc3); + IDS.put("正在清除…", R.string.text_0571a5f5f8ec4c83); + IDS.put("正在获取本机 ID…", R.string.text_0e6336c8fe918730); + IDS.put("正在读取所选文件…", R.string.text_faebd20c2801fd0f); + IDS.put("正在连接", R.string.text_694186911ae3e4da); + IDS.put("正在连接信令服务器…", R.string.text_c3ccc7f7d37533e3); + IDS.put("正在连接服务器…", R.string.text_4024d3c0f467a4f6); + IDS.put("正在重连服务器…", R.string.text_46fe1ef52ec3a10f); + IDS.put("此设备没有可用的文件选择器", R.string.text_4e4fce649fc00238); + IDS.put("清除", R.string.text_bce2377283c2455a); + IDS.put("清除预览图", R.string.text_ee0e76b8507212de); + IDS.put("清除预览图?", R.string.text_ecc809e44637de18); + IDS.put("源码与构建说明", R.string.text_2782e4485ad23d34); + IDS.put("源码版本", R.string.text_1f566fe8f8b718f3); + IDS.put("版本", R.string.text_5f76b2bf82dd2c5d); + IDS.put("版权与许可声明", R.string.text_16410ee9663fad10); + IDS.put("电脑键盘", R.string.text_11de77e1e41e680f); + IDS.put("画质优先", R.string.text_20f57900234debd7); + IDS.put("画面偏好", R.string.text_43b04aba53a54cf5); + IDS.put("画面延时", R.string.text_82a5600c470179fa); + IDS.put("画面设置", R.string.text_33b458faaf967e15); + IDS.put("画面质量", R.string.text_afb5acdf8f07fadb); + IDS.put("画面采集帧率", R.string.text_12b41b7a3fbcf8ca); + IDS.put("相对位置", R.string.text_66062971234f422d); + IDS.put("相对鼠标", R.string.text_c421dc051bea3f11); + IDS.put("知道了", R.string.text_de32e20193ad1042); + IDS.put("确定", R.string.text_fac2a67ad87807c4); + IDS.put("确认", R.string.text_36f33adaf0942634); + IDS.put("确认连接", R.string.text_a5b7fba4dbd8f622); + IDS.put("离线", R.string.text_be1b4f3c6c1cda1e); + IDS.put("空格", R.string.text_bfa4a6e0fe42ac28); + IDS.put("端口范围为 1–65535", R.string.text_471a579e8d87faac); + IDS.put("符号功能", R.string.text_c7d0c77862e32b52); + IDS.put("等待电脑返回隐私屏状态;旧版电脑端可能不支持", R.string.text_a562f07bd38c1a49); + IDS.put("等待远端屏幕信息", R.string.text_5ee880e2524a983a); + IDS.put("等待远端画面…", R.string.text_674c723a85ee7f57); + IDS.put("等待隐私授权", R.string.text_119f0483da4756c4); + IDS.put("系统键盘", R.string.text_7916071c1a8ee458); + IDS.put("绝对位置", R.string.text_02e9ba6fda719e2e); + IDS.put("绝对鼠标", R.string.text_8527c8c6d1ccc1ca); + IDS.put("网络状态", R.string.text_872428a7210d5e0c); + IDS.put("自定义", R.string.text_4eafa9e925b30bcd); + IDS.put("虚拟鼠标", R.string.text_dffd0c12b8f27247); + IDS.put("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", R.string.text_62c199f37bf95869); + IDS.put("被控端版本过低,请升级到最新版本。", R.string.text_a569ce729c1d6e19); + IDS.put("被控端编码器", R.string.text_d814476826827b78); + IDS.put("要发送到远端的文本", R.string.text_488402883e27f6f0); + IDS.put("视频", R.string.text_c20f7618d330a854); + IDS.put("许可", R.string.text_310c625425f014d8); + IDS.put("许可与版权声明", R.string.text_5c34f7d0e2124dca); + IDS.put("许可与版权声明可离线查阅。", R.string.text_e24134b643a17975); + IDS.put("设备身份保存失败,请检查安全存储", R.string.text_5e7628f043ce71d0); + IDS.put("设备身份及选择保存的访问密码使用 Android Keystore 加密。连接记录仅保存在本机,不纳入设备备份。剪贴板内容在结束会话时清除。离开应用后通过画中画或连接通知保持会话,可在应用或通知中断开。", R.string.text_5d35ee0d7945fcbc); + IDS.put("设置", R.string.text_df3d58c7d84b85f2); + IDS.put("设置,有新版本", R.string.text_4f8771952222a011); + IDS.put("访问密码", R.string.text_f4f712d5be91721a); + IDS.put("访问密码错误,请重新输入", R.string.text_dd6c465847af1b60); + IDS.put("证书校验失败 · 点击重试", R.string.text_defba1d2989bfab4); + IDS.put("请先完成联网授权", R.string.text_44f3d4d52347095a); + IDS.put("请在远端启用 CrossDesk 系统服务后重试", R.string.text_2a07ca002bc5093d); + IDS.put("请求超时,尚未确认电脑的隐私屏状态", R.string.text_990fd23c62de5ccf); + IDS.put("请等待当前文件发送完成", R.string.text_e5c8fa6dcf7b2a8b); + IDS.put("请输入 1–65535 范围内的端口", R.string.text_9305d9d72b06110d); + IDS.put("请输入 9 位设备 ID", R.string.text_3c7223dfb8dde5cf); + IDS.put("请输入有效访问密码", R.string.text_285a0714894d2899); + IDS.put("调整失败,请重试。", R.string.text_c808bb77ffd2b4cd); + IDS.put("软件许可", R.string.text_a762e7e650e285fa); + IDS.put("返回", R.string.text_572cf45ba43634b3); + IDS.put("返回控制栏", R.string.text_7565f94031582c7c); + IDS.put("还没有连接记录", R.string.text_55113b6925c362fd); + IDS.put("这条公告已更新或删除,请返回公告列表查看。", R.string.text_3aa527b2106cc987); + IDS.put("远程任务已关闭", R.string.text_e357aa9a0fb28c16); + IDS.put("远程桌面", R.string.text_c255841f68096d3b); + IDS.put("远程桌面触控区域", R.string.text_133f4c7dabd88b97); + IDS.put("远程桌面:轻触点击,拖动移动,长按右键,双指捏合缩放,放大后双指拖动画面,原始比例下双指上下滑动滚动", R.string.text_5931aeb3778f28f1); + IDS.put("远程电脑", R.string.text_3535087994d050de); + IDS.put("远程窗口已关闭,或后台保活未能启动,会话已结束", R.string.text_ed2e03072ce131de); + IDS.put("远程连接", R.string.text_678b783fb578172b); + IDS.put("远端密码错误", R.string.text_deccbd3eb9ba45f2); + IDS.put("远端已关闭连接", R.string.text_a2ce499295e358ae); + IDS.put("远端当前不可用", R.string.text_176e117df3ace734); + IDS.put("远端访问密码已失效,请重新连接", R.string.text_d2c0694243f93249); + IDS.put("连接", R.string.text_a5574109f0208e89); + IDS.put("连接 ", R.string.text_1d54bfbae5f8ac08); + IDS.put("连接失败", R.string.text_89c4766afc85125f); + IDS.put("连接失败 · 点击重试", R.string.text_04bf1a61ba1369f6); + IDS.put("连接已断开", R.string.text_2ab7d89557e779ab); + IDS.put("连接已结束", R.string.text_c1d20bf4c3e471c1); + IDS.put("连接延时(RTT)", R.string.text_e57d2cbc0e9908e6); + IDS.put("连接建立后可调整,需被控端支持。", R.string.text_db4d4f0fab78498a); + IDS.put("连接建立后锁定横屏", R.string.text_2123a9ed718f2c40); + IDS.put("连接提示", R.string.text_f741e0536210eafa); + IDS.put("连接方式", R.string.text_485a26050ce57431); + IDS.put("连接服务器", R.string.text_5a048351a77fe88d); + IDS.put("连接服务器后可获取最新公告。", R.string.text_5854c4add7ab0f7a); + IDS.put("连接超时,请检查设备 ID、服务器及远端在线状态", R.string.text_32cd27b5a72515f3); + IDS.put("连接远程桌面", R.string.text_6edc4b54cc1a9838); + IDS.put("退格", R.string.text_d5407b4f3c666681); + IDS.put("通知公告", R.string.text_e02926784fcedb91); + IDS.put("部分预览图未能清除,请重试。", R.string.text_465a092680d132b3); + IDS.put("重试", R.string.text_b8784c8dd5636ff2); + IDS.put("重试保存阅读状态", R.string.text_a504fb6f162bdb20); + IDS.put("锁定", R.string.text_ff9872a023e3a8aa); + IDS.put("键盘", R.string.text_864200bbb241e067); + IDS.put("阅读并授权", R.string.text_1f0f014d4177a0cc); + IDS.put("隐私", R.string.text_86651d17a401c55b); + IDS.put("隐私与授权", R.string.text_26c6e011e343708c); + IDS.put("隐私屏", R.string.text_6cad42fd3da85585); + IDS.put("隐私屏已关闭", R.string.text_e157fafb76aad954); + IDS.put("隐私屏已开启", R.string.text_bbef0eac0c04f214); + IDS.put("隐私屏已被解锁", R.string.text_0c7535f7c5e43b6f); + IDS.put("隐私屏异常", R.string.text_b62ac3dfb606c00b); + IDS.put("隐私屏暂不可用", R.string.text_598a2747dbd21dd5); + IDS.put("隐私屏状态已过期,等待电脑确认", R.string.text_4d59be3c75189032); + IDS.put("隐私屏状态待确认", R.string.text_1674532c70ed1db2); + IDS.put("隐私政策", R.string.text_e464b41fd5c45ba5); + IDS.put("隐私政策暂时无法读取,请拒绝联网并重新安装应用。", R.string.text_554e957e8e3c00af); + IDS.put("静音", R.string.text_7db2e189ecb01065); + IDS.put("音频", R.string.text_296c632ec857a0ba); + IDS.put("项目主页", R.string.text_0cadb49096a382e0); + IDS.put("预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。", R.string.text_3beca60bd0c654f7); + IDS.put("高", R.string.text_b1c27820fec23edb); + IDS.put("默认", R.string.text_844b8cc8dff7c1d8); + IDS.put("默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。", R.string.text_4db8737054f3b0cc); + IDS.put("鼠标右键,按住并拖动,松开结束拖拽", R.string.text_1184a97edd8e1646); + IDS.put("鼠标左键,按住并拖动,松开结束拖拽", R.string.text_926eaa3af0b5e48e); + IDS.put("鼠标控制", R.string.text_269f39a07b4a4e01); + IDS.put("鼠标滚轮,上下滑动,可滑出按键范围", R.string.text_cba62aeeb4a63a23); + IDS.put(",丢包率 ", R.string.text_9aa238fc6121dede); + IDS.put(",发送 ", R.string.text_0b5d16c21095fe10); + IDS.put(",已保存密码", R.string.text_ba9a792d063a8c86); + IDS.put(",接收 ", R.string.text_f4c1f9d7896760a7); + IDS.put(",点击重试", R.string.text_42237b5ec70c26f3); + } + private LocalizationKeys() {} +} diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/MainActivity.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/MainActivity.java index d3e7cc9e..74835269 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/MainActivity.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/MainActivity.java @@ -89,7 +89,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen private static final int PICK_FILE=41,SAVE_FILE=42; private NativeSession documentSession; private java.io.File receivedFile,documentToSave; - private final Runnable documentTimeout=()->{if(documentSession!=null&&!foreground)end("文件选择已超时,会话已结束");}; + private final Runnable documentTimeout=()->{if(documentSession!=null&&!foreground)end(L10n.tr("文件选择已超时,会话已结束"));}; private RemoteVideoSettings videoSettings=new RemoteVideoSettings(1); private final android.os.Handler mainHandler=new android.os.Handler(android.os.Looper.getMainLooper()); private Runnable videoSettingsTimeout; @@ -158,7 +158,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen } private LinearLayout navigation(String title,Runnable back){ LinearLayout bar=row();bar.setPadding(dp(12),0,dp(12),0);root.addView(bar,ui.size(-1,56)); - bar.addView(ui.iconButton("back","返回",this::navigateBack),ui.size(44,44)); + bar.addView(ui.iconButton("back",L10n.tr("返回"),this::navigateBack),ui.size(44,44)); TextView label=text(title,17,true);label.setGravity(Gravity.CENTER);label.setSingleLine();label.setEllipsize(TextUtils.TruncateAt.END);bar.addView(label,new LinearLayout.LayoutParams(0,-1,1)); bar.addView(new View(this),ui.size(44,44));backAction=back;return bar; } @@ -200,34 +200,34 @@ public final class MainActivity extends Activity implements NativeSession.Listen signalBadge=text("",12,true);signalBadge.setGravity(Gravity.CENTER);signalBadge.setPadding(dp(11),0,dp(11),0);signalBadge.setSingleLine(true); signalBadge.setOnClickListener(v->{ if(!preferences.getBoolean("networkConsent",false))consent(this::renderSignaling); - else if(signalState==1)toast("已连接 "+serverKey()); + else if(signalState==1)toast(L10n.tr("已连接 ")+serverKey()); else {stopSignaling();ensureSignaling();} });renderSignaling();toolbar.addView(signalBadge,ui.size(-2,34));toolbar.addView(new View(this),new LinearLayout.LayoutParams(0,1,1)); - FrameLayout announcementButton=(FrameLayout)ui.iconButton("envelope","通知公告",this::announcements);announcementButton.setClipChildren(false);toolbar.setClipChildren(false);toolbar.setClipToPadding(false); + FrameLayout announcementButton=(FrameLayout)ui.iconButton("envelope",L10n.tr("通知公告"),this::announcements);announcementButton.setClipChildren(false);toolbar.setClipChildren(false);toolbar.setClipToPadding(false); announcementBadge=text("",10,true);announcementBadge.setTextColor(Color.WHITE);announcementBadge.setGravity(Gravity.CENTER);announcementBadge.setMinWidth(dp(16));announcementBadge.setPadding(dp(4),0,dp(4),0);announcementBadge.setBackground(ui.background(RED,12));announcementBadge.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); FrameLayout.LayoutParams badgePosition=new FrameLayout.LayoutParams(-2,dp(16),Gravity.TOP|Gravity.END);badgePosition.topMargin=-dp(3);badgePosition.setMarginEnd(-dp(5));announcementButton.addView(announcementBadge,badgePosition);renderAnnouncements(); toolbar.addView(announcementButton,ui.size(40,40));View spacer=new View(this);toolbar.addView(spacer,ui.size(12,1)); - FrameLayout settingsButton=(FrameLayout)ui.iconButton("settings","设置",this::settings);settingsButton.setClipChildren(false);settingsUpdateButton=settingsButton; + FrameLayout settingsButton=(FrameLayout)ui.iconButton("settings",L10n.tr("设置"),this::settings);settingsButton.setClipChildren(false);settingsUpdateButton=settingsButton; TextView updateBadge=text("!",10,true);updateBadge.setTextColor(Color.WHITE);updateBadge.setGravity(Gravity.CENTER);updateBadge.setIncludeFontPadding(false);updateBadge.setBackground(ui.background(RED,8));updateBadge.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);settingsUpdateDot=updateBadge; FrameLayout.LayoutParams updatePosition=new FrameLayout.LayoutParams(dp(16),dp(16),Gravity.TOP|Gravity.END);updatePosition.topMargin=-dp(3);updatePosition.setMarginEnd(-dp(5));settingsButton.addView(settingsUpdateDot,updatePosition); toolbar.addView(settingsButton,ui.size(40,40));renderAppUpdates(); HomeLayout layout=new HomeLayout(ui);root.addView(layout,new LinearLayout.LayoutParams(-1,0,1));LinearLayout content=layout.panels; LinearLayout connection=column();connection.setPadding(dp(18),dp(18),dp(18),dp(18));content.addView(ui.shadowCard(connection,20)); - connection.addView(text("远程桌面",20,true));ui.gap(connection,16); + connection.addView(text(L10n.tr("远程桌面"),20,true));ui.gap(connection,16); LinearLayout entry=row();connection.addView(entry,ui.size(-1,54)); - remote=field("对端 ID",InputType.TYPE_CLASS_NUMBER);remote.setTextSize(20);remote.setTypeface(Typeface.create("sans-serif-medium",Typeface.NORMAL)); + remote=field(L10n.tr("对端 ID"),InputType.TYPE_CLASS_NUMBER);remote.setTextSize(20);remote.setTypeface(Typeface.create("sans-serif-medium",Typeface.NORMAL)); remote.setOnFocusChangeListener((view,focused)->{GradientDrawable shape=ui.background(BACKGROUND,12);shape.setStroke(dp(focused?2:1),focused?BLUE:LINE);remote.setBackground(shape);}); remote.setFilters(new InputFilter[]{new InputFilter.LengthFilter(11)});remote.setText(formatId(preferences.getString("lastRemote",""))); entry.addView(remote,new LinearLayout.LayoutParams(0,-1,1)); - TextView connect=ui.primary("连接",()->promptConnection(id()));connect.setContentDescription("连接");LinearLayout.LayoutParams buttonParams=ui.size(96,54);buttonParams.leftMargin=dp(10);entry.addView(connect,buttonParams); + TextView connect=ui.primary(L10n.tr("连接"),()->promptConnection(id()));connect.setContentDescription(L10n.tr("连接"));LinearLayout.LayoutParams buttonParams=ui.size(96,54);buttonParams.leftMargin=dp(10);entry.addView(connect,buttonParams); Runnable update=()->{connect.setEnabled(!id().isEmpty());connect.setAlpha(id().isEmpty()?.45f:1);};update.run(); remote.addTextChangedListener(new TextWatcher(){boolean editing;public void beforeTextChanged(CharSequence s,int start,int count,int after){}public void onTextChanged(CharSequence s,int start,int before,int count){update.run();}public void afterTextChanged(Editable value){if(editing)return;String formatted=formatId(value.toString());if(!formatted.equals(value.toString())){editing=true;int cursor=remote.getSelectionStart(),digits=value.subSequence(0,Math.max(0,cursor)).toString().replaceAll("[^0-9]","").length();remote.setText(formatted);remote.setSelection(Math.min(formatted.length(),digits+Math.max(0,digits-1)/3));editing=false;}}}); LinearLayout recent=column();recent.setPadding(dp(16),dp(16),dp(16),dp(16));ui.card(recent,18);LinearLayout.LayoutParams p=new LinearLayout.LayoutParams(-1,0,1);p.topMargin=dp(20);content.addView(recent,p); - JSONArray records=history.list(serverKey());recentPresence.watch(records,android.os.SystemClock.elapsedRealtime());LinearLayout heading=row();heading.addView(text("最近连接",20,true),new LinearLayout.LayoutParams(0,-2,1)); - if(records.length()>0){TextView count=text(records.length()+" 台设备",12,false);count.setTextColor(SECONDARY);heading.addView(count);}recent.addView(heading); + JSONArray records=history.list(serverKey());recentPresence.watch(records,android.os.SystemClock.elapsedRealtime());LinearLayout heading=row();heading.addView(text(L10n.tr("最近连接"),20,true),new LinearLayout.LayoutParams(0,-2,1)); + if(records.length()>0){TextView count=text(L10n.format("{0} 台设备",records.length()),12,false);count.setTextColor(SECONDARY);heading.addView(count);}recent.addView(heading); if(records.length()==0){ LinearLayout empty=column();empty.setGravity(Gravity.CENTER);recent.addView(empty,new LinearLayout.LayoutParams(-1,0,1));empty.addView(ui.icon("history",0xFFB6B6BB),ui.size(34,34));ui.gap(empty,12); - TextView emptyTitle=text("还没有连接记录",17,true);emptyTitle.setGravity(Gravity.CENTER);empty.addView(emptyTitle);ui.gap(empty,8);TextView hint=text("成功连接后,这里会显示最近的远程设备。",13,false);hint.setTextColor(SECONDARY);hint.setGravity(Gravity.CENTER);empty.addView(hint); + TextView emptyTitle=text(L10n.tr("还没有连接记录"),17,true);emptyTitle.setGravity(Gravity.CENTER);empty.addView(emptyTitle);ui.gap(empty,8);TextView hint=text(L10n.tr("成功连接后,这里会显示最近的远程设备。"),13,false);hint.setTextColor(SECONDARY);hint.setGravity(Gravity.CENTER);empty.addView(hint); }else{ ui.gap(recent,14);ScrollView scroll=new ScrollView(this);recent.addView(scroll,new LinearLayout.LayoutParams(-1,0,1));recentGrid=column();scroll.addView(recentGrid); recentGrid.addOnLayoutChangeListener((view,left,top,right,bottom,oldLeft,oldTop,oldRight,oldBottom)->{ @@ -243,7 +243,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen private void showConnectionMessage(){ if(pendingConnectionMessage.isEmpty()||!foreground||isFinishing()||isDestroyed())return; if(connectionDialog!=null)connectionDialog.dismiss(); - connectionDialog=new AlertDialog.Builder(this).setTitle("连接提示").setMessage(pendingConnectionMessage).setPositiveButton("确定",null).create(); + connectionDialog=new AlertDialog.Builder(this).setTitle(L10n.tr("连接提示")).setMessage(pendingConnectionMessage).setPositiveButton(L10n.tr("确定"),null).create(); connectionDialog.setOnDismissListener(dialog->connectionDialog=null); pendingConnectionMessage="";connectionDialog.show(); } @@ -259,27 +259,27 @@ public final class MainActivity extends Activity implements NativeSession.Listen if(item==null)return new View(this);String id=item.optString("id"),platform=item.optString("platform"); LinearLayout card=column();ui.card(card,14);FrameLayout preview=new FrameLayout(this){@Override protected void onMeasure(int w,int h){super.onMeasure(w,MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(w)*9/16,MeasureSpec.EXACTLY));}}; int color=platform.equals("windows")?0xFF316AB7:platform.equals("macos")?0xFF8057B9:platform.equals("linux")?0xFFAE642B:0xFF677587;preview.setBackgroundColor(color); - TextView label=text(platform.equals("windows")?"Windows":platform.equals("macos")?"macOS":platform.equals("linux")?"Linux":"远程电脑",19,true);label.setGravity(Gravity.CENTER);label.setTextColor(Color.WHITE);preview.addView(label,new FrameLayout.LayoutParams(-1,-1));card.addView(preview,ui.size(-1,80)); + TextView label=text(platform.equals("windows")?"Windows":platform.equals("macos")?"macOS":platform.equals("linux")?"Linux":L10n.tr("远程电脑"),19,true);label.setGravity(Gravity.CENTER);label.setTextColor(Color.WHITE);preview.addView(label,new FrameLayout.LayoutParams(-1,-1));card.addView(preview,ui.size(-1,80)); ImageView image=new ImageView(this);image.setScaleType(ImageView.ScaleType.CENTER_CROP);image.setVisibility(View.GONE);image.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);preview.addView(image,new FrameLayout.LayoutParams(-1,-1)); String server=serverKey();Runnable load=()->{if(!image.isAttachedToWindow())return;Object binding=new Object();image.setTag(binding);image.setImageDrawable(null);image.setVisibility(View.GONE);label.setVisibility(View.VISIBLE); previews.load(server,id,bitmap->{if(image.getTag()!=binding||!image.isAttachedToWindow()){if(bitmap!=null)bitmap.recycle();return;}if(bitmap!=null){image.setImageBitmap(bitmap);image.setVisibility(View.VISIBLE);label.setVisibility(View.GONE);}});};previewCards.add(load);image.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener(){public void onViewAttachedToWindow(View view){load.run();}public void onViewDetachedFromWindow(View view){image.setTag(null);}});if(image.isAttachedToWindow())load.run(); LinearLayout caption=column();caption.setPadding(dp(9),dp(9),dp(9),dp(9));TextView name=text(item.optString("name",id),12,true);name.setSingleLine();name.setEllipsize(TextUtils.TruncateAt.END);caption.addView(name);ui.gap(caption,4); LinearLayout details=row();TextView detail=text("ID "+id,10,false);detail.setTypeface(Typeface.create("sans-serif",Typeface.NORMAL));detail.setTextColor(SECONDARY);detail.setSingleLine();detail.setEllipsize(TextUtils.TruncateAt.END);details.addView(detail,new LinearLayout.LayoutParams(0,-2,1)); - if(item.optBoolean("remember")){View key=ui.icon("key",SECONDARY);key.setContentDescription("已保存密码");LinearLayout.LayoutParams keySize=ui.size(10,10);keySize.leftMargin=dp(4);details.addView(key,keySize);} - boolean online=recentPresence.isOnline(id,android.os.SystemClock.elapsedRealtime());String availability=online?"在线":"离线";TextView presence=text(availability,10,true);presence.setSingleLine();presence.setTextColor(online?GREEN:SECONDARY);LinearLayout.LayoutParams presenceSize=ui.size(-2,-2);presenceSize.leftMargin=dp(5);details.addView(presence,presenceSize);caption.addView(details);card.addView(caption); - card.setContentDescription("连接 "+item.optString("name",id)+",ID "+id+(item.optBoolean("remember")?",已保存密码":"")+","+availability);card.setClickable(true);card.setFocusable(true);card.setOnClickListener(v->{remote.setText(formatId(id));promptConnection(id);}); - card.setOnLongClickListener(v->{new AlertDialog.Builder(this).setTitle(item.optString("name",id)).setItems(new String[]{"连接","删除记录"},(d,w)->{if(w==0)promptConnection(id);else{history.delete(serverKey(),id);home("");}}).show();return true;});return card; + if(item.optBoolean("remember")){View key=ui.icon("key",SECONDARY);key.setContentDescription(L10n.tr("已保存密码"));LinearLayout.LayoutParams keySize=ui.size(10,10);keySize.leftMargin=dp(4);details.addView(key,keySize);} + boolean online=recentPresence.isOnline(id,android.os.SystemClock.elapsedRealtime());String availability=online?L10n.tr("在线"):L10n.tr("离线");TextView presence=text(availability,10,true);presence.setSingleLine();presence.setTextColor(online?GREEN:SECONDARY);LinearLayout.LayoutParams presenceSize=ui.size(-2,-2);presenceSize.leftMargin=dp(5);details.addView(presence,presenceSize);caption.addView(details);card.addView(caption); + card.setContentDescription(L10n.tr("连接 ")+item.optString("name",id)+",ID "+id+(item.optBoolean("remember")?L10n.tr(",已保存密码"):"")+","+availability);card.setClickable(true);card.setFocusable(true);card.setOnClickListener(v->{remote.setText(formatId(id));promptConnection(id);}); + card.setOnLongClickListener(v->{new AlertDialog.Builder(this).setTitle(item.optString("name",id)).setItems(new String[]{L10n.tr("连接"),L10n.tr("删除记录")},(d,w)->{if(w==0)promptConnection(id);else{history.delete(serverKey(),id);home("");}}).show();return true;});return card; } private void promptConnection(String id){ - hideKeyboard();if(!id.matches("[0-9]{9}")){remote.setError("请输入 9 位设备 ID");remote.requestFocus();return;} + hideKeyboard();if(!id.matches("[0-9]{9}")){remote.setError(L10n.tr("请输入 9 位设备 ID"));remote.requestFocus();return;} if(!preferences.getBoolean("networkConsent",false)){consent(()->connectOrPrompt(id));return;}connectOrPrompt(id); } private void connectOrPrompt(String id){ String stored; - try{stored=history.password(serverKey(),id);}catch(Exception error){passwordSheet(id,"已保存密码无法读取,请重新输入",true);return;} + try{stored=history.password(serverKey(),id);}catch(Exception error){passwordSheet(id,L10n.tr("已保存密码无法读取,请重新输入"),true);return;} if(!stored.isEmpty()){rememberPassword=true;begin(id,stored);return;} boolean remember=history.remembersPassword(serverKey(),id); - passwordSheet(id,remember?"已保存的密码未能保留,请重新输入一次":"",remember); + passwordSheet(id,remember?L10n.tr("已保存的密码未能保留,请重新输入一次"):"",remember); } private void consent(Runnable accepted){ if(privacyDialog!=null&&privacyDialog.isShowing())return; @@ -291,15 +291,15 @@ public final class MainActivity extends Activity implements NativeSession.Listen private void passwordSheet(String id,String error,boolean rememberDefault){ Dialog dialog=new Dialog(this);passwordDialog=dialog;LinearLayout sheet=column();sheet.setPadding(dp(22),dp(10),dp(22),dp(22));sheet.setBackground(ui.background(BACKGROUND,24)); View handle=new View(this);handle.setBackground(ui.background(0xFFC6C6CB,3));LinearLayout.LayoutParams hp=ui.size(36,5);hp.gravity=Gravity.CENTER;sheet.addView(handle,hp);ui.gap(sheet,20); - LinearLayout header=row(),titles=column();titles.addView(text("连接远程桌面",22,true));ui.gap(titles,5);TextView subtitle=text("对端 ID "+id,15,false);subtitle.setTextColor(SECONDARY);titles.addView(subtitle);header.addView(titles,new LinearLayout.LayoutParams(0,-2,1));header.addView(ui.iconButton("close","关闭",dialog::dismiss),ui.size(36,36));sheet.addView(header);ui.gap(sheet,18); - LinearLayout passwordRow=row();ui.card(passwordRow,10);EditText password=field("访问密码",InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_PASSWORD);password.setBackgroundColor(Color.TRANSPARENT);passwordRow.addView(password,new LinearLayout.LayoutParams(0,dp(50),1)); - View eye=ui.iconButton("eye","显示密码",()->{boolean hidden=password.getTransformationMethod()!=null;password.setTransformationMethod(hidden?null:PasswordTransformationMethod.getInstance());password.setSelection(password.length());});passwordRow.addView(eye,ui.size(44,44));sheet.addView(passwordRow);ui.gap(sheet,18); - LinearLayout save=row(),saveText=column();saveText.addView(text("保存密码",15,true));ui.gap(saveText,3);TextView security=text("密码将加密保存在本机 Android Keystore 中",11,false);security.setTextColor(SECONDARY);saveText.addView(security);save.addView(saveText,new LinearLayout.LayoutParams(0,-2,1));Switch remember=new Switch(this);remember.setContentDescription("保存密码");save.addView(remember);sheet.addView(save); + LinearLayout header=row(),titles=column();titles.addView(text(L10n.tr("连接远程桌面"),22,true));ui.gap(titles,5);TextView subtitle=text(L10n.format("对端 ID {0}",id),15,false);subtitle.setTextColor(SECONDARY);titles.addView(subtitle);header.addView(titles,new LinearLayout.LayoutParams(0,-2,1));header.addView(ui.iconButton("close",L10n.tr("关闭"),dialog::dismiss),ui.size(36,36));sheet.addView(header);ui.gap(sheet,18); + LinearLayout passwordRow=row();ui.card(passwordRow,10);EditText password=field(L10n.tr("访问密码"),InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_PASSWORD);password.setBackgroundColor(Color.TRANSPARENT);passwordRow.addView(password,new LinearLayout.LayoutParams(0,dp(50),1)); + View eye=ui.iconButton("eye",L10n.tr("显示密码"),()->{boolean hidden=password.getTransformationMethod()!=null;password.setTransformationMethod(hidden?null:PasswordTransformationMethod.getInstance());password.setSelection(password.length());});passwordRow.addView(eye,ui.size(44,44));sheet.addView(passwordRow);ui.gap(sheet,18); + LinearLayout save=row(),saveText=column();saveText.addView(text(L10n.tr("保存密码"),15,true));ui.gap(saveText,3);TextView security=text(L10n.tr("密码将加密保存在本机 Android Keystore 中"),11,false);security.setTextColor(SECONDARY);saveText.addView(security);save.addView(saveText,new LinearLayout.LayoutParams(0,-2,1));Switch remember=new Switch(this);remember.setContentDescription(L10n.tr("保存密码"));save.addView(remember);sheet.addView(save); remember.setChecked(rememberDefault); - ui.gap(sheet,18);TextView connect=ui.primary("连接",()->{ - String secret=password.getText().toString();if(secret.isEmpty()||secret.length()>128||secret.contains("@")){password.setError("请输入有效访问密码");return;} + ui.gap(sheet,18);TextView connect=ui.primary(L10n.tr("连接"),()->{ + String secret=password.getText().toString();if(secret.isEmpty()||secret.length()>128||secret.contains("@")){password.setError(L10n.tr("请输入有效访问密码"));return;} rememberPassword=remember.isChecked();password.setText("");dialog.dismiss();begin(id,secret); - });connect.setContentDescription("确认连接");sheet.addView(connect,ui.size(-1,48)); + });connect.setContentDescription(L10n.tr("确认连接"));sheet.addView(connect,ui.size(-1,48)); ScrollView scroll=new ScrollView(this);scroll.addView(sheet); dialog.setContentView(scroll);Window window=dialog.getWindow();if(window!=null){window.setBackgroundDrawableResource(android.R.color.transparent);window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);window.setDimAmount(.22f);}dialog.show();sizePasswordDialog();password.requestFocus();if(!error.isEmpty())password.setError(error); dialog.setOnDismissListener(d->{password.setText("");passwordDialog=null;}); @@ -319,12 +319,12 @@ public final class MainActivity extends Activity implements NativeSession.Listen previewCapture=previews.begin(serverKey(),id);previewCopying=false;previewAttempts=0; connectedRemote=id;pendingPassword=rememberPassword?secret:"";ready=false;muted=false;selectedDisplay=0;hostPlatform="";remoteClipboard="";displays=new JSONArray();preferences.edit().putString("lastRemote",id).apply(); ensureSignaling(); - if(signaling==null){pendingPassword="";toast("请先完成联网授权");return;} + if(signaling==null){pendingPassword="";toast(L10n.tr("请先完成联网授权"));return;} session=signaling;showProgress();session.connect(id,secret); } private void showProgress(){ Dialog dialog=new Dialog(this);progressDialog=dialog;LinearLayout card=column();ui.card(card,24);card.setGravity(Gravity.CENTER_HORIZONTAL);LinearLayout body=column();body.setGravity(Gravity.CENTER);body.setPadding(dp(26),dp(24),dp(26),dp(20)); - ProgressBar spinner=new ProgressBar(this);spinner.setIndeterminateTintList(ColorStateList.valueOf(BLUE));body.addView(spinner,ui.size(34,34));ui.gap(body,14);TextView title=text("正在连接",20,true);title.setGravity(Gravity.CENTER);body.addView(title);ui.gap(body,6);status=text("正在连接信令服务器…",14,false);status.setGravity(Gravity.CENTER);status.setTextColor(SECONDARY);status.setMinHeight(dp(36));body.addView(status);card.addView(body,ui.size(-1,-2));ui.divider(card);card.addView(ui.action("取消连接",RED,()->end("")),ui.size(-1,46)); + ProgressBar spinner=new ProgressBar(this);spinner.setIndeterminateTintList(ColorStateList.valueOf(BLUE));body.addView(spinner,ui.size(34,34));ui.gap(body,14);TextView title=text(L10n.tr("正在连接"),20,true);title.setGravity(Gravity.CENTER);body.addView(title);ui.gap(body,6);status=text(L10n.tr("正在连接信令服务器…"),14,false);status.setGravity(Gravity.CENTER);status.setTextColor(SECONDARY);status.setMinHeight(dp(36));body.addView(status);card.addView(body,ui.size(-1,-2));ui.divider(card);card.addView(ui.action(L10n.tr("取消连接"),RED,()->end("")),ui.size(-1,46)); dialog.setContentView(card);dialog.setCanceledOnTouchOutside(false);dialog.setOnCancelListener(d->end(""));Window w=dialog.getWindow();if(w!=null){w.setBackgroundDrawableResource(android.R.color.transparent);w.setDimAmount(.08f);}dialog.show();if(w!=null)w.setLayout(dp(292),-2); } private void sessionScreen(boolean autoLandscape){ @@ -349,7 +349,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen }); pictureInPicture.connected();updatePictureInPicture(); } - private void confirmDisconnect(){disconnectDialog=new AlertDialog.Builder(this).setTitle("断开远程连接?").setMessage("断开后将返回首页").setNegativeButton("取消",null).setPositiveButton("断开连接",(d,w)->end("")).show();} + private void confirmDisconnect(){disconnectDialog=new AlertDialog.Builder(this).setTitle(L10n.tr("断开远程连接?")).setMessage(L10n.tr("断开后将返回首页")).setNegativeButton(L10n.tr("取消"),null).setPositiveButton(L10n.tr("断开连接"),(d,w)->end("")).show();} private void end(String reason){ dismissPrivacyUnlockDialog(); remoteOrientation.end(); @@ -367,48 +367,48 @@ public final class MainActivity extends Activity implements NativeSession.Listen appUpdates.checkNow(); } private void settings(){ - LinearLayout content=formPage("settings","设置",()->home("")); - LinearLayout mouse=section(content,"鼠标控制",MobileUi.SETTINGS_CARD_RADIUS);mouse.setPadding(dp(12),dp(12),dp(12),dp(12));boolean relative=preferences.getBoolean("relativeMouse",true); - mouse.addView(segments(new String[]{"相对位置","绝对位置"},relative?0:1,true,index->preferences.edit().putBoolean("relativeMouse",index==0).apply())); - LinearLayout picture=section(content,"画面偏好",MobileUi.SETTINGS_CARD_RADIUS);picture.setPadding(dp(12),dp(12),dp(12),dp(12));int preference=Math.max(0,Math.min(2,preferences.getInt("videoPreference",1))); - picture.addView(segments(RemoteVideoSettings.PREFERENCES,preference,true,index->preferences.edit().putInt("videoPreference",index).apply()));ui.gap(content,28); - LinearLayout direction=section(content,"屏幕方向",MobileUi.SETTINGS_CARD_RADIUS);LinearLayout directionRow=row();directionRow.setPadding(dp(16),dp(10),dp(16),dp(10));directionRow.addView(text("连接建立后锁定横屏",16,false),new LinearLayout.LayoutParams(0,-2,1)); - Switch autoLandscape=new Switch(this);autoLandscape.setContentDescription("连接建立后锁定横屏");autoLandscape.setChecked(preferences.getBoolean("autoLandscape",false));autoLandscape.setOnCheckedChangeListener((button,checked)->preferences.edit().putBoolean("autoLandscape",checked).apply());directionRow.addView(autoLandscape);direction.addView(directionRow); - footer(content,"默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。"); + LinearLayout content=formPage("settings",L10n.tr("设置"),()->home("")); + LinearLayout mouse=section(content,L10n.tr("鼠标控制"),MobileUi.SETTINGS_CARD_RADIUS);mouse.setPadding(dp(12),dp(12),dp(12),dp(12));boolean relative=preferences.getBoolean("relativeMouse",true); + mouse.addView(segments(new String[]{L10n.tr("相对位置"),L10n.tr("绝对位置")},relative?0:1,true,index->preferences.edit().putBoolean("relativeMouse",index==0).apply())); + LinearLayout picture=section(content,L10n.tr("画面偏好"),MobileUi.SETTINGS_CARD_RADIUS);picture.setPadding(dp(12),dp(12),dp(12),dp(12));int preference=Math.max(0,Math.min(2,preferences.getInt("videoPreference",1))); + picture.addView(segments(RemoteVideoSettings.preferences(),preference,true,index->preferences.edit().putInt("videoPreference",index).apply()));ui.gap(content,28); + LinearLayout direction=section(content,L10n.tr("屏幕方向"),MobileUi.SETTINGS_CARD_RADIUS);LinearLayout directionRow=row();directionRow.setPadding(dp(16),dp(10),dp(16),dp(10));directionRow.addView(text(L10n.tr("连接建立后锁定横屏"),16,false),new LinearLayout.LayoutParams(0,-2,1)); + Switch autoLandscape=new Switch(this);autoLandscape.setContentDescription(L10n.tr("连接建立后锁定横屏"));autoLandscape.setChecked(preferences.getBoolean("autoLandscape",false));autoLandscape.setOnCheckedChangeListener((button,checked)->preferences.edit().putBoolean("autoLandscape",checked).apply());directionRow.addView(autoLandscape);direction.addView(directionRow); + footer(content,L10n.tr("默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。")); LinearLayout server=section(content,"",MobileUi.SETTINGS_CARD_RADIUS);LinearLayout fields=column();fields.setVisibility(View.GONE);boolean custom=!host.equals("api.crossdesk.cn")||port!=9099; - link(server,"服务器",custom?"自定义":"默认",()->fields.setVisibility(fields.getVisibility()==View.VISIBLE?View.GONE:View.VISIBLE));server.addView(fields); - LinearLayout toggleRow=row();toggleRow.setPadding(dp(16),dp(8),dp(16),dp(8));toggleRow.addView(text("使用自定义服务器",16,false),new LinearLayout.LayoutParams(0,-2,1));Switch toggle=new Switch(this);toggle.setContentDescription("使用自定义服务器");toggle.setChecked(custom);toggleRow.addView(toggle);fields.addView(toggleRow); - LinearLayout inputs=column();inputs.setPadding(dp(12),0,dp(12),dp(12));EditText address=field("服务器地址",InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_URI),number=field("服务器端口",InputType.TYPE_CLASS_NUMBER);address.setText(custom?host:"");number.setText(custom?String.valueOf(port):"");inputs.addView(address,ui.size(-1,48));ui.gap(inputs,8);inputs.addView(number,ui.size(-1,48));ui.gap(inputs,8); - inputs.addView(ui.action("完成",BLUE,()->{if(saveServer(address,number)){hideKeyboard();settings();}}));fields.addView(inputs);inputs.setVisibility(custom?View.VISIBLE:View.GONE); + link(server,L10n.tr("服务器"),custom?L10n.tr("自定义"):L10n.tr("默认"),()->fields.setVisibility(fields.getVisibility()==View.VISIBLE?View.GONE:View.VISIBLE));server.addView(fields); + LinearLayout toggleRow=row();toggleRow.setPadding(dp(16),dp(8),dp(16),dp(8));toggleRow.addView(text(L10n.tr("使用自定义服务器"),16,false),new LinearLayout.LayoutParams(0,-2,1));Switch toggle=new Switch(this);toggle.setContentDescription(L10n.tr("使用自定义服务器"));toggle.setChecked(custom);toggleRow.addView(toggle);fields.addView(toggleRow); + LinearLayout inputs=column();inputs.setPadding(dp(12),0,dp(12),dp(12));EditText address=field(L10n.tr("服务器地址"),InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_URI),number=field(L10n.tr("服务器端口"),InputType.TYPE_CLASS_NUMBER);address.setText(custom?host:"");number.setText(custom?String.valueOf(port):"");inputs.addView(address,ui.size(-1,48));ui.gap(inputs,8);inputs.addView(number,ui.size(-1,48));ui.gap(inputs,8); + inputs.addView(ui.action(L10n.tr("完成"),BLUE,()->{if(saveServer(address,number)){hideKeyboard();settings();}}));fields.addView(inputs);inputs.setVisibility(custom?View.VISIBLE:View.GONE); toggle.setOnCheckedChangeListener((button,checked)->{inputs.setVisibility(checked?View.VISIBLE:View.GONE);if(!checked){host="api.crossdesk.cn";port=9099;preferences.edit().putString("host",host).putInt("port",port).apply();ensureSignaling();} }); backAction=()->{if(toggle.isChecked()&&!saveServer(address,number))return;hideKeyboard();home("");}; identitySummary=text("",12,false);identitySummary.setTextColor(SECONDARY);identitySummary.setGravity(Gravity.CENTER);identitySummary.setPadding(dp(16),dp(12),dp(16),dp(16));identitySummary.setTextIsSelectable(true);content.addView(identitySummary);renderSignaling(); - LinearLayout privacy=section(content,"隐私",MobileUi.SETTINGS_CARD_RADIUS);link(privacy,"隐私与授权",preferences.getBoolean("networkConsent",false)?"已授权":"未授权",this::privacyPage);ui.divider(privacy); - LinearLayout preview=row();preview.setPadding(dp(16),dp(10),dp(16),dp(10));preview.addView(text("保存远程画面预览",16,false),new LinearLayout.LayoutParams(0,-2,1));previewSwitch=new Switch(this);previewSwitch.setContentDescription("保存远程画面预览");preview.addView(previewSwitch);privacy.addView(preview); + LinearLayout privacy=section(content,L10n.tr("隐私"),MobileUi.SETTINGS_CARD_RADIUS);link(privacy,L10n.tr("隐私与授权"),preferences.getBoolean("networkConsent",false)?L10n.tr("已授权"):L10n.tr("未授权"),this::privacyPage);ui.divider(privacy); + LinearLayout preview=row();preview.setPadding(dp(16),dp(10),dp(16),dp(10));preview.addView(text(L10n.tr("保存远程画面预览"),16,false),new LinearLayout.LayoutParams(0,-2,1));previewSwitch=new Switch(this);previewSwitch.setContentDescription(L10n.tr("保存远程画面预览"));preview.addView(previewSwitch);privacy.addView(preview); previewSwitch.setOnCheckedChangeListener((button,checked)->{if(updatingPreviewSwitch)return;if(checked){renderPreviews();confirmPreviewSaving();}else previews.setEnabled(false);}); - ui.divider(privacy);clearPreviewsButton=ui.action("清除预览图",RED,this::confirmClearPreviews);clearPreviewsButton.setGravity(Gravity.START|Gravity.CENTER_VERTICAL);clearPreviewsButton.setTypeface(Typeface.DEFAULT);clearPreviewsButton.setPadding(dp(16),0,dp(16),0);privacy.addView(clearPreviewsButton,ui.size(-1,48)); + ui.divider(privacy);clearPreviewsButton=ui.action(L10n.tr("清除预览图"),RED,this::confirmClearPreviews);clearPreviewsButton.setGravity(Gravity.START|Gravity.CENTER_VERTICAL);clearPreviewsButton.setTypeface(Typeface.DEFAULT);clearPreviewsButton.setPadding(dp(16),0,dp(16),0);privacy.addView(clearPreviewsButton,ui.size(-1,48)); previewCleanupError=text("",12,false);previewCleanupError.setTextColor(RED);previewCleanupError.setPadding(dp(16),dp(8),dp(16),dp(12));privacy.addView(previewCleanupError);renderPreviews(); - ui.gap(content,28);LinearLayout about=section(content,"",MobileUi.SETTINGS_CARD_RADIUS);LinearLayout aboutLink=link(about,"关于","新版本",this::about);aboutUpdateRow=aboutLink; + ui.gap(content,28);LinearLayout about=section(content,"",MobileUi.SETTINGS_CARD_RADIUS);LinearLayout aboutLink=link(about,L10n.tr("关于"),L10n.tr("新版本"),this::about);aboutUpdateRow=aboutLink; aboutUpdateLabel=(TextView)aboutLink.getChildAt(1);aboutUpdateLabel.setPadding(0,0,dp(8),0); aboutUpdateDot=updateDot();LinearLayout.LayoutParams dotPosition=new LinearLayout.LayoutParams(dp(8),dp(8));dotPosition.setMarginEnd(dp(8));aboutLink.addView(aboutUpdateDot,2,dotPosition);renderAppUpdates(); } private void confirmPreviewSaving(){ - previewDialog=new AlertDialog.Builder(this).setTitle("保存远程画面预览?") - .setMessage("预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。") - .setNegativeButton("取消",null).setPositiveButton("开启保存",(d,w)->previews.setEnabled(true)).show(); + previewDialog=new AlertDialog.Builder(this).setTitle(L10n.tr("保存远程画面预览?")) + .setMessage(L10n.tr("预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。")) + .setNegativeButton(L10n.tr("取消"),null).setPositiveButton(L10n.tr("开启保存"),(d,w)->previews.setEnabled(true)).show(); previewDialog.setOnDismissListener(d->{previewDialog=null;renderPreviews();}); } private void confirmClearPreviews(){ - previewDialog=new AlertDialog.Builder(this).setTitle("清除预览图?") - .setMessage("将删除本机保存的所有远程预览图,保留连接记录和密码。"+(previews.enabled()?"后续连接仍会保存新的预览图。":"")) - .setNegativeButton("取消",null).setPositiveButton("清除",(d,w)->previews.clear()).show(); + previewDialog=new AlertDialog.Builder(this).setTitle(L10n.tr("清除预览图?")) + .setMessage(L10n.tr("将删除本机保存的所有远程预览图,保留连接记录和密码。")+(previews.enabled()?L10n.tr("后续连接仍会保存新的预览图。"):"")) + .setNegativeButton(L10n.tr("取消"),null).setPositiveButton(L10n.tr("清除"),(d,w)->previews.clear()).show(); previewDialog.setOnDismissListener(d->previewDialog=null); } private void renderPreviews(){ if(previews==null)return; if(!previews.enabled()||previews.cleaning)previewCapture=null; if(previewSwitch!=null){updatingPreviewSwitch=true;previewSwitch.setChecked(previews.enabled());previewSwitch.setEnabled(preferences.getBoolean("networkConsent",false)&&!previews.cleaning);updatingPreviewSwitch=false;} - if(clearPreviewsButton!=null){clearPreviewsButton.setText(previews.cleaning?"正在清除…":"清除预览图");clearPreviewsButton.setEnabled(!previews.cleaning);} + if(clearPreviewsButton!=null){clearPreviewsButton.setText(previews.cleaning?L10n.tr("正在清除…"):L10n.tr("清除预览图"));clearPreviewsButton.setEnabled(!previews.cleaning);} if(previewCleanupError!=null){previewCleanupError.setText(previews.cleanupError);previewCleanupError.setVisibility(previews.cleanupError.isEmpty()?View.GONE:View.VISIBLE);} for(Runnable card:previewCards)card.run(); } @@ -427,17 +427,17 @@ public final class MainActivity extends Activity implements NativeSession.Listen return new SegmentedControl(ui,titles,selected,enabled,changed); } private boolean saveServer(EditText address,EditText number){ - String name=address.getText().toString().trim();int value;try{value=Integer.parseInt(number.getText().toString());}catch(NumberFormatException e){number.setError("请输入 1–65535 范围内的端口");return false;} - if(name.length()>253||!name.matches("[A-Za-z0-9.-]+")||name.startsWith(".")||name.endsWith(".")){address.setError("填写主机名或 IPv4 地址,不含协议和路径");return false;}if(value<1||value>65535){number.setError("端口范围为 1–65535");return false;}host=name;port=value;preferences.edit().putString("host",host).putInt("port",port).apply();ensureSignaling();return true; + String name=address.getText().toString().trim();int value;try{value=Integer.parseInt(number.getText().toString());}catch(NumberFormatException e){number.setError(L10n.tr("请输入 1–65535 范围内的端口"));return false;} + if(name.length()>253||!name.matches("[A-Za-z0-9.-]+")||name.startsWith(".")||name.endsWith(".")){address.setError(L10n.tr("填写主机名或 IPv4 地址,不含协议和路径"));return false;}if(value<1||value>65535){number.setError(L10n.tr("端口范围为 1–65535"));return false;}host=name;port=value;preferences.edit().putString("host",host).putInt("port",port).apply();ensureSignaling();return true; } private void announcements(){ - installRoot("announcements",false);LinearLayout bar=navigation("通知公告",()->home("")); - bar.removeViewAt(bar.getChildCount()-1);announcementRefresh=ui.iconButton("refresh","刷新公告",announcementInbox::refresh);bar.addView(announcementRefresh,ui.size(44,44)); + installRoot("announcements",false);LinearLayout bar=navigation(L10n.tr("通知公告"),()->home("")); + bar.removeViewAt(bar.getChildCount()-1);announcementRefresh=ui.iconButton("refresh",L10n.tr("刷新公告"),announcementInbox::refresh);bar.addView(announcementRefresh,ui.size(44,44)); announcementView=new AnnouncementView(ui,announcementInbox,null,this::announcementDetail,this::connectAnnouncements); root.addView(announcementView,new LinearLayout.LayoutParams(-1,0,1));announcementInbox.refresh();renderAnnouncements(); } private void announcementDetail(AnnouncementInbox.Item item){ - installRoot("announcement-detail",false);navigation("公告详情",this::announcements); + installRoot("announcement-detail",false);navigation(L10n.tr("公告详情"),this::announcements); announcementView=new AnnouncementView(ui,announcementInbox,item,this::announcementDetail,this::connectAnnouncements); root.addView(announcementView,new LinearLayout.LayoutParams(-1,0,1));announcementInbox.markRead(item); } @@ -447,7 +447,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen } private void renderAnnouncements(){ if(announcementBadge!=null){int unread=announcementInbox.unread;announcementBadge.setText(unread>99?"99+":String.valueOf(unread));announcementBadge.setVisibility(unread>0?View.VISIBLE:View.GONE); - if(android.os.Build.VERSION.SDK_INT>=30)((View)announcementBadge.getParent()).setStateDescription(unread>0?unread+" 条未读":"无未读公告");} + if(android.os.Build.VERSION.SDK_INT>=30)((View)announcementBadge.getParent()).setStateDescription(unread>0?L10n.format("{0} 条未读",unread):L10n.tr("无未读公告"));} if(announcementRefresh!=null){boolean enabled=announcementInbox.isConnected()&&!announcementInbox.loading;announcementRefresh.setEnabled(enabled);announcementRefresh.setAlpha(enabled?1:.4f);} if(announcementView!=null)announcementView.render(); } @@ -457,12 +457,12 @@ public final class MainActivity extends Activity implements NativeSession.Listen } @Override public void announcementFailed(String requestId){announcementInbox.failed(requestId);} private void privacyPage(){ - LinearLayout content=formPage("privacy","隐私与授权",this::settings);LinearLayout card=section(content,"");boolean consent=preferences.getBoolean("networkConsent",false);link(card,"授权状态",consent?"已授权":"未授权",()->{});ui.divider(card);link(card,"隐私政策","",this::privacyPolicyPage); - footer(content,"设备身份及选择保存的访问密码使用 Android Keystore 加密。连接记录仅保存在本机,不纳入设备备份。剪贴板内容在结束会话时清除。离开应用后通过画中画或连接通知保持会话,可在应用或通知中断开。"); - if(consent)content.addView(ui.action("撤回联网授权",RED,()->new AlertDialog.Builder(this).setTitle("撤回联网授权?").setMessage("撤回后将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。").setNegativeButton("取消",null).setPositiveButton("撤回",(d,w)->{preferences.edit().putBoolean("networkConsent",false).apply();appUpdates.setEnabled(false);previews.setEnabled(false);stopSignaling();announcementInbox.reset();privacyPage();}).show()));else content.addView(ui.primary("阅读并授权",()->consent(this::privacyPage))); + LinearLayout content=formPage("privacy",L10n.tr("隐私与授权"),this::settings);LinearLayout card=section(content,"");boolean consent=preferences.getBoolean("networkConsent",false);link(card,L10n.tr("授权状态"),consent?L10n.tr("已授权"):L10n.tr("未授权"),()->{});ui.divider(card);link(card,L10n.tr("隐私政策"),"",this::privacyPolicyPage); + footer(content,L10n.tr("设备身份及选择保存的访问密码使用 Android Keystore 加密。连接记录仅保存在本机,不纳入设备备份。剪贴板内容在结束会话时清除。离开应用后通过画中画或连接通知保持会话,可在应用或通知中断开。")); + if(consent)content.addView(ui.action(L10n.tr("撤回联网授权"),RED,()->new AlertDialog.Builder(this).setTitle(L10n.tr("撤回联网授权?")).setMessage(L10n.tr("撤回后将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。")).setNegativeButton(L10n.tr("取消"),null).setPositiveButton(L10n.tr("撤回"),(d,w)->{preferences.edit().putBoolean("networkConsent",false).apply();appUpdates.setEnabled(false);previews.setEnabled(false);stopSignaling();announcementInbox.reset();privacyPage();}).show()));else content.addView(ui.primary(L10n.tr("阅读并授权"),()->consent(this::privacyPage))); } private void privacyPolicyPage(){ - installRoot("privacy-policy",false);navigation("隐私政策",this::privacyPage); + installRoot("privacy-policy",false);navigation(L10n.tr("隐私政策"),this::privacyPage); root.addView(new PrivacyPolicyDocument(this).view(ui),new LinearLayout.LayoutParams(-1,0,1)); } String applicationVersion(){ @@ -479,8 +479,8 @@ public final class MainActivity extends Activity implements NativeSession.Listen if(settingsUpdateDot!=null)settingsUpdateDot.setVisibility(available?View.VISIBLE:View.GONE); if(aboutUpdateDot!=null)aboutUpdateDot.setVisibility(available?View.VISIBLE:View.GONE); if(aboutUpdateLabel!=null)aboutUpdateLabel.setVisibility(available?View.VISIBLE:View.GONE); - if(settingsUpdateButton!=null)settingsUpdateButton.setContentDescription(available?"设置,有新版本":"设置"); - if(aboutUpdateRow!=null)aboutUpdateRow.setContentDescription(available?"关于,有新版本":"关于"); + if(settingsUpdateButton!=null)settingsUpdateButton.setContentDescription(available?L10n.tr("设置,有新版本"):L10n.tr("设置")); + if(aboutUpdateRow!=null)aboutUpdateRow.setContentDescription(available?L10n.tr("关于,有新版本"):L10n.tr("关于")); if(aboutPages!=null&&page.equals("about"))aboutPages.renderUpdates(); } private void about(){ @@ -490,16 +490,16 @@ public final class MainActivity extends Activity implements NativeSession.Listen private boolean sendTextEdit(int count,String value){ if(session==null)return false; if(session.textEdit(count,value))return true; - toast("当前远端不支持直接输入此文本,请使用支持文本输入的被控端版本,或通过剪贴板发送");return false; + toast(L10n.tr("当前远端不支持直接输入此文本,请使用支持文本输入的被控端版本,或通过剪贴板发送"));return false; } private void tapKey(int code){if(session!=null){session.key(code,true);session.key(code,false);}} private void shortcut(int code){if(session!=null){int modifier=hostPlatform.equals("macos")?0x5B:0x11;session.key(modifier,true);tapKey(code);session.key(modifier,false);}} private void selectDisplay(){ - if(!ready)return;int count=Math.min(displays.length(),8);if(count==0){toast("等待远端屏幕信息");return;}String[] labels=new String[count];for(int i=0;i{if(session!=null){if(w!=selectedDisplay&&video!=null)video.resetViewport();selectedDisplay=w;session.control(4,w);if(controls!=null)controls.resetVideoStatistics();}}).show(); + if(!ready)return;int count=Math.min(displays.length(),8);if(count==0){toast(L10n.tr("等待远端屏幕信息"));return;}String[] labels=new String[count];for(int i=0;i{if(session!=null){if(w!=selectedDisplay&&video!=null)video.resetViewport();selectedDisplay=w;session.control(4,w);if(controls!=null)controls.resetVideoStatistics();}}).show(); } private void secureAttention(){ if(!ready||session==null||!hostPlatform.equals("windows"))return; - if(!remoteServiceAvailable){controlFeedback("请在远端启用 CrossDesk 系统服务后重试");return;} + if(!remoteServiceAvailable){controlFeedback(L10n.tr("请在远端启用 CrossDesk 系统服务后重试"));return;} session.secureAttention(); } private void chooseFile(){ @@ -516,7 +516,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen documentSession=session;releaseKeys(); pictureInPicture.choosingDocument(true);updatePictureInPicture(); try{startActivityForResult(intent,request);mainHandler.postDelayed(documentTimeout,5*60*1000);} - catch(android.content.ActivityNotFoundException error){documentSession=null;documentToSave=null;pictureInPicture.choosingDocument(false);updatePictureInPicture();controlFeedback("此设备没有可用的文件选择器");} + catch(android.content.ActivityNotFoundException error){documentSession=null;documentToSave=null;pictureInPicture.choosingDocument(false);updatePictureInPicture();controlFeedback(L10n.tr("此设备没有可用的文件选择器"));} } @Override protected void onActivityResult(int request,int result,Intent data){ super.onActivityResult(request,result,data); @@ -530,7 +530,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen @Override public void fileTransfer(String name,double progress,boolean sending,java.io.File received){ if(!ready)return; if(received!=null)receivedFile=received; - String fileStatus=progress<0?name+" 传输失败":(sending?"发送 ":"接收 ")+name+(progress>=1?" · 已完成":" · "+(int)(progress*100)+"%"); + String fileStatus=progress<0?L10n.format("{0} 传输失败",name):(sending?L10n.tr("发送 "):L10n.tr("接收 "))+name+(progress>=1?L10n.tr(" · 已完成"):" · "+(int)(progress*100)+"%"); if(controls!=null)controls.fileStatus(fileStatus,receivedFile!=null); if(progress<0||progress>=1)toast(fileStatus); } @@ -539,14 +539,14 @@ public final class MainActivity extends Activity implements NativeSession.Listen } private void clipboard(){ if(!ready)return; - EditText input=field("要发送到远端的文本",InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_MULTI_LINE);input.setSingleLine(false);input.setMinLines(3); - new AlertDialog.Builder(this).setTitle("剪贴板").setView(input) - .setMessage("发送后,在远程键盘中点击“粘贴”。接收的远端文本可手动复制到本机。") - .setNegativeButton("关闭",null).setNeutralButton("复制远端文本",(d,w)->{ + EditText input=field(L10n.tr("要发送到远端的文本"),InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_MULTI_LINE);input.setSingleLine(false);input.setMinLines(3); + new AlertDialog.Builder(this).setTitle(L10n.tr("剪贴板")).setView(input) + .setMessage(L10n.tr("发送后,在远程键盘中点击“粘贴”。接收的远端文本可手动复制到本机。")) + .setNegativeButton(L10n.tr("关闭"),null).setNeutralButton(L10n.tr("复制远端文本"),(d,w)->{ if(!remoteClipboard.isEmpty())((ClipboardManager)getSystemService(CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("CrossDesk",remoteClipboard)); - }).setPositiveButton("发送文本",(d,w)->{ + }).setPositiveButton(L10n.tr("发送文本"),(d,w)->{ String value=input.getText().toString(); - if(value.getBytes(java.nio.charset.StandardCharsets.UTF_8).length>128*1024){Toast.makeText(this,"文本超过 128 KB",Toast.LENGTH_SHORT).show();return;} + if(value.getBytes(java.nio.charset.StandardCharsets.UTF_8).length>128*1024){Toast.makeText(this,L10n.tr("文本超过 128 KB"),Toast.LENGTH_SHORT).show();return;} if(session!=null)session.clipboard(value); }).show(); } @@ -581,17 +581,17 @@ public final class MainActivity extends Activity implements NativeSession.Listen boolean consent=preferences.getBoolean("networkConsent",false); boolean connected=consent&&signalError.isEmpty()&&signalState==1; String label;int tint,background; - if(!consent){label="等待隐私授权";tint=0xFFB76A00;background=0xFFFFEBD2;} - else if(!signalError.isEmpty()){label=signalError.contains("TLS")?"证书校验失败 · 点击重试":"连接失败 · 点击重试";tint=RED;background=0xFFFFE8E6;} - else if(connected){label="已连接服务器";tint=GREEN;background=0xFFE5F4E8;} - else{label=signalState==0?"正在连接服务器…":signalState==4?"正在重连服务器…":"未连接服务器 · 点击重试";tint=0xFFB76A00;background=0xFFFFEBD2;} + if(!consent){label=L10n.tr("等待隐私授权");tint=0xFFB76A00;background=0xFFFFEBD2;} + else if(!signalError.isEmpty()){label=signalError.contains("TLS")?L10n.tr("证书校验失败 · 点击重试"):L10n.tr("连接失败 · 点击重试");tint=RED;background=0xFFFFE8E6;} + else if(connected){label=L10n.tr("已连接服务器");tint=GREEN;background=0xFFE5F4E8;} + else{label=signalState==0?L10n.tr("正在连接服务器…"):signalState==4?L10n.tr("正在重连服务器…"):L10n.tr("未连接服务器 · 点击重试");tint=0xFFB76A00;background=0xFFFFEBD2;} if(signalBadge!=null){ android.graphics.drawable.Drawable icon=connected?getDrawable(R.drawable.ic_check_circle):null; if(icon!=null){int size=dp(14);icon.setBounds(0,0,size,size);} signalBadge.setCompoundDrawablesRelative(icon,null,null,null);signalBadge.setCompoundDrawablePadding(dp(6)); - signalBadge.setText(label);signalBadge.setTextColor(tint);signalBadge.setBackground(ui.background(background,20));signalBadge.setContentDescription(signalError.isEmpty()?label:signalError+",点击重试"); + signalBadge.setText(label);signalBadge.setTextColor(tint);signalBadge.setBackground(ui.background(background,20));signalBadge.setContentDescription(signalError.isEmpty()?label:signalError+L10n.tr(",点击重试")); } - if(identitySummary!=null)identitySummary.setText(!consent?"完成隐私授权后登记本机身份":!localIdentity.isEmpty()?"本机 ID "+localIdentity:!signalError.isEmpty()?signalError:"正在获取本机 ID…"); + if(identitySummary!=null)identitySummary.setText(!consent?L10n.tr("完成隐私授权后登记本机身份"):!localIdentity.isEmpty()?L10n.format("本机 ID {0}",localIdentity):!signalError.isEmpty()?signalError:L10n.tr("正在获取本机 ID…")); } @Override public void signaling(int state,String deviceId){ signalState=state;localIdentity=deviceId;signalError="";renderSignaling(); @@ -606,7 +606,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen // Transport readiness can be reported again after ICE changes its selected path. // The first success consumes pendingPassword; a duplicate must not save it again. if(session==null||ready)return;ready=true;if(progressDialog!=null){progressDialog.dismiss();progressDialog=null;} - try{history.save(serverKey(),connectedRemote,connectedRemote,hostPlatform,rememberPassword,pendingPassword);}catch(Exception error){toast("密码保存失败,本次连接仍可使用");}pendingPassword="";sessionScreen(preferences.getBoolean("autoLandscape",false)); + try{history.save(serverKey(),connectedRemote,connectedRemote,hostPlatform,rememberPassword,pendingPassword);}catch(Exception error){toast(L10n.tr("密码保存失败,本次连接仍可使用"));}pendingPassword="";sessionScreen(preferences.getBoolean("autoLandscape",false)); if(!canUsePictureInPicture())prepareBackgroundSession(true); if(videoSettings.supported&&videoSettings.requestId==0)updateVideoSettings(videoSettings.selection); if(foreground&&preferences.getBoolean("networkConsent",false))remoteVersionCheck.connected(); @@ -620,12 +620,12 @@ public final class MainActivity extends Activity implements NativeSession.Listen String id=connectedRemote;boolean remember=rememberPassword; end(""); // Let the user replace an expired credential; never retry it automatically. - if(foreground)passwordSheet(id,"访问密码错误,请重新输入",remember); + if(foreground)passwordSheet(id,L10n.tr("访问密码错误,请重新输入"),remember); } private void cancelVideoSettingsTimeout(){if(videoSettingsTimeout!=null)mainHandler.removeCallbacks(videoSettingsTimeout);videoSettingsTimeout=null;} private void showRemoteUpdate(){ if(!ready||session==null||!foreground||pictureInPictureUi||isInPictureInPictureMode()||isFinishing()||!preferences.getBoolean("networkConsent",false))return; - remoteUpdateDialog=new AlertDialog.Builder(this).setTitle("升级提示").setMessage(RemoteVersionCheck.NOTICE).setPositiveButton("知道了",null).create(); + remoteUpdateDialog=new AlertDialog.Builder(this).setTitle(L10n.tr("升级提示")).setMessage(L10n.tr(RemoteVersionCheck.NOTICE)).setPositiveButton(L10n.tr("知道了"),null).create(); remoteUpdateDialog.setOnDismissListener(dialog->remoteUpdateDialog=null); remoteUpdateDialog.setCanceledOnTouchOutside(false); remoteUpdateDialog.show(); @@ -673,12 +673,12 @@ public final class MainActivity extends Activity implements NativeSession.Listen releaseKeys(); if (controls != null) { controls.closeKeyboard(); controls.cancelMouseInput(); } if (video != null) video.releaseMouse(); - privacyUnlockDialog = new AlertDialog.Builder(this).setTitle("隐私屏已被解锁") - .setMessage("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。") - .setNegativeButton("确认", (dialog, which) -> { + privacyUnlockDialog = new AlertDialog.Builder(this).setTitle(L10n.tr("隐私屏已被解锁")) + .setMessage(L10n.tr("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。")) + .setNegativeButton(L10n.tr("确认"), (dialog, which) -> { if (session != null) session.privacyScreen.unlockNotice = false; dismissPrivacyUnlockDialog(); - }).setPositiveButton("锁定", null).create(); + }).setPositiveButton(L10n.tr("锁定"), null).create(); privacyUnlockDialog.setCancelable(false); privacyUnlockDialog.show(); privacyUnlockDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(view -> { @@ -686,7 +686,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen }); } String feedback = session.privacyScreen.feedback(android.os.SystemClock.elapsedRealtime()); - privacyUnlockDialog.setMessage("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" + privacyUnlockDialog.setMessage(L10n.tr("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。") + (feedback.isEmpty() ? "" : "\n\n" + feedback)); privacyUnlockDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled( session.privacyScreen.canLock(android.os.SystemClock.elapsedRealtime())); @@ -744,10 +744,10 @@ public final class MainActivity extends Activity implements NativeSession.Listen backgroundSession=retained;captureBackgroundSession();retained.attach(this);session.setListener(retained); if(!RemoteSessionService.retain(this,retained)){ session.setListener(this);retained.detach(this);backgroundSession=null; - if(inform)toast("后台保活未能启动,请保持应用在前台");return false; + if(inform)toast(L10n.tr("后台保活未能启动,请保持应用在前台"));return false; } if(inform){ - toast("已启用后台保活,可从连接通知返回或断开"); + toast(L10n.tr("已启用后台保活,可从连接通知返回或断开")); requestBackgroundNotifications(); } return true; @@ -762,7 +762,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen BackgroundSession retained=backgroundSession!=null?backgroundSession:RemoteSessionService.current(); if(retained==null)return false; if(retained.ended||retained.session.isClosed()||!hasNetworkConsent()||!host.equals(retained.host)||port!=retained.port){ - retained.detach(this);retained.finish("后台连接已结束,请重新连接");backgroundSession=null; + retained.detach(this);retained.finish(L10n.tr("后台连接已结束,请重新连接"));backgroundSession=null; if(session==retained.session)end(retained.endReason);return false; } boolean rebuild=session!=retained.session||video==null||!page.equals("session"); @@ -832,7 +832,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen mainHandler.removeCallbacks(presenceTick);recentPresence.setConnected(false,android.os.SystemClock.elapsedRealtime());announcementInbox.setConnected(false); cancelVideoSettingsTimeout();if(videoSettings.pending)videoSettings.expire(videoSettings.requestId); resetRemoteVersionCheck();if(disconnectDialog!=null)disconnectDialog.dismiss(); - }else if(documentSession==null||documentSession!=session||isFinishing()){if(session!=null)end(isFinishing()?"":"远程窗口已关闭,或后台保活未能启动,会话已结束");stopSignaling();} + }else if(documentSession==null||documentSession!=session||isFinishing()){if(session!=null)end(isFinishing()?"":L10n.tr("远程窗口已关闭,或后台保活未能启动,会话已结束"));stopSignaling();} super.onStop();} @Override protected void onDestroy(){dismissPrivacyUnlockDialog();mainHandler.removeCallbacks(documentTimeout);documentSession=null;documentToSave=null;appUpdates.setEnabled(false);pageHost.finish();resetRemoteVersionCheck();cancelVideoSettingsTimeout();previews.removeListener(previewChanged);if(privacyDialog!=null)privacyDialog.dismiss();if(previewDialog!=null)previewDialog.dismiss();announcementInbox.close();if(disconnectDialog!=null)disconnectDialog.dismiss();if(passwordDialog!=null)passwordDialog.dismiss();if(progressDialog!=null)progressDialog.dismiss(); if(connectionDialog!=null)connectionDialog.dismiss(); diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/MobileUi.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/MobileUi.java index b4a37efe..0e193097 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/MobileUi.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/MobileUi.java @@ -52,6 +52,7 @@ final class MobileUi { } TextView primary(String title,Runnable click) { TextView v=action(title,Color.WHITE,click); + v.setMaxLines(2);v.setAutoSizeTextTypeUniformWithConfiguration(11,16,1,android.util.TypedValue.COMPLEX_UNIT_SP); GradientDrawable gradient=new GradientDrawable(GradientDrawable.Orientation.TL_BR,new int[]{BLUE,0xFF1F61C7});gradient.setCornerRadius(dp(12));v.setBackground(gradient);return v; } View iconButton(String icon,String label,Runnable click) { diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/NativeSession.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/NativeSession.java index fbdbdbec..8003c9e0 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/NativeSession.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/NativeSession.java @@ -35,7 +35,7 @@ final class NativeSession implements AutoCloseable { default void presence(JSONObject message) { } default void announcement(JSONObject message) { } default void announcementFailed(String requestId) { } - default void passwordRejected() { ended("远端密码错误"); } + default void passwordRejected() { ended(L10n.tr("远端密码错误")); } } // Serializes all peer creation/API calls/destruction, including across activities. private static final ExecutorService RTC = Executors.newSingleThreadExecutor(r -> new Thread(r, "CrossDesk RTC")); @@ -71,8 +71,8 @@ final class NativeSession implements AutoCloseable { if(!closed)main.postDelayed(this,1000); }}; private final Runnable timeout = () -> fail(remote.isEmpty() - ? "服务器连接超时,请检查服务器地址和网络" - : "连接超时,请检查设备 ID、服务器及远端在线状态"); + ? L10n.tr("服务器连接超时,请检查服务器地址和网络") + : L10n.tr("连接超时,请检查设备 ID、服务器及远端在线状态")); NativeSession(Context context, String host, int port, String remote, String password, Listener listener) { this.context = context.getApplicationContext(); this.listener = listener; @@ -92,10 +92,10 @@ final class NativeSession implements AutoCloseable { File logs = new File(context.getNoBackupFilesDir(), "logs"); if (!logs.isDirectory() && !logs.mkdirs()) throw new IllegalStateException("Log directory unavailable"); handle = nCreate(this, host, port, identity, logs.getAbsolutePath(), certificates.getAbsolutePath()); - if (handle == 0) { fail("原生连接初始化失败"); return; } + if (handle == 0) { fail(L10n.tr("原生连接初始化失败")); return; } nFileDirectory(handle,new File(documents.directory,"received").getAbsolutePath()); if (surface != null && surface.isValid()) nSurface(handle, surface); - } catch (Exception error) { fail("安全存储或证书初始化失败,请重试或清除应用数据"); } + } catch (Exception error) { fail(L10n.tr("安全存储或证书初始化失败,请重试或清除应用数据")); } }); } /** Promote the already registered identity peer to an outgoing desktop session. */ @@ -147,7 +147,7 @@ final class NativeSession implements AutoCloseable { if (handle == 0 || joining || remote.isEmpty() || !signalReady || identity.isEmpty()) return; joining = true; String base = identity.split("@", 2)[0]; - if (!nConnect(handle, base, remote, password)) fail("无法发起远程连接"); + if (!nConnect(handle, base, remote, password)) fail(L10n.tr("无法发起远程连接")); password = ""; } // Called on arbitrary native callback threads; borrowed payloads were copied by JNI. @@ -175,10 +175,10 @@ final class NativeSession implements AutoCloseable { publishSignaling(); tryJoin(); } - if (status == 6) fail("服务器 TLS 证书校验失败"); - else if (status == 2) fail("服务器登录失败,请检查服务器地址和网络"); - else if (status >= 3 && connected) fail("信令连接中断,请重新连接"); - else if (status == 0 || status == 4) ui(() -> listener.status("正在连接信令服务器…")); + if (status == 6) fail(L10n.tr("服务器 TLS 证书校验失败")); + else if (status == 2) fail(L10n.tr("服务器登录失败,请检查服务器地址和网络")); + else if (status >= 3 && connected) fail(L10n.tr("信令连接中断,请重新连接")); + else if (status == 0 || status == 4) ui(() -> listener.status(L10n.tr("正在连接信令服务器…"))); } else if (type == 2) { int status = event.getInt("status"); if (status == 1) { @@ -187,12 +187,12 @@ final class NativeSession implements AutoCloseable { audio = new AudioPlayer(); nControl(handle, 2, 1); ui(() -> { listener.connected(); if(!closed){statisticsTick.run();fileTick.run();} }); - } else if (status == 0 || status == 2) ui(() -> listener.status("正在建立安全连接…")); + } else if (status == 0 || status == 2) ui(() -> listener.status(L10n.tr("正在建立安全连接…"))); else if (status == 6) ui(() -> { listener.passwordRejected(); close(); }); else { - String[] reasons = {"", "", "", "连接已断开", "连接失败", "远端已关闭连接", - "远端密码错误", "找不到该设备 ID", "远端当前不可用"}; - fail(status >= 0 && status < reasons.length ? reasons[status] : "连接已结束"); + String[] reasons = {"", "", "", L10n.tr("连接已断开"), L10n.tr("连接失败"), L10n.tr("远端已关闭连接"), + L10n.tr("远端密码错误"), L10n.tr("找不到该设备 ID"), L10n.tr("远端当前不可用")}; + fail(status >= 0 && status < reasons.length ? reasons[status] : L10n.tr("连接已结束")); } } else if (type == 4) { if(event.optInt("type",-1)==14){ @@ -228,7 +228,7 @@ final class NativeSession implements AutoCloseable { listener.fileTransfer(name,progress,sending,path.isEmpty()?null:new File(path));}); } } catch (Exception error) { - if (type == 3) fail("设备身份保存失败,请检查安全存储"); + if (type == 3) fail(L10n.tr("设备身份保存失败,请检查安全存储")); } }); } @@ -303,24 +303,24 @@ final class NativeSession implements AutoCloseable { } void secureAttention(){execute(()->{ boolean sent=connected&&nSecureAttention(handle); - ui(()->listener.controlFeedback(sent?"已发送 Ctrl+Alt+Del":"指令发送失败,请重试")); + ui(()->listener.controlFeedback(sent?L10n.tr("已发送 Ctrl+Alt+Del"):L10n.tr("指令发送失败,请重试"))); });} void sendFile(android.net.Uri uri){ if(closed)return; - if(sendingFile){listener.controlFeedback("请等待当前文件发送完成");return;} - sendingFile=true;listener.fileTransfer("正在读取所选文件…",0,true,null); + if(sendingFile){listener.controlFeedback(L10n.tr("请等待当前文件发送完成"));return;} + sendingFile=true;listener.fileTransfer(L10n.tr("正在读取所选文件…"),0,true,null); documents.prepare(uri,new SessionDocuments.Prepared(){ public void ready(File file,String name){execute(()->{ if(!connected||!nSendFile(handle,file.getAbsolutePath(),name.getBytes(StandardCharsets.UTF_8))){ file.delete();ui(()->{sendingFile=false;listener.fileTransfer(name,-1,true,null);}); } });} - public void failed(){ui(()->{sendingFile=false;listener.fileTransfer("所选文件(无法读取或空间不足)",-1,true,null);});} + public void failed(){ui(()->{sendingFile=false;listener.fileTransfer(L10n.tr("所选文件(无法读取或空间不足)"),-1,true,null);});} }); } void saveFile(File file,android.net.Uri destination){ if(closed)return; - documents.save(file,destination,success->ui(()->listener.controlFeedback(success?"文件已保存":"文件保存失败,请重试"))); + documents.save(file,destination,success->ui(()->listener.controlFeedback(success?L10n.tr("文件已保存"):L10n.tr("文件保存失败,请重试")))); } @Override public void close() { if (closed) return; diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyConsentDialog.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyConsentDialog.java index c08f753b..485f3d5e 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyConsentDialog.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyConsentDialog.java @@ -20,16 +20,16 @@ final class PrivacyConsentDialog extends Dialog { PrivacyConsentDialog(Activity activity,MobileUi ui,PrivacyPolicyDocument policy,Runnable accepted){ super(activity);this.activity=activity;this.ui=ui;requestWindowFeature(Window.FEATURE_NO_TITLE);setCancelable(false);setCanceledOnTouchOutside(false); LinearLayout sheet=ui.column();sheet.setBackground(ui.background(android.graphics.Color.WHITE,20));sheet.setClipToOutline(true); - TextView title=ui.text("隐私政策",17,true);title.setGravity(Gravity.CENTER);sheet.addView(title,ui.size(-1,56));ui.divider(sheet); + TextView title=ui.text(L10n.tr("隐私政策"),17,true);title.setGravity(Gravity.CENTER);sheet.addView(title,ui.size(-1,56));ui.divider(sheet); sheet.addView(policy.view(ui),new LinearLayout.LayoutParams(-1,0,1));ui.divider(sheet); LinearLayout actions=ui.column();actions.setPadding(ui.dp(20),ui.dp(12),ui.dp(20),ui.dp(12));sheet.addView(actions); - CheckBox hasReadPolicy=new CheckBox(activity);hasReadPolicy.setText("我已阅读并同意《隐私政策》");hasReadPolicy.setTextColor(INK);hasReadPolicy.setTextSize(14);hasReadPolicy.setMinHeight(ui.dp(44));actions.addView(hasReadPolicy,ui.size(-1,-2));ui.gap(actions,12); - TextView agree=ui.primary("同意并继续",()->{ + CheckBox hasReadPolicy=new CheckBox(activity);hasReadPolicy.setText(L10n.tr("我已阅读并同意《隐私政策》"));hasReadPolicy.setTextColor(INK);hasReadPolicy.setTextSize(14);hasReadPolicy.setMinHeight(ui.dp(44));actions.addView(hasReadPolicy,ui.size(-1,-2));ui.gap(actions,12); + TextView agree=ui.primary(L10n.tr("同意并继续"),()->{ if(!hasReadPolicy.isChecked()||!policy.available)return; dismiss();accepted.run(); });agree.setEnabled(false);agree.setAlpha(.45f);actions.addView(agree,ui.size(-1,48)); hasReadPolicy.setOnCheckedChangeListener((button,checked)->{boolean enabled=checked&&policy.available;agree.setEnabled(enabled);agree.setAlpha(enabled?1:.45f);}); - ui.gap(actions,12);actions.addView(ui.action("暂不同意",SECONDARY,this::dismiss),ui.size(-1,44)); + ui.gap(actions,12);actions.addView(ui.action(L10n.tr("暂不同意"),SECONDARY,this::dismiss),ui.size(-1,44)); setContentView(sheet);Window window=getWindow();if(window!=null){window.setBackgroundDrawableResource(android.R.color.transparent);window.setDimAmount(.22f);} } @Override public void show(){ diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyPolicyDocument.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyPolicyDocument.java index 3f0a7710..6aebe291 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyPolicyDocument.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/PrivacyPolicyDocument.java @@ -13,12 +13,14 @@ final class PrivacyPolicyDocument { final boolean available; final String text; - PrivacyPolicyDocument(Context context){this(load(context));} - PrivacyPolicyDocument(String document){ + PrivacyPolicyDocument(Context context){this(load(context),L10n.isChinese());} + PrivacyPolicyDocument(String document){this(document,true);} + private PrivacyPolicyDocument(String document,boolean chinese){ available=document!=null&&!document.trim().isEmpty(); - String value=available?document:"隐私政策暂时无法读取,请拒绝联网并重新安装应用。"; + String value=available?document:L10n.tr("隐私政策暂时无法读取,请拒绝联网并重新安装应用。"); int start=value.indexOf("## 中文\n"),end=start<0?-1:value.indexOf("## English",start); - text=start>=0&&end>start?value.substring(start+"## 中文\n".length(),end).trim():value; + text=chinese&&start>=0&&end>start?value.substring(start+"## 中文\n".length(),end).trim(): + !chinese&&end>=0?value.substring(end+"## English".length()).trim():value; } private static String load(Context context){ try{return LicenseCatalog.read(context,"PRIVACY.md");}catch(IOException error){return null;} @@ -28,7 +30,7 @@ final class PrivacyPolicyDocument { LinearLayout content=ui.column();content.setPadding(ui.dp(20),ui.dp(20),ui.dp(20),ui.dp(20));scroll.addView(content); for(String paragraph:text.split("\n\n")){ paragraph=paragraph.trim();if(paragraph.isEmpty()||paragraph.equals("---"))continue; - boolean heading=paragraph.startsWith("#"),date=paragraph.startsWith("更新日期:"); + boolean heading=paragraph.startsWith("#"),date=paragraph.startsWith("更新日期:")||paragraph.startsWith("Last updated:"); String value=heading?paragraph.replaceFirst("^#+\\s*",""):paragraph.replace("**",""); TextView label=ui.text(value,date?12:16,heading);label.setTextIsSelectable(true);label.setLineSpacing(ui.dp(4),1); if(date)label.setTextColor(SECONDARY); diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteKeyboard.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteKeyboard.java index 43acb0e3..93758522 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteKeyboard.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteKeyboard.java @@ -39,12 +39,12 @@ final class RemoteKeyboard extends LinearLayout { header.addView(editor,new FrameLayout.LayoutParams(1,1,Gravity.BOTTOM)); toolbar=ui.row();toolbar.setGravity(Gravity.CENTER_VERTICAL);toolbar.setPadding(ui.dp(6),0,ui.dp(6),0); header.addView(toolbar,new FrameLayout.LayoutParams(-1,-1)); - switchButton=button("电脑键盘",this::switchKeyboard);switchButton.setPadding(ui.dp(8),0,ui.dp(8),0); + switchButton=button(L10n.tr("电脑键盘"),this::switchKeyboard);switchButton.setPadding(ui.dp(8),0,ui.dp(8),0); toolbar.addView(switchButton,new LayoutParams(-2,-1)); LinearLayout pages=ui.row();pages.setGravity(Gravity.CENTER);toolbar.addView(pages,new LayoutParams(0,-1,1)); - lettersButton=button("字母数字",()->page(false));functionsButton=button("符号功能",()->page(true)); + lettersButton=button(L10n.tr("字母数字"),()->page(false));functionsButton=button(L10n.tr("符号功能"),()->page(true)); pages.addView(lettersButton,new LayoutParams(-2,ui.dp(32)));pages.addView(functionsButton,new LayoutParams(-2,ui.dp(32))); - FrameLayout hide=new FrameLayout(context);hide.setContentDescription("收起键盘");hide.setClickable(true);hide.setFocusable(true); + FrameLayout hide=new FrameLayout(context);hide.setContentDescription(L10n.tr("收起键盘"));hide.setClickable(true);hide.setFocusable(true); hide.addView(ui.icon("keyboard_hide",foreground()),new FrameLayout.LayoutParams(ui.dp(24),ui.dp(24),Gravity.CENTER)); hide.setOnClickListener(v->{feedback(v);close();});toolbar.addView(hide,new LayoutParams(ui.dp(44),ui.dp(44))); keys=ui.column();keys.setPadding(ui.dp(3),ui.dp(4),ui.dp(3),ui.dp(4));addView(keys,new LayoutParams(-1,0,1)); @@ -157,7 +157,7 @@ final class RemoteKeyboard extends LinearLayout { } private void render(){ setBackgroundColor(dark()?0xFF202124:0xFFE8EAED); - switchButton.setText(computer?"系统键盘":"电脑键盘");switchButton.setTextColor(foreground()); + switchButton.setText(computer?L10n.tr("系统键盘"):L10n.tr("电脑键盘"));switchButton.setTextColor(foreground()); lettersButton.setVisibility(computer?VISIBLE:GONE);functionsButton.setVisibility(computer?VISIBLE:GONE); for(TextView view:new TextView[]{lettersButton,functionsButton}){ boolean selected=(view==functionsButton)==functions;view.setSelected(selected); @@ -185,12 +185,12 @@ final class RemoteKeyboard extends LinearLayout { LinearLayout line=ui.row();line.setGravity(Gravity.CENTER); for(String value:values){ boolean shift=modifiers.contains(16);String shown=shift&&value.length()==1?shifted(value):value; - TextView key=button(shown,()->key(value));key.setPadding(0,0,0,0); + TextView key=button(L10n.tr(shown),()->key(value));key.setPadding(0,0,0,0); key.setTextSize(value.length()>1?12:18);key.setSingleLine(true); int modifier=modifier(value);boolean selected=modifier!=0&&modifiers.contains(modifier);key.setSelected(selected); int color=selected?(dark()?0xFF596D8C:0xFFA8C7FA):value.length()>1||value.equals("⇧")||value.equals("⌫")?(dark()?0xFF30343B:0xFFD0D5DC):(dark()?0xFF3C4043:Color.WHITE); StateListDrawable background=new StateListDrawable();background.addState(new int[]{android.R.attr.state_pressed},ui.background(dark()?0xFF68717D:0xFFBDC9D8,7));background.addState(new int[]{},ui.background(color,7));key.setBackground(background); - if(value.equals("⇧"))key.setContentDescription("Shift");else if(value.equals("⌫"))key.setContentDescription("退格"); + if(value.equals("⇧"))key.setContentDescription("Shift");else if(value.equals("⌫"))key.setContentDescription(L10n.tr("退格")); // Both penultimate rows allocate exactly 1/8 to Shift and Backspace. boolean penultimate=values[0].equals("⇧");float weight=value.equals("空格")?4:1; if(penultimate)weight=value.equals("⇧")||value.equals("⌫")?1:(6f/(values.length-2)); diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteNetworkStatistics.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteNetworkStatistics.java index 36f1b18c..b9bca614 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteNetworkStatistics.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteNetworkStatistics.java @@ -24,7 +24,7 @@ final class RemoteNetworkStatistics { final Report report;final int fps,width,height;final double latency,rtt; final String remoteEncoder,localDecoder; Snapshot(Report report,int fps,int width,int height,double latency,double rtt,String remoteEncoder,String localDecoder){this.report=report;this.fps=fps;this.width=width;this.height=height;this.latency=latency;this.rtt=rtt;this.remoteEncoder=remoteEncoder;this.localDecoder=localDecoder;} - String mode(){return report==null?"—":report.mode==0?"P2P 直连":report.mode==1?"TURN 中继":"—";} + String mode(){return report==null?"—":report.mode==0?L10n.tr("P2P 直连"):report.mode==1?L10n.tr("TURN 中继"):"—";} String resolution(){return width>0&&height>0?width+" × "+height:"—";} } private static final class Frame { diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePreviewStore.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePreviewStore.java index 2e60cdac..b75b1f5a 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePreviewStore.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePreviewStore.java @@ -127,7 +127,7 @@ final class RemotePreviewStore { new AtomicFile(new File(directory,key+".jpg")).delete(); synchronized(this){ boolean saved=index.edit().putStringSet("files",new HashSet<>(files)).commit(); - if(!saved||new File(directory,key+".jpg").exists())cleanupError="部分预览图未能清除,请重试。"; + if(!saved||new File(directory,key+".jpg").exists())cleanupError=L10n.tr("部分预览图未能清除,请重试。"); } changed(); });changed(); @@ -139,7 +139,7 @@ final class RemotePreviewStore { try{deleteTree(directory);}catch(IOException error){success=false;} synchronized(this){ if(epoch!=generation)return; - cleaning=false;cleanupError=success?"":"部分预览图未能清除,请重试。"; + cleaning=false;cleanupError=success?"":L10n.tr("部分预览图未能清除,请重试。"); } changed(); }); diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePrivacyScreen.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePrivacyScreen.java index 4a69ae9a..c64f6fa2 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePrivacyScreen.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemotePrivacyScreen.java @@ -45,9 +45,9 @@ final class RemotePrivacyScreen { boolean fresh(long now) { return received && now - receivedAt <= 5000; } boolean enabled(long now) { return fresh(now) && state == 3 && overlay && !remotePaused; } String buttonTitle(long now) { - if (enabled(now)) return "隐私屏已开启"; - if (fresh(now) && supported && state == 1 && !active()) return "隐私屏已关闭"; - return "隐私屏"; + if (enabled(now)) return L10n.tr("隐私屏已开启"); + if (fresh(now) && supported && state == 1 && !active()) return L10n.tr("隐私屏已关闭"); + return L10n.tr("隐私屏"); } String feedback(long now) { if (!desktopAvailable) return ""; @@ -71,25 +71,25 @@ final class RemotePrivacyScreen { return ++requestId; } void failed(long id) { - if (pending && requestId == id) { pending = false; failure = "指令发送失败,请重试"; } + if (pending && requestId == id) { pending = false; failure = L10n.tr("指令发送失败,请重试"); } } void tick(long now) { if (pending && now - requestedAt >= 15000) { - pending = false; failure = "请求超时,尚未确认电脑的隐私屏状态"; + pending = false; failure = L10n.tr("请求超时,尚未确认电脑的隐私屏状态"); } } String status(long now) { if (!failure.isEmpty()) return failure; - if (!received) return "等待电脑返回隐私屏状态;旧版电脑端可能不支持"; - if (!fresh(now)) return "隐私屏状态已过期,等待电脑确认"; - if (state == 2) return "正在开启隐私屏…"; - if (state == 4) return "正在关闭隐私屏…"; - if (pending) return "指令已发送,等待电脑确认…"; - if (state == 5) return "隐私屏异常"; - if (!supported || state == 0) return "隐私屏暂不可用"; + if (!received) return L10n.tr("等待电脑返回隐私屏状态;旧版电脑端可能不支持"); + if (!fresh(now)) return L10n.tr("隐私屏状态已过期,等待电脑确认"); + if (state == 2) return L10n.tr("正在开启隐私屏…"); + if (state == 4) return L10n.tr("正在关闭隐私屏…"); + if (pending) return L10n.tr("指令已发送,等待电脑确认…"); + if (state == 5) return L10n.tr("隐私屏异常"); + if (!supported || state == 0) return L10n.tr("隐私屏暂不可用"); if (state == 3 && overlay && !remotePaused) - return "隐私屏已开启"; - return state == 1 && !active() ? "隐私屏已关闭" : "隐私屏状态待确认"; + return L10n.tr("隐私屏已开启"); + return state == 1 && !active() ? L10n.tr("隐私屏已关闭") : L10n.tr("隐私屏状态待确认"); } String detail(long now) { return fresh(now) && (state == 0 || state == 5 || !supported) ? reason : ""; diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteSessionService.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteSessionService.java index b3696e42..d43261b8 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteSessionService.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteSessionService.java @@ -51,7 +51,7 @@ public final class RemoteSessionService extends Service { @Override public void onCreate() { super.onCreate(); running = this; getSystemService(NotificationManager.class).createNotificationChannel( - new NotificationChannel(CHANNEL, "远程连接", NotificationManager.IMPORTANCE_LOW)); + new NotificationChannel(CHANNEL, L10n.tr("远程连接"), NotificationManager.IMPORTANCE_LOW)); wakeLock = getSystemService(PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CrossDesk:RemoteSession"); wakeLock.setReferenceCounted(false); } @@ -60,7 +60,7 @@ public final class RemoteSessionService extends Service { if (value == null || value.ended || value.session.isClosed()) { stopSelf(startId); return START_NOT_STICKY; } if (intent == null || !value.token.equals(intent.getStringExtra("session"))) return START_NOT_STICKY; owned = value; - if (STOP.equals(intent.getAction())) { value.finish("已从通知断开远程连接"); return START_NOT_STICKY; } + if (STOP.equals(intent.getAction())) { value.finish(L10n.tr("已从通知断开远程连接")); return START_NOT_STICKY; } try { Notification notification = notification(); if (Build.VERSION.SDK_INT >= 34) startForeground(NOTIFICATION, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE); @@ -68,7 +68,7 @@ public final class RemoteSessionService extends Service { update(); } catch (RuntimeException error) { Log.w("CrossDesk", "Background session foreground promotion failed", error); - value.finish("后台保活未能启动,请保持应用在前台后重新连接"); + value.finish(L10n.tr("后台保活未能启动,请保持应用在前台后重新连接")); } return START_NOT_STICKY; } @@ -80,12 +80,12 @@ public final class RemoteSessionService extends Service { .setData(android.net.Uri.parse("crossdesk-session:" + owned.token)).putExtra("session", owned.token); PendingIntent stop = PendingIntent.getService(this, 1, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); return new Notification.Builder(this, CHANNEL).setSmallIcon(R.drawable.ic_remote_session) - .setContentTitle("CrossDesk 远程连接") - .setContentText(owned.background ? "后台保持连接,点按返回远程桌面" : "已启用后台保活,切换应用可继续保持连接") + .setContentTitle(L10n.tr("CrossDesk 远程连接")) + .setContentText(owned.background ? L10n.tr("后台保持连接,点按返回远程桌面") : L10n.tr("已启用后台保活,切换应用可继续保持连接")) .setContentIntent(open).setOngoing(true).setOnlyAlertOnce(true).setShowWhen(false) .setCategory(Notification.CATEGORY_SERVICE).setVisibility(Notification.VISIBILITY_PRIVATE) - .addAction(new Notification.Action.Builder(null, "返回", open).build()) - .addAction(new Notification.Action.Builder(null, "断开", stop).build()).build(); + .addAction(new Notification.Action.Builder(null, L10n.tr("返回"), open).build()) + .addAction(new Notification.Action.Builder(null, L10n.tr("断开"), stop).build()).build(); } @android.annotation.SuppressLint("WakelockTimeout") // Released on foreground return, disconnect, task removal and service destruction. private void update() { @@ -96,14 +96,14 @@ public final class RemoteSessionService extends Service { } private void releaseWakeLock() { if (wakeLock != null && wakeLock.isHeld()) wakeLock.release(); } @Override public void onTaskRemoved(Intent rootIntent) { - if (current == owned && owned != null) owned.finish("远程任务已关闭"); + if (current == owned && owned != null) owned.finish(L10n.tr("远程任务已关闭")); stopSelf(); } @Override public void onDestroy() { if (running == this) running = null; releaseWakeLock(); stopForeground(STOP_FOREGROUND_REMOVE); BackgroundSession value = owned; - if (current == value && value != null) { current = null; value.finish("后台连接服务已停止,请重新连接"); } + if (current == value && value != null) { current = null; value.finish(L10n.tr("后台连接服务已停止,请重新连接")); } super.onDestroy(); } } diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoSettings.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoSettings.java index 717309f8..d421e4c3 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoSettings.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoSettings.java @@ -4,11 +4,11 @@ import org.json.JSONObject; /** Same request/acknowledgement and rollback rules as the iOS controller. */ final class RemoteVideoSettings { - static final String[] PREFERENCES={"帧率优先","画质优先","平衡"}; - static final String[] DETAILS={ - "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。", - "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。", - "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。"}; + static String[] preferences(){return new String[]{L10n.tr("帧率优先"),L10n.tr("画质优先"),L10n.tr("平衡")};} + static String[] details(){return new String[]{ + L10n.tr("优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。"), + L10n.tr("始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。"), + L10n.tr("兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。")};} static final class Values { final int quality,frameRate,preference; Values(int quality,int frameRate,int preference){this.quality=quality;this.frameRate=frameRate;this.preference=preference;} @@ -54,5 +54,5 @@ final class RemoteVideoSettings { }catch(org.json.JSONException ignored){ } } void expire(long expiredId){if(pending&&expiredId==requestId){selection=applied;pending=false;failed=true;}} - String feedback(){return !supported?"连接建立后可调整,需被控端支持。":failed?"调整失败,请重试。":"";} + String feedback(){return !supported?L10n.tr("连接建立后可调整,需被控端支持。"):failed?L10n.tr("调整失败,请重试。"):"";} } diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java index 2e9f770a..b207f3af 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java @@ -104,7 +104,7 @@ final class RemoteVideoView extends FrameLayout implements SurfaceHolder.Callbac } return true; }); - setContentDescription("远程桌面:轻触点击,拖动移动,长按右键,双指捏合缩放,放大后双指拖动画面,原始比例下双指上下滑动滚动"); + setContentDescription(L10n.tr("远程桌面:轻触点击,拖动移动,长按右键,双指捏合缩放,放大后双指拖动画面,原始比例下双指上下滑动滚动")); } void videoSize(int width, int height) { if (width <= 0 || height <= 0) return; @@ -244,7 +244,7 @@ final class RemoteVideoView extends FrameLayout implements SurfaceHolder.Callbac private final Path arrow = new Path(); private final float arrowWidth = 12, arrowHeight = 15; Cursor(Context context) { - super(context); setClickable(true); setContentDescription("远程桌面触控区域"); + super(context); setClickable(true); setContentDescription(L10n.tr("远程桌面触控区域")); // Match the iOS RemoteCursorArrowShape in density-independent units. arrow.moveTo(arrowWidth*.08f,arrowHeight*.04f); arrow.lineTo(arrowWidth*.08f,arrowHeight*.78f); diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/SegmentedControl.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/SegmentedControl.java index 1e4d0a7d..1a6777fa 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/SegmentedControl.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/SegmentedControl.java @@ -31,7 +31,7 @@ final class SegmentedControl extends LinearLayout { setGravity(Gravity.CENTER_VERTICAL);setPadding(inset,inset,inset,inset);setBackground(ui.background(0xFFE9E9EF,MobileUi.SEGMENT_HEIGHT/2));paint.setColor(Color.WHITE); for(int i=0;iselect(index)); - choice.setTextSize(13);choice.setMinHeight(height);choice.setSelected(i==selected);choice.setEnabled(enabled);choice.setAlpha(enabled?1:.45f); + choice.setTextSize(13);choice.setSingleLine();choice.setAutoSizeTextTypeUniformWithConfiguration(9,13,1,android.util.TypedValue.COMPLEX_UNIT_SP);choice.setMinHeight(height);choice.setSelected(i==selected);choice.setEnabled(enabled);choice.setAlpha(enabled?1:.45f); addView(choice,new LayoutParams(0,height,1)); } } diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/SessionControls.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/SessionControls.java index a54f5196..3b2d5197 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/SessionControls.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/SessionControls.java @@ -59,8 +59,8 @@ final class SessionControls extends FrameLayout { addView(keyboard,new LayoutParams(-1,ui.dp(44),Gravity.BOTTOM)); // This container must remain transparent to remote touch outside its controls. waiting=ui.column();waiting.setMinimumWidth(ui.dp(200));waiting.setGravity(Gravity.CENTER);waiting.setPadding(ui.dp(20),ui.dp(20),ui.dp(20),ui.dp(20));waiting.setBackground(ui.background(0xB0202024,14)); - ProgressBar progress=new ProgressBar(context);progress.setIndeterminateTintList(android.content.res.ColorStateList.valueOf(Color.WHITE));waiting.addView(progress,ui.size(28,28));ui.gap(waiting,12);TextView message=ui.text("等待远端画面…",14,false);message.setTextColor(Color.WHITE);message.setGravity(Gravity.CENTER);waiting.addView(message);addView(waiting,new LayoutParams(-2,-2,Gravity.CENTER)); - orb=ui.iconButton("display","展开远程控制菜单",()->{if(menu==null)openMenu("controls");else closeMenu();}); + ProgressBar progress=new ProgressBar(context);progress.setIndeterminateTintList(android.content.res.ColorStateList.valueOf(Color.WHITE));waiting.addView(progress,ui.size(28,28));ui.gap(waiting,12);TextView message=ui.text(L10n.tr("等待远端画面…"),14,false);message.setTextColor(Color.WHITE);message.setGravity(Gravity.CENTER);waiting.addView(message);addView(waiting,new LayoutParams(-2,-2,Gravity.CENTER)); + orb=ui.iconButton("display",L10n.tr("展开远程控制菜单"),()->{if(menu==null)openMenu("controls");else closeMenu();}); ImageView brand=new ImageView(context);brand.setImageResource(R.drawable.mobile_brand);brand.setScaleType(ImageView.ScaleType.CENTER_CROP);brand.setBackground(ui.background(Color.WHITE,23));brand.setClipToOutline(true);brand.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); ((FrameLayout)orb).removeAllViews();((FrameLayout)orb).addView(brand,new LayoutParams(ui.dp(46),ui.dp(46),Gravity.CENTER)); orb.setBackground(ui.background(0xFFF5F5F7,27));orb.setElevation(ui.dp(7));addView(orb,new LayoutParams(ui.dp(54),ui.dp(54))); @@ -117,15 +117,15 @@ final class SessionControls extends FrameLayout { if(transferLabel!=null){transferLabel.setText(transferStatus);transferLabel.setVisibility(transferStatus.isEmpty()?GONE:VISIBLE);} if(saveFileButton!=null)saveFileButton.setVisibility(hasReceivedFile?VISIBLE:GONE); } - private void closeMenu(){if(menu!=null){removeView(menu);menu=null;menuScroll=null;}if(shield!=null){removeView(shield);shield=null;}videoFeedback=transferLabel=saveFileButton=null;privacyFeedback=privacyCaption=null;privacyButton=null;privacyIcon=null;trafficCells=null;trafficRows=null;networkDetails=null;encryptionLock=encryptionOpen=null;settingRows.clear();orb.setContentDescription("展开远程控制菜单");positionMouse();} + private void closeMenu(){if(menu!=null){removeView(menu);menu=null;menuScroll=null;}if(shield!=null){removeView(shield);shield=null;}videoFeedback=transferLabel=saveFileButton=null;privacyFeedback=privacyCaption=null;privacyButton=null;privacyIcon=null;trafficCells=null;trafficRows=null;networkDetails=null;encryptionLock=encryptionOpen=null;settingRows.clear();orb.setContentDescription(L10n.tr("展开远程控制菜单"));positionMouse();} private void openMenu(String page){ cancelMouseInput(); closeMenu();menuPage=page;shield=new View(getContext());shield.setOnClickListener(v->closeMenu());addView(shield,new LayoutParams(-1,-1)); menu=ui.column();menu.setPadding(ui.dp(12),ui.dp(12),ui.dp(12),ui.dp(12));ui.card(menu,18);menu.setElevation(ui.dp(12)); LinearLayout header=ui.row(); - if(!page.equals("controls"))header.addView(ui.iconButton("back","返回控制栏",()->openMenu("controls")),ui.size(28,32)); - TextView title=ui.text(page.equals("controls")?"● 已连接":page.equals("video")?"画面设置":"网络状态",14,true); - header.addView(title,new LinearLayout.LayoutParams(0,-2,1));header.addView(ui.iconButton("close","关闭控制栏",this::closeMenu),ui.size(30,32));menu.addView(header);ui.gap(menu,9); + if(!page.equals("controls"))header.addView(ui.iconButton("back",L10n.tr("返回控制栏"),()->openMenu("controls")),ui.size(28,32)); + TextView title=ui.text(page.equals("controls")?L10n.tr("● 已连接"):page.equals("video")?L10n.tr("画面设置"):L10n.tr("网络状态"),14,true); + header.addView(title,new LinearLayout.LayoutParams(0,-2,1));header.addView(ui.iconButton("close",L10n.tr("关闭控制栏"),this::closeMenu),ui.size(30,32));menu.addView(header);ui.gap(menu,9); if(page.equals("video")){videoFeedback=ui.text("",12,false);videoFeedback.setTextColor(SECONDARY);videoFeedback.setPadding(0,0,0,ui.dp(9));menu.addView(videoFeedback);} ScrollView scroll=new ScrollView(getContext());menuScroll=scroll;menu.addView(scroll,new LinearLayout.LayoutParams(-1,0,1));LinearLayout body=ui.column();scroll.addView(body); if(page.equals("network")){ @@ -133,7 +133,7 @@ final class SessionControls extends FrameLayout { scroll.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);body.setPadding(0,0,ui.dp(6),0); } if(page.equals("controls")){ - String[] labels={"键盘",mouseVisible?"收起鼠标":"虚拟鼠标",relative?"相对鼠标":"绝对鼠标","显示器","画面设置",muted?"静音":"声音","发送文件","网络状态","Ctrl+Alt+Del","剪贴板","隐私屏"}; + String[] labels={L10n.tr("键盘"),mouseVisible?L10n.tr("收起鼠标"):L10n.tr("虚拟鼠标"),relative?L10n.tr("相对鼠标"):L10n.tr("绝对鼠标"),L10n.tr("显示器"),L10n.tr("画面设置"),muted?L10n.tr("静音"):L10n.tr("声音"),L10n.tr("发送文件"),L10n.tr("网络状态"),"Ctrl+Alt+Del",L10n.tr("剪贴板"),L10n.tr("隐私屏")}; String[] icons={"keyboard","mouse","mouse","display","sliders","audio","folder","chart","lock","clipboard","eye"}; Runnable[] clicks={()->{closeMenu();toggleKeyboard();},this::toggleMouse,actions::mouse,actions::display,()->openMenu("video"),actions::mute,actions::sendFile,()->openMenu("network"),actions::secureAttention,actions::clipboard,actions::togglePrivacy}; menuColumns=controlColumns(); @@ -143,22 +143,22 @@ final class SessionControls extends FrameLayout { visibleControls.add(index); } int controlCount=visibleControls.size(); - for(int row=0;row<(controlCount+menuColumns-1)/menuColumns;row++){LinearLayout line=ui.row();for(int col=0;col=controlCount){View spacer=new View(getContext());LinearLayout.LayoutParams p=new LinearLayout.LayoutParams(0,ui.dp(52),1);if(col>0)p.leftMargin=ui.dp(7);line.addView(spacer,p);continue;}int index=visibleControls.get(position);LinearLayout control=ui.column();control.setGravity(Gravity.CENTER);control.setBackground(ui.background(0xFFF0F0F2,10));MobileUi.Icon icon=ui.icon(icons[index],INK);control.addView(icon,ui.size(19,19));ui.gap(control,4);TextView caption=ui.text(labels[index],10,false);caption.setSingleLine();caption.setGravity(Gravity.CENTER);control.addView(caption);control.setContentDescription(labels[index]);control.setClickable(true);control.setFocusable(true);control.setOnClickListener(v->clicks[index].run()); + for(int row=0;row<(controlCount+menuColumns-1)/menuColumns;row++){LinearLayout line=ui.row();for(int col=0;col=controlCount){View spacer=new View(getContext());LinearLayout.LayoutParams p=new LinearLayout.LayoutParams(0,ui.dp(52),1);if(col>0)p.leftMargin=ui.dp(7);line.addView(spacer,p);continue;}int index=visibleControls.get(position);LinearLayout control=ui.column();control.setGravity(Gravity.CENTER);control.setBackground(ui.background(0xFFF0F0F2,10));MobileUi.Icon icon=ui.icon(icons[index],INK);control.addView(icon,ui.size(19,19));ui.gap(control,4);TextView caption=ui.text(labels[index],10,false);caption.setMaxLines(2);caption.setAutoSizeTextTypeUniformWithConfiguration(8,10,1,android.util.TypedValue.COMPLEX_UNIT_SP);caption.setGravity(Gravity.CENTER);control.addView(caption);control.setContentDescription(labels[index]);control.setClickable(true);control.setFocusable(true);control.setOnClickListener(v->clicks[index].run()); if(index==10){privacyButton=control;privacyIcon=icon;privacyCaption=caption;} LinearLayout.LayoutParams p=new LinearLayout.LayoutParams(0,ui.dp(52),1);if(col>0)p.leftMargin=ui.dp(7);line.addView(control,p); }body.addView(line);if((row+1)*menuColumns{closeMenu();closeKeyboard();actions.disconnect();});disconnect.setMinHeight(ui.dp(34));disconnect.setTextSize(14);disconnect.setBackground(ui.background(RED,8));menu.addView(disconnect,ui.size(-1,34)); - addView(menu,new LayoutParams(panelWidth(getWidth()),panelHeight(getHeight())));orb.bringToFront();orb.setContentDescription("收起远程控制菜单"); + ui.gap(menu,9);TextView disconnect=ui.action(L10n.tr("断开连接"),Color.WHITE,()->{closeMenu();closeKeyboard();actions.disconnect();});disconnect.setMinHeight(ui.dp(34));disconnect.setTextSize(14);disconnect.setBackground(ui.background(RED,8));menu.addView(disconnect,ui.size(-1,34)); + addView(menu,new LayoutParams(panelWidth(getWidth()),panelHeight(getHeight())));orb.bringToFront();orb.setContentDescription(L10n.tr("收起远程控制菜单")); positionMouse(); } private void renderPrivacy(){ @@ -168,7 +168,7 @@ final class SessionControls extends FrameLayout { long now=android.os.SystemClock.elapsedRealtime();privacy.tick(now); if(privacyFeedback!=null){String feedback=privacy.feedback(now);privacyFeedback.setText(feedback);privacyFeedback.setVisibility(feedback.isEmpty()?GONE:VISIBLE);} if(privacyButton==null)return; - boolean enabled=privacy.enabled(now);String action=privacy.active()?"关闭隐私屏":"开启隐私屏"; + boolean enabled=privacy.enabled(now);String action=privacy.active()?L10n.tr("关闭隐私屏"):L10n.tr("开启隐私屏"); privacyIcon.setName(enabled?"eye_off":"eye"); privacyCaption.setText(privacy.buttonTitle(now)); privacyButton.setSelected(enabled); @@ -183,7 +183,7 @@ final class SessionControls extends FrameLayout { group=new SegmentedControl(ui,labels,selectionIndex(),settings.supported,index->actions.videoSettings(field,values[index])); group.setPadding(ui.dp(2),ui.dp(2),ui.dp(2),ui.dp(2));body.addView(group); for(int i=0;i=6?new LinearLayout.LayoutParams(-2,-2):new LinearLayout.LayoutParams(0,-2,1)); if(i==5){encryptionLock=ui.icon("lock",GREEN);encryptionOpen=ui.icon("unlock",SECONDARY);for(View icon:new View[]{encryptionLock,encryptionOpen}){LinearLayout.LayoutParams p=ui.size(14,14);p.rightMargin=ui.dp(4);row.addView(icon,p);}} TextView value=ui.text("—",12,false);value.setFontFeatureSettings("tnum"); @@ -219,13 +219,13 @@ final class SessionControls extends FrameLayout { } private void renderNetwork(){ if(trafficCells==null)return; - String[] names={"视频","音频","数据","合计"}; + String[] names={L10n.tr("视频"),L10n.tr("音频"),L10n.tr("数据"),L10n.tr("合计")}; for(int i=0;i<4;i++){ RemoteNetworkStatistics.Traffic traffic=network.report==null?null:network.report.traffic[i]; String in=RemoteNetworkStatistics.bitrate(traffic==null?-1:traffic.inbound),out=RemoteNetworkStatistics.bitrate(traffic==null?-1:traffic.outbound),loss=RemoteNetworkStatistics.loss(traffic==null?Double.NaN:traffic.loss); - trafficCells[i][0].setText(in);trafficCells[i][1].setText(out);trafficCells[i][2].setText(loss);trafficRows[i].setContentDescription(names[i]+",接收 "+in+",发送 "+out+",丢包率 "+loss); + trafficCells[i][0].setText(in);trafficCells[i][1].setText(out);trafficCells[i][2].setText(loss);trafficRows[i].setContentDescription(L10n.format("{0},接收 {1},发送 {2},丢包率 {3}",names[i],in,out,loss)); } - String[] values={network.fps+" FPS",network.resolution(),RemoteNetworkStatistics.latency(network.latency),RemoteNetworkStatistics.latency(network.rtt),network.mode(),network.report==null?"—":network.report.srtp?"SRTP 已启用":"未启用",network.remoteEncoder.isEmpty()?"—":network.remoteEncoder,network.localDecoder.isEmpty()?"—":network.localDecoder}; + String[] values={network.fps+" FPS",network.resolution(),RemoteNetworkStatistics.latency(network.latency),RemoteNetworkStatistics.latency(network.rtt),network.mode(),network.report==null?"—":network.report.srtp?L10n.tr("SRTP 已启用"):L10n.tr("未启用"),network.remoteEncoder.isEmpty()?"—":network.remoteEncoder,network.localDecoder.isEmpty()?"—":network.localDecoder}; // Reassigning identical text every statistics tick restarts the marquee. for(int i=0;i + + + " · 已完成" + " 传输失败" + " 台设备" + " 条 · " + " 条未读" + "CrossDesk 远程连接" + "GNU GPL 第 3 版" + "OpenFEC 告知" + "OpenFEC 许可与源码" + "P2P 直连" + "SRTP 已启用" + "TURN 中继" + "{0} 传输失败" + "{0} 台设备" + "{0} 条未读" + "{0},接收 {1},发送 {2},丢包率 {3}" + "● 已连接" + "下拉刷新" + "丢包率" + "中" + "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" + "低" + "使用自定义服务器" + "保存密码" + "保存收到的文件" + "保存远程画面预览" + "保存远程画面预览?" + "信令连接中断,请重新连接" + "公告加载失败,请重试。" + "公告详情" + "共 " + "共 {0} 条 · {1} 条未读" + "关于" + "关于 CrossDesk" + "关于,有新版本" + "关闭" + "关闭控制栏" + "关闭隐私屏" + "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" + "分辨率" + "删除" + "删除公告" + "删除记录" + "删除这条公告?" + "刷新公告" + "剪贴板" + "加载中…" + "加载更多" + "升级提示" + "原生连接初始化失败" + "发送" + "发送 " + "发送后,在远程键盘中点击“粘贴”。接收的远端文本可手动复制到本机。" + "发送文件" + "发送文本" + "取消" + "取消连接" + "各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" + "合计" + "同意并继续" + "后台保持连接,点按返回远程桌面" + "后台保活未能启动,请保持应用在前台" + "后台保活未能启动,请保持应用在前台后重新连接" + "后台连接已结束,请重新连接" + "后台连接服务已停止,请重新连接" + "后续连接仍会保存新的预览图。" + "在线" + "填写主机名或 IPv4 地址,不含协议和路径" + "声音" + "复制远端文本" + "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" + "媒体加密" + "字母数字" + "安全存储或证书初始化失败,请重试或清除应用数据" + "完成" + "完成隐私授权后可检查更新" + "完成隐私授权后登记本机身份" + "密码保存失败,本次连接仍可使用" + "密码将加密保存在本机 Android Keystore 中" + "对端 ID" + "对端 ID " + "对端 ID {0}" + "将删除本机保存的所有远程预览图,保留连接记录和密码。" + "屏幕方向" + "展开远程控制菜单" + "已从通知断开远程连接" + "已保存密码" + "已保存密码无法读取,请重新输入" + "已保存的密码未能保留,请重新输入一次" + "已发送 Ctrl+Alt+Del" + "已启用后台保活,切换应用可继续保持连接" + "已启用后台保活,可从连接通知返回或断开" + "已授权" + "已读" + "已连接 " + "已连接服务器" + "帧率" + "帧率优先" + "平衡" + "应用中的许可文件缺失或损坏,请重新安装应用。" + "开发版本包含尚未发布的修改,以下链接为基础版本源码。" + "开启保存" + "开启隐私屏" + "开源组件" + "开源软件权利说明" + "当前已是最新版本" + "当前远端不支持直接输入此文本,请使用支持文本输入的被控端版本,或通过剪贴板发送" + "成功连接后,这里会显示最近的远程设备。" + "我已阅读并同意《隐私政策》" + "所选文件(无法读取或空间不足)" + "找不到该设备 ID" + "指令发送失败,请重试" + "指令已发送,等待电脑确认…" + "授权状态" + "接收" + "接收 " + "控制端解码器" + "撤回" + "撤回后将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。" + "撤回联网授权" + "撤回联网授权?" + "收起远程控制菜单" + "收起键盘" + "收起鼠标" + "数据" + "文件保存失败,请重试" + "文件已保存" + "文件选择已超时,会话已结束" + "文本超过 128 KB" + "断开" + "断开后将返回首页" + "断开远程连接?" + "断开连接" + "新版本" + "新版本可用:v" + "新版本可用:v{0}" + "无未读公告" + "无法保存本地阅读状态,请重试。" + "无法删除这条公告,请重试。" + "无法发起远程连接" + "无法读取开源许可" + "显示器" + "显示密码" + "暂不同意" + "暂无公告" + "最近连接" + "服务器" + "服务器 TLS 证书校验失败" + "服务器地址" + "服务器登录失败,请检查服务器地址和网络" + "服务器端口" + "服务器连接超时,请检查服务器地址和网络" + "未启用" + "未找到可打开链接的浏览器" + "未授权" + "未读" + "未连接服务器 · 点击重试" + "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" + "本机 ID " + "本机 ID {0}" + "本版本源码与构建说明" + "本版本源码信息暂不可用。" + "松开刷新" + "构建说明" + "构建配方与项目补丁" + "查看源码" + "检查失败,请稍后重试" + "检查更新" + "正在关闭隐私屏…" + "正在建立安全连接…" + "正在开启隐私屏…" + "正在检查更新…" + "正在清除…" + "正在获取本机 ID…" + "正在读取所选文件…" + "正在连接" + "正在连接信令服务器…" + "正在连接服务器…" + "正在重连服务器…" + "此设备没有可用的文件选择器" + "清除" + "清除预览图" + "清除预览图?" + "源码与构建说明" + "源码版本" + "版本" + "版权与许可声明" + "电脑键盘" + "画质优先" + "画面偏好" + "画面延时" + "画面设置" + "画面质量" + "画面采集帧率" + "相对位置" + "相对鼠标" + "知道了" + "确定" + "确认" + "确认连接" + "离线" + "空格" + "端口范围为 1–65535" + "符号功能" + "等待电脑返回隐私屏状态;旧版电脑端可能不支持" + "等待远端屏幕信息" + "等待远端画面…" + "等待隐私授权" + "系统键盘" + "绝对位置" + "绝对鼠标" + "网络状态" + "自定义" + "虚拟鼠标" + "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" + "被控端版本过低,请升级到最新版本。" + "被控端编码器" + "要发送到远端的文本" + "视频" + "许可" + "许可与版权声明" + "许可与版权声明可离线查阅。" + "设备身份保存失败,请检查安全存储" + "设备身份及选择保存的访问密码使用 Android Keystore 加密。连接记录仅保存在本机,不纳入设备备份。剪贴板内容在结束会话时清除。离开应用后通过画中画或连接通知保持会话,可在应用或通知中断开。" + "设置" + "设置,有新版本" + "访问密码" + "访问密码错误,请重新输入" + "证书校验失败 · 点击重试" + "请先完成联网授权" + "请在远端启用 CrossDesk 系统服务后重试" + "请求超时,尚未确认电脑的隐私屏状态" + "请等待当前文件发送完成" + "请输入 1–65535 范围内的端口" + "请输入 9 位设备 ID" + "请输入有效访问密码" + "调整失败,请重试。" + "软件许可" + "返回" + "返回控制栏" + "还没有连接记录" + "这条公告已更新或删除,请返回公告列表查看。" + "远程任务已关闭" + "远程桌面" + "远程桌面触控区域" + "远程桌面:轻触点击,拖动移动,长按右键,双指捏合缩放,放大后双指拖动画面,原始比例下双指上下滑动滚动" + "远程电脑" + "远程窗口已关闭,或后台保活未能启动,会话已结束" + "远程连接" + "远端密码错误" + "远端已关闭连接" + "远端当前不可用" + "远端访问密码已失效,请重新连接" + "连接" + "连接 " + "连接失败" + "连接失败 · 点击重试" + "连接已断开" + "连接已结束" + "连接延时(RTT)" + "连接建立后可调整,需被控端支持。" + "连接建立后锁定横屏" + "连接提示" + "连接方式" + "连接服务器" + "连接服务器后可获取最新公告。" + "连接超时,请检查设备 ID、服务器及远端在线状态" + "连接远程桌面" + "退格" + "通知公告" + "部分预览图未能清除,请重试。" + "重试" + "重试保存阅读状态" + "锁定" + "键盘" + "阅读并授权" + "隐私" + "隐私与授权" + "隐私屏" + "隐私屏已关闭" + "隐私屏已开启" + "隐私屏已被解锁" + "隐私屏异常" + "隐私屏暂不可用" + "隐私屏状态已过期,等待电脑确认" + "隐私屏状态待确认" + "隐私政策" + "隐私政策暂时无法读取,请拒绝联网并重新安装应用。" + "静音" + "音频" + "项目主页" + "预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" + "高" + "默认" + "默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。" + "鼠标右键,按住并拖动,松开结束拖拽" + "鼠标左键,按住并拖动,松开结束拖拽" + "鼠标控制" + "鼠标滚轮,上下滑动,可滑出按键范围" + ",丢包率 " + ",发送 " + ",已保存密码" + ",接收 " + ",点击重试" + diff --git a/apps/android/app/src/main/res/values-b+zh+Hant/strings.xml b/apps/android/app/src/main/res/values-b+zh+Hant/strings.xml new file mode 100644 index 00000000..c78dada6 --- /dev/null +++ b/apps/android/app/src/main/res/values-b+zh+Hant/strings.xml @@ -0,0 +1,308 @@ + + + + " · 已完成" + " 傳輸失敗" + " 臺裝置" + " 條 · " + " 條未讀" + "CrossDesk 遠端連線" + "GNU GPL 第 3 版" + "OpenFEC 告知" + "OpenFEC 許可與原始碼" + "P2P 直連" + "SRTP 已啟用" + "TURN 中繼" + "{0} 傳輸失敗" + "{0} 臺裝置" + "{0} 條未讀" + "{0},接收 {1},傳送 {2},丟包率 {3}" + "● 已連線" + "下拉重新整理" + "丟包率" + "中" + "優先保持畫面流暢,頻寬或編碼壓力較大時會更積極地降低解析度。" + "低" + "使用自定義伺服器" + "儲存密碼" + "儲存收到的檔案" + "儲存遠端畫面預覽" + "儲存遠端畫面預覽?" + "信令連線中斷,請重新連線" + "公告載入失敗,請重試。" + "公告詳情" + "共 " + "共 {0} 條 · {1} 條未讀" + "關於" + "關於 CrossDesk" + "關於,有新版本" + "關閉" + "關閉控制欄" + "關閉隱私屏" + "兼顧清晰度和流暢度,只在持續壓力下逐步降低解析度。" + "解析度" + "刪除" + "刪除公告" + "刪除記錄" + "刪除這條公告?" + "重新整理公告" + "剪貼簿" + "載入中…" + "載入更多" + "更新提示" + "原生連線初始化失敗" + "傳送" + "傳送 " + "傳送後,在遠端鍵盤中點選“貼上”。接收的遠端文字可手動複製到本機。" + "傳送檔案" + "傳送文字" + "取消" + "取消連線" + "各元件遵循所列開源許可證,其授予的權利不受本應用普通使用條款限制。檢視原始碼需要網路連線。" + "合計" + "同意並繼續" + "後臺保持連線,點按返回遠端桌面" + "後臺保活未能啟動,請保持應用在前臺" + "後臺保活未能啟動,請保持應用在前臺後重新連線" + "後臺連線已結束,請重新連線" + "後臺連線服務已停止,請重新連線" + "後續連線仍會儲存新的預覽圖。" + "線上" + "填寫主機名或 IPv4 地址,不含協議和路徑" + "聲音" + "複製遠端文字" + "始終保持較高解析度,頻寬不足時透過降低幀率來保證畫面清晰度。" + "媒體加密" + "字母數字" + "安全儲存或證書初始化失敗,請重試或清除應用資料" + "完成" + "完成隱私授權後可檢查更新" + "完成隱私授權後登記本機身份" + "密碼儲存失敗,本次連線仍可使用" + "密碼將加密儲存在本機 Android Keystore 中" + "對端 ID" + "對端 ID " + "對端 ID {0}" + "將刪除本機儲存的所有遠端預覽圖,保留連線記錄和密碼。" + "螢幕方向" + "展開遠端控制選單" + "已從通知斷開遠端連線" + "已儲存密碼" + "已儲存密碼無法讀取,請重新輸入" + "已儲存的密碼未能保留,請重新輸入一次" + "已傳送 Ctrl+Alt+Del" + "已啟用後臺保活,切換應用可繼續保持連線" + "已啟用後臺保活,可從連線通知返回或斷開" + "已授權" + "已讀" + "已連線 " + "已連線伺服器" + "幀率" + "影格率優先" + "平衡" + "應用中的許可檔案缺失或損壞,請重新安裝應用。" + "開發版本包含尚未釋出的修改,以下連結為基礎版本原始碼。" + "啟用儲存" + "開啟隱私屏" + "開源元件" + "開源軟體權利說明" + "當前已是最新版本" + "當前遠端不支援直接輸入此文字,請使用支援文字輸入的被控端版本,或透過剪貼簿傳送" + "成功連線後,這裡會顯示最近的遠端裝置。" + "我已閱讀並同意《隱私政策》" + "所選檔案(無法讀取或空間不足)" + "找不到該裝置 ID" + "指令傳送失敗,請重試" + "指令已傳送,等待電腦確認…" + "授權狀態" + "接收" + "接收 " + "控制端解碼器" + "撤回" + "撤回後將停止遠端連線、關閉畫面預覽儲存並清除已有預覽。連線記錄和密碼會保留,重新連線前需再次授權。" + "撤回聯網授權" + "撤回聯網授權?" + "收起遠端控制選單" + "收起鍵盤" + "收起滑鼠" + "資料" + "檔案儲存失敗,請重試" + "檔案已儲存" + "檔案選擇已超時,會話已結束" + "文字超過 128 KB" + "斷開" + "斷開後將返回首頁" + "斷開遠端連線?" + "中斷連線" + "新版本" + "新版本可用:v" + "新版本可用:v{0}" + "無未讀公告" + "無法儲存本地閱讀狀態,請重試。" + "無法刪除這條公告,請重試。" + "無法發起遠端連線" + "無法讀取開源許可" + "顯示器" + "顯示密碼" + "暫不同意" + "暫無公告" + "最近連線" + "伺服器" + "伺服器 TLS 證書校驗失敗" + "伺服器地址" + "伺服器登入失敗,請檢查伺服器地址和網路" + "伺服器埠" + "伺服器連線超時,請檢查伺服器地址和網路" + "未啟用" + "未找到可開啟連結的瀏覽器" + "未授權" + "未讀" + "未連線伺服器 · 點選重試" + "本應用使用 OpenFEC 提供前向糾錯功能,遵循 CeCILL-C 1.0 許可。該許可規定了有限保證及責任限制,詳情見許可全文。" + "本機 ID " + "本機 ID {0}" + "本版本原始碼與構建說明" + "本版本原始碼資訊暫不可用。" + "鬆開重新整理" + "構建說明" + "構建配方與專案補丁" + "檢視原始碼" + "檢查失敗,請稍後重試" + "檢查更新" + "正在關閉隱私屏…" + "正在建立安全連線…" + "正在開啟隱私屏…" + "正在檢查更新…" + "正在清除…" + "正在獲取本機 ID…" + "正在讀取所選檔案…" + "正在連線" + "正在連線信令伺服器…" + "正在連線伺服器…" + "正在重連伺服器…" + "此裝置沒有可用的檔案選擇器" + "清除" + "清除預覽圖" + "清除預覽圖?" + "原始碼與構建說明" + "原始碼版本" + "版本" + "版權與許可宣告" + "電腦鍵盤" + "畫質優先" + "畫面偏好" + "畫面延遲" + "畫面設定" + "畫面質量" + "畫面採集幀率" + "相對位置" + "相對滑鼠" + "知道了" + "確定" + "確認" + "確認連線" + "離線" + "空白鍵" + "埠範圍為 1–65535" + "符號功能" + "等待電腦返回隱私屏狀態;舊版電腦端可能不支援" + "等待遠端螢幕資訊" + "等待遠端畫面…" + "等待隱私授權" + "系統鍵盤" + "絕對位置" + "絕對滑鼠" + "網路狀態" + "自定義" + "虛擬滑鼠" + "被控端已透過組合鍵解除隱私屏。點選“鎖定”將重新開啟隱私屏,並禁止本機使用組合鍵解鎖。" + "被控端版本過低,請升級到最新版本。" + "被控端編碼器" + "要傳送到遠端的文字" + "影片" + "許可" + "許可與版權宣告" + "許可與版權宣告可離線查閱。" + "裝置身份儲存失敗,請檢查安全儲存" + "裝置身份及選擇儲存的訪問密碼使用 Android Keystore 加密。連線記錄僅儲存在本機,不納入裝置備份。剪貼簿內容在結束會話時清除。離開應用後透過畫中畫或連線通知保持會話,可在應用或通知中斷開。" + "設定" + "設定,有新版本" + "訪問密碼" + "訪問密碼錯誤,請重新輸入" + "證書校驗失敗 · 點選重試" + "請先完成聯網授權" + "請在遠端啟用 CrossDesk 系統服務後重試" + "請求超時,尚未確認電腦的隱私屏狀態" + "請等待當前檔案傳送完成" + "請輸入 1–65535 範圍內的埠" + "請輸入 9 位裝置 ID" + "請輸入有效訪問密碼" + "調整失敗,請重試。" + "軟體許可" + "返回" + "返回控制欄" + "還沒有連線記錄" + "這條公告已更新或刪除,請返回公告列表檢視。" + "遠端任務已關閉" + "遠端桌面" + "遠端桌面觸控區域" + "遠端桌面:輕觸點選,拖動移動,長按右鍵,雙指捏合縮放,放大後雙指拖動畫面,原始比例下雙指上下滑動滾動" + "遠端電腦" + "遠端視窗已關閉,或後臺保活未能啟動,會話已結束" + "遠端連線" + "遠端密碼錯誤" + "遠端已關閉連線" + "遠端當前不可用" + "遠端訪問密碼已失效,請重新連線" + "連線" + "連線 " + "連線失敗" + "連線失敗 · 點選重試" + "連線已斷開" + "連線已結束" + "連線延時(RTT)" + "連線建立後可調整,需被控端支援。" + "連線建立後鎖定橫屏" + "連線提示" + "連線方式" + "連線伺服器" + "連線伺服器後可獲取最新公告。" + "連線超時,請檢查裝置 ID、伺服器及遠端線上狀態" + "連線遠端桌面" + "退格" + "通知公告" + "部分預覽圖未能清除,請重試。" + "重試" + "重試儲存閱讀狀態" + "鎖定" + "鍵盤" + "閱讀並授權" + "隱私" + "隱私與授權" + "隱私屏" + "隱私屏已關閉" + "隱私屏已開啟" + "隱私屏已被解鎖" + "隱私屏異常" + "隱私屏暫不可用" + "隱私屏狀態已過期,等待電腦確認" + "隱私屏狀態待確認" + "隱私政策" + "隱私政策暫時無法讀取,請拒絕聯網並重新安裝應用。" + "靜音" + "音訊" + "專案主頁" + "預覽可能包含遠端電腦上的個人或工作資訊。開啟後,每次連線會自動將一張畫面儲存在本機並顯示在最近連線中。你可以隨時關閉並清除。" + "高" + "預設" + "預設關閉。開啟後,手機連線時進入並保持橫屏;關閉時跟隨裝置方向。平板和多視窗不受影響。" + "滑鼠右鍵,按住並拖動,鬆開結束拖拽" + "滑鼠左鍵,按住並拖動,鬆開結束拖拽" + "滑鼠控制" + "滑鼠滾輪,上下滑動,可滑出按鍵範圍" + ",丟包率 " + ",傳送 " + ",已儲存密碼" + ",接收 " + ",點選重試" + diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml new file mode 100644 index 00000000..5c879a5a --- /dev/null +++ b/apps/android/app/src/main/res/values-de/strings.xml @@ -0,0 +1,308 @@ + + + + " · Abgeschlossen" + " Übertragung fehlgeschlagen" + " Geräte" + " Artikel · " + " ungelesene Artikel" + "CrossDesk Remote-Verbindung" + "GNU GPL Version 3" + "OpenFEC-Hinweis" + "OpenFEC Lizenz und Quelle" + "P2P-Direktverbindung" + "SRTP enabled" + "TURN-Relais" + "{0}-Übertragung fehlgeschlagen" + "Geräte: {0}" + "{0} ungelesene Elemente" + "{0}, Empfangen von {1}, Senden von {2}, Paketverlustrate {3}" + "● Verbunden" + "Zum Aktualisieren nach unten ziehen" + "Verlustrate" + "Mittel" + "Priorisiert die Aufrechterhaltung eines flüssigen Bildes und reduziert die Auflösung stärker, wenn die Bandbreite oder der Codierungsdruck hoch ist." + "Niedrig" + "Verwendung eines benutzerdefinierten Servers" + "Passwort speichern" + "Empfangene Datei speichern" + "Remote-Bildschirmvorschauen speichern" + "Remote-Bildschirmvorschau speichern?" + "Die Signalverbindung ist unterbrochen. Bitte stellen Sie die Verbindung wieder her." + "Das Laden der Ankündigung ist fehlgeschlagen. Bitte versuchen Sie es erneut." + "Einzelheiten zur Ankündigung" + "Insgesamt " + "Insgesamt {0} Artikel ·{1} ungelesene Artikel" + "Ungefähr" + "Über CrossDesk" + "Ungefähr, es gibt eine neue Version" + "Schließen" + "Bedienbügel schließen" + "Privatsphäre-Bildschirm deaktivieren" + "Gleicht Klarheit und Glätte aus und verringert die Auflösung bei konstantem Druck nur allmählich." + "Auflösung" + "Löschen" + "Ansage löschen" + "Datensatz löschen" + "Diese Ankündigung löschen?" + "Ankündigung aktualisieren" + "Zwischenablage" + "Laden…" + "Mehr laden" + "Update empfohlen" + "Die Initialisierung der nativen Verbindung ist fehlgeschlagen" + "Senden" + "Senden " + "Klicken Sie nach dem Senden auf der Remote-Tastatur auf „Einfügen“. Der empfangene Remote-Text kann manuell auf den lokalen Computer kopiert werden." + "Datei senden" + "Text senden" + "Abbrechen" + "Verbindung abbrechen" + "Jede Komponente unterliegt der aufgeführten Open-Source-Lizenz und die gewährten Rechte unterliegen nicht den allgemeinen Nutzungsbedingungen dieser Anwendung. Für die Anzeige des Quellcodes ist eine Internetverbindung erforderlich." + "Insgesamt" + "Zustimmen und fortfahren" + "Bleiben Sie im Hintergrund verbunden. Klicken Sie, um zum Remote-Desktop zurückzukehren" + "Hintergrund-Keepalive konnte nicht gestartet werden. Bitte lassen Sie die Anwendung im Vordergrund" + "Hintergrund-Keepalive konnte nicht gestartet werden. Bitte lassen Sie die Anwendung im Vordergrund und stellen Sie die Verbindung erneut her." + "Die Hintergrundverbindung wurde beendet. Bitte stellen Sie die Verbindung wieder her." + "Der Hintergrundverbindungsdienst wurde beendet. Bitte stellen Sie die Verbindung wieder her." + "Neue Vorschauen werden bei nachfolgenden Verbindungen weiterhin gespeichert." + "Online" + "Geben Sie den Hostnamen oder die IPv4-Adresse ein, ohne Protokoll und Pfad" + "Ton" + "Remote-Text kopieren" + "Behalten Sie immer eine höhere Auflösung bei und reduzieren Sie die Bildrate, um die Bildschärfe zu gewährleisten, wenn die Bandbreite nicht ausreicht." + "Medienverschlüsselung" + "Buchstaben & Zahlen" + "Der sichere Speicher oder die Initialisierung des Zertifikats ist fehlgeschlagen. Bitte versuchen Sie es erneut oder löschen Sie die Anwendungsdaten" + "Fertig" + "Sie können nach Abschluss der Datenschutzautorisierung nach Updates suchen" + "Registrieren Sie die lokale Identität, nachdem Sie die Datenschutzautorisierung abgeschlossen haben" + "Das Speichern des Passworts ist fehlgeschlagen. Diese Verbindung kann weiterhin verwendet werden" + "Passwörter werden verschlüsselt im nativen Android Keystore gespeichert" + "Remote-ID" + "Peer-ID " + "Peer-ID {0}" + "Alle auf diesem Computer gespeicherten Remote-Vorschauen werden gelöscht und die Verbindungsdatensätze und Passwörter bleiben erhalten." + "Bildschirmausrichtung" + "Fernbedienungsmenü erweitern" + "Remote-Verbindung wegen Benachrichtigung getrennt" + "Passwort gespeichert" + "Das gespeicherte Passwort kann nicht gelesen werden, bitte geben Sie es erneut ein." + "Das gespeicherte Passwort kann nicht beibehalten werden, bitte geben Sie es erneut ein." + "Ctrl+Alt+Del gesendet" + "Hintergrund-Keep-Alive ist aktiviert, wechselnde Anwendungen können die Verbindung weiterhin aufrechterhalten" + "Hintergrund-Keepalive aktiviert, um Verbindungsbenachrichtigungen zurückzugeben oder zu trennen" + "Zugegeben" + "Lesen" + "Verbunden " + "Mit Server verbunden" + "Bildrate" + "Flüssig" + "Balance" + "Die Lizenzdatei in der Anwendung fehlt oder ist beschädigt. Bitte installieren Sie die Anwendung neu." + "Die Entwicklungsversion enthält Änderungen, die noch nicht veröffentlicht wurden. Der folgende Link ist der Quellcode der Basisversion." + "Speichern aktivieren" + "Privatsphärenschutz aktivieren" + "Open-Source-Komponenten" + "Beschreibung der Open-Source-Softwarerechte" + "Dies ist derzeit die neueste Version" + "Derzeit unterstützt die Gegenstelle keine direkte Eingabe dieses Textes. Bitte verwenden Sie eine Version des gesteuerten Endes, die die Texteingabe unterstützt, oder senden Sie sie über die Zwischenablage." + "Nach erfolgreicher Verbindung wird hier das nächstgelegene Remote-Gerät angezeigt." + "Ich habe die Datenschutzerklärung gelesen und bin damit einverstanden" + "Ausgewählte Datei (kann nicht gelesen werden oder nicht genügend Speicherplatz)" + "Die Geräte-ID wurde nicht gefunden" + "Das Senden des Befehls ist fehlgeschlagen. Bitte versuchen Sie es erneut" + "Der Befehl wurde gesendet und wartet auf die Bestätigung des Computers ..." + "Autorisierungsstatus" + "Empfangen" + "erhalten " + "Lokaler Decoder" + "Widerrufen" + "Nach dem Abheben wird die Fernverbindung beendet, die Bildschirmvorschau geschlossen und die bestehende Vorschau gelöscht. Der Verbindungsdatensatz und das Passwort bleiben erhalten und vor der erneuten Verbindung ist eine erneute Autorisierung erforderlich." + "Netzwerkberechtigung entziehen" + "Netzwerkberechtigung entziehen?" + "Fernbedienungsmenü einklappen" + "Tastatur ausblenden" + "Maus ausblenden" + "Daten" + "Das Speichern der Datei ist fehlgeschlagen. Bitte versuchen Sie es erneut" + "Datei gespeichert" + "Zeitüberschreitung bei der Dateiauswahl und Sitzung beendet" + "Der Text ist größer als 128 KB" + "Trennen" + "Kehrt nach dem Trennen der Verbindung zur Startseite zurück" + "Remote-Verbindung trennen?" + "Trennen" + "Neue Version" + "Neue Version verfügbar: v" + "Neue Version verfügbar: v{0}" + "Keine ungelesenen Ankündigungen" + "Lesestatus kann nicht lokal gespeichert werden. Bitte versuchen Sie es erneut." + "Diese Ankündigung kann nicht gelöscht werden. Bitte versuchen Sie es erneut." + "Remote-Verbindung konnte nicht initiiert werden" + "Open-Source-Lizenz kann nicht gelesen werden" + "Bildschirm" + "Passwort anzeigen" + "Jetzt nicht" + "Keine Ankündigungen" + "Letzte Verbindungen" + "Server" + "Server TLS certificate-Überprüfung fehlgeschlagen" + "Serveradresse" + "Die Serveranmeldung ist fehlgeschlagen. Bitte überprüfen Sie die Serveradresse und das Netzwerk" + "Server-Port" + "Zeitüberschreitung bei der Serververbindung. Bitte überprüfen Sie die Serveradresse und das Netzwerk" + "Nicht aktiviert" + "Es wurde kein Browser zum Öffnen des Links gefunden" + "Nicht autorisiert" + "Ungelesen" + "Server nicht verbunden · Klicken Sie, um es erneut zu versuchen" + "Diese Anwendung verwendet OpenFEC zur Vorwärtsfehlerkorrektur unterCeCILL-C1.0, was eingeschränkte Garantien und Haftungsbeschränkungen bietet. Einzelheiten finden Sie in der vollständigen Lizenz." + "Lokale ID " + "Lokale ID {0}" + "Quellcode und Build-Anweisungen für diese Version" + "Die Quellrevision ist für diesen Build nicht verfügbar." + "Zum Aktualisieren loslassen" + "Bauanleitung" + "Erstellen Sie Rezepte und Projekt-Patches" + "Quellcode anzeigen" + "Prüfung fehlgeschlagen. Bitte versuchen Sie es später noch einmal." + "Suchen Sie nach Updates" + "Sichtschutz wird geschlossen…" + "Sichere Verbindung wird hergestellt…" + "Privatsphärenschutz einschalten..." + "Suche nach Updates…" + "Löschen..." + "Lokale ID erhalten..." + "Ausgewählte Datei wird gelesen..." + "Verbinden" + "Verbindung zum Signalisierungsserver wird hergestellt..." + "Verbindung zum Server herstellen..." + "Verbindung zum Server wird wiederhergestellt..." + "Für dieses Gerät ist keine Dateiauswahl verfügbar" + "Klar" + "Vorschaubilder löschen" + "Vorschaubilder löschen?" + "Quellcode und Build-Anweisungen" + "Quellcode-Version" + "Version" + "Urheberrechts- und Lizenzerklärung" + "Computertastatur" + "Qualität" + "Videopräferenz" + "Videolatenz" + "Videoeinstellungen" + "Videoqualität" + "Bildrate der Videoaufnahme" + "Touchpad" + "Relative Maus" + "Verstanden" + "Okay" + "Bestätigen" + "Verbindung bestätigen" + "Offline" + "Leertaste" + "Der Portbereich liegt zwischen 1 und 65535" + "Symbole & Tasten" + "Warten Sie, bis der Computer in den Datenschutzstatus zurückkehrt. Ältere Computer unterstützen dies möglicherweise nicht." + "Warten auf Remote-Bildschirminformationen" + "Warten auf den Remote-Bildschirm ..." + "Datenschutzzustimmung ausstehend" + "Systemtastatur" + "Direkte Berührung" + "Absolute Maus" + "Netzwerk" + "Benutzerdefiniert" + "Virtuelle Maus" + "Der Remote-Datenschutzbildschirm wurde über die lokale Verknüpfung entsperrt. Sperren Sie es erneut, um die Privatsphäre wiederherzustellen und das Entsperren lokaler Verknüpfungen zu deaktivieren." + "Die kontrollierte Version ist zu niedrig, bitte aktualisieren Sie auf die neueste Version." + "Remote-Encoder" + "Text, der an die Gegenstelle gesendet werden soll" + "Video" + "Lizenz" + "Lizenzen und Urheberrechtshinweise" + "Die Lizenz- und Urheberrechtshinweise sind offline verfügbar." + "Die Geräteidentität konnte nicht gespeichert werden. Bitte überprüfen Sie den sicheren Speicher" + "Geräteidentität und ausgewählte gespeicherte Zugangskennwörter werden mit Android Keystore verschlüsselt. Verbindungsdatensätze werden nur lokal gespeichert und sind nicht in der Gerätesicherung enthalten. Der Inhalt der Zwischenablage wird gelöscht, wenn die Sitzung beendet wird. Bleiben Sie mit Bild-in-Bild- oder verbundenen Benachrichtigungen in der Sitzung, nachdem Sie die App verlassen haben, und trennen Sie die Verbindung innerhalb der App oder der Benachrichtigungen." + "Einstellungen" + "Einstellungen, es gibt eine neue Version" + "Zugangspasswort" + "Das Zugangspasswort ist falsch, bitte geben Sie es erneut ein." + "Zertifikatsüberprüfung fehlgeschlagen · Klicken Sie, um es erneut zu versuchen" + "Bitte füllen Sie zunächst die Online-Autorisierung aus" + "Bitte aktivieren Sie den CrossDesk-Systemdienst auf der Gegenseite und versuchen Sie es erneut" + "Die Anfrage ist abgelaufen und der Datenschutzstatus des Computers wurde nicht bestätigt." + "Bitte warten Sie, bis die aktuelle Datei gesendet wird." + "Bitte geben Sie einen Port im Bereich 1–65535 ein" + "Geben Sie eine 9-stellige Geräte-ID ein" + "Bitte geben Sie ein gültiges Zugangspasswort ein" + "Einstellungen konnten nicht angewendet werden. Versuchen Sie es erneut." + "Softwarelizenz" + "Zurück" + "Zurück zur Steuerleiste" + "Noch kein Verbindungsdatensatz" + "Diese Ankündigung wurde aktualisiert oder gelöscht. Bitte kehren Sie zur Ankündigungsliste zurück, um sie anzuzeigen." + "Remote-Aufgabe ist geschlossen" + "Remotedesktop" + "Remote-Desktop-Touchbereich" + "Remote-Desktop: Berühren und klicken, zum Verschieben ziehen, die rechte Taste gedrückt halten, zum Zoomen zusammenziehen, hineinzoomen und den Bildschirm mit zwei Fingern ziehen, mit zwei Fingern nach oben und unten streichen, um im Originalmaßstab zu scrollen" + "Remote-Computer" + "Das Remote-Fenster wurde geschlossen oder der Hintergrund-Keepalive konnte nicht gestartet werden und die Sitzung wurde beendet." + "Remote-Verbindung" + "Falsches Remote-Passwort" + "Die Gegenstelle hat die Verbindung geschlossen" + "Die Gegenstelle ist derzeit nicht verfügbar" + "Das Passwort für den Fernzugriff ist abgelaufen. Bitte verbinden Sie sich erneut." + "Verbinden" + "Verbindung " + "Verbindung fehlgeschlagen" + "Verbindung fehlgeschlagen · Klicken Sie, um es erneut zu versuchen" + "Verbindung verloren" + "Verbindung beendet" + "Verbindungsverzögerung (RTT)" + "Verfügbar bei Verbindung mit einem unterstützten Remote-Gerät." + "Querformatbildschirm sperren, nachdem die Verbindung hergestellt wurde" + "Verbindungsaufforderung" + "Verbindungsmethode" + "Mit dem Server verbinden" + "Stellen Sie eine Verbindung zum Server her, um die neuesten Ankündigungen zu erhalten." + "Zeitüberschreitung bei der Verbindung. Bitte überprüfen Sie die Geräte-ID, den Server und den Remote-Online-Status" + "Mit Remote-Desktop verbinden" + "Rücktaste" + "Mitteilungen" + "Einige Vorschauen konnten nicht gelöscht werden. Bitte versuchen Sie es erneut." + "Versuchen Sie es erneut" + "Versuchen Sie erneut, den Lesestatus zu speichern" + "Sperren" + "Tastatur" + "Lesen und autorisieren" + "Datenschutz" + "Datenschutz und Autorisierung" + "Sichtschutz" + "Sichtschutz aus" + "Sichtschutz an" + "Datenschutzbildschirm entsperrt" + "Anomalie des Sichtschutzbildschirms" + "Der Datenschutzbildschirm ist vorübergehend nicht verfügbar" + "Der Status des Datenschutzbildschirms ist abgelaufen und wartet auf Computerbestätigung" + "Status des Datenschutzbildschirms muss bestätigt werden" + "Datenschutzrichtlinie" + "Die Datenschutzerklärung kann vorübergehend nicht gelesen werden. Bitte verweigern Sie die Verbindung zum Internet und installieren Sie die Anwendung neu." + "Stumm" + "Audio" + "Projektwebsite" + "Vorschauen können persönliche oder geschäftliche Informationen vom Remote-Computer enthalten. Nach dem Einschalten speichert jede Verbindung automatisch ein Bild auf dem Gerät und zeigt es in den letzten Verbindungen an. Sie können jederzeit schließen und löschen." + "Hoch" + "Standard" + "Standardmäßig deaktiviert. Wenn es eingeschaltet ist, wird der Bildschirm angezeigt und bleibt im Querformat, wenn das Telefon angeschlossen ist. Wenn es ausgeschaltet ist, folgt es der Richtung des Geräts. Tablets und Multi-Windows sind nicht betroffen." + "Rechte Maustaste, drücken und ziehen, loslassen, um das Ziehen zu beenden" + "Linke Maustaste, drücken und ziehen, loslassen, um das Ziehen zu beenden" + "Maussteuerung" + "Mausrad, nach oben und unten schieben, um aus dem Tastenbereich zu gleiten" + ", Paketverlustrate " + ", senden " + ", Passwort gespeichert" + ", empfangen " + ", klicken Sie auf Wiederholen" + diff --git a/apps/android/app/src/main/res/values-es/strings.xml b/apps/android/app/src/main/res/values-es/strings.xml new file mode 100644 index 00000000..0c98c2fd --- /dev/null +++ b/apps/android/app/src/main/res/values-es/strings.xml @@ -0,0 +1,308 @@ + + + + " · Completado" + " Transferencia fallida" + " dispositivos" + " Artículo · " + " elementos no leídos" + "Conexión remota CrossDesk" + "GNU GPL versión 3" + "Aviso OpenFEC" + "Licencia y fuente OpenFEC" + "Conexión directa P2P" + "SRTP habilitado" + "Relé de GIRO" + "Error en la transmisión {0}" + "Dispositivos: {0}" + "{0} elementos no leídos" + "{0}, recepción de {1}, envío de {2}, tasa de pérdida de paquetes {3}" + "● Conectado" + "Tire hacia abajo para actualizar" + "Tasa de pérdidas" + "Media" + "Da prioridad a mantener la imagen fluida y reducirá la resolución de manera más agresiva cuando el ancho de banda o la presión de codificación sean altos." + "Baja" + "Usando un servidor personalizado" + "Guardar contraseña" + "Guardar archivo recibido" + "Guardar vistas previas de pantalla remotas" + "¿Guardar vista previa de pantalla remota?" + "La conexión de señalización está interrumpida, vuelva a conectarse." + "Error al cargar el anuncio, inténtelo de nuevo." + "Detalles del anuncio" + "totales " + "Total de elementos {0}· Elementos no leídos {1}" + "Acerca de" + "Acerca de CrossDesk" + "Acerca de, hay una nueva versión." + "Cerrar" + "Cerrar barra de control" + "Desactivar la pantalla de privacidad" + "Equilibra la claridad y la suavidad, reduciendo solo gradualmente la resolución bajo presión constante." + "Resolución" + "Eliminar" + "Eliminar anuncio" + "Eliminar registro" + "¿Eliminar este anuncio?" + "Actualizar anuncio" + "Portapapeles" + "Cargando…" + "Cargar más" + "Actualización recomendada" + "Falló la inicialización de la conexión nativa" + "Enviar" + "Enviar " + "Después de enviar, haga clic en \"Pegar\" en el teclado remoto. El texto remoto recibido se puede copiar manualmente a la máquina local." + "Enviar archivo" + "Enviar texto" + "Cancelar" + "Cancelar conexión" + "Cada componente está sujeto a la licencia de código abierto enumerada y los derechos otorgados no están sujetos a los términos generales de uso de esta aplicación. Para ver el código fuente se requiere una conexión a Internet." + "Total" + "Aceptar y continuar" + "Manténgase conectado en segundo plano, haga clic para regresar al escritorio remoto" + "No se pudo iniciar el mantenimiento en segundo plano; mantenga la aplicación en primer plano" + "No se pudo iniciar el mantenimiento en segundo plano. Mantenga la aplicación en primer plano y vuelva a conectarse." + "La conexión en segundo plano ha finalizado; vuelva a conectarse." + "El servicio de conexión en segundo plano se detuvo; vuelva a conectarse." + "Las nuevas vistas previas aún se guardarán en conexiones posteriores." + "En línea" + "Complete el nombre del host o la dirección IPv4, sin protocolo ni ruta" + "Sonido" + "Copiar texto remoto" + "Mantenga siempre una resolución más alta y reduzca la velocidad de fotogramas para garantizar la claridad de la imagen cuando el ancho de banda sea insuficiente." + "Cifrado de medios" + "Letras y números" + "Error en el almacenamiento seguro o en la inicialización del certificado. Inténtelo de nuevo o borre los datos de la aplicación." + "Hecho" + "Puede buscar actualizaciones después de completar la autorización de privacidad" + "Registre la identidad local después de completar la autorización de privacidad" + "Error al guardar la contraseña, esta conexión aún se puede utilizar" + "Las contraseñas se guardan cifradas en el almacén de claves nativo de Android" + "Identificación remota" + "Identificación de pares " + "ID de igual {0}" + "Se eliminarán todas las vistas previas remotas guardadas en esta máquina y se conservarán los registros de conexión y las contraseñas." + "Orientación de la pantalla" + "Ampliar el menú del control remoto" + "Conexión remota desconectada de la notificación" + "Contraseña guardada" + "La contraseña guardada no se puede leer; vuelva a ingresarla." + "La contraseña guardada no se puede conservar; vuelva a ingresarla." + "Ctrl+Alt+Del enviado" + "Mantener vivo en segundo plano está habilitado, cambiar de aplicación puede continuar manteniendo la conexión" + "Keepalive en segundo plano habilitado para regresar o desconectarse de las notificaciones de conexión" + "Concedido" + "Leer" + "Conectado " + "Conectado al servidor" + "Velocidad de fotogramas" + "Fluidez" + "Equilibrado" + "El archivo de licencia de la aplicación falta o está dañado; reinstale la aplicación." + "La versión de desarrollo contiene modificaciones que aún no han sido publicadas. El siguiente enlace es el código fuente de la versión básica." + "Activar guardado" + "Habilitar pantalla de privacidad" + "Componentes de código abierto" + "Descripción de los derechos del software de código abierto" + "Esta es actualmente la última versión." + "Actualmente, el extremo remoto no admite la entrada directa de este texto. Utilice una versión del extremo controlado que admita la entrada de texto o envíela a través del portapapeles." + "Tras una conexión exitosa, aquí se mostrará el dispositivo remoto más cercano." + "He leído y acepto la Política de Privacidad" + "Archivo seleccionado (no se puede leer o no hay suficiente espacio)" + "No se encontró el ID del dispositivo" + "Error al enviar el comando, inténtelo de nuevo" + "El comando ha sido enviado, esperando confirmación por computadora..." + "Estado de autorización" + "Recibir" + "recibir " + "Decodificador local" + "Retirar" + "Después de retirarse, se detendrá la conexión remota, se cerrará la vista previa de la pantalla y se borrará la vista previa existente. El registro de conexión y la contraseña se conservarán y se requerirá autorización nuevamente antes de volver a conectarse." + "Retirar la autorización de red" + "¿Retirar la autorización de la red?" + "Contraer menú de control remoto" + "Ocultar teclado" + "Ocultar ratón" + "Datos" + "Error al guardar el archivo, inténtelo de nuevo" + "Archivo guardado" + "Se agotó el tiempo de selección de archivos y la sesión finalizó" + "El texto supera los 128 KB" + "Desconectar" + "Volverá a la página de inicio después de desconectarse" + "¿Desconectar la conexión remota?" + "Desconectar" + "Nueva versión" + "Nueva versión disponible :v" + "Nueva versión disponible: v{0}" + "No hay anuncios no leídos" + "No se puede guardar el estado de lectura localmente. Por favor inténtalo de nuevo." + "No se puede eliminar este anuncio. Por favor inténtalo de nuevo." + "No se puede iniciar la conexión remota" + "No se puede leer la licencia de código abierto" + "Pantalla" + "Mostrar contraseña" + "Ahora no" + "Sin anuncios" + "Conexiones recientes" + "Servidor" + "Error en la verificación del certificado Server TLS" + "Dirección del servidor" + "Error al iniciar sesión en el servidor; verifique la dirección y la red del servidor" + "Puerto del servidor" + "Se agotó el tiempo de espera de la conexión del servidor; verifique la dirección y la red del servidor." + "No habilitado" + "No se encontró ningún navegador para abrir el enlace." + "No autorizado" + "No leído" + "Servidor no conectado · Haga clic para intentar nuevamente" + "Esta aplicación utiliza OpenFEC para la corrección de errores directos bajoCeCILL-C1.0, que proporciona garantías limitadas y limita la responsabilidad. Consulte la licencia completa para obtener más detalles." + "Identificación local " + "ID local {0}" + "Código fuente e instrucciones de compilación para esta versión" + "La revisión fuente no está disponible para esta compilación." + "Suelte para actualizar" + "Instrucciones de construcción" + "Crear recetas y parches de proyectos" + "Ver código fuente" + "La verificación falló. Inténtelo de nuevo más tarde." + "Buscar actualizaciones" + "Cerrando la pantalla de privacidad..." + "Estableciendo una conexión segura..." + "Activando la pantalla de privacidad..." + "Buscando actualizaciones..." + "Borrando..." + "Obtención de identificación local..." + "Leyendo el archivo seleccionado..." + "Conexión" + "Conectándose al servidor de señalización..." + "Conectándose al servidor..." + "Reconectándose al servidor..." + "No hay selector de archivos disponible para este dispositivo" + "Borrar" + "Borrar vistas previas" + "¿Borrar vistas previas?" + "Código fuente e instrucciones de compilación" + "Versión del código fuente" + "Versión" + "Declaración de derechos de autor y licencia" + "Teclado de computadora" + "Calidad" + "Preferencia de vídeo" + "Latencia de vídeo" + "Configuración de vídeo" + "Calidad de vídeo" + "Velocidad de fotogramas de captura de vídeo" + "Panel táctil" + "Ratón relativo" + "Entendido" + "Aceptar" + "Confirmar" + "Confirmar conexión" + "Sin conexión" + "Espacio" + "El rango de puertos es 1–65535" + "Símbolos y teclas" + "Espere a que la computadora vuelva al estado de pantalla de privacidad; Es posible que las computadoras más antiguas no lo admitan." + "Esperando información de la pantalla remota" + "Esperando la pantalla remota..." + "Esperando autorización de privacidad" + "Teclado del sistema" + "Toque directo" + "Ratón absoluto" + "Red" + "Personalizado" + "Ratón virtual" + "La pantalla de privacidad remota se desbloqueó usando el acceso directo local. Bloquéelo nuevamente para restaurar la privacidad y deshabilitar el desbloqueo de accesos directos locales." + "La versión controlada es demasiado baja; actualice a la última versión." + "Codificador remoto" + "Texto a enviar al extremo remoto" + "Vídeo" + "Licencia" + "Licencias y avisos de derechos de autor" + "La licencia y el aviso de derechos de autor están disponibles sin conexión." + "No se pudo guardar la identidad del dispositivo; verifique el almacenamiento seguro" + "La identidad del dispositivo y las contraseñas de acceso guardadas seleccionadas se cifran mediante Android Keystore. Los registros de conexión solo se guardan localmente y no se incluyen en la copia de seguridad del dispositivo. El contenido del portapapeles se borra cuando finaliza la sesión. Manténgase en sesión con imagen en imagen o notificaciones conectadas después de salir de la aplicación y desconéctese dentro de la aplicación o las notificaciones." + "Ajustes" + "Configuración, hay una nueva versión." + "Contraseña de acceso" + "La contraseña de acceso es incorrecta, por favor vuelva a ingresarla." + "Error en la verificación del certificado · Haga clic para intentar nuevamente" + "Primero complete la autorización en línea" + "Habilite el servicio del sistema CrossDesk en el extremo remoto y vuelva a intentarlo." + "Se agotó el tiempo de espera de la solicitud y no se ha confirmado el estado de la pantalla de privacidad de la computadora." + "Espere a que se envíe el archivo actual." + "Ingrese un puerto en el rango 1–65535" + "Ingrese una ID de dispositivo de 9 dígitos" + "Por favor ingrese una contraseña de acceso válida" + "No se pudieron aplicar las configuraciones. Intentar otra vez." + "Licencia de software" + "Volver" + "Volver a la barra de control" + "Aún no hay registro de conexión" + "Este anuncio ha sido actualizado o eliminado, regrese a la lista de anuncios para verlo." + "La tarea remota está cerrada" + "Escritorio remoto" + "Área táctil del escritorio remoto" + "Escritorio remoto: toque y haga clic, arrastre para mover, presione y mantenga presionado el botón derecho, pellizque para hacer zoom, acerque y arrastre la pantalla con dos dedos, deslice hacia arriba y hacia abajo con dos dedos para desplazarse a la escala original" + "Computadora remota" + "La ventana remota se cerró o el mantenimiento en segundo plano no se pudo iniciar y la sesión finalizó." + "Conexión remota" + "Contraseña remota incorrecta" + "El extremo remoto ha cerrado la conexión" + "El extremo remoto no está disponible actualmente" + "La contraseña de acceso remoto ha caducado, vuelva a conectarse." + "Conectar" + "Conexión " + "Error de conexión" + "Error de conexión · Haga clic para intentarlo de nuevo" + "Conexión perdida" + "Conexión finalizada" + "Retardo de conexión (RTT)" + "Disponible cuando se conecta a un dispositivo remoto compatible." + "Bloquear la pantalla horizontal después de establecer la conexión" + "Aviso de conexión" + "Método de conexión" + "Conectarse al servidor" + "Conéctese al servidor para obtener los últimos anuncios." + "Se agotó el tiempo de conexión; verifique el ID del dispositivo, el servidor y el estado en línea remoto" + "Conectarse al escritorio remoto" + "Retroceso" + "Anuncios" + "Algunas vistas previas no se pudieron borrar, inténtalo de nuevo." + "Inténtalo de nuevo" + "Reintentar guardar el estado de lectura" + "Bloquear" + "Teclado" + "Leer y autorizar" + "Privacidad" + "Privacidad y autorización" + "Pantalla de privacidad" + "Privacidad desactivada" + "Privacidad activada" + "Pantalla de privacidad desbloqueada" + "Anormalidad en la pantalla de privacidad" + "La pantalla de privacidad no está disponible temporalmente" + "El estado de la pantalla de privacidad ha caducado, esperando confirmación por computadora" + "Estado de la pantalla de privacidad por confirmar" + "Política de privacidad" + "La política de privacidad no se puede leer temporalmente. Rechace conectarse a Internet y reinstale la aplicación." + "Silencio" + "Audio" + "Sitio web del proyecto" + "Las vistas previas pueden contener información personal o laboral de la computadora remota. Después de encenderlo, cada conexión guardará automáticamente una imagen en la máquina y la mostrará en las conexiones recientes. Puedes cerrar y borrar en cualquier momento." + "Alta" + "Predeterminado" + "Desactivado de forma predeterminada. Cuando esté encendido, la pantalla entrará y permanecerá en orientación horizontal cuando el teléfono esté conectado; cuando esté apagado, seguirá la dirección del dispositivo. Las tabletas y las ventanas múltiples no se ven afectadas." + "Botón derecho del mouse, presione y arrastre, suelte para finalizar el arrastre" + "Botón izquierdo del mouse, presione y arrastre, suelte para finalizar el arrastre" + "Control del ratón" + "Rueda del mouse, deslícela hacia arriba y hacia abajo para salir del rango de teclas" + ", tasa de pérdida de paquetes " + ", enviar " + ", contraseña guardada" + ", recibir " + ", haga clic en Reintentar" + diff --git a/apps/android/app/src/main/res/values-fr/strings.xml b/apps/android/app/src/main/res/values-fr/strings.xml new file mode 100644 index 00000000..37524a15 --- /dev/null +++ b/apps/android/app/src/main/res/values-fr/strings.xml @@ -0,0 +1,308 @@ + + + + " · Terminé" + " Échec du transfert" + " appareils" + " Article · " + " éléments non lus" + "Connexion à distance CrossDesk" + "GNU GPL version 3" + "Avis OpenFEC" + "Licence et source OpenFEC" + "Connexion directe P2P" + "SRTP activé" + "Relais TOUR" + "Échec de la transmission {0}" + "Appareils : {0}" + "Éléments non lus {0}" + "{0}, réception de {1}, envoi de {2}, taux de perte de paquets {3}" + "● Connecté" + "Déroulez pour actualiser" + "Taux de perte" + "Moyenne" + "Donne la priorité au maintien de la fluidité de l\'image et réduira la résolution de manière plus agressive lorsque la bande passante ou la pression d\'encodage est élevée." + "Faible" + "Utilisation d\'un serveur personnalisé" + "Enregistrer le mot de passe" + "Enregistrer le fichier reçu" + "Enregistrer les aperçus de l\'écran distant" + "Enregistrer l\'aperçu de l\'écran distant ?" + "La connexion de signalisation est interrompue, veuillez vous reconnecter." + "Le chargement de l\'annonce a échoué, veuillez réessayer." + "Détails de l\'annonce" + "Total " + "Total des éléments {0}· Éléments non lus {1}" + "À propos" + "À propos de CrossDesk" + "À propos, il existe une nouvelle version" + "Fermer" + "Fermer la barre de contrôle" + "Désactiver l\'écran de confidentialité" + "Équilibre la clarté et la douceur, en réduisant seulement progressivement la résolution sous une pression constante." + "Résolution" + "Supprimer" + "Supprimer l\'annonce" + "Supprimer l\'enregistrement" + "Supprimer cette annonce ?" + "Actualiser l\'annonce" + "Presse-papiers" + "Chargement…" + "Charger plus" + "Mise à jour conseillée" + "L\'initialisation de la connexion native a échoué" + "Envoi" + "Envoyer " + "Après l\'envoi, cliquez sur \"Coller\" sur le clavier distant. Le texte distant reçu peut être copié manuellement sur la machine locale." + "Envoyer le fichier" + "Envoyer un SMS" + "Annuler" + "Annuler la connexion" + "Chaque composant est soumis à la licence open source répertoriée, et les droits accordés ne sont pas soumis aux conditions générales d\'utilisation de cette application. La visualisation du code source nécessite une connexion Internet." + "Total" + "Accepter et continuer" + "Restez connecté en arrière-plan, cliquez pour revenir au bureau distant" + "Échec du démarrage de Keepalive en arrière-plan, veuillez conserver l\'application au premier plan" + "L\'application Keepalive en arrière-plan n\'a pas pu démarrer. Veuillez conserver l\'application au premier plan et vous reconnecter." + "La connexion en arrière-plan est terminée, veuillez vous reconnecter." + "Le service de connexion en arrière-plan s\'est arrêté, veuillez vous reconnecter." + "Les nouveaux aperçus seront toujours enregistrés lors des connexions ultérieures." + "En ligne" + "Remplissez le nom d\'hôte ou l\'adresse IPv4, sans protocole ni chemin" + "Son" + "Copier le texte distant" + "Maintenez toujours une résolution plus élevée et réduisez la fréquence d\'images pour garantir la clarté de l\'image lorsque la bande passante est insuffisante." + "Cryptage multimédia" + "Lettres et chiffres" + "Échec du stockage sécurisé ou de l\'initialisation du certificat. Veuillez réessayer ou effacer les données de l\'application." + "Terminé" + "Vous pouvez vérifier les mises à jour après avoir terminé l\'autorisation de confidentialité" + "Enregistrez l\'identité locale après avoir terminé l\'autorisation de confidentialité" + "L\'enregistrement du mot de passe a échoué, cette connexion peut toujours être utilisée" + "Les mots de passe sont enregistrés cryptés dans le Keystore Android natif" + "ID à distance" + "Identification des pairs " + "ID homologue {0}" + "Tous les aperçus à distance enregistrés sur cette machine seront supprimés et les enregistrements de connexion et les mots de passe seront conservés." + "Orientation de l\'écran" + "Développer le menu de la télécommande" + "Connexion à distance déconnectée de la notification" + "Mot de passe enregistré" + "Le mot de passe enregistré ne peut pas être lu, veuillez le saisir à nouveau." + "Le mot de passe enregistré ne peut pas être conservé, veuillez le saisir à nouveau." + "Ctrl+Alt+Del envoyé" + "Le maintien de l\'activité en arrière-plan est activé, les applications de commutation peuvent continuer à maintenir la connexion." + "Keepalive en arrière-plan activé pour revenir ou se déconnecter des notifications de connexion" + "Accordé" + "Lire" + "Connecté " + "Connecté au serveur" + "Fréquence d\'images" + "Fluidité" + "Équilibré" + "Le fichier de licence dans l\'application est manquant ou endommagé, veuillez réinstaller l\'application." + "La version de développement contient des modifications qui n\'ont pas encore été publiées. Le lien suivant est le code source de la version de base." + "Activer l’enregistrement" + "Activer l\'écran de confidentialité" + "Composants open source" + "Description des droits sur les logiciels open source" + "Il s\'agit actuellement de la dernière version" + "Actuellement, l\'extrémité distante ne prend pas en charge la saisie directe de ce texte. Veuillez utiliser une version de l\'extrémité contrôlée qui prend en charge la saisie de texte ou envoyez-la via le presse-papiers." + "Une fois la connexion réussie, l\'appareil distant le plus proche sera affiché ici." + "J\'ai lu et accepté la politique de confidentialité" + "Fichier sélectionné (impossible en lecture ou espace insuffisant)" + "L\'ID de l\'appareil n\'a pas été trouvé" + "L\'envoi de la commande a échoué, veuillez réessayer" + "La commande a été envoyée, en attente de confirmation informatique..." + "Statut d\'autorisation" + "Réception" + "recevoir " + "Décodeur local" + "Retirer" + "Après le retrait, la connexion à distance sera arrêtée, l\'aperçu de l\'écran sera fermé et l\'aperçu existant sera effacé. L\'enregistrement de connexion et le mot de passe seront conservés et une autorisation sera à nouveau requise avant de se reconnecter." + "Retirer l\'autorisation réseau" + "Retirer l\'autorisation réseau ?" + "Réduire le menu de la télécommande" + "Masquer le clavier" + "Masquer la souris" + "Données" + "L\'enregistrement du fichier a échoué, veuillez réessayer" + "Fichier enregistré" + "La sélection de fichier a expiré et la session s\'est terminée" + "Le texte dépasse 128 Ko" + "Déconnecter" + "Reviendra à la page d\'accueil après la déconnexion" + "Déconnecter la connexion à distance ?" + "Déconnecter" + "Nouvelle version" + "Nouvelle version disponible : v" + "Nouvelle version disponible : v{0}" + "Aucune annonce non lue" + "Impossible d\'enregistrer l\'état de lecture localement. Veuillez réessayer." + "Impossible de supprimer cette annonce. Veuillez réessayer." + "Impossible d\'établir une connexion à distance" + "Impossible de lire la licence open source" + "Écran" + "Afficher le mot de passe" + "Pas maintenant" + "Aucune annonce" + "Connexions récentes" + "Serveur" + "La vérification du certificat Server TLS a échoué" + "Adresse du serveur" + "Échec de la connexion au serveur, veuillez vérifier l\'adresse du serveur et le réseau" + "Port du serveur" + "La connexion au serveur a expiré, veuillez vérifier l\'adresse du serveur et le réseau" + "Non activé" + "Aucun navigateur trouvé pour ouvrir le lien" + "Non autorisé" + "Non lu" + "Serveur non connecté · Cliquez pour réessayer" + "Cette application utilise OpenFEC pour la correction d\'erreur directe sousCeCILL-C1.0, qui offre des garanties limitées et limite la responsabilité. Consultez la licence complète pour plus de détails." + "ID local " + "ID local {0}" + "Code source et instructions de construction pour cette version" + "La révision source n\'est pas disponible pour cette version." + "Relâchez pour actualiser" + "Instructions de construction" + "Créer des recettes et des correctifs de projet" + "Afficher le code source" + "La vérification a échoué. Veuillez réessayer plus tard." + "Rechercher des mises à jour" + "Fermeture de l\'écran de confidentialité…" + "Établir une connexion sécurisée…" + "Activation de l\'écran de confidentialité..." + "Vérification des mises à jour…" + "Effacement..." + "Obtention d\'une pièce d\'identité locale..." + "Lecture du fichier sélectionné..." + "Connexion" + "Connexion au serveur de signalisation..." + "Connexion au serveur..." + "Reconnexion au serveur..." + "Aucun sélecteur de fichiers disponible pour cet appareil" + "Effacer" + "Supprimer les aperçus" + "Supprimer les aperçus ?" + "Code source et instructions de construction" + "Version du code source" + "Version" + "Déclaration de droits d\'auteur et de licence" + "Clavier d\'ordinateur" + "Qualité" + "Préférence vidéo" + "Latence vidéo" + "Paramètres vidéo" + "Qualité vidéo" + "Fréquence d\'images de capture vidéo" + "Pavé tactile" + "Souris relative" + "Compris" + "D\'accord" + "Confirmer" + "Confirmer la connexion" + "Hors ligne" + "Espace" + "La plage de ports est comprise entre 1 et 65 535." + "Symboles et touches" + "Attendez que l\'ordinateur revienne à l\'état de l\'écran de confidentialité ; les ordinateurs plus anciens peuvent ne pas le prendre en charge." + "En attente d\'informations sur l\'écran distant" + "En attente de l\'écran distant..." + "En attente d\'une autorisation de confidentialité" + "Clavier système" + "Toucher direct" + "Souris absolue" + "Réseau" + "Personnalisé" + "Souris virtuelle" + "L\'écran de confidentialité à distance a été déverrouillé à l\'aide du raccourci local. Verrouillez-le à nouveau pour restaurer la confidentialité et désactiver le déverrouillage des raccourcis locaux." + "La version contrôlée est trop basse, veuillez mettre à niveau vers la dernière version." + "Encodeur déporté" + "Texte à envoyer à l\'extrémité distante" + "Vidéo" + "Licence" + "Licences et mentions de droits d\'auteur" + "La licence et la notice de copyright sont disponibles hors ligne." + "L\'identité de l\'appareil n\'a pas pu être enregistrée. Veuillez vérifier le stockage sécurisé." + "L\'identité de l\'appareil et les mots de passe d\'accès enregistrés sélectionnés sont cryptés à l\'aide d\'Android Keystore. Les enregistrements de connexion sont uniquement enregistrés localement et ne sont pas inclus dans la sauvegarde de l\'appareil. Le contenu du presse-papiers est effacé à la fin de la session. Restez en session avec des notifications d\'image dans l\'image ou connectées après avoir quitté l\'application, et déconnectez-vous de l\'application ou des notifications." + "Réglages" + "Paramètres, il existe une nouvelle version" + "Mot de passe d\'accès" + "Le mot de passe d\'accès est erroné, veuillez le saisir à nouveau." + "Échec de la vérification du certificat · Cliquez pour réessayer" + "Veuillez d\'abord remplir l\'autorisation en ligne" + "Veuillez activer le service système CrossDesk sur l\'extrémité distante et réessayer." + "Le délai de demande a expiré et l\'état de l\'écran de confidentialité de l\'ordinateur n\'a pas été confirmé." + "Veuillez attendre que le fichier actuel soit envoyé." + "Veuillez saisir un port compris entre 1 et 65535." + "Saisissez un identifiant d\'appareil à 9 chiffres" + "Veuillez saisir un mot de passe d\'accès valide" + "Impossible d\'appliquer les paramètres. Essayer à nouveau." + "Licence du logiciel" + "Retour" + "Retour à la barre de contrôle" + "Aucun enregistrement de connexion pour l\'instant" + "Cette annonce a été mise à jour ou supprimée, veuillez revenir à la liste des annonces pour la consulter." + "La tâche distante est fermée" + "Bureau à distance" + "Zone tactile du bureau à distance" + "Bureau à distance : touchez et cliquez, faites glisser pour déplacer, appuyez et maintenez le bouton droit enfoncé, pincez pour zoomer, zoomez et faites glisser l\'écran avec deux doigts, faites glisser de haut en bas avec deux doigts pour faire défiler à l\'échelle d\'origine." + "Ordinateur distant" + "La fenêtre distante a été fermée ou le keepalive en arrière-plan n\'a pas pu démarrer et la session est terminée." + "Connexion à distance" + "Mot de passe distant incorrect" + "L\'extrémité distante a fermé la connexion" + "L\'extrémité distante est actuellement indisponible" + "Le mot de passe d\'accès à distance a expiré, veuillez vous reconnecter." + "Connecter" + "Connexion " + "Échec de la connexion" + "Échec de la connexion · Cliquez pour réessayer" + "Connexion perdue" + "Connexion terminée" + "Délai de connexion (RTT)" + "Disponible lors de la connexion à un appareil distant pris en charge." + "Verrouiller l\'écran paysage une fois la connexion établie" + "Invite de connexion" + "Méthode de connexion" + "Connectez-vous au serveur" + "Connectez-vous au serveur pour recevoir les dernières annonces." + "La connexion a expiré. Veuillez vérifier l\'ID de l\'appareil, le serveur et l\'état en ligne à distance." + "Connectez-vous au bureau à distance" + "Retour arrière" + "Annonces" + "Certains aperçus n\'ont pas pu être effacés, veuillez réessayer." + "Réessayez" + "Réessayez d\'enregistrer l\'état de lecture" + "Verrouillage" + "Clavier" + "Lire et autoriser" + "Confidentialité" + "Confidentialité et autorisation" + "Écran de confidentialité" + "Confidentialité inactive" + "Confidentialité active" + "Écran de confidentialité déverrouillé" + "Anomalie de l\'écran de confidentialité" + "L\'écran de confidentialité est temporairement indisponible" + "L\'état de l\'écran de confidentialité a expiré, en attente de confirmation par l\'ordinateur" + "Statut de l\'écran de confidentialité à confirmer" + "Politique de confidentialité" + "La politique de confidentialité ne peut pas être lue temporairement. Veuillez refuser de vous connecter à Internet et réinstaller l\'application." + "Muet" + "Audio" + "Site Web du projet" + "Les aperçus peuvent contenir des informations personnelles ou professionnelles provenant de l\'ordinateur distant. Après l\'avoir allumé, chaque connexion enregistrera automatiquement une image sur la machine et l\'affichera dans les connexions récentes. Vous pouvez fermer et effacer à tout moment." + "Élevée" + "Par défaut" + "Désactivé par défaut. Lorsqu\'il est allumé, l\'écran entre et reste en orientation paysage lorsque le téléphone est connecté ; lorsqu\'il est éteint, il suivra la direction de l\'appareil. Les tablettes et multi-fenêtres ne sont pas concernées." + "Bouton droit de la souris, appuyez et faites glisser, relâchez pour terminer le glisser" + "Bouton gauche de la souris, appuyez et faites glisser, relâchez pour terminer le glisser" + "Contrôle de la souris" + "Molette de la souris, faites-la glisser de haut en bas pour sortir de la plage de touches" + ", taux de perte de paquets " + ", envoyer " + ", mot de passe enregistré" + ", recevoir " + ", cliquez sur Réessayer" + diff --git a/apps/android/app/src/main/res/values-ja/strings.xml b/apps/android/app/src/main/res/values-ja/strings.xml new file mode 100644 index 00000000..f766d11e --- /dev/null +++ b/apps/android/app/src/main/res/values-ja/strings.xml @@ -0,0 +1,308 @@ + + + + " ・完了" + " 転送に失敗しました" + " 台のデバイス" + " 記事 ・ " + " 未読項目" + "CrossDeskリモート接続" + "GNU GPL バージョン 3" + "OpenFEC通知" + "OpenFECライセンスとソース" + "P2P直接接続" + "SRT有効" + "ターンリレー" + "{0}送信失敗" + "デバイス数: {0}" + "{0}の未読アイテム" + "{0}、受信{1}、送信{2}、パケットロス率{3}" + "● 接続されました" + "プルダウンして更新します" + "損失率" + "中" + "画像を滑らかに保つことを優先し、帯域幅やエンコード圧力が高い場合には、より積極的に解像度を下げます。" + "低" + "カスタムサーバーの使用" + "パスワードの保存" + "受信したファイルを保存する" + "リモート画面のプレビューを保存する" + "リモート画面のプレビューを保存しますか?" + "信号接続が中断されました。再接続してください。" + "お知らせを読み込めませんでした。再試行してください。" + "発表内容" + "合計 " + "合計{0}個のアイテム ·{1}個の未読アイテム" + "概要" + "CrossDesk について" + "について、新しいバージョンがあります" + "閉じる" + "コントロールバーを閉じる" + "プライバシー画面を無効にする" + "明瞭さと滑らかさのバランスを保ち、一定の圧力下で解像度を徐々に低下させるだけです。" + "解像度" + "削除" + "お知らせの削除" + "レコードの削除" + "このお知らせを削除しますか?" + "リフレッシュのお知らせ" + "クリップボード" + "読み込み中…" + "さらに読み込む" + "更新のご案内" + "ネイティブ接続の初期化に失敗しました" + "送信" + "送信 " + "送信後、リモートキーボードの「貼り付け」をクリックしてください。受信したリモート テキストはローカル マシンに手動でコピーできます。" + "ファイル送信" + "テキストを送信する" + "キャンセル" + "接続をキャンセルする" + "各コンポーネントは、リストされているオープン ソース ライセンスの対象となり、付与された権利は、このアプリケーションの一般的な使用条件の対象ではありません。ソース コードを表示するには、インターネット接続が必要です。" + "合計" + "同意して続行" + "バックグラウンドで接続を維持し、クリックしてリモート デスクトップに戻ります" + "バックグラウンドのキープアライブを開始できませんでした。アプリケーションをフォアグラウンドで維持してください。" + "バックグラウンド キープアライブの開始に失敗しました。アプリケーションをフォアグラウンドに保ち、再接続してください。" + "バックグラウンド接続が終了しました。再接続してください。" + "バックグラウンド接続サービスが停止しました。再接続してください。" + "新しいプレビューはその後の接続でも保存されます。" + "オンライン" + "プロトコルとパスを除いて、ホスト名または IPv4 アドレスを入力します。" + "サウンド" + "リモートテキストをコピーする" + "帯域幅が不十分な場合は、常に高い解像度を維持し、フレーム レートを下げて画像の鮮明さを確保します。" + "メディアの暗号化" + "英数字" + "安全なストレージまたは証明書の初期化に失敗しました。再試行するか、アプリケーション データをクリアしてください。" + "完了" + "プライバシー認証を完了すると、アップデートを確認できます" + "プライバシー認証完了後、ローカル ID を登録します" + "パスワードの保存に失敗しました。この接続はまだ使用できます" + "パスワードは暗号化されてネイティブ Android キーストアに保存されます" + "リモートID" + "ピアID " + "ピアID{0}" + "本機に保存されているリモートプレビューはすべて削除され、接続記録とパスワードは保持されます。" + "画面の向き" + "リモコンメニューを展開する" + "通知によりリモート接続が切断されました" + "パスワード保存済み" + "保存したパスワードが読み取れないため、再入力してください。" + "保存したパスワードは保持できませんので、再度入力してください。" + "Ctrl+Alt+Delを送信しました" + "バックグラウンドキープアライブが有効になり、アプリケーションを切り替えて接続を維持し続けることができます。" + "バックグラウンドキープアライブを有効にして、接続通知を返すか接続を切断することができます" + "認められる" + "読む" + "接続されました " + "サーバーに接続しました" + "フレームレート" + "滑らかさ" + "バランス" + "アプリケーション内のライセンス ファイルが見つからないか破損しています。アプリケーションを再インストールしてください。" + "開発バージョンには、まだリリースされていない修正が含まれています。以下のリンクは基本バージョンのソースコードです。" + "保存を有効にする" + "プライバシー画面を有効にする" + "オープンソースコンポーネント" + "オープンソース ソフトウェアの権利の説明" + "これが現在の最新バージョンです" + "現在、リモート エンドはこのテキストの直接入力をサポートしていません。テキスト入力をサポートするバージョンのコントロール エンドを使用するか、クリップボード経由で送信してください。" + "接続に成功すると、最も近いリモート デバイスがここに表示されます。" + "プライバシーポリシーを読んで同意します" + "選択したファイル(読み込み不可、または容量不足)" + "デバイスIDが見つかりませんでした" + "コマンドの送信に失敗しました。もう一度お試しください。" + "コマンドが送信され、コンピューターの確認を待っています..." + "認可ステータス" + "受信" + "受け取る " + "ローカルデコーダ" + "撤回" + "退会後はリモート接続が停止され、画面プレビューが閉じられ、既存のプレビューが消去されます。接続記録とパスワードは保持され、再接続する前に再度認証が必要になります。" + "ネットワーク認証の撤回" + "ネットワーク認証を取り消しますか?" + "リモコンメニューを折りたたむ" + "キーボードを隠す" + "マウスを隠す" + "データ" + "ファイルの保存に失敗しました。もう一度お試しください。" + "ファイルを保存しました" + "ファイル選択がタイムアウトし、セッションが終了しました" + "テキストが128KBを超えています" + "切断" + "切断後ホームページに戻ります" + "リモート接続を切断しますか?" + "切断" + "新しいバージョン" + "利用可能な新しいバージョン: v" + "利用可能な新しいバージョン: v{0}" + "未読のお知らせはありません" + "読み取りステータスをローカルに保存できません。もう一度試してください。" + "このお知らせは削除できません。もう一度試してください。" + "リモート接続を開始できません" + "オープンソースライセンスを読み取れません" + "ディスプレイ" + "パスワードを表示" + "今は同意しない" + "アナウンスはありません" + "最近の接続" + "サーバー" + "ServerTLS証明書の検証に失敗しました" + "サーバーアドレス" + "サーバーへのログインに失敗しました。サーバーのアドレスとネットワークを確認してください。" + "サーバーポート" + "サーバー接続がタイムアウトしました。サーバーのアドレスとネットワークを確認してください。" + "有効ではありません" + "リンクを開くブラウザが見つかりませんでした" + "無許可" + "未読" + "サーバーが接続されていません · クリックして再試行してください" + "このアプリケーションは、限定保証を提供し、責任を制限するCeCILL-C1.0 に基づく前方誤り訂正にOpenFECを使用します。詳細については、完全なライセンスを参照してください。" + "ローカルID " + "ローカルID{0}" + "このバージョンのソース コードとビルド手順" + "このビルドではソース リビジョンが利用できません。" + "放してリフレッシュ" + "組み立て説明書" + "ビルドレシピとプロジェクトパッチ" + "ソースコードを表示する" + "チェックに失敗しました。後でもう一度試してください。" + "アップデートを確認する" + "プライバシー画面を閉じています…" + "安全な接続を確立中…" + "プライバシー画面を有効化中…" + "アップデートを確認しています…" + "クリア中..." + "ローカルIDを取得中..." + "選択したファイルを読み込み中..." + "接続する" + "シグナリングサーバーに接続しています..." + "サーバーに接続中..." + "サーバーに再接続中..." + "このデバイスでは使用できるファイル ピッカーがありません" + "クリア" + "プレビューを削除" + "プレビューを削除しますか?" + "ソースコードとビルド手順" + "ソースコードのバージョン" + "バージョン" + "著作権およびライセンスに関する声明" + "コンピューターのキーボード" + "画質" + "ビデオ設定" + "映像遅延" + "ビデオ設定" + "ビデオ品質" + "ビデオキャプチャフレームレート" + "トラックパッド" + "相対マウス" + "分かりました" + "OK" + "確認する" + "接続を確認する" + "オフライン" + "スペース" + "ポート範囲は 1 ~ 65535 です。" + "記号・機能" + "コンピューターがプライバシー画面の状態に戻るまで待ちます。古いコンピューターではサポートされていない可能性があります。" + "リモート画面情報待ち" + "リモート画面を待っています..." + "プライバシー認証待ち" + "システムキーボード" + "直接タッチ" + "アブソリュートマウス" + "ネットワーク" + "カスタム" + "仮想マウス" + "ローカル ショートカットを使用してリモート プライバシー画面のロックが解除されました。再度ロックするとプライバシーが回復され、ローカル ショートカットのロック解除が無効になります。" + "管理されているバージョンが低すぎるため、最新バージョンにアップグレードしてください。" + "リモートエンコーダー" + "相手側に送信するテキスト" + "ビデオ" + "ライセンス" + "ライセンスと著作権表示" + "ライセンスと著作権表示はオフラインでも利用できます。" + "デバイス ID を保存できませんでした。安全なストレージを確認してください。" + "デバイス ID と選択された保存されたアクセス パスワードは、Android キーストアを使用して暗号化されます。接続記録はローカルにのみ保存され、デバイスのバックアップには含まれません。クリップボードの内容はセッションが終了するとクリアされます。アプリを終了した後もピクチャーインピクチャーまたは接続された通知でセッションを維持し、アプリまたは通知内で切断します。" + "設定" + "設定、新しいバージョンがあります" + "アクセスパスワード" + "アクセスパスワードが間違っていますので、再度入力してください。" + "証明書の検証に失敗しました · クリックして再試行してください" + "最初にオンライン認証を完了してください" + "リモート エンドでCrossDeskシステム サービスを有効にして、再試行してください。" + "リクエストがタイムアウトし、コンピュータのプライバシー画面の状態が確認できませんでした。" + "現在のファイルが送信されるまでお待ちください。" + "1 ~ 65535 の範囲でポートを入力してください" + "9桁のデバイスIDを入力" + "有効なアクセスパスワードを入力してください" + "設定を適用できませんでした。もう一度やり直してください。" + "ソフトウェアライセンス" + "戻る" + "コントロールバーに戻る" + "まだ接続実績がありません" + "このお知らせは更新または削除されました。表示するにはお知らせリストに戻ってください。" + "リモートタスクが終了しました" + "リモートデスクトップ" + "リモートデスクトップタッチエリア" + "リモート デスクトップ: タッチしてクリック、ドラッグして移動、右ボタンを押したまま、ピンチしてズーム、ズームインして 2 本の指で画面をドラッグ、2 本の指で上下にスライドして元のスケールでスクロール" + "リモートコンピュータ" + "リモート ウィンドウが閉じられたか、バックグラウンド キープアライブの開始に失敗し、セッションが終了しました。" + "リモート接続" + "リモートパスワードが正しくありません" + "リモートエンドが接続を閉じました" + "リモートエンドは現在利用できません" + "リモートアクセスパスワードの有効期限が切れています。再接続してください。" + "接続" + "接続 " + "接続に失敗しました" + "接続に失敗しました · クリックして再試行してください" + "接続が失われました" + "接続が終了しました" + "接続遅延 (RTT)" + "サポートされているリモート デバイスに接続されている場合に使用できます。" + "接続完了後、横画面をロックする" + "接続プロンプト" + "接続方法" + "サーバーに接続する" + "サーバーに接続して最新のお知らせを取得します。" + "接続がタイムアウトしました。デバイス ID、サーバー、リモートのオンライン ステータスを確認してください。" + "リモートデスクトップに接続する" + "バックスペース" + "お知らせ" + "一部のプレビューをクリアできませんでした。もう一度お試しください。" + "もう一度お試しください" + "読み取りステータスの保存をリトライする" + "ロック" + "キーボード" + "読んで承認する" + "プライバシー" + "プライバシーと認証" + "プライバシー画面" + "プライバシー画面:オフ" + "プライバシー画面:オン" + "プライバシー画面のロックが解除されました" + "プライバシー画面異常" + "プライバシー画面が一時的に利用できなくなります" + "プライバシー画面のステータスが期限切れになり、コンピュータの確認を待っています" + "プライバシー画面のステータスを確認する" + "プライバシーポリシー" + "一時的にプライバシーポリシーが閲覧できなくなります。インターネットへの接続を拒否し、アプリケーションを再インストールしてください。" + "ミュート" + "オーディオ" + "プロジェクトWebサイト" + "プレビューには、リモート コンピューターからの個人情報または仕事情報が含まれる場合があります。オンにすると、接続するたびにマシンに写真が自動的に保存され、最近の接続で表示されます。いつでも閉じてクリアできます。" + "高" + "デフォルト" + "デフォルトではオフです。オンにすると、電話が接続されているときに画面が横向きになり、横向きのままになります。オフにすると、デバイスの方向に従います。タブレットやマルチウィンドウは影響を受けません。" + "マウスの右ボタンを押してドラッグし、放してドラッグを終了します" + "マウスの左ボタンを押してドラッグし、放してドラッグを終了します" + "マウスコントロール" + "マウスホイール、上下にスライドしてキー範囲外にスライドします" + "、パケットロス率 " + "、送信します " + "、パスワードが保存されました" + "、受け取ります " + "、「再試行」をクリックします" + diff --git a/apps/android/app/src/main/res/values-ko/strings.xml b/apps/android/app/src/main/res/values-ko/strings.xml new file mode 100644 index 00000000..439b874a --- /dev/null +++ b/apps/android/app/src/main/res/values-ko/strings.xml @@ -0,0 +1,308 @@ + + + + " · 완료" + " 전송 실패" + " 장치" + " 기사 · " + " 읽지 않은 항목" + "CrossDesk원격접속" + "GNU GPL 버전 3" + "OpenFEC공지" + "OpenFEC라이선스 및 소스" + "P2P 직접 연결" + "SRTP 활성화됨" + "TURN 릴레이" + "{0}전송 실패" + "기기: {0}" + "{0}읽지 않은 항목" + "{0}, 수신{1}, 송신{2}, 패킷 손실률{3}" + "● 연결됨" + "아래로 당겨 새로고침" + "손실률" + "중간" + "영상을 부드럽게 유지하는 데 우선 순위를 두며 대역폭이나 인코딩 압력이 높을 때 해상도를 더욱 적극적으로 줄입니다." + "낮음" + "커스텀 서버 이용하기" + "비밀번호 저장" + "수신된 파일 저장" + "원격 화면 미리보기 저장" + "원격 화면 미리보기를 저장하시겠습니까?" + "신호 연결이 중단되었습니다. 다시 연결하십시오." + "공지사항 로딩에 실패했습니다. 다시 시도해주세요." + "공지사항" + "합계 " + "총{0}항목 ·{1}읽지 않은 항목" + "소개" + "CrossDesk 정보" + "새 버전이 있습니다." + "닫기" + "컨트롤 바 닫기" + "개인 정보 보호 화면 비활성화" + "선명도와 부드러움의 균형을 유지하며 일정한 압력을 가하면 해상도가 점차 감소합니다." + "해상도" + "삭제" + "공지사항 삭제" + "기록 삭제" + "이 공지를 삭제하시겠습니까?" + "새로고침 안내" + "클립보드" + "로드 중…" + "더 로드하기" + "업데이트 안내" + "기본 연결 초기화 실패" + "송신" + "보내기 " + "전송 후 원격 키보드에서 \"붙여넣기\"를 클릭하세요. 수신된 원격 텍스트를 로컬 시스템에 수동으로 복사할 수 있습니다." + "파일 보내기" + "문자 보내기" + "취소" + "연결 취소" + "각 구성 요소에는 나열된 오픈 소스 라이선스가 적용되며 부여된 권리에는 이 애플리케이션의 일반 사용 약관이 적용되지 않습니다. 소스 코드를 보려면 인터넷 연결이 필요합니다." + "합계" + "동의하고 계속하기" + "백그라운드에서 연결을 유지하고 원격 데스크톱으로 돌아가려면 클릭하세요." + "백그라운드 연결 유지를 시작하지 못했습니다. 애플리케이션을 포그라운드에 유지하세요." + "백그라운드 연결 유지를 시작하지 못했습니다. 애플리케이션을 포그라운드에 유지하고 다시 연결하세요." + "백그라운드 연결이 종료되었습니다. 다시 연결해 주세요." + "백그라운드 연결 서비스가 중지되었습니다. 다시 연결해 주세요." + "새로운 미리보기는 후속 연결에도 계속 저장됩니다." + "온라인" + "프로토콜 및 경로 없이 호스트 이름 또는 IPv4 주소를 입력하세요." + "소리" + "원격 텍스트 복사" + "대역폭이 부족할 때 영상 선명도를 보장하려면 항상 더 높은 해상도를 유지하고 프레임 속도를 낮추십시오." + "미디어 암호화" + "문자·숫자" + "보안 저장 또는 인증서 초기화에 실패했습니다. 다시 시도하거나 애플리케이션 데이터를 삭제하세요." + "완료" + "개인정보 동의 완료 후 업데이트 내용을 확인할 수 있습니다." + "개인정보 인증 완료 후 로컬 신원 등록" + "비밀번호 저장에 실패했습니다. 이 연결은 계속 사용할 수 있습니다." + "비밀번호는 기본 Android 키 저장소에 암호화되어 저장됩니다." + "원격 ID" + "피어 ID " + "피어 ID{0}" + "이 기기에 저장된 원격 미리보기는 모두 삭제되며, 연결 기록과 비밀번호는 유지됩니다." + "화면 방향" + "원격제어 메뉴 확장" + "알림으로 인해 원격 연결이 끊어졌습니다." + "비밀번호 저장됨" + "저장된 비밀번호를 읽을 수 없습니다. 다시 입력해 주세요." + "저장된 비밀번호는 보관할 수 없으므로 다시 입력해 주세요." + "Ctrl+Alt+Del가 전송되었습니다." + "백그라운드 연결 유지가 활성화되어 전환 애플리케이션이 계속 연결을 유지할 수 있습니다." + "연결 알림에서 돌아가거나 연결을 끊기 위해 백그라운드 연결 유지가 활성화되었습니다." + "승인됨" + "읽기" + "연결됨 " + "서버에 연결됨" + "프레임 속도" + "부드러움" + "균형" + "애플리케이션의 라이센스 파일이 없거나 손상되었습니다. 애플리케이션을 다시 설치하십시오." + "개발 버전에는 아직 출시되지 않은 수정 사항이 포함되어 있습니다. 다음 링크는 기본 버전의 소스 코드입니다." + "저장 사용" + "개인 정보 보호 화면 활성화" + "오픈 소스 구성 요소" + "오픈소스 소프트웨어 권리 설명" + "현재 최신 버전입니다." + "현재 원격측에서는 이 텍스트를 직접 입력하는 기능을 지원하지 않습니다. 텍스트 입력을 지원하는 제어된 버전을 사용하거나 클립보드를 통해 보내주세요." + "성공적으로 연결되면 가장 가까운 원격 장치가 여기에 표시됩니다." + "개인정보 보호정책을 읽었으며 이에 동의합니다." + "선택한 파일(읽을 수 없거나 공간이 부족함)" + "장치 ID를 찾을 수 없습니다" + "명령 전송에 실패했습니다. 다시 시도해 주세요." + "명령이 전송되었으며 컴퓨터 확인을 기다리고 있습니다..." + "인증상태" + "수신" + "받다 " + "로컬 디코더" + "철회" + "탈퇴 후에는 원격접속이 중단되며 화면 미리보기가 닫히고 기존 미리보기는 지워집니다. 접속 기록과 비밀번호는 유지되며, 재접속 전 다시 인증이 필요합니다." + "네트워크 승인 철회" + "네트워크 승인을 철회하시겠습니까?" + "리모컨 메뉴 접기" + "키보드 숨기기" + "마우스 숨기기" + "데이터" + "파일 저장에 실패했습니다. 다시 시도해 주세요." + "파일이 저장되었습니다" + "파일 선택 시간이 초과되어 세션이 종료되었습니다." + "텍스트가 128KB를 초과합니다." + "연결 끊기" + "연결을 끊으면 홈페이지로 돌아갑니다." + "원격 연결을 끊으시겠습니까?" + "연결 해제" + "새 버전" + "새 버전 사용 가능: v" + "새 버전 사용 가능: v{0}" + "읽지 않은 공지사항 없음" + "읽기 상태를 로컬에 저장할 수 없습니다. 다시 시도해 주세요." + "이 공지를 삭제할 수 없습니다. 다시 시도해 주세요." + "원격 연결을 시작할 수 없습니다" + "오픈소스 라이선스를 읽을 수 없습니다." + "디스플레이" + "비밀번호 표시" + "나중에" + "공지 없음" + "최근 연결" + "서버" + "ServerTLS인증서 확인 실패" + "서버 주소" + "서버 로그인에 실패했습니다. 서버 주소와 네트워크를 확인해주세요." + "서버 포트" + "서버 연결 시간이 초과되었습니다. 서버 주소와 네트워크를 확인하세요." + "활성화되지 않음" + "링크를 열 수 있는 브라우저가 없습니다." + "무단" + "읽지 않음" + "서버가 연결되지 않았습니다. · 다시 시도하려면 클릭하세요." + "이 애플리케이션은 제한된 보증과 책임 제한을 제공하는CeCILL-C1.0에 따라 순방향 오류 수정을 위해OpenFEC를 사용합니다. 자세한 내용은 전체 라이센스를 참조하세요." + "로컬 ID " + "로컬 ID{0}" + "이 버전의 소스 코드 및 빌드 지침" + "이 빌드에는 소스 개정을 사용할 수 없습니다." + "새로고침하려면 릴리즈하세요" + "빌드 지침" + "레시피 및 프로젝트 패치 빌드" + "소스코드 보기" + "확인에 실패했습니다. 나중에 다시 시도해 주세요." + "업데이트 확인" + "개인정보 보호 화면을 닫는 중…" + "보안 연결 설정 중…" + "개인정보 보호 화면을 켜는 중..." + "업데이트 확인 중…" + "지우는 중..." + "로컬 ID를 얻는 중..." + "선택한 파일을 읽는 중..." + "연결 중" + "시그널링 서버에 연결 중..." + "서버에 연결하는 중..." + "서버에 재접속하는 중..." + "이 장치에 사용할 수 있는 파일 선택기가 없습니다." + "클리어" + "미리보기 삭제" + "미리보기를 삭제할까요?" + "소스 코드 및 빌드 지침" + "소스코드 버전" + "버전" + "저작권 및 라이선스 정책" + "컴퓨터 키보드" + "화질" + "영상 선호도" + "영상 지연" + "영상 설정" + "비디오 품질" + "비디오 캡처 프레임 속도" + "트랙패드" + "상대 마우스" + "알겠습니다" + "알았어" + "확인" + "연결 확인" + "오프라인" + "스페이스" + "포트 범위는 1~65535입니다." + "기호·기능" + "컴퓨터가 개인 정보 보호 화면 상태로 돌아갈 때까지 기다립니다. 오래된 컴퓨터에서는 이를 지원하지 않을 수 있습니다." + "원격 화면 정보를 기다리는 중" + "원격 화면을 기다리는 중..." + "개인정보 인증 대기 중" + "시스템 키보드" + "직접 터치" + "앱솔루트 마우스" + "네트워크" + "커스텀" + "가상마우스" + "로컬 단축키를 사용하여 원격 개인정보 보호 화면을 잠금 해제했습니다. 개인정보 보호를 복원하고 로컬 바로가기 잠금 해제를 비활성화하려면 다시 잠그세요." + "제어 버전이 너무 낮습니다. 최신 버전으로 업그레이드하세요." + "리모트 엔코더" + "원격지로 보낼 텍스트" + "영상" + "라이센스" + "라이센스 및 저작권 고지" + "라이센스 및 저작권 고지는 오프라인에서 확인할 수 있습니다." + "기기 ID를 저장하지 못했습니다. 보안 저장소를 확인하세요." + "기기 ID와 선택된 저장된 액세스 비밀번호는 Android Keystore를 사용하여 암호화됩니다. 연결 기록은 로컬에만 저장되며 장치 백업에는 포함되지 않습니다. 세션이 종료되면 클립보드 내용이 지워집니다. 앱을 종료한 후에도 PIP(picture-in-picture) 또는 연결된 알림으로 세션을 유지하고 앱 또는 알림 내에서 연결을 끊습니다." + "설정" + "설정, 새 버전이 있습니다" + "접속 비밀번호" + "접속비밀번호가 잘못되었습니다. 다시 입력해 주세요." + "인증서 확인 실패 · 다시 시도하려면 클릭하세요." + "먼저 온라인 인증을 완료해주세요." + "원격 측에서CrossDesk시스템 서비스를 활성화하고 다시 시도하십시오." + "요청 시간이 초과되어 컴퓨터의 개인 정보 보호 화면 상태가 확인되지 않았습니다." + "현재 파일이 전송될 때까지 기다려 주십시오." + "1~65535 범위의 포트를 입력하세요." + "기기 ID 9자리를 입력하세요." + "유효한 접속 비밀번호를 입력해주세요" + "설정을 적용할 수 없습니다. 다시 시도해 보세요." + "소프트웨어 라이센스" + "뒤로" + "컨트롤 바로 돌아가기" + "아직 접속기록이 없습니다" + "본 공지사항은 업데이트 또는 삭제되었습니다. 공지사항 목록으로 돌아가서 확인하시기 바랍니다." + "원격 작업이 종료되었습니다." + "원격 데스크톱" + "원격 데스크톱 터치 영역" + "원격 데스크톱: 터치하고 클릭하고, 드래그하여 이동하고, 오른쪽 버튼을 길게 누르고, 핀치하여 확대/축소하고, 두 손가락으로 화면을 확대하고 드래그하고, 두 손가락으로 위아래로 밀어 원래 크기로 스크롤합니다." + "원격 컴퓨터" + "원격 창이 닫혔거나 백그라운드 Keepalive 시작에 실패하여 세션이 종료되었습니다." + "원격 접속" + "원격 비밀번호가 올바르지 않습니다." + "원격 측에서 연결을 종료했습니다." + "현재 원격 끝을 사용할 수 없습니다." + "원격 접속 비밀번호가 만료되었습니다. 다시 접속해 주세요." + "연결" + "연결 " + "연결 실패" + "연결 실패 · 다시 시도하려면 클릭하세요." + "연결 끊김" + "연결이 종료되었습니다" + "연결 지연(RTT)" + "지원되는 원격 장치에 연결된 경우 사용할 수 있습니다." + "연결 완료 후 가로 화면 잠금" + "연결 프롬프트" + "연결 방법" + "서버에 접속" + "서버에 접속하여 최신 공지사항을 받아보세요." + "연결 시간이 초과되었습니다. 장치 ID, 서버 및 원격 온라인 상태를 확인하십시오." + "원격 데스크톱에 연결" + "백스페이스" + "공지사항" + "일부 미리보기를 삭제할 수 없습니다. 다시 시도해 주세요." + "다시 시도해 보세요" + "읽은 상태 저장 다시 시도" + "잠금" + "키보드" + "읽기 및 승인" + "개인 정보 보호" + "개인 정보 보호 및 승인" + "개인정보 보호 화면" + "화면 보호 꺼짐" + "화면 보호 켜짐" + "개인정보 보호 화면 잠금 해제됨" + "개인정보 화면 이상" + "개인 정보 보호 화면을 일시적으로 사용할 수 없습니다." + "개인 정보 보호 화면 상태가 만료되어 컴퓨터 확인을 기다리는 중입니다." + "개인정보 보호 화면 상태 확인 예정" + "개인정보 보호정책" + "개인정보취급방침은 일시적으로 열람할 수 없습니다. 인터넷 연결을 거부하고 애플리케이션을 다시 설치하십시오." + "음소거" + "오디오" + "프로젝트 홈페이지" + "미리보기에는 원격 컴퓨터의 개인 정보나 업무 정보가 포함될 수 있습니다. 전원을 켜면 각 연결이 자동으로 기기에 사진을 저장하고 최근 연결에 표시됩니다. 언제든지 닫고 지울 수 있습니다." + "높음" + "기본값" + "기본적으로 꺼져 있습니다. 전원을 켜면 휴대폰이 연결되면 화면이 가로 방향으로 전환되고 유지됩니다. 꺼지면 장치의 방향을 따릅니다. 태블릿과 멀티 윈도우는 영향을 받지 않습니다." + "마우스 오른쪽 버튼을 누르고 드래그한 후 떼면 드래그가 종료됩니다." + "마우스 왼쪽 버튼을 누르고 드래그한 후 떼면 드래그가 종료됩니다." + "마우스 제어" + "마우스 휠, 위아래로 밀어 키 범위 밖으로 슬라이드" + ", 패킷 손실률 " + ", 보내다 " + ", 비밀번호가 저장되었습니다" + ", 수신 " + ", 재시도를 클릭하세요." + diff --git a/apps/android/app/src/main/res/values-pt/strings.xml b/apps/android/app/src/main/res/values-pt/strings.xml new file mode 100644 index 00000000..432c15db --- /dev/null +++ b/apps/android/app/src/main/res/values-pt/strings.xml @@ -0,0 +1,308 @@ + + + + " · Concluído" + " Falha na transferência" + " dispositivos" + " Artigo · " + " itens não lidos" + "Conexão remota CrossDesk" + "GNU GPL versão 3" + "Aviso OpenFEC" + "Licença e fonte OpenFEC" + "Conexão direta P2P" + "SRT habilitado" + "GIRAR relé" + "Falha na transmissão {0}" + "Dispositivos: {0}" + "Itens não lidos {0}" + "{0}, recebendo {1}, enviando {2}, taxa de perda de pacotes {3}" + "● Conectado" + "Puxe para baixo para atualizar" + "Taxa de perda" + "Média" + "Prioriza manter a imagem suave e reduzirá a resolução de forma mais agressiva quando a largura de banda ou a pressão de codificação forem altas." + "Baixa" + "Usando um servidor personalizado" + "Salvar senha" + "Salvar arquivo recebido" + "Salvar visualizações de tela remotas" + "Salvar visualização remota da tela?" + "A conexão de sinalização foi interrompida, reconecte." + "Falha ao carregar o anúncio. Tente novamente." + "Detalhes do anúncio" + "Total " + "Total de itens {0}· Itens não lidos {1}" + "Sobre" + "Sobre o CrossDesk" + "Sobre, há uma nova versão" + "Fechar" + "Fechar barra de controle" + "Desativar tela de privacidade" + "Equilibra clareza e suavidade, reduzindo apenas gradualmente a resolução sob pressão constante." + "Resolução" + "Excluir" + "Excluir anúncio" + "Excluir registro" + "Excluir este anúncio?" + "Anúncio de atualização" + "Área de transferência" + "Carregando…" + "Carregue mais" + "Atualização recomendada" + "Falha na inicialização da conexão nativa" + "Enviar" + "Enviar " + "Após o envio, clique em “Colar” no teclado remoto. O texto remoto recebido pode ser copiado manualmente para a máquina local." + "Enviar arquivo" + "Enviar texto" + "Cancelar" + "Cancelar conexão" + "Cada componente está sujeito à licença de código aberto listada e os direitos concedidos não estão sujeitos aos termos gerais de uso deste aplicativo. A visualização do código-fonte requer uma conexão com a Internet." + "Total" + "Concorde e continue" + "Mantenha-se conectado em segundo plano, clique para retornar à área de trabalho remota" + "Falha ao iniciar a manutenção de atividade em segundo plano, mantenha o aplicativo em primeiro plano" + "Falha ao iniciar a manutenção de atividade em segundo plano. Mantenha o aplicativo em primeiro plano e reconecte." + "A conexão em segundo plano foi encerrada. Reconecte." + "O serviço de conexão em segundo plano foi interrompido, reconecte." + "Novas visualizações ainda serão salvas nas conexões subsequentes." + "On-line" + "Preencha o nome do host ou endereço IPv4, sem protocolo e caminho" + "Som" + "Copiar texto remoto" + "Sempre mantenha uma resolução mais alta e reduza a taxa de quadros para garantir a clareza da imagem quando a largura de banda for insuficiente." + "Criptografia de mídia" + "Letras e números" + "Falha no armazenamento seguro ou na inicialização do certificado. Tente novamente ou limpe os dados do aplicativo" + "Feito" + "Você pode verificar se há atualizações após concluir a autorização de privacidade" + "Registre a identidade local após concluir a autorização de privacidade" + "Falha ao salvar a senha, esta conexão ainda pode ser usada" + "As senhas são salvas criptografadas no Android Keystore nativo" + "ID remoto" + "ID do par " + "ID de par {0}" + "Todas as visualizações remotas salvas nesta máquina serão excluídas e os registros de conexão e senhas serão mantidos." + "Orientação da tela" + "Expandir menu de controle remoto" + "Conexão remota desconectada da notificação" + "Senha salva" + "A senha salva não pode ser lida, digite-a novamente." + "A senha salva não pode ser mantida, digite-a novamente." + "Ctrl+Alt+Del enviado" + "O keep-alive em segundo plano está habilitado, a troca de aplicativos pode continuar a manter a conexão" + "Manutenção de atividade em segundo plano habilitada para retornar ou desconectar das notificações de conexão" + "Concedido" + "Leia" + "Conectado " + "Conectado ao servidor" + "Taxa de quadros" + "Fluidez" + "Equilibrado" + "O arquivo de licença do aplicativo está ausente ou danificado. Reinstale o aplicativo." + "A versão de desenvolvimento contém modificações que ainda não foram lançadas. O link a seguir é o código fonte da versão básica." + "Ativar salvamento" + "Habilitar tela de privacidade" + "Componentes de código aberto" + "Descrição dos direitos de software de código aberto" + "Esta é atualmente a versão mais recente" + "Atualmente, a extremidade remota não suporta a entrada direta deste texto. Use uma versão do final controlado que suporte entrada de texto ou envie-o através da área de transferência." + "Após a conexão bem-sucedida, o dispositivo remoto mais próximo será exibido aqui." + "Li e concordo com a Política de Privacidade" + "Arquivo selecionado (não pode ser lido ou espaço insuficiente)" + "O ID do dispositivo não foi encontrado" + "Falha no envio do comando, tente novamente" + "O comando foi enviado, aguardando confirmação do computador..." + "Status de autorização" + "Receber" + "receber " + "Decodificador local" + "Revogar" + "Após a retirada, a conexão remota será interrompida, a visualização da tela será fechada e a visualização existente será apagada. O registro de conexão e a senha serão mantidos e será necessária autorização novamente antes de reconectar." + "Retirar autorização de rede" + "Retirar a autorização da rede?" + "Recolher menu de controle remoto" + "Ocultar teclado" + "Ocultar mouse" + "Dados" + "Falha ao salvar o arquivo, tente novamente" + "Arquivo salvo" + "A seleção do arquivo expirou e a sessão foi encerrada" + "O texto excede 128 KB" + "Desconectar" + "Retornará à página inicial após desconectar" + "Desconectar a conexão remota?" + "Desconectar" + "Nova versão" + "Nova versão disponível: v" + "Nova versão disponível: v{0}" + "Nenhum anúncio não lido" + "Não é possível salvar o status de leitura localmente. Por favor, tente novamente." + "Não é possível excluir este anúncio. Por favor, tente novamente." + "Não é possível iniciar a conexão remota" + "Não é possível ler a licença de código aberto" + "Tela" + "Mostrar senha" + "Agora não" + "Sem anúncios" + "Conexões recentes" + "Servidor" + "Falha na verificação do certificado Server TLS" + "Endereço do servidor" + "Falha no login do servidor, verifique o endereço do servidor e a rede" + "Porta do servidor" + "A conexão do servidor expirou, verifique o endereço do servidor e a rede" + "Não habilitado" + "Nenhum navegador encontrado para abrir o link" + "Não autorizado" + "Não lido" + "Servidor não conectado · Clique para tentar novamente" + "Este aplicativo usa OpenFEC para correção direta de erros noCeCILL-C1.0, que fornece garantias limitadas e limita a responsabilidade. Veja a licença completa para detalhes." + "ID local " + "ID local {0}" + "Código-fonte e instruções de construção para esta versão" + "A revisão fonte não está disponível para esta compilação." + "Solte para atualizar" + "Instruções de construção" + "Crie receitas e patches de projeto" + "Ver código-fonte" + "Falha na verificação. Por favor, tente novamente mais tarde." + "Verifique se há atualizações" + "Fechando a tela de privacidade…" + "Estabelecendo conexão segura…" + "Ativando a tela de privacidade..." + "Verificando atualizações…" + "Limpando..." + "Obtendo ID local..." + "Lendo arquivo selecionado..." + "Conectando" + "Conectando ao servidor de sinalização..." + "Conectando ao servidor..." + "Reconectando ao servidor..." + "Nenhum seletor de arquivos disponível para este dispositivo" + "Limpar" + "Limpar prévias" + "Limpar prévias?" + "Código-fonte e instruções de construção" + "Versão do código-fonte" + "Versão" + "Declaração de direitos autorais e licença" + "Teclado de computador" + "Qualidade" + "Preferência de vídeo" + "Latência do vídeo" + "Configurações de vídeo" + "Qualidade de vídeo" + "Taxa de quadros de captura de vídeo" + "Touchpad" + "Rato relativo" + "Entendi" + "OK" + "Confirmar" + "Confirme a conexão" + "Off-line" + "Espaço" + "O intervalo de portas é 1–65535" + "Símbolos e teclas" + "Aguarde o computador retornar ao estado da tela de privacidade; computadores mais antigos podem não suportá-lo." + "Aguardando informações da tela remota" + "Aguardando a tela remota..." + "Aguardando autorização de privacidade" + "Teclado do sistema" + "Toque direto" + "Rato Absoluto" + "Rede" + "Personalizado" + "Rato virtual" + "A tela de privacidade remota foi desbloqueada usando o atalho local. Bloqueie-o novamente para restaurar a privacidade e desativar o desbloqueio de atalhos locais." + "A versão controlada é muito baixa, atualize para a versão mais recente." + "Codificador remoto" + "Texto a ser enviado para o terminal remoto" + "Vídeo" + "Licença" + "Licenças e avisos de direitos autorais" + "A licença e o aviso de direitos autorais estão disponíveis offline." + "Falha ao salvar a identidade do dispositivo. Verifique o armazenamento seguro" + "A identidade do dispositivo e as senhas de acesso salvas selecionadas são criptografadas usando o Android Keystore. Os registros de conexão são salvos apenas localmente e não são incluídos no backup do dispositivo. O conteúdo da área de transferência é apagado quando a sessão é encerrada. Mantenha a sessão com notificações picture-in-picture ou conectadas depois de sair do aplicativo e desconecte-se do aplicativo ou das notificações." + "Configurações" + "Configurações, há uma nova versão" + "Senha de acesso" + "A senha de acesso está errada, digite-a novamente." + "Falha na verificação do certificado · Clique para tentar novamente" + "Por favor, preencha primeiro a autorização online" + "Ative o serviço do sistema CrossDesk na extremidade remota e tente novamente" + "A solicitação expirou e o status da tela de privacidade do computador não foi confirmado." + "Aguarde o envio do arquivo atual." + "Insira uma porta no intervalo 1–65535" + "Insira um ID de dispositivo de 9 dígitos" + "Por favor, insira uma senha de acesso válida" + "Não foi possível aplicar as configurações. Tente novamente." + "Licença de software" + "Voltar" + "Retornar à barra de controle" + "Ainda não há registro de conexão" + "Este anúncio foi atualizado ou excluído. Volte à lista de anúncios para visualizá-lo." + "A tarefa remota está fechada" + "Área de Trabalho Remota" + "Área de toque da área de trabalho remota" + "Área de trabalho remota: toque e clique, arraste para mover, pressione e segure o botão direito, aperte para ampliar, amplie e arraste a tela com dois dedos, deslize para cima e para baixo com dois dedos para rolar na escala original" + "Computador remoto" + "A janela remota foi fechada ou a manutenção de atividade em segundo plano falhou ao iniciar e a sessão foi encerrada." + "Conexão remota" + "Senha remota incorreta" + "A extremidade remota fechou a conexão" + "A extremidade remota está indisponível no momento" + "A senha de acesso remoto expirou, reconecte." + "Conectar" + "Conexão " + "Falha na conexão" + "Falha na conexão · Clique para tentar novamente" + "Conexão perdida" + "Conexão encerrada" + "Atraso de conexão (RTT)" + "Disponível quando conectado a um dispositivo remoto compatível." + "Bloqueie a tela paisagem após a conexão ser estabelecida" + "Solicitação de conexão" + "Método de conexão" + "Conecte-se ao servidor" + "Conecte-se ao servidor para obter os anúncios mais recentes." + "A conexão expirou, verifique o ID do dispositivo, o servidor e o status on-line remoto" + "Conecte-se à área de trabalho remota" + "Retrocesso" + "Avisos" + "Não foi possível limpar algumas visualizações. Tente novamente." + "Tente novamente" + "Tente salvar novamente o status de leitura" + "Bloqueio" + "Teclado" + "Ler e autorizar" + "Privacidade" + "Privacidade e Autorização" + "Tela de privacidade" + "Privacidade desativada" + "Privacidade ativada" + "Tela de privacidade desbloqueada" + "Anormalidade na tela de privacidade" + "A tela de privacidade está temporariamente indisponível" + "O status da tela de privacidade expirou, aguardando confirmação do computador" + "Status da tela de privacidade a ser confirmado" + "Política de Privacidade" + "A política de privacidade não pode ser lida temporariamente. Recuse-se a se conectar à Internet e reinstale o aplicativo." + "Mudo" + "Áudio" + "Site do projeto" + "As visualizações podem conter informações pessoais ou de trabalho do computador remoto. Após ligá-lo, cada conexão salvará automaticamente uma imagem na máquina e a exibirá nas conexões recentes. Você pode fechar e limpar a qualquer momento." + "Alta" + "Padrão" + "Desligado por padrão. Quando ligado, a tela entrará e permanecerá na orientação paisagem quando o telefone estiver conectado; quando desligado, seguirá a direção do dispositivo. Tablets e janelas múltiplas não são afetados." + "Botão direito do mouse, pressione e arraste, solte para finalizar o arrasto" + "Botão esquerdo do mouse, pressione e arraste, solte para finalizar o arrasto" + "Controle do mouse" + "Roda do mouse, deslize para cima e para baixo para sair do intervalo de teclas" + ", taxa de perda de pacotes " + ", enviar " + ", senha salva" + ", receba " + ", clique em Tentar novamente" + diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml new file mode 100644 index 00000000..02655d1d --- /dev/null +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -0,0 +1,308 @@ + + + + " · Завершено" + " Передача не удалась" + " устройства" + " Статья · " + " непрочитанные элементы" + "Удаленное подключение CrossDesk" + "GNU GPL версия 3" + "Уведомление OpenFEC" + "Лицензия и исходный код OpenFEC" + "Прямое соединение P2P" + "SRTP включен" + "Реле ПОВОРОТА" + "Передача {0} не удалась." + "Устройства: {0}" + "{0} непрочитанные элементы" + "{0}, прием {1}, отправка {2}, скорость потери пакетов {3}" + "● Подключено" + "Потяните вниз, чтобы обновить" + "Потери пакетов" + "Среднее" + "Отдает приоритет сохранению плавности изображения и более агрессивно снижает разрешение при высокой пропускной способности или нагрузке на кодирование." + "Низкое" + "Использование пользовательского сервера" + "Сохранить пароль" + "Сохранить полученный файл" + "Сохранять превью удалённого экрана" + "Сохранить предварительный просмотр удаленного экрана?" + "Сигнальное соединение прервано, пожалуйста, переподключитесь." + "Не удалось загрузить объявление. Повторите попытку." + "Подробности объявления" + "Итого " + "Всего элементов {0}· Непрочитанные элементы {1}" + "О программе" + "О CrossDesk" + "О, вышла новая версия" + "Закрыть" + "Закрыть панель управления" + "Выключить приватный экран" + "Балансирует четкость и плавность изображения, постепенно снижая разрешение под постоянным давлением." + "Разрешение" + "Удалить" + "Удалить объявление" + "Удалить запись" + "Удалить это объявление?" + "Обновить объявление" + "Буфер обмена" + "Загрузка…" + "Загрузить еще" + "Рекомендуется обновление" + "Не удалось инициализировать собственное соединение." + "Отправка" + "Отправить " + "После отправки нажмите «Вставить» на удаленной клавиатуре. Полученный удаленный текст можно вручную скопировать на локальный компьютер." + "Отправить файл" + "Отправить текст" + "Отмена" + "Отмена соединения" + "На каждый компонент распространяется действие указанной лицензии с открытым исходным кодом, а предоставленные права не подпадают под действие общих условий использования этого приложения. Для просмотра исходного кода требуется подключение к Интернету." + "Итого" + "Согласитесь и продолжайте." + "Оставайтесь на связи в фоновом режиме, нажмите, чтобы вернуться к удаленному рабочему столу." + "Не удалось запустить фоновую поддержку активности, оставьте приложение на переднем плане." + "Не удалось запустить фоновую поддержку активности. Оставьте приложение в активном режиме и переподключитесь." + "Фоновое соединение прервано, подключитесь заново." + "Служба фонового подключения остановлена, подключитесь повторно." + "Новые превью по-прежнему будут сохраняться при последующих подключениях." + "В сети" + "Введите имя хоста или IPv4-адрес без протокола и пути." + "Звук" + "Копирование удаленного текста" + "Всегда поддерживайте более высокое разрешение и уменьшайте частоту кадров, чтобы обеспечить четкость изображения при недостаточной полосе пропускания." + "Шифрование мультимедиа" + "Буквы и цифры" + "Не удалось инициализировать безопасное хранилище или сертификат. Повторите попытку или очистите данные приложения." + "Готово" + "Вы можете проверить наличие обновлений после завершения авторизации конфиденциальности." + "Зарегистрируйте локальную личность после завершения авторизации конфиденциальности." + "Не удалось сохранить пароль, это соединение все еще можно использовать." + "Пароли сохраняются в зашифрованном виде в собственном хранилище ключей Android." + "Удаленный ID" + "Идентификатор узла " + "Идентификатор узла {0}" + "Все удаленные просмотры, сохраненные на этом компьютере, будут удалены, а записи подключений и пароли сохранятся." + "Ориентация экрана" + "Развернуть меню пульта дистанционного управления" + "Удаленное соединение отключено из-за уведомления" + "Пароль сохранён" + "Сохраненный пароль невозможно прочитать, введите его еще раз." + "Сохраненный пароль невозможно сохранить, введите его еще раз." + "Ctrl+Alt+Del отправлено" + "Фоновая поддержка активности включена, переключающиеся приложения могут продолжать поддерживать соединение." + "Фоновая поддержка активности включена для возврата или отключения от уведомлений о соединении." + "Разрешено" + "Прочитано" + "Подключено " + "Подключено к серверу" + "Частота кадров" + "Плавность" + "Баланс" + "Файл лицензии в приложении отсутствует или поврежден, переустановите приложение." + "Версия для разработки содержит модификации, которые еще не были выпущены. По следующей ссылке приведен исходный код базовой версии." + "Включить сохранение" + "Включить приватный экран" + "Компоненты с открытым кодом" + "Описание прав на программное обеспечение с открытым исходным кодом." + "На данный момент это последняя версия." + "В настоящее время удаленный конец не поддерживает прямой ввод этого текста. Пожалуйста, используйте версию управляемого конца, поддерживающую ввод текста, или отправьте его через буфер обмена." + "При успешном подключении здесь будет отображено ближайшее удаленное устройство." + "Я прочитал и согласен с Политикой конфиденциальности." + "Выбранный файл (невозможно прочитать или недостаточно места)" + "Идентификатор устройства не найден." + "Не удалось отправить команду. Повторите попытку." + "Команда отправлена, ждём подтверждения от компьютера..." + "Статус авторизации" + "Приём" + "получить " + "Локальный декодер" + "Отозвать" + "После выхода удаленное соединение будет остановлено, предварительный просмотр экрана закроется, а существующий предварительный просмотр будет очищен. Запись о подключении и пароль будут сохранены, и перед повторным подключением потребуется повторная авторизация." + "Отозвать сетевую авторизацию" + "Отозвать сетевую авторизацию?" + "Свернуть меню пульта дистанционного управления" + "Скрыть клавиатуру" + "Скрыть мышь" + "Данные" + "Не удалось сохранить файл. Повторите попытку." + "Файл сохранен." + "Тайм-аут выбора файла истек, сеанс завершен." + "Размер текста превышает 128 КБ." + "Отключить" + "Вернется на домашнюю страницу после отключения." + "Отключить удаленное соединение?" + "Отключить" + "Новая версия" + "Доступна новая версия: v" + "Доступна новая версия: v{0}" + "Нет непрочитанных объявлений" + "Не удалось сохранить статус чтения локально. Повторите попытку." + "Не удалось удалить объявление. Повторите попытку." + "Невозможно инициировать удаленное соединение." + "Невозможно прочитать лицензию с открытым исходным кодом." + "Экран" + "Показать пароль" + "Не сейчас" + "Нет объявлений" + "Недавние связи" + "Сервер" + "Проверка Server TLS certificate не удалась." + "Адрес сервера" + "Не удалось войти на сервер, проверьте адрес сервера и сеть." + "Порт сервера" + "Тайм-аут подключения к серверу истек, проверьте адрес сервера и сеть." + "Не включено" + "Не найден браузер, в котором можно было бы открыть ссылку." + "Несанкционированное" + "Не прочитано" + "Сервер не подключен · Нажмите, чтобы повторить попытку." + "Приложение использует OpenFEC для прямого исправления ошибок по лицензии CeCILL-C 1.0 с ограниченной гарантией и ответственностью. Подробности — в тексте лицензии." + "Местный идентификатор " + "Локальный идентификатор {0}" + "Исходный код и инструкции по сборке этой версии." + "Ревизия исходного кода этой сборки недоступна." + "Отпустите, чтобы обновить" + "Инструкции по сборке" + "Рецепты сборки и исправления проектов." + "Открыть исходный код" + "Не удалось проверить обновления. Повторите позже." + "Проверить обновления" + "Закрытие экрана конфиденциальности…" + "Установление безопасного соединения…" + "Включение экрана конфиденциальности..." + "Проверка обновлений…" + "Очистка..." + "Получение локального идентификатора..." + "Чтение выбранного файла..." + "Подключение" + "Подключение к серверу сигнализации..." + "Подключение к серверу..." + "Повторное подключение к серверу..." + "Для этого устройства средство выбора файлов недоступно." + "Очистить" + "Удалить превью" + "Удалить превью?" + "Исходный код и сборка" + "Версия исходного кода" + "Версия" + "Положение об авторских правах и лицензии." + "Компьютерная клавиатура" + "Качество" + "Режим видео" + "Задержка видео" + "Настройки видео" + "Качество видео" + "Частота захвата видео" + "Тачпад" + "Родственная мышь" + "Понятно" + "ОК" + "Подтвердить" + "Подтвердите соединение" + "Не в сети" + "Пробел" + "Диапазон портов: 1–65535." + "Символы и клавиши" + "Подождите, пока компьютер вернется в состояние экрана конфиденциальности; старые компьютеры могут его не поддерживать." + "Ожидание информации об удаленном экране." + "Ожидание удаленного экрана..." + "Ожидание разрешения на конфиденциальность." + "Системная клавиатура" + "Касание" + "Абсолютная мышь" + "Сеть" + "Пользовательский" + "Виртуальная мышь" + "Приватный экран отключён локальным сочетанием клавиш. Заблокируйте его снова, чтобы восстановить защиту и запретить локальную разблокировку." + "Управляемая версия слишком низкая, обновите ее до последней версии." + "Кодер удалённой стороны" + "Текст для отправки на удаленный конец" + "Видео" + "Лицензия" + "Лицензии и авторские права" + "Лицензия и уведомление об авторских правах доступны в автономном режиме." + "Не удалось сохранить идентификационные данные устройства. Проверьте безопасное хранилище." + "Идентификатор устройства и выбранные сохраненные пароли доступа шифруются с помощью хранилища ключей Android. Записи подключений сохраняются только локально и не включаются в резервную копию устройства. Содержимое буфера обмена очищается после завершения сеанса. Оставайтесь в сеансе с помощью «картинка в картинке» или подключенных уведомлений после выхода из приложения и отключайтесь внутри приложения или уведомлений." + "Настройки" + "Настройки, есть новая версия" + "Пароль доступа" + "Неверный пароль доступа, пожалуйста, введите его еще раз." + "Не удалось проверить сертификат · Нажмите, чтобы повторить попытку." + "Сначала пройдите онлайн-авторизацию." + "Пожалуйста, включите системную службу CrossDesk на удаленном конце и повторите попытку." + "Время ожидания запроса истекло, а состояние экрана конфиденциальности компьютера не подтверждено." + "Пожалуйста, дождитесь отправки текущего файла." + "Введите порт в диапазоне 1–65535." + "Введите ID из 9 цифр" + "Пожалуйста, введите действительный пароль доступа." + "Не удалось применить настройки. Повторите попытку." + "Лицензия программы" + "Назад" + "Возврат к панели управления." + "Пока нет записей о подключении" + "Это объявление было обновлено или удалено. Чтобы просмотреть его, вернитесь к списку объявлений." + "Удаленная задача закрыта." + "Удаленный рабочий стол" + "Сенсорная область удаленного рабочего стола" + "Удаленный рабочий стол: коснитесь и щелкните, перетащите для перемещения, нажмите и удерживайте правую кнопку, сведите пальцы для масштабирования, увеличьте масштаб и перетащите экран двумя пальцами, проведите двумя пальцами вверх и вниз для прокрутки в исходном масштабе." + "Удаленный компьютер" + "Удаленное окно было закрыто, или не удалось запустить фоновую проверку активности, и сеанс завершился." + "Удаленное подключение" + "Неверный удаленный пароль." + "Удаленная сторона закрыла соединение." + "Удаленный конец в настоящее время недоступен." + "Срок действия пароля удаленного доступа истек, подключитесь повторно." + "Подключиться" + "Подключение " + "Соединение не удалось" + "Не удалось подключиться · Нажмите, чтобы повторить попытку." + "Соединение потеряно" + "Соединение завершено" + "Задержка соединения (RTT)" + "Доступно при подключении к поддерживаемому устройству." + "Блокировка горизонтального экрана после установления соединения." + "Запрос на подключение" + "Способ подключения" + "Подключиться к серверу" + "Подключитесь к серверу, чтобы получать последние объявления." + "Тайм-аут соединения истек, проверьте идентификатор устройства, сервер и удаленный онлайн-статус." + "Подключение к удаленному рабочему столу" + "Возврат" + "Объявления" + "Некоторые предварительные просмотры не удалось удалить. Повторите попытку." + "Попробуйте еще раз" + "Повторить попытку сохранения статуса чтения." + "Заблокировать" + "Клавиатура" + "Прочитать и авторизоваться" + "Конфиденциальность" + "Конфиденциальность и авторизация" + "Приватный экран" + "Приватный экран выкл." + "Приватный экран вкл." + "Приватный экран разблокирован" + "Неисправность экрана конфиденциальности." + "Экран конфиденциальности временно недоступен." + "Срок действия статуса экрана конфиденциальности истек, ожидание подтверждения от компьютера." + "Статус экрана конфиденциальности подлежит подтверждению." + "Политика конфиденциальности" + "Политику конфиденциальности временно невозможно прочитать. Пожалуйста, откажитесь от подключения к Интернету и переустановите приложение." + "Без звука" + "Аудио" + "Сайт проекта" + "Предварительный просмотр может содержать личную или рабочую информацию с удаленного компьютера. После его включения каждое подключение будет автоматически сохранять изображение на устройстве и отображать его при последних подключениях. Вы можете закрыть и очистить в любое время." + "Высокое" + "По умолчанию" + "По умолчанию выключено. При включении экран войдет и останется в альбомной ориентации при подключении телефона; в выключенном состоянии он будет следовать направлению устройства. Планшеты и мультиокна не затронуты." + "Правая кнопка мыши, нажмите и перетащите, отпустите, чтобы завершить перетаскивание." + "Левую кнопку мыши нажмите и перетащите, отпустите, чтобы завершить перетаскивание." + "Управление мышью" + "Колесо мыши: проведите вверх и вниз, чтобы выйти за пределы диапазона клавиш." + ", коэффициент потери пакетов " + ", отправить " + ", пароль сохранен" + ", получить " + "нажмите «Повторить»." + diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..c34c6c41 --- /dev/null +++ b/apps/android/app/src/main/res/values/strings.xml @@ -0,0 +1,308 @@ + + + + " · Completed" + " Transfer failed" + " devices" + " Article · " + " unread items" + "CrossDesk remote connection" + "GNU GPL version 3" + "OpenFEC notice" + "OpenFEC license and source" + "P2P direct connection" + "SRTP enabled" + "TURN relay" + "{0} transmission failed" + "Devices: {0}" + "{0} unread items" + "{0}, receiving {1}, sending {2}, packet loss rate {3}" + "● Connected" + "Pull down to refresh" + "Loss Rate" + "Medium" + "Prioritizes keeping the picture smooth, and will reduce resolution more aggressively when bandwidth or encoding pressure is high." + "Low" + "Using a custom server" + "Save password" + "Save received file" + "Save remote screen previews" + "Save remote screen preview?" + "The signaling connection is interrupted, please reconnect." + "Announcement loading failed, please try again." + "Announcement details" + "Total " + "Total {0} items ·{1} unread items" + "About" + "About CrossDesk" + "About, there is a new version" + "Close" + "Close control bar" + "Disable privacy screen" + "Balances clarity and smoothness, only gradually reducing resolution under constant pressure." + "Resolution" + "Delete" + "Delete announcement" + "Delete record" + "Delete this announcement?" + "Refresh announcement" + "Clipboard" + "Loading…" + "Load more" + "Update recommended" + "Native connection initialization failed" + "Send" + "Send " + "After sending, click \"Paste\" on the remote keyboard. The received remote text can be manually copied to the local machine." + "Send file" + "Send text" + "Cancel" + "Cancel connection" + "Each component is subject to the listed open source license, and the rights granted are not subject to the general terms of use of this application. Viewing source code requires an internet connection." + "Total" + "Agree and continue" + "Keep connected in the background, click to return to the remote desktop" + "Background keepalive failed to start, please keep the application in the foreground" + "Background keepalive failed to start, please keep the application in the foreground and reconnect." + "The background connection has ended, please reconnect." + "The background connection service has stopped, please reconnect." + "New previews will still be saved on subsequent connections." + "Online" + "Fill in the host name or IPv4 address, without protocol and path" + "Sound" + "Copy remote text" + "Always maintain a higher resolution and reduce the frame rate to ensure picture clarity when bandwidth is insufficient." + "Media encryption" + "Letters & numbers" + "Secure storage or certificate initialization failed, please try again or clear application data" + "Done" + "You can check for updates after completing privacy authorization" + "Register the local identity after completing privacy authorization" + "Password saving failed, this connection can still be used" + "Passwords are saved encrypted in the native Android Keystore" + "Remote ID" + "Peer ID " + "Peer ID {0}" + "All remote previews saved on this machine will be deleted, and the connection records and passwords will be retained." + "Screen orientation" + "Expand remote control menu" + "Remote connection disconnected from notification" + "Password saved" + "The saved password cannot be read, please re-enter it." + "The saved password cannot be retained, please re-enter it." + "Ctrl+Alt+Del sent" + "Background keep-alive is enabled, switching applications can continue to maintain the connection" + "Background keepalive enabled to return or disconnect from connection notifications" + "Granted" + "Read" + "Connected " + "Connected to server" + "Frame rate" + "Smooth" + "Balanced" + "The license file in the application is missing or damaged, please reinstall the application." + "The development version contains modifications that have not yet been released. The following link is the source code of the basic version." + "Enable saving" + "Enable privacy screen" + "Open-source components" + "Open source software rights description" + "This is currently the latest version" + "Currently, the remote end does not support direct input of this text. Please use a version of the controlled end that supports text input, or send it through the clipboard." + "Upon successful connection, the nearest remote device will be displayed here." + "I have read and agreed to the Privacy Policy" + "Selected file (cannot be read or insufficient space)" + "The device ID was not found" + "Command sending failed, please try again" + "The command has been sent, waiting for computer confirmation..." + "Authorization status" + "Receive" + "receive " + "Local decoder" + "Withdraw" + "After withdrawing, the remote connection will be stopped, the screen preview will be closed and the existing preview will be cleared. The connection record and password will be retained, and authorization is required again before reconnecting." + "Withdraw network authorization" + "Withdraw network authorization?" + "Collapse remote control menu" + "Hide keyboard" + "Hide mouse" + "Data" + "File saving failed, please try again" + "File saved" + "File selection timed out and session ended" + "Text exceeds 128 KB" + "Disconnect" + "Will return to the homepage after disconnecting" + "Disconnect remote connection?" + "Disconnect" + "New version" + "New version available: v" + "New version available: v{0}" + "No unread announcements" + "Unable to save reading status locally. Please try again." + "Unable to delete this announcement. Please try again." + "Unable to initiate remote connection" + "Unable to read open source license" + "Display" + "Show password" + "Not now" + "No announcements" + "Recent connections" + "Server" + "Server TLS certificate verification failed" + "Server Address" + "Server login failed, please check the server address and network" + "Server port" + "Server connection timed out, please check the server address and network" + "Not enabled" + "No browser found to open the link" + "Unauthorized" + "Unread" + "Server not connected · Click to try again" + "This application uses OpenFEC for forward error correction under CeCILL-C 1.0, which provides limited warranties and limits liability. See the full license for details." + "Local ID " + "Local ID {0}" + "Source code and build instructions for this version" + "Source revision is unavailable for this build." + "Release to refresh" + "Build instructions" + "Build recipes and project patches" + "View source code" + "Check failed. Please try again later." + "Check for updates" + "Closing privacy screen…" + "Establishing secure connection…" + "Turning on privacy screen..." + "Checking for updates…" + "Clearing..." + "Obtaining local ID..." + "Reading selected file..." + "Connecting" + "Connecting to signaling server..." + "Connecting to server..." + "Reconnecting to server..." + "No file picker available for this device" + "Clear" + "Clear previews" + "Clear previews?" + "Source code and build instructions" + "Source code version" + "Version" + "Copyright and License Statement" + "Computer keyboard" + "Quality" + "Video Preference" + "Video latency" + "Video settings" + "Video Quality" + "Video Capture Frame Rate" + "Trackpad" + "Relative mouse" + "Got it" + "OK" + "Confirm" + "Confirm connection" + "Offline" + "Space" + "Port range is 1–65535" + "Symbols & keys" + "Wait for the computer to return to the privacy screen state; older computers may not support it." + "Waiting for remote screen information" + "Waiting for the remote screen..." + "Waiting for privacy authorization" + "System keyboard" + "Direct touch" + "Absolute Mouse" + "Network" + "Custom" + "Virtual mouse" + "The remote privacy screen was unlocked using the local shortcut. Lock it again to restore privacy and disable local shortcut unlocking." + "The controlled version is too low, please upgrade to the latest version." + "Remote encoder" + "Text to be sent to the remote end" + "Video" + "License" + "Licenses and copyright notices" + "The license and copyright notice are available offline." + "Device identity failed to save, please check secure storage" + "Device identity and selected saved access passwords are encrypted using Android Keystore. Connection records are only saved locally and are not included in device backup. The clipboard contents are cleared when the session is ended. Stay in session with picture-in-picture or connected notifications after leaving the app, and disconnect within the app or notifications." + "Settings" + "Settings, there is a new version" + "Access password" + "The access password is wrong, please re-enter it." + "Certificate verification failed · Click to try again" + "Please complete the online authorization first" + "Please enable the CrossDesk system service on the remote end and try again" + "The request timed out and the computer\'s privacy screen status has not been confirmed." + "Please wait for the current file to be sent." + "Please enter a port in the range 1–65535" + "Enter a 9-digit device ID" + "Please enter a valid access password" + "Could not apply settings. Try again." + "Software license" + "Back" + "Return to control bar" + "No connection record yet" + "This announcement has been updated or deleted, please return to the announcement list to view it." + "Remote task is closed" + "Remote Desktop" + "Remote desktop touch area" + "Remote desktop: Touch and click, drag to move, press and hold the right button, pinch to zoom, zoom in and drag the screen with two fingers, slide up and down with two fingers to scroll at the original scale" + "Remote computer" + "The remote window has been closed, or the background keepalive failed to start, and the session has ended." + "Remote connection" + "Incorrect remote password" + "The remote end has closed the connection" + "The remote end is currently unavailable" + "The remote access password has expired, please reconnect." + "Connect" + "Connection " + "Connection failed" + "Connection failed · Click to try again" + "Connection lost" + "Connection ended" + "Connection delay (RTT)" + "Available when connected to a supported remote device." + "Lock landscape screen after connection is established" + "Connection prompt" + "Connection method" + "Connect to server" + "Connect to the server to get the latest announcements." + "Connection timed out, please check the device ID, server and remote online status" + "Connect to remote desktop" + "Backspace" + "Announcements" + "Some previews could not be cleared, please try again." + "Try again" + "Retry saving reading status" + "Lock" + "Keyboard" + "Read and authorize" + "Privacy" + "Privacy and Authorization" + "Privacy screen" + "Privacy screen off" + "Privacy screen on" + "Privacy screen unlocked" + "Privacy screen abnormality" + "Privacy screen is temporarily unavailable" + "Privacy screen status has expired, waiting for computer confirmation" + "Privacy screen status to be confirmed" + "Privacy Policy" + "The privacy policy cannot be read temporarily. Please refuse to connect to the Internet and reinstall the application." + "Mute" + "Audio" + "Project website" + "Previews may contain personal or work information from the remote computer. After turning it on, each connection will automatically save a picture on the machine and display it in recent connections. You can close and clear at any time." + "High" + "Default" + "Off by default. When turned on, the screen will enter and remain in landscape orientation when the phone is connected; when turned off, it will follow the direction of the device. Tablets and multi-windows are not affected." + "Right mouse button, press and drag, release to end dragging" + "Left mouse button, press and drag, release to end dragging" + "Mouse control" + "Mouse wheel, slide up and down to slide out of the key range" + ", packet loss rate " + ", send " + ", password saved" + ", receive " + ", click Retry" + diff --git a/apps/android/app/src/main/res/xml/locales_config.xml b/apps/android/app/src/main/res/xml/locales_config.xml new file mode 100644 index 00000000..12966c02 --- /dev/null +++ b/apps/android/app/src/main/res/xml/locales_config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/apps/desktop/src/app/main.cpp b/apps/desktop/src/app/main.cpp index ea909210..4bfc3833 100644 --- a/apps/desktop/src/app/main.cpp +++ b/apps/desktop/src/app/main.cpp @@ -427,7 +427,7 @@ int main(int argc, char* argv[]) { CSimpleIniA config; config.SetUnicode(true); config.LoadFile((paths.GetCachePath() / "config.ini").string().c_str()); - console.SetLanguage(static_cast(config.GetLongValue("Settings", "language", 0))); + console.SetLanguage(static_cast(config.GetLongValue("Settings", "language", 10))); std::cout << console.Text("console_cli_help"); return 0; } diff --git a/apps/desktop/src/config_center/config_center.cpp b/apps/desktop/src/config_center/config_center.cpp index 5eaf70cf..1be7b836 100644 --- a/apps/desktop/src/config_center/config_center.cpp +++ b/apps/desktop/src/config_center/config_center.cpp @@ -62,7 +62,7 @@ int ConfigCenter::Load() { const long language_value = ini_->GetLongValue(section_, "language", static_cast(language_)); if (language_value < static_cast(LANGUAGE::CHINESE) || - language_value > static_cast(LANGUAGE::RUSSIAN)) { + language_value > static_cast(LANGUAGE::SYSTEM)) { language_ = LANGUAGE::ENGLISH; } else { language_ = static_cast(language_value); @@ -261,7 +261,7 @@ int ConfigCenter::Save() { int ConfigCenter::SetLanguage(LANGUAGE language) { const int value = static_cast(language); - if (value < 0 || value > 2 || StoreValues({{"language", std::to_string(value)}}) != 0) return -1; + if (value < 0 || value > static_cast(LANGUAGE::SYSTEM) || StoreValues({{"language", std::to_string(value)}}) != 0) return -1; language_ = language; return 0; } diff --git a/apps/desktop/src/config_center/config_center.h b/apps/desktop/src/config_center/config_center.h index b03f0e4b..33439b75 100644 --- a/apps/desktop/src/config_center/config_center.h +++ b/apps/desktop/src/config_center/config_center.h @@ -20,7 +20,11 @@ namespace crossdesk { class ConfigCenter { public: - enum class LANGUAGE { CHINESE = 0, ENGLISH = 1, RUSSIAN = 2 }; + enum class LANGUAGE { + CHINESE = 0, ENGLISH = 1, RUSSIAN = 2, TRADITIONAL_CHINESE = 3, + JAPANESE = 4, KOREAN = 5, GERMAN = 6, FRENCH = 7, SPANISH = 8, + BRAZILIAN_PORTUGUESE = 9, SYSTEM = 10 + }; enum class CONNECTION_MODE { DEVICE_ID = 0, DIRECT_IP = 1 }; enum class VIDEO_ENCODE_FORMAT { H264 = 0, AV1 = 1 }; enum class TURN_MODE { @@ -93,7 +97,7 @@ class ConfigCenter { std::unique_ptr ini_; const char* section_ = "Settings"; - LANGUAGE language_ = LANGUAGE::CHINESE; + LANGUAGE language_ = LANGUAGE::SYSTEM; CONNECTION_MODE connection_mode_ = CONNECTION_MODE::DEVICE_ID; bool enable_ip_direct_ = true; ScreenCaptureMethod screen_capture_method_ = ScreenCaptureMethod::Auto; diff --git a/apps/desktop/src/gui/application/gui_application.cpp b/apps/desktop/src/gui/application/gui_application.cpp index 91bc8bfc..c21dc488 100644 --- a/apps/desktop/src/gui/application/gui_application.cpp +++ b/apps/desktop/src/gui/application/gui_application.cpp @@ -1201,9 +1201,8 @@ void GuiApplication::InitializeSettings() { settings_.LoadRecentConnectionAliases(); localization_language_index_ = localization::detail::ClampLanguageIndex(language_button_value_); - language_button_value_ = localization_language_index_; localization_language_ = - static_cast(localization_language_index_); + static_cast(language_button_value_); privacy_.SetText({ localization::privacy_screen_unlock_hint[localization_language_index_]}); } @@ -1563,11 +1562,7 @@ void GuiApplication::BindMainCallbacks(bool gallery_window) { if (config_center_->SetConnectionMode(mode) != 0) { LOG_WARN("Could not save connection mode preference"); main->set_offline_warning(UiText( - localization_language_index_ == 0 - ? "无法保存连接模式,下次启动可能不会恢复当前模式。" - : localization_language_index_ == 2 - ? "Не удалось сохранить режим подключения. При следующем запуске он может не восстановиться." - : "Could not save the connection mode. It may not be restored on the next launch.")); + localization::Literal("无法保存连接模式,下次启动可能不会恢复当前模式。", localization_language_index_))); } }); main->on_toggle_gallery_fullscreen( @@ -3078,13 +3073,9 @@ void GuiApplication::UpdateLocalization() { return; } #if _WIN32 - // All views refer to static literals; selecting the text needs no allocation - // and only runs when the language changes. Tick still checks connection state. - ui_->shutdown_reason = language == 0 - ? L"远程控制连接中,保留连接以确认或取消关机。" - : language == 2 - ? L"Удалённый сеанс активен. Соединение сохранено для подтверждения или отмены выключения." - : L"Remote session active. Keeping the connection available to confirm or cancel shutdown."; + static std::vector shutdown_reasons(localization::GetSupportedLanguages().size()); + ui_->shutdown_reason = localization::GetWindowsLocalizedLabel( + language, "shutdown_reason", L"Remote session active.", shutdown_reasons); #endif ui_localization::ApplyMainWindowStrings(ui_->main, language); ui_localization::ApplyStreamWindowStrings(ui_->main, language); @@ -3247,13 +3238,12 @@ void GuiApplication::SyncMainWindow() { // Keep this filter separate from DeskHub's current group, keyed by name so // adding/removing groups does not silently select a different one by index. - const auto tr_group = [this](const char* zh, const char* en, const char* ru) { - return UiText(localization_language_index_ == 0 ? zh - : localization_language_index_ == 2 ? ru : en); + const auto tr_group = [this](const char* zh) { + return UiText(localization::Literal(zh, localization_language_index_).c_str()); }; std::vector recent_groups{ - tr_group("全部设备", "All devices", "Все устройства"), - tr_group("未分组", "Ungrouped", "Без группы")}; + tr_group("全部设备"), + tr_group("未分组")}; const bool lan_mode = ui_->main->get_lan_mode(); int recent_group_index = 0; if (!lan_mode && ui_->recent_group_filter) { @@ -4565,9 +4555,7 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) { // common save succeeds. Restore the previous wall file if it fails. if (!wall_settings || (wall_changed && !updated_wall.Save(ui_->gallery_path))) { main->set_gallery_settings_error(UiText( - localization_language_index_ == 0 ? "保存失败,请重试" - : localization_language_index_ == 2 ? "Не удалось сохранить. Повторите попытку" - : "Could not save; try again")); + localization::Literal("保存失败,请重试", localization_language_index_))); main->set_settings_tab(1); return false; } @@ -4586,9 +4574,7 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) { if (wall_changed && !ui_->gallery.Save(ui_->gallery_path)) LOG_ERROR("Failed to restore DeskHub settings after IP direct save failure"); main->set_settings_save_error(UiText( - localization_language_index_ == 0 ? "无法保存 IP 连接设置,请重试。" - : localization_language_index_ == 2 ? "Не удалось сохранить настройки подключения по IP. Повторите попытку." - : "Could not save IP connection settings. Try again.")); + localization::Literal("无法保存 IP 连接设置,请重试。", localization_language_index_))); return false; } #if defined(_WIN32) || defined(__APPLE__) || (defined(__linux__) && !defined(__OHOS__)) @@ -4596,22 +4582,18 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) { if (wall_changed && !ui_->gallery.Save(ui_->gallery_path)) LOG_ERROR("Failed to restore DeskHub settings after lock preference save failure"); main->set_settings_save_error(UiText( - localization_language_index_ == 0 ? "无法保存断开后锁屏设置,请重试。" - : localization_language_index_ == 2 ? "Не удалось сохранить настройку блокировки при отключении. Повторите попытку." - : "Could not save lock-on-disconnect settings. Try again.")); + localization::Literal("无法保存断开后锁屏设置,请重试。", localization_language_index_))); return false; } #endif if (config_center_->SetPrivacyLocalUnlock(main->get_privacy_local_unlock_allowed()) != 0) { if (wall_changed) ui_->gallery.Save(ui_->gallery_path); main->set_settings_save_error(UiText( - localization_language_index_ == 0 ? "无法保存隐私屏解锁设置,请重试。" - : localization_language_index_ == 2 ? "Не удалось сохранить настройку разблокировки. Повторите попытку." - : "Could not save privacy unlock settings. Try again.")); + localization::Literal("无法保存隐私屏解锁设置,请重试。", localization_language_index_))); return false; } language_button_value_ = - localization::detail::ClampLanguageIndex(main->get_language_index()); + std::clamp(main->get_language_index(), 0, localization::kSystemLanguage); video_encode_format_button_value_ = std::clamp(main->get_codec_index(), 0, 1); enable_self_hosted_ = main->get_self_hosted_enabled(); #if !defined(__OHOS__) @@ -4621,7 +4603,7 @@ bool GuiApplication::SaveSettingsFromUi(bool gallery_window) { localization_language_ = static_cast(language_button_value_); - localization_language_index_ = language_button_value_; + localization_language_index_ = localization::detail::ClampLanguageIndex(language_button_value_); config_center_->SetLanguage(localization_language_); privacy_.SetText( {localization::privacy_screen_unlock_hint[localization_language_index_], @@ -4773,10 +4755,7 @@ void GuiApplication::ConnectFromUi(const std::string& input) { const std::string remote_id = CompactPeerId(input); if (!gallery::Workspace::ValidId(remote_id)) { ui_->main->set_connection_input_error( - UiText(localization_language_index_ == 0 ? "请输入有效的 9 位设备 ID" - : localization_language_index_ == 2 - ? "Введите корректный 9-значный ID устройства" - : "Enter a valid 9-digit device ID")); + UiText(localization::Literal("请输入有效的 9 位设备 ID", localization_language_index_))); return; } ui_->main->set_connection_input_error(""); @@ -5330,41 +5309,31 @@ bool GuiApplication::AddGalleryDevice(const std::string& input, const std::string& password, const std::string& group, bool remember_password) { - const auto error = [this](const char* zh, const char* en, const char* ru) { + const auto error = [this](const char* zh) { ui_->wall->set_gallery_notice(UiText( - localization_language_index_ == 0 ? zh - : localization_language_index_ == 2 ? ru : en)); + localization::Literal(zh, localization_language_index_).c_str())); return false; }; const auto id = gallery::Workspace::NormalizeId(input); if (!gallery::Workspace::ValidId(id)) - return error("请输入有效的 9 位设备 ID", - "Enter a valid 9-digit device ID", - "Введите корректный 9-значный ID устройства"); + return error("请输入有效的 9 位设备 ID"); if (password.empty() || password.size() > 6 || password.find_first_not_of( "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") != std::string::npos) - return error("请输入 1–6 位英文字母或数字密码", - "Use 1–6 letters (A–Z, a–z) or digits (0–9)", - "Пароль: 1–6 латинских букв или цифр"); + return error("请输入 1–6 位英文字母或数字密码"); if (!signal_connected_) - return error("尚未连接服务器,请稍后重试", - "Not connected to the server; try again shortly", - "Нет соединения с сервером. Повторите позже"); + return error("尚未连接服务器,请稍后重试"); using State = SlintUi::BatchOperation::State; for (const auto& operation : ui_->batch_operations) if (operation.id == id && operation.action == "connect" && (operation.state == State::Queued || operation.state == State::Running)) - return error("该设备正在连接,请稍候", - "This device is already connecting", - "Устройство уже подключается"); + return error("该设备正在连接,请稍候"); auto updated = ui_->gallery; updated.Add(id, Trim(group)); if (!updated.Save(ui_->gallery_path)) - return error("保存失败,请重试", "Could not save; try again", - "Не удалось сохранить. Повторите попытку"); + return error("保存失败,请重试"); ui_->gallery = std::move(updated); ui_->gallery_hidden_active_ids.erase(id); if (auto props = FindRemoteSession(id)) { @@ -5406,9 +5375,7 @@ bool GuiApplication::ImportGalleryRecent(const std::string& input_group) { updated.AddMany(ids, group); if (!updated.Save(ui_->gallery_path)) { ui_->wall->set_gallery_notice(UiText( - localization_language_index_ == 0 ? "保存失败,请重试" - : localization_language_index_ == 2 ? "Не удалось сохранить. Повторите попытку" - : "Could not save; try again")); + localization::Literal("保存失败,请重试", localization_language_index_))); return false; } ui_->gallery = std::move(updated); @@ -5488,9 +5455,7 @@ bool GuiApplication::SaveDeviceGroups(const std::string& new_group, auto updated = ui_->gallery; if (!updated.SetGroups(id, names) || !updated.Save(ui_->gallery_path)) { main->set_device_group_error(UiText( - localization_language_index_ == 0 ? "保存失败,请重试" - : localization_language_index_ == 2 ? "Не удалось сохранить. Повторите попытку" - : "Could not save; try again")); + localization::Literal("保存失败,请重试", localization_language_index_))); return false; } // Removing an empty group shifts indices. Retain the filter by name instead @@ -5528,10 +5493,8 @@ void GuiApplication::GalleryAction(const std::string& action, ui_->gallery_network_synced = {}; return; } - const auto tr = [this](const char* zh, const char* en, const char* ru) { - return UiText(localization_language_index_ == 0 ? zh - : localization_language_index_ == 2 ? ru - : en); + const auto tr = [this](const char* zh) { + return UiText(localization::Literal(zh, localization_language_index_).c_str()); }; if (action == "recent-open") { ReleaseControl(); @@ -5749,7 +5712,7 @@ void GuiApplication::GalleryAction(const std::string& action, SyncGallery(); }; if (action == "file") { - OpenFileDialog(std::string(tr("选择分发文件", "Select a file to send", "Выберите файл для отправки")), + OpenFileDialog(std::string(tr("选择分发文件")), [enqueue](std::string file) { if (!file.empty()) enqueue(file); }); @@ -6026,11 +5989,8 @@ void GuiApplication::SyncGallery() { ui_->wall->set_gallery_recent_available(available); ui_->wall->set_gallery_recent_selected(selected); } - const auto tr = [this](const char* zh, const char* en, - const char* ru) -> std::string { - return localization_language_index_ == 0 ? zh - : localization_language_index_ == 2 ? ru - : en; + const auto tr = [this](const char* zh) -> std::string { + return localization::Literal(zh, localization_language_index_).c_str(); }; const auto name = [this](const std::string& id) { for (const auto& [_, recent] : recent_connections_) @@ -6070,10 +6030,10 @@ void GuiApplication::SyncGallery() { device.id = UiText(FormatPeerId(id.c_str())); const auto mode = props->traversal_mode_.load(); device.mode = UiText(mode == TraversalMode::P2P - ? tr("直连", "Direct", "Прямой") + ? tr("直连") : mode == TraversalMode::UnknownMode - ? tr("等待统计", "Awaiting stats", "Ожидание статистики") - : tr("中继", "Relay", "Ретрансляция")); + ? tr("等待统计") + : tr("中继")); device.inbound = device.outbound = device.loss = "—"; device.video_latency = "—"; // Prefer the wall's own frame path. An independently displayed stream @@ -6241,7 +6201,7 @@ void GuiApplication::SyncGallery() { label += member.group; } std::vector groups{ - UiText(tr("全部设备", "All devices", "Все устройства"))}; + UiText(tr("全部设备"))}; for (const auto& group : wall.groups) groups.push_back(UiText(group)); const auto old_groups = ui_->wall->get_gallery_groups(); bool changed_groups = !old_groups || old_groups->row_count() != groups.size(); @@ -6325,8 +6285,8 @@ void GuiApplication::SyncGallery() { tile.online = tile.connected || online.value_or(false); tile.presence_known = tile.connected || online.has_value(); tile.status = UiText( - tile.connected ? tr("等待画面", "Waiting for video", "Ожидание видео") - : tr("未连接", "Not connected", "Нет соединения")); + tile.connected ? tr("等待画面") + : tr("未连接")); const bool queued = !tile.connected && std::any_of( ui_->batch_operations.begin(), ui_->batch_operations.end(), [&](const auto& operation) { @@ -6335,9 +6295,9 @@ void GuiApplication::SyncGallery() { }); // A queued retry takes precedence over errors from the previous session. if (queued) - tile.status = UiText(tr("队列中", "Queued", "В очереди")); + tile.status = UiText(tr("队列中")); else if (props && props->connection_auth_.Get().password_required) - tile.status = UiText(tr("需要密码", "Password required", "Нужен пароль")); + tile.status = UiText(tr("需要密码")); else if (props && !tile.connected) tile.status = UiText(ConnectionStatusText( props->connection_status_.load(), localization_language_index_)); @@ -6365,8 +6325,8 @@ void GuiApplication::SyncGallery() { tile.has_frame = true; tile.stale = now - props->gallery_frame_at_ > 5s; tile.status = - UiText(tile.stale ? tr("画面已停留", "Frame stale", "Кадр устарел") - : tr("只读预览", "View only", "Просмотр")); + UiText(tile.stale ? tr("画面已停留") + : tr("只读预览")); } } return tile; diff --git a/apps/desktop/src/gui/assets/localization/localization.h b/apps/desktop/src/gui/assets/localization/localization.h index 820e11c5..f42dbae2 100644 --- a/apps/desktop/src/gui/assets/localization/localization.h +++ b/apps/desktop/src/gui/assets/localization/localization.h @@ -1,116 +1,91 @@ -/* - * @Author: DI JUNKUN - * @Date: 2024-05-29 - * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. - */ -#ifndef _LOCALIZATION_H_ -#define _LOCALIZATION_H_ - +/* + * @Author: DI JUNKUN + * @Date: 2024-05-29 + * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. + */ +#ifndef _LOCALIZATION_H_ +#define _LOCALIZATION_H_ + #include #include #include #include #include "localization_data.h" +#include "system_language.h" #if _WIN32 #include #endif - -namespace crossdesk { -namespace localization { - + +namespace crossdesk { +namespace localization { + struct LanguageOption { std::string code; std::string display_name; }; class LocalizedString { - public: - constexpr explicit LocalizedString(const char* key) : key_(key) {} - const std::string& operator[](int language_index) const; - - private: - const char* key_; -}; - -inline const std::vector& GetSupportedLanguages() { - static const std::vector kSupportedLanguages = { - {"zh-CN", reinterpret_cast(u8"中文")}, - {"en-US", "English"}, - {"ru-RU", reinterpret_cast(u8"Русский")}}; - return kSupportedLanguages; -} - + public: + constexpr explicit LocalizedString(const char* key) : key_(key) {} + const std::string& operator[](int language_index) const; + + private: + const char* key_; +}; + +inline const std::vector& GetSupportedLanguages() { + static const std::vector kSupportedLanguages = { + {"zh-CN", "简体中文"}, {"en-US", "English"}, {"ru-RU", "Русский"}, + {"zh-Hant", "繁體中文"}, {"ja", "日本語"}, {"ko", "한국어"}, + {"de", "Deutsch"}, {"fr", "Français"}, {"es", "Español"}, + {"pt-BR", "Português (Brasil)"}}; + return kSupportedLanguages; +} + namespace detail { inline int ClampLanguageIndex(int language_index) { - if (language_index >= 0 && - language_index < static_cast(GetSupportedLanguages().size())) { - return language_index; - } - return 0; + if (language_index == kSystemLanguage) return SystemLanguage(); + return language_index >= 0 && language_index < kSystemLanguage + ? language_index : kEnglishLanguage; } -using TranslationTable = - std::unordered_map>; - -inline std::unordered_map MakeLocalizedValues( - const TranslationRow& row) { - return {{"zh-CN", reinterpret_cast(row.zh)}, - {"en-US", reinterpret_cast(row.en)}, - {"ru-RU", reinterpret_cast(row.ru)}}; -} - -inline TranslationTable BuildTranslationTable() { - TranslationTable table; - for (const auto& row : kTranslationRows) { - table[row.key] = MakeLocalizedValues(row); - } - +using TranslationTable = std::unordered_map>; +inline const TranslationTable& LiteralTable() { + static const TranslationTable table = [] { + TranslationTable result; + for (const auto& row : kTranslationRows) + result.emplace(row.key, std::vector(std::begin(row.text), std::end(row.text))); + return result; + }(); return table; } - -inline const TranslationTable& GetTranslationTable() { - static const TranslationTable table = BuildTranslationTable(); - return table; -} - -inline const std::string& GetTranslatedText(const std::string& key, - int language_index) { - static const std::string kEmptyText = ""; - - const auto& table = GetTranslationTable(); - const auto key_it = table.find(key); - if (key_it == table.end()) { - return kEmptyText; - } - - const auto& localized_values = key_it->second; - const std::string& language_code = - GetSupportedLanguages()[ClampLanguageIndex(language_index)].code; - - const auto exact_it = localized_values.find(language_code); - if (exact_it != localized_values.end()) { - return exact_it->second; - } - - const auto english_it = localized_values.find("en-US"); - if (english_it != localized_values.end()) { - return english_it->second; - } - - const auto chinese_it = localized_values.find("zh-CN"); - if (chinese_it != localized_values.end()) { - return chinese_it->second; - } - - return kEmptyText; -} - -} // namespace detail - +inline const std::string& GetLiteralText(const std::string& key, int language) { + static const std::string empty; + const auto it = LiteralTable().find(key); + if (it == LiteralTable().end()) return empty; + const auto& values = it->second; + return values[ClampLanguageIndex(language)]; +} +inline const std::string& GetTranslatedText(const std::string& key, int language) { + static const std::unordered_map names = [] { + std::unordered_map result; + for (const auto& row : kNamedTranslations) result.emplace(row.name, row.literal); + return result; + }(); + static const std::string empty; + const auto it = names.find(key); + return it == names.end() ? empty : GetLiteralText(it->second, language); +} + +} // namespace detail + +inline const std::string& Literal(const std::string& key, int language) { + return detail::GetLiteralText(key, language); +} + inline const std::string& LocalizedString::operator[]( int language_index) const { return detail::GetTranslatedText(key_, language_index); @@ -130,11 +105,11 @@ inline std::string FormatDisplayLabel(size_t display_index, return label; } -#define CROSSDESK_DECLARE_LOCALIZED_STRING(name, zh, en, ru) \ - inline const LocalizedString name(#name); -CROSSDESK_LOCALIZATION_ALL(CROSSDESK_DECLARE_LOCALIZED_STRING) -#undef CROSSDESK_DECLARE_LOCALIZED_STRING - +#define CROSSDESK_DECLARE_LOCALIZED_STRING(name) \ + inline const LocalizedString name(#name); +CROSSDESK_LOCALIZATION_ALL(CROSSDESK_DECLARE_LOCALIZED_STRING) +#undef CROSSDESK_DECLARE_LOCALIZED_STRING + #if _WIN32 inline const wchar_t* GetWindowsLocalizedLabel( int language_index, const char* key, const wchar_t* fallback, @@ -187,8 +162,8 @@ inline const wchar_t* GetExitProgramLabel(int language_index) { cache); } #endif - -} // namespace localization -} // namespace crossdesk - -#endif + +} // namespace localization +} // namespace crossdesk + +#endif diff --git a/apps/desktop/src/gui/assets/localization/localization_data.h b/apps/desktop/src/gui/assets/localization/localization_data.h index 0431d9d7..172e77d4 100644 --- a/apps/desktop/src/gui/assets/localization/localization_data.h +++ b/apps/desktop/src/gui/assets/localization/localization_data.h @@ -7,422 +7,1272 @@ #ifndef _LOCALIZATION_DATA_H_ #define _LOCALIZATION_DATA_H_ +// Generated by localization/generate.py. Edit localization/catalog.json. namespace crossdesk { namespace localization { - namespace detail { - -struct TranslationRow { - const char* key; - const void* zh; - const void* en; - const void* ru; -}; - -// Single source of truth for all UI strings. -#define CROSSDESK_LOCALIZATION_ALL(X) \ - X(window_minimize, u8"最小化", "Minimize", u8"Свернуть") \ - X(window_maximize, u8"最大化", "Maximize", u8"Развернуть") \ - X(window_restore, u8"还原窗口", "Restore window", u8"Восстановить окно") \ - X(window_close, u8"关闭窗口", "Close window", u8"Закрыть окно") \ - X(save, u8"保存", "Save", u8"Сохранить") \ - X(copyright_notice, u8"© 2026 JUNKUN DI。保留所有权利。", "© 2026 by JUNKUN DI. All rights reserved.", u8"© 2026 JUNKUN DI. Все права защищены.") \ - X(license_notice, u8"依据 GNU GPL v3 许可发布。", "Licensed under GNU GPL v3.", u8"Распространяется по лицензии GNU GPL v3.") \ - X(messages, u8"消息", "Messages", u8"Сообщения") \ - X(message_unread, u8"未读", "Unread", u8"Не прочитано") \ - X(message_read, u8"已读", "Read", u8"Прочитано") \ - X(message_read_all, u8"全部已读", "Mark all as read", u8"Отметить всё прочитанным") \ - X(message_empty, u8"暂无公告", "No announcements", u8"Нет объявлений") \ - X(message_select, u8"选择公告查看详情", "Select an announcement to read", u8"Выберите объявление для просмотра") \ - X(message_loading, u8"正在加载…", "Loading…", u8"Загрузка…") \ - X(message_read_save_error, u8"无法保存本地阅读状态,请重试。", "Unable to save reading status locally. Please try again.", u8"Не удалось сохранить статус чтения локально. Повторите попытку.") \ - X(message_close, u8"关闭", "Close", u8"Закрыть") \ - X(message_delete, u8"删除", "Delete", u8"Удалить") \ - X(message_delete_title, u8"删除公告", "Delete announcement", u8"Удалить объявление") \ - X(message_delete_confirmation, u8"删除这条公告?", "Delete this announcement?", u8"Удалить это объявление?") \ - X(message_delete_error, u8"无法删除这条公告,请重试。", "Unable to delete this announcement. Please try again.", u8"Не удалось удалить объявление. Повторите попытку.") \ - X(console_cli_help, u8"Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n", "Linux headless options:\n --headless Select an existing desktop and enable the console\n --headless-display DISPLAY Advanced: override desktop selection\n --headless-size WIDTHxHEIGHT New virtual display; default 1920x1080, even 320..8192\n --headless-session EXECUTABLE Start a desktop (startxfce4; none for a bare display)\n --no-headless Disable automatic fallback\nNormal startup selects your existing desktop automatically. Enter settings in the console to configure it.\n", u8"Параметры запуска без монитора:\n --headless Выбрать рабочий стол и включить консоль\n --headless-display DISPLAY Дополнительно: указать сеанс дисплея\n --headless-size WIDTHxHEIGHT Новый виртуальный экран; 1920x1080 по умолчанию, чётные размеры 320..8192\n --headless-session EXECUTABLE Запустить рабочий стол (startxfce4; none — только экран)\n --no-headless Отключить автоматический резервный запуск\nРабочий стол выбирается автоматически. Команда settings открывает настройки консоли.\n") \ - X(console_title, u8"CrossDesk 无头控制台", "CrossDesk headless console", u8"Консоль CrossDesk без графического интерфейса") \ - X(console_log_file, u8"日志文件", "Log file", u8"Файл журнала") \ - X(console_help, u8"命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出", "Commands: status — show ID/password/status; settings — configure; password — change password; random — random password; help — help; quit — exit", u8"Команды: status — ID/пароль/состояние; settings — настройки; password — сменить пароль; random — случайный пароль; help — справка; quit — выход") \ - X(console_status, u8"状态", "Status", u8"Состояние") \ - X(console_online, u8"在线", "Online", u8"В сети") \ - X(console_offline, u8"未连接服务器", "Disconnected from server", u8"Нет подключения к серверу") \ - X(console_id, u8"设备 ID", "Device ID", u8"ID устройства") \ - X(console_password, u8"连接密码", "Connection password", u8"Пароль подключения") \ - X(console_waiting, u8"等待分配", "Waiting for assignment", u8"Ожидание назначения") \ - X(console_password_hidden, u8"(仅在交互终端显示)", "(shown only in an interactive terminal)", u8"(виден только в интерактивном терминале)") \ - X(console_cancelled, u8"已取消修改。", "Change cancelled.", u8"Изменение отменено.") \ - X(console_password_invalid, u8"密码必须是6位英文字母或数字,未提交修改。", "Password must be 6 ASCII letters or digits; no change submitted.", u8"Пароль должен содержать 6 латинских букв или цифр. Изменение не отправлено.") \ - X(console_password_offline, u8"尚未连接服务器,暂时无法修改密码。", "Connect to the server before changing the password.", u8"Для смены пароля подключитесь к серверу.") \ - X(console_password_prompt, u8"输入新密码(6位英文字母或数字;输入 cancel 取消):", "New password (6 ASCII letters or digits; cancel to abort):", u8"Новый пароль (6 латинских букв или цифр; cancel — отмена):") \ - X(console_quitting, u8"正在退出 CrossDesk……", "Exiting CrossDesk...", u8"Выход из CrossDesk...") \ - X(console_unknown_command, u8"未知命令,输入 help 查看帮助。", "Unknown command. Enter help for commands.", u8"Неизвестная команда. Введите help для справки.") \ - X(console_line_too_long, u8"命令过长,已忽略。", "Command too long; ignored.", u8"Команда слишком длинная и проигнорирована.") \ - X(console_random_failed, u8"无法生成随机密码,请重试。", "Unable to generate a random password; try again.", u8"Не удалось создать случайный пароль. Повторите попытку.") \ - X(console_password_pending, u8"密码修改正在处理中,请等待服务器确认。", "Password change pending; wait for server confirmation.", u8"Смена пароля выполняется. Дождитесь подтверждения сервера.") \ - X(console_password_stage_failed, u8"无法保存密码修改记录,未提交修改。请检查日志。", "Unable to save password recovery record; no change submitted. Check the log.", u8"Не удалось сохранить запись восстановления пароля. Изменение не отправлено. Проверьте журнал.") \ - X(console_password_send_failed, u8"发送密码修改请求失败,请等待连接恢复后重试。", "Failed to submit password change; retry after reconnection.", u8"Не удалось отправить запрос смены пароля. Повторите после подключения.") \ - X(console_password_submitted, u8"已提交密码修改,正在等待服务器确认……", "Password change submitted; waiting for server confirmation...", u8"Запрос смены пароля отправлен. Ожидание подтверждения...") \ - X(console_password_uncertain, u8"密码修改结果尚未确认,正在重新连接服务器核实。", "Password change not yet confirmed; reconnecting to verify.", u8"Смена пароля не подтверждена. Повторное подключение для проверки.") \ - X(console_password_rejected, u8"服务器未接受密码修改,原密码保持不变。详情见日志。", "Server rejected the password change; the original password remains. See the log.", u8"Сервер отклонил смену пароля. Старый пароль сохранён. См. журнал.") \ - X(console_password_confirmed, u8"服务器已确认密码修改,正在重新连接。", "Server confirmed the password change; reconnecting.", u8"Сервер подтвердил смену пароля. Повторное подключение.") \ - X(console_password_recovered, u8"重新连接确认:新密码已生效。", "Reconnection confirmed: the new password is active.", u8"Повторное подключение подтвердило новый пароль.") \ - X(console_password_retained, u8"重新连接确认:继续使用原密码。", "Reconnection confirmed: the original password remains active.", u8"Повторное подключение подтвердило прежний пароль.") \ - X(console_exited, u8"CrossDesk 已退出。", "CrossDesk exited.", u8"CrossDesk завершён.") \ - X(console_stopped, u8"CrossDesk 已停止,退出码", "CrossDesk stopped; exit code", u8"CrossDesk остановлен; код выхода") \ - X(console_settings_title, u8"设置(修改后立即保存)", "Settings (each change is saved immediately)", u8"Настройки (изменения сохраняются сразу)") \ - X(console_settings_prompt, u8"输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。", "Enter an item number or key; back to return. Shortcut: settings set KEY VALUE.", u8"Введите номер или имя параметра; back — назад. Команда: settings set KEY VALUE.") \ - X(console_settings_value, u8"输入新值(cancel 取消)", "Enter a new value (cancel to abort)", u8"Введите новое значение (cancel — отмена)") \ - X(console_settings_unavailable, u8"设置尚未初始化,请稍后重试。", "Settings are not ready; try again shortly.", u8"Настройки ещё не готовы. Повторите позже.") \ - X(console_settings_invalid, u8"无效的选项或值,未保存。请按菜单列出的格式输入。", "Invalid setting or value; not saved. Use the format shown in the menu.", u8"Неверный параметр или значение. Ничего не сохранено. Используйте указанный формат.") \ - X(console_settings_save_failed, u8"保存设置失败,原设置保持不变。请检查日志。", "Failed to save settings; the previous value is retained. Check the log.", u8"Не удалось сохранить настройки. Прежнее значение сохранено. Проверьте журнал.") \ - X(console_settings_busy, u8"有远程会话或密码修改正在进行,暂时不能更改连接设置。", "Connection settings cannot change during a remote session or password change.", u8"Нельзя менять параметры подключения во время удалённого сеанса или смены пароля.") \ - X(console_settings_saved, u8"已保存并生效。", "Saved and applied.", u8"Сохранено и применено.") \ - X(console_settings_unchanged, u8"设置未改变。", "Setting unchanged.", u8"Настройка не изменилась.") \ - X(console_settings_reconnect, u8"已保存,正在重新连接服务器。", "Saved; reconnecting to the server.", u8"Сохранено. Повторное подключение к серверу.") \ - X(console_settings_next_connection, u8"已保存,将用于后续连接。", "Saved; applies to subsequent connections.", u8"Сохранено. Будет применено к следующим подключениям.") \ - X(console_settings_next_file, u8"已保存,将用于后续接收的文件。", "Saved; applies to subsequently received files.", u8"Сохранено. Будет применено к следующим получаемым файлам.") \ - X(console_settings_autostart, u8"已保存,在下次图形桌面登录时生效。", "Saved; applies at the next graphical desktop login.", u8"Сохранено. Будет применено при следующем входе в графический сеанс.") \ - X(console_settings_daemon, u8"已保存,普通模式重启后生效;无头控制台仍保持前台运行。", "Saved for the next normal-mode start; the headless console stays in the foreground.", u8"Сохранено для следующего запуска в обычном режиме. Консоль без графического интерфейса остаётся на переднем плане.") \ - X(console_settings_server_required, u8"请先设置有效的服务器地址和端口,再启用自托管。", "Set a valid server host and port before enabling self-hosting.", u8"Укажите адрес и порт сервера перед включением собственного сервера.") \ - X(console_settings_path_invalid, u8"请选择已存在且可写的绝对目录路径;default 使用默认目录。", "Use an existing writable absolute directory, or default for the default location.", u8"Укажите существующий доступный для записи абсолютный путь к каталогу или default.") \ - X(console_settings_readonly, u8"该选项由系统或控制端管理,不可在此修改。", "This option is managed by the system or controller and is read-only here.", u8"Этот параметр управляется системой или клиентом и здесь недоступен для изменения.") \ - X(console_setting_language, u8"语言", "Language", u8"Язык") \ - X(console_setting_codec, u8"视频编码", "Video codec", u8"Видеокодек") \ - X(console_setting_turn, u8"中继模式", "TURN relay mode", u8"Режим ретрансляции TURN") \ - X(console_setting_self_hosted, u8"自托管", "Self-hosted server", u8"Собственный сервер") \ - X(console_setting_host, u8"服务器地址", "Server host", u8"Адрес сервера") \ - X(console_setting_port, u8"信令端口", "Signaling port", u8"Порт сигнализации") \ - X(console_setting_privacy, u8"连接时自动开启隐私屏", "Privacy screen on connection", u8"Приватный экран при подключении") \ - X(console_setting_files, u8"文件保存目录", "Received file directory", u8"Каталог получаемых файлов") \ - X(console_setting_autostart, u8"登录桌面时自启", "Start at desktop login", u8"Запуск при входе в систему") \ - X(console_setting_daemon, u8"守护进程(无头控制台中不生效)", "Daemon (inactive in headless console)", u8"Фоновый режим (не действует в консоли)") \ - X(save_remote_previews, u8"保存远程画面预览", "Save remote screen previews", u8"Сохранять превью удалённого экрана") \ - X(unknown_platform, u8"未知平台", "Unknown platform", u8"Неизвестная платформа") \ - X(privacy_screen, u8"隐私屏", "Privacy screen", u8"Приватный экран") \ - X(privacy_enable, u8"开启隐私屏", "Enable privacy screen", u8"Включить приватный экран") \ - X(privacy_disable, u8"关闭隐私屏", "Disable privacy screen", u8"Выключить приватный экран") \ - X(privacy_on, u8"隐私屏:已开启", "Privacy screen: on", u8"Приватный экран: включён") \ - X(privacy_off, u8"隐私屏:已关闭", "Privacy screen: off", u8"Приватный экран: выключен") \ - X(privacy_unsupported, u8"隐私屏:不可用", "Privacy screen: unavailable", u8"Приватный экран: недоступен") \ - X(local_desktop, u8"本桌面", "Local Desktop", u8"Локальный рабочий стол") \ - X(local_id, u8"本机 ID", "Local ID", u8"Локальный ID") \ - X(local_id_copied_to_clipboard, u8"已复制到剪贴板", "Copied to clipboard", \ - u8"Скопировано в буфер обмена") \ - X(password, u8"密码", "Password", u8"Пароль") \ - X(refresh_password, u8"刷新随机密码", "Refresh random password", \ - u8"Обновить случайный пароль") \ - X(password_format_invalid, u8"密码必须为 6 位英文字母或数字。", "Use exactly 6 letters (A–Z, a–z) or digits (0–9).", u8"Пароль должен содержать ровно 6 латинских букв или цифр.") \ - X(remote_desktop, u8"远程桌面", "Remote Desktop", \ - u8"Удаленный рабочий стол") \ - X(device_name, u8"设备名称", "Device Name", u8"Имя устройства") \ - X(remote_id, u8"对端 ID", "Remote ID", u8"Удаленный ID") \ - X(connect, u8"连接", "Connect", u8"Подключиться") \ - X(recent_connections, u8"近期连接", "Recent Connections", \ - u8"Недавние подключения") \ - X(disconnect, u8"断开连接", "Disconnect", u8"Отключить") \ - X(stream_confirm_disconnect, u8"断开当前连接?", "Disconnect this session?", \ - u8"Отключить текущий сеанс?") \ - X(stream_disconnect_description, u8"当前远程控制会话将结束。", \ - "The current remote session will end.", \ - u8"Текущий сеанс удалённого управления будет завершён.") \ - X(select_display, u8"选择显示器", "Select Display", u8"Выбрать дисплей") \ - X(display_screen, u8"显示屏", "Display", u8"Экран") \ - X(expand_control_bar, u8"展开控制栏", "Expand Control Bar", \ - u8"Развернуть панель управления") \ - X(collapse_control_bar, u8"收起控制栏", "Collapse Control Bar", \ - u8"Свернуть панель управления") \ - X(fullscreen, u8"全屏", "Fullscreen", u8"На весь экран") \ - X(show_net_traffic_stats, u8"显示网络状态", "Show network status", u8"Показать состояние сети") \ - X(hide_net_traffic_stats, u8"隐藏网络状态", "Hide network status", u8"Скрыть состояние сети") \ - X(video, u8"视频", "Video", u8"Видео") \ - X(audio, u8"音频", "Audio", u8"Аудио") \ - X(data, u8"数据", "Data", u8"Данные") \ - X(total, u8"总计", "Total", u8"Итого") \ - X(in, u8"输入", "In", u8"Вход") \ - X(out, u8"输出", "Out", u8"Выход") \ - X(loss_rate, u8"丢包率", "Loss Rate", u8"Потери пакетов") \ - X(exit_fullscreen, u8"退出全屏", "Exit fullscreen", \ - u8"Выйти из полноэкранного режима") \ - X(control_mouse, u8"控制鼠标", "Control Mouse", u8"Управление мышью") \ - X(release_mouse, u8"释放鼠标", "Release Mouse", u8"Освободить мышь") \ - X(audio_capture, u8"播放声音", "Play audio", u8"Воспроизведение звука") \ - X(mute, u8"静音", "Mute", u8"Без звука") \ - X(send_shortcut, u8"发送组合键", "Send Shortcut", u8"Отправить сочетание клавиш") \ - X(send_sas, u8"发送 SAS", "Send SAS", u8"Отправить SAS") \ - X(lock_remote, u8"锁定远端", "Lock Remote", u8"Заблокировать удалённое устройство") \ - X(remote_password_box_visible, u8"远端密码框已出现", "Remote password box visible", u8"На удалённом устройстве появилось поле пароля") \ - X(remote_lock_screen_hint, u8"远端处于锁屏封面,可发送 SAS", "Remote lock screen visible, send SAS", u8"Удалённый экран заблокирован, можно отправить SAS") \ - X(remote_secure_desktop_active, u8"远端已进入安全桌面", "Remote secure desktop active", u8"На удалённом устройстве активен защищённый рабочий стол") \ - X(remote_service_unavailable, u8"远端 Windows 服务不可用", \ - "Remote Windows service unavailable", \ - u8"Служба Windows на удаленной стороне недоступна") \ - X(windows_service_setup_title, u8"安装 CrossDesk Service", \ - "Install CrossDesk Service", u8"Установить CrossDesk Service") \ - X(windows_service_setup_message, \ - u8"为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk " \ - u8"Service。\n未安装该服务不影响 CrossDesk " \ - u8"正常使用,仅无法在锁屏状态下控制本机。", \ - "To support remote control of this device while it is locked, CrossDesk " \ - "Service must be installed with administrator permission.\nWithout this " \ - "service, CrossDesk still works normally; only lock-screen control of " \ - "this computer is unavailable.", \ - u8"Чтобы поддерживать удаленное управление этим устройством на экране " \ - u8"блокировки, необходимо установить CrossDesk Service с правами " \ - u8"администратора.\nБез этой службы CrossDesk продолжит работать " \ - u8"нормально; будет недоступно только управление этим компьютером на " \ - u8"экране блокировки.") \ - X(install_windows_service, u8"安装", "Install", u8"Установить") \ - X(windows_service_settings_label, u8"锁屏控制服务", "Lock-screen control service", u8"Служба управления при блокировке") \ - X(windows_service_installed, u8"已安装", "Installed", u8"Установлена") \ - X(do_not_remind_again, u8"不再提醒", "Do not remind again", \ - u8"Больше не напоминать") \ - X(windows_service_prompt_suppressed_message, \ - u8"已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。", \ - "You will not be reminded again. To enable remote control while locked " \ - "later, click Install in Settings.", \ - u8"Напоминание отключено. Чтобы позже включить удаленное управление на " \ - u8"экране блокировки, нажмите «Установить» в настройках.") \ - X(installing_windows_service, u8"正在安装服务...", "Installing service...", \ - u8"Установка службы...") \ - X(windows_service_install_success, u8"服务已安装并启动", \ - "Service installed and started", u8"Служба установлена и запущена") \ - X(windows_service_install_failed, \ - u8"服务安装失败。请确认 " \ - u8"CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe " \ - u8"位于同一便携目录中,并在系统弹窗中允许管理员权限。", \ - "Service installation failed. Make sure CrossDesk.exe, " \ - "crossdesk_service.exe, and crossdesk_session_helper.exe are in the same " \ - "portable folder, then approve the administrator prompt.", \ - u8"Не удалось установить службу. Убедитесь, что CrossDesk.exe, " \ - u8"crossdesk_service.exe и crossdesk_session_helper.exe находятся в " \ - u8"одной папке портативной версии, затем подтвердите запрос прав " \ - u8"администратора.") \ - X(remote_unlock_requires_secure_desktop, \ - u8"当前仍需要安全桌面专用采集/输入", \ - "Secure desktop capture/input is still required", \ - u8"По-прежнему нужен отдельный захват/ввод для защищенного рабочего " \ - u8"стола") \ - X(settings, u8"设置", "Settings", u8"Настройки") \ - X(language, u8"语言", "Language", u8"Язык") \ - X(screen_capture_method, u8"采集方式", "Capture Method", \ - u8"Способ захвата") \ - X(screen_capture_method_auto, u8"自动", "Auto", u8"Авто") \ - X(video_settings, u8"画面设置", "Video settings", u8"Настройки видео") \ - X(remote_update_title, u8"建议升级被控端", "Remote update recommended", u8"Рекомендуем обновить удалённое устройство") \ - X(remote_update, u8"新版本包含功能改进和性能优化,建议将被控端升级至最新版本。", "Update the remote device to the latest version for improved features and performance.", u8"В новой версии улучшены функции и производительность. Рекомендуем обновить CrossDesk на удалённом устройстве до последней версии.") \ - X(remote_update_dismiss, u8"知道了", "Got it", u8"Понятно") \ - X(video_settings_pending, u8"正在应用…", "Applying…", u8"Применение…") \ - X(video_settings_failed, u8"调整失败,请重试。", "Could not apply settings. Try again.", u8"Не удалось применить настройки. Повторите попытку.") \ - X(video_settings_unavailable, u8"连接建立后可调整,需被控端支持。", "Available when connected to a supported remote device.", u8"Доступно при подключении к поддерживаемому устройству.") \ - X(video_quality, u8"画面质量", "Video Quality", u8"Качество видео") \ - X(video_frame_rate, u8"画面采集帧率", \ - "Video Capture Frame Rate", u8"Частота захвата видео") \ - X(video_adaptation_policy, u8"画面偏好", "Video Preference", \ - u8"Режим видео") \ - X(video_priority_frame_rate, u8"帧率优先", "Frame Rate", \ - u8"Частота кадров") \ - X(video_priority_quality, u8"画质优先", "Quality", u8"Качество") \ - X(video_priority_balanced, u8"平衡", "Balanced", u8"Баланс") \ - X(video_quality_high, u8"高", "High", u8"Высокое") \ - X(video_quality_medium, u8"中", "Medium", u8"Среднее") \ - X(video_quality_low, u8"低", "Low", u8"Низкое") \ - X(video_encode_format, u8"视频编码格式", "Video codec", u8"Видеокодек") \ - X(av1, u8"AV1", "AV1", "AV1") \ - X(h264, u8"H.264", "H.264", "H.264") \ - X(force_relay, u8"强制中继连接", "Force relay connection", u8"Только через ретранслятор") \ - X(self_hosted_server_config, u8"自托管配置", "Self-hosted server", u8"Собственный сервер") \ - X(self_hosted_server_settings, u8"自托管设置", "Self-hosted server settings", u8"Настройки своего сервера") \ - X(self_hosted_server_address, u8"服务器地址", \ - "Server Address", u8"Адрес сервера") \ - X(self_hosted_server_port, u8"信令服务端口", "Signaling port", u8"Порт сигнализации") \ - X(self_hosted_address_invalid, u8"请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。", "Enter a valid host, IP, or HTTPS/WSS signaling URL. Paths are supported.", u8"Введите имя хоста, IP или HTTPS/WSS-адрес сигнального сервиса. Путь допустим.") \ - X(self_hosted_port_invalid, u8"请输入 1–65535 范围内的信令端口。", "Enter a signaling port between 1 and 65535.", u8"Введите порт сигнального сервиса от 1 до 65535.") \ - X(self_hosted_save_failed, u8"配置保存失败,请检查配置目录是否可写后重试。", "Could not save settings. Check that the configuration directory is writable and retry.", u8"Не удалось сохранить настройки. Проверьте доступ на запись в каталог конфигурации и повторите попытку.") \ - X(ok, u8"确认", "OK", u8"ОК") \ - X(cancel, u8"取消", "Cancel", u8"Отмена") \ - X(new_password, u8"请输入六位密码:", "Enter a six-character password:", u8"Введите пароль из 6 символов:") \ - X(input_password, u8"请输入密码:", \ - "Please input password:", u8"Введите пароль:") \ - X(validate_password, u8"验证密码中...", "Validating password...", u8"Проверка пароля...") \ - X(reinput_password, u8"请重新输入密码", "Please input password again", \ - u8"Повторно введите пароль") \ - X(remember_password, u8"记住密码", "Remember password", \ - u8"Запомнить пароль") \ - X(signal_connected, u8"已连接服务器", "Connected to server", u8"Подключено к серверу") \ - X(signal_disconnected, u8"未连接服务器", "Disconnected from server", u8"Нет подключения к серверу") \ - X(signal_reconnect, u8"重新连接", "Reconnect", u8"Переподключиться") \ - X(signal_reconnecting, u8"正在重新连接...", "Reconnecting...", \ - u8"Переподключение...") \ - X(signal_tls_cert_error, u8"证书验证失败,请重新安装自托管根证书", "Certificate verification failed. Reinstall the self-hosted root certificate.", u8"Ошибка проверки сертификата. Переустановите корневой сертификат собственного сервера.") \ - X(p2p_connected, u8"对等连接已建立", "P2P Connected", u8"P2P подключено") \ - X(p2p_disconnected, u8"对等连接已断开", "P2P Disconnected", \ - u8"P2P отключено") \ - X(p2p_connecting, u8"正在建立对等连接...", "P2P Connecting ...", \ - u8"Подключение P2P...") \ - X(p2p_gathering, u8"正在收集候选地址...", "Gathering candidates ...", \ - u8"Сбор кандидатов...") \ - X(receiving_screen, u8"画面接收中...", "Receiving screen...", \ - u8"Получение изображения...") \ - X(p2p_failed, u8"对等连接失败", "P2P Failed", u8"Сбой P2P") \ - X(connection_auth_throttled, u8"验证尝试过于频繁,请稍后重试。", "Too many authentication attempts. Try again later.", u8"Слишком много попыток аутентификации. Повторите позже.") \ - X(connection_service_busy, u8"认证服务繁忙,请稍后重试。", "Authentication service busy. Try again later.", u8"Сервис проверки занят. Повторите позже.") \ - X(connection_not_authenticated, u8"登录状态已失效,请重新连接。", "Signaling login expired. Please reconnect.", u8"Сеанс входа истёк. Подключитесь заново.") \ - X(connection_retry_after, u8"请在 %d 秒后重试。", "Retry in %d seconds.", u8"Повторите через %d сек.") \ - X(p2p_closed, u8"对等连接已关闭", "P2P closed", u8"P2P закрыто") \ - X(no_such_id, u8"无此 ID", "No such ID", u8"ID не найден") \ - X(about, u8"关于", "About", u8"О программе") \ - X(sponsorship_title, u8"赞助支持", "Sponsorship", u8"Поддержка проекта") \ - X(sponsorship_message, u8"如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!", \ - "If CrossDesk is useful to you, consider supporting its continued development, cross-platform testing, and maintenance. Thank you for your support!", \ - u8"Если CrossDesk вам полезен, поддержите его дальнейшую разработку, тестирование на разных платформах и сопровождение. Спасибо за вашу поддержку!") \ - X(sponsorship_dismiss_hint, u8"关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。", \ - "Once closed, this prompt stays hidden until the version changes. Sponsorship links remain available in About.", \ - u8"После закрытия это окно появится только при смене версии. Ссылки для поддержки останутся в разделе «О программе».") \ - X(sponsor_via_afdian, u8"爱发电", "AFDIAN", "AFDIAN") \ - X(notification, u8"通知", "Notification", u8"Уведомление") \ - X(new_version, u8"新版本", "New version", u8"Новая версия") \ - X(new_version_available, u8"新版本可用", "New Version Available", \ - u8"Доступна новая версия") \ - X(check_for_updates, u8"检查更新", "Check for updates", \ - u8"Проверить обновления") \ - X(checking_for_updates, u8"正在检查更新…", "Checking for updates…", \ - u8"Проверка обновлений…") \ - X(up_to_date, u8"已是最新版本", "You're up to date", \ - u8"Установлена последняя версия") \ - X(update_check_failed, u8"检查失败,请稍后重试", \ - "Check failed. Please try again later.", \ - u8"Не удалось проверить обновления. Повторите позже.") \ - X(release_notes, u8"更新内容", "Release Notes", u8"Содержание обновления") \ - X(view_release_notes, u8"更新日志", "Release notes", u8"История изменений") \ - X(version, u8"版本", "Version", u8"Версия") \ - X(release_date, u8"发布日期: ", "Release Date: ", u8"Дата релиза: ") \ - X(access_website, u8"访问官网: ", \ - "Access Website: ", u8"Официальный сайт: ") \ - X(update, u8"更新", "Update", u8"Обновить") \ - X(install_update, u8"安装更新", "Install update", u8"Установить обновление") \ - X(manual_download, u8"手动下载", "Download manually", u8"Скачать вручную") \ - X(install_update_confirm, u8"下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?", \ - "CrossDesk will close after downloading the update. Connections and file transfers will be interrupted. Installation requires system authorization, then CrossDesk will restart. Continue?", \ - u8"После загрузки CrossDesk закроется для обновления. Соединения и передача файлов будут прерваны. Потребуется разрешение системы, затем приложение перезапустится. Продолжить?") \ - X(update_preparing, u8"正在准备更新…", "Preparing update…", u8"Подготовка обновления…") \ - X(update_install_failed, u8"更新未完成,可重试或手动安装。", "Update did not complete. Retry or install manually.", u8"Обновление не завершено. Повторите или установите вручную.") \ - X(connection_alias, u8"修改名称", "Rename", u8"Переименовать") \ - X(delete_connection, u8"删除连接", "Delete Connection", \ - u8"Удалить подключение") \ - X(connect_to_this_connection, u8"发起连接", "Connect", u8"Подключиться") \ - X(input_connection_alias, u8"请输入连接名称:", \ - "Please input connection name:", u8"Введите имя подключения:") \ - X(confirm_delete_connection, u8"确认删除此连接", "Delete this connection?", u8"Удалить это подключение?") \ - X(enable_autostart, u8"开机自启", "Auto Start", u8"Автозапуск") \ - X(enable_daemon, u8"启用守护进程", "Enable Daemon", u8"Включить демон") \ - X(privacy_on_connect, u8"被连接时开启隐私屏", "Privacy screen on incoming connection", u8"Приватный экран при подключении") \ - X(lock_on_disconnect, u8"连接断开后锁屏", "Lock screen on disconnect", \ - u8"Блокировка при отключении") \ - X(takes_effect_after_restart, u8"重启后生效", "Takes effect after restart", \ - u8"Вступит в силу после перезапуска") \ - X(select_file, u8"选择文件发送", "Select File to Send", \ - u8"Выбрать файл для отправки") \ - X(file_transfer_progress, u8"文件传输进度", "File Transfer Progress", \ - u8"Прогресс передачи файлов") \ - X(file_sending_progress, u8"文件发送进度", "File Sending Progress", \ - u8"Отправка файла") \ - X(file_receiving_progress, u8"文件接收进度", "File Receiving Progress", \ - u8"Получение файла") \ - X(queued, u8"队列中", "Queued", u8"В очереди") \ - X(sending, u8"正在传输", "Sending", u8"Передача") \ - X(receiving, u8"正在接收", "Receiving", u8"Получение") \ - X(completed, u8"已完成", "Completed", u8"Завершено") \ - X(failed, u8"失败", "Failed", u8"Ошибка") \ - X(cancelling, u8"正在取消", "Cancelling", u8"Отмена…") \ - X(cancelled, u8"已取消", "Cancelled", u8"Отменено") \ - X(controller, u8"控制端:", "Controller:", u8"Контроллер:") \ - X(server_controlled, u8"被控中", "Controlled", u8"Под управлением") \ - X(server_heading, u8"此设备被控中", "This device is controlled", u8"Устройство под управлением") \ - X(server_connected, u8"已连接", "Connected", u8"Подключено") \ - X(server_send_file, u8"发送文件", "Send file", u8"Отправить файл") \ - X(server_disconnect, u8"断开", "Disconnect", u8"Отключить") \ - X(server_disconnect_all, u8"全部断开", "Disconnect all", u8"Отключить всех") \ - X(server_confirm_disconnect, u8"断开所有控制端的连接?", "Disconnect all controllers?", u8"Отключить все контроллеры?") \ - X(file_transfer, u8"文件传输:", "File Transfer:", u8"Передача файлов:") \ - X(connection_status, u8"连接状态:", \ - "Connection Status:", u8"Состояние соединения:") \ - X(file_transfer_save_path, u8"文件接收保存路径", \ - "File Transfer Save Path", u8"Путь сохранения файлов") \ - X(default_desktop, u8"桌面", "Desktop", u8"Рабочий стол") \ - X(resolution, u8"分辨率", "Res", u8"Разрешение") \ - X(video_latency, u8"视频延时", "Video latency", u8"Задержка видео") \ - X(connection_latency, u8"连接延时", "Connection latency", u8"Задержка соединения") \ - X(connection_mode, u8"连接模式", "Connection mode", u8"Режим подключения") \ - X(connection_mode_direct, u8"直连", "Direct", u8"Прямой") \ - X(connection_mode_relay, u8"中继", "Relay", u8"Ретрансляция") \ - X(transport_encryption, u8"加密传输", "Encryption", u8"Шифрование") \ - X(remote_video_encoder, u8"被控端编码器", "Remote encoder", u8"Кодер удалённой стороны") \ - X(local_video_decoder, u8"控制端解码器", "Local decoder", u8"Локальный декодер") \ - X(transport_encryption_enabled, u8"已开启", "Enabled", u8"Включено") \ - X(transport_encryption_disabled, u8"未开启", "Disabled", u8"Выключено") \ - X(online, u8"在线", "Online", u8"В сети") \ - X(offline, u8"离线", "Offline", u8"Не в сети") \ - X(device_offline, u8"设备离线", "Device Offline", u8"Устройство не в сети") \ - X(request_permissions, u8"权限请求", "Request Permissions", \ - u8"Запрос разрешений") \ - X(screen_recording_permission, u8"屏幕录制权限", \ - "Screen Recording Permission", u8"Разрешение на запись экрана") \ - X(accessibility_permission, u8"辅助功能权限", "Accessibility Permission", \ - u8"Разрешение специальных возможностей") \ - X(permission_required_message, u8"该应用需要授权以下权限:", \ - "The application requires the following permissions:", \ - u8"Для работы приложения требуются следующие разрешения:") \ - X(wayland_notice_title, u8"Wayland 会话提示", "Wayland Session Notice", \ - u8"Уведомление о сеансе Wayland") \ - X(wayland_notice_subtitle, u8"检测到当前桌面会话使用 Wayland。", \ - "The current desktop session uses Wayland.", \ - u8"Текущий сеанс рабочего стола использует Wayland.") \ - X(wayland_permission_title, u8"每次共享均需本机授权", \ - "Local approval required each time", \ - u8"Разрешение требуется каждый раз") \ - X(wayland_notice_message, \ - u8"受 Wayland 安全机制限制,每次启动远程桌面共享时," \ - u8"均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。", \ - "Wayland security restrictions require you to authorize screen sharing " \ - "and remote control locally each time you start sharing this desktop. " \ - "Remote access is available only after authorization.", \ - u8"Из-за ограничений безопасности Wayland при каждом запуске общего " \ - u8"доступа к рабочему столу необходимо вручную разрешать на этом " \ - u8"компьютере показ экрана и удалённое управление. Удалённый доступ " \ - u8"возможен только после разрешения.") \ - X(wayland_recommendation_title, u8"建议使用 X11(Xorg)", \ - "X11 (Xorg) is recommended", u8"Рекомендуем X11 (Xorg)") \ - X(wayland_recommendation_message, \ - u8"为便于持续使用远程桌面,建议注销当前桌面会话," \ - u8"在登录界面选择 X11(Xorg)会话后重新登录。", \ - "For ongoing remote desktop access, we recommend logging out, selecting " \ - "an X11 (Xorg) session on the login screen, and logging in again.", \ - u8"Для постоянного удалённого доступа рекомендуем завершить сеанс, " \ - u8"выбрать X11 (Xorg) на экране входа и войти снова.") \ - X(wayland_notice_acknowledge, u8"我知道了", "Got it", u8"Понятно") \ - X(show_main_window, u8"显示主界面", "Show Main Window", \ - u8"Показать главное окно") \ - X(privacy_local_unlock, u8"允许被控时解锁隐私屏", "Allow privacy screen unlock while controlled", u8"Разрешить разблокировку приватного экрана при удалённом управлении") \ - X(privacy_screen_locked_hint, u8"隐私屏已开启,本机解锁已禁用", "Privacy screen is on. Local unlocking is disabled.", u8"Приватный экран включён. Локальная разблокировка отключена.") \ - X(privacy_unlocked_title, u8"隐私屏已被解锁", "Privacy screen unlocked", u8"Приватный экран разблокирован") \ - X(privacy_unlocked_message, u8"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", "The remote privacy screen was unlocked using the local shortcut. Lock it again to restore privacy and disable local shortcut unlocking.", u8"Приватный экран отключён локальным сочетанием клавиш. Заблокируйте его снова, чтобы восстановить защиту и запретить локальную разблокировку.") \ - X(privacy_unlock_confirm, u8"确认", "Confirm", u8"Подтвердить") \ - X(privacy_unlock_lock, u8"锁定", "Lock", u8"Заблокировать") \ - X(privacy_screen_unlock_hint, u8"按下快捷键,解除隐私屏", \ - "To turn off the privacy screen, press", \ - u8"Чтобы отключить приватный экран, нажмите") \ - X(exit_program, u8"退出", "Exit", u8"Выход") - +struct TranslationRow { const char* key; const char* text[10]; }; inline constexpr TranslationRow kTranslationRows[] = { -#define CROSSDESK_DECLARE_TRANSLATION_ROW(name, zh, en, ru) {#name, zh, en, ru}, - CROSSDESK_LOCALIZATION_ALL(CROSSDESK_DECLARE_TRANSLATION_ROW) -#undef CROSSDESK_DECLARE_TRANSLATION_ROW + {"", {"", " ", " ", "", "", "", "", "", "", ""}}, + {" 台", {" 台", "", "", " 臺", " ", " ", " ", " ", " ", " "}}, + {" 台已连接", {" 台已连接", " connected", " подключено", " 臺已連線", " 接続されています", " 연결됨", " verbunden", " connecté", " conectado", " conectado"}}, + {"9 位设备 ID", {"9 位设备 ID", "9-digit device ID", "ID из 9 цифр", "9 位裝置 ID", "9桁のデバイスID", "9자리 기기 ID", "9-stellige Geräte-ID", "ID d'appareil à 9 chiffres", "ID del dispositivo de 9 dígitos", "ID do dispositivo de 9 dígitos"}}, + {"AV1", {"AV1", "AV1", "AV1", "AV1", "AV1", "AV1", "AV1", "AV1", "AV1", "AV1"}}, + {"CrossDesk 已停止,退出码", {"CrossDesk 已停止,退出码", "CrossDesk stopped; exit code", "CrossDesk остановлен; код выхода", "CrossDesk 已停止,退出碼", "CrossDeskが停止しました。終了コード", "CrossDesk가 중지되었습니다. 종료 코드", "CrossDesk gestoppt; Exit-Code", "CrossDesk arrêté ; code de sortie", "CrossDesk detenido; código de salida", "CrossDesk parado; código de saída"}}, + {"CrossDesk 已退出。", {"CrossDesk 已退出。", "CrossDesk exited.", "CrossDesk завершён.", "CrossDesk 已退出。", "CrossDeskが終了しました。", "CrossDesk가 종료되었습니다.", "CrossDesk beendet.", "CrossDesk est sorti.", "CrossDesk salió.", "CrossDesk saiu."}}, + {"CrossDesk 无头控制台", {"CrossDesk 无头控制台", "CrossDesk headless console", "Консоль CrossDesk без графического интерфейса", "CrossDesk 無頭控制檯", "CrossDeskヘッドレス コンソール", "CrossDesk헤드리스 콘솔", "CrossDesk Headless-Konsole", "Console sans tête CrossDesk", "Consola sin cabeza CrossDesk", "Console sem cabeça CrossDesk"}}, + {"H.264", {"H.264", "H.264", "H.264", "H.264", "H.264", "H.264", "H.264", "H.264", "H.264", "H.264"}}, + {"ID 连接", {"ID 连接", "ID mode", "Режим ID", "ID 連線", "IDモード", "ID 모드", "ID-Modus", "Mode identification", "Modo de identificación", "Modo ID"}}, + {"IP 和端口已复制", {"IP 和端口已复制", "IP and port copied", "IP и порт скопированы", "IP 和埠已複製", "IP とポートがコピーされました", "IP와 포트가 복사되었습니다.", "IP und Port kopiert", "IP et port copiés", "IP y puerto copiados", "IP e porta copiados"}}, + {"IP 连接", {"IP 连接", "IP mode", "Режим IP", "IP 連線", "IPモード", "IP 모드", "IP-Modus", "Mode IP", "Modo IP", "Modo IP"}}, + {"IP 连接准备中…", {"IP 连接准备中…", "Preparing IP connections…", "Подготовка подключений по IP…", "IP 連線準備中…", "IP接続を準備中…", "IP 연결 준비 중…", "IP-Verbindungen vorbereiten…", "Préparation des connexions IP…", "Preparando conexiones IP…", "Preparando conexões IP…"}}, + {"IP 连接已启用", {"IP 连接已启用", "IP connections enabled", "Подключения по IP включены", "IP 連線已啟用", "IP 接続が有効になっています", "IP 연결 활성화", "IP-Verbindungen aktiviert", "Connexions IP activées", "Conexiones IP habilitadas", "Conexões IP habilitadas"}}, + {"IP 连接操作失败,详情:", {"IP 连接操作失败,详情:", "IP connection operation failed. Details: ", "Ошибка операции IP-подключения. Подробности: ", "IP 連線操作失敗,詳情:", "IP 接続操作に失敗しました。詳細:", "IP 연결 작업이 실패했습니다. 세부정보:", "IP-Verbindungsvorgang fehlgeschlagen. Einzelheiten:", "L'opération de connexion IP a échoué. Détails :", "Error en la operación de conexión IP. Detalles:", "Falha na operação de conexão IP. Detalhes:"}}, + {"IP 连接数量已达上限,请先断开部分连接后重试。", {"IP 连接数量已达上限,请先断开部分连接后重试。", "The IP connection limit has been reached. Disconnect some sessions and try again.", "Достигнут лимит IP-подключений. Завершите часть сеансов и повторите попытку.", "IP 連線數量已達上限,請先斷開部分連線後重試。", "IP 接続の制限に達しました。いくつかのセッションを切断して、再試行してください。", "IP 연결 제한에 도달했습니다. 일부 세션의 연결을 끊고 다시 시도하십시오.", "Das IP-Verbindungslimit wurde erreicht. Trennen Sie einige Sitzungen und versuchen Sie es erneut.", "La limite de connexion IP a été atteinte. Déconnectez certaines sessions et réessayez.", "Se ha alcanzado el límite de conexión IP. Desconecta algunas sesiones y vuelve a intentarlo.", "O limite de conexão IP foi atingido. Desconecte algumas sessões e tente novamente."}}, + {"IP 连接未就绪", {"IP 连接未就绪", "IP connections not ready", "Подключения по IP не готовы", "IP 連線未就緒", "IP 接続の準備ができていません", "IP 연결이 준비되지 않았습니다.", "IP-Verbindungen nicht bereit", "Les connexions IP ne sont pas prêtes", "Conexiones IP no listas", "Conexões IP não prontas"}}, + {"IP 连接模式", {"IP 连接模式", "IP connection mode", "Режим IP", "IP 連線模式", "IP接続モード", "IP 연결 모드", "IP-Verbindungsmodus", "Mode de connexion IP", "Modo de conexión IP", "Modo de conexão IP"}}, + {"Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n", {"Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n", "Linux headless options:\n --headless Select an existing desktop and enable the console\n --headless-display DISPLAY Advanced: override desktop selection\n --headless-size WIDTHxHEIGHT New virtual display; default 1920x1080, even 320..8192\n --headless-session EXECUTABLE Start a desktop (startxfce4; none for a bare display)\n --no-headless Disable automatic fallback\nNormal startup selects your existing desktop automatically. Enter settings in the console to configure it.\n", "Параметры запуска без монитора:\n --headless Выбрать рабочий стол и включить консоль\n --headless-display DISPLAY Дополнительно: указать сеанс дисплея\n --headless-size WIDTHxHEIGHT Новый виртуальный экран; 1920x1080 по умолчанию, чётные размеры 320..8192\n --headless-session EXECUTABLE Запустить рабочий стол (startxfce4; none — только экран)\n --no-headless Отключить автоматический резервный запуск\nРабочий стол выбирается автоматически. Команда settings открывает настройки консоли.\n", "Linux 無頭執行選項:\n --headless 自動選擇已有桌面並啟用控制檯\n --headless-display DISPLAY 高階:指定已有顯示會話\n --headless-size WIDTHxHEIGHT 新建虛擬螢幕;預設1920x1080,偶數尺寸320..8192\n --headless-session EXECUTABLE 啟動桌面環境(startxfce4;none 僅啟動裸螢幕)\n --no-headless 禁用自動回退\n正常啟動會自動選擇已有桌面,無需填寫顯示編號。控制檯輸入 settings 管理設定。\n", "Linux ヘッドレス オプション:\n--headless既存のデスクトップを選択し、コンソールを有効にする\n--headless-displayDISPLAY 詳細: デスクトップの選択を上書きする\n--headless-sizeWIDTHxHEIGHT 新しい仮想ディスプレイ。デフォルトは 1920x1080、320..8192 でも可\n--headless-sessionEXECUTABLE デスクトップを起動します (startxfce4; 裸のディスプレイの場合はなし)\n--no-headless自動フォールバックを無効にする\n通常の起動では、既存のデスクトップが自動的に選択されます。コンソールに設定を入力して構成します。\n", "Linux 헤드리스 옵션:\n--headless기존 데스크톱을 선택하고 콘솔을 활성화합니다.\n--headless-displayDISPLAY 고급: 데스크톱 선택 재정의\n--headless-sizeWIDTHxHEIGHT 새로운 가상 디스플레이; 기본값 1920x1080, 심지어 320..8192\n--headless-sessionEXECUTABLE 데스크탑 시작(startxfce4, 베어 디스플레이의 경우 없음)\n--no-headless자동 폴백 비활성화\n일반 시작에서는 기존 데스크탑을 자동으로 선택합니다. 콘솔에 설정을 입력하여 구성하세요.\n", "Linux-Headless-Optionen:\n--headlessWählen Sie einen vorhandenen Desktop aus und aktivieren Sie die Konsole.\n--headless-displayDISPLAY Erweitert: Desktop-Auswahl überschreiben\n--headless-sizeWIDTHxHEIGHT Neue virtuelle Anzeige; Standard 1920x1080, sogar 320..8192\n--headless-sessionAUSFÜHRBAR Starten Sie einen Desktop (startxfce4; keiner für eine bloße Anzeige)\n--no-headlessAutomatisches Fallback deaktivieren\nBeim normalen Start wird Ihr vorhandener Desktop automatisch ausgewählt. Geben Sie in der Konsole Einstellungen ein, um es zu konfigurieren.\n", "Options sans tête Linux :\n--headlessSélectionnez un bureau existant et activez la console.\n--headless-displayDISPLAY Avancé : remplacer la sélection du bureau\n--headless-sizeWIDTHxHEIGHT Nouvel affichage virtuel ; par défaut 1920x1080, même 320..8192\n--headless-sessionEXECUTABLE Démarrer un bureau (startxfce4 ; aucun pour un affichage nu)\n--no-headlessDésactiver le repli automatique\nLe démarrage normal sélectionne automatiquement votre bureau existant. Entrez les paramètres dans la console pour le configurer.\n", "Opciones sin cabeza de Linux:\n--headlessSeleccione un escritorio existente y habilite la consola\n--headless-displayDISPLAY Avanzado: anule la selección de escritorio\n--headless-sizeWIDTHxHEIGHT Nueva pantalla virtual; predeterminado 1920x1080, incluso 320..8192\n--headless-sessionEJECUTABLE Iniciar un escritorio (startxfce4; ninguno para una pantalla simple)\n--no-headlessDeshabilitar el respaldo automático\nEl inicio normal selecciona automáticamente su escritorio existente. Ingrese la configuración en la consola para configurarlo.\n", "Opções sem cabeça do Linux:\n--headlessSelecione um desktop existente e ative o console\n--headless-displayDISPLAY Avançado: substitui a seleção do desktop\n--headless-sizeWIDTHxHEIGHT Novo display virtual; padrão 1920x1080, até 320..8192\n--headless-sessionEXECUTABLE Iniciar uma área de trabalho (startxfce4; nenhum para uma tela vazia)\n--no-headlessDesativar fallback automático\nA inicialização normal seleciona sua área de trabalho existente automaticamente. Insira as configurações no console para configurá-lo.\n"}}, + {"OpenFEC 告知", {"OpenFEC 告知", "OpenFEC notice", "Уведомление OpenFEC", "OpenFEC 告知", "OpenFEC通知", "OpenFEC공지", "OpenFEC-Hinweis", "Avis OpenFEC", "Aviso OpenFEC", "Aviso OpenFEC"}}, + {"OpenFEC 许可与源码", {"OpenFEC 许可与源码", "OpenFEC license and source", "Лицензия и исходный код OpenFEC", "OpenFEC 許可與原始碼", "OpenFECライセンスとソース", "OpenFEC라이선스 및 소스", "OpenFEC Lizenz und Quelle", "Licence et source OpenFEC", "Licencia y fuente OpenFEC", "Licença e fonte OpenFEC"}}, + {"Wayland 会话提示", {"Wayland 会话提示", "Wayland Session Notice", "Уведомление о сеансе Wayland", "Wayland 會話提示", "Waylandセッションのお知らせ", "Wayland 세션 공지", "Wayland-Sitzungsmitteilung", "Avis de session Wayland", "Aviso de sesión de Wayland", "Aviso de Sessão Wayland"}}, + {"© 2026 JUNKUN DI。保留所有权利。", {"© 2026 JUNKUN DI。保留所有权利。", "© 2026 by JUNKUN DI. All rights reserved.", "© 2026 JUNKUN DI. Все права защищены.", "© 2026 JUNKUN DI。保留所有權利。", "© 2026 by JUNKUN DI.無断転載を禁じます。", "© 2026 by JUNKUN DI. 모든 권리 보유.", "© 2026 von JUNKUN DI. Alle Rechte vorbehalten.", "© 2026 par JUNKUN DI. Tous droits réservés.", "© 2026 por JUNKUN DI. Reservados todos los derechos.", "© 2026 por JUNKUN DI. Todos os direitos reservados."}}, + {"上下拖动,调整缩略图与主画面大小", {"上下拖动,调整缩略图与主画面大小", "Drag up or down to resize the thumbnails and main preview", "Потяните вверх или вниз, чтобы изменить размер миниатюр и основного экрана", "上下拖動,調整縮圖與主畫面大小", "上下にドラッグしてサムネイルとメイン プレビューのサイズを変更します", "썸네일과 메인 미리보기의 크기를 조정하려면 위나 아래로 드래그하세요.", "Ziehen Sie nach oben oder unten, um die Größe der Miniaturansichten und der Hauptvorschau zu ändern", "Faites glisser vers le haut ou vers le bas pour redimensionner les vignettes et l'aperçu principal", "Arrastre hacia arriba o hacia abajo para cambiar el tamaño de las miniaturas y la vista previa principal", "Arraste para cima ou para baixo para redimensionar as miniaturas e a visualização principal"}}, + {"下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?", {"下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?", "CrossDesk will close after downloading the update. Connections and file transfers will be interrupted. Installation requires system authorization, then CrossDesk will restart. Continue?", "После загрузки CrossDesk закроется для обновления. Соединения и передача файлов будут прерваны. Потребуется разрешение системы, затем приложение перезапустится. Продолжить?", "下載完成後將關閉 CrossDesk 並安裝更新,當前連線和檔案傳輸會中斷。安裝需要系統授權,完成後重新啟動。是否繼續?", "アップデートをダウンロードした後、CrossDeskは閉じます。接続とファイル転送は中断されます。インストールにはシステム認証が必要です。その後、CrossDeskが再起動します。続く?", "업데이트를 다운로드한 후CrossDesk가 종료됩니다. 연결 및 파일 전송이 중단됩니다. 설치하려면 시스템 인증이 필요하며, 그런 다음CrossDesk가 다시 시작됩니다. 계속하다?", "CrossDesk wird nach dem Herunterladen des Updates geschlossen. Verbindungen und Dateiübertragungen werden unterbrochen. Für die Installation ist eine Systemautorisierung erforderlich. Anschließend wird CrossDesk neu gestartet. Weitermachen?", "CrossDesk se fermera après le téléchargement de la mise à jour. Les connexions et les transferts de fichiers seront interrompus. L'installation nécessite une autorisation du système, puis CrossDesk redémarrera. Continuer?", "CrossDesk se cerrará después de descargar la actualización. Se interrumpirán las conexiones y transferencias de archivos. La instalación requiere autorización del sistema, luego CrossDesk se reiniciará. ¿Continuar?", "CrossDesk será fechado após o download da atualização. As conexões e transferências de arquivos serão interrompidas. A instalação requer autorização do sistema e o CrossDesk será reiniciado. Continuar?"}}, + {"不再提醒", {"不再提醒", "Do not remind again", "Больше не напоминать", "不再提醒", "二度と思い出さないでください", "다시 알림 안 함", "Nicht noch einmal erinnern", "Ne plus rappeler", "No volver a recordar", "Não lembre novamente"}}, + {"不填端口时,默认使用 52888", {"不填端口时,默认使用 52888", "Port defaults to 52888 if omitted", "Без порта используется 52888", "不填埠時,預設使用 52888", "省略した場合、ポートはデフォルトで 52888 になります。", "생략할 경우 포트 기본값은 52888입니다.", "Der Port ist standardmäßig 52888, wenn er weggelassen wird", "Le port par défaut est 52888 s'il est omis", "El puerto predeterminado es 52888 si se omite", "A porta padrão é 52888 se omitida"}}, + {"丢包 ", {"丢包 ", "Loss ", "Потери ", "丟包 ", "損失 ", "손실 ", "Verlust ", "Perte ", "Pérdida ", "Perda "}}, + {"丢包率", {"丢包率", "Loss Rate", "Потери пакетов", "丟包率", "損失率", "손실률", "Verlustrate", "Taux de perte", "Tasa de pérdidas", "Taxa de perda"}}, + {"中", {"中", "Medium", "Среднее", "中", "中", "중간", "Mittel", "Moyenne", "Media", "Média"}}, + {"中继", {"中继", "Relay", "Ретрансляция", "中繼", "リレー", "릴레이", "Relais", "Relais", "Relé", "Relé"}}, + {"中继模式", {"中继模式", "TURN relay mode", "Режим ретрансляции TURN", "中繼模式", "TURNリレーモード", "TURN 릴레이 모드", "TURN-Relaismodus", "Mode relais TOUR", "Modo de relé GIRO", "Modo de relé TURN"}}, + {"为便于持续使用远程桌面,建议注销当前桌面会话,在登录界面选择 X11(Xorg)会话后重新登录。", {"为便于持续使用远程桌面,建议注销当前桌面会话,在登录界面选择 X11(Xorg)会话后重新登录。", "For ongoing remote desktop access, we recommend logging out, selecting an X11 (Xorg) session on the login screen, and logging in again.", "Для постоянного удалённого доступа рекомендуем завершить сеанс, выбрать X11 (Xorg) на экране входа и войти снова.", "為便於持續使用遠端桌面,建議登出當前桌面會話,在登入介面選擇 X11(Xorg)會話後重新登入。", "継続的なリモート デスクトップ アクセスの場合は、ログアウトし、ログイン画面で X11 (Xorg) セッションを選択し、再度ログインすることをお勧めします。", "지속적인 원격 데스크톱 접속을 위해서는 로그아웃 후 로그인 화면에서 X11(Xorg) 세션을 선택한 후 다시 로그인하는 것을 권장합니다.", "Für den dauerhaften Remote-Desktop-Zugriff empfehlen wir, sich abzumelden, auf dem Anmeldebildschirm eine X11-Sitzung (Xorg) auszuwählen und sich erneut anzumelden.", "Pour un accès continu au bureau à distance, nous vous recommandons de vous déconnecter, de sélectionner une session X11 (Xorg) sur l'écran de connexion et de vous reconnecter.", "Para un acceso continuo al escritorio remoto, recomendamos cerrar sesión, seleccionar una sesión X11 (Xorg) en la pantalla de inicio de sesión e iniciar sesión nuevamente.", "Para acesso contínuo à área de trabalho remota, recomendamos fazer logout, selecionar uma sessão X11 (Xorg) na tela de login e fazer login novamente."}}, + {"为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk Service。\n未安装该服务不影响 CrossDesk 正常使用,仅无法在锁屏状态下控制本机。", {"为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk Service。\n未安装该服务不影响 CrossDesk 正常使用,仅无法在锁屏状态下控制本机。", "To support remote control of this device while it is locked, CrossDesk Service must be installed with administrator permission.\nWithout this service, CrossDesk still works normally; only lock-screen control of this computer is unavailable.", "Чтобы поддерживать удаленное управление этим устройством на экране блокировки, необходимо установить CrossDesk Service с правами администратора.\nБез этой службы CrossDesk продолжит работать нормально; будет недоступно только управление этим компьютером на экране блокировки.", "為支援該裝置在鎖屏狀態下被遠端控制,需要以管理員許可權安裝 CrossDesk Service。\n未安裝該服務不影響 CrossDesk 正常使用,僅無法在鎖屏狀態下控制本機。", "ロック中のこのデバイスのリモート制御をサポートするには、管理者権限でCrossDeskサービスをインストールする必要があります。\nこのサービスがなくても、CrossDeskは通常どおり動作します。このコンピュータのロック画面制御のみが利用できません。", "이 장치가 잠겨 있는 동안 원격 제어를 지원하려면 관리자 권한으로CrossDesk서비스를 설치해야 합니다.\n이 서비스가 없으면CrossDesk는 여전히 정상적으로 작동합니다. 이 컴퓨터의 잠금 화면 제어만 사용할 수 없습니다.", "Um die Fernsteuerung dieses Geräts zu unterstützen, während es gesperrt ist, muss der CrossDesk-Dienst mit Administratorrechten installiert werden.\nOhne diesen Dienst funktioniert CrossDesk weiterhin normal. Nur die Sperrbildschirmsteuerung dieses Computers ist nicht verfügbar.", "Pour prendre en charge le contrôle à distance de cet appareil lorsqu'il est verrouillé, le service CrossDesk doit être installé avec l'autorisation d'administrateur.\nSans ce service,CrossDesk fonctionne toujours normalement ; seul le contrôle de l'écran de verrouillage de cet ordinateur n'est pas disponible.", "Para admitir el control remoto de este dispositivo mientras está bloqueado, el servicio CrossDesk debe instalarse con permiso de administrador.\nSin este servicio,CrossDesk todavía funciona normalmente; Sólo el control de pantalla de bloqueo de esta computadora no está disponible.", "Para oferecer suporte ao controle remoto deste dispositivo enquanto ele está bloqueado, o serviço CrossDesk deve ser instalado com permissão de administrador.\nSem este serviço,CrossDesk ainda funciona normalmente; apenas o controle da tela de bloqueio deste computador está indisponível."}}, + {"从当前分组移除此设备?", {"从当前分组移除此设备?", "Remove from this group?", "Убрать из этой группы?", "從當前分組移除此裝置?", "このグループから削除しますか?", "이 그룹에서 제거하시겠습니까?", "Aus dieser Gruppe entfernen?", "Supprimer de ce groupe ?", "¿Eliminar de este grupo?", "Remover deste grupo?"}}, + {"从桌面墙移除", {"从桌面墙移除", "Remove from DeskHub", "Убрать из DeskHub", "從桌面牆移除", "DeskHubから削除", "DeskHub에서 제거", "Aus DeskHub entfernen", "Supprimer de DeskHub", "Eliminar de DeskHub", "Remover de DeskHub"}}, + {"从桌面墙移除此设备?", {"从桌面墙移除此设备?", "Remove from DeskHub?", "Убрать из DeskHub?", "從桌面牆移除此裝置?", "DeskHubから削除しますか?", "DeskHub에서 제거하시겠습니까?", "Aus DeskHub entfernen?", "Supprimer de DeskHub?", "¿Eliminar de DeskHub?", "Remover de DeskHub?"}}, + {"从近期连接添加", {"从近期连接添加", "Add from recent connections", "Добавить из недавних", "從近期連線新增", "最近の接続から追加", "최근 연결에서 추가", "Aus den letzten Verbindungen hinzufügen", "Ajouter à partir de connexions récentes", "Agregar desde conexiones recientes", "Adicionar de conexões recentes"}}, + {"以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", {"以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", "Main open-source components used in this build. Each component is covered by its own license.", "Основные открытые компоненты этой сборки. Каждый распространяется по своей лицензии.", "以下列出本版本的主要開源元件。各元件遵循各自的開源許可。", "このビルドで使用される主なオープンソース コンポーネント。各コンポーネントは独自のライセンスによってカバーされます。", "이 빌드에 사용된 주요 오픈 소스 구성 요소입니다. 각 구성요소에는 자체 라이센스가 적용됩니다.", "In diesem Build verwendete Haupt-Open-Source-Komponenten. Für jede Komponente gilt eine eigene Lizenz.", "Principaux composants open source utilisés dans cette version. Chaque composant est couvert par sa propre licence.", "Principales componentes de código abierto utilizados en esta compilación. Cada componente está cubierto por su propia licencia.", "Principais componentes de código aberto usados nesta compilação. Cada componente é coberto por sua própria licença."}}, + {"低", {"低", "Low", "Низкое", "低", "低", "낮음", "Niedrig", "Faible", "Baja", "Baixa"}}, + {"依据 GNU GPL v3 许可发布。", {"依据 GNU GPL v3 许可发布。", "Licensed under GNU GPL v3.", "Распространяется по лицензии GNU GPL v3.", "依據 GNU GPL v3 許可釋出。", "GNU GPL v3に基づいてライセンスされています。", "GNU GPL v3에 따라 라이센스가 부여되었습니다.", "Lizenziert unterGNU GPL v3.", "Sous licenceGNU GPL v3.", "Con licenciaGNU GPL v3.", "Licenciado sobGNU GPL v3."}}, + {"保存", {"保存", "Save", "Сохранить", "儲存", "保存", "저장", "Speichern", "Enregistrer", "Guardar", "Salvar"}}, + {"保存失败,请重试", {"保存失败,请重试", "Could not save; try again", "Не удалось сохранить. Повторите попытку", "儲存失敗,請重試", "保存できませんでした。もう一度試してください", "저장할 수 없습니다. 다시 시도", "Konnte nicht gespeichert werden; Versuchen Sie es noch einmal", "Impossible d'enregistrer ; réessaye", "No se pudo guardar; intentarlo de nuevo", "Não foi possível salvar; tente novamente"}}, + {"保存设置失败,原设置保持不变。请检查日志。", {"保存设置失败,原设置保持不变。请检查日志。", "Failed to save settings; the previous value is retained. Check the log.", "Не удалось сохранить настройки. Прежнее значение сохранено. Проверьте журнал.", "儲存設定失敗,原設定保持不變。請檢查日誌。", "設定の保存に失敗しました。以前の値が保持されます。ログを確認してください。", "설정을 저장하지 못했습니다. 이전 값이 유지됩니다. 로그를 확인하세요.", "Einstellungen konnten nicht gespeichert werden; der bisherige Wert bleibt erhalten. Überprüfen Sie das Protokoll.", "Échec de l'enregistrement des paramètres ; la valeur précédente est conservée. Vérifiez le journal.", "No se pudo guardar la configuración; se mantiene el valor anterior. Consulta el registro.", "Falha ao salvar configurações; o valor anterior é mantido. Verifique o registro."}}, + {"保存远程画面预览", {"保存远程画面预览", "Save remote screen previews", "Сохранять превью удалённого экрана", "儲存遠端畫面預覽", "リモート画面のプレビューを保存する", "원격 화면 미리보기 저장", "Remote-Bildschirmvorschauen speichern", "Enregistrer les aperçus de l'écran distant", "Guardar vistas previas de pantalla remotas", "Salvar visualizações de tela remotas"}}, + {"信令服务端口", {"信令服务端口", "Signaling port", "Порт сигнализации", "信令服務埠", "信号ポート", "신호 포트", "Signalisierungsport", "Port de signalisation", "Puerto de señalización", "Porta de sinalização"}}, + {"信令端口", {"信令端口", "Signaling port", "Порт сигнализации", "信令埠", "信号ポート", "신호 포트", "Signalisierungsport", "Port de signalisation", "Puerto de señalización", "Porta de sinalização"}}, + {"修改分组", {"修改分组", "Edit groups", "Изменить группы", "修改分組", "グループの編集", "그룹 편집", "Gruppen bearbeiten", "Modifier les groupes", "Editar grupos", "Editar grupos"}}, + {"修改名称", {"修改名称", "Rename", "Переименовать", "修改名稱", "名前を変更", "이름 바꾸기", "Umbenennen", "Renommer", "Cambiar nombre", "Renomear"}}, + {"修改密码", {"修改密码", "Change password", "Изменить пароль", "修改密碼", "パスワード変更", "비밀번호 변경", "Passwort ändern", "Changer le mot de passe", "Cambiar contraseña", "Alterar senha"}}, + {"修改端口", {"修改端口", "Edit port", "Изменить порт", "修改埠", "ポートの編集", "포트 편집", "Port bearbeiten", "Modifier le port", "Editar puerto", "Editar porta"}}, + {"停留翻页,松开取消", {"停留翻页,松开取消", "Hold to turn page; release to cancel", "Удерживайте для перелистывания; отпустите для отмены", "停留翻頁,鬆開取消", "長押ししてページをめくります。リリースしてキャンセルする", "페이지를 넘기려면 길게 누르세요. 취소하다", "Halten Sie gedrückt, um die Seite umzublättern. Freigabe zum Abbrechen", "Maintenez enfoncé pour tourner la page ; libérer pour annuler", "Mantenga presionado para pasar la página; liberar para cancelar", "Segure para virar a página; liberar para cancelar"}}, + {"允许共享此 Mac 的屏幕画面", {"允许共享此 Mac 的屏幕画面", "Allow sharing this Mac’s screen", "Разрешить показ экрана этого Mac", "允許共享此 Mac 的螢幕畫面", "この Mac の画面の共有を許可する", "이 Mac의 화면 공유를 허용합니다", "Erlauben Sie die Freigabe des Bildschirms dieses Mac", "Autoriser le partage de l'écran de ce Mac", "Permitir compartir la pantalla de esta Mac", "Permitir compartilhar a tela deste Mac"}}, + {"允许被控时解锁隐私屏", {"允许被控时解锁隐私屏", "Allow privacy screen unlock while controlled", "Разрешить разблокировку приватного экрана при удалённом управлении", "允許被控時解鎖隱私屏", "制御中にプライバシー画面のロック解除を許可する", "제어되는 동안 개인 정보 보호 화면 잠금 해제 허용", "Entsperren des Sichtschutzbildschirms während der Steuerung zulassen", "Autoriser le déverrouillage de l'écran de confidentialité pendant le contrôle", "Permitir el desbloqueo de la pantalla de privacidad mientras está controlado", "Permitir desbloqueio da tela de privacidade enquanto controlado"}}, + {"允许远程键盘和鼠标控制", {"允许远程键盘和鼠标控制", "Allow remote keyboard and mouse input", "Разрешить удалённый ввод с клавиатуры и мыши", "允許遠端鍵盤和滑鼠控制", "リモートのキーボードとマウスの入力を許可する", "원격 키보드 및 마우스 입력 허용", "Remote-Tastatur- und Mauseingabe zulassen", "Autoriser la saisie au clavier et à la souris à distance", "Permitir la entrada remota de teclado y mouse", "Permitir entrada remota de teclado e mouse"}}, + {"全屏", {"全屏", "Fullscreen", "На весь экран", "全屏", "フルスクリーン", "전체화면", "Vollbild", "Plein écran", "Pantalla completa", "Tela cheia"}}, + {"全选", {"全选", "Select all", "Выбрать все", "全選", "全て選択", "모두 선택", "Alles auswählen", "Sélectionner tout", "Seleccionar todo", "Selecionar tudo"}}, + {"全部已读", {"全部已读", "Mark all as read", "Отметить всё прочитанным", "全部已讀", "すべて既読にする", "모두 읽음으로 표시", "Alle als gelesen markieren", "Marquer tout comme lu", "Marcar todo como leído", "Marcar tudo como lido"}}, + {"全部断开", {"全部断开", "Disconnect all", "Отключить всех", "全部斷開", "全て切断する", "모두 연결 해제", "Alle Verbindungen trennen", "Tout déconnecter", "Desconectar todo", "Desconecte tudo"}}, + {"全部设备", {"全部设备", "All devices", "Все устройства", "全部裝置", "すべてのデバイス", "모든 장치", "Alle Geräte", "Tous les appareils", "Todos los dispositivos", "Todos os dispositivos"}}, + {"关于", {"关于", "About", "О программе", "關於", "概要", "소개", "Ungefähr", "À propos", "Acerca de", "Sobre"}}, + {"关闭", {"关闭", "Close", "Закрыть", "關閉", "閉じる", "닫기", "Schließen", "Fermer", "Cerrar", "Fechar"}}, + {"关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。", {"关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。", "Disabling IP connections hides the mode button and ends IP sessions.", "Отключение подключений по IP скроет кнопку режима и завершит IP-сеансы.", "關閉 IP 連線將隱藏模式按鈕,並斷開 IP 連線會話。", "IP 接続を無効にすると、モード ボタンが非表示になり、IP セッションが終了します。", "IP 연결을 비활성화하면 모드 버튼이 숨겨지고 IP 세션이 종료됩니다.", "Durch das Deaktivieren von IP-Verbindungen wird die Modusschaltfläche ausgeblendet und IP-Sitzungen beendet.", "La désactivation des connexions IP masque le bouton de mode et met fin aux sessions IP.", "Deshabilitar las conexiones IP oculta el botón de modo y finaliza las sesiones IP.", "Desativar conexões IP oculta o botão de modo e encerra sessões IP."}}, + {"关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。", {"关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。", "Once closed, this prompt stays hidden until the version changes. Sponsorship links remain available in About.", "После закрытия это окно появится только при смене версии. Ссылки для поддержки останутся в разделе «О программе».", "關閉後本版本不再提示,升級後再次顯示。贊助入口仍在「關於」中。", "このプロンプトは一度閉じると、バージョンが変更されるまで非表示になります。スポンサーリンクは「About」から引き続き利用できます。", "일단 닫히면 이 메시지는 버전이 변경될 때까지 숨겨진 상태로 유지됩니다. 후원 링크는 정보에서 계속 사용할 수 있습니다.", "Nach dem Schließen bleibt diese Eingabeaufforderung ausgeblendet, bis sich die Version ändert. Sponsoring-Links bleiben weiterhin in „Info“ verfügbar.", "Une fois fermée, cette invite reste masquée jusqu'à ce que la version change. Les liens de parrainage restent disponibles dans À propos.", "Una vez cerrado, este mensaje permanece oculto hasta que cambie la versión. Los enlaces de patrocinio permanecen disponibles en Acerca de.", "Uma vez fechado, este prompt permanece oculto até que a versão seja alterada. Os links de patrocínio permanecem disponíveis em Sobre."}}, + {"关闭窗口", {"关闭窗口", "Close window", "Закрыть окно", "關閉視窗", "ウィンドウを閉じる", "창 닫기", "Fenster schließen", "Fermer la fenêtre", "Cerrar ventana", "Fechar janela"}}, + {"关闭群控", {"关闭群控", "Stop group control", "Откл. групп. ввод", "關閉群控", "グループ制御の停止", "그룹 제어 중지", "Gruppensteuerung stoppen", "Arrêter le contrôle de groupe", "Detener control de grupo", "Parar controle de grupo"}}, + {"关闭隐私屏", {"关闭隐私屏", "Disable privacy screen", "Выключить приватный экран", "關閉隱私屏", "プライバシー画面を無効にする", "개인 정보 보호 화면 비활성화", "Privatsphäre-Bildschirm deaktivieren", "Désactiver l'écran de confidentialité", "Desactivar la pantalla de privacidad", "Desativar tela de privacidade"}}, + {"分发文件", {"分发文件", "Send file", "Отправить файл", "分發檔案", "ファイルの送信", "파일 보내기", "Datei senden", "Envoyer le fichier", "Enviar archivo", "Enviar arquivo"}}, + {"分组", {"分组", "Group", "Группа", "分組", "グループ", "그룹", "Gruppe", "Groupe", "Grupo", "Grupo"}}, + {"分组名称(可选)", {"分组名称(可选)", "Group name (optional)", "Группа (необязательно)", "分組名稱(可選)", "グループ名(任意)", "그룹 이름(선택)", "Gruppenname (optional)", "Nom du groupe (facultatif)", "Nombre del grupo (opcional)", "Nome do grupo (opcional)"}}, + {"分辨率", {"分辨率", "Resolution", "Разрешение", "解析度", "解像度", "해상도", "Auflösung", "Résolution", "Resolución", "Resolução"}}, + {"分辨率上限", {"分辨率上限", "Resolution limit", "Макс. разрешение", "解析度上限", "解像度制限", "해상도 제한", "Auflösungsgrenze", "Limite de résolution", "Límite de resolución", "Limite de resolução"}}, + {"切换 IP", {"切换 IP", "Switch IP", "Сменить IP", "切換 IP", "スイッチIP", "IP 전환", "IP wechseln", "Changer d'adresse IP", "Cambiar IP", "Trocar IP"}}, + {"切换到 ID 连接模式", {"切换到 ID 连接模式", "Switch to ID connection mode", "Переключить в режим ID", "切換到 ID 連線模式", "ID接続モードに切り替える", "ID 연결 모드로 전환", "Wechseln Sie in den ID-Verbindungsmodus", "Passer en mode de connexion ID", "Cambiar al modo de conexión ID", "Mudar para o modo de conexão ID"}}, + {"切换到 IP 连接模式", {"切换到 IP 连接模式", "Switch to IP connection mode", "Переключить в режим IP", "切換到 IP 連線模式", "IP接続モードに切り替える", "IP 연결 모드로 전환", "Wechseln Sie in den IP-Verbindungsmodus", "Passer en mode de connexion IP", "Cambiar al modo de conexión IP", "Mudar para o modo de conexão IP"}}, + {"切换本机 IP", {"切换本机 IP", "Switch local IP", "Сменить локальный IP", "切換本機 IP", "ローカルIPの切り替え", "로컬 IP 전환", "Lokale IP wechseln", "Changer d'adresse IP locale", "Cambiar IP local", "Trocar IP local"}}, + {"切换设备分组,查看其他连接记录。", {"切换设备分组,查看其他连接记录。", "Choose another group to see your other connections.", "Выберите другую группу для просмотра подключений.", "切換裝置分組,檢視其他連線記錄。", "別のグループを選択して、他の接続を確認します。", "다른 연결을 보려면 다른 그룹을 선택하세요.", "Wählen Sie eine andere Gruppe, um Ihre anderen Verbindungen anzuzeigen.", "Choisissez un autre groupe pour voir vos autres connexions.", "Elige otro grupo para ver tus otras conexiones.", "Escolha outro grupo para ver suas outras conexões."}}, + {"删除", {"删除", "Delete", "Удалить", "刪除", "削除", "삭제", "Löschen", "Supprimer", "Eliminar", "Excluir"}}, + {"删除公告", {"删除公告", "Delete announcement", "Удалить объявление", "刪除公告", "お知らせの削除", "공지사항 삭제", "Ansage löschen", "Supprimer l'annonce", "Eliminar anuncio", "Excluir anúncio"}}, + {"删除记录", {"删除记录", "Delete record", "Удалить запись", "刪除記錄", "レコードの削除", "기록 삭제", "Datensatz löschen", "Supprimer l'enregistrement", "Eliminar registro", "Excluir registro"}}, + {"删除这条公告?", {"删除这条公告?", "Delete this announcement?", "Удалить это объявление?", "刪除這條公告?", "このお知らせを削除しますか?", "이 공지를 삭제하시겠습니까?", "Diese Ankündigung löschen?", "Supprimer cette annonce ?", "¿Eliminar este anuncio?", "Excluir este anúncio?"}}, + {"删除连接", {"删除连接", "Delete Connection", "Удалить подключение", "刪除連線", "接続を削除", "연결 삭제", "Verbindung löschen", "Supprimer la connexion", "Eliminar conexión", "Excluir conexão"}}, + {"刷新状态", {"刷新状态", "Refresh status", "Обновить статус", "重新整理狀態", "リフレッシュステータス", "새로 고침 상태", "Aktualisierungsstatus", "Actualiser l'état", "Estado de actualización", "Atualizar status"}}, + {"刷新随机密码", {"刷新随机密码", "Refresh random password", "Обновить случайный пароль", "重新整理隨機密碼", "ランダムパスワードを更新する", "무작위 비밀번호 새로고침", "Zufälliges Passwort aktualisieren", "Actualiser le mot de passe aléatoire", "Actualizar contraseña aleatoria", "Atualizar senha aleatória"}}, + {"前往设置", {"前往设置", "Open settings", "Настройки", "前往設定", "設定を開く", "설정 열기", "Einstellungen öffnen", "Ouvrir les paramètres", "Abrir configuración", "Abrir configurações"}}, + {"加入桌面墙", {"加入桌面墙", "Add to DeskHub", "В DeskHub", "加入桌面牆", "DeskHubに追加", "DeskHub에 추가", "Zu DeskHub hinzufügen", "Ajouter à DeskHub", "Agregar a DeskHub", "Adicionar a DeskHub"}}, + {"加入桌面墙后,可通过批量选择连接", {"加入桌面墙后,可通过批量选择连接", "Add to DeskHub, then select devices to connect.", "Добавьте в DeskHub, затем выберите устройства для подключения.", "加入桌面牆後,可透過批次選擇連線", "DeskHubに追加し、接続するデバイスを選択します。", "DeskHub에 추가하고, 연결할 기기를 선택하세요.", "Zu DeskHub hinzufügen und dann die zu verbindenden Geräte auswählen.", "Ajoutez à DeskHub, puis sélectionnez les appareils à connecter.", "Agregar a DeskHub, luego seleccione los dispositivos para conectar.", "Adicione a DeskHub e selecione os dispositivos para conectar."}}, + {"加密传输", {"加密传输", "Encryption", "Шифрование", "加密傳輸", "暗号化", "암호화", "Verschlüsselung", "Cryptage", "Cifrado", "Criptografia"}}, + {"原始分辨率", {"原始分辨率", "Original resolution", "Исходное разрешение", "原始解析度", "元の解像度", "원본 해상도", "Originalauflösung", "Résolution originale", "Resolución original", "Resolução original"}}, + {"原设置已保留。", {"原设置已保留。", "Your previous settings are unchanged.", "Прежние настройки сохранены.", "原設定已保留。", "以前の設定は変更されません。", "이전 설정은 변경되지 않습니다.", "Ihre bisherigen Einstellungen bleiben unverändert.", "Vos paramètres précédents restent inchangés.", "Tus configuraciones anteriores no cambian.", "Suas configurações anteriores permanecem inalteradas."}}, + {"双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。", {"双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。", "The protocol or encryption capabilities are incompatible. Update CrossDesk on both devices and try again.", "Протоколы или возможности шифрования несовместимы. Обновите CrossDesk на обоих устройствах и повторите попытку.", "雙方的協議或加密能力不相容,請將雙方 CrossDesk 升級至最新版本後重試。", "プロトコルまたは暗号化機能に互換性がありません。両方のデバイスでCrossDeskを更新し、再試行してください。", "프로토콜 또는 암호화 기능이 호환되지 않습니다. 두 기기 모두에서CrossDesk를 업데이트하고 다시 시도하세요.", "Das Protokoll oder die Verschlüsselungsfunktionen sind nicht kompatibel. Aktualisieren Sie CrossDesk auf beiden Geräten und versuchen Sie es erneut.", "Le protocole ou les capacités de cryptage sont incompatibles. Mettez à jour CrossDesk sur les deux appareils et réessayez.", "El protocolo o las capacidades de cifrado son incompatibles. Actualice CrossDesk en ambos dispositivos y vuelva a intentarlo.", "O protocolo ou os recursos de criptografia são incompatíveis. Atualize CrossDesk em ambos os dispositivos e tente novamente."}}, + {"发布日期: ", {"发布日期: ", "Release Date: ", "Дата релиза: ", "釋出日期: ", "発売日: ", "출시일: ", "Erscheinungsdatum: ", "Date de sortie : ", "Fecha de lanzamiento: ", "Data de lançamento: "}}, + {"发起连接", {"发起连接", "Connect", "Подключиться", "發起連線", "接続する", "연결하다", "Verbinden", "Connectez-vous", "Conectar", "Conectar"}}, + {"发送 SAS", {"发送 SAS", "Send SAS", "Отправить SAS", "傳送 SAS", "SASの送信", "SAS 보내기", "SAS senden", "Envoyer SAS", "Enviar SAS", "Enviar SAS"}}, + {"发送密码修改请求失败,请等待连接恢复后重试。", {"发送密码修改请求失败,请等待连接恢复后重试。", "Failed to submit password change; retry after reconnection.", "Не удалось отправить запрос смены пароля. Повторите после подключения.", "傳送密碼修改請求失敗,請等待連線恢復後重試。", "パスワード変更の送信に失敗しました。再接続後に再試行してください。", "비밀번호 변경을 제출하지 못했습니다. 다시 연결한 후 다시 시도하세요.", "Passwortänderung konnte nicht übermittelt werden; Versuchen Sie es nach erneuter Verbindung erneut.", "Échec de la soumission du changement de mot de passe ; réessayez après la reconnexion.", "No se pudo enviar el cambio de contraseña; Vuelva a intentarlo después de la reconexión.", "Falha ao enviar alteração de senha; tente novamente após a reconexão."}}, + {"发送文件", {"发送文件", "Send file", "Отправить файл", "傳送檔案", "ファイル送信", "파일 보내기", "Datei senden", "Envoyer le fichier", "Enviar archivo", "Enviar arquivo"}}, + {"发送组合键", {"发送组合键", "Send Shortcut", "Отправить сочетание клавиш", "傳送組合鍵", "ショートカット送信", "바로가기 보내기", "Verknüpfung senden", "Envoyer un raccourci", "Enviar acceso directo", "Enviar atalho"}}, + {"取消", {"取消", "Cancel", "Отмена", "取消", "キャンセル", "취소", "Abbrechen", "Annuler", "Cancelar", "Cancelar"}}, + {"取消全选", {"取消全选", "Deselect all", "Снять выбор", "取消全選", "すべての選択を解除", "모두 선택 취소", "Alle abwählen", "Tout désélectionner", "Deseleccionar todo", "Desmarcar tudo"}}, + {"取消静音", {"取消静音", "Unmute", "Со звуком", "取消靜音", "ミュートを解除する", "음소거 해제", "Stummschaltung aufheben", "Activer le son", "Activar el silencio", "Ativar som"}}, + {"受 Wayland 安全机制限制,每次启动远程桌面共享时,均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。", {"受 Wayland 安全机制限制,每次启动远程桌面共享时,均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。", "Wayland security restrictions require you to authorize screen sharing and remote control locally each time you start sharing this desktop. Remote access is available only after authorization.", "Из-за ограничений безопасности Wayland при каждом запуске общего доступа к рабочему столу необходимо вручную разрешать на этом компьютере показ экрана и удалённое управление. Удалённый доступ возможен только после разрешения.", "受 Wayland 安全機制限制,每次啟動遠端桌面共享時,均需在本機手動授權螢幕共享與遠端控制,授權後方可正常使用。", "Wayland のセキュリティ制限により、このデスクトップの共有を開始するたびに、ローカルでの画面共有とリモート コントロールを承認する必要があります。リモートアクセスは認証後にのみ利用可能です。", "Wayland 보안 제한 사항에서는 이 데스크탑 공유를 시작할 때마다 로컬에서 화면 공유 및 원격 제어를 승인해야 합니다. 원격 접속은 인증 후에만 가능합니다.", "Aufgrund der Sicherheitsbeschränkungen von Wayland müssen Sie die Bildschirmfreigabe und Fernsteuerung jedes Mal lokal autorisieren, wenn Sie mit der Freigabe dieses Desktops beginnen. Der Fernzugriff ist nur nach Autorisierung möglich.", "Les restrictions de sécurité de Wayland vous obligent à autoriser le partage d'écran et le contrôle à distance localement chaque fois que vous commencez à partager ce bureau. L'accès à distance n'est disponible qu'après autorisation.", "Las restricciones de seguridad de Wayland requieren que autorices el uso compartido de pantalla y el control remoto localmente cada vez que comienzas a compartir este escritorio. El acceso remoto está disponible solo después de la autorización.", "As restrições de segurança do Wayland exigem que você autorize o compartilhamento de tela e o controle remoto localmente sempre que começar a compartilhar esta área de trabalho. O acesso remoto está disponível somente após autorização."}}, + {"只读预览", {"只读预览", "View only", "Просмотр", "只讀預覽", "閲覧のみ", "보기 전용", "Nur Ansicht", "Visualisation uniquement", "Ver solo", "Somente visualização"}}, + {"台设备", {"台设备", "devices", "устройств", "臺裝置", "デバイス", "장치", "Geräte", "appareils", "dispositivos", "dispositivos"}}, + {"启动与后台", {"启动与后台", "Startup & background", "Запуск и фоновая работа", "啟動與後臺", "起動と背景", "창업 및 배경", "Start und Hintergrund", "Démarrage et arrière-plan", "Inicio y antecedentes", "Inicialização e histórico"}}, + {"启用 IP 连接", {"启用 IP 连接", "Enable IP connections", "Подключение по IP", "啟用 IP 連線", "IP接続を有効にする", "IP 연결 활성화", "IP-Verbindungen aktivieren", "Activer les connexions IP", "Habilitar conexiones IP", "Habilitar conexões IP"}}, + {"启用守护进程", {"启用守护进程", "Enable Daemon", "Включить демон", "啟用守護程序", "デーモンを有効にする", "데몬 활성화", "Daemon aktivieren", "Activer le démon", "Habilitar demonio", "Habilitar Daemon"}}, + {"命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出", {"命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出", "Commands: status — show ID/password/status; settings — configure; password — change password; random — random password; help — help; quit — exit", "Команды: status — ID/пароль/состояние; settings — настройки; password — сменить пароль; random — случайный пароль; help — справка; quit — выход", "命令: status 檢視 ID/密碼/狀態;settings 設定;password 修改密碼;random 隨機密碼;help 幫助;quit 退出", "コマンド: status — ID/パスワード/ステータスを表示します。設定 — 構成します。パスワード — パスワードを変更します。ランダム — ランダムなパスワード。助けてください — 助けてください。終了 — 終了", "명령: status — ID/비밀번호/상태를 표시합니다. 설정 - 구성; 비밀번호 - 비밀번호 변경; 무작위 - 무작위 비밀번호; 도움 — 도움; 종료 - 종료", "Befehle: Status – ID/Passwort/Status anzeigen; Einstellungen – konfigurieren; Passwort – Passwort ändern; random – zufälliges Passwort; Hilfe – Hilfe; beenden – beenden", "Commandes : statut – afficher l'ID/mot de passe/statut ; paramètres — configurer ; mot de passe — changer le mot de passe ; aléatoire — mot de passe aléatoire ; aide — aide; quitter - sortir", "Comandos: estado: mostrar ID/contraseña/estado; ajustes - configurar; contraseña — cambiar contraseña; aleatorio — contraseña aleatoria; ayuda—ayuda; salir - salir", "Comandos: status — mostrar ID/senha/status; configurações — configurar; senha — alterar senha; aleatório — senha aleatória; ajuda — ajuda; sair – sair"}}, + {"命令过长,已忽略。", {"命令过长,已忽略。", "Command too long; ignored.", "Команда слишком длинная и проигнорирована.", "命令過長,已忽略。", "コマンドが長すぎます。無視されました。", "명령이 너무 깁니다. 무시되었습니다.", "Befehl zu lang; ignoriert.", "Commande trop longue ; ignoré.", "Comando demasiado largo; ignorado.", "Comando muito longo; ignorado."}}, + {"在线", {"在线", "Online", "В сети", "線上", "オンライン", "온라인", "Online", "En ligne", "En línea", "On-line"}}, + {"复制 IP 和端口", {"复制 IP 和端口", "Copy IP and port", "Копировать IP и порт", "複製 IP 和埠", "IPとポートをコピーする", "IP 및 포트 복사", "IP und Port kopieren", "Copier l'IP et le port", "Copiar IP y puerto", "Copiar IP e porta"}}, + {"复制失败,请重试", {"复制失败,请重试", "Couldn’t copy. Try again", "Не удалось скопировать. Повторите попытку", "複製失敗,請重試", "コピーできませんでした。もう一度試してください", "복사할 수 없습니다. 다시 시도하세요", "Kopieren nicht möglich. Versuchen Sie es erneut", "Impossible de copier. Réessayez", "No se pudo copiar. Inténtalo de nuevo", "Não foi possível copiar. Tente novamente"}}, + {"复制失败,请重试。", {"复制失败,请重试。", "Could not copy. Try again.", "Не удалось скопировать. Повторите попытку.", "複製失敗,請重試。", "コピーできませんでした。もう一度やり直してください。", "복사할 수 없습니다. 다시 시도해 보세요.", "Kopieren nicht möglich. Versuchen Sie es erneut.", "Impossible de copier. Essayer à nouveau.", "No se pudo copiar. Intentar otra vez.", "Não foi possível copiar. Tente novamente."}}, + {"复制本机 ID", {"复制本机 ID", "Copy local ID", "Копировать ID", "複製本機 ID", "ローカルIDをコピーする", "로컬 ID 복사", "Lokale ID kopieren", "Copier l'identifiant local", "Copiar ID local", "Copiar ID local"}}, + {"失败", {"失败", "Failed", "Ошибка", "失敗", "失敗しました", "실패", "Fehlgeschlagen", "Échec", "Fallido", "Falhou"}}, + {"如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!", {"如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!", "If CrossDesk is useful to you, consider supporting its continued development, cross-platform testing, and maintenance. Thank you for your support!", "Если CrossDesk вам полезен, поддержите его дальнейшую разработку, тестирование на разных платформах и сопровождение. Спасибо за вашу поддержку!", "如果 CrossDesk 對你有幫助,歡迎贊助支援專案的持續開發、跨平臺測試與日常維護。感謝你的支援!", "CrossDeskが役立つ場合は、継続的な開発、クロスプラットフォーム テスト、およびメンテナンスのサポートを検討してください。ご支援ありがとうございます!", "CrossDesk가 유용하다면 지속적인 개발, 크로스 플랫폼 테스트 및 유지 관리 지원을 고려해보세요. 귀하의 지원에 감사드립니다!", "Wenn CrossDesk für Sie nützlich ist, sollten Sie darüber nachdenken, seine weitere Entwicklung, plattformübergreifende Tests und Wartung zu unterstützen. Vielen Dank für Ihre Unterstützung!", "Si CrossDesk vous est utile, envisagez de prendre en charge son développement continu, ses tests multiplateformes et sa maintenance. Merci pour votre soutien !", "Si CrossDesk le resulta útil, considere respaldar su desarrollo continuo, pruebas multiplataforma y mantenimiento. ¡Gracias por su apoyo!", "Se CrossDesk for útil para você, considere apoiar seu desenvolvimento contínuo, testes de plataforma cruzada e manutenção. Obrigado pelo seu apoio!"}}, + {"守护进程(无头控制台中不生效)", {"守护进程(无头控制台中不生效)", "Daemon (inactive in headless console)", "Фоновый режим (не действует в консоли)", "守護程序(無頭控制檯中不生效)", "デーモン (ヘッドレス コンソールでは非アクティブ)", "데몬(헤드리스 콘솔에서는 비활성)", "Daemon (in der Headless-Konsole inaktiv)", "Démon (inactif dans la console sans tête)", "Daemon (inactivo en consola sin cabeza)", "Daemon (inativo no console headless)"}}, + {"安装", {"安装", "Install", "Установить", "安裝", "インストール", "설치", "Installieren", "Installer", "Instalar", "Instalar"}}, + {"安装 CrossDesk Service", {"安装 CrossDesk Service", "Install CrossDesk Service", "Установить CrossDesk Service", "安裝 CrossDesk Service", "CrossDeskサービスのインストール", "CrossDesk서비스 설치", "Installieren Sie den CrossDesk-Dienst", "Installer le service CrossDesk", "Instalar el servicio CrossDesk", "Instale o serviço CrossDesk"}}, + {"安装更新", {"安装更新", "Install update", "Установить обновление", "安裝更新", "アップデートのインストール", "업데이트 설치", "Update installieren", "Installer la mise à jour", "Instalar actualización", "Instalar atualização"}}, + {"完成", {"完成", "Done", "Готово", "完成", "完了", "완료", "Fertig", "Terminé", "Hecho", "Feito"}}, + {"密码", {"密码", "Password", "Пароль", "密碼", "パスワード", "비밀번호", "Passwort", "Mot de passe", "Contraseña", "Senha"}}, + {"密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。", {"密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。", "The password is incorrect or has changed. Check the other desktop's current LAN password and try again.", "Пароль неверен или изменён. Проверьте текущий пароль LAN другого компьютера и повторите попытку.", "密碼不正確,或對方密碼已更新。請檢視對方的區域網訪問密碼後重試。", "パスワードが間違っているか、変更されています。他のデスクトップの現在の LAN パスワードを確認し、再試行してください。", "비밀번호가 틀리거나 변경되었습니다. 다른 데스크톱의 현재 LAN 비밀번호를 확인하고 다시 시도하세요.", "Das Passwort ist falsch oder wurde geändert. Überprüfen Sie das aktuelle LAN-Passwort des anderen Desktops und versuchen Sie es erneut.", "Le mot de passe est incorrect ou a changé. Vérifiez le mot de passe LAN actuel de l'autre ordinateur de bureau et réessayez.", "La contraseña es incorrecta o ha cambiado. Verifique la contraseña LAN actual del otro escritorio e inténtelo nuevamente.", "A senha está incorreta ou foi alterada. Verifique a senha LAN atual da outra área de trabalho e tente novamente."}}, + {"密码修改正在处理中,请等待服务器确认。", {"密码修改正在处理中,请等待服务器确认。", "Password change pending; wait for server confirmation.", "Смена пароля выполняется. Дождитесь подтверждения сервера.", "密碼修改正在處理中,請等待伺服器確認。", "パスワード変更は保留中です。サーバーの確認を待ちます。", "비밀번호 변경이 보류 중입니다. 서버 확인을 기다립니다.", "Passwortänderung steht aus; Warten Sie auf die Serverbestätigung.", "Changement de mot de passe en attente ; attendez la confirmation du serveur.", "Cambio de contraseña pendiente; espere la confirmación del servidor.", "Alteração de senha pendente; aguarde a confirmação do servidor."}}, + {"密码修改结果尚未确认,正在重新连接服务器核实。", {"密码修改结果尚未确认,正在重新连接服务器核实。", "Password change not yet confirmed; reconnecting to verify.", "Смена пароля не подтверждена. Повторное подключение для проверки.", "密碼修改結果尚未確認,正在重新連線伺服器核實。", "パスワードの変更はまだ確認されていません。再接続して確認します。", "비밀번호 변경이 아직 확인되지 않았습니다. 확인을 위해 다시 연결하는 중입니다.", "Passwortänderung noch nicht bestätigt; Zur Überprüfung wird die Verbindung erneut hergestellt.", "Changement de mot de passe pas encore confirmé ; reconnexion pour vérifier.", "Cambio de contraseña aún no confirmado; reconectándose para verificar.", "Alteração de senha ainda não confirmada; reconectando para verificar."}}, + {"密码必须为 6 位英文字母或数字。", {"密码必须为 6 位英文字母或数字。", "Use exactly 6 letters (A–Z, a–z) or digits (0–9).", "Пароль должен содержать ровно 6 латинских букв или цифр.", "密碼必須為 6 位英文字母或數字。", "正確に 6 つの文字 (A ~ Z、a ~ z) または数字 (0 ~ 9) を使用します。", "정확히 6개의 문자(A~Z, a~z) 또는 숫자(0~9)를 사용하세요.", "Verwenden Sie genau 6 Buchstaben (A–Z, a–z) oder Ziffern (0–9).", "Utilisez exactement 6 lettres (A–Z, a–z) ou chiffres (0–9).", "Utilice exactamente 6 letras (A–Z, a–z) o dígitos (0–9).", "Use exatamente 6 letras (A–Z, a–z) ou dígitos (0–9)."}}, + {"密码必须是6位英文字母或数字,未提交修改。", {"密码必须是6位英文字母或数字,未提交修改。", "Password must be 6 ASCII letters or digits; no change submitted.", "Пароль должен содержать 6 латинских букв или цифр. Изменение не отправлено.", "密碼必須是6位英文字母或數字,未提交修改。", "パスワードは 6 文字の ASCII 文字または数字でなければなりません。変更は送信されませんでした。", "비밀번호는 6자리 ASCII 문자 또는 숫자여야 합니다. 변경사항이 제출되지 않았습니다.", "Das Passwort muss aus 6 ASCII-Buchstaben oder -Ziffern bestehen. Keine Änderung eingereicht.", "Le mot de passe doit contenir 6 lettres ou chiffres ASCII ; aucun changement soumis.", "La contraseña debe tener 6 letras o dígitos ASCII; no se envió ningún cambio.", "A senha deve ter 6 letras ou dígitos ASCII; nenhuma alteração enviada."}}, + {"对方密码已更新,请使用新密码重试。", {"对方密码已更新,请使用新密码重试。", "The password changed. Try again with the new password.", "Пароль изменился. Повторите с новым паролем.", "對方密碼已更新,請使用新密碼重試。", "パスワードが変更されました。新しいパスワードを使用して再試行してください。", "비밀번호가 변경되었습니다. 새 비밀번호로 다시 시도해 보세요.", "Das Passwort wurde geändert. Versuchen Sie es erneut mit dem neuen Passwort.", "Le mot de passe a changé. Réessayez avec le nouveau mot de passe.", "La contraseña cambió. Vuelva a intentarlo con la nueva contraseña.", "A senha foi alterada. Tente novamente com a nova senha."}}, + {"对端 ID", {"对端 ID", "Remote ID", "Удаленный ID", "對端 ID", "リモートID", "원격 ID", "Remote-ID", "ID à distance", "Identificación remota", "ID remoto"}}, + {"对等连接失败", {"对等连接失败", "P2P Failed", "Сбой P2P", "對等連線失敗", "P2P 失敗", "P2P 실패", "P2P fehlgeschlagen", "Échec du P2P", "P2P falló", "Falha no P2P"}}, + {"对等连接已关闭", {"对等连接已关闭", "P2P closed", "P2P закрыто", "對等連線已關閉", "P2Pは終了しました", "P2P 폐쇄", "P2P geschlossen", "P2P fermé", "P2P cerrado", "P2P fechado"}}, + {"对等连接已建立", {"对等连接已建立", "P2P Connected", "P2P подключено", "對等連線已建立", "P2P接続済み", "P2P 연결됨", "P2P verbunden", "P2P connecté", "P2P conectado", "Conectado P2P"}}, + {"对等连接已断开", {"对等连接已断开", "P2P Disconnected", "P2P отключено", "對等連線已斷開", "P2Pが切断されました", "P2P 연결 끊김", "P2P getrennt", "P2P déconnecté", "P2P desconectado", "P2P desconectado"}}, + {"将 ID 和密码分享给连接方", {"将 ID 和密码分享给连接方", "Share your ID and password to get connected", "Передайте ID и пароль для подключения", "將 ID 和密碼分享給連線方", "IDとパスワードを共有して接続する", "연결을 위해 ID와 비밀번호를 공유하세요", "Teilen Sie Ihre ID und Ihr Passwort mit, um eine Verbindung herzustellen", "Partagez votre identifiant et votre mot de passe pour vous connecter", "Comparte tu ID y contraseña para conectarte", "Compartilhe seu ID e senha para se conectar"}}, + {"将 IP 和密码分享给连接方", {"将 IP 和密码分享给连接方", "Share your IP and password to get connected", "Передайте IP и пароль для подключения", "將 IP 和密碼分享給連線方", "IP とパスワードを共有して接続します", "연결하려면 IP와 비밀번호를 공유하세요.", "Teilen Sie Ihre IP und Ihr Passwort mit, um eine Verbindung herzustellen", "Partagez votre IP et votre mot de passe pour vous connecter", "Comparte tu IP y contraseña para conectarte", "Compartilhe seu IP e senha para se conectar"}}, + {"尚未连接服务器,暂时无法修改密码。", {"尚未连接服务器,暂时无法修改密码。", "Connect to the server before changing the password.", "Для смены пароля подключитесь к серверу.", "尚未連線伺服器,暫時無法修改密碼。", "パスワードを変更する前にサーバーに接続してください。", "비밀번호를 변경하기 전에 서버에 접속하세요.", "Stellen Sie eine Verbindung zum Server her, bevor Sie das Passwort ändern.", "Connectez-vous au serveur avant de modifier le mot de passe.", "Conéctese al servidor antes de cambiar la contraseña.", "Conecte-se ao servidor antes de alterar a senha."}}, + {"尚未连接服务器,请稍后重试", {"尚未连接服务器,请稍后重试", "Not connected to the server; try again shortly", "Нет соединения с сервером. Повторите позже", "尚未連線伺服器,請稍後重試", "サーバーに接続されていません。すぐにもう一度試してください", "서버에 연결되지 않았습니다. 잠시 후 다시 시도해 보세요", "Keine Verbindung zum Server; Versuchen Sie es in Kürze noch einmal", "Non connecté au serveur ; réessayez sous peu", "No conectado al servidor; inténtalo de nuevo en breve", "Não conectado ao servidor; tente novamente em breve"}}, + {"尝试次数过多,请等待倒计时结束后重试。", {"尝试次数过多,请等待倒计时结束后重试。", "Too many attempts. Try again when the countdown ends.", "Слишком много попыток. Дождитесь окончания обратного отсчёта.", "嘗試次數過多,請等待倒計時結束後重試。", "試行回数が多すぎます。カウントダウンが終了したらもう一度お試しください。", "시도 횟수가 너무 많습니다. 카운트다운이 끝나면 다시 시도하세요.", "Zu viele Versuche. Versuchen Sie es erneut, wenn der Countdown abgelaufen ist.", "Trop de tentatives. Réessayez une fois le compte à rebours terminé.", "Demasiados intentos. Inténtalo de nuevo cuando termine la cuenta regresiva.", "Muitas tentativas. Tente novamente quando a contagem regressiva terminar."}}, + {"局域网端口", {"局域网端口", "LAN port", "Порт LAN", "區域網埠", "LANポート", "LAN 포트", "LAN-Anschluss", "Port LAN", "Puerto LAN", "Porta LAN"}}, + {"屏幕录制权限", {"屏幕录制权限", "Screen Recording Permission", "Разрешение на запись экрана", "螢幕錄製許可權", "画面録画許可", "화면 녹화 권한", "Erlaubnis zur Bildschirmaufzeichnung", "Autorisation d'enregistrement d'écran", "Permiso de grabación de pantalla", "Permissão de gravação de tela"}}, + {"展开控制栏", {"展开控制栏", "Expand Control Bar", "Развернуть панель управления", "展開控制欄", "コントロールバーを展開する", "컨트롤 바 확장", "Erweitern Sie die Steuerleiste", "Développer la barre de contrôle", "Expandir barra de control", "Expandir barra de controle"}}, + {"已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。", {"已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。", "You will not be reminded again. To enable remote control while locked later, click Install in Settings.", "Напоминание отключено. Чтобы позже включить удаленное управление на экране блокировки, нажмите «Установить» в настройках.", "已不再提醒。後續如需啟用鎖屏狀態下被遠端控制,可在設定中點選“安裝”。", "再度通知されることはありません。後でロック中にリモート コントロールを有効にするには、[設定] で [インストール] をクリックします。", "다시 알림을 받지 않습니다. 나중에 잠긴 상태에서 원격 제어를 활성화하려면 설정에서 설치를 클릭하세요.", "Sie werden nicht erneut erinnert. Um die Fernsteuerung später bei gesperrtem Gerät zu aktivieren, klicken Sie in den Einstellungen auf „Installieren“.", "Vous ne recevrez plus de rappel. Pour activer le contrôle à distance tout en étant verrouillé ultérieurement, cliquez sur Installer dans Paramètres.", "No se te recordará más. Para habilitar el control remoto mientras está bloqueado más tarde, haga clic en Instalar en Configuración.", "Você não será lembrado novamente. Para ativar o controle remoto enquanto estiver bloqueado posteriormente, clique em Instalar em Configurações."}}, + {"已保存并生效。", {"已保存并生效。", "Saved and applied.", "Сохранено и применено.", "已儲存並生效。", "保存して適用しました。", "저장하고 적용했습니다.", "Gespeichert und angewendet.", "Enregistré et appliqué.", "Guardado y aplicado.", "Salvo e aplicado."}}, + {"已保存,在下次图形桌面登录时生效。", {"已保存,在下次图形桌面登录时生效。", "Saved; applies at the next graphical desktop login.", "Сохранено. Будет применено при следующем входе в графический сеанс.", "已儲存,在下次圖形桌面登入時生效。", "保存されました。次回のグラフィカル デスクトップ ログイン時に適用されます。", "저장되었습니다. 다음 그래픽 데스크탑 로그인 시 적용됩니다.", "Gespeichert; gilt beim nächsten grafischen Desktop-Login.", "Enregistré ; s'applique à la prochaine connexion au bureau graphique.", "Guardado; se aplica en el siguiente inicio de sesión del escritorio gráfico.", "Salvo; aplica-se no próximo login da área de trabalho gráfica."}}, + {"已保存,将用于后续接收的文件。", {"已保存,将用于后续接收的文件。", "Saved; applies to subsequently received files.", "Сохранено. Будет применено к следующим получаемым файлам.", "已儲存,將用於後續接收的檔案。", "保存されました。以降に受信したファイルに適用されます。", "저장되었습니다. 이후에 수신된 파일에 적용됩니다.", "Gespeichert; gilt für später empfangene Dateien.", "Enregistré ; s'applique aux fichiers reçus ultérieurement.", "Guardado; se aplica a los archivos recibidos posteriormente.", "Salvo; aplica-se a arquivos recebidos posteriormente."}}, + {"已保存,将用于后续连接。", {"已保存,将用于后续连接。", "Saved; applies to subsequent connections.", "Сохранено. Будет применено к следующим подключениям.", "已儲存,將用於後續連線。", "保存されました。後続の接続に適用されます。", "저장되었습니다. 후속 연결에 적용됩니다.", "Gespeichert; gilt für spätere Verbindungen.", "Enregistré ; s’applique aux connexions ultérieures.", "Guardado; se aplica a las conexiones posteriores.", "Salvo; aplica-se a conexões subsequentes."}}, + {"已保存,普通模式重启后生效;无头控制台仍保持前台运行。", {"已保存,普通模式重启后生效;无头控制台仍保持前台运行。", "Saved for the next normal-mode start; the headless console stays in the foreground.", "Сохранено для следующего запуска в обычном режиме. Консоль без графического интерфейса остаётся на переднем плане.", "已儲存,普通模式重啟後生效;無頭控制檯仍保持前臺執行。", "次回の通常モードの開始のために保存されます。ヘッドレス コンソールはフォアグラウンドに残ります。", "다음 일반 모드 시작을 위해 저장되었습니다. 헤드리스 콘솔은 전경에 유지됩니다.", "Wird für den nächsten Start im Normalmodus gespeichert; Die Headless-Konsole bleibt im Vordergrund.", "Enregistré pour le prochain démarrage en mode normal ; la console sans tête reste au premier plan.", "Guardado para el próximo inicio del modo normal; la consola sin cabeza permanece en primer plano.", "Salvo para a próxima inicialização no modo normal; o console sem cabeça permanece em primeiro plano."}}, + {"已保存,正在重新连接服务器。", {"已保存,正在重新连接服务器。", "Saved; reconnecting to the server.", "Сохранено. Повторное подключение к серверу.", "已儲存,正在重新連線伺服器。", "保存されました。サーバーに再接続しています。", "저장되었습니다. 서버에 다시 연결하는 중입니다.", "Gespeichert; erneute Verbindung zum Server herstellen.", "Enregistré ; reconnexion au serveur.", "Guardado; reconectándose al servidor.", "Salvo; reconectando-se ao servidor."}}, + {"已加密", {"已加密", "Encrypted", "Зашифровано", "已加密", "暗号化", "암호화됨", "Verschlüsselt", "Crypté", "Encriptado", "Criptografado"}}, + {"已取消", {"已取消", "Cancelled", "Отменено", "已取消", "キャンセル", "취소됨", "Abgesagt", "Annulé", "Cancelado", "Cancelado"}}, + {"已取消修改。", {"已取消修改。", "Change cancelled.", "Изменение отменено.", "已取消修改。", "変更はキャンセルされました。", "변경이 취소되었습니다.", "Änderung abgebrochen.", "Modification annulée.", "Cambio cancelado.", "Alteração cancelada."}}, + {"已复制到剪贴板", {"已复制到剪贴板", "Copied to clipboard", "Скопировано в буфер обмена", "已複製到剪貼簿", "クリップボードにコピーされました", "클립보드에 복사됨", "In die Zwischenablage kopiert", "Copié dans le presse-papiers", "Copiado al portapapeles", "Copiado para a área de transferência"}}, + {"已安装", {"已安装", "Installed", "Установлена", "已安裝", "インストール済み", "설치됨", "Installiert", "Installé", "Instalado", "Instalado"}}, + {"已完成", {"已完成", "Completed", "Завершено", "已完成", "完成", "완료됨", "Abgeschlossen", "Terminé", "Completado", "Concluído"}}, + {"已开启", {"已开启", "Enabled", "Включён", "已開啟", "有効", "활성화됨", "Aktiviert", "Activé", "Habilitado", "Habilitado"}}, + {"已授权", {"已授权", "Granted", "Разрешено", "已授權", "認められる", "승인됨", "Zugegeben", "Accordé", "Concedido", "Concedido"}}, + {"已提交密码修改,正在等待服务器确认……", {"已提交密码修改,正在等待服务器确认……", "Password change submitted; waiting for server confirmation...", "Запрос смены пароля отправлен. Ожидание подтверждения...", "已提交密碼修改,正在等待伺服器確認……", "パスワード変更が送信されました。サーバーの確認を待っています...", "비밀번호 변경이 제출되었습니다. 서버 확인을 기다리는 중...", "Passwortänderung übermittelt; warte auf Serverbestätigung...", "Modification du mot de passe soumise ; en attente de confirmation du serveur...", "Cambio de contraseña enviado; esperando confirmación del servidor...", "Alteração de senha enviada; aguardando confirmação do servidor..."}}, + {"已是最新版本", {"已是最新版本", "You're up to date", "Установлена последняя версия", "已是最新版本", "最新情報を入手しました", "최신 상태입니다", "Du bist auf dem Laufenden", "Vous êtes à jour", "Estás al día", "Você está atualizado"}}, + {"已添加", {"已添加", "Added", "Добавлено", "已新增", "追加", "추가됨", "Hinzugefügt", "Ajouté", "Añadido", "Adicionado"}}, + {"已读", {"已读", "Read", "Прочитано", "已讀", "読む", "읽기", "Lesen", "Lire", "Leer", "Leia"}}, + {"已连接", {"已连接", "Connected", "Подключено", "已連線", "接続されました", "연결됨", "Verbunden", "Connecté", "Conectado", "Conectado"}}, + {"已连接服务器", {"已连接服务器", "Connected to server", "Подключено к серверу", "已連線伺服器", "サーバーに接続しました", "서버에 연결됨", "Mit Server verbunden", "Connecté au serveur", "Conectado al servidor", "Conectado ao servidor"}}, + {"已连接设备 ", {"已连接设备 ", "Connected devices ", "Подключённые устройства ", "已連線裝置 ", "接続機器 ", "연결된 장치 ", "Angeschlossene Geräte ", "Appareils connectés ", "Dispositivos conectados ", "Dispositivos conectados "}}, + {"已选 ", {"已选 ", "Selected ", "Выбрано ", "已選 ", "選択済み ", "선택됨 ", "Ausgewählt ", "Sélectionné ", "Seleccionado ", "Selecionado "}}, + {"帧率", {"帧率", "Frame rate", "Частота кадров", "幀率", "フレームレート", "프레임 속도", "Bildrate", "Fréquence d'images", "Velocidad de fotogramas", "Taxa de quadros"}}, + {"帧率优先", {"帧率优先", "Smooth", "Плавность", "影格率優先", "滑らかさ", "부드러움", "Flüssig", "Fluidité", "Fluidez", "Fluidez"}}, + {"常规", {"常规", "General", "Общие", "常規", "一般", "일반", "Allgemein", "Général", "Generalidades", "Geral"}}, + {"平衡", {"平衡", "Balanced", "Баланс", "平衡", "バランス", "균형", "Balance", "Équilibré", "Equilibrado", "Equilibrado"}}, + {"建立连接后,网络和画面信息将在此显示", {"建立连接后,网络和画面信息将在此显示", "Network and video details appear here once connected", "После подключения здесь появятся данные сети и видео", "建立連線後,網路和畫面資訊將在此顯示", "接続すると、ネットワークとビデオの詳細がここに表示されます", "연결되면 여기에 네트워크 및 비디오 세부정보가 표시됩니다.", "Sobald die Verbindung hergestellt ist, werden hier Netzwerk- und Videodetails angezeigt", "Les détails du réseau et de la vidéo apparaissent ici une fois connectés", "Los detalles de red y video aparecen aquí una vez conectado", "Os detalhes da rede e do vídeo aparecem aqui quando conectado"}}, + {"建议使用 X11(Xorg)", {"建议使用 X11(Xorg)", "X11 (Xorg) is recommended", "Рекомендуем X11 (Xorg)", "建議使用 X11(Xorg)", "X11(Xorg)を推奨", "X11(Xorg)을 권장합니다.", "X11 (Xorg) wird empfohlen", "X11 (Xorg) est recommandé", "Se recomienda X11 (Xorg)", "X11 (Xorg) é recomendado"}}, + {"建议升级被控端", {"建议升级被控端", "Remote update recommended", "Рекомендуем обновить удалённое устройство", "建議升級被控端", "リモートアップデートを推奨", "원격 업데이트 권장", "Remote-Update empfohlen", "Mise à jour à distance recommandée", "Se recomienda actualización remota", "Atualização remota recomendada"}}, + {"开启群控", {"开启群控", "Group control", "Групп. ввод", "開啟群控", "グループ制御", "그룹 제어", "Gruppenkontrolle", "Contrôle de groupe", "Control de grupo", "Controle de grupo"}}, + {"开启隐私屏", {"开启隐私屏", "Enable privacy screen", "Включить приватный экран", "開啟隱私屏", "プライバシー画面を有効にする", "개인 정보 보호 화면 활성화", "Privatsphärenschutz aktivieren", "Activer l'écran de confidentialité", "Habilitar pantalla de privacidad", "Habilitar tela de privacidade"}}, + {"开机自启", {"开机自启", "Auto Start", "Автозапуск", "開機自啟", "オートスタート", "자동 시작", "Autostart", "Démarrage automatique", "Inicio automático", "Início automático"}}, + {"开源组件", {"开源组件", "Open-source components", "Компоненты с открытым кодом", "開源元件", "オープンソースコンポーネント", "오픈 소스 구성 요소", "Open-Source-Komponenten", "Composants open source", "Componentes de código abierto", "Componentes de código aberto"}}, + {"强制中继连接", {"强制中继连接", "Force relay connection", "Только через ретранслятор", "強制中繼連線", "強制リレー接続", "강제 릴레이 연결", "Relaisverbindung erzwingen", "Forcer la connexion du relais", "Conexión del relé de fuerza", "Forçar conexão do relé"}}, + {"当前仍需要安全桌面专用采集/输入", {"当前仍需要安全桌面专用采集/输入", "Secure desktop capture/input is still required", "По-прежнему нужен отдельный захват/ввод для защищенного рабочего стола", "當前仍需要安全桌面專用採集/輸入", "安全なデスクトップ キャプチャ/入力が引き続き必要です", "안전한 데스크톱 캡처/입력이 여전히 필요합니다.", "Eine sichere Desktop-Erfassung/-Eingabe ist weiterhin erforderlich", "La capture/saisie sécurisée du bureau est toujours requise", "Aún se requiere captura/entrada de escritorio segura", "A captura/entrada segura da área de trabalho ainda é necessária"}}, + {"当前网络路径不支持 IP 连接,请检查双方的局域网连接。", {"当前网络路径不支持 IP 连接,请检查双方的局域网连接。", "This network path does not support IP connections. Check both devices' LAN connections.", "Этот сетевой маршрут не поддерживает IP-подключения. Проверьте подключения обоих устройств к LAN.", "當前網路路徑不支援 IP 連線,請檢查雙方的區域網連線。", "このネットワーク パスは IP 接続をサポートしていません。両方のデバイスの LAN 接続を確認します。", "이 네트워크 경로는 IP 연결을 지원하지 않습니다. 두 장치의 LAN 연결을 확인하십시오.", "Dieser Netzwerkpfad unterstützt keine IP-Verbindungen. Überprüfen Sie die LAN-Verbindungen beider Geräte.", "Ce chemin réseau ne prend pas en charge les connexions IP. Vérifiez les connexions LAN des deux appareils.", "Esta ruta de red no admite conexiones IP. Verifique las conexiones LAN de ambos dispositivos.", "Este caminho de rede não suporta conexões IP. Verifique as conexões LAN de ambos os dispositivos."}}, + {"当前设备不支持开机自启动。", {"当前设备不支持开机自启动。", "This device does not support auto start.", "Это устройство не поддерживает автозапуск.", "當前裝置不支援開機自啟動。", "このデバイスは自動起動をサポートしていません。", "이 장치는 자동 시작을 지원하지 않습니다.", "Dieses Gerät unterstützt keinen automatischen Start.", "Cet appareil ne prend pas en charge le démarrage automatique.", "Este dispositivo no admite el inicio automático.", "Este dispositivo não suporta inicialização automática."}}, + {"当前远程控制会话将结束。", {"当前远程控制会话将结束。", "The current remote session will end.", "Текущий сеанс удалённого управления будет завершён.", "當前遠端控制會話將結束。", "現在のリモートセッションが終了します。", "현재 원격 세션이 종료됩니다.", "Die aktuelle Remote-Sitzung wird beendet.", "La session à distance en cours se terminera.", "La sesión remota actual finalizará.", "A sessão remota atual será encerrada."}}, + {"待添加 ", {"待添加 ", "To add ", "К добавлению ", "待新增 ", "追加するには ", "추가하려면 ", "Zum Hinzufügen ", "Pour ajouter ", "Para agregar ", "Para adicionar "}}, + {"待确认", {"待确认", "Unknown", "Неизвестно", "待確認", "不明", "알 수 없음", "Unbekannt", "Inconnu", "Desconocido", "Desconhecido"}}, + {"总计", {"总计", "Total", "Итого", "總計", "合計", "합계", "Insgesamt", "Total", "Total", "Total"}}, + {"我知道了", {"我知道了", "Got it", "Понятно", "我知道了", "分かりました", "알겠습니다", "Verstanden", "Compris", "Entendido", "Entendi"}}, + {"或在主界面选择本机 IP。", {"或在主界面选择本机 IP。", "or select a local IP on the main screen.", "или выберите локальный IP в главном окне.", "或在主介面選擇本機 IP。", "またはメイン画面でローカル IP を選択します。", "또는 메인 화면에서 로컬 IP를 선택하세요.", "oder wählen Sie im Hauptbildschirm eine lokale IP aus.", "ou sélectionnez une adresse IP locale sur l'écran principal.", "o seleccione una IP local en la pantalla principal.", "ou selecione um IP local na tela principal."}}, + {"手动下载", {"手动下载", "Download manually", "Скачать вручную", "手動下載", "手動ダウンロード", "수동으로 다운로드", "Manuell herunterladen", "Télécharger manuellement", "Descargar manualmente", "Baixe manualmente"}}, + {"拖到另一台设备上", {"拖到另一台设备上", "Drag onto another device", "Перетащите на другое устройство", "拖到另一臺裝置上", "別のデバイス上にドラッグします", "다른 장치로 드래그", "Auf ein anderes Gerät ziehen", "Faire glisser sur un autre appareil", "Arrastrar a otro dispositivo", "Arraste para outro dispositivo"}}, + {"拖动表格分隔线,同步调整所有设备大小", {"拖动表格分隔线,同步调整所有设备大小", "Drag a table divider to resize all devices", "Потяните за разделитель таблицы, чтобы изменить размер всех устройств", "拖動表格分隔線,同步調整所有裝置大小", "テーブルの分割線をドラッグして、すべてのデバイスのサイズを変更します", "모든 장치의 크기를 조정하려면 표 구분선을 드래그하세요.", "Ziehen Sie einen Tabellenteiler, um die Größe aller Geräte zu ändern", "Faites glisser un séparateur de tableau pour redimensionner tous les appareils", "Arrastre un divisor de tabla para cambiar el tamaño de todos los dispositivos", "Arraste um divisor de mesa para redimensionar todos os dispositivos"}}, + {"按下快捷键,解除隐私屏", {"按下快捷键,解除隐私屏", "To turn off the privacy screen, press", "Чтобы отключить приватный экран, нажмите", "按下快捷鍵,解除隱私屏", "プライバシー画面をオフにするには、 を押します。", "개인정보 보호 화면을 끄려면 다음을 누르세요.", "Um den Datenschutzbildschirm auszuschalten, drücken Sie", "Pour désactiver l'écran de confidentialité, appuyez sur", "Para desactivar la pantalla de privacidad, presione", "Para desligar a tela de privacidade, pressione"}}, + {"换位未保存,请重试", {"换位未保存,请重试", "Couldn't save positions. Please try again.", "Не удалось сохранить порядок. Повторите попытку.", "換位未儲存,請重試", "ポジションを保存できませんでした。もう一度試してください。", "위치를 저장할 수 없습니다. 다시 시도해 주세요.", "Positionen konnten nicht gespeichert werden. Bitte versuchen Sie es erneut.", "Impossible d'enregistrer les positions. Veuillez réessayer.", "No se pudieron guardar posiciones. Por favor inténtalo de nuevo.", "Não foi possível salvar posições. Por favor, tente novamente."}}, + {"接管操控", {"接管操控", "Control", "Управлять", "接管操控", "コントロール", "제어", "Kontrolle", "Contrôle", "controlar", "Controle"}}, + {"控制端:", {"控制端:", "Controller:", "Контроллер:", "控制端:", "コントローラー:", "컨트롤러:", "Verantwortlicher:", "Contrôleur :", "Controlador:", "Controlador:"}}, + {"控制端解码器", {"控制端解码器", "Local decoder", "Локальный декодер", "控制端解碼器", "ローカルデコーダ", "로컬 디코더", "Lokaler Decoder", "Décodeur local", "Decodificador local", "Decodificador local"}}, + {"控制端解码器 ", {"控制端解码器 ", "Local decoder ", "Локальный декодер ", "控制端解碼器 ", "ローカルデコーダ ", "로컬 디코더 ", "Lokaler Decoder ", "Décodeur local ", "Decodificador local ", "Decodificador local "}}, + {"控制鼠标", {"控制鼠标", "Control Mouse", "Управление мышью", "控制滑鼠", "コントロールマウス", "마우스 제어", "Maus steuern", "Contrôler la souris", "Controlar el ratón", "Controle do mouse"}}, + {"播放声音", {"播放声音", "Play audio", "Воспроизведение звука", "播放聲音", "音声を再生する", "오디오 재생", "Audio abspielen", "Lire l'audio", "Reproducir audio", "Reproduzir áudio"}}, + {"收发速率", {"收发速率", "Transfer rate", "Скорость", "收發速率", "転送速度", "전송률", "Übertragungsrate", "Taux de transfert", "Tasa de transferencia", "Taxa de transferência"}}, + {"收起控制栏", {"收起控制栏", "Collapse Control Bar", "Свернуть панель управления", "收起控制欄", "コントロールバーを折りたたむ", "축소 컨트롤 바", "Steuerleiste ausblenden", "Réduire la barre de contrôle", "Contraer barra de control", "Recolher barra de controle"}}, + {"数据", {"数据", "Data", "Данные", "資料", "データ", "데이터", "Daten", "Données", "Datos", "Dados"}}, + {"文件传输:", {"文件传输:", "File Transfer:", "Передача файлов:", "檔案傳輸:", "ファイル転送:", "파일 전송:", "Dateiübertragung:", "Transfert de fichiers :", "Transferencia de archivos:", "Transferência de arquivos:"}}, + {"文件传输进度", {"文件传输进度", "File Transfer Progress", "Прогресс передачи файлов", "檔案傳輸進度", "ファイル転送の進行状況", "파일 전송 진행", "Dateiübertragungsfortschritt", "Progression du transfert de fichiers", "Progreso de la transferencia de archivos", "Progresso da transferência de arquivos"}}, + {"文件保存目录", {"文件保存目录", "Received file directory", "Каталог получаемых файлов", "檔案儲存目錄", "受信ファイルディレクトリ", "수신된 파일 디렉터리", "Verzeichnis der empfangenen Dateien", "Répertoire des fichiers reçus", "Directorio de archivos recibidos", "Diretório de arquivo recebido"}}, + {"文件发送进度", {"文件发送进度", "File Sending Progress", "Отправка файла", "檔案傳送進度", "ファイル送信の進行状況", "파일 전송 진행 상황", "Fortschritt beim Senden der Datei", "Progression de l'envoi du fichier", "Progreso del envío de archivos", "Progresso do envio de arquivos"}}, + {"文件接收保存路径", {"文件接收保存路径", "File Transfer Save Path", "Путь сохранения файлов", "檔案接收儲存路徑", "ファイル転送の保存パス", "파일 전송 저장 경로", "Speicherpfad für die Dateiübertragung", "Chemin d'enregistrement du transfert de fichiers", "Ruta para guardar la transferencia de archivos", "Caminho para salvar transferência de arquivos"}}, + {"文件接收进度", {"文件接收进度", "File Receiving Progress", "Получение файла", "檔案接收進度", "ファイル受信進捗状況", "파일 수신 진행 상황", "Fortschritt des Dateiempfangs", "Progression de la réception des fichiers", "Progreso de recepción de archivos", "Progresso do recebimento de arquivos"}}, + {"断开", {"断开", "Disconnect", "Отключить", "斷開", "切断", "연결 끊기", "Trennen", "Déconnecter", "Desconectar", "Desconectar"}}, + {"断开当前连接?", {"断开当前连接?", "Disconnect this session?", "Отключить текущий сеанс?", "斷開當前連線?", "このセッションを切断しますか?", "이 세션을 연결 해제하시겠습니까?", "Diese Sitzung trennen?", "Déconnecter cette session ?", "¿Desconectar esta sesión?", "Desconectar esta sessão?"}}, + {"断开所有控制端的连接?", {"断开所有控制端的连接?", "Disconnect all controllers?", "Отключить все контроллеры?", "斷開所有控制端的連線?", "すべてのコントローラーを切断しますか?", "모든 컨트롤러를 연결 해제하시겠습니까?", "Alle Controller abklemmen?", "Déconnecter tous les contrôleurs ?", "¿Desconectar todos los controladores?", "Desconectar todos os controladores?"}}, + {"断开连接", {"断开连接", "Disconnect", "Отключить", "中斷連線", "切断", "연결 해제", "Trennen", "Déconnecter", "Desconectar", "Desconectar"}}, + {"新建分组(可选)", {"新建分组(可选)", "New group (optional)", "Новая группа (необязательно)", "新建分組(可選)", "新しいグループ (オプション)", "새 그룹(선택 사항)", "Neue Gruppe (optional)", "Nouveau groupe (facultatif)", "Nuevo grupo (opcional)", "Novo grupo (opcional)"}}, + {"新版本", {"新版本", "New version", "Новая версия", "新版本", "新しいバージョン", "새 버전", "Neue Version", "Nouvelle version", "Nueva versión", "Nova versão"}}, + {"新版本包含功能改进和性能优化,建议将被控端升级至最新版本。", {"新版本包含功能改进和性能优化,建议将被控端升级至最新版本。", "Update the remote device to the latest version for improved features and performance.", "В новой версии улучшены функции и производительность. Рекомендуем обновить CrossDesk на удалённом устройстве до последней версии.", "新版本包含功能改進和效能最佳化,建議將被控端升級至最新版本。", "機能とパフォーマンスを向上させるために、リモート デバイスを最新バージョンに更新します。", "향상된 기능과 성능을 위해 원격 장치를 최신 버전으로 업데이트하세요.", "Aktualisieren Sie das Remote-Gerät auf die neueste Version, um verbesserte Funktionen und Leistung zu erhalten.", "Mettez à jour le périphérique distant vers la dernière version pour des fonctionnalités et des performances améliorées.", "Actualice el dispositivo remoto a la última versión para mejorar las funciones y el rendimiento.", "Atualize o dispositivo remoto para a versão mais recente para obter recursos e desempenho aprimorados."}}, + {"新版本可用", {"新版本可用", "New Version Available", "Доступна новая версия", "新版本可用", "新しいバージョンが利用可能になりました", "새 버전 출시", "Neue Version verfügbar", "Nouvelle version disponible", "Nueva versión disponible", "Nova versão disponível"}}, + {"无效的选项或值,未保存。请按菜单列出的格式输入。", {"无效的选项或值,未保存。请按菜单列出的格式输入。", "Invalid setting or value; not saved. Use the format shown in the menu.", "Неверный параметр или значение. Ничего не сохранено. Используйте указанный формат.", "無效的選項或值,未儲存。請按選單列出的格式輸入。", "無効な設定または値です。保存されていません。メニューに表示される形式を使用します。", "잘못된 설정 또는 값입니다. 저장되지 않았습니다. 메뉴에 표시된 형식을 사용하십시오.", "Ungültige Einstellung oder ungültiger Wert; nicht gespeichert. Verwenden Sie das im Menü angezeigte Format.", "Paramètre ou valeur invalide ; pas sauvegardé. Utilisez le format indiqué dans le menu.", "Configuración o valor no válido; no salvo. Utilice el formato que se muestra en el menú.", "Configuração ou valor inválido; não salvo. Use o formato mostrado no menu."}}, + {"无此 ID", {"无此 ID", "No such ID", "ID не найден", "無此 ID", "そのようなIDはありません", "해당 아이디가 없습니다.", "Kein solcher Ausweis", "Aucune pièce d'identité de ce type", "No existe tal identificación", "Não existe tal ID"}}, + {"无法使用此端口,", {"无法使用此端口,", "Cannot use this port.", "Порт недоступен.", "無法使用此埠,", "このポートは使用できません。", "이 포트를 사용할 수 없습니다.", "Dieser Port kann nicht verwendet werden.", "Impossible d'utiliser ce port.", "No se puede utilizar este puerto.", "Não é possível usar esta porta."}}, + {"无法保存 IP 连接设置,请重试。", {"无法保存 IP 连接设置,请重试。", "Could not save IP connection settings. Try again.", "Не удалось сохранить настройки подключения по IP. Повторите попытку.", "無法儲存 IP 連線設定,請重試。", "IP接続設定を保存できませんでした。もう一度やり直してください。", "IP 연결 설정을 저장할 수 없습니다. 다시 시도해 보세요.", "IP-Verbindungseinstellungen konnten nicht gespeichert werden. Versuchen Sie es erneut.", "Impossible d'enregistrer les paramètres de connexion IP. Essayer à nouveau.", "No se pudo guardar la configuración de la conexión IP. Intentar otra vez.", "Não foi possível salvar as configurações de conexão IP. Tente novamente."}}, + {"无法保存密码修改记录,未提交修改。请检查日志。", {"无法保存密码修改记录,未提交修改。请检查日志。", "Unable to save password recovery record; no change submitted. Check the log.", "Не удалось сохранить запись восстановления пароля. Изменение не отправлено. Проверьте журнал.", "無法儲存密碼修改記錄,未提交修改。請檢查日誌。", "パスワード回復記録を保存できません。変更は送信されませんでした。ログを確認してください。", "비밀번호 복구 기록을 저장할 수 없습니다. 변경사항이 제출되지 않았습니다. 로그를 확인하세요.", "Der Datensatz zur Passwortwiederherstellung konnte nicht gespeichert werden. Keine Änderung eingereicht. Überprüfen Sie das Protokoll.", "Impossible d'enregistrer l'enregistrement de récupération du mot de passe ; aucun changement soumis. Vérifiez le journal.", "No se puede guardar el registro de recuperación de contraseña; no se envió ningún cambio. Consulta el registro.", "Não foi possível salvar o registro de recuperação de senha; nenhuma alteração enviada. Verifique o registro."}}, + {"无法保存断开后锁屏设置,请重试。", {"无法保存断开后锁屏设置,请重试。", "Could not save lock-on-disconnect settings. Try again.", "Не удалось сохранить настройку блокировки при отключении. Повторите попытку.", "無法儲存斷開後鎖屏設定,請重試。", "切断時ロック設定を保存できませんでした。もう一度やり直してください。", "연결 해제 시 잠금 설정을 저장할 수 없습니다. 다시 시도해 보세요.", "Lock-on-Disconnect-Einstellungen konnten nicht gespeichert werden. Versuchen Sie es erneut.", "Impossible d'enregistrer les paramètres de verrouillage à la déconnexion. Essayer à nouveau.", "No se pudo guardar la configuración de bloqueo al desconectar. Intentar otra vez.", "Não foi possível salvar as configurações de bloqueio ao desconectar. Tente novamente."}}, + {"无法保存本地阅读状态,请重试。", {"无法保存本地阅读状态,请重试。", "Unable to save reading status locally. Please try again.", "Не удалось сохранить статус чтения локально. Повторите попытку.", "無法儲存本地閱讀狀態,請重試。", "読み取りステータスをローカルに保存できません。もう一度試してください。", "읽기 상태를 로컬에 저장할 수 없습니다. 다시 시도해 주세요.", "Lesestatus kann nicht lokal gespeichert werden. Bitte versuchen Sie es erneut.", "Impossible d'enregistrer l'état de lecture localement. Veuillez réessayer.", "No se puede guardar el estado de lectura localmente. Por favor inténtalo de nuevo.", "Não é possível salvar o status de leitura localmente. Por favor, tente novamente."}}, + {"无法保存连接模式,下次启动可能不会恢复当前模式。", {"无法保存连接模式,下次启动可能不会恢复当前模式。", "Could not save the connection mode. It may not be restored on the next launch.", "Не удалось сохранить режим подключения. При следующем запуске он может не восстановиться.", "無法儲存連線模式,下次啟動可能不會恢復當前模式。", "接続モードを保存できませんでした。次回起動時には復元されない可能性があります。", "연결 모드를 저장할 수 없습니다. 다음 실행 시 복원되지 않을 수 있습니다.", "Der Verbindungsmodus konnte nicht gespeichert werden. Es kann sein, dass es beim nächsten Start nicht wiederhergestellt wird.", "Impossible d'enregistrer le mode de connexion. Il se peut qu'il ne soit pas restauré au prochain lancement.", "No se pudo guardar el modo de conexión. Es posible que no se restablezca en el próximo lanzamiento.", "Não foi possível salvar o modo de conexão. Pode não ser restaurado na próxima inicialização."}}, + {"无法保存隐私屏解锁设置,请重试。", {"无法保存隐私屏解锁设置,请重试。", "Could not save privacy unlock settings. Try again.", "Не удалось сохранить настройку разблокировки. Повторите попытку.", "無法儲存隱私屏解鎖設定,請重試。", "プライバシーロック解除設定を保存できませんでした。もう一度やり直してください。", "개인 정보 잠금 해제 설정을 저장할 수 없습니다. 다시 시도해 보세요.", "Die Einstellungen zum Entsperren der Privatsphäre konnten nicht gespeichert werden. Versuchen Sie es erneut.", "Impossible d'enregistrer les paramètres de déverrouillage de la confidentialité. Essayer à nouveau.", "No se pudo guardar la configuración de desbloqueo de privacidad. Intentar otra vez.", "Não foi possível salvar as configurações de desbloqueio de privacidade. Tente novamente."}}, + {"无法准备远程会话,请稍后重试。", {"无法准备远程会话,请稍后重试。", "Could not prepare the remote session. Try again shortly.", "Не удалось подготовить удалённый сеанс. Повторите позже.", "無法準備遠端會話,請稍後重試。", "リモートセッションを準備できませんでした。しばらくしてからもう一度お試しください。", "원격 세션을 준비할 수 없습니다. 잠시 후 다시 시도하세요.", "Die Remote-Sitzung konnte nicht vorbereitet werden. Versuchen Sie es in Kürze noch einmal.", "Impossible de préparer la session à distance. Réessayez sous peu.", "No se pudo preparar la sesión remota. Vuelve a intentarlo en breve.", "Não foi possível preparar a sessão remota. Tente novamente em breve."}}, + {"无法删除这条公告,请重试。", {"无法删除这条公告,请重试。", "Unable to delete this announcement. Please try again.", "Не удалось удалить объявление. Повторите попытку.", "無法刪除這條公告,請重試。", "このお知らせは削除できません。もう一度試してください。", "이 공지를 삭제할 수 없습니다. 다시 시도해 주세요.", "Diese Ankündigung kann nicht gelöscht werden. Bitte versuchen Sie es erneut.", "Impossible de supprimer cette annonce. Veuillez réessayer.", "No se puede eliminar este anuncio. Por favor inténtalo de nuevo.", "Não é possível excluir este anúncio. Por favor, tente novamente."}}, + {"无法建立加密连接,请检查双方网络并重试。", {"无法建立加密连接,请检查双方网络并重试。", "Could not establish an encrypted connection. Check both devices' networks and try again.", "Не удалось установить зашифрованное соединение. Проверьте сеть на обоих устройствах и повторите попытку.", "無法建立加密連線,請檢查雙方網路並重試。", "暗号化接続を確立できませんでした。両方のデバイスのネットワークを確認して、再試行してください。", "암호화된 연결을 설정할 수 없습니다. 두 기기의 네트워크를 모두 확인하고 다시 시도하세요.", "Es konnte keine verschlüsselte Verbindung hergestellt werden. Überprüfen Sie die Netzwerke beider Geräte und versuchen Sie es erneut.", "Impossible d'établir une connexion cryptée. Vérifiez les réseaux des deux appareils et réessayez.", "No se pudo establecer una conexión cifrada. Verifique las redes de ambos dispositivos e inténtelo nuevamente.", "Não foi possível estabelecer uma conexão criptografada. Verifique as redes de ambos os dispositivos e tente novamente."}}, + {"无法生成随机密码,请重试。", {"无法生成随机密码,请重试。", "Unable to generate a random password; try again.", "Не удалось создать случайный пароль. Повторите попытку.", "無法生成隨機密碼,請重試。", "ランダムなパスワードを生成できません。もう一度やり直してください。", "임의의 비밀번호를 생성할 수 없습니다. 다시 시도해 보세요.", "Es kann kein zufälliges Passwort generiert werden; versuchen Sie es erneut.", "Impossible de générer un mot de passe aléatoire ; essayer à nouveau.", "No se puede generar una contraseña aleatoria; intentar otra vez.", "Não foi possível gerar uma senha aleatória; tente novamente."}}, + {"无法确认此端口是否可用,", {"无法确认此端口是否可用,", "Could not check this port.", "Не удалось проверить порт.", "無法確認此埠是否可用,", "このポートを確認できませんでした。", "이 포트를 확인할 수 없습니다.", "Dieser Port konnte nicht überprüft werden.", "Impossible de vérifier ce port.", "No se pudo verificar este puerto.", "Não foi possível verificar esta porta."}}, + {"无法读取系统状态。请刷新重试,或在系统设置中核对。", {"无法读取系统状态。请刷新重试,或在系统设置中核对。", "Could not read the system status. Refresh to retry, or check System Settings.", "Не удалось прочитать состояние. Повторите попытку или проверьте настройки системы.", "無法讀取系統狀態。請重新整理重試,或在系統設定中核對。", "システムステータスを読み取れませんでした。更新して再試行するか、システム設定を確認してください。", "시스템 상태를 읽을 수 없습니다. 다시 시도하려면 새로고침하거나 시스템 설정을 확인하세요.", "Der Systemstatus konnte nicht gelesen werden. Aktualisieren Sie, um es noch einmal zu versuchen, oder überprüfen Sie die Systemeinstellungen.", "Impossible de lire l'état du système. Actualisez pour réessayer ou vérifiez les paramètres système.", "No se pudo leer el estado del sistema. Actualice para volver a intentarlo o verifique la Configuración del sistema.", "Não foi possível ler o status do sistema. Atualize para tentar novamente ou verifique as configurações do sistema."}}, + {"无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。", {"无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。", "Could not connect. Check the IP, whether the other desktop is running CrossDesk, and its firewall settings.", "Не удалось подключиться. Проверьте IP, работу CrossDesk на другом компьютере и брандмауэр.", "無法連線,請檢查對方 IP、程式是否執行,以及防火牆是否放行。", "接続できませんでした。 IP、他のデスクトップがCrossDeskを実行しているかどうか、およびそのファイアウォール設定を確認してください。", "연결할 수 없습니다. IP, 다른 데스크톱이CrossDesk를 실행 중인지 여부 및 방화벽 설정을 확인하세요.", "Verbindung konnte nicht hergestellt werden. Überprüfen Sie die IP, ob auf dem anderen Desktop CrossDesk ausgeführt wird, und seine Firewall-Einstellungen.", "Impossible de se connecter. Vérifiez l'adresse IP, si l'autre bureau exécute CrossDesk et ses paramètres de pare-feu.", "No se pudo conectar. Verifique la IP, si el otro escritorio está ejecutando CrossDesk y su configuración de firewall.", "Não foi possível conectar. Verifique o IP, se o outro desktop está executando CrossDesk e suas configurações de firewall."}}, + {"无法验证对方设备的身份,请确认连接地址和对方设备后重试。", {"无法验证对方设备的身份,请确认连接地址和对方设备后重试。", "Could not verify the remote device's identity. Check the address and the remote device before retrying.", "Не удалось проверить подлинность удалённого устройства. Проверьте адрес и устройство перед повторной попыткой.", "無法驗證對方裝置的身份,請確認連線地址和對方裝置後重試。", "リモート デバイスの ID を確認できませんでした。再試行する前に、アドレスとリモート デバイスを確認してください。", "원격 장치의 신원을 확인할 수 없습니다. 다시 시도하기 전에 주소와 원격 장치를 확인하십시오.", "Die Identität des Remote-Geräts konnte nicht überprüft werden. Überprüfen Sie die Adresse und das Remote-Gerät, bevor Sie es erneut versuchen.", "Impossible de vérifier l'identité du périphérique distant. Vérifiez l'adresse et le périphérique distant avant de réessayer.", "No se pudo verificar la identidad del dispositivo remoto. Verifique la dirección y el dispositivo remoto antes de volver a intentarlo.", "Não foi possível verificar a identidade do dispositivo remoto. Verifique o endereço e o dispositivo remoto antes de tentar novamente."}}, + {"日志文件", {"日志文件", "Log file", "Файл журнала", "日誌檔案", "ログファイル", "로그 파일", "Protokolldatei", "Fichier journal", "Archivo de registro", "Arquivo de registro"}}, + {"显示主界面", {"显示主界面", "Show Main Window", "Показать главное окно", "顯示主介面", "メインウィンドウを表示", "메인 창 표시", "Hauptfenster anzeigen", "Afficher la fenêtre principale", "Mostrar ventana principal", "Mostrar janela principal"}}, + {"显示密码", {"显示密码", "Show password", "Показать пароль", "顯示密碼", "パスワードを表示", "비밀번호 표시", "Passwort anzeigen", "Afficher le mot de passe", "Mostrar contraseña", "Mostrar senha"}}, + {"显示屏", {"显示屏", "Display", "Экран", "顯示屏", "表示", "디스플레이", "Anzeige", "Affichage", "Pantalla", "Exibição"}}, + {"显示网络状态", {"显示网络状态", "Show network status", "Показать состояние сети", "顯示網路狀態", "ネットワークの状態を表示する", "네트워크 상태 표시", "Netzwerkstatus anzeigen", "Afficher l'état du réseau", "Mostrar estado de la red", "Mostrar status da rede"}}, + {"暂无公告", {"暂无公告", "No announcements", "Нет объявлений", "暫無公告", "アナウンスはありません", "공지 없음", "Keine Ankündigungen", "Aucune annonce", "Sin anuncios", "Sem anúncios"}}, + {"暂无已连接设备", {"暂无已连接设备", "No connected devices", "Нет подключённых устройств", "暫無已連線裝置", "接続されているデバイスがありません", "연결된 장치가 없습니다", "Keine angeschlossenen Geräte", "Aucun appareil connecté", "No hay dispositivos conectados", "Nenhum dispositivo conectado"}}, + {"暂无设备,退出精简模式后可添加", {"暂无设备,退出精简模式后可添加", "No devices. Exit compact mode to add devices", "Нет устройств. Выйдите из компактного режима, чтобы добавить их", "暫無裝置,退出精簡模式後可新增", "デバイスはありません。コンパクト モードを終了してデバイスを追加します", "장치가 없습니다. 기기를 추가하려면 컴팩트 모드를 종료하세요.", "Keine Geräte. Verlassen Sie den Kompaktmodus, um Geräte hinzuzufügen", "Aucun appareil. Quitter le mode compact pour ajouter des appareils", "Sin dispositivos. Salga del modo compacto para agregar dispositivos", "Nenhum dispositivo. Saia do modo compacto para adicionar dispositivos"}}, + {"暂无近期 IP 连接", {"暂无近期 IP 连接", "No recent IP connections", "Нет недавних IP-подключений", "暫無近期 IP 連線", "最近の IP 接続はありません", "최근 IP 연결이 없습니다", "Keine aktuellen IP-Verbindungen", "Aucune connexion IP récente", "No hay conexiones IP recientes", "Nenhuma conexão IP recente"}}, + {"暂无近期连接", {"暂无近期连接", "No recent connections", "Нет недавних подключений", "暫無近期連線", "最近の接続はありません", "최근 연결 없음", "Keine aktuellen Verbindungen", "Aucune connexion récente", "No hay conexiones recientes", "Nenhuma conexão recente"}}, + {"更多", {"更多", "More", "Ещё", "更多", "詳細", "더보기", "Mehr", "Plus", "Más", "Mais"}}, + {"更多操作", {"更多操作", "More actions", "Другие действия", "更多操作", "その他のアクション", "추가 작업", "Weitere Aktionen", "Plus d'actions", "Más acciones", "Mais ações"}}, + {"更新", {"更新", "Update", "Обновить", "更新", "アップデート", "업데이트", "Aktualisieren", "Mise à jour", "Actualización", "Atualização"}}, + {"更新内容", {"更新内容", "Release Notes", "Содержание обновления", "更新內容", "リリースノート", "릴리스 노트", "Versionshinweise", "Notes de version", "Notas de la versión", "Notas de versão"}}, + {"更新日志", {"更新日志", "Release notes", "История изменений", "更新日誌", "リリースノート", "릴리스 노트", "Versionshinweise", "Notes de version", "Notas de la versión", "Notas de lançamento"}}, + {"更新未完成,可重试或手动安装。", {"更新未完成,可重试或手动安装。", "Update did not complete. Retry or install manually.", "Обновление не завершено. Повторите или установите вручную.", "更新未完成,可重試或手動安裝。", "アップデートが完了しませんでした。再試行するか、手動でインストールしてください。", "업데이트가 완료되지 않았습니다. 다시 시도하거나 수동으로 설치하세요.", "Das Update wurde nicht abgeschlossen. Versuchen Sie es erneut oder installieren Sie es manuell.", "La mise à jour n'a pas été effectuée. Réessayez ou installez manuellement.", "La actualización no se completó. Vuelva a intentarlo o instálelo manualmente.", "A atualização não foi concluída. Tente novamente ou instale manualmente."}}, + {"最后一个远程控制端断开后,自动锁定本机。", {"最后一个远程控制端断开后,自动锁定本机。", "Lock this device when the last remote controller disconnects.", "Блокировать это устройство после отключения последнего управляющего клиента.", "最後一個遠端控制端斷開後,自動鎖定本機。", "最後の送信機が切断されたときに、このデバイスをロックします。", "마지막 리모컨의 연결이 끊어지면 이 장치를 잠급니다.", "Sperren Sie dieses Gerät, wenn die letzte Fernbedienung getrennt wird.", "Verrouillez cet appareil lorsque la dernière télécommande se déconnecte.", "Bloquee este dispositivo cuando se desconecte el último control remoto.", "Bloqueie este dispositivo quando o último controle remoto for desconectado."}}, + {"最大化", {"最大化", "Maximize", "Развернуть", "最大化", "最大化", "최대화", "Maximieren", "Maximiser", "Maximizar", "Maximizar"}}, + {"最小化", {"最小化", "Minimize", "Свернуть", "最小化", "最小化", "최소화", "Minimieren", "Réduire", "Minimizar", "Minimizar"}}, + {"有远程会话或密码修改正在进行,暂时不能更改连接设置。", {"有远程会话或密码修改正在进行,暂时不能更改连接设置。", "Connection settings cannot change during a remote session or password change.", "Нельзя менять параметры подключения во время удалённого сеанса или смены пароля.", "有遠端會話或密碼修改正在進行,暫時不能更改連線設定。", "リモート セッション中またはパスワード変更中に接続設定を変更することはできません。", "원격 세션이나 비밀번호 변경 중에는 연결 설정을 변경할 수 없습니다.", "Verbindungseinstellungen können während einer Remote-Sitzung oder Passwortänderung nicht geändert werden.", "Les paramètres de connexion ne peuvent pas changer pendant une session à distance ou un changement de mot de passe.", "La configuración de conexión no puede cambiar durante una sesión remota o un cambio de contraseña.", "As configurações de conexão não podem ser alteradas durante uma sessão remota ou alteração de senha."}}, + {"服务器地址", {"服务器地址", "Server Address", "Адрес сервера", "伺服器地址", "サーバーアドレス", "서버 주소", "Serveradresse", "Adresse du serveur", "Dirección del servidor", "Endereço do servidor"}}, + {"服务器已确认密码修改,正在重新连接。", {"服务器已确认密码修改,正在重新连接。", "Server confirmed the password change; reconnecting.", "Сервер подтвердил смену пароля. Повторное подключение.", "伺服器已確認密碼修改,正在重新連線。", "サーバーはパスワードの変更を確認しました。再接続中。", "서버가 비밀번호 변경을 확인했습니다. 다시 연결 중.", "Der Server hat die Passwortänderung bestätigt. wieder verbinden.", "Le serveur a confirmé le changement de mot de passe ; reconnexion.", "El servidor confirmó el cambio de contraseña; reconectando.", "O servidor confirmou a alteração da senha; reconectando."}}, + {"服务器未接受密码修改,原密码保持不变。详情见日志。", {"服务器未接受密码修改,原密码保持不变。详情见日志。", "Server rejected the password change; the original password remains. See the log.", "Сервер отклонил смену пароля. Старый пароль сохранён. См. журнал.", "伺服器未接受密碼修改,原密碼保持不變。詳情見日誌。", "サーバーがパスワードの変更を拒否しました。元のパスワードはそのまま残ります。ログを参照してください。", "서버가 비밀번호 변경을 거부했습니다. 원래 비밀번호는 그대로 유지됩니다. 로그를 참조하세요.", "Der Server hat die Passwortänderung abgelehnt. das ursprüngliche Passwort bleibt erhalten. Siehe das Protokoll.", "Le serveur a rejeté le changement de mot de passe ; le mot de passe d'origine reste. Voir le journal.", "El servidor rechazó el cambio de contraseña; la contraseña original permanece. Ver el registro.", "O servidor rejeitou a alteração da senha; a senha original permanece. Veja o registro."}}, + {"服务安装失败。请确认 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位于同一便携目录中,并在系统弹窗中允许管理员权限。", {"服务安装失败。请确认 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位于同一便携目录中,并在系统弹窗中允许管理员权限。", "Service installation failed. Make sure CrossDesk.exe, crossdesk_service.exe, and crossdesk_session_helper.exe are in the same portable folder, then approve the administrator prompt.", "Не удалось установить службу. Убедитесь, что CrossDesk.exe, crossdesk_service.exe и crossdesk_session_helper.exe находятся в одной папке портативной версии, затем подтвердите запрос прав администратора.", "服務安裝失敗。請確認 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位於同一便攜目錄中,並在系統彈窗中允許管理員許可權。", "サービスのインストールに失敗しました。CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe が同じポータブル フォルダー内にあることを確認し、管理者プロンプトを承認します。", "서비스 설치에 실패했습니다.CrossDesk.exe, crossdesk_service.exe 및 crossdesk_session_helper.exe가 동일한 휴대용 폴더에 있는지 확인한 다음 관리자 프롬프트를 승인하십시오.", "Die Installation des Dienstes ist fehlgeschlagen. Stellen Sie sicher, dass sich CrossDesk.exe, crossdesk_service.exe und crossdesk_session_helper.exe im selben tragbaren Ordner befinden, und genehmigen Sie dann die Administratoraufforderung.", "L'installation du service a échoué. Assurez-vous que CrossDesk.exe, crossdesk_service.exe et crossdesk_session_helper.exe se trouvent dans le même dossier portable, puis approuvez l'invite de l'administrateur.", "Error en la instalación del servicio. Asegúrese de que CrossDesk.exe, crossdesk_service.exe y crossdesk_session_helper.exe estén en la misma carpeta portátil y luego apruebe el mensaje del administrador.", "Falha na instalação do serviço. Certifique-se de que CrossDesk.exe, crossdesk_service.exe e crossdesk_session_helper.exe estejam na mesma pasta portátil e aprove o prompt do administrador."}}, + {"服务已安装并启动", {"服务已安装并启动", "Service installed and started", "Служба установлена и запущена", "服務已安裝並啟動", "サービスのインストールと開始", "서비스 설치 및 시작", "Dienst installiert und gestartet", "Service installé et démarré", "Servicio instalado e iniciado", "Serviço instalado e iniciado"}}, + {"未分组", {"未分组", "Ungrouped", "Без группы", "未分組", "グループ化されていない", "그룹 해제됨", "Nicht gruppiert", "Non groupé", "Desagrupado", "Desagrupado"}}, + {"未加密", {"未加密", "Unencrypted", "Без шифр.", "未加密", "非暗号化", "암호화되지 않음", "Unverschlüsselt", "Non crypté", "Sin cifrar", "Não criptografado"}}, + {"未开启", {"未开启", "Disabled", "Выключен", "未開啟", "無効", "비활성화됨", "Deaktiviert", "Désactivé", "Deshabilitado", "Desativado"}}, + {"未找到可用的局域网连接。", {"未找到可用的局域网连接。", "No local network connection was found.", "Нет доступного подключения к LAN.", "未找到可用的區域網連線。", "ローカル ネットワーク接続が見つかりませんでした。", "로컬 네트워크 연결을 찾을 수 없습니다.", "Es wurde keine lokale Netzwerkverbindung gefunden.", "Aucune connexion au réseau local n'a été trouvée.", "No se encontró ninguna conexión de red local.", "Nenhuma conexão de rede local foi encontrada."}}, + {"未知", {"未知", "Unknown", "Неизвестно", "未知", "不明", "알 수 없음", "Unbekannt", "Inconnu", "Desconocido", "Desconhecido"}}, + {"未知命令,输入 help 查看帮助。", {"未知命令,输入 help 查看帮助。", "Unknown command. Enter help for commands.", "Неизвестная команда. Введите help для справки.", "未知命令,輸入 help 檢視幫助。", "不明なコマンドです。コマンドのヘルプを入力します。", "알 수 없는 명령입니다. 명령에 대한 도움말을 입력합니다.", "Unbekannter Befehl. Geben Sie Hilfe für Befehle ein.", "Commande inconnue. Entrez l'aide pour les commandes.", "Comando desconocido. Ingrese ayuda para los comandos.", "Comando desconhecido. Insira ajuda para comandos."}}, + {"未知平台", {"未知平台", "Unknown platform", "Неизвестная платформа", "未知平臺", "不明なプラットフォーム", "알 수 없는 플랫폼", "Unbekannte Plattform", "Plateforme inconnue", "Plataforma desconocida", "Plataforma desconhecida"}}, + {"未读", {"未读", "Unread", "Не прочитано", "未讀", "未読", "읽지 않음", "Ungelesen", "Non lu", "No leído", "Não lido"}}, + {"未连接", {"未连接", "Not connected", "Нет соединения", "未連線", "接続されていません", "연결되지 않음", "Nicht verbunden", "Non connecté", "No conectado", "Não conectado"}}, + {"未连接服务器", {"未连接服务器", "Disconnected from server", "Нет подключения к серверу", "未連線伺服器", "サーバーから切断されました", "서버와의 연결이 끊겼습니다.", "Vom Server getrennt", "Déconnecté du serveur", "Desconectado del servidor", "Desconectado do servidor"}}, + {"本地存储", {"本地存储", "Local storage", "Локальное хранение", "本地儲存", "ローカルストレージ", "로컬 스토리지", "Lokaler Speicher", "Stockage local", "Almacenamiento local", "Armazenamento local"}}, + {"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", {"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", "This application uses OpenFEC for forward error correction under CeCILL-C 1.0, which provides limited warranties and limits liability. See the full license for details.", "Приложение использует OpenFEC для прямого исправления ошибок по лицензии CeCILL-C 1.0 с ограниченной гарантией и ответственностью. Подробности — в тексте лицензии.", "本應用使用 OpenFEC 提供前向糾錯功能,遵循 CeCILL-C 1.0 許可。該許可規定了有限保證及責任限制,詳情見許可全文。", "このアプリケーションは、限定保証を提供し、責任を制限するCeCILL-C1.0 に基づく前方誤り訂正にOpenFECを使用します。詳細については、完全なライセンスを参照してください。", "이 애플리케이션은 제한된 보증과 책임 제한을 제공하는CeCILL-C1.0에 따라 순방향 오류 수정을 위해OpenFEC를 사용합니다. 자세한 내용은 전체 라이센스를 참조하세요.", "Diese Anwendung verwendet OpenFEC zur Vorwärtsfehlerkorrektur unterCeCILL-C1.0, was eingeschränkte Garantien und Haftungsbeschränkungen bietet. Einzelheiten finden Sie in der vollständigen Lizenz.", "Cette application utilise OpenFEC pour la correction d'erreur directe sousCeCILL-C1.0, qui offre des garanties limitées et limite la responsabilité. Consultez la licence complète pour plus de détails.", "Esta aplicación utiliza OpenFEC para la corrección de errores directos bajoCeCILL-C1.0, que proporciona garantías limitadas y limita la responsabilidad. Consulte la licencia completa para obtener más detalles.", "Este aplicativo usa OpenFEC para correção direta de erros noCeCILL-C1.0, que fornece garantias limitadas e limita a responsabilidade. Veja a licença completa para detalhes."}}, + {"本机 ID", {"本机 ID", "Local ID", "Локальный ID", "本機 ID", "ローカルID", "로컬 ID", "Lokale ID", "ID local", "Identificación local", "ID local"}}, + {"本机 IP / 端口", {"本机 IP / 端口", "Local IP / Port", "IP / Порт", "本機 IP / 埠", "ローカルIP/ポート", "로컬 IP / 포트", "Lokale IP/Port", "IP/Port local", "IP local/puerto", "IP/Porta Local"}}, + {"本桌面", {"本桌面", "Local Desktop", "Локальный рабочий стол", "本桌面", "ローカルデスクトップ", "로컬 데스크톱", "Lokaler Desktop", "Bureau local", "Escritorio local", "Área de trabalho local"}}, + {"本版本源码信息暂不可用。", {"本版本源码信息暂不可用。", "Source revision is unavailable for this build.", "Ревизия исходного кода этой сборки недоступна.", "本版本原始碼資訊暫不可用。", "このビルドではソース リビジョンが利用できません。", "이 빌드에는 소스 개정을 사용할 수 없습니다.", "Die Quellrevision ist für diesen Build nicht verfügbar.", "La révision source n'est pas disponible pour cette version.", "La revisión fuente no está disponible para esta compilación.", "A revisão fonte não está disponível para esta compilação."}}, + {"本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", {"本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", "License text is not bundled for this component. Use View source code to read its license and copyright notices.", "Текст лицензии не включён. Откройте исходный код для просмотра лицензии и авторских прав.", "本元件未內建許可文字,請透過“檢視原始碼”查閱許可與版權宣告。", "このコンポーネントにはライセンス テキストはバンドルされていません。 [ソース コードの表示] を使用して、ライセンスと著作権表示を確認します。", "이 구성 요소에 대한 라이센스 텍스트는 번들로 제공되지 않습니다. 라이센스 및 저작권 고지를 읽으려면 소스 코드 보기를 사용하십시오.", "Der Lizenztext ist für diese Komponente nicht gebündelt. Verwenden Sie „Quellcode anzeigen“, um die Lizenz- und Urheberrechtshinweise zu lesen.", "Le texte de la licence n'est pas regroupé pour ce composant. Utilisez Afficher le code source pour lire ses avis de licence et de droits d'auteur.", "El texto de la licencia no está incluido para este componente. Utilice Ver código fuente para leer sus avisos de licencia y derechos de autor.", "O texto da licença não está incluído neste componente. Use Exibir código-fonte para ler seus avisos de licença e direitos autorais."}}, + {"权限请求", {"权限请求", "Request Permissions", "Запрос разрешений", "許可權請求", "権限のリクエスト", "권한 요청", "Berechtigungen anfordern", "Demander des autorisations", "Solicitar permisos", "Solicitar permissões"}}, + {"松开鼠标交换位置", {"松开鼠标交换位置", "Release to swap", "Отпустите для обмена", "鬆開滑鼠交換位置", "リリースしてスワップする", "스왑으로 릴리스", "Zum Tauschen loslassen", "Relâcher pour échanger", "Liberar para intercambiar", "Liberar para trocar"}}, + {"构建说明", {"构建说明", "Build instructions", "Инструкции по сборке", "構建說明", "組み立て説明書", "빌드 지침", "Bauanleitung", "Instructions de construction", "Instrucciones de construcción", "Instruções de construção"}}, + {"查看源码", {"查看源码", "View source code", "Открыть исходный код", "檢視原始碼", "ソースコードを表示する", "소스코드 보기", "Quellcode anzeigen", "Afficher le code source", "Ver código fuente", "Ver código-fonte"}}, + {"桌面", {"桌面", "Desktop", "Рабочий стол", "桌面", "デスクトップ", "데스크탑", "Desktop", "Bureau", "Escritorio", "Área de Trabalho"}}, + {"桌面墙", {"桌面墙", "DeskHub", "DeskHub", "桌面牆", "DeskHub", "DeskHub", "DeskHub", "DeskHub", "DeskHub", "DeskHub"}}, + {"检查失败,请稍后重试", {"检查失败,请稍后重试", "Check failed. Please try again later.", "Не удалось проверить обновления. Повторите позже.", "檢查失敗,請稍後重試", "チェックに失敗しました。後でもう一度試してください。", "확인에 실패했습니다. 나중에 다시 시도해 주세요.", "Prüfung fehlgeschlagen. Bitte versuchen Sie es später noch einmal.", "La vérification a échoué. Veuillez réessayer plus tard.", "La verificación falló. Inténtelo de nuevo más tarde.", "Falha na verificação. Por favor, tente novamente mais tarde."}}, + {"检查更新", {"检查更新", "Check for updates", "Проверить обновления", "檢查更新", "アップデートを確認する", "업데이트 확인", "Suchen Sie nach Updates", "Rechercher des mises à jour", "Buscar actualizaciones", "Verifique se há atualizações"}}, + {"检测到当前桌面会话使用 Wayland。", {"检测到当前桌面会话使用 Wayland。", "The current desktop session uses Wayland.", "Текущий сеанс рабочего стола использует Wayland.", "檢測到當前桌面會話使用 Wayland。", "現在のデスクトップ セッションは Wayland を使用しています。", "현재 데스크톱 세션은 Wayland를 사용합니다.", "Die aktuelle Desktop-Sitzung verwendet Wayland.", "La session de bureau actuelle utilise Wayland.", "La sesión de escritorio actual utiliza Wayland.", "A sessão atual da área de trabalho usa Wayland."}}, + {"正在传输", {"正在传输", "Sending", "Передача", "正在傳輸", "送信", "보내는 중", "Senden", "Envoi", "Envío", "Envio"}}, + {"正在准备更新…", {"正在准备更新…", "Preparing update…", "Подготовка обновления…", "正在準備更新…", "アップデートを準備しています…", "업데이트 준비 중…", "Update wird vorbereitet…", "Préparation de la mise à jour…", "Preparando actualización…", "Preparando atualização…"}}, + {"正在加载…", {"正在加载…", "Loading…", "Загрузка…", "正在載入…", "読み込み中…", "로드 중…", "Laden…", "Chargement…", "Cargando…", "Carregando…"}}, + {"正在取消", {"正在取消", "Cancelling", "Отмена…", "正在取消", "キャンセルする", "취소 중", "Abbrechen", "Annulation", "Cancelando", "Cancelando"}}, + {"正在安装服务...", {"正在安装服务...", "Installing service...", "Установка службы...", "正在安裝服務...", "サービスをインストール中…", "서비스 설치 중...", "Dienst wird installiert...", "Installation du service...", "Instalando servicio...", "Instalando serviço..."}}, + {"正在应用…", {"正在应用…", "Applying…", "Применение…", "正在應用…", "申請中…", "신청 중…", "Bewerbung…", "Candidature…", "Aplicando...", "Aplicando…"}}, + {"正在建立对等连接...", {"正在建立对等连接...", "P2P Connecting ...", "Подключение P2P...", "正在建立對等連線...", "P2P接続中...", "P2P 연결중...", "P2P-Verbindung ...", "Connexion P2P...", "Conexión P2P...", "Conexão P2P..."}}, + {"正在接收", {"正在接收", "Receiving", "Получение", "正在接收", "受信中", "수신", "Empfangen", "Réception", "Recepción", "Recebendo"}}, + {"正在操控", {"正在操控", "Controlling", "Управление", "正在操控", "制御する", "제어", "Kontrollieren", "Contrôler", "Controlar", "Controle"}}, + {"正在收集候选地址...", {"正在收集候选地址...", "Gathering candidates ...", "Сбор кандидатов...", "正在收集候選地址...", "候補者を集めて…", "후보자를 모으는 중...", "Kandidaten sammeln ...", "Rassembler les candidats...", "Reuniendo candidatos...", "Reunindo candidatos..."}}, + {"正在检查更新…", {"正在检查更新…", "Checking for updates…", "Проверка обновлений…", "正在檢查更新…", "アップデートを確認しています…", "업데이트 확인 중…", "Suche nach Updates…", "Vérification des mises à jour…", "Buscando actualizaciones...", "Verificando atualizações…"}}, + {"正在读取…", {"正在读取…", "Checking…", "Проверка…", "正在讀取…", "確認中…", "확인 중…", "Überprüfen…", "Vérification…", "Comprobando…", "Verificando…"}}, + {"正在连接…", {"正在连接…", "Connecting…", "Подключение…", "正在連線…", "接続中…", "연결 중…", "Verbinden…", "Connexion…", "Conectando...", "Conectando…"}}, + {"正在退出 CrossDesk……", {"正在退出 CrossDesk……", "Exiting CrossDesk...", "Выход из CrossDesk...", "正在退出 CrossDesk……", "CrossDeskを終了します ...", "CrossDesk종료 중...", "CrossDesk wird beendet ...", "Sortie de CrossDesk...", "Saliendo de CrossDesk...", "Saindo de CrossDesk..."}}, + {"正在重新连接...", {"正在重新连接...", "Reconnecting...", "Переподключение...", "正在重新連線...", "再接続中...", "다시 연결하는 중...", "Verbindung wird wiederhergestellt...", "Reconnexion...", "Reconectando...", "Reconectando..."}}, + {"此端口已被占用,", {"此端口已被占用,", "This port is in use.", "Порт занят.", "此埠已被佔用,", "このポートは使用中です。", "이 포트는 사용 중입니다.", "Dieser Port wird verwendet.", "Ce port est utilisé.", "Este puerto está en uso.", "Esta porta está em uso."}}, + {"此设备被控中", {"此设备被控中", "This device is controlled", "Устройство под управлением", "此裝置被控中", "このデバイスは制御されています", "이 장치는 제어됩니다", "Dieses Gerät wird gesteuert", "Cet appareil est contrôlé", "Este dispositivo está controlado", "Este dispositivo é controlado"}}, + {"每次共享均需本机授权", {"每次共享均需本机授权", "Local approval required each time", "Разрешение требуется каждый раз", "每次共享均需本機授權", "都度現地の承認が必要", "매번 현지 승인 필요", "Jedes Mal ist eine örtliche Genehmigung erforderlich", "Approbation locale requise à chaque fois", "Se requiere aprobación local cada vez", "Aprovação local necessária sempre"}}, + {"消息", {"消息", "Messages", "Сообщения", "訊息", "メッセージ", "메시지", "Nachrichten", "Messages", "Mensajes", "Mensagens"}}, + {"添加", {"添加", "Add", "Добавить", "新增", "追加", "추가", "Hinzufügen", "Ajouter", "Agregar", "Adicionar"}}, + {"添加并连接", {"添加并连接", "Add and connect", "Добавить и подключить", "新增並連線", "追加して接続する", "추가 및 연결", "Hinzufügen und verbinden", "Ajouter et connecter", "Agregar y conectar", "Adicionar e conectar"}}, + {"添加设备", {"添加设备", "Add device", "Добавить устройство", "新增裝置", "デバイスの追加", "장치 추가", "Gerät hinzufügen", "Ajouter un appareil", "Agregar dispositivo", "Adicionar dispositivo"}}, + {"添加设备,建立你的桌面墙", {"添加设备,建立你的桌面墙", "Add devices to build your DeskHub", "Добавьте устройства в DeskHub", "新增裝置,建立你的桌面牆", "デバイスを追加してDeskHubを構築します", "DeskHub를 구축하기 위한 장치 추가", "Fügen Sie Geräte hinzu, um Ihr DeskHub zu erstellen", "Ajoutez des appareils pour créer votre DeskHub", "Agregue dispositivos para construir su DeskHub", "Adicione dispositivos para construir seu DeskHub"}}, + {"源码与构建说明", {"源码与构建说明", "Source code and build instructions", "Исходный код и сборка", "原始碼與構建說明", "ソースコードとビルド手順", "소스 코드 및 빌드 지침", "Quellcode und Build-Anweisungen", "Code source et instructions de construction", "Código fuente e instrucciones de compilación", "Código-fonte e instruções de construção"}}, + {"源码版本:", {"源码版本:", "Source revision: ", "Ревизия исходного кода: ", "原始碼版本:", "ソース改訂:", "소스 개정:", "Überarbeitung der Quelle:", "Révision de la source :", "Revisión de la fuente:", "Revisão da fonte:"}}, + {"点击修改端口", {"点击修改端口", "Click to edit the port", "Нажмите, чтобы изменить порт", "點選修改埠", "クリックしてポートを編集します", "포트를 편집하려면 클릭하세요.", "Klicken Sie, um den Port zu bearbeiten", "Cliquez pour modifier le port", "Haga clic para editar el puerto.", "Clique para editar a porta"}}, + {"点击切换本机 IP", {"点击切换本机 IP", "Click to switch the local IP", "Нажмите, чтобы сменить IP", "點選切換本機 IP", "クリックしてローカルIPを切り替えます", "로컬 IP를 전환하려면 클릭하세요.", "Klicken Sie hier, um die lokale IP zu wechseln", "Cliquez pour changer l'adresse IP locale", "Haga clic para cambiar la IP local", "Clique para mudar o IP local"}}, + {"爱发电", {"爱发电", "AFDIAN", "AFDIAN", "愛發電", "AFDIAN", "아디안", "AFDIAN", "AFDIEN", "AFDIANO", "AFDIAN"}}, + {"版本", {"版本", "Version", "Версия", "版本", "バージョン", "버전", "Version", "Version", "Versión", "Versão"}}, + {"状态", {"状态", "Status", "Состояние", "狀態", "ステータス", "상태", "Status", "Statut", "Estado", "Estado"}}, + {"画质优先", {"画质优先", "Quality", "Качество", "畫質優先", "画質", "화질", "Qualität", "Qualité", "Calidad", "Qualidade"}}, + {"画面", {"画面", "Video", "Видео", "畫面", "ビデオ", "영상", "Video", "Vidéo", "Vídeo", "Vídeo"}}, + {"画面传输", {"画面传输", "Video transmission", "Передача видео", "畫面傳輸", "ビデオ送信", "영상 전송", "Videoübertragung", "Transmission vidéo", "Transmisión de vídeo", "Transmissão de vídeo"}}, + {"画面偏好", {"画面偏好", "Video Preference", "Режим видео", "畫面偏好", "ビデオ設定", "영상 선호도", "Videopräferenz", "Préférence vidéo", "Preferencia de vídeo", "Preferência de vídeo"}}, + {"画面已停留", {"画面已停留", "Frame stale", "Кадр устарел", "畫面已停留", "フレームが古い", "프레임 부실", "Rahmen veraltet", "Cadre obsolète", "Marco obsoleto", "Quadro obsoleto"}}, + {"画面接收中...", {"画面接收中...", "Receiving screen...", "Получение изображения...", "畫面接收中...", "受信画面…", "수신화면...", "Empfangsbildschirm...", "Écran de réception...", "Pantalla de recepción...", "Recebendo tela..."}}, + {"画面设置", {"画面设置", "Video settings", "Настройки видео", "畫面設定", "ビデオ設定", "영상 설정", "Videoeinstellungen", "Paramètres vidéo", "Configuración de vídeo", "Configurações de vídeo"}}, + {"画面质量", {"画面质量", "Video Quality", "Качество видео", "畫面質量", "ビデオ品質", "비디오 품질", "Videoqualität", "Qualité vidéo", "Calidad de vídeo", "Qualidade de vídeo"}}, + {"画面采集帧率", {"画面采集帧率", "Video Capture Frame Rate", "Частота захвата видео", "畫面採集幀率", "ビデオキャプチャフレームレート", "비디오 캡처 프레임 속도", "Bildrate der Videoaufnahme", "Fréquence d'images de capture vidéo", "Velocidad de fotogramas de captura de vídeo", "Taxa de quadros de captura de vídeo"}}, + {"界面", {"界面", "Interface", "Интерфейс", "介面", "インターフェース", "인터페이스", "Oberfläche", "Interfaces", "Interfaz", "Interface"}}, + {"登录桌面时自启", {"登录桌面时自启", "Start at desktop login", "Запуск при входе в систему", "登入桌面時自啟", "デスクトップログインで起動", "데스크톱 로그인에서 시작", "Beginnen Sie mit der Desktop-Anmeldung", "Démarrer lors de la connexion au bureau", "Iniciar sesión en el escritorio", "Comece no login da área de trabalho"}}, + {"登录状态已失效,请重新连接。", {"登录状态已失效,请重新连接。", "Signaling login expired. Please reconnect.", "Сеанс входа истёк. Подключитесь заново.", "登入狀態已失效,請重新連線。", "シグナリングログインの有効期限が切れました。再接続してください。", "시그널링 로그인이 만료되었습니다. 다시 연결해 주세요.", "Signalisierungsanmeldung abgelaufen. Bitte stellen Sie die Verbindung wieder her.", "La connexion de signalisation a expiré. Veuillez vous reconnecter.", "El inicio de sesión de señalización expiró. Por favor vuelva a conectarse.", "O login de sinalização expirou. Por favor, reconecte."}}, + {"直连", {"直连", "Direct", "Прямой", "直連", "直接", "다이렉트", "Direkt", "Direct", "Directo", "Direto"}}, + {"知道了", {"知道了", "Got it", "Понятно", "知道了", "分かりました", "알겠습니다", "Verstanden", "Compris", "Entendido", "Entendi"}}, + {"确认", {"确认", "Confirm", "Подтвердить", "確認", "確認する", "확인", "Bestätigen", "Confirmer", "Confirmar", "Confirmar"}}, + {"确认删除此连接", {"确认删除此连接", "Delete this connection?", "Удалить это подключение?", "確認刪除此連線", "この接続を削除しますか?", "이 연결을 삭제하시겠습니까?", "Diese Verbindung löschen?", "Supprimer cette connexion ?", "¿Eliminar esta conexión?", "Excluir esta conexão?"}}, + {"确认执行", {"确认执行", "Continue", "Продолжить", "確認執行", "続き", "계속", "Weiter", "Continuer", "Continuar", "Continuar"}}, + {"确认断开", {"确认断开", "Disconnect", "Отключить", "確認斷開", "切断", "연결 끊기", "Trennen", "Déconnecter", "Desconectar", "Desconectar"}}, + {"确认断开连接?", {"确认断开连接?", "Disconnect this session?", "Отключить этот сеанс?", "確認斷開連線?", "このセッションを切断しますか?", "이 세션을 연결 해제하시겠습니까?", "Diese Sitzung trennen?", "Déconnecter cette session ?", "¿Desconectar esta sesión?", "Desconectar esta sessão?"}}, + {"离线", {"离线", "Offline", "Не в сети", "離線", "オフライン", "오프라인", "Offline", "Hors ligne", "Sin conexión", "Off-line"}}, + {"等待分配", {"等待分配", "Waiting for assignment", "Ожидание назначения", "等待分配", "割り当て待ち", "과제를 기다리는 중", "Warten auf Zuweisung", "En attente d'affectation", "Esperando asignación", "Aguardando atribuição"}}, + {"等待画面", {"等待画面", "Waiting for video", "Ожидание видео", "等待畫面", "ビデオ待機中", "영상을 기다리는 중", "Warten auf Video", "En attente de la vidéo", "Esperando vídeo", "Aguardando vídeo"}}, + {"等待统计", {"等待统计", "Awaiting stats", "Ожидание статистики", "等待統計", "統計待ち", "통계 대기 중", "Warten auf Statistiken", "En attente de statistiques", "En espera de estadísticas", "Aguardando estatísticas"}}, + {"精简模式", {"精简模式", "Compact", "Компактно", "精簡模式", "コンパクト", "콤팩트", "Kompakt", "Compacte", "Compacto", "Compacto"}}, + {"编辑", {"编辑", "Edit", "Изменить", "編輯", "編集", "편집", "Bearbeiten", "Modifier", "Editar", "Editar"}}, + {"网络状态", {"网络状态", "Network", "Сеть", "網路狀態", "ネットワーク", "네트워크", "Netzwerk", "Réseau", "Red", "Rede"}}, + {"网络连接", {"网络连接", "Network", "Сеть", "網路連線", "ネットワーク", "네트워크", "Netzwerk", "Réseau", "Red", "Rede"}}, + {"群控中", {"群控中", "Group control", "Групп. управление", "群控中", "グループ制御", "그룹 제어", "Gruppenkontrolle", "Contrôle de groupe", "Control de grupo", "Controle de grupo"}}, + {"群控中 · 所有已连接设备", {"群控中 · 所有已连接设备", "Group control · All connected devices", "Групповое управление · Все подключения", "群控中 · 所有已連線裝置", "グループ制御・接続されているすべてのデバイス", "그룹 제어 · 연결된 모든 장치", "Gruppensteuerung · Alle angeschlossenen Geräte", "Contrôle de groupe · Tous les appareils connectés", "Control de grupo · Todos los dispositivos conectados", "Controle de grupo · Todos os dispositivos conectados"}}, + {"自动", {"自动", "Auto", "Авто", "自動", "オート", "자동", "Automatisch", "Automatique", "Automático", "Automático"}}, + {"自托管", {"自托管", "Self-hosted server", "Собственный сервер", "自託管", "セルフホストサーバー", "자체 호스팅 서버", "Selbstgehosteter Server", "Serveur auto-hébergé", "Servidor autohospedado", "Servidor auto-hospedado"}}, + {"自托管设置", {"自托管设置", "Self-hosted server settings", "Настройки своего сервера", "自託管設定", "セルフホストサーバーの設定", "자체 호스팅 서버 설정", "Selbstgehostete Servereinstellungen", "Paramètres du serveur auto-hébergé", "Configuración del servidor autohospedado", "Configurações do servidor auto-hospedado"}}, + {"自托管配置", {"自托管配置", "Self-hosted server", "Собственный сервер", "自託管配置", "セルフホストサーバー", "자체 호스팅 서버", "Selbstgehosteter Server", "Serveur auto-hébergé", "Servidor autohospedado", "Servidor auto-hospedado"}}, + {"被控中", {"被控中", "Controlled", "Под управлением", "被控中", "制御済み", "제어됨", "Kontrolliert", "Contrôlé", "Controlado", "Controlado"}}, + {"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", {"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", "The remote privacy screen was unlocked using the local shortcut. Lock it again to restore privacy and disable local shortcut unlocking.", "Приватный экран отключён локальным сочетанием клавиш. Заблокируйте его снова, чтобы восстановить защиту и запретить локальную разблокировку.", "被控端已透過組合鍵解除隱私屏。點選“鎖定”將重新開啟隱私屏,並禁止本機使用組合鍵解鎖。", "ローカル ショートカットを使用してリモート プライバシー画面のロックが解除されました。再度ロックするとプライバシーが回復され、ローカル ショートカットのロック解除が無効になります。", "로컬 단축키를 사용하여 원격 개인정보 보호 화면을 잠금 해제했습니다. 개인정보 보호를 복원하고 로컬 바로가기 잠금 해제를 비활성화하려면 다시 잠그세요.", "Der Remote-Datenschutzbildschirm wurde über die lokale Verknüpfung entsperrt. Sperren Sie es erneut, um die Privatsphäre wiederherzustellen und das Entsperren lokaler Verknüpfungen zu deaktivieren.", "L'écran de confidentialité à distance a été déverrouillé à l'aide du raccourci local. Verrouillez-le à nouveau pour restaurer la confidentialité et désactiver le déverrouillage des raccourcis locaux.", "La pantalla de privacidad remota se desbloqueó usando el acceso directo local. Bloquéelo nuevamente para restaurar la privacidad y deshabilitar el desbloqueo de accesos directos locales.", "A tela de privacidade remota foi desbloqueada usando o atalho local. Bloqueie-o novamente para restaurar a privacidade e desativar o desbloqueio de atalhos locais."}}, + {"被控端编码器", {"被控端编码器", "Remote encoder", "Кодер удалённой стороны", "被控端編碼器", "リモートエンコーダー", "리모트 엔코더", "Remote-Encoder", "Encodeur déporté", "Codificador remoto", "Codificador remoto"}}, + {"被控端编码器 ", {"被控端编码器 ", "Remote encoder ", "Удалённый кодер ", "被控端編碼器 ", "リモートエンコーダー ", "리모트 엔코더 ", "Remote-Encoder ", "Encodeur déporté ", "Codificador remoto ", "Codificador remoto "}}, + {"被连接时开启隐私屏", {"被连接时开启隐私屏", "Privacy screen on incoming connection", "Приватный экран при подключении", "被連線時開啟隱私屏", "着信接続時のプライバシー画面", "연결 수신 시 개인정보 보호 화면", "Datenschutzbildschirm bei eingehender Verbindung", "Écran de confidentialité sur la connexion entrante", "Pantalla de privacidad en la conexión entrante", "Tela de privacidade na conexão de entrada"}}, + {"视频", {"视频", "Video", "Видео", "影片", "ビデオ", "영상", "Video", "Vidéo", "Vídeo", "Vídeo"}}, + {"视频延时", {"视频延时", "Video latency", "Задержка видео", "影片延時", "ビデオの遅延", "영상 지연", "Videolatenz", "Latence vidéo", "Latencia de vídeo", "Latência de vídeo"}}, + {"视频总带宽", {"视频总带宽", "Total bandwidth", "Общий битрейт", "影片總頻寬", "総帯域幅", "총 대역폭", "Gesamtbandbreite", "Bande passante totale", "Ancho de banda total", "Largura de banda total"}}, + {"视频编码", {"视频编码", "Video codec", "Видеокодек", "影片編碼", "ビデオコーデック", "비디오 코덱", "Videocodec", "Codec vidéo", "Códec de vídeo", "Codec de vídeo"}}, + {"视频编码格式", {"视频编码格式", "Video codec", "Видеокодек", "影片編碼格式", "ビデオコーデック", "비디오 코덱", "Videocodec", "Codec vidéo", "Códec de vídeo", "Codec de vídeo"}}, + {"认证服务繁忙,请稍后重试。", {"认证服务繁忙,请稍后重试。", "Authentication service busy. Try again later.", "Сервис проверки занят. Повторите позже.", "認證服務繁忙,請稍後重試。", "認証サービスがビジー状態です。後でもう一度試してください。", "인증 서비스가 사용 중입니다. 나중에 다시 시도하세요.", "Authentifizierungsdienst ausgelastet. Versuchen Sie es später noch einmal.", "Service d'authentification occupé. Réessayez plus tard.", "Servicio de autenticación ocupado. Vuelve a intentarlo más tarde.", "Serviço de autenticação ocupado. Tente novamente mais tarde."}}, + {"记住密码", {"记住密码", "Remember password", "Запомнить пароль", "記住密碼", "パスワードを記憶する", "비밀번호 기억하기", "Passwort merken", "Mémoriser le mot de passe", "Recordar contraseña", "Lembrar senha"}}, + {"许可与版权声明", {"许可与版权声明", "Licenses and copyright notices", "Лицензии и авторские права", "許可與版權宣告", "ライセンスと著作権表示", "라이센스 및 저작권 고지", "Lizenzen und Urheberrechtshinweise", "Licences et mentions de droits d'auteur", "Licencias y avisos de derechos de autor", "Licenças e avisos de direitos autorais"}}, + {"设备", {"设备", "device", "устройство", "裝置", "デバイス", "장치", "Gerät", "appareil", "dispositivo", "dispositivo"}}, + {"设备 / ID", {"设备 / ID", "Device / ID", "Устройство / ID", "裝置 / ID", "デバイス/ID", "기기/ID", "Gerät / ID", "Appareil/ID", "Dispositivo/ID", "Dispositivo/ID"}}, + {"设备 ID", {"设备 ID", "Device ID", "ID", "裝置 ID", "デバイスID", "장치 ID", "Geräte-ID", "ID de l'appareil", "ID del dispositivo", "ID do dispositivo"}}, + {"设备不支持", {"设备不支持", "Unsupported", "Не поддерживается", "裝置不支援", "サポートされていません", "지원되지 않음", "Nicht unterstützt", "Non pris en charge", "No compatible", "Não suportado"}}, + {"设备名称", {"设备名称", "Device Name", "Имя устройства", "裝置名稱", "デバイス名", "장치 이름", "Gerätename", "Nom de l'appareil", "Nombre del dispositivo", "Nome do dispositivo"}}, + {"设备正忙,请稍后重试。", {"设备正忙,请稍后重试。", "The desktop is busy. Try again shortly.", "Компьютер занят. Повторите позже.", "裝置正忙,請稍後重試。", "デスクトップはビジー状態です。しばらくしてからもう一度お試しください。", "데스크톱이 사용 중입니다. 잠시 후 다시 시도하세요.", "Der Desktop ist beschäftigt. Versuchen Sie es in Kürze noch einmal.", "Le bureau est occupé. Réessayez sous peu.", "El escritorio está ocupado. Vuelve a intentarlo en breve.", "A área de trabalho está ocupada. Tente novamente em breve."}}, + {"设备离线", {"设备离线", "Device Offline", "Устройство не в сети", "裝置離線", "デバイスがオフライン", "장치 오프라인", "Gerät offline", "Appareil hors ligne", "Dispositivo sin conexión", "Dispositivo off-line"}}, + {"设备网络状态", {"设备网络状态", "Device network status", "Состояние сети устройств", "裝置網路狀態", "デバイスのネットワーク状態", "기기 네트워크 상태", "Netzwerkstatus des Geräts", "État du réseau de l'appareil", "Estado de la red del dispositivo", "Status da rede do dispositivo"}}, + {"设备连接密码", {"设备连接密码", "Device password", "Пароль устройства", "裝置連線密碼", "デバイスパスワード", "기기 비밀번호", "Gerätepasswort", "Mot de passe de l'appareil", "Contraseña del dispositivo", "Senha do dispositivo"}}, + {"设置", {"设置", "Settings", "Настройки", "設定", "設定", "설정", "Einstellungen", "Réglages", "Ajustes", "Configurações"}}, + {"设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。", {"设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。", "Settings → Apps & services → App startup management\n\nEnable: choose Add app, select CrossDesk, then choose Done.\n\nDisable: find this app in the startup list and choose Remove.", "Настройки → Приложения и сервисы → Управление запуском\n\nВключить: добавьте CrossDesk в список и подтвердите выбор.\n\nВыключить: удалите приложение из списка автозапуска.", "設定 → 應用和元服務 → 應用啟動管理\n\n開啟:點選“新增應用”,選擇 CrossDesk,然後點選“完成”。\n\n關閉:在自啟動列表中找到本應用,點選“移除”。", "[設定] → [アプリとサービス] → [アプリ起動管理]\n\n有効にする: [アプリの追加] を選択し、 [CrossDesk] を選択して、 [完了] を選択します。\n\n無効にする: スタートアップ リストでこのアプリを見つけて、[削除] を選択します。", "설정 → 앱 및 서비스 → 앱 시작 관리\n\n활성화: 앱 추가를 선택하고CrossDesk를 선택한 다음 완료를 선택합니다.\n\n비활성화: 시작 목록에서 이 앱을 찾아 제거를 선택합니다.", "Einstellungen → Apps & Dienste → App-Startup-Verwaltung\n\nAktivieren: Wählen Sie „App hinzufügen“, wählen Sie CrossDesk und dann „Fertig“.\n\nDeaktivieren: Suchen Sie diese App in der Startliste und wählen Sie „Entfernen“.", "Paramètres → Applications et services → Gestion du démarrage des applications\n\nActiver : choisissez Ajouter une application, sélectionnez CrossDesk, puis choisissez Terminé.\n\nDésactiver : recherchez cette application dans la liste de démarrage et choisissez Supprimer.", "Configuración → Aplicaciones y servicios → Gestión de inicio de aplicaciones\n\nHabilitar: elija Agregar aplicación, seleccione CrossDesk y luego elija Listo.\n\nDesactivar: busque esta aplicación en la lista de inicio y elija Eliminar.", "Configurações → Aplicativos e serviços → Gerenciamento de inicialização de aplicativos\n\nAtivar: escolha Adicionar aplicativo, selecione CrossDesk e escolha Concluído.\n\nDesativar: encontre este aplicativo na lista de inicialização e escolha Remover."}}, + {"设置尚未初始化,请稍后重试。", {"设置尚未初始化,请稍后重试。", "Settings are not ready; try again shortly.", "Настройки ещё не готовы. Повторите позже.", "設定尚未初始化,請稍後重試。", "設定の準備ができていません。すぐにもう一度試してください。", "설정이 준비되지 않았습니다. 잠시 후 다시 시도해 보세요.", "Einstellungen sind nicht bereit; Versuchen Sie es in Kürze noch einmal.", "Les paramètres ne sont pas prêts ; réessayez sous peu.", "Las configuraciones no están listas; Inténtalo de nuevo en breve.", "As configurações não estão prontas; tente novamente em breve."}}, + {"设置开机自启动", {"设置开机自启动", "Set up auto start", "Настройка автозапуска", "設定開機自啟動", "自動起動の設定", "자동 시작 설정", "Automatischen Start einrichten", "Configurer le démarrage automatique", "Configurar el inicio automático", "Configurar início automático"}}, + {"设置未改变。", {"设置未改变。", "Setting unchanged.", "Настройка не изменилась.", "設定未改變。", "設定は変更されません。", "설정은 변경되지 않습니다.", "Einstellung unverändert.", "Paramètre inchangé.", "Configuración sin cambios.", "Configuração inalterada."}}, + {"设置(修改后立即保存)", {"设置(修改后立即保存)", "Settings (each change is saved immediately)", "Настройки (изменения сохраняются сразу)", "設定(修改後立即儲存)", "設定 (各変更はすぐに保存されます)", "설정(각 변경 사항은 즉시 저장됩니다)", "Einstellungen (jede Änderung wird sofort gespeichert)", "Paramètres (chaque modification est enregistrée immédiatement)", "Configuración (cada cambio se guarda inmediatamente)", "Configurações (cada alteração é salva imediatamente)"}}, + {"访问官网: ", {"访问官网: ", "Access Website: ", "Официальный сайт: ", "訪問官網: ", "ウェブサイトにアクセス: ", "웹사이트 접속: ", "Zugriff auf die Website: ", "Accéder au site Web : ", "Acceder al sitio web: ", "Acesse o site: "}}, + {"访问密码必须为 6 位英文字母或数字,区分大小写。", {"访问密码必须为 6 位英文字母或数字,区分大小写。", "Use exactly 6 letters (A–Z, a–z) or digits (0–9). Case-sensitive.", "Пароль: ровно 6 латинских букв или цифр. Регистр учитывается.", "訪問密碼必須為 6 位英文字母或數字,區分大小寫。", "正確に 6 つの文字 (A ~ Z、a ~ z) または数字 (0 ~ 9) を使用してください。大文字と小文字を区別。", "정확히 6개의 문자(A–Z, a–z) 또는 숫자(0–9)를 사용하세요. 대소문자를 구분합니다.", "Verwenden Sie genau 6 Buchstaben (A–Z, a–z) oder Ziffern (0–9). Groß- und Kleinschreibung beachten.", "Utilisez exactement 6 lettres (A–Z, a–z) ou chiffres (0–9). Sensible aux majuscules et minuscules.", "Utilice exactamente 6 letras (A–Z, a–z) o dígitos (0–9). Distingue mayúsculas y minúsculas.", "Use exatamente 6 letras (A–Z, a–z) ou dígitos (0–9). Maiúsculas e minúsculas."}}, + {"证书验证失败,请重新安装自托管根证书", {"证书验证失败,请重新安装自托管根证书", "Certificate verification failed. Reinstall the self-hosted root certificate.", "Ошибка проверки сертификата. Переустановите корневой сертификат собственного сервера.", "證書驗證失敗,請重新安裝自託管根證書", "証明書の検証に失敗しました。セルフホスト型ルート証明書を再インストールします。", "인증서 확인에 실패했습니다. 자체 호스팅 루트 인증서를 다시 설치합니다.", "Die Zertifikatsüberprüfung ist fehlgeschlagen. Installieren Sie das selbstgehostete Stammzertifikat neu.", "La vérification du certificat a échoué. Réinstallez le certificat racine auto-hébergé.", "Falló la verificación del certificado. Reinstale el certificado raíz autohospedado.", "Falha na verificação do certificado. Reinstale o certificado raiz auto-hospedado."}}, + {"该分组暂无近期连接", {"该分组暂无近期连接", "No recent connections in this group", "В этой группе нет недавних подключений", "該分組暫無近期連線", "このグループには最近の接続がありません", "이 그룹에는 최근 연결이 없습니다.", "Keine aktuellen Verbindungen in dieser Gruppe", "Aucune connexion récente dans ce groupe", "No hay conexiones recientes en este grupo.", "Nenhuma conexão recente neste grupo"}}, + {"该应用需要授权以下权限:", {"该应用需要授权以下权限:", "The application requires the following permissions:", "Для работы приложения требуются следующие разрешения:", "該應用需要授權以下許可權:", "アプリケーションには次の権限が必要です。", "애플리케이션에는 다음 권한이 필요합니다.", "Die Anwendung erfordert die folgenden Berechtigungen:", "L'application nécessite les autorisations suivantes :", "La aplicación requiere los siguientes permisos:", "O aplicativo requer as seguintes permissões:"}}, + {"该设备正在连接,请稍候", {"该设备正在连接,请稍候", "This device is already connecting", "Устройство уже подключается", "該裝置正在連線,請稍候", "このデバイスはすでに接続されています", "이 장치는 이미 연결되어 있습니다", "Dieses Gerät stellt bereits eine Verbindung her", "Cet appareil est déjà connecté", "Este dispositivo ya se está conectando", "Este dispositivo já está conectado"}}, + {"该选项由系统或控制端管理,不可在此修改。", {"该选项由系统或控制端管理,不可在此修改。", "This option is managed by the system or controller and is read-only here.", "Этот параметр управляется системой или клиентом и здесь недоступен для изменения.", "該選項由系統或控制端管理,不可在此修改。", "このオプションはシステムまたはコントローラーによって管理され、ここでは読み取り専用です。", "이 옵션은 시스템이나 컨트롤러에 의해 관리되며 여기서는 읽기 전용입니다.", "Diese Option wird vom System oder Controller verwaltet und ist hier schreibgeschützt.", "Cette option est gérée par le système ou le contrôleur et est ici en lecture seule.", "Esta opción es administrada por el sistema o controlador y aquí es de solo lectura.", "Esta opção é gerenciada pelo sistema ou controlador e é somente leitura aqui."}}, + {"语言", {"语言", "Language", "Язык", "語言", "言語", "언어", "Sprache", "Langue", "Idioma", "Idioma"}}, + {"请先设置有效的服务器地址和端口,再启用自托管。", {"请先设置有效的服务器地址和端口,再启用自托管。", "Set a valid server host and port before enabling self-hosting.", "Укажите адрес и порт сервера перед включением собственного сервера.", "請先設定有效的伺服器地址和埠,再啟用自託管。", "セルフホスティングを有効にする前に、有効なサーバー ホストとポートを設定します。", "셀프 호스팅을 활성화하기 전에 유효한 서버 호스트와 포트를 설정하세요.", "Legen Sie einen gültigen Serverhost und -port fest, bevor Sie das Selbsthosting aktivieren.", "Définissez un hôte et un port de serveur valides avant d'activer l'auto-hébergement.", "Configure un host y un puerto de servidor válidos antes de habilitar el autohospedaje.", "Defina um host e uma porta de servidor válidos antes de ativar a auto-hospedagem."}}, + {"请在 %d 秒后重试。", {"请在 %d 秒后重试。", "Retry in %d seconds.", "Повторите через %d сек.", "請在 %d 秒後重試。", "%d秒後に再試行します。", "%d초 후에 다시 시도하세요.", "Wiederholen Sie den Vorgang in%dSekunden.", "Réessayez dans%dsecondes.", "Reintentar en%dsegundos.", "Tente novamente em%dsegundos."}}, + {"请在 {0} 秒后重试", {"请在 {0} 秒后重试", "Try again in {0} s", "Повторите через {0} с", "請在 {0} 秒後重試", "{0} 秒後に再試行してください", "{0}초 후 다시 시도하세요", "In {0} s erneut versuchen", "Réessayez dans {0} s", "Reintentar en {0} s", "Tente novamente em {0} s"}}, + {"请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。", {"请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。", "Allow CrossDesk access in System Settings. Reopen the app if macOS asks you to.", "Разрешите доступ для CrossDesk в Системных настройках. Перезапустите приложение, если macOS попросит об этом.", "請在系統設定中允許 CrossDesk 訪問。如系統提示重新開啟應用,請按提示操作。", "システム設定でCrossDeskアクセスを許可します。 macOS が要求した場合は、アプリを再度開きます。", "시스템 설정에서CrossDesk액세스를 허용합니다. macOS에서 요청하면 앱을 다시 엽니다.", "Erlauben Sie den CrossDesk-Zugriff in den Systemeinstellungen. Öffnen Sie die App erneut, wenn macOS Sie dazu auffordert.", "Autoriser l'accès à CrossDesk dans les paramètres système. Rouvrez l'application si macOS vous le demande.", "Permitir el acceso a CrossDesk en Configuración del sistema. Vuelva a abrir la aplicación si macOS se lo solicita.", "Permitir acesso CrossDesk nas configurações do sistema. Abra novamente o aplicativo se o macOS solicitar."}}, + {"请在系统设置中添加或移除本应用,返回后会自动刷新状态。", {"请在系统设置中添加或移除本应用,返回后会自动刷新状态。", "Add or remove this app in system Settings. The status refreshes when you return.", "Добавьте или удалите приложение в настройках системы. После возвращения статус обновится.", "請在系統設定中新增或移除本應用,返回後會自動重新整理狀態。", "システム設定でこのアプリを追加または削除します。戻るとステータスが更新されます。", "시스템 설정에서 이 앱을 추가하거나 제거하세요. 돌아오면 상태가 새로 고쳐집니다.", "Fügen Sie diese App in den Systemeinstellungen hinzu oder entfernen Sie sie. Der Status wird aktualisiert, wenn Sie zurückkehren.", "Ajoutez ou supprimez cette application dans les paramètres système. Le statut s'actualise à votre retour.", "Agregue o elimine esta aplicación en la Configuración del sistema. El estado se actualiza cuando regresa.", "Adicione ou remova este aplicativo nas configurações do sistema. O status é atualizado quando você retorna."}}, + {"请更换端口。", {"请更换端口。", "Choose another port.", "Выберите другой порт.", "請更換埠。", "別のポートを選択します。", "다른 포트를 선택하세요.", "Wählen Sie einen anderen Port.", "Choisissez un autre port.", "Elija otro puerto.", "Escolha outra porta."}}, + {"请点击主界面密码旁的修改按钮设置密码。", {"请点击主界面密码旁的修改按钮设置密码。", "Set a password using Edit next to the password on the main screen.", "Задайте пароль кнопкой редактирования рядом с паролем в главном окне.", "請點選主介面密碼旁的修改按鈕設定密碼。", "メイン画面のパスワード横の「編集」でパスワードを設定します。", "메인 화면의 비밀번호 옆에 있는 편집을 이용하여 비밀번호를 설정하세요.", "Legen Sie mit „Bearbeiten“ neben dem Passwort auf dem Hauptbildschirm ein Passwort fest.", "Définissez un mot de passe en utilisant Modifier à côté du mot de passe sur l'écran principal.", "Establezca una contraseña usando Editar junto a la contraseña en la pantalla principal.", "Defina uma senha usando Editar ao lado da senha na tela principal."}}, + {"请输入 1–6 位英文字母或数字密码", {"请输入 1–6 位英文字母或数字密码", "Use 1–6 letters (A–Z, a–z) or digits (0–9)", "Пароль: 1–6 латинских букв или цифр", "請輸入 1–6 位英文字母或數字密碼", "1 ~ 6 個の文字 (A ~ Z、a ~ z) または数字 (0 ~ 9) を使用します。", "1~6자의 문자(A~Z, a~z) 또는 숫자(0~9)를 사용하세요.", "Verwenden Sie 1–6 Buchstaben (A–Z, a–z) oder Ziffern (0–9)", "Utilisez 1 à 6 lettres (A à Z, a à z) ou chiffres (0 à 9)", "Utilice de 1 a 6 letras (A–Z, a–z) o dígitos (0–9)", "Use 1–6 letras (A–Z, a–z) ou dígitos (0–9)"}}, + {"请输入 1–65535 之间的整数端口。", {"请输入 1–65535 之间的整数端口。", "Enter a port number from 1 to 65535.", "Введите целый номер порта от 1 до 65535.", "請輸入 1–65535 之間的整數埠。", "ポート番号を1~65535まで入力します。", "1~65535 사이의 포트 번호를 입력하세요.", "Geben Sie eine Portnummer von 1 bis 65535 ein.", "Entrez un numéro de port compris entre 1 et 65535.", "Ingrese un número de puerto del 1 al 65535.", "Insira um número de porta de 1 a 65535."}}, + {"请输入 1–65535 范围内的信令端口。", {"请输入 1–65535 范围内的信令端口。", "Enter a signaling port between 1 and 65535.", "Введите порт сигнального сервиса от 1 до 65535.", "請輸入 1–65535 範圍內的信令埠。", "1 ~ 65535 のシグナリング ポートを入力します。", "1~65535 사이의 신호 포트를 입력하세요.", "Geben Sie einen Signalisierungsport zwischen 1 und 65535 ein.", "Entrez un port de signalisation compris entre 1 et 65535.", "Ingrese un puerto de señalización entre 1 y 65535.", "Insira uma porta de sinalização entre 1 e 65535."}}, + {"请输入 9 位设备 ID", {"请输入 9 位设备 ID", "Enter a 9-digit device ID", "Введите ID из 9 цифр", "請輸入 9 位裝置 ID", "9桁のデバイスIDを入力", "기기 ID 9자리를 입력하세요.", "Geben Sie eine 9-stellige Geräte-ID ein", "Saisissez un identifiant d'appareil à 9 chiffres", "Ingrese una ID de dispositivo de 9 dígitos", "Insira um ID de dispositivo de 9 dígitos"}}, + {"请输入六位密码:", {"请输入六位密码:", "Enter a six-character password:", "Введите пароль из 6 символов:", "請輸入六位密碼:", "6 文字のパスワードを入力します。", "6자리 비밀번호를 입력하세요.", "Geben Sie ein sechsstelliges Passwort ein:", "Saisissez un mot de passe à six caractères :", "Ingrese una contraseña de seis caracteres:", "Digite uma senha de seis caracteres:"}}, + {"请输入密码:", {"请输入密码:", "Please input password:", "Введите пароль:", "請輸入密碼:", "パスワードを入力してください:", "비밀번호를 입력해주세요:", "Bitte geben Sie das Passwort ein:", "Veuillez saisir le mot de passe :", "Por favor ingrese la contraseña:", "Insira a senha:"}}, + {"请输入有效的 9 位设备 ID", {"请输入有效的 9 位设备 ID", "Enter a valid 9-digit device ID", "Введите корректный 9-значный ID устройства", "請輸入有效的 9 位裝置 ID", "有効な9桁のデバイスIDを入力してください", "유효한 9자리 장치 ID를 입력하세요.", "Geben Sie eine gültige 9-stellige Geräte-ID ein", "Entrez un identifiant d'appareil valide à 9 chiffres", "Ingrese una ID de dispositivo válida de 9 dígitos", "Insira um ID de dispositivo válido de 9 dígitos"}}, + {"请输入有效的 IPv4 或 IPv4:端口", {"请输入有效的 IPv4 或 IPv4:端口", "Enter a valid IPv4 or IPv4:port", "Укажите IPv4 или IPv4:порт", "請輸入有效的 IPv4 或 IPv4:埠", "有効な IPv4 または IPv4:port を入力してください", "유효한 IPv4 또는 IPv4:포트를 입력하세요.", "Geben Sie einen gültigen IPv4- oder IPv4:Port ein", "Entrez un port IPv4 ou IPv4 valide", "Ingrese un IPv4 válido o IPv4:puerto", "Insira um IPv4 ou IPv4:porta válido"}}, + {"请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。", {"请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。", "Enter a valid IPv4 address such as 192.168.1.20, or IPv4:port (1–65535).", "Введите IPv4, например 192.168.1.20, или IPv4:порт (1–65535).", "請輸入有效的 IPv4,例如 192.168.1.20;指定埠可用 IPv4:埠,埠範圍 1–65535。", "192.168.1.20 または IPv4:port (1 ~ 65535) などの有効な IPv4 アドレスを入力します。", "192.168.1.20 또는 IPv4:포트(1~65535)와 같은 유효한 IPv4 주소를 입력하세요.", "Geben Sie eine gültige IPv4-Adresse ein, z. B. 192.168.1.20 oder IPv4:Port (1–65535).", "Saisissez une adresse IPv4 valide telle que 192.168.1.20 ou IPv4:port (1–65535).", "Ingrese una dirección IPv4 válida como 192.168.1.20 o IPv4:puerto (1–65535).", "Insira um endereço IPv4 válido, como 192.168.1.20 ou IPv4:porta (1–65535)."}}, + {"请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。", {"请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。", "Enter a valid host, IP, or HTTPS/WSS signaling URL. Paths are supported.", "Введите имя хоста, IP или HTTPS/WSS-адрес сигнального сервиса. Путь допустим.", "請輸入有效的主機名、IP 或 HTTPS/WSS 信令地址,可包含路徑。", "有効なホスト、IP、または HTTPS/WSS シグナリング URL を入力します。パスがサポートされています。", "유효한 호스트, IP 또는 HTTPS/WSS 신호 URL을 입력하세요. 경로가 지원됩니다.", "Geben Sie eine gültige Host-, IP- oder HTTPS/WSS-Signalisierungs-URL ein. Pfade werden unterstützt.", "Entrez une URL de signalisation d'hôte, d'adresse IP ou HTTPS/WSS valide. Les chemins sont pris en charge.", "Ingrese un host válido, IP o URL de señalización HTTPS/WSS. Se admiten caminos.", "Insira um URL de sinalização de host, IP ou HTTPS/WSS válido. Caminhos são suportados."}}, + {"请输入连接名称:", {"请输入连接名称:", "Please input connection name:", "Введите имя подключения:", "請輸入連線名稱:", "接続名を入力してください:", "연결 이름을 입력하세요:", "Bitte geben Sie den Verbindungsnamen ein:", "Veuillez saisir le nom de la connexion :", "Ingrese el nombre de la conexión:", "Insira o nome da conexão:"}}, + {"请连接 Wi-Fi 或网线,", {"请连接 Wi-Fi 或网线,", "Connect to Wi-Fi or Ethernet,", "Подключитесь к Wi-Fi или Ethernet", "請連線 Wi-Fi 或網線,", "Wi-Fiまたはイーサネットに接続し、", "Wi-Fi 또는 이더넷에 연결하고,", "Mit WLAN oder Ethernet verbinden,", "Connectez-vous au Wi-Fi ou à Ethernet,", "Conéctese a Wi-Fi o Ethernet,", "Conecte-se a Wi-Fi ou Ethernet,"}}, + {"请选择其他端口或检查系统权限。", {"请选择其他端口或检查系统权限。", "Choose another port or check system permissions.", "Смените порт или проверьте разрешения.", "請選擇其他埠或檢查系統許可權。", "別のポートを選択するか、システム権限を確認してください。", "다른 포트를 선택하거나 시스템 권한을 확인하세요.", "Wählen Sie einen anderen Port oder überprüfen Sie die Systemberechtigungen.", "Choisissez un autre port ou vérifiez les autorisations du système.", "Elija otro puerto o verifique los permisos del sistema.", "Escolha outra porta ou verifique as permissões do sistema."}}, + {"请选择已存在且可写的绝对目录路径;default 使用默认目录。", {"请选择已存在且可写的绝对目录路径;default 使用默认目录。", "Use an existing writable absolute directory, or default for the default location.", "Укажите существующий доступный для записи абсолютный путь к каталогу или default.", "請選擇已存在且可寫的絕對目錄路徑;default 使用預設目錄。", "既存の書き込み可能な絶対ディレクトリを使用するか、デフォルトの場所にはデフォルトを使用します。", "기존의 쓰기 가능한 절대 디렉토리를 사용하거나 기본 위치로 기본값을 사용하십시오.", "Verwenden Sie ein vorhandenes beschreibbares absolutes Verzeichnis oder Standard für den Standardspeicherort.", "Utilisez un répertoire absolu accessible en écriture existant, ou par défaut pour l'emplacement par défaut.", "Utilice un directorio absoluto grabable existente o el predeterminado para la ubicación predeterminada.", "Use um diretório absoluto gravável existente ou padrão para o local padrão."}}, + {"请重新输入密码", {"请重新输入密码", "Please input password again", "Повторно введите пароль", "請重新輸入密碼", "パスワードを再度入力してください", "비밀번호를 다시 입력해주세요", "Bitte geben Sie das Passwort erneut ein", "Veuillez saisir à nouveau le mot de passe", "Ingrese la contraseña nuevamente", "Insira a senha novamente"}}, + {"请重试或检查本机防火墙。", {"请重试或检查本机防火墙。", "Retry or check the local firewall.", "Повторите попытку или проверьте брандмауэр.", "請重試或檢查本機防火牆。", "再試行するか、ローカル ファイアウォールを確認します。", "로컬 방화벽을 다시 시도하거나 확인하세요.", "Versuchen Sie es erneut oder überprüfen Sie die lokale Firewall.", "Réessayez ou vérifiez le pare-feu local.", "Vuelva a intentarlo o verifique el firewall local.", "Tente novamente ou verifique o firewall local."}}, + {"读取失败", {"读取失败", "Read failed", "Ошибка чтения", "讀取失敗", "読み取りに失敗しました", "읽기 실패", "Lesen fehlgeschlagen", "Échec de la lecture", "Error de lectura", "Falha na leitura"}}, + {"调整失败,请重试。", {"调整失败,请重试。", "Could not apply settings. Try again.", "Не удалось применить настройки. Повторите попытку.", "調整失敗,請重試。", "設定を適用できませんでした。もう一度やり直してください。", "설정을 적용할 수 없습니다. 다시 시도해 보세요.", "Einstellungen konnten nicht angewendet werden. Versuchen Sie es erneut.", "Impossible d'appliquer les paramètres. Essayer à nouveau.", "No se pudieron aplicar las configuraciones. Intentar otra vez.", "Não foi possível aplicar as configurações. Tente novamente."}}, + {"赞助支持", {"赞助支持", "Sponsorship", "Поддержка проекта", "贊助支援", "開発を支援", "후원", "Sponsoring", "Parrainage", "Patrocinio", "Patrocínio"}}, + {"跟随系统", {"跟随系统", "Follow system", "Как в системе", "跟隨系統", "システム設定に従う", "시스템 설정 따르기", "Systemsprache", "Langue du système", "Idioma del sistema", "Idioma do sistema"}}, + {"跟随设备设置", {"跟随设备设置", "Follow device settings", "Настройки устройства", "跟隨裝置設定", "デバイスの設定に従ってください", "기기 설정을 따르세요.", "Befolgen Sie die Geräteeinstellungen", "Suivre les paramètres de l'appareil", "Siga la configuración del dispositivo", "Siga as configurações do dispositivo"}}, + {"跨页 ", {"跨页 ", "Other pages ", "Вне страницы ", "跨頁 ", "その他のページ ", "기타 페이지 ", "Andere Seiten ", "Autres pages ", "Otras páginas ", "Outras páginas "}}, + {"软件许可", {"软件许可", "Software license", "Лицензия программы", "軟體許可", "ソフトウェアライセンス", "소프트웨어 라이센스", "Softwarelizenz", "Licence du logiciel", "Licencia de software", "Licença de software"}}, + {"辅助功能权限", {"辅助功能权限", "Accessibility Permission", "Разрешение специальных возможностей", "輔助功能許可權", "アクセシビリティ許可", "접근성 권한", "Zugänglichkeitsgenehmigung", "Autorisation d'accessibilité", "Permiso de accesibilidad", "Permissão de acessibilidade"}}, + {"输入", {"输入", "In", "Вход", "輸入", "で", "인", "In", "Dans", "En", "Em"}}, + {"输入 IP:端口,通过局域网连接", {"输入 IP:端口,通过局域网连接", "Enter IP:port to connect over LAN", "Введите IP:порт для подключения по LAN", "輸入 IP:埠,透過區域網連線", "LAN経由で接続するIP:ポートを入力します。", "LAN을 통해 연결하려면 IP:포트를 입력하세요.", "Geben Sie IP:Port ein, um eine Verbindung über LAN herzustellen", "Entrez IP:port pour vous connecter via LAN", "Ingrese IP: puerto para conectarse a través de LAN", "Digite IP:porta para conectar pela LAN"}}, + {"输入新值(cancel 取消)", {"输入新值(cancel 取消)", "Enter a new value (cancel to abort)", "Введите новое значение (cancel — отмена)", "輸入新值(cancel 取消)", "新しい値を入力します(中止するにはキャンセル)", "새 값을 입력하세요(중단하려면 취소하세요).", "Geben Sie einen neuen Wert ein (Abbrechen zum Abbrechen)", "Entrez une nouvelle valeur (annuler pour abandonner)", "Ingrese un nuevo valor (cancelar para cancelar)", "Insira um novo valor (cancelar para abortar)"}}, + {"输入新密码(6位英文字母或数字;输入 cancel 取消):", {"输入新密码(6位英文字母或数字;输入 cancel 取消):", "New password (6 ASCII letters or digits; cancel to abort):", "Новый пароль (6 латинских букв или цифр; cancel — отмена):", "輸入新密碼(6位英文字母或數字;輸入 cancel 取消):", "新しいパスワード (6 つの ASCII 文字または数字、中止するにはキャンセル):", "새 비밀번호(ASCII 문자 또는 숫자 6개, 중단하려면 취소):", "Neues Passwort (6 ASCII-Buchstaben oder Ziffern; Abbrechen zum Abbrechen):", "Nouveau mot de passe (6 lettres ou chiffres ASCII ; annuler pour abandonner) :", "Nueva contraseña (6 letras o dígitos ASCII; cancelar para cancelar):", "Nova senha (6 letras ou dígitos ASCII; cancelar para abortar):"}}, + {"输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。", {"输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。", "Enter an item number or key; back to return. Shortcut: settings set KEY VALUE.", "Введите номер или имя параметра; back — назад. Команда: settings set KEY VALUE.", "輸入編號或選項名稱修改;back 返回。也可使用 settings set 名稱 值。", "項目番号またはキーを入力します。戻って戻る。ショートカット: 設定はキー値を設定します。", "품목 번호나 키를 입력하세요. 다시 돌아가기 위해. 바로가기: 설정은 KEY VALUE를 설정합니다.", "Geben Sie eine Artikelnummer oder einen Schlüssel ein. zurück, um zurückzukehren. Verknüpfung: Einstellungen legen SCHLÜSSELWERT fest.", "Entrez un numéro d'article ou une clé ; retour pour revenir. Raccourci : les paramètres définissent la VALEUR CLÉ.", "Ingrese un número de artículo o clave; volver para volver. Acceso directo: configuración establece VALOR CLAVE.", "Insira um número de item ou chave; voltar para voltar. Atalho: configurações definidas KEY VALUE."}}, + {"输入设备 ID,连接远程桌面", {"输入设备 ID,连接远程桌面", "Enter a device ID to start a remote session", "Введите ID для удалённого подключения", "輸入裝置 ID,連線遠端桌面", "デバイスIDを入力してリモートセッションを開始します", "원격 세션을 시작하려면 장치 ID를 입력하세요.", "Geben Sie eine Geräte-ID ein, um eine Remote-Sitzung zu starten", "Entrez un identifiant d'appareil pour démarrer une session à distance", "Ingrese una ID de dispositivo para iniciar una sesión remota", "Insira um ID de dispositivo para iniciar uma sessão remota"}}, + {"输出", {"输出", "Out", "Выход", "輸出", "アウト", "아웃", "Raus", "Sortie", "Fuera", "Fora"}}, + {"近期连接", {"近期连接", "Recent Connections", "Недавние подключения", "近期連線", "最近の接続", "최근 연결", "Aktuelle Verbindungen", "Connexions récentes", "Conexiones recientes", "Conexões recentes"}}, + {"返回", {"返回", "Back", "Назад", "返回", "戻る", "뒤로", "Zurück", "Retour", "Volver", "Voltar"}}, + {"还原窗口", {"还原窗口", "Restore window", "Восстановить окно", "還原視窗", "復元ウィンドウ", "복원 창", "Fenster „Wiederherstellen“.", "Fenêtre de restauration", "Restaurar ventana", "Janela de restauração"}}, + {"远程控制连接中,保留连接以确认或取消关机。", {"远程控制连接中,保留连接以确认或取消关机。", "Remote session active. Keeping the connection available to confirm or cancel shutdown.", "Удалённый сеанс активен. Соединение сохранено для подтверждения или отмены выключения.", "遠端控制連線中,保留連線以確認或取消關機。", "リモート接続中です。シャットダウンの確認または取り消しのため、接続を維持しています。", "원격 세션이 활성화되어 있습니다. 종료 확인 또는 취소를 위해 연결을 유지합니다.", "Remotesitzung aktiv. Die Verbindung bleibt zum Bestätigen oder Abbrechen des Herunterfahrens bestehen.", "Session distante active. La connexion reste disponible pour confirmer ou annuler l’arrêt.", "Sesión remota activa. Se mantiene la conexión para confirmar o cancelar el apagado.", "Sessão remota ativa. A conexão é mantida para confirmar ou cancelar o desligamento."}}, + {"远程桌面", {"远程桌面", "Remote Desktop", "Удаленный рабочий стол", "遠端桌面", "リモートデスクトップ", "원격 데스크톱", "Remotedesktop", "Bureau à distance", "Escritorio remoto", "Área de Trabalho Remota"}}, + {"远端 IP / 端口", {"远端 IP / 端口", "Remote IP / Port", "Удалённый IP / Порт", "遠端 IP / 埠", "リモートIP/ポート", "원격 IP / 포트", "Remote-IP/Port", "IP/port distant", "IP/puerto remoto", "IP/Porta Remota"}}, + {"远端 Windows 服务不可用", {"远端 Windows 服务不可用", "Remote Windows service unavailable", "Служба Windows на удаленной стороне недоступна", "遠端 Windows 服務不可用", "リモート Windows サービスが利用できない", "원격 Windows 서비스를 사용할 수 없습니다.", "Remote-Windows-Dienst nicht verfügbar", "Service Windows distant indisponible", "Servicio remoto de Windows no disponible", "Serviço remoto do Windows indisponível"}}, + {"远端处于锁屏封面,可发送 SAS", {"远端处于锁屏封面,可发送 SAS", "Remote lock screen visible, send SAS", "Удалённый экран заблокирован, можно отправить SAS", "遠端處於鎖屏封面,可傳送 SAS", "リモート ロック画面が表示され、SAS を送信", "원격 잠금 화면 표시, SAS 전송", "Remote-Sperrbildschirm sichtbar, SAS senden", "Écran de verrouillage à distance visible, envoyer SAS", "Pantalla de bloqueo remoto visible, enviar SAS", "Tela de bloqueio remoto visível, envie SAS"}}, + {"远端密码框已出现", {"远端密码框已出现", "Remote password box visible", "На удалённом устройстве появилось поле пароля", "遠端密碼框已出現", "リモートパスワードボックスが表示されます", "원격 비밀번호 상자 표시", "Remote-Passwortfeld sichtbar", "Boîte de mot de passe distante visible", "Cuadro de contraseña remota visible", "Caixa de senha remota visível"}}, + {"远端已进入安全桌面", {"远端已进入安全桌面", "Remote secure desktop active", "На удалённом устройстве активен защищённый рабочий стол", "遠端已進入安全桌面", "リモート セキュア デスクトップがアクティブです", "원격 보안 데스크톱 활성화", "Remote Secure Desktop aktiv", "Bureau sécurisé à distance actif", "Escritorio seguro remoto activo", "Área de trabalho remota segura ativa"}}, + {"连接", {"连接", "Connect", "Подключиться", "連線", "接続", "연결", "Verbinden", "Connecter", "Conectar", "Conectar"}}, + {"连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。", {"连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。", "Invalid connection negotiation data. Try again and check that both CrossDesk versions are compatible.", "Неверные данные согласования соединения. Повторите попытку и проверьте совместимость версий CrossDesk.", "連線協商資料無效,請重試並確認雙方 CrossDesk 版本相容。", "接続ネゴシエーション データが無効です。もう一度試して、両方のCrossDeskバージョンに互換性があることを確認してください。", "연결 협상 데이터가 잘못되었습니다. 다시 시도하여 두CrossDesk버전이 모두 호환되는지 확인하세요.", "Ungültige Verbindungsaushandlungsdaten. Versuchen Sie es erneut und prüfen Sie, ob beide CrossDesk-Versionen kompatibel sind.", "Données de négociation de connexion invalides. Réessayez et vérifiez que les deux versions de CrossDesk sont compatibles.", "Datos de negociación de conexión no válidos. Inténtalo de nuevo y comprueba que ambas versiones de CrossDesk sean compatibles.", "Dados de negociação de conexão inválidos. Tente novamente e verifique se ambas as versões do CrossDesk são compatíveis."}}, + {"连接地址或监听端口已更改,请确认最新地址后重试。", {"连接地址或监听端口已更改,请确认最新地址后重试。", "The connection address or listening port has changed. Check the current address and try again.", "Адрес подключения или порт прослушивания изменился. Проверьте текущий адрес и повторите попытку.", "連線地址或監聽埠已更改,請確認最新地址後重試。", "接続アドレスまたはリスニングポートが変更されました。現在のアドレスを確認して、再試行してください。", "연결 주소 또는 수신 포트가 변경되었습니다. 현재 주소를 확인하고 다시 시도하세요.", "Die Verbindungsadresse oder der Überwachungsport hat sich geändert. Überprüfen Sie die aktuelle Adresse und versuchen Sie es erneut.", "L'adresse de connexion ou le port d'écoute a changé. Vérifiez l'adresse actuelle et réessayez.", "La dirección de conexión o el puerto de escucha ha cambiado. Verifique la dirección actual e inténtelo nuevamente.", "O endereço de conexão ou porta de escuta foi alterado. Verifique o endereço atual e tente novamente."}}, + {"连接密码", {"连接密码", "Connection password", "Пароль подключения", "連線密碼", "接続パスワード", "연결 비밀번호", "Verbindungspasswort", "Mot de passe de connexion", "Contraseña de conexión", "Senha de conexão"}}, + {"连接延时", {"连接延时", "Connection latency", "Задержка соединения", "連線延時", "接続遅延", "연결 지연", "Verbindungslatenz", "Latence de connexion", "Latencia de conexión", "Latência de conexão"}}, + {"连接建立后可调整,需被控端支持。", {"连接建立后可调整,需被控端支持。", "Available when connected to a supported remote device.", "Доступно при подключении к поддерживаемому устройству.", "連線建立後可調整,需被控端支援。", "サポートされているリモート デバイスに接続されている場合に使用できます。", "지원되는 원격 장치에 연결된 경우 사용할 수 있습니다.", "Verfügbar bei Verbindung mit einem unterstützten Remote-Gerät.", "Disponible lors de la connexion à un appareil distant pris en charge.", "Disponible cuando se conecta a un dispositivo remoto compatible.", "Disponível quando conectado a um dispositivo remoto compatível."}}, + {"连接断开后锁屏", {"连接断开后锁屏", "Lock screen on disconnect", "Блокировка при отключении", "連線斷開後鎖屏", "切断時のロック画面", "연결 해제 시 잠금 화면", "Bildschirm beim Trennen sperren", "Écran de verrouillage à la déconnexion", "Pantalla de bloqueo al desconectar", "Bloquear tela ao desconectar"}}, + {"连接时自动开启隐私屏", {"连接时自动开启隐私屏", "Privacy screen on connection", "Приватный экран при подключении", "連線時自動開啟隱私屏", "接続時のプライバシー画面", "연결 시 개인정보 보호 화면", "Datenschutzbildschirm bei Verbindung", "Écran de confidentialité lors de la connexion", "Pantalla de privacidad al conectarse", "Tela de privacidade na conexão"}}, + {"连接模式", {"连接模式", "Connection mode", "Режим подключения", "連線模式", "接続モード", "연결 모드", "Verbindungsmodus", "Mode de connexion", "Modo de conexión", "Modo de conexão"}}, + {"连接状态:", {"连接状态:", "Connection Status:", "Состояние соединения:", "連線狀態:", "接続ステータス:", "연결 상태:", "Verbindungsstatus:", "État de la connexion :", "Estado de conexión:", "Status da conexão:"}}, + {"连接过的设备会显示在这里,方便下次快速访问。", {"连接过的设备会显示在这里,方便下次快速访问。", "Devices you connect to will appear here for quick access.", "Устройства появятся здесь после первого подключения.", "連線過的裝置會顯示在這裡,方便下次快速訪問。", "接続しているデバイスがここに表示され、簡単にアクセスできます。", "빠른 액세스를 위해 연결한 장치가 여기에 표시됩니다.", "Geräte, mit denen Sie eine Verbindung herstellen, werden hier angezeigt, damit Sie schnell darauf zugreifen können.", "Les appareils auxquels vous vous connectez apparaîtront ici pour un accès rapide.", "Los dispositivos a los que te conectes aparecerán aquí para un acceso rápido.", "Os dispositivos aos quais você se conecta aparecerão aqui para acesso rápido."}}, + {"退出", {"退出", "Exit", "Выход", "退出", "出口", "종료", "Ausgang", "Quitter", "Salir", "Sair"}}, + {"退出全屏", {"退出全屏", "Exit fullscreen", "Выйти из полноэкранного режима", "退出全屏", "全画面表示を終了する", "전체 화면 종료", "Vollbild beenden", "Quitter le mode plein écran", "Salir de pantalla completa", "Sair da tela cheia"}}, + {"退出精简", {"退出精简", "Exit compact", "Обычный вид", "退出精簡", "コンパクトに終了", "컴팩트 종료", "Kompakt verlassen", "Quitter le compact", "Salir compacto", "Sair do compacto"}}, + {"选择", {"选择", "Select", "Выбрать", "選擇", "選択", "선택", "Auswählen", "Sélectionnez", "Seleccionar", "Selecione"}}, + {"选择公告查看详情", {"选择公告查看详情", "Select an announcement to read", "Выберите объявление для просмотра", "選擇公告檢視詳情", "読むお知らせを選択してください", "읽을 공지사항을 선택하세요.", "Wählen Sie eine Ankündigung zum Lesen aus", "Sélectionnez une annonce à lire", "Seleccione un anuncio para leer", "Selecione um anúncio para ler"}}, + {"选择分发文件", {"选择分发文件", "Select a file to send", "Выберите файл для отправки", "選擇分發檔案", "送信するファイルを選択する", "보낼 파일을 선택하세요", "Wählen Sie eine Datei zum Senden aus", "Sélectionnez un fichier à envoyer", "Seleccione un archivo para enviar", "Selecione um arquivo para enviar"}}, + {"选择文件发送", {"选择文件发送", "Select File to Send", "Выбрать файл для отправки", "選擇檔案傳送", "送信するファイルの選択", "보낼 파일 선택", "Wählen Sie die Datei zum Senden aus", "Sélectionnez le fichier à envoyer", "Seleccionar archivo para enviar", "Selecione o arquivo para enviar"}}, + {"选择显示器", {"选择显示器", "Select Display", "Выбрать дисплей", "選擇顯示器", "表示の選択", "디스플레이 선택", "Wählen Sie Anzeige", "Sélectionner l'affichage", "Seleccionar pantalla", "Selecionar exibição"}}, + {"通知", {"通知", "Notification", "Уведомление", "通知", "お知らせ", "알림", "Benachrichtigung", "Notification", "Notificación", "Notificação"}}, + {"通过 IP 连接过的设备会显示在这里。", {"通过 IP 连接过的设备会显示在这里。", "Devices you connect to by IP will appear here.", "Здесь появятся устройства, подключённые по IP.", "透過 IP 連線過的裝置會顯示在這裡。", "IP で接続するデバイスがここに表示されます。", "IP로 연결한 장치가 여기에 표시됩니다.", "Geräte, mit denen Sie über IP eine Verbindung herstellen, werden hier angezeigt.", "Les appareils auxquels vous vous connectez par IP apparaîtront ici.", "Los dispositivos a los que te conectas por IP aparecerán aquí.", "Os dispositivos aos quais você se conecta por IP aparecerão aqui."}}, + {"通过设备 ID 添加", {"通过设备 ID 添加", "Add by device ID", "Добавить по ID устройства", "透過裝置 ID 新增", "デバイスIDによる追加", "기기 ID로 추가", "Nach Geräte-ID hinzufügen", "Ajouter par ID d'appareil", "Agregar por ID de dispositivo", "Adicionar por ID do dispositivo"}}, + {"配置保存失败,请检查配置目录是否可写后重试。", {"配置保存失败,请检查配置目录是否可写后重试。", "Could not save settings. Check that the configuration directory is writable and retry.", "Не удалось сохранить настройки. Проверьте доступ на запись в каталог конфигурации и повторите попытку.", "配置儲存失敗,請檢查配置目錄是否可寫後重試。", "設定を保存できませんでした。構成ディレクトリが書き込み可能であることを確認して、再試行してください。", "설정을 저장할 수 없습니다. 구성 디렉터리가 쓰기 가능한지 확인하고 다시 시도하세요.", "Einstellungen konnten nicht gespeichert werden. Überprüfen Sie, ob das Konfigurationsverzeichnis beschreibbar ist, und versuchen Sie es erneut.", "Impossible d'enregistrer les paramètres. Vérifiez que le répertoire de configuration est accessible en écriture et réessayez.", "No se pudo guardar la configuración. Compruebe que se pueda escribir en el directorio de configuración y vuelva a intentarlo.", "Não foi possível salvar as configurações. Verifique se o diretório de configuração é gravável e tente novamente."}}, + {"采集方式", {"采集方式", "Capture Method", "Способ захвата", "採集方式", "捕獲方法", "캡처 방법", "Erfassungsmethode", "Méthode de capture", "Método de captura", "Método de Captura"}}, + {"释放操控", {"释放操控", "Release", "Отпустить", "釋放操控", "リリース", "출시", "Veröffentlichung", "Libération", "Lanzamiento", "Liberação"}}, + {"释放鼠标", {"释放鼠标", "Release Mouse", "Освободить мышь", "釋放滑鼠", "マウスを放します", "마우스 놓기", "Lassen Sie die Maus los", "Relâcher la souris", "Soltar el ratón", "Solte o mouse"}}, + {"重启后生效", {"重启后生效", "Takes effect after restart", "Вступит в силу после перезапуска", "重啟後生效", "再起動後に有効になります", "다시 시작하면 적용됩니다.", "Wird nach dem Neustart wirksam", "Prend effet après le redémarrage", "Entra en vigor después del reinicio", "Entra em vigor após reiniciar"}}, + {"重新连接", {"重新连接", "Reconnect", "Переподключиться", "重新連線", "再接続", "다시 연결", "Erneut verbinden", "Reconnecter", "Reconectar", "Reconectar"}}, + {"重新连接确认:新密码已生效。", {"重新连接确认:新密码已生效。", "Reconnection confirmed: the new password is active.", "Повторное подключение подтвердило новый пароль.", "重新連線確認:新密碼已生效。", "再接続が確認されました: 新しいパスワードが有効です。", "재연결 확인됨: 새 비밀번호가 활성화되었습니다.", "Wiederverbindung bestätigt: Das neue Passwort ist aktiv.", "Reconnexion confirmée : le nouveau mot de passe est actif.", "Reconexión confirmada: la nueva contraseña está activa.", "Reconexão confirmada: a nova senha está ativa."}}, + {"重新连接确认:继续使用原密码。", {"重新连接确认:继续使用原密码。", "Reconnection confirmed: the original password remains active.", "Повторное подключение подтвердило прежний пароль.", "重新連線確認:繼續使用原密碼。", "再接続が確認されました: 元のパスワードは有効のままです。", "재연결 확인됨: 원래 비밀번호가 활성 상태로 유지됩니다.", "Wiederverbindung bestätigt: Das ursprüngliche Passwort bleibt aktiv.", "Reconnexion confirmée : le mot de passe d'origine reste actif.", "Reconexión confirmada: la contraseña original permanece activa.", "Reconexão confirmada: a senha original permanece ativa."}}, + {"锁定", {"锁定", "Lock", "Заблокировать", "鎖定", "ロック", "잠금", "Sperren", "Verrouillage", "Bloquear", "Bloqueio"}}, + {"锁定远端", {"锁定远端", "Lock Remote", "Заблокировать удалённое устройство", "鎖定遠端", "リモコンをロックする", "원격 잠금", "Fernbedienung sperren", "Verrouillage à distance", "Bloquear control remoto", "Bloquear remoto"}}, + {"锁屏控制服务", {"锁屏控制服务", "Lock-screen control service", "Служба управления при блокировке", "鎖屏控制服務", "ロック画面コントロールサービス", "잠금화면 제어 서비스", "Sperrbildschirm-Steuerungsdienst", "Service de contrôle de l'écran de verrouillage", "Servicio de control de pantalla de bloqueo", "Serviço de controle de tela de bloqueio"}}, + {"队列中", {"队列中", "Queued", "В очереди", "佇列中", "キューに入れられました", "대기 중", "In der Warteschlange", "En file d'attente", "En cola", "Na fila"}}, + {"隐私保护", {"隐私保护", "Privacy", "Приватность", "隱私保護", "プライバシー", "개인 정보 보호", "Datenschutz", "Confidentialité", "Privacidad", "Privacidade"}}, + {"隐私屏", {"隐私屏", "Privacy screen", "Приватный экран", "隱私屏", "プライバシー画面", "개인정보 보호 화면", "Sichtschutz", "Écran de confidentialité", "Pantalla de privacidad", "Tela de privacidade"}}, + {"隐私屏已开启,本机解锁已禁用", {"隐私屏已开启,本机解锁已禁用", "Privacy screen is on. Local unlocking is disabled.", "Приватный экран включён. Локальная разблокировка отключена.", "隱私屏已開啟,本機解鎖已禁用", "プライバシー画面がオンになっています。ローカルのロック解除は無効になっています。", "개인정보 보호 화면이 켜져 있습니다. 로컬 잠금 해제가 비활성화되었습니다.", "Der Datenschutzbildschirm ist aktiviert. Die lokale Entsperrung ist deaktiviert.", "L'écran de confidentialité est activé. Le déverrouillage local est désactivé.", "La pantalla de privacidad está activada. El desbloqueo local está deshabilitado.", "A tela de privacidade está ativada. O desbloqueio local está desativado."}}, + {"隐私屏已被解锁", {"隐私屏已被解锁", "Privacy screen unlocked", "Приватный экран разблокирован", "隱私屏已被解鎖", "プライバシー画面のロックが解除されました", "개인정보 보호 화면 잠금 해제됨", "Datenschutzbildschirm entsperrt", "Écran de confidentialité déverrouillé", "Pantalla de privacidad desbloqueada", "Tela de privacidade desbloqueada"}}, + {"隐私屏:不可用", {"隐私屏:不可用", "Privacy screen: unavailable", "Приватный экран: недоступен", "隱私屏:不可用", "プライバシー画面:使用不可", "개인 정보 보호 화면: 사용할 수 없음", "Datenschutzbildschirm: nicht verfügbar", "Écran de confidentialité : indisponible", "Pantalla de privacidad: no disponible", "Tela de privacidade: indisponível"}}, + {"隐私屏:已关闭", {"隐私屏:已关闭", "Privacy screen: off", "Приватный экран: выключен", "隱私屏:已關閉", "プライバシー画面:オフ", "개인정보 보호 화면: 꺼짐", "Datenschutzbildschirm: aus", "Écran de confidentialité : désactivé", "Pantalla de privacidad: desactivada", "Tela de privacidade: desativada"}}, + {"隐私屏:已开启", {"隐私屏:已开启", "Privacy screen: on", "Приватный экран: включён", "隱私屏:已開啟", "プライバシー画面:オン", "개인정보 보호 화면: 켜짐", "Datenschutzbildschirm: ein", "Écran de confidentialité : activé", "Pantalla de privacidad: activada", "Tela de privacidade: ativada"}}, + {"隐藏密码", {"隐藏密码", "Hide password", "Скрыть пароль", "隱藏密碼", "パスワードを隠す", "비밀번호 숨기기", "Passwort verbergen", "Masquer le mot de passe", "Ocultar contraseña", "Ocultar senha"}}, + {"隐藏网络状态", {"隐藏网络状态", "Hide network status", "Скрыть состояние сети", "隱藏網路狀態", "ネットワークステータスを非表示にする", "네트워크 상태 숨기기", "Netzwerkstatus ausblenden", "Masquer l'état du réseau", "Ocultar estado de la red", "Ocultar status da rede"}}, + {"需要密码", {"需要密码", "Password required", "Нужен пароль", "需要密碼", "パスワードが必要です", "비밀번호가 필요합니다", "Passwort erforderlich", "Mot de passe requis", "Se requiere contraseña", "Senha necessária"}}, + {"静音", {"静音", "Mute", "Без звука", "靜音", "ミュート", "음소거", "Stumm", "Muet", "Silencio", "Mudo"}}, + {"音频", {"音频", "Audio", "Аудио", "音訊", "オーディオ", "오디오", "Audio", "Audio", "Audio", "Áudio"}}, + {"项目主页", {"项目主页", "Project website", "Сайт проекта", "專案主頁", "プロジェクトWebサイト", "프로젝트 홈페이지", "Projektwebsite", "Site Web du projet", "Sitio web del proyecto", "Site do projeto"}}, + {"验证密码中...", {"验证密码中...", "Validating password...", "Проверка пароля...", "驗證密碼中...", "パスワードを検証中...", "비밀번호 확인 중...", "Passwort wird validiert...", "Validation du mot de passe...", "Validando contraseña...", "Validando senha..."}}, + {"验证尝试过于频繁,请稍后重试。", {"验证尝试过于频繁,请稍后重试。", "Too many authentication attempts. Try again later.", "Слишком много попыток аутентификации. Повторите позже.", "驗證嘗試過於頻繁,請稍後重試。", "認証試行が多すぎます。後でもう一度試してください。", "인증 시도 횟수가 너무 많습니다. 나중에 다시 시도하세요.", "Zu viele Authentifizierungsversuche. Versuchen Sie es später noch einmal.", "Trop de tentatives d'authentification. Réessayez plus tard.", "Demasiados intentos de autenticación. Vuelve a intentarlo más tarde.", "Muitas tentativas de autenticação. Tente novamente mais tarde."}}, + {"高", {"高", "High", "Высокое", "高", "高", "높음", "Hoch", "Élevée", "Alta", "Alta"}}, + {"(仅在交互终端显示)", {"(仅在交互终端显示)", "(shown only in an interactive terminal)", "(виден только в интерактивном терминале)", "(僅在互動終端顯示)", "(対話型端末でのみ表示)", "(대화형 터미널에만 표시됨)", "(wird nur in einem interaktiven Terminal angezeigt)", "(affiché uniquement dans un terminal interactif)", "(se muestra solo en una terminal interactiva)", "(mostrado apenas em um terminal interativo)"}}, + {":同步键鼠到所有已连接设备", {":同步键鼠到所有已连接设备", ": mirror input to all connected devices", ": ввод на всех подключённых устройствах", ":同步鍵鼠到所有已連線裝置", ": 接続されているすべてのデバイスへのミラー入力", ": 연결된 모든 장치에 대한 미러 입력", ": Eingang auf alle angeschlossenen Geräte spiegeln", ": entrée miroir sur tous les appareils connectés", ": entrada espejo para todos los dispositivos conectados", ": entrada espelhada para todos os dispositivos conectados"}}, }; +struct NamedTranslation { const char* name; const char* literal; }; +inline constexpr NamedTranslation kNamedTranslations[] = { + {"window_minimize", "最小化"}, + {"window_maximize", "最大化"}, + {"window_restore", "还原窗口"}, + {"window_close", "关闭窗口"}, + {"save", "保存"}, + {"copyright_notice", "© 2026 JUNKUN DI。保留所有权利。"}, + {"license_notice", "依据 GNU GPL v3 许可发布。"}, + {"messages", "消息"}, + {"message_unread", "未读"}, + {"message_read", "已读"}, + {"message_read_all", "全部已读"}, + {"message_empty", "暂无公告"}, + {"message_select", "选择公告查看详情"}, + {"message_loading", "正在加载…"}, + {"message_read_save_error", "无法保存本地阅读状态,请重试。"}, + {"message_close", "关闭"}, + {"message_delete", "删除"}, + {"message_delete_title", "删除公告"}, + {"message_delete_confirmation", "删除这条公告?"}, + {"message_delete_error", "无法删除这条公告,请重试。"}, + {"console_cli_help", "Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n"}, + {"console_title", "CrossDesk 无头控制台"}, + {"console_log_file", "日志文件"}, + {"console_help", "命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出"}, + {"console_status", "状态"}, + {"console_online", "在线"}, + {"console_offline", "未连接服务器"}, + {"console_id", "设备 ID"}, + {"console_password", "连接密码"}, + {"console_waiting", "等待分配"}, + {"console_password_hidden", "(仅在交互终端显示)"}, + {"console_cancelled", "已取消修改。"}, + {"console_password_invalid", "密码必须是6位英文字母或数字,未提交修改。"}, + {"console_password_offline", "尚未连接服务器,暂时无法修改密码。"}, + {"console_password_prompt", "输入新密码(6位英文字母或数字;输入 cancel 取消):"}, + {"console_quitting", "正在退出 CrossDesk……"}, + {"console_unknown_command", "未知命令,输入 help 查看帮助。"}, + {"console_line_too_long", "命令过长,已忽略。"}, + {"console_random_failed", "无法生成随机密码,请重试。"}, + {"console_password_pending", "密码修改正在处理中,请等待服务器确认。"}, + {"console_password_stage_failed", "无法保存密码修改记录,未提交修改。请检查日志。"}, + {"console_password_send_failed", "发送密码修改请求失败,请等待连接恢复后重试。"}, + {"console_password_submitted", "已提交密码修改,正在等待服务器确认……"}, + {"console_password_uncertain", "密码修改结果尚未确认,正在重新连接服务器核实。"}, + {"console_password_rejected", "服务器未接受密码修改,原密码保持不变。详情见日志。"}, + {"console_password_confirmed", "服务器已确认密码修改,正在重新连接。"}, + {"console_password_recovered", "重新连接确认:新密码已生效。"}, + {"console_password_retained", "重新连接确认:继续使用原密码。"}, + {"console_exited", "CrossDesk 已退出。"}, + {"console_stopped", "CrossDesk 已停止,退出码"}, + {"console_settings_title", "设置(修改后立即保存)"}, + {"console_settings_prompt", "输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。"}, + {"console_settings_value", "输入新值(cancel 取消)"}, + {"console_settings_unavailable", "设置尚未初始化,请稍后重试。"}, + {"console_settings_invalid", "无效的选项或值,未保存。请按菜单列出的格式输入。"}, + {"console_settings_save_failed", "保存设置失败,原设置保持不变。请检查日志。"}, + {"console_settings_busy", "有远程会话或密码修改正在进行,暂时不能更改连接设置。"}, + {"console_settings_saved", "已保存并生效。"}, + {"console_settings_unchanged", "设置未改变。"}, + {"console_settings_reconnect", "已保存,正在重新连接服务器。"}, + {"console_settings_next_connection", "已保存,将用于后续连接。"}, + {"console_settings_next_file", "已保存,将用于后续接收的文件。"}, + {"console_settings_autostart", "已保存,在下次图形桌面登录时生效。"}, + {"console_settings_daemon", "已保存,普通模式重启后生效;无头控制台仍保持前台运行。"}, + {"console_settings_server_required", "请先设置有效的服务器地址和端口,再启用自托管。"}, + {"console_settings_path_invalid", "请选择已存在且可写的绝对目录路径;default 使用默认目录。"}, + {"console_settings_readonly", "该选项由系统或控制端管理,不可在此修改。"}, + {"console_setting_language", "语言"}, + {"console_setting_codec", "视频编码"}, + {"console_setting_turn", "中继模式"}, + {"console_setting_self_hosted", "自托管"}, + {"console_setting_host", "服务器地址"}, + {"console_setting_port", "信令端口"}, + {"console_setting_privacy", "连接时自动开启隐私屏"}, + {"console_setting_files", "文件保存目录"}, + {"console_setting_autostart", "登录桌面时自启"}, + {"console_setting_daemon", "守护进程(无头控制台中不生效)"}, + {"save_remote_previews", "保存远程画面预览"}, + {"unknown_platform", "未知平台"}, + {"privacy_screen", "隐私屏"}, + {"privacy_enable", "开启隐私屏"}, + {"privacy_disable", "关闭隐私屏"}, + {"privacy_on", "隐私屏:已开启"}, + {"privacy_off", "隐私屏:已关闭"}, + {"privacy_unsupported", "隐私屏:不可用"}, + {"local_desktop", "本桌面"}, + {"local_id", "本机 ID"}, + {"local_id_copied_to_clipboard", "已复制到剪贴板"}, + {"password", "密码"}, + {"refresh_password", "刷新随机密码"}, + {"password_format_invalid", "密码必须为 6 位英文字母或数字。"}, + {"remote_desktop", "远程桌面"}, + {"device_name", "设备名称"}, + {"remote_id", "对端 ID"}, + {"connect", "连接"}, + {"recent_connections", "近期连接"}, + {"disconnect", "断开连接"}, + {"stream_confirm_disconnect", "断开当前连接?"}, + {"stream_disconnect_description", "当前远程控制会话将结束。"}, + {"select_display", "选择显示器"}, + {"display_screen", "显示屏"}, + {"expand_control_bar", "展开控制栏"}, + {"collapse_control_bar", "收起控制栏"}, + {"fullscreen", "全屏"}, + {"show_net_traffic_stats", "显示网络状态"}, + {"hide_net_traffic_stats", "隐藏网络状态"}, + {"video", "视频"}, + {"audio", "音频"}, + {"data", "数据"}, + {"total", "总计"}, + {"in", "输入"}, + {"out", "输出"}, + {"loss_rate", "丢包率"}, + {"exit_fullscreen", "退出全屏"}, + {"control_mouse", "控制鼠标"}, + {"release_mouse", "释放鼠标"}, + {"audio_capture", "播放声音"}, + {"mute", "静音"}, + {"send_shortcut", "发送组合键"}, + {"send_sas", "发送 SAS"}, + {"lock_remote", "锁定远端"}, + {"remote_password_box_visible", "远端密码框已出现"}, + {"remote_lock_screen_hint", "远端处于锁屏封面,可发送 SAS"}, + {"remote_secure_desktop_active", "远端已进入安全桌面"}, + {"remote_service_unavailable", "远端 Windows 服务不可用"}, + {"windows_service_setup_title", "安装 CrossDesk Service"}, + {"windows_service_setup_message", "为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk Service。\n未安装该服务不影响 CrossDesk 正常使用,仅无法在锁屏状态下控制本机。"}, + {"install_windows_service", "安装"}, + {"windows_service_settings_label", "锁屏控制服务"}, + {"windows_service_installed", "已安装"}, + {"do_not_remind_again", "不再提醒"}, + {"windows_service_prompt_suppressed_message", "已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。"}, + {"installing_windows_service", "正在安装服务..."}, + {"windows_service_install_success", "服务已安装并启动"}, + {"windows_service_install_failed", "服务安装失败。请确认 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位于同一便携目录中,并在系统弹窗中允许管理员权限。"}, + {"remote_unlock_requires_secure_desktop", "当前仍需要安全桌面专用采集/输入"}, + {"settings", "设置"}, + {"language", "语言"}, + {"screen_capture_method", "采集方式"}, + {"screen_capture_method_auto", "自动"}, + {"video_settings", "画面设置"}, + {"remote_update_title", "建议升级被控端"}, + {"remote_update", "新版本包含功能改进和性能优化,建议将被控端升级至最新版本。"}, + {"remote_update_dismiss", "知道了"}, + {"video_settings_pending", "正在应用…"}, + {"video_settings_failed", "调整失败,请重试。"}, + {"video_settings_unavailable", "连接建立后可调整,需被控端支持。"}, + {"video_quality", "画面质量"}, + {"video_frame_rate", "画面采集帧率"}, + {"video_adaptation_policy", "画面偏好"}, + {"video_priority_frame_rate", "帧率优先"}, + {"video_priority_quality", "画质优先"}, + {"video_priority_balanced", "平衡"}, + {"video_quality_high", "高"}, + {"video_quality_medium", "中"}, + {"video_quality_low", "低"}, + {"video_encode_format", "视频编码格式"}, + {"av1", "AV1"}, + {"h264", "H.264"}, + {"force_relay", "强制中继连接"}, + {"self_hosted_server_config", "自托管配置"}, + {"self_hosted_server_settings", "自托管设置"}, + {"self_hosted_server_address", "服务器地址"}, + {"self_hosted_server_port", "信令服务端口"}, + {"self_hosted_address_invalid", "请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。"}, + {"self_hosted_port_invalid", "请输入 1–65535 范围内的信令端口。"}, + {"self_hosted_save_failed", "配置保存失败,请检查配置目录是否可写后重试。"}, + {"ok", "确认"}, + {"cancel", "取消"}, + {"new_password", "请输入六位密码:"}, + {"input_password", "请输入密码:"}, + {"validate_password", "验证密码中..."}, + {"reinput_password", "请重新输入密码"}, + {"remember_password", "记住密码"}, + {"signal_connected", "已连接服务器"}, + {"signal_disconnected", "未连接服务器"}, + {"signal_reconnect", "重新连接"}, + {"signal_reconnecting", "正在重新连接..."}, + {"signal_tls_cert_error", "证书验证失败,请重新安装自托管根证书"}, + {"p2p_connected", "对等连接已建立"}, + {"p2p_disconnected", "对等连接已断开"}, + {"p2p_connecting", "正在建立对等连接..."}, + {"p2p_gathering", "正在收集候选地址..."}, + {"receiving_screen", "画面接收中..."}, + {"p2p_failed", "对等连接失败"}, + {"connection_auth_throttled", "验证尝试过于频繁,请稍后重试。"}, + {"connection_service_busy", "认证服务繁忙,请稍后重试。"}, + {"connection_not_authenticated", "登录状态已失效,请重新连接。"}, + {"connection_retry_after", "请在 %d 秒后重试。"}, + {"p2p_closed", "对等连接已关闭"}, + {"no_such_id", "无此 ID"}, + {"about", "关于"}, + {"sponsorship_title", "赞助支持"}, + {"sponsorship_message", "如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!"}, + {"sponsorship_dismiss_hint", "关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。"}, + {"sponsor_via_afdian", "爱发电"}, + {"notification", "通知"}, + {"new_version", "新版本"}, + {"new_version_available", "新版本可用"}, + {"check_for_updates", "检查更新"}, + {"checking_for_updates", "正在检查更新…"}, + {"up_to_date", "已是最新版本"}, + {"update_check_failed", "检查失败,请稍后重试"}, + {"release_notes", "更新内容"}, + {"view_release_notes", "更新日志"}, + {"version", "版本"}, + {"release_date", "发布日期: "}, + {"access_website", "访问官网: "}, + {"update", "更新"}, + {"install_update", "安装更新"}, + {"manual_download", "手动下载"}, + {"install_update_confirm", "下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?"}, + {"update_preparing", "正在准备更新…"}, + {"update_install_failed", "更新未完成,可重试或手动安装。"}, + {"connection_alias", "修改名称"}, + {"delete_connection", "删除连接"}, + {"connect_to_this_connection", "发起连接"}, + {"input_connection_alias", "请输入连接名称:"}, + {"confirm_delete_connection", "确认删除此连接"}, + {"enable_autostart", "开机自启"}, + {"enable_daemon", "启用守护进程"}, + {"privacy_on_connect", "被连接时开启隐私屏"}, + {"lock_on_disconnect", "连接断开后锁屏"}, + {"takes_effect_after_restart", "重启后生效"}, + {"select_file", "选择文件发送"}, + {"file_transfer_progress", "文件传输进度"}, + {"file_sending_progress", "文件发送进度"}, + {"file_receiving_progress", "文件接收进度"}, + {"queued", "队列中"}, + {"sending", "正在传输"}, + {"receiving", "正在接收"}, + {"completed", "已完成"}, + {"failed", "失败"}, + {"cancelling", "正在取消"}, + {"cancelled", "已取消"}, + {"controller", "控制端:"}, + {"server_controlled", "被控中"}, + {"server_heading", "此设备被控中"}, + {"server_connected", "已连接"}, + {"server_send_file", "发送文件"}, + {"server_disconnect", "断开"}, + {"server_disconnect_all", "全部断开"}, + {"server_confirm_disconnect", "断开所有控制端的连接?"}, + {"file_transfer", "文件传输:"}, + {"connection_status", "连接状态:"}, + {"file_transfer_save_path", "文件接收保存路径"}, + {"default_desktop", "桌面"}, + {"resolution", "分辨率"}, + {"video_latency", "视频延时"}, + {"connection_latency", "连接延时"}, + {"connection_mode", "连接模式"}, + {"connection_mode_direct", "直连"}, + {"connection_mode_relay", "中继"}, + {"transport_encryption", "加密传输"}, + {"remote_video_encoder", "被控端编码器"}, + {"local_video_decoder", "控制端解码器"}, + {"transport_encryption_enabled", "已开启"}, + {"transport_encryption_disabled", "未开启"}, + {"online", "在线"}, + {"offline", "离线"}, + {"device_offline", "设备离线"}, + {"request_permissions", "权限请求"}, + {"screen_recording_permission", "屏幕录制权限"}, + {"accessibility_permission", "辅助功能权限"}, + {"permission_required_message", "该应用需要授权以下权限:"}, + {"wayland_notice_title", "Wayland 会话提示"}, + {"wayland_notice_subtitle", "检测到当前桌面会话使用 Wayland。"}, + {"wayland_permission_title", "每次共享均需本机授权"}, + {"wayland_notice_message", "受 Wayland 安全机制限制,每次启动远程桌面共享时,均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。"}, + {"wayland_recommendation_title", "建议使用 X11(Xorg)"}, + {"wayland_recommendation_message", "为便于持续使用远程桌面,建议注销当前桌面会话,在登录界面选择 X11(Xorg)会话后重新登录。"}, + {"wayland_notice_acknowledge", "我知道了"}, + {"show_main_window", "显示主界面"}, + {"privacy_local_unlock", "允许被控时解锁隐私屏"}, + {"privacy_screen_locked_hint", "隐私屏已开启,本机解锁已禁用"}, + {"privacy_unlocked_title", "隐私屏已被解锁"}, + {"privacy_unlocked_message", "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。"}, + {"privacy_unlock_confirm", "确认"}, + {"privacy_unlock_lock", "锁定"}, + {"privacy_screen_unlock_hint", "按下快捷键,解除隐私屏"}, + {"exit_program", "退出"}, + {"shutdown_reason", "远程控制连接中,保留连接以确认或取消关机。"}, +}; +inline constexpr const char* kSlintLiterals[] = { + "此端口已被占用,", + "请更换端口。", + "原设置已保留。", + "无法确认此端口是否可用,", + "请重试或检查本机防火墙。", + "无法使用此端口,", + "请选择其他端口或检查系统权限。", + "未找到可用的局域网连接。", + "请连接 Wi-Fi 或网线,", + "或在主界面选择本机 IP。", + "", + "密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。", + "尝试次数过多,请等待倒计时结束后重试。", + "对方密码已更新,请使用新密码重试。", + "设备正忙,请稍后重试。", + "访问密码必须为 6 位英文字母或数字,区分大小写。", + "无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。", + "请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。", + "请输入 1–65535 之间的整数端口。", + "请点击主界面密码旁的修改按钮设置密码。", + "IP 连接数量已达上限,请先断开部分连接后重试。", + "当前网络路径不支持 IP 连接,请检查双方的局域网连接。", + "双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。", + "无法验证对方设备的身份,请确认连接地址和对方设备后重试。", + "无法建立加密连接,请检查双方网络并重试。", + "连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。", + "连接地址或监听端口已更改,请确认最新地址后重试。", + "无法准备远程会话,请稍后重试。", + "复制失败,请重试。", + "IP 连接操作失败,详情:", + "修改分组", + "未分组", + "新建分组(可选)", + "取消", + "保存", + "修改名称", + "断开", + "连接", + "待确认", + "已加密", + "未加密", + "画面", + "收发速率", + "视频延时", + "丢包 ", + "被控端编码器 ", + "控制端解码器 ", + "暂无已连接设备", + "建立连接后,网络和画面信息将在此显示", + "设备网络状态", + "关闭", + "已连接设备 ", + " 台", + "设备 / ID", + "桌面墙", + "请输入有效的 IPv4 或 IPv4:端口", + "正在连接…", + "全部设备", + "正在读取…", + "已开启", + "未开启", + "设备不支持", + "读取失败", + "切换到 ID 连接模式", + "切换到 IP 连接模式", + "IP 连接模式", + "IP 连接", + "ID 连接", + "更多", + "将 IP 和密码分享给连接方", + "将 ID 和密码分享给连接方", + "本机 IP / 端口", + "切换 IP", + "修改端口", + "切换本机 IP", + "局域网端口", + "复制 IP 和端口", + "复制本机 ID", + "点击切换本机 IP", + "点击修改端口", + "隐藏密码", + "显示密码", + "修改密码", + "输入 IP:端口,通过局域网连接", + "输入设备 ID,连接远程桌面", + "远端 IP / 端口", + "请输入 9 位设备 ID", + "不填端口时,默认使用 52888", + "暂无近期 IP 连接", + "暂无近期连接", + "该分组暂无近期连接", + "通过 IP 连接过的设备会显示在这里。", + "连接过的设备会显示在这里,方便下次快速访问。", + "切换设备分组,查看其他连接记录。", + "更多操作", + "删除记录", + "断开连接", + "IP 连接已启用", + "IP 连接准备中…", + "IP 连接未就绪", + "未知", + "分组", + "复制失败,请重试", + "IP 和端口已复制", + "从当前分组移除此设备?", + "从桌面墙移除此设备?", + "确认断开连接?", + "当前远程控制会话将结束。", + "允许远程键盘和鼠标控制", + "允许共享此 Mac 的屏幕画面", + "前往设置", + "已授权", + "请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。", + "常规", + "界面", + "视频", + "网络连接", + "启用 IP 连接", + "编辑", + "关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。", + "隐私保护", + "最后一个远程控制端断开后,自动锁定本机。", + "本地存储", + "启动与后台", + "设置开机自启动", + "当前设备不支持开机自启动。", + "无法读取系统状态。请刷新重试,或在系统设置中核对。", + "请在系统设置中添加或移除本应用,返回后会自动刷新状态。", + "设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。", + "刷新状态", + "软件许可", + "开源组件", + "源码与构建说明", + "许可与版权声明", + "查看源码", + "返回", + "以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", + "OpenFEC 告知", + "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", + "OpenFEC 许可与源码", + "本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", + "源码版本:", + "本版本源码信息暂不可用。", + "构建说明", + "项目主页", + "画面传输", + "分辨率上限", + "自动", + "原始分辨率", + "帧率", + "跟随设备设置", + "视频总带宽", + " 台已连接", + "添加", + "通过设备 ID 添加", + "从近期连接添加", + "已选 ", + "跨页 ", + "取消全选", + "全选", + "取消静音", + "静音", + "分发文件", + "选择", + "完成", + "拖动表格分隔线,同步调整所有设备大小", + "在线", + "离线", + "从桌面墙移除", + "暂无设备,退出精简模式后可添加", + "添加设备,建立你的桌面墙", + "群控中", + "正在操控", + "只读预览", + "关闭群控", + "开启群控", + ":同步键鼠到所有已连接设备", + "释放操控", + "接管操控", + "上下拖动,调整缩略图与主画面大小", + "群控中 · 所有已连接设备", + "网络状态", + "退出精简", + "精简模式", + "退出全屏", + "全屏", + "停留翻页,松开取消", + "松开鼠标交换位置", + "拖到另一台设备上", + "换位未保存,请重试", + "添加设备", + "设备 ID", + "9 位设备 ID", + "密码", + "设备连接密码", + "分组名称(可选)", + "记住密码", + "添加并连接", + "加入桌面墙后,可通过批量选择连接", + "待添加 ", + "已添加", + "加入桌面墙", + "已连接", + "未连接", + "确认断开", + "确认执行", +}; } // namespace detail +#define CROSSDESK_LOCALIZATION_ALL(X) \ + X(window_minimize) \ + X(window_maximize) \ + X(window_restore) \ + X(window_close) \ + X(save) \ + X(copyright_notice) \ + X(license_notice) \ + X(messages) \ + X(message_unread) \ + X(message_read) \ + X(message_read_all) \ + X(message_empty) \ + X(message_select) \ + X(message_loading) \ + X(message_read_save_error) \ + X(message_close) \ + X(message_delete) \ + X(message_delete_title) \ + X(message_delete_confirmation) \ + X(message_delete_error) \ + X(console_cli_help) \ + X(console_title) \ + X(console_log_file) \ + X(console_help) \ + X(console_status) \ + X(console_online) \ + X(console_offline) \ + X(console_id) \ + X(console_password) \ + X(console_waiting) \ + X(console_password_hidden) \ + X(console_cancelled) \ + X(console_password_invalid) \ + X(console_password_offline) \ + X(console_password_prompt) \ + X(console_quitting) \ + X(console_unknown_command) \ + X(console_line_too_long) \ + X(console_random_failed) \ + X(console_password_pending) \ + X(console_password_stage_failed) \ + X(console_password_send_failed) \ + X(console_password_submitted) \ + X(console_password_uncertain) \ + X(console_password_rejected) \ + X(console_password_confirmed) \ + X(console_password_recovered) \ + X(console_password_retained) \ + X(console_exited) \ + X(console_stopped) \ + X(console_settings_title) \ + X(console_settings_prompt) \ + X(console_settings_value) \ + X(console_settings_unavailable) \ + X(console_settings_invalid) \ + X(console_settings_save_failed) \ + X(console_settings_busy) \ + X(console_settings_saved) \ + X(console_settings_unchanged) \ + X(console_settings_reconnect) \ + X(console_settings_next_connection) \ + X(console_settings_next_file) \ + X(console_settings_autostart) \ + X(console_settings_daemon) \ + X(console_settings_server_required) \ + X(console_settings_path_invalid) \ + X(console_settings_readonly) \ + X(console_setting_language) \ + X(console_setting_codec) \ + X(console_setting_turn) \ + X(console_setting_self_hosted) \ + X(console_setting_host) \ + X(console_setting_port) \ + X(console_setting_privacy) \ + X(console_setting_files) \ + X(console_setting_autostart) \ + X(console_setting_daemon) \ + X(save_remote_previews) \ + X(unknown_platform) \ + X(privacy_screen) \ + X(privacy_enable) \ + X(privacy_disable) \ + X(privacy_on) \ + X(privacy_off) \ + X(privacy_unsupported) \ + X(local_desktop) \ + X(local_id) \ + X(local_id_copied_to_clipboard) \ + X(password) \ + X(refresh_password) \ + X(password_format_invalid) \ + X(remote_desktop) \ + X(device_name) \ + X(remote_id) \ + X(connect) \ + X(recent_connections) \ + X(disconnect) \ + X(stream_confirm_disconnect) \ + X(stream_disconnect_description) \ + X(select_display) \ + X(display_screen) \ + X(expand_control_bar) \ + X(collapse_control_bar) \ + X(fullscreen) \ + X(show_net_traffic_stats) \ + X(hide_net_traffic_stats) \ + X(video) \ + X(audio) \ + X(data) \ + X(total) \ + X(in) \ + X(out) \ + X(loss_rate) \ + X(exit_fullscreen) \ + X(control_mouse) \ + X(release_mouse) \ + X(audio_capture) \ + X(mute) \ + X(send_shortcut) \ + X(send_sas) \ + X(lock_remote) \ + X(remote_password_box_visible) \ + X(remote_lock_screen_hint) \ + X(remote_secure_desktop_active) \ + X(remote_service_unavailable) \ + X(windows_service_setup_title) \ + X(windows_service_setup_message) \ + X(install_windows_service) \ + X(windows_service_settings_label) \ + X(windows_service_installed) \ + X(do_not_remind_again) \ + X(windows_service_prompt_suppressed_message) \ + X(installing_windows_service) \ + X(windows_service_install_success) \ + X(windows_service_install_failed) \ + X(remote_unlock_requires_secure_desktop) \ + X(settings) \ + X(language) \ + X(screen_capture_method) \ + X(screen_capture_method_auto) \ + X(video_settings) \ + X(remote_update_title) \ + X(remote_update) \ + X(remote_update_dismiss) \ + X(video_settings_pending) \ + X(video_settings_failed) \ + X(video_settings_unavailable) \ + X(video_quality) \ + X(video_frame_rate) \ + X(video_adaptation_policy) \ + X(video_priority_frame_rate) \ + X(video_priority_quality) \ + X(video_priority_balanced) \ + X(video_quality_high) \ + X(video_quality_medium) \ + X(video_quality_low) \ + X(video_encode_format) \ + X(av1) \ + X(h264) \ + X(force_relay) \ + X(self_hosted_server_config) \ + X(self_hosted_server_settings) \ + X(self_hosted_server_address) \ + X(self_hosted_server_port) \ + X(self_hosted_address_invalid) \ + X(self_hosted_port_invalid) \ + X(self_hosted_save_failed) \ + X(ok) \ + X(cancel) \ + X(new_password) \ + X(input_password) \ + X(validate_password) \ + X(reinput_password) \ + X(remember_password) \ + X(signal_connected) \ + X(signal_disconnected) \ + X(signal_reconnect) \ + X(signal_reconnecting) \ + X(signal_tls_cert_error) \ + X(p2p_connected) \ + X(p2p_disconnected) \ + X(p2p_connecting) \ + X(p2p_gathering) \ + X(receiving_screen) \ + X(p2p_failed) \ + X(connection_auth_throttled) \ + X(connection_service_busy) \ + X(connection_not_authenticated) \ + X(connection_retry_after) \ + X(p2p_closed) \ + X(no_such_id) \ + X(about) \ + X(sponsorship_title) \ + X(sponsorship_message) \ + X(sponsorship_dismiss_hint) \ + X(sponsor_via_afdian) \ + X(notification) \ + X(new_version) \ + X(new_version_available) \ + X(check_for_updates) \ + X(checking_for_updates) \ + X(up_to_date) \ + X(update_check_failed) \ + X(release_notes) \ + X(view_release_notes) \ + X(version) \ + X(release_date) \ + X(access_website) \ + X(update) \ + X(install_update) \ + X(manual_download) \ + X(install_update_confirm) \ + X(update_preparing) \ + X(update_install_failed) \ + X(connection_alias) \ + X(delete_connection) \ + X(connect_to_this_connection) \ + X(input_connection_alias) \ + X(confirm_delete_connection) \ + X(enable_autostart) \ + X(enable_daemon) \ + X(privacy_on_connect) \ + X(lock_on_disconnect) \ + X(takes_effect_after_restart) \ + X(select_file) \ + X(file_transfer_progress) \ + X(file_sending_progress) \ + X(file_receiving_progress) \ + X(queued) \ + X(sending) \ + X(receiving) \ + X(completed) \ + X(failed) \ + X(cancelling) \ + X(cancelled) \ + X(controller) \ + X(server_controlled) \ + X(server_heading) \ + X(server_connected) \ + X(server_send_file) \ + X(server_disconnect) \ + X(server_disconnect_all) \ + X(server_confirm_disconnect) \ + X(file_transfer) \ + X(connection_status) \ + X(file_transfer_save_path) \ + X(default_desktop) \ + X(resolution) \ + X(video_latency) \ + X(connection_latency) \ + X(connection_mode) \ + X(connection_mode_direct) \ + X(connection_mode_relay) \ + X(transport_encryption) \ + X(remote_video_encoder) \ + X(local_video_decoder) \ + X(transport_encryption_enabled) \ + X(transport_encryption_disabled) \ + X(online) \ + X(offline) \ + X(device_offline) \ + X(request_permissions) \ + X(screen_recording_permission) \ + X(accessibility_permission) \ + X(permission_required_message) \ + X(wayland_notice_title) \ + X(wayland_notice_subtitle) \ + X(wayland_permission_title) \ + X(wayland_notice_message) \ + X(wayland_recommendation_title) \ + X(wayland_recommendation_message) \ + X(wayland_notice_acknowledge) \ + X(show_main_window) \ + X(privacy_local_unlock) \ + X(privacy_screen_locked_hint) \ + X(privacy_unlocked_title) \ + X(privacy_unlocked_message) \ + X(privacy_unlock_confirm) \ + X(privacy_unlock_lock) \ + X(privacy_screen_unlock_hint) \ + X(exit_program) \ + X(shutdown_reason) + } // namespace localization } // namespace crossdesk diff --git a/apps/desktop/src/gui/assets/localization/system_language.h b/apps/desktop/src/gui/assets/localization/system_language.h new file mode 100644 index 00000000..7954c0d1 --- /dev/null +++ b/apps/desktop/src/gui/assets/localization/system_language.h @@ -0,0 +1,111 @@ +/* + * @Author: DI JUNKUN + * @Date: 2026-10-27 + * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _SYSTEM_LANGUAGE_H_ +#define _SYSTEM_LANGUAGE_H_ + +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#elif defined(__APPLE__) +#include +#endif + +namespace crossdesk { +namespace localization { + +inline constexpr int kSystemLanguage = 10; +inline constexpr int kEnglishLanguage = 1; + +// Keep 0/1/2 compatible with existing Chinese/English/Russian config files. +inline int MatchLanguage(std::string tag) { + for (char& c : tag) { + if (c == '_') c = '-'; + else if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + } + tag = tag.substr(0, tag.find_first_of(".@")); + const auto base = tag.substr(0, tag.find('-')); + if (base == "zh") { + const auto parts = "-" + tag + "-"; + if (parts.find("-hans-") != std::string::npos) return 0; + return parts.find("-hant-") != std::string::npos || + parts.find("-tw-") != std::string::npos || + parts.find("-hk-") != std::string::npos || + parts.find("-mo-") != std::string::npos ? 3 : 0; + } + const char* codes[] = {"zh", "en", "ru", "zh", "ja", "ko", "de", "fr", "es", "pt"}; + for (int i = 1; i < kSystemLanguage; ++i) + if (i != 3 && base == codes[i]) return i; + if (base == "c" || base == "posix") return kEnglishLanguage; + return -1; +} + +inline int MatchPreferredLanguages(const std::vector& tags) { + for (const auto& tag : tags) { + const int match = MatchLanguage(tag); + if (match >= 0) return match; + } + return kEnglishLanguage; +} + +inline int DetectSystemLanguage() { + std::vector tags; +#if defined(_WIN32) + ULONG count = 0, length = 0; + GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, nullptr, &length); + std::vector names(length); + if (length && GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, names.data(), &length)) { + for (const wchar_t* name = names.data(); *name; name += wcslen(name) + 1) { + std::string tag; + for (const wchar_t* c = name; *c; ++c) tag += static_cast(*c); + tags.push_back(tag); + } + } +#elif defined(__APPLE__) + if (CFArrayRef names = CFLocaleCopyPreferredLanguages()) { + for (CFIndex i = 0; i < CFArrayGetCount(names); ++i) { + char tag[128] = {}; + auto name = static_cast(CFArrayGetValueAtIndex(names, i)); + if (CFStringGetCString(name, tag, sizeof(tag), kCFStringEncodingUTF8)) tags.emplace_back(tag); + } + CFRelease(names); + } +#else + // The Harmony desktop host supplies LANGUAGE from the system i18n API. + const char* locale = std::getenv("LC_ALL"); + if (!locale || !*locale) locale = std::getenv("LC_MESSAGES"); + if (!locale || !*locale) locale = std::getenv("LANG"); + if (locale && (std::string(locale) == "C" || std::string(locale) == "POSIX")) return kEnglishLanguage; + if (const char* preferred = std::getenv("LANGUAGE")) { + std::string list(preferred); + size_t start = 0; + do { + const auto end = list.find(':', start); + tags.push_back(list.substr(start, end - start)); + if (end == std::string::npos) break; + start = end + 1; + } while (start < list.size()); + } + if (locale) tags.emplace_back(locale); +#endif + return MatchPreferredLanguages(tags); +} + +inline int SystemLanguage() { + // Language changes take effect on the next application launch; explicit + // application preferences always win over this process-wide default. + static const int language = DetectSystemLanguage(); + return language; +} + +} // namespace localization +} // namespace crossdesk + +#endif diff --git a/apps/desktop/src/gui/features/settings/settings_manager.cpp b/apps/desktop/src/gui/features/settings/settings_manager.cpp index a569d6a0..36c2ac68 100644 --- a/apps/desktop/src/gui/features/settings/settings_manager.cpp +++ b/apps/desktop/src/gui/features/settings/settings_manager.cpp @@ -461,8 +461,7 @@ int SettingsManager::Load() { std::make_shared(owner_.cache_path_ + "/thumbnails/", owner_.aes128_key_, owner_.aes128_iv_); - owner_.language_button_value_ = localization::detail::ClampLanguageIndex( - static_cast(owner_.config_center_->GetLanguage())); + owner_.language_button_value_ = static_cast(owner_.config_center_->GetLanguage()); owner_.video_encode_format_button_value_ = static_cast(owner_.config_center_->GetVideoEncodeFormat()); owner_.enable_self_hosted_ = owner_.config_center_->IsSelfHosted(); diff --git a/apps/desktop/src/gui/ui/about_panel.slint b/apps/desktop/src/gui/ui/about_panel.slint index 6e4a17fe..7002121c 100644 --- a/apps/desktop/src/gui/ui/about_panel.slint +++ b/apps/desktop/src/gui/ui/about_panel.slint @@ -19,12 +19,12 @@ export struct AboutComponent { } export global AboutStrings { - out property software-license: GalleryStrings.tr("软件许可", "Software license", "Лицензия программы"); - out property components: GalleryStrings.tr("开源组件", "Open-source components", "Компоненты с открытым кодом"); - out property source: GalleryStrings.tr("源码与构建说明", "Source code and build instructions", "Исходный код и сборка"); - out property notices: GalleryStrings.tr("许可与版权声明", "Licenses and copyright notices", "Лицензии и авторские права"); - out property view-source: GalleryStrings.tr("查看源码", "View source code", "Открыть исходный код"); - out property back: GalleryStrings.tr("返回", "Back", "Назад"); + out property software-license: GalleryStrings.texts[130]; + out property components: GalleryStrings.texts[131]; + out property source: GalleryStrings.texts[132]; + out property notices: GalleryStrings.texts[133]; + out property view-source: GalleryStrings.texts[134]; + out property back: GalleryStrings.texts[135]; } export component AboutNavigationGroup inherits FlatSurface { @@ -137,7 +137,7 @@ export component AboutPanel inherits SettingsDialog { if root.page == AboutPage.components: VerticalLayout { padding: 0px; spacing: 10px; Text { - text: GalleryStrings.tr("以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", "Main open-source components used in this build. Each component is covered by its own license.", "Основные открытые компоненты этой сборки. Каждый распространяется по своей лицензии."); + text: GalleryStrings.texts[136]; color: WorkbenchStyle.muted; font-size: 12px; wrap: word-wrap; } Rectangle { @@ -146,9 +146,9 @@ export component AboutPanel inherits SettingsDialog { notice := VerticalLayout { x: 16px; y: 16px; width: parent.width - 32px; height: self.preferred-height; spacing: 12px; - Text { text: GalleryStrings.tr("OpenFEC 告知", "OpenFEC notice", "Уведомление OpenFEC"); color: WorkbenchStyle.text; font-size: 14px; font-weight: 600; } + Text { text: GalleryStrings.texts[137]; color: WorkbenchStyle.text; font-size: 14px; font-weight: 600; } Text { - text: GalleryStrings.tr("本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", "This application uses OpenFEC for forward error correction under CeCILL-C 1.0, which provides limited warranties and limits liability. See the full license for details.", "Приложение использует OpenFEC для прямого исправления ошибок по лицензии CeCILL-C 1.0 с ограниченной гарантией и ответственностью. Подробности — в тексте лицензии."); + text: GalleryStrings.texts[138]; color: WorkbenchStyle.muted; font-size: 13px; wrap: word-wrap; font-family: "CrossDesk Message Spacing"; } @@ -158,7 +158,7 @@ export component AboutPanel inherits SettingsDialog { font-family: "CrossDesk Message Spacing"; } if root.openfec-index >= 0: AboutNavigationRow { - title: GalleryStrings.tr("OpenFEC 许可与源码", "OpenFEC license and source", "Лицензия и исходный код OpenFEC"); + title: GalleryStrings.texts[139]; clicked => { root.component-index = root.openfec-index; root.page = AboutPage.component; } } } @@ -185,24 +185,24 @@ export component AboutPanel inherits SettingsDialog { clicked => { root.document-index = index; root.page = AboutPage.document; } } if root.selected.documents.length == 0: Text { - text: GalleryStrings.tr("本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", "License text is not bundled for this component. Use View source code to read its license and copyright notices.", "Текст лицензии не включён. Откройте исходный код для просмотра лицензии и авторских прав."); + text: GalleryStrings.texts[140]; color: WorkbenchStyle.muted; font-size: 12px; wrap: word-wrap; } } if root.page == AboutPage.source: VerticalLayout { padding: 0px; spacing: 12px; Text { - text: root.revision != "" ? GalleryStrings.tr("源码版本:", "Source revision: ", "Ревизия исходного кода: ") + root.revision - : GalleryStrings.tr("本版本源码信息暂不可用。", "Source revision is unavailable for this build.", "Ревизия исходного кода этой сборки недоступна."); + text: root.revision != "" ? GalleryStrings.texts[141] + root.revision + : GalleryStrings.texts[142]; color: WorkbenchStyle.text; font-size: 13px; wrap: word-wrap; } AboutNavigationRow { title: AboutStrings.view-source; external: true; clicked => { root.open-link(root.source-url); } } AboutNavigationRow { - title: GalleryStrings.tr("构建说明", "Build instructions", "Инструкции по сборке"); external: true; + title: GalleryStrings.texts[143]; external: true; clicked => { root.open-link(root.build-url); } } AboutNavigationRow { - title: GalleryStrings.tr("项目主页", "Project website", "Сайт проекта"); external: true; + title: GalleryStrings.texts[144]; external: true; clicked => { root.open-link("https://crossdesk.cn"); } } } diff --git a/apps/desktop/src/gui/ui/device_card_actions.slint b/apps/desktop/src/gui/ui/device_card_actions.slint index 66053f14..4def2518 100644 --- a/apps/desktop/src/gui/ui/device_card_actions.slint +++ b/apps/desktop/src/gui/ui/device_card_actions.slint @@ -35,12 +35,12 @@ export component DeviceCardActions inherits Rectangle { spacing: 0px; CardAction { icon: FontAwesomeIcons.pen; - tooltip: GalleryStrings.tr("修改名称", "Rename", "Переименовать"); + tooltip: GalleryStrings.texts[35]; clicked => { root.edit-alias(); } } CardAction { icon: FontAwesomeIcons.tags; - tooltip: GalleryStrings.tr("修改分组", "Edit groups", "Изменить группы"); + tooltip: GalleryStrings.texts[30]; clicked => { root.edit-groups(); } } CardAction { @@ -51,7 +51,7 @@ export component DeviceCardActions inherits Rectangle { CardAction { icon: root.connected ? FontAwesomeIcons.xmark : FontAwesomeIcons.arrow-right-long; icon-size: 13px; - tooltip: root.connected ? GalleryStrings.tr("断开", "Disconnect", "Отключить") : GalleryStrings.tr("连接", "Connect", "Подключить"); + tooltip: root.connected ? GalleryStrings.texts[36] : GalleryStrings.texts[37]; clicked => { if root.connected { root.disconnect-device(); } else { root.connect-device(); } diff --git a/apps/desktop/src/gui/ui/device_group_dialog.slint b/apps/desktop/src/gui/ui/device_group_dialog.slint index 6e1d15ef..2f6c690c 100644 --- a/apps/desktop/src/gui/ui/device_group_dialog.slint +++ b/apps/desktop/src/gui/ui/device_group_dialog.slint @@ -31,7 +31,7 @@ export component DeviceGroupDialog inherits Rectangle { TouchArea {} Text { x: 18px; y: 16px; height: 24px; - text: GalleryStrings.tr("修改分组", "Edit groups", "Изменить группы"); + text: GalleryStrings.texts[30]; color: #24272d; font-size: 17px; font-weight: 600; } Text { @@ -64,7 +64,7 @@ export component DeviceGroupDialog inherits Rectangle { } Text { x: 39px; width: parent.width - 48px; height: parent.height; - text: option.name == "" ? GalleryStrings.tr("未分组", "Ungrouped", "Без группы") : option.name; + text: option.name == "" ? GalleryStrings.texts[31] : option.name; color: parent.selected ? ControlStyle.selected-text : #30343b; font-weight: parent.selected ? 600 : 400; font-size: 12px; overflow: elide; vertical-alignment: center; @@ -91,7 +91,7 @@ export component DeviceGroupDialog inherits Rectangle { x: 18px; y: group-list.y + group-list.height + 12px; width: parent.width - 36px; height: 30px; text <=> root.new-group; - placeholder-text: GalleryStrings.tr("新建分组(可选)", "New group (optional)", "Новая группа (необязательно)"); + placeholder-text: GalleryStrings.texts[32]; } if root.error != "": Text { x: 18px; y: group-list.y + group-list.height + 48px; @@ -102,8 +102,8 @@ export component DeviceGroupDialog inherits Rectangle { x: 18px; y: parent.height - 46px; width: parent.width - 36px; height: 28px; spacing: 10px; Rectangle { horizontal-stretch: 1; } - CompactButton { width: 72px; height: 28px; text: GalleryStrings.tr("取消", "Cancel", "Отмена"); clicked => { root.cancel(); } } - CompactButton { width: 88px; height: 28px; primary: true; text: GalleryStrings.tr("保存", "Save", "Сохранить"); clicked => { root.save(root.new-group); } } + CompactButton { width: 72px; height: 28px; text: GalleryStrings.texts[33]; clicked => { root.cancel(); } } + CompactButton { width: 88px; height: 28px; primary: true; text: GalleryStrings.texts[34]; clicked => { root.save(root.new-group); } } } } } diff --git a/apps/desktop/src/gui/ui/device_strings.slint b/apps/desktop/src/gui/ui/device_strings.slint index 2c123ff9..73a34291 100644 --- a/apps/desktop/src/gui/ui/device_strings.slint +++ b/apps/desktop/src/gui/ui/device_strings.slint @@ -1,10 +1,24 @@ export global GalleryStrings { in-out property language: 0; + in-out property <[string]> texts; + in-out property retry-prefix; + in-out property retry-suffix; + public pure function retry-after(seconds: int) -> string { + return self.retry-prefix + seconds + self.retry-suffix; + } + // Compatibility for embedding callers with their own three-language text. public pure function tr(zh: string, en: string, ru: string) -> string { return self.language == 0 ? zh : self.language == 2 ? ru : en; } public pure function device-count(count: int) -> string { if self.language == 0 { return count + " 台设备"; } + if self.language == 3 { return count + " 臺裝置"; } + if self.language == 4 { return count + " 台"; } + if self.language == 5 { return count + "개 기기"; } + if self.language == 6 { return count + (count == 1 ? " Gerät" : " Geräte"); } + if self.language == 7 { return count + (count == 1 ? " appareil" : " appareils"); } + if self.language == 8 { return count + (count == 1 ? " dispositivo" : " dispositivos"); } + if self.language == 9 { return count + (count == 1 ? " dispositivo" : " dispositivos"); } if self.language == 2 { let last-two = mod(count, 100); let last = mod(count, 10); diff --git a/apps/desktop/src/gui/ui/gallery_network_dialog.slint b/apps/desktop/src/gui/ui/gallery_network_dialog.slint index e819e0a4..20dc65ed 100644 --- a/apps/desktop/src/gui/ui/gallery_network_dialog.slint +++ b/apps/desktop/src/gui/ui/gallery_network_dialog.slint @@ -65,10 +65,10 @@ component NetworkRow inherits Rectangle { encryption-text := Text { x: 6px; width: parent.width - 12px; height: parent.height; text: !root.device.encryption-known - ? GalleryStrings.tr("待确认", "Unknown", "Неизвестно") + ? GalleryStrings.texts[38] : root.device.encryption-enabled - ? GalleryStrings.tr("已加密", "Encrypted", "Зашифровано") - : GalleryStrings.tr("未加密", "Unencrypted", "Без шифр."); + ? GalleryStrings.texts[39] + : GalleryStrings.texts[40]; color: !root.device.encryption-known ? #7a8490 : root.device.encryption-enabled ? #18794e : #8a6428; font-size: 10px; horizontal-alignment: center; @@ -83,7 +83,7 @@ component NetworkRow inherits Rectangle { Text { y: root.heading ? 0px : 8px; height: root.heading ? parent.height : 20px; width: parent.width; - text: root.heading ? GalleryStrings.tr("画面", "Video", "Видео") : root.device.resolution; + text: root.heading ? GalleryStrings.texts[41] : root.device.resolution; font-size: root.heading ? 11px : 12px; font-weight: root.heading ? 600 : 400; color: root.heading ? #6b7785 : #293746; vertical-alignment: center; overflow: elide; @@ -98,7 +98,7 @@ component NetworkRow inherits Rectangle { width: max(100px, root.width * 0.18); if root.heading: Text { x: 0px; width: parent.width; - text: GalleryStrings.tr("收发速率", "Transfer rate", "Скорость"); + text: GalleryStrings.texts[42]; font-size: 11px; font-weight: 600; color: #6b7785; vertical-alignment: center; overflow: elide; } @@ -126,14 +126,14 @@ component NetworkRow inherits Rectangle { Text { y: root.heading ? 0px : 8px; height: root.heading ? parent.height : 20px; width: parent.width; - text: root.heading ? GalleryStrings.tr("视频延时", "Video latency", "Задержка видео") : root.device.video-latency; + text: root.heading ? GalleryStrings.texts[43] : root.device.video-latency; font-size: root.heading ? 11px : 12px; font-weight: root.heading ? 600 : 400; color: root.heading ? #6b7785 : #293746; vertical-alignment: center; overflow: elide; } if !root.heading: Text { y: 30px; height: 17px; width: parent.width; - text: GalleryStrings.tr("丢包 ", "Loss ", "Потери ") + root.device.loss; + text: GalleryStrings.texts[44] + root.device.loss; font-size: 11px; color: #7a8490; vertical-alignment: center; overflow: elide; } @@ -155,7 +155,7 @@ component NetworkRow inherits Rectangle { width: (parent.width - 12px) / 2; encoder-label := Text { height: parent.height; width: self.preferred-width; - text: GalleryStrings.tr("被控端编码器 ", "Remote encoder ", "Удалённый кодер "); + text: GalleryStrings.texts[45]; font-size: 10px; color: #586f87; vertical-alignment: center; } ScrollingText { @@ -167,7 +167,7 @@ component NetworkRow inherits Rectangle { width: (parent.width - 12px) / 2; decoder-label := Text { height: parent.height; width: self.preferred-width; - text: GalleryStrings.tr("控制端解码器 ", "Local decoder ", "Локальный декодер "); + text: GalleryStrings.texts[46]; font-size: 10px; color: #586f87; vertical-alignment: center; } ScrollingText { @@ -182,11 +182,11 @@ component NetworkEmptyState inherits Rectangle { VerticalLayout { alignment: center; spacing: 8px; Text { - text: GalleryStrings.tr("暂无已连接设备", "No connected devices", "Нет подключённых устройств"); + text: GalleryStrings.texts[47]; font-size: 13px; color: #596878; horizontal-alignment: center; } Text { - text: GalleryStrings.tr("建立连接后,网络和画面信息将在此显示", "Network and video details appear here once connected", "После подключения здесь появятся данные сети и видео"); + text: GalleryStrings.texts[48]; font-size: 11px; color: #8a95a1; horizontal-alignment: center; } } @@ -216,25 +216,25 @@ export component GalleryNetworkDialog inherits Rectangle { } Text { x: 20px; y: 17px; width: parent.width - 120px; height: 24px; - text: GalleryStrings.tr("设备网络状态", "Device network status", "Состояние сети устройств"); + text: GalleryStrings.texts[49]; font-size: 17px; font-weight: 600; color: #293746; } CompactButton { border-radius: UiRadius.control; x: parent.width - 80px; y: 17px; width: 60px; height: 26px; - text: GalleryStrings.tr("关闭", "Close", "Закрыть"); clicked => { root.close(); } + text: GalleryStrings.texts[50]; clicked => { root.close(); } } Text { x: 20px; y: 48px; width: parent.width - 40px; height: 18px; - text: GalleryStrings.tr("已连接设备 ", "Connected devices ", "Подключённые устройства ") + root.devices.length - + GalleryStrings.tr(" 台", "", ""); + text: GalleryStrings.texts[51] + root.devices.length + + GalleryStrings.texts[52]; font-size: 11px; color: #7a8490; overflow: elide; } NetworkRow { x: 12px; y: 78px; width: parent.width - 38px; height: 30px; heading: true; background: #f3f5f8; border-radius: UiRadius.control; device: { - name: GalleryStrings.tr("设备 / ID", "Device / ID", "Устройство / ID"), + name: GalleryStrings.texts[53], }; } list := ScrollView { diff --git a/apps/desktop/src/gui/ui/gallery_settings.slint b/apps/desktop/src/gui/ui/gallery_settings.slint index 42b15ddb..b6295cb0 100644 --- a/apps/desktop/src/gui/ui/gallery_settings.slint +++ b/apps/desktop/src/gui/ui/gallery_settings.slint @@ -9,31 +9,31 @@ export component GallerySettings inherits Rectangle { in property error; SettingsGroup { y: 0px; width: parent.width; - title: GalleryStrings.tr("画面传输", "Video transmission", "Передача видео"); rows: 3; + title: GalleryStrings.texts[145]; rows: 3; SettingsRow { - label: GalleryStrings.tr("分辨率上限", "Resolution limit", "Макс. разрешение"); + label: GalleryStrings.texts[146]; label-reserve: self.width - 112px; SettingsSelect { border-radius: UiRadius.control; x: 136px; y: 4px; width: parent.width - 150px; current-index <=> root.resolution-index; - model: [GalleryStrings.tr("自动", "Auto", "Авто"), + model: [GalleryStrings.texts[147], "320 × 180", "640 × 360", "1280 × 720", "1920 × 1080", "2560 × 1440", "3840 × 2160", - GalleryStrings.tr("原始分辨率", "Original resolution", "Исходное разрешение")]; + GalleryStrings.texts[148]]; } } SettingsRow { - label: GalleryStrings.tr("帧率", "Frame rate", "Частота кадров"); + label: GalleryStrings.texts[149]; label-reserve: self.width - 112px; SettingsSelect { border-radius: UiRadius.control; x: 136px; y: 4px; width: parent.width - 150px; current-index <=> root.frame-rate-index; - model: [GalleryStrings.tr("跟随设备设置", "Follow device settings", "Настройки устройства"), "15 FPS", "30 FPS", "60 FPS"]; + model: [GalleryStrings.texts[150], "15 FPS", "30 FPS", "60 FPS"]; } } SettingsRow { - label: GalleryStrings.tr("视频总带宽", "Total bandwidth", "Общий битрейт"); + label: GalleryStrings.texts[151]; label-reserve: self.width - 112px; divider: false; SettingsSelect { border-radius: UiRadius.control; diff --git a/apps/desktop/src/gui/ui/gallery_view.slint b/apps/desktop/src/gui/ui/gallery_view.slint index 0f566306..1148d7c2 100644 --- a/apps/desktop/src/gui/ui/gallery_view.slint +++ b/apps/desktop/src/gui/ui/gallery_view.slint @@ -156,7 +156,7 @@ export component GalleryView inherits Rectangle { in property count: 0; in property connected-count: 0; private property connected-summary: root.connected-count + " / " + root.count - + GalleryStrings.tr(" 台已连接", " connected", " подключено"); + + GalleryStrings.texts[152]; callback network-open; in property selected-count: 0; in property selected-audio-available: false; @@ -297,10 +297,10 @@ export component GalleryView inherits Rectangle { add-menu := GalleryMenuButton { horizontal-padding: root.toolbar-button-padding; width: self.preferred-button-width; - text: GalleryStrings.tr("添加", "Add", "Добавить"); menu-width: 232px; + text: GalleryStrings.texts[153]; menu-width: 232px; items: [ - {label: GalleryStrings.tr("通过设备 ID 添加", "Add by device ID", "Добавить по ID устройства"), enabled: true}, - {label: GalleryStrings.tr("从近期连接添加", "Add from recent", "Добавить из недавних"), enabled: true}, + {label: GalleryStrings.texts[154], enabled: true}, + {label: GalleryStrings.texts[155], enabled: true}, ]; opened => { root.device-tooltip-id = ""; root.action("release", ""); } selected(index) => { @@ -316,12 +316,12 @@ export component GalleryView inherits Rectangle { horizontal-stretch: 1; min-width: 0px; Text { x: 0px; y: 0px; width: parent.width; height: root.hidden-selected > 0 ? 13px : parent.height; - text: GalleryStrings.tr("已选 ", "Selected ", "Выбрано ") + root.selected-count + GalleryStrings.tr(" 台", "", ""); + text: GalleryStrings.texts[156] + root.selected-count + GalleryStrings.texts[52]; color: #62666d; vertical-alignment: center; font-size: 11px; overflow: elide; } if root.hidden-selected > 0: Text { y: 14px; width: parent.width; height: 10px; - text: GalleryStrings.tr("跨页 ", "Other pages ", "Вне страницы ") + root.hidden-selected; + text: GalleryStrings.texts[157] + root.hidden-selected; color: #80858d; font-size: 10px; overflow: elide; } } @@ -329,27 +329,27 @@ export component GalleryView inherits Rectangle { horizontal-padding: root.toolbar-button-padding; enabled: root.count > 0; text: root.count > 0 && root.selected-count == root.count - ? GalleryStrings.tr("取消全选", "Deselect all", "Снять выбор") - : GalleryStrings.tr("全选", "Select all", "Выбрать все"); + ? GalleryStrings.texts[158] + : GalleryStrings.texts[159]; alternate-text: root.count > 0 && root.selected-count == root.count - ? GalleryStrings.tr("全选", "Select all", "Выбрать все") - : GalleryStrings.tr("取消全选", "Deselect all", "Снять выбор"); + ? GalleryStrings.texts[159] + : GalleryStrings.texts[158]; clicked => { root.action("all-select", ""); } } - GalleryToolbarButton { horizontal-padding: root.toolbar-button-padding; primary: true; enabled: root.selected-count > 0; text: GalleryStrings.tr("连接", "Connect", "Подключить"); clicked => { root.action("connect", ""); } } - GalleryToolbarButton { horizontal-padding: root.toolbar-button-padding; enabled: root.selected-count > 0; text: GalleryStrings.tr("断开", "Disconnect", "Отключить"); clicked => { root.confirm-action("disconnect", self.text); } } + GalleryToolbarButton { horizontal-padding: root.toolbar-button-padding; primary: true; enabled: root.selected-count > 0; text: GalleryStrings.texts[37]; clicked => { root.action("connect", ""); } } + GalleryToolbarButton { horizontal-padding: root.toolbar-button-padding; enabled: root.selected-count > 0; text: GalleryStrings.texts[36]; clicked => { root.confirm-action("disconnect", self.text); } } batch-menu := GalleryMenuButton { horizontal-padding: root.toolbar-button-padding; width: self.preferred-button-width; enabled: root.selected-count > 0; - text: GalleryStrings.tr("更多", "More", "Ещё"); + text: GalleryStrings.texts[68]; items: [ - {label: root.selected-audio-muted ? GalleryStrings.tr("取消静音", "Unmute", "Со звуком") : GalleryStrings.tr("静音", "Mute", "Без звука"), enabled: root.selected-audio-available}, - {label: GalleryStrings.tr("分发文件", "Send file", "Отправить файл"), enabled: root.selected-count > 0}, + {label: root.selected-audio-muted ? GalleryStrings.texts[160] : GalleryStrings.texts[161], enabled: root.selected-audio-available}, + {label: GalleryStrings.texts[162], enabled: root.selected-count > 0}, ]; opened => { root.device-tooltip-id = ""; root.action("release", ""); } selected(index) => { if index == 0 { root.action(root.selected-audio-muted ? "unmute" : "mute", ""); } - else { root.confirm-action("file", GalleryStrings.tr("分发文件", "Send file", "Отправить файл")); } + else { root.confirm-action("file", GalleryStrings.texts[162]); } } } } @@ -357,8 +357,8 @@ export component GalleryView inherits Rectangle { x: parent.width - self.width; y: 0px; horizontal-padding: root.toolbar-button-padding; primary: root.batch; - alternate-text: GalleryStrings.tr("选择", "Select", "Выбрать"); - text: root.batch ? GalleryStrings.tr("完成", "Done", "Готово") : GalleryStrings.tr("选择", "Select", "Выбрать"); + alternate-text: GalleryStrings.texts[163]; + text: root.batch ? GalleryStrings.texts[164] : GalleryStrings.texts[163]; clicked => { root.batch = !root.batch; root.action("selection", ""); } } } @@ -405,7 +405,7 @@ export component GalleryView inherits Rectangle { function show-hint() { if self.has-hover && !self.pressed && (self.edge-x != 0 || self.edge-y != 0) { root.device-tooltip-id = "resize-grid"; - root.device-tooltip-text = GalleryStrings.tr("拖动表格分隔线,同步调整所有设备大小", "Drag a table divider to resize all devices", "Потяните за разделитель таблицы, чтобы изменить размер всех устройств"); + root.device-tooltip-text = GalleryStrings.texts[165]; root.device-tooltip-x = grid.x + self.mouse-x; root.device-tooltip-y = grid.y + self.mouse-y + 16px; } else if root.device-tooltip-id == "resize-grid" { root.device-tooltip-id = ""; } @@ -461,8 +461,8 @@ export component GalleryView inherits Rectangle { else if root.drag-source != "" { root.move-device-drag(self.mouse-x, self.mouse-y); } } for tile[index] in root.tiles: tile-card := Rectangle { - private property presence: tile.online ? GalleryStrings.tr("在线", "Online", "В сети") - : tile.presence-known ? GalleryStrings.tr("离线", "Offline", "Не в сети") : GalleryStrings.tr("未知", "Unknown", "Неизвестно"); + private property presence: tile.online ? GalleryStrings.texts[166] + : tile.presence-known ? GalleryStrings.texts[167] : GalleryStrings.texts[100]; private property details: tile.name + "\n" + tile.host-name + "\nID: " + tile.id + "\n" + tile.group-names + "\n" + self.presence; accessible-role: button; accessible-label: self.details; accessible-action-default => { root.action(root.batch && !root.simplified ? "select" : "focus", tile.id); } @@ -522,7 +522,7 @@ export component GalleryView inherits Rectangle { changed over-actions => { if self.has-hover { self.show-details(); } } if tile-touch.has-hover && !root.dragging && !root.resizing && !root.batch && !root.simplified: DeviceCardActions { x: parent.width - self.width; y: parent.height - 23px; - remove-label: GalleryStrings.tr("从桌面墙移除", "Remove from DeskHub", "Убрать из DeskHub"); + remove-label: GalleryStrings.texts[168]; connected: tile.connected; edit-alias => { root.action("release", ""); root.edit-alias(tile.id, tile.name); } edit-groups => { root.edit-groups(tile.id, tile.name); } @@ -557,8 +557,8 @@ export component GalleryView inherits Rectangle { } if root.count == 0: Text { text: root.simplified - ? GalleryStrings.tr("暂无设备,退出精简模式后可添加", "No devices. Exit compact mode to add devices", "Нет устройств. Выйдите из компактного режима, чтобы добавить их") - : GalleryStrings.tr("添加设备,建立你的桌面墙", "Add devices to build your DeskHub", "Добавьте устройства в DeskHub"); + ? GalleryStrings.texts[169] + : GalleryStrings.texts[170]; color: #808080; horizontal-alignment: center; vertical-alignment: center; } } @@ -568,7 +568,7 @@ export component GalleryView inherits Rectangle { height: footer.y - 12px - self.y; HorizontalLayout { x: 0px; y: 0px; width: parent.width - root.view-controls-space; height: 24px; spacing: 8px; - GalleryButton { width: 52px; text: GalleryStrings.tr("返回", "Back", "Назад"); clicked => { root.action("focus", ""); } } + GalleryButton { width: 52px; text: GalleryStrings.texts[135]; clicked => { root.action("focus", ""); } } Rectangle { horizontal-stretch: 1; min-width: 0px; Text { x: 0px; width: parent.width; height: parent.height; text: root.focused.name; color: root.focused.online ? #303943 : DeviceCardStyle.offline-text; font-size: 12px; font-weight: 600; overflow: elide; horizontal-alignment: left; vertical-alignment: center; } @@ -579,10 +579,10 @@ export component GalleryView inherits Rectangle { background: root.controlling ? #e7f1fd : #f0f2f5; focus-state := Text { x: 8px; width: parent.width - 16px; height: parent.height; - text: root.group-controlling ? GalleryStrings.tr("群控中", "Group control", "Групп. управление") - : root.controlling ? GalleryStrings.tr("正在操控", "Controlling", "Управление") + text: root.group-controlling ? GalleryStrings.texts[171] + : root.controlling ? GalleryStrings.texts[172] : root.focused.connected && root.focused.has-frame && !root.focused.stale - ? GalleryStrings.tr("只读预览", "View only", "Просмотр") : root.focused.status; + ? GalleryStrings.texts[173] : root.focused.status; font-size: 10px; color: root.controlling ? #3e77b3 : #6b7480; vertical-alignment: center; overflow: elide; } } @@ -590,14 +590,14 @@ export component GalleryView inherits Rectangle { horizontal-padding: root.toolbar-button-padding; primary: root.group-controlling; enabled: root.group-controlling || (root.focused.connected && root.focused.has-frame && !root.focused.stale); - text: root.group-controlling ? GalleryStrings.tr("关闭群控", "Stop group control", "Откл. групп. ввод") : GalleryStrings.tr("开启群控", "Group control", "Групп. ввод"); - alternate-text: root.group-controlling ? GalleryStrings.tr("开启群控", "Group control", "Групп. ввод") : GalleryStrings.tr("关闭群控", "Stop group control", "Откл. групп. ввод"); + text: root.group-controlling ? GalleryStrings.texts[174] : GalleryStrings.texts[175]; + alternate-text: root.group-controlling ? GalleryStrings.texts[175] : GalleryStrings.texts[174]; accessible-role: button; - accessible-label: self.text + GalleryStrings.tr(":同步键鼠到所有已连接设备", ": mirror input to all connected devices", ": ввод на всех подключённых устройствах"); + accessible-label: self.text + GalleryStrings.texts[176]; accessible-action-default => { self.clicked(); } clicked => { root.action(root.group-controlling ? "group-release" : "group-control", root.focused.id); } } - GalleryButton { width: 100px; primary: true; enabled: !root.focused.connected || root.controlling || (root.focused.has-frame && !root.focused.stale); text: root.focused.connected ? (root.controlling ? GalleryStrings.tr("释放操控", "Release", "Отпустить") : GalleryStrings.tr("接管操控", "Control", "Управлять")) : GalleryStrings.tr("连接", "Connect", "Подключить"); clicked => { root.action(root.focused.connected ? (root.controlling ? "release" : "control") : "connect", root.focused.id); } } + GalleryButton { width: 100px; primary: true; enabled: !root.focused.connected || root.controlling || (root.focused.has-frame && !root.focused.stale); text: root.focused.connected ? (root.controlling ? GalleryStrings.texts[177] : GalleryStrings.texts[178]) : GalleryStrings.texts[37]; clicked => { root.action(root.focused.connected ? (root.controlling ? "release" : "control") : "connect", root.focused.id); } } } FlatSurface { x: 0px; y: rail.visible ? focus-divider.y + focus-divider.height : 36px; @@ -671,8 +671,8 @@ export component GalleryView inherits Rectangle { width: tile.id == root.focused.id ? 0px : root.rail-slot-width; height: root.rail-card-height; visible: tile.id != root.focused.id; rail-card := FlatSurface { - private property presence: tile.online ? GalleryStrings.tr("在线", "Online", "В сети") - : tile.presence-known ? GalleryStrings.tr("离线", "Offline", "Не в сети") : GalleryStrings.tr("未知", "Unknown", "Неизвестно"); + private property presence: tile.online ? GalleryStrings.texts[166] + : tile.presence-known ? GalleryStrings.texts[167] : GalleryStrings.texts[100]; private property details: tile.name + "\n" + tile.host-name + "\nID: " + tile.id + "\n" + tile.group-names + "\n" + self.presence; width: root.rail-preview-width + 10px; height: root.rail-card-height; border-radius: UiRadius.surface; background: tile.online ? #f5f6f8 : DeviceCardStyle.offline-background; outline-color: UiSurface.edge; @@ -744,7 +744,7 @@ export component GalleryView inherits Rectangle { function show-hint() { if self.has-hover && !root.focus-resizing { root.device-tooltip-id = "resize-focus"; - root.device-tooltip-text = GalleryStrings.tr("上下拖动,调整缩略图与主画面大小", "Drag up or down to resize the thumbnails and main preview", "Потяните вверх или вниз, чтобы изменить размер миниатюр и основного экрана"); + root.device-tooltip-text = GalleryStrings.texts[179]; root.device-tooltip-x = focus-view.x + self.mouse-x; root.device-tooltip-y = focus-view.y + focus-divider.y + self.mouse-y + 16px; } else if root.device-tooltip-id == "resize-focus" { root.device-tooltip-id = ""; } @@ -788,7 +788,7 @@ export component GalleryView inherits Rectangle { connection-count := Text { x: 0px; width: min(self.preferred-width, parent.width - network-button.width - 12px); height: parent.height; text: root.group-controlling - ? GalleryStrings.tr("群控中 · 所有已连接设备", "Group control · All connected devices", "Групповое управление · Все подключения") + ? GalleryStrings.texts[180] : root.connected-summary; color: #62666d; vertical-alignment: center; font-size: 11px; overflow: elide; } @@ -796,7 +796,7 @@ export component GalleryView inherits Rectangle { x: connection-count.x + connection-count.width + 12px; width: 64px; height: parent.height; outline-color: UiSurface.edge; border-radius: UiRadius.control; - text: GalleryStrings.tr("网络状态", "Network", "Сеть"); + text: GalleryStrings.texts[181]; accessible-role: button; accessible-label: self.text; accessible-action-default => { self.clicked(); } @@ -817,9 +817,9 @@ export component GalleryView inherits Rectangle { compact-toggle := GalleryToolbarButton { horizontal-padding: root.toolbar-button-padding; primary: root.simplified; - alternate-text: GalleryStrings.tr("退出精简", "Exit compact", "Обычный вид"); - text: root.simplified ? GalleryStrings.tr("退出精简", "Exit compact", "Обычный вид") - : GalleryStrings.tr("精简模式", "Compact", "Компактно"); + alternate-text: GalleryStrings.texts[182]; + text: root.simplified ? GalleryStrings.texts[182] + : GalleryStrings.texts[183]; clicked => { root.toggle-simplified(); } } IconButton { @@ -827,7 +827,7 @@ export component GalleryView inherits Rectangle { border-radius: UiRadius.control; normal-background: ControlStyle.surface; icon: root.fullscreen ? FontAwesomeIcons.compress : FontAwesomeIcons.expand; - tooltip: root.fullscreen ? GalleryStrings.tr("退出全屏", "Exit fullscreen", "Выйти из полноэкранного режима") : GalleryStrings.tr("全屏", "Fullscreen", "На весь экран"); + tooltip: root.fullscreen ? GalleryStrings.texts[184] : GalleryStrings.texts[185]; clicked => { root.toggle-fullscreen(); } } } @@ -859,9 +859,9 @@ export component GalleryView inherits Rectangle { Text { x: 80px; y: 8px; width: parent.width - 88px; height: 18px; text: root.dragged-tile.name; font-size: 12px; color: #303943; overflow: elide; } drag-hint := Text { x: 80px; y: 29px; width: parent.width - 88px; height: max(16px, self.preferred-height); - text: root.drag-page-direction != 0 ? GalleryStrings.tr("停留翻页,松开取消", "Hold to turn page; release to cancel", "Удерживайте для перелистывания; отпустите для отмены") - : root.drag-target >= 0 ? GalleryStrings.tr("松开鼠标交换位置", "Release to swap", "Отпустите для обмена") - : GalleryStrings.tr("拖到另一台设备上", "Drag onto another device", "Перетащите на другое устройство"); + text: root.drag-page-direction != 0 ? GalleryStrings.texts[186] + : root.drag-target >= 0 ? GalleryStrings.texts[187] + : GalleryStrings.texts[188]; font-size: 10px; color: #527ca8; wrap: word-wrap; } } @@ -870,7 +870,7 @@ export component GalleryView inherits Rectangle { width: min(420px, parent.width - 32px); height: 36px; z: 10; background: #fff2f0; outline-color: UiSurface.edge; border-radius: UiRadius.surface; Text { x: 12px; y: 0px; width: parent.width - 24px; height: parent.height; font-size: 12px; color: #9d4339; vertical-alignment: center; - text: GalleryStrings.tr("换位未保存,请重试", "Couldn't save positions. Please try again.", "Не удалось сохранить порядок. Повторите попытку."); overflow: elide; + text: GalleryStrings.texts[189]; overflow: elide; } } // Device details are rendered by MainWindow; resize hints stay local. @@ -896,36 +896,36 @@ export component GalleryView inherits Rectangle { root.adding = false; } } - Text { x: 18px; y: 16px; height: 24px; text: GalleryStrings.tr("添加设备", "Add device", "Добавить устройство"); font-size: 16px; } - Text { x: 18px; y: 56px; width: 72px; height: 30px; text: GalleryStrings.tr("设备 ID", "Device ID", "ID"); vertical-alignment: center; font-size: 12px; } + Text { x: 18px; y: 16px; height: 24px; text: GalleryStrings.texts[190]; font-size: 16px; } + Text { x: 18px; y: 56px; width: 72px; height: 30px; text: GalleryStrings.texts[191]; vertical-alignment: center; font-size: 12px; } device-id := RoundedLineEdit { x: 96px; y: 56px; width: 286px; height: 30px; - placeholder-text: GalleryStrings.tr("9 位设备 ID", "9-digit device ID", "ID из 9 цифр"); + placeholder-text: GalleryStrings.texts[192]; input-type: InputType.number; accepted => { password.focus(); } } - Text { x: 18px; y: 100px; width: 72px; height: 30px; text: GalleryStrings.tr("密码", "Password", "Пароль"); vertical-alignment: center; font-size: 12px; } + Text { x: 18px; y: 100px; width: 72px; height: 30px; text: GalleryStrings.texts[193]; vertical-alignment: center; font-size: 12px; } password := RoundedLineEdit { x: 96px; y: 100px; width: 286px; height: 30px; - placeholder-text: GalleryStrings.tr("设备连接密码", "Device password", "Пароль устройства"); + placeholder-text: GalleryStrings.texts[194]; input-type: InputType.password; accepted => { group.focus(); } } - Text { x: 18px; y: 144px; width: 72px; height: 30px; text: GalleryStrings.tr("分组", "Group", "Группа"); vertical-alignment: center; font-size: 12px; } + Text { x: 18px; y: 144px; width: 72px; height: 30px; text: GalleryStrings.texts[101]; vertical-alignment: center; font-size: 12px; } group := RoundedLineEdit { x: 96px; y: 144px; width: 286px; height: 30px; - placeholder-text: GalleryStrings.tr("分组名称(可选)", "Group name (optional)", "Группа (необязательно)"); + placeholder-text: GalleryStrings.texts[195]; accepted => { add-dialog.submit(); } } remember := ImGuiCheckBox { x: 96px; y: 188px; } - Text { x: 123px; y: 188px; height: 21px; text: GalleryStrings.tr("记住密码", "Remember password", "Запомнить пароль"); font-size: 12px; vertical-alignment: center; + Text { x: 123px; y: 188px; height: 21px; text: GalleryStrings.texts[196]; font-size: 12px; vertical-alignment: center; TouchArea { clicked => { remember.checked = !remember.checked; } } } Text { x: 18px; y: 216px; width: 364px; height: 28px; text: root.notice; color: #8e4740; font-size: 11px; wrap: word-wrap; overflow: elide; } - GalleryButton { x: 136px; y: 260px; width: 72px; height: 28px; text: GalleryStrings.tr("取消", "Cancel", "Отмена"); clicked => { password.text = ""; root.adding = false; } } + GalleryButton { x: 136px; y: 260px; width: 72px; height: 28px; text: GalleryStrings.texts[33]; clicked => { password.text = ""; root.adding = false; } } GalleryButton { x: 218px; y: 260px; width: 164px; height: 28px; primary: true; - text: GalleryStrings.tr("添加并连接", "Add and connect", "Добавить и подключить"); + text: GalleryStrings.texts[197]; enabled: device-id.text != "" && password.text != ""; clicked => { add-dialog.submit(); } } @@ -937,12 +937,12 @@ export component GalleryView inherits Rectangle { FlatSurface { x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; width: 440px; height: 378px; background: white; border-radius: UiRadius.surface; outline-color: UiSurface.edge; - Text { x: 18px; y: 16px; height: 24px; text: GalleryStrings.tr("从近期连接添加", "Add from recent connections", "Добавить из недавних"); font-size: 16px; } - Text { x: 18px; y: 44px; width: 404px; height: 18px; text: GalleryStrings.tr("加入桌面墙后,可通过批量选择连接", "Add to DeskHub, then select devices to connect.", "Добавьте в DeskHub, затем выберите устройства для подключения."); color: #62666d; font-size: 11px; } + Text { x: 18px; y: 16px; height: 24px; text: GalleryStrings.texts[155]; font-size: 16px; } + Text { x: 18px; y: 44px; width: 404px; height: 18px; text: GalleryStrings.texts[198]; color: #62666d; font-size: 11px; } ImGuiCheckBox { x: 18px; y: 74px; enabled: root.recent-available > 0; checked: root.recent-devices.length > 0 && root.recent-selected == root.recent-available; } - Text { x: 45px; y: 74px; height: 21px; text: GalleryStrings.tr("全选", "Select all", "Выбрать все"); color: root.recent-available > 0 ? #24272d : #92969e; font-size: 12px; vertical-alignment: center; } + Text { x: 45px; y: 74px; height: 21px; text: GalleryStrings.texts[159]; color: root.recent-available > 0 ? #24272d : #92969e; font-size: 12px; vertical-alignment: center; } TouchArea { x: 18px; y: 74px; width: 144px; height: 21px; enabled: root.recent-available > 0; clicked => { root.action("recent-all", ""); } } - Text { x: 224px; y: 74px; width: 198px; height: 21px; text: GalleryStrings.tr("待添加 ", "To add ", "К добавлению ") + root.recent-selected + " / " + root.recent-available; horizontal-alignment: right; vertical-alignment: center; font-size: 12px; color: #62666d; } + Text { x: 224px; y: 74px; width: 198px; height: 21px; text: GalleryStrings.texts[199] + root.recent-selected + " / " + root.recent-available; horizontal-alignment: right; vertical-alignment: center; font-size: 12px; color: #62666d; } FlatSurface { x: 18px; y: 102px; width: 404px; height: 160px; outline-color: UiSurface.edge; border-radius: UiRadius.surface; clip: true; @@ -961,13 +961,13 @@ export component GalleryView inherits Rectangle { Rectangle { x: parent.width - 74px; y: 19px; width: 6px; height: 6px; border-radius: 3px; background: !device.added && device.online ? #21b567 : #92969e; } Text { x: parent.width - 61px; y: 12px; width: 57px; height: 20px; - text: device.added ? GalleryStrings.tr("已添加", "Added", "Добавлено") : device.online ? GalleryStrings.tr("在线", "Online", "В сети") : GalleryStrings.tr("离线", "Offline", "Не в сети"); + text: device.added ? GalleryStrings.texts[200] : device.online ? GalleryStrings.texts[166] : GalleryStrings.texts[167]; color: device.added ? #92969e : device.online ? #17854c : #808080; font-size: 11px; vertical-alignment: center; } row-touch := TouchArea { enabled: !device.added; clicked => { root.action("recent-select", device.id); } } } } - if root.recent-devices.length == 0: Text { text: GalleryStrings.tr("暂无近期连接", "No recent connections", "Нет недавних подключений"); color: #808080; font-size: 12px; horizontal-alignment: center; vertical-alignment: center; } + if root.recent-devices.length == 0: Text { text: GalleryStrings.texts[89]; color: #808080; font-size: 12px; horizontal-alignment: center; vertical-alignment: center; } Rectangle { x: -UiRadius.surface; y: -UiRadius.surface; width: parent.width + 2 * UiRadius.surface; @@ -981,11 +981,11 @@ export component GalleryView inherits Rectangle { outline-color: UiSurface.edge; } } - Text { x: 18px; y: 274px; width: 60px; height: 30px; text: GalleryStrings.tr("分组", "Group", "Группа"); font-size: 12px; vertical-alignment: center; } - import-group := RoundedLineEdit { x: 84px; y: 274px; width: 338px; height: 30px; text: root.import-group; placeholder-text: GalleryStrings.tr("分组名称(可选)", "Group name (optional)", "Группа (необязательно)"); } + Text { x: 18px; y: 274px; width: 60px; height: 30px; text: GalleryStrings.texts[101]; font-size: 12px; vertical-alignment: center; } + import-group := RoundedLineEdit { x: 84px; y: 274px; width: 338px; height: 30px; text: root.import-group; placeholder-text: GalleryStrings.texts[195]; } Text { x: 18px; y: 309px; width: 404px; height: 20px; text: root.notice; font-size: 11px; color: #8e4740; overflow: elide; } - GalleryButton { x: 192px; y: 336px; width: 72px; text: GalleryStrings.tr("取消", "Cancel", "Отмена"); clicked => { root.importing = false; } } - GalleryButton { x: 274px; y: 336px; width: 148px; primary: true; text: GalleryStrings.tr("加入桌面墙", "Add to DeskHub", "В DeskHub"); enabled: root.recent-selected > 0; clicked => { if root.import-recent(import-group.text) { root.importing = false; } } } + GalleryButton { x: 192px; y: 336px; width: 72px; text: GalleryStrings.texts[33]; clicked => { root.importing = false; } } + GalleryButton { x: 274px; y: 336px; width: 148px; primary: true; text: GalleryStrings.texts[201]; enabled: root.recent-selected > 0; clicked => { if root.import-recent(import-group.text) { root.importing = false; } } } } } if root.confirming: Rectangle { @@ -996,7 +996,7 @@ export component GalleryView inherits Rectangle { background: white; border-radius: UiRadius.surface; outline-color: UiSurface.edge; Text { x: 20px; y: 18px; width: parent.width - 132px; height: 24px; - text: root.action-code == "disconnect" ? GalleryStrings.tr("断开连接", "Disconnect devices", "Отключение") : root.action-name; + text: root.action-code == "disconnect" ? GalleryStrings.texts[96] : root.action-name; color: #24272d; font-size: 16px; font-weight: 600; vertical-alignment: center; } Rectangle { @@ -1021,16 +1021,16 @@ export component GalleryView inherits Rectangle { width: GalleryStrings.language == 0 ? 68px : 104px; height: 20px; border-radius: 10px; background: device.connected ? #eaf6ee : #f0f2f5; Rectangle { x: 9px; y: 7px; width: 6px; height: 6px; border-radius: 3px; background: device.connected ? #27a762 : #a0a6b0; } - Text { x: 21px; width: parent.width - 27px; height: parent.height; text: device.connected ? GalleryStrings.tr("已连接", "Connected", "Подключено") : GalleryStrings.tr("未连接", "Not connected", "Нет соединения"); color: device.connected ? #348259 : #858d98; font-size: 10px; vertical-alignment: center; } + Text { x: 21px; width: parent.width - 27px; height: parent.height; text: device.connected ? GalleryStrings.texts[202] : GalleryStrings.texts[203]; color: device.connected ? #348259 : #858d98; font-size: 10px; vertical-alignment: center; } } if index + 1 < root.selected-devices.length: SurfaceSeparator { x: 12px; y: parent.height - 1px; width: parent.width - 24px; height: 1px; outline-color: UiSurface.separator; } } } } - GalleryButton { x: parent.width - 208px; y: parent.height - 46px; width: 72px; height: 28px; text: GalleryStrings.tr("取消", "Cancel", "Отмена"); clicked => { root.confirming = false; } } + GalleryButton { x: parent.width - 208px; y: parent.height - 46px; width: 72px; height: 28px; text: GalleryStrings.texts[33]; clicked => { root.confirming = false; } } GalleryButton { x: parent.width - 126px; y: parent.height - 46px; width: 108px; height: 28px; primary: true; - text: root.action-code == "disconnect" ? GalleryStrings.tr("确认断开", "Disconnect", "Отключить") : GalleryStrings.tr("确认执行", "Continue", "Продолжить"); + text: root.action-code == "disconnect" ? GalleryStrings.texts[204] : GalleryStrings.texts[205]; clicked => { root.confirming = false; root.action(root.action-code, ""); } } } diff --git a/apps/desktop/src/gui/ui/lan_strings.slint b/apps/desktop/src/gui/ui/lan_strings.slint index bc10363a..61b394cc 100644 --- a/apps/desktop/src/gui/ui/lan_strings.slint +++ b/apps/desktop/src/gui/ui/lan_strings.slint @@ -5,24 +5,24 @@ export global LanStrings { // Slint Text does not expose a line-height property. public pure function access-error-lines(code: string) -> [string] { if code == "LanPortInUse" { return [ - GalleryStrings.tr("此端口已被占用,", "This port is in use.", "Порт занят."), - GalleryStrings.tr("请更换端口。", "Choose another port.", "Выберите другой порт."), - GalleryStrings.tr("原设置已保留。", "Your previous settings are unchanged.", "Прежние настройки сохранены.") + GalleryStrings.texts[0], + GalleryStrings.texts[1], + GalleryStrings.texts[2] ]; } if code == "LanPortCheckFailed" { return [ - GalleryStrings.tr("无法确认此端口是否可用,", "Could not check this port.", "Не удалось проверить порт."), - GalleryStrings.tr("请重试或检查本机防火墙。", "Retry or check the local firewall.", "Повторите попытку или проверьте брандмауэр."), - GalleryStrings.tr("原设置已保留。", "Your previous settings are unchanged.", "Прежние настройки сохранены.") + GalleryStrings.texts[3], + GalleryStrings.texts[4], + GalleryStrings.texts[2] ]; } if code == "LanPortPermissionDenied" { return [ - GalleryStrings.tr("无法使用此端口,", "Cannot use this port.", "Порт недоступен."), - GalleryStrings.tr("请选择其他端口或检查系统权限。", "Choose another port or check system permissions.", "Смените порт или проверьте разрешения."), - GalleryStrings.tr("原设置已保留。", "Your previous settings are unchanged.", "Прежние настройки сохранены.") + GalleryStrings.texts[5], + GalleryStrings.texts[6], + GalleryStrings.texts[2] ]; } if code == "Selected LAN interface is unavailable" { return [ - GalleryStrings.tr("未找到可用的局域网连接。", "No local network connection was found.", "Нет доступного подключения к LAN."), - GalleryStrings.tr("请连接 Wi-Fi 或网线,", "Connect to Wi-Fi or Ethernet,", "Подключитесь к Wi-Fi или Ethernet"), - GalleryStrings.tr("或在主界面选择本机 IP。", "or select a local IP on the main screen.", "или выберите локальный IP в главном окне.") + GalleryStrings.texts[7], + GalleryStrings.texts[8], + GalleryStrings.texts[9] ]; } // Keep all branches the same size for Slint's C++ model generator. return ["", "", ""]; @@ -30,29 +30,29 @@ export global LanStrings { public pure function error-message(code: string) -> string { let lines = LanStrings.access-error-lines(code); if lines[0] != "" { - let separator = GalleryStrings.tr("", " ", " "); + let separator = GalleryStrings.texts[10]; return lines[0] + separator + lines[1] + separator + lines[2]; } if code == "" { return ""; } - if code == "InvalidCredentials" { return GalleryStrings.tr("密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。", "The password is incorrect or has changed. Check the other desktop's current LAN password and try again.", "Пароль неверен или изменён. Проверьте текущий пароль LAN другого компьютера и повторите попытку."); } - if code == "AuthenticationRateLimited" { return GalleryStrings.tr("尝试次数过多,请等待倒计时结束后重试。", "Too many attempts. Try again when the countdown ends.", "Слишком много попыток. Дождитесь окончания обратного отсчёта."); } - if code == "CredentialsChanged" { return GalleryStrings.tr("对方密码已更新,请使用新密码重试。", "The password changed. Try again with the new password.", "Пароль изменился. Повторите с новым паролем."); } - if code == "Busy" { return GalleryStrings.tr("设备正忙,请稍后重试。", "The desktop is busy. Try again shortly.", "Компьютер занят. Повторите позже."); } - if code == "LAN password must contain exactly 6 ASCII letters or digits" { return GalleryStrings.tr("访问密码必须为 6 位英文字母或数字,区分大小写。", "Use exactly 6 letters (A–Z, a–z) or digits (0–9). Case-sensitive.", "Пароль: ровно 6 латинских букв или цифр. Регистр учитывается."); } - if code == "ConnectionFailed" || code == "ConnectionTimeout" || code == "IceConnectionTimeout" || code == "Timeout" || code == "ConnectionClosed" || code == "HeartbeatTimeout" || code == "SignalSendFailed" { return GalleryStrings.tr("无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。", "Could not connect. Check the IP, whether the other desktop is running CrossDesk, and its firewall settings.", "Не удалось подключиться. Проверьте IP, работу CrossDesk на другом компьютере и брандмауэр."); } - if code == "Enter a numeric IPv4 address or IPv4:port" || code == "Invalid LAN endpoint" { return GalleryStrings.tr("请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。", "Enter a valid IPv4 address such as 192.168.1.20, or IPv4:port (1–65535).", "Введите IPv4, например 192.168.1.20, или IPv4:порт (1–65535)."); } - if code == "Invalid LAN port" { return GalleryStrings.tr("请输入 1–65535 之间的整数端口。", "Enter a port number from 1 to 65535.", "Введите целый номер порта от 1 до 65535."); } - if code == "LAN password is not ready" { return GalleryStrings.tr("请点击主界面密码旁的修改按钮设置密码。", "Set a password using Edit next to the password on the main screen.", "Задайте пароль кнопкой редактирования рядом с паролем в главном окне."); } - if code == "LAN connection limit reached" { return GalleryStrings.tr("IP 连接数量已达上限,请先断开部分连接后重试。", "The IP connection limit has been reached. Disconnect some sessions and try again.", "Достигнут лимит IP-подключений. Завершите часть сеансов и повторите попытку."); } - if code == "UnsupportedNetworkPath" || code == "NetworkPolicyFailed" { return GalleryStrings.tr("当前网络路径不支持 IP 连接,请检查双方的局域网连接。", "This network path does not support IP connections. Check both devices' LAN connections.", "Этот сетевой маршрут не поддерживает IP-подключения. Проверьте подключения обоих устройств к LAN."); } - if code == "IncompatibleProtocol" || code == "RequiredCryptoUnsupported" || code == "TLS 1.3 is required for LAN connections" { return GalleryStrings.tr("双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。", "The protocol or encryption capabilities are incompatible. Update CrossDesk on both devices and try again.", "Протоколы или возможности шифрования несовместимы. Обновите CrossDesk на обоих устройствах и повторите попытку."); } - if code == "InvalidCertificate" || code == "FingerprintMissing" || code == "FingerprintMismatch" { return GalleryStrings.tr("无法验证对方设备的身份,请确认连接地址和对方设备后重试。", "Could not verify the remote device's identity. Check the address and the remote device before retrying.", "Не удалось проверить подлинность удалённого устройства. Проверьте адрес и устройство перед повторной попыткой."); } - if code == "DtlsHandshakeFailed" || code == "SrtpInstallFailed" || code == "SrtpKeyExportFailed" || code == "SecureTransportFailed" { return GalleryStrings.tr("无法建立加密连接,请检查双方网络并重试。", "Could not establish an encrypted connection. Check both devices' networks and try again.", "Не удалось установить зашифрованное соединение. Проверьте сеть на обоих устройствах и повторите попытку."); } - if code == "InvalidSignal" || code == "InvalidLocalSignal" || code == "Invalid LAN protocol message" { return GalleryStrings.tr("连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。", "Invalid connection negotiation data. Try again and check that both CrossDesk versions are compatible.", "Неверные данные согласования соединения. Повторите попытку и проверьте совместимость версий CrossDesk."); } - if code == "ListenerChanged" { return GalleryStrings.tr("连接地址或监听端口已更改,请确认最新地址后重试。", "The connection address or listening port has changed. Check the current address and try again.", "Адрес подключения или порт прослушивания изменился. Проверьте текущий адрес и повторите попытку."); } - if code == "PeerPreparationFailed" { return GalleryStrings.tr("无法准备远程会话,请稍后重试。", "Could not prepare the remote session. Try again shortly.", "Не удалось подготовить удалённый сеанс. Повторите позже."); } - if code == "Cannot copy text" { return GalleryStrings.tr("复制失败,请重试。", "Could not copy. Try again.", "Не удалось скопировать. Повторите попытку."); } + if code == "InvalidCredentials" { return GalleryStrings.texts[11]; } + if code == "AuthenticationRateLimited" { return GalleryStrings.texts[12]; } + if code == "CredentialsChanged" { return GalleryStrings.texts[13]; } + if code == "Busy" { return GalleryStrings.texts[14]; } + if code == "LAN password must contain exactly 6 ASCII letters or digits" { return GalleryStrings.texts[15]; } + if code == "ConnectionFailed" || code == "ConnectionTimeout" || code == "IceConnectionTimeout" || code == "Timeout" || code == "ConnectionClosed" || code == "HeartbeatTimeout" || code == "SignalSendFailed" { return GalleryStrings.texts[16]; } + if code == "Enter a numeric IPv4 address or IPv4:port" || code == "Invalid LAN endpoint" { return GalleryStrings.texts[17]; } + if code == "Invalid LAN port" { return GalleryStrings.texts[18]; } + if code == "LAN password is not ready" { return GalleryStrings.texts[19]; } + if code == "LAN connection limit reached" { return GalleryStrings.texts[20]; } + if code == "UnsupportedNetworkPath" || code == "NetworkPolicyFailed" { return GalleryStrings.texts[21]; } + if code == "IncompatibleProtocol" || code == "RequiredCryptoUnsupported" || code == "TLS 1.3 is required for LAN connections" { return GalleryStrings.texts[22]; } + if code == "InvalidCertificate" || code == "FingerprintMissing" || code == "FingerprintMismatch" { return GalleryStrings.texts[23]; } + if code == "DtlsHandshakeFailed" || code == "SrtpInstallFailed" || code == "SrtpKeyExportFailed" || code == "SecureTransportFailed" { return GalleryStrings.texts[24]; } + if code == "InvalidSignal" || code == "InvalidLocalSignal" || code == "Invalid LAN protocol message" { return GalleryStrings.texts[25]; } + if code == "ListenerChanged" { return GalleryStrings.texts[26]; } + if code == "PeerPreparationFailed" { return GalleryStrings.texts[27]; } + if code == "Cannot copy text" { return GalleryStrings.texts[28]; } // Keep diagnostic details for unexpected system errors, with a localized explanation. - return GalleryStrings.tr("IP 连接操作失败,详情:", "IP connection operation failed. Details: ", "Ошибка операции IP-подключения. Подробности: ") + code; + return GalleryStrings.texts[29] + code; } } diff --git a/apps/desktop/src/gui/ui/main_window.slint b/apps/desktop/src/gui/ui/main_window.slint index 16c3bfe4..4df8a03a 100644 --- a/apps/desktop/src/gui/ui/main_window.slint +++ b/apps/desktop/src/gui/ui/main_window.slint @@ -265,7 +265,7 @@ component PasswordInput inherits FlatSurface { } export component MainWindow inherits Window { - title: root.gallery-mode ? "CrossDesk " + GalleryStrings.tr("桌面墙", "DeskHub", "DeskHub") : "CrossDesk"; + title: root.gallery-mode ? "CrossDesk " + GalleryStrings.texts[54] : "CrossDesk"; icon: @image-url("../../../resources/linux/crossdesk_256x256.png"); preferred-width: root.minimum-window-width; preferred-height: root.minimum-window-height; @@ -455,7 +455,7 @@ export component MainWindow inherits Window { root.lan-remember-password = false; let error = root.lan-prepare-connect(address); root.connection-input-error = error == "Enter a numeric IPv4 address or IPv4:port" - ? GalleryStrings.tr("请输入有效的 IPv4 或 IPv4:端口", "Enter a valid IPv4 or IPv4:port", "Укажите IPv4 или IPv4:порт") + ? GalleryStrings.texts[55] : LanStrings.error-message(error); if error == "" { root.lan-open = true; @@ -527,8 +527,8 @@ export component MainWindow inherits Window { private property prompt-validating: root.lan-open ? root.lan-connecting : root.connection-validating; private property prompt-pending: root.lan-open ? root.lan-connecting : root.connection-pending; private property prompt-status-text: !root.lan-open ? root.connection-status-text - : root.lan-connecting ? GalleryStrings.tr("正在连接…", "Connecting…", "Подключение…") - : root.lan-retry-after > 0 ? GalleryStrings.tr("请在 " + root.lan-retry-after + " 秒后重试", "Try again in " + root.lan-retry-after + "s", "Повторите через " + root.lan-retry-after + " с") + : root.lan-connecting ? GalleryStrings.texts[56] + : root.lan-retry-after > 0 ? GalleryStrings.retry-after(root.lan-retry-after) : root.lan-message == "InvalidCredentials" ? UiStrings.reinput-password : root.lan-message == "" || root.lan-message == "AuthenticationRateLimited" ? UiStrings.input-password : LanStrings.error-message(root.lan-message); @@ -556,7 +556,7 @@ export component MainWindow inherits Window { in property <[RecentConnection]> recent-connections; out property recent-preview-width: max(1px, (recent-scroll.width - 24px) / 3); out property recent-preview-height: 80px; - in property <[string]> recent-groups: [GalleryStrings.tr("全部设备", "All devices", "Все устройства"), GalleryStrings.tr("未分组", "Ungrouped", "Без группы")]; + in property <[string]> recent-groups: [GalleryStrings.texts[57], GalleryStrings.texts[31]]; in-out property recent-group-index: 0; callback recent-group-selected(int); changed recent-group-index => { @@ -628,7 +628,8 @@ export component MainWindow inherits Window { in property portable-service-status: ""; in-out property portable-service-do-not-remind: false; - in-out property language-index: 0; + in-out property language-index: 10; + in property <[string]> language-options; in property capture-method-visible: false; in-out property capture-method-index: 0; in-out property codec-index: 0; @@ -640,11 +641,11 @@ export component MainWindow inherits Window { in property autostart-system-managed: false; in property autostart-status: AutostartStatus.checking; out property autostart-status-text: - root.autostart-status == AutostartStatus.checking ? GalleryStrings.tr("正在读取…", "Checking…", "Проверка…") : - root.autostart-status == AutostartStatus.enabled ? GalleryStrings.tr("已开启", "Enabled", "Включён") : - root.autostart-status == AutostartStatus.disabled ? GalleryStrings.tr("未开启", "Disabled", "Выключен") : - root.autostart-status == AutostartStatus.unsupported ? GalleryStrings.tr("设备不支持", "Unsupported", "Не поддерживается") : - GalleryStrings.tr("读取失败", "Read failed", "Ошибка чтения"); + root.autostart-status == AutostartStatus.checking ? GalleryStrings.texts[58] : + root.autostart-status == AutostartStatus.enabled ? GalleryStrings.texts[59] : + root.autostart-status == AutostartStatus.disabled ? GalleryStrings.texts[60] : + root.autostart-status == AutostartStatus.unsupported ? GalleryStrings.texts[61] : + GalleryStrings.texts[62]; in-out property autostart-guide-open: false; changed autostart-guide-open => { if root.autostart-guide-open { root.dialog-focus-pending = true; } } in-out property daemon-enabled: false; @@ -770,7 +771,7 @@ export component MainWindow inherits Window { focus-sink.focus(); } private property copy-feedback: idle; - private property compact-language: root.language-index == 0; + private property compact-language: GalleryStrings.language == 0 || GalleryStrings.language == 3 || GalleryStrings.language == 4 || GalleryStrings.language == 5; private property recent-tooltip-visible: false; private property recent-tooltip-name: ""; private property recent-tooltip-host: ""; @@ -1114,9 +1115,9 @@ export component MainWindow inherits Window { width: 136px; height: 28px; background: WorkbenchStyle.field-surface; enabled: !root.connection-pending && !root.lan-connecting; - tooltip: root.lan-mode ? GalleryStrings.tr("切换到 ID 连接模式", "Switch to ID connection mode", "Переключить в режим ID") : GalleryStrings.tr("切换到 IP 连接模式", "Switch to IP connection mode", "Переключить в режим IP"); + tooltip: root.lan-mode ? GalleryStrings.texts[63] : GalleryStrings.texts[64]; accessible-role: switch; - accessible-label: GalleryStrings.tr("IP 连接模式", "IP connection mode", "Режим IP"); + accessible-label: GalleryStrings.texts[65]; accessible-checked: root.lan-mode; z: 8; clicked => { @@ -1138,7 +1139,7 @@ export component MainWindow inherits Window { y: 2px; width: (parent.width - 6px) / 2; height: parent.height - 4px; - text: lan ? GalleryStrings.tr("IP 连接", "IP mode", "Режим IP") : GalleryStrings.tr("ID 连接", "ID mode", "Режим ID"); + text: lan ? GalleryStrings.texts[66] : GalleryStrings.texts[67]; font-size: 12px; font-weight: 500; color: root.lan-mode == lan ? white : WorkbenchStyle.muted; @@ -1154,7 +1155,7 @@ export component MainWindow inherits Window { y: connection-mode-switch.y; width: 80px; height: 28px; normal-background: white; - text: GalleryStrings.tr("桌面墙", "DeskHub", "DeskHub"); + text: GalleryStrings.texts[54]; z: 8; clicked => { root.open-gallery(); } } @@ -1164,7 +1165,7 @@ export component MainWindow inherits Window { width: 36px; height: 28px; normal-background: white; icon: FontAwesomeIcons.bars; - tooltip: GalleryStrings.tr("更多", "More", "Ещё"); + tooltip: GalleryStrings.texts[68]; z: 8; clicked => { root.gallery-action("release", ""); root.menu-open = !root.menu-open; } } @@ -1247,16 +1248,16 @@ export component MainWindow inherits Window { x: 0px; y: 0px; width: (parent.width - 16px) / 2; height: parent.height; Text { x: 16px; y: 14px; width: parent.width - 32px; height: 24px; overflow: elide; text: UiStrings.local-desktop; font-size: 16px; font-weight: 600; color: WorkbenchStyle.text; } - Text { x: 16px; y: 38px; width: parent.width - 32px; height: 18px; text: root.lan-mode ? GalleryStrings.tr("将 IP 和密码分享给连接方", "Share your IP and password to get connected", "Передайте IP и пароль для подключения") : GalleryStrings.tr("将 ID 和密码分享给连接方", "Share your ID and password to get connected", "Передайте ID и пароль для подключения"); font-size: 11px; color: WorkbenchStyle.muted; overflow: elide; } - local-address-label := Text { x: 16px; y: 68px; height: 18px; text: root.lan-mode ? GalleryStrings.tr("本机 IP / 端口", "Local IP / Port", "IP / Порт") : UiStrings.local-id; font-size: 12px; color: WorkbenchStyle.muted; vertical-alignment: top; } + Text { x: 16px; y: 38px; width: parent.width - 32px; height: 18px; text: root.lan-mode ? GalleryStrings.texts[69] : GalleryStrings.texts[70]; font-size: 11px; color: WorkbenchStyle.muted; overflow: elide; } + local-address-label := Text { x: 16px; y: 68px; height: 18px; text: root.lan-mode ? GalleryStrings.texts[71] : UiStrings.local-id; font-size: 12px; color: WorkbenchStyle.muted; vertical-alignment: top; } lan-switch-ip-metrics := Text { visible: false; accessible-role: none; - text: GalleryStrings.tr("切换 IP", "Switch IP", "Сменить IP"); + text: GalleryStrings.texts[72]; font-size: 12px; font-weight: 500; } lan-edit-port-metrics := Text { visible: false; accessible-role: none; - text: GalleryStrings.tr("修改端口", "Edit port", "Изменить порт"); + text: GalleryStrings.texts[73]; font-size: 12px; font-weight: 500; } lan-switch-ip-action := WorkbenchButton { @@ -1328,7 +1329,7 @@ export component MainWindow inherits Window { normal-outline-color: UiSurface.edge; hover-outline-color: UiSurface.hover; focus-outline-color: WorkbenchStyle.accent; - accessible-label: GalleryStrings.tr("切换本机 IP", "Switch local IP", "Сменить локальный IP"); + accessible-label: GalleryStrings.texts[74]; selected(index) => { root.copy-feedback = CopyFeedback.idle; // Save the draft for its original IP before changing @@ -1384,7 +1385,7 @@ export component MainWindow inherits Window { font-size: 18px * local-address-field.lan-font-scale; font-weight: 600; input-type: InputType.number; color: WorkbenchStyle.text; enabled: root.lan-mode && !root.lan-password-pending; - accessible-label: GalleryStrings.tr("局域网端口", "LAN port", "Порт LAN"); + accessible-label: GalleryStrings.texts[75]; vertical-alignment: center; horizontal-alignment: left; selection-foreground-color: white; selection-background-color: WorkbenchStyle.accent; changed has-focus => { @@ -1403,7 +1404,7 @@ export component MainWindow inherits Window { x: parent.width - 42px; y: 2px; width: 36px; quiet: true; icon: root.copy-feedback == CopyFeedback.success ? FontAwesomeIcons.check : FontAwesomeIcons.copy; icon-color: root.copy-feedback == CopyFeedback.success ? WorkbenchStyle.success : WorkbenchStyle.muted; - tooltip: root.lan-mode ? GalleryStrings.tr("复制 IP 和端口", "Copy IP and port", "Копировать IP и порт") : GalleryStrings.tr("复制本机 ID", "Copy local ID", "Копировать ID"); + tooltip: root.lan-mode ? GalleryStrings.texts[76] : GalleryStrings.texts[77]; enabled: !root.lan-mode || root.lan-listener-address != ""; tooltip-suppressed: root.copy-feedback != CopyFeedback.idle; // Let other controls receive the original click; moving @@ -1420,8 +1421,8 @@ export component MainWindow inherits Window { } private property edit-hint: !root.lan-mode || !root.sponsorship-unobstructed || root.lan-password-pending ? "" - : lan-ip-picker.has-hover ? GalleryStrings.tr("点击切换本机 IP", "Click to switch the local IP", "Нажмите, чтобы сменить IP") - : lan-port-hover.has-hover && !lan-port-editor.has-focus ? GalleryStrings.tr("点击修改端口", "Click to edit the port", "Нажмите, чтобы изменить порт") : ""; + : lan-ip-picker.has-hover ? GalleryStrings.texts[78] + : lan-port-hover.has-hover && !lan-port-editor.has-focus ? GalleryStrings.texts[79] : ""; private property edit-hint-visible; changed edit-hint => { local-address-field.edit-hint-visible = false; } Timer { @@ -1453,7 +1454,7 @@ export component MainWindow inherits Window { WorkbenchButton { x: parent.width - 112px; y: 0px; width: 36px; quiet: true; icon: root.active-password-visible ? FontAwesomeIcons.eye : FontAwesomeIcons.eye-slash; - tooltip: root.active-password-visible ? GalleryStrings.tr("隐藏密码", "Hide password", "Скрыть пароль") : GalleryStrings.tr("显示密码", "Show password", "Показать пароль"); + tooltip: root.active-password-visible ? GalleryStrings.texts[80] : GalleryStrings.texts[81]; clicked => { if root.lan-mode { root.lan-password-visible = !root.lan-password-visible; } else { root.toggle-password-visibility(); } } } WorkbenchButton { @@ -1465,7 +1466,7 @@ export component MainWindow inherits Window { WorkbenchButton { x: parent.width - 36px; y: 0px; width: 36px; quiet: true; icon: FontAwesomeIcons.pen; - tooltip: GalleryStrings.tr("修改密码", "Change password", "Изменить пароль"); + tooltip: GalleryStrings.texts[82]; enabled: root.lan-mode ? !root.lan-password-pending : !root.password-change-pending; clicked => { root.reset-password-open = true; } } @@ -1474,8 +1475,8 @@ export component MainWindow inherits Window { WorkbenchCard { x: local-card.width + 16px; y: 0px; width: local-card.width; height: parent.height; Text { x: 16px; y: 14px; width: parent.width - 32px; height: 24px; overflow: elide; text: UiStrings.remote-desktop; font-size: 16px; font-weight: 600; color: WorkbenchStyle.text; } - Text { x: 16px; y: 38px; width: parent.width - 32px; height: 18px; text: root.lan-mode ? GalleryStrings.tr("输入 IP:端口,通过局域网连接", "Enter IP:port to connect over LAN", "Введите IP:порт для подключения по LAN") : GalleryStrings.tr("输入设备 ID,连接远程桌面", "Enter a device ID to start a remote session", "Введите ID для удалённого подключения"); font-size: 11px; color: WorkbenchStyle.muted; overflow: elide; } - Text { x: 16px; y: 68px; height: 18px; text: root.lan-mode ? GalleryStrings.tr("远端 IP / 端口", "Remote IP / Port", "Удалённый IP / Порт") : UiStrings.remote-id; font-size: 12px; color: WorkbenchStyle.muted; } + Text { x: 16px; y: 38px; width: parent.width - 32px; height: 18px; text: root.lan-mode ? GalleryStrings.texts[83] : GalleryStrings.texts[84]; font-size: 11px; color: WorkbenchStyle.muted; overflow: elide; } + Text { x: 16px; y: 68px; height: 18px; text: root.lan-mode ? GalleryStrings.texts[85] : UiStrings.remote-id; font-size: 12px; color: WorkbenchStyle.muted; } FlatSurface { x: 16px; y: 90px; width: parent.width - 32px; height: 40px; background: remote-id-editor.has-focus ? ControlStyle.input-focused : ControlStyle.input-surface; @@ -1485,14 +1486,14 @@ export component MainWindow inherits Window { animate outline-color { duration: 120ms; } if root.remote-id-input == "": Text { x: 12px; width: parent.width - 24px; height: parent.height; - text: root.lan-mode ? "192.168.1.20:52888" : GalleryStrings.tr("请输入 9 位设备 ID", "Enter a 9-digit device ID", "Введите ID из 9 цифр"); + text: root.lan-mode ? "192.168.1.20:52888" : GalleryStrings.texts[86]; font-size: 13px; color: ControlStyle.input-placeholder; vertical-alignment: center; } remote-id-editor := TextInput { x: 12px; width: parent.width - 24px; height: parent.height; text <=> root.remote-id-input; font-size: root.lan-mode ? 18px : 24px; font-weight: 600; letter-spacing: root.lan-mode ? 0px : 1px; input-type: root.lan-mode ? InputType.text : InputType.number; color: WorkbenchStyle.text; - accessible-label: root.lan-mode ? GalleryStrings.tr("远端 IP / 端口", "Remote IP / Port", "Удалённый IP / Порт") : UiStrings.remote-id; + accessible-label: root.lan-mode ? GalleryStrings.texts[85] : UiStrings.remote-id; enabled: !root.connection-pending && !root.lan-connecting; vertical-alignment: center; selection-foreground-color: white; selection-background-color: WorkbenchStyle.accent; @@ -1512,13 +1513,13 @@ export component MainWindow inherits Window { Text { x: 16px; y: 133px; width: parent.width - 32px; height: 24px; text: root.connection-input-error != "" ? root.connection-input-error - : root.lan-mode ? GalleryStrings.tr("不填端口时,默认使用 52888", "Port defaults to 52888 if omitted", "Без порта используется 52888") : ""; + : root.lan-mode ? GalleryStrings.texts[87] : ""; font-size: 11px; color: root.connection-input-error != "" ? #be3d42 : WorkbenchStyle.muted; wrap: word-wrap; } WorkbenchButton { x: 16px; y: 158px; width: parent.width - 32px; height: 36px; primary: true; icon: FontAwesomeIcons.arrow-right-long; - text: root.connection-pending || root.lan-connecting ? GalleryStrings.tr("正在连接…", "Connecting…", "Подключение…") : UiStrings.connect; + text: root.connection-pending || root.lan-connecting ? GalleryStrings.texts[56] : UiStrings.connect; enabled: !root.connection-pending && !root.lan-connecting; clicked => { root.submit-connection(); } } @@ -1566,19 +1567,19 @@ export component MainWindow inherits Window { Text { x: 84px; y: 36px; width: parent.width - 104px; height: 24px; text: root.lan-mode - ? GalleryStrings.tr("暂无近期 IP 连接", "No recent IP connections", "Нет недавних IP-подключений") + ? GalleryStrings.texts[88] : root.recent-group-index == 0 - ? GalleryStrings.tr("暂无近期连接", "No recent connections", "Нет недавних подключений") - : GalleryStrings.tr("该分组暂无近期连接", "No recent connections in this group", "В этой группе нет недавних подключений"); + ? GalleryStrings.texts[89] + : GalleryStrings.texts[90]; color: WorkbenchStyle.text; font-size: 14px; font-weight: 600; } Text { x: 84px; y: 68px; width: parent.width - 104px; height: 20px; text: root.lan-mode - ? GalleryStrings.tr("通过 IP 连接过的设备会显示在这里。", "Devices you connect to by IP will appear here.", "Здесь появятся устройства, подключённые по IP.") + ? GalleryStrings.texts[91] : root.recent-group-index == 0 - ? GalleryStrings.tr("连接过的设备会显示在这里,方便下次快速访问。", "Devices you connect to will appear here for quick access.", "Устройства появятся здесь после первого подключения.") - : GalleryStrings.tr("切换设备分组,查看其他连接记录。", "Choose another group to see your other connections.", "Выберите другую группу для просмотра подключений."); + ? GalleryStrings.texts[92] + : GalleryStrings.texts[93]; color: WorkbenchStyle.muted; font-size: 12px; } } @@ -1762,12 +1763,12 @@ export component MainWindow inherits Window { compact-trigger: true; compact-menu: true; enabled: !root.gallery-mode; - text: GalleryStrings.tr("更多操作", "More actions", "Другие действия"); - menu-width: root.compact-language ? 116px : root.language-index == 2 ? 156px : 128px; + text: GalleryStrings.texts[94]; + menu-width: root.compact-language ? 116px : 156px; items: [ - {label: GalleryStrings.tr("修改名称", "Rename", "Переименовать"), enabled: true}, - {label: GalleryStrings.tr("修改分组", "Edit groups", "Изменить группы"), enabled: !connection.lan}, - {label: GalleryStrings.tr("删除记录", "Delete record", "Удалить запись"), enabled: true}, + {label: GalleryStrings.texts[35], enabled: true}, + {label: GalleryStrings.texts[30], enabled: !connection.lan}, + {label: GalleryStrings.texts[95], enabled: true}, ]; item-icons: [FontAwesomeIcons.pen, FontAwesomeIcons.tags, FontAwesomeIcons.trash-can]; destructive-index: 2; @@ -1794,7 +1795,7 @@ export component MainWindow inherits Window { primary: !connection.connected; destructive: connection.connected; icon: connection.connected ? FontAwesomeIcons.xmark : FontAwesomeIcons.arrow-right-long; - tooltip: connection.connected ? GalleryStrings.tr("断开连接", "Disconnect", "Отключить") : UiStrings.connect; + tooltip: connection.connected ? GalleryStrings.texts[96] : UiStrings.connect; tooltip-above: true; clicked => { root.copy-feedback = CopyFeedback.idle; @@ -1884,7 +1885,7 @@ export component MainWindow inherits Window { height: parent.height; width: parent.width - 160px; overflow: elide; - text: root.lan-mode ? (root.lan-message != "" ? LanStrings.error-message(root.lan-message) : root.lan-listener-error != "" ? (root.lan-listener-address == "" ? "" : root.lan-listener-address + " · ") + LanStrings.error-message(root.lan-listener-error) : root.lan-listening ? GalleryStrings.tr("IP 连接已启用", "IP connections enabled", "Подключения по IP включены") : root.lan-password-pending ? GalleryStrings.tr("IP 连接准备中…", "Preparing IP connections…", "Подготовка подключений по IP…") : GalleryStrings.tr("IP 连接未就绪", "IP connections not ready", "Подключения по IP не готовы")) + text: root.lan-mode ? (root.lan-message != "" ? LanStrings.error-message(root.lan-message) : root.lan-listener-error != "" ? (root.lan-listener-address == "" ? "" : root.lan-listener-address + " · ") + LanStrings.error-message(root.lan-listener-error) : root.lan-listening ? GalleryStrings.texts[97] : root.lan-password-pending ? GalleryStrings.texts[98] : GalleryStrings.texts[99]) : root.signal-tls-error ? UiStrings.tls-error : root.signal-connected ? UiStrings.signal-connected : root.signal-reconnecting ? UiStrings.signal-reconnecting @@ -1969,7 +1970,7 @@ export component MainWindow inherits Window { tooltip-status-text := Text { x: 7px; width: parent.width - 14px; height: parent.height; text: device-tip.online ? UiStrings.online : device-tip.presence-known ? UiStrings.offline - : GalleryStrings.tr("未知", "Unknown", "Неизвестно"); + : GalleryStrings.texts[100]; color: device-tip.status-color; font-size: 10px; font-weight: 600; vertical-alignment: center; } @@ -2013,14 +2014,14 @@ export component MainWindow inherits Window { tooltip-group-label := Text { x: 12px; y: tooltip-groups.y; width: device-tip.label-width; height: 16px; - text: GalleryStrings.tr("分组", "Groups", "Группы"); + text: GalleryStrings.texts[101]; color: WorkbenchStyle.muted; font-size: 10px; vertical-alignment: center; } tooltip-groups := Text { x: 20px + device-tip.label-width; y: tooltip-id-label.y + tooltip-id-label.height + 4px; width: parent.width - self.x - 12px; height: max(16px, self.preferred-height); - text: device-tip.group-names == "" ? GalleryStrings.tr("未分组", "Ungrouped", "Без группы") : device-tip.group-names; + text: device-tip.group-names == "" ? GalleryStrings.texts[31] : device-tip.group-names; color: device-tip.group-names == "" ? WorkbenchStyle.muted : WorkbenchStyle.accent; font-size: 10px; wrap: word-wrap; horizontal-alignment: right; vertical-alignment: center; @@ -2220,8 +2221,8 @@ export component MainWindow inherits Window { error: root.copy-feedback == CopyFeedback.failed; icon: self.error ? FontAwesomeIcons.xmark : FontAwesomeIcons.check; text: self.error - ? GalleryStrings.tr("复制失败,请重试", "Couldn’t copy. Try again", "Не удалось скопировать. Повторите попытку") - : root.lan-mode ? GalleryStrings.tr("IP 和端口已复制", "IP and port copied", "IP и порт скопированы") : UiStrings.copied; + ? GalleryStrings.texts[102] + : root.lan-mode ? GalleryStrings.texts[103] : UiStrings.copied; z: 30; } @@ -2332,7 +2333,7 @@ export component MainWindow inherits Window { height: 140px; VerticalLayout { padding: 20px; spacing: 18px; - DialogPromptText { prompt: root.delete-from-gallery ? (root.gallery-group-index > 0 ? GalleryStrings.tr("从当前分组移除此设备?", "Remove from this group?", "Убрать из этой группы?") : GalleryStrings.tr("从桌面墙移除此设备?", "Remove from DeskHub?", "Убрать из DeskHub?")) : UiStrings.confirm-delete; } + DialogPromptText { prompt: root.delete-from-gallery ? (root.gallery-group-index > 0 ? GalleryStrings.texts[104] : GalleryStrings.texts[105]) : UiStrings.confirm-delete; } HorizontalLayout { alignment: center; spacing: 8px; PrimaryButton { text: UiStrings.ok; clicked => { if root.delete-from-gallery { root.gallery-action("remove", root.delete-remote-id); } else { root.recent-delete(root.delete-remote-id); } root.delete-open = false; } } @@ -2385,7 +2386,7 @@ export component MainWindow inherits Window { padding: 24px; spacing: 16px; Text { - text: GalleryStrings.tr("确认断开连接?", "Disconnect this session?", "Отключить этот сеанс?"); + text: GalleryStrings.texts[106]; color: WorkbenchStyle.text; font-size: 18px; font-weight: 600; @@ -2407,7 +2408,7 @@ export component MainWindow inherits Window { } } Text { - text: GalleryStrings.tr("当前远程控制会话将结束。", "The current remote session will end.", "Текущий сеанс удалённого управления будет завершён."); + text: GalleryStrings.texts[107]; color: WorkbenchStyle.muted; font-size: 13px; wrap: word-wrap; @@ -2420,7 +2421,7 @@ export component MainWindow inherits Window { clicked => { root.dismiss-disconnect(); } } disconnect-confirm := WorkbenchButton { - text: GalleryStrings.tr("断开连接", "Disconnect", "Отключить"); + text: GalleryStrings.texts[96]; destructive: true; clicked => { let remote-id = root.disconnect-remote-id; @@ -2548,9 +2549,9 @@ export component MainWindow inherits Window { spacing: 12px; for permission[index] in [ {label: UiStrings.accessibility-permission, granted: root.accessibility-granted, - description: GalleryStrings.tr("允许远程键盘和鼠标控制", "Allow remote keyboard and mouse input", "Разрешить удалённый ввод с клавиатуры и мыши")}, + description: GalleryStrings.texts[108]}, {label: UiStrings.screen-recording-permission, granted: root.screen-recording-granted, - description: GalleryStrings.tr("允许共享此 Mac 的屏幕画面", "Allow sharing this Mac’s screen", "Разрешить показ экрана этого Mac")}, + description: GalleryStrings.texts[109]}, ]: WorkbenchCard { height: max(80px, permission-labels.preferred-height + 32px); permission-labels := VerticalLayout { @@ -2571,7 +2572,7 @@ export component MainWindow inherits Window { height: 36px; permission-action-metrics := Text { visible: false; font-size: 13px; font-weight: 600; - text: GalleryStrings.tr("前往设置", "Open settings", "Настройки"); + text: GalleryStrings.texts[110]; } if !permission.granted: WorkbenchButton { width: parent.width; height: parent.height; primary: true; @@ -2590,7 +2591,7 @@ export component MainWindow inherits Window { vertical-alignment: center; accessible-role: none; } Text { - text: GalleryStrings.tr("已授权", "Granted", "Разрешено"); + text: GalleryStrings.texts[111]; font-size: 12px; color: WorkbenchStyle.success; vertical-alignment: center; } } @@ -2601,9 +2602,7 @@ export component MainWindow inherits Window { spacing: 12px; SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; } Text { - text: GalleryStrings.tr("请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。", - "Allow CrossDesk access in System Settings. Reopen the app if macOS asks you to.", - "Разрешите доступ для CrossDesk в Системных настройках. Перезапустите приложение, если macOS попросит об этом."); + text: GalleryStrings.texts[112]; font-size: 11px; color: WorkbenchStyle.muted; wrap: word-wrap; } } @@ -2645,7 +2644,7 @@ export component MainWindow inherits Window { background: WorkbenchStyle.accent; border-radius: UiRadius.control; animate x { duration: 180ms; easing: ease-in-out; } } - for label[index] in [GalleryStrings.tr("常规", "General", "Общие"), GalleryStrings.tr("桌面墙", "DeskHub", "DeskHub")]: Rectangle { + for label[index] in [GalleryStrings.texts[113], GalleryStrings.texts[54]]: Rectangle { x: index == 1 ? parent.width / 2 + 1px : 2px; y: 2px; width: (parent.width - 6px) / 2; height: parent.height - 4px; accessible-role: button; accessible-label: label; @@ -2683,14 +2682,14 @@ export component MainWindow inherits Window { padding-right: settings-dialog.scrollbar-gutter; padding-bottom: 4px; spacing: 14px; SettingsGroup { - title: GalleryStrings.tr("界面", "Interface", "Интерфейс"); rows: 1; + title: GalleryStrings.texts[114]; rows: 1; SettingsRow { label: UiStrings.language; divider: false; - SettingsSelect { x: parent.width - 116px; y: 4px; width: 104px; model: ["中文", "English", "Русский"]; current-index <=> root.language-index; } + SettingsSelect { x: parent.width - 192px; y: 4px; width: 180px; model: root.language-options; current-index <=> root.language-index; } } } SettingsGroup { - title: GalleryStrings.tr("视频", "Video", "Видео"); + title: GalleryStrings.texts[115]; rows: root.capture-method-visible ? 2 : 1; if root.capture-method-visible: SettingsRow { label: UiStrings.capture-method; enabled: !root.settings-session-active; @@ -2702,9 +2701,9 @@ export component MainWindow inherits Window { } } SettingsGroup { - title: GalleryStrings.tr("网络连接", "Network", "Сеть"); rows: 3; + title: GalleryStrings.texts[116]; rows: 3; SettingsToggleRow { - label: GalleryStrings.tr("启用 IP 连接", "Enable IP connections", "Подключение по IP"); + label: GalleryStrings.texts[117]; checked <=> root.ip-direct-enabled-draft; } SettingsToggleRow { label: UiStrings.force-relay; checked <=> root.force-relay-enabled; enabled: !root.settings-session-active; } @@ -2715,7 +2714,7 @@ export component MainWindow inherits Window { self-host-edit := SettingsButton { x: parent.width - self.width - 60px; y: 4px; width: self-host-edit-metrics.preferred-width + 24px; height: 28px; - text: GalleryStrings.tr("编辑", "Edit", "Изменить"); + text: GalleryStrings.texts[118]; enabled: !root.settings-session-active; clicked => { root.self-host-settings-open = true; } self-host-edit-metrics := Text { @@ -2726,21 +2725,21 @@ export component MainWindow inherits Window { } } Text { - text: GalleryStrings.tr("关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。", "Disabling IP connections hides the mode button and ends IP sessions.", "Отключение подключений по IP скроет кнопку режима и завершит IP-сеансы."); + text: GalleryStrings.texts[119]; font-size: 11px; color: WorkbenchStyle.muted; wrap: word-wrap; } SettingsGroup { - title: GalleryStrings.tr("隐私保护", "Privacy", "Приватность"); rows: 3; + title: GalleryStrings.texts[120]; rows: 3; SettingsToggleRow { label: UiStrings.privacy-on-connect; checked <=> root.privacy-on-connect-enabled; enabled: root.privacy-setting-available; } SettingsToggleRow { label: UiStrings.privacy-local-unlock; checked <=> root.privacy-local-unlock-allowed; enabled: root.privacy-setting-available; } SettingsToggleRow { label: UiStrings.lock-on-disconnect; checked <=> root.lock-on-disconnect-enabled; enabled: root.lock-on-disconnect-available; divider: false; } } Text { - text: GalleryStrings.tr("最后一个远程控制端断开后,自动锁定本机。", "Lock this device when the last remote controller disconnects.", "Блокировать это устройство после отключения последнего управляющего клиента."); + text: GalleryStrings.texts[121]; font-size: 11px; color: WorkbenchStyle.muted; wrap: word-wrap; } SettingsGroup { - title: GalleryStrings.tr("本地存储", "Local storage", "Локальное хранение"); rows: 2; + title: GalleryStrings.texts[122]; rows: 2; SettingsToggleRow { label: UiStrings.save-remote-previews; checked <=> root.save-remote-previews; } SettingsRow { label: UiStrings.file-save-path; enabled: !root.settings-session-active; divider: false; @@ -2748,7 +2747,7 @@ export component MainWindow inherits Window { } } SettingsGroup { - title: GalleryStrings.tr("启动与后台", "Startup & background", "Запуск и фоновая работа"); rows: 2; + title: GalleryStrings.texts[123]; rows: 2; if !root.autostart-system-managed: SettingsToggleRow { label: UiStrings.autostart; checked <=> root.autostart-enabled; enabled: !root.settings-session-active; } if root.autostart-system-managed: SettingsToggleRow { label: UiStrings.autostart; @@ -2784,12 +2783,12 @@ export component MainWindow inherits Window { width: parent.width - 2 * settings-dialog.content-inset; height: 32px; spacing: 10px; Rectangle { horizontal-stretch: 1; } SettingsButton { - width: 80px; text: UiStrings.cancel; + width: max(80px, self.label-width); text: UiStrings.cancel; clicked => { root.cancel-settings(); root.settings-open = false; root.self-host-settings-open = false; } } SettingsButton { - width: 92px; primary: true; - text: GalleryStrings.tr("保存", "Save", "Сохранить"); + width: max(92px, self.label-width); primary: true; + text: GalleryStrings.texts[34]; clicked => { if root.save-settings() { root.settings-open = false; root.self-host-settings-open = false; } } } } @@ -2807,7 +2806,7 @@ export component MainWindow inherits Window { TouchArea { clicked => { focus-sink.focus(); } } Text { x: 24px; y: 18px; width: parent.width - 48px; height: 26px; - text: GalleryStrings.tr("设置开机自启动", "Set up auto start", "Настройка автозапуска"); + text: GalleryStrings.texts[124]; font-size: 18px; font-weight: 600; color: WorkbenchStyle.text; } ScrollView { @@ -2819,25 +2818,20 @@ export component MainWindow inherits Window { width: parent.width; padding: 0px; spacing: 12px; Text { text: root.autostart-status-text; color: WorkbenchStyle.accent; font-size: 13px; wrap: word-wrap; } Text { - text: root.autostart-status == AutostartStatus.unsupported ? GalleryStrings.tr( - "当前设备不支持开机自启动。", "This device does not support auto start.", "Это устройство не поддерживает автозапуск.") : - root.autostart-status == AutostartStatus.failed ? GalleryStrings.tr( - "无法读取系统状态。请刷新重试,或在系统设置中核对。", "Could not read the system status. Refresh to retry, or check System Settings.", "Не удалось прочитать состояние. Повторите попытку или проверьте настройки системы.") : - GalleryStrings.tr("请在系统设置中添加或移除本应用,返回后会自动刷新状态。", "Add or remove this app in system Settings. The status refreshes when you return.", "Добавьте или удалите приложение в настройках системы. После возвращения статус обновится."); + text: root.autostart-status == AutostartStatus.unsupported ? GalleryStrings.texts[125] : + root.autostart-status == AutostartStatus.failed ? GalleryStrings.texts[126] : + GalleryStrings.texts[127]; color: WorkbenchStyle.text; font-size: 13px; wrap: word-wrap; } if root.autostart-status != AutostartStatus.unsupported: Text { - text: GalleryStrings.tr( - "设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。", - "Settings → Apps & services → App startup management\n\nEnable: choose Add app, select CrossDesk, then choose Done.\n\nDisable: find this app in the startup list and choose Remove.", - "Настройки → Приложения и сервисы → Управление запуском\n\nВключить: добавьте CrossDesk в список и подтвердите выбор.\n\nВыключить: удалите приложение из списка автозапуска."); + text: GalleryStrings.texts[128]; color: WorkbenchStyle.text; font-size: 13px; wrap: word-wrap; } } } SettingsButton { x: 24px; y: parent.height - 48px; width: 112px; - text: GalleryStrings.tr("刷新状态", "Refresh status", "Обновить статус"); + text: GalleryStrings.texts[129]; enabled: root.autostart-status != AutostartStatus.checking; clicked => { root.refresh-autostart-status(); } } @@ -2882,7 +2876,7 @@ export component MainWindow inherits Window { } SurfaceSeparator { x: 18px; y: parent.height - 66px; width: parent.width - 36px; height: 1px; outline-color: UiSurface.separator; } SettingsButton { x: parent.width - 114px; y: parent.height - 50px; width: 92px; primary: true; text: UiStrings.ok; clicked => { if root.save-self-hosted-settings() { root.self-host-settings-open = false; } } } - SettingsButton { x: parent.width - 204px; y: parent.height - 50px; width: 80px; text: UiStrings.cancel; clicked => { root.cancel-self-hosted-settings(); root.self-host-settings-open = false; } } + SettingsButton { x: parent.width - 124px - self.width; y: parent.height - 50px; width: max(80px, self.label-width); text: UiStrings.cancel; clicked => { root.cancel-self-hosted-settings(); root.self-host-settings-open = false; } } } } diff --git a/apps/desktop/src/gui/ui/settings_controls.slint b/apps/desktop/src/gui/ui/settings_controls.slint index 84f56837..6f046050 100644 --- a/apps/desktop/src/gui/ui/settings_controls.slint +++ b/apps/desktop/src/gui/ui/settings_controls.slint @@ -11,6 +11,7 @@ export component SettingsButton inherits FlatSurface { in property quiet: false; in property align-left: false; in property enabled: true; + out property label-width: button-label.preferred-width + 2 * root.content-padding + (root.has-icon ? 24px : 0px); private property has-icon: root.icon.width > 0; private property content-padding: root.has-icon ? 8px : 12px; callback clicked(); diff --git a/apps/desktop/src/gui/ui/ui_localization.h b/apps/desktop/src/gui/ui/ui_localization.h index 2c2ec7ae..aefbd26e 100644 --- a/apps/desktop/src/gui/ui/ui_localization.h +++ b/apps/desktop/src/gui/ui/ui_localization.h @@ -40,7 +40,21 @@ inline int ApplyMainWindowStrings( int language_index) { const int language = localization::detail::ClampLanguageIndex(language_index); - window->global().set_language(language); + auto& gallery = window->global(); + gallery.set_language(language); + const auto& retry = localization::Literal("请在 {0} 秒后重试", language); + const auto split = retry.find("{0}"); + gallery.set_retry_prefix(Text(retry.substr(0, split))); + gallery.set_retry_suffix(Text(split == std::string::npos ? "" : retry.substr(split + 3))); + std::vector literals; + for (const auto* key : localization::detail::kSlintLiterals) + literals.push_back(Text(localization::Literal(key, language))); + gallery.set_texts(std::make_shared>(literals)); + std::vector languages; + for (const auto& option : localization::GetSupportedLanguages()) + languages.push_back(Text(option.display_name)); + languages.push_back(Text(localization::Literal("跟随系统", language))); + window->set_language_options(std::make_shared>(languages)); auto& strings = window->global(); strings.set_window_minimize(Text(localization::window_minimize[language])); strings.set_window_close(Text(localization::window_close[language])); diff --git a/apps/desktop/src/platform/linux/headless/headless_settings.cpp b/apps/desktop/src/platform/linux/headless/headless_settings.cpp index 3f585c7c..60074fe8 100644 --- a/apps/desktop/src/platform/linux/headless/headless_settings.cpp +++ b/apps/desktop/src/platform/linux/headless/headless_settings.cpp @@ -25,15 +25,15 @@ std::optional Boolean(const std::string& value) { return std::nullopt; } const char* OnOff(bool value) { return value ? "on" : "off"; } -const char* languages[] = {"zh-CN", "en-US", "ru-RU"}; +const char* languages[] = {"zh-CN", "en-US", "ru-RU", "zh-Hant", "ja", "ko", "de", "fr", "es", "pt-BR", "system"}; const char* turn_modes[] = {"off", "auto", "udp", "tcp"}; } // namespace std::vector GetConsoleSettings(const ConfigCenter& config) { - const auto language = std::clamp(static_cast(config.GetLanguage()), 0, 2); + const auto language = std::clamp(static_cast(config.GetLanguage()), 0, 10); const auto turn = std::clamp(static_cast(config.GetTurnMode()), 0, 3); return { - {"language", "console_setting_language", languages[language], "zh-CN / en-US / ru-RU"}, + {"language", "console_setting_language", languages[language], "system / zh-CN / en-US / ru-RU / zh-Hant / ja / ko / de / fr / es / pt-BR"}, {"codec", "console_setting_codec", config.GetVideoEncodeFormat() == ConfigCenter::VIDEO_ENCODE_FORMAT::AV1 ? "av1" : "h264", "h264 / av1"}, {"turn", "console_setting_turn", turn_modes[turn], "off / auto / udp / tcp"}, {"self_hosted", "console_setting_self_hosted", OnOff(config.IsSelfHosted()), "on / off"}, @@ -70,6 +70,10 @@ SettingResult ApplyConsoleSetting(ConfigCenter& config, const std::string& key, int language = value == "zh-cn" || value == "zh" || value == "0" ? 0 : value == "en-us" || value == "en" || value == "1" ? 1 : value == "ru-ru" || value == "ru" || value == "2" ? 2 : -1; + if (language < 0) { + for (int i = 0; i <= 10; ++i) + if (value == Lower(languages[i]) || value == std::to_string(i)) language = i; + } if (language < 0) return result; canonical = languages[language]; save = [&config, language] { return config.SetLanguage(static_cast(language)); }; diff --git a/apps/harmony/desktop-port/DesktopHost.ets b/apps/harmony/desktop-port/DesktopHost.ets index 81d5e24a..9765a8d9 100644 --- a/apps/harmony/desktop-port/DesktopHost.ets +++ b/apps/harmony/desktop-port/DesktopHost.ets @@ -1,3 +1,4 @@ +import { i18n } from '@kit.LocalizationKit'; import native from 'libslint_desktop.so'; import { TextInputHost } from './TextInputHost'; import { TrayHost } from './TrayHost'; @@ -128,7 +129,7 @@ export class DesktopHost { if (event.op === 'clipboardChanged') DesktopHost.clipboardChanged(); else DesktopHost.send(event); }, hostPermissions); - native.start(JSON.stringify({ filesDir: context.filesDir, cacheDir: context.cacheDir, + native.start(JSON.stringify({ language: i18n.System.getSystemLanguage(), filesDir: context.filesDir, cacheDir: context.cacheDir, width: screen.width, height: screen.height, density: screen.densityPixels, displayId: screen.id, displays: screens, name: 'Harmony PC', certificates: certificateManager.getCertificateStorePath({ certType: certificateManager.CertType.CA_CERT_SYSTEM }) })); diff --git a/apps/harmony/desktop-port/desktop.cpp b/apps/harmony/desktop-port/desktop.cpp index 9c9dabf8..805f0c96 100644 --- a/apps/harmony/desktop-port/desktop.cpp +++ b/apps/harmony/desktop-port/desktop.cpp @@ -307,6 +307,8 @@ napi_value Start(napi_env env, napi_callback_info info) { stopping = false; gui_thread = std::thread([] { try { + const auto language = Environment().value("language", "en"); + setenv("LANGUAGE", language.c_str(), 1); setenv("SLINT_DEFAULT_FONT", "/system/fonts/HarmonyOS_Sans.ttf", 1); setenv("SLINT_FONT_PATH", "/system/fonts/HarmonyOS_Sans_SC.ttf", 1); const auto certificates = Environment().value("certificates", ""); diff --git a/apps/harmony/entry/src/main/ets/mobile/ControllerModels.ets b/apps/harmony/entry/src/main/ets/mobile/ControllerModels.ets index 42c2048b..026932db 100644 --- a/apps/harmony/entry/src/main/ets/mobile/ControllerModels.ets +++ b/apps/harmony/entry/src/main/ets/mobile/ControllerModels.ets @@ -1,3 +1,4 @@ +import { tr } from './Localization'; // Platform-independent controller rules ported from the Android client. // Keep gesture geometry, acknowledgement ordering and expiry behavior identical. export function clamp(value: number, low: number, high: number): number { @@ -96,7 +97,7 @@ export class VideoSettings { this.pending = false; this.failed = !accepted; this.selection = this.applied; } expire(id: number): void { if (this.pending && id === this.requestId) { this.pending = false; this.failed = true; this.selection = this.applied; } } - feedback(): string { return !this.supported ? '连接建立后可调整,需被控端支持。' : this.failed ? '调整失败,请重试。' : this.pending ? '等待电脑端确认…' : ''; } + feedback(): string { return !this.supported ? tr("连接建立后可调整,需被控端支持。") : this.failed ? tr("调整失败,请重试。") : this.pending ? tr("等待电脑端确认…") : ''; } } export interface Traffic { inbound: number; outbound: number; loss: number; } export interface NetworkReport { rtt: number; mode: number; srtp: boolean; decoder?: string; video: Traffic; audio: Traffic; data: Traffic; total: Traffic; } @@ -133,7 +134,7 @@ export class NetworkStatistics { return count ? valid.reduce((n: number, f: FrameSample) => n + f.latency * f.latencyCount, 0) / count : -1; } current(now: number): NetworkReport | undefined { return now - this.reportTime < 3000 ? this.report : undefined; } - mode(now: number): string { const report = this.current(now); return !report ? '—' : report.mode === 0 ? 'P2P 直连' : report.mode === 1 ? 'TURN 中继' : '—'; } + mode(now: number): string { const report = this.current(now); return !report ? '—' : report.mode === 0 ? tr("P2P 直连") : report.mode === 1 ? tr("TURN 中继") : '—'; } static rate(n: number): string { return !Number.isFinite(n) || n < 0 ? '—' : n >= 1000000 ? `${(n / 1000000).toFixed(1)} Mbps` : n >= 1000 ? `${(n / 1000).toFixed(0)} Kbps` : `${n} bps`; } static loss(n: number): string { return Number.isFinite(n) && n >= 0 ? `${(n * 100).toFixed(1)}%` : '—'; } static delay(n: number): string { return !Number.isFinite(n) || n < 0 ? '—' : n < 1 ? '<1 ms' : `${n.toFixed(0)} ms`; } diff --git a/apps/harmony/entry/src/main/ets/mobile/EntryAbility.ets b/apps/harmony/entry/src/main/ets/mobile/EntryAbility.ets index f64f4ff1..087c09dc 100644 --- a/apps/harmony/entry/src/main/ets/mobile/EntryAbility.ets +++ b/apps/harmony/entry/src/main/ets/mobile/EntryAbility.ets @@ -1,3 +1,5 @@ +import { i18n } from '@kit.LocalizationKit'; +import { setLanguageProvider } from './Localization'; import { UIAbility } from '@kit.AbilityKit'; import { window } from '@kit.ArkUI'; import { hilog } from '@kit.PerformanceAnalysisKit'; @@ -5,6 +7,7 @@ import { MobileLifecycle } from './MobilePlatform'; export default class EntryAbility extends UIAbility { onWindowStageCreate(stage: window.WindowStage): void { + setLanguageProvider(() => i18n.System.getSystemLanguage()); stage.loadContent('pages/Mobile', (error) => { if (error.code) hilog.error(0, 'CrossDesk', 'Unable to load the main page: %{public}d', error.code); }); diff --git a/apps/harmony/entry/src/main/ets/mobile/Localization.ets b/apps/harmony/entry/src/main/ets/mobile/Localization.ets new file mode 100644 index 00000000..323c835b --- /dev/null +++ b/apps/harmony/entry/src/main/ets/mobile/Localization.ets @@ -0,0 +1,37 @@ +import { translations } from './LocalizationData'; + +let languageProvider: (() => string) | undefined = undefined; + +export function setLanguageProvider(provider: () => string): void { + languageProvider = provider; +} + +export function languageIndex(tag: string): number { + const value = tag.toLowerCase().replace(/_/g, '-').split('.')[0].split('@')[0]; + const base = value.split('-')[0]; + if (base === 'zh') { + const parts = '-' + value + '-'; + if (parts.includes('-hans-')) return 0; + return ['-hant-', '-tw-', '-hk-', '-mo-'].some((part: string) => parts.includes(part)) ? 3 : 0; + } + const codes = ['zh', 'en', 'ru', 'zh-hant', 'ja', 'ko', 'de', 'fr', 'es', 'pt']; + const index = codes.indexOf(base); + return index < 0 ? 1 : index; +} + +export function currentLanguage(): number { + try { return languageProvider ? languageIndex(languageProvider()) : 1; } + catch { return 1; } +} + +export function tr(key: string, args: string[] = []): string { + // The pure models can also run before an ability installs its locale provider. + const values = translations[key]; + let text = languageProvider && values ? values[currentLanguage()] || values[1] : key; + // A single replacement pass avoids interpreting placeholder-like user data. + text = text.replace(/\{(\d+)\}/g, (match: string, index: string) => { + const value = args[Number(index)]; + return value === undefined ? match : value; + }); + return text; +} diff --git a/apps/harmony/entry/src/main/ets/mobile/LocalizationData.ets b/apps/harmony/entry/src/main/ets/mobile/LocalizationData.ets new file mode 100644 index 00000000..c718d1df --- /dev/null +++ b/apps/harmony/entry/src/main/ets/mobile/LocalizationData.ets @@ -0,0 +1,243 @@ +// Generated by localization/generate.py. +export const translations: Record = { + "OpenFEC 告知": ["OpenFEC 告知", "OpenFEC notice", "Уведомление OpenFEC", "OpenFEC 告知", "OpenFEC通知", "OpenFEC공지", "OpenFEC-Hinweis", "Avis OpenFEC", "Aviso OpenFEC", "Aviso OpenFEC"], + "OpenFEC 提供前向纠错能力,遵循 CeCILL-C 1.0 许可。其许可规定了有限保证及责任限制,请阅读组件详情。": ["OpenFEC 提供前向纠错能力,遵循 CeCILL-C 1.0 许可。其许可规定了有限保证及责任限制,请阅读组件详情。", "OpenFEC provides forward error correction capabilities and is licensed under theCeCILL-C1.0 license. The license provides for a limited warranty and limitations of liability, please read the component details.", "OpenFEC обеспечивает возможности прямого исправления ошибок и лицензируется по лицензии CeCILL-C1.0. Лицензия предусматривает ограниченную гарантию и ограничение ответственности. Пожалуйста, ознакомьтесь с подробностями компонента.", "OpenFEC 提供前向糾錯能力,遵循 CeCILL-C 1.0 許可。其許可規定了有限保證及責任限制,請閱讀元件詳情。", "OpenFECは前方誤り訂正機能を提供し、CeCILL-C1.0 ライセンスに基づいてライセンスされています。ライセンスには限定保証と責任制限が規定されています。コンポーネントの詳細をお読みください。", "OpenFEC는 순방향 오류 수정 기능을 제공하며 CeCILL-C1.0 라이선스에 따라 라이선스가 부여됩니다. 라이센스는 제한된 보증 및 책임 제한을 제공합니다. 구성 요소 세부 정보를 읽어보십시오.", "OpenFEC bietet Vorwärtsfehlerkorrekturfunktionen und ist unter der CeCILL-C1.0-Lizenz lizenziert. Die Lizenz sieht eine eingeschränkte Garantie und Haftungsbeschränkungen vor. Bitte lesen Sie die Komponentendetails.", "OpenFEC fournit des capacités de correction d'erreur directe et est sous licence CeCILL-C1.0. La licence prévoit une garantie limitée et des limitations de responsabilité, veuillez lire les détails des composants.", "OpenFEC proporciona capacidades de corrección de errores hacia adelante y tiene la licencia CeCILL-C1.0. La licencia proporciona una garantía limitada y limitaciones de responsabilidad; lea los detalles del componente.", "OpenFEC fornece recursos de correção direta de erros e é licenciado sob a licença CeCILL-C1.0. A licença fornece uma garantia limitada e limitações de responsabilidade. Leia os detalhes do componente."], + "P2P 直连": ["P2P 直连", "P2P direct connection", "Прямое соединение P2P", "P2P 直連", "P2P直接接続", "P2P 직접 연결", "P2P-Direktverbindung", "Connexion directe P2P", "Conexión directa P2P", "Conexão direta P2P"], + "SRTP 已启用": ["SRTP 已启用", "SRTP enabled", "SRTP включен", "SRTP 已啟用", "SRT有効", "SRTP 활성화됨", "SRTP enabled", "SRTP activé", "SRTP habilitado", "SRT habilitado"], + "TURN 中继": ["TURN 中继", "TURN relay", "Реле ПОВОРОТА", "TURN 中繼", "ターンリレー", "TURN 릴레이", "TURN-Relais", "Relais TOUR", "Relé de GIRO", "GIRAR relé"], + "{0} 传输失败": ["{0} 传输失败", "{0} transmission failed", "Передача {0} не удалась.", "{0} 傳輸失敗", "{0}送信失敗", "{0}전송 실패", "{0}-Übertragung fehlgeschlagen", "Échec de la transmission {0}", "Error en la transmisión {0}", "Falha na transmissão {0}"], + "{0} 台设备": ["{0} 台设备", "Devices: {0}", "Устройства: {0}", "{0} 臺裝置", "デバイス数: {0}", "기기: {0}", "Geräte: {0}", "Appareils : {0}", "Dispositivos: {0}", "Dispositivos: {0}"], + "丢包率": ["丢包率", "Loss Rate", "Потери пакетов", "丟包率", "損失率", "손실률", "Verlustrate", "Taux de perte", "Tasa de pérdidas", "Taxa de perda"], + "中": ["中", "Medium", "Среднее", "中", "中", "중간", "Mittel", "Moyenne", "Media", "Média"], + "中文等文本请通过剪贴板发送,再点击粘贴": ["中文等文本请通过剪贴板发送,再点击粘贴", "Please send Chinese and other texts via the clipboard, then click paste", "Отправьте текст на китайском и других языках через буфер обмена, затем нажмите «Вставить».", "中文等文字請透過剪貼簿傳送,再點選貼上", "中国語やその他のテキストをクリップボード経由で送信し、貼り付けをクリックしてください", "클립보드를 통해 중국어 및 기타 문자를 보내신 후 붙여넣기를 눌러주세요.", "Bitte senden Sie chinesische und andere Texte über die Zwischenablage und klicken Sie dann auf Einfügen", "Veuillez envoyer les textes chinois et autres via le presse-papiers, puis cliquez sur Coller", "Envíe textos en chino y otros a través del portapapeles, luego haga clic en pegar", "Envie textos em chinês e outros textos através da área de transferência e clique em colar"], + "低": ["低", "Low", "Низкое", "低", "低", "낮음", "Niedrig", "Faible", "Baja", "Baixa"], + "使用自定义服务器": ["使用自定义服务器", "Using a custom server", "Использование пользовательского сервера", "使用自定義伺服器", "カスタムサーバーの使用", "커스텀 서버 이용하기", "Verwendung eines benutzerdefinierten Servers", "Utilisation d'un serveur personnalisé", "Usando un servidor personalizado", "Usando um servidor personalizado"], + "保存密码": ["保存密码", "Save password", "Сохранить пароль", "儲存密碼", "パスワードの保存", "비밀번호 저장", "Passwort speichern", "Enregistrer le mot de passe", "Guardar contraseña", "Salvar senha"], + "保存收到的文件": ["保存收到的文件", "Save received file", "Сохранить полученный файл", "儲存收到的檔案", "受信したファイルを保存する", "수신된 파일 저장", "Empfangene Datei speichern", "Enregistrer le fichier reçu", "Guardar archivo recibido", "Salvar arquivo recebido"], + "保存远程画面预览": ["保存远程画面预览", "Save remote screen previews", "Сохранять превью удалённого экрана", "儲存遠端畫面預覽", "リモート画面のプレビューを保存する", "원격 화면 미리보기 저장", "Remote-Bildschirmvorschauen speichern", "Enregistrer les aperçus de l'écran distant", "Guardar vistas previas de pantalla remotas", "Salvar visualizações de tela remotas"], + "保存远程画面预览?": ["保存远程画面预览?", "Save remote screen preview?", "Сохранить предварительный просмотр удаленного экрана?", "儲存遠端畫面預覽?", "リモート画面のプレビューを保存しますか?", "원격 화면 미리보기를 저장하시겠습니까?", "Remote-Bildschirmvorschau speichern?", "Enregistrer l'aperçu de l'écran distant ?", "¿Guardar vista previa de pantalla remota?", "Salvar visualização remota da tela?"], + "全选": ["全选", "Select all", "Выбрать все", "全選", "全て選択", "모두 선택", "Alles auswählen", "Sélectionner tout", "Seleccionar todo", "Selecionar tudo"], + "公告详情": ["公告详情", "Announcement details", "Подробности объявления", "公告詳情", "発表内容", "공지사항", "Einzelheiten zur Ankündigung", "Détails de l'annonce", "Detalles del anuncio", "Detalhes do anúncio"], + "关于": ["关于", "About", "О программе", "關於", "概要", "소개", "Ungefähr", "À propos", "Acerca de", "Sobre"], + "关于 CrossDesk": ["关于 CrossDesk", "About CrossDesk", "О CrossDesk", "關於 CrossDesk", "CrossDesk について", "CrossDesk 정보", "Über CrossDesk", "À propos de CrossDesk", "Acerca de CrossDesk", "Sobre o CrossDesk"], + "关闭": ["关闭", "Close", "Закрыть", "關閉", "閉じる", "닫기", "Schließen", "Fermer", "Cerrar", "Fechar"], + "关闭控制栏": ["关闭控制栏", "Close control bar", "Закрыть панель управления", "關閉控制欄", "コントロールバーを閉じる", "컨트롤 바 닫기", "Bedienbügel schließen", "Fermer la barre de contrôle", "Cerrar barra de control", "Fechar barra de controle"], + "分辨率": ["分辨率", "Resolution", "Разрешение", "解析度", "解像度", "해상도", "Auflösung", "Résolution", "Resolución", "Resolução"], + "删除": ["删除", "Delete", "Удалить", "刪除", "削除", "삭제", "Löschen", "Supprimer", "Eliminar", "Excluir"], + "删除公告": ["删除公告", "Delete announcement", "Удалить объявление", "刪除公告", "お知らせの削除", "공지사항 삭제", "Ansage löschen", "Supprimer l'annonce", "Eliminar anuncio", "Excluir anúncio"], + "删除公告?": ["删除公告?", "Delete announcement?", "Удалить объявление?", "刪除公告?", "お知らせを削除しますか?", "공지사항을 삭제하시겠습니까?", "Ankündigung löschen?", "Supprimer l'annonce ?", "¿Eliminar anuncio?", "Excluir anúncio?"], + "删除记录": ["删除记录", "Delete record", "Удалить запись", "刪除記錄", "レコードの削除", "기록 삭제", "Datensatz löschen", "Supprimer l'enregistrement", "Eliminar registro", "Excluir registro"], + "删除记录?": ["删除记录?", "Delete records?", "Удалить записи?", "刪除記錄?", "記録を削除しますか?", "기록을 삭제하시겠습니까?", "Datensätze löschen?", "Supprimer les enregistrements ?", "¿Eliminar registros?", "Excluir registros?"], + "刷新公告": ["刷新公告", "Refresh announcement", "Обновить объявление", "重新整理公告", "リフレッシュのお知らせ", "새로고침 안내", "Ankündigung aktualisieren", "Actualiser l'annonce", "Actualizar anuncio", "Anúncio de atualização"], + "剪贴板": ["剪贴板", "Clipboard", "Буфер обмена", "剪貼簿", "クリップボード", "클립보드", "Zwischenablage", "Presse-papiers", "Portapapeles", "Área de transferência"], + "加载失败,点击重试": ["加载失败,点击重试", "Loading failed, click to try again", "Не удалось загрузить. Нажмите, чтобы повторить попытку.", "載入失敗,點選重試", "読み込みに失敗しました。クリックして再試行してください", "로드에 실패했습니다. 다시 시도하려면 클릭하세요.", "Der Ladevorgang ist fehlgeschlagen. Klicken Sie hier, um es erneut zu versuchen", "Échec du chargement, cliquez pour réessayer", "Error al cargar, haga clic para intentarlo de nuevo", "Falha no carregamento, clique para tentar novamente"], + "加载更多": ["加载更多", "Load more", "Загрузить еще", "載入更多", "さらに読み込む", "더 로드하기", "Mehr laden", "Charger plus", "Cargar más", "Carregue mais"], + "升级提示": ["升级提示", "Update recommended", "Рекомендуется обновление", "更新提示", "更新のご案内", "업데이트 안내", "Update empfohlen", "Mise à jour conseillée", "Actualización recomendada", "Atualização recomendada"], + "原生通信库不可用,请重新构建并安装": ["原生通信库不可用,请重新构建并安装", "The native communication library is not available, please rebuild and install it", "Собственная коммуникационная библиотека недоступна, пересоберите и установите ее.", "原生通訊庫不可用,請重新構建並安裝", "ネイティブ通信ライブラリは利用できません。再構築してインストールしてください。", "기본 통신 라이브러리를 사용할 수 없습니다. 다시 빌드하고 설치하십시오.", "Die native Kommunikationsbibliothek ist nicht verfügbar. Bitte erstellen und installieren Sie sie neu", "La bibliothèque de communication native n'est pas disponible, veuillez la reconstruire et l'installer", "La biblioteca de comunicación nativa no está disponible; reconstrúyala e instálela", "A biblioteca de comunicação nativa não está disponível, reconstrua-a e instale-a"], + "发现新版本 {0}": ["发现新版本 {0}", "Found new version {0}", "Найдена новая версия {0}.", "發現新版本 {0}", "新しいバージョン{0}が見つかりました", "새 버전{0}발견", "Neue Version {0} gefunden", "Nouvelle version trouvée {0}", "Nueva versión encontrada {0}", "Nova versão encontrada {0}"], + "发送": ["发送", "Send", "Отправка", "傳送", "送信", "송신", "Senden", "Envoi", "Enviar", "Enviar"], + "发送 {0} · 0%": ["发送 {0} · 0%", "Send {0}· 0%", "Отправить {0}· 0%", "傳送 {0} · 0%", "{0} を送信 · 0%", "{0}보내기 · 0%", "Senden {0}· 0 %", "Envoyer {0}· 0%", "Enviar {0}· 0%", "Enviar {0}· 0%"], + "发送文件": ["发送文件", "Send file", "Отправить файл", "傳送檔案", "ファイル送信", "파일 보내기", "Datei senden", "Envoyer le fichier", "Enviar archivo", "Enviar arquivo"], + "发送文本": ["发送文本", "Send text", "Отправить текст", "傳送文字", "テキストを送信する", "문자 보내기", "Text senden", "Envoyer un SMS", "Enviar texto", "Enviar texto"], + "发送文本后,点击“粘贴到远端”使用。": ["发送文本后,点击“粘贴到远端”使用。", "After sending the text, click \"Paste to Remote\" to use.", "После отправки текста нажмите «Вставить на удаленный компьютер», чтобы использовать его.", "傳送文字後,點選“貼上到遠端”使用。", "テキストを送信後、「リモートに貼り付け」をクリックして使用します。", "문자 전송 후 \"원격에 붙여넣기\"를 클릭하여 사용하세요.", "Klicken Sie nach dem Senden des Textes auf „In Remote einfügen“, um ihn zu verwenden.", "Après avoir envoyé le texte, cliquez sur \"Coller sur Remote\" pour l'utiliser.", "Después de enviar el texto, haga clic en \"Pegar en control remoto\" para usarlo.", "Após enviar o texto, clique em “Colar no Remoto” para usar."], + "取消": ["取消", "Cancel", "Отмена", "取消", "キャンセル", "취소", "Abbrechen", "Annuler", "Cancelar", "Cancelar"], + "取消连接": ["取消连接", "Cancel connection", "Отмена соединения", "取消連線", "接続をキャンセルする", "연결 취소", "Verbindung abbrechen", "Annuler la connexion", "Cancelar conexión", "Cancelar conexão"], + "各组件遵循所列开源许可证。许可与版权声明可离线查阅,查看源码需要网络连接。": ["各组件遵循所列开源许可证。许可与版权声明可离线查阅,查看源码需要网络连接。", "Each component is covered by the listed open source license. The license and copyright statement can be viewed offline, and an Internet connection is required to view the source code.", "На каждый компонент распространяется указанная лицензия с открытым исходным кодом. Лицензию и заявление об авторских правах можно просмотреть в автономном режиме, а для просмотра исходного кода требуется подключение к Интернету.", "各元件遵循所列開源許可證。許可與版權宣告可離線查閱,檢視原始碼需要網路連線。", "各コンポーネントは、リストされているオープンソース ライセンスの対象となります。ライセンスと著作権に関する声明はオフラインでも表示できますが、ソース コードを表示するにはインターネット接続が必要です。", "각 구성 요소에는 나열된 오픈 소스 라이선스가 적용됩니다. 라이센스 및 저작권 표시는 오프라인으로 볼 수 있으며, 소스 코드를 보려면 인터넷 연결이 필요합니다.", "Jede Komponente unterliegt der aufgeführten Open-Source-Lizenz. Die Lizenz- und Urheberrechtserklärung kann offline angezeigt werden. Zum Anzeigen des Quellcodes ist eine Internetverbindung erforderlich.", "Chaque composant est couvert par la licence open source répertoriée. La licence et la déclaration de droits d'auteur peuvent être consultées hors ligne et une connexion Internet est requise pour afficher le code source.", "Cada componente está cubierto por la licencia de código abierto indicada. La declaración de licencia y derechos de autor se puede ver sin conexión y se requiere una conexión a Internet para ver el código fuente.", "Cada componente é coberto pela licença de código aberto listada. A licença e a declaração de direitos autorais podem ser visualizadas offline e é necessária uma conexão com a Internet para visualizar o código-fonte."], + "合计": ["合计", "Total", "Итого", "合計", "合計", "합계", "Insgesamt", "Total", "Total", "Total"], + "同意并继续": ["同意并继续", "Agree and continue", "Согласитесь и продолжайте.", "同意並繼續", "同意して続行", "동의하고 계속하기", "Zustimmen und fortfahren", "Accepter et continuer", "Aceptar y continuar", "Concorde e continue"], + "同意联网后可查看公告": ["同意联网后可查看公告", "You can view the announcement after agreeing to connect to the Internet", "Посмотреть объявление можно после согласия на подключение к Интернету.", "同意聯網後可檢視公告", "インターネットへの接続に同意するとお知らせがご覧いただけます", "공지사항은 인터넷 연결 동의 후 보실 수 있습니다.", "Sie können die Ankündigung ansehen, nachdem Sie der Verbindung mit dem Internet zugestimmt haben", "Vous pouvez consulter l'annonce après avoir accepté de vous connecter à Internet", "Puede ver el anuncio después de aceptar conectarse a Internet.", "Você pode ver o anúncio depois de concordar em se conectar à Internet"], + "同时删除该设备保存的密码和预览。": ["同时删除该设备保存的密码和预览。", "Also deletes passwords and previews saved by the device.", "Также удаляет пароли и предварительный просмотр, сохраненные на устройстве.", "同時刪除該裝置儲存的密碼和預覽。", "デバイスに保存されているパスワードとプレビューも削除します。", "기기에 저장된 비밀번호와 미리보기도 삭제됩니다.", "Löscht auch vom Gerät gespeicherte Passwörter und Vorschauen.", "Supprime également les mots de passe et les aperçus enregistrés par l'appareil.", "También elimina contraseñas y vistas previas guardadas por el dispositivo.", "Também exclui senhas e visualizações salvas pelo dispositivo."], + "在线": ["在线", "Online", "В сети", "線上", "オンライン", "온라인", "Online", "En ligne", "En línea", "On-line"], + "声音": ["声音", "Sound", "Звук", "聲音", "サウンド", "소리", "Ton", "Son", "Sonido", "Som"], + "复制": ["复制", "Copy", "Копировать", "複製", "コピー", "복사", "Kopieren", "Copier", "Copiar", "Copiar"], + "复制失败,请重试": ["复制失败,请重试", "Couldn’t copy. Try again", "Не удалось скопировать. Повторите попытку", "複製失敗,請重試", "コピーできませんでした。もう一度試してください", "복사할 수 없습니다. 다시 시도하세요", "Kopieren nicht möglich. Versuchen Sie es erneut", "Impossible de copier. Réessayez", "No se pudo copiar. Inténtalo de nuevo", "Não foi possível copiar. Tente novamente"], + "复制远端文本": ["复制远端文本", "Copy remote text", "Копирование удаленного текста", "複製遠端文字", "リモートテキストをコピーする", "원격 텍스트 복사", "Remote-Text kopieren", "Copier le texte distant", "Copiar texto remoto", "Copiar texto remoto"], + "媒体加密": ["媒体加密", "Media encryption", "Шифрование мультимедиа", "媒體加密", "メディアの暗号化", "미디어 암호화", "Medienverschlüsselung", "Cryptage multimédia", "Cifrado de medios", "Criptografia de mídia"], + "安全存储不可用,请解锁设备后重试": ["安全存储不可用,请解锁设备后重试", "Secure storage is unavailable, please unlock the device and try again", "Безопасное хранилище недоступно. Разблокируйте устройство и повторите попытку.", "安全儲存不可用,請解鎖裝置後重試", "安全なストレージが利用できません。デバイスのロックを解除して、もう一度お試しください。", "보안 저장소를 사용할 수 없습니다. 장치를 잠금 해제한 후 다시 시도해 주세요.", "Der sichere Speicher ist nicht verfügbar. Bitte entsperren Sie das Gerät und versuchen Sie es erneut", "Le stockage sécurisé n'est pas disponible, veuillez déverrouiller l'appareil et réessayer", "El almacenamiento seguro no está disponible. Desbloquee el dispositivo e inténtelo nuevamente.", "O armazenamento seguro não está disponível. Desbloqueie o dispositivo e tente novamente"], + "完成": ["完成", "Done", "Готово", "完成", "完了", "완료", "Fertig", "Terminé", "Hecho", "Feito"], + "密码保存失败,本次连接仍可使用": ["密码保存失败,本次连接仍可使用", "Password saving failed, this connection can still be used", "Не удалось сохранить пароль, это соединение все еще можно использовать.", "密碼儲存失敗,本次連線仍可使用", "パスワードの保存に失敗しました。この接続はまだ使用できます", "비밀번호 저장에 실패했습니다. 이 연결은 계속 사용할 수 있습니다.", "Das Speichern des Passworts ist fehlgeschlagen. Diese Verbindung kann weiterhin verwendet werden", "L'enregistrement du mot de passe a échoué, cette connexion peut toujours être utilisée", "Error al guardar la contraseña, esta conexión aún se puede utilizar", "Falha ao salvar a senha, esta conexão ainda pode ser usada"], + "密码将加密保存在此设备上": ["密码将加密保存在此设备上", "Passwords will be stored encrypted on this device", "Пароли будут храниться на этом устройстве в зашифрованном виде.", "密碼將加密儲存在此裝置上", "パスワードはこのデバイスに暗号化されて保存されます", "비밀번호는 이 장치에 암호화되어 저장됩니다.", "Passwörter werden auf diesem Gerät verschlüsselt gespeichert", "Les mots de passe seront stockés cryptés sur cet appareil", "Las contraseñas se almacenarán cifradas en este dispositivo", "As senhas serão armazenadas criptografadas neste dispositivo"], + "对端 ID": ["对端 ID", "Remote ID", "Удаленный ID", "對端 ID", "リモートID", "원격 ID", "Remote-ID", "ID à distance", "Identificación remota", "ID remoto"], + "对端 ID {0}": ["对端 ID {0}", "Peer ID {0}", "Идентификатор узла {0}", "對端 ID {0}", "ピアID{0}", "피어 ID{0}", "Peer-ID {0}", "ID homologue {0}", "ID de igual {0}", "ID de par {0}"], + "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。": ["将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。", "Will stop the remote connection, close the screen preview save and clear the existing preview. The connection record and password will be retained, and authorization is required again before reconnecting.", "Остановит удаленное соединение, закроет сохранение предварительного просмотра экрана и очистит существующий предварительный просмотр. Запись о подключении и пароль будут сохранены, и перед повторным подключением потребуется повторная авторизация.", "將停止遠端連線、關閉畫面預覽儲存並清除已有預覽。連線記錄和密碼會保留,重新連線前需再次授權。", "リモート接続を停止し、画面プレビューの保存を閉じて、既存のプレビューをクリアします。接続記録とパスワードは保持され、再接続する前に再度認証が必要になります。", "원격 연결을 중지하고 화면 미리보기 저장을 닫은 후 기존 미리보기를 지웁니다. 접속 기록과 비밀번호는 유지되며, 재접속 전 다시 인증이 필요합니다.", "Stoppt die Remote-Verbindung, schließt die Bildschirmvorschau, speichert sie und löscht die vorhandene Vorschau. Der Verbindungsdatensatz und das Passwort bleiben erhalten und vor der erneuten Verbindung ist eine erneute Autorisierung erforderlich.", "Arrêtera la connexion à distance, fermera la sauvegarde de l'aperçu de l'écran et effacera l'aperçu existant. L'enregistrement de connexion et le mot de passe seront conservés et une autorisation sera à nouveau requise avant de se reconnecter.", "Detendrá la conexión remota, cerrará la vista previa de la pantalla y borrará la vista previa existente. El registro de conexión y la contraseña se conservarán y se requerirá autorización nuevamente antes de volver a conectarse.", "Interromperá a conexão remota, fechará o salvamento da visualização da tela e limpará a visualização existente. O registro de conexão e a senha serão mantidos e será necessária autorização novamente antes de reconectar."], + "将清除此设备保存的所有远程画面预览,保留连接记录和访问密码。": ["将清除此设备保存的所有远程画面预览,保留连接记录和访问密码。", "All remote screen previews saved by this device will be cleared, and connection records and access passwords will be retained.", "Все предварительные просмотры удаленного экрана, сохраненные на этом устройстве, будут удалены, а записи подключений и пароли доступа сохранятся.", "將清除此裝置儲存的所有遠端畫面預覽,保留連線記錄和訪問密碼。", "このデバイスによって保存されたすべてのリモート画面プレビューは消去され、接続記録とアクセス パスワードは保持されます。", "이 기기에 저장된 원격 화면 미리보기는 모두 삭제되며, 연결 기록 및 접속 비밀번호는 유지됩니다.", "Alle von diesem Gerät gespeicherten Remote-Bildschirmvorschauen werden gelöscht und Verbindungsaufzeichnungen und Zugriffskennwörter bleiben erhalten.", "Tous les aperçus d'écran à distance enregistrés par cet appareil seront effacés et les enregistrements de connexion et les mots de passe d'accès seront conservés.", "Se borrarán todas las vistas previas de pantalla remota guardadas por este dispositivo y se conservarán los registros de conexión y las contraseñas de acceso.", "Todas as visualizações de tela remotas salvas por este dispositivo serão apagadas e os registros de conexão e senhas de acesso serão retidos."], + "尚未收到远端文本": ["尚未收到远端文本", "Remote text not received yet", "Удаленное сообщение еще не получено.", "尚未收到遠端文字", "リモートテキストがまだ受信されていません", "원격 문자가 아직 수신되지 않았습니다.", "Remote-Text noch nicht empfangen", "SMS distant pas encore reçu", "Texto remoto aún no recibido", "Texto remoto ainda não recebido"], + "屏幕方向": ["屏幕方向", "Screen orientation", "Ориентация экрана", "螢幕方向", "画面の向き", "화면 방향", "Bildschirmausrichtung", "Orientation de l'écran", "Orientación de la pantalla", "Orientação da tela"], + "已保存密码": ["已保存密码", "Password saved", "Пароль сохранён", "已儲存密碼", "パスワード保存済み", "비밀번호 저장됨", "Passwort gespeichert", "Mot de passe enregistré", "Contraseña guardada", "Senha salva"], + "已保存密码无法读取,请重新输入": ["已保存密码无法读取,请重新输入", "The saved password cannot be read, please re-enter it.", "Сохраненный пароль невозможно прочитать, введите его еще раз.", "已儲存密碼無法讀取,請重新輸入", "保存したパスワードが読み取れないため、再入力してください。", "저장된 비밀번호를 읽을 수 없습니다. 다시 입력해 주세요.", "Das gespeicherte Passwort kann nicht gelesen werden, bitte geben Sie es erneut ein.", "Le mot de passe enregistré ne peut pas être lu, veuillez le saisir à nouveau.", "La contraseña guardada no se puede leer; vuelva a ingresarla.", "A senha salva não pode ser lida, digite-a novamente."], + "已发送,请在远端粘贴": ["已发送,请在远端粘贴", "Sent, please paste at the remote end", "Отправлено, вставьте на удаленном конце", "已傳送,請在遠端貼上", "送信されました。リモート側で貼り付けてください", "보냈습니다. 원격 끝에 붙여넣으세요.", "Gesendet, bitte am entfernten Ende einfügen", "Envoyé, veuillez coller à l'extrémité distante", "Enviado, péguelo en el extremo remoto", "Enviado, cole no terminal remoto"], + "已复制远端文本": ["已复制远端文本", "Remote text copied", "Удаленный текст скопирован.", "已複製遠端文字", "リモートテキストをコピーしました", "원격 텍스트 복사됨", "Remote-Text kopiert", "Texte distant copié", "Texto remoto copiado", "Texto remoto copiado"], + "已授权": ["已授权", "Granted", "Разрешено", "已授權", "認められる", "승인됨", "Zugegeben", "Accordé", "Concedido", "Concedido"], + "已是最新版本": ["已是最新版本", "You're up to date", "Установлена последняя версия", "已是最新版本", "最新情報を入手しました", "최신 상태입니다", "Du bist auf dem Laufenden", "Vous êtes à jour", "Estás al día", "Você está atualizado"], + "已清除预览": ["已清除预览", "Preview cleared", "Предварительный просмотр отключен.", "已清除預覽", "プレビューをクリアしました", "미리보기가 삭제되었습니다.", "Vorschau gelöscht", "Aperçu effacé", "Vista previa borrada", "Visualização apagada"], + "已读或删除状态保存失败,请重试": ["已读或删除状态保存失败,请重试", "Failed to save read or deleted status, please try again", "Не удалось сохранить статус прочтения или удаления. Повторите попытку.", "已讀或刪除狀態儲存失敗,請重試", "既読または削除済みステータスの保存に失敗しました。もう一度お試しください。", "읽은 상태나 삭제된 상태를 저장하지 못했습니다. 다시 시도해 주세요.", "Der Lese- oder Löschstatus konnte nicht gespeichert werden. Bitte versuchen Sie es erneut", "Échec de l'enregistrement du statut lu ou supprimé, veuillez réessayer", "No se pudo guardar el estado leído o eliminado, inténtelo de nuevo", "Falha ao salvar o status de leitura ou exclusão. Tente novamente"], + "已连接": ["已连接", "Connected", "Подключено", "已連線", "接続されました", "연결됨", "Verbunden", "Connecté", "Conectado", "Conectado"], + "帧率": ["帧率", "Frame rate", "Частота кадров", "幀率", "フレームレート", "프레임 속도", "Bildrate", "Fréquence d'images", "Velocidad de fotogramas", "Taxa de quadros"], + "帧率优先": ["帧率优先", "Smooth", "Плавность", "影格率優先", "滑らかさ", "부드러움", "Flüssig", "Fluidité", "Fluidez", "Fluidez"], + "平衡": ["平衡", "Balanced", "Баланс", "平衡", "バランス", "균형", "Balance", "Équilibré", "Equilibrado", "Equilibrado"], + "开发版本包含尚未发布的修改,以下链接为基础版本源码。": ["开发版本包含尚未发布的修改,以下链接为基础版本源码。", "The development version contains modifications that have not yet been released. The following link is the source code of the basic version.", "Версия для разработки содержит модификации, которые еще не были выпущены. По следующей ссылке приведен исходный код базовой версии.", "開發版本包含尚未釋出的修改,以下連結為基礎版本原始碼。", "開発バージョンには、まだリリースされていない修正が含まれています。以下のリンクは基本バージョンのソースコードです。", "개발 버전에는 아직 출시되지 않은 수정 사항이 포함되어 있습니다. 다음 링크는 기본 버전의 소스 코드입니다.", "Die Entwicklungsversion enthält Änderungen, die noch nicht veröffentlicht wurden. Der folgende Link ist der Quellcode der Basisversion.", "La version de développement contient des modifications qui n'ont pas encore été publiées. Le lien suivant est le code source de la version de base.", "La versión de desarrollo contiene modificaciones que aún no han sido publicadas. El siguiente enlace es el código fuente de la versión básica.", "A versão de desenvolvimento contém modificações que ainda não foram lançadas. O link a seguir é o código fonte da versão básica."], + "开启": ["开启", "Turn on", "Включить", "開啟", "オンにする", "켜다", "Einschalten", "Allumer", "Encender", "Ligar"], + "开源组件": ["开源组件", "Open-source components", "Компоненты с открытым кодом", "開源元件", "オープンソースコンポーネント", "오픈 소스 구성 요소", "Open-Source-Komponenten", "Composants open source", "Componentes de código abierto", "Componentes de código aberto"], + "开源软件权利说明": ["开源软件权利说明", "Open source software rights description", "Описание прав на программное обеспечение с открытым исходным кодом.", "開源軟體權利說明", "オープンソース ソフトウェアの権利の説明", "오픈소스 소프트웨어 권리 설명", "Beschreibung der Open-Source-Softwarerechte", "Description des droits sur les logiciels open source", "Descripción de los derechos del software de código abierto", "Descrição dos direitos de software de código aberto"], + "成功连接后,这里会显示最近的远程设备。": ["成功连接后,这里会显示最近的远程设备。", "Upon successful connection, the nearest remote device will be displayed here.", "При успешном подключении здесь будет отображено ближайшее удаленное устройство.", "成功連線後,這裡會顯示最近的遠端裝置。", "接続に成功すると、最も近いリモート デバイスがここに表示されます。", "성공적으로 연결되면 가장 가까운 원격 장치가 여기에 표시됩니다.", "Nach erfolgreicher Verbindung wird hier das nächstgelegene Remote-Gerät angezeigt.", "Une fois la connexion réussie, l'appareil distant le plus proche sera affiché ici.", "Tras una conexión exitosa, aquí se mostrará el dispositivo remoto más cercano.", "Após a conexão bem-sucedida, o dispositivo remoto mais próximo será exibido aqui."], + "我已阅读并同意《隐私政策》": ["我已阅读并同意《隐私政策》", "I have read and agreed to the Privacy Policy", "Я прочитал и согласен с Политикой конфиденциальности.", "我已閱讀並同意《隱私政策》", "プライバシーポリシーを読んで同意します", "개인정보 보호정책을 읽었으며 이에 동의합니다.", "Ich habe die Datenschutzerklärung gelesen und bin damit einverstanden", "J'ai lu et accepté la politique de confidentialité", "He leído y acepto la Política de Privacidad", "Li e concordo com a Política de Privacidade"], + "我已阅读并同意隐私政策": ["我已阅读并同意隐私政策", "I have read and agree to the privacy policy", "Я прочитал и согласен с политикой конфиденциальности.", "我已閱讀並同意隱私政策", "プライバシーポリシーを読んで同意します", "개인정보취급방침을 읽었으며 이에 동의합니다.", "Ich habe die Datenschutzbestimmungen gelesen und stimme ihnen zu", "J'ai lu et j'accepte la politique de confidentialité", "He leído y acepto la política de privacidad", "Li e concordo com a política de privacidade"], + "找不到该设备 ID": ["找不到该设备 ID", "The device ID was not found", "Идентификатор устройства не найден.", "找不到該裝置 ID", "デバイスIDが見つかりませんでした", "장치 ID를 찾을 수 없습니다", "Die Geräte-ID wurde nicht gefunden", "L'ID de l'appareil n'a pas été trouvé", "No se encontró el ID del dispositivo", "O ID do dispositivo não foi encontrado"], + "拖动键盘": ["拖动键盘", "Drag keyboard", "Перетащите клавиатуру", "拖動鍵盤", "キーボードをドラッグする", "키보드 드래그", "Tastatur ziehen", "Faites glisser le clavier", "Arrastrar teclado", "Arraste o teclado"], + "指令发送失败,请重试": ["指令发送失败,请重试", "Command sending failed, please try again", "Не удалось отправить команду. Повторите попытку.", "指令傳送失敗,請重試", "コマンドの送信に失敗しました。もう一度お試しください。", "명령 전송에 실패했습니다. 다시 시도해 주세요.", "Das Senden des Befehls ist fehlgeschlagen. Bitte versuchen Sie es erneut", "L'envoi de la commande a échoué, veuillez réessayer", "Error al enviar el comando, inténtelo de nuevo", "Falha no envio do comando, tente novamente"], + "指令已发送,等待电脑确认…": ["指令已发送,等待电脑确认…", "The command has been sent, waiting for computer confirmation...", "Команда отправлена, ждём подтверждения от компьютера...", "指令已傳送,等待電腦確認…", "コマンドが送信され、コンピューターの確認を待っています...", "명령이 전송되었으며 컴퓨터 확인을 기다리고 있습니다...", "Der Befehl wurde gesendet und wartet auf die Bestätigung des Computers ...", "La commande a été envoyée, en attente de confirmation informatique...", "El comando ha sido enviado, esperando confirmación por computadora...", "O comando foi enviado, aguardando confirmação do computador..."], + "授权状态": ["授权状态", "Authorization status", "Статус авторизации", "授權狀態", "認可ステータス", "인증상태", "Autorisierungsstatus", "Statut d'autorisation", "Estado de autorización", "Status de autorização"], + "接收": ["接收", "Receive", "Приём", "接收", "受信", "수신", "Empfangen", "Réception", "Recibir", "Receber"], + "控制端解码器": ["控制端解码器", "Local decoder", "Локальный декодер", "控制端解碼器", "ローカルデコーダ", "로컬 디코더", "Lokaler Decoder", "Décodeur local", "Decodificador local", "Decodificador local"], + "撤回授权": ["撤回授权", "Withdraw authorization", "Отозвать разрешение", "撤回授權", "認可の撤回", "철회 승인", "Autorisierung entziehen", "Retirer l'autorisation", "Retirar autorización", "Retirar autorização"], + "撤回联网授权": ["撤回联网授权", "Withdraw network authorization", "Отозвать сетевую авторизацию", "撤回聯網授權", "ネットワーク認証の撤回", "네트워크 승인 철회", "Netzwerkberechtigung entziehen", "Retirer l'autorisation réseau", "Retirar la autorización de red", "Retirar autorização de rede"], + "撤回联网授权?": ["撤回联网授权?", "Withdraw network authorization?", "Отозвать сетевую авторизацию?", "撤回聯網授權?", "ネットワーク認証を取り消しますか?", "네트워크 승인을 철회하시겠습니까?", "Netzwerkberechtigung entziehen?", "Retirer l'autorisation réseau ?", "¿Retirar la autorización de la red?", "Retirar a autorização da rede?"], + "操作失败": ["操作失败", "Operation failed", "Операция не удалась", "操作失敗", "操作が失敗しました", "작업 실패", "Der Vorgang ist fehlgeschlagen", "Échec de l'opération", "Operación fallida", "Operação falhou"], + "收起键盘": ["收起键盘", "Hide keyboard", "Скрыть клавиатуру", "收起鍵盤", "キーボードを隠す", "키보드 숨기기", "Tastatur ausblenden", "Masquer le clavier", "Ocultar teclado", "Ocultar teclado"], + "收起鼠标": ["收起鼠标", "Hide mouse", "Скрыть мышь", "收起滑鼠", "マウスを隠す", "마우스 숨기기", "Maus ausblenden", "Masquer la souris", "Ocultar ratón", "Ocultar mouse"], + "数据": ["数据", "Data", "Данные", "資料", "データ", "데이터", "Daten", "Données", "Datos", "Dados"], + "文件保存失败,请重试": ["文件保存失败,请重试", "File saving failed, please try again", "Не удалось сохранить файл. Повторите попытку.", "檔案儲存失敗,請重試", "ファイルの保存に失敗しました。もう一度お試しください。", "파일 저장에 실패했습니다. 다시 시도해 주세요.", "Das Speichern der Datei ist fehlgeschlagen. Bitte versuchen Sie es erneut", "L'enregistrement du fichier a échoué, veuillez réessayer", "Error al guardar el archivo, inténtelo de nuevo", "Falha ao salvar o arquivo, tente novamente"], + "文件已保存": ["文件已保存", "File saved", "Файл сохранен.", "檔案已儲存", "ファイルを保存しました", "파일이 저장되었습니다", "Datei gespeichert", "Fichier enregistré", "Archivo guardado", "Arquivo salvo"], + "文本超过 128 KB": ["文本超过 128 KB", "Text exceeds 128 KB", "Размер текста превышает 128 КБ.", "文字超過 128 KB", "テキストが128KBを超えています", "텍스트가 128KB를 초과합니다.", "Der Text ist größer als 128 KB", "Le texte dépasse 128 Ko", "El texto supera los 128 KB", "O texto excede 128 KB"], + "断开后将返回首页。": ["断开后将返回首页。", "Will return to the homepage after disconnecting.", "Вернется на домашнюю страницу после отключения.", "斷開後將返回首頁。", "切断後、ホームページに戻ります。", "연결이 끊어지면 홈페이지로 돌아갑니다.", "Kehrt nach dem Trennen der Verbindung zur Startseite zurück.", "Reviendra à la page d'accueil après la déconnexion.", "Volverá a la página de inicio después de desconectarse.", "Retornará à página inicial após desconectar."], + "断开远程连接?": ["断开远程连接?", "Disconnect remote connection?", "Отключить удаленное соединение?", "斷開遠端連線?", "リモート接続を切断しますか?", "원격 연결을 끊으시겠습니까?", "Remote-Verbindung trennen?", "Déconnecter la connexion à distance ?", "¿Desconectar la conexión remota?", "Desconectar a conexão remota?"], + "断开连接": ["断开连接", "Disconnect", "Отключить", "中斷連線", "切断", "연결 해제", "Trennen", "Déconnecter", "Desconectar", "Desconectar"], + "新版本 ●": ["新版本 ●", "New version ●", "Новая версия ●", "新版本 ●", "新バージョン●", "새 버전 ●", "Neue Version ●", "Nouvelle version ●", "Nueva versión ●", "Nova versão ●"], + "新版本可用": ["新版本可用", "New Version Available", "Доступна новая версия", "新版本可用", "新しいバージョンが利用可能になりました", "새 버전 출시", "Neue Version verfügbar", "Nouvelle version disponible", "Nueva versión disponible", "Nova versão disponível"], + "无法保存联网授权,请重试": ["无法保存联网授权,请重试", "Unable to save network authorization, please try again", "Невозможно сохранить сетевую авторизацию. Повторите попытку.", "無法儲存聯網授權,請重試", "ネットワーク認証を保存できません。もう一度お試しください。", "네트워크 인증을 저장할 수 없습니다. 다시 시도해 주세요.", "Die Netzwerkautorisierung konnte nicht gespeichert werden. Bitte versuchen Sie es erneut", "Impossible d'enregistrer l'autorisation réseau, veuillez réessayer", "No se puede guardar la autorización de red, inténtelo de nuevo", "Não foi possível salvar a autorização de rede. Tente novamente"], + "无法删除已保存的凭据": ["无法删除已保存的凭据", "Unable to delete saved credentials", "Невозможно удалить сохраненные учетные данные.", "無法刪除已儲存的憑據", "保存した認証情報を削除できない", "저장된 자격 증명을 삭제할 수 없습니다", "Gespeicherte Anmeldeinformationen können nicht gelöscht werden", "Impossible de supprimer les informations d'identification enregistrées", "No se pueden eliminar las credenciales guardadas", "Não é possível excluir credenciais salvas"], + "无法打开网页": ["无法打开网页", "Unable to open web page", "Невозможно открыть веб-страницу.", "無法開啟網頁", "Webページを開けません", "웹페이지를 열 수 없습니다", "Webseite kann nicht geöffnet werden", "Impossible d'ouvrir la page Web", "No se puede abrir la página web", "Não é possível abrir a página da web"], + "无法读取所选文件或存储空间不足": ["无法读取所选文件或存储空间不足", "The selected file cannot be read or there is insufficient storage space.", "Выбранный файл не может быть прочитан или недостаточно места для хранения.", "無法讀取所選檔案或儲存空間不足", "選択したファイルが読み込めないか、ストレージ容量が不足しています。", "선택한 파일을 읽을 수 없거나 저장공간이 부족합니다.", "Die ausgewählte Datei kann nicht gelesen werden oder es ist nicht genügend Speicherplatz vorhanden.", "Le fichier sélectionné ne peut pas être lu ou l'espace de stockage est insuffisant.", "El archivo seleccionado no se puede leer o no hay suficiente espacio de almacenamiento.", "O arquivo selecionado não pode ser lido ou não há espaço de armazenamento suficiente."], + "无法读取文档": ["无法读取文档", "Unable to read document", "Невозможно прочитать документ.", "無法讀取文件", "文書を読み取れません", "문서를 읽을 수 없습니다", "Dokument kann nicht gelesen werden", "Impossible de lire le document", "No se puede leer el documento", "Não é possível ler o documento"], + "显示器": ["显示器", "Display", "Экран", "顯示器", "ディスプレイ", "디스플레이", "Bildschirm", "Écran", "Pantalla", "Tela"], + "显示密码": ["显示密码", "Show password", "Показать пароль", "顯示密碼", "パスワードを表示", "비밀번호 표시", "Passwort anzeigen", "Afficher le mot de passe", "Mostrar contraseña", "Mostrar senha"], + "暂不同意": ["暂不同意", "Not now", "Не сейчас", "暫不同意", "今は同意しない", "나중에", "Jetzt nicht", "Pas maintenant", "Ahora no", "Agora não"], + "暂无公告": ["暂无公告", "No announcements", "Нет объявлений", "暫無公告", "アナウンスはありません", "공지 없음", "Keine Ankündigungen", "Aucune annonce", "Sin anuncios", "Sem anúncios"], + "暂无鸿蒙版本信息,请稍后重试": ["暂无鸿蒙版本信息,请稍后重试", "There is currently no Hongmeng version information, please try again later.", "На данный момент информации о версии Hongmeng нет. Повторите попытку позже.", "暫無鴻蒙版本資訊,請稍後重試", "現在、Hongmeng のバージョン情報はありません。後でもう一度お試しください。", "현재 홍멍 버전 정보가 없습니다. 나중에 다시 시도해 주세요.", "Derzeit liegen keine Hongmeng-Versionsinformationen vor. Bitte versuchen Sie es später erneut.", "Il n'y a actuellement aucune information sur la version de Hongmeng, veuillez réessayer plus tard.", "Actualmente no hay información sobre la versión de Hongmeng, inténtelo de nuevo más tarde.", "Atualmente não há informações sobre a versão do Hongmeng, tente novamente mais tarde."], + "最近连接": ["最近连接", "Recent connections", "Недавние связи", "最近連線", "最近の接続", "최근 연결", "Letzte Verbindungen", "Connexions récentes", "Conexiones recientes", "Conexões recentes"], + "服务器": ["服务器", "Server", "Сервер", "伺服器", "サーバー", "서버", "Server", "Serveur", "Servidor", "Servidor"], + "服务器地址": ["服务器地址", "Server Address", "Адрес сервера", "伺服器地址", "サーバーアドレス", "서버 주소", "Serveradresse", "Adresse du serveur", "Dirección del servidor", "Endereço do servidor"], + "服务器已断开": ["服务器已断开", "Server disconnected", "Сервер отключен", "伺服器已斷開", "サーバーが切断されました", "서버 연결이 끊어졌습니다.", "Serververbindung getrennt", "Serveur déconnecté", "Servidor desconectado", "Servidor desconectado"], + "服务器端口": ["服务器端口", "Server port", "Порт сервера", "伺服器埠", "サーバーポート", "서버 포트", "Server-Port", "Port du serveur", "Puerto del servidor", "Porta do servidor"], + "服务器证书校验失败": ["服务器证书校验失败", "Server certificate verification failed", "Проверка сертификата сервера не удалась.", "伺服器證書校驗失敗", "サーバー証明書の検証に失敗しました", "서버 인증서 확인 실패", "Die Überprüfung des Serverzertifikats ist fehlgeschlagen", "La vérification du certificat du serveur a échoué", "Error en la verificación del certificado del servidor", "Falha na verificação do certificado do servidor"], + "未启用": ["未启用", "Not enabled", "Не включено", "未啟用", "有効ではありません", "활성화되지 않음", "Nicht aktiviert", "Non activé", "No habilitado", "Não habilitado"], + "未授权": ["未授权", "Unauthorized", "Несанкционированное", "未授權", "無許可", "무단", "Nicht autorisiert", "Non autorisé", "No autorizado", "Não autorizado"], + "未连接": ["未连接", "Not connected", "Нет соединения", "未連線", "接続されていません", "연결되지 않음", "Nicht verbunden", "Non connecté", "No conectado", "Não conectado"], + "本机 ID {0}": ["本机 ID {0}", "Local ID {0}", "Локальный идентификатор {0}", "本機 ID {0}", "ローカルID{0}", "로컬 ID{0}", "Lokale ID {0}", "ID local {0}", "ID local {0}", "ID local {0}"], + "本版本源码与构建说明": ["本版本源码与构建说明", "Source code and build instructions for this version", "Исходный код и инструкции по сборке этой версии.", "本版本原始碼與構建說明", "このバージョンのソース コードとビルド手順", "이 버전의 소스 코드 및 빌드 지침", "Quellcode und Build-Anweisungen für diese Version", "Code source et instructions de construction pour cette version", "Código fuente e instrucciones de compilación para esta versión", "Código-fonte e instruções de construção para esta versão"], + "构建文档": ["构建文档", "Build documentation", "Документация по сборке", "構建文件", "ビルドドキュメント", "문서 작성", "Build-Dokumentation", "Construire la documentation", "Documentación de compilación", "Documentação de construção"], + "查看源码": ["查看源码", "View source code", "Открыть исходный код", "檢視原始碼", "ソースコードを表示する", "소스코드 보기", "Quellcode anzeigen", "Afficher le code source", "Ver código fuente", "Ver código-fonte"], + "查看联网说明": ["查看联网说明", "View networking instructions", "Просмотр инструкций по работе в сети", "檢視聯網說明", "ネットワークの手順を表示する", "네트워킹 지침 보기", "Netzwerkanweisungen anzeigen", "Afficher les instructions de mise en réseau", "Ver instrucciones de red", "Ver instruções de rede"], + "检查失败,请稍后重试": ["检查失败,请稍后重试", "Check failed. Please try again later.", "Не удалось проверить обновления. Повторите позже.", "檢查失敗,請稍後重試", "チェックに失敗しました。後でもう一度試してください。", "확인에 실패했습니다. 나중에 다시 시도해 주세요.", "Prüfung fehlgeschlagen. Bitte versuchen Sie es später noch einmal.", "La vérification a échoué. Veuillez réessayer plus tard.", "La verificación falló. Inténtelo de nuevo más tarde.", "Falha na verificação. Por favor, tente novamente mais tarde."], + "检查更新": ["检查更新", "Check for updates", "Проверить обновления", "檢查更新", "アップデートを確認する", "업데이트 확인", "Suchen Sie nach Updates", "Rechercher des mises à jour", "Buscar actualizaciones", "Verifique se há atualizações"], + "正在关闭隐私屏…": ["正在关闭隐私屏…", "Closing privacy screen…", "Закрытие экрана конфиденциальности…", "正在關閉隱私屏…", "プライバシー画面を閉じています…", "개인정보 보호 화면을 닫는 중…", "Sichtschutz wird geschlossen…", "Fermeture de l'écran de confidentialité…", "Cerrando la pantalla de privacidad...", "Fechando a tela de privacidade…"], + "正在建立安全连接…": ["正在建立安全连接…", "Establishing secure connection…", "Установление безопасного соединения…", "正在建立安全連線…", "安全な接続を確立中…", "보안 연결 설정 중…", "Sichere Verbindung wird hergestellt…", "Établir une connexion sécurisée…", "Estableciendo una conexión segura...", "Estabelecendo conexão segura…"], + "正在开启隐私屏…": ["正在开启隐私屏…", "Turning on privacy screen...", "Включение экрана конфиденциальности...", "正在開啟隱私屏…", "プライバシー画面を有効化中…", "개인정보 보호 화면을 켜는 중...", "Privatsphärenschutz einschalten...", "Activation de l'écran de confidentialité...", "Activando la pantalla de privacidad...", "Ativando a tela de privacidade..."], + "正在检查…": ["正在检查…", "Checking…", "Проверка…", "正在檢查…", "確認中…", "확인 중…", "Überprüfen…", "Vérification…", "Comprobando…", "Verificando…"], + "正在连接": ["正在连接", "Connecting", "Подключение", "正在連線", "接続する", "연결 중", "Verbinden", "Connexion", "Conexión", "Conectando"], + "正在连接…": ["正在连接…", "Connecting…", "Подключение…", "正在連線…", "接続中…", "연결 중…", "Verbinden…", "Connexion…", "Conectando...", "Conectando…"], + "正在重连…": ["正在重连…", "Reconnecting...", "Повторное подключение...", "正在重連…", "再接続中...", "다시 연결하는 중...", "Verbindung wird wiederhergestellt...", "Reconnexion...", "Reconectando...", "Reconectando..."], + "此公告将从列表中移除。": ["此公告将从列表中移除。", "This announcement will be removed from the list.", "Это объявление будет удалено из списка.", "此公告將從列表中移除。", "この発表はリストから削除されます。", "이 공지는 목록에서 제거됩니다.", "Diese Ankündigung wird aus der Liste entfernt.", "Cette annonce sera supprimée de la liste.", "Este anuncio será eliminado de la lista.", "Este anúncio será removido da lista."], + "清除": ["清除", "Clear", "Очистить", "清除", "クリア", "클리어", "Klar", "Effacer", "Borrar", "Limpar"], + "清除预览图": ["清除预览图", "Clear previews", "Удалить превью", "清除預覽圖", "プレビューを削除", "미리보기 삭제", "Vorschaubilder löschen", "Supprimer les aperçus", "Borrar vistas previas", "Limpar prévias"], + "清除预览图?": ["清除预览图?", "Clear previews?", "Удалить превью?", "清除預覽圖?", "プレビューを削除しますか?", "미리보기를 삭제할까요?", "Vorschaubilder löschen?", "Supprimer les aperçus ?", "¿Borrar vistas previas?", "Limpar prévias?"], + "源码与构建说明": ["源码与构建说明", "Source code and build instructions", "Исходный код и сборка", "原始碼與構建說明", "ソースコードとビルド手順", "소스 코드 및 빌드 지침", "Quellcode und Build-Anweisungen", "Code source et instructions de construction", "Código fuente e instrucciones de compilación", "Código-fonte e instruções de construção"], + "源码版本": ["源码版本", "Source code version", "Версия исходного кода", "原始碼版本", "ソースコードのバージョン", "소스코드 버전", "Quellcode-Version", "Version du code source", "Versión del código fuente", "Versão do código-fonte"], + "滚轮,上下滑动": ["滚轮,上下滑动", "Scroll wheel; swipe up or down", "Колесо: проведите вверх или вниз", "滾輪,上下滑動", "ホイール:上下にスワイプ", "휠: 위아래로 스와이프", "Mausrad; nach oben oder unten wischen", "Molette : balayez vers le haut ou le bas", "Rueda: desliza arriba o abajo", "Roda: deslize para cima ou para baixo"], + "版本": ["版本", "Version", "Версия", "版本", "バージョン", "버전", "Version", "Version", "Versión", "Versão"], + "电脑": ["电脑", "Computer", "Компьютер", "電腦", "コンピューター", "컴퓨터", "Computer", "Ordinateur", "Computadora", "Computador"], + "画中画已关闭": ["画中画已关闭", "Picture-in-picture is turned off", "Функция «Картинка в картинке» отключена.", "畫中畫已關閉", "ピクチャーインピクチャーがオフになっています", "PIP(Picture-in-Picture)가 꺼졌습니다.", "Bild-in-Bild ist ausgeschaltet", "L'image dans l'image est désactivée", "La imagen en imagen está desactivada", "Picture-in-picture está desativado"], + "画质优先": ["画质优先", "Quality", "Качество", "畫質優先", "画質", "화질", "Qualität", "Qualité", "Calidad", "Qualidade"], + "画面偏好": ["画面偏好", "Video Preference", "Режим видео", "畫面偏好", "ビデオ設定", "영상 선호도", "Videopräferenz", "Préférence vidéo", "Preferencia de vídeo", "Preferência de vídeo"], + "画面延时": ["画面延时", "Video latency", "Задержка видео", "畫面延遲", "映像遅延", "영상 지연", "Videolatenz", "Latence vidéo", "Latencia de vídeo", "Latência do vídeo"], + "画面设置": ["画面设置", "Video settings", "Настройки видео", "畫面設定", "ビデオ設定", "영상 설정", "Videoeinstellungen", "Paramètres vidéo", "Configuración de vídeo", "Configurações de vídeo"], + "画面质量": ["画面质量", "Video Quality", "Качество видео", "畫面質量", "ビデオ品質", "비디오 품질", "Videoqualität", "Qualité vidéo", "Calidad de vídeo", "Qualidade de vídeo"], + "画面采集帧率": ["画面采集帧率", "Video Capture Frame Rate", "Частота захвата видео", "畫面採集幀率", "ビデオキャプチャフレームレート", "비디오 캡처 프레임 속도", "Bildrate der Videoaufnahme", "Fréquence d'images de capture vidéo", "Velocidad de fotogramas de captura de vídeo", "Taxa de quadros de captura de vídeo"], + "相对位置": ["相对位置", "Trackpad", "Тачпад", "相對位置", "トラックパッド", "트랙패드", "Touchpad", "Pavé tactile", "Panel táctil", "Touchpad"], + "相对鼠标": ["相对鼠标", "Relative mouse", "Родственная мышь", "相對滑鼠", "相対マウス", "상대 마우스", "Relative Maus", "Souris relative", "Ratón relativo", "Rato relativo"], + "知道了": ["知道了", "Got it", "Понятно", "知道了", "分かりました", "알겠습니다", "Verstanden", "Compris", "Entendido", "Entendi"], + "确认": ["确认", "Confirm", "Подтвердить", "確認", "確認する", "확인", "Bestätigen", "Confirmer", "Confirmar", "Confirmar"], + "离线": ["离线", "Offline", "Не в сети", "離線", "オフライン", "오프라인", "Offline", "Hors ligne", "Sin conexión", "Off-line"], + "空格": ["空格", "Space", "Пробел", "空白鍵", "スペース", "스페이스", "Leertaste", "Espace", "Espacio", "Espaço"], + "等待电脑端确认…": ["等待电脑端确认…", "Waiting for confirmation from the computer...", "Ожидание подтверждения от компьютера...", "等待電腦端確認…", "コンピューターからの確認を待っています...", "컴퓨터의 확인을 기다리는 중...", "Warten auf Bestätigung vom Computer...", "En attente de confirmation de l'ordinateur...", "Esperando confirmación del ordenador...", "Aguardando confirmação do computador..."], + "等待电脑返回隐私屏状态;旧版电脑端可能不支持": ["等待电脑返回隐私屏状态;旧版电脑端可能不支持", "Wait for the computer to return to the privacy screen state; older computers may not support it.", "Подождите, пока компьютер вернется в состояние экрана конфиденциальности; старые компьютеры могут его не поддерживать.", "等待電腦返回隱私屏狀態;舊版電腦端可能不支援", "コンピューターがプライバシー画面の状態に戻るまで待ちます。古いコンピューターではサポートされていない可能性があります。", "컴퓨터가 개인 정보 보호 화면 상태로 돌아갈 때까지 기다립니다. 오래된 컴퓨터에서는 이를 지원하지 않을 수 있습니다.", "Warten Sie, bis der Computer in den Datenschutzstatus zurückkehrt. Ältere Computer unterstützen dies möglicherweise nicht.", "Attendez que l'ordinateur revienne à l'état de l'écran de confidentialité ; les ordinateurs plus anciens peuvent ne pas le prendre en charge.", "Espere a que la computadora vuelva al estado de pantalla de privacidad; Es posible que las computadoras más antiguas no lo admitan.", "Aguarde o computador retornar ao estado da tela de privacidade; computadores mais antigos podem não suportá-lo."], + "等待远端屏幕信息": ["等待远端屏幕信息", "Waiting for remote screen information", "Ожидание информации об удаленном экране.", "等待遠端螢幕資訊", "リモート画面情報待ち", "원격 화면 정보를 기다리는 중", "Warten auf Remote-Bildschirminformationen", "En attente d'informations sur l'écran distant", "Esperando información de la pantalla remota", "Aguardando informações da tela remota"], + "等待远端画面…": ["等待远端画面…", "Waiting for the remote screen...", "Ожидание удаленного экрана...", "等待遠端畫面…", "リモート画面を待っています...", "원격 화면을 기다리는 중...", "Warten auf den Remote-Bildschirm ...", "En attente de l'écran distant...", "Esperando la pantalla remota...", "Aguardando a tela remota..."], + "粘贴": ["粘贴", "Paste", "Вставить", "貼上", "貼り付け", "붙여넣기", "Einfügen", "Coller", "Pegar", "Colar"], + "粘贴到远端": ["粘贴到远端", "Paste to remote", "Вставить на пульт", "貼上到遠端", "接続先に貼り付け", "원격에 붙여넣기", "Auf Fernbedienung einfügen", "Coller sur la télécommande", "Pegar en remoto", "Colar no controle remoto"], + "系统已停止后台会话": ["系统已停止后台会话", "The system has stopped the background session", "Система остановила фоновый сеанс.", "系統已停止後臺會話", "システムはバックグラウンド セッションを停止しました", "시스템이 백그라운드 세션을 중지했습니다.", "Das System hat die Hintergrundsitzung gestoppt", "Le système a arrêté la session en arrière-plan", "El sistema ha detenido la sesión en segundo plano.", "O sistema interrompeu a sessão em segundo plano"], + "系统未允许后台会话,连接已断开": ["系统未允许后台会话,连接已断开", "Background session not allowed by system, connection disconnected", "Фоновый сеанс запрещен системой, соединение прервано.", "系統未允許後臺會話,連線已斷開", "バックグラウンド セッションがシステムによって許可されていないため、接続が切断されました", "시스템에서 백그라운드 세션을 허용하지 않아 연결이 끊어졌습니다.", "Hintergrundsitzung vom System nicht zugelassen, Verbindung getrennt", "Session en arrière-plan non autorisée par le système, connexion déconnectée", "Sesión en segundo plano no permitida por el sistema, conexión desconectada", "Sessão em segundo plano não permitida pelo sistema, conexão desconectada"], + "绝对位置": ["绝对位置", "Direct touch", "Касание", "絕對位置", "直接タッチ", "직접 터치", "Direkte Berührung", "Toucher direct", "Toque directo", "Toque direto"], + "绝对鼠标": ["绝对鼠标", "Absolute Mouse", "Абсолютная мышь", "絕對滑鼠", "アブソリュートマウス", "앱솔루트 마우스", "Absolute Maus", "Souris absolue", "Ratón absoluto", "Rato Absoluto"], + "网络状态": ["网络状态", "Network", "Сеть", "網路狀態", "ネットワーク", "네트워크", "Netzwerk", "Réseau", "Red", "Rede"], + "自定义": ["自定义", "Custom", "Пользовательский", "自定義", "カスタム", "커스텀", "Benutzerdefiniert", "Personnalisé", "Personalizado", "Personalizado"], + "虚拟鼠标": ["虚拟鼠标", "Virtual mouse", "Виртуальная мышь", "虛擬滑鼠", "仮想マウス", "가상마우스", "Virtuelle Maus", "Souris virtuelle", "Ratón virtual", "Rato virtual"], + "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。": ["被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", "The remote privacy screen was unlocked using the local shortcut. Lock it again to restore privacy and disable local shortcut unlocking.", "Приватный экран отключён локальным сочетанием клавиш. Заблокируйте его снова, чтобы восстановить защиту и запретить локальную разблокировку.", "被控端已透過組合鍵解除隱私屏。點選“鎖定”將重新開啟隱私屏,並禁止本機使用組合鍵解鎖。", "ローカル ショートカットを使用してリモート プライバシー画面のロックが解除されました。再度ロックするとプライバシーが回復され、ローカル ショートカットのロック解除が無効になります。", "로컬 단축키를 사용하여 원격 개인정보 보호 화면을 잠금 해제했습니다. 개인정보 보호를 복원하고 로컬 바로가기 잠금 해제를 비활성화하려면 다시 잠그세요.", "Der Remote-Datenschutzbildschirm wurde über die lokale Verknüpfung entsperrt. Sperren Sie es erneut, um die Privatsphäre wiederherzustellen und das Entsperren lokaler Verknüpfungen zu deaktivieren.", "L'écran de confidentialité à distance a été déverrouillé à l'aide du raccourci local. Verrouillez-le à nouveau pour restaurer la confidentialité et désactiver le déverrouillage des raccourcis locaux.", "La pantalla de privacidad remota se desbloqueó usando el acceso directo local. Bloquéelo nuevamente para restaurar la privacidad y deshabilitar el desbloqueo de accesos directos locales.", "A tela de privacidade remota foi desbloqueada usando o atalho local. Bloqueie-o novamente para restaurar a privacidade e desativar o desbloqueio de atalhos locais."], + "被控端版本过低,请升级到最新版本。": ["被控端版本过低,请升级到最新版本。", "The controlled version is too low, please upgrade to the latest version.", "Управляемая версия слишком низкая, обновите ее до последней версии.", "被控端版本過低,請升級到最新版本。", "管理されているバージョンが低すぎるため、最新バージョンにアップグレードしてください。", "제어 버전이 너무 낮습니다. 최신 버전으로 업그레이드하세요.", "Die kontrollierte Version ist zu niedrig, bitte aktualisieren Sie auf die neueste Version.", "La version contrôlée est trop basse, veuillez mettre à niveau vers la dernière version.", "La versión controlada es demasiado baja; actualice a la última versión.", "A versão controlada é muito baixa, atualize para a versão mais recente."], + "被控端编码器": ["被控端编码器", "Remote encoder", "Кодер удалённой стороны", "被控端編碼器", "リモートエンコーダー", "리모트 엔코더", "Remote-Encoder", "Encodeur déporté", "Codificador remoto", "Codificador remoto"], + "要发送到远端的文本": ["要发送到远端的文本", "Text to be sent to the remote end", "Текст для отправки на удаленный конец", "要傳送到遠端的文字", "相手側に送信するテキスト", "원격지로 보낼 텍스트", "Text, der an die Gegenstelle gesendet werden soll", "Texte à envoyer à l'extrémité distante", "Texto a enviar al extremo remoto", "Texto a ser enviado para o terminal remoto"], + "视频": ["视频", "Video", "Видео", "影片", "ビデオ", "영상", "Video", "Vidéo", "Vídeo", "Vídeo"], + "记录或密码删除失败,请重试": ["记录或密码删除失败,请重试", "Record or password deletion failed, please try again", "Не удалось удалить запись или пароль. Повторите попытку.", "記錄或密碼刪除失敗,請重試", "レコードまたはパスワードの削除に失敗しました。もう一度お試しください。", "기록 또는 비밀번호 삭제에 실패했습니다. 다시 시도해 주세요.", "Datensatz oder Passwort konnten nicht gelöscht werden. Bitte versuchen Sie es erneut", "La suppression de l'enregistrement ou du mot de passe a échoué, veuillez réessayer", "Error al eliminar el registro o la contraseña, inténtelo de nuevo", "Falha ao excluir registro ou senha, tente novamente"], + "许可": ["许可", "License", "Лицензия", "許可", "ライセンス", "라이센스", "Lizenz", "Licence", "Licencia", "Licença"], + "许可与版权声明": ["许可与版权声明", "Licenses and copyright notices", "Лицензии и авторские права", "許可與版權宣告", "ライセンスと著作権表示", "라이센스 및 저작권 고지", "Lizenzen und Urheberrechtshinweise", "Licences et mentions de droits d'auteur", "Licencias y avisos de derechos de autor", "Licenças e avisos de direitos autorais"], + "许可与版权声明可离线查阅。": ["许可与版权声明可离线查阅。", "The license and copyright notice are available offline.", "Лицензия и уведомление об авторских правах доступны в автономном режиме.", "許可與版權宣告可離線查閱。", "ライセンスと著作権表示はオフラインでも利用できます。", "라이센스 및 저작권 고지는 오프라인에서 확인할 수 있습니다.", "Die Lizenz- und Urheberrechtshinweise sind offline verfügbar.", "La licence et la notice de copyright sont disponibles hors ligne.", "La licencia y el aviso de derechos de autor están disponibles sin conexión.", "A licença e o aviso de direitos autorais estão disponíveis offline."], + "设备身份保存失败,请检查安全存储": ["设备身份保存失败,请检查安全存储", "Device identity failed to save, please check secure storage", "Не удалось сохранить идентификационные данные устройства. Проверьте безопасное хранилище.", "裝置身份儲存失敗,請檢查安全儲存", "デバイス ID を保存できませんでした。安全なストレージを確認してください。", "기기 ID를 저장하지 못했습니다. 보안 저장소를 확인하세요.", "Die Geräteidentität konnte nicht gespeichert werden. Bitte überprüfen Sie den sicheren Speicher", "L'identité de l'appareil n'a pas pu être enregistrée. Veuillez vérifier le stockage sécurisé.", "No se pudo guardar la identidad del dispositivo; verifique el almacenamiento seguro", "Falha ao salvar a identidade do dispositivo. Verifique o armazenamento seguro"], + "设备身份及选择保存的访问密码加密保存在本机。画面预览默认关闭,开启后从下一次连接起保存。剪贴板内容在结束会话时清除。离开应用后通过画中画或后台任务保持会话,可随时返回应用断开。": ["设备身份及选择保存的访问密码加密保存在本机。画面预览默认关闭,开启后从下一次连接起保存。剪贴板内容在结束会话时清除。离开应用后通过画中画或后台任务保持会话,可随时返回应用断开。", "The device identity and the access password selected to be saved are encrypted and stored locally. Screen preview is turned off by default and will be saved from the next connection after it is turned on. The clipboard contents are cleared when the session is ended. Maintain the session through picture-in-picture or background tasks after leaving the app, and return to the app at any time to disconnect.", "Идентификатор устройства и выбранный для сохранения пароль доступа шифруются и хранятся локально. Предварительный просмотр экрана по умолчанию отключен и будет сохранен при следующем подключении после включения. Содержимое буфера обмена очищается после завершения сеанса. Поддерживайте сеанс с помощью функции «картинка в картинке» или фоновых задач после выхода из приложения и возвращайтесь в приложение в любое время, чтобы отключиться.", "裝置身份及選擇儲存的訪問密碼加密儲存在本機。畫面預覽預設關閉,開啟後從下一次連線起儲存。剪貼簿內容在結束會話時清除。離開應用後透過畫中畫或後臺任務保持會話,可隨時返回應用斷開。", "保存するように選択されたデバイス ID とアクセス パスワードは、暗号化されてローカルに保存されます。画面プレビューはデフォルトではオフになっており、オンにすると次回の接続から保存されます。クリップボードの内容はセッションが終了するとクリアされます。アプリを終了した後も、ピクチャ イン ピクチャまたはバックグラウンド タスクを通じてセッションを維持し、いつでもアプリに戻って切断します。", "저장하기 위해 선택한 기기 ID와 접속 비밀번호는 암호화되어 로컬에 저장됩니다. 화면 미리보기는 기본적으로 꺼져 있으며, 켜진 후 다음 연결부터 저장됩니다. 세션이 종료되면 클립보드 내용이 지워집니다. 앱을 종료한 후에도 PIP 또는 백그라운드 작업을 통해 세션을 유지하고, 언제든지 앱으로 돌아와 연결을 끊을 수 있습니다.", "Die Geräteidentität und das zum Speichern ausgewählte Zugangspasswort werden verschlüsselt und lokal gespeichert. Die Bildschirmvorschau ist standardmäßig deaktiviert und wird nach dem Einschalten bei der nächsten Verbindung gespeichert. Der Inhalt der Zwischenablage wird gelöscht, wenn die Sitzung beendet wird. Halten Sie die Sitzung durch Bild-in-Bild- oder Hintergrundaufgaben aufrecht, nachdem Sie die App verlassen haben, und kehren Sie jederzeit zur App zurück, um die Verbindung zu trennen.", "L'identité de l'appareil et le mot de passe d'accès sélectionnés pour être enregistrés sont cryptés et stockés localement. L'aperçu de l'écran est désactivé par défaut et sera enregistré à partir de la prochaine connexion après son activation. Le contenu du presse-papiers est effacé à la fin de la session. Maintenez la session via des tâches d'image dans l'image ou en arrière-plan après avoir quitté l'application, et revenez à l'application à tout moment pour vous déconnecter.", "La identidad del dispositivo y la contraseña de acceso seleccionada para guardar se cifran y almacenan localmente. La vista previa de la pantalla está desactivada de forma predeterminada y se guardará en la siguiente conexión después de activarla. El contenido del portapapeles se borra cuando finaliza la sesión. Mantenga la sesión mediante tareas de imagen en imagen o en segundo plano después de salir de la aplicación y regrese a la aplicación en cualquier momento para desconectarse.", "A identidade do dispositivo e a senha de acesso selecionada para ser salva são criptografadas e armazenadas localmente. A visualização da tela está desativada por padrão e será salva na próxima conexão após ser ativada. O conteúdo da área de transferência é apagado quando a sessão é encerrada. Mantenha a sessão por meio de tarefas picture-in-picture ou em segundo plano após sair do aplicativo e retorne ao aplicativo a qualquer momento para desconectar."], + "设置": ["设置", "Settings", "Настройки", "設定", "設定", "설정", "Einstellungen", "Réglages", "Ajustes", "Configurações"], + "访问密码": ["访问密码", "Access password", "Пароль доступа", "訪問密碼", "アクセスパスワード", "접속 비밀번호", "Zugangspasswort", "Mot de passe d'accès", "Contraseña de acceso", "Senha de acesso"], + "访问密码错误": ["访问密码错误", "Wrong access password", "Неправильный пароль доступа.", "訪問密碼錯誤", "アクセスパスワードが間違っています", "접속 비밀번호가 잘못되었습니다.", "Falsches Zugangspasswort", "Mot de passe d'accès erroné", "Contraseña de acceso incorrecta", "Senha de acesso errada"], + "访问密码错误,请重新输入": ["访问密码错误,请重新输入", "The access password is wrong, please re-enter it.", "Неверный пароль доступа, пожалуйста, введите его еще раз.", "訪問密碼錯誤,請重新輸入", "アクセスパスワードが間違っていますので、再度入力してください。", "접속비밀번호가 잘못되었습니다. 다시 입력해 주세요.", "Das Zugangspasswort ist falsch, bitte geben Sie es erneut ein.", "Le mot de passe d'accès est erroné, veuillez le saisir à nouveau.", "La contraseña de acceso es incorrecta, por favor vuelva a ingresarla.", "A senha de acesso está errada, digite-a novamente."], + "请在远端启用 CrossDesk 系统服务后重试": ["请在远端启用 CrossDesk 系统服务后重试", "Please enable the CrossDesk system service on the remote end and try again", "Пожалуйста, включите системную службу CrossDesk на удаленном конце и повторите попытку.", "請在遠端啟用 CrossDesk 系統服務後重試", "リモート エンドでCrossDeskシステム サービスを有効にして、再試行してください。", "원격 측에서CrossDesk시스템 서비스를 활성화하고 다시 시도하십시오.", "Bitte aktivieren Sie den CrossDesk-Systemdienst auf der Gegenseite und versuchen Sie es erneut", "Veuillez activer le service système CrossDesk sur l'extrémité distante et réessayer.", "Habilite el servicio del sistema CrossDesk en el extremo remoto y vuelva a intentarlo.", "Ative o serviço do sistema CrossDesk na extremidade remota e tente novamente"], + "请求超时,尚未确认电脑的隐私屏状态": ["请求超时,尚未确认电脑的隐私屏状态", "The request timed out and the computer's privacy screen status has not been confirmed.", "Время ожидания запроса истекло, а состояние экрана конфиденциальности компьютера не подтверждено.", "請求超時,尚未確認電腦的隱私屏狀態", "リクエストがタイムアウトし、コンピュータのプライバシー画面の状態が確認できませんでした。", "요청 시간이 초과되어 컴퓨터의 개인 정보 보호 화면 상태가 확인되지 않았습니다.", "Die Anfrage ist abgelaufen und der Datenschutzstatus des Computers wurde nicht bestätigt.", "Le délai de demande a expiré et l'état de l'écran de confidentialité de l'ordinateur n'a pas été confirmé.", "Se agotó el tiempo de espera de la solicitud y no se ha confirmado el estado de la pantalla de privacidad de la computadora.", "A solicitação expirou e o status da tela de privacidade do computador não foi confirmado."], + "请等待当前文件发送完成": ["请等待当前文件发送完成", "Please wait for the current file to be sent.", "Пожалуйста, дождитесь отправки текущего файла.", "請等待當前檔案傳送完成", "現在のファイルが送信されるまでお待ちください。", "현재 파일이 전송될 때까지 기다려 주십시오.", "Bitte warten Sie, bis die aktuelle Datei gesendet wird.", "Veuillez attendre que le fichier actuel soit envoyé.", "Espere a que se envíe el archivo actual.", "Aguarde o envio do arquivo atual."], + "请输入 9 位设备 ID": ["请输入 9 位设备 ID", "Enter a 9-digit device ID", "Введите ID из 9 цифр", "請輸入 9 位裝置 ID", "9桁のデバイスIDを入力", "기기 ID 9자리를 입력하세요.", "Geben Sie eine 9-stellige Geräte-ID ein", "Saisissez un identifiant d'appareil à 9 chiffres", "Ingrese una ID de dispositivo de 9 dígitos", "Insira um ID de dispositivo de 9 dígitos"], + "请输入有效的服务器地址和端口": ["请输入有效的服务器地址和端口", "Please enter a valid server address and port", "Введите действительный адрес и порт сервера.", "請輸入有效的伺服器地址和埠", "有効なサーバー アドレスとポートを入力してください", "유효한 서버 주소와 포트를 입력하세요", "Bitte geben Sie eine gültige Serveradresse und einen gültigen Port ein", "Veuillez saisir une adresse de serveur et un port valides", "Ingrese una dirección de servidor y un puerto válidos", "Insira um endereço de servidor e porta válidos"], + "请输入有效的访问密码": ["请输入有效的访问密码", "Please enter a valid access password", "Пожалуйста, введите действительный пароль доступа.", "請輸入有效的訪問密碼", "有効なアクセスパスワードを入力してください", "유효한 접속 비밀번호를 입력해주세요", "Bitte geben Sie ein gültiges Zugangspasswort ein", "Veuillez saisir un mot de passe d'accès valide", "Por favor ingrese una contraseña de acceso válida", "Insira uma senha de acesso válida"], + "调整失败,请重试。": ["调整失败,请重试。", "Could not apply settings. Try again.", "Не удалось применить настройки. Повторите попытку.", "調整失敗,請重試。", "設定を適用できませんでした。もう一度やり直してください。", "설정을 적용할 수 없습니다. 다시 시도해 보세요.", "Einstellungen konnten nicht angewendet werden. Versuchen Sie es erneut.", "Impossible d'appliquer les paramètres. Essayer à nouveau.", "No se pudieron aplicar las configuraciones. Intentar otra vez.", "Não foi possível aplicar as configurações. Tente novamente."], + "软件许可": ["软件许可", "Software license", "Лицензия программы", "軟體許可", "ソフトウェアライセンス", "소프트웨어 라이센스", "Softwarelizenz", "Licence du logiciel", "Licencia de software", "Licença de software"], + "返回": ["返回", "Back", "Назад", "返回", "戻る", "뒤로", "Zurück", "Retour", "Volver", "Voltar"], + "返回控制栏": ["返回控制栏", "Return to control bar", "Возврат к панели управления.", "返回控制欄", "コントロールバーに戻る", "컨트롤 바로 돌아가기", "Zurück zur Steuerleiste", "Retour à la barre de contrôle", "Volver a la barra de control", "Retornar à barra de controle"], + "还没有连接记录": ["还没有连接记录", "No connection record yet", "Пока нет записей о подключении", "還沒有連線記錄", "まだ接続実績がありません", "아직 접속기록이 없습니다", "Noch kein Verbindungsdatensatz", "Aucun enregistrement de connexion pour l'instant", "Aún no hay registro de conexión", "Ainda não há registro de conexão"], + "远程控制菜单,拖动可移动": ["远程控制菜单,拖动可移动", "Remote control menu, drag to move", "Меню пульта дистанционного управления, перетаскивайте для перемещения.", "遠端控制選單,拖動可移動", "リモコンメニュー、ドラッグして移動", "리모컨 메뉴, 드래그하여 이동", "Fernbedienungsmenü, zum Verschieben ziehen", "Menu de la télécommande, faites glisser pour déplacer", "Menú de control remoto, arrastre para mover", "Menu de controle remoto, arraste para mover"], + "远程桌面": ["远程桌面", "Remote Desktop", "Удаленный рабочий стол", "遠端桌面", "リモートデスクトップ", "원격 데스크톱", "Remotedesktop", "Bureau à distance", "Escritorio remoto", "Área de Trabalho Remota"], + "远程桌面:轻触点击、长按右键、双指捏合缩放、放大后双指拖动画面,原始比例下双指滚动": ["远程桌面:轻触点击、长按右键、双指捏合缩放、放大后双指拖动画面,原始比例下双指滚动", "Remote desktop: tap and click, long press the right button, pinch to zoom with two fingers, drag the screen with two fingers after zooming in, scroll with two fingers at the original ratio", "Удаленный рабочий стол: коснитесь и щелкните, нажмите и удерживайте правую кнопку, сведите два пальца для увеличения, перетащите экран двумя пальцами после увеличения, прокрутите двумя пальцами в исходном соотношении.", "遠端桌面:輕觸點選、長按右鍵、雙指捏合縮放、放大後雙指拖動畫面,原始比例下雙指滾動", "リモートデスクトップ:タップ&クリック、右ボタン長押し、2本指でピンチして拡大、拡大後2本指で画面をドラッグ、2本指で元の比率でスクロール", "원격 데스크톱: 탭 앤 클릭, 오른쪽 버튼 길게 누르기, 두 손가락으로 핀치하여 확대/축소, 확대 후 두 손가락으로 화면 드래그, 원래 비율로 두 손가락으로 스크롤", "Remote-Desktop: Tippen und klicken, die rechte Taste lange drücken, zum Zoomen mit zwei Fingern zusammenziehen, nach dem Vergrößern mit zwei Fingern über den Bildschirm ziehen, mit zwei Fingern im Originalverhältnis scrollen", "Bureau à distance : appuyez et cliquez, appuyez longuement sur le bouton droit, pincez pour zoomer avec deux doigts, faites glisser l'écran avec deux doigts après avoir zoomé, faites défiler avec deux doigts au rapport d'origine", "Escritorio remoto: toque y haga clic, mantenga presionado el botón derecho, pellizque para hacer zoom con dos dedos, arrastre la pantalla con dos dedos después de hacer zoom, desplácese con dos dedos en la proporción original", "Área de trabalho remota: toque e clique, mantenha pressionado o botão direito, aperte para ampliar com dois dedos, arraste a tela com dois dedos após aumentar o zoom, role com dois dedos na proporção original"], + "远程电脑": ["远程电脑", "Remote computer", "Удаленный компьютер", "遠端電腦", "リモートコンピュータ", "원격 컴퓨터", "Remote-Computer", "Ordinateur distant", "Computadora remota", "Computador remoto"], + "远端已关闭连接": ["远端已关闭连接", "The remote end has closed the connection", "Удаленная сторона закрыла соединение.", "遠端已關閉連線", "リモートエンドが接続を閉じました", "원격 측에서 연결을 종료했습니다.", "Die Gegenstelle hat die Verbindung geschlossen", "L'extrémité distante a fermé la connexion", "El extremo remoto ha cerrado la conexión", "A extremidade remota fechou a conexão"], + "远端当前不可用": ["远端当前不可用", "The remote end is currently unavailable", "Удаленный конец в настоящее время недоступен.", "遠端當前不可用", "リモートエンドは現在利用できません", "현재 원격 끝을 사용할 수 없습니다.", "Die Gegenstelle ist derzeit nicht verfügbar", "L'extrémité distante est actuellement indisponible", "El extremo remoto no está disponible actualmente", "A extremidade remota está indisponível no momento"], + "连接": ["连接", "Connect", "Подключиться", "連線", "接続", "연결", "Verbinden", "Connecter", "Conectar", "Conectar"], + "连接失败": ["连接失败", "Connection failed", "Соединение не удалось", "連線失敗", "接続に失敗しました", "연결 실패", "Verbindung fehlgeschlagen", "Échec de la connexion", "Error de conexión", "Falha na conexão"], + "连接已断开": ["连接已断开", "Connection lost", "Соединение потеряно", "連線已斷開", "接続が失われました", "연결 끊김", "Verbindung verloren", "Connexion perdue", "Conexión perdida", "Conexão perdida"], + "连接已结束": ["连接已结束", "Connection ended", "Соединение завершено", "連線已結束", "接続が終了しました", "연결이 종료되었습니다", "Verbindung beendet", "Connexion terminée", "Conexión finalizada", "Conexão encerrada"], + "连接延时(RTT)": ["连接延时(RTT)", "Connection delay (RTT)", "Задержка соединения (RTT)", "連線延時(RTT)", "接続遅延 (RTT)", "연결 지연(RTT)", "Verbindungsverzögerung (RTT)", "Délai de connexion (RTT)", "Retardo de conexión (RTT)", "Atraso de conexão (RTT)"], + "连接建立后可调整,需被控端支持。": ["连接建立后可调整,需被控端支持。", "Available when connected to a supported remote device.", "Доступно при подключении к поддерживаемому устройству.", "連線建立後可調整,需被控端支援。", "サポートされているリモート デバイスに接続されている場合に使用できます。", "지원되는 원격 장치에 연결된 경우 사용할 수 있습니다.", "Verfügbar bei Verbindung mit einem unterstützten Remote-Gerät.", "Disponible lors de la connexion à un appareil distant pris en charge.", "Disponible cuando se conecta a un dispositivo remoto compatible.", "Disponível quando conectado a um dispositivo remoto compatível."], + "连接建立后锁定横屏": ["连接建立后锁定横屏", "Lock landscape screen after connection is established", "Блокировка горизонтального экрана после установления соединения.", "連線建立後鎖定橫屏", "接続完了後、横画面をロックする", "연결 완료 후 가로 화면 잠금", "Querformatbildschirm sperren, nachdem die Verbindung hergestellt wurde", "Verrouiller l'écran paysage une fois la connexion établie", "Bloquear la pantalla horizontal después de establecer la conexión", "Bloqueie a tela paisagem após a conexão ser estabelecida"], + "连接提示": ["连接提示", "Connection prompt", "Запрос на подключение", "連線提示", "接続プロンプト", "연결 프롬프트", "Verbindungsaufforderung", "Invite de connexion", "Aviso de conexión", "Solicitação de conexão"], + "连接方式": ["连接方式", "Connection method", "Способ подключения", "連線方式", "接続方法", "연결 방법", "Verbindungsmethode", "Méthode de connexion", "Método de conexión", "Método de conexão"], + "连接远程桌面": ["连接远程桌面", "Connect to remote desktop", "Подключение к удаленному рабочему столу", "連線遠端桌面", "リモートデスクトップに接続する", "원격 데스크톱에 연결", "Mit Remote-Desktop verbinden", "Connectez-vous au bureau à distance", "Conectarse al escritorio remoto", "Conecte-se à área de trabalho remota"], + "通知公告": ["通知公告", "Announcements", "Объявления", "通知公告", "お知らせ", "공지사항", "Mitteilungen", "Annonces", "Anuncios", "Avisos"], + "锁定": ["锁定", "Lock", "Заблокировать", "鎖定", "ロック", "잠금", "Sperren", "Verrouillage", "Bloquear", "Bloqueio"], + "键盘": ["键盘", "Keyboard", "Клавиатура", "鍵盤", "キーボード", "키보드", "Tastatur", "Clavier", "Teclado", "Teclado"], + "阅读并授权": ["阅读并授权", "Read and authorize", "Прочитать и авторизоваться", "閱讀並授權", "読んで承認する", "읽기 및 승인", "Lesen und autorisieren", "Lire et autoriser", "Leer y autorizar", "Ler e autorizar"], + "隐私": ["隐私", "Privacy", "Конфиденциальность", "隱私", "プライバシー", "개인 정보 보호", "Datenschutz", "Confidentialité", "Privacidad", "Privacidade"], + "隐私与授权": ["隐私与授权", "Privacy and Authorization", "Конфиденциальность и авторизация", "隱私與授權", "プライバシーと認証", "개인 정보 보호 및 승인", "Datenschutz und Autorisierung", "Confidentialité et autorisation", "Privacidad y autorización", "Privacidade e Autorização"], + "隐私屏": ["隐私屏", "Privacy screen", "Приватный экран", "隱私屏", "プライバシー画面", "개인정보 보호 화면", "Sichtschutz", "Écran de confidentialité", "Pantalla de privacidad", "Tela de privacidade"], + "隐私屏已关闭": ["隐私屏已关闭", "Privacy screen off", "Приватный экран выкл.", "隱私屏已關閉", "プライバシー画面:オフ", "화면 보호 꺼짐", "Sichtschutz aus", "Confidentialité inactive", "Privacidad desactivada", "Privacidade desativada"], + "隐私屏已开启": ["隐私屏已开启", "Privacy screen on", "Приватный экран вкл.", "隱私屏已開啟", "プライバシー画面:オン", "화면 보호 켜짐", "Sichtschutz an", "Confidentialité active", "Privacidad activada", "Privacidade ativada"], + "隐私屏已被解锁": ["隐私屏已被解锁", "Privacy screen unlocked", "Приватный экран разблокирован", "隱私屏已被解鎖", "プライバシー画面のロックが解除されました", "개인정보 보호 화면 잠금 해제됨", "Datenschutzbildschirm entsperrt", "Écran de confidentialité déverrouillé", "Pantalla de privacidad desbloqueada", "Tela de privacidade desbloqueada"], + "隐私屏异常": ["隐私屏异常", "Privacy screen abnormality", "Неисправность экрана конфиденциальности.", "隱私屏異常", "プライバシー画面異常", "개인정보 화면 이상", "Anomalie des Sichtschutzbildschirms", "Anomalie de l'écran de confidentialité", "Anormalidad en la pantalla de privacidad", "Anormalidade na tela de privacidade"], + "隐私屏暂不可用": ["隐私屏暂不可用", "Privacy screen is temporarily unavailable", "Экран конфиденциальности временно недоступен.", "隱私屏暫不可用", "プライバシー画面が一時的に利用できなくなります", "개인 정보 보호 화면을 일시적으로 사용할 수 없습니다.", "Der Datenschutzbildschirm ist vorübergehend nicht verfügbar", "L'écran de confidentialité est temporairement indisponible", "La pantalla de privacidad no está disponible temporalmente", "A tela de privacidade está temporariamente indisponível"], + "隐私屏状态已过期,等待电脑确认": ["隐私屏状态已过期,等待电脑确认", "Privacy screen status has expired, waiting for computer confirmation", "Срок действия статуса экрана конфиденциальности истек, ожидание подтверждения от компьютера.", "隱私屏狀態已過期,等待電腦確認", "プライバシー画面のステータスが期限切れになり、コンピュータの確認を待っています", "개인 정보 보호 화면 상태가 만료되어 컴퓨터 확인을 기다리는 중입니다.", "Der Status des Datenschutzbildschirms ist abgelaufen und wartet auf Computerbestätigung", "L'état de l'écran de confidentialité a expiré, en attente de confirmation par l'ordinateur", "El estado de la pantalla de privacidad ha caducado, esperando confirmación por computadora", "O status da tela de privacidade expirou, aguardando confirmação do computador"], + "隐私屏状态待确认": ["隐私屏状态待确认", "Privacy screen status to be confirmed", "Статус экрана конфиденциальности подлежит подтверждению.", "隱私屏狀態待確認", "プライバシー画面のステータスを確認する", "개인정보 보호 화면 상태 확인 예정", "Status des Datenschutzbildschirms muss bestätigt werden", "Statut de l'écran de confidentialité à confirmer", "Estado de la pantalla de privacidad por confirmar", "Status da tela de privacidade a ser confirmado"], + "隐私政策": ["隐私政策", "Privacy Policy", "Политика конфиденциальности", "隱私政策", "プライバシーポリシー", "개인정보 보호정책", "Datenschutzrichtlinie", "Politique de confidentialité", "Política de privacidad", "Política de Privacidade"], + "隐私政策无法读取,请重新安装应用": ["隐私政策无法读取,请重新安装应用", "Privacy policy cannot be read, please reinstall the app", "Невозможно прочитать политику конфиденциальности, переустановите приложение.", "隱私政策無法讀取,請重新安裝應用", "プライバシーポリシーが読めない場合はアプリを再インストールしてください", "개인정보취급방침을 읽을 수 없습니다. 앱을 다시 설치해 주세요.", "Datenschutzbestimmungen können nicht gelesen werden, bitte installieren Sie die App neu", "La politique de confidentialité ne peut pas être lue, veuillez réinstaller l'application", "No se puede leer la política de privacidad; reinstale la aplicación", "A política de privacidade não pode ser lida, reinstale o aplicativo"], + "隐藏密码": ["隐藏密码", "Hide password", "Скрыть пароль", "隱藏密碼", "パスワードを隠す", "비밀번호 숨기기", "Passwort verbergen", "Masquer le mot de passe", "Ocultar contraseña", "Ocultar senha"], + "静音": ["静音", "Mute", "Без звука", "靜音", "ミュート", "음소거", "Stumm", "Muet", "Silencio", "Mudo"], + "音频": ["音频", "Audio", "Аудио", "音訊", "オーディオ", "오디오", "Audio", "Audio", "Audio", "Áudio"], + "预览可能包含远程设备上的敏感内容。仅保存在本机,从下一次连接起生效,可随时关闭并清除。": ["预览可能包含远程设备上的敏感内容。仅保存在本机,从下一次连接起生效,可随时关闭并清除。", "The preview may contain sensitive content on the remote device. It is only saved locally and takes effect from the next connection. It can be closed and cleared at any time.", "Предварительный просмотр может содержать конфиденциальный контент на удаленном устройстве. Он сохраняется только локально и вступает в силу при следующем подключении. Его можно закрыть и очистить в любой момент.", "預覽可能包含遠端裝置上的敏感內容。僅儲存在本機,從下一次連線起生效,可隨時關閉並清除。", "プレビューには、リモート デバイス上の機密コンテンツが含まれる可能性があります。これはローカルにのみ保存され、次回の接続から有効になります。いつでも閉じたりクリアしたりできます。", "미리보기에는 원격 장치의 민감한 콘텐츠가 포함될 수 있습니다. 로컬에만 저장되며 다음 연결부터 적용됩니다. 언제든지 닫고 지울 수 있습니다.", "Die Vorschau enthält möglicherweise vertrauliche Inhalte auf dem Remote-Gerät. Es wird nur lokal gespeichert und ist ab der nächsten Verbindung wirksam. Es kann jederzeit geschlossen und geräumt werden.", "L'aperçu peut contenir du contenu sensible sur l'appareil distant. Il est uniquement enregistré localement et prend effet dès la prochaine connexion. Il peut être fermé et effacé à tout moment.", "La vista previa puede contener contenido confidencial en el dispositivo remoto. Sólo se guarda localmente y entra en vigor a partir de la siguiente conexión. Se puede cerrar y borrar en cualquier momento.", "A visualização pode conter conteúdo confidencial no dispositivo remoto. Ele é salvo apenas localmente e entra em vigor na próxima conexão. Pode ser fechado e limpo a qualquer momento."], + "高": ["高", "High", "Высокое", "高", "高", "높음", "Hoch", "Élevée", "Alta", "Alta"], + "默认": ["默认", "Default", "По умолчанию", "預設", "デフォルト", "기본값", "Standard", "Par défaut", "Predeterminado", "Padrão"], + "默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。": ["默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。", "Off by default. When turned on, the screen will enter and remain in landscape orientation when the phone is connected; when turned off, it will follow the direction of the device. Tablets and multi-windows are not affected.", "По умолчанию выключено. При включении экран войдет и останется в альбомной ориентации при подключении телефона; в выключенном состоянии он будет следовать направлению устройства. Планшеты и мультиокна не затронуты.", "預設關閉。開啟後,手機連線時進入並保持橫屏;關閉時跟隨裝置方向。平板和多視窗不受影響。", "デフォルトではオフです。オンにすると、電話が接続されているときに画面が横向きになり、横向きのままになります。オフにすると、デバイスの方向に従います。タブレットやマルチウィンドウは影響を受けません。", "기본적으로 꺼져 있습니다. 전원을 켜면 휴대폰이 연결되면 화면이 가로 방향으로 전환되고 유지됩니다. 꺼지면 장치의 방향을 따릅니다. 태블릿과 멀티 윈도우는 영향을 받지 않습니다.", "Standardmäßig deaktiviert. Wenn es eingeschaltet ist, wird der Bildschirm angezeigt und bleibt im Querformat, wenn das Telefon angeschlossen ist. Wenn es ausgeschaltet ist, folgt es der Richtung des Geräts. Tablets und Multi-Windows sind nicht betroffen.", "Désactivé par défaut. Lorsqu'il est allumé, l'écran entre et reste en orientation paysage lorsque le téléphone est connecté ; lorsqu'il est éteint, il suivra la direction de l'appareil. Les tablettes et multi-fenêtres ne sont pas concernées.", "Desactivado de forma predeterminada. Cuando esté encendido, la pantalla entrará y permanecerá en orientación horizontal cuando el teléfono esté conectado; cuando esté apagado, seguirá la dirección del dispositivo. Las tabletas y las ventanas múltiples no se ven afectadas.", "Desligado por padrão. Quando ligado, a tela entrará e permanecerá na orientação paisagem quando o telefone estiver conectado; quando desligado, seguirá a direção do dispositivo. Tablets e janelas múltiplas não são afetados."], + "鼠标右键,按住拖动": ["鼠标右键,按住拖动", "Right mouse button, hold down and drag", "Правая кнопка мыши, удерживайте ее и перетащите", "滑鼠右鍵,按住拖動", "マウスの右ボタンを押したままドラッグします", "마우스 오른쪽 버튼을 누르고 드래그하세요.", "Rechte Maustaste, gedrückt halten und ziehen", "Bouton droit de la souris, maintenez enfoncé et faites glisser", "Botón derecho del ratón, mantén pulsado y arrastra", "Botão direito do mouse, mantenha pressionado e arraste"], + "鼠标左键,按住拖动": ["鼠标左键,按住拖动", "Left mouse button, hold down and drag", "Левая кнопка мыши, удерживая ее, перетащите", "滑鼠左鍵,按住拖動", "マウスの左ボタンを押したままドラッグします", "마우스 왼쪽 버튼을 누른 채 드래그", "Linke Maustaste, gedrückt halten und ziehen", "Bouton gauche de la souris, maintenez enfoncé et faites glisser", "Botón izquierdo del ratón, mantén pulsado y arrastra", "Botão esquerdo do mouse, mantenha pressionado e arraste"], + "鼠标控制": ["鼠标控制", "Mouse control", "Управление мышью", "滑鼠控制", "マウスコントロール", "마우스 제어", "Maussteuerung", "Contrôle de la souris", "Control del ratón", "Controle do mouse"], +}; diff --git a/apps/harmony/entry/src/main/ets/mobile/MobileController.ets b/apps/harmony/entry/src/main/ets/mobile/MobileController.ets index 5ef6c6c1..a9e3176f 100644 --- a/apps/harmony/entry/src/main/ets/mobile/MobileController.ets +++ b/apps/harmony/entry/src/main/ets/mobile/MobileController.ets @@ -1,3 +1,4 @@ +import { tr } from './Localization'; import { RemotePrivacyScreen, PrivacyStatus } from './RemotePrivacyScreen'; import bridge from 'libcrossdesk.so'; import { common, bundleManager } from '@kit.AbilityKit'; @@ -44,7 +45,7 @@ export class MobileState { password: string = ''; remember: boolean = false; signal: number = -1; - signalText: string = '未连接'; + signalText: string = tr("未连接"); identity: string = ''; connecting: boolean = false; ready: boolean = false; @@ -76,7 +77,7 @@ export class MobileState { videoSupported: boolean = false; videoFeedback: string = ''; privacyStatus: string = ''; - privacyButtonTitle: string = '隐私屏'; + privacyButtonTitle: string = tr("隐私屏"); privacyFeedback: string = ''; privacyEnabled: boolean = false; privacyActive: boolean = false; @@ -160,9 +161,9 @@ export class MobileController { now(): number { return systemDateTime.getUptime(systemDateTime.TimeType.STARTUP, false); } toast(text: string): void { if (this.foreground) promptAction.showToast({ message: text, duration: 3000 }); else this.state.notice = text; } async consent(): Promise { - if (!this.state.privacyAvailable) { this.state.notice = '隐私政策无法读取,请重新安装应用'; return; } + if (!this.state.privacyAvailable) { this.state.notice = tr("隐私政策无法读取,请重新安装应用"); return; } try { this.store.put('consent', true); this.state.consent = true; this.state.modal = ''; await this.ensureSignal(); this.checkLocal(); } - catch { this.toast('无法保存联网授权,请重试'); } + catch { this.toast(tr("无法保存联网授权,请重试")); } } revoke(): void { this.end(''); this.stopSignal(); this.state.consent = false; this.state.previews = false; @@ -188,16 +189,16 @@ export class MobileController { // A public ID alone is not a login credential. Discard legacy incomplete records. if (identity && !/^[0-9]{9}@.+$/.test(identity)) { await this.store.removeSecret(`identity:${scope}`); identity = ''; } if (session !== this.session || !this.foreground || !this.state.consent) return; - this.state.signalText = '正在连接…'; this.state.signal = 0; this.started = true; + this.state.signalText = tr("正在连接…"); this.state.signal = 0; this.started = true; this.send({ op: 'start', session: session, server: this.state.server, port: Number(this.state.port), identity: identity, logs: this.context.cacheDir, certificates: '/etc/security/certificates', directory: this.store.directory, previewDirectory: this.store.previewDirectory, version: this.state.version }); - } catch { this.state.signalText = '安全存储不可用,请解锁设备后重试'; this.state.signal = -1; } + } catch { this.state.signalText = tr("安全存储不可用,请解锁设备后重试"); this.state.signal = -1; } finally { if (session === this.session) this.starting = false; } } private stopSignal(): void { this.session++; this.starting = this.started = false; this.signalGeneration = -1; - this.send({ op: 'stop' }); this.state.signal = -1; this.state.identity = ''; this.state.signalText = '未连接'; + this.send({ op: 'stop' }); this.state.signal = -1; this.state.identity = ''; this.state.signalText = tr("未连接"); this.presence.connect(false, this.now()); this.inbox.connect(false); this.platform.cancelRequests(); this.localVersionRequest = this.remoteVersionRequest = 0; this.checkingLocal = false; } @@ -205,7 +206,7 @@ export class MobileController { saveSettings(server: string, port: string): void { server = server.trim(); const number = Number(port); if (!server || server.length > 253 || /[\s/@?#]/.test(server) || !Number.isInteger(number) || number < 1 || number > 65535) { - this.toast('请输入有效的服务器地址和端口'); return; + this.toast(tr("请输入有效的服务器地址和端口")); return; } const changed = server !== this.state.server || port !== this.state.port; this.store.put('server', server); this.store.put('port', port); this.state.server = server; this.state.port = port; @@ -219,11 +220,11 @@ export class MobileController { .concat(values.filter((d: RecentDevice) => !this.presence?.online(d.id, now))); } async deleteRecent(id: string): Promise { - try { await this.store.delete(this.scope(), id); this.history(); } catch { this.toast('记录或密码删除失败,请重试'); } + try { await this.store.delete(this.scope(), id); this.history(); } catch { this.toast(tr("记录或密码删除失败,请重试")); } } async requestConnection(id: string): Promise { id = id.replace(/\s/g, ''); this.state.remote = id; - if (!/^[0-9]{9}$/.test(id)) { this.toast('请输入 9 位设备 ID'); return; } + if (!/^[0-9]{9}$/.test(id)) { this.toast(tr("请输入 9 位设备 ID")); return; } if (!this.state.consent) { this.state.modal = 'consent'; return; } const epoch = ++this.uiEpoch, scope = this.scope(); this.state.password = ''; this.state.notice = ''; @@ -232,11 +233,11 @@ export class MobileController { const password = await this.store.secret(`password:${scope}:${id}`); if (epoch !== this.uiEpoch || !this.foreground || !this.state.consent) return; if (password) { this.state.remember = true; this.begin(password); return; } - } catch { if (epoch === this.uiEpoch) this.state.notice = '已保存密码无法读取,请重新输入'; } + } catch { if (epoch === this.uiEpoch) this.state.notice = tr("已保存密码无法读取,请重新输入"); } if (epoch === this.uiEpoch) this.state.modal = 'password'; } begin(password: string): void { - if (!this.state.consent || !/^[0-9]{9}$/.test(this.state.remote) || !password || password.length > 128 || password.includes('@')) { this.toast('请输入有效的访问密码'); return; } + if (!this.state.consent || !/^[0-9]{9}$/.test(this.state.remote) || !password || password.length > 128 || password.includes('@')) { this.toast(tr("请输入有效的访问密码")); return; } this.joinSent = false; this.connection++; this.connectingId = this.state.remote; this.pendingPassword = password; this.state.connecting = true; this.state.ready = false; this.state.modal = 'connecting'; this.state.notice = ''; this.state.muted = false; this.state.platform = ''; this.state.hostName = ''; this.state.receivedPath = this.state.receivedName = this.state.transfer = ''; @@ -276,7 +277,7 @@ export class MobileController { } shortcut(code: number): void { this.chord(code, [this.state.platform === 'macos' ? 91 : 17]); } text(text: string): void { - if (text.length > 2048 || Array.from(text).some((c: string) => asciiKey(c) === 0)) { this.toast('中文等文本请通过剪贴板发送,再点击粘贴'); return; } + if (text.length > 2048 || Array.from(text).some((c: string) => asciiKey(c) === 0)) { this.toast(tr("中文等文本请通过剪贴板发送,再点击粘贴")); return; } for (const c of text) { const code = asciiKey(c); this.chord(code & 255, code & 256 ? [16] : []); } } setRelative(value: boolean): void { this.release(); this.state.relative = value; this.store.put('relative', value); } @@ -301,27 +302,27 @@ export class MobileController { if (!value) { this.send({ op: 'cancelPreview' }); this.previewEligible = false; this.store.clearPreviews(); this.history(); } this.state.modal = ''; } - clearPreviews(): void { this.send({ op: 'cancelPreview' }); this.previewEligible = false; this.store.clearPreviews(); this.history(); this.toast('已清除预览'); } + clearPreviews(): void { this.send({ op: 'cancelPreview' }); this.previewEligible = false; this.store.clearPreviews(); this.history(); this.toast(tr("已清除预览")); } clipboard(): void { const text = this.state.clipboardText; - if (new util.TextEncoder().encodeInto(text).length > 128 * 1024) { this.toast('文本超过 128 KB'); return; } - if (text) { this.send({ op: 'clipboard', text: text }); this.toast('已发送,请在远端粘贴'); } + if (new util.TextEncoder().encodeInto(text).length > 128 * 1024) { this.toast(tr("文本超过 128 KB")); return; } + if (text) { this.send({ op: 'clipboard', text: text }); this.toast(tr("已发送,请在远端粘贴")); } } async copyRemote(): Promise { - if (!this.state.remoteClipboard) { this.toast('尚未收到远端文本'); return; } - try { await pasteboard.getSystemPasteboard().setData(pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, this.state.remoteClipboard)); this.toast('已复制远端文本'); } - catch { this.toast('复制失败,请重试'); } + if (!this.state.remoteClipboard) { this.toast(tr("尚未收到远端文本")); return; } + try { await pasteboard.getSystemPasteboard().setData(pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, this.state.remoteClipboard)); this.toast(tr("已复制远端文本")); } + catch { this.toast(tr("复制失败,请重试")); } } sas(): void { if (this.state.platform !== 'windows') return; - if (!this.serviceAvailable) { this.toast('请在远端启用 CrossDesk 系统服务后重试'); return; } + if (!this.serviceAvailable) { this.toast(tr("请在远端启用 CrossDesk 系统服务后重试")); return; } this.send({ op: 'sas' }); } async chooseFile(): Promise { - if (this.sendingFile) { this.toast('请等待当前文件发送完成'); return; } + if (this.sendingFile) { this.toast(tr("请等待当前文件发送完成")); return; } const connection = this.connection; const file = await this.platform.choose(this.store.directory); if (connection !== this.connection || !this.state.ready || !file) { if (file) this.store.discardOutgoing(file.path); return; } - this.sendingFile = true; this.state.transfer = `发送 ${file.name} · 0%`; + this.sendingFile = true; this.state.transfer = tr("发送 {0} · 0%", [String(file.name)]); this.send({ op: 'sendFile', path: file.path, name: file.name }); } saveFile(): void { if (this.state.receivedPath) this.platform.save(this.state.receivedPath, this.state.receivedName); } @@ -331,17 +332,17 @@ export class MobileController { async checkLocal(manual: boolean = false): Promise { if (!this.state.consent || !this.foreground || this.checkingLocal) return; this.checkingLocal = true; const request = ++this.versionRequest; this.localVersionRequest = request; - const epoch = this.uiEpoch; if (manual) this.state.updateStatus = '正在检查…'; + const epoch = this.uiEpoch; if (manual) this.state.updateStatus = tr("正在检查…"); const body = await this.platform.version(); if (request !== this.localVersionRequest || epoch !== this.uiEpoch || !this.foreground || !this.state.consent) return; this.checkingLocal = false; if (body) this.send({ op: 'version', body: body, local: true, version: this.state.version, request: request }); - else if (manual) this.state.updateStatus = '检查失败,请稍后重试'; + else if (manual) this.state.updateStatus = tr("检查失败,请稍后重试"); } private async checkRemote(version: string): Promise { if (this.checkedRemote || !this.foreground || !this.state.consent || !this.state.ready) return; this.checkedRemote = true; - if (!version || !/^\d+\.\d+\.\d+/.test(version)) { this.state.notice = '被控端版本过低,请升级到最新版本。'; this.state.modal = 'upgrade'; return; } + if (!version || !/^\d+\.\d+\.\d+/.test(version)) { this.state.notice = tr("被控端版本过低,请升级到最新版本。"); this.state.modal = 'upgrade'; return; } const request = ++this.versionRequest, connection = this.connection; this.remoteVersionRequest = request; const body = await this.platform.version(); if (body && request === this.remoteVersionRequest && connection === this.connection && this.foreground && this.state.consent) @@ -351,7 +352,7 @@ export class MobileController { try { this.state.documentText = name === 'PRIVACY.md' ? this.privacy : util.TextDecoder.create('utf-8').decodeWithStream(this.context.resourceManager.getRawFileContentSync(name)); this.state.documentTitle = title; this.state.documentBack = back; this.state.page = 'document'; this.state.modal = ''; - } catch { this.toast('无法读取文档'); } + } catch { this.toast(tr("无法读取文档")); } } dismissPrivacyUnlock(): void { this.privacyScreen.unlockNotice = false; @@ -389,7 +390,7 @@ export class MobileController { } private poll(): void { try { const events = JSON.parse(bridge.mobilePoll()) as NativeEvent[]; events.forEach((event: NativeEvent) => this.event(event)); } - catch { this.state.signalText = '原生通信库不可用,请重新构建并安装'; } + catch { this.state.signalText = tr("原生通信库不可用,请重新构建并安装"); } if (++this.seconds % 20 === 0) { if (this.state.ready) this.syncPrivacy(); this.state.networkTime = this.now(); this.presence.tick(this.state.networkTime); this.history(); @@ -401,13 +402,13 @@ export class MobileController { } if (e.type === 'identity' && e.identity) { this.state.identity = e.identity.split('@')[0]; const scope = this.scope(); - if (e.identity.includes('@')) this.store.saveSecret(`identity:${scope}`, e.identity).catch(() => this.toast('设备身份保存失败,请检查安全存储')); + if (e.identity.includes('@')) this.store.saveSecret(`identity:${scope}`, e.identity).catch(() => this.toast(tr("设备身份保存失败,请检查安全存储"))); this.joinIfReady(); this.configureInbox(); } else if (e.type === 'signal' && !e.controller) { if (e.generation !== this.signalGeneration) { this.signalGeneration = e.generation ?? -1; this.presence.connect(false, this.now()); this.inbox.connect(false); } this.state.signal = e.status ?? -1; this.state.identity = e.id || this.state.identity; - const labels = ['正在连接…', '已连接', '连接失败', '服务器已断开', '正在重连…', '服务器已断开', '服务器证书校验失败']; - this.state.signalText = labels[this.state.signal] ?? '未连接'; this.presence.connect(this.state.signal === 1, this.now()); this.configureInbox(); this.joinIfReady(); + const labels = [tr("正在连接…"), tr("已连接"), tr("连接失败"), tr("服务器已断开"), tr("正在重连…"), tr("服务器已断开"), tr("服务器证书校验失败")]; + this.state.signalText = labels[this.state.signal] ?? tr("未连接"); this.presence.connect(this.state.signal === 1, this.now()); this.configureInbox(); this.joinIfReady(); } else if (e.type === 'signalMessage' && e.generation === this.signalGeneration && e.message) { const type = (e.message as SignalType).type; if (type === 'announcements_changed') this.inbox.refresh(); @@ -417,10 +418,10 @@ export class MobileController { else if (e.type === 'connection') { if (e.status === 1 && !this.state.ready) this.connected(); else if (e.status === 6) { - this.end(''); this.state.remote = this.connectingId; this.state.notice = '访问密码错误,请重新输入'; this.state.modal = 'password'; + this.end(''); this.state.remote = this.connectingId; this.state.notice = tr("访问密码错误,请重新输入"); this.state.modal = 'password'; } else if ((e.status ?? 0) >= 3) { - const reasons = ['', '', '', '连接已断开', '连接失败', '远端已关闭连接', '访问密码错误', '找不到该设备 ID', '远端当前不可用']; - this.end(reasons[e.status ?? 0] ?? '连接已结束'); + const reasons = ['', '', '', tr("连接已断开"), tr("连接失败"), tr("远端已关闭连接"), tr("访问密码错误"), tr("找不到该设备 ID"), tr("远端当前不可用")]; + this.end(reasons[e.status ?? 0] ?? tr("连接已结束")); } } else if (e.type === 'ended') this.end(e.reason ?? ''); else if (e.type === 'data' && e.message) this.data(e.message as ControlData); @@ -437,7 +438,7 @@ export class MobileController { else if (e.type === 'feedback') this.toast(e.text ?? ''); else if (e.type === 'file') { if (e.sending && ((e.progress ?? 0) < 0 || (e.progress ?? 0) >= 1)) this.sendingFile = false; - this.state.transfer = (e.progress ?? 0) < 0 ? `${e.name} 传输失败` : `${e.sending ? '发送' : '接收'} ${e.name} · ${(e.progress ?? 0) >= 1 ? '已完成' : Math.floor((e.progress ?? 0) * 100) + '%'}`; + this.state.transfer = (e.progress ?? 0) < 0 ? tr("{0} 传输失败", [String(e.name)]) : `${e.sending ? '发送' : '接收'} ${e.name} · ${(e.progress ?? 0) >= 1 ? '已完成' : Math.floor((e.progress ?? 0) * 100) + '%'}`; if (e.path) { this.state.receivedPath = e.path; this.state.receivedName = e.name ?? 'received-file'; } } else if (e.type === 'privacyFailed') { this.privacyScreen.failed(Number(e.request)); this.syncPrivacy(); } else if (e.type === 'settingsFailed') { this.video.expire(Number(e.request)); this.syncVideo(); } @@ -448,14 +449,14 @@ export class MobileController { } else if (e.path) this.store.discardRaw(e.path); } else if (e.type === 'version') { if (e.request === this.localVersionRequest && this.foreground && this.state.consent) { - if (e.ok) { this.state.update = e.latest ?? ''; this.state.updateStatus = this.state.update ? `发现新版本 ${this.state.update}` : '已是最新版本'; } - else this.state.updateStatus = '暂无鸿蒙版本信息,请稍后重试'; + if (e.ok) { this.state.update = e.latest ?? ''; this.state.updateStatus = this.state.update ? tr("发现新版本 {0}", [String(this.state.update)]) : tr("已是最新版本"); } + else this.state.updateStatus = tr("暂无鸿蒙版本信息,请稍后重试"); } else if (e.request === this.remoteVersionRequest && e.ok && e.latest && this.foreground && this.state.ready) { - this.state.notice = '被控端版本过低,请升级到最新版本。'; this.state.modal = 'upgrade'; + this.state.notice = tr("被控端版本过低,请升级到最新版本。"); this.state.modal = 'upgrade'; } } else if (e.type === 'error') { - this.state.signalText = e.text ?? '连接失败'; if (this.state.connecting) { this.end(e.text ?? '连接失败'); this.stopSignal(); } - else if (!this.state.ready) { const text = e.text ?? '操作失败'; this.stopSignal(); this.state.signalText = text; } else this.toast(e.text ?? '操作失败'); + this.state.signalText = e.text ?? tr("连接失败"); if (this.state.connecting) { this.end(e.text ?? tr("连接失败")); this.stopSignal(); } + else if (!this.state.ready) { const text = e.text ?? tr("操作失败"); this.stopSignal(); this.state.signalText = text; } else this.toast(e.text ?? tr("操作失败")); } } private configureInbox(): void { @@ -474,7 +475,7 @@ export class MobileController { if (this.state.hostName) this.store.metadata(scope, device.id, this.state.hostName, this.state.platform); this.history(); } - }).catch(() => this.toast('密码保存失败,本次连接仍可使用')); + }).catch(() => this.toast(tr("密码保存失败,本次连接仍可使用"))); this.platform.connected(this.state.autoLandscape); if (this.video.supported && this.video.requestId === 0) this.updateVideo(0, this.video.selection.quality); if (this.receivedHostInfo) this.checkRemote(this.remoteVersion); diff --git a/apps/harmony/entry/src/main/ets/mobile/MobilePlatform.ets b/apps/harmony/entry/src/main/ets/mobile/MobilePlatform.ets index 705be76e..f714e653 100644 --- a/apps/harmony/entry/src/main/ets/mobile/MobilePlatform.ets +++ b/apps/harmony/entry/src/main/ets/mobile/MobilePlatform.ets @@ -1,3 +1,4 @@ +import { tr } from './Localization'; import { deviceInfo } from '@kit.BasicServicesKit'; import { common, wantAgent } from '@kit.AbilityKit'; import { PiPWindow, window, display } from '@kit.ArkUI'; @@ -34,7 +35,7 @@ export class MobilePlatform { private feedback: (message: string) => void; private backgroundCancelled: () => void = () => { this.backgroundActive = false; - if (this.active && !this.foreground && !this.pipActive && !this.choosing) this.ended('系统已停止后台会话'); + if (this.active && !this.foreground && !this.pipActive && !this.choosing) this.ended(tr("系统已停止后台会话")); }; constructor(context: common.UIAbilityContext, ended: (reason: string) => void, release: () => void, feedback: (message: string) => void) { this.context = context; this.ended = ended; this.release = release; this.feedback = feedback; @@ -82,7 +83,7 @@ export class MobilePlatform { if (state === PiPWindow.PiPState.STOPPED) { this.pipActive = false; this.onVisibility(this.foreground); - if (!this.foreground && !this.choosing && this.active) this.ended('画中画已关闭'); + if (!this.foreground && !this.choosing && this.active) this.ended(tr("画中画已关闭")); } }); } catch { /* A continuous data-transfer task remains the fallback. */ } @@ -104,7 +105,7 @@ export class MobilePlatform { } await this.backgroundQueue; if (generation === this.generation && !this.foreground && this.active && !this.backgroundActive && !this.pipActive && !this.choosing) - this.ended('系统未允许后台会话,连接已断开'); + this.ended(tr("系统未允许后台会话,连接已断开")); } resume(): void { this.foreground = true; this.dismissPiP(); this.orientation(this.active); this.onVisibility(true); } private async dismissPiP(): Promise { @@ -164,7 +165,7 @@ export class MobilePlatform { try { await fs.copyFile(input.fd, path); } finally { await fs.close(input); } if (generation !== this.generation || !this.active) { await fs.unlink(path); return undefined; } return { path: path, name: name }; - } catch { if (path) try { await fs.unlink(path); } catch {} this.feedback('无法读取所选文件或存储空间不足'); return undefined; } + } catch { if (path) try { await fs.unlink(path); } catch {} this.feedback(tr("无法读取所选文件或存储空间不足")); return undefined; } finally { if (generation === this.generation) this.setChoosing(false); } } async save(path: string, name: string): Promise { @@ -177,8 +178,8 @@ export class MobilePlatform { if (!uris.length || generation !== this.generation || !this.active) return; const output = await fs.open(uris[0], fs.OpenMode.WRITE_ONLY | fs.OpenMode.TRUNC); try { await fs.copyFile(path, output.fd); } finally { await fs.close(output); } - if (generation === this.generation) this.feedback('文件已保存'); - } catch { if (generation === this.generation) this.feedback('文件保存失败,请重试'); } + if (generation === this.generation) this.feedback(tr("文件已保存")); + } catch { if (generation === this.generation) this.feedback(tr("文件保存失败,请重试")); } finally { if (generation === this.generation) this.setChoosing(false); } } async version(): Promise { @@ -196,7 +197,7 @@ export class MobilePlatform { cancelRequests(): void { for (const request of this.requests) request.destroy(); this.requests = []; } openLink(url: string): void { if (!isAnnouncementURL(url)) return; - this.context.startAbility({ action: 'ohos.want.action.viewData', uri: url }).catch(() => this.feedback('无法打开网页')); + this.context.startAbility({ action: 'ohos.want.action.viewData', uri: url }).catch(() => this.feedback(tr("无法打开网页"))); } } export interface PreparedFile { path: string; name: string; } diff --git a/apps/harmony/entry/src/main/ets/mobile/MobileRemoteView.ets b/apps/harmony/entry/src/main/ets/mobile/MobileRemoteView.ets index bf421d0b..d9bd69b9 100644 --- a/apps/harmony/entry/src/main/ets/mobile/MobileRemoteView.ets +++ b/apps/harmony/entry/src/main/ets/mobile/MobileRemoteView.ets @@ -1,3 +1,4 @@ +import { tr } from './Localization'; import { MobileController, MobileState } from './MobileController'; import { RemoteViewport, MouseInput, TouchInput, TouchPoint, clamp, NetworkStatistics, Traffic, asciiKey } from './ControllerModels'; import { MobileTheme, MobileSegment, MobileIcon, MobileIconButton } from './MobileWidgets'; @@ -136,7 +137,7 @@ export struct MobileRemoteView { if (index === 10) this.controller?.togglePrivacy(); } private labels(): string[] { - return ['键盘', this.state.relative ? '相对鼠标' : '绝对鼠标', this.mouseVisible ? '收起鼠标' : '虚拟鼠标', '显示器', '画面设置', this.state.muted ? '静音' : '声音', '发送文件', '网络状态', 'Ctrl+Alt+Del', '剪贴板', this.state.privacyButtonTitle]; + return [tr("键盘"), this.state.relative ? tr("相对鼠标") : tr("绝对鼠标"), this.mouseVisible ? tr("收起鼠标") : tr("虚拟鼠标"), tr("显示器"), tr("画面设置"), this.state.muted ? tr("静音") : tr("声音"), tr("发送文件"), tr("网络状态"), 'Ctrl+Alt+Del', tr("剪贴板"), this.state.privacyButtonTitle]; } private controlIds(): number[] { return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].filter((index: number) => @@ -155,22 +156,33 @@ export struct MobileRemoteView { return { x: clamp(x, 8, this.viewWidth - 148), y: clamp(y, 8, this.viewHeight - 56) }; } private keyboardWidth(): number { return Math.max(1, Math.min(this.computerKeyboard ? 520 : 440, this.viewWidth - 16)); } + private keyboardTitle(key: string): string { + switch (key) { + case 'copy': return tr("复制"); + case 'paste': return tr("粘贴"); + case 'select_all': return tr("全选"); + case 'space': return tr("空格"); + case 'computer': return tr("电脑"); + case 'clipboard': return tr("剪贴板"); + default: return this.shift && key.length === 1 ? key.toUpperCase() : key; + } + } private keyboardRows(): KeyRow[] { return this.computerKeyboard ? [ { keys: ['Esc', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6'] }, { keys: ['Tab', 'Ctrl', 'Alt', 'Win', '↑', '⌫'] }, - { keys: ['复制', '粘贴', '全选', '←', '↓', '→'] }, { keys: ['ABC', '空格', 'Enter'] } + { keys: ['copy', 'paste', 'select_all', '←', '↓', '→'] }, { keys: ['ABC', 'space', 'Enter'] } ] : [{ keys: ['1','2','3','4','5','6','7','8','9','0'] }, { keys: ['q','w','e','r','t','y','u','i','o','p'] }, { keys: ['a','s','d','f','g','h','j','k','l'] }, { keys: ['⇧','z','x','c','v','b','n','m','⌫'] }, - { keys: ['电脑','剪贴板','空格','.','Enter'] }]; + { keys: ['computer','clipboard','space','.','Enter'] }]; } private keyboardKey(value: string): void { if (value === '⇧') { this.shift = !this.shift; return; } - if (value === '电脑' || value === 'ABC') { this.computerKeyboard = value === '电脑'; return; } - if (value === '剪贴板') { this.state.modal = 'clipboard'; return; } + if (value === 'computer' || value === 'ABC') { this.computerKeyboard = value === 'computer'; return; } + if (value === 'clipboard') { this.state.modal = 'clipboard'; return; } const modifier = value === 'Ctrl' ? 17 : value === 'Alt' ? 18 : value === 'Win' ? 91 : 0; if (modifier) { this.modifiers = this.modifiers.includes(modifier) ? this.modifiers.filter((m: number) => m !== modifier) : [...this.modifiers, modifier]; return; } - if (value === '复制' || value === '粘贴' || value === '全选') { this.controller?.shortcut(value === '复制' ? 67 : value === '粘贴' ? 86 : 65); return; } - const names = ['空格','⌫','Enter','Esc','Tab','↑','↓','←','→']; const codes = [32,8,13,27,9,38,40,37,39]; + if (value === 'copy' || value === 'paste' || value === 'select_all') { this.controller?.shortcut(value === 'copy' ? 67 : value === 'paste' ? 86 : 65); return; } + const names = ['space','⌫','Enter','Esc','Tab','↑','↓','←','→']; const codes = [32,8,13,27,9,38,40,37,39]; let code = names.includes(value) ? codes[names.indexOf(value)] : /^F[1-6]$/.test(value) ? 111 + Number(value.substring(1)) : 0; if (!code && this.modifiers.length) { const key = asciiKey(this.shift ? value.toUpperCase() : value); code = key & 255; if (key & 256) this.modifiers = [...this.modifiers, 16]; } if (code) { this.controller?.chord(code, this.modifiers); this.modifiers = []; } @@ -183,11 +195,11 @@ export struct MobileRemoteView { @Builder NetworkRow(title: string, traffic: Traffic | undefined) { Row({ space: 4 }) { - Text(title).fontSize(11).fontWeight(title === '合计' ? 600 : 400).fontColor(MobileTheme.ink).width(28) + Text(title).fontSize(11).minFontSize(8).maxFontSize(11).maxLines(1).fontWeight(title === tr("合计") ? 600 : 400).fontColor(MobileTheme.ink).width(48) Text(NetworkStatistics.rate(traffic?.inbound ?? -1)).fontSize(11).minFontSize(8).maxLines(1).layoutWeight(1).textAlign(TextAlign.End) Text(NetworkStatistics.rate(traffic?.outbound ?? -1)).fontSize(11).minFontSize(8).maxLines(1).layoutWeight(1).textAlign(TextAlign.End) Text(NetworkStatistics.loss(traffic?.loss ?? -1)).fontSize(11).width(46).textAlign(TextAlign.End) - }.padding({ left: 4, right: 4 }).height(26).width('100%').borderRadius(5).backgroundColor(title === '合计' ? '#122E7ADB' : Color.Transparent) + }.padding({ left: 4, right: 4 }).height(26).width('100%').borderRadius(5).backgroundColor(title === tr("合计") ? '#122E7ADB' : Color.Transparent) } @Builder NetworkDetail(label: string, value: string, encrypted: boolean = false) { @@ -210,12 +222,12 @@ export struct MobileRemoteView { Menu() { Column({ space: 10 }) { Row({ space: 6 }) { - if (this.menu !== 'controls') { MobileIconButton({ icon: 'back', label: '返回控制栏', iconExtent: 30, iconSize: 19, action: () => this.menu = 'controls' }) } + if (this.menu !== 'controls') { MobileIconButton({ icon: 'back', label: tr("返回控制栏"), iconExtent: 30, iconSize: 19, action: () => this.menu = 'controls' }) } Row({ space: 6 }) { if (this.menu === 'controls') { Row() {}.width(6).height(6).borderRadius(3).backgroundColor(MobileTheme.green) } - Text(this.menu === 'controls' ? '已连接' : this.menu === 'video' ? '画面设置' : '网络状态').fontSize(14).fontWeight(600).fontColor(MobileTheme.ink) + Text(this.menu === 'controls' ? tr("已连接") : this.menu === 'video' ? tr("画面设置") : tr("网络状态")).fontSize(14).fontWeight(600).fontColor(MobileTheme.ink) }.layoutWeight(1) - MobileIconButton({ icon: 'close', label: '关闭控制栏', iconExtent: 30, iconSize: 20, action: () => this.menu = '' }) + MobileIconButton({ icon: 'close', label: tr("关闭控制栏"), iconExtent: 30, iconSize: 20, action: () => this.menu = '' }) }.width('100%') Scroll() { Column({ space: 8 }) { @@ -225,7 +237,7 @@ export struct MobileRemoteView { GridCol() { Column({ space: 4 }) { MobileIcon({ name: this.icons()[index], iconExtent: 19 }) - Text(this.labels()[index]).fontSize(10).fontColor(MobileTheme.ink).maxLines(1) + Text(this.labels()[index]).fontSize(10).minFontSize(8).maxFontSize(10).fontColor(MobileTheme.ink).maxLines(2).textAlign(TextAlign.Center) } .height(52).width('100%').justifyContent(FlexAlign.Center) .backgroundColor('#F0F0F2').borderRadius(10) @@ -238,44 +250,44 @@ export struct MobileRemoteView { } if (this.state.privacyFeedback) { Text(this.state.privacyFeedback).fontSize(11).fontColor(MobileTheme.secondary).width('100%') } if (this.state.transfer) { Text(this.state.transfer).fontSize(11).fontColor(MobileTheme.secondary).width('100%') } - if (this.state.receivedPath) { Button('保存收到的文件', { type: ButtonType.Normal }).fontSize(14).fontColor(MobileTheme.blue).backgroundColor(Color.White).height(42).width('100%').onClick(() => this.controller?.saveFile()) } + if (this.state.receivedPath) { Button(tr("保存收到的文件"), { type: ButtonType.Normal }).fontSize(14).fontColor(MobileTheme.blue).backgroundColor(Color.White).height(42).width('100%').onClick(() => this.controller?.saveFile()) } } else if (this.menu === 'video') { Text(this.state.videoFeedback).fontSize(12).fontColor(MobileTheme.secondary).width('100%') - Text('画面质量').fontSize(12).width('100%') - MobileSegment({ labels: ['低', '中', '高'], selection: this.state.videoQuality, + Text(tr("画面质量")).fontSize(12).width('100%') + MobileSegment({ labels: [tr("低"), tr("中"), tr("高")], selection: this.state.videoQuality, available: this.state.videoSupported, changed: (i: number) => this.controller?.updateVideo(0, i) }) - Text('画面采集帧率').fontSize(12).width('100%') + Text(tr("画面采集帧率")).fontSize(12).width('100%') MobileSegment({ labels: ['30 fps', '60 fps'], selection: this.state.videoRate === 60 ? 1 : 0, available: this.state.videoSupported, changed: (i: number) => this.controller?.updateVideo(1, i ? 60 : 30) }) - Text('画面偏好').fontSize(12).width('100%') - MobileSegment({ labels: ['帧率优先', '画质优先', '平衡'], selection: this.state.videoSelectedPreference, + Text(tr("画面偏好")).fontSize(12).width('100%') + MobileSegment({ labels: [tr("帧率优先"), tr("画质优先"), tr("平衡")], selection: this.state.videoSelectedPreference, available: this.state.videoSupported, changed: (i: number) => this.controller?.updateVideo(2, i) }) } else { Row({ space: 4 }) { - Text('').width(28) - Text('接收').fontSize(11).fontColor(MobileTheme.secondary).layoutWeight(1).textAlign(TextAlign.End) - Text('发送').fontSize(11).fontColor(MobileTheme.secondary).layoutWeight(1).textAlign(TextAlign.End) - Text('丢包率').fontSize(11).fontColor(MobileTheme.secondary).width(46).textAlign(TextAlign.End) + Text('').width(48) + Text(tr("接收")).fontSize(11).fontColor(MobileTheme.secondary).layoutWeight(1).textAlign(TextAlign.End) + Text(tr("发送")).fontSize(11).fontColor(MobileTheme.secondary).layoutWeight(1).textAlign(TextAlign.End) + Text(tr("丢包率")).fontSize(11).minFontSize(8).maxFontSize(11).maxLines(2).fontColor(MobileTheme.secondary).width(46).textAlign(TextAlign.End) }.padding({ left: 4, right: 4 }).height(24).width('100%') Column() { - this.NetworkRow('视频', this.controller?.network.current(this.state.networkTime)?.video) - this.NetworkRow('音频', this.controller?.network.current(this.state.networkTime)?.audio) - this.NetworkRow('数据', this.controller?.network.current(this.state.networkTime)?.data) - this.NetworkRow('合计', this.controller?.network.current(this.state.networkTime)?.total) + this.NetworkRow(tr("视频"), this.controller?.network.current(this.state.networkTime)?.video) + this.NetworkRow(tr("音频"), this.controller?.network.current(this.state.networkTime)?.audio) + this.NetworkRow(tr("数据"), this.controller?.network.current(this.state.networkTime)?.data) + this.NetworkRow(tr("合计"), this.controller?.network.current(this.state.networkTime)?.total) }.width('100%') Divider().strokeWidth(0.5).color(MobileTheme.line).margin({ top: 2, bottom: 2 }) - this.NetworkDetail('帧率', `${this.controller?.network.fps(this.state.networkTime) ?? '—'} FPS`) - this.NetworkDetail('分辨率', this.state.hasFrame ? `${this.state.width} × ${this.state.height}` : '—') - this.NetworkDetail('画面延时', NetworkStatistics.delay(this.controller?.network.latency(this.state.networkTime) ?? -1)) - this.NetworkDetail('连接延时(RTT)', NetworkStatistics.delay(this.state.networkTime - (this.controller?.network.rttTime ?? 0) < 3000 ? this.controller?.network.rtt ?? -1 : -1)) - this.NetworkDetail('连接方式', this.controller?.network.mode(this.state.networkTime) ?? '—') - this.NetworkDetail('媒体加密', this.controller?.network.current(this.state.networkTime) === undefined ? '—' : this.controller?.network.report?.srtp ? 'SRTP 已启用' : '未启用', this.controller?.network.current(this.state.networkTime)?.srtp === true) - this.NetworkCodec('被控端编码器', this.controller?.network.remoteEncoder || '—') - this.NetworkCodec('控制端解码器', this.controller?.network.report?.decoder || '—') + this.NetworkDetail(tr("帧率"), `${this.controller?.network.fps(this.state.networkTime) ?? '—'} FPS`) + this.NetworkDetail(tr("分辨率"), this.state.hasFrame ? `${this.state.width} × ${this.state.height}` : '—') + this.NetworkDetail(tr("画面延时"), NetworkStatistics.delay(this.controller?.network.latency(this.state.networkTime) ?? -1)) + this.NetworkDetail(tr("连接延时(RTT)"), NetworkStatistics.delay(this.state.networkTime - (this.controller?.network.rttTime ?? 0) < 3000 ? this.controller?.network.rtt ?? -1 : -1)) + this.NetworkDetail(tr("连接方式"), this.controller?.network.mode(this.state.networkTime) ?? '—') + this.NetworkDetail(tr("媒体加密"), this.controller?.network.current(this.state.networkTime) === undefined ? '—' : this.controller?.network.report?.srtp ? tr("SRTP 已启用") : tr("未启用"), this.controller?.network.current(this.state.networkTime)?.srtp === true) + this.NetworkCodec(tr("被控端编码器"), this.controller?.network.remoteEncoder || '—') + this.NetworkCodec(tr("控制端解码器"), this.controller?.network.report?.decoder || '—') } }.width('100%') }.constraintSize({ maxHeight: Math.max(48, this.viewHeight - 132) }).width('100%').scrollBar(BarState.Off) - Button('断开连接', { type: ButtonType.Normal }).fontSize(14).fontColor(Color.White).width('100%').height(34).borderRadius(8).backgroundColor(MobileTheme.red) + Button(tr("断开连接"), { type: ButtonType.Normal }).fontSize(14).fontColor(Color.White).width('100%').height(34).borderRadius(8).backgroundColor(MobileTheme.red) .onClick(() => { this.release(); this.state.modal = 'disconnect'; this.menu = ''; this.keyboard = false; }) }.padding(12).width(this.menuWidth()).backgroundColor(Color.White).borderRadius(18) .border({ width: 0.5, color: MobileTheme.line }).shadow({ radius: 24, color: '#33000000', offsetY: 6 }) @@ -286,21 +298,21 @@ export struct MobileRemoteView { Keyboard() { Column({ space: 3 }) { Row() { - Stack() { Row() {}.width(32).height(4).backgroundColor(MobileTheme.secondary).borderRadius(2) }.layoutWeight(1).height(28).accessibilityText('拖动键盘') + Stack() { Row() {}.width(32).height(4).backgroundColor(MobileTheme.secondary).borderRadius(2) }.layoutWeight(1).height(28).accessibilityText(tr("拖动键盘")) .gesture(PanGesture().onActionStart(() => { this.keyboardOriginX = this.keyboardX; this.keyboardOriginY = this.keyboardY; }) .onActionUpdate((e: GestureEvent) => this.keyboardDrag(e))) - MobileIconButton({ icon: 'close', label: '收起键盘', iconExtent: 28, iconSize: 18, action: () => { this.keyboard = false; this.modifiers = []; } }) + MobileIconButton({ icon: 'close', label: tr("收起键盘"), iconExtent: 28, iconSize: 18, action: () => { this.keyboard = false; this.modifiers = []; } }) }.width('100%') Scroll() { Column({ space: 3 }) { ForEach(this.keyboardRows(), (row: KeyRow) => { Row({ space: 3 }) { ForEach(row.keys, (key: string) => { - Text(this.shift && key.length === 1 ? key.toUpperCase() : key).fontSize(key.length > 2 ? 11 : 14) - .height(31).layoutWeight(key === '空格' ? 3 : 1).textAlign(TextAlign.Center).borderRadius(5).fontColor(MobileTheme.ink) + Text(this.keyboardTitle(key)).fontSize(key.length > 2 ? 11 : 14).minFontSize(8).maxFontSize(key.length > 2 ? 11 : 14).maxLines(1) + .height(31).layoutWeight(key === 'space' ? 3 : 1).textAlign(TextAlign.Center).borderRadius(5).fontColor(MobileTheme.ink) .shadow({ radius: 0.5, color: '#33000000', offsetY: 1 }) .backgroundColor((key === '⇧' && this.shift) || this.modifiers.includes(key === 'Ctrl' ? 17 : key === 'Alt' ? 18 : key === 'Win' ? 91 : -1) ? '#9BC7F7' : key.length > 1 || key === '⇧' ? '#AFB8C5' : '#FFFFFF') - .accessibilityText(key).accessibilityLevel('yes').onClick(() => this.keyboardKey(key)) + .accessibilityText(this.keyboardTitle(key)).accessibilityLevel('yes').onClick(() => this.keyboardKey(key)) }, (key: string) => key) }.width('100%') }) @@ -324,7 +336,7 @@ export struct MobileRemoteView { } else { MobileIcon({ name: button === 0 ? 'mouse_left' : 'mouse_right', iconExtent: 22 }) } }.width(44).height(44).borderRadius(7).clip(true) .backgroundColor(button === 0 && this.leftHeld || button === 2 && this.rightHeld ? '#9BC7F7' : '#E9E9EE') - .accessibilityText(button === 0 ? '鼠标左键,按住拖动' : button === 1 ? '滚轮,上下滑动' : '鼠标右键,按住拖动') + .accessibilityText(button === 0 ? tr("鼠标左键,按住拖动") : button === 1 ? tr("滚轮,上下滑动") : tr("鼠标右键,按住拖动")) .onTouch((event: TouchEvent) => this.barTouch(event, button)) }) }.padding(2).width(140).height(48).backgroundColor('#FFFFFF').borderRadius(10) @@ -339,7 +351,7 @@ export struct MobileRemoteView { if (!this.state.hasFrame) { Column({ space: 12 }) { LoadingProgress().width(32).height(32).color(Color.White) - Text('等待远端画面…').fontSize(14).fontColor(Color.White) + Text(tr("等待远端画面…")).fontSize(14).fontColor(Color.White) }.padding(20).constraintSize({ minWidth: 200 }).backgroundColor('#B0202024').borderRadius(14) .position({ x: (this.viewWidth - 200) / 2, y: (this.viewHeight - 104) / 2 }).hitTestBehavior(HitTestMode.None) } @@ -348,7 +360,7 @@ export struct MobileRemoteView { .onAxisEvent((event: AxisEvent) => { const delta = event.getVerticalAxisValue(); if (delta) this.mouse.scroll(-delta); }) .onKeyEvent((e: KeyEvent) => { if (e.type === KeyType.Down || e.type === KeyType.Up) { this.controller?.physicalKey(e.keyCode, e.type === KeyType.Down); return true; } return false; }) .onBlur(() => this.controller?.release()) - .accessibilityText('远程桌面:轻触点击、长按右键、双指捏合缩放、放大后双指拖动画面,原始比例下双指滚动') + .accessibilityText(tr("远程桌面:轻触点击、长按右键、双指捏合缩放、放大后双指拖动画面,原始比例下双指滚动")) MobileIcon({ name: 'cursor', iconExtent: 24, color: '#000000' }) .position({ x: this.cursorX - 1, y: this.cursorY - 1 }).hitTestBehavior(HitTestMode.None) if (this.menu) { Column() {}.width('100%').height('100%').onClick(() => this.menu = ''); this.Menu() } @@ -357,7 +369,7 @@ export struct MobileRemoteView { Stack() { Image($r('app.media.mobile_brand')).width(46).height(46).objectFit(ImageFit.Cover).borderRadius(23).draggable(false).hitTestBehavior(HitTestMode.None) }.width(54).height(54).backgroundColor('#F5F5F7').borderRadius(27).shadow({ radius: 14, color: '#33000000', offsetY: 4 }) - .position({ x: this.orbX, y: this.orbY }).accessibilityText('远程控制菜单,拖动可移动').accessibilityLevel('yes') + .position({ x: this.orbX, y: this.orbY }).accessibilityText(tr("远程控制菜单,拖动可移动")).accessibilityLevel('yes') .onTouch((e: TouchEvent) => this.orbTouch(e)) }.width('100%').height('100%').backgroundColor(Color.Black).clip(true) .onAreaChange((_old: Area, next: Area) => { diff --git a/apps/harmony/entry/src/main/ets/mobile/MobileStore.ets b/apps/harmony/entry/src/main/ets/mobile/MobileStore.ets index 5bea4af7..7d759f48 100644 --- a/apps/harmony/entry/src/main/ets/mobile/MobileStore.ets +++ b/apps/harmony/entry/src/main/ets/mobile/MobileStore.ets @@ -1,3 +1,4 @@ +import { tr } from './Localization'; import { common } from '@kit.AbilityKit'; import { preferences } from '@kit.ArkData'; import { asset } from '@kit.AssetStoreKit'; @@ -42,7 +43,7 @@ export class MobileStore { return value instanceof Uint8Array ? util.TextDecoder.create('utf-8').decodeWithStream(value) : ''; } catch (error) { if ((error as ErrorWithCode).code === asset.ErrorCode.NOT_FOUND) return ''; - throw new Error('安全存储不可用,请解锁设备后重试'); + throw new Error(tr("安全存储不可用,请解锁设备后重试")); } } async saveSecret(key: string, value: string): Promise { @@ -56,7 +57,7 @@ export class MobileStore { } async removeSecret(key: string): Promise { try { await asset.remove(await this.query(key)); } - catch (error) { if ((error as ErrorWithCode).code !== asset.ErrorCode.NOT_FOUND) throw new Error('无法删除已保存的凭据'); } + catch (error) { if ((error as ErrorWithCode).code !== asset.ErrorCode.NOT_FOUND) throw new Error(tr("无法删除已保存的凭据")); } } recent(scope: string): RecentDevice[] { try { diff --git a/apps/harmony/entry/src/main/ets/mobile/MobileWidgets.ets b/apps/harmony/entry/src/main/ets/mobile/MobileWidgets.ets index 1cf0af7c..255eac8d 100644 --- a/apps/harmony/entry/src/main/ets/mobile/MobileWidgets.ets +++ b/apps/harmony/entry/src/main/ets/mobile/MobileWidgets.ets @@ -1,3 +1,4 @@ +import { tr } from './Localization'; import { LengthMetricsUnit } from '@kit.ArkUI'; export class MobileTheme { @@ -86,7 +87,7 @@ export struct MobileIconButton { } @Component export struct MobilePrimaryButton { - label: string = '连接'; + label: string = tr("连接"); @Prop available: boolean = true; arrow: boolean = false; buttonHeight: number = 48; @@ -94,7 +95,7 @@ export struct MobilePrimaryButton { build() { Button({ type: ButtonType.Normal, stateEffect: true }) { Row({ space: 8 }) { - Text(this.label).fontSize(16).fontWeight(600).fontColor(Color.White) + Text(this.label).fontSize(16).minFontSize(11).maxFontSize(16).maxLines(2).textAlign(TextAlign.Center).fontWeight(600).fontColor(Color.White) if (this.arrow) { MobileIcon({ name: 'arrow', iconExtent: 18, color: '#FFFFFF' }) } }.justifyContent(FlexAlign.Center).width('100%') }.height(this.buttonHeight).width('100%').padding({ left: 12, right: 12 }).borderRadius(12) @@ -118,7 +119,7 @@ export struct MobileSegment { .backgroundColor(Color.White).borderRadius(7).shadow({ radius: 2, color: '#18000000', offsetY: 1 }).translate({ x: 2 + this.selected * Math.max(0, this.viewWidth - 4) / Math.max(1, this.labels.length) }) Row() { ForEach(this.labels, (label: string, index: number) => { - Text(label).fontSize(12).fontWeight(this.selection === index ? 600 : 400).fontColor(MobileTheme.ink) + Text(label).fontSize(12).minFontSize(9).maxFontSize(12).maxLines(2).fontWeight(this.selection === index ? 600 : 400).fontColor(MobileTheme.ink) .textAlign(TextAlign.Center).height(32).layoutWeight(1).enabled(this.available) .accessibilityLevel('yes').accessibilityText(label).accessibilitySelected(this.selection === index) .onClick(() => this.changed(index)) diff --git a/apps/harmony/entry/src/main/ets/mobile/RemotePrivacyScreen.ets b/apps/harmony/entry/src/main/ets/mobile/RemotePrivacyScreen.ets index 581a2e6f..fe22ee99 100644 --- a/apps/harmony/entry/src/main/ets/mobile/RemotePrivacyScreen.ets +++ b/apps/harmony/entry/src/main/ets/mobile/RemotePrivacyScreen.ets @@ -1,3 +1,4 @@ +import { tr } from './Localization'; export interface PrivacyStatus { state: number; supported: boolean; input_block_supported: boolean; overlay_active: boolean; input_blocked: boolean; remote_paused: boolean; @@ -44,10 +45,10 @@ export class RemotePrivacyScreen { return s !== undefined && this.fresh(now) && s.state === 3 && s.overlay_active && !s.remote_paused; } buttonTitle(now: number): string { - if (this.enabled(now)) return '隐私屏已开启'; + if (this.enabled(now)) return tr("隐私屏已开启"); const s = this.snapshot; - if (this.fresh(now) && s?.supported && s.state === 1 && !this.active()) return '隐私屏已关闭'; - return '隐私屏'; + if (this.fresh(now) && s?.supported && s.state === 1 && !this.active()) return tr("隐私屏已关闭"); + return tr("隐私屏"); } feedback(now: number): string { if (!this.desktopAvailable) return ''; @@ -73,26 +74,26 @@ export class RemotePrivacyScreen { return this.requestId; } failed(id: number): void { - if (this.pending && this.requestId === id) { this.pending = false; this.failure = '指令发送失败,请重试'; } + if (this.pending && this.requestId === id) { this.pending = false; this.failure = tr("指令发送失败,请重试"); } } tick(now: number): void { if (this.pending && now - this.requestedAt >= 15000) { - this.pending = false; this.failure = '请求超时,尚未确认电脑的隐私屏状态'; + this.pending = false; this.failure = tr("请求超时,尚未确认电脑的隐私屏状态"); } } status(now: number): string { if (this.failure) return this.failure; const s = this.snapshot; - if (!s) return '等待电脑返回隐私屏状态;旧版电脑端可能不支持'; - if (!this.fresh(now)) return '隐私屏状态已过期,等待电脑确认'; - if (s.state === 2) return '正在开启隐私屏…'; - if (s.state === 4) return '正在关闭隐私屏…'; - if (this.pending) return '指令已发送,等待电脑确认…'; - if (s.state === 5) return '隐私屏异常'; - if (!s.supported || s.state === 0) return '隐私屏暂不可用'; + if (!s) return tr("等待电脑返回隐私屏状态;旧版电脑端可能不支持"); + if (!this.fresh(now)) return tr("隐私屏状态已过期,等待电脑确认"); + if (s.state === 2) return tr("正在开启隐私屏…"); + if (s.state === 4) return tr("正在关闭隐私屏…"); + if (this.pending) return tr("指令已发送,等待电脑确认…"); + if (s.state === 5) return tr("隐私屏异常"); + if (!s.supported || s.state === 0) return tr("隐私屏暂不可用"); if (s.state === 3 && s.overlay_active && !s.remote_paused) - return '隐私屏已开启'; - return s.state === 1 && !this.active() ? '隐私屏已关闭' : '隐私屏状态待确认'; + return tr("隐私屏已开启"); + return s.state === 1 && !this.active() ? tr("隐私屏已关闭") : tr("隐私屏状态待确认"); } detail(now: number): string { const s = this.snapshot; diff --git a/apps/harmony/entry/src/main/ets/pages/Mobile.ets b/apps/harmony/entry/src/main/ets/pages/Mobile.ets index fceff85e..7b7f149d 100644 --- a/apps/harmony/entry/src/main/ets/pages/Mobile.ets +++ b/apps/harmony/entry/src/main/ets/pages/Mobile.ets @@ -1,3 +1,4 @@ +import { tr, currentLanguage } from '../mobile/Localization'; import { common } from '@kit.AbilityKit'; import { MobileController, MobileState, RemoteDisplay } from '../mobile/MobileController'; import { MobileRemoteView } from '../mobile/MobileRemoteView'; @@ -69,9 +70,9 @@ struct Mobile { } private title(): string { switch (this.state.page) { - case 'settings': return '设置'; case 'privacy': return '隐私与授权'; - case 'about': return '关于 CrossDesk'; case 'licenses': return '开源组件'; case 'component': return this.component?.name ?? ''; - case 'source': return '源码与构建说明'; case 'announcements': return '通知公告'; case 'announcement': return '公告详情'; + case 'settings': return tr("设置"); case 'privacy': return tr("隐私与授权"); + case 'about': return tr("关于 CrossDesk"); case 'licenses': return tr("开源组件"); case 'component': return this.component?.name ?? ''; + case 'source': return tr("源码与构建说明"); case 'announcements': return tr("通知公告"); case 'announcement': return tr("公告详情"); case 'document': return this.state.documentTitle; default: return ''; } } @@ -80,7 +81,9 @@ struct Mobile { private policyParagraphs(body: string): string[] { const text = body.replace(/\r\n/g, '\n'); const start = text.indexOf('## 中文\n'), end = start < 0 ? -1 : text.indexOf('## English', start); - const localized = start >= 0 && end > start ? text.substring(start + '## 中文\n'.length, end) : text; + const chinese = currentLanguage() === 0 || currentLanguage() === 3; + const localized = chinese && start >= 0 && end > start ? text.substring(start + '## 中文\n'.length, end) : + !chinese && end >= 0 ? text.substring(end + '## English'.length) : text; return localized.split(/\n\s*\n/).map((paragraph: string) => paragraph.trim()).filter((paragraph: string) => !!paragraph && paragraph !== '---'); } private openAnnouncement(item: AnnouncementItem): void { this.controller?.inbox.markRead(item); this.state.announcement = item; this.navigate('announcement'); } @@ -141,16 +144,16 @@ struct Mobile { @Builder ConnectionCard() { Column({ space: 16 }) { - Text('远程桌面').fontSize(20).fontWeight(600).fontColor(MobileTheme.ink).width('100%') + Text(tr("远程桌面")).fontSize(20).fontWeight(600).fontColor(MobileTheme.ink).width('100%') Row({ space: 10 }) { - TextInput({ text: this.formatId(this.state.remote), placeholder: '对端 ID' }).type(InputType.Number).maxLength(11) + TextInput({ text: this.formatId(this.state.remote), placeholder: tr("对端 ID") }).type(InputType.Number).maxLength(11) .fontSize(20).fontWeight(500).fontColor(MobileTheme.ink).placeholderColor(MobileTheme.secondary) .height(54).layoutWeight(1).backgroundColor(MobileTheme.background).borderRadius(12) .border({ width: this.idFocused ? 2 : 1, color: this.idFocused ? MobileTheme.blue : MobileTheme.line }) .padding({ left: 14, right: 14 }).onFocus(() => this.idFocused = true).onBlur(() => this.idFocused = false) .onChange((value: string) => this.state.remote = this.deviceId(value)).onSubmit(() => this.controller?.requestConnection(this.state.remote)) Column() { - MobilePrimaryButton({ label: '连接', buttonHeight: 54, available: this.state.remote.length > 0, + MobilePrimaryButton({ label: tr("连接"), buttonHeight: 54, available: this.state.remote.length > 0, action: () => this.controller?.requestConnection(this.state.remote) }) }.width(96) }.width('100%') @@ -161,7 +164,7 @@ struct Mobile { RecentCard(device: RecentDevice) { Column() { Stack() { - Text(device.platform === 'windows' ? 'Windows' : device.platform === 'macos' ? 'macOS' : device.platform === 'linux' ? 'Linux' : '远程电脑') + Text(device.platform === 'windows' ? 'Windows' : device.platform === 'macos' ? 'macOS' : device.platform === 'linux' ? 'Linux' : tr("远程电脑")) .fontSize(19).fontWeight(600).fontColor(Color.White).width('100%').height('100%').textAlign(TextAlign.Center) if (this.state.previews && device.preview) { Image(`file://${device.preview}`).objectFit(ImageFit.Cover).width('100%').height('100%') } }.aspectRatio(16 / 9).width('100%').backgroundColor(device.platform === 'windows' ? '#316AB7' : device.platform === 'macos' ? '#8057B9' : device.platform === 'linux' ? '#AE642B' : '#677587') @@ -169,8 +172,8 @@ struct Mobile { Text(device.name || device.id).fontSize(12).fontWeight(600).maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }).width('100%') Row({ space: 4 }) { Text(`ID ${device.id}`).fontSize(10).fontColor(MobileTheme.secondary).layoutWeight(1) - if (device.remember) { MobileIcon({ name: 'key', iconExtent: 11, color: MobileTheme.secondary }).accessibilityText('已保存密码') } - Text(this.controller?.presence.online(device.id, this.controller?.now() ?? 0) ? '在线' : '离线').fontSize(10) + if (device.remember) { MobileIcon({ name: 'key', iconExtent: 11, color: MobileTheme.secondary }).accessibilityText(tr("已保存密码")) } + Text(this.controller?.presence.online(device.id, this.controller?.now() ?? 0) ? tr("在线") : tr("离线")).fontSize(10) .fontColor(this.controller?.presence.online(device.id, this.controller?.now() ?? 0) ? MobileTheme.green : MobileTheme.secondary) }.width('100%') }.padding(9).width('100%') @@ -182,14 +185,14 @@ struct Mobile { Recent() { Column({ space: 14 }) { Row() { - Text('最近连接').fontSize(20).fontWeight(600).fontColor(MobileTheme.ink).layoutWeight(1) - if (this.state.recent.length) { Text(`${this.state.recent.length} 台设备`).fontSize(12).fontColor(MobileTheme.secondary) } + Text(tr("最近连接")).fontSize(20).fontWeight(600).fontColor(MobileTheme.ink).layoutWeight(1) + if (this.state.recent.length) { Text(tr("{0} 台设备", [String(this.state.recent.length)])).fontSize(12).fontColor(MobileTheme.secondary) } }.width('100%') if (this.state.recent.length === 0) { Column() { MobileIcon({ name: 'history', iconExtent: 34, color: '#B6B6BB' }) - Text('还没有连接记录').fontSize(17).fontWeight(600).fontColor(MobileTheme.ink).margin({ top: 12, bottom: 8 }) - Text('成功连接后,这里会显示最近的远程设备。').fontSize(13).lineHeight(19).fontColor(MobileTheme.secondary).textAlign(TextAlign.Center) + Text(tr("还没有连接记录")).fontSize(17).fontWeight(600).fontColor(MobileTheme.ink).margin({ top: 12, bottom: 8 }) + Text(tr("成功连接后,这里会显示最近的远程设备。")).fontSize(13).lineHeight(19).fontColor(MobileTheme.secondary).textAlign(TextAlign.Center) }.layoutWeight(1).width('100%').justifyContent(FlexAlign.Center).padding({ left: 6, right: 6 }) } else { Scroll() { @@ -212,7 +215,7 @@ struct Mobile { }.padding({ left: 11, right: 11 }).height(34).backgroundColor(Color.White).borderRadius(17).onClick(() => this.controller?.reconnect()) Blank() Stack({ alignContent: Alignment.TopEnd }) { - MobileIconButton({ icon: 'envelope', label: '通知公告', action: () => this.navigate('announcements') }) + MobileIconButton({ icon: 'envelope', label: tr("通知公告"), action: () => this.navigate('announcements') }) if (this.state.unread > 0) { Text(this.state.unread > 99 ? '99+' : `${this.state.unread}`).fontSize(10).fontWeight(600).fontColor(Color.White) .textAlign(TextAlign.Center).padding({ left: 4, right: 4 }).constraintSize({ minWidth: 16 }).height(16) @@ -220,7 +223,7 @@ struct Mobile { } } Stack({ alignContent: Alignment.TopEnd }) { - MobileIconButton({ icon: 'settings', label: '设置', action: () => this.navigate('settings') }) + MobileIconButton({ icon: 'settings', label: tr("设置"), action: () => this.navigate('settings') }) if (this.state.update) { Text('!').fontSize(10).fontWeight(600).fontColor(Color.White).textAlign(TextAlign.Center).width(16).height(16) .backgroundColor(MobileTheme.red).borderRadius(8).translate({ x: 5, y: -3 }).hitTestBehavior(HitTestMode.None) @@ -246,72 +249,72 @@ struct Mobile { @Builder PreviewRow() { Row({ space: 12 }) { - Text('保存远程画面预览').fontSize(16).fontColor(MobileTheme.ink).layoutWeight(1) + Text(tr("保存远程画面预览")).fontSize(16).fontColor(MobileTheme.ink).layoutWeight(1) Toggle({ type: ToggleType.Switch, isOn: this.previewToggle }).selectedColor(MobileTheme.green) .onChange((value: boolean) => { this.previewToggle = value; if (value && !this.state.previews) this.state.modal = 'previews'; else if (!value) this.controller?.setPreviews(false); - }).accessibilityText('保存远程画面预览') + }).accessibilityText(tr("保存远程画面预览")) }.constraintSize({ minHeight: 52 }).padding({ left: 16, right: 16, top: 8, bottom: 8 }).width('100%') } @Builder Settings() { Column() { - this.SectionTitle('鼠标控制') + this.SectionTitle(tr("鼠标控制")) Column() { - MobileSegment({ labels: ['相对位置', '绝对位置'], selection: this.state.relative ? 0 : 1, + MobileSegment({ labels: [tr("相对位置"), tr("绝对位置")], selection: this.state.relative ? 0 : 1, changed: (i: number) => this.controller?.setRelative(i === 0) }) }.padding(12).width('100%').backgroundColor(Color.White).borderRadius(26).border({ width: 0.5, color: MobileTheme.line }) - this.SectionTitle('画面偏好') + this.SectionTitle(tr("画面偏好")) Column() { - MobileSegment({ labels: ['帧率优先', '画质优先', '平衡'], selection: this.state.videoPreference, + MobileSegment({ labels: [tr("帧率优先"), tr("画质优先"), tr("平衡")], selection: this.state.videoPreference, changed: (i: number) => this.controller?.setPreference(i) }) }.padding(12).width('100%').backgroundColor(Color.White).borderRadius(26).border({ width: 0.5, color: MobileTheme.line }) - this.SectionTitle('屏幕方向') + this.SectionTitle(tr("屏幕方向")) Row() { - Text('连接建立后锁定横屏').fontSize(16).fontColor(MobileTheme.ink).layoutWeight(1) + Text(tr("连接建立后锁定横屏")).fontSize(16).fontColor(MobileTheme.ink).layoutWeight(1) Toggle({ type: ToggleType.Switch, isOn: this.state.autoLandscape }).selectedColor(MobileTheme.green) - .onChange((value: boolean) => this.controller?.setAutoLandscape(value)).accessibilityText('连接建立后锁定横屏') + .onChange((value: boolean) => this.controller?.setAutoLandscape(value)).accessibilityText(tr("连接建立后锁定横屏")) }.padding({ left: 16, right: 16, top: 10, bottom: 10 }).width('100%').backgroundColor(Color.White) .borderRadius(26).border({ width: 0.5, color: MobileTheme.line }) - Text('默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。') + Text(tr("默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。")) .fontSize(12).fontColor(MobileTheme.secondary).width('100%').padding({ left: 16, right: 16, top: 8, bottom: 12 }) Column() { - this.SettingRow('服务器', this.customServer ? '自定义' : '默认', () => this.serverExpanded = !this.serverExpanded) + this.SettingRow(tr("服务器"), this.customServer ? tr("自定义") : tr("默认"), () => this.serverExpanded = !this.serverExpanded) if (this.serverExpanded) { this.Rule() Row() { - Text('使用自定义服务器').fontSize(16).fontColor(MobileTheme.ink).layoutWeight(1) + Text(tr("使用自定义服务器")).fontSize(16).fontColor(MobileTheme.ink).layoutWeight(1) Toggle({ type: ToggleType.Switch, isOn: this.customServer }).selectedColor(MobileTheme.green).onChange((value: boolean) => { this.customServer = value; if (!value) { this.editingServer = 'api.crossdesk.cn'; this.editingPort = '9099'; this.controller?.saveSettings(this.editingServer, this.editingPort); } - }).accessibilityText('使用自定义服务器') + }).accessibilityText(tr("使用自定义服务器")) }.padding({ left: 16, right: 16, top: 8, bottom: 8 }).width('100%') if (this.customServer) { Column({ space: 8 }) { - TextInput({ text: this.editingServer, placeholder: '服务器地址' }).fontSize(17).height(48).borderRadius(12) + TextInput({ text: this.editingServer, placeholder: tr("服务器地址") }).fontSize(17).height(48).borderRadius(12) .backgroundColor(MobileTheme.background).onChange((v: string) => this.editingServer = v) - TextInput({ text: this.editingPort, placeholder: '服务器端口' }).fontSize(17).height(48).borderRadius(12) + TextInput({ text: this.editingPort, placeholder: tr("服务器端口") }).fontSize(17).height(48).borderRadius(12) .backgroundColor(MobileTheme.background).type(InputType.Number).onChange((v: string) => this.editingPort = v) - this.Action('完成', () => { this.saveServer(); }) + this.Action(tr("完成"), () => { this.saveServer(); }) }.padding({ left: 12, right: 12, bottom: 12 }).width('100%') } } }.width('100%').backgroundColor(Color.White).borderRadius(26).clip(true).border({ width: 0.5, color: MobileTheme.line }).margin({ top: 28 }) - Text(this.state.identity ? `本机 ID ${this.formatId(this.state.identity)}` : this.state.signalText).fontSize(12).fontColor(MobileTheme.secondary) + Text(this.state.identity ? tr("本机 ID {0}", [String(this.formatId(this.state.identity))]) : this.state.signalText).fontSize(12).fontColor(MobileTheme.secondary) .textAlign(TextAlign.Center).padding({ left: 16, right: 16, top: 12, bottom: 16 }).width('100%').copyOption(CopyOptions.LocalDevice) - this.SectionTitle('隐私') + this.SectionTitle(tr("隐私")) Column() { - this.SettingRow('隐私与授权', this.state.consent ? '已授权' : '未授权', () => this.navigate('privacy')) + this.SettingRow(tr("隐私与授权"), this.state.consent ? tr("已授权") : tr("未授权"), () => this.navigate('privacy')) this.Rule() this.PreviewRow() this.Rule() - Button({ type: ButtonType.Normal }) { Text('清除预览图').fontSize(16).fontColor(MobileTheme.red).width('100%').textAlign(TextAlign.Start) } + Button({ type: ButtonType.Normal }) { Text(tr("清除预览图")).fontSize(16).fontColor(MobileTheme.red).width('100%').textAlign(TextAlign.Start) } .height(48).width('100%').padding({ left: 16 }).backgroundColor(Color.White) .onClick(() => this.state.modal = 'clearPreviews') }.width('100%').backgroundColor(Color.White).borderRadius(26).clip(true).border({ width: 0.5, color: MobileTheme.line }) - Column() { this.SettingRow('关于', this.state.update ? '新版本 ●' : '', () => this.navigate('about')) } + Column() { this.SettingRow(tr("关于"), this.state.update ? tr("新版本 ●") : '', () => this.navigate('about')) } .width('100%').backgroundColor(Color.White).borderRadius(26).clip(true).border({ width: 0.5, color: MobileTheme.line }).margin({ top: 28 }) }.width('100%') } @@ -319,45 +322,45 @@ struct Mobile { Privacy() { Column() { Column() { - this.ValueRow('授权状态', this.state.consent ? '已授权' : '未授权') + this.ValueRow(tr("授权状态"), this.state.consent ? tr("已授权") : tr("未授权")) this.Rule() - this.SettingRow('隐私政策', '', () => this.controller?.document('PRIVACY.md', '隐私政策', 'privacy')) + this.SettingRow(tr("隐私政策"), '', () => this.controller?.document('PRIVACY.md', tr("隐私政策"), 'privacy')) }.width('100%').backgroundColor(Color.White).borderRadius(12).clip(true).border({ width: 0.5, color: MobileTheme.line }) - this.Footer('设备身份及选择保存的访问密码加密保存在本机。画面预览默认关闭,开启后从下一次连接起保存。剪贴板内容在结束会话时清除。离开应用后通过画中画或后台任务保持会话,可随时返回应用断开。') - if (this.state.consent) { this.Action('撤回联网授权', () => this.state.modal = 'revoke', true) } - else { MobilePrimaryButton({ label: '阅读并授权', action: () => this.state.modal = 'consent' }) } + this.Footer(tr("设备身份及选择保存的访问密码加密保存在本机。画面预览默认关闭,开启后从下一次连接起保存。剪贴板内容在结束会话时清除。离开应用后通过画中画或后台任务保持会话,可随时返回应用断开。")) + if (this.state.consent) { this.Action(tr("撤回联网授权"), () => this.state.modal = 'revoke', true) } + else { MobilePrimaryButton({ label: tr("阅读并授权"), action: () => this.state.modal = 'consent' }) } }.width('100%') } @Builder About() { Column() { Column() { - this.ValueRow('版本', this.state.version) - if (this.state.update) { this.Rule(); this.SettingRow('新版本可用', `v${this.state.update}`, () => this.controller?.platform.openLink('https://crossdesk.cn')) } + this.ValueRow(tr("版本"), this.state.version) + if (this.state.update) { this.Rule(); this.SettingRow(tr("新版本可用"), `v${this.state.update}`, () => this.controller?.platform.openLink('https://crossdesk.cn')) } if (this.state.updateStatus) { this.Footer(this.state.updateStatus) } this.Rule() - this.Action('检查更新', () => this.controller?.checkLocal(true)) + this.Action(tr("检查更新"), () => this.controller?.checkLocal(true)) }.width('100%').backgroundColor(Color.White).borderRadius(12).clip(true).border({ width: 0.5, color: MobileTheme.line }) Column() { - this.SettingRow('软件许可', 'GPL-3.0-only', () => this.controller?.document('LICENSE', '软件许可')) + this.SettingRow(tr("软件许可"), 'GPL-3.0-only', () => this.controller?.document('LICENSE', tr("软件许可"))) this.Rule() - this.SettingRow('开源软件权利说明', '', () => this.controller?.document('OPEN_SOURCE_NOTICE.txt', '开源软件权利说明')) + this.SettingRow(tr("开源软件权利说明"), '', () => this.controller?.document('OPEN_SOURCE_NOTICE.txt', tr("开源软件权利说明"))) this.Rule() - this.SettingRow('开源组件', '', () => this.navigate('licenses')) + this.SettingRow(tr("开源组件"), '', () => this.navigate('licenses')) this.Rule() - this.SettingRow('源码与构建说明', '', () => this.navigate('source')) + this.SettingRow(tr("源码与构建说明"), '', () => this.navigate('source')) }.backgroundColor(Color.White).borderRadius(12).clip(true).width('100%').border({ width: 0.5, color: MobileTheme.line }).margin({ top: 28 }) - this.Footer('许可与版权声明可离线查阅。') + this.Footer(tr("许可与版权声明可离线查阅。")) }.width('100%') } @Builder Announcements() { Column({ space: 12 }) { - if (!this.state.consent) { Text('同意联网后可查看公告').fontSize(14); this.Action('查看联网说明', () => this.state.modal = 'consent') } - if (this.controller?.inbox.failed) { this.Action('加载失败,点击重试', () => this.controller?.inbox.refresh()) } + if (!this.state.consent) { Text(tr("同意联网后可查看公告")).fontSize(14); this.Action(tr("查看联网说明"), () => this.state.modal = 'consent') } + if (this.controller?.inbox.failed) { this.Action(tr("加载失败,点击重试"), () => this.controller?.inbox.refresh()) } if (this.controller?.inbox.loading) { LoadingProgress().width(28).height(28) } - if (this.controller?.inbox.saveFailed) { Text('已读或删除状态保存失败,请重试').fontSize(12).fontColor(MobileTheme.red) } - if (!this.state.announcements.length && this.controller?.inbox.loaded && !this.controller?.inbox.loading) { Text('暂无公告').fontSize(16).fontColor(MobileTheme.secondary).padding(40) } + if (this.controller?.inbox.saveFailed) { Text(tr("已读或删除状态保存失败,请重试")).fontSize(12).fontColor(MobileTheme.red) } + if (!this.state.announcements.length && this.controller?.inbox.loaded && !this.controller?.inbox.loading) { Text(tr("暂无公告")).fontSize(16).fontColor(MobileTheme.secondary).padding(40) } ForEach(this.state.announcements, (item: AnnouncementItem) => { Column({ space: 8 }) { Row({ space: 8 }) { if (!item.read) { Row() {}.width(6).height(6).borderRadius(3).backgroundColor(MobileTheme.blue) } Text(item.title).fontSize(17).fontWeight(600).layoutWeight(1) }.width('100%') @@ -366,7 +369,7 @@ struct Mobile { }.padding(18).width('100%').backgroundColor(Color.White).borderRadius(18).border({ width: 0.5, color: MobileTheme.line }) .onClick(() => this.openAnnouncement(item)).gesture(LongPressGesture().onAction(() => { this.state.announcement = item; this.state.modal = 'deleteAnnouncement'; })) }, (item: AnnouncementItem) => `${item.id}:${item.revision}:${item.read}`) - if ((this.controller?.inbox.total ?? 0) > this.state.announcements.length) { this.Action('加载更多', () => this.controller?.inbox.more()) } + if ((this.controller?.inbox.total ?? 0) > this.state.announcements.length) { this.Action(tr("加载更多"), () => this.controller?.inbox.more()) } }.width('100%') } @Builder @@ -385,10 +388,10 @@ struct Mobile { } else { Span(part.text) } }) }.fontSize(16).lineHeight(25).width('100%').copyOption(CopyOptions.LocalDevice) - this.Action('删除公告', () => this.state.modal = 'deleteAnnouncement', true) + this.Action(tr("删除公告"), () => this.state.modal = 'deleteAnnouncement', true) }.width('100%') } else if (this.state.page === 'document') { - if (this.state.documentTitle === '隐私政策') { this.PolicyText(this.state.documentText) } + if (this.state.documentTitle === tr("隐私政策")) { this.PolicyText(this.state.documentText) } else { Column({ space: 12 }) { ForEach(this.state.documentText.match(/[\s\S]{1,4000}/g) ?? [], (paragraph: string) => { @@ -398,8 +401,8 @@ struct Mobile { } } else if (this.state.page === 'licenses') { Column() { - this.SectionTitle('OpenFEC 告知') - Column() { this.Footer('OpenFEC 提供前向纠错能力,遵循 CeCILL-C 1.0 许可。其许可规定了有限保证及责任限制,请阅读组件详情。') } + this.SectionTitle(tr("OpenFEC 告知")) + Column() { this.Footer(tr("OpenFEC 提供前向纠错能力,遵循 CeCILL-C 1.0 许可。其许可规定了有限保证及责任限制,请阅读组件详情。")) } .width('100%').backgroundColor(Color.White).borderRadius(12).border({ width: 0.5, color: MobileTheme.line }) Column() { ForEach(this.licenses, (component: LicenseComponent, index: number) => { @@ -415,18 +418,18 @@ struct Mobile { }.width('100%').padding(0).backgroundColor(Color.White).onClick(() => { this.component = component; this.navigate('component'); }) }, (component: LicenseComponent) => component.id) }.width('100%').backgroundColor(Color.White).borderRadius(12).clip(true).border({ width: 0.5, color: MobileTheme.line }).margin({ top: 28 }) - this.Footer('各组件遵循所列开源许可证。许可与版权声明可离线查阅,查看源码需要网络连接。') + this.Footer(tr("各组件遵循所列开源许可证。许可与版权声明可离线查阅,查看源码需要网络连接。")) }.width('100%') } else if (this.state.page === 'component') { Column() { Column() { - this.ValueRow('版本', this.component?.version ?? '') + this.ValueRow(tr("版本"), this.component?.version ?? '') this.Rule() - this.ValueRow('许可', this.component?.license ?? '') + this.ValueRow(tr("许可"), this.component?.license ?? '') this.Rule() - this.SettingRow('查看源码', '', () => this.controller?.platform.openLink(this.component?.sourceURL ?? '')) + this.SettingRow(tr("查看源码"), '', () => this.controller?.platform.openLink(this.component?.sourceURL ?? '')) }.width('100%').backgroundColor(Color.White).borderRadius(12).clip(true).border({ width: 0.5, color: MobileTheme.line }) - this.SectionTitle('许可与版权声明') + this.SectionTitle(tr("许可与版权声明")) Column() { ForEach(this.component?.documents ?? [], (document: LicenseDocument, index: number) => { if (index > 0) { this.Rule() } @@ -436,16 +439,16 @@ struct Mobile { }.width('100%') } else if (this.state.page === 'source') { Column() { - this.SectionTitle('本版本源码与构建说明') + this.SectionTitle(tr("本版本源码与构建说明")) Column() { - this.ValueRow('源码版本', (this.source?.revision ?? '').substring(0, 12)) + this.ValueRow(tr("源码版本"), (this.source?.revision ?? '').substring(0, 12)) this.Rule() this.ValueRow('MiniRTC', (this.source?.miniRTCRevision ?? '').substring(0, 12)) - if (this.source?.isModified) { this.Rule(); this.Footer('开发版本包含尚未发布的修改,以下链接为基础版本源码。') } + if (this.source?.isModified) { this.Rule(); this.Footer(tr("开发版本包含尚未发布的修改,以下链接为基础版本源码。")) } this.Rule() - this.SettingRow('查看源码', '', () => this.controller?.platform.openLink(this.source?.sourceURL ?? '')) + this.SettingRow(tr("查看源码"), '', () => this.controller?.platform.openLink(this.source?.sourceURL ?? '')) }.width('100%').backgroundColor(Color.White).borderRadius(12).clip(true).border({ width: 0.5, color: MobileTheme.line }) - this.SectionTitle('构建文档') + this.SectionTitle(tr("构建文档")) Column() { ForEach(this.source?.buildDocuments ?? [], (document: LicenseDocument, index: number) => { if (index > 0) { this.Rule() } @@ -462,7 +465,7 @@ struct Mobile { Text(title).fontSize(22).fontWeight(600).fontColor(MobileTheme.ink).width('100%') if (subtitle) { Text(subtitle).fontSize(15).fontColor(MobileTheme.secondary).width('100%') } }.layoutWeight(1) - MobileIconButton({ icon: 'close', label: '关闭', iconExtent: 36, iconSize: 20, action: () => this.dismissModal() }) + MobileIconButton({ icon: 'close', label: tr("关闭"), iconExtent: 36, iconSize: 20, action: () => this.dismissModal() }) }.width('100%') } @Builder @@ -470,24 +473,24 @@ struct Mobile { Scroll() { Column() { Row() {}.width(36).height(5).backgroundColor('#C6C6CB').borderRadius(3).margin({ bottom: 20 }) - this.SheetHeader('连接远程桌面', `对端 ID ${this.formatId(this.state.remote)}`) + this.SheetHeader(tr("连接远程桌面"), tr("对端 ID {0}", [String(this.formatId(this.state.remote))])) Row() { - TextInput({ text: this.state.password, placeholder: '访问密码' }).type(this.showPassword ? InputType.Normal : InputType.Password) + TextInput({ text: this.state.password, placeholder: tr("访问密码") }).type(this.showPassword ? InputType.Normal : InputType.Password) .showPasswordIcon(false).maxLength(128).fontSize(17).height(50).layoutWeight(1).backgroundColor(Color.Transparent) .padding({ left: 14, right: 4 }).onChange((value: string) => this.state.password = value).onSubmit(() => this.controller?.begin(this.state.password)) - MobileIconButton({ icon: this.showPassword ? 'eye_off' : 'eye', label: this.showPassword ? '隐藏密码' : '显示密码', iconExtent: 44, + MobileIconButton({ icon: this.showPassword ? 'eye_off' : 'eye', label: this.showPassword ? tr("隐藏密码") : tr("显示密码"), iconExtent: 44, action: () => this.showPassword = !this.showPassword }) }.width('100%').backgroundColor(Color.White).borderRadius(10).border({ width: 0.5, color: MobileTheme.line }).margin({ top: 18 }) if (this.state.notice) { Text(this.state.notice).fontSize(13).fontColor(MobileTheme.red).width('100%').margin({ top: 8 }) } Row({ space: 12 }) { Column({ space: 3 }) { - Text('保存密码').fontSize(15).fontWeight(600).fontColor(MobileTheme.ink).width('100%') - Text('密码将加密保存在此设备上').fontSize(11).fontColor(MobileTheme.secondary).width('100%') + Text(tr("保存密码")).fontSize(15).fontWeight(600).fontColor(MobileTheme.ink).width('100%') + Text(tr("密码将加密保存在此设备上")).fontSize(11).fontColor(MobileTheme.secondary).width('100%') }.layoutWeight(1) Toggle({ type: ToggleType.Switch, isOn: this.state.remember }).selectedColor(MobileTheme.green) - .onChange((value: boolean) => this.state.remember = value).accessibilityText('保存密码') + .onChange((value: boolean) => this.state.remember = value).accessibilityText(tr("保存密码")) }.width('100%').margin({ top: 18, bottom: 18 }) - MobilePrimaryButton({ label: '连接', available: this.state.password.length > 0, action: () => this.controller?.begin(this.state.password) }) + MobilePrimaryButton({ label: tr("连接"), available: this.state.password.length > 0, action: () => this.controller?.begin(this.state.password) }) }.padding({ left: 22, right: 22, top: 10, bottom: 22 }).width('100%') }.width(this.viewWidth < 600 ? '100%' : Math.min(520, this.viewWidth - 48)).constraintSize({ maxHeight: this.viewHeight * 0.92 }) .backgroundColor(MobileTheme.background).borderRadius(24).scrollBar(BarState.Off) @@ -506,11 +509,11 @@ struct Mobile { @Builder ConsentSheet() { Column() { - Text('隐私政策').fontSize(17).fontWeight(600).fontColor(MobileTheme.ink).height(56).width('100%').textAlign(TextAlign.Center) + Text(tr("隐私政策")).fontSize(17).fontWeight(600).fontColor(MobileTheme.ink).height(56).width('100%').textAlign(TextAlign.Center) this.Rule() Scroll() { Column({ space: 12 }) { - if (!this.state.privacyAvailable) { Text('隐私政策无法读取,请重新安装应用').fontSize(14).fontColor(MobileTheme.red) } + if (!this.state.privacyAvailable) { Text(tr("隐私政策无法读取,请重新安装应用")).fontSize(14).fontColor(MobileTheme.red) } this.PolicyText(this.privacyText) }.padding(20).width('100%') }.layoutWeight(1).width('100%').align(Alignment.Top).scrollBar(BarState.Off) @@ -518,11 +521,11 @@ struct Mobile { Column({ space: 12 }) { Row({ space: 8 }) { Checkbox({ name: 'consent' }).width(20).height(20).margin(0).select(this.accepted).selectedColor(MobileTheme.blue) - .onChange((value: boolean) => this.accepted = value).accessibilityText('我已阅读并同意隐私政策') - Text('我已阅读并同意《隐私政策》').fontSize(14).fontColor(MobileTheme.ink).layoutWeight(1).onClick(() => this.accepted = !this.accepted) + .onChange((value: boolean) => this.accepted = value).accessibilityText(tr("我已阅读并同意隐私政策")) + Text(tr("我已阅读并同意《隐私政策》")).fontSize(14).fontColor(MobileTheme.ink).layoutWeight(1).onClick(() => this.accepted = !this.accepted) }.width('100%').constraintSize({ minHeight: 44 }) - MobilePrimaryButton({ label: '同意并继续', available: this.accepted && this.state.privacyAvailable, action: () => this.controller?.consent() }) - Button('暂不同意', { type: ButtonType.Normal }).fontSize(16).fontColor(MobileTheme.secondary).height(44).width('100%') + MobilePrimaryButton({ label: tr("同意并继续"), available: this.accepted && this.state.privacyAvailable, action: () => this.controller?.consent() }) + Button(tr("暂不同意"), { type: ButtonType.Normal }).fontSize(16).fontColor(MobileTheme.secondary).height(44).width('100%') .backgroundColor(Color.Transparent).onClick(() => this.dismissModal()) }.padding({ left: 20, right: 20, top: 12, bottom: 12 }).width('100%') }.width(this.viewWidth < 600 ? '100%' : Math.min(640, this.viewWidth - 48)).height(Math.min(760, this.viewHeight * 0.9)) @@ -533,42 +536,42 @@ struct Mobile { if (this.state.modal === 'connecting') { Column({ space: 14 }) { LoadingProgress().width(34).height(34).color(MobileTheme.blue) - Text('正在连接').fontSize(20).fontWeight(600).fontColor(MobileTheme.ink) - Text(this.state.signal === 1 ? '正在建立安全连接…' : this.state.signalText).fontSize(14).fontColor(MobileTheme.secondary).textAlign(TextAlign.Center).constraintSize({ minHeight: 36 }) + Text(tr("正在连接")).fontSize(20).fontWeight(600).fontColor(MobileTheme.ink) + Text(this.state.signal === 1 ? tr("正在建立安全连接…") : this.state.signalText).fontSize(14).fontColor(MobileTheme.secondary).textAlign(TextAlign.Center).constraintSize({ minHeight: 36 }) }.padding({ left: 26, right: 26, top: 24, bottom: 20 }).width('100%') this.Rule() - this.Action('取消连接', () => this.controller?.end(''), true) + this.Action(tr("取消连接"), () => this.controller?.end(''), true) } else if (this.state.modal === 'privacyUnlock') { Column({ space: 12 }) { - Text('隐私屏已被解锁').fontSize(20).fontWeight(600).fontColor(MobileTheme.ink) - Text('被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。') + Text(tr("隐私屏已被解锁")).fontSize(20).fontWeight(600).fontColor(MobileTheme.ink) + Text(tr("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。")) .fontSize(14).lineHeight(21).fontColor(MobileTheme.secondary).width('100%') if (this.state.privacyFeedback) { Text(this.state.privacyFeedback).fontSize(12).fontColor(MobileTheme.secondary) } }.padding(24).width('100%') this.Rule() Row() { - Button('确认', { type: ButtonType.Normal }).fontSize(16).fontColor(MobileTheme.blue).height(50).layoutWeight(1) + Button(tr("确认"), { type: ButtonType.Normal }).fontSize(16).fontColor(MobileTheme.blue).height(50).layoutWeight(1) .backgroundColor(Color.White).onClick(() => this.dismissModal()) Divider().vertical(true).height(50).strokeWidth(0.5).color(MobileTheme.line) - Button('锁定', { type: ButtonType.Normal }).fontSize(16).fontWeight(600).fontColor(MobileTheme.blue).height(50).layoutWeight(1) + Button(tr("锁定"), { type: ButtonType.Normal }).fontSize(16).fontWeight(600).fontColor(MobileTheme.blue).height(50).layoutWeight(1) .backgroundColor(Color.White).enabled(this.state.privacyCanLock).onClick(() => this.controller?.lockPrivacy()) }.width('100%') } else if (this.state.modal === 'clipboard') { Column({ space: 16 }) { - this.SheetHeader('剪贴板') - Text('发送文本后,点击“粘贴到远端”使用。').fontSize(13).fontColor(MobileTheme.secondary).width('100%') - TextArea({ text: this.state.clipboardText, placeholder: '要发送到远端的文本' }).fontSize(15).height(120).borderRadius(12).barState(BarState.Off) + this.SheetHeader(tr("剪贴板")) + Text(tr("发送文本后,点击“粘贴到远端”使用。")).fontSize(13).fontColor(MobileTheme.secondary).width('100%') + TextArea({ text: this.state.clipboardText, placeholder: tr("要发送到远端的文本") }).fontSize(15).height(120).borderRadius(12).barState(BarState.Off) .backgroundColor(MobileTheme.background).onChange((value: string) => this.state.clipboardText = value) - MobilePrimaryButton({ label: '发送文本', action: () => this.controller?.clipboard() }) + MobilePrimaryButton({ label: tr("发送文本"), action: () => this.controller?.clipboard() }) Row({ space: 8 }) { - Column() { this.Action('粘贴到远端', () => this.controller?.shortcut(86)) }.layoutWeight(1) - Column() { this.Action('复制远端文本', () => this.controller?.copyRemote()) }.layoutWeight(1) + Column() { this.Action(tr("粘贴到远端"), () => this.controller?.shortcut(86)) }.layoutWeight(1) + Column() { this.Action(tr("复制远端文本"), () => this.controller?.copyRemote()) }.layoutWeight(1) }.width('100%') }.padding(20).width('100%') } else if (this.state.modal === 'displays') { Column({ space: 12 }) { - this.SheetHeader('显示器') - if (!this.state.displays.length) { this.Footer('等待远端屏幕信息') } + this.SheetHeader(tr("显示器")) + if (!this.state.displays.length) { this.Footer(tr("等待远端屏幕信息")) } ForEach(this.state.displays, (screen: RemoteDisplay, index: number) => { Button({ type: ButtonType.Normal }) { Row({ space: 12 }) { @@ -584,31 +587,31 @@ struct Mobile { Text(this.state.recent.find((d: RecentDevice) => d.id === this.deleteId)?.name || this.formatId(this.deleteId)) .fontSize(17).fontWeight(600).fontColor(MobileTheme.ink).padding(20).width('100%').textAlign(TextAlign.Center) this.Rule() - this.Action('连接', () => { this.dismissModal(); this.controller?.requestConnection(this.deleteId); }) + this.Action(tr("连接"), () => { this.dismissModal(); this.controller?.requestConnection(this.deleteId); }) this.Rule() - this.Action('删除记录', () => this.state.modal = 'delete', true) + this.Action(tr("删除记录"), () => this.state.modal = 'delete', true) this.Rule() - this.Action('取消', () => this.dismissModal()) + this.Action(tr("取消"), () => this.dismissModal()) } else { Column({ space: 12 }) { - Text(this.state.modal === 'notice' ? '连接提示' : this.state.modal === 'upgrade' ? '升级提示' : this.state.modal === 'disconnect' ? '断开远程连接?' : - this.state.modal === 'revoke' ? '撤回联网授权?' : this.state.modal === 'previews' ? '保存远程画面预览?' : this.state.modal === 'clearPreviews' ? '清除预览图?' : this.state.modal === 'deleteAnnouncement' ? '删除公告?' : '删除记录?') + Text(this.state.modal === 'notice' ? tr("连接提示") : this.state.modal === 'upgrade' ? tr("升级提示") : this.state.modal === 'disconnect' ? tr("断开远程连接?") : + this.state.modal === 'revoke' ? tr("撤回联网授权?") : this.state.modal === 'previews' ? tr("保存远程画面预览?") : this.state.modal === 'clearPreviews' ? tr("清除预览图?") : this.state.modal === 'deleteAnnouncement' ? tr("删除公告?") : tr("删除记录?")) .fontSize(20).fontWeight(600).fontColor(MobileTheme.ink).textAlign(TextAlign.Center).width('100%') - Text(this.state.modal === 'notice' || this.state.modal === 'upgrade' ? this.state.notice : this.state.modal === 'disconnect' ? '断开后将返回首页。' : - this.state.modal === 'previews' ? '预览可能包含远程设备上的敏感内容。仅保存在本机,从下一次连接起生效,可随时关闭并清除。' : - this.state.modal === 'clearPreviews' ? '将清除此设备保存的所有远程画面预览,保留连接记录和访问密码。' : - this.state.modal === 'revoke' ? '将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。' : - this.state.modal === 'delete' ? '同时删除该设备保存的密码和预览。' : '此公告将从列表中移除。') + Text(this.state.modal === 'notice' || this.state.modal === 'upgrade' ? this.state.notice : this.state.modal === 'disconnect' ? tr("断开后将返回首页。") : + this.state.modal === 'previews' ? tr("预览可能包含远程设备上的敏感内容。仅保存在本机,从下一次连接起生效,可随时关闭并清除。") : + this.state.modal === 'clearPreviews' ? tr("将清除此设备保存的所有远程画面预览,保留连接记录和访问密码。") : + this.state.modal === 'revoke' ? tr("将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。") : + this.state.modal === 'delete' ? tr("同时删除该设备保存的密码和预览。") : tr("此公告将从列表中移除。")) .fontSize(14).lineHeight(21).fontColor(MobileTheme.secondary).textAlign(TextAlign.Center).width('100%') }.padding(24).width('100%') this.Rule() - if (this.state.modal === 'notice' || this.state.modal === 'upgrade') { this.Action('知道了', () => this.dismissModal()) } + if (this.state.modal === 'notice' || this.state.modal === 'upgrade') { this.Action(tr("知道了"), () => this.dismissModal()) } else { Row() { - Button('取消', { type: ButtonType.Normal }).fontSize(16).fontColor(MobileTheme.blue).height(50).layoutWeight(1) + Button(tr("取消"), { type: ButtonType.Normal }).fontSize(16).fontColor(MobileTheme.blue).height(50).layoutWeight(1) .backgroundColor(Color.White).onClick(() => this.dismissModal()) Divider().vertical(true).height(50).strokeWidth(0.5).color(MobileTheme.line) - Button(this.state.modal === 'previews' ? '开启' : this.state.modal === 'disconnect' ? '断开连接' : this.state.modal === 'revoke' ? '撤回授权' : this.state.modal === 'clearPreviews' ? '清除' : '删除', { type: ButtonType.Normal }) + Button(this.state.modal === 'previews' ? tr("开启") : this.state.modal === 'disconnect' ? tr("断开连接") : this.state.modal === 'revoke' ? tr("撤回授权") : this.state.modal === 'clearPreviews' ? tr("清除") : tr("删除"), { type: ButtonType.Normal }) .fontSize(16).fontWeight(600).fontColor(this.state.modal === 'previews' ? MobileTheme.blue : MobileTheme.red).height(50).layoutWeight(1) .backgroundColor(Color.White).onClick(() => this.confirmModal()) }.width('100%') @@ -637,11 +640,11 @@ struct Mobile { else { Column() { Row({ space: 0 }) { - MobileIconButton({ icon: 'back', label: '返回', iconExtent: 44, iconSize: 22, action: () => this.back() }) + MobileIconButton({ icon: 'back', label: tr("返回"), iconExtent: 44, iconSize: 22, action: () => this.back() }) Text(this.title()).fontSize(17).fontWeight(600).fontColor(MobileTheme.ink).layoutWeight(1).textAlign(TextAlign.Center) .maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }) if (this.state.page === 'announcements') { - MobileIconButton({ icon: 'refresh', label: '刷新公告', iconExtent: 44, iconSize: 22, action: () => this.controller?.inbox.refresh() }) + MobileIconButton({ icon: 'refresh', label: tr("刷新公告"), iconExtent: 44, iconSize: 22, action: () => this.controller?.inbox.refresh() }) } else { Blank().width(44) } }.width('100%').constraintSize({ maxWidth: 720 }).height(56).padding({ left: 12, right: 12 }) if (this.state.page === 'announcements') { diff --git a/apps/ios/CrossDeskMobile.xcodeproj/project.pbxproj b/apps/ios/CrossDeskMobile.xcodeproj/project.pbxproj index 60c68c34..3cebddfe 100644 --- a/apps/ios/CrossDeskMobile.xcodeproj/project.pbxproj +++ b/apps/ios/CrossDeskMobile.xcodeproj/project.pbxproj @@ -35,6 +35,8 @@ 10000000000000000000001A /* AnnouncementText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20000000000000000000001A /* AnnouncementText.swift */; }; 10000000000000000000001B /* AnnouncementInboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20000000000000000000001B /* AnnouncementInboxView.swift */; }; 10000000000000000000001C /* AppUpdateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20000000000000000000001C /* AppUpdateChecker.swift */; }; + 3C550ED141D4AEA30950BB7A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5BD6CC3A43B86A2E2267994F; }; + 4870B14C46F4C4B8F10FEF08 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A0A3C0DA09EE562AE21DF986; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -70,6 +72,28 @@ 20000000000000000000001A /* AnnouncementText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementText.swift; sourceTree = ""; }; 20000000000000000000001B /* AnnouncementInboxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementInboxView.swift; sourceTree = ""; }; 20000000000000000000001C /* AppUpdateChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateChecker.swift; sourceTree = ""; }; + 51B43C654308785E6FC27C98 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en"; path = "Resources/en.lproj/Localizable.strings"; sourceTree = ""; }; + C04C96DC6D837D5C45257B37 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Resources/zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; + 4E23FD4A4331F613A7BF3C81 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Resources/zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; + 10718835138E0FDDFDE9B567 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ru"; path = "Resources/ru.lproj/Localizable.strings"; sourceTree = ""; }; + BA8BCB85D00055B796EBB9E1 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ja"; path = "Resources/ja.lproj/Localizable.strings"; sourceTree = ""; }; + 10083BB5398965A4432CEC1E /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ko"; path = "Resources/ko.lproj/Localizable.strings"; sourceTree = ""; }; + 8CEF64DB2A646A3C710CAAE7 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de"; path = "Resources/de.lproj/Localizable.strings"; sourceTree = ""; }; + 467DE174FF993E9771FAEE5D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr"; path = "Resources/fr.lproj/Localizable.strings"; sourceTree = ""; }; + 2EA0435DFAEE685F04391B3B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es"; path = "Resources/es.lproj/Localizable.strings"; sourceTree = ""; }; + 1C906F7AD7B701DB61B512D2 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "Resources/pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; + B6189259C1AE18847A742A13 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt"; path = "Resources/pt.lproj/Localizable.strings"; sourceTree = ""; }; + 23D5AD87A9BF0CBF3A6AADDF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en"; path = "Resources/en.lproj/InfoPlist.strings"; sourceTree = ""; }; + 2E83770B40B2D299796EB0CD /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Resources/zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; + 36B135DFBFBD8F03E16FB09A /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Resources/zh-Hant.lproj/InfoPlist.strings"; sourceTree = ""; }; + 56DE65D659C5D65945CF834F /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ru"; path = "Resources/ru.lproj/InfoPlist.strings"; sourceTree = ""; }; + 02A713C4B5A1623480A005D6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ja"; path = "Resources/ja.lproj/InfoPlist.strings"; sourceTree = ""; }; + EA650495031B45A6FE5892FD /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ko"; path = "Resources/ko.lproj/InfoPlist.strings"; sourceTree = ""; }; + E653CAF5C4E87548BF6D8670 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de"; path = "Resources/de.lproj/InfoPlist.strings"; sourceTree = ""; }; + 0BB7EC0F2A5A6A313F782DCA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr"; path = "Resources/fr.lproj/InfoPlist.strings"; sourceTree = ""; }; + 093D4362C938821DE02B9032 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es"; path = "Resources/es.lproj/InfoPlist.strings"; sourceTree = ""; }; + 125E3BF17EC58E43B32F2AC3 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "Resources/pt-BR.lproj/InfoPlist.strings"; sourceTree = ""; }; + 7DDF05F5D35AB063DB447879 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt"; path = "Resources/pt.lproj/InfoPlist.strings"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -125,6 +149,8 @@ 200000000000000000000003 /* ContentView.swift */, 20000000000000000000000E /* ThirdPartyLicensesView.swift */, 20000000000000000000000F /* ThirdPartyLicenses.json */, + A0A3C0DA09EE562AE21DF986 /* InfoPlist.strings */, + 5BD6CC3A43B86A2E2267994F /* Localizable.strings */, 200000000000000000000010 /* PrivacyInfo.xcprivacy */, 200000000000000000000004 /* RemoteSessionView.swift */, 400000000000000000000003 /* Bridge */, @@ -206,6 +232,11 @@ }; /* End PBXNativeTarget section */ +/* Begin PBXVariantGroup section */ + 5BD6CC3A43B86A2E2267994F /* Localizable.strings */ = {isa = PBXVariantGroup; children = (51B43C654308785E6FC27C98, C04C96DC6D837D5C45257B37, 4E23FD4A4331F613A7BF3C81, 10718835138E0FDDFDE9B567, BA8BCB85D00055B796EBB9E1, 10083BB5398965A4432CEC1E, 8CEF64DB2A646A3C710CAAE7, 467DE174FF993E9771FAEE5D, 2EA0435DFAEE685F04391B3B, 1C906F7AD7B701DB61B512D2, B6189259C1AE18847A742A13, ); name = Localizable.strings; sourceTree = ""; }; + A0A3C0DA09EE562AE21DF986 /* InfoPlist.strings */ = {isa = PBXVariantGroup; children = (23D5AD87A9BF0CBF3A6AADDF, 2E83770B40B2D299796EB0CD, 36B135DFBFBD8F03E16FB09A, 56DE65D659C5D65945CF834F, 02A713C4B5A1623480A005D6, EA650495031B45A6FE5892FD, E653CAF5C4E87548BF6D8670, 0BB7EC0F2A5A6A313F782DCA, 093D4362C938821DE02B9032, 125E3BF17EC58E43B32F2AC3, 7DDF05F5D35AB063DB447879, ); name = InfoPlist.strings; sourceTree = ""; }; +/* End PBXVariantGroup section */ + /* Begin PBXProject section */ 800000000000000000000001 /* Project object */ = { isa = PBXProject; @@ -221,13 +252,9 @@ }; buildConfigurationList = 900000000000000000000001 /* Build configuration list for PBXProject "CrossDeskMobile" */; compatibilityVersion = "Xcode 15.0"; - developmentRegion = zh_CN; + developmentRegion = en; hasScannedForEncodings = 0; - knownRegions = ( - Base, - en, - zh_CN, - ); + knownRegions = (Base, "en", "zh-Hans", "zh-Hant", "ru", "ja", "ko", "de", "fr", "es", "pt-BR", "pt", ); mainGroup = 400000000000000000000001; productRefGroup = 400000000000000000000007 /* Products */; projectDirPath = ""; @@ -245,6 +272,8 @@ files = ( 100000000000000000000008 /* Assets.xcassets in Resources */, 10000000000000000000000A /* ThirdPartyLicenses.json in Resources */, + 4870B14C46F4C4B8F10FEF08 /* InfoPlist.strings in Resources */, + 3C550ED141D4AEA30950BB7A /* Localizable.strings in Resources */, 10000000000000000000000B /* PrivacyInfo.xcprivacy in Resources */, 100000000000000000000015 /* PRIVACY.md in Resources */, ); diff --git a/apps/ios/CrossDeskMobile/AnnouncementInboxView.swift b/apps/ios/CrossDeskMobile/AnnouncementInboxView.swift index 27eab882..5d7c7e96 100644 --- a/apps/ios/CrossDeskMobile/AnnouncementInboxView.swift +++ b/apps/ios/CrossDeskMobile/AnnouncementInboxView.swift @@ -21,8 +21,8 @@ struct AnnouncementBadge: View { } } .accessibilityElement(children: .ignore) - .accessibilityLabel("通知公告") - .accessibilityValue(inbox.state.unread > 0 ? "\(inbox.state.unread) 条未读" : "无未读公告") + .accessibilityLabel(NSLocalizedString("通知公告", comment: "")) + .accessibilityValue(inbox.state.unread > 0 ? String(format: NSLocalizedString("%1$@ 条未读", comment: ""), String(describing: inbox.state.unread)) : NSLocalizedString("无未读公告", comment: "")) } } @@ -49,14 +49,14 @@ struct AnnouncementInboxView: View { var body: some View { List { if inbox.state.deleteFailed { - Text("无法删除这条公告,请重试。") + Text(NSLocalizedString("无法删除这条公告,请重试。", comment: "")) .foregroundStyle(.red) } if inbox.state.failed && session.announcementsConnected { HStack { - Text("公告加载失败,请重试。") + Text(NSLocalizedString("公告加载失败,请重试。", comment: "")) Spacer() - Button("重试") { session.refreshAnnouncements() } + Button(NSLocalizedString("重试", comment: "")) { session.refreshAnnouncements() } .disabled(!session.announcementsConnected) } } @@ -82,42 +82,42 @@ struct AnnouncementInboxView: View { } .padding(.vertical, 5) .accessibilityElement(children: .combine) - .accessibilityValue(item.read ? "已读" : "未读") + .accessibilityValue(item.read ? NSLocalizedString("已读", comment: "") : NSLocalizedString("未读", comment: "")) } .swipeActions { - Button("删除", role: .destructive) { pendingDelete = item } + Button(NSLocalizedString("删除", comment: ""), role: .destructive) { pendingDelete = item } } .contextMenu { - Button("删除公告", role: .destructive) { pendingDelete = item } + Button(NSLocalizedString("删除公告", comment: ""), role: .destructive) { pendingDelete = item } } } if inbox.state.loading { - HStack { Spacer(); ProgressView("加载中…"); Spacer() } + HStack { Spacer(); ProgressView(NSLocalizedString("加载中…", comment: "")); Spacer() } } else if inbox.state.items.count < inbox.state.total && !inbox.state.failed { - Button("加载更多") { inbox.loadMore() } + Button(NSLocalizedString("加载更多", comment: "")) { inbox.loadMore() } .frame(maxWidth: .infinity) .disabled(!session.announcementsConnected) .onAppear { inbox.loadMore() } } else if inbox.state.loaded && inbox.state.total == 0 && !inbox.state.failed && session.announcementsConnected { - Text("暂无公告") + Text(NSLocalizedString("暂无公告", comment: "")) .foregroundStyle(.secondary) .frame(maxWidth: .infinity, minHeight: 120) } } header: { - Text("共 \(inbox.state.total) 条 · \(inbox.state.unread) 条未读") + Text(String(format: NSLocalizedString("共 %1$@ 条 · %2$@ 条未读", comment: ""), String(describing: inbox.state.total), String(describing: inbox.state.unread))) } } .readableContentWidth() .background(Color(.systemGroupedBackground).ignoresSafeArea()) - .navigationTitle("通知公告") + .navigationTitle(NSLocalizedString("通知公告", comment: "")) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button { session.refreshAnnouncements() } label: { Image(systemName: "arrow.clockwise") } - .accessibilityLabel("刷新公告") + .accessibilityLabel(NSLocalizedString("刷新公告", comment: "")) .disabled(inbox.state.loading || !session.announcementsConnected) } } @@ -128,17 +128,17 @@ struct AnnouncementInboxView: View { } } .onAppear { session.refreshAnnouncements() } - .alert("删除公告", isPresented: Binding( + .alert(NSLocalizedString("删除公告", comment: ""), isPresented: Binding( get: { pendingDelete != nil }, set: { if !$0 { pendingDelete = nil } } )) { - Button("取消", role: .cancel) { pendingDelete = nil } - Button("删除", role: .destructive) { + Button(NSLocalizedString("取消", comment: ""), role: .cancel) { pendingDelete = nil } + Button(NSLocalizedString("删除", comment: ""), role: .destructive) { if let item = pendingDelete { inbox.dismiss(item) } pendingDelete = nil } } message: { - Text("删除这条公告?") + Text(NSLocalizedString("删除这条公告?", comment: "")) } } } @@ -158,13 +158,13 @@ struct AnnouncementDetailView: View { VStack(alignment: .leading, spacing: 16) { Text(verbatim: item.title) .font(.title2.weight(.semibold)) - Text("\(AnnouncementDate.string(item)) · \(item.read ? "已读" : "未读")") + Text("\(AnnouncementDate.string(item)) · \(NSLocalizedString(item.read ? "已读" : "未读", comment: ""))") .font(.caption) .foregroundStyle(.secondary) if inbox.state.readSaveFailed { - Text("无法保存本地阅读状态,请重试。") + Text(NSLocalizedString("无法保存本地阅读状态,请重试。", comment: "")) .foregroundStyle(.red) - Button("重试保存阅读状态") { inbox.markRead(item) } + Button(NSLocalizedString("重试保存阅读状态", comment: "")) { inbox.markRead(item) } } Text(AnnouncementText.format(item.body)) .textSelection(.enabled) @@ -178,13 +178,13 @@ struct AnnouncementDetailView: View { .padding(20) .readableContentWidth() } else { - Text("这条公告已更新或删除,请返回公告列表查看。") + Text(NSLocalizedString("这条公告已更新或删除,请返回公告列表查看。", comment: "")) .foregroundStyle(.secondary) .padding(20) .readableContentWidth() } } - .navigationTitle("公告详情") + .navigationTitle(NSLocalizedString("公告详情", comment: "")) .navigationBarTitleDisplayMode(.inline) .onAppear { if let item { inbox.markRead(item) } diff --git a/apps/ios/CrossDeskMobile/ContentView.swift b/apps/ios/CrossDeskMobile/ContentView.swift index 2cc333c7..420976b0 100644 --- a/apps/ios/CrossDeskMobile/ContentView.swift +++ b/apps/ios/CrossDeskMobile/ContentView.swift @@ -65,11 +65,11 @@ struct ContentView: View { .presentationDragIndicator(.hidden) .interactiveDismissDisabled() } - .alert("连接提示", isPresented: Binding( + .alert(NSLocalizedString("连接提示", comment: ""), isPresented: Binding( get: { session.connectionFailureMessage != nil }, set: { if !$0 { session.dismissConnectionFailure() } } )) { - Button("确定", role: .cancel) { session.dismissConnectionFailure() } + Button(NSLocalizedString("确定", comment: ""), role: .cancel) { session.dismissConnectionFailure() } } message: { Text(session.connectionFailureMessage ?? "") } @@ -196,17 +196,8 @@ private struct ConnectionHomeView: View { ) } - private var signalIsConnected: Bool { - session.signalStatus == "已连接服务器" - } - - private var signalHasError: Bool { - session.signalStatus.contains("失败") || - session.signalStatus.contains("无法") || - session.signalStatus.contains("无效") || - session.signalStatus.contains("关闭") || - session.signalStatus.contains("未知") - } + private var signalIsConnected: Bool { session.signalConnected } + private var signalHasError: Bool { session.signalHasError } private var signalTint: Color { if signalIsConnected { return .green } @@ -303,13 +294,13 @@ private struct ConnectionHomeView: View { .presentationDetents([.height(340)]) .presentationDragIndicator(.visible) } - .alert("设备离线", isPresented: Binding( + .alert(NSLocalizedString("设备离线", comment: ""), isPresented: Binding( get: { session.deviceOfflineAlertVisible }, set: { visible in if !visible { session.dismissDeviceOfflineAlert() } } )) { - Button("确定") { + Button(NSLocalizedString("确定", comment: "")) { session.dismissDeviceOfflineAlert() } } @@ -337,7 +328,7 @@ private struct ConnectionHomeView: View { .fixedSize(horizontal: true, vertical: false) } .buttonStyle(.plain) - .accessibilityHint("打开隐私政策") + .accessibilityHint(NSLocalizedString("打开隐私政策", comment: "")) } } ToolbarItem(placement: .navigationBarTrailing) { @@ -369,7 +360,7 @@ private struct ConnectionHomeView: View { } .foregroundStyle(.primary) .disabled(session.isConnecting) - .accessibilityLabel(appUpdates.updateAvailable ? "设置,有新版本" : "设置") + .accessibilityLabel(appUpdates.updateAvailable ? NSLocalizedString("设置,有新版本", comment: "") : NSLocalizedString("设置", comment: "")) } } @@ -398,13 +389,13 @@ private struct ConnectionHomeView: View { private var remoteConnectionPanel: some View { VStack(alignment: .leading, spacing: 16) { HStack { - Text("远程桌面") + Text(NSLocalizedString("远程桌面", comment: "")) .font(.title3.weight(.bold)) Spacer() } HStack(spacing: 10) { - TextField("对端 ID", text: groupedRemoteID) + TextField(NSLocalizedString("对端 ID", comment: ""), text: groupedRemoteID) .keyboardType(.numberPad) .textContentType(.username) .textInputAutocapitalization(.never) @@ -431,8 +422,10 @@ private struct ConnectionHomeView: View { Button { presentPasswordPrompt(for: trimmedRemoteID) } label: { - Text("连接") + Text(NSLocalizedString("连接", comment: "")) .font(.system(size: 16, weight: .bold)) + .lineLimit(1) + .minimumScaleFactor(0.65) .frame(width: 96, height: 54) .foregroundStyle(.white) .background(LinearGradient(colors: [ @@ -447,7 +440,7 @@ private struct ConnectionHomeView: View { .buttonStyle(.plain) .disabled(trimmedRemoteID.isEmpty || session.isConnecting) .opacity(trimmedRemoteID.isEmpty || session.isConnecting ? 0.45 : 1) - .accessibilityLabel("连接") + .accessibilityLabel(NSLocalizedString("连接", comment: "")) } } .padding(18) @@ -464,11 +457,11 @@ private struct ConnectionHomeView: View { private func recentConnectionsPanel(windowWidth: CGFloat) -> some View { VStack(alignment: .leading, spacing: 14) { HStack(alignment: .firstTextBaseline) { - Text("最近连接") + Text(NSLocalizedString("最近连接", comment: "")) .font(.title3.bold()) Spacer() if !session.recentConnections.isEmpty { - Text("\(session.recentConnections.count) 台设备") + Text(String(format: NSLocalizedString("%1$@ 台设备", comment: ""), String(describing: session.recentConnections.count))) .font(.caption) .foregroundStyle(.secondary) } @@ -479,9 +472,9 @@ private struct ConnectionHomeView: View { Image(systemName: "clock.arrow.circlepath") .font(.system(size: 30, weight: .medium)) .foregroundStyle(.tertiary) - Text("还没有连接记录") + Text(NSLocalizedString("还没有连接记录", comment: "")) .font(.headline) - Text("成功连接后,这里会显示远端桌面的缩略图。") + Text(NSLocalizedString("成功连接后,这里会显示远端桌面的缩略图。", comment: "")) .font(.footnote) .foregroundStyle(.secondary) .multilineTextAlignment(.center) @@ -532,7 +525,7 @@ private struct ConnectionHomeView: View { .tint(connectionAccent) VStack(spacing: 6) { - Text("正在连接") + Text(NSLocalizedString("正在连接", comment: "")) .font(.title3.weight(.semibold)) .foregroundStyle(.primary) Text(session.connectionStatus) @@ -550,7 +543,7 @@ private struct ConnectionHomeView: View { Divider() Button(role: .cancel, action: session.disconnect) { - Text("取消连接") + Text(NSLocalizedString("取消连接", comment: "")) .font(.subheadline.weight(.semibold)) .foregroundStyle(Color.red) .frame(maxWidth: .infinity) @@ -656,7 +649,7 @@ private struct RecentConnectionCard: View { .minimumScaleFactor(0.8) .foregroundStyle(.white) .padding(8) - .accessibilityLabel("被控端平台:\(connection.platform.displayName)") + .accessibilityLabel(String(format: NSLocalizedString("被控端平台:%1$@", comment: ""), String(describing: connection.platform.displayName))) } } .frame(maxWidth: .infinity) @@ -678,12 +671,12 @@ private struct RecentConnectionCard: View { Image(systemName: "key.fill") .font(.system(size: 9, weight: .semibold)) .foregroundStyle(.secondary) - .accessibilityLabel("已保存密码") + .accessibilityLabel(NSLocalizedString("已保存密码", comment: "")) } - Text(online ? "在线" : "离线") + Text(online ? NSLocalizedString("在线", comment: "") : NSLocalizedString("离线", comment: "")) .font(.caption2.weight(.semibold)) .foregroundStyle(online ? Color.green : Color.secondary) - .accessibilityLabel(online ? "在线" : "离线") + .accessibilityLabel(online ? NSLocalizedString("在线", comment: "") : NSLocalizedString("离线", comment: "")) } } .padding(9) @@ -698,10 +691,10 @@ private struct RecentConnectionCard: View { .buttonStyle(.plain) .contextMenu { Button(action: connect) { - Text("连接") + Text(NSLocalizedString("连接", comment: "")) } Button(role: .destructive, action: delete) { - Label("删除记录", systemImage: "trash") + Label(NSLocalizedString("删除记录", comment: ""), systemImage: "trash") } } } @@ -722,9 +715,9 @@ private struct PasswordPromptView: View { VStack(alignment: .leading, spacing: 18) { HStack { VStack(alignment: .leading, spacing: 4) { - Text("连接远程桌面") + Text(NSLocalizedString("连接远程桌面", comment: "")) .font(.title2.bold()) - Text("对端 ID \(remoteID)") + Text(String(format: NSLocalizedString("对端 ID %1$@", comment: ""), String(describing: remoteID))) .font(.subheadline.monospacedDigit()) .foregroundStyle(.secondary) } @@ -736,15 +729,15 @@ private struct PasswordPromptView: View { .font(.title2) .foregroundStyle(.secondary) } - .accessibilityLabel("关闭") + .accessibilityLabel(NSLocalizedString("关闭", comment: "")) } HStack(spacing: 10) { Group { if passwordVisible { - TextField("访问密码", text: $password) + TextField(NSLocalizedString("访问密码", comment: ""), text: $password) } else { - SecureField("访问密码", text: $password) + SecureField(NSLocalizedString("访问密码", comment: ""), text: $password) } } .keyboardType(.asciiCapable) @@ -759,7 +752,7 @@ private struct PasswordPromptView: View { Image(systemName: passwordVisible ? "eye.slash" : "eye") .foregroundStyle(.secondary) } - .accessibilityLabel(passwordVisible ? "隐藏密码" : "显示密码") + .accessibilityLabel(passwordVisible ? NSLocalizedString("隐藏密码", comment: "") : NSLocalizedString("显示密码", comment: "")) } .padding(.horizontal, 13) .frame(height: 50) @@ -773,16 +766,16 @@ private struct PasswordPromptView: View { Toggle(isOn: $rememberPassword) { VStack(alignment: .leading, spacing: 2) { - Text("保存密码") + Text(NSLocalizedString("保存密码", comment: "")) .font(.subheadline.weight(.semibold)) - Text("密码将安全保存在本机 Keychain 中") + Text(NSLocalizedString("密码将安全保存在本机 Keychain 中", comment: "")) .font(.caption) .foregroundStyle(.secondary) } } Button(action: connect) { - Text("连接") + Text(NSLocalizedString("连接", comment: "")) .font(.headline) .frame(maxWidth: .infinity) .frame(height: 48) @@ -823,16 +816,16 @@ private struct ServerSettingsView: View { var body: some View { Form { - Section("鼠标控制") { - Picker("控制模式", selection: $session.mouseControlMode) { + Section(NSLocalizedString("鼠标控制", comment: "")) { + Picker(NSLocalizedString("控制模式", comment: ""), selection: $session.mouseControlMode) { ForEach(MouseControlMode.allCases) { mode in Text(mode.title).tag(mode) } } .pickerStyle(.segmented) } - Section("画面偏好") { - Picker("偏好模式", selection: $session.videoAdaptationPolicy) { + Section(NSLocalizedString("画面偏好", comment: "")) { + Picker(NSLocalizedString("偏好模式", comment: ""), selection: $session.videoAdaptationPolicy) { ForEach(VideoAdaptationPolicy.allCases) { policy in Text(policy.title).tag(policy) } @@ -840,18 +833,18 @@ private struct ServerSettingsView: View { .pickerStyle(.segmented) } Section { - Toggle("连接建立后锁定横屏", isOn: $session.autoLandscape) + Toggle(NSLocalizedString("连接建立后锁定横屏", comment: ""), isOn: $session.autoLandscape) } header: { - Text("屏幕方向") + Text(NSLocalizedString("屏幕方向", comment: "")) } footer: { - Text("默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。") + Text(NSLocalizedString("默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。", comment: "")) } Section { DisclosureGroup(isExpanded: $serverConfigurationExpanded) { - Toggle("使用自定义服务器", isOn: $usesCustomServer) + Toggle(NSLocalizedString("使用自定义服务器", comment: ""), isOn: $usesCustomServer) if usesCustomServer { - LabeledContent("地址") { - TextField("填写服务器地址", text: $customServerHost) + LabeledContent(NSLocalizedString("地址", comment: "")) { + TextField(NSLocalizedString("填写服务器地址", comment: ""), text: $customServerHost) .textInputAutocapitalization(.never) .autocorrectionDisabled() .keyboardType(.URL) @@ -859,21 +852,21 @@ private struct ServerSettingsView: View { .focused($focusedServerField, equals: .host) .submitLabel(.next) .onSubmit { focusedServerField = .port } - .accessibilityLabel("服务器地址") + .accessibilityLabel(NSLocalizedString("服务器地址", comment: "")) } - LabeledContent("端口") { - TextField("填写端口", text: $customServerPort) + LabeledContent(NSLocalizedString("端口", comment: "")) { + TextField(NSLocalizedString("填写端口", comment: ""), text: $customServerPort) .keyboardType(.numberPad) .multilineTextAlignment(.trailing) .focused($focusedServerField, equals: .port) - .accessibilityLabel("服务器端口") + .accessibilityLabel(NSLocalizedString("服务器端口", comment: "")) } } } label: { HStack { - Text("服务器") + Text(NSLocalizedString("服务器", comment: "")) Spacer() - Text(usesCustomServer ? "自定义" : "默认") + Text(usesCustomServer ? NSLocalizedString("自定义", comment: "") : NSLocalizedString("默认", comment: "")) .foregroundStyle(.secondary) } } @@ -886,9 +879,9 @@ private struct ServerSettingsView: View { Text(warning) .foregroundStyle(.orange) } - Text(!session.hasNetworkConsent ? "完成隐私授权后登记本机身份" : session.localIdentity.isEmpty - ? "正在获取本机 ID…" - : "本机 ID \(session.localIdentity)") + Text(!session.hasNetworkConsent ? NSLocalizedString("完成隐私授权后登记本机身份", comment: "") : session.localIdentity.isEmpty + ? NSLocalizedString("正在获取本机 ID…", comment: "") + : String(format: NSLocalizedString("本机 ID %1$@", comment: ""), String(describing: session.localIdentity))) .font(.caption2.monospacedDigit()) .foregroundStyle(.secondary) .frame(maxWidth: .infinity, alignment: .center) @@ -901,20 +894,20 @@ private struct ServerSettingsView: View { ThirdPartyLicensesView(session: session) } label: { HStack { - Text("关于") + Text(NSLocalizedString("关于", comment: "")) Spacer() if appUpdates.updateAvailable { - Text("新版本").foregroundStyle(.secondary) + Text(NSLocalizedString("新版本", comment: "")).foregroundStyle(.secondary) UpdateDot() } } } - .accessibilityLabel(appUpdates.updateAvailable ? "关于,有新版本" : "关于") + .accessibilityLabel(appUpdates.updateAvailable ? NSLocalizedString("关于,有新版本", comment: "") : NSLocalizedString("关于", comment: "")) } } .readableContentWidth() .background(Color(.systemGroupedBackground).ignoresSafeArea()) - .navigationTitle("设置") + .navigationTitle(NSLocalizedString("设置", comment: "")) .navigationBarTitleDisplayMode(.inline) .scrollDismissesKeyboard(.interactively) .background { @@ -943,7 +936,7 @@ private struct ServerSettingsView: View { .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() - Button("完成") { + Button(NSLocalizedString("完成", comment: "")) { focusedServerField = nil } } @@ -965,11 +958,11 @@ private struct ServerSettingsView: View { let host = customServerHost.trimmingCharacters(in: .whitespacesAndNewlines) let port = customServerPort.trimmingCharacters(in: .whitespacesAndNewlines) guard !host.isEmpty else { - serverConfigurationError = "请输入服务器地址,或关闭“使用自定义服务器”。" + serverConfigurationError = NSLocalizedString("请输入服务器地址,或关闭“使用自定义服务器”。", comment: "") return } guard let portNumber = Int(port), (1...65535).contains(portNumber) else { - serverConfigurationError = "请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" + serverConfigurationError = NSLocalizedString("请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。", comment: "") return } serverConfigurationError = nil diff --git a/apps/ios/CrossDeskMobile/Info.plist b/apps/ios/CrossDeskMobile/Info.plist index 5b4eaec6..8d439762 100644 --- a/apps/ios/CrossDeskMobile/Info.plist +++ b/apps/ios/CrossDeskMobile/Info.plist @@ -5,7 +5,7 @@ CFBundleDisplayName CrossDesk CFBundleDevelopmentRegion - zh_CN + en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/apps/ios/CrossDeskMobile/Input/RemoteSystemKeyboard.swift b/apps/ios/CrossDeskMobile/Input/RemoteSystemKeyboard.swift index 2b5d1459..fbaf89b3 100644 --- a/apps/ios/CrossDeskMobile/Input/RemoteSystemKeyboard.swift +++ b/apps/ios/CrossDeskMobile/Input/RemoteSystemKeyboard.swift @@ -321,13 +321,13 @@ final class RemoteKeyboardInputBar: UIView { heightConstraint.isActive = true let computerButton = UIButton(type: .system) - computerButton.setTitle("电脑键盘", for: .normal) + computerButton.setTitle(NSLocalizedString("电脑键盘", comment: ""), for: .normal) computerButton.titleLabel?.font = .systemFont(ofSize: 15, weight: .medium) - computerButton.accessibilityLabel = "切换到电脑键盘" + computerButton.accessibilityLabel = NSLocalizedString("切换到电脑键盘", comment: "") computerButton.addTarget(self, action: #selector(switchToComputer), for: .touchUpInside) let dismissButton = RemoteKeyboardDismissButton.makeButton() - dismissButton.accessibilityLabel = "收起系统键盘" + dismissButton.accessibilityLabel = NSLocalizedString("收起系统键盘", comment: "") dismissButton.addTarget(self, action: #selector(hideKeyboard), for: .touchUpInside) row.axis = .horizontal diff --git a/apps/ios/CrossDeskMobile/Input/VirtualMouseBar.swift b/apps/ios/CrossDeskMobile/Input/VirtualMouseBar.swift index 4bcf7051..3b52eb34 100644 --- a/apps/ios/CrossDeskMobile/Input/VirtualMouseBar.swift +++ b/apps/ios/CrossDeskMobile/Input/VirtualMouseBar.swift @@ -64,8 +64,8 @@ private final class VirtualMouseKey: UIView { isMultipleTouchEnabled = false isAccessibilityElement = true accessibilityTraits = kind == .wheel ? [.adjustable] : [.button] - accessibilityLabel = kind == .left ? "鼠标左键" : kind == .right ? "鼠标右键" : "鼠标滚轮" - accessibilityHint = kind == .wheel ? "上下滑动,可滑出按键范围" : "按住并拖动,可滑出按键范围,松开结束拖拽" + accessibilityLabel = kind == .left ? NSLocalizedString("鼠标左键", comment: "") : kind == .right ? NSLocalizedString("鼠标右键", comment: "") : NSLocalizedString("鼠标滚轮", comment: "") + accessibilityHint = kind == .wheel ? NSLocalizedString("上下滑动,可滑出按键范围", comment: "") : NSLocalizedString("按住并拖动,可滑出按键范围,松开结束拖拽", comment: "") face.isUserInteractionEnabled = false face.layer.mask = faceMask addSubview(face) diff --git a/apps/ios/CrossDeskMobile/PrivacyViews.swift b/apps/ios/CrossDeskMobile/PrivacyViews.swift index 72589030..cdadbc9f 100644 --- a/apps/ios/CrossDeskMobile/PrivacyViews.swift +++ b/apps/ios/CrossDeskMobile/PrivacyViews.swift @@ -16,7 +16,7 @@ struct PrivacyConsentView: View { .safeAreaInset(edge: .bottom, spacing: 0) { consentActions } - .navigationTitle("隐私政策") + .navigationTitle(NSLocalizedString("隐私政策", comment: "")) .navigationBarTitleDisplayMode(.inline) } } @@ -27,7 +27,7 @@ struct PrivacyConsentView: View { VStack(spacing: 12) { Toggle(isOn: $hasReadPolicy) { - Text("我已阅读并同意《隐私政策》") + Text(NSLocalizedString("我已阅读并同意《隐私政策》", comment: "")) .font(.subheadline) } .toggleStyle(ConsentCheckboxStyle()) @@ -36,7 +36,7 @@ struct PrivacyConsentView: View { guard hasReadPolicy else { return } session.acceptNetworkConsent() } label: { - Text("同意并继续") + Text(NSLocalizedString("同意并继续", comment: "")) .font(.body.weight(.semibold)) .frame(maxWidth: .infinity, minHeight: 24) } @@ -48,7 +48,7 @@ struct PrivacyConsentView: View { Button { session.declineNetworkConsent() } label: { - Text("暂不同意") + Text(NSLocalizedString("暂不同意", comment: "")) .font(.body) .frame(maxWidth: .infinity, minHeight: 44) .contentShape(Rectangle()) @@ -81,8 +81,8 @@ private struct ConsentCheckboxStyle: ToggleStyle { .contentShape(Rectangle()) } .buttonStyle(.plain) - .accessibilityLabel("我已阅读并同意隐私政策") - .accessibilityValue(configuration.isOn ? "已勾选" : "未勾选") + .accessibilityLabel(NSLocalizedString("我已阅读并同意隐私政策", comment: "")) + .accessibilityValue(configuration.isOn ? NSLocalizedString("已勾选", comment: "") : NSLocalizedString("未勾选", comment: "")) } } @@ -97,13 +97,13 @@ struct PrivacySettingsSection: View { PrivacyAuthorizationView(session: session) } label: { HStack { - Text("隐私与授权") + Text(NSLocalizedString("隐私与授权", comment: "")) Spacer() - Text(session.hasNetworkConsent ? "已授权" : "未授权") + Text(session.hasNetworkConsent ? NSLocalizedString("已授权", comment: "") : NSLocalizedString("未授权", comment: "")) .foregroundStyle(.secondary) } } - Toggle("保存远程画面预览", isOn: Binding( + Toggle(NSLocalizedString("保存远程画面预览", comment: ""), isOn: Binding( get: { session.savesConnectionThumbnails }, set: { enabled in if enabled { confirmThumbnails = true } @@ -111,7 +111,7 @@ struct PrivacySettingsSection: View { } )) .disabled(!session.hasNetworkConsent || session.thumbnailCleanupInProgress) - Button(session.thumbnailCleanupInProgress ? "正在清除…" : "清除预览图", role: .destructive) { + Button(session.thumbnailCleanupInProgress ? NSLocalizedString("正在清除…", comment: "") : NSLocalizedString("清除预览图", comment: ""), role: .destructive) { confirmClear = true } .disabled(session.thumbnailCleanupInProgress) @@ -119,21 +119,21 @@ struct PrivacySettingsSection: View { Text(error).font(.footnote).foregroundStyle(.secondary) } } header: { - Text("隐私") + Text(NSLocalizedString("隐私", comment: "")) } - .alert("保存远程画面预览?", isPresented: $confirmThumbnails) { - Button("开启保存") { session.setSavesConnectionThumbnails(true) } - Button("取消", role: .cancel) { } + .alert(NSLocalizedString("保存远程画面预览?", comment: ""), isPresented: $confirmThumbnails) { + Button(NSLocalizedString("开启保存", comment: "")) { session.setSavesConnectionThumbnails(true) } + Button(NSLocalizedString("取消", comment: ""), role: .cancel) { } } message: { - Text("预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。") + Text(NSLocalizedString("预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。", comment: "")) } - .alert("清除预览图?", isPresented: $confirmClear) { - Button("清除", role: .destructive) { session.clearConnectionThumbnails() } - Button("取消", role: .cancel) { } + .alert(NSLocalizedString("清除预览图?", comment: ""), isPresented: $confirmClear) { + Button(NSLocalizedString("清除", comment: ""), role: .destructive) { session.clearConnectionThumbnails() } + Button(NSLocalizedString("取消", comment: ""), role: .cancel) { } } message: { Text(session.savesConnectionThumbnails - ? "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" - : "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。") + ? NSLocalizedString("将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。", comment: "") + : NSLocalizedString("将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。", comment: "")) } } } @@ -145,33 +145,33 @@ private struct PrivacyAuthorizationView: View { var body: some View { Form { Section { - LabeledContent("授权状态", value: session.hasNetworkConsent ? "已授权" : "未授权") - NavigationLink("隐私政策") { PrivacyPolicyView() } + LabeledContent(NSLocalizedString("授权状态", comment: ""), value: session.hasNetworkConsent ? NSLocalizedString("已授权", comment: "") : NSLocalizedString("未授权", comment: "")) + NavigationLink(NSLocalizedString("隐私政策", comment: "")) { PrivacyPolicyView() } } footer: { if !session.hasNetworkConsent { - Text("授权后可使用远程连接。") + Text(NSLocalizedString("授权后可使用远程连接。", comment: "")) } } Section { if session.hasNetworkConsent { - Button("撤回隐私授权", role: .destructive) { + Button(NSLocalizedString("撤回隐私授权", comment: ""), role: .destructive) { confirmWithdrawal = true } } else { - Button("阅读并授权") { session.showPrivacyNotice() } + Button(NSLocalizedString("阅读并授权", comment: "")) { session.showPrivacyNotice() } } } } .readableContentWidth() .background(Color(.systemGroupedBackground).ignoresSafeArea()) - .navigationTitle("隐私与授权") + .navigationTitle(NSLocalizedString("隐私与授权", comment: "")) .navigationBarTitleDisplayMode(.inline) - .alert("是否撤回隐私授权?", isPresented: $confirmWithdrawal) { - Button("撤回授权", role: .destructive) { session.revokeNetworkConsent() } - Button("取消", role: .cancel) { } + .alert(NSLocalizedString("是否撤回隐私授权?", comment: ""), isPresented: $confirmWithdrawal) { + Button(NSLocalizedString("撤回授权", comment: ""), role: .destructive) { session.revokeNetworkConsent() } + Button(NSLocalizedString("取消", comment: ""), role: .cancel) { } } message: { - Text("将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。") + Text(NSLocalizedString("将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。", comment: "")) } } } @@ -182,15 +182,17 @@ private struct PrivacyPolicyDocument: View { guard let url = Bundle.main.url(forResource: "PRIVACY", withExtension: "md"), let text = try? String(contentsOf: url, encoding: .utf8), !text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return nil } - // The app's interface is Chinese; show the complete Chinese translation. + // Keep the published policy intact; use its English version outside Chinese locales. if let start = text.range(of: "## 中文\n"), let end = text.range(of: "## English", range: start.upperBound.. String { - if enabled(at: now) { return "隐私屏已开启" } + if enabled(at: now) { return NSLocalizedString("隐私屏已开启", comment: "") } if fresh(at: now), let s = snapshot, s.supported && s.state == 1 && !active { - return "隐私屏已关闭" + return NSLocalizedString("隐私屏已关闭", comment: "") } - return "隐私屏" + return NSLocalizedString("隐私屏", comment: "") } func feedback(at now: TimeInterval) -> String { if !desktopAvailable { return "" } @@ -87,26 +87,26 @@ struct RemotePrivacyScreen { return requestID } mutating func failed(request: UInt32) { - if pending && requestID == request { pending = false; failure = "指令发送失败,请重试" } + if pending && requestID == request { pending = false; failure = NSLocalizedString("指令发送失败,请重试", comment: "") } } mutating func tick(at now: TimeInterval) { if pending && now - requestedAt >= 15 { - pending = false; failure = "请求超时,尚未确认电脑的隐私屏状态" + pending = false; failure = NSLocalizedString("请求超时,尚未确认电脑的隐私屏状态", comment: "") } } func status(at now: TimeInterval) -> String { if !failure.isEmpty { return failure } - guard let s = snapshot else { return "等待电脑返回隐私屏状态;旧版电脑端可能不支持" } - if !fresh(at: now) { return "隐私屏状态已过期,等待电脑确认" } - if s.state == 2 { return "正在开启隐私屏…" } - if s.state == 4 { return "正在关闭隐私屏…" } - if pending { return "指令已发送,等待电脑确认…" } - if s.state == 5 { return "隐私屏异常" } - if !s.supported || s.state == 0 { return "隐私屏暂不可用" } + guard let s = snapshot else { return NSLocalizedString("等待电脑返回隐私屏状态;旧版电脑端可能不支持", comment: "") } + if !fresh(at: now) { return NSLocalizedString("隐私屏状态已过期,等待电脑确认", comment: "") } + if s.state == 2 { return NSLocalizedString("正在开启隐私屏…", comment: "") } + if s.state == 4 { return NSLocalizedString("正在关闭隐私屏…", comment: "") } + if pending { return NSLocalizedString("指令已发送,等待电脑确认…", comment: "") } + if s.state == 5 { return NSLocalizedString("隐私屏异常", comment: "") } + if !s.supported || s.state == 0 { return NSLocalizedString("隐私屏暂不可用", comment: "") } if s.state == 3 && s.overlayActive && !s.remotePaused { - return "隐私屏已开启" + return NSLocalizedString("隐私屏已开启", comment: "") } - return s.state == 1 && !active ? "隐私屏已关闭" : "隐私屏状态待确认" + return s.state == 1 && !active ? NSLocalizedString("隐私屏已关闭", comment: "") : NSLocalizedString("隐私屏状态待确认", comment: "") } func detail(at now: TimeInterval) -> String { guard let s = snapshot, fresh(at: now), s.state == 0 || s.state == 5 || !s.supported else { return "" } diff --git a/apps/ios/CrossDeskMobile/RemoteSessionModel.swift b/apps/ios/CrossDeskMobile/RemoteSessionModel.swift index 02d91110..f064e216 100644 --- a/apps/ios/CrossDeskMobile/RemoteSessionModel.swift +++ b/apps/ios/CrossDeskMobile/RemoteSessionModel.swift @@ -15,17 +15,17 @@ enum MouseControlMode: String, CaseIterable, Identifiable { var title: String { switch self { - case .absolute: return "绝对位置" - case .relative: return "相对位置" + case .absolute: return NSLocalizedString("绝对位置", comment: "") + case .relative: return NSLocalizedString("相对位置", comment: "") } } var detail: String { switch self { case .absolute: - return "触摸位置直接对应远端屏幕位置,适合快速定位。" + return NSLocalizedString("触摸位置直接对应远端屏幕位置,适合快速定位。", comment: "") case .relative: - return "像触控板一样滑动光标,点击时操作当前光标位置。" + return NSLocalizedString("像触控板一样滑动光标,点击时操作当前光标位置。", comment: "") } } @@ -53,20 +53,20 @@ enum VideoAdaptationPolicy: String, CaseIterable, Identifiable { var title: String { switch self { - case .frameRatePriority: return "帧率优先" - case .qualityPriority: return "画质优先" - case .balanced: return "平衡" + case .frameRatePriority: return NSLocalizedString("帧率优先", comment: "") + case .qualityPriority: return NSLocalizedString("画质优先", comment: "") + case .balanced: return NSLocalizedString("平衡", comment: "") } } var detail: String { switch self { case .frameRatePriority: - return "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" + return NSLocalizedString("优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。", comment: "") case .qualityPriority: - return "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" + return NSLocalizedString("始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。", comment: "") case .balanced: - return "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" + return NSLocalizedString("兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。", comment: "") } } @@ -321,8 +321,8 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe private var privacyTimer: Timer? @Published var remoteID = "" @Published var password = "" - @Published private(set) var signalStatus = "等待隐私授权" - @Published private(set) var connectionStatus = "未连接" + @Published private(set) var signalStatus = NSLocalizedString("等待隐私授权", comment: "") + @Published private(set) var connectionStatus = NSLocalizedString("未连接", comment: "") @Published private(set) var localIdentity = "" @Published private(set) var identityStorageWarning: String? @Published private(set) var isConnecting = false @@ -337,7 +337,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe @Published private(set) var hasRemoteCursorState = false private var networkStatistics = RemoteNetworkStatistics() private var videoFrameID: UInt64 = 0 - @Published private(set) var displays: [String] = ["显示器 1"] + @Published private(set) var displays: [String] = [NSLocalizedString("显示器 1", comment: "")] @Published private(set) var displaySizes: [CGSize] = [] @Published var selectedDisplay = 0 @Published var audioEnabled = true @@ -368,7 +368,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe private var remoteVersionCheckAttempted = false private var remoteVersionCheckGeneration = UUID() private var remoteVersionCheckTask: URLSessionDataTask? - private static let remoteUpdateNotice = "被控端版本过低,请升级到最新版本。" + private static let remoteUpdateNotice = NSLocalizedString("被控端版本过低,请升级到最新版本。", comment: "") private var pendingRememberPassword = false private var connectionRecorded = false private var shouldCaptureThumbnail = false @@ -380,7 +380,8 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe private var videoSettingsTimeoutTask: Task? private var pendingPresenceRemoteID: String? private var presenceProbeGeneration: UInt64 = 0 - private var signalConnected = false + @Published private(set) var signalConnected = false + @Published private(set) var signalHasError = false private var presenceIsForeground = false private var awaitingPresenceSnapshot = true private var presenceUpdatedAt: [String: ContinuousClock.Instant] = [:] @@ -425,7 +426,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe self.audioPlayer.setEnabled(playing && self.audioEnabled) } pictureInPicture.failed = { [weak self] in - self?.controlStatus = "画中画未能开启,请保持应用在前台后重试。" + self?.controlStatus = NSLocalizedString("画中画未能开启,请保持应用在前台后重试。", comment: "") } announcements.send = { [weak bridge] data, requestID in bridge?.sendAnnouncementRequest(data, requestID: requestID) @@ -498,7 +499,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe announcements.reset() bridgeConfiguration = nil localIdentity = "" - signalStatus = "等待隐私授权" + signalStatus = NSLocalizedString("等待隐私授权", comment: ""); signalHasError = false savesConnectionThumbnails = false clearConnectionThumbnails() } @@ -526,7 +527,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe self.thumbnailCleanupInProgress = false self.thumbnailCleanupError = success ? nil - : "部分预览图未能清除,请重试。" + : NSLocalizedString("部分预览图未能清除,请重试。", comment: "") } } @@ -542,14 +543,14 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe @discardableResult func configureBridge() -> Bool { guard hasNetworkConsent else { - signalStatus = "等待隐私授权" + signalStatus = NSLocalizedString("等待隐私授权", comment: ""); signalHasError = false return false } let host = signalHost.trimmingCharacters(in: .whitespacesAndNewlines) guard let signal = Int(signalPort), (1...65535).contains(signal), !host.isEmpty else { - signalStatus = "服务器配置无效" + signalStatus = NSLocalizedString("服务器配置无效", comment: ""); signalHasError = true return false } let configuration = BridgeConfiguration(host: host, signalPort: signal) @@ -558,12 +559,12 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe signalConnected = false localIdentity = "" announcements.reset() - signalStatus = "正在连接信令服务" + signalStatus = NSLocalizedString("正在连接信令服务", comment: ""); signalHasError = false stopPresenceMonitoring() invalidatePresence() cancelPendingPresenceConnection() } else if signalConnected { - signalStatus = "已连接服务器" + signalStatus = NSLocalizedString("已连接服务器", comment: ""); signalHasError = false } bridge.setVideoAdaptationPolicy(videoAdaptationPolicy.bridgeValue) bridge.configure(withSignalHost: host, @@ -585,7 +586,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe connectionFailureMessage = nil let identifier = remoteID.trimmingCharacters(in: .whitespacesAndNewlines) guard !identifier.isEmpty else { - connectionStatus = "请输入远程设备 ID" + connectionStatus = NSLocalizedString("请输入远程设备 ID", comment: "") return } remoteID = identifier @@ -616,7 +617,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe isConnected = false sessionVisible = false resetRemoteCursorState() - connectionStatus = "正在准备连接…" + connectionStatus = NSLocalizedString("正在准备连接…", comment: "") bridge.connect(toRemoteID: identifier, password: password) } @@ -632,7 +633,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe isConnecting = true isConnected = false sessionVisible = false - connectionStatus = "正在确认设备状态…" + connectionStatus = NSLocalizedString("正在确认设备状态…", comment: "") requestPresenceProbe(identifier) DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [weak self] in @@ -656,7 +657,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe guard pendingPresenceRemoteID != nil else { return } cancelPresenceProbe() isConnecting = false - connectionStatus = "未连接" + connectionStatus = NSLocalizedString("未连接", comment: "") } private func requestPresenceProbe(_ identifier: String) { @@ -671,7 +672,7 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe isConnecting = false isConnected = false sessionVisible = false - connectionStatus = "设备离线" + connectionStatus = NSLocalizedString("设备离线", comment: "") deviceOfflineAlertVisible = true } @@ -720,10 +721,10 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe resetRemoteCursorState() frameCount = 0 networkStatistics = RemoteNetworkStatistics() - displays = ["显示器 1"] + displays = [NSLocalizedString("显示器 1", comment: "")] displaySizes = [] selectedDisplay = 0 - connectionStatus = "未连接" + connectionStatus = NSLocalizedString("未连接", comment: "") audioPlayer.endSession() AppOrientation.endSession() appUpdates.checkNow() @@ -1006,9 +1007,9 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe var videoSettingsFeedback: String { if !canChangeVideoSettings { - return "连接建立后可调整,需被控端支持。" + return NSLocalizedString("连接建立后可调整,需被控端支持。", comment: "") } - if videoSettings.failed { return "调整失败,请重试。" } + if videoSettings.failed { return NSLocalizedString("调整失败,请重试。", comment: "") } return "" } @@ -1077,20 +1078,20 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe func sendClipboard() { guard hasNetworkConsent, isConnected else { return } guard let text = UIPasteboard.general.string, !text.isEmpty else { - clipboardStatus = "剪贴板中没有文本" + clipboardStatus = NSLocalizedString("剪贴板中没有文本", comment: "") return } guard text.lengthOfBytes(using: .utf8) <= 128 * 1024 else { - clipboardStatus = "剪贴板文本超过 128 KiB" + clipboardStatus = NSLocalizedString("剪贴板文本超过 128 KiB", comment: "") return } bridge.sendClipboardText(text) - clipboardStatus = "已发送本机剪贴板" + clipboardStatus = NSLocalizedString("已发送本机剪贴板", comment: "") } func sendFile(_ url: URL) { guard hasNetworkConsent, isConnected else { return } - transferStatus = "正在发送 \(url.lastPathComponent)" + transferStatus = String(format: NSLocalizedString("正在发送 %1$@", comment: ""), String(describing: url.lastPathComponent)) transferProgress = 0 bridge.sendFile(at: url) } @@ -1129,15 +1130,15 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe func sendSecureAttention() { guard hasNetworkConsent, isConnected, remotePlatform == .windows else { return } guard remoteServiceAvailable else { - controlStatus = "Ctrl+Alt+Del 需要远端启用 Windows 系统服务" + controlStatus = NSLocalizedString("Ctrl+Alt+Del 需要远端启用 Windows 系统服务", comment: "") return } bridge.sendSecureAttentionSequence() - controlStatus = "正在发送 Ctrl+Alt+Del…" + controlStatus = NSLocalizedString("正在发送 Ctrl+Alt+Del…", comment: "") } func fileImportFailed() { - transferStatus = "无法读取所选文件,请重试" + transferStatus = NSLocalizedString("无法读取所选文件,请重试", comment: "") transferProgress = 0 } @@ -1146,14 +1147,14 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe func sendSystemTextEdit(deleting count: Int, inserting text: String) -> Bool { guard hasNetworkConsent, isConnected else { return false } guard (0...16 * 1024).contains(count), text.utf8.count <= 16 * 1024, !text.unicodeScalars.contains(where: { $0.value == 0 }) else { - keyboardInputStatus = "单次输入最多 16 KiB,且不能包含空字符" + keyboardInputStatus = NSLocalizedString("单次输入最多 16 KiB,且不能包含空字符", comment: "") return false } let isASCII = text.unicodeScalars.allSatisfy({ (0x20...0x7e).contains($0.value) || [9, 10, 13].contains($0.value) }) guard supportsTextInput || isASCII else { - keyboardInputStatus = "被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" + keyboardInputStatus = NSLocalizedString("被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴", comment: "") return false } for _ in 0.. 0 { - return "视频 \(Int(frameSize.width))×\(Int(frameSize.height)) · \(frameCount) 帧" + return String(format: NSLocalizedString("视频 %1$@×%2$@ · %3$@ 帧", comment: ""), String(describing: Int(frameSize.width)), String(describing: Int(frameSize.height)), String(describing: frameCount)) } - return isConnected ? "正在取回远程画面…" : "等待连接" + return isConnected ? NSLocalizedString("正在取回远程画面…", comment: "") : NSLocalizedString("等待连接", comment: "") } } diff --git a/apps/ios/CrossDeskMobile/RemoteSessionView.swift b/apps/ios/CrossDeskMobile/RemoteSessionView.swift index 0540f5be..55bc2a0f 100644 --- a/apps/ios/CrossDeskMobile/RemoteSessionView.swift +++ b/apps/ios/CrossDeskMobile/RemoteSessionView.swift @@ -189,11 +189,11 @@ struct RemoteSessionView: View { .zIndex(50) } } - .alert("升级提示", isPresented: Binding( + .alert(NSLocalizedString("升级提示", comment: ""), isPresented: Binding( get: { !session.privacyScreen.unlockNotice && session.remoteUpdateMessage != nil }, set: { if !$0 && !session.privacyScreen.unlockNotice { session.dismissRemoteUpdate() } } )) { - Button("知道了", role: .cancel) { session.dismissRemoteUpdate() } + Button(NSLocalizedString("知道了", comment: ""), role: .cancel) { session.dismissRemoteUpdate() } } message: { Text(session.remoteUpdateMessage ?? "") } @@ -282,18 +282,18 @@ struct RemoteSessionView: View { Color.black.opacity(0.28).ignoresSafeArea().contentShape(Rectangle()).onTapGesture { } VStack(spacing: 0) { VStack(spacing: 12) { - Text("隐私屏已被解锁").font(.headline) - Text("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。") + Text(NSLocalizedString("隐私屏已被解锁", comment: "")).font(.headline) + Text(NSLocalizedString("被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", comment: "")) .font(.subheadline).foregroundStyle(.secondary) let feedback = session.privacyScreen.feedback(at: session.privacyClock) if !feedback.isEmpty { Text(feedback).font(.caption).foregroundStyle(.secondary) } }.padding(24) Divider() HStack(spacing: 0) { - Button("确认") { session.privacyScreen.unlockNotice = false } + Button(NSLocalizedString("确认", comment: "")) { session.privacyScreen.unlockNotice = false } .frame(maxWidth: .infinity, minHeight: 48) Divider().frame(height: 48) - Button("锁定") { session.lockPrivacyScreen() } + Button(NSLocalizedString("锁定", comment: "")) { session.lockPrivacyScreen() } .fontWeight(.semibold).frame(maxWidth: .infinity, minHeight: 48) .disabled(!session.privacyScreen.canLock(at: session.privacyClock)) } @@ -320,11 +320,11 @@ struct RemoteSessionView: View { VStack(spacing: 0) { VStack(spacing: 4) { - Text("断开远程连接?") + Text(NSLocalizedString("断开远程连接?", comment: "")) .font(.headline) .foregroundStyle(Color.black.opacity(0.9)) - Text("断开后将返回首页") + Text(NSLocalizedString("断开后将返回首页", comment: "")) .font(.subheadline) .foregroundStyle(Color.black.opacity(0.55)) } @@ -337,7 +337,7 @@ struct RemoteSessionView: View { disconnectConfirmationVisible = false session.disconnect() } label: { - Text("断开连接") + Text(NSLocalizedString("断开连接", comment: "")) .font(.body.weight(.semibold)) .foregroundStyle(Color.red) .frame(maxWidth: .infinity) @@ -351,7 +351,7 @@ struct RemoteSessionView: View { disconnectConfirmationVisible = false } } label: { - Text("取消") + Text(NSLocalizedString("取消", comment: "")) .font(.body.weight(.semibold)) .foregroundStyle(Color.blue) .frame(maxWidth: .infinity) @@ -765,8 +765,8 @@ private struct RemoteComputerKey { if let title { return title.replacingOccurrences(of: "\n", with: " ") } switch symbol { case "shift": return "Shift" - case "delete.left": return "退格" - default: return "键盘操作" + case "delete.left": return NSLocalizedString("退格", comment: "") + default: return NSLocalizedString("键盘操作", comment: "") } } @@ -842,27 +842,27 @@ private struct RemoteComputerKeyboard: View { .init("Ctrl", 0x11, isModifier: true), .init("Win", 0x5B, isModifier: true), .init("Alt", 0x12, isModifier: true), - .init("空格", 0x20, width: 2.6), - .init("回车", 0x0D, width: 1.4, style: .special) + .init(NSLocalizedString("空格", comment: ""), 0x20, width: 2.6), + .init(NSLocalizedString("回车", comment: ""), 0x0D, width: 1.4, style: .special) ] var body: some View { VStack(spacing: 0) { HStack(spacing: 4) { - Button("系统键盘") { + Button(NSLocalizedString("系统键盘", comment: "")) { feedback.keyPressed() releaseModifiers() switchKeyboard() } .font(.system(size: 15, weight: .medium)) .frame(width: 80, height: 44) - .accessibilityLabel("切换到系统键盘") + .accessibilityLabel(NSLocalizedString("切换到系统键盘", comment: "")) if verticalSizeClass == .compact { pageTabs } else { Spacer(minLength: 0) } - RemoteKeyboardDismissButton(accessibilityLabel: "收起电脑键盘") { + RemoteKeyboardDismissButton(accessibilityLabel: NSLocalizedString("收起电脑键盘", comment: "")) { feedback.keyPressed() releaseModifiers() dismiss() @@ -943,14 +943,14 @@ private struct RemoteComputerKeyboard: View { feedback.keyPressed() page = item } label: { - Text(item.rawValue) + Text(NSLocalizedString(item.rawValue, comment: "")) .font(.system(size: 14, weight: page == item ? .semibold : .regular)) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(page == item ? RemoteKeyboardPalette.specialKey : .clear, in: RoundedRectangle(cornerRadius: 6)) .contentShape(Rectangle()) } - .accessibilityLabel("\(item.rawValue)键盘页") + .accessibilityLabel(String(format: NSLocalizedString("%1$@键盘页", comment: ""), NSLocalizedString(item.rawValue, comment: ""))) .accessibilityAddTraits(page == item ? .isSelected : []) } } @@ -1066,7 +1066,7 @@ private struct CrossDeskStatusOrb: View { lineWidth: isExpanded ? 2 : 1) } .compositingGroup() - .accessibilityLabel(isExpanded ? "收起远程控制菜单" : "展开远程控制菜单") + .accessibilityLabel(isExpanded ? NSLocalizedString("收起远程控制菜单", comment: "") : NSLocalizedString("展开远程控制菜单", comment: "")) } } @@ -1194,8 +1194,8 @@ private struct FloatingSessionMenu: View { .frame(width: 28, height: 32) } .buttonStyle(.plain) - .accessibilityLabel("返回控制栏") - Text(page == .videoSettings ? "画面设置" : "网络状态") + .accessibilityLabel(NSLocalizedString("返回控制栏", comment: "")) + Text(page == .videoSettings ? NSLocalizedString("画面设置", comment: "") : NSLocalizedString("网络状态", comment: "")) .font(.subheadline.weight(.semibold)) } else { Circle() @@ -1212,7 +1212,7 @@ private struct FloatingSessionMenu: View { .foregroundStyle(.secondary) } .buttonStyle(.plain) - .accessibilityLabel("关闭控制栏") + .accessibilityLabel(NSLocalizedString("关闭控制栏", comment: "")) } if page == .videoSettings, !session.videoSettingsFeedback.isEmpty { @@ -1232,12 +1232,12 @@ private struct FloatingSessionMenu: View { } else { VStack(spacing: 9) { LazyVGrid(columns: columns, spacing: 7) { - FloatingControlButton(title: "键盘", symbol: "keyboard", + FloatingControlButton(title: NSLocalizedString("键盘", comment: ""), symbol: "keyboard", action: showKeyboard) - FloatingControlButton(title: virtualMouseVisible ? "收起鼠标" : "虚拟鼠标", + FloatingControlButton(title: virtualMouseVisible ? NSLocalizedString("收起鼠标", comment: "") : NSLocalizedString("虚拟鼠标", comment: ""), symbol: "computermouse", action: toggleMouse) FloatingControlButton( - title: session.mouseControlMode == .relative ? "相对鼠标" : "绝对鼠标", + title: session.mouseControlMode == .relative ? NSLocalizedString("相对鼠标", comment: "") : NSLocalizedString("绝对鼠标", comment: ""), symbol: "computermouse", action: { session.mouseControlMode = session.mouseControlMode == .relative @@ -1259,22 +1259,22 @@ private struct FloatingSessionMenu: View { } } } label: { - FloatingControlLabel(title: "显示器", symbol: "display") + FloatingControlLabel(title: NSLocalizedString("显示器", comment: ""), symbol: "display") } .buttonStyle(.plain) - FloatingControlButton(title: "画面设置", symbol: "slider.horizontal.3") { + FloatingControlButton(title: NSLocalizedString("画面设置", comment: ""), symbol: "slider.horizontal.3") { page = .videoSettings } FloatingControlButton( - title: session.audioEnabled ? "声音" : "静音", + title: session.audioEnabled ? NSLocalizedString("声音", comment: "") : NSLocalizedString("静音", comment: ""), symbol: session.audioEnabled ? "speaker.wave.2" : "speaker.slash", action: session.toggleAudio ) - FloatingControlButton(title: "发送文件", + FloatingControlButton(title: NSLocalizedString("发送文件", comment: ""), symbol: "folder.badge.plus", action: chooseFile) - FloatingControlButton(title: "网络状态", symbol: "chart.bar.xaxis") { + FloatingControlButton(title: NSLocalizedString("网络状态", comment: ""), symbol: "chart.bar.xaxis") { page = .networkStats } if session.remotePlatform == .windows { @@ -1282,7 +1282,7 @@ private struct FloatingSessionMenu: View { symbol: "lock.trianglebadge.exclamationmark", action: session.sendSecureAttention) } - FloatingControlButton(title: "剪贴板", symbol: "doc.on.clipboard", + FloatingControlButton(title: NSLocalizedString("剪贴板", comment: ""), symbol: "doc.on.clipboard", action: session.sendClipboard) if session.privacyScreen.desktopAvailable { FloatingControlButton( @@ -1293,9 +1293,9 @@ private struct FloatingSessionMenu: View { ) .disabled(!session.isConnected || !session.privacyScreen.canToggle(at: session.privacyClock)) .opacity(session.isConnected && session.privacyScreen.canToggle(at: session.privacyClock) ? 1 : 0.45) - .accessibilityLabel("隐私屏") + .accessibilityLabel(NSLocalizedString("隐私屏", comment: "")) .accessibilityValue(session.privacyScreen.status(at: session.privacyClock)) - .accessibilityHint(session.privacyScreen.active ? "关闭隐私屏" : "开启隐私屏") + .accessibilityHint(session.privacyScreen.active ? NSLocalizedString("关闭隐私屏", comment: "") : NSLocalizedString("开启隐私屏", comment: "")) } } @@ -1335,7 +1335,7 @@ private struct FloatingSessionMenu: View { private var disconnectButton: some View { Button(role: .destructive, action: disconnect) { - Text("断开连接") + Text(NSLocalizedString("断开连接", comment: "")) .font(.subheadline.weight(.semibold)) .frame(maxWidth: .infinity) .frame(height: 34) @@ -1393,12 +1393,12 @@ private struct FloatingNetworkStatistics: View { var body: some View { VStack(spacing: 10) { VStack(spacing: 0) { - trafficRow("", inbound: "接收", outbound: "发送", loss: "丢包率") + trafficRow("", inbound: NSLocalizedString("接收", comment: ""), outbound: NSLocalizedString("发送", comment: ""), loss: NSLocalizedString("丢包率", comment: "")) .foregroundStyle(.secondary) - trafficRow("视频", statistics: snapshot.report?.video) - trafficRow("音频", statistics: snapshot.report?.audio) - trafficRow("数据", statistics: snapshot.report?.data) - trafficRow("合计", statistics: snapshot.report?.total) + trafficRow(NSLocalizedString("视频", comment: ""), statistics: snapshot.report?.video) + trafficRow(NSLocalizedString("音频", comment: ""), statistics: snapshot.report?.audio) + trafficRow(NSLocalizedString("数据", comment: ""), statistics: snapshot.report?.data) + trafficRow(NSLocalizedString("合计", comment: ""), statistics: snapshot.report?.total) .fontWeight(.semibold) .background(Color.blue.opacity(0.07), in: RoundedRectangle(cornerRadius: 5)) } @@ -1407,17 +1407,17 @@ private struct FloatingNetworkStatistics: View { Divider() VStack(spacing: 7) { - detail("帧率", value: "\(snapshot.framesPerSecond) FPS") - detail("分辨率", value: resolution) - detail("画面延时", value: RemoteNetworkSnapshot.latency(snapshot.videoLatencyMilliseconds)) - detail("连接延时(RTT)", value: RemoteNetworkSnapshot.latency(snapshot.rttMilliseconds)) - detail("连接方式", value: snapshot.connectionMode) + detail(NSLocalizedString("帧率", comment: ""), value: "\(snapshot.framesPerSecond) FPS") + detail(NSLocalizedString("分辨率", comment: ""), value: resolution) + detail(NSLocalizedString("画面延时", comment: ""), value: RemoteNetworkSnapshot.latency(snapshot.videoLatencyMilliseconds)) + detail(NSLocalizedString("连接延时(RTT)", comment: ""), value: RemoteNetworkSnapshot.latency(snapshot.rttMilliseconds)) + detail(NSLocalizedString("连接方式", comment: ""), value: snapshot.connectionMode) HStack { - Text("媒体加密") + Text(NSLocalizedString("媒体加密", comment: "")) .foregroundStyle(.secondary) Spacer(minLength: 8) if let report = snapshot.report { - Label(report.srtpActive ? "SRTP 已启用" : "未启用", + Label(report.srtpActive ? NSLocalizedString("SRTP 已启用", comment: "") : NSLocalizedString("未启用", comment: ""), systemImage: report.srtpActive ? "lock.shield" : "lock.open") .foregroundStyle(report.srtpActive ? Color.green : Color.secondary) } else { @@ -1425,8 +1425,8 @@ private struct FloatingNetworkStatistics: View { } } .accessibilityElement(children: .combine) - codec("被控端编码器", value: snapshot.remoteVideoEncoder) - codec("控制端解码器", value: snapshot.localVideoDecoder) + codec(NSLocalizedString("被控端编码器", comment: ""), value: snapshot.remoteVideoEncoder) + codec(NSLocalizedString("控制端解码器", comment: ""), value: snapshot.localVideoDecoder) } .font(.caption.monospacedDigit()) } @@ -1460,13 +1460,13 @@ private struct FloatingNetworkStatistics: View { inbound: RemoteNetworkSnapshot.bitrate(statistics?.inboundBitrate), outbound: RemoteNetworkSnapshot.bitrate(statistics?.outboundBitrate), loss: RemoteNetworkSnapshot.lossRate(statistics?.lossRate)) - .accessibilityLabel("\(title),接收 \(RemoteNetworkSnapshot.bitrate(statistics?.inboundBitrate)),发送 \(RemoteNetworkSnapshot.bitrate(statistics?.outboundBitrate)),丢包率 \(RemoteNetworkSnapshot.lossRate(statistics?.lossRate))") + .accessibilityLabel(String(format: NSLocalizedString("%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@", comment: ""), String(describing: title), String(describing: RemoteNetworkSnapshot.bitrate(statistics?.inboundBitrate)), String(describing: RemoteNetworkSnapshot.bitrate(statistics?.outboundBitrate)), String(describing: RemoteNetworkSnapshot.lossRate(statistics?.lossRate)))) } private func trafficRow(_ title: String, inbound: String, outbound: String, loss: String) -> some View { HStack(spacing: 4) { - Text(title).frame(width: 28, alignment: .leading) + Text(title).frame(width: 48, alignment: .leading) Text(inbound).frame(maxWidth: .infinity, alignment: .trailing) Text(outbound).frame(maxWidth: .infinity, alignment: .trailing) Text(loss).frame(width: 46, alignment: .trailing) @@ -1484,17 +1484,17 @@ private struct FloatingVideoSettings: View { var body: some View { VStack(alignment: .leading, spacing: 12) { - settingRow("画面质量", options: ["低", "中", "高"], + settingRow(NSLocalizedString("画面质量", comment: ""), options: [NSLocalizedString("低", comment: ""), NSLocalizedString("中", comment: ""), NSLocalizedString("高", comment: "")], values: [0, 1, 2], selection: Binding( get: { session.videoSettings.selection.quality }, set: { session.updateVideoSettings(quality: $0) } )) - settingRow("画面采集帧率", options: ["30 fps", "60 fps"], + settingRow(NSLocalizedString("画面采集帧率", comment: ""), options: ["30 fps", "60 fps"], values: [30, 60], selection: Binding( get: { session.videoSettings.selection.frameRate }, set: { session.updateVideoSettings(frameRate: $0) } )) - settingRow("画面偏好", options: VideoAdaptationPolicy.allCases.map(\.title), + settingRow(NSLocalizedString("画面偏好", comment: ""), options: VideoAdaptationPolicy.allCases.map(\.title), values: VideoAdaptationPolicy.allCases.map { $0.bridgeValue.rawValue }, selection: Binding( get: { session.videoSettings.selection.preference }, @@ -1546,7 +1546,8 @@ private struct FloatingControlLabel: View { .font(.system(size: 16, weight: .semibold)) Text(title) .font(.system(size: 9.5, weight: .medium)) - .lineLimit(1) + .lineLimit(2) + .multilineTextAlignment(.center) .minimumScaleFactor(0.72) } .foregroundStyle(.primary) diff --git a/apps/ios/CrossDeskMobile/Resources/de.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/de.lproj/InfoPlist.strings new file mode 100644 index 00000000..fb2cb0e4 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/de.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk nutzt das lokale Netzwerk, um native P2P-Fernsteuerungsverbindungen zu erkennen und aufzubauen."; diff --git a/apps/ios/CrossDeskMobile/Resources/de.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/de.lproj/Localizable.strings new file mode 100644 index 00000000..8c849277 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/de.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "%1$@-Übertragung fehlgeschlagen"; +"%1$@ 台设备" = "Geräte: %1$@"; +"%1$@ 条未读" = "%1$@ ungelesene Elemente"; +"%1$@键盘页" = "%1$@ Tastaturseite"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, Empfangen von %2$@, Senden von %3$@, Paketverlustrate %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk nutzt das lokale Netzwerk, um native P2P-Fernsteuerungsverbindungen zu erkennen und aufzubauen."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del erfordert eine Remote-Aktivierung der Windows-Systemdienste"; +"GNU GPL 第 3 版" = "GNU GPL Version 3"; +"OpenFEC 告知" = "OpenFEC-Hinweis"; +"OpenFEC 许可与源码" = "OpenFEC Lizenz und Quelle"; +"P2P 直连" = "P2P-Direktverbindung"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN Verbindungsaufbau fehlgeschlagen, bitte überprüfen Sie das Netzwerk und versuchen Sie es erneut."; +"SRTP 已启用" = "SRTP enabled"; +"TLS 证书校验失败" = "Die Überprüfung des TLS-Zertifikats ist fehlgeschlagen"; +"TURN 中继" = "TURN-Relais"; +"上下滑动,可滑出按键范围" = "Nach oben und unten schieben, um aus dem Tastenbereich herauszurutschen"; +"丢包率" = "Verlustrate"; +"中" = "Mittel"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "Priorisiert die Aufrechterhaltung eines flüssigen Bildes und reduziert die Auflösung stärker, wenn die Bandbreite oder der Codierungsdruck hoch ist."; +"低" = "Niedrig"; +"使用自定义服务器" = "Verwendung eines benutzerdefinierten Servers"; +"保存密码" = "Passwort speichern"; +"保存远程画面预览" = "Remote-Bildschirmvorschauen speichern"; +"保存远程画面预览?" = "Remote-Bildschirmvorschau speichern?"; +"信令服务器已关闭连接" = "Der Signalisierungsserver hat die Verbindung geschlossen"; +"信令服务重连中" = "Signalisierungsdienst stellt erneut Verbindung her"; +"信令连接失败" = "Signalverbindung fehlgeschlagen"; +"信令连接已关闭" = "Signalverbindung geschlossen"; +"偏好模式" = "Präferenzmodus"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "Bewegen Sie den Cursor wie ein Trackpad und bedienen Sie die aktuelle Cursorposition, wenn Sie darauf klicken."; +"公告加载失败,请重试。" = "Das Laden der Ankündigung ist fehlgeschlagen. Bitte versuchen Sie es erneut."; +"公告详情" = "Einzelheiten zur Ankündigung"; +"共 %1$@ 条 · %2$@ 条未读" = "Insgesamt %1$@ Artikel ·%2$@ ungelesene Artikel"; +"关于" = "Ungefähr"; +"关于 CrossDesk" = "Über CrossDesk"; +"关于,有新版本" = "Ungefähr, es gibt eine neue Version"; +"关闭" = "Schließen"; +"关闭控制栏" = "Bedienbügel schließen"; +"关闭隐私屏" = "Privatsphäre-Bildschirm deaktivieren"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "Gleicht Klarheit und Glätte aus und verringert die Auflösung bei konstantem Druck nur allmählich."; +"分辨率" = "Auflösung"; +"切换到电脑键盘" = "Zur Computertastatur wechseln"; +"切换到系统键盘" = "Zur Systemtastatur wechseln"; +"删除" = "Löschen"; +"删除公告" = "Ansage löschen"; +"删除记录" = "Datensatz löschen"; +"删除这条公告?" = "Diese Ankündigung löschen?"; +"刷新公告" = "Ankündigung aktualisieren"; +"剪贴板" = "Zwischenablage"; +"剪贴板中没有文本" = "Kein Text in der Zwischenablage"; +"剪贴板文本超过 128 KiB" = "Der Text in der Zwischenablage ist größer als 128 KiB"; +"加载中…" = "Laden…"; +"加载更多" = "Mehr laden"; +"升级提示" = "Update empfohlen"; +"单次输入最多 16 KiB,且不能包含空字符" = "Eine einzelne Eingabe kann bis zu 16 KiB groß sein und darf keine Nullzeichen enthalten"; +"发送" = "Senden"; +"发送文件" = "Datei senden"; +"取消" = "Abbrechen"; +"取消连接" = "Verbindung abbrechen"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "Jede Komponente unterliegt der aufgeführten Open-Source-Lizenz und die gewährten Rechte unterliegen nicht den allgemeinen Nutzungsbedingungen dieser Anwendung. Für die Anzeige des Quellcodes ist eine Internetverbindung erforderlich."; +"合计" = "Insgesamt"; +"同意并继续" = "Zustimmen und fortfahren"; +"回车" = "Treten Sie ein"; +"在线" = "Online"; +"地址" = "Adresse"; +"填写服务器地址" = "Geben Sie die Serveradresse ein"; +"填写端口" = "Füllen Sie den Port aus"; +"声音" = "Ton"; +"失败" = "Fehlgeschlagen"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "Behalten Sie immer eine höhere Auflösung bei und reduzieren Sie die Bildrate, um die Bildschärfe zu gewährleisten, wenn die Bandbreite nicht ausreicht."; +"媒体加密" = "Medienverschlüsselung"; +"字母数字" = "Buchstaben & Zahlen"; +"完成" = "Fertig"; +"完成隐私授权后可检查更新" = "Sie können nach Abschluss der Datenschutzautorisierung nach Updates suchen"; +"完成隐私授权后登记本机身份" = "Registrieren Sie die lokale Identität, nachdem Sie die Datenschutzautorisierung abgeschlossen haben"; +"密码将安全保存在本机 Keychain 中" = "Passwörter werden sicher im lokalen Schlüsselbund gespeichert"; +"对端 ID" = "Remote-ID"; +"对端 ID %1$@" = "Peer-ID %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "Stoppt die Remote-Verbindung, schließt die Bildschirmvorschau, speichert sie und löscht die vorhandene Vorschau. Verbindungsdatensätze und empfangene Dateien bleiben erhalten und vorhandene Serverdaten werden nicht gelöscht. Sie können sich jederzeit erneut autorisieren."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "Alle auf diesem Computer gespeicherten Remote-Vorschauen werden gelöscht, während Verbindungsdatensätze, Passwörter und empfangene Dateien erhalten bleiben."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "Alle auf diesem Computer gespeicherten Remote-Vorschauen werden gelöscht, während Verbindungsdatensätze, Passwörter und empfangene Dateien erhalten bleiben. Bei späteren Verbindungen werden weiterhin neue Vorschauen gespeichert."; +"屏幕方向" = "Bildschirmausrichtung"; +"展开远程控制菜单" = "Fernbedienungsmenü erweitern"; +"已保存密码" = "Passwort gespeichert"; +"已勾选" = "Geprüft"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del gesendet"; +"已发送本机剪贴板" = "Lokale Zwischenablage gesendet"; +"已授权" = "Zugegeben"; +"已接收 %1$@" = "%1$@ erhalten"; +"已接收远端剪贴板" = "Remote-Zwischenablage empfangen"; +"已读" = "Lesen"; +"已连接" = "Verbunden"; +"已连接服务器" = "Mit Server verbunden"; +"帧率" = "Bildrate"; +"帧率优先" = "Flüssig"; +"平衡" = "Balance"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "Die Lizenzdatei in der Anwendung fehlt oder ist beschädigt. Bitte installieren Sie die Anwendung neu."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "Die Entwicklungsversion enthält Änderungen, die noch nicht veröffentlicht wurden. Der folgende Link ist der Quellcode der Basisversion."; +"开启保存" = "Speichern aktivieren"; +"开启隐私屏" = "Privatsphärenschutz aktivieren"; +"开源组件" = "Open-Source-Komponenten"; +"开源软件权利说明" = "Beschreibung der Open-Source-Softwarerechte"; +"当前已是最新版本" = "Dies ist derzeit die neueste Version"; +"成功连接后,这里会显示远端桌面的缩略图。" = "Nach erfolgreicher Verbindung wird hier eine Miniaturansicht des Remote-Desktops angezeigt."; +"我已阅读并同意《隐私政策》" = "Ich habe die Datenschutzerklärung gelesen und bin damit einverstanden"; +"我已阅读并同意隐私政策" = "Ich habe die Datenschutzbestimmungen gelesen und stimme ihnen zu"; +"打开隐私政策" = "Datenschutzerklärung öffnen"; +"指令发送失败,请重试" = "Das Senden des Befehls ist fehlgeschlagen. Bitte versuchen Sie es erneut"; +"指令已发送,等待电脑确认…" = "Der Befehl wurde gesendet und wartet auf die Bestätigung des Computers ..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "Drücken und ziehen Sie, um aus dem Tastenbereich zu gleiten, und lassen Sie los, um das Ziehen zu beenden"; +"授权后可使用远程连接。" = "Remote-Verbindungen sind nach Autorisierung verfügbar."; +"授权状态" = "Autorisierungsstatus"; +"接收" = "Empfangen"; +"控制模式" = "Steuermodus"; +"控制端解码器" = "Lokaler Decoder"; +"撤回授权" = "Autorisierung entziehen"; +"撤回隐私授权" = "Datenschutzberechtigung entziehen"; +"收起电脑键盘" = "PC-Tastatur ausblenden"; +"收起系统键盘" = "Systemtastatur einklappen"; +"收起远程控制菜单" = "Fernbedienungsmenü einklappen"; +"收起鼠标" = "Maus ausblenden"; +"数据" = "Daten"; +"断开后将返回首页" = "Kehrt nach dem Trennen der Verbindung zur Startseite zurück"; +"断开远程连接?" = "Remote-Verbindung trennen?"; +"断开连接" = "Trennen"; +"新版本" = "Neue Version"; +"新版本可用:v%1$@" = "Neue Version verfügbar: v%1$@"; +"无效" = "Ungültig"; +"无未读公告" = "Keine ungelesenen Ankündigungen"; +"无法" = "Unfähig"; +"无法保存本地阅读状态,请重试。" = "Lesestatus kann nicht lokal gespeichert werden. Bitte versuchen Sie es erneut."; +"无法删除这条公告,请重试。" = "Diese Ankündigung kann nicht gelöscht werden. Bitte versuchen Sie es erneut."; +"无法访问本机登录凭据,请解锁后重试" = "Der Zugriff auf die lokalen Anmeldedaten ist nicht möglich. Bitte entsperren Sie die Sperre und versuchen Sie es erneut"; +"无法读取开源许可" = "Open-Source-Lizenz kann nicht gelesen werden"; +"无法读取所选文件,请重试" = "Die ausgewählte Datei konnte nicht gelesen werden. Bitte versuchen Sie es erneut"; +"是否撤回隐私授权?" = "Datenschutzberechtigung entziehen?"; +"显示器" = "Bildschirm"; +"显示器 %1$@" = "Monitor %1$@"; +"显示器 1" = "Monitor 1"; +"显示密码" = "Passwort anzeigen"; +"暂不同意" = "Jetzt nicht"; +"暂无公告" = "Keine Ankündigungen"; +"最近连接" = "Letzte Verbindungen"; +"服务器" = "Server"; +"服务器地址" = "Serveradresse"; +"服务器端口" = "Server-Port"; +"服务器配置无效" = "Ungültige Serverkonfiguration"; +"未勾选" = "Nicht überprüft"; +"未启用" = "Nicht aktiviert"; +"未授权" = "Nicht autorisiert"; +"未知" = "Unbekannt"; +"未知信令状态" = "Unbekannter Signalisierungsstatus"; +"未知连接状态" = "Unbekannter Verbindungsstatus"; +"未读" = "Ungelesen"; +"未连接" = "Nicht verbunden"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "Diese Anwendung verwendet OpenFEC zur Vorwärtsfehlerkorrektur unterCeCILL-C1.0, was eingeschränkte Garantien und Haftungsbeschränkungen bietet. Einzelheiten finden Sie in der vollständigen Lizenz."; +"本机 ID %1$@" = "Lokale ID %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "Die Anmeldeinformationen für diesen Computer sind vorübergehend unsicher. Bitte entsperren Sie Ihr Gerät und klicken Sie in den Einstellungen auf „Übernehmen“, um es erneut zu versuchen."; +"本版本源码与构建说明" = "Quellcode und Build-Anweisungen für diese Version"; +"本版本源码信息暂不可用。" = "Die Quellrevision ist für diesen Build nicht verfügbar."; +"构建说明" = "Bauanleitung"; +"构建配方与项目补丁" = "Erstellen Sie Rezepte und Projekt-Patches"; +"查看源码" = "Quellcode anzeigen"; +"检查失败,请稍后重试" = "Prüfung fehlgeschlagen. Bitte versuchen Sie es später noch einmal."; +"检查更新" = "Suchen Sie nach Updates"; +"正在关闭隐私屏…" = "Sichtschutz wird geschlossen…"; +"正在准备连接…" = "Verbindung wird vorbereitet..."; +"正在发送 %1$@" = "Senden von %1$@"; +"正在发送 Ctrl+Alt+Del…" = "Senden von Ctrl+Alt+Del…"; +"正在取回远程画面…" = "Remote-Bildschirm abrufen..."; +"正在建立远程连接" = "Remote-Verbindung aufbauen"; +"正在开启隐私屏…" = "Privatsphärenschutz einschalten..."; +"正在收集 ICE 候选" = "Sammeln von ICE-Kandidaten"; +"正在检查更新…" = "Suche nach Updates…"; +"正在清除…" = "Löschen..."; +"正在确认设备状态…" = "Gerätestatus bestätigen..."; +"正在获取本机 ID…" = "Lokale ID erhalten..."; +"正在连接" = "Verbinden"; +"正在连接信令服务" = "Verbindung zum Signalisierungsdienst herstellen"; +"清除" = "Klar"; +"清除预览图" = "Vorschaubilder löschen"; +"清除预览图?" = "Vorschaubilder löschen?"; +"源码与构建说明" = "Quellcode und Build-Anweisungen"; +"源码版本" = "Quellcode-Version"; +"版本" = "Version"; +"版权与许可声明" = "Urheberrechts- und Lizenzerklärung"; +"电脑键盘" = "Computertastatur"; +"画中画未能开启,请保持应用在前台后重试。" = "Bild-in-Bild konnte nicht geöffnet werden. Bitte lassen Sie die Anwendung im Vordergrund und versuchen Sie es erneut."; +"画质优先" = "Qualität"; +"画面偏好" = "Videopräferenz"; +"画面延时" = "Videolatenz"; +"画面设置" = "Videoeinstellungen"; +"画面质量" = "Videoqualität"; +"画面采集帧率" = "Bildrate der Videoaufnahme"; +"相对位置" = "Touchpad"; +"相对鼠标" = "Relative Maus"; +"知道了" = "Verstanden"; +"确定" = "Okay"; +"确认" = "Bestätigen"; +"离线" = "Offline"; +"空格" = "Leertaste"; +"端口" = "Hafen"; +"符号功能" = "Symbole & Tasten"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "Warten Sie, bis der Computer in den Datenschutzstatus zurückkehrt. Ältere Computer unterstützen dies möglicherweise nicht."; +"等待连接" = "Warten auf Verbindung"; +"等待隐私授权" = "Datenschutzzustimmung ausstehend"; +"系统键盘" = "Systemtastatur"; +"绝对位置" = "Direkte Berührung"; +"绝对鼠标" = "Absolute Maus"; +"网络状态" = "Netzwerk"; +"网络连接已中断,请重新连接。" = "Die Netzwerkverbindung wurde unterbrochen. Bitte stellen Sie die Verbindung wieder her."; +"自定义" = "Benutzerdefiniert"; +"虚拟鼠标" = "Virtuelle Maus"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "Das gesteuerte Terminal unterstützt keine direkte Eingabe von Chinesisch. Bitte aktualisieren Sie das von macOS gesteuerte Terminal. Sie können den Text auch zunächst kopieren, über die Zwischenablage des Fernbedienungsmenüs senden und dann einfügen"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "Der Remote-Datenschutzbildschirm wurde über die lokale Verknüpfung entsperrt. Sperren Sie es erneut, um die Privatsphäre wiederherzustellen und das Entsperren lokaler Verknüpfungen zu deaktivieren."; +"被控端平台:%1$@" = "Kontrollierte Terminalplattform:%1$@"; +"被控端版本过低,请升级到最新版本。" = "Die kontrollierte Version ist zu niedrig, bitte aktualisieren Sie auf die neueste Version."; +"被控端编码器" = "Remote-Encoder"; +"视频" = "Video"; +"视频 %1$@×%2$@ · %3$@ 帧" = "Video %1$@×%2$@·%3$@-Frames"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "Die Berührungsposition entspricht direkt der Remote-Bildschirmposition, die für eine schnelle Positionierung geeignet ist."; +"许可" = "Lizenz"; +"许可与版权声明" = "Lizenzen und Urheberrechtshinweise"; +"许可与版权声明可离线查阅。" = "Die Lizenz- und Urheberrechtshinweise sind offline verfügbar."; +"设备离线" = "Gerät offline"; +"设置" = "Einstellungen"; +"设置,有新版本" = "Einstellungen, es gibt eine neue Version"; +"访问密码" = "Zugangspasswort"; +"访问密码错误,请重新输入。" = "Das Zugangspasswort ist falsch, bitte geben Sie es erneut ein."; +"请求超时,尚未确认电脑的隐私屏状态" = "Die Anfrage ist abgelaufen und der Datenschutzstatus des Computers wurde nicht bestätigt."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "Bitte geben Sie einen Port im Bereich 1–65535 ein oder deaktivieren Sie „Benutzerdefinierten Server verwenden“."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "Bitte geben Sie die Serveradresse ein oder deaktivieren Sie „Benutzerdefinierten Server verwenden“."; +"请输入远程设备 ID" = "Bitte geben Sie die Remote-Geräte-ID ein"; +"调整失败,请重试。" = "Einstellungen konnten nicht angewendet werden. Versuchen Sie es erneut."; +"软件许可" = "Softwarelizenz"; +"返回控制栏" = "Zurück zur Steuerleiste"; +"还没有连接记录" = "Noch kein Verbindungsdatensatz"; +"这条公告已更新或删除,请返回公告列表查看。" = "Diese Ankündigung wurde aktualisiert oder gelöscht. Bitte kehren Sie zur Ankündigungsliste zurück, um sie anzuzeigen."; +"远程桌面" = "Remotedesktop"; +"远程设备 ID 不存在,请检查设备 ID。" = "Remote-Geräte-ID existiert nicht, bitte überprüfen Sie die Geräte-ID."; +"远程设备当前不可用,请稍后重试。" = "Das Remote-Gerät ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut."; +"远程连接已结束。" = "Remote-Verbindung beendet."; +"连接" = "Verbinden"; +"连接延时(RTT)" = "Verbindungsverzögerung (RTT)"; +"连接建立后可调整,需被控端支持。" = "Verfügbar bei Verbindung mit einem unterstützten Remote-Gerät."; +"连接建立后锁定横屏" = "Querformatbildschirm sperren, nachdem die Verbindung hergestellt wurde"; +"连接提示" = "Verbindungsaufforderung"; +"连接方式" = "Verbindungsmethode"; +"连接远程桌面" = "Mit Remote-Desktop verbinden"; +"退格" = "Rücktaste"; +"通知公告" = "Mitteilungen"; +"部分预览图未能清除,请重试。" = "Einige Vorschauen konnten nicht gelöscht werden. Bitte versuchen Sie es erneut."; +"重试" = "Versuchen Sie es erneut"; +"重试保存阅读状态" = "Versuchen Sie erneut, den Lesestatus zu speichern"; +"锁定" = "Sperren"; +"键盘" = "Tastatur"; +"键盘操作" = "Tastaturbedienung"; +"阅读并授权" = "Lesen und autorisieren"; +"隐私" = "Datenschutz"; +"隐私与授权" = "Datenschutz und Autorisierung"; +"隐私屏" = "Sichtschutz"; +"隐私屏已关闭" = "Sichtschutz aus"; +"隐私屏已开启" = "Sichtschutz an"; +"隐私屏已被解锁" = "Datenschutzbildschirm entsperrt"; +"隐私屏异常" = "Anomalie des Sichtschutzbildschirms"; +"隐私屏暂不可用" = "Der Datenschutzbildschirm ist vorübergehend nicht verfügbar"; +"隐私屏状态已过期,等待电脑确认" = "Der Status des Datenschutzbildschirms ist abgelaufen und wartet auf Computerbestätigung"; +"隐私屏状态待确认" = "Status des Datenschutzbildschirms muss bestätigt werden"; +"隐私政策" = "Datenschutzrichtlinie"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "Die Datenschutzerklärung kann vorübergehend nicht gelesen werden. Bitte verweigern Sie die Verbindung zum Internet und installieren Sie die Anwendung neu."; +"隐藏密码" = "Passwort verbergen"; +"静音" = "Stumm"; +"音频" = "Audio"; +"项目主页" = "Projektwebsite"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "Vorschauen können persönliche oder geschäftliche Informationen vom Remote-Computer enthalten. Nach dem Einschalten speichert jede Verbindung automatisch ein Bild auf dem Gerät und zeigt es in den letzten Verbindungen an. Sie können jederzeit schließen und löschen."; +"高" = "Hoch"; +"默认" = "Standard"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "Standardmäßig deaktiviert. Beim Einschalten wechselt das iPhone in die Querformatausrichtung und bleibt beim Anschließen im Querformat. Im ausgeschalteten Zustand folgt es der Ausrichtung des Geräts. iPads sind nicht betroffen."; +"鼠标右键" = "Rechte Maustaste"; +"鼠标左键" = "Linke Maustaste"; +"鼠标控制" = "Maussteuerung"; +"鼠标滚轮" = "Mausrad"; diff --git a/apps/ios/CrossDeskMobile/Resources/en.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..01c55879 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/en.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk uses the local network to discover and establish native P2P remote control connections."; diff --git a/apps/ios/CrossDeskMobile/Resources/en.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/en.lproj/Localizable.strings new file mode 100644 index 00000000..a601612d --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/en.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "%1$@ transmission failed"; +"%1$@ 台设备" = "Devices: %1$@"; +"%1$@ 条未读" = "%1$@ unread items"; +"%1$@键盘页" = "%1$@ keyboard page"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, receiving %2$@, sending %3$@, packet loss rate %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk uses the local network to discover and establish native P2P remote control connections."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del requires remote activation of Windows system services"; +"GNU GPL 第 3 版" = "GNU GPL version 3"; +"OpenFEC 告知" = "OpenFEC notice"; +"OpenFEC 许可与源码" = "OpenFEC license and source"; +"P2P 直连" = "P2P direct connection"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN Link establishment failed, please check the network and try again."; +"SRTP 已启用" = "SRTP enabled"; +"TLS 证书校验失败" = "TLS certificate verification failed"; +"TURN 中继" = "TURN relay"; +"上下滑动,可滑出按键范围" = "Slide up and down to slide out of the key range"; +"丢包率" = "Loss Rate"; +"中" = "Medium"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "Prioritizes keeping the picture smooth, and will reduce resolution more aggressively when bandwidth or encoding pressure is high."; +"低" = "Low"; +"使用自定义服务器" = "Using a custom server"; +"保存密码" = "Save password"; +"保存远程画面预览" = "Save remote screen previews"; +"保存远程画面预览?" = "Save remote screen preview?"; +"信令服务器已关闭连接" = "The signaling server has closed the connection"; +"信令服务重连中" = "Signaling service reconnecting"; +"信令连接失败" = "Signaling connection failed"; +"信令连接已关闭" = "Signaling connection closed"; +"偏好模式" = "Preference mode"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "Slide the cursor like a trackpad and operate the current cursor position when clicked."; +"公告加载失败,请重试。" = "Announcement loading failed, please try again."; +"公告详情" = "Announcement details"; +"共 %1$@ 条 · %2$@ 条未读" = "Total %1$@ items ·%2$@ unread items"; +"关于" = "About"; +"关于 CrossDesk" = "About CrossDesk"; +"关于,有新版本" = "About, there is a new version"; +"关闭" = "Close"; +"关闭控制栏" = "Close control bar"; +"关闭隐私屏" = "Disable privacy screen"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "Balances clarity and smoothness, only gradually reducing resolution under constant pressure."; +"分辨率" = "Resolution"; +"切换到电脑键盘" = "Switch to computer keyboard"; +"切换到系统键盘" = "Switch to system keyboard"; +"删除" = "Delete"; +"删除公告" = "Delete announcement"; +"删除记录" = "Delete record"; +"删除这条公告?" = "Delete this announcement?"; +"刷新公告" = "Refresh announcement"; +"剪贴板" = "Clipboard"; +"剪贴板中没有文本" = "No text in clipboard"; +"剪贴板文本超过 128 KiB" = "Clipboard text exceeds 128 KiB"; +"加载中…" = "Loading…"; +"加载更多" = "Load more"; +"升级提示" = "Update recommended"; +"单次输入最多 16 KiB,且不能包含空字符" = "A single input can be up to 16 KiB and cannot contain null characters"; +"发送" = "Send"; +"发送文件" = "Send file"; +"取消" = "Cancel"; +"取消连接" = "Cancel connection"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "Each component is subject to the listed open source license, and the rights granted are not subject to the general terms of use of this application. Viewing source code requires an internet connection."; +"合计" = "Total"; +"同意并继续" = "Agree and continue"; +"回车" = "Enter"; +"在线" = "Online"; +"地址" = "Address"; +"填写服务器地址" = "Fill in the server address"; +"填写端口" = "Fill in the port"; +"声音" = "Sound"; +"失败" = "Failed"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "Always maintain a higher resolution and reduce the frame rate to ensure picture clarity when bandwidth is insufficient."; +"媒体加密" = "Media encryption"; +"字母数字" = "Letters & numbers"; +"完成" = "Done"; +"完成隐私授权后可检查更新" = "You can check for updates after completing privacy authorization"; +"完成隐私授权后登记本机身份" = "Register the local identity after completing privacy authorization"; +"密码将安全保存在本机 Keychain 中" = "Passwords will be safely stored in the local Keychain"; +"对端 ID" = "Remote ID"; +"对端 ID %1$@" = "Peer ID %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "Will stop the remote connection, close the screen preview save and clear the existing preview. Connection records and received files will be retained, and existing server data will not be deleted. You can reauthorize at any time."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "All remote previews saved on this machine will be deleted, while connection records, passwords and received files will be retained."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "All remote previews saved on this machine will be deleted, while connection records, passwords and received files will be retained. Subsequent connections will still save new previews."; +"屏幕方向" = "Screen orientation"; +"展开远程控制菜单" = "Expand remote control menu"; +"已保存密码" = "Password saved"; +"已勾选" = "Checked"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del sent"; +"已发送本机剪贴板" = "Local clipboard sent"; +"已授权" = "Granted"; +"已接收 %1$@" = "Received %1$@"; +"已接收远端剪贴板" = "Remote clipboard received"; +"已读" = "Read"; +"已连接" = "Connected"; +"已连接服务器" = "Connected to server"; +"帧率" = "Frame rate"; +"帧率优先" = "Smooth"; +"平衡" = "Balanced"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "The license file in the application is missing or damaged, please reinstall the application."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "The development version contains modifications that have not yet been released. The following link is the source code of the basic version."; +"开启保存" = "Enable saving"; +"开启隐私屏" = "Enable privacy screen"; +"开源组件" = "Open-source components"; +"开源软件权利说明" = "Open source software rights description"; +"当前已是最新版本" = "This is currently the latest version"; +"成功连接后,这里会显示远端桌面的缩略图。" = "After a successful connection, a thumbnail of the remote desktop will be displayed here."; +"我已阅读并同意《隐私政策》" = "I have read and agreed to the Privacy Policy"; +"我已阅读并同意隐私政策" = "I have read and agree to the privacy policy"; +"打开隐私政策" = "Open privacy policy"; +"指令发送失败,请重试" = "Command sending failed, please try again"; +"指令已发送,等待电脑确认…" = "The command has been sent, waiting for computer confirmation..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "Press and drag to slide out of the key range, release to end dragging"; +"授权后可使用远程连接。" = "Remote connections are available after authorization."; +"授权状态" = "Authorization status"; +"接收" = "Receive"; +"控制模式" = "Control mode"; +"控制端解码器" = "Local decoder"; +"撤回授权" = "Withdraw authorization"; +"撤回隐私授权" = "Withdraw privacy authorization"; +"收起电脑键盘" = "Hide computer keyboard"; +"收起系统键盘" = "Collapse system keyboard"; +"收起远程控制菜单" = "Collapse remote control menu"; +"收起鼠标" = "Hide mouse"; +"数据" = "Data"; +"断开后将返回首页" = "Will return to the homepage after disconnecting"; +"断开远程连接?" = "Disconnect remote connection?"; +"断开连接" = "Disconnect"; +"新版本" = "New version"; +"新版本可用:v%1$@" = "New version available: v%1$@"; +"无效" = "Invalid"; +"无未读公告" = "No unread announcements"; +"无法" = "Unable to"; +"无法保存本地阅读状态,请重试。" = "Unable to save reading status locally. Please try again."; +"无法删除这条公告,请重试。" = "Unable to delete this announcement. Please try again."; +"无法访问本机登录凭据,请解锁后重试" = "Unable to access local login credentials, please unlock and try again"; +"无法读取开源许可" = "Unable to read open source license"; +"无法读取所选文件,请重试" = "Unable to read selected file, please try again"; +"是否撤回隐私授权?" = "Withdraw privacy authorization?"; +"显示器" = "Display"; +"显示器 %1$@" = "Monitor %1$@"; +"显示器 1" = "Monitor 1"; +"显示密码" = "Show password"; +"暂不同意" = "Not now"; +"暂无公告" = "No announcements"; +"最近连接" = "Recent connections"; +"服务器" = "Server"; +"服务器地址" = "Server Address"; +"服务器端口" = "Server port"; +"服务器配置无效" = "Invalid server configuration"; +"未勾选" = "Not checked"; +"未启用" = "Not enabled"; +"未授权" = "Unauthorized"; +"未知" = "Unknown"; +"未知信令状态" = "Unknown signaling status"; +"未知连接状态" = "Unknown connection status"; +"未读" = "Unread"; +"未连接" = "Not connected"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "This application uses OpenFEC for forward error correction under CeCILL-C 1.0, which provides limited warranties and limits liability. See the full license for details."; +"本机 ID %1$@" = "Local ID %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "The login credentials for this machine are temporarily insecure. Please unlock your device and click \"Apply\" in settings to try again."; +"本版本源码与构建说明" = "Source code and build instructions for this version"; +"本版本源码信息暂不可用。" = "Source revision is unavailable for this build."; +"构建说明" = "Build instructions"; +"构建配方与项目补丁" = "Build recipes and project patches"; +"查看源码" = "View source code"; +"检查失败,请稍后重试" = "Check failed. Please try again later."; +"检查更新" = "Check for updates"; +"正在关闭隐私屏…" = "Closing privacy screen…"; +"正在准备连接…" = "Preparing to connect..."; +"正在发送 %1$@" = "Sending %1$@"; +"正在发送 Ctrl+Alt+Del…" = "Sending Ctrl+Alt+Del…"; +"正在取回远程画面…" = "Retrieving remote screen..."; +"正在建立远程连接" = "Establishing remote connection"; +"正在开启隐私屏…" = "Turning on privacy screen..."; +"正在收集 ICE 候选" = "Collecting ICE candidates"; +"正在检查更新…" = "Checking for updates…"; +"正在清除…" = "Clearing..."; +"正在确认设备状态…" = "Confirming device status..."; +"正在获取本机 ID…" = "Obtaining local ID..."; +"正在连接" = "Connecting"; +"正在连接信令服务" = "Connecting to signaling service"; +"清除" = "Clear"; +"清除预览图" = "Clear previews"; +"清除预览图?" = "Clear previews?"; +"源码与构建说明" = "Source code and build instructions"; +"源码版本" = "Source code version"; +"版本" = "Version"; +"版权与许可声明" = "Copyright and License Statement"; +"电脑键盘" = "Computer keyboard"; +"画中画未能开启,请保持应用在前台后重试。" = "Picture-in-picture failed to open, please keep the application in the foreground and try again."; +"画质优先" = "Quality"; +"画面偏好" = "Video Preference"; +"画面延时" = "Video latency"; +"画面设置" = "Video settings"; +"画面质量" = "Video Quality"; +"画面采集帧率" = "Video Capture Frame Rate"; +"相对位置" = "Trackpad"; +"相对鼠标" = "Relative mouse"; +"知道了" = "Got it"; +"确定" = "OK"; +"确认" = "Confirm"; +"离线" = "Offline"; +"空格" = "Space"; +"端口" = "Port"; +"符号功能" = "Symbols & keys"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "Wait for the computer to return to the privacy screen state; older computers may not support it."; +"等待连接" = "Waiting for connection"; +"等待隐私授权" = "Waiting for privacy authorization"; +"系统键盘" = "System keyboard"; +"绝对位置" = "Direct touch"; +"绝对鼠标" = "Absolute Mouse"; +"网络状态" = "Network"; +"网络连接已中断,请重新连接。" = "The network connection has been interrupted, please reconnect."; +"自定义" = "Custom"; +"虚拟鼠标" = "Virtual mouse"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "The controlled terminal does not support direct input of Chinese, please update the macOS controlled terminal; you can also copy the text first, send it through the clipboard of the remote control menu and then paste it"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "The remote privacy screen was unlocked using the local shortcut. Lock it again to restore privacy and disable local shortcut unlocking."; +"被控端平台:%1$@" = "Controlled terminal platform:%1$@"; +"被控端版本过低,请升级到最新版本。" = "The controlled version is too low, please upgrade to the latest version."; +"被控端编码器" = "Remote encoder"; +"视频" = "Video"; +"视频 %1$@×%2$@ · %3$@ 帧" = "Video %1$@×%2$@·%3$@ frames"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "The touch position directly corresponds to the remote screen position, which is suitable for quick positioning."; +"许可" = "License"; +"许可与版权声明" = "Licenses and copyright notices"; +"许可与版权声明可离线查阅。" = "The license and copyright notice are available offline."; +"设备离线" = "Device Offline"; +"设置" = "Settings"; +"设置,有新版本" = "Settings, there is a new version"; +"访问密码" = "Access password"; +"访问密码错误,请重新输入。" = "The access password is wrong, please re-enter it."; +"请求超时,尚未确认电脑的隐私屏状态" = "The request timed out and the computer's privacy screen status has not been confirmed."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "Please enter a port in the range 1–65535, or turn off \"Use custom server\"."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "Please enter the server address, or turn off \"Use a custom server\"."; +"请输入远程设备 ID" = "Please enter the remote device ID"; +"调整失败,请重试。" = "Could not apply settings. Try again."; +"软件许可" = "Software license"; +"返回控制栏" = "Return to control bar"; +"还没有连接记录" = "No connection record yet"; +"这条公告已更新或删除,请返回公告列表查看。" = "This announcement has been updated or deleted, please return to the announcement list to view it."; +"远程桌面" = "Remote Desktop"; +"远程设备 ID 不存在,请检查设备 ID。" = "Remote device ID does not exist, please check device ID."; +"远程设备当前不可用,请稍后重试。" = "The remote device is currently unavailable, please try again later."; +"远程连接已结束。" = "Remote connection ended."; +"连接" = "Connect"; +"连接延时(RTT)" = "Connection delay (RTT)"; +"连接建立后可调整,需被控端支持。" = "Available when connected to a supported remote device."; +"连接建立后锁定横屏" = "Lock landscape screen after connection is established"; +"连接提示" = "Connection prompt"; +"连接方式" = "Connection method"; +"连接远程桌面" = "Connect to remote desktop"; +"退格" = "Backspace"; +"通知公告" = "Announcements"; +"部分预览图未能清除,请重试。" = "Some previews could not be cleared, please try again."; +"重试" = "Try again"; +"重试保存阅读状态" = "Retry saving reading status"; +"锁定" = "Lock"; +"键盘" = "Keyboard"; +"键盘操作" = "Keyboard operation"; +"阅读并授权" = "Read and authorize"; +"隐私" = "Privacy"; +"隐私与授权" = "Privacy and Authorization"; +"隐私屏" = "Privacy screen"; +"隐私屏已关闭" = "Privacy screen off"; +"隐私屏已开启" = "Privacy screen on"; +"隐私屏已被解锁" = "Privacy screen unlocked"; +"隐私屏异常" = "Privacy screen abnormality"; +"隐私屏暂不可用" = "Privacy screen is temporarily unavailable"; +"隐私屏状态已过期,等待电脑确认" = "Privacy screen status has expired, waiting for computer confirmation"; +"隐私屏状态待确认" = "Privacy screen status to be confirmed"; +"隐私政策" = "Privacy Policy"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "The privacy policy cannot be read temporarily. Please refuse to connect to the Internet and reinstall the application."; +"隐藏密码" = "Hide password"; +"静音" = "Mute"; +"音频" = "Audio"; +"项目主页" = "Project website"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "Previews may contain personal or work information from the remote computer. After turning it on, each connection will automatically save a picture on the machine and display it in recent connections. You can close and clear at any time."; +"高" = "High"; +"默认" = "Default"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "Off by default. When turned on, the iPhone goes into and stays in landscape orientation when connected; when turned off, it follows the device orientation. iPads are not affected."; +"鼠标右键" = "Right mouse button"; +"鼠标左键" = "Left mouse button"; +"鼠标控制" = "Mouse control"; +"鼠标滚轮" = "Mouse wheel"; diff --git a/apps/ios/CrossDeskMobile/Resources/es.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/es.lproj/InfoPlist.strings new file mode 100644 index 00000000..d00db0bb --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/es.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk utiliza la red local para descubrir y establecer conexiones nativas de control remoto P2P."; diff --git a/apps/ios/CrossDeskMobile/Resources/es.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/es.lproj/Localizable.strings new file mode 100644 index 00000000..125d527a --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/es.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "Error en la transmisión %1$@"; +"%1$@ 台设备" = "Dispositivos: %1$@"; +"%1$@ 条未读" = "%1$@ elementos no leídos"; +"%1$@键盘页" = "Página del teclado %1$@"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, recepción de %2$@, envío de %3$@, tasa de pérdida de paquetes %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk utiliza la red local para descubrir y establecer conexiones nativas de control remoto P2P."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del requiere activación remota de los servicios del sistema Windows"; +"GNU GPL 第 3 版" = "GNU GPL versión 3"; +"OpenFEC 告知" = "Aviso OpenFEC"; +"OpenFEC 许可与源码" = "Licencia y fuente OpenFEC"; +"P2P 直连" = "Conexión directa P2P"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN Error al establecer el enlace, verifique la red e inténtelo nuevamente."; +"SRTP 已启用" = "SRTP habilitado"; +"TLS 证书校验失败" = "Error en la verificación del certificado TLS"; +"TURN 中继" = "Relé de GIRO"; +"上下滑动,可滑出按键范围" = "Deslice hacia arriba y hacia abajo para salir del rango de teclas"; +"丢包率" = "Tasa de pérdidas"; +"中" = "Media"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "Da prioridad a mantener la imagen fluida y reducirá la resolución de manera más agresiva cuando el ancho de banda o la presión de codificación sean altos."; +"低" = "Baja"; +"使用自定义服务器" = "Usando un servidor personalizado"; +"保存密码" = "Guardar contraseña"; +"保存远程画面预览" = "Guardar vistas previas de pantalla remotas"; +"保存远程画面预览?" = "¿Guardar vista previa de pantalla remota?"; +"信令服务器已关闭连接" = "El servidor de señalización ha cerrado la conexión."; +"信令服务重连中" = "Reconexión del servicio de señalización"; +"信令连接失败" = "Error en la conexión de señalización"; +"信令连接已关闭" = "Conexión de señalización cerrada"; +"偏好模式" = "Modo de preferencia"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "Deslice el cursor como un trackpad y opere la posición actual del cursor cuando se haga clic."; +"公告加载失败,请重试。" = "Error al cargar el anuncio, inténtelo de nuevo."; +"公告详情" = "Detalles del anuncio"; +"共 %1$@ 条 · %2$@ 条未读" = "Total de elementos %1$@· Elementos no leídos %2$@"; +"关于" = "Acerca de"; +"关于 CrossDesk" = "Acerca de CrossDesk"; +"关于,有新版本" = "Acerca de, hay una nueva versión."; +"关闭" = "Cerrar"; +"关闭控制栏" = "Cerrar barra de control"; +"关闭隐私屏" = "Desactivar la pantalla de privacidad"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "Equilibra la claridad y la suavidad, reduciendo solo gradualmente la resolución bajo presión constante."; +"分辨率" = "Resolución"; +"切换到电脑键盘" = "Cambiar al teclado de la computadora"; +"切换到系统键盘" = "Cambiar al teclado del sistema"; +"删除" = "Eliminar"; +"删除公告" = "Eliminar anuncio"; +"删除记录" = "Eliminar registro"; +"删除这条公告?" = "¿Eliminar este anuncio?"; +"刷新公告" = "Actualizar anuncio"; +"剪贴板" = "Portapapeles"; +"剪贴板中没有文本" = "No hay texto en el portapapeles"; +"剪贴板文本超过 128 KiB" = "El texto del portapapeles supera los 128 KiB"; +"加载中…" = "Cargando…"; +"加载更多" = "Cargar más"; +"升级提示" = "Actualización recomendada"; +"单次输入最多 16 KiB,且不能包含空字符" = "Una sola entrada puede tener hasta 16 KiB y no puede contener caracteres nulos"; +"发送" = "Enviar"; +"发送文件" = "Enviar archivo"; +"取消" = "Cancelar"; +"取消连接" = "Cancelar conexión"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "Cada componente está sujeto a la licencia de código abierto enumerada y los derechos otorgados no están sujetos a los términos generales de uso de esta aplicación. Para ver el código fuente se requiere una conexión a Internet."; +"合计" = "Total"; +"同意并继续" = "Aceptar y continuar"; +"回车" = "Entrar"; +"在线" = "En línea"; +"地址" = "Dirección"; +"填写服务器地址" = "Complete la dirección del servidor"; +"填写端口" = "Complete el puerto"; +"声音" = "Sonido"; +"失败" = "Fallido"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "Mantenga siempre una resolución más alta y reduzca la velocidad de fotogramas para garantizar la claridad de la imagen cuando el ancho de banda sea insuficiente."; +"媒体加密" = "Cifrado de medios"; +"字母数字" = "Letras y números"; +"完成" = "Hecho"; +"完成隐私授权后可检查更新" = "Puede buscar actualizaciones después de completar la autorización de privacidad"; +"完成隐私授权后登记本机身份" = "Registre la identidad local después de completar la autorización de privacidad"; +"密码将安全保存在本机 Keychain 中" = "Las contraseñas se almacenarán de forma segura en el llavero local."; +"对端 ID" = "Identificación remota"; +"对端 ID %1$@" = "ID de igual %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "Detendrá la conexión remota, cerrará la vista previa de la pantalla y borrará la vista previa existente. Los registros de conexión y los archivos recibidos se conservarán y los datos existentes del servidor no se eliminarán. Puede volver a autorizar en cualquier momento."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "Se eliminarán todas las vistas previas remotas guardadas en esta máquina, mientras que se conservarán los registros de conexión, las contraseñas y los archivos recibidos."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "Se eliminarán todas las vistas previas remotas guardadas en esta máquina, mientras que se conservarán los registros de conexión, las contraseñas y los archivos recibidos. Las conexiones posteriores seguirán guardando nuevas vistas previas."; +"屏幕方向" = "Orientación de la pantalla"; +"展开远程控制菜单" = "Ampliar el menú del control remoto"; +"已保存密码" = "Contraseña guardada"; +"已勾选" = "Comprobado"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del enviado"; +"已发送本机剪贴板" = "Portapapeles local enviado"; +"已授权" = "Concedido"; +"已接收 %1$@" = "Recibido %1$@"; +"已接收远端剪贴板" = "Portapapeles remoto recibido"; +"已读" = "Leer"; +"已连接" = "Conectado"; +"已连接服务器" = "Conectado al servidor"; +"帧率" = "Velocidad de fotogramas"; +"帧率优先" = "Fluidez"; +"平衡" = "Equilibrado"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "El archivo de licencia de la aplicación falta o está dañado; reinstale la aplicación."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "La versión de desarrollo contiene modificaciones que aún no han sido publicadas. El siguiente enlace es el código fuente de la versión básica."; +"开启保存" = "Activar guardado"; +"开启隐私屏" = "Habilitar pantalla de privacidad"; +"开源组件" = "Componentes de código abierto"; +"开源软件权利说明" = "Descripción de los derechos del software de código abierto"; +"当前已是最新版本" = "Esta es actualmente la última versión."; +"成功连接后,这里会显示远端桌面的缩略图。" = "Después de una conexión exitosa, aquí se mostrará una miniatura del escritorio remoto."; +"我已阅读并同意《隐私政策》" = "He leído y acepto la Política de Privacidad"; +"我已阅读并同意隐私政策" = "He leído y acepto la política de privacidad"; +"打开隐私政策" = "Abrir política de privacidad"; +"指令发送失败,请重试" = "Error al enviar el comando, inténtelo de nuevo"; +"指令已发送,等待电脑确认…" = "El comando ha sido enviado, esperando confirmación por computadora..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "Presione y arrastre para deslizarse fuera del rango de teclas, suelte para finalizar el arrastre"; +"授权后可使用远程连接。" = "Las conexiones remotas están disponibles después de la autorización."; +"授权状态" = "Estado de autorización"; +"接收" = "Recibir"; +"控制模式" = "Modo de control"; +"控制端解码器" = "Decodificador local"; +"撤回授权" = "Retirar autorización"; +"撤回隐私授权" = "Retirar la autorización de privacidad"; +"收起电脑键盘" = "Ocultar teclado del PC"; +"收起系统键盘" = "Contraer teclado del sistema"; +"收起远程控制菜单" = "Contraer menú de control remoto"; +"收起鼠标" = "Ocultar ratón"; +"数据" = "Datos"; +"断开后将返回首页" = "Volverá a la página de inicio después de desconectarse"; +"断开远程连接?" = "¿Desconectar la conexión remota?"; +"断开连接" = "Desconectar"; +"新版本" = "Nueva versión"; +"新版本可用:v%1$@" = "Nueva versión disponible: v%1$@"; +"无效" = "Inválido"; +"无未读公告" = "No hay anuncios no leídos"; +"无法" = "No puedo"; +"无法保存本地阅读状态,请重试。" = "No se puede guardar el estado de lectura localmente. Por favor inténtalo de nuevo."; +"无法删除这条公告,请重试。" = "No se puede eliminar este anuncio. Por favor inténtalo de nuevo."; +"无法访问本机登录凭据,请解锁后重试" = "No se puede acceder a las credenciales de inicio de sesión locales, desbloquee e intente nuevamente"; +"无法读取开源许可" = "No se puede leer la licencia de código abierto"; +"无法读取所选文件,请重试" = "No se puede leer el archivo seleccionado, inténtelo de nuevo"; +"是否撤回隐私授权?" = "¿Retirar la autorización de privacidad?"; +"显示器" = "Pantalla"; +"显示器 %1$@" = "Monitorizar %1$@"; +"显示器 1" = "Monitor 1"; +"显示密码" = "Mostrar contraseña"; +"暂不同意" = "Ahora no"; +"暂无公告" = "Sin anuncios"; +"最近连接" = "Conexiones recientes"; +"服务器" = "Servidor"; +"服务器地址" = "Dirección del servidor"; +"服务器端口" = "Puerto del servidor"; +"服务器配置无效" = "Configuración del servidor no válida"; +"未勾选" = "No marcado"; +"未启用" = "No habilitado"; +"未授权" = "No autorizado"; +"未知" = "Desconocido"; +"未知信令状态" = "Estado de señalización desconocido"; +"未知连接状态" = "Estado de conexión desconocido"; +"未读" = "No leído"; +"未连接" = "No conectado"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "Esta aplicación utiliza OpenFEC para la corrección de errores directos bajoCeCILL-C1.0, que proporciona garantías limitadas y limita la responsabilidad. Consulte la licencia completa para obtener más detalles."; +"本机 ID %1$@" = "ID local %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "Las credenciales de inicio de sesión para esta máquina son temporalmente inseguras. Desbloquee su dispositivo y haga clic en \"Aplicar\" en la configuración para volver a intentarlo."; +"本版本源码与构建说明" = "Código fuente e instrucciones de compilación para esta versión"; +"本版本源码信息暂不可用。" = "La revisión fuente no está disponible para esta compilación."; +"构建说明" = "Instrucciones de construcción"; +"构建配方与项目补丁" = "Crear recetas y parches de proyectos"; +"查看源码" = "Ver código fuente"; +"检查失败,请稍后重试" = "La verificación falló. Inténtelo de nuevo más tarde."; +"检查更新" = "Buscar actualizaciones"; +"正在关闭隐私屏…" = "Cerrando la pantalla de privacidad..."; +"正在准备连接…" = "Preparándose para conectarse..."; +"正在发送 %1$@" = "Envío de %1$@"; +"正在发送 Ctrl+Alt+Del…" = "Enviando Ctrl+Alt+Del…"; +"正在取回远程画面…" = "Recuperando la pantalla remota..."; +"正在建立远程连接" = "Establecer conexión remota"; +"正在开启隐私屏…" = "Activando la pantalla de privacidad..."; +"正在收集 ICE 候选" = "Recopilación de candidatos de ICE"; +"正在检查更新…" = "Buscando actualizaciones..."; +"正在清除…" = "Borrando..."; +"正在确认设备状态…" = "Confirmando el estado del dispositivo..."; +"正在获取本机 ID…" = "Obtención de identificación local..."; +"正在连接" = "Conexión"; +"正在连接信令服务" = "Conexión al servicio de señalización"; +"清除" = "Borrar"; +"清除预览图" = "Borrar vistas previas"; +"清除预览图?" = "¿Borrar vistas previas?"; +"源码与构建说明" = "Código fuente e instrucciones de compilación"; +"源码版本" = "Versión del código fuente"; +"版本" = "Versión"; +"版权与许可声明" = "Declaración de derechos de autor y licencia"; +"电脑键盘" = "Teclado de computadora"; +"画中画未能开启,请保持应用在前台后重试。" = "No se pudo abrir la imagen en imagen. Mantenga la aplicación en primer plano e inténtelo nuevamente."; +"画质优先" = "Calidad"; +"画面偏好" = "Preferencia de vídeo"; +"画面延时" = "Latencia de vídeo"; +"画面设置" = "Configuración de vídeo"; +"画面质量" = "Calidad de vídeo"; +"画面采集帧率" = "Velocidad de fotogramas de captura de vídeo"; +"相对位置" = "Panel táctil"; +"相对鼠标" = "Ratón relativo"; +"知道了" = "Entendido"; +"确定" = "Aceptar"; +"确认" = "Confirmar"; +"离线" = "Sin conexión"; +"空格" = "Espacio"; +"端口" = "Puerto"; +"符号功能" = "Símbolos y teclas"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "Espere a que la computadora vuelva al estado de pantalla de privacidad; Es posible que las computadoras más antiguas no lo admitan."; +"等待连接" = "Esperando conexión"; +"等待隐私授权" = "Esperando autorización de privacidad"; +"系统键盘" = "Teclado del sistema"; +"绝对位置" = "Toque directo"; +"绝对鼠标" = "Ratón absoluto"; +"网络状态" = "Red"; +"网络连接已中断,请重新连接。" = "La conexión de red ha sido interrumpida, vuelva a conectarse."; +"自定义" = "Personalizado"; +"虚拟鼠标" = "Ratón virtual"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "El terminal controlado no admite la entrada directa de chino; actualice el terminal controlado por macOS; También puedes copiar el texto primero, enviarlo a través del portapapeles del menú del control remoto y luego pegarlo."; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "La pantalla de privacidad remota se desbloqueó usando el acceso directo local. Bloquéelo nuevamente para restaurar la privacidad y deshabilitar el desbloqueo de accesos directos locales."; +"被控端平台:%1$@" = "Plataforma terminal controlada:%1$@"; +"被控端版本过低,请升级到最新版本。" = "La versión controlada es demasiado baja; actualice a la última versión."; +"被控端编码器" = "Codificador remoto"; +"视频" = "Vídeo"; +"视频 %1$@×%2$@ · %3$@ 帧" = "Vídeo %1$@×%2$@· Cuadros %3$@"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "La posición táctil corresponde directamente a la posición de la pantalla remota, que es adecuada para un posicionamiento rápido."; +"许可" = "Licencia"; +"许可与版权声明" = "Licencias y avisos de derechos de autor"; +"许可与版权声明可离线查阅。" = "La licencia y el aviso de derechos de autor están disponibles sin conexión."; +"设备离线" = "Dispositivo sin conexión"; +"设置" = "Ajustes"; +"设置,有新版本" = "Configuración, hay una nueva versión."; +"访问密码" = "Contraseña de acceso"; +"访问密码错误,请重新输入。" = "La contraseña de acceso es incorrecta, por favor vuelva a ingresarla."; +"请求超时,尚未确认电脑的隐私屏状态" = "Se agotó el tiempo de espera de la solicitud y no se ha confirmado el estado de la pantalla de privacidad de la computadora."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "Ingrese un puerto en el rango 1–65535 o desactive \"Usar servidor personalizado\"."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "Ingrese la dirección del servidor o desactive \"Usar un servidor personalizado\"."; +"请输入远程设备 ID" = "Ingrese el ID del dispositivo remoto"; +"调整失败,请重试。" = "No se pudieron aplicar las configuraciones. Intentar otra vez."; +"软件许可" = "Licencia de software"; +"返回控制栏" = "Volver a la barra de control"; +"还没有连接记录" = "Aún no hay registro de conexión"; +"这条公告已更新或删除,请返回公告列表查看。" = "Este anuncio ha sido actualizado o eliminado, regrese a la lista de anuncios para verlo."; +"远程桌面" = "Escritorio remoto"; +"远程设备 ID 不存在,请检查设备 ID。" = "La ID del dispositivo remoto no existe; verifique la ID del dispositivo."; +"远程设备当前不可用,请稍后重试。" = "El dispositivo remoto no está disponible actualmente; inténtelo nuevamente más tarde."; +"远程连接已结束。" = "La conexión remota finalizó."; +"连接" = "Conectar"; +"连接延时(RTT)" = "Retardo de conexión (RTT)"; +"连接建立后可调整,需被控端支持。" = "Disponible cuando se conecta a un dispositivo remoto compatible."; +"连接建立后锁定横屏" = "Bloquear la pantalla horizontal después de establecer la conexión"; +"连接提示" = "Aviso de conexión"; +"连接方式" = "Método de conexión"; +"连接远程桌面" = "Conectarse al escritorio remoto"; +"退格" = "Retroceso"; +"通知公告" = "Anuncios"; +"部分预览图未能清除,请重试。" = "Algunas vistas previas no se pudieron borrar, inténtalo de nuevo."; +"重试" = "Inténtalo de nuevo"; +"重试保存阅读状态" = "Reintentar guardar el estado de lectura"; +"锁定" = "Bloquear"; +"键盘" = "Teclado"; +"键盘操作" = "Operación del teclado"; +"阅读并授权" = "Leer y autorizar"; +"隐私" = "Privacidad"; +"隐私与授权" = "Privacidad y autorización"; +"隐私屏" = "Pantalla de privacidad"; +"隐私屏已关闭" = "Privacidad desactivada"; +"隐私屏已开启" = "Privacidad activada"; +"隐私屏已被解锁" = "Pantalla de privacidad desbloqueada"; +"隐私屏异常" = "Anormalidad en la pantalla de privacidad"; +"隐私屏暂不可用" = "La pantalla de privacidad no está disponible temporalmente"; +"隐私屏状态已过期,等待电脑确认" = "El estado de la pantalla de privacidad ha caducado, esperando confirmación por computadora"; +"隐私屏状态待确认" = "Estado de la pantalla de privacidad por confirmar"; +"隐私政策" = "Política de privacidad"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "La política de privacidad no se puede leer temporalmente. Rechace conectarse a Internet y reinstale la aplicación."; +"隐藏密码" = "Ocultar contraseña"; +"静音" = "Silencio"; +"音频" = "Audio"; +"项目主页" = "Sitio web del proyecto"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "Las vistas previas pueden contener información personal o laboral de la computadora remota. Después de encenderlo, cada conexión guardará automáticamente una imagen en la máquina y la mostrará en las conexiones recientes. Puedes cerrar y borrar en cualquier momento."; +"高" = "Alta"; +"默认" = "Predeterminado"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "Desactivado de forma predeterminada. Cuando se enciende, el iPhone entra y permanece en orientación horizontal cuando está conectado; cuando está apagado, sigue la orientación del dispositivo. Los iPad no se ven afectados."; +"鼠标右键" = "Botón derecho del ratón"; +"鼠标左键" = "Botón izquierdo del ratón"; +"鼠标控制" = "Control del ratón"; +"鼠标滚轮" = "Rueda del ratón"; diff --git a/apps/ios/CrossDeskMobile/Resources/fr.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/fr.lproj/InfoPlist.strings new file mode 100644 index 00000000..35836aee --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/fr.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk utilise le réseau local pour découvrir et établir des connexions de contrôle à distance P2P natives."; diff --git a/apps/ios/CrossDeskMobile/Resources/fr.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/fr.lproj/Localizable.strings new file mode 100644 index 00000000..52ad0d34 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/fr.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "Échec de la transmission %1$@"; +"%1$@ 台设备" = "Appareils : %1$@"; +"%1$@ 条未读" = "Éléments non lus %1$@"; +"%1$@键盘页" = "Page du clavier %1$@"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, réception de %2$@, envoi de %3$@, taux de perte de paquets %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk utilise le réseau local pour découvrir et établir des connexions de contrôle à distance P2P natives."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del nécessite l'activation à distance des services système Windows"; +"GNU GPL 第 3 版" = "GNU GPL version 3"; +"OpenFEC 告知" = "Avis OpenFEC"; +"OpenFEC 许可与源码" = "Licence et source OpenFEC"; +"P2P 直连" = "Connexion directe P2P"; +"P2P/TURN 建链失败,请检查网络后重试。" = "Échec de l'établissement du lien P2P/TURN, veuillez vérifier le réseau et réessayer."; +"SRTP 已启用" = "SRTP activé"; +"TLS 证书校验失败" = "La vérification du certificat TLS a échoué"; +"TURN 中继" = "Relais TOUR"; +"上下滑动,可滑出按键范围" = "Faites glisser vers le haut et vers le bas pour sortir de la plage de touches"; +"丢包率" = "Taux de perte"; +"中" = "Moyenne"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "Donne la priorité au maintien de la fluidité de l'image et réduira la résolution de manière plus agressive lorsque la bande passante ou la pression d'encodage est élevée."; +"低" = "Faible"; +"使用自定义服务器" = "Utilisation d'un serveur personnalisé"; +"保存密码" = "Enregistrer le mot de passe"; +"保存远程画面预览" = "Enregistrer les aperçus de l'écran distant"; +"保存远程画面预览?" = "Enregistrer l'aperçu de l'écran distant ?"; +"信令服务器已关闭连接" = "Le serveur de signalisation a fermé la connexion"; +"信令服务重连中" = "Reconnexion du service de signalisation"; +"信令连接失败" = "Échec de la connexion de signalisation"; +"信令连接已关闭" = "Connexion de signalisation fermée"; +"偏好模式" = "Mode préférence"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "Faites glisser le curseur comme un trackpad et actionnez la position actuelle du curseur lorsque vous cliquez dessus."; +"公告加载失败,请重试。" = "Le chargement de l'annonce a échoué, veuillez réessayer."; +"公告详情" = "Détails de l'annonce"; +"共 %1$@ 条 · %2$@ 条未读" = "Total des éléments %1$@· Éléments non lus %2$@"; +"关于" = "À propos"; +"关于 CrossDesk" = "À propos de CrossDesk"; +"关于,有新版本" = "À propos, il existe une nouvelle version"; +"关闭" = "Fermer"; +"关闭控制栏" = "Fermer la barre de contrôle"; +"关闭隐私屏" = "Désactiver l'écran de confidentialité"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "Équilibre la clarté et la douceur, en réduisant seulement progressivement la résolution sous une pression constante."; +"分辨率" = "Résolution"; +"切换到电脑键盘" = "Passer au clavier de l'ordinateur"; +"切换到系统键盘" = "Passer au clavier système"; +"删除" = "Supprimer"; +"删除公告" = "Supprimer l'annonce"; +"删除记录" = "Supprimer l'enregistrement"; +"删除这条公告?" = "Supprimer cette annonce ?"; +"刷新公告" = "Actualiser l'annonce"; +"剪贴板" = "Presse-papiers"; +"剪贴板中没有文本" = "Aucun texte dans le presse-papiers"; +"剪贴板文本超过 128 KiB" = "Le texte du presse-papiers dépasse 128 Ko"; +"加载中…" = "Chargement…"; +"加载更多" = "Charger plus"; +"升级提示" = "Mise à jour conseillée"; +"单次输入最多 16 KiB,且不能包含空字符" = "Une seule entrée peut atteindre 16 Ko et ne peut pas contenir de caractères nuls"; +"发送" = "Envoi"; +"发送文件" = "Envoyer le fichier"; +"取消" = "Annuler"; +"取消连接" = "Annuler la connexion"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "Chaque composant est soumis à la licence open source répertoriée, et les droits accordés ne sont pas soumis aux conditions générales d'utilisation de cette application. La visualisation du code source nécessite une connexion Internet."; +"合计" = "Total"; +"同意并继续" = "Accepter et continuer"; +"回车" = "Entrez"; +"在线" = "En ligne"; +"地址" = "Adresse"; +"填写服务器地址" = "Remplissez l'adresse du serveur"; +"填写端口" = "Remplissez le port"; +"声音" = "Son"; +"失败" = "Échec"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "Maintenez toujours une résolution plus élevée et réduisez la fréquence d'images pour garantir la clarté de l'image lorsque la bande passante est insuffisante."; +"媒体加密" = "Cryptage multimédia"; +"字母数字" = "Lettres et chiffres"; +"完成" = "Terminé"; +"完成隐私授权后可检查更新" = "Vous pouvez vérifier les mises à jour après avoir terminé l'autorisation de confidentialité"; +"完成隐私授权后登记本机身份" = "Enregistrez l'identité locale après avoir terminé l'autorisation de confidentialité"; +"密码将安全保存在本机 Keychain 中" = "Les mots de passe seront stockés en toute sécurité dans le trousseau local"; +"对端 ID" = "ID à distance"; +"对端 ID %1$@" = "ID homologue %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "Arrêtera la connexion à distance, fermera la sauvegarde de l'aperçu de l'écran et effacera l'aperçu existant. Les enregistrements de connexion et les fichiers reçus seront conservés et les données du serveur existantes ne seront pas supprimées. Vous pouvez réautoriser à tout moment."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "Tous les aperçus à distance enregistrés sur cette machine seront supprimés, tandis que les enregistrements de connexion, les mots de passe et les fichiers reçus seront conservés."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "Tous les aperçus à distance enregistrés sur cette machine seront supprimés, tandis que les enregistrements de connexion, les mots de passe et les fichiers reçus seront conservés. Les connexions ultérieures enregistreront toujours les nouveaux aperçus."; +"屏幕方向" = "Orientation de l'écran"; +"展开远程控制菜单" = "Développer le menu de la télécommande"; +"已保存密码" = "Mot de passe enregistré"; +"已勾选" = "Vérifié"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del envoyé"; +"已发送本机剪贴板" = "Presse-papiers local envoyé"; +"已授权" = "Accordé"; +"已接收 %1$@" = "Reçu %1$@"; +"已接收远端剪贴板" = "Presse-papiers distant reçu"; +"已读" = "Lire"; +"已连接" = "Connecté"; +"已连接服务器" = "Connecté au serveur"; +"帧率" = "Fréquence d'images"; +"帧率优先" = "Fluidité"; +"平衡" = "Équilibré"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "Le fichier de licence dans l'application est manquant ou endommagé, veuillez réinstaller l'application."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "La version de développement contient des modifications qui n'ont pas encore été publiées. Le lien suivant est le code source de la version de base."; +"开启保存" = "Activer l’enregistrement"; +"开启隐私屏" = "Activer l'écran de confidentialité"; +"开源组件" = "Composants open source"; +"开源软件权利说明" = "Description des droits sur les logiciels open source"; +"当前已是最新版本" = "Il s'agit actuellement de la dernière version"; +"成功连接后,这里会显示远端桌面的缩略图。" = "Après une connexion réussie, une vignette du bureau distant s'affichera ici."; +"我已阅读并同意《隐私政策》" = "J'ai lu et accepté la politique de confidentialité"; +"我已阅读并同意隐私政策" = "J'ai lu et j'accepte la politique de confidentialité"; +"打开隐私政策" = "Ouvrir la politique de confidentialité"; +"指令发送失败,请重试" = "L'envoi de la commande a échoué, veuillez réessayer"; +"指令已发送,等待电脑确认…" = "La commande a été envoyée, en attente de confirmation informatique..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "Appuyez et faites glisser pour sortir de la plage de touches, relâchez pour terminer le glissement"; +"授权后可使用远程连接。" = "Les connexions à distance sont disponibles après autorisation."; +"授权状态" = "Statut d'autorisation"; +"接收" = "Réception"; +"控制模式" = "Mode de contrôle"; +"控制端解码器" = "Décodeur local"; +"撤回授权" = "Retirer l'autorisation"; +"撤回隐私授权" = "Retirer l'autorisation de confidentialité"; +"收起电脑键盘" = "Masquer le clavier du PC"; +"收起系统键盘" = "Réduire le clavier système"; +"收起远程控制菜单" = "Réduire le menu de la télécommande"; +"收起鼠标" = "Masquer la souris"; +"数据" = "Données"; +"断开后将返回首页" = "Reviendra à la page d'accueil après la déconnexion"; +"断开远程连接?" = "Déconnecter la connexion à distance ?"; +"断开连接" = "Déconnecter"; +"新版本" = "Nouvelle version"; +"新版本可用:v%1$@" = "Nouvelle version disponible : v%1$@"; +"无效" = "Invalide"; +"无未读公告" = "Aucune annonce non lue"; +"无法" = "Impossible de"; +"无法保存本地阅读状态,请重试。" = "Impossible d'enregistrer l'état de lecture localement. Veuillez réessayer."; +"无法删除这条公告,请重试。" = "Impossible de supprimer cette annonce. Veuillez réessayer."; +"无法访问本机登录凭据,请解锁后重试" = "Impossible d'accéder aux informations de connexion locales, veuillez déverrouiller et réessayer"; +"无法读取开源许可" = "Impossible de lire la licence open source"; +"无法读取所选文件,请重试" = "Impossible de lire le fichier sélectionné, veuillez réessayer"; +"是否撤回隐私授权?" = "Retirer l'autorisation de confidentialité ?"; +"显示器" = "Écran"; +"显示器 %1$@" = "Moniteur %1$@"; +"显示器 1" = "Moniteur 1"; +"显示密码" = "Afficher le mot de passe"; +"暂不同意" = "Pas maintenant"; +"暂无公告" = "Aucune annonce"; +"最近连接" = "Connexions récentes"; +"服务器" = "Serveur"; +"服务器地址" = "Adresse du serveur"; +"服务器端口" = "Port du serveur"; +"服务器配置无效" = "Configuration du serveur invalide"; +"未勾选" = "Non coché"; +"未启用" = "Non activé"; +"未授权" = "Non autorisé"; +"未知" = "Inconnu"; +"未知信令状态" = "État de signalisation inconnu"; +"未知连接状态" = "État de connexion inconnu"; +"未读" = "Non lu"; +"未连接" = "Non connecté"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "Cette application utilise OpenFEC pour la correction d'erreur directe sousCeCILL-C1.0, qui offre des garanties limitées et limite la responsabilité. Consultez la licence complète pour plus de détails."; +"本机 ID %1$@" = "ID local %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "Les informations de connexion pour cette machine ne sont temporairement pas sécurisées. Veuillez déverrouiller votre appareil et cliquer sur « Appliquer » dans les paramètres pour réessayer."; +"本版本源码与构建说明" = "Code source et instructions de construction pour cette version"; +"本版本源码信息暂不可用。" = "La révision source n'est pas disponible pour cette version."; +"构建说明" = "Instructions de construction"; +"构建配方与项目补丁" = "Créer des recettes et des correctifs de projet"; +"查看源码" = "Afficher le code source"; +"检查失败,请稍后重试" = "La vérification a échoué. Veuillez réessayer plus tard."; +"检查更新" = "Rechercher des mises à jour"; +"正在关闭隐私屏…" = "Fermeture de l'écran de confidentialité…"; +"正在准备连接…" = "Préparation de la connexion..."; +"正在发送 %1$@" = "Envoi de %1$@"; +"正在发送 Ctrl+Alt+Del…" = "Envoi de Ctrl+Alt+Del…"; +"正在取回远程画面…" = "Récupération de l'écran distant..."; +"正在建立远程连接" = "Établissement d'une connexion à distance"; +"正在开启隐私屏…" = "Activation de l'écran de confidentialité..."; +"正在收集 ICE 候选" = "Collecte des candidats ICE"; +"正在检查更新…" = "Vérification des mises à jour…"; +"正在清除…" = "Effacement..."; +"正在确认设备状态…" = "Confirmation de l'état de l'appareil..."; +"正在获取本机 ID…" = "Obtention d'une pièce d'identité locale..."; +"正在连接" = "Connexion"; +"正在连接信令服务" = "Connexion au service de signalisation"; +"清除" = "Effacer"; +"清除预览图" = "Supprimer les aperçus"; +"清除预览图?" = "Supprimer les aperçus ?"; +"源码与构建说明" = "Code source et instructions de construction"; +"源码版本" = "Version du code source"; +"版本" = "Version"; +"版权与许可声明" = "Déclaration de droits d'auteur et de licence"; +"电脑键盘" = "Clavier d'ordinateur"; +"画中画未能开启,请保持应用在前台后重试。" = "L'image dans l'image n'a pas pu s'ouvrir. Veuillez conserver l'application au premier plan et réessayer."; +"画质优先" = "Qualité"; +"画面偏好" = "Préférence vidéo"; +"画面延时" = "Latence vidéo"; +"画面设置" = "Paramètres vidéo"; +"画面质量" = "Qualité vidéo"; +"画面采集帧率" = "Fréquence d'images de capture vidéo"; +"相对位置" = "Pavé tactile"; +"相对鼠标" = "Souris relative"; +"知道了" = "Compris"; +"确定" = "D'accord"; +"确认" = "Confirmer"; +"离线" = "Hors ligne"; +"空格" = "Espace"; +"端口" = "Port"; +"符号功能" = "Symboles et touches"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "Attendez que l'ordinateur revienne à l'état de l'écran de confidentialité ; les ordinateurs plus anciens peuvent ne pas le prendre en charge."; +"等待连接" = "En attente de connexion"; +"等待隐私授权" = "En attente d'une autorisation de confidentialité"; +"系统键盘" = "Clavier système"; +"绝对位置" = "Toucher direct"; +"绝对鼠标" = "Souris absolue"; +"网络状态" = "Réseau"; +"网络连接已中断,请重新连接。" = "La connexion réseau a été interrompue, veuillez vous reconnecter."; +"自定义" = "Personnalisé"; +"虚拟鼠标" = "Souris virtuelle"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "Le terminal contrôlé ne prend pas en charge la saisie directe du chinois, veuillez mettre à jour le terminal contrôlé par macOS ; vous pouvez également d'abord copier le texte, l'envoyer via le presse-papiers du menu de la télécommande, puis le coller"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "L'écran de confidentialité à distance a été déverrouillé à l'aide du raccourci local. Verrouillez-le à nouveau pour restaurer la confidentialité et désactiver le déverrouillage des raccourcis locaux."; +"被控端平台:%1$@" = "Plateforme terminale contrôlée :%1$@"; +"被控端版本过低,请升级到最新版本。" = "La version contrôlée est trop basse, veuillez mettre à niveau vers la dernière version."; +"被控端编码器" = "Encodeur déporté"; +"视频" = "Vidéo"; +"视频 %1$@×%2$@ · %3$@ 帧" = "Vidéo %1$@×%2$@· Images %3$@"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "La position tactile correspond directement à la position de l'écran distant, ce qui convient à un positionnement rapide."; +"许可" = "Licence"; +"许可与版权声明" = "Licences et mentions de droits d'auteur"; +"许可与版权声明可离线查阅。" = "La licence et la notice de copyright sont disponibles hors ligne."; +"设备离线" = "Appareil hors ligne"; +"设置" = "Réglages"; +"设置,有新版本" = "Paramètres, il existe une nouvelle version"; +"访问密码" = "Mot de passe d'accès"; +"访问密码错误,请重新输入。" = "Le mot de passe d'accès est erroné, veuillez le saisir à nouveau."; +"请求超时,尚未确认电脑的隐私屏状态" = "Le délai de demande a expiré et l'état de l'écran de confidentialité de l'ordinateur n'a pas été confirmé."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "Veuillez saisir un port compris entre 1 et 65 535 ou désactivez « Utiliser un serveur personnalisé »."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "Veuillez saisir l'adresse du serveur ou désactiver « Utiliser un serveur personnalisé »."; +"请输入远程设备 ID" = "Veuillez saisir l'ID de l'appareil distant"; +"调整失败,请重试。" = "Impossible d'appliquer les paramètres. Essayer à nouveau."; +"软件许可" = "Licence du logiciel"; +"返回控制栏" = "Retour à la barre de contrôle"; +"还没有连接记录" = "Aucun enregistrement de connexion pour l'instant"; +"这条公告已更新或删除,请返回公告列表查看。" = "Cette annonce a été mise à jour ou supprimée, veuillez revenir à la liste des annonces pour la consulter."; +"远程桌面" = "Bureau à distance"; +"远程设备 ID 不存在,请检查设备 ID。" = "L'ID de l'appareil distant n'existe pas, veuillez vérifier l'ID de l'appareil."; +"远程设备当前不可用,请稍后重试。" = "L'appareil distant est actuellement indisponible, veuillez réessayer plus tard."; +"远程连接已结束。" = "Connexion à distance terminée."; +"连接" = "Connecter"; +"连接延时(RTT)" = "Délai de connexion (RTT)"; +"连接建立后可调整,需被控端支持。" = "Disponible lors de la connexion à un appareil distant pris en charge."; +"连接建立后锁定横屏" = "Verrouiller l'écran paysage une fois la connexion établie"; +"连接提示" = "Invite de connexion"; +"连接方式" = "Méthode de connexion"; +"连接远程桌面" = "Connectez-vous au bureau à distance"; +"退格" = "Retour arrière"; +"通知公告" = "Annonces"; +"部分预览图未能清除,请重试。" = "Certains aperçus n'ont pas pu être effacés, veuillez réessayer."; +"重试" = "Réessayez"; +"重试保存阅读状态" = "Réessayez d'enregistrer l'état de lecture"; +"锁定" = "Verrouillage"; +"键盘" = "Clavier"; +"键盘操作" = "Fonctionnement du clavier"; +"阅读并授权" = "Lire et autoriser"; +"隐私" = "Confidentialité"; +"隐私与授权" = "Confidentialité et autorisation"; +"隐私屏" = "Écran de confidentialité"; +"隐私屏已关闭" = "Confidentialité inactive"; +"隐私屏已开启" = "Confidentialité active"; +"隐私屏已被解锁" = "Écran de confidentialité déverrouillé"; +"隐私屏异常" = "Anomalie de l'écran de confidentialité"; +"隐私屏暂不可用" = "L'écran de confidentialité est temporairement indisponible"; +"隐私屏状态已过期,等待电脑确认" = "L'état de l'écran de confidentialité a expiré, en attente de confirmation par l'ordinateur"; +"隐私屏状态待确认" = "Statut de l'écran de confidentialité à confirmer"; +"隐私政策" = "Politique de confidentialité"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "La politique de confidentialité ne peut pas être lue temporairement. Veuillez refuser de vous connecter à Internet et réinstaller l'application."; +"隐藏密码" = "Masquer le mot de passe"; +"静音" = "Muet"; +"音频" = "Audio"; +"项目主页" = "Site Web du projet"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "Les aperçus peuvent contenir des informations personnelles ou professionnelles provenant de l'ordinateur distant. Après l'avoir allumé, chaque connexion enregistrera automatiquement une image sur la machine et l'affichera dans les connexions récentes. Vous pouvez fermer et effacer à tout moment."; +"高" = "Élevée"; +"默认" = "Par défaut"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "Désactivé par défaut. Lorsqu'il est allumé, l'iPhone passe et reste en orientation paysage lorsqu'il est connecté ; lorsqu'il est éteint, il suit l'orientation de l'appareil. Les iPad ne sont pas concernés."; +"鼠标右键" = "Bouton droit de la souris"; +"鼠标左键" = "Bouton gauche de la souris"; +"鼠标控制" = "Contrôle de la souris"; +"鼠标滚轮" = "Molette de la souris"; diff --git a/apps/ios/CrossDeskMobile/Resources/ja.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/ja.lproj/InfoPlist.strings new file mode 100644 index 00000000..926361c8 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/ja.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDeskは、ローカル ネットワークを使用してネイティブ P2P リモート コントロール接続を検出し、確立します。"; diff --git a/apps/ios/CrossDeskMobile/Resources/ja.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/ja.lproj/Localizable.strings new file mode 100644 index 00000000..c8d28339 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/ja.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "%1$@送信失敗"; +"%1$@ 台设备" = "デバイス数: %1$@"; +"%1$@ 条未读" = "%1$@の未読アイテム"; +"%1$@键盘页" = "%1$@キーボードページ"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@、受信%2$@、送信%3$@、パケットロス率%4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDeskは、ローカル ネットワークを使用してネイティブ P2P リモート コントロール接続を検出し、確立します。"; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Delでは Windows システム サービスのリモート アクティベーションが必要です"; +"GNU GPL 第 3 版" = "GNU GPL バージョン 3"; +"OpenFEC 告知" = "OpenFEC通知"; +"OpenFEC 许可与源码" = "OpenFECライセンスとソース"; +"P2P 直连" = "P2P直接接続"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURNリンクの確立に失敗しました。ネットワークを確認して再試行してください。"; +"SRTP 已启用" = "SRT有効"; +"TLS 证书校验失败" = "TLS証明書の検証に失敗しました"; +"TURN 中继" = "ターンリレー"; +"上下滑动,可滑出按键范围" = "上下にスライドしてキー範囲外にスライドします"; +"丢包率" = "損失率"; +"中" = "中"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "画像を滑らかに保つことを優先し、帯域幅やエンコード圧力が高い場合には、より積極的に解像度を下げます。"; +"低" = "低"; +"使用自定义服务器" = "カスタムサーバーの使用"; +"保存密码" = "パスワードの保存"; +"保存远程画面预览" = "リモート画面のプレビューを保存する"; +"保存远程画面预览?" = "リモート画面のプレビューを保存しますか?"; +"信令服务器已关闭连接" = "シグナリングサーバーが接続を閉じました"; +"信令服务重连中" = "シグナリング サービスの再接続"; +"信令连接失败" = "シグナリング接続に失敗しました"; +"信令连接已关闭" = "信号接続が閉じられています"; +"偏好模式" = "プリファレンスモード"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "トラックパッドのようにカーソルをスライドさせ、クリックすると現在のカーソル位置を操作します。"; +"公告加载失败,请重试。" = "お知らせを読み込めませんでした。再試行してください。"; +"公告详情" = "発表内容"; +"共 %1$@ 条 · %2$@ 条未读" = "合計%1$@個のアイテム ·%2$@個の未読アイテム"; +"关于" = "概要"; +"关于 CrossDesk" = "CrossDesk について"; +"关于,有新版本" = "について、新しいバージョンがあります"; +"关闭" = "閉じる"; +"关闭控制栏" = "コントロールバーを閉じる"; +"关闭隐私屏" = "プライバシー画面を無効にする"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "明瞭さと滑らかさのバランスを保ち、一定の圧力下で解像度を徐々に低下させるだけです。"; +"分辨率" = "解像度"; +"切换到电脑键盘" = "コンピューターのキーボードに切り替える"; +"切换到系统键盘" = "システムキーボードに切り替える"; +"删除" = "削除"; +"删除公告" = "お知らせの削除"; +"删除记录" = "レコードの削除"; +"删除这条公告?" = "このお知らせを削除しますか?"; +"刷新公告" = "リフレッシュのお知らせ"; +"剪贴板" = "クリップボード"; +"剪贴板中没有文本" = "クリップボードにテキストがありません"; +"剪贴板文本超过 128 KiB" = "クリップボードのテキストが 128 KiB を超えています"; +"加载中…" = "読み込み中…"; +"加载更多" = "さらに読み込む"; +"升级提示" = "更新のご案内"; +"单次输入最多 16 KiB,且不能包含空字符" = "1 つの入力は最大 16 KiB であり、null 文字を含めることはできません"; +"发送" = "送信"; +"发送文件" = "ファイル送信"; +"取消" = "キャンセル"; +"取消连接" = "接続をキャンセルする"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "各コンポーネントは、リストされているオープン ソース ライセンスの対象となり、付与された権利は、このアプリケーションの一般的な使用条件の対象ではありません。ソース コードを表示するには、インターネット接続が必要です。"; +"合计" = "合計"; +"同意并继续" = "同意して続行"; +"回车" = "入る"; +"在线" = "オンライン"; +"地址" = "住所"; +"填写服务器地址" = "サーバーアドレスを入力します"; +"填写端口" = "ポートを記入します"; +"声音" = "サウンド"; +"失败" = "失敗しました"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "帯域幅が不十分な場合は、常に高い解像度を維持し、フレーム レートを下げて画像の鮮明さを確保します。"; +"媒体加密" = "メディアの暗号化"; +"字母数字" = "英数字"; +"完成" = "完了"; +"完成隐私授权后可检查更新" = "プライバシー認証を完了すると、アップデートを確認できます"; +"完成隐私授权后登记本机身份" = "プライバシー認証完了後、ローカル ID を登録します"; +"密码将安全保存在本机 Keychain 中" = "パスワードはローカルのキーチェーンに安全に保存されます"; +"对端 ID" = "リモートID"; +"对端 ID %1$@" = "ピアID%1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "リモート接続を停止し、画面プレビューの保存を閉じて、既存のプレビューをクリアします。接続記録と受信したファイルは保持され、既存のサーバー データは削除されません。いつでも再認証できます。"; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "本機に保存されているリモートプレビューはすべて削除されますが、接続記録、パスワード、受信したファイルは保持されます。"; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "本機に保存されているリモート プレビューはすべて削除されますが、接続記録、パスワード、受信したファイルは保持されます。後続の接続でも新しいプレビューが保存されます。"; +"屏幕方向" = "画面の向き"; +"展开远程控制菜单" = "リモコンメニューを展開する"; +"已保存密码" = "パスワード保存済み"; +"已勾选" = "チェックあり"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Delを送信しました"; +"已发送本机剪贴板" = "ローカルのクリップボードを送信しました"; +"已授权" = "認められる"; +"已接收 %1$@" = "%1$@を受け取りました"; +"已接收远端剪贴板" = "リモートクリップボードを受信しました"; +"已读" = "読む"; +"已连接" = "接続されました"; +"已连接服务器" = "サーバーに接続しました"; +"帧率" = "フレームレート"; +"帧率优先" = "滑らかさ"; +"平衡" = "バランス"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "アプリケーション内のライセンス ファイルが見つからないか破損しています。アプリケーションを再インストールしてください。"; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "開発バージョンには、まだリリースされていない修正が含まれています。以下のリンクは基本バージョンのソースコードです。"; +"开启保存" = "保存を有効にする"; +"开启隐私屏" = "プライバシー画面を有効にする"; +"开源组件" = "オープンソースコンポーネント"; +"开源软件权利说明" = "オープンソース ソフトウェアの権利の説明"; +"当前已是最新版本" = "これが現在の最新バージョンです"; +"成功连接后,这里会显示远端桌面的缩略图。" = "接続に成功すると、ここにリモート デスクトップのサムネイルが表示されます。"; +"我已阅读并同意《隐私政策》" = "プライバシーポリシーを読んで同意します"; +"我已阅读并同意隐私政策" = "プライバシーポリシーを読んで同意します"; +"打开隐私政策" = "オープンなプライバシーポリシー"; +"指令发送失败,请重试" = "コマンドの送信に失敗しました。もう一度お試しください。"; +"指令已发送,等待电脑确认…" = "コマンドが送信され、コンピューターの確認を待っています..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "押してドラッグするとキー範囲からスライドし、放すとドラッグが終了します"; +"授权后可使用远程连接。" = "認証後、リモート接続が可能になります。"; +"授权状态" = "認可ステータス"; +"接收" = "受信"; +"控制模式" = "制御モード"; +"控制端解码器" = "ローカルデコーダ"; +"撤回授权" = "認可の撤回"; +"撤回隐私授权" = "プライバシー認証の撤回"; +"收起电脑键盘" = "PC キーボードを隠す"; +"收起系统键盘" = "システムキーボードを折りたたむ"; +"收起远程控制菜单" = "リモコンメニューを折りたたむ"; +"收起鼠标" = "マウスを隠す"; +"数据" = "データ"; +"断开后将返回首页" = "切断後ホームページに戻ります"; +"断开远程连接?" = "リモート接続を切断しますか?"; +"断开连接" = "切断"; +"新版本" = "新しいバージョン"; +"新版本可用:v%1$@" = "利用可能な新しいバージョン: v%1$@"; +"无效" = "無効"; +"无未读公告" = "未読のお知らせはありません"; +"无法" = "できません"; +"无法保存本地阅读状态,请重试。" = "読み取りステータスをローカルに保存できません。もう一度試してください。"; +"无法删除这条公告,请重试。" = "このお知らせは削除できません。もう一度試してください。"; +"无法访问本机登录凭据,请解锁后重试" = "ローカル ログイン資格情報にアクセスできません。ロックを解除して再試行してください。"; +"无法读取开源许可" = "オープンソースライセンスを読み取れません"; +"无法读取所选文件,请重试" = "選択したファイルを読み取れません。もう一度お試しください。"; +"是否撤回隐私授权?" = "プライバシー認証を取り消しますか?"; +"显示器" = "ディスプレイ"; +"显示器 %1$@" = "モニター%1$@"; +"显示器 1" = "モニター1"; +"显示密码" = "パスワードを表示"; +"暂不同意" = "今は同意しない"; +"暂无公告" = "アナウンスはありません"; +"最近连接" = "最近の接続"; +"服务器" = "サーバー"; +"服务器地址" = "サーバーアドレス"; +"服务器端口" = "サーバーポート"; +"服务器配置无效" = "無効なサーバー構成"; +"未勾选" = "チェックなし"; +"未启用" = "有効ではありません"; +"未授权" = "無許可"; +"未知" = "不明"; +"未知信令状态" = "不明な信号ステータス"; +"未知连接状态" = "不明な接続ステータス"; +"未读" = "未読"; +"未连接" = "接続されていません"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "このアプリケーションは、限定保証を提供し、責任を制限するCeCILL-C1.0 に基づく前方誤り訂正にOpenFECを使用します。詳細については、完全なライセンスを参照してください。"; +"本机 ID %1$@" = "ローカルID%1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "このマシンのログイン資格情報は一時的に安全ではありません。デバイスのロックを解除し、設定で「適用」をクリックして再試行してください。"; +"本版本源码与构建说明" = "このバージョンのソース コードとビルド手順"; +"本版本源码信息暂不可用。" = "このビルドではソース リビジョンが利用できません。"; +"构建说明" = "組み立て説明書"; +"构建配方与项目补丁" = "ビルドレシピとプロジェクトパッチ"; +"查看源码" = "ソースコードを表示する"; +"检查失败,请稍后重试" = "チェックに失敗しました。後でもう一度試してください。"; +"检查更新" = "アップデートを確認する"; +"正在关闭隐私屏…" = "プライバシー画面を閉じています…"; +"正在准备连接…" = "接続準備中..."; +"正在发送 %1$@" = "%1$@の送信"; +"正在发送 Ctrl+Alt+Del…" = "Ctrl+Alt+Delを送信中 …"; +"正在取回远程画面…" = "リモート画面を取得中..."; +"正在建立远程连接" = "リモート接続の確立"; +"正在开启隐私屏…" = "プライバシー画面を有効化中…"; +"正在收集 ICE 候选" = "ICE 候補を収集中"; +"正在检查更新…" = "アップデートを確認しています…"; +"正在清除…" = "クリア中..."; +"正在确认设备状态…" = "機器の状態を確認しています..."; +"正在获取本机 ID…" = "ローカルIDを取得中..."; +"正在连接" = "接続する"; +"正在连接信令服务" = "シグナリングサービスへの接続"; +"清除" = "クリア"; +"清除预览图" = "プレビューを削除"; +"清除预览图?" = "プレビューを削除しますか?"; +"源码与构建说明" = "ソースコードとビルド手順"; +"源码版本" = "ソースコードのバージョン"; +"版本" = "バージョン"; +"版权与许可声明" = "著作権およびライセンスに関する声明"; +"电脑键盘" = "コンピューターのキーボード"; +"画中画未能开启,请保持应用在前台后重试。" = "ピクチャーインピクチャーを開けませんでした。アプリケーションをフォアグラウンドに保ち、もう一度お試しください。"; +"画质优先" = "画質"; +"画面偏好" = "ビデオ設定"; +"画面延时" = "映像遅延"; +"画面设置" = "ビデオ設定"; +"画面质量" = "ビデオ品質"; +"画面采集帧率" = "ビデオキャプチャフレームレート"; +"相对位置" = "トラックパッド"; +"相对鼠标" = "相対マウス"; +"知道了" = "分かりました"; +"确定" = "OK"; +"确认" = "確認する"; +"离线" = "オフライン"; +"空格" = "スペース"; +"端口" = "港"; +"符号功能" = "記号・機能"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "コンピューターがプライバシー画面の状態に戻るまで待ちます。古いコンピューターではサポートされていない可能性があります。"; +"等待连接" = "接続待ち"; +"等待隐私授权" = "プライバシー認証待ち"; +"系统键盘" = "システムキーボード"; +"绝对位置" = "直接タッチ"; +"绝对鼠标" = "アブソリュートマウス"; +"网络状态" = "ネットワーク"; +"网络连接已中断,请重新连接。" = "ネットワーク接続が切断されました。再接続してください。"; +"自定义" = "カスタム"; +"虚拟鼠标" = "仮想マウス"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "制御端末は中国語の直接入力をサポートしていません。macOS 制御端末を更新してください。最初にテキストをコピーし、リモート コントロール メニューのクリップボード経由で送信してから貼り付けることもできます。"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "ローカル ショートカットを使用してリモート プライバシー画面のロックが解除されました。再度ロックするとプライバシーが回復され、ローカル ショートカットのロック解除が無効になります。"; +"被控端平台:%1$@" = "制御端末プラットフォーム:%1$@"; +"被控端版本过低,请升级到最新版本。" = "管理されているバージョンが低すぎるため、最新バージョンにアップグレードしてください。"; +"被控端编码器" = "リモートエンコーダー"; +"视频" = "ビデオ"; +"视频 %1$@×%2$@ · %3$@ 帧" = "ビデオ%1$@×%2$@・%3$@フレーム"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "タッチ位置はリモート画面位置に直接対応するため、素早い位置決めに適しています。"; +"许可" = "ライセンス"; +"许可与版权声明" = "ライセンスと著作権表示"; +"许可与版权声明可离线查阅。" = "ライセンスと著作権表示はオフラインでも利用できます。"; +"设备离线" = "デバイスがオフライン"; +"设置" = "設定"; +"设置,有新版本" = "設定、新しいバージョンがあります"; +"访问密码" = "アクセスパスワード"; +"访问密码错误,请重新输入。" = "アクセスパスワードが間違っていますので、再度入力してください。"; +"请求超时,尚未确认电脑的隐私屏状态" = "リクエストがタイムアウトし、コンピュータのプライバシー画面の状態が確認できませんでした。"; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "1 ~ 65535 の範囲でポートを入力するか、「カスタム サーバーを使用する」をオフにしてください。"; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "サーバーアドレスを入力するか、「カスタムサーバーを使用する」をオフにしてください。"; +"请输入远程设备 ID" = "リモートデバイスIDを入力してください"; +"调整失败,请重试。" = "設定を適用できませんでした。もう一度やり直してください。"; +"软件许可" = "ソフトウェアライセンス"; +"返回控制栏" = "コントロールバーに戻る"; +"还没有连接记录" = "まだ接続実績がありません"; +"这条公告已更新或删除,请返回公告列表查看。" = "このお知らせは更新または削除されました。表示するにはお知らせリストに戻ってください。"; +"远程桌面" = "リモートデスクトップ"; +"远程设备 ID 不存在,请检查设备 ID。" = "リモートデバイス ID が存在しません。デバイス ID を確認してください。"; +"远程设备当前不可用,请稍后重试。" = "リモート デバイスは現在利用できません。後でもう一度試してください。"; +"远程连接已结束。" = "リモート接続が終了しました。"; +"连接" = "接続"; +"连接延时(RTT)" = "接続遅延 (RTT)"; +"连接建立后可调整,需被控端支持。" = "サポートされているリモート デバイスに接続されている場合に使用できます。"; +"连接建立后锁定横屏" = "接続完了後、横画面をロックする"; +"连接提示" = "接続プロンプト"; +"连接方式" = "接続方法"; +"连接远程桌面" = "リモートデスクトップに接続する"; +"退格" = "バックスペース"; +"通知公告" = "お知らせ"; +"部分预览图未能清除,请重试。" = "一部のプレビューをクリアできませんでした。もう一度お試しください。"; +"重试" = "もう一度お試しください"; +"重试保存阅读状态" = "読み取りステータスの保存をリトライする"; +"锁定" = "ロック"; +"键盘" = "キーボード"; +"键盘操作" = "キーボード操作"; +"阅读并授权" = "読んで承認する"; +"隐私" = "プライバシー"; +"隐私与授权" = "プライバシーと認証"; +"隐私屏" = "プライバシー画面"; +"隐私屏已关闭" = "プライバシー画面:オフ"; +"隐私屏已开启" = "プライバシー画面:オン"; +"隐私屏已被解锁" = "プライバシー画面のロックが解除されました"; +"隐私屏异常" = "プライバシー画面異常"; +"隐私屏暂不可用" = "プライバシー画面が一時的に利用できなくなります"; +"隐私屏状态已过期,等待电脑确认" = "プライバシー画面のステータスが期限切れになり、コンピュータの確認を待っています"; +"隐私屏状态待确认" = "プライバシー画面のステータスを確認する"; +"隐私政策" = "プライバシーポリシー"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "一時的にプライバシーポリシーが閲覧できなくなります。インターネットへの接続を拒否し、アプリケーションを再インストールしてください。"; +"隐藏密码" = "パスワードを隠す"; +"静音" = "ミュート"; +"音频" = "オーディオ"; +"项目主页" = "プロジェクトWebサイト"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "プレビューには、リモート コンピューターからの個人情報または仕事情報が含まれる場合があります。オンにすると、接続するたびにマシンに写真が自動的に保存され、最近の接続で表示されます。いつでも閉じてクリアできます。"; +"高" = "高"; +"默认" = "デフォルト"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "デフォルトではオフです。オンにすると、iPhone は接続時に横向きになり、横向きのままになります。オフにすると、デバイスの向きに従います。 iPad は影響を受けません。"; +"鼠标右键" = "マウスの右ボタン"; +"鼠标左键" = "マウスの左ボタン"; +"鼠标控制" = "マウスコントロール"; +"鼠标滚轮" = "マウスホイール"; diff --git a/apps/ios/CrossDeskMobile/Resources/ko.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/ko.lproj/InfoPlist.strings new file mode 100644 index 00000000..afe0f1bf --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/ko.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk는 로컬 네트워크를 사용하여 기본 P2P 원격 제어 연결을 검색하고 설정합니다."; diff --git a/apps/ios/CrossDeskMobile/Resources/ko.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/ko.lproj/Localizable.strings new file mode 100644 index 00000000..d246a7b6 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/ko.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "%1$@전송 실패"; +"%1$@ 台设备" = "기기: %1$@"; +"%1$@ 条未读" = "%1$@읽지 않은 항목"; +"%1$@键盘页" = "%1$@키보드 페이지"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, 수신%2$@, 송신%3$@, 패킷 손실률%4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk는 로컬 네트워크를 사용하여 기본 P2P 원격 제어 연결을 검색하고 설정합니다."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del에는 Windows 시스템 서비스의 원격 활성화가 필요합니다."; +"GNU GPL 第 3 版" = "GNU GPL 버전 3"; +"OpenFEC 告知" = "OpenFEC공지"; +"OpenFEC 许可与源码" = "OpenFEC라이선스 및 소스"; +"P2P 直连" = "P2P 직접 연결"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN링크 설정에 실패했습니다. 네트워크를 확인하고 다시 시도하십시오."; +"SRTP 已启用" = "SRTP 활성화됨"; +"TLS 证书校验失败" = "TLS인증서 확인 실패"; +"TURN 中继" = "TURN 릴레이"; +"上下滑动,可滑出按键范围" = "키 범위에서 벗어나려면 위아래로 슬라이드하세요."; +"丢包率" = "손실률"; +"中" = "중간"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "영상을 부드럽게 유지하는 데 우선 순위를 두며 대역폭이나 인코딩 압력이 높을 때 해상도를 더욱 적극적으로 줄입니다."; +"低" = "낮음"; +"使用自定义服务器" = "커스텀 서버 이용하기"; +"保存密码" = "비밀번호 저장"; +"保存远程画面预览" = "원격 화면 미리보기 저장"; +"保存远程画面预览?" = "원격 화면 미리보기를 저장하시겠습니까?"; +"信令服务器已关闭连接" = "시그널링 서버가 연결을 종료했습니다."; +"信令服务重连中" = "시그널링 서비스 재접속"; +"信令连接失败" = "시그널링 연결 실패"; +"信令连接已关闭" = "신호 연결이 닫혔습니다."; +"偏好模式" = "선호 모드"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "커서를 트랙패드처럼 밀어서 클릭하면 현재 커서 위치를 조작합니다."; +"公告加载失败,请重试。" = "공지사항 로딩에 실패했습니다. 다시 시도해주세요."; +"公告详情" = "공지사항"; +"共 %1$@ 条 · %2$@ 条未读" = "총%1$@항목 ·%2$@읽지 않은 항목"; +"关于" = "소개"; +"关于 CrossDesk" = "CrossDesk 정보"; +"关于,有新版本" = "새 버전이 있습니다."; +"关闭" = "닫기"; +"关闭控制栏" = "컨트롤 바 닫기"; +"关闭隐私屏" = "개인 정보 보호 화면 비활성화"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "선명도와 부드러움의 균형을 유지하며 일정한 압력을 가하면 해상도가 점차 감소합니다."; +"分辨率" = "해상도"; +"切换到电脑键盘" = "컴퓨터 키보드로 전환"; +"切换到系统键盘" = "시스템 키보드로 전환"; +"删除" = "삭제"; +"删除公告" = "공지사항 삭제"; +"删除记录" = "기록 삭제"; +"删除这条公告?" = "이 공지를 삭제하시겠습니까?"; +"刷新公告" = "새로고침 안내"; +"剪贴板" = "클립보드"; +"剪贴板中没有文本" = "클립보드에 텍스트가 없습니다."; +"剪贴板文本超过 128 KiB" = "클립보드 텍스트가 128KiB를 초과합니다."; +"加载中…" = "로드 중…"; +"加载更多" = "더 로드하기"; +"升级提示" = "업데이트 안내"; +"单次输入最多 16 KiB,且不能包含空字符" = "단일 입력은 최대 16KiB일 수 있으며 null 문자를 포함할 수 없습니다."; +"发送" = "송신"; +"发送文件" = "파일 보내기"; +"取消" = "취소"; +"取消连接" = "연결 취소"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "각 구성 요소에는 나열된 오픈 소스 라이선스가 적용되며 부여된 권리에는 이 애플리케이션의 일반 사용 약관이 적용되지 않습니다. 소스 코드를 보려면 인터넷 연결이 필요합니다."; +"合计" = "합계"; +"同意并继续" = "동의하고 계속하기"; +"回车" = "들어가다"; +"在线" = "온라인"; +"地址" = "주소"; +"填写服务器地址" = "서버 주소를 입력하세요"; +"填写端口" = "포트를 채워주세요"; +"声音" = "소리"; +"失败" = "실패"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "대역폭이 부족할 때 영상 선명도를 보장하려면 항상 더 높은 해상도를 유지하고 프레임 속도를 낮추십시오."; +"媒体加密" = "미디어 암호화"; +"字母数字" = "문자·숫자"; +"完成" = "완료"; +"完成隐私授权后可检查更新" = "개인정보 동의 완료 후 업데이트 내용을 확인할 수 있습니다."; +"完成隐私授权后登记本机身份" = "개인정보 인증 완료 후 로컬 신원 등록"; +"密码将安全保存在本机 Keychain 中" = "비밀번호는 로컬 키체인에 안전하게 저장됩니다."; +"对端 ID" = "원격 ID"; +"对端 ID %1$@" = "피어 ID%1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "원격 연결을 중지하고 화면 미리보기 저장을 닫은 후 기존 미리보기를 지웁니다. 접속 기록 및 수신 파일은 그대로 유지되며, 기존 서버 데이터는 삭제되지 않습니다. 언제든지 재승인할 수 있습니다."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "이 기기에 저장된 원격 미리보기는 모두 삭제되지만 연결 기록, 비밀번호 및 수신된 파일은 유지됩니다."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "이 기기에 저장된 원격 미리보기는 모두 삭제되지만 연결 기록, 비밀번호 및 수신된 파일은 유지됩니다. 후속 연결에서는 계속해서 새로운 미리보기가 저장됩니다."; +"屏幕方向" = "화면 방향"; +"展开远程控制菜单" = "원격제어 메뉴 확장"; +"已保存密码" = "비밀번호 저장됨"; +"已勾选" = "확인됨"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del가 전송되었습니다."; +"已发送本机剪贴板" = "로컬 클립보드 전송됨"; +"已授权" = "승인됨"; +"已接收 %1$@" = "%1$@수신됨"; +"已接收远端剪贴板" = "원격 클립보드 수신됨"; +"已读" = "읽기"; +"已连接" = "연결됨"; +"已连接服务器" = "서버에 연결됨"; +"帧率" = "프레임 속도"; +"帧率优先" = "부드러움"; +"平衡" = "균형"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "애플리케이션의 라이센스 파일이 없거나 손상되었습니다. 애플리케이션을 다시 설치하십시오."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "개발 버전에는 아직 출시되지 않은 수정 사항이 포함되어 있습니다. 다음 링크는 기본 버전의 소스 코드입니다."; +"开启保存" = "저장 사용"; +"开启隐私屏" = "개인 정보 보호 화면 활성화"; +"开源组件" = "오픈 소스 구성 요소"; +"开源软件权利说明" = "오픈소스 소프트웨어 권리 설명"; +"当前已是最新版本" = "현재 최신 버전입니다."; +"成功连接后,这里会显示远端桌面的缩略图。" = "성공적으로 연결되면 원격 데스크톱의 썸네일이 여기에 표시됩니다."; +"我已阅读并同意《隐私政策》" = "개인정보 보호정책을 읽었으며 이에 동의합니다."; +"我已阅读并同意隐私政策" = "개인정보취급방침을 읽었으며 이에 동의합니다."; +"打开隐私政策" = "공개 개인 정보 보호 정책"; +"指令发送失败,请重试" = "명령 전송에 실패했습니다. 다시 시도해 주세요."; +"指令已发送,等待电脑确认…" = "명령이 전송되었으며 컴퓨터 확인을 기다리고 있습니다..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "누르고 드래그하여 키 범위 밖으로 슬라이드하고, 드래그를 종료하려면 놓습니다."; +"授权后可使用远程连接。" = "인증 후 원격접속이 가능합니다."; +"授权状态" = "인증상태"; +"接收" = "수신"; +"控制模式" = "제어 모드"; +"控制端解码器" = "로컬 디코더"; +"撤回授权" = "철회 승인"; +"撤回隐私授权" = "개인정보 승인 철회"; +"收起电脑键盘" = "PC 키보드 숨기기"; +"收起系统键盘" = "시스템 키보드 축소"; +"收起远程控制菜单" = "리모컨 메뉴 접기"; +"收起鼠标" = "마우스 숨기기"; +"数据" = "데이터"; +"断开后将返回首页" = "연결을 끊으면 홈페이지로 돌아갑니다."; +"断开远程连接?" = "원격 연결을 끊으시겠습니까?"; +"断开连接" = "연결 해제"; +"新版本" = "새 버전"; +"新版本可用:v%1$@" = "새 버전 사용 가능: v%1$@"; +"无效" = "유효하지 않음"; +"无未读公告" = "읽지 않은 공지사항 없음"; +"无法" = "할 수 없다"; +"无法保存本地阅读状态,请重试。" = "읽기 상태를 로컬에 저장할 수 없습니다. 다시 시도해 주세요."; +"无法删除这条公告,请重试。" = "이 공지를 삭제할 수 없습니다. 다시 시도해 주세요."; +"无法访问本机登录凭据,请解锁后重试" = "로컬 로그인 자격 증명에 액세스할 수 없습니다. 잠금을 해제하고 다시 시도하십시오."; +"无法读取开源许可" = "오픈소스 라이선스를 읽을 수 없습니다."; +"无法读取所选文件,请重试" = "선택한 파일을 읽을 수 없습니다. 다시 시도해 주세요."; +"是否撤回隐私授权?" = "개인정보 보호 승인을 철회하시겠습니까?"; +"显示器" = "디스플레이"; +"显示器 %1$@" = "모니터%1$@"; +"显示器 1" = "모니터 1"; +"显示密码" = "비밀번호 표시"; +"暂不同意" = "나중에"; +"暂无公告" = "공지 없음"; +"最近连接" = "최근 연결"; +"服务器" = "서버"; +"服务器地址" = "서버 주소"; +"服务器端口" = "서버 포트"; +"服务器配置无效" = "잘못된 서버 구성"; +"未勾选" = "체크하지 않음"; +"未启用" = "활성화되지 않음"; +"未授权" = "무단"; +"未知" = "알 수 없음"; +"未知信令状态" = "알 수 없는 신호 상태"; +"未知连接状态" = "알 수 없는 연결 상태"; +"未读" = "읽지 않음"; +"未连接" = "연결되지 않음"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "이 애플리케이션은 제한된 보증과 책임 제한을 제공하는CeCILL-C1.0에 따라 순방향 오류 수정을 위해OpenFEC를 사용합니다. 자세한 내용은 전체 라이센스를 참조하세요."; +"本机 ID %1$@" = "로컬 ID%1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "이 시스템의 로그인 자격 증명은 일시적으로 안전하지 않습니다. 기기를 잠금 해제하고 설정에서 '적용'을 클릭하여 다시 시도하세요."; +"本版本源码与构建说明" = "이 버전의 소스 코드 및 빌드 지침"; +"本版本源码信息暂不可用。" = "이 빌드에는 소스 개정을 사용할 수 없습니다."; +"构建说明" = "빌드 지침"; +"构建配方与项目补丁" = "레시피 및 프로젝트 패치 빌드"; +"查看源码" = "소스코드 보기"; +"检查失败,请稍后重试" = "확인에 실패했습니다. 나중에 다시 시도해 주세요."; +"检查更新" = "업데이트 확인"; +"正在关闭隐私屏…" = "개인정보 보호 화면을 닫는 중…"; +"正在准备连接…" = "연결 준비 중..."; +"正在发送 %1$@" = "%1$@보내기"; +"正在发送 Ctrl+Alt+Del…" = "Ctrl+Alt+Del를 보내는 중…"; +"正在取回远程画面…" = "원격 화면을 검색하는 중..."; +"正在建立远程连接" = "원격 연결 설정"; +"正在开启隐私屏…" = "개인정보 보호 화면을 켜는 중..."; +"正在收集 ICE 候选" = "ICE후보 수집"; +"正在检查更新…" = "업데이트 확인 중…"; +"正在清除…" = "지우는 중..."; +"正在确认设备状态…" = "기기 상태를 확인하는 중..."; +"正在获取本机 ID…" = "로컬 ID를 얻는 중..."; +"正在连接" = "연결 중"; +"正在连接信令服务" = "시그널링 서비스 연결"; +"清除" = "클리어"; +"清除预览图" = "미리보기 삭제"; +"清除预览图?" = "미리보기를 삭제할까요?"; +"源码与构建说明" = "소스 코드 및 빌드 지침"; +"源码版本" = "소스코드 버전"; +"版本" = "버전"; +"版权与许可声明" = "저작권 및 라이선스 정책"; +"电脑键盘" = "컴퓨터 키보드"; +"画中画未能开启,请保持应用在前台后重试。" = "PIP(Picture-in-Picture)를 열지 못했습니다. 애플리케이션을 포그라운드에 두고 다시 시도하십시오."; +"画质优先" = "화질"; +"画面偏好" = "영상 선호도"; +"画面延时" = "영상 지연"; +"画面设置" = "영상 설정"; +"画面质量" = "비디오 품질"; +"画面采集帧率" = "비디오 캡처 프레임 속도"; +"相对位置" = "트랙패드"; +"相对鼠标" = "상대 마우스"; +"知道了" = "알겠습니다"; +"确定" = "알았어"; +"确认" = "확인"; +"离线" = "오프라인"; +"空格" = "스페이스"; +"端口" = "포트"; +"符号功能" = "기호·기능"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "컴퓨터가 개인 정보 보호 화면 상태로 돌아갈 때까지 기다립니다. 오래된 컴퓨터에서는 이를 지원하지 않을 수 있습니다."; +"等待连接" = "연결 대기 중"; +"等待隐私授权" = "개인정보 인증 대기 중"; +"系统键盘" = "시스템 키보드"; +"绝对位置" = "직접 터치"; +"绝对鼠标" = "앱솔루트 마우스"; +"网络状态" = "네트워크"; +"网络连接已中断,请重新连接。" = "네트워크 연결이 중단되었습니다. 다시 연결해 주세요."; +"自定义" = "커스텀"; +"虚拟鼠标" = "가상마우스"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "제어 터미널은 중국어 직접 입력을 지원하지 않습니다. macOS 제어 터미널을 업데이트하세요. 텍스트를 먼저 복사한 후 리모컨 메뉴의 클립보드를 통해 전송한 후 붙여넣을 수도 있습니다."; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "로컬 단축키를 사용하여 원격 개인정보 보호 화면을 잠금 해제했습니다. 개인정보 보호를 복원하고 로컬 바로가기 잠금 해제를 비활성화하려면 다시 잠그세요."; +"被控端平台:%1$@" = "제어 터미널 플랫폼:%1$@"; +"被控端版本过低,请升级到最新版本。" = "제어 버전이 너무 낮습니다. 최신 버전으로 업그레이드하세요."; +"被控端编码器" = "리모트 엔코더"; +"视频" = "영상"; +"视频 %1$@×%2$@ · %3$@ 帧" = "비디오%1$@×%2$@·%3$@프레임"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "터치 위치는 원격 화면 위치와 직접적으로 일치하므로 빠른 위치 지정에 적합합니다."; +"许可" = "라이센스"; +"许可与版权声明" = "라이센스 및 저작권 고지"; +"许可与版权声明可离线查阅。" = "라이센스 및 저작권 고지는 오프라인에서 확인할 수 있습니다."; +"设备离线" = "장치 오프라인"; +"设置" = "설정"; +"设置,有新版本" = "설정, 새 버전이 있습니다"; +"访问密码" = "접속 비밀번호"; +"访问密码错误,请重新输入。" = "접속비밀번호가 잘못되었습니다. 다시 입력해 주세요."; +"请求超时,尚未确认电脑的隐私屏状态" = "요청 시간이 초과되어 컴퓨터의 개인 정보 보호 화면 상태가 확인되지 않았습니다."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "1~65535 범위의 포트를 입력하거나 \"사용자 정의 서버 사용\"을 꺼주세요."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "서버 주소를 입력하시거나, \"커스텀 서버 사용\"을 꺼주세요."; +"请输入远程设备 ID" = "원격장치 ID를 입력해주세요."; +"调整失败,请重试。" = "설정을 적용할 수 없습니다. 다시 시도해 보세요."; +"软件许可" = "소프트웨어 라이센스"; +"返回控制栏" = "컨트롤 바로 돌아가기"; +"还没有连接记录" = "아직 접속기록이 없습니다"; +"这条公告已更新或删除,请返回公告列表查看。" = "본 공지사항은 업데이트 또는 삭제되었습니다. 공지사항 목록으로 돌아가서 확인하시기 바랍니다."; +"远程桌面" = "원격 데스크톱"; +"远程设备 ID 不存在,请检查设备 ID。" = "원격 장치 ID가 존재하지 않습니다. 장치 ID를 확인하십시오."; +"远程设备当前不可用,请稍后重试。" = "현재 원격 장치를 사용할 수 없습니다. 나중에 다시 시도하십시오."; +"远程连接已结束。" = "원격 연결이 종료되었습니다."; +"连接" = "연결"; +"连接延时(RTT)" = "연결 지연(RTT)"; +"连接建立后可调整,需被控端支持。" = "지원되는 원격 장치에 연결된 경우 사용할 수 있습니다."; +"连接建立后锁定横屏" = "연결 완료 후 가로 화면 잠금"; +"连接提示" = "연결 프롬프트"; +"连接方式" = "연결 방법"; +"连接远程桌面" = "원격 데스크톱에 연결"; +"退格" = "백스페이스"; +"通知公告" = "공지사항"; +"部分预览图未能清除,请重试。" = "일부 미리보기를 삭제할 수 없습니다. 다시 시도해 주세요."; +"重试" = "다시 시도해 보세요"; +"重试保存阅读状态" = "읽은 상태 저장 다시 시도"; +"锁定" = "잠금"; +"键盘" = "키보드"; +"键盘操作" = "키보드 조작"; +"阅读并授权" = "읽기 및 승인"; +"隐私" = "개인 정보 보호"; +"隐私与授权" = "개인 정보 보호 및 승인"; +"隐私屏" = "개인정보 보호 화면"; +"隐私屏已关闭" = "화면 보호 꺼짐"; +"隐私屏已开启" = "화면 보호 켜짐"; +"隐私屏已被解锁" = "개인정보 보호 화면 잠금 해제됨"; +"隐私屏异常" = "개인정보 화면 이상"; +"隐私屏暂不可用" = "개인 정보 보호 화면을 일시적으로 사용할 수 없습니다."; +"隐私屏状态已过期,等待电脑确认" = "개인 정보 보호 화면 상태가 만료되어 컴퓨터 확인을 기다리는 중입니다."; +"隐私屏状态待确认" = "개인정보 보호 화면 상태 확인 예정"; +"隐私政策" = "개인정보 보호정책"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "개인정보취급방침은 일시적으로 열람할 수 없습니다. 인터넷 연결을 거부하고 애플리케이션을 다시 설치하십시오."; +"隐藏密码" = "비밀번호 숨기기"; +"静音" = "음소거"; +"音频" = "오디오"; +"项目主页" = "프로젝트 홈페이지"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "미리보기에는 원격 컴퓨터의 개인 정보나 업무 정보가 포함될 수 있습니다. 전원을 켜면 각 연결이 자동으로 기기에 사진을 저장하고 최근 연결에 표시됩니다. 언제든지 닫고 지울 수 있습니다."; +"高" = "높음"; +"默认" = "기본값"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "기본적으로 꺼져 있습니다. iPhone을 켜면 연결 시 iPhone이 가로 방향으로 전환되어 유지됩니다. 꺼지면 장치 방향을 따릅니다. iPad는 영향을 받지 않습니다."; +"鼠标右键" = "마우스 오른쪽 버튼"; +"鼠标左键" = "마우스 왼쪽 버튼"; +"鼠标控制" = "마우스 제어"; +"鼠标滚轮" = "마우스 휠"; diff --git a/apps/ios/CrossDeskMobile/Resources/pt-BR.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/pt-BR.lproj/InfoPlist.strings new file mode 100644 index 00000000..5dd3c797 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/pt-BR.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk usa a rede local para descobrir e estabelecer conexões de controle remoto P2P nativas."; diff --git a/apps/ios/CrossDeskMobile/Resources/pt-BR.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/pt-BR.lproj/Localizable.strings new file mode 100644 index 00000000..3faa1b63 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/pt-BR.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "Falha na transmissão %1$@"; +"%1$@ 台设备" = "Dispositivos: %1$@"; +"%1$@ 条未读" = "Itens não lidos %1$@"; +"%1$@键盘页" = "Página do teclado %1$@"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, recebendo %2$@, enviando %3$@, taxa de perda de pacotes %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk usa a rede local para descobrir e estabelecer conexões de controle remoto P2P nativas."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del requer ativação remota dos serviços do sistema Windows"; +"GNU GPL 第 3 版" = "GNU GPL versão 3"; +"OpenFEC 告知" = "Aviso OpenFEC"; +"OpenFEC 许可与源码" = "Licença e fonte OpenFEC"; +"P2P 直连" = "Conexão direta P2P"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN Falha no estabelecimento do link, verifique a rede e tente novamente."; +"SRTP 已启用" = "SRT habilitado"; +"TLS 证书校验失败" = "Falha na verificação do certificado TLS"; +"TURN 中继" = "GIRAR relé"; +"上下滑动,可滑出按键范围" = "Deslize para cima e para baixo para sair do intervalo de teclas"; +"丢包率" = "Taxa de perda"; +"中" = "Média"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "Prioriza manter a imagem suave e reduzirá a resolução de forma mais agressiva quando a largura de banda ou a pressão de codificação forem altas."; +"低" = "Baixa"; +"使用自定义服务器" = "Usando um servidor personalizado"; +"保存密码" = "Salvar senha"; +"保存远程画面预览" = "Salvar visualizações de tela remotas"; +"保存远程画面预览?" = "Salvar visualização remota da tela?"; +"信令服务器已关闭连接" = "O servidor de sinalização fechou a conexão"; +"信令服务重连中" = "Reconexão do serviço de sinalização"; +"信令连接失败" = "Falha na conexão de sinalização"; +"信令连接已关闭" = "Conexão de sinalização fechada"; +"偏好模式" = "Modo de preferência"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "Deslize o cursor como um trackpad e opere a posição atual do cursor quando clicado."; +"公告加载失败,请重试。" = "Falha ao carregar o anúncio. Tente novamente."; +"公告详情" = "Detalhes do anúncio"; +"共 %1$@ 条 · %2$@ 条未读" = "Total de itens %1$@· Itens não lidos %2$@"; +"关于" = "Sobre"; +"关于 CrossDesk" = "Sobre o CrossDesk"; +"关于,有新版本" = "Sobre, há uma nova versão"; +"关闭" = "Fechar"; +"关闭控制栏" = "Fechar barra de controle"; +"关闭隐私屏" = "Desativar tela de privacidade"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "Equilibra clareza e suavidade, reduzindo apenas gradualmente a resolução sob pressão constante."; +"分辨率" = "Resolução"; +"切换到电脑键盘" = "Mudar para o teclado do computador"; +"切换到系统键盘" = "Mudar para o teclado do sistema"; +"删除" = "Excluir"; +"删除公告" = "Excluir anúncio"; +"删除记录" = "Excluir registro"; +"删除这条公告?" = "Excluir este anúncio?"; +"刷新公告" = "Anúncio de atualização"; +"剪贴板" = "Área de transferência"; +"剪贴板中没有文本" = "Nenhum texto na área de transferência"; +"剪贴板文本超过 128 KiB" = "O texto da área de transferência excede 128 KiB"; +"加载中…" = "Carregando…"; +"加载更多" = "Carregue mais"; +"升级提示" = "Atualização recomendada"; +"单次输入最多 16 KiB,且不能包含空字符" = "Uma única entrada pode ter até 16 KiB e não pode conter caracteres nulos"; +"发送" = "Enviar"; +"发送文件" = "Enviar arquivo"; +"取消" = "Cancelar"; +"取消连接" = "Cancelar conexão"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "Cada componente está sujeito à licença de código aberto listada e os direitos concedidos não estão sujeitos aos termos gerais de uso deste aplicativo. A visualização do código-fonte requer uma conexão com a Internet."; +"合计" = "Total"; +"同意并继续" = "Concorde e continue"; +"回车" = "Entrar"; +"在线" = "On-line"; +"地址" = "Endereço"; +"填写服务器地址" = "Preencha o endereço do servidor"; +"填写端口" = "Preencha a porta"; +"声音" = "Som"; +"失败" = "Falhou"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "Sempre mantenha uma resolução mais alta e reduza a taxa de quadros para garantir a clareza da imagem quando a largura de banda for insuficiente."; +"媒体加密" = "Criptografia de mídia"; +"字母数字" = "Letras e números"; +"完成" = "Feito"; +"完成隐私授权后可检查更新" = "Você pode verificar se há atualizações após concluir a autorização de privacidade"; +"完成隐私授权后登记本机身份" = "Registre a identidade local após concluir a autorização de privacidade"; +"密码将安全保存在本机 Keychain 中" = "As senhas serão armazenadas com segurança no chaveiro local"; +"对端 ID" = "ID remoto"; +"对端 ID %1$@" = "ID de par %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "Interromperá a conexão remota, fechará o salvamento da visualização da tela e limpará a visualização existente. Os registros de conexão e os arquivos recebidos serão retidos e os dados existentes do servidor não serão excluídos. Você pode reautorizar a qualquer momento."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "Todas as visualizações remotas salvas nesta máquina serão excluídas, enquanto os registros de conexão, senhas e arquivos recebidos serão mantidos."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "Todas as visualizações remotas salvas nesta máquina serão excluídas, enquanto os registros de conexão, senhas e arquivos recebidos serão mantidos. As conexões subsequentes ainda salvarão novas visualizações."; +"屏幕方向" = "Orientação da tela"; +"展开远程控制菜单" = "Expandir menu de controle remoto"; +"已保存密码" = "Senha salva"; +"已勾选" = "Verificado"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del enviado"; +"已发送本机剪贴板" = "Área de transferência local enviada"; +"已授权" = "Concedido"; +"已接收 %1$@" = "%1$@ recebido"; +"已接收远端剪贴板" = "Área de transferência remota recebida"; +"已读" = "Leia"; +"已连接" = "Conectado"; +"已连接服务器" = "Conectado ao servidor"; +"帧率" = "Taxa de quadros"; +"帧率优先" = "Fluidez"; +"平衡" = "Equilibrado"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "O arquivo de licença do aplicativo está ausente ou danificado. Reinstale o aplicativo."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "A versão de desenvolvimento contém modificações que ainda não foram lançadas. O link a seguir é o código fonte da versão básica."; +"开启保存" = "Ativar salvamento"; +"开启隐私屏" = "Habilitar tela de privacidade"; +"开源组件" = "Componentes de código aberto"; +"开源软件权利说明" = "Descrição dos direitos de software de código aberto"; +"当前已是最新版本" = "Esta é atualmente a versão mais recente"; +"成功连接后,这里会显示远端桌面的缩略图。" = "Após uma conexão bem-sucedida, uma miniatura da área de trabalho remota será exibida aqui."; +"我已阅读并同意《隐私政策》" = "Li e concordo com a Política de Privacidade"; +"我已阅读并同意隐私政策" = "Li e concordo com a política de privacidade"; +"打开隐私政策" = "Política de privacidade aberta"; +"指令发送失败,请重试" = "Falha no envio do comando, tente novamente"; +"指令已发送,等待电脑确认…" = "O comando foi enviado, aguardando confirmação do computador..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "Pressione e arraste para deslizar para fora do intervalo de teclas, solte para encerrar o arrasto"; +"授权后可使用远程连接。" = "Conexões remotas estão disponíveis após autorização."; +"授权状态" = "Status de autorização"; +"接收" = "Receber"; +"控制模式" = "Modo de controle"; +"控制端解码器" = "Decodificador local"; +"撤回授权" = "Retirar autorização"; +"撤回隐私授权" = "Retirar autorização de privacidade"; +"收起电脑键盘" = "Ocultar teclado do PC"; +"收起系统键盘" = "Recolher o teclado do sistema"; +"收起远程控制菜单" = "Recolher menu de controle remoto"; +"收起鼠标" = "Ocultar mouse"; +"数据" = "Dados"; +"断开后将返回首页" = "Retornará à página inicial após desconectar"; +"断开远程连接?" = "Desconectar a conexão remota?"; +"断开连接" = "Desconectar"; +"新版本" = "Nova versão"; +"新版本可用:v%1$@" = "Nova versão disponível: v%1$@"; +"无效" = "Inválido"; +"无未读公告" = "Nenhum anúncio não lido"; +"无法" = "Incapaz de"; +"无法保存本地阅读状态,请重试。" = "Não é possível salvar o status de leitura localmente. Por favor, tente novamente."; +"无法删除这条公告,请重试。" = "Não é possível excluir este anúncio. Por favor, tente novamente."; +"无法访问本机登录凭据,请解锁后重试" = "Não é possível acessar as credenciais de login locais, desbloqueie e tente novamente"; +"无法读取开源许可" = "Não é possível ler a licença de código aberto"; +"无法读取所选文件,请重试" = "Não foi possível ler o arquivo selecionado, tente novamente"; +"是否撤回隐私授权?" = "Retirar autorização de privacidade?"; +"显示器" = "Tela"; +"显示器 %1$@" = "Monitor %1$@"; +"显示器 1" = "Monitor 1"; +"显示密码" = "Mostrar senha"; +"暂不同意" = "Agora não"; +"暂无公告" = "Sem anúncios"; +"最近连接" = "Conexões recentes"; +"服务器" = "Servidor"; +"服务器地址" = "Endereço do servidor"; +"服务器端口" = "Porta do servidor"; +"服务器配置无效" = "Configuração de servidor inválida"; +"未勾选" = "Não verificado"; +"未启用" = "Não habilitado"; +"未授权" = "Não autorizado"; +"未知" = "Desconhecido"; +"未知信令状态" = "Status de sinalização desconhecido"; +"未知连接状态" = "Status de conexão desconhecido"; +"未读" = "Não lido"; +"未连接" = "Não conectado"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "Este aplicativo usa OpenFEC para correção direta de erros noCeCILL-C1.0, que fornece garantias limitadas e limita a responsabilidade. Veja a licença completa para detalhes."; +"本机 ID %1$@" = "ID local %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "As credenciais de login desta máquina são temporariamente inseguras. Desbloqueie seu dispositivo e clique em \"Aplicar\" nas configurações para tentar novamente."; +"本版本源码与构建说明" = "Código-fonte e instruções de construção para esta versão"; +"本版本源码信息暂不可用。" = "A revisão fonte não está disponível para esta compilação."; +"构建说明" = "Instruções de construção"; +"构建配方与项目补丁" = "Crie receitas e patches de projeto"; +"查看源码" = "Ver código-fonte"; +"检查失败,请稍后重试" = "Falha na verificação. Por favor, tente novamente mais tarde."; +"检查更新" = "Verifique se há atualizações"; +"正在关闭隐私屏…" = "Fechando a tela de privacidade…"; +"正在准备连接…" = "Preparando para conectar..."; +"正在发送 %1$@" = "Enviando %1$@"; +"正在发送 Ctrl+Alt+Del…" = "Enviando Ctrl+Alt+Del…"; +"正在取回远程画面…" = "Recuperando tela remota..."; +"正在建立远程连接" = "Estabelecendo conexão remota"; +"正在开启隐私屏…" = "Ativando a tela de privacidade..."; +"正在收集 ICE 候选" = "Coletando candidatos do ICE"; +"正在检查更新…" = "Verificando atualizações…"; +"正在清除…" = "Limpando..."; +"正在确认设备状态…" = "Confirmando o status do dispositivo..."; +"正在获取本机 ID…" = "Obtendo ID local..."; +"正在连接" = "Conectando"; +"正在连接信令服务" = "Conectando-se ao serviço de sinalização"; +"清除" = "Limpar"; +"清除预览图" = "Limpar prévias"; +"清除预览图?" = "Limpar prévias?"; +"源码与构建说明" = "Código-fonte e instruções de construção"; +"源码版本" = "Versão do código-fonte"; +"版本" = "Versão"; +"版权与许可声明" = "Declaração de direitos autorais e licença"; +"电脑键盘" = "Teclado de computador"; +"画中画未能开启,请保持应用在前台后重试。" = "Falha ao abrir o Picture-in-picture. Mantenha o aplicativo em primeiro plano e tente novamente."; +"画质优先" = "Qualidade"; +"画面偏好" = "Preferência de vídeo"; +"画面延时" = "Latência do vídeo"; +"画面设置" = "Configurações de vídeo"; +"画面质量" = "Qualidade de vídeo"; +"画面采集帧率" = "Taxa de quadros de captura de vídeo"; +"相对位置" = "Touchpad"; +"相对鼠标" = "Rato relativo"; +"知道了" = "Entendi"; +"确定" = "OK"; +"确认" = "Confirmar"; +"离线" = "Off-line"; +"空格" = "Espaço"; +"端口" = "Porto"; +"符号功能" = "Símbolos e teclas"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "Aguarde o computador retornar ao estado da tela de privacidade; computadores mais antigos podem não suportá-lo."; +"等待连接" = "Aguardando conexão"; +"等待隐私授权" = "Aguardando autorização de privacidade"; +"系统键盘" = "Teclado do sistema"; +"绝对位置" = "Toque direto"; +"绝对鼠标" = "Rato Absoluto"; +"网络状态" = "Rede"; +"网络连接已中断,请重新连接。" = "A conexão de rede foi interrompida, reconecte."; +"自定义" = "Personalizado"; +"虚拟鼠标" = "Rato virtual"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "O terminal controlado não suporta entrada direta de chinês. Atualize o terminal controlado pelo macOS; você também pode copiar o texto primeiro, enviá-lo pela área de transferência do menu do controle remoto e depois colá-lo"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "A tela de privacidade remota foi desbloqueada usando o atalho local. Bloqueie-o novamente para restaurar a privacidade e desativar o desbloqueio de atalhos locais."; +"被控端平台:%1$@" = "Plataforma de terminal controlada:%1$@"; +"被控端版本过低,请升级到最新版本。" = "A versão controlada é muito baixa, atualize para a versão mais recente."; +"被控端编码器" = "Codificador remoto"; +"视频" = "Vídeo"; +"视频 %1$@×%2$@ · %3$@ 帧" = "Vídeo %1$@×%2$@· Quadros %3$@"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "A posição de toque corresponde diretamente à posição da tela remota, que é adequada para posicionamento rápido."; +"许可" = "Licença"; +"许可与版权声明" = "Licenças e avisos de direitos autorais"; +"许可与版权声明可离线查阅。" = "A licença e o aviso de direitos autorais estão disponíveis offline."; +"设备离线" = "Dispositivo off-line"; +"设置" = "Configurações"; +"设置,有新版本" = "Configurações, há uma nova versão"; +"访问密码" = "Senha de acesso"; +"访问密码错误,请重新输入。" = "A senha de acesso está errada, digite-a novamente."; +"请求超时,尚未确认电脑的隐私屏状态" = "A solicitação expirou e o status da tela de privacidade do computador não foi confirmado."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "Insira uma porta no intervalo de 1 a 65535 ou desative \"Usar servidor personalizado\"."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "Insira o endereço do servidor ou desative \"Usar um servidor personalizado\"."; +"请输入远程设备 ID" = "Insira o ID do dispositivo remoto"; +"调整失败,请重试。" = "Não foi possível aplicar as configurações. Tente novamente."; +"软件许可" = "Licença de software"; +"返回控制栏" = "Retornar à barra de controle"; +"还没有连接记录" = "Ainda não há registro de conexão"; +"这条公告已更新或删除,请返回公告列表查看。" = "Este anúncio foi atualizado ou excluído. Volte à lista de anúncios para visualizá-lo."; +"远程桌面" = "Área de Trabalho Remota"; +"远程设备 ID 不存在,请检查设备 ID。" = "O ID do dispositivo remoto não existe, verifique o ID do dispositivo."; +"远程设备当前不可用,请稍后重试。" = "O dispositivo remoto não está disponível no momento. Tente novamente mais tarde."; +"远程连接已结束。" = "A conexão remota foi encerrada."; +"连接" = "Conectar"; +"连接延时(RTT)" = "Atraso de conexão (RTT)"; +"连接建立后可调整,需被控端支持。" = "Disponível quando conectado a um dispositivo remoto compatível."; +"连接建立后锁定横屏" = "Bloqueie a tela paisagem após a conexão ser estabelecida"; +"连接提示" = "Solicitação de conexão"; +"连接方式" = "Método de conexão"; +"连接远程桌面" = "Conecte-se à área de trabalho remota"; +"退格" = "Retrocesso"; +"通知公告" = "Avisos"; +"部分预览图未能清除,请重试。" = "Não foi possível limpar algumas visualizações. Tente novamente."; +"重试" = "Tente novamente"; +"重试保存阅读状态" = "Tente salvar novamente o status de leitura"; +"锁定" = "Bloqueio"; +"键盘" = "Teclado"; +"键盘操作" = "Operação do teclado"; +"阅读并授权" = "Ler e autorizar"; +"隐私" = "Privacidade"; +"隐私与授权" = "Privacidade e Autorização"; +"隐私屏" = "Tela de privacidade"; +"隐私屏已关闭" = "Privacidade desativada"; +"隐私屏已开启" = "Privacidade ativada"; +"隐私屏已被解锁" = "Tela de privacidade desbloqueada"; +"隐私屏异常" = "Anormalidade na tela de privacidade"; +"隐私屏暂不可用" = "A tela de privacidade está temporariamente indisponível"; +"隐私屏状态已过期,等待电脑确认" = "O status da tela de privacidade expirou, aguardando confirmação do computador"; +"隐私屏状态待确认" = "Status da tela de privacidade a ser confirmado"; +"隐私政策" = "Política de Privacidade"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "A política de privacidade não pode ser lida temporariamente. Recuse-se a se conectar à Internet e reinstale o aplicativo."; +"隐藏密码" = "Ocultar senha"; +"静音" = "Mudo"; +"音频" = "Áudio"; +"项目主页" = "Site do projeto"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "As visualizações podem conter informações pessoais ou de trabalho do computador remoto. Após ligá-lo, cada conexão salvará automaticamente uma imagem na máquina e a exibirá nas conexões recentes. Você pode fechar e limpar a qualquer momento."; +"高" = "Alta"; +"默认" = "Padrão"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "Desligado por padrão. Quando ligado, o iPhone entra e permanece na orientação paisagem quando conectado; quando desligado, segue a orientação do dispositivo. Os iPads não são afetados."; +"鼠标右键" = "Botão direito do mouse"; +"鼠标左键" = "Botão esquerdo do mouse"; +"鼠标控制" = "Controle do mouse"; +"鼠标滚轮" = "Roda do mouse"; diff --git a/apps/ios/CrossDeskMobile/Resources/pt.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/pt.lproj/InfoPlist.strings new file mode 100644 index 00000000..5dd3c797 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/pt.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk usa a rede local para descobrir e estabelecer conexões de controle remoto P2P nativas."; diff --git a/apps/ios/CrossDeskMobile/Resources/pt.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/pt.lproj/Localizable.strings new file mode 100644 index 00000000..3faa1b63 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/pt.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "Falha na transmissão %1$@"; +"%1$@ 台设备" = "Dispositivos: %1$@"; +"%1$@ 条未读" = "Itens não lidos %1$@"; +"%1$@键盘页" = "Página do teclado %1$@"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, recebendo %2$@, enviando %3$@, taxa de perda de pacotes %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk usa a rede local para descobrir e estabelecer conexões de controle remoto P2P nativas."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del requer ativação remota dos serviços do sistema Windows"; +"GNU GPL 第 3 版" = "GNU GPL versão 3"; +"OpenFEC 告知" = "Aviso OpenFEC"; +"OpenFEC 许可与源码" = "Licença e fonte OpenFEC"; +"P2P 直连" = "Conexão direta P2P"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN Falha no estabelecimento do link, verifique a rede e tente novamente."; +"SRTP 已启用" = "SRT habilitado"; +"TLS 证书校验失败" = "Falha na verificação do certificado TLS"; +"TURN 中继" = "GIRAR relé"; +"上下滑动,可滑出按键范围" = "Deslize para cima e para baixo para sair do intervalo de teclas"; +"丢包率" = "Taxa de perda"; +"中" = "Média"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "Prioriza manter a imagem suave e reduzirá a resolução de forma mais agressiva quando a largura de banda ou a pressão de codificação forem altas."; +"低" = "Baixa"; +"使用自定义服务器" = "Usando um servidor personalizado"; +"保存密码" = "Salvar senha"; +"保存远程画面预览" = "Salvar visualizações de tela remotas"; +"保存远程画面预览?" = "Salvar visualização remota da tela?"; +"信令服务器已关闭连接" = "O servidor de sinalização fechou a conexão"; +"信令服务重连中" = "Reconexão do serviço de sinalização"; +"信令连接失败" = "Falha na conexão de sinalização"; +"信令连接已关闭" = "Conexão de sinalização fechada"; +"偏好模式" = "Modo de preferência"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "Deslize o cursor como um trackpad e opere a posição atual do cursor quando clicado."; +"公告加载失败,请重试。" = "Falha ao carregar o anúncio. Tente novamente."; +"公告详情" = "Detalhes do anúncio"; +"共 %1$@ 条 · %2$@ 条未读" = "Total de itens %1$@· Itens não lidos %2$@"; +"关于" = "Sobre"; +"关于 CrossDesk" = "Sobre o CrossDesk"; +"关于,有新版本" = "Sobre, há uma nova versão"; +"关闭" = "Fechar"; +"关闭控制栏" = "Fechar barra de controle"; +"关闭隐私屏" = "Desativar tela de privacidade"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "Equilibra clareza e suavidade, reduzindo apenas gradualmente a resolução sob pressão constante."; +"分辨率" = "Resolução"; +"切换到电脑键盘" = "Mudar para o teclado do computador"; +"切换到系统键盘" = "Mudar para o teclado do sistema"; +"删除" = "Excluir"; +"删除公告" = "Excluir anúncio"; +"删除记录" = "Excluir registro"; +"删除这条公告?" = "Excluir este anúncio?"; +"刷新公告" = "Anúncio de atualização"; +"剪贴板" = "Área de transferência"; +"剪贴板中没有文本" = "Nenhum texto na área de transferência"; +"剪贴板文本超过 128 KiB" = "O texto da área de transferência excede 128 KiB"; +"加载中…" = "Carregando…"; +"加载更多" = "Carregue mais"; +"升级提示" = "Atualização recomendada"; +"单次输入最多 16 KiB,且不能包含空字符" = "Uma única entrada pode ter até 16 KiB e não pode conter caracteres nulos"; +"发送" = "Enviar"; +"发送文件" = "Enviar arquivo"; +"取消" = "Cancelar"; +"取消连接" = "Cancelar conexão"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "Cada componente está sujeito à licença de código aberto listada e os direitos concedidos não estão sujeitos aos termos gerais de uso deste aplicativo. A visualização do código-fonte requer uma conexão com a Internet."; +"合计" = "Total"; +"同意并继续" = "Concorde e continue"; +"回车" = "Entrar"; +"在线" = "On-line"; +"地址" = "Endereço"; +"填写服务器地址" = "Preencha o endereço do servidor"; +"填写端口" = "Preencha a porta"; +"声音" = "Som"; +"失败" = "Falhou"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "Sempre mantenha uma resolução mais alta e reduza a taxa de quadros para garantir a clareza da imagem quando a largura de banda for insuficiente."; +"媒体加密" = "Criptografia de mídia"; +"字母数字" = "Letras e números"; +"完成" = "Feito"; +"完成隐私授权后可检查更新" = "Você pode verificar se há atualizações após concluir a autorização de privacidade"; +"完成隐私授权后登记本机身份" = "Registre a identidade local após concluir a autorização de privacidade"; +"密码将安全保存在本机 Keychain 中" = "As senhas serão armazenadas com segurança no chaveiro local"; +"对端 ID" = "ID remoto"; +"对端 ID %1$@" = "ID de par %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "Interromperá a conexão remota, fechará o salvamento da visualização da tela e limpará a visualização existente. Os registros de conexão e os arquivos recebidos serão retidos e os dados existentes do servidor não serão excluídos. Você pode reautorizar a qualquer momento."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "Todas as visualizações remotas salvas nesta máquina serão excluídas, enquanto os registros de conexão, senhas e arquivos recebidos serão mantidos."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "Todas as visualizações remotas salvas nesta máquina serão excluídas, enquanto os registros de conexão, senhas e arquivos recebidos serão mantidos. As conexões subsequentes ainda salvarão novas visualizações."; +"屏幕方向" = "Orientação da tela"; +"展开远程控制菜单" = "Expandir menu de controle remoto"; +"已保存密码" = "Senha salva"; +"已勾选" = "Verificado"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del enviado"; +"已发送本机剪贴板" = "Área de transferência local enviada"; +"已授权" = "Concedido"; +"已接收 %1$@" = "%1$@ recebido"; +"已接收远端剪贴板" = "Área de transferência remota recebida"; +"已读" = "Leia"; +"已连接" = "Conectado"; +"已连接服务器" = "Conectado ao servidor"; +"帧率" = "Taxa de quadros"; +"帧率优先" = "Fluidez"; +"平衡" = "Equilibrado"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "O arquivo de licença do aplicativo está ausente ou danificado. Reinstale o aplicativo."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "A versão de desenvolvimento contém modificações que ainda não foram lançadas. O link a seguir é o código fonte da versão básica."; +"开启保存" = "Ativar salvamento"; +"开启隐私屏" = "Habilitar tela de privacidade"; +"开源组件" = "Componentes de código aberto"; +"开源软件权利说明" = "Descrição dos direitos de software de código aberto"; +"当前已是最新版本" = "Esta é atualmente a versão mais recente"; +"成功连接后,这里会显示远端桌面的缩略图。" = "Após uma conexão bem-sucedida, uma miniatura da área de trabalho remota será exibida aqui."; +"我已阅读并同意《隐私政策》" = "Li e concordo com a Política de Privacidade"; +"我已阅读并同意隐私政策" = "Li e concordo com a política de privacidade"; +"打开隐私政策" = "Política de privacidade aberta"; +"指令发送失败,请重试" = "Falha no envio do comando, tente novamente"; +"指令已发送,等待电脑确认…" = "O comando foi enviado, aguardando confirmação do computador..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "Pressione e arraste para deslizar para fora do intervalo de teclas, solte para encerrar o arrasto"; +"授权后可使用远程连接。" = "Conexões remotas estão disponíveis após autorização."; +"授权状态" = "Status de autorização"; +"接收" = "Receber"; +"控制模式" = "Modo de controle"; +"控制端解码器" = "Decodificador local"; +"撤回授权" = "Retirar autorização"; +"撤回隐私授权" = "Retirar autorização de privacidade"; +"收起电脑键盘" = "Ocultar teclado do PC"; +"收起系统键盘" = "Recolher o teclado do sistema"; +"收起远程控制菜单" = "Recolher menu de controle remoto"; +"收起鼠标" = "Ocultar mouse"; +"数据" = "Dados"; +"断开后将返回首页" = "Retornará à página inicial após desconectar"; +"断开远程连接?" = "Desconectar a conexão remota?"; +"断开连接" = "Desconectar"; +"新版本" = "Nova versão"; +"新版本可用:v%1$@" = "Nova versão disponível: v%1$@"; +"无效" = "Inválido"; +"无未读公告" = "Nenhum anúncio não lido"; +"无法" = "Incapaz de"; +"无法保存本地阅读状态,请重试。" = "Não é possível salvar o status de leitura localmente. Por favor, tente novamente."; +"无法删除这条公告,请重试。" = "Não é possível excluir este anúncio. Por favor, tente novamente."; +"无法访问本机登录凭据,请解锁后重试" = "Não é possível acessar as credenciais de login locais, desbloqueie e tente novamente"; +"无法读取开源许可" = "Não é possível ler a licença de código aberto"; +"无法读取所选文件,请重试" = "Não foi possível ler o arquivo selecionado, tente novamente"; +"是否撤回隐私授权?" = "Retirar autorização de privacidade?"; +"显示器" = "Tela"; +"显示器 %1$@" = "Monitor %1$@"; +"显示器 1" = "Monitor 1"; +"显示密码" = "Mostrar senha"; +"暂不同意" = "Agora não"; +"暂无公告" = "Sem anúncios"; +"最近连接" = "Conexões recentes"; +"服务器" = "Servidor"; +"服务器地址" = "Endereço do servidor"; +"服务器端口" = "Porta do servidor"; +"服务器配置无效" = "Configuração de servidor inválida"; +"未勾选" = "Não verificado"; +"未启用" = "Não habilitado"; +"未授权" = "Não autorizado"; +"未知" = "Desconhecido"; +"未知信令状态" = "Status de sinalização desconhecido"; +"未知连接状态" = "Status de conexão desconhecido"; +"未读" = "Não lido"; +"未连接" = "Não conectado"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "Este aplicativo usa OpenFEC para correção direta de erros noCeCILL-C1.0, que fornece garantias limitadas e limita a responsabilidade. Veja a licença completa para detalhes."; +"本机 ID %1$@" = "ID local %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "As credenciais de login desta máquina são temporariamente inseguras. Desbloqueie seu dispositivo e clique em \"Aplicar\" nas configurações para tentar novamente."; +"本版本源码与构建说明" = "Código-fonte e instruções de construção para esta versão"; +"本版本源码信息暂不可用。" = "A revisão fonte não está disponível para esta compilação."; +"构建说明" = "Instruções de construção"; +"构建配方与项目补丁" = "Crie receitas e patches de projeto"; +"查看源码" = "Ver código-fonte"; +"检查失败,请稍后重试" = "Falha na verificação. Por favor, tente novamente mais tarde."; +"检查更新" = "Verifique se há atualizações"; +"正在关闭隐私屏…" = "Fechando a tela de privacidade…"; +"正在准备连接…" = "Preparando para conectar..."; +"正在发送 %1$@" = "Enviando %1$@"; +"正在发送 Ctrl+Alt+Del…" = "Enviando Ctrl+Alt+Del…"; +"正在取回远程画面…" = "Recuperando tela remota..."; +"正在建立远程连接" = "Estabelecendo conexão remota"; +"正在开启隐私屏…" = "Ativando a tela de privacidade..."; +"正在收集 ICE 候选" = "Coletando candidatos do ICE"; +"正在检查更新…" = "Verificando atualizações…"; +"正在清除…" = "Limpando..."; +"正在确认设备状态…" = "Confirmando o status do dispositivo..."; +"正在获取本机 ID…" = "Obtendo ID local..."; +"正在连接" = "Conectando"; +"正在连接信令服务" = "Conectando-se ao serviço de sinalização"; +"清除" = "Limpar"; +"清除预览图" = "Limpar prévias"; +"清除预览图?" = "Limpar prévias?"; +"源码与构建说明" = "Código-fonte e instruções de construção"; +"源码版本" = "Versão do código-fonte"; +"版本" = "Versão"; +"版权与许可声明" = "Declaração de direitos autorais e licença"; +"电脑键盘" = "Teclado de computador"; +"画中画未能开启,请保持应用在前台后重试。" = "Falha ao abrir o Picture-in-picture. Mantenha o aplicativo em primeiro plano e tente novamente."; +"画质优先" = "Qualidade"; +"画面偏好" = "Preferência de vídeo"; +"画面延时" = "Latência do vídeo"; +"画面设置" = "Configurações de vídeo"; +"画面质量" = "Qualidade de vídeo"; +"画面采集帧率" = "Taxa de quadros de captura de vídeo"; +"相对位置" = "Touchpad"; +"相对鼠标" = "Rato relativo"; +"知道了" = "Entendi"; +"确定" = "OK"; +"确认" = "Confirmar"; +"离线" = "Off-line"; +"空格" = "Espaço"; +"端口" = "Porto"; +"符号功能" = "Símbolos e teclas"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "Aguarde o computador retornar ao estado da tela de privacidade; computadores mais antigos podem não suportá-lo."; +"等待连接" = "Aguardando conexão"; +"等待隐私授权" = "Aguardando autorização de privacidade"; +"系统键盘" = "Teclado do sistema"; +"绝对位置" = "Toque direto"; +"绝对鼠标" = "Rato Absoluto"; +"网络状态" = "Rede"; +"网络连接已中断,请重新连接。" = "A conexão de rede foi interrompida, reconecte."; +"自定义" = "Personalizado"; +"虚拟鼠标" = "Rato virtual"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "O terminal controlado não suporta entrada direta de chinês. Atualize o terminal controlado pelo macOS; você também pode copiar o texto primeiro, enviá-lo pela área de transferência do menu do controle remoto e depois colá-lo"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "A tela de privacidade remota foi desbloqueada usando o atalho local. Bloqueie-o novamente para restaurar a privacidade e desativar o desbloqueio de atalhos locais."; +"被控端平台:%1$@" = "Plataforma de terminal controlada:%1$@"; +"被控端版本过低,请升级到最新版本。" = "A versão controlada é muito baixa, atualize para a versão mais recente."; +"被控端编码器" = "Codificador remoto"; +"视频" = "Vídeo"; +"视频 %1$@×%2$@ · %3$@ 帧" = "Vídeo %1$@×%2$@· Quadros %3$@"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "A posição de toque corresponde diretamente à posição da tela remota, que é adequada para posicionamento rápido."; +"许可" = "Licença"; +"许可与版权声明" = "Licenças e avisos de direitos autorais"; +"许可与版权声明可离线查阅。" = "A licença e o aviso de direitos autorais estão disponíveis offline."; +"设备离线" = "Dispositivo off-line"; +"设置" = "Configurações"; +"设置,有新版本" = "Configurações, há uma nova versão"; +"访问密码" = "Senha de acesso"; +"访问密码错误,请重新输入。" = "A senha de acesso está errada, digite-a novamente."; +"请求超时,尚未确认电脑的隐私屏状态" = "A solicitação expirou e o status da tela de privacidade do computador não foi confirmado."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "Insira uma porta no intervalo de 1 a 65535 ou desative \"Usar servidor personalizado\"."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "Insira o endereço do servidor ou desative \"Usar um servidor personalizado\"."; +"请输入远程设备 ID" = "Insira o ID do dispositivo remoto"; +"调整失败,请重试。" = "Não foi possível aplicar as configurações. Tente novamente."; +"软件许可" = "Licença de software"; +"返回控制栏" = "Retornar à barra de controle"; +"还没有连接记录" = "Ainda não há registro de conexão"; +"这条公告已更新或删除,请返回公告列表查看。" = "Este anúncio foi atualizado ou excluído. Volte à lista de anúncios para visualizá-lo."; +"远程桌面" = "Área de Trabalho Remota"; +"远程设备 ID 不存在,请检查设备 ID。" = "O ID do dispositivo remoto não existe, verifique o ID do dispositivo."; +"远程设备当前不可用,请稍后重试。" = "O dispositivo remoto não está disponível no momento. Tente novamente mais tarde."; +"远程连接已结束。" = "A conexão remota foi encerrada."; +"连接" = "Conectar"; +"连接延时(RTT)" = "Atraso de conexão (RTT)"; +"连接建立后可调整,需被控端支持。" = "Disponível quando conectado a um dispositivo remoto compatível."; +"连接建立后锁定横屏" = "Bloqueie a tela paisagem após a conexão ser estabelecida"; +"连接提示" = "Solicitação de conexão"; +"连接方式" = "Método de conexão"; +"连接远程桌面" = "Conecte-se à área de trabalho remota"; +"退格" = "Retrocesso"; +"通知公告" = "Avisos"; +"部分预览图未能清除,请重试。" = "Não foi possível limpar algumas visualizações. Tente novamente."; +"重试" = "Tente novamente"; +"重试保存阅读状态" = "Tente salvar novamente o status de leitura"; +"锁定" = "Bloqueio"; +"键盘" = "Teclado"; +"键盘操作" = "Operação do teclado"; +"阅读并授权" = "Ler e autorizar"; +"隐私" = "Privacidade"; +"隐私与授权" = "Privacidade e Autorização"; +"隐私屏" = "Tela de privacidade"; +"隐私屏已关闭" = "Privacidade desativada"; +"隐私屏已开启" = "Privacidade ativada"; +"隐私屏已被解锁" = "Tela de privacidade desbloqueada"; +"隐私屏异常" = "Anormalidade na tela de privacidade"; +"隐私屏暂不可用" = "A tela de privacidade está temporariamente indisponível"; +"隐私屏状态已过期,等待电脑确认" = "O status da tela de privacidade expirou, aguardando confirmação do computador"; +"隐私屏状态待确认" = "Status da tela de privacidade a ser confirmado"; +"隐私政策" = "Política de Privacidade"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "A política de privacidade não pode ser lida temporariamente. Recuse-se a se conectar à Internet e reinstale o aplicativo."; +"隐藏密码" = "Ocultar senha"; +"静音" = "Mudo"; +"音频" = "Áudio"; +"项目主页" = "Site do projeto"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "As visualizações podem conter informações pessoais ou de trabalho do computador remoto. Após ligá-lo, cada conexão salvará automaticamente uma imagem na máquina e a exibirá nas conexões recentes. Você pode fechar e limpar a qualquer momento."; +"高" = "Alta"; +"默认" = "Padrão"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "Desligado por padrão. Quando ligado, o iPhone entra e permanece na orientação paisagem quando conectado; quando desligado, segue a orientação do dispositivo. Os iPads não são afetados."; +"鼠标右键" = "Botão direito do mouse"; +"鼠标左键" = "Botão esquerdo do mouse"; +"鼠标控制" = "Controle do mouse"; +"鼠标滚轮" = "Roda do mouse"; diff --git a/apps/ios/CrossDeskMobile/Resources/ru.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/ru.lproj/InfoPlist.strings new file mode 100644 index 00000000..76350606 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/ru.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk использует локальную сеть для обнаружения и установления собственных P2P-соединений удаленного управления."; diff --git a/apps/ios/CrossDeskMobile/Resources/ru.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/ru.lproj/Localizable.strings new file mode 100644 index 00000000..3b129c74 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/ru.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "Передача %1$@ не удалась."; +"%1$@ 台设备" = "Устройства: %1$@"; +"%1$@ 条未读" = "%1$@ непрочитанные элементы"; +"%1$@键盘页" = "Страница клавиатуры %1$@"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@, прием %2$@, отправка %3$@, скорость потери пакетов %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk использует локальную сеть для обнаружения и установления собственных P2P-соединений удаленного управления."; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del требует удаленной активации системных служб Windows."; +"GNU GPL 第 3 版" = "GNU GPL версия 3"; +"OpenFEC 告知" = "Уведомление OpenFEC"; +"OpenFEC 许可与源码" = "Лицензия и исходный код OpenFEC"; +"P2P 直连" = "Прямое соединение P2P"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN Не удалось установить соединение. Проверьте сеть и повторите попытку."; +"SRTP 已启用" = "SRTP включен"; +"TLS 证书校验失败" = "Проверка TLS certificate не удалась."; +"TURN 中继" = "Реле ПОВОРОТА"; +"上下滑动,可滑出按键范围" = "Сдвиньте вверх и вниз, чтобы выйти за пределы диапазона клавиш."; +"丢包率" = "Потери пакетов"; +"中" = "Среднее"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "Отдает приоритет сохранению плавности изображения и более агрессивно снижает разрешение при высокой пропускной способности или нагрузке на кодирование."; +"低" = "Низкое"; +"使用自定义服务器" = "Использование пользовательского сервера"; +"保存密码" = "Сохранить пароль"; +"保存远程画面预览" = "Сохранять превью удалённого экрана"; +"保存远程画面预览?" = "Сохранить предварительный просмотр удаленного экрана?"; +"信令服务器已关闭连接" = "Сервер сигнализации закрыл соединение."; +"信令服务重连中" = "Повторное подключение услуги сигнализации"; +"信令连接失败" = "Не удалось установить сигнальное соединение."; +"信令连接已关闭" = "Сигнальное соединение закрыто"; +"偏好模式" = "Режим предпочтений"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "Перемещайте курсор, как трекпад, и управляйте текущим положением курсора при нажатии."; +"公告加载失败,请重试。" = "Не удалось загрузить объявление. Повторите попытку."; +"公告详情" = "Подробности объявления"; +"共 %1$@ 条 · %2$@ 条未读" = "Всего элементов %1$@· Непрочитанные элементы %2$@"; +"关于" = "О программе"; +"关于 CrossDesk" = "О CrossDesk"; +"关于,有新版本" = "О, вышла новая версия"; +"关闭" = "Закрыть"; +"关闭控制栏" = "Закрыть панель управления"; +"关闭隐私屏" = "Выключить приватный экран"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "Балансирует четкость и плавность изображения, постепенно снижая разрешение под постоянным давлением."; +"分辨率" = "Разрешение"; +"切换到电脑键盘" = "Переключение на клавиатуру компьютера."; +"切换到系统键盘" = "Переключение на системную клавиатуру"; +"删除" = "Удалить"; +"删除公告" = "Удалить объявление"; +"删除记录" = "Удалить запись"; +"删除这条公告?" = "Удалить это объявление?"; +"刷新公告" = "Обновить объявление"; +"剪贴板" = "Буфер обмена"; +"剪贴板中没有文本" = "Нет текста в буфере обмена."; +"剪贴板文本超过 128 KiB" = "Размер текста в буфере обмена превышает 128 КиБ."; +"加载中…" = "Загрузка…"; +"加载更多" = "Загрузить еще"; +"升级提示" = "Рекомендуется обновление"; +"单次输入最多 16 KiB,且不能包含空字符" = "Один ввод может иметь размер до 16 КиБ и не может содержать нулевые символы."; +"发送" = "Отправка"; +"发送文件" = "Отправить файл"; +"取消" = "Отмена"; +"取消连接" = "Отмена соединения"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "На каждый компонент распространяется действие указанной лицензии с открытым исходным кодом, а предоставленные права не подпадают под действие общих условий использования этого приложения. Для просмотра исходного кода требуется подключение к Интернету."; +"合计" = "Итого"; +"同意并继续" = "Согласитесь и продолжайте."; +"回车" = "Ввести"; +"在线" = "В сети"; +"地址" = "Адрес"; +"填写服务器地址" = "Введите адрес сервера"; +"填写端口" = "Заполните порт"; +"声音" = "Звук"; +"失败" = "Ошибка"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "Всегда поддерживайте более высокое разрешение и уменьшайте частоту кадров, чтобы обеспечить четкость изображения при недостаточной полосе пропускания."; +"媒体加密" = "Шифрование мультимедиа"; +"字母数字" = "Буквы и цифры"; +"完成" = "Готово"; +"完成隐私授权后可检查更新" = "Вы можете проверить наличие обновлений после завершения авторизации конфиденциальности."; +"完成隐私授权后登记本机身份" = "Зарегистрируйте локальную личность после завершения авторизации конфиденциальности."; +"密码将安全保存在本机 Keychain 中" = "Пароли будут безопасно храниться в локальной связке ключей."; +"对端 ID" = "Удаленный ID"; +"对端 ID %1$@" = "Идентификатор узла %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "Остановит удаленное соединение, закроет сохранение предварительного просмотра экрана и очистит существующий предварительный просмотр. Записи подключений и полученные файлы сохранятся, а существующие данные сервера не будут удалены. Вы можете повторно авторизоваться в любое время."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "Все удаленные предварительные просмотры, сохраненные на этом компьютере, будут удалены, а записи подключений, пароли и полученные файлы сохранятся."; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "Все удаленные предварительные просмотры, сохраненные на этом компьютере, будут удалены, а записи подключений, пароли и полученные файлы сохранятся. Последующие подключения по-прежнему будут сохранять новые предварительные просмотры."; +"屏幕方向" = "Ориентация экрана"; +"展开远程控制菜单" = "Развернуть меню пульта дистанционного управления"; +"已保存密码" = "Пароль сохранён"; +"已勾选" = "Проверено"; +"已发送 Ctrl+Alt+Del" = "Ctrl+Alt+Del отправлено"; +"已发送本机剪贴板" = "Локальный буфер отправлен"; +"已授权" = "Разрешено"; +"已接收 %1$@" = "Получено %1$@"; +"已接收远端剪贴板" = "Получен удаленный буфер обмена."; +"已读" = "Прочитано"; +"已连接" = "Подключено"; +"已连接服务器" = "Подключено к серверу"; +"帧率" = "Частота кадров"; +"帧率优先" = "Плавность"; +"平衡" = "Баланс"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "Файл лицензии в приложении отсутствует или поврежден, переустановите приложение."; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "Версия для разработки содержит модификации, которые еще не были выпущены. По следующей ссылке приведен исходный код базовой версии."; +"开启保存" = "Включить сохранение"; +"开启隐私屏" = "Включить приватный экран"; +"开源组件" = "Компоненты с открытым кодом"; +"开源软件权利说明" = "Описание прав на программное обеспечение с открытым исходным кодом."; +"当前已是最新版本" = "На данный момент это последняя версия."; +"成功连接后,这里会显示远端桌面的缩略图。" = "После успешного подключения здесь отобразится миниатюра удаленного рабочего стола."; +"我已阅读并同意《隐私政策》" = "Я прочитал и согласен с Политикой конфиденциальности."; +"我已阅读并同意隐私政策" = "Я прочитал и согласен с политикой конфиденциальности."; +"打开隐私政策" = "Открытая политика конфиденциальности"; +"指令发送失败,请重试" = "Не удалось отправить команду. Повторите попытку."; +"指令已发送,等待电脑确认…" = "Команда отправлена, ждём подтверждения от компьютера..."; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "Нажмите и перетащите, чтобы выйти за пределы диапазона клавиш, отпустите, чтобы завершить перетаскивание."; +"授权后可使用远程连接。" = "Удаленные подключения доступны после авторизации."; +"授权状态" = "Статус авторизации"; +"接收" = "Приём"; +"控制模式" = "Режим управления"; +"控制端解码器" = "Локальный декодер"; +"撤回授权" = "Отозвать разрешение"; +"撤回隐私授权" = "Отозвать разрешение на конфиденциальность"; +"收起电脑键盘" = "Скрыть клавиатуру ПК"; +"收起系统键盘" = "Свернуть системную клавиатуру"; +"收起远程控制菜单" = "Свернуть меню пульта дистанционного управления"; +"收起鼠标" = "Скрыть мышь"; +"数据" = "Данные"; +"断开后将返回首页" = "Вернется на домашнюю страницу после отключения."; +"断开远程连接?" = "Отключить удаленное соединение?"; +"断开连接" = "Отключить"; +"新版本" = "Новая версия"; +"新版本可用:v%1$@" = "Доступна новая версия: v%1$@"; +"无效" = "Недействительно"; +"无未读公告" = "Нет непрочитанных объявлений"; +"无法" = "Невозможно"; +"无法保存本地阅读状态,请重试。" = "Не удалось сохранить статус чтения локально. Повторите попытку."; +"无法删除这条公告,请重试。" = "Не удалось удалить объявление. Повторите попытку."; +"无法访问本机登录凭据,请解锁后重试" = "Невозможно получить доступ к локальным учетным данным для входа. Разблокируйте и повторите попытку."; +"无法读取开源许可" = "Невозможно прочитать лицензию с открытым исходным кодом."; +"无法读取所选文件,请重试" = "Невозможно прочитать выбранный файл, попробуйте еще раз."; +"是否撤回隐私授权?" = "Отозвать разрешение на конфиденциальность?"; +"显示器" = "Экран"; +"显示器 %1$@" = "Монитор %1$@"; +"显示器 1" = "Монитор 1"; +"显示密码" = "Показать пароль"; +"暂不同意" = "Не сейчас"; +"暂无公告" = "Нет объявлений"; +"最近连接" = "Недавние связи"; +"服务器" = "Сервер"; +"服务器地址" = "Адрес сервера"; +"服务器端口" = "Порт сервера"; +"服务器配置无效" = "Неверная конфигурация сервера."; +"未勾选" = "Не отмечено"; +"未启用" = "Не включено"; +"未授权" = "Несанкционированное"; +"未知" = "Неизвестно"; +"未知信令状态" = "Неизвестный статус сигнализации"; +"未知连接状态" = "Неизвестный статус соединения"; +"未读" = "Не прочитано"; +"未连接" = "Нет соединения"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "Приложение использует OpenFEC для прямого исправления ошибок по лицензии CeCILL-C 1.0 с ограниченной гарантией и ответственностью. Подробности — в тексте лицензии."; +"本机 ID %1$@" = "Локальный идентификатор %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "Учетные данные для входа на этот компьютер временно небезопасны. Пожалуйста, разблокируйте свое устройство и нажмите «Применить» в настройках, чтобы повторить попытку."; +"本版本源码与构建说明" = "Исходный код и инструкции по сборке этой версии."; +"本版本源码信息暂不可用。" = "Ревизия исходного кода этой сборки недоступна."; +"构建说明" = "Инструкции по сборке"; +"构建配方与项目补丁" = "Рецепты сборки и исправления проектов."; +"查看源码" = "Открыть исходный код"; +"检查失败,请稍后重试" = "Не удалось проверить обновления. Повторите позже."; +"检查更新" = "Проверить обновления"; +"正在关闭隐私屏…" = "Закрытие экрана конфиденциальности…"; +"正在准备连接…" = "Подготовка к подключению..."; +"正在发送 %1$@" = "Отправка %1$@"; +"正在发送 Ctrl+Alt+Del…" = "Отправка Ctrl+Alt+Del…"; +"正在取回远程画面…" = "Получение удаленного экрана..."; +"正在建立远程连接" = "Установление удаленного соединения"; +"正在开启隐私屏…" = "Включение экрана конфиденциальности..."; +"正在收集 ICE 候选" = "Сбор кандидатов ICE"; +"正在检查更新…" = "Проверка обновлений…"; +"正在清除…" = "Очистка..."; +"正在确认设备状态…" = "Подтверждение статуса устройства..."; +"正在获取本机 ID…" = "Получение локального идентификатора..."; +"正在连接" = "Подключение"; +"正在连接信令服务" = "Подключение к службе сигнализации"; +"清除" = "Очистить"; +"清除预览图" = "Удалить превью"; +"清除预览图?" = "Удалить превью?"; +"源码与构建说明" = "Исходный код и сборка"; +"源码版本" = "Версия исходного кода"; +"版本" = "Версия"; +"版权与许可声明" = "Положение об авторских правах и лицензии."; +"电脑键盘" = "Компьютерная клавиатура"; +"画中画未能开启,请保持应用在前台后重试。" = "Не удалось открыть функцию «Картинка в картинке». Оставьте приложение на переднем плане и повторите попытку."; +"画质优先" = "Качество"; +"画面偏好" = "Режим видео"; +"画面延时" = "Задержка видео"; +"画面设置" = "Настройки видео"; +"画面质量" = "Качество видео"; +"画面采集帧率" = "Частота захвата видео"; +"相对位置" = "Тачпад"; +"相对鼠标" = "Родственная мышь"; +"知道了" = "Понятно"; +"确定" = "ОК"; +"确认" = "Подтвердить"; +"离线" = "Не в сети"; +"空格" = "Пробел"; +"端口" = "Порт"; +"符号功能" = "Символы и клавиши"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "Подождите, пока компьютер вернется в состояние экрана конфиденциальности; старые компьютеры могут его не поддерживать."; +"等待连接" = "Ожидание соединения"; +"等待隐私授权" = "Ожидание разрешения на конфиденциальность."; +"系统键盘" = "Системная клавиатура"; +"绝对位置" = "Касание"; +"绝对鼠标" = "Абсолютная мышь"; +"网络状态" = "Сеть"; +"网络连接已中断,请重新连接。" = "Сетевое соединение прервано, подключитесь заново."; +"自定义" = "Пользовательский"; +"虚拟鼠标" = "Виртуальная мышь"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "Управляемый терминал не поддерживает прямой ввод китайского языка, обновите управляемый терминал macOS; вы также можете сначала скопировать текст, отправить его через буфер обмена меню пульта дистанционного управления, а затем вставить"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "Приватный экран отключён локальным сочетанием клавиш. Заблокируйте его снова, чтобы восстановить защиту и запретить локальную разблокировку."; +"被控端平台:%1$@" = "Управляемая терминальная платформа:%1$@."; +"被控端版本过低,请升级到最新版本。" = "Управляемая версия слишком низкая, обновите ее до последней версии."; +"被控端编码器" = "Кодер удалённой стороны"; +"视频" = "Видео"; +"视频 %1$@×%2$@ · %3$@ 帧" = "Видео %1$@×%2$@·%3$@ кадры"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "Положение касания напрямую соответствует положению удаленного экрана, что подходит для быстрого позиционирования."; +"许可" = "Лицензия"; +"许可与版权声明" = "Лицензии и авторские права"; +"许可与版权声明可离线查阅。" = "Лицензия и уведомление об авторских правах доступны в автономном режиме."; +"设备离线" = "Устройство не в сети"; +"设置" = "Настройки"; +"设置,有新版本" = "Настройки, есть новая версия"; +"访问密码" = "Пароль доступа"; +"访问密码错误,请重新输入。" = "Неверный пароль доступа, пожалуйста, введите его еще раз."; +"请求超时,尚未确认电脑的隐私屏状态" = "Время ожидания запроса истекло, а состояние экрана конфиденциальности компьютера не подтверждено."; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "Введите порт в диапазоне 1–65535 или отключите параметр «Использовать собственный сервер»."; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "Введите адрес сервера или отключите параметр «Использовать собственный сервер»."; +"请输入远程设备 ID" = "Введите идентификатор удаленного устройства."; +"调整失败,请重试。" = "Не удалось применить настройки. Повторите попытку."; +"软件许可" = "Лицензия программы"; +"返回控制栏" = "Возврат к панели управления."; +"还没有连接记录" = "Пока нет записей о подключении"; +"这条公告已更新或删除,请返回公告列表查看。" = "Это объявление было обновлено или удалено. Чтобы просмотреть его, вернитесь к списку объявлений."; +"远程桌面" = "Удаленный рабочий стол"; +"远程设备 ID 不存在,请检查设备 ID。" = "Идентификатор удаленного устройства не существует, проверьте идентификатор устройства."; +"远程设备当前不可用,请稍后重试。" = "Удаленное устройство в настоящее время недоступно. Повторите попытку позже."; +"远程连接已结束。" = "Удаленное соединение прервано."; +"连接" = "Подключиться"; +"连接延时(RTT)" = "Задержка соединения (RTT)"; +"连接建立后可调整,需被控端支持。" = "Доступно при подключении к поддерживаемому устройству."; +"连接建立后锁定横屏" = "Блокировка горизонтального экрана после установления соединения."; +"连接提示" = "Запрос на подключение"; +"连接方式" = "Способ подключения"; +"连接远程桌面" = "Подключение к удаленному рабочему столу"; +"退格" = "Возврат"; +"通知公告" = "Объявления"; +"部分预览图未能清除,请重试。" = "Некоторые предварительные просмотры не удалось удалить. Повторите попытку."; +"重试" = "Попробуйте еще раз"; +"重试保存阅读状态" = "Повторить попытку сохранения статуса чтения."; +"锁定" = "Заблокировать"; +"键盘" = "Клавиатура"; +"键盘操作" = "Работа с клавиатурой"; +"阅读并授权" = "Прочитать и авторизоваться"; +"隐私" = "Конфиденциальность"; +"隐私与授权" = "Конфиденциальность и авторизация"; +"隐私屏" = "Приватный экран"; +"隐私屏已关闭" = "Приватный экран выкл."; +"隐私屏已开启" = "Приватный экран вкл."; +"隐私屏已被解锁" = "Приватный экран разблокирован"; +"隐私屏异常" = "Неисправность экрана конфиденциальности."; +"隐私屏暂不可用" = "Экран конфиденциальности временно недоступен."; +"隐私屏状态已过期,等待电脑确认" = "Срок действия статуса экрана конфиденциальности истек, ожидание подтверждения от компьютера."; +"隐私屏状态待确认" = "Статус экрана конфиденциальности подлежит подтверждению."; +"隐私政策" = "Политика конфиденциальности"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "Политику конфиденциальности временно невозможно прочитать. Пожалуйста, откажитесь от подключения к Интернету и переустановите приложение."; +"隐藏密码" = "Скрыть пароль"; +"静音" = "Без звука"; +"音频" = "Аудио"; +"项目主页" = "Сайт проекта"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "Предварительный просмотр может содержать личную или рабочую информацию с удаленного компьютера. После его включения каждое подключение будет автоматически сохранять изображение на устройстве и отображать его при последних подключениях. Вы можете закрыть и очистить в любое время."; +"高" = "Высокое"; +"默认" = "По умолчанию"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "По умолчанию выключено. При включении iPhone переходит в альбомную ориентацию и остается при подключении; в выключенном состоянии он следует ориентации устройства. iPad не затрагивается."; +"鼠标右键" = "Правая кнопка мыши"; +"鼠标左键" = "Левая кнопка мыши"; +"鼠标控制" = "Управление мышью"; +"鼠标滚轮" = "Колесо мыши"; diff --git a/apps/ios/CrossDeskMobile/Resources/zh-Hans.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/zh-Hans.lproj/InfoPlist.strings new file mode 100644 index 00000000..86877d5d --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/zh-Hans.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。"; diff --git a/apps/ios/CrossDeskMobile/Resources/zh-Hans.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/zh-Hans.lproj/Localizable.strings new file mode 100644 index 00000000..71d20c62 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "%1$@ 传输失败"; +"%1$@ 台设备" = "%1$@ 台设备"; +"%1$@ 条未读" = "%1$@ 条未读"; +"%1$@键盘页" = "%1$@键盘页"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。"; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del 需要远端启用 Windows 系统服务"; +"GNU GPL 第 3 版" = "GNU GPL 第 3 版"; +"OpenFEC 告知" = "OpenFEC 告知"; +"OpenFEC 许可与源码" = "OpenFEC 许可与源码"; +"P2P 直连" = "P2P 直连"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN 建链失败,请检查网络后重试。"; +"SRTP 已启用" = "SRTP 已启用"; +"TLS 证书校验失败" = "TLS 证书校验失败"; +"TURN 中继" = "TURN 中继"; +"上下滑动,可滑出按键范围" = "上下滑动,可滑出按键范围"; +"丢包率" = "丢包率"; +"中" = "中"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。"; +"低" = "低"; +"使用自定义服务器" = "使用自定义服务器"; +"保存密码" = "保存密码"; +"保存远程画面预览" = "保存远程画面预览"; +"保存远程画面预览?" = "保存远程画面预览?"; +"信令服务器已关闭连接" = "信令服务器已关闭连接"; +"信令服务重连中" = "信令服务重连中"; +"信令连接失败" = "信令连接失败"; +"信令连接已关闭" = "信令连接已关闭"; +"偏好模式" = "偏好模式"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "像触控板一样滑动光标,点击时操作当前光标位置。"; +"公告加载失败,请重试。" = "公告加载失败,请重试。"; +"公告详情" = "公告详情"; +"共 %1$@ 条 · %2$@ 条未读" = "共 %1$@ 条 · %2$@ 条未读"; +"关于" = "关于"; +"关于 CrossDesk" = "关于 CrossDesk"; +"关于,有新版本" = "关于,有新版本"; +"关闭" = "关闭"; +"关闭控制栏" = "关闭控制栏"; +"关闭隐私屏" = "关闭隐私屏"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。"; +"分辨率" = "分辨率"; +"切换到电脑键盘" = "切换到电脑键盘"; +"切换到系统键盘" = "切换到系统键盘"; +"删除" = "删除"; +"删除公告" = "删除公告"; +"删除记录" = "删除记录"; +"删除这条公告?" = "删除这条公告?"; +"刷新公告" = "刷新公告"; +"剪贴板" = "剪贴板"; +"剪贴板中没有文本" = "剪贴板中没有文本"; +"剪贴板文本超过 128 KiB" = "剪贴板文本超过 128 KiB"; +"加载中…" = "加载中…"; +"加载更多" = "加载更多"; +"升级提示" = "升级提示"; +"单次输入最多 16 KiB,且不能包含空字符" = "单次输入最多 16 KiB,且不能包含空字符"; +"发送" = "发送"; +"发送文件" = "发送文件"; +"取消" = "取消"; +"取消连接" = "取消连接"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。"; +"合计" = "合计"; +"同意并继续" = "同意并继续"; +"回车" = "回车"; +"在线" = "在线"; +"地址" = "地址"; +"填写服务器地址" = "填写服务器地址"; +"填写端口" = "填写端口"; +"声音" = "声音"; +"失败" = "失败"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。"; +"媒体加密" = "媒体加密"; +"字母数字" = "字母数字"; +"完成" = "完成"; +"完成隐私授权后可检查更新" = "完成隐私授权后可检查更新"; +"完成隐私授权后登记本机身份" = "完成隐私授权后登记本机身份"; +"密码将安全保存在本机 Keychain 中" = "密码将安全保存在本机 Keychain 中"; +"对端 ID" = "对端 ID"; +"对端 ID %1$@" = "对端 ID %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。"; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。"; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。"; +"屏幕方向" = "屏幕方向"; +"展开远程控制菜单" = "展开远程控制菜单"; +"已保存密码" = "已保存密码"; +"已勾选" = "已勾选"; +"已发送 Ctrl+Alt+Del" = "已发送 Ctrl+Alt+Del"; +"已发送本机剪贴板" = "已发送本机剪贴板"; +"已授权" = "已授权"; +"已接收 %1$@" = "已接收 %1$@"; +"已接收远端剪贴板" = "已接收远端剪贴板"; +"已读" = "已读"; +"已连接" = "已连接"; +"已连接服务器" = "已连接服务器"; +"帧率" = "帧率"; +"帧率优先" = "帧率优先"; +"平衡" = "平衡"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "应用中的许可文件缺失或损坏,请重新安装应用。"; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "开发版本包含尚未发布的修改,以下链接为基础版本源码。"; +"开启保存" = "开启保存"; +"开启隐私屏" = "开启隐私屏"; +"开源组件" = "开源组件"; +"开源软件权利说明" = "开源软件权利说明"; +"当前已是最新版本" = "当前已是最新版本"; +"成功连接后,这里会显示远端桌面的缩略图。" = "成功连接后,这里会显示远端桌面的缩略图。"; +"我已阅读并同意《隐私政策》" = "我已阅读并同意《隐私政策》"; +"我已阅读并同意隐私政策" = "我已阅读并同意隐私政策"; +"打开隐私政策" = "打开隐私政策"; +"指令发送失败,请重试" = "指令发送失败,请重试"; +"指令已发送,等待电脑确认…" = "指令已发送,等待电脑确认…"; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "按住并拖动,可滑出按键范围,松开结束拖拽"; +"授权后可使用远程连接。" = "授权后可使用远程连接。"; +"授权状态" = "授权状态"; +"接收" = "接收"; +"控制模式" = "控制模式"; +"控制端解码器" = "控制端解码器"; +"撤回授权" = "撤回授权"; +"撤回隐私授权" = "撤回隐私授权"; +"收起电脑键盘" = "收起电脑键盘"; +"收起系统键盘" = "收起系统键盘"; +"收起远程控制菜单" = "收起远程控制菜单"; +"收起鼠标" = "收起鼠标"; +"数据" = "数据"; +"断开后将返回首页" = "断开后将返回首页"; +"断开远程连接?" = "断开远程连接?"; +"断开连接" = "断开连接"; +"新版本" = "新版本"; +"新版本可用:v%1$@" = "新版本可用:v%1$@"; +"无效" = "无效"; +"无未读公告" = "无未读公告"; +"无法" = "无法"; +"无法保存本地阅读状态,请重试。" = "无法保存本地阅读状态,请重试。"; +"无法删除这条公告,请重试。" = "无法删除这条公告,请重试。"; +"无法访问本机登录凭据,请解锁后重试" = "无法访问本机登录凭据,请解锁后重试"; +"无法读取开源许可" = "无法读取开源许可"; +"无法读取所选文件,请重试" = "无法读取所选文件,请重试"; +"是否撤回隐私授权?" = "是否撤回隐私授权?"; +"显示器" = "显示器"; +"显示器 %1$@" = "显示器 %1$@"; +"显示器 1" = "显示器 1"; +"显示密码" = "显示密码"; +"暂不同意" = "暂不同意"; +"暂无公告" = "暂无公告"; +"最近连接" = "最近连接"; +"服务器" = "服务器"; +"服务器地址" = "服务器地址"; +"服务器端口" = "服务器端口"; +"服务器配置无效" = "服务器配置无效"; +"未勾选" = "未勾选"; +"未启用" = "未启用"; +"未授权" = "未授权"; +"未知" = "未知"; +"未知信令状态" = "未知信令状态"; +"未知连接状态" = "未知连接状态"; +"未读" = "未读"; +"未连接" = "未连接"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。"; +"本机 ID %1$@" = "本机 ID %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。"; +"本版本源码与构建说明" = "本版本源码与构建说明"; +"本版本源码信息暂不可用。" = "本版本源码信息暂不可用。"; +"构建说明" = "构建说明"; +"构建配方与项目补丁" = "构建配方与项目补丁"; +"查看源码" = "查看源码"; +"检查失败,请稍后重试" = "检查失败,请稍后重试"; +"检查更新" = "检查更新"; +"正在关闭隐私屏…" = "正在关闭隐私屏…"; +"正在准备连接…" = "正在准备连接…"; +"正在发送 %1$@" = "正在发送 %1$@"; +"正在发送 Ctrl+Alt+Del…" = "正在发送 Ctrl+Alt+Del…"; +"正在取回远程画面…" = "正在取回远程画面…"; +"正在建立远程连接" = "正在建立远程连接"; +"正在开启隐私屏…" = "正在开启隐私屏…"; +"正在收集 ICE 候选" = "正在收集 ICE 候选"; +"正在检查更新…" = "正在检查更新…"; +"正在清除…" = "正在清除…"; +"正在确认设备状态…" = "正在确认设备状态…"; +"正在获取本机 ID…" = "正在获取本机 ID…"; +"正在连接" = "正在连接"; +"正在连接信令服务" = "正在连接信令服务"; +"清除" = "清除"; +"清除预览图" = "清除预览图"; +"清除预览图?" = "清除预览图?"; +"源码与构建说明" = "源码与构建说明"; +"源码版本" = "源码版本"; +"版本" = "版本"; +"版权与许可声明" = "版权与许可声明"; +"电脑键盘" = "电脑键盘"; +"画中画未能开启,请保持应用在前台后重试。" = "画中画未能开启,请保持应用在前台后重试。"; +"画质优先" = "画质优先"; +"画面偏好" = "画面偏好"; +"画面延时" = "画面延时"; +"画面设置" = "画面设置"; +"画面质量" = "画面质量"; +"画面采集帧率" = "画面采集帧率"; +"相对位置" = "相对位置"; +"相对鼠标" = "相对鼠标"; +"知道了" = "知道了"; +"确定" = "确定"; +"确认" = "确认"; +"离线" = "离线"; +"空格" = "空格"; +"端口" = "端口"; +"符号功能" = "符号功能"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "等待电脑返回隐私屏状态;旧版电脑端可能不支持"; +"等待连接" = "等待连接"; +"等待隐私授权" = "等待隐私授权"; +"系统键盘" = "系统键盘"; +"绝对位置" = "绝对位置"; +"绝对鼠标" = "绝对鼠标"; +"网络状态" = "网络状态"; +"网络连接已中断,请重新连接。" = "网络连接已中断,请重新连接。"; +"自定义" = "自定义"; +"虚拟鼠标" = "虚拟鼠标"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。"; +"被控端平台:%1$@" = "被控端平台:%1$@"; +"被控端版本过低,请升级到最新版本。" = "被控端版本过低,请升级到最新版本。"; +"被控端编码器" = "被控端编码器"; +"视频" = "视频"; +"视频 %1$@×%2$@ · %3$@ 帧" = "视频 %1$@×%2$@ · %3$@ 帧"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "触摸位置直接对应远端屏幕位置,适合快速定位。"; +"许可" = "许可"; +"许可与版权声明" = "许可与版权声明"; +"许可与版权声明可离线查阅。" = "许可与版权声明可离线查阅。"; +"设备离线" = "设备离线"; +"设置" = "设置"; +"设置,有新版本" = "设置,有新版本"; +"访问密码" = "访问密码"; +"访问密码错误,请重新输入。" = "访问密码错误,请重新输入。"; +"请求超时,尚未确认电脑的隐私屏状态" = "请求超时,尚未确认电脑的隐私屏状态"; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。"; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "请输入服务器地址,或关闭“使用自定义服务器”。"; +"请输入远程设备 ID" = "请输入远程设备 ID"; +"调整失败,请重试。" = "调整失败,请重试。"; +"软件许可" = "软件许可"; +"返回控制栏" = "返回控制栏"; +"还没有连接记录" = "还没有连接记录"; +"这条公告已更新或删除,请返回公告列表查看。" = "这条公告已更新或删除,请返回公告列表查看。"; +"远程桌面" = "远程桌面"; +"远程设备 ID 不存在,请检查设备 ID。" = "远程设备 ID 不存在,请检查设备 ID。"; +"远程设备当前不可用,请稍后重试。" = "远程设备当前不可用,请稍后重试。"; +"远程连接已结束。" = "远程连接已结束。"; +"连接" = "连接"; +"连接延时(RTT)" = "连接延时(RTT)"; +"连接建立后可调整,需被控端支持。" = "连接建立后可调整,需被控端支持。"; +"连接建立后锁定横屏" = "连接建立后锁定横屏"; +"连接提示" = "连接提示"; +"连接方式" = "连接方式"; +"连接远程桌面" = "连接远程桌面"; +"退格" = "退格"; +"通知公告" = "通知公告"; +"部分预览图未能清除,请重试。" = "部分预览图未能清除,请重试。"; +"重试" = "重试"; +"重试保存阅读状态" = "重试保存阅读状态"; +"锁定" = "锁定"; +"键盘" = "键盘"; +"键盘操作" = "键盘操作"; +"阅读并授权" = "阅读并授权"; +"隐私" = "隐私"; +"隐私与授权" = "隐私与授权"; +"隐私屏" = "隐私屏"; +"隐私屏已关闭" = "隐私屏已关闭"; +"隐私屏已开启" = "隐私屏已开启"; +"隐私屏已被解锁" = "隐私屏已被解锁"; +"隐私屏异常" = "隐私屏异常"; +"隐私屏暂不可用" = "隐私屏暂不可用"; +"隐私屏状态已过期,等待电脑确认" = "隐私屏状态已过期,等待电脑确认"; +"隐私屏状态待确认" = "隐私屏状态待确认"; +"隐私政策" = "隐私政策"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "隐私政策暂时无法读取,请拒绝联网并重新安装应用。"; +"隐藏密码" = "隐藏密码"; +"静音" = "静音"; +"音频" = "音频"; +"项目主页" = "项目主页"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。"; +"高" = "高"; +"默认" = "默认"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。"; +"鼠标右键" = "鼠标右键"; +"鼠标左键" = "鼠标左键"; +"鼠标控制" = "鼠标控制"; +"鼠标滚轮" = "鼠标滚轮"; diff --git a/apps/ios/CrossDeskMobile/Resources/zh-Hant.lproj/InfoPlist.strings b/apps/ios/CrossDeskMobile/Resources/zh-Hant.lproj/InfoPlist.strings new file mode 100644 index 00000000..6c635271 --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/zh-Hant.lproj/InfoPlist.strings @@ -0,0 +1 @@ +"NSLocalNetworkUsageDescription" = "CrossDesk 使用區域網發現並建立原生 P2P 遠端控制連線。"; diff --git a/apps/ios/CrossDeskMobile/Resources/zh-Hant.lproj/Localizable.strings b/apps/ios/CrossDeskMobile/Resources/zh-Hant.lproj/Localizable.strings new file mode 100644 index 00000000..44c680be --- /dev/null +++ b/apps/ios/CrossDeskMobile/Resources/zh-Hant.lproj/Localizable.strings @@ -0,0 +1,283 @@ +// Generated by localization/generate.py. +"%1$@ 传输失败" = "%1$@ 傳輸失敗"; +"%1$@ 台设备" = "%1$@ 臺裝置"; +"%1$@ 条未读" = "%1$@ 條未讀"; +"%1$@键盘页" = "%1$@鍵盤頁"; +"%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@" = "%1$@,接收 %2$@,傳送 %3$@,丟包率 %4$@"; +"CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。" = "CrossDesk 使用區域網發現並建立原生 P2P 遠端控制連線。"; +"Ctrl+Alt+Del 需要远端启用 Windows 系统服务" = "Ctrl+Alt+Del 需要遠端啟用 Windows 系統服務"; +"GNU GPL 第 3 版" = "GNU GPL 第 3 版"; +"OpenFEC 告知" = "OpenFEC 告知"; +"OpenFEC 许可与源码" = "OpenFEC 許可與原始碼"; +"P2P 直连" = "P2P 直連"; +"P2P/TURN 建链失败,请检查网络后重试。" = "P2P/TURN 建鏈失敗,請檢查網路後重試。"; +"SRTP 已启用" = "SRTP 已啟用"; +"TLS 证书校验失败" = "TLS 證書校驗失敗"; +"TURN 中继" = "TURN 中繼"; +"上下滑动,可滑出按键范围" = "上下滑動,可滑出按鍵範圍"; +"丢包率" = "丟包率"; +"中" = "中"; +"优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。" = "優先保持畫面流暢,頻寬或編碼壓力較大時會更積極地降低解析度。"; +"低" = "低"; +"使用自定义服务器" = "使用自定義伺服器"; +"保存密码" = "儲存密碼"; +"保存远程画面预览" = "儲存遠端畫面預覽"; +"保存远程画面预览?" = "儲存遠端畫面預覽?"; +"信令服务器已关闭连接" = "信令伺服器已關閉連線"; +"信令服务重连中" = "信令服務重連中"; +"信令连接失败" = "信令連線失敗"; +"信令连接已关闭" = "信令連線已關閉"; +"偏好模式" = "偏好模式"; +"像触控板一样滑动光标,点击时操作当前光标位置。" = "像觸控板一樣滑動游標,點選時操作當前游標位置。"; +"公告加载失败,请重试。" = "公告載入失敗,請重試。"; +"公告详情" = "公告詳情"; +"共 %1$@ 条 · %2$@ 条未读" = "共 %1$@ 條 · %2$@ 條未讀"; +"关于" = "關於"; +"关于 CrossDesk" = "關於 CrossDesk"; +"关于,有新版本" = "關於,有新版本"; +"关闭" = "關閉"; +"关闭控制栏" = "關閉控制欄"; +"关闭隐私屏" = "關閉隱私屏"; +"兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。" = "兼顧清晰度和流暢度,只在持續壓力下逐步降低解析度。"; +"分辨率" = "解析度"; +"切换到电脑键盘" = "切換到電腦鍵盤"; +"切换到系统键盘" = "切換到系統鍵盤"; +"删除" = "刪除"; +"删除公告" = "刪除公告"; +"删除记录" = "刪除記錄"; +"删除这条公告?" = "刪除這條公告?"; +"刷新公告" = "重新整理公告"; +"剪贴板" = "剪貼簿"; +"剪贴板中没有文本" = "剪貼簿中沒有文字"; +"剪贴板文本超过 128 KiB" = "剪貼簿文字超過 128 KiB"; +"加载中…" = "載入中…"; +"加载更多" = "載入更多"; +"升级提示" = "更新提示"; +"单次输入最多 16 KiB,且不能包含空字符" = "單次輸入最多 16 KiB,且不能包含空字元"; +"发送" = "傳送"; +"发送文件" = "傳送檔案"; +"取消" = "取消"; +"取消连接" = "取消連線"; +"各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。" = "各元件遵循所列開源許可證,其授予的權利不受本應用普通使用條款限制。檢視原始碼需要網路連線。"; +"合计" = "合計"; +"同意并继续" = "同意並繼續"; +"回车" = "回車"; +"在线" = "線上"; +"地址" = "地址"; +"填写服务器地址" = "填寫伺服器地址"; +"填写端口" = "填寫埠"; +"声音" = "聲音"; +"失败" = "失敗"; +"始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。" = "始終保持較高解析度,頻寬不足時透過降低幀率來保證畫面清晰度。"; +"媒体加密" = "媒體加密"; +"字母数字" = "字母數字"; +"完成" = "完成"; +"完成隐私授权后可检查更新" = "完成隱私授權後可檢查更新"; +"完成隐私授权后登记本机身份" = "完成隱私授權後登記本機身份"; +"密码将安全保存在本机 Keychain 中" = "密碼將安全儲存在本機 Keychain 中"; +"对端 ID" = "對端 ID"; +"对端 ID %1$@" = "對端 ID %1$@"; +"将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。" = "將停止遠端連線、關閉畫面預覽儲存並清除已有預覽。連線記錄和接收檔案會保留,已有服務端資料不會刪除。您可隨時重新授權。"; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。" = "將刪除本機儲存的所有遠端預覽圖,保留連線記錄、密碼和接收的檔案。"; +"将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。" = "將刪除本機儲存的所有遠端預覽圖,保留連線記錄、密碼和接收的檔案。後續連線仍會儲存新的預覽圖。"; +"屏幕方向" = "螢幕方向"; +"展开远程控制菜单" = "展開遠端控制選單"; +"已保存密码" = "已儲存密碼"; +"已勾选" = "已勾選"; +"已发送 Ctrl+Alt+Del" = "已傳送 Ctrl+Alt+Del"; +"已发送本机剪贴板" = "已傳送本機剪貼簿"; +"已授权" = "已授權"; +"已接收 %1$@" = "已接收 %1$@"; +"已接收远端剪贴板" = "已接收遠端剪貼簿"; +"已读" = "已讀"; +"已连接" = "已連線"; +"已连接服务器" = "已連線伺服器"; +"帧率" = "幀率"; +"帧率优先" = "影格率優先"; +"平衡" = "平衡"; +"应用中的许可文件缺失或损坏,请重新安装应用。" = "應用中的許可檔案缺失或損壞,請重新安裝應用。"; +"开发版本包含尚未发布的修改,以下链接为基础版本源码。" = "開發版本包含尚未釋出的修改,以下連結為基礎版本原始碼。"; +"开启保存" = "啟用儲存"; +"开启隐私屏" = "開啟隱私屏"; +"开源组件" = "開源元件"; +"开源软件权利说明" = "開源軟體權利說明"; +"当前已是最新版本" = "當前已是最新版本"; +"成功连接后,这里会显示远端桌面的缩略图。" = "成功連線後,這裡會顯示遠端桌面的縮圖。"; +"我已阅读并同意《隐私政策》" = "我已閱讀並同意《隱私政策》"; +"我已阅读并同意隐私政策" = "我已閱讀並同意隱私政策"; +"打开隐私政策" = "開啟隱私政策"; +"指令发送失败,请重试" = "指令傳送失敗,請重試"; +"指令已发送,等待电脑确认…" = "指令已傳送,等待電腦確認…"; +"按住并拖动,可滑出按键范围,松开结束拖拽" = "按住並拖動,可滑出按鍵範圍,鬆開結束拖拽"; +"授权后可使用远程连接。" = "授權後可使用遠端連線。"; +"授权状态" = "授權狀態"; +"接收" = "接收"; +"控制模式" = "控制模式"; +"控制端解码器" = "控制端解碼器"; +"撤回授权" = "撤回授權"; +"撤回隐私授权" = "撤回隱私授權"; +"收起电脑键盘" = "收起電腦鍵盤"; +"收起系统键盘" = "收起系統鍵盤"; +"收起远程控制菜单" = "收起遠端控制選單"; +"收起鼠标" = "收起滑鼠"; +"数据" = "資料"; +"断开后将返回首页" = "斷開後將返回首頁"; +"断开远程连接?" = "斷開遠端連線?"; +"断开连接" = "中斷連線"; +"新版本" = "新版本"; +"新版本可用:v%1$@" = "新版本可用:v%1$@"; +"无效" = "無效"; +"无未读公告" = "無未讀公告"; +"无法" = "無法"; +"无法保存本地阅读状态,请重试。" = "無法儲存本地閱讀狀態,請重試。"; +"无法删除这条公告,请重试。" = "無法刪除這條公告,請重試。"; +"无法访问本机登录凭据,请解锁后重试" = "無法訪問本機登入憑據,請解鎖後重試"; +"无法读取开源许可" = "無法讀取開源許可"; +"无法读取所选文件,请重试" = "無法讀取所選檔案,請重試"; +"是否撤回隐私授权?" = "是否撤回隱私授權?"; +"显示器" = "顯示器"; +"显示器 %1$@" = "顯示器 %1$@"; +"显示器 1" = "顯示器 1"; +"显示密码" = "顯示密碼"; +"暂不同意" = "暫不同意"; +"暂无公告" = "暫無公告"; +"最近连接" = "最近連線"; +"服务器" = "伺服器"; +"服务器地址" = "伺服器地址"; +"服务器端口" = "伺服器埠"; +"服务器配置无效" = "伺服器配置無效"; +"未勾选" = "未勾選"; +"未启用" = "未啟用"; +"未授权" = "未授權"; +"未知" = "未知"; +"未知信令状态" = "未知信令狀態"; +"未知连接状态" = "未知連線狀態"; +"未读" = "未讀"; +"未连接" = "未連線"; +"本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。" = "本應用使用 OpenFEC 提供前向糾錯功能,遵循 CeCILL-C 1.0 許可。該許可規定了有限保證及責任限制,詳情見許可全文。"; +"本机 ID %1$@" = "本機 ID %1$@"; +"本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。" = "本機登入憑據暫時無法安全存取。請解鎖裝置後,在設定中點選“應用”重試。"; +"本版本源码与构建说明" = "本版本原始碼與構建說明"; +"本版本源码信息暂不可用。" = "本版本原始碼資訊暫不可用。"; +"构建说明" = "構建說明"; +"构建配方与项目补丁" = "構建配方與專案補丁"; +"查看源码" = "檢視原始碼"; +"检查失败,请稍后重试" = "檢查失敗,請稍後重試"; +"检查更新" = "檢查更新"; +"正在关闭隐私屏…" = "正在關閉隱私屏…"; +"正在准备连接…" = "正在準備連線…"; +"正在发送 %1$@" = "正在傳送 %1$@"; +"正在发送 Ctrl+Alt+Del…" = "正在傳送 Ctrl+Alt+Del…"; +"正在取回远程画面…" = "正在取回遠端畫面…"; +"正在建立远程连接" = "正在建立遠端連線"; +"正在开启隐私屏…" = "正在開啟隱私屏…"; +"正在收集 ICE 候选" = "正在收集 ICE 候選"; +"正在检查更新…" = "正在檢查更新…"; +"正在清除…" = "正在清除…"; +"正在确认设备状态…" = "正在確認裝置狀態…"; +"正在获取本机 ID…" = "正在獲取本機 ID…"; +"正在连接" = "正在連線"; +"正在连接信令服务" = "正在連線信令服務"; +"清除" = "清除"; +"清除预览图" = "清除預覽圖"; +"清除预览图?" = "清除預覽圖?"; +"源码与构建说明" = "原始碼與構建說明"; +"源码版本" = "原始碼版本"; +"版本" = "版本"; +"版权与许可声明" = "版權與許可宣告"; +"电脑键盘" = "電腦鍵盤"; +"画中画未能开启,请保持应用在前台后重试。" = "畫中畫未能開啟,請保持應用在前臺後重試。"; +"画质优先" = "畫質優先"; +"画面偏好" = "畫面偏好"; +"画面延时" = "畫面延遲"; +"画面设置" = "畫面設定"; +"画面质量" = "畫面質量"; +"画面采集帧率" = "畫面採集幀率"; +"相对位置" = "相對位置"; +"相对鼠标" = "相對滑鼠"; +"知道了" = "知道了"; +"确定" = "確定"; +"确认" = "確認"; +"离线" = "離線"; +"空格" = "空白鍵"; +"端口" = "埠"; +"符号功能" = "符號功能"; +"等待电脑返回隐私屏状态;旧版电脑端可能不支持" = "等待電腦返回隱私屏狀態;舊版電腦端可能不支援"; +"等待连接" = "等待連線"; +"等待隐私授权" = "等待隱私授權"; +"系统键盘" = "系統鍵盤"; +"绝对位置" = "絕對位置"; +"绝对鼠标" = "絕對滑鼠"; +"网络状态" = "網路狀態"; +"网络连接已中断,请重新连接。" = "網路連線已中斷,請重新連線。"; +"自定义" = "自定義"; +"虚拟鼠标" = "虛擬滑鼠"; +"被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴" = "被控端不支援直接輸入中文,請更新 macOS 被控端;也可先複製文字,透過遠控選單的剪貼簿傳送後貼上"; +"被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。" = "被控端已透過組合鍵解除隱私屏。點選“鎖定”將重新開啟隱私屏,並禁止本機使用組合鍵解鎖。"; +"被控端平台:%1$@" = "被控端平臺:%1$@"; +"被控端版本过低,请升级到最新版本。" = "被控端版本過低,請升級到最新版本。"; +"被控端编码器" = "被控端編碼器"; +"视频" = "影片"; +"视频 %1$@×%2$@ · %3$@ 帧" = "影片 %1$@×%2$@ · %3$@ 幀"; +"触摸位置直接对应远端屏幕位置,适合快速定位。" = "觸控位置直接對應遠端螢幕位置,適合快速定位。"; +"许可" = "許可"; +"许可与版权声明" = "許可與版權宣告"; +"许可与版权声明可离线查阅。" = "許可與版權宣告可離線查閱。"; +"设备离线" = "裝置離線"; +"设置" = "設定"; +"设置,有新版本" = "設定,有新版本"; +"访问密码" = "訪問密碼"; +"访问密码错误,请重新输入。" = "訪問密碼錯誤,請重新輸入。"; +"请求超时,尚未确认电脑的隐私屏状态" = "請求超時,尚未確認電腦的隱私屏狀態"; +"请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。" = "請輸入 1–65535 範圍內的埠,或關閉“使用自定義伺服器”。"; +"请输入服务器地址,或关闭“使用自定义服务器”。" = "請輸入伺服器地址,或關閉“使用自定義伺服器”。"; +"请输入远程设备 ID" = "請輸入遠端裝置 ID"; +"调整失败,请重试。" = "調整失敗,請重試。"; +"软件许可" = "軟體許可"; +"返回控制栏" = "返回控制欄"; +"还没有连接记录" = "還沒有連線記錄"; +"这条公告已更新或删除,请返回公告列表查看。" = "這條公告已更新或刪除,請返回公告列表檢視。"; +"远程桌面" = "遠端桌面"; +"远程设备 ID 不存在,请检查设备 ID。" = "遠端裝置 ID 不存在,請檢查裝置 ID。"; +"远程设备当前不可用,请稍后重试。" = "遠端裝置當前不可用,請稍後重試。"; +"远程连接已结束。" = "遠端連線已結束。"; +"连接" = "連線"; +"连接延时(RTT)" = "連線延時(RTT)"; +"连接建立后可调整,需被控端支持。" = "連線建立後可調整,需被控端支援。"; +"连接建立后锁定横屏" = "連線建立後鎖定橫屏"; +"连接提示" = "連線提示"; +"连接方式" = "連線方式"; +"连接远程桌面" = "連線遠端桌面"; +"退格" = "退格"; +"通知公告" = "通知公告"; +"部分预览图未能清除,请重试。" = "部分預覽圖未能清除,請重試。"; +"重试" = "重試"; +"重试保存阅读状态" = "重試儲存閱讀狀態"; +"锁定" = "鎖定"; +"键盘" = "鍵盤"; +"键盘操作" = "鍵盤操作"; +"阅读并授权" = "閱讀並授權"; +"隐私" = "隱私"; +"隐私与授权" = "隱私與授權"; +"隐私屏" = "隱私屏"; +"隐私屏已关闭" = "隱私屏已關閉"; +"隐私屏已开启" = "隱私屏已開啟"; +"隐私屏已被解锁" = "隱私屏已被解鎖"; +"隐私屏异常" = "隱私屏異常"; +"隐私屏暂不可用" = "隱私屏暫不可用"; +"隐私屏状态已过期,等待电脑确认" = "隱私屏狀態已過期,等待電腦確認"; +"隐私屏状态待确认" = "隱私屏狀態待確認"; +"隐私政策" = "隱私政策"; +"隐私政策暂时无法读取,请拒绝联网并重新安装应用。" = "隱私政策暫時無法讀取,請拒絕聯網並重新安裝應用。"; +"隐藏密码" = "隱藏密碼"; +"静音" = "靜音"; +"音频" = "音訊"; +"项目主页" = "專案主頁"; +"预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。" = "預覽可能包含遠端電腦上的個人或工作資訊。開啟後,每次連線會自動將一張畫面儲存在本機並顯示在最近連線中。你可以隨時關閉並清除。"; +"高" = "高"; +"默认" = "預設"; +"默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。" = "預設關閉。開啟後,iPhone 連線時進入並保持橫屏;關閉時跟隨裝置方向。iPad 不受影響。"; +"鼠标右键" = "滑鼠右鍵"; +"鼠标左键" = "滑鼠左鍵"; +"鼠标控制" = "滑鼠控制"; +"鼠标滚轮" = "滑鼠滾輪"; diff --git a/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift b/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift index b43f17a3..f4306611 100644 --- a/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift +++ b/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift @@ -82,27 +82,27 @@ struct ThirdPartyLicensesView: View { var body: some View { List { Section { - LabeledContent("版本", value: appUpdates.currentVersion) + LabeledContent(NSLocalizedString("版本", comment: ""), value: appUpdates.currentVersion) if appUpdates.updateAvailable { Link(destination: URL(string: "https://crossdesk.cn")!) { HStack { UpdateDot() - Text("新版本可用:v\(appUpdates.availableVersion)") + Text(String(format: NSLocalizedString("新版本可用:v%1$@", comment: ""), String(describing: appUpdates.availableVersion))) Spacer() Image(systemName: "arrow.up.right") } } } if !session.hasNetworkConsent { - Text("完成隐私授权后可检查更新").foregroundStyle(.secondary) + Text(NSLocalizedString("完成隐私授权后可检查更新", comment: "")).foregroundStyle(.secondary) } else if appUpdates.status == .checking { - Text("正在检查更新…").foregroundStyle(.secondary) + Text(NSLocalizedString("正在检查更新…", comment: "")).foregroundStyle(.secondary) } else if appUpdates.status == .upToDate { - Text("当前已是最新版本").foregroundStyle(.secondary) + Text(NSLocalizedString("当前已是最新版本", comment: "")).foregroundStyle(.secondary) } else if appUpdates.status == .failed { - Text("检查失败,请稍后重试").foregroundStyle(.red) + Text(NSLocalizedString("检查失败,请稍后重试", comment: "")).foregroundStyle(.red) } - Button("检查更新") { + Button(NSLocalizedString("检查更新", comment: "")) { if session.hasNetworkConsent { appUpdates.checkNow() } else { session.showPrivacyNotice() } } @@ -112,26 +112,26 @@ struct ThirdPartyLicensesView: View { case .success(let catalog): if let application = catalog.components.first(where: { $0.id == "crossdesk" }) { Section { - NavigationLink("软件许可") { + NavigationLink(NSLocalizedString("软件许可", comment: "")) { ComponentLicenseView(component: application) } - NavigationLink("开源组件") { + NavigationLink(NSLocalizedString("开源组件", comment: "")) { OpenSourceComponentsView(catalog: catalog) } - NavigationLink("源码与构建说明") { + NavigationLink(NSLocalizedString("源码与构建说明", comment: "")) { SourceCodeView(application: application) } } footer: { - Text("许可与版权声明可离线查阅。") + Text(NSLocalizedString("许可与版权声明可离线查阅。", comment: "")) } } case .failure: VStack(spacing: 12) { Image(systemName: "doc.text.magnifyingglass") .font(.largeTitle) - Text("无法读取开源许可") + Text(NSLocalizedString("无法读取开源许可", comment: "")) .font(.headline) - Text("应用中的许可文件缺失或损坏,请重新安装应用。") + Text(NSLocalizedString("应用中的许可文件缺失或损坏,请重新安装应用。", comment: "")) .foregroundStyle(.secondary) .multilineTextAlignment(.center) } @@ -140,7 +140,7 @@ struct ThirdPartyLicensesView: View { } .readableContentWidth() .background(Color(.systemGroupedBackground).ignoresSafeArea()) - .navigationTitle("关于 CrossDesk") + .navigationTitle(NSLocalizedString("关于 CrossDesk", comment: "")) .navigationBarTitleDisplayMode(.inline) .onChange(of: session.hasNetworkConsent) { allowed in if allowed { appUpdates.checkNow() } @@ -163,13 +163,13 @@ private struct OpenSourceComponentsView: View { var body: some View { List { if let openFEC = catalog.components.first(where: { $0.id == "openfec" }) { - Section("OpenFEC 告知") { - Text("本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。") + Section(NSLocalizedString("OpenFEC 告知", comment: "")) { + Text(NSLocalizedString("本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", comment: "")) .font(.footnote) .foregroundStyle(.secondary) Text("(c) Copyright 2009 - 2012 INRIA - All rights reserved") .font(.footnote) - NavigationLink("OpenFEC 许可与源码") { + NavigationLink(NSLocalizedString("OpenFEC 许可与源码", comment: "")) { ComponentLicenseView(component: openFEC) } } @@ -188,12 +188,12 @@ private struct OpenSourceComponentsView: View { } } } footer: { - Text("各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。") + Text(NSLocalizedString("各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。", comment: "")) } } .readableContentWidth() .background(Color(.systemGroupedBackground).ignoresSafeArea()) - .navigationTitle("开源组件") + .navigationTitle(NSLocalizedString("开源组件", comment: "")) .navigationBarTitleDisplayMode(.inline) } } @@ -203,27 +203,27 @@ private struct SourceCodeView: View { var body: some View { List { - Section("本版本源码与构建说明") { + Section(NSLocalizedString("本版本源码与构建说明", comment: "")) { if let source = SourceMetadata.bundled { - LabeledContent("源码版本", value: source.tag ?? String(source.revision.prefix(12))) + LabeledContent(NSLocalizedString("源码版本", comment: ""), value: source.tag ?? String(source.revision.prefix(12))) .textSelection(.enabled) if source.isModified { - Text("开发版本包含尚未发布的修改,以下链接为基础版本源码。") + Text(NSLocalizedString("开发版本包含尚未发布的修改,以下链接为基础版本源码。", comment: "")) .font(.footnote) .foregroundStyle(.secondary) } - Link("查看源码", destination: source.sourceURL) - Link("构建说明", destination: source.buildInstructionsURL) + Link(NSLocalizedString("查看源码", comment: ""), destination: source.sourceURL) + Link(NSLocalizedString("构建说明", comment: ""), destination: source.buildInstructionsURL) } else { - Text("本版本源码信息暂不可用。") + Text(NSLocalizedString("本版本源码信息暂不可用。", comment: "")) .foregroundStyle(.secondary) - Link("项目主页", destination: application.sourceURL) + Link(NSLocalizedString("项目主页", comment: ""), destination: application.sourceURL) } } } .readableContentWidth() .background(Color(.systemGroupedBackground).ignoresSafeArea()) - .navigationTitle("源码与构建说明") + .navigationTitle(NSLocalizedString("源码与构建说明", comment: "")) .navigationBarTitleDisplayMode(.inline) } } @@ -234,15 +234,15 @@ private struct ComponentLicenseView: View { var body: some View { List { Section { - LabeledContent("版本", value: component.displayVersion) + LabeledContent(NSLocalizedString("版本", comment: ""), value: component.displayVersion) .textSelection(.enabled) - LabeledContent("许可", value: component.license) - Link("查看源码", destination: component.resolvedSourceURL) + LabeledContent(NSLocalizedString("许可", comment: ""), value: component.license) + Link(NSLocalizedString("查看源码", comment: ""), destination: component.resolvedSourceURL) if let buildSourceURL = component.resolvedBuildSourceURL { - Link("构建配方与项目补丁", destination: buildSourceURL) + Link(NSLocalizedString("构建配方与项目补丁", comment: ""), destination: buildSourceURL) } } - Section("许可与版权声明") { + Section(NSLocalizedString("许可与版权声明", comment: "")) { ForEach(component.documents) { document in NavigationLink { LicenseTextView(text: document.text) @@ -263,9 +263,9 @@ private struct ComponentLicenseView: View { private func documentTitle(_ title: String) -> String { switch title { - case "Source copyright and license notices": return "版权与许可声明" - case "apps/ios/licenses/OPEN_SOURCE_NOTICE.txt": return "开源软件权利说明" - case "LICENSE" where component.id == "crossdesk": return "GNU GPL 第 3 版" + case "Source copyright and license notices": return NSLocalizedString("版权与许可声明", comment: "") + case "apps/ios/licenses/OPEN_SOURCE_NOTICE.txt": return NSLocalizedString("开源软件权利说明", comment: "") + case "LICENSE" where component.id == "crossdesk": return NSLocalizedString("GNU GPL 第 3 版", comment: "") default: return title } } diff --git a/localization/README.md b/localization/README.md new file mode 100644 index 00000000..899a6c64 --- /dev/null +++ b/localization/README.md @@ -0,0 +1,39 @@ +# CrossDesk 界面本地化 + +桌面端和 Android、iOS、HarmonyOS 移动端共用 `catalog.json` 中的界面文案,支持以下 10 种语言版本: + +| 语言 | 标识 | +| --- | --- | +| 简体中文 | `zh-Hans` | +| English | `en` | +| Русский | `ru` | +| 繁體中文 | `zh-Hant` | +| 日本語 | `ja` | +| 한국어 | `ko` | +| Deutsch | `de` | +| Français | `fr` | +| Español | `es` | +| Português (Brasil) | `pt-BR` | + +## 语言选择 + +- 新安装的桌面端默认“跟随系统”,也可以在设置中手动指定语言。已有配置中的中文、英文、俄文选择继续保留。 +- 移动端使用系统语言;Android 和 iOS 同时支持操作系统提供的应用语言设置。 +- 地区变体匹配相应语言;中文优先识别 `Hans` / `Hant`,台湾、香港、澳门使用繁体。葡萄牙语地区变体共用巴西葡萄牙语文案。 +- 支持系统首选语言列表的平台使用其中可用的语言,没有匹配项时回退到英文。修改系统语言后重新打开应用可确保所有页面与状态文案更新。 +- 只翻译应用界面。远端设备名称、文件名、用户输入、服务器公告和协议内容不作翻译。隐私政策正文使用项目已发布的中文或英文版本,第三方许可证保留原文。 + +## 维护资源 + +`catalog.json` 是唯一编辑入口,生成结果提交到各平台目录,应用运行时不依赖翻译服务。 + +```sh +python3 localization/generate.py +python3 localization/generate.py --check +``` + +生成器使用 Python 标准库,输出桌面 C++ 文案表、Android 原生资源及语言声明、iOS `.lproj` 资源,以及 HarmonyOS 文案表。`--check` 检查语言覆盖、格式占位符和生成文件是否同步。 + +新增文案时,在 `strings` 中提供所有语言的译文,并加入 `platforms` 中对应的平台列表。桌面命名键同时加入 `desktop`;Slint 使用的键追加到 `slint` 列表末尾,已有索引不能重排。桌面语言顺序中的前 3 项与历史配置兼容,修改顺序需要配置迁移。 + +占位符须完整保留:Android/HarmonyOS 使用 `{0}` 等位置占位符;iOS 使用 `%1$@` 等位置格式;已有桌面文案使用其原有格式。不同语言可以调整占位符位置,但不能更改数量或类型。新语言的初始译文包含机器辅助翻译,发布前应由对应语言使用者复核术语、语气及长文本。 diff --git a/localization/catalog.json b/localization/catalog.json new file mode 100644 index 00000000..3e58bd39 --- /dev/null +++ b/localization/catalog.json @@ -0,0 +1,12071 @@ +{ + "languages": [ + "zh-Hans", + "en", + "ru", + "zh-Hant", + "ja", + "ko", + "de", + "fr", + "es", + "pt-BR" + ], + "strings": { + "": { + "zh-Hans": "", + "en": " ", + "ru": " ", + "zh-Hant": "", + "ja": "", + "ko": "", + "de": "", + "fr": "", + "es": "", + "pt-BR": "" + }, + " · 已完成": { + "zh-Hans": " · 已完成", + "en": " · Completed", + "zh-Hant": " · 已完成", + "ja": " ・完了", + "ko": " · 완료", + "de": " · Abgeschlossen", + "fr": " · Terminé", + "es": " · Completado", + "pt-BR": " · Concluído", + "ru": " · Завершено" + }, + " 传输失败": { + "zh-Hans": " 传输失败", + "en": " Transfer failed", + "zh-Hant": " 傳輸失敗", + "ja": " 転送に失敗しました", + "ko": " 전송 실패", + "de": " Übertragung fehlgeschlagen", + "fr": " Échec du transfert", + "es": " Transferencia fallida", + "pt-BR": " Falha na transferência", + "ru": " Передача не удалась" + }, + " 台": { + "zh-Hans": " 台", + "en": "", + "ru": "", + "zh-Hant": " 臺", + "ja": " ", + "ko": " ", + "de": " ", + "fr": " ", + "es": " ", + "pt-BR": " " + }, + " 台已连接": { + "zh-Hans": " 台已连接", + "en": " connected", + "ru": " подключено", + "zh-Hant": " 臺已連線", + "ja": " 接続されています", + "ko": " 연결됨", + "de": " verbunden", + "fr": " connecté", + "es": " conectado", + "pt-BR": " conectado" + }, + " 台设备": { + "zh-Hans": " 台设备", + "en": " devices", + "zh-Hant": " 臺裝置", + "ja": " 台のデバイス", + "ko": " 장치", + "de": " Geräte", + "fr": " appareils", + "es": " dispositivos", + "pt-BR": " dispositivos", + "ru": " устройства" + }, + " 条 · ": { + "zh-Hans": " 条 · ", + "en": " Article · ", + "zh-Hant": " 條 · ", + "ja": " 記事 ・ ", + "ko": " 기사 · ", + "de": " Artikel · ", + "fr": " Article · ", + "es": " Artículo · ", + "pt-BR": " Artigo · ", + "ru": " Статья · " + }, + " 条未读": { + "zh-Hans": " 条未读", + "en": " unread items", + "zh-Hant": " 條未讀", + "ja": " 未読項目", + "ko": " 읽지 않은 항목", + "de": " ungelesene Artikel", + "fr": " éléments non lus", + "es": " elementos no leídos", + "pt-BR": " itens não lidos", + "ru": " непрочитанные элементы" + }, + "%1$@ 传输失败": { + "zh-Hans": "%1$@ 传输失败", + "en": "%1$@ transmission failed", + "zh-Hant": "%1$@ 傳輸失敗", + "ja": "%1$@送信失敗", + "ko": "%1$@전송 실패", + "de": "%1$@-Übertragung fehlgeschlagen", + "fr": "Échec de la transmission %1$@", + "es": "Error en la transmisión %1$@", + "pt-BR": "Falha na transmissão %1$@", + "ru": "Передача %1$@ не удалась." + }, + "%1$@ 台设备": { + "zh-Hans": "%1$@ 台设备", + "en": "Devices: %1$@", + "zh-Hant": "%1$@ 臺裝置", + "ja": "デバイス数: %1$@", + "ko": "기기: %1$@", + "de": "Geräte: %1$@", + "fr": "Appareils : %1$@", + "es": "Dispositivos: %1$@", + "pt-BR": "Dispositivos: %1$@", + "ru": "Устройства: %1$@" + }, + "%1$@ 条未读": { + "zh-Hans": "%1$@ 条未读", + "en": "%1$@ unread items", + "zh-Hant": "%1$@ 條未讀", + "ja": "%1$@の未読アイテム", + "ko": "%1$@읽지 않은 항목", + "de": "%1$@ ungelesene Elemente", + "fr": "Éléments non lus %1$@", + "es": "%1$@ elementos no leídos", + "pt-BR": "Itens não lidos %1$@", + "ru": "%1$@ непрочитанные элементы" + }, + "%1$@键盘页": { + "zh-Hans": "%1$@键盘页", + "en": "%1$@ keyboard page", + "zh-Hant": "%1$@鍵盤頁", + "ja": "%1$@キーボードページ", + "ko": "%1$@키보드 페이지", + "de": "%1$@ Tastaturseite", + "fr": "Page du clavier %1$@", + "es": "Página del teclado %1$@", + "pt-BR": "Página do teclado %1$@", + "ru": "Страница клавиатуры %1$@" + }, + "%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@": { + "zh-Hans": "%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@", + "en": "%1$@, receiving %2$@, sending %3$@, packet loss rate %4$@", + "zh-Hant": "%1$@,接收 %2$@,傳送 %3$@,丟包率 %4$@", + "ja": "%1$@、受信%2$@、送信%3$@、パケットロス率%4$@", + "ko": "%1$@, 수신%2$@, 송신%3$@, 패킷 손실률%4$@", + "de": "%1$@, Empfangen von %2$@, Senden von %3$@, Paketverlustrate %4$@", + "fr": "%1$@, réception de %2$@, envoi de %3$@, taux de perte de paquets %4$@", + "es": "%1$@, recepción de %2$@, envío de %3$@, tasa de pérdida de paquetes %4$@", + "pt-BR": "%1$@, recebendo %2$@, enviando %3$@, taxa de perda de pacotes %4$@", + "ru": "%1$@, прием %2$@, отправка %3$@, скорость потери пакетов %4$@" + }, + "9 位设备 ID": { + "zh-Hans": "9 位设备 ID", + "en": "9-digit device ID", + "ru": "ID из 9 цифр", + "zh-Hant": "9 位裝置 ID", + "ja": "9桁のデバイスID", + "ko": "9자리 기기 ID", + "de": "9-stellige Geräte-ID", + "fr": "ID d'appareil à 9 chiffres", + "es": "ID del dispositivo de 9 dígitos", + "pt-BR": "ID do dispositivo de 9 dígitos" + }, + "AV1": { + "zh-Hans": "AV1", + "en": "AV1", + "ru": "AV1", + "zh-Hant": "AV1", + "ja": "AV1", + "ko": "AV1", + "de": "AV1", + "fr": "AV1", + "es": "AV1", + "pt-BR": "AV1" + }, + "CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。": { + "zh-Hans": "CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。", + "en": "CrossDesk uses the local network to discover and establish native P2P remote control connections.", + "zh-Hant": "CrossDesk 使用區域網發現並建立原生 P2P 遠端控制連線。", + "ja": "CrossDeskは、ローカル ネットワークを使用してネイティブ P2P リモート コントロール接続を検出し、確立します。", + "ko": "CrossDesk는 로컬 네트워크를 사용하여 기본 P2P 원격 제어 연결을 검색하고 설정합니다.", + "de": "CrossDesk nutzt das lokale Netzwerk, um native P2P-Fernsteuerungsverbindungen zu erkennen und aufzubauen.", + "fr": "CrossDesk utilise le réseau local pour découvrir et établir des connexions de contrôle à distance P2P natives.", + "es": "CrossDesk utiliza la red local para descubrir y establecer conexiones nativas de control remoto P2P.", + "pt-BR": "CrossDesk usa a rede local para descobrir e estabelecer conexões de controle remoto P2P nativas.", + "ru": "CrossDesk использует локальную сеть для обнаружения и установления собственных P2P-соединений удаленного управления." + }, + "CrossDesk 已停止,退出码": { + "zh-Hans": "CrossDesk 已停止,退出码", + "en": "CrossDesk stopped; exit code", + "ru": "CrossDesk остановлен; код выхода", + "zh-Hant": "CrossDesk 已停止,退出碼", + "ja": "CrossDeskが停止しました。終了コード", + "ko": "CrossDesk가 중지되었습니다. 종료 코드", + "de": "CrossDesk gestoppt; Exit-Code", + "fr": "CrossDesk arrêté ; code de sortie", + "es": "CrossDesk detenido; código de salida", + "pt-BR": "CrossDesk parado; código de saída" + }, + "CrossDesk 已退出。": { + "zh-Hans": "CrossDesk 已退出。", + "en": "CrossDesk exited.", + "ru": "CrossDesk завершён.", + "zh-Hant": "CrossDesk 已退出。", + "ja": "CrossDeskが終了しました。", + "ko": "CrossDesk가 종료되었습니다.", + "de": "CrossDesk beendet.", + "fr": "CrossDesk est sorti.", + "es": "CrossDesk salió.", + "pt-BR": "CrossDesk saiu." + }, + "CrossDesk 无头控制台": { + "zh-Hans": "CrossDesk 无头控制台", + "en": "CrossDesk headless console", + "ru": "Консоль CrossDesk без графического интерфейса", + "zh-Hant": "CrossDesk 無頭控制檯", + "ja": "CrossDeskヘッドレス コンソール", + "ko": "CrossDesk헤드리스 콘솔", + "de": "CrossDesk Headless-Konsole", + "fr": "Console sans tête CrossDesk", + "es": "Consola sin cabeza CrossDesk", + "pt-BR": "Console sem cabeça CrossDesk" + }, + "CrossDesk 远程连接": { + "zh-Hans": "CrossDesk 远程连接", + "en": "CrossDesk remote connection", + "zh-Hant": "CrossDesk 遠端連線", + "ja": "CrossDeskリモート接続", + "ko": "CrossDesk원격접속", + "de": "CrossDesk Remote-Verbindung", + "fr": "Connexion à distance CrossDesk", + "es": "Conexión remota CrossDesk", + "pt-BR": "Conexão remota CrossDesk", + "ru": "Удаленное подключение CrossDesk" + }, + "Ctrl+Alt+Del 需要远端启用 Windows 系统服务": { + "zh-Hans": "Ctrl+Alt+Del 需要远端启用 Windows 系统服务", + "en": "Ctrl+Alt+Del requires remote activation of Windows system services", + "zh-Hant": "Ctrl+Alt+Del 需要遠端啟用 Windows 系統服務", + "ja": "Ctrl+Alt+Delでは Windows システム サービスのリモート アクティベーションが必要です", + "ko": "Ctrl+Alt+Del에는 Windows 시스템 서비스의 원격 활성화가 필요합니다.", + "de": "Ctrl+Alt+Del erfordert eine Remote-Aktivierung der Windows-Systemdienste", + "fr": "Ctrl+Alt+Del nécessite l'activation à distance des services système Windows", + "es": "Ctrl+Alt+Del requiere activación remota de los servicios del sistema Windows", + "pt-BR": "Ctrl+Alt+Del requer ativação remota dos serviços do sistema Windows", + "ru": "Ctrl+Alt+Del требует удаленной активации системных служб Windows." + }, + "GNU GPL 第 3 版": { + "zh-Hans": "GNU GPL 第 3 版", + "en": "GNU GPL version 3", + "zh-Hant": "GNU GPL 第 3 版", + "ja": "GNU GPL バージョン 3", + "ko": "GNU GPL 버전 3", + "de": "GNU GPL Version 3", + "fr": "GNU GPL version 3", + "es": "GNU GPL versión 3", + "pt-BR": "GNU GPL versão 3", + "ru": "GNU GPL версия 3" + }, + "H.264": { + "zh-Hans": "H.264", + "en": "H.264", + "ru": "H.264", + "zh-Hant": "H.264", + "ja": "H.264", + "ko": "H.264", + "de": "H.264", + "fr": "H.264", + "es": "H.264", + "pt-BR": "H.264" + }, + "ID 连接": { + "zh-Hans": "ID 连接", + "en": "ID mode", + "ru": "Режим ID", + "zh-Hant": "ID 連線", + "ja": "IDモード", + "ko": "ID 모드", + "de": "ID-Modus", + "fr": "Mode identification", + "es": "Modo de identificación", + "pt-BR": "Modo ID" + }, + "IP 和端口已复制": { + "zh-Hans": "IP 和端口已复制", + "en": "IP and port copied", + "ru": "IP и порт скопированы", + "zh-Hant": "IP 和埠已複製", + "ja": "IP とポートがコピーされました", + "ko": "IP와 포트가 복사되었습니다.", + "de": "IP und Port kopiert", + "fr": "IP et port copiés", + "es": "IP y puerto copiados", + "pt-BR": "IP e porta copiados" + }, + "IP 连接": { + "zh-Hans": "IP 连接", + "en": "IP mode", + "ru": "Режим IP", + "zh-Hant": "IP 連線", + "ja": "IPモード", + "ko": "IP 모드", + "de": "IP-Modus", + "fr": "Mode IP", + "es": "Modo IP", + "pt-BR": "Modo IP" + }, + "IP 连接准备中…": { + "zh-Hans": "IP 连接准备中…", + "en": "Preparing IP connections…", + "ru": "Подготовка подключений по IP…", + "zh-Hant": "IP 連線準備中…", + "ja": "IP接続を準備中…", + "ko": "IP 연결 준비 중…", + "de": "IP-Verbindungen vorbereiten…", + "fr": "Préparation des connexions IP…", + "es": "Preparando conexiones IP…", + "pt-BR": "Preparando conexões IP…" + }, + "IP 连接已启用": { + "zh-Hans": "IP 连接已启用", + "en": "IP connections enabled", + "ru": "Подключения по IP включены", + "zh-Hant": "IP 連線已啟用", + "ja": "IP 接続が有効になっています", + "ko": "IP 연결 활성화", + "de": "IP-Verbindungen aktiviert", + "fr": "Connexions IP activées", + "es": "Conexiones IP habilitadas", + "pt-BR": "Conexões IP habilitadas" + }, + "IP 连接操作失败,详情:": { + "zh-Hans": "IP 连接操作失败,详情:", + "en": "IP connection operation failed. Details: ", + "ru": "Ошибка операции IP-подключения. Подробности: ", + "zh-Hant": "IP 連線操作失敗,詳情:", + "ja": "IP 接続操作に失敗しました。詳細:", + "ko": "IP 연결 작업이 실패했습니다. 세부정보:", + "de": "IP-Verbindungsvorgang fehlgeschlagen. Einzelheiten:", + "fr": "L'opération de connexion IP a échoué. Détails :", + "es": "Error en la operación de conexión IP. Detalles:", + "pt-BR": "Falha na operação de conexão IP. Detalhes:" + }, + "IP 连接数量已达上限,请先断开部分连接后重试。": { + "zh-Hans": "IP 连接数量已达上限,请先断开部分连接后重试。", + "en": "The IP connection limit has been reached. Disconnect some sessions and try again.", + "ru": "Достигнут лимит IP-подключений. Завершите часть сеансов и повторите попытку.", + "zh-Hant": "IP 連線數量已達上限,請先斷開部分連線後重試。", + "ja": "IP 接続の制限に達しました。いくつかのセッションを切断して、再試行してください。", + "ko": "IP 연결 제한에 도달했습니다. 일부 세션의 연결을 끊고 다시 시도하십시오.", + "de": "Das IP-Verbindungslimit wurde erreicht. Trennen Sie einige Sitzungen und versuchen Sie es erneut.", + "fr": "La limite de connexion IP a été atteinte. Déconnectez certaines sessions et réessayez.", + "es": "Se ha alcanzado el límite de conexión IP. Desconecta algunas sesiones y vuelve a intentarlo.", + "pt-BR": "O limite de conexão IP foi atingido. Desconecte algumas sessões e tente novamente." + }, + "IP 连接未就绪": { + "zh-Hans": "IP 连接未就绪", + "en": "IP connections not ready", + "ru": "Подключения по IP не готовы", + "zh-Hant": "IP 連線未就緒", + "ja": "IP 接続の準備ができていません", + "ko": "IP 연결이 준비되지 않았습니다.", + "de": "IP-Verbindungen nicht bereit", + "fr": "Les connexions IP ne sont pas prêtes", + "es": "Conexiones IP no listas", + "pt-BR": "Conexões IP não prontas" + }, + "IP 连接模式": { + "zh-Hans": "IP 连接模式", + "en": "IP connection mode", + "ru": "Режим IP", + "zh-Hant": "IP 連線模式", + "ja": "IP接続モード", + "ko": "IP 연결 모드", + "de": "IP-Verbindungsmodus", + "fr": "Mode de connexion IP", + "es": "Modo de conexión IP", + "pt-BR": "Modo de conexão IP" + }, + "Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n": { + "zh-Hans": "Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n", + "en": "Linux headless options:\n --headless Select an existing desktop and enable the console\n --headless-display DISPLAY Advanced: override desktop selection\n --headless-size WIDTHxHEIGHT New virtual display; default 1920x1080, even 320..8192\n --headless-session EXECUTABLE Start a desktop (startxfce4; none for a bare display)\n --no-headless Disable automatic fallback\nNormal startup selects your existing desktop automatically. Enter settings in the console to configure it.\n", + "ru": "Параметры запуска без монитора:\n --headless Выбрать рабочий стол и включить консоль\n --headless-display DISPLAY Дополнительно: указать сеанс дисплея\n --headless-size WIDTHxHEIGHT Новый виртуальный экран; 1920x1080 по умолчанию, чётные размеры 320..8192\n --headless-session EXECUTABLE Запустить рабочий стол (startxfce4; none — только экран)\n --no-headless Отключить автоматический резервный запуск\nРабочий стол выбирается автоматически. Команда settings открывает настройки консоли.\n", + "zh-Hant": "Linux 無頭執行選項:\n --headless 自動選擇已有桌面並啟用控制檯\n --headless-display DISPLAY 高階:指定已有顯示會話\n --headless-size WIDTHxHEIGHT 新建虛擬螢幕;預設1920x1080,偶數尺寸320..8192\n --headless-session EXECUTABLE 啟動桌面環境(startxfce4;none 僅啟動裸螢幕)\n --no-headless 禁用自動回退\n正常啟動會自動選擇已有桌面,無需填寫顯示編號。控制檯輸入 settings 管理設定。\n", + "ja": "Linux ヘッドレス オプション:\n--headless既存のデスクトップを選択し、コンソールを有効にする\n--headless-displayDISPLAY 詳細: デスクトップの選択を上書きする\n--headless-sizeWIDTHxHEIGHT 新しい仮想ディスプレイ。デフォルトは 1920x1080、320..8192 でも可\n--headless-sessionEXECUTABLE デスクトップを起動します (startxfce4; 裸のディスプレイの場合はなし)\n--no-headless自動フォールバックを無効にする\n通常の起動では、既存のデスクトップが自動的に選択されます。コンソールに設定を入力して構成します。\n", + "ko": "Linux 헤드리스 옵션:\n--headless기존 데스크톱을 선택하고 콘솔을 활성화합니다.\n--headless-displayDISPLAY 고급: 데스크톱 선택 재정의\n--headless-sizeWIDTHxHEIGHT 새로운 가상 디스플레이; 기본값 1920x1080, 심지어 320..8192\n--headless-sessionEXECUTABLE 데스크탑 시작(startxfce4, 베어 디스플레이의 경우 없음)\n--no-headless자동 폴백 비활성화\n일반 시작에서는 기존 데스크탑을 자동으로 선택합니다. 콘솔에 설정을 입력하여 구성하세요.\n", + "de": "Linux-Headless-Optionen:\n--headlessWählen Sie einen vorhandenen Desktop aus und aktivieren Sie die Konsole.\n--headless-displayDISPLAY Erweitert: Desktop-Auswahl überschreiben\n--headless-sizeWIDTHxHEIGHT Neue virtuelle Anzeige; Standard 1920x1080, sogar 320..8192\n--headless-sessionAUSFÜHRBAR Starten Sie einen Desktop (startxfce4; keiner für eine bloße Anzeige)\n--no-headlessAutomatisches Fallback deaktivieren\nBeim normalen Start wird Ihr vorhandener Desktop automatisch ausgewählt. Geben Sie in der Konsole Einstellungen ein, um es zu konfigurieren.\n", + "fr": "Options sans tête Linux :\n--headlessSélectionnez un bureau existant et activez la console.\n--headless-displayDISPLAY Avancé : remplacer la sélection du bureau\n--headless-sizeWIDTHxHEIGHT Nouvel affichage virtuel ; par défaut 1920x1080, même 320..8192\n--headless-sessionEXECUTABLE Démarrer un bureau (startxfce4 ; aucun pour un affichage nu)\n--no-headlessDésactiver le repli automatique\nLe démarrage normal sélectionne automatiquement votre bureau existant. Entrez les paramètres dans la console pour le configurer.\n", + "es": "Opciones sin cabeza de Linux:\n--headlessSeleccione un escritorio existente y habilite la consola\n--headless-displayDISPLAY Avanzado: anule la selección de escritorio\n--headless-sizeWIDTHxHEIGHT Nueva pantalla virtual; predeterminado 1920x1080, incluso 320..8192\n--headless-sessionEJECUTABLE Iniciar un escritorio (startxfce4; ninguno para una pantalla simple)\n--no-headlessDeshabilitar el respaldo automático\nEl inicio normal selecciona automáticamente su escritorio existente. Ingrese la configuración en la consola para configurarlo.\n", + "pt-BR": "Opções sem cabeça do Linux:\n--headlessSelecione um desktop existente e ative o console\n--headless-displayDISPLAY Avançado: substitui a seleção do desktop\n--headless-sizeWIDTHxHEIGHT Novo display virtual; padrão 1920x1080, até 320..8192\n--headless-sessionEXECUTABLE Iniciar uma área de trabalho (startxfce4; nenhum para uma tela vazia)\n--no-headlessDesativar fallback automático\nA inicialização normal seleciona sua área de trabalho existente automaticamente. Insira as configurações no console para configurá-lo.\n" + }, + "OpenFEC 告知": { + "zh-Hans": "OpenFEC 告知", + "en": "OpenFEC notice", + "ru": "Уведомление OpenFEC", + "zh-Hant": "OpenFEC 告知", + "ja": "OpenFEC通知", + "ko": "OpenFEC공지", + "de": "OpenFEC-Hinweis", + "fr": "Avis OpenFEC", + "es": "Aviso OpenFEC", + "pt-BR": "Aviso OpenFEC" + }, + "OpenFEC 提供前向纠错能力,遵循 CeCILL-C 1.0 许可。其许可规定了有限保证及责任限制,请阅读组件详情。": { + "zh-Hans": "OpenFEC 提供前向纠错能力,遵循 CeCILL-C 1.0 许可。其许可规定了有限保证及责任限制,请阅读组件详情。", + "en": "OpenFEC provides forward error correction capabilities and is licensed under theCeCILL-C1.0 license. The license provides for a limited warranty and limitations of liability, please read the component details.", + "zh-Hant": "OpenFEC 提供前向糾錯能力,遵循 CeCILL-C 1.0 許可。其許可規定了有限保證及責任限制,請閱讀元件詳情。", + "ja": "OpenFECは前方誤り訂正機能を提供し、CeCILL-C1.0 ライセンスに基づいてライセンスされています。ライセンスには限定保証と責任制限が規定されています。コンポーネントの詳細をお読みください。", + "ko": "OpenFEC는 순방향 오류 수정 기능을 제공하며 CeCILL-C1.0 라이선스에 따라 라이선스가 부여됩니다. 라이센스는 제한된 보증 및 책임 제한을 제공합니다. 구성 요소 세부 정보를 읽어보십시오.", + "de": "OpenFEC bietet Vorwärtsfehlerkorrekturfunktionen und ist unter der CeCILL-C1.0-Lizenz lizenziert. Die Lizenz sieht eine eingeschränkte Garantie und Haftungsbeschränkungen vor. Bitte lesen Sie die Komponentendetails.", + "fr": "OpenFEC fournit des capacités de correction d'erreur directe et est sous licence CeCILL-C1.0. La licence prévoit une garantie limitée et des limitations de responsabilité, veuillez lire les détails des composants.", + "es": "OpenFEC proporciona capacidades de corrección de errores hacia adelante y tiene la licencia CeCILL-C1.0. La licencia proporciona una garantía limitada y limitaciones de responsabilidad; lea los detalles del componente.", + "pt-BR": "OpenFEC fornece recursos de correção direta de erros e é licenciado sob a licença CeCILL-C1.0. A licença fornece uma garantia limitada e limitações de responsabilidade. Leia os detalhes do componente.", + "ru": "OpenFEC обеспечивает возможности прямого исправления ошибок и лицензируется по лицензии CeCILL-C1.0. Лицензия предусматривает ограниченную гарантию и ограничение ответственности. Пожалуйста, ознакомьтесь с подробностями компонента." + }, + "OpenFEC 许可与源码": { + "zh-Hans": "OpenFEC 许可与源码", + "en": "OpenFEC license and source", + "ru": "Лицензия и исходный код OpenFEC", + "zh-Hant": "OpenFEC 許可與原始碼", + "ja": "OpenFECライセンスとソース", + "ko": "OpenFEC라이선스 및 소스", + "de": "OpenFEC Lizenz und Quelle", + "fr": "Licence et source OpenFEC", + "es": "Licencia y fuente OpenFEC", + "pt-BR": "Licença e fonte OpenFEC" + }, + "P2P 直连": { + "zh-Hans": "P2P 直连", + "en": "P2P direct connection", + "zh-Hant": "P2P 直連", + "ja": "P2P直接接続", + "ko": "P2P 직접 연결", + "de": "P2P-Direktverbindung", + "fr": "Connexion directe P2P", + "es": "Conexión directa P2P", + "pt-BR": "Conexão direta P2P", + "ru": "Прямое соединение P2P" + }, + "P2P/TURN 建链失败,请检查网络后重试。": { + "zh-Hans": "P2P/TURN 建链失败,请检查网络后重试。", + "en": "P2P/TURN Link establishment failed, please check the network and try again.", + "zh-Hant": "P2P/TURN 建鏈失敗,請檢查網路後重試。", + "ja": "P2P/TURNリンクの確立に失敗しました。ネットワークを確認して再試行してください。", + "ko": "P2P/TURN링크 설정에 실패했습니다. 네트워크를 확인하고 다시 시도하십시오.", + "de": "P2P/TURN Verbindungsaufbau fehlgeschlagen, bitte überprüfen Sie das Netzwerk und versuchen Sie es erneut.", + "fr": "Échec de l'établissement du lien P2P/TURN, veuillez vérifier le réseau et réessayer.", + "es": "P2P/TURN Error al establecer el enlace, verifique la red e inténtelo nuevamente.", + "pt-BR": "P2P/TURN Falha no estabelecimento do link, verifique a rede e tente novamente.", + "ru": "P2P/TURN Не удалось установить соединение. Проверьте сеть и повторите попытку." + }, + "SRTP 已启用": { + "zh-Hans": "SRTP 已启用", + "en": "SRTP enabled", + "zh-Hant": "SRTP 已啟用", + "ja": "SRT有効", + "ko": "SRTP 활성화됨", + "de": "SRTP enabled", + "fr": "SRTP activé", + "es": "SRTP habilitado", + "pt-BR": "SRT habilitado", + "ru": "SRTP включен" + }, + "TLS 证书校验失败": { + "zh-Hans": "TLS 证书校验失败", + "en": "TLS certificate verification failed", + "zh-Hant": "TLS 證書校驗失敗", + "ja": "TLS証明書の検証に失敗しました", + "ko": "TLS인증서 확인 실패", + "de": "Die Überprüfung des TLS-Zertifikats ist fehlgeschlagen", + "fr": "La vérification du certificat TLS a échoué", + "es": "Error en la verificación del certificado TLS", + "pt-BR": "Falha na verificação do certificado TLS", + "ru": "Проверка TLS certificate не удалась." + }, + "TURN 中继": { + "zh-Hans": "TURN 中继", + "en": "TURN relay", + "zh-Hant": "TURN 中繼", + "ja": "ターンリレー", + "ko": "TURN 릴레이", + "de": "TURN-Relais", + "fr": "Relais TOUR", + "es": "Relé de GIRO", + "pt-BR": "GIRAR relé", + "ru": "Реле ПОВОРОТА" + }, + "Wayland 会话提示": { + "zh-Hans": "Wayland 会话提示", + "en": "Wayland Session Notice", + "ru": "Уведомление о сеансе Wayland", + "zh-Hant": "Wayland 會話提示", + "ja": "Waylandセッションのお知らせ", + "ko": "Wayland 세션 공지", + "de": "Wayland-Sitzungsmitteilung", + "fr": "Avis de session Wayland", + "es": "Aviso de sesión de Wayland", + "pt-BR": "Aviso de Sessão Wayland" + }, + "{0} 传输失败": { + "zh-Hans": "{0} 传输失败", + "en": "{0} transmission failed", + "zh-Hant": "{0} 傳輸失敗", + "ja": "{0}送信失敗", + "ko": "{0}전송 실패", + "de": "{0}-Übertragung fehlgeschlagen", + "fr": "Échec de la transmission {0}", + "es": "Error en la transmisión {0}", + "pt-BR": "Falha na transmissão {0}", + "ru": "Передача {0} не удалась." + }, + "{0} 台设备": { + "zh-Hans": "{0} 台设备", + "en": "Devices: {0}", + "zh-Hant": "{0} 臺裝置", + "ja": "デバイス数: {0}", + "ko": "기기: {0}", + "de": "Geräte: {0}", + "fr": "Appareils : {0}", + "es": "Dispositivos: {0}", + "pt-BR": "Dispositivos: {0}", + "ru": "Устройства: {0}" + }, + "© 2026 JUNKUN DI。保留所有权利。": { + "zh-Hans": "© 2026 JUNKUN DI。保留所有权利。", + "en": "© 2026 by JUNKUN DI. All rights reserved.", + "ru": "© 2026 JUNKUN DI. Все права защищены.", + "zh-Hant": "© 2026 JUNKUN DI。保留所有權利。", + "ja": "© 2026 by JUNKUN DI.無断転載を禁じます。", + "ko": "© 2026 by JUNKUN DI. 모든 권리 보유.", + "de": "© 2026 von JUNKUN DI. Alle Rechte vorbehalten.", + "fr": "© 2026 par JUNKUN DI. Tous droits réservés.", + "es": "© 2026 por JUNKUN DI. Reservados todos los derechos.", + "pt-BR": "© 2026 por JUNKUN DI. Todos os direitos reservados." + }, + "● 已连接": { + "zh-Hans": "● 已连接", + "en": "● Connected", + "zh-Hant": "● 已連線", + "ja": "● 接続されました", + "ko": "● 연결됨", + "de": "● Verbunden", + "fr": "● Connecté", + "es": "● Conectado", + "pt-BR": "● Conectado", + "ru": "● Подключено" + }, + "上下拖动,调整缩略图与主画面大小": { + "zh-Hans": "上下拖动,调整缩略图与主画面大小", + "en": "Drag up or down to resize the thumbnails and main preview", + "ru": "Потяните вверх или вниз, чтобы изменить размер миниатюр и основного экрана", + "zh-Hant": "上下拖動,調整縮圖與主畫面大小", + "ja": "上下にドラッグしてサムネイルとメイン プレビューのサイズを変更します", + "ko": "썸네일과 메인 미리보기의 크기를 조정하려면 위나 아래로 드래그하세요.", + "de": "Ziehen Sie nach oben oder unten, um die Größe der Miniaturansichten und der Hauptvorschau zu ändern", + "fr": "Faites glisser vers le haut ou vers le bas pour redimensionner les vignettes et l'aperçu principal", + "es": "Arrastre hacia arriba o hacia abajo para cambiar el tamaño de las miniaturas y la vista previa principal", + "pt-BR": "Arraste para cima ou para baixo para redimensionar as miniaturas e a visualização principal" + }, + "上下滑动,可滑出按键范围": { + "zh-Hans": "上下滑动,可滑出按键范围", + "en": "Slide up and down to slide out of the key range", + "zh-Hant": "上下滑動,可滑出按鍵範圍", + "ja": "上下にスライドしてキー範囲外にスライドします", + "ko": "키 범위에서 벗어나려면 위아래로 슬라이드하세요.", + "de": "Nach oben und unten schieben, um aus dem Tastenbereich herauszurutschen", + "fr": "Faites glisser vers le haut et vers le bas pour sortir de la plage de touches", + "es": "Deslice hacia arriba y hacia abajo para salir del rango de teclas", + "pt-BR": "Deslize para cima e para baixo para sair do intervalo de teclas", + "ru": "Сдвиньте вверх и вниз, чтобы выйти за пределы диапазона клавиш." + }, + "下拉刷新": { + "zh-Hans": "下拉刷新", + "en": "Pull down to refresh", + "zh-Hant": "下拉重新整理", + "ja": "プルダウンして更新します", + "ko": "아래로 당겨 새로고침", + "de": "Zum Aktualisieren nach unten ziehen", + "fr": "Déroulez pour actualiser", + "es": "Tire hacia abajo para actualizar", + "pt-BR": "Puxe para baixo para atualizar", + "ru": "Потяните вниз, чтобы обновить" + }, + "下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?": { + "zh-Hans": "下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?", + "en": "CrossDesk will close after downloading the update. Connections and file transfers will be interrupted. Installation requires system authorization, then CrossDesk will restart. Continue?", + "ru": "После загрузки CrossDesk закроется для обновления. Соединения и передача файлов будут прерваны. Потребуется разрешение системы, затем приложение перезапустится. Продолжить?", + "zh-Hant": "下載完成後將關閉 CrossDesk 並安裝更新,當前連線和檔案傳輸會中斷。安裝需要系統授權,完成後重新啟動。是否繼續?", + "ja": "アップデートをダウンロードした後、CrossDeskは閉じます。接続とファイル転送は中断されます。インストールにはシステム認証が必要です。その後、CrossDeskが再起動します。続く?", + "ko": "업데이트를 다운로드한 후CrossDesk가 종료됩니다. 연결 및 파일 전송이 중단됩니다. 설치하려면 시스템 인증이 필요하며, 그런 다음CrossDesk가 다시 시작됩니다. 계속하다?", + "de": "CrossDesk wird nach dem Herunterladen des Updates geschlossen. Verbindungen und Dateiübertragungen werden unterbrochen. Für die Installation ist eine Systemautorisierung erforderlich. Anschließend wird CrossDesk neu gestartet. Weitermachen?", + "fr": "CrossDesk se fermera après le téléchargement de la mise à jour. Les connexions et les transferts de fichiers seront interrompus. L'installation nécessite une autorisation du système, puis CrossDesk redémarrera. Continuer?", + "es": "CrossDesk se cerrará después de descargar la actualización. Se interrumpirán las conexiones y transferencias de archivos. La instalación requiere autorización del sistema, luego CrossDesk se reiniciará. ¿Continuar?", + "pt-BR": "CrossDesk será fechado após o download da atualização. As conexões e transferências de arquivos serão interrompidas. A instalação requer autorização do sistema e o CrossDesk será reiniciado. Continuar?" + }, + "不再提醒": { + "zh-Hans": "不再提醒", + "en": "Do not remind again", + "ru": "Больше не напоминать", + "zh-Hant": "不再提醒", + "ja": "二度と思い出さないでください", + "ko": "다시 알림 안 함", + "de": "Nicht noch einmal erinnern", + "fr": "Ne plus rappeler", + "es": "No volver a recordar", + "pt-BR": "Não lembre novamente" + }, + "不填端口时,默认使用 52888": { + "zh-Hans": "不填端口时,默认使用 52888", + "en": "Port defaults to 52888 if omitted", + "ru": "Без порта используется 52888", + "zh-Hant": "不填埠時,預設使用 52888", + "ja": "省略した場合、ポートはデフォルトで 52888 になります。", + "ko": "생략할 경우 포트 기본값은 52888입니다.", + "de": "Der Port ist standardmäßig 52888, wenn er weggelassen wird", + "fr": "Le port par défaut est 52888 s'il est omis", + "es": "El puerto predeterminado es 52888 si se omite", + "pt-BR": "A porta padrão é 52888 se omitida" + }, + "丢包 ": { + "zh-Hans": "丢包 ", + "en": "Loss ", + "ru": "Потери ", + "zh-Hant": "丟包 ", + "ja": "損失 ", + "ko": "손실 ", + "de": "Verlust ", + "fr": "Perte ", + "es": "Pérdida ", + "pt-BR": "Perda " + }, + "丢包率": { + "zh-Hans": "丢包率", + "en": "Loss Rate", + "ru": "Потери пакетов", + "zh-Hant": "丟包率", + "ja": "損失率", + "ko": "손실률", + "de": "Verlustrate", + "fr": "Taux de perte", + "es": "Tasa de pérdidas", + "pt-BR": "Taxa de perda" + }, + "中": { + "zh-Hans": "中", + "en": "Medium", + "ru": "Среднее", + "zh-Hant": "中", + "ja": "中", + "ko": "중간", + "de": "Mittel", + "fr": "Moyenne", + "es": "Media", + "pt-BR": "Média" + }, + "中文等文本请通过剪贴板发送,再点击粘贴": { + "zh-Hans": "中文等文本请通过剪贴板发送,再点击粘贴", + "en": "Please send Chinese and other texts via the clipboard, then click paste", + "zh-Hant": "中文等文字請透過剪貼簿傳送,再點選貼上", + "ja": "中国語やその他のテキストをクリップボード経由で送信し、貼り付けをクリックしてください", + "ko": "클립보드를 통해 중국어 및 기타 문자를 보내신 후 붙여넣기를 눌러주세요.", + "de": "Bitte senden Sie chinesische und andere Texte über die Zwischenablage und klicken Sie dann auf Einfügen", + "fr": "Veuillez envoyer les textes chinois et autres via le presse-papiers, puis cliquez sur Coller", + "es": "Envíe textos en chino y otros a través del portapapeles, luego haga clic en pegar", + "pt-BR": "Envie textos em chinês e outros textos através da área de transferência e clique em colar", + "ru": "Отправьте текст на китайском и других языках через буфер обмена, затем нажмите «Вставить»." + }, + "中继": { + "zh-Hans": "中继", + "en": "Relay", + "ru": "Ретрансляция", + "zh-Hant": "中繼", + "ja": "リレー", + "ko": "릴레이", + "de": "Relais", + "fr": "Relais", + "es": "Relé", + "pt-BR": "Relé" + }, + "中继模式": { + "zh-Hans": "中继模式", + "en": "TURN relay mode", + "ru": "Режим ретрансляции TURN", + "zh-Hant": "中繼模式", + "ja": "TURNリレーモード", + "ko": "TURN 릴레이 모드", + "de": "TURN-Relaismodus", + "fr": "Mode relais TOUR", + "es": "Modo de relé GIRO", + "pt-BR": "Modo de relé TURN" + }, + "为便于持续使用远程桌面,建议注销当前桌面会话,在登录界面选择 X11(Xorg)会话后重新登录。": { + "zh-Hans": "为便于持续使用远程桌面,建议注销当前桌面会话,在登录界面选择 X11(Xorg)会话后重新登录。", + "en": "For ongoing remote desktop access, we recommend logging out, selecting an X11 (Xorg) session on the login screen, and logging in again.", + "ru": "Для постоянного удалённого доступа рекомендуем завершить сеанс, выбрать X11 (Xorg) на экране входа и войти снова.", + "zh-Hant": "為便於持續使用遠端桌面,建議登出當前桌面會話,在登入介面選擇 X11(Xorg)會話後重新登入。", + "ja": "継続的なリモート デスクトップ アクセスの場合は、ログアウトし、ログイン画面で X11 (Xorg) セッションを選択し、再度ログインすることをお勧めします。", + "ko": "지속적인 원격 데스크톱 접속을 위해서는 로그아웃 후 로그인 화면에서 X11(Xorg) 세션을 선택한 후 다시 로그인하는 것을 권장합니다.", + "de": "Für den dauerhaften Remote-Desktop-Zugriff empfehlen wir, sich abzumelden, auf dem Anmeldebildschirm eine X11-Sitzung (Xorg) auszuwählen und sich erneut anzumelden.", + "fr": "Pour un accès continu au bureau à distance, nous vous recommandons de vous déconnecter, de sélectionner une session X11 (Xorg) sur l'écran de connexion et de vous reconnecter.", + "es": "Para un acceso continuo al escritorio remoto, recomendamos cerrar sesión, seleccionar una sesión X11 (Xorg) en la pantalla de inicio de sesión e iniciar sesión nuevamente.", + "pt-BR": "Para acesso contínuo à área de trabalho remota, recomendamos fazer logout, selecionar uma sessão X11 (Xorg) na tela de login e fazer login novamente." + }, + "为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk Service。\n未安装该服务不影响 CrossDesk 正常使用,仅无法在锁屏状态下控制本机。": { + "zh-Hans": "为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk Service。\n未安装该服务不影响 CrossDesk 正常使用,仅无法在锁屏状态下控制本机。", + "en": "To support remote control of this device while it is locked, CrossDesk Service must be installed with administrator permission.\nWithout this service, CrossDesk still works normally; only lock-screen control of this computer is unavailable.", + "ru": "Чтобы поддерживать удаленное управление этим устройством на экране блокировки, необходимо установить CrossDesk Service с правами администратора.\nБез этой службы CrossDesk продолжит работать нормально; будет недоступно только управление этим компьютером на экране блокировки.", + "zh-Hant": "為支援該裝置在鎖屏狀態下被遠端控制,需要以管理員許可權安裝 CrossDesk Service。\n未安裝該服務不影響 CrossDesk 正常使用,僅無法在鎖屏狀態下控制本機。", + "ja": "ロック中のこのデバイスのリモート制御をサポートするには、管理者権限でCrossDeskサービスをインストールする必要があります。\nこのサービスがなくても、CrossDeskは通常どおり動作します。このコンピュータのロック画面制御のみが利用できません。", + "ko": "이 장치가 잠겨 있는 동안 원격 제어를 지원하려면 관리자 권한으로CrossDesk서비스를 설치해야 합니다.\n이 서비스가 없으면CrossDesk는 여전히 정상적으로 작동합니다. 이 컴퓨터의 잠금 화면 제어만 사용할 수 없습니다.", + "de": "Um die Fernsteuerung dieses Geräts zu unterstützen, während es gesperrt ist, muss der CrossDesk-Dienst mit Administratorrechten installiert werden.\nOhne diesen Dienst funktioniert CrossDesk weiterhin normal. Nur die Sperrbildschirmsteuerung dieses Computers ist nicht verfügbar.", + "fr": "Pour prendre en charge le contrôle à distance de cet appareil lorsqu'il est verrouillé, le service CrossDesk doit être installé avec l'autorisation d'administrateur.\nSans ce service,CrossDesk fonctionne toujours normalement ; seul le contrôle de l'écran de verrouillage de cet ordinateur n'est pas disponible.", + "es": "Para admitir el control remoto de este dispositivo mientras está bloqueado, el servicio CrossDesk debe instalarse con permiso de administrador.\nSin este servicio,CrossDesk todavía funciona normalmente; Sólo el control de pantalla de bloqueo de esta computadora no está disponible.", + "pt-BR": "Para oferecer suporte ao controle remoto deste dispositivo enquanto ele está bloqueado, o serviço CrossDesk deve ser instalado com permissão de administrador.\nSem este serviço,CrossDesk ainda funciona normalmente; apenas o controle da tela de bloqueio deste computador está indisponível." + }, + "从当前分组移除此设备?": { + "zh-Hans": "从当前分组移除此设备?", + "en": "Remove from this group?", + "ru": "Убрать из этой группы?", + "zh-Hant": "從當前分組移除此裝置?", + "ja": "このグループから削除しますか?", + "ko": "이 그룹에서 제거하시겠습니까?", + "de": "Aus dieser Gruppe entfernen?", + "fr": "Supprimer de ce groupe ?", + "es": "¿Eliminar de este grupo?", + "pt-BR": "Remover deste grupo?" + }, + "从桌面墙移除": { + "zh-Hans": "从桌面墙移除", + "en": "Remove from DeskHub", + "ru": "Убрать из DeskHub", + "zh-Hant": "從桌面牆移除", + "ja": "DeskHubから削除", + "ko": "DeskHub에서 제거", + "de": "Aus DeskHub entfernen", + "fr": "Supprimer de DeskHub", + "es": "Eliminar de DeskHub", + "pt-BR": "Remover de DeskHub" + }, + "从桌面墙移除此设备?": { + "zh-Hans": "从桌面墙移除此设备?", + "en": "Remove from DeskHub?", + "ru": "Убрать из DeskHub?", + "zh-Hant": "從桌面牆移除此裝置?", + "ja": "DeskHubから削除しますか?", + "ko": "DeskHub에서 제거하시겠습니까?", + "de": "Aus DeskHub entfernen?", + "fr": "Supprimer de DeskHub?", + "es": "¿Eliminar de DeskHub?", + "pt-BR": "Remover de DeskHub?" + }, + "从近期连接添加": { + "zh-Hans": "从近期连接添加", + "en": "Add from recent connections", + "ru": "Добавить из недавних", + "zh-Hant": "從近期連線新增", + "ja": "最近の接続から追加", + "ko": "최근 연결에서 추가", + "de": "Aus den letzten Verbindungen hinzufügen", + "fr": "Ajouter à partir de connexions récentes", + "es": "Agregar desde conexiones recientes", + "pt-BR": "Adicionar de conexões recentes" + }, + "以下列出本版本的主要开源组件。各组件遵循各自的开源许可。": { + "zh-Hans": "以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", + "en": "Main open-source components used in this build. Each component is covered by its own license.", + "ru": "Основные открытые компоненты этой сборки. Каждый распространяется по своей лицензии.", + "zh-Hant": "以下列出本版本的主要開源元件。各元件遵循各自的開源許可。", + "ja": "このビルドで使用される主なオープンソース コンポーネント。各コンポーネントは独自のライセンスによってカバーされます。", + "ko": "이 빌드에 사용된 주요 오픈 소스 구성 요소입니다. 각 구성요소에는 자체 라이센스가 적용됩니다.", + "de": "In diesem Build verwendete Haupt-Open-Source-Komponenten. Für jede Komponente gilt eine eigene Lizenz.", + "fr": "Principaux composants open source utilisés dans cette version. Chaque composant est couvert par sa propre licence.", + "es": "Principales componentes de código abierto utilizados en esta compilación. Cada componente está cubierto por su propia licencia.", + "pt-BR": "Principais componentes de código aberto usados nesta compilação. Cada componente é coberto por sua própria licença." + }, + "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。": { + "zh-Hans": "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。", + "en": "Prioritizes keeping the picture smooth, and will reduce resolution more aggressively when bandwidth or encoding pressure is high.", + "zh-Hant": "優先保持畫面流暢,頻寬或編碼壓力較大時會更積極地降低解析度。", + "ja": "画像を滑らかに保つことを優先し、帯域幅やエンコード圧力が高い場合には、より積極的に解像度を下げます。", + "ko": "영상을 부드럽게 유지하는 데 우선 순위를 두며 대역폭이나 인코딩 압력이 높을 때 해상도를 더욱 적극적으로 줄입니다.", + "de": "Priorisiert die Aufrechterhaltung eines flüssigen Bildes und reduziert die Auflösung stärker, wenn die Bandbreite oder der Codierungsdruck hoch ist.", + "fr": "Donne la priorité au maintien de la fluidité de l'image et réduira la résolution de manière plus agressive lorsque la bande passante ou la pression d'encodage est élevée.", + "es": "Da prioridad a mantener la imagen fluida y reducirá la resolución de manera más agresiva cuando el ancho de banda o la presión de codificación sean altos.", + "pt-BR": "Prioriza manter a imagem suave e reduzirá a resolução de forma mais agressiva quando a largura de banda ou a pressão de codificação forem altas.", + "ru": "Отдает приоритет сохранению плавности изображения и более агрессивно снижает разрешение при высокой пропускной способности или нагрузке на кодирование." + }, + "低": { + "zh-Hans": "低", + "en": "Low", + "ru": "Низкое", + "zh-Hant": "低", + "ja": "低", + "ko": "낮음", + "de": "Niedrig", + "fr": "Faible", + "es": "Baja", + "pt-BR": "Baixa" + }, + "使用自定义服务器": { + "zh-Hans": "使用自定义服务器", + "en": "Using a custom server", + "zh-Hant": "使用自定義伺服器", + "ja": "カスタムサーバーの使用", + "ko": "커스텀 서버 이용하기", + "de": "Verwendung eines benutzerdefinierten Servers", + "fr": "Utilisation d'un serveur personnalisé", + "es": "Usando un servidor personalizado", + "pt-BR": "Usando um servidor personalizado", + "ru": "Использование пользовательского сервера" + }, + "依据 GNU GPL v3 许可发布。": { + "zh-Hans": "依据 GNU GPL v3 许可发布。", + "en": "Licensed under GNU GPL v3.", + "ru": "Распространяется по лицензии GNU GPL v3.", + "zh-Hant": "依據 GNU GPL v3 許可釋出。", + "ja": "GNU GPL v3に基づいてライセンスされています。", + "ko": "GNU GPL v3에 따라 라이센스가 부여되었습니다.", + "de": "Lizenziert unterGNU GPL v3.", + "fr": "Sous licenceGNU GPL v3.", + "es": "Con licenciaGNU GPL v3.", + "pt-BR": "Licenciado sobGNU GPL v3." + }, + "保存": { + "zh-Hans": "保存", + "en": "Save", + "ru": "Сохранить", + "zh-Hant": "儲存", + "ja": "保存", + "ko": "저장", + "de": "Speichern", + "fr": "Enregistrer", + "es": "Guardar", + "pt-BR": "Salvar" + }, + "保存失败,请重试": { + "zh-Hans": "保存失败,请重试", + "en": "Could not save; try again", + "ru": "Не удалось сохранить. Повторите попытку", + "zh-Hant": "儲存失敗,請重試", + "ja": "保存できませんでした。もう一度試してください", + "ko": "저장할 수 없습니다. 다시 시도", + "de": "Konnte nicht gespeichert werden; Versuchen Sie es noch einmal", + "fr": "Impossible d'enregistrer ; réessaye", + "es": "No se pudo guardar; intentarlo de nuevo", + "pt-BR": "Não foi possível salvar; tente novamente" + }, + "保存密码": { + "zh-Hans": "保存密码", + "en": "Save password", + "zh-Hant": "儲存密碼", + "ja": "パスワードの保存", + "ko": "비밀번호 저장", + "de": "Passwort speichern", + "fr": "Enregistrer le mot de passe", + "es": "Guardar contraseña", + "pt-BR": "Salvar senha", + "ru": "Сохранить пароль" + }, + "保存收到的文件": { + "zh-Hans": "保存收到的文件", + "en": "Save received file", + "zh-Hant": "儲存收到的檔案", + "ja": "受信したファイルを保存する", + "ko": "수신된 파일 저장", + "de": "Empfangene Datei speichern", + "fr": "Enregistrer le fichier reçu", + "es": "Guardar archivo recibido", + "pt-BR": "Salvar arquivo recebido", + "ru": "Сохранить полученный файл" + }, + "保存设置失败,原设置保持不变。请检查日志。": { + "zh-Hans": "保存设置失败,原设置保持不变。请检查日志。", + "en": "Failed to save settings; the previous value is retained. Check the log.", + "ru": "Не удалось сохранить настройки. Прежнее значение сохранено. Проверьте журнал.", + "zh-Hant": "儲存設定失敗,原設定保持不變。請檢查日誌。", + "ja": "設定の保存に失敗しました。以前の値が保持されます。ログを確認してください。", + "ko": "설정을 저장하지 못했습니다. 이전 값이 유지됩니다. 로그를 확인하세요.", + "de": "Einstellungen konnten nicht gespeichert werden; der bisherige Wert bleibt erhalten. Überprüfen Sie das Protokoll.", + "fr": "Échec de l'enregistrement des paramètres ; la valeur précédente est conservée. Vérifiez le journal.", + "es": "No se pudo guardar la configuración; se mantiene el valor anterior. Consulta el registro.", + "pt-BR": "Falha ao salvar configurações; o valor anterior é mantido. Verifique o registro." + }, + "保存远程画面预览": { + "zh-Hans": "保存远程画面预览", + "en": "Save remote screen previews", + "ru": "Сохранять превью удалённого экрана", + "zh-Hant": "儲存遠端畫面預覽", + "ja": "リモート画面のプレビューを保存する", + "ko": "원격 화면 미리보기 저장", + "de": "Remote-Bildschirmvorschauen speichern", + "fr": "Enregistrer les aperçus de l'écran distant", + "es": "Guardar vistas previas de pantalla remotas", + "pt-BR": "Salvar visualizações de tela remotas" + }, + "保存远程画面预览?": { + "zh-Hans": "保存远程画面预览?", + "en": "Save remote screen preview?", + "zh-Hant": "儲存遠端畫面預覽?", + "ja": "リモート画面のプレビューを保存しますか?", + "ko": "원격 화면 미리보기를 저장하시겠습니까?", + "de": "Remote-Bildschirmvorschau speichern?", + "fr": "Enregistrer l'aperçu de l'écran distant ?", + "es": "¿Guardar vista previa de pantalla remota?", + "pt-BR": "Salvar visualização remota da tela?", + "ru": "Сохранить предварительный просмотр удаленного экрана?" + }, + "信令服务器已关闭连接": { + "zh-Hans": "信令服务器已关闭连接", + "en": "The signaling server has closed the connection", + "zh-Hant": "信令伺服器已關閉連線", + "ja": "シグナリングサーバーが接続を閉じました", + "ko": "시그널링 서버가 연결을 종료했습니다.", + "de": "Der Signalisierungsserver hat die Verbindung geschlossen", + "fr": "Le serveur de signalisation a fermé la connexion", + "es": "El servidor de señalización ha cerrado la conexión.", + "pt-BR": "O servidor de sinalização fechou a conexão", + "ru": "Сервер сигнализации закрыл соединение." + }, + "信令服务端口": { + "zh-Hans": "信令服务端口", + "en": "Signaling port", + "ru": "Порт сигнализации", + "zh-Hant": "信令服務埠", + "ja": "信号ポート", + "ko": "신호 포트", + "de": "Signalisierungsport", + "fr": "Port de signalisation", + "es": "Puerto de señalización", + "pt-BR": "Porta de sinalização" + }, + "信令服务重连中": { + "zh-Hans": "信令服务重连中", + "en": "Signaling service reconnecting", + "zh-Hant": "信令服務重連中", + "ja": "シグナリング サービスの再接続", + "ko": "시그널링 서비스 재접속", + "de": "Signalisierungsdienst stellt erneut Verbindung her", + "fr": "Reconnexion du service de signalisation", + "es": "Reconexión del servicio de señalización", + "pt-BR": "Reconexão do serviço de sinalização", + "ru": "Повторное подключение услуги сигнализации" + }, + "信令端口": { + "zh-Hans": "信令端口", + "en": "Signaling port", + "ru": "Порт сигнализации", + "zh-Hant": "信令埠", + "ja": "信号ポート", + "ko": "신호 포트", + "de": "Signalisierungsport", + "fr": "Port de signalisation", + "es": "Puerto de señalización", + "pt-BR": "Porta de sinalização" + }, + "信令连接中断,请重新连接": { + "zh-Hans": "信令连接中断,请重新连接", + "en": "The signaling connection is interrupted, please reconnect.", + "zh-Hant": "信令連線中斷,請重新連線", + "ja": "信号接続が中断されました。再接続してください。", + "ko": "신호 연결이 중단되었습니다. 다시 연결하십시오.", + "de": "Die Signalverbindung ist unterbrochen. Bitte stellen Sie die Verbindung wieder her.", + "fr": "La connexion de signalisation est interrompue, veuillez vous reconnecter.", + "es": "La conexión de señalización está interrumpida, vuelva a conectarse.", + "pt-BR": "A conexão de sinalização foi interrompida, reconecte.", + "ru": "Сигнальное соединение прервано, пожалуйста, переподключитесь." + }, + "信令连接失败": { + "zh-Hans": "信令连接失败", + "en": "Signaling connection failed", + "zh-Hant": "信令連線失敗", + "ja": "シグナリング接続に失敗しました", + "ko": "시그널링 연결 실패", + "de": "Signalverbindung fehlgeschlagen", + "fr": "Échec de la connexion de signalisation", + "es": "Error en la conexión de señalización", + "pt-BR": "Falha na conexão de sinalização", + "ru": "Не удалось установить сигнальное соединение." + }, + "信令连接已关闭": { + "zh-Hans": "信令连接已关闭", + "en": "Signaling connection closed", + "zh-Hant": "信令連線已關閉", + "ja": "信号接続が閉じられています", + "ko": "신호 연결이 닫혔습니다.", + "de": "Signalverbindung geschlossen", + "fr": "Connexion de signalisation fermée", + "es": "Conexión de señalización cerrada", + "pt-BR": "Conexão de sinalização fechada", + "ru": "Сигнальное соединение закрыто" + }, + "修改分组": { + "zh-Hans": "修改分组", + "en": "Edit groups", + "ru": "Изменить группы", + "zh-Hant": "修改分組", + "ja": "グループの編集", + "ko": "그룹 편집", + "de": "Gruppen bearbeiten", + "fr": "Modifier les groupes", + "es": "Editar grupos", + "pt-BR": "Editar grupos" + }, + "修改名称": { + "zh-Hans": "修改名称", + "en": "Rename", + "ru": "Переименовать", + "zh-Hant": "修改名稱", + "ja": "名前を変更", + "ko": "이름 바꾸기", + "de": "Umbenennen", + "fr": "Renommer", + "es": "Cambiar nombre", + "pt-BR": "Renomear" + }, + "修改密码": { + "zh-Hans": "修改密码", + "en": "Change password", + "ru": "Изменить пароль", + "zh-Hant": "修改密碼", + "ja": "パスワード変更", + "ko": "비밀번호 변경", + "de": "Passwort ändern", + "fr": "Changer le mot de passe", + "es": "Cambiar contraseña", + "pt-BR": "Alterar senha" + }, + "修改端口": { + "zh-Hans": "修改端口", + "en": "Edit port", + "ru": "Изменить порт", + "zh-Hant": "修改埠", + "ja": "ポートの編集", + "ko": "포트 편집", + "de": "Port bearbeiten", + "fr": "Modifier le port", + "es": "Editar puerto", + "pt-BR": "Editar porta" + }, + "偏好模式": { + "zh-Hans": "偏好模式", + "en": "Preference mode", + "zh-Hant": "偏好模式", + "ja": "プリファレンスモード", + "ko": "선호 모드", + "de": "Präferenzmodus", + "fr": "Mode préférence", + "es": "Modo de preferencia", + "pt-BR": "Modo de preferência", + "ru": "Режим предпочтений" + }, + "停留翻页,松开取消": { + "zh-Hans": "停留翻页,松开取消", + "en": "Hold to turn page; release to cancel", + "ru": "Удерживайте для перелистывания; отпустите для отмены", + "zh-Hant": "停留翻頁,鬆開取消", + "ja": "長押ししてページをめくります。リリースしてキャンセルする", + "ko": "페이지를 넘기려면 길게 누르세요. 취소하다", + "de": "Halten Sie gedrückt, um die Seite umzublättern. Freigabe zum Abbrechen", + "fr": "Maintenez enfoncé pour tourner la page ; libérer pour annuler", + "es": "Mantenga presionado para pasar la página; liberar para cancelar", + "pt-BR": "Segure para virar a página; liberar para cancelar" + }, + "像触控板一样滑动光标,点击时操作当前光标位置。": { + "zh-Hans": "像触控板一样滑动光标,点击时操作当前光标位置。", + "en": "Slide the cursor like a trackpad and operate the current cursor position when clicked.", + "zh-Hant": "像觸控板一樣滑動游標,點選時操作當前游標位置。", + "ja": "トラックパッドのようにカーソルをスライドさせ、クリックすると現在のカーソル位置を操作します。", + "ko": "커서를 트랙패드처럼 밀어서 클릭하면 현재 커서 위치를 조작합니다.", + "de": "Bewegen Sie den Cursor wie ein Trackpad und bedienen Sie die aktuelle Cursorposition, wenn Sie darauf klicken.", + "fr": "Faites glisser le curseur comme un trackpad et actionnez la position actuelle du curseur lorsque vous cliquez dessus.", + "es": "Deslice el cursor como un trackpad y opere la posición actual del cursor cuando se haga clic.", + "pt-BR": "Deslize o cursor como um trackpad e opere a posição atual do cursor quando clicado.", + "ru": "Перемещайте курсор, как трекпад, и управляйте текущим положением курсора при нажатии." + }, + "允许共享此 Mac 的屏幕画面": { + "zh-Hans": "允许共享此 Mac 的屏幕画面", + "en": "Allow sharing this Mac’s screen", + "ru": "Разрешить показ экрана этого Mac", + "zh-Hant": "允許共享此 Mac 的螢幕畫面", + "ja": "この Mac の画面の共有を許可する", + "ko": "이 Mac의 화면 공유를 허용합니다", + "de": "Erlauben Sie die Freigabe des Bildschirms dieses Mac", + "fr": "Autoriser le partage de l'écran de ce Mac", + "es": "Permitir compartir la pantalla de esta Mac", + "pt-BR": "Permitir compartilhar a tela deste Mac" + }, + "允许被控时解锁隐私屏": { + "zh-Hans": "允许被控时解锁隐私屏", + "en": "Allow privacy screen unlock while controlled", + "ru": "Разрешить разблокировку приватного экрана при удалённом управлении", + "zh-Hant": "允許被控時解鎖隱私屏", + "ja": "制御中にプライバシー画面のロック解除を許可する", + "ko": "제어되는 동안 개인 정보 보호 화면 잠금 해제 허용", + "de": "Entsperren des Sichtschutzbildschirms während der Steuerung zulassen", + "fr": "Autoriser le déverrouillage de l'écran de confidentialité pendant le contrôle", + "es": "Permitir el desbloqueo de la pantalla de privacidad mientras está controlado", + "pt-BR": "Permitir desbloqueio da tela de privacidade enquanto controlado" + }, + "允许远程键盘和鼠标控制": { + "zh-Hans": "允许远程键盘和鼠标控制", + "en": "Allow remote keyboard and mouse input", + "ru": "Разрешить удалённый ввод с клавиатуры и мыши", + "zh-Hant": "允許遠端鍵盤和滑鼠控制", + "ja": "リモートのキーボードとマウスの入力を許可する", + "ko": "원격 키보드 및 마우스 입력 허용", + "de": "Remote-Tastatur- und Mauseingabe zulassen", + "fr": "Autoriser la saisie au clavier et à la souris à distance", + "es": "Permitir la entrada remota de teclado y mouse", + "pt-BR": "Permitir entrada remota de teclado e mouse" + }, + "全屏": { + "zh-Hans": "全屏", + "en": "Fullscreen", + "ru": "На весь экран", + "zh-Hant": "全屏", + "ja": "フルスクリーン", + "ko": "전체화면", + "de": "Vollbild", + "fr": "Plein écran", + "es": "Pantalla completa", + "pt-BR": "Tela cheia" + }, + "全选": { + "zh-Hans": "全选", + "en": "Select all", + "ru": "Выбрать все", + "zh-Hant": "全選", + "ja": "全て選択", + "ko": "모두 선택", + "de": "Alles auswählen", + "fr": "Sélectionner tout", + "es": "Seleccionar todo", + "pt-BR": "Selecionar tudo" + }, + "全部已读": { + "zh-Hans": "全部已读", + "en": "Mark all as read", + "ru": "Отметить всё прочитанным", + "zh-Hant": "全部已讀", + "ja": "すべて既読にする", + "ko": "모두 읽음으로 표시", + "de": "Alle als gelesen markieren", + "fr": "Marquer tout comme lu", + "es": "Marcar todo como leído", + "pt-BR": "Marcar tudo como lido" + }, + "全部断开": { + "zh-Hans": "全部断开", + "en": "Disconnect all", + "ru": "Отключить всех", + "zh-Hant": "全部斷開", + "ja": "全て切断する", + "ko": "모두 연결 해제", + "de": "Alle Verbindungen trennen", + "fr": "Tout déconnecter", + "es": "Desconectar todo", + "pt-BR": "Desconecte tudo" + }, + "全部设备": { + "zh-Hans": "全部设备", + "en": "All devices", + "ru": "Все устройства", + "zh-Hant": "全部裝置", + "ja": "すべてのデバイス", + "ko": "모든 장치", + "de": "Alle Geräte", + "fr": "Tous les appareils", + "es": "Todos los dispositivos", + "pt-BR": "Todos os dispositivos" + }, + "公告加载失败,请重试。": { + "zh-Hans": "公告加载失败,请重试。", + "en": "Announcement loading failed, please try again.", + "zh-Hant": "公告載入失敗,請重試。", + "ja": "お知らせを読み込めませんでした。再試行してください。", + "ko": "공지사항 로딩에 실패했습니다. 다시 시도해주세요.", + "de": "Das Laden der Ankündigung ist fehlgeschlagen. Bitte versuchen Sie es erneut.", + "fr": "Le chargement de l'annonce a échoué, veuillez réessayer.", + "es": "Error al cargar el anuncio, inténtelo de nuevo.", + "pt-BR": "Falha ao carregar o anúncio. Tente novamente.", + "ru": "Не удалось загрузить объявление. Повторите попытку." + }, + "公告详情": { + "zh-Hans": "公告详情", + "en": "Announcement details", + "zh-Hant": "公告詳情", + "ja": "発表内容", + "ko": "공지사항", + "de": "Einzelheiten zur Ankündigung", + "fr": "Détails de l'annonce", + "es": "Detalles del anuncio", + "pt-BR": "Detalhes do anúncio", + "ru": "Подробности объявления" + }, + "共 ": { + "zh-Hans": "共 ", + "en": "Total ", + "zh-Hant": "共 ", + "ja": "合計 ", + "ko": "합계 ", + "de": "Insgesamt ", + "fr": "Total ", + "es": "totales ", + "pt-BR": "Total ", + "ru": "Итого " + }, + "共 %1$@ 条 · %2$@ 条未读": { + "zh-Hans": "共 %1$@ 条 · %2$@ 条未读", + "en": "Total %1$@ items ·%2$@ unread items", + "zh-Hant": "共 %1$@ 條 · %2$@ 條未讀", + "ja": "合計%1$@個のアイテム ·%2$@個の未読アイテム", + "ko": "총%1$@항목 ·%2$@읽지 않은 항목", + "de": "Insgesamt %1$@ Artikel ·%2$@ ungelesene Artikel", + "fr": "Total des éléments %1$@· Éléments non lus %2$@", + "es": "Total de elementos %1$@· Elementos no leídos %2$@", + "pt-BR": "Total de itens %1$@· Itens não lidos %2$@", + "ru": "Всего элементов %1$@· Непрочитанные элементы %2$@" + }, + "关于": { + "zh-Hans": "关于", + "en": "About", + "ru": "О программе", + "zh-Hant": "關於", + "ja": "概要", + "ko": "소개", + "de": "Ungefähr", + "fr": "À propos", + "es": "Acerca de", + "pt-BR": "Sobre" + }, + "关于 CrossDesk": { + "zh-Hans": "关于 CrossDesk", + "en": "About CrossDesk", + "ru": "О CrossDesk", + "zh-Hant": "關於 CrossDesk", + "ja": "CrossDesk について", + "ko": "CrossDesk 정보", + "de": "Über CrossDesk", + "fr": "À propos de CrossDesk", + "es": "Acerca de CrossDesk", + "pt-BR": "Sobre o CrossDesk" + }, + "关于,有新版本": { + "zh-Hans": "关于,有新版本", + "en": "About, there is a new version", + "zh-Hant": "關於,有新版本", + "ja": "について、新しいバージョンがあります", + "ko": "새 버전이 있습니다.", + "de": "Ungefähr, es gibt eine neue Version", + "fr": "À propos, il existe une nouvelle version", + "es": "Acerca de, hay una nueva versión.", + "pt-BR": "Sobre, há uma nova versão", + "ru": "О, вышла новая версия" + }, + "关闭": { + "zh-Hans": "关闭", + "en": "Close", + "ru": "Закрыть", + "zh-Hant": "關閉", + "ja": "閉じる", + "ko": "닫기", + "de": "Schließen", + "fr": "Fermer", + "es": "Cerrar", + "pt-BR": "Fechar" + }, + "关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。": { + "zh-Hans": "关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。", + "en": "Disabling IP connections hides the mode button and ends IP sessions.", + "ru": "Отключение подключений по IP скроет кнопку режима и завершит IP-сеансы.", + "zh-Hant": "關閉 IP 連線將隱藏模式按鈕,並斷開 IP 連線會話。", + "ja": "IP 接続を無効にすると、モード ボタンが非表示になり、IP セッションが終了します。", + "ko": "IP 연결을 비활성화하면 모드 버튼이 숨겨지고 IP 세션이 종료됩니다.", + "de": "Durch das Deaktivieren von IP-Verbindungen wird die Modusschaltfläche ausgeblendet und IP-Sitzungen beendet.", + "fr": "La désactivation des connexions IP masque le bouton de mode et met fin aux sessions IP.", + "es": "Deshabilitar las conexiones IP oculta el botón de modo y finaliza las sesiones IP.", + "pt-BR": "Desativar conexões IP oculta o botão de modo e encerra sessões IP." + }, + "关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。": { + "zh-Hans": "关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。", + "en": "Once closed, this prompt stays hidden until the version changes. Sponsorship links remain available in About.", + "ru": "После закрытия это окно появится только при смене версии. Ссылки для поддержки останутся в разделе «О программе».", + "zh-Hant": "關閉後本版本不再提示,升級後再次顯示。贊助入口仍在「關於」中。", + "ja": "このプロンプトは一度閉じると、バージョンが変更されるまで非表示になります。スポンサーリンクは「About」から引き続き利用できます。", + "ko": "일단 닫히면 이 메시지는 버전이 변경될 때까지 숨겨진 상태로 유지됩니다. 후원 링크는 정보에서 계속 사용할 수 있습니다.", + "de": "Nach dem Schließen bleibt diese Eingabeaufforderung ausgeblendet, bis sich die Version ändert. Sponsoring-Links bleiben weiterhin in „Info“ verfügbar.", + "fr": "Une fois fermée, cette invite reste masquée jusqu'à ce que la version change. Les liens de parrainage restent disponibles dans À propos.", + "es": "Una vez cerrado, este mensaje permanece oculto hasta que cambie la versión. Los enlaces de patrocinio permanecen disponibles en Acerca de.", + "pt-BR": "Uma vez fechado, este prompt permanece oculto até que a versão seja alterada. Os links de patrocínio permanecem disponíveis em Sobre." + }, + "关闭控制栏": { + "zh-Hans": "关闭控制栏", + "en": "Close control bar", + "zh-Hant": "關閉控制欄", + "ja": "コントロールバーを閉じる", + "ko": "컨트롤 바 닫기", + "de": "Bedienbügel schließen", + "fr": "Fermer la barre de contrôle", + "es": "Cerrar barra de control", + "pt-BR": "Fechar barra de controle", + "ru": "Закрыть панель управления" + }, + "关闭窗口": { + "zh-Hans": "关闭窗口", + "en": "Close window", + "ru": "Закрыть окно", + "zh-Hant": "關閉視窗", + "ja": "ウィンドウを閉じる", + "ko": "창 닫기", + "de": "Fenster schließen", + "fr": "Fermer la fenêtre", + "es": "Cerrar ventana", + "pt-BR": "Fechar janela" + }, + "关闭群控": { + "zh-Hans": "关闭群控", + "en": "Stop group control", + "ru": "Откл. групп. ввод", + "zh-Hant": "關閉群控", + "ja": "グループ制御の停止", + "ko": "그룹 제어 중지", + "de": "Gruppensteuerung stoppen", + "fr": "Arrêter le contrôle de groupe", + "es": "Detener control de grupo", + "pt-BR": "Parar controle de grupo" + }, + "关闭隐私屏": { + "zh-Hans": "关闭隐私屏", + "en": "Disable privacy screen", + "ru": "Выключить приватный экран", + "zh-Hant": "關閉隱私屏", + "ja": "プライバシー画面を無効にする", + "ko": "개인 정보 보호 화면 비활성화", + "de": "Privatsphäre-Bildschirm deaktivieren", + "fr": "Désactiver l'écran de confidentialité", + "es": "Desactivar la pantalla de privacidad", + "pt-BR": "Desativar tela de privacidade" + }, + "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。": { + "zh-Hans": "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。", + "en": "Balances clarity and smoothness, only gradually reducing resolution under constant pressure.", + "zh-Hant": "兼顧清晰度和流暢度,只在持續壓力下逐步降低解析度。", + "ja": "明瞭さと滑らかさのバランスを保ち、一定の圧力下で解像度を徐々に低下させるだけです。", + "ko": "선명도와 부드러움의 균형을 유지하며 일정한 압력을 가하면 해상도가 점차 감소합니다.", + "de": "Gleicht Klarheit und Glätte aus und verringert die Auflösung bei konstantem Druck nur allmählich.", + "fr": "Équilibre la clarté et la douceur, en réduisant seulement progressivement la résolution sous une pression constante.", + "es": "Equilibra la claridad y la suavidad, reduciendo solo gradualmente la resolución bajo presión constante.", + "pt-BR": "Equilibra clareza e suavidade, reduzindo apenas gradualmente a resolução sob pressão constante.", + "ru": "Балансирует четкость и плавность изображения, постепенно снижая разрешение под постоянным давлением." + }, + "分发文件": { + "zh-Hans": "分发文件", + "en": "Send file", + "ru": "Отправить файл", + "zh-Hant": "分發檔案", + "ja": "ファイルの送信", + "ko": "파일 보내기", + "de": "Datei senden", + "fr": "Envoyer le fichier", + "es": "Enviar archivo", + "pt-BR": "Enviar arquivo" + }, + "分组": { + "zh-Hans": "分组", + "en": "Group", + "ru": "Группа", + "zh-Hant": "分組", + "ja": "グループ", + "ko": "그룹", + "de": "Gruppe", + "fr": "Groupe", + "es": "Grupo", + "pt-BR": "Grupo" + }, + "分组名称(可选)": { + "zh-Hans": "分组名称(可选)", + "en": "Group name (optional)", + "ru": "Группа (необязательно)", + "zh-Hant": "分組名稱(可選)", + "ja": "グループ名(任意)", + "ko": "그룹 이름(선택)", + "de": "Gruppenname (optional)", + "fr": "Nom du groupe (facultatif)", + "es": "Nombre del grupo (opcional)", + "pt-BR": "Nome do grupo (opcional)" + }, + "分辨率": { + "zh-Hans": "分辨率", + "en": "Resolution", + "ru": "Разрешение", + "zh-Hant": "解析度", + "ja": "解像度", + "ko": "해상도", + "de": "Auflösung", + "fr": "Résolution", + "es": "Resolución", + "pt-BR": "Resolução" + }, + "分辨率上限": { + "zh-Hans": "分辨率上限", + "en": "Resolution limit", + "ru": "Макс. разрешение", + "zh-Hant": "解析度上限", + "ja": "解像度制限", + "ko": "해상도 제한", + "de": "Auflösungsgrenze", + "fr": "Limite de résolution", + "es": "Límite de resolución", + "pt-BR": "Limite de resolução" + }, + "切换 IP": { + "zh-Hans": "切换 IP", + "en": "Switch IP", + "ru": "Сменить IP", + "zh-Hant": "切換 IP", + "ja": "スイッチIP", + "ko": "IP 전환", + "de": "IP wechseln", + "fr": "Changer d'adresse IP", + "es": "Cambiar IP", + "pt-BR": "Trocar IP" + }, + "切换到 ID 连接模式": { + "zh-Hans": "切换到 ID 连接模式", + "en": "Switch to ID connection mode", + "ru": "Переключить в режим ID", + "zh-Hant": "切換到 ID 連線模式", + "ja": "ID接続モードに切り替える", + "ko": "ID 연결 모드로 전환", + "de": "Wechseln Sie in den ID-Verbindungsmodus", + "fr": "Passer en mode de connexion ID", + "es": "Cambiar al modo de conexión ID", + "pt-BR": "Mudar para o modo de conexão ID" + }, + "切换到 IP 连接模式": { + "zh-Hans": "切换到 IP 连接模式", + "en": "Switch to IP connection mode", + "ru": "Переключить в режим IP", + "zh-Hant": "切換到 IP 連線模式", + "ja": "IP接続モードに切り替える", + "ko": "IP 연결 모드로 전환", + "de": "Wechseln Sie in den IP-Verbindungsmodus", + "fr": "Passer en mode de connexion IP", + "es": "Cambiar al modo de conexión IP", + "pt-BR": "Mudar para o modo de conexão IP" + }, + "切换到电脑键盘": { + "zh-Hans": "切换到电脑键盘", + "en": "Switch to computer keyboard", + "zh-Hant": "切換到電腦鍵盤", + "ja": "コンピューターのキーボードに切り替える", + "ko": "컴퓨터 키보드로 전환", + "de": "Zur Computertastatur wechseln", + "fr": "Passer au clavier de l'ordinateur", + "es": "Cambiar al teclado de la computadora", + "pt-BR": "Mudar para o teclado do computador", + "ru": "Переключение на клавиатуру компьютера." + }, + "切换到系统键盘": { + "zh-Hans": "切换到系统键盘", + "en": "Switch to system keyboard", + "zh-Hant": "切換到系統鍵盤", + "ja": "システムキーボードに切り替える", + "ko": "시스템 키보드로 전환", + "de": "Zur Systemtastatur wechseln", + "fr": "Passer au clavier système", + "es": "Cambiar al teclado del sistema", + "pt-BR": "Mudar para o teclado do sistema", + "ru": "Переключение на системную клавиатуру" + }, + "切换本机 IP": { + "zh-Hans": "切换本机 IP", + "en": "Switch local IP", + "ru": "Сменить локальный IP", + "zh-Hant": "切換本機 IP", + "ja": "ローカルIPの切り替え", + "ko": "로컬 IP 전환", + "de": "Lokale IP wechseln", + "fr": "Changer d'adresse IP locale", + "es": "Cambiar IP local", + "pt-BR": "Trocar IP local" + }, + "切换设备分组,查看其他连接记录。": { + "zh-Hans": "切换设备分组,查看其他连接记录。", + "en": "Choose another group to see your other connections.", + "ru": "Выберите другую группу для просмотра подключений.", + "zh-Hant": "切換裝置分組,檢視其他連線記錄。", + "ja": "別のグループを選択して、他の接続を確認します。", + "ko": "다른 연결을 보려면 다른 그룹을 선택하세요.", + "de": "Wählen Sie eine andere Gruppe, um Ihre anderen Verbindungen anzuzeigen.", + "fr": "Choisissez un autre groupe pour voir vos autres connexions.", + "es": "Elige otro grupo para ver tus otras conexiones.", + "pt-BR": "Escolha outro grupo para ver suas outras conexões." + }, + "删除": { + "zh-Hans": "删除", + "en": "Delete", + "ru": "Удалить", + "zh-Hant": "刪除", + "ja": "削除", + "ko": "삭제", + "de": "Löschen", + "fr": "Supprimer", + "es": "Eliminar", + "pt-BR": "Excluir" + }, + "删除公告": { + "zh-Hans": "删除公告", + "en": "Delete announcement", + "ru": "Удалить объявление", + "zh-Hant": "刪除公告", + "ja": "お知らせの削除", + "ko": "공지사항 삭제", + "de": "Ansage löschen", + "fr": "Supprimer l'annonce", + "es": "Eliminar anuncio", + "pt-BR": "Excluir anúncio" + }, + "删除公告?": { + "zh-Hans": "删除公告?", + "en": "Delete announcement?", + "zh-Hant": "刪除公告?", + "ja": "お知らせを削除しますか?", + "ko": "공지사항을 삭제하시겠습니까?", + "de": "Ankündigung löschen?", + "fr": "Supprimer l'annonce ?", + "es": "¿Eliminar anuncio?", + "pt-BR": "Excluir anúncio?", + "ru": "Удалить объявление?" + }, + "删除记录": { + "zh-Hans": "删除记录", + "en": "Delete record", + "ru": "Удалить запись", + "zh-Hant": "刪除記錄", + "ja": "レコードの削除", + "ko": "기록 삭제", + "de": "Datensatz löschen", + "fr": "Supprimer l'enregistrement", + "es": "Eliminar registro", + "pt-BR": "Excluir registro" + }, + "删除记录?": { + "zh-Hans": "删除记录?", + "en": "Delete records?", + "zh-Hant": "刪除記錄?", + "ja": "記録を削除しますか?", + "ko": "기록을 삭제하시겠습니까?", + "de": "Datensätze löschen?", + "fr": "Supprimer les enregistrements ?", + "es": "¿Eliminar registros?", + "pt-BR": "Excluir registros?", + "ru": "Удалить записи?" + }, + "删除这条公告?": { + "zh-Hans": "删除这条公告?", + "en": "Delete this announcement?", + "ru": "Удалить это объявление?", + "zh-Hant": "刪除這條公告?", + "ja": "このお知らせを削除しますか?", + "ko": "이 공지를 삭제하시겠습니까?", + "de": "Diese Ankündigung löschen?", + "fr": "Supprimer cette annonce ?", + "es": "¿Eliminar este anuncio?", + "pt-BR": "Excluir este anúncio?" + }, + "删除连接": { + "zh-Hans": "删除连接", + "en": "Delete Connection", + "ru": "Удалить подключение", + "zh-Hant": "刪除連線", + "ja": "接続を削除", + "ko": "연결 삭제", + "de": "Verbindung löschen", + "fr": "Supprimer la connexion", + "es": "Eliminar conexión", + "pt-BR": "Excluir conexão" + }, + "刷新公告": { + "zh-Hans": "刷新公告", + "en": "Refresh announcement", + "zh-Hant": "重新整理公告", + "ja": "リフレッシュのお知らせ", + "ko": "새로고침 안내", + "de": "Ankündigung aktualisieren", + "fr": "Actualiser l'annonce", + "es": "Actualizar anuncio", + "pt-BR": "Anúncio de atualização", + "ru": "Обновить объявление" + }, + "刷新状态": { + "zh-Hans": "刷新状态", + "en": "Refresh status", + "ru": "Обновить статус", + "zh-Hant": "重新整理狀態", + "ja": "リフレッシュステータス", + "ko": "새로 고침 상태", + "de": "Aktualisierungsstatus", + "fr": "Actualiser l'état", + "es": "Estado de actualización", + "pt-BR": "Atualizar status" + }, + "刷新随机密码": { + "zh-Hans": "刷新随机密码", + "en": "Refresh random password", + "ru": "Обновить случайный пароль", + "zh-Hant": "重新整理隨機密碼", + "ja": "ランダムパスワードを更新する", + "ko": "무작위 비밀번호 새로고침", + "de": "Zufälliges Passwort aktualisieren", + "fr": "Actualiser le mot de passe aléatoire", + "es": "Actualizar contraseña aleatoria", + "pt-BR": "Atualizar senha aleatória" + }, + "前往设置": { + "zh-Hans": "前往设置", + "en": "Open settings", + "ru": "Настройки", + "zh-Hant": "前往設定", + "ja": "設定を開く", + "ko": "설정 열기", + "de": "Einstellungen öffnen", + "fr": "Ouvrir les paramètres", + "es": "Abrir configuración", + "pt-BR": "Abrir configurações" + }, + "剪贴板": { + "zh-Hans": "剪贴板", + "en": "Clipboard", + "zh-Hant": "剪貼簿", + "ja": "クリップボード", + "ko": "클립보드", + "de": "Zwischenablage", + "fr": "Presse-papiers", + "es": "Portapapeles", + "pt-BR": "Área de transferência", + "ru": "Буфер обмена" + }, + "剪贴板中没有文本": { + "zh-Hans": "剪贴板中没有文本", + "en": "No text in clipboard", + "zh-Hant": "剪貼簿中沒有文字", + "ja": "クリップボードにテキストがありません", + "ko": "클립보드에 텍스트가 없습니다.", + "de": "Kein Text in der Zwischenablage", + "fr": "Aucun texte dans le presse-papiers", + "es": "No hay texto en el portapapeles", + "pt-BR": "Nenhum texto na área de transferência", + "ru": "Нет текста в буфере обмена." + }, + "剪贴板文本超过 128 KiB": { + "zh-Hans": "剪贴板文本超过 128 KiB", + "en": "Clipboard text exceeds 128 KiB", + "zh-Hant": "剪貼簿文字超過 128 KiB", + "ja": "クリップボードのテキストが 128 KiB を超えています", + "ko": "클립보드 텍스트가 128KiB를 초과합니다.", + "de": "Der Text in der Zwischenablage ist größer als 128 KiB", + "fr": "Le texte du presse-papiers dépasse 128 Ko", + "es": "El texto del portapapeles supera los 128 KiB", + "pt-BR": "O texto da área de transferência excede 128 KiB", + "ru": "Размер текста в буфере обмена превышает 128 КиБ." + }, + "加入桌面墙": { + "zh-Hans": "加入桌面墙", + "en": "Add to DeskHub", + "ru": "В DeskHub", + "zh-Hant": "加入桌面牆", + "ja": "DeskHubに追加", + "ko": "DeskHub에 추가", + "de": "Zu DeskHub hinzufügen", + "fr": "Ajouter à DeskHub", + "es": "Agregar a DeskHub", + "pt-BR": "Adicionar a DeskHub" + }, + "加入桌面墙后,可通过批量选择连接": { + "zh-Hans": "加入桌面墙后,可通过批量选择连接", + "en": "Add to DeskHub, then select devices to connect.", + "ru": "Добавьте в DeskHub, затем выберите устройства для подключения.", + "zh-Hant": "加入桌面牆後,可透過批次選擇連線", + "ja": "DeskHubに追加し、接続するデバイスを選択します。", + "ko": "DeskHub에 추가하고, 연결할 기기를 선택하세요.", + "de": "Zu DeskHub hinzufügen und dann die zu verbindenden Geräte auswählen.", + "fr": "Ajoutez à DeskHub, puis sélectionnez les appareils à connecter.", + "es": "Agregar a DeskHub, luego seleccione los dispositivos para conectar.", + "pt-BR": "Adicione a DeskHub e selecione os dispositivos para conectar." + }, + "加密传输": { + "zh-Hans": "加密传输", + "en": "Encryption", + "ru": "Шифрование", + "zh-Hant": "加密傳輸", + "ja": "暗号化", + "ko": "암호화", + "de": "Verschlüsselung", + "fr": "Cryptage", + "es": "Cifrado", + "pt-BR": "Criptografia" + }, + "加载中…": { + "zh-Hans": "加载中…", + "en": "Loading…", + "zh-Hant": "載入中…", + "ja": "読み込み中…", + "ko": "로드 중…", + "de": "Laden…", + "fr": "Chargement…", + "es": "Cargando…", + "pt-BR": "Carregando…", + "ru": "Загрузка…" + }, + "加载失败,点击重试": { + "zh-Hans": "加载失败,点击重试", + "en": "Loading failed, click to try again", + "zh-Hant": "載入失敗,點選重試", + "ja": "読み込みに失敗しました。クリックして再試行してください", + "ko": "로드에 실패했습니다. 다시 시도하려면 클릭하세요.", + "de": "Der Ladevorgang ist fehlgeschlagen. Klicken Sie hier, um es erneut zu versuchen", + "fr": "Échec du chargement, cliquez pour réessayer", + "es": "Error al cargar, haga clic para intentarlo de nuevo", + "pt-BR": "Falha no carregamento, clique para tentar novamente", + "ru": "Не удалось загрузить. Нажмите, чтобы повторить попытку." + }, + "加载更多": { + "zh-Hans": "加载更多", + "en": "Load more", + "zh-Hant": "載入更多", + "ja": "さらに読み込む", + "ko": "더 로드하기", + "de": "Mehr laden", + "fr": "Charger plus", + "es": "Cargar más", + "pt-BR": "Carregue mais", + "ru": "Загрузить еще" + }, + "升级提示": { + "zh-Hans": "升级提示", + "en": "Update recommended", + "ru": "Рекомендуется обновление", + "zh-Hant": "更新提示", + "ja": "更新のご案内", + "ko": "업데이트 안내", + "de": "Update empfohlen", + "fr": "Mise à jour conseillée", + "es": "Actualización recomendada", + "pt-BR": "Atualização recomendada" + }, + "单次输入最多 16 KiB,且不能包含空字符": { + "zh-Hans": "单次输入最多 16 KiB,且不能包含空字符", + "en": "A single input can be up to 16 KiB and cannot contain null characters", + "zh-Hant": "單次輸入最多 16 KiB,且不能包含空字元", + "ja": "1 つの入力は最大 16 KiB であり、null 文字を含めることはできません", + "ko": "단일 입력은 최대 16KiB일 수 있으며 null 문자를 포함할 수 없습니다.", + "de": "Eine einzelne Eingabe kann bis zu 16 KiB groß sein und darf keine Nullzeichen enthalten", + "fr": "Une seule entrée peut atteindre 16 Ko et ne peut pas contenir de caractères nuls", + "es": "Una sola entrada puede tener hasta 16 KiB y no puede contener caracteres nulos", + "pt-BR": "Uma única entrada pode ter até 16 KiB e não pode conter caracteres nulos", + "ru": "Один ввод может иметь размер до 16 КиБ и не может содержать нулевые символы." + }, + "原始分辨率": { + "zh-Hans": "原始分辨率", + "en": "Original resolution", + "ru": "Исходное разрешение", + "zh-Hant": "原始解析度", + "ja": "元の解像度", + "ko": "원본 해상도", + "de": "Originalauflösung", + "fr": "Résolution originale", + "es": "Resolución original", + "pt-BR": "Resolução original" + }, + "原生连接初始化失败": { + "zh-Hans": "原生连接初始化失败", + "en": "Native connection initialization failed", + "zh-Hant": "原生連線初始化失敗", + "ja": "ネイティブ接続の初期化に失敗しました", + "ko": "기본 연결 초기화 실패", + "de": "Die Initialisierung der nativen Verbindung ist fehlgeschlagen", + "fr": "L'initialisation de la connexion native a échoué", + "es": "Falló la inicialización de la conexión nativa", + "pt-BR": "Falha na inicialização da conexão nativa", + "ru": "Не удалось инициализировать собственное соединение." + }, + "原生通信库不可用,请重新构建并安装": { + "zh-Hans": "原生通信库不可用,请重新构建并安装", + "en": "The native communication library is not available, please rebuild and install it", + "zh-Hant": "原生通訊庫不可用,請重新構建並安裝", + "ja": "ネイティブ通信ライブラリは利用できません。再構築してインストールしてください。", + "ko": "기본 통신 라이브러리를 사용할 수 없습니다. 다시 빌드하고 설치하십시오.", + "de": "Die native Kommunikationsbibliothek ist nicht verfügbar. Bitte erstellen und installieren Sie sie neu", + "fr": "La bibliothèque de communication native n'est pas disponible, veuillez la reconstruire et l'installer", + "es": "La biblioteca de comunicación nativa no está disponible; reconstrúyala e instálela", + "pt-BR": "A biblioteca de comunicação nativa não está disponível, reconstrua-a e instale-a", + "ru": "Собственная коммуникационная библиотека недоступна, пересоберите и установите ее." + }, + "原设置已保留。": { + "zh-Hans": "原设置已保留。", + "en": "Your previous settings are unchanged.", + "ru": "Прежние настройки сохранены.", + "zh-Hant": "原設定已保留。", + "ja": "以前の設定は変更されません。", + "ko": "이전 설정은 변경되지 않습니다.", + "de": "Ihre bisherigen Einstellungen bleiben unverändert.", + "fr": "Vos paramètres précédents restent inchangés.", + "es": "Tus configuraciones anteriores no cambian.", + "pt-BR": "Suas configurações anteriores permanecem inalteradas." + }, + "双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。": { + "zh-Hans": "双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。", + "en": "The protocol or encryption capabilities are incompatible. Update CrossDesk on both devices and try again.", + "ru": "Протоколы или возможности шифрования несовместимы. Обновите CrossDesk на обоих устройствах и повторите попытку.", + "zh-Hant": "雙方的協議或加密能力不相容,請將雙方 CrossDesk 升級至最新版本後重試。", + "ja": "プロトコルまたは暗号化機能に互換性がありません。両方のデバイスでCrossDeskを更新し、再試行してください。", + "ko": "프로토콜 또는 암호화 기능이 호환되지 않습니다. 두 기기 모두에서CrossDesk를 업데이트하고 다시 시도하세요.", + "de": "Das Protokoll oder die Verschlüsselungsfunktionen sind nicht kompatibel. Aktualisieren Sie CrossDesk auf beiden Geräten und versuchen Sie es erneut.", + "fr": "Le protocole ou les capacités de cryptage sont incompatibles. Mettez à jour CrossDesk sur les deux appareils et réessayez.", + "es": "El protocolo o las capacidades de cifrado son incompatibles. Actualice CrossDesk en ambos dispositivos y vuelva a intentarlo.", + "pt-BR": "O protocolo ou os recursos de criptografia são incompatíveis. Atualize CrossDesk em ambos os dispositivos e tente novamente." + }, + "发布日期: ": { + "zh-Hans": "发布日期: ", + "en": "Release Date: ", + "ru": "Дата релиза: ", + "zh-Hant": "釋出日期: ", + "ja": "発売日: ", + "ko": "출시일: ", + "de": "Erscheinungsdatum: ", + "fr": "Date de sortie : ", + "es": "Fecha de lanzamiento: ", + "pt-BR": "Data de lançamento: " + }, + "发现新版本 {0}": { + "zh-Hans": "发现新版本 {0}", + "en": "Found new version {0}", + "zh-Hant": "發現新版本 {0}", + "ja": "新しいバージョン{0}が見つかりました", + "ko": "새 버전{0}발견", + "de": "Neue Version {0} gefunden", + "fr": "Nouvelle version trouvée {0}", + "es": "Nueva versión encontrada {0}", + "pt-BR": "Nova versão encontrada {0}", + "ru": "Найдена новая версия {0}." + }, + "发起连接": { + "zh-Hans": "发起连接", + "en": "Connect", + "ru": "Подключиться", + "zh-Hant": "發起連線", + "ja": "接続する", + "ko": "연결하다", + "de": "Verbinden", + "fr": "Connectez-vous", + "es": "Conectar", + "pt-BR": "Conectar" + }, + "发送": { + "zh-Hans": "发送", + "en": "Send", + "ru": "Отправка", + "zh-Hant": "傳送", + "ja": "送信", + "ko": "송신", + "de": "Senden", + "fr": "Envoi", + "es": "Enviar", + "pt-BR": "Enviar" + }, + "发送 ": { + "zh-Hans": "发送 ", + "en": "Send ", + "zh-Hant": "傳送 ", + "ja": "送信 ", + "ko": "보내기 ", + "de": "Senden ", + "fr": "Envoyer ", + "es": "Enviar ", + "pt-BR": "Enviar ", + "ru": "Отправить " + }, + "发送 SAS": { + "zh-Hans": "发送 SAS", + "en": "Send SAS", + "ru": "Отправить SAS", + "zh-Hant": "傳送 SAS", + "ja": "SASの送信", + "ko": "SAS 보내기", + "de": "SAS senden", + "fr": "Envoyer SAS", + "es": "Enviar SAS", + "pt-BR": "Enviar SAS" + }, + "发送 {0} · 0%": { + "zh-Hans": "发送 {0} · 0%", + "en": "Send {0}· 0%", + "zh-Hant": "傳送 {0} · 0%", + "ja": "{0} を送信 · 0%", + "ko": "{0}보내기 · 0%", + "de": "Senden {0}· 0 %", + "fr": "Envoyer {0}· 0%", + "es": "Enviar {0}· 0%", + "pt-BR": "Enviar {0}· 0%", + "ru": "Отправить {0}· 0%" + }, + "发送后,在远程键盘中点击“粘贴”。接收的远端文本可手动复制到本机。": { + "zh-Hans": "发送后,在远程键盘中点击“粘贴”。接收的远端文本可手动复制到本机。", + "en": "After sending, click \"Paste\" on the remote keyboard. The received remote text can be manually copied to the local machine.", + "zh-Hant": "傳送後,在遠端鍵盤中點選“貼上”。接收的遠端文字可手動複製到本機。", + "ja": "送信後、リモートキーボードの「貼り付け」をクリックしてください。受信したリモート テキストはローカル マシンに手動でコピーできます。", + "ko": "전송 후 원격 키보드에서 \"붙여넣기\"를 클릭하세요. 수신된 원격 텍스트를 로컬 시스템에 수동으로 복사할 수 있습니다.", + "de": "Klicken Sie nach dem Senden auf der Remote-Tastatur auf „Einfügen“. Der empfangene Remote-Text kann manuell auf den lokalen Computer kopiert werden.", + "fr": "Après l'envoi, cliquez sur \"Coller\" sur le clavier distant. Le texte distant reçu peut être copié manuellement sur la machine locale.", + "es": "Después de enviar, haga clic en \"Pegar\" en el teclado remoto. El texto remoto recibido se puede copiar manualmente a la máquina local.", + "pt-BR": "Após o envio, clique em “Colar” no teclado remoto. O texto remoto recebido pode ser copiado manualmente para a máquina local.", + "ru": "После отправки нажмите «Вставить» на удаленной клавиатуре. Полученный удаленный текст можно вручную скопировать на локальный компьютер." + }, + "发送密码修改请求失败,请等待连接恢复后重试。": { + "zh-Hans": "发送密码修改请求失败,请等待连接恢复后重试。", + "en": "Failed to submit password change; retry after reconnection.", + "ru": "Не удалось отправить запрос смены пароля. Повторите после подключения.", + "zh-Hant": "傳送密碼修改請求失敗,請等待連線恢復後重試。", + "ja": "パスワード変更の送信に失敗しました。再接続後に再試行してください。", + "ko": "비밀번호 변경을 제출하지 못했습니다. 다시 연결한 후 다시 시도하세요.", + "de": "Passwortänderung konnte nicht übermittelt werden; Versuchen Sie es nach erneuter Verbindung erneut.", + "fr": "Échec de la soumission du changement de mot de passe ; réessayez après la reconnexion.", + "es": "No se pudo enviar el cambio de contraseña; Vuelva a intentarlo después de la reconexión.", + "pt-BR": "Falha ao enviar alteração de senha; tente novamente após a reconexão." + }, + "发送文件": { + "zh-Hans": "发送文件", + "en": "Send file", + "ru": "Отправить файл", + "zh-Hant": "傳送檔案", + "ja": "ファイル送信", + "ko": "파일 보내기", + "de": "Datei senden", + "fr": "Envoyer le fichier", + "es": "Enviar archivo", + "pt-BR": "Enviar arquivo" + }, + "发送文本": { + "zh-Hans": "发送文本", + "en": "Send text", + "zh-Hant": "傳送文字", + "ja": "テキストを送信する", + "ko": "문자 보내기", + "de": "Text senden", + "fr": "Envoyer un SMS", + "es": "Enviar texto", + "pt-BR": "Enviar texto", + "ru": "Отправить текст" + }, + "发送文本后,点击“粘贴到远端”使用。": { + "zh-Hans": "发送文本后,点击“粘贴到远端”使用。", + "en": "After sending the text, click \"Paste to Remote\" to use.", + "zh-Hant": "傳送文字後,點選“貼上到遠端”使用。", + "ja": "テキストを送信後、「リモートに貼り付け」をクリックして使用します。", + "ko": "문자 전송 후 \"원격에 붙여넣기\"를 클릭하여 사용하세요.", + "de": "Klicken Sie nach dem Senden des Textes auf „In Remote einfügen“, um ihn zu verwenden.", + "fr": "Après avoir envoyé le texte, cliquez sur \"Coller sur Remote\" pour l'utiliser.", + "es": "Después de enviar el texto, haga clic en \"Pegar en control remoto\" para usarlo.", + "pt-BR": "Após enviar o texto, clique em “Colar no Remoto” para usar.", + "ru": "После отправки текста нажмите «Вставить на удаленный компьютер», чтобы использовать его." + }, + "发送组合键": { + "zh-Hans": "发送组合键", + "en": "Send Shortcut", + "ru": "Отправить сочетание клавиш", + "zh-Hant": "傳送組合鍵", + "ja": "ショートカット送信", + "ko": "바로가기 보내기", + "de": "Verknüpfung senden", + "fr": "Envoyer un raccourci", + "es": "Enviar acceso directo", + "pt-BR": "Enviar atalho" + }, + "取消": { + "zh-Hans": "取消", + "en": "Cancel", + "ru": "Отмена", + "zh-Hant": "取消", + "ja": "キャンセル", + "ko": "취소", + "de": "Abbrechen", + "fr": "Annuler", + "es": "Cancelar", + "pt-BR": "Cancelar" + }, + "取消全选": { + "zh-Hans": "取消全选", + "en": "Deselect all", + "ru": "Снять выбор", + "zh-Hant": "取消全選", + "ja": "すべての選択を解除", + "ko": "모두 선택 취소", + "de": "Alle abwählen", + "fr": "Tout désélectionner", + "es": "Deseleccionar todo", + "pt-BR": "Desmarcar tudo" + }, + "取消连接": { + "zh-Hans": "取消连接", + "en": "Cancel connection", + "zh-Hant": "取消連線", + "ja": "接続をキャンセルする", + "ko": "연결 취소", + "de": "Verbindung abbrechen", + "fr": "Annuler la connexion", + "es": "Cancelar conexión", + "pt-BR": "Cancelar conexão", + "ru": "Отмена соединения" + }, + "取消静音": { + "zh-Hans": "取消静音", + "en": "Unmute", + "ru": "Со звуком", + "zh-Hant": "取消靜音", + "ja": "ミュートを解除する", + "ko": "음소거 해제", + "de": "Stummschaltung aufheben", + "fr": "Activer le son", + "es": "Activar el silencio", + "pt-BR": "Ativar som" + }, + "受 Wayland 安全机制限制,每次启动远程桌面共享时,均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。": { + "zh-Hans": "受 Wayland 安全机制限制,每次启动远程桌面共享时,均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。", + "en": "Wayland security restrictions require you to authorize screen sharing and remote control locally each time you start sharing this desktop. Remote access is available only after authorization.", + "ru": "Из-за ограничений безопасности Wayland при каждом запуске общего доступа к рабочему столу необходимо вручную разрешать на этом компьютере показ экрана и удалённое управление. Удалённый доступ возможен только после разрешения.", + "zh-Hant": "受 Wayland 安全機制限制,每次啟動遠端桌面共享時,均需在本機手動授權螢幕共享與遠端控制,授權後方可正常使用。", + "ja": "Wayland のセキュリティ制限により、このデスクトップの共有を開始するたびに、ローカルでの画面共有とリモート コントロールを承認する必要があります。リモートアクセスは認証後にのみ利用可能です。", + "ko": "Wayland 보안 제한 사항에서는 이 데스크탑 공유를 시작할 때마다 로컬에서 화면 공유 및 원격 제어를 승인해야 합니다. 원격 접속은 인증 후에만 가능합니다.", + "de": "Aufgrund der Sicherheitsbeschränkungen von Wayland müssen Sie die Bildschirmfreigabe und Fernsteuerung jedes Mal lokal autorisieren, wenn Sie mit der Freigabe dieses Desktops beginnen. Der Fernzugriff ist nur nach Autorisierung möglich.", + "fr": "Les restrictions de sécurité de Wayland vous obligent à autoriser le partage d'écran et le contrôle à distance localement chaque fois que vous commencez à partager ce bureau. L'accès à distance n'est disponible qu'après autorisation.", + "es": "Las restricciones de seguridad de Wayland requieren que autorices el uso compartido de pantalla y el control remoto localmente cada vez que comienzas a compartir este escritorio. El acceso remoto está disponible solo después de la autorización.", + "pt-BR": "As restrições de segurança do Wayland exigem que você autorize o compartilhamento de tela e o controle remoto localmente sempre que começar a compartilhar esta área de trabalho. O acesso remoto está disponível somente após autorização." + }, + "只读预览": { + "zh-Hans": "只读预览", + "en": "View only", + "ru": "Просмотр", + "zh-Hant": "只讀預覽", + "ja": "閲覧のみ", + "ko": "보기 전용", + "de": "Nur Ansicht", + "fr": "Visualisation uniquement", + "es": "Ver solo", + "pt-BR": "Somente visualização" + }, + "台设备": { + "zh-Hans": "台设备", + "en": "devices", + "ru": "устройств", + "zh-Hant": "臺裝置", + "ja": "デバイス", + "ko": "장치", + "de": "Geräte", + "fr": "appareils", + "es": "dispositivos", + "pt-BR": "dispositivos" + }, + "各组件遵循所列开源许可证。许可与版权声明可离线查阅,查看源码需要网络连接。": { + "zh-Hans": "各组件遵循所列开源许可证。许可与版权声明可离线查阅,查看源码需要网络连接。", + "en": "Each component is covered by the listed open source license. The license and copyright statement can be viewed offline, and an Internet connection is required to view the source code.", + "zh-Hant": "各元件遵循所列開源許可證。許可與版權宣告可離線查閱,檢視原始碼需要網路連線。", + "ja": "各コンポーネントは、リストされているオープンソース ライセンスの対象となります。ライセンスと著作権に関する声明はオフラインでも表示できますが、ソース コードを表示するにはインターネット接続が必要です。", + "ko": "각 구성 요소에는 나열된 오픈 소스 라이선스가 적용됩니다. 라이센스 및 저작권 표시는 오프라인으로 볼 수 있으며, 소스 코드를 보려면 인터넷 연결이 필요합니다.", + "de": "Jede Komponente unterliegt der aufgeführten Open-Source-Lizenz. Die Lizenz- und Urheberrechtserklärung kann offline angezeigt werden. Zum Anzeigen des Quellcodes ist eine Internetverbindung erforderlich.", + "fr": "Chaque composant est couvert par la licence open source répertoriée. La licence et la déclaration de droits d'auteur peuvent être consultées hors ligne et une connexion Internet est requise pour afficher le code source.", + "es": "Cada componente está cubierto por la licencia de código abierto indicada. La declaración de licencia y derechos de autor se puede ver sin conexión y se requiere una conexión a Internet para ver el código fuente.", + "pt-BR": "Cada componente é coberto pela licença de código aberto listada. A licença e a declaração de direitos autorais podem ser visualizadas offline e é necessária uma conexão com a Internet para visualizar o código-fonte.", + "ru": "На каждый компонент распространяется указанная лицензия с открытым исходным кодом. Лицензию и заявление об авторских правах можно просмотреть в автономном режиме, а для просмотра исходного кода требуется подключение к Интернету." + }, + "各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。": { + "zh-Hans": "各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。", + "en": "Each component is subject to the listed open source license, and the rights granted are not subject to the general terms of use of this application. Viewing source code requires an internet connection.", + "zh-Hant": "各元件遵循所列開源許可證,其授予的權利不受本應用普通使用條款限制。檢視原始碼需要網路連線。", + "ja": "各コンポーネントは、リストされているオープン ソース ライセンスの対象となり、付与された権利は、このアプリケーションの一般的な使用条件の対象ではありません。ソース コードを表示するには、インターネット接続が必要です。", + "ko": "각 구성 요소에는 나열된 오픈 소스 라이선스가 적용되며 부여된 권리에는 이 애플리케이션의 일반 사용 약관이 적용되지 않습니다. 소스 코드를 보려면 인터넷 연결이 필요합니다.", + "de": "Jede Komponente unterliegt der aufgeführten Open-Source-Lizenz und die gewährten Rechte unterliegen nicht den allgemeinen Nutzungsbedingungen dieser Anwendung. Für die Anzeige des Quellcodes ist eine Internetverbindung erforderlich.", + "fr": "Chaque composant est soumis à la licence open source répertoriée, et les droits accordés ne sont pas soumis aux conditions générales d'utilisation de cette application. La visualisation du code source nécessite une connexion Internet.", + "es": "Cada componente está sujeto a la licencia de código abierto enumerada y los derechos otorgados no están sujetos a los términos generales de uso de esta aplicación. Para ver el código fuente se requiere una conexión a Internet.", + "pt-BR": "Cada componente está sujeito à licença de código aberto listada e os direitos concedidos não estão sujeitos aos termos gerais de uso deste aplicativo. A visualização do código-fonte requer uma conexão com a Internet.", + "ru": "На каждый компонент распространяется действие указанной лицензии с открытым исходным кодом, а предоставленные права не подпадают под действие общих условий использования этого приложения. Для просмотра исходного кода требуется подключение к Интернету." + }, + "合计": { + "zh-Hans": "合计", + "en": "Total", + "zh-Hant": "合計", + "ja": "合計", + "ko": "합계", + "de": "Insgesamt", + "fr": "Total", + "es": "Total", + "pt-BR": "Total", + "ru": "Итого" + }, + "同意并继续": { + "zh-Hans": "同意并继续", + "en": "Agree and continue", + "zh-Hant": "同意並繼續", + "ja": "同意して続行", + "ko": "동의하고 계속하기", + "de": "Zustimmen und fortfahren", + "fr": "Accepter et continuer", + "es": "Aceptar y continuar", + "pt-BR": "Concorde e continue", + "ru": "Согласитесь и продолжайте." + }, + "同意联网后可查看公告": { + "zh-Hans": "同意联网后可查看公告", + "en": "You can view the announcement after agreeing to connect to the Internet", + "zh-Hant": "同意聯網後可檢視公告", + "ja": "インターネットへの接続に同意するとお知らせがご覧いただけます", + "ko": "공지사항은 인터넷 연결 동의 후 보실 수 있습니다.", + "de": "Sie können die Ankündigung ansehen, nachdem Sie der Verbindung mit dem Internet zugestimmt haben", + "fr": "Vous pouvez consulter l'annonce après avoir accepté de vous connecter à Internet", + "es": "Puede ver el anuncio después de aceptar conectarse a Internet.", + "pt-BR": "Você pode ver o anúncio depois de concordar em se conectar à Internet", + "ru": "Посмотреть объявление можно после согласия на подключение к Интернету." + }, + "同时删除该设备保存的密码和预览。": { + "zh-Hans": "同时删除该设备保存的密码和预览。", + "en": "Also deletes passwords and previews saved by the device.", + "zh-Hant": "同時刪除該裝置儲存的密碼和預覽。", + "ja": "デバイスに保存されているパスワードとプレビューも削除します。", + "ko": "기기에 저장된 비밀번호와 미리보기도 삭제됩니다.", + "de": "Löscht auch vom Gerät gespeicherte Passwörter und Vorschauen.", + "fr": "Supprime également les mots de passe et les aperçus enregistrés par l'appareil.", + "es": "También elimina contraseñas y vistas previas guardadas por el dispositivo.", + "pt-BR": "Também exclui senhas e visualizações salvas pelo dispositivo.", + "ru": "Также удаляет пароли и предварительный просмотр, сохраненные на устройстве." + }, + "后台保持连接,点按返回远程桌面": { + "zh-Hans": "后台保持连接,点按返回远程桌面", + "en": "Keep connected in the background, click to return to the remote desktop", + "zh-Hant": "後臺保持連線,點按返回遠端桌面", + "ja": "バックグラウンドで接続を維持し、クリックしてリモート デスクトップに戻ります", + "ko": "백그라운드에서 연결을 유지하고 원격 데스크톱으로 돌아가려면 클릭하세요.", + "de": "Bleiben Sie im Hintergrund verbunden. Klicken Sie, um zum Remote-Desktop zurückzukehren", + "fr": "Restez connecté en arrière-plan, cliquez pour revenir au bureau distant", + "es": "Manténgase conectado en segundo plano, haga clic para regresar al escritorio remoto", + "pt-BR": "Mantenha-se conectado em segundo plano, clique para retornar à área de trabalho remota", + "ru": "Оставайтесь на связи в фоновом режиме, нажмите, чтобы вернуться к удаленному рабочему столу." + }, + "后台保活未能启动,请保持应用在前台": { + "zh-Hans": "后台保活未能启动,请保持应用在前台", + "en": "Background keepalive failed to start, please keep the application in the foreground", + "zh-Hant": "後臺保活未能啟動,請保持應用在前臺", + "ja": "バックグラウンドのキープアライブを開始できませんでした。アプリケーションをフォアグラウンドで維持してください。", + "ko": "백그라운드 연결 유지를 시작하지 못했습니다. 애플리케이션을 포그라운드에 유지하세요.", + "de": "Hintergrund-Keepalive konnte nicht gestartet werden. Bitte lassen Sie die Anwendung im Vordergrund", + "fr": "Échec du démarrage de Keepalive en arrière-plan, veuillez conserver l'application au premier plan", + "es": "No se pudo iniciar el mantenimiento en segundo plano; mantenga la aplicación en primer plano", + "pt-BR": "Falha ao iniciar a manutenção de atividade em segundo plano, mantenha o aplicativo em primeiro plano", + "ru": "Не удалось запустить фоновую поддержку активности, оставьте приложение на переднем плане." + }, + "后台保活未能启动,请保持应用在前台后重新连接": { + "zh-Hans": "后台保活未能启动,请保持应用在前台后重新连接", + "en": "Background keepalive failed to start, please keep the application in the foreground and reconnect.", + "zh-Hant": "後臺保活未能啟動,請保持應用在前臺後重新連線", + "ja": "バックグラウンド キープアライブの開始に失敗しました。アプリケーションをフォアグラウンドに保ち、再接続してください。", + "ko": "백그라운드 연결 유지를 시작하지 못했습니다. 애플리케이션을 포그라운드에 유지하고 다시 연결하세요.", + "de": "Hintergrund-Keepalive konnte nicht gestartet werden. Bitte lassen Sie die Anwendung im Vordergrund und stellen Sie die Verbindung erneut her.", + "fr": "L'application Keepalive en arrière-plan n'a pas pu démarrer. Veuillez conserver l'application au premier plan et vous reconnecter.", + "es": "No se pudo iniciar el mantenimiento en segundo plano. Mantenga la aplicación en primer plano y vuelva a conectarse.", + "pt-BR": "Falha ao iniciar a manutenção de atividade em segundo plano. Mantenha o aplicativo em primeiro plano e reconecte.", + "ru": "Не удалось запустить фоновую поддержку активности. Оставьте приложение в активном режиме и переподключитесь." + }, + "后台连接已结束,请重新连接": { + "zh-Hans": "后台连接已结束,请重新连接", + "en": "The background connection has ended, please reconnect.", + "zh-Hant": "後臺連線已結束,請重新連線", + "ja": "バックグラウンド接続が終了しました。再接続してください。", + "ko": "백그라운드 연결이 종료되었습니다. 다시 연결해 주세요.", + "de": "Die Hintergrundverbindung wurde beendet. Bitte stellen Sie die Verbindung wieder her.", + "fr": "La connexion en arrière-plan est terminée, veuillez vous reconnecter.", + "es": "La conexión en segundo plano ha finalizado; vuelva a conectarse.", + "pt-BR": "A conexão em segundo plano foi encerrada. Reconecte.", + "ru": "Фоновое соединение прервано, подключитесь заново." + }, + "后台连接服务已停止,请重新连接": { + "zh-Hans": "后台连接服务已停止,请重新连接", + "en": "The background connection service has stopped, please reconnect.", + "zh-Hant": "後臺連線服務已停止,請重新連線", + "ja": "バックグラウンド接続サービスが停止しました。再接続してください。", + "ko": "백그라운드 연결 서비스가 중지되었습니다. 다시 연결해 주세요.", + "de": "Der Hintergrundverbindungsdienst wurde beendet. Bitte stellen Sie die Verbindung wieder her.", + "fr": "Le service de connexion en arrière-plan s'est arrêté, veuillez vous reconnecter.", + "es": "El servicio de conexión en segundo plano se detuvo; vuelva a conectarse.", + "pt-BR": "O serviço de conexão em segundo plano foi interrompido, reconecte.", + "ru": "Служба фонового подключения остановлена, подключитесь повторно." + }, + "后续连接仍会保存新的预览图。": { + "zh-Hans": "后续连接仍会保存新的预览图。", + "en": "New previews will still be saved on subsequent connections.", + "zh-Hant": "後續連線仍會儲存新的預覽圖。", + "ja": "新しいプレビューはその後の接続でも保存されます。", + "ko": "새로운 미리보기는 후속 연결에도 계속 저장됩니다.", + "de": "Neue Vorschauen werden bei nachfolgenden Verbindungen weiterhin gespeichert.", + "fr": "Les nouveaux aperçus seront toujours enregistrés lors des connexions ultérieures.", + "es": "Las nuevas vistas previas aún se guardarán en conexiones posteriores.", + "pt-BR": "Novas visualizações ainda serão salvas nas conexões subsequentes.", + "ru": "Новые превью по-прежнему будут сохраняться при последующих подключениях." + }, + "启动与后台": { + "zh-Hans": "启动与后台", + "en": "Startup & background", + "ru": "Запуск и фоновая работа", + "zh-Hant": "啟動與後臺", + "ja": "起動と背景", + "ko": "창업 및 배경", + "de": "Start und Hintergrund", + "fr": "Démarrage et arrière-plan", + "es": "Inicio y antecedentes", + "pt-BR": "Inicialização e histórico" + }, + "启用 IP 连接": { + "zh-Hans": "启用 IP 连接", + "en": "Enable IP connections", + "ru": "Подключение по IP", + "zh-Hant": "啟用 IP 連線", + "ja": "IP接続を有効にする", + "ko": "IP 연결 활성화", + "de": "IP-Verbindungen aktivieren", + "fr": "Activer les connexions IP", + "es": "Habilitar conexiones IP", + "pt-BR": "Habilitar conexões IP" + }, + "启用守护进程": { + "zh-Hans": "启用守护进程", + "en": "Enable Daemon", + "ru": "Включить демон", + "zh-Hant": "啟用守護程序", + "ja": "デーモンを有効にする", + "ko": "데몬 활성화", + "de": "Daemon aktivieren", + "fr": "Activer le démon", + "es": "Habilitar demonio", + "pt-BR": "Habilitar Daemon" + }, + "命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出": { + "zh-Hans": "命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出", + "en": "Commands: status — show ID/password/status; settings — configure; password — change password; random — random password; help — help; quit — exit", + "ru": "Команды: status — ID/пароль/состояние; settings — настройки; password — сменить пароль; random — случайный пароль; help — справка; quit — выход", + "zh-Hant": "命令: status 檢視 ID/密碼/狀態;settings 設定;password 修改密碼;random 隨機密碼;help 幫助;quit 退出", + "ja": "コマンド: status — ID/パスワード/ステータスを表示します。設定 — 構成します。パスワード — パスワードを変更します。ランダム — ランダムなパスワード。助けてください — 助けてください。終了 — 終了", + "ko": "명령: status — ID/비밀번호/상태를 표시합니다. 설정 - 구성; 비밀번호 - 비밀번호 변경; 무작위 - 무작위 비밀번호; 도움 — 도움; 종료 - 종료", + "de": "Befehle: Status – ID/Passwort/Status anzeigen; Einstellungen – konfigurieren; Passwort – Passwort ändern; random – zufälliges Passwort; Hilfe – Hilfe; beenden – beenden", + "fr": "Commandes : statut – afficher l'ID/mot de passe/statut ; paramètres — configurer ; mot de passe — changer le mot de passe ; aléatoire — mot de passe aléatoire ; aide — aide; quitter - sortir", + "es": "Comandos: estado: mostrar ID/contraseña/estado; ajustes - configurar; contraseña — cambiar contraseña; aleatorio — contraseña aleatoria; ayuda—ayuda; salir - salir", + "pt-BR": "Comandos: status — mostrar ID/senha/status; configurações — configurar; senha — alterar senha; aleatório — senha aleatória; ajuda — ajuda; sair – sair" + }, + "命令过长,已忽略。": { + "zh-Hans": "命令过长,已忽略。", + "en": "Command too long; ignored.", + "ru": "Команда слишком длинная и проигнорирована.", + "zh-Hant": "命令過長,已忽略。", + "ja": "コマンドが長すぎます。無視されました。", + "ko": "명령이 너무 깁니다. 무시되었습니다.", + "de": "Befehl zu lang; ignoriert.", + "fr": "Commande trop longue ; ignoré.", + "es": "Comando demasiado largo; ignorado.", + "pt-BR": "Comando muito longo; ignorado." + }, + "回车": { + "zh-Hans": "回车", + "en": "Enter", + "zh-Hant": "回車", + "ja": "入る", + "ko": "들어가다", + "de": "Treten Sie ein", + "fr": "Entrez", + "es": "Entrar", + "pt-BR": "Entrar", + "ru": "Ввести" + }, + "在线": { + "zh-Hans": "在线", + "en": "Online", + "ru": "В сети", + "zh-Hant": "線上", + "ja": "オンライン", + "ko": "온라인", + "de": "Online", + "fr": "En ligne", + "es": "En línea", + "pt-BR": "On-line" + }, + "地址": { + "zh-Hans": "地址", + "en": "Address", + "zh-Hant": "地址", + "ja": "住所", + "ko": "주소", + "de": "Adresse", + "fr": "Adresse", + "es": "Dirección", + "pt-BR": "Endereço", + "ru": "Адрес" + }, + "填写主机名或 IPv4 地址,不含协议和路径": { + "zh-Hans": "填写主机名或 IPv4 地址,不含协议和路径", + "en": "Fill in the host name or IPv4 address, without protocol and path", + "zh-Hant": "填寫主機名或 IPv4 地址,不含協議和路徑", + "ja": "プロトコルとパスを除いて、ホスト名または IPv4 アドレスを入力します。", + "ko": "프로토콜 및 경로 없이 호스트 이름 또는 IPv4 주소를 입력하세요.", + "de": "Geben Sie den Hostnamen oder die IPv4-Adresse ein, ohne Protokoll und Pfad", + "fr": "Remplissez le nom d'hôte ou l'adresse IPv4, sans protocole ni chemin", + "es": "Complete el nombre del host o la dirección IPv4, sin protocolo ni ruta", + "pt-BR": "Preencha o nome do host ou endereço IPv4, sem protocolo e caminho", + "ru": "Введите имя хоста или IPv4-адрес без протокола и пути." + }, + "填写服务器地址": { + "zh-Hans": "填写服务器地址", + "en": "Fill in the server address", + "zh-Hant": "填寫伺服器地址", + "ja": "サーバーアドレスを入力します", + "ko": "서버 주소를 입력하세요", + "de": "Geben Sie die Serveradresse ein", + "fr": "Remplissez l'adresse du serveur", + "es": "Complete la dirección del servidor", + "pt-BR": "Preencha o endereço do servidor", + "ru": "Введите адрес сервера" + }, + "填写端口": { + "zh-Hans": "填写端口", + "en": "Fill in the port", + "zh-Hant": "填寫埠", + "ja": "ポートを記入します", + "ko": "포트를 채워주세요", + "de": "Füllen Sie den Port aus", + "fr": "Remplissez le port", + "es": "Complete el puerto", + "pt-BR": "Preencha a porta", + "ru": "Заполните порт" + }, + "声音": { + "zh-Hans": "声音", + "en": "Sound", + "zh-Hant": "聲音", + "ja": "サウンド", + "ko": "소리", + "de": "Ton", + "fr": "Son", + "es": "Sonido", + "pt-BR": "Som", + "ru": "Звук" + }, + "复制": { + "zh-Hans": "复制", + "en": "Copy", + "zh-Hant": "複製", + "ja": "コピー", + "ko": "복사", + "de": "Kopieren", + "fr": "Copier", + "es": "Copiar", + "pt-BR": "Copiar", + "ru": "Копировать" + }, + "复制 IP 和端口": { + "zh-Hans": "复制 IP 和端口", + "en": "Copy IP and port", + "ru": "Копировать IP и порт", + "zh-Hant": "複製 IP 和埠", + "ja": "IPとポートをコピーする", + "ko": "IP 및 포트 복사", + "de": "IP und Port kopieren", + "fr": "Copier l'IP et le port", + "es": "Copiar IP y puerto", + "pt-BR": "Copiar IP e porta" + }, + "复制失败,请重试": { + "zh-Hans": "复制失败,请重试", + "en": "Couldn’t copy. Try again", + "ru": "Не удалось скопировать. Повторите попытку", + "zh-Hant": "複製失敗,請重試", + "ja": "コピーできませんでした。もう一度試してください", + "ko": "복사할 수 없습니다. 다시 시도하세요", + "de": "Kopieren nicht möglich. Versuchen Sie es erneut", + "fr": "Impossible de copier. Réessayez", + "es": "No se pudo copiar. Inténtalo de nuevo", + "pt-BR": "Não foi possível copiar. Tente novamente" + }, + "复制失败,请重试。": { + "zh-Hans": "复制失败,请重试。", + "en": "Could not copy. Try again.", + "ru": "Не удалось скопировать. Повторите попытку.", + "zh-Hant": "複製失敗,請重試。", + "ja": "コピーできませんでした。もう一度やり直してください。", + "ko": "복사할 수 없습니다. 다시 시도해 보세요.", + "de": "Kopieren nicht möglich. Versuchen Sie es erneut.", + "fr": "Impossible de copier. Essayer à nouveau.", + "es": "No se pudo copiar. Intentar otra vez.", + "pt-BR": "Não foi possível copiar. Tente novamente." + }, + "复制本机 ID": { + "zh-Hans": "复制本机 ID", + "en": "Copy local ID", + "ru": "Копировать ID", + "zh-Hant": "複製本機 ID", + "ja": "ローカルIDをコピーする", + "ko": "로컬 ID 복사", + "de": "Lokale ID kopieren", + "fr": "Copier l'identifiant local", + "es": "Copiar ID local", + "pt-BR": "Copiar ID local" + }, + "复制远端文本": { + "zh-Hans": "复制远端文本", + "en": "Copy remote text", + "zh-Hant": "複製遠端文字", + "ja": "リモートテキストをコピーする", + "ko": "원격 텍스트 복사", + "de": "Remote-Text kopieren", + "fr": "Copier le texte distant", + "es": "Copiar texto remoto", + "pt-BR": "Copiar texto remoto", + "ru": "Копирование удаленного текста" + }, + "失败": { + "zh-Hans": "失败", + "en": "Failed", + "ru": "Ошибка", + "zh-Hant": "失敗", + "ja": "失敗しました", + "ko": "실패", + "de": "Fehlgeschlagen", + "fr": "Échec", + "es": "Fallido", + "pt-BR": "Falhou" + }, + "如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!": { + "zh-Hans": "如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!", + "en": "If CrossDesk is useful to you, consider supporting its continued development, cross-platform testing, and maintenance. Thank you for your support!", + "ru": "Если CrossDesk вам полезен, поддержите его дальнейшую разработку, тестирование на разных платформах и сопровождение. Спасибо за вашу поддержку!", + "zh-Hant": "如果 CrossDesk 對你有幫助,歡迎贊助支援專案的持續開發、跨平臺測試與日常維護。感謝你的支援!", + "ja": "CrossDeskが役立つ場合は、継続的な開発、クロスプラットフォーム テスト、およびメンテナンスのサポートを検討してください。ご支援ありがとうございます!", + "ko": "CrossDesk가 유용하다면 지속적인 개발, 크로스 플랫폼 테스트 및 유지 관리 지원을 고려해보세요. 귀하의 지원에 감사드립니다!", + "de": "Wenn CrossDesk für Sie nützlich ist, sollten Sie darüber nachdenken, seine weitere Entwicklung, plattformübergreifende Tests und Wartung zu unterstützen. Vielen Dank für Ihre Unterstützung!", + "fr": "Si CrossDesk vous est utile, envisagez de prendre en charge son développement continu, ses tests multiplateformes et sa maintenance. Merci pour votre soutien !", + "es": "Si CrossDesk le resulta útil, considere respaldar su desarrollo continuo, pruebas multiplataforma y mantenimiento. ¡Gracias por su apoyo!", + "pt-BR": "Se CrossDesk for útil para você, considere apoiar seu desenvolvimento contínuo, testes de plataforma cruzada e manutenção. Obrigado pelo seu apoio!" + }, + "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。": { + "zh-Hans": "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。", + "en": "Always maintain a higher resolution and reduce the frame rate to ensure picture clarity when bandwidth is insufficient.", + "zh-Hant": "始終保持較高解析度,頻寬不足時透過降低幀率來保證畫面清晰度。", + "ja": "帯域幅が不十分な場合は、常に高い解像度を維持し、フレーム レートを下げて画像の鮮明さを確保します。", + "ko": "대역폭이 부족할 때 영상 선명도를 보장하려면 항상 더 높은 해상도를 유지하고 프레임 속도를 낮추십시오.", + "de": "Behalten Sie immer eine höhere Auflösung bei und reduzieren Sie die Bildrate, um die Bildschärfe zu gewährleisten, wenn die Bandbreite nicht ausreicht.", + "fr": "Maintenez toujours une résolution plus élevée et réduisez la fréquence d'images pour garantir la clarté de l'image lorsque la bande passante est insuffisante.", + "es": "Mantenga siempre una resolución más alta y reduzca la velocidad de fotogramas para garantizar la claridad de la imagen cuando el ancho de banda sea insuficiente.", + "pt-BR": "Sempre mantenha uma resolução mais alta e reduza a taxa de quadros para garantir a clareza da imagem quando a largura de banda for insuficiente.", + "ru": "Всегда поддерживайте более высокое разрешение и уменьшайте частоту кадров, чтобы обеспечить четкость изображения при недостаточной полосе пропускания." + }, + "媒体加密": { + "zh-Hans": "媒体加密", + "en": "Media encryption", + "zh-Hant": "媒體加密", + "ja": "メディアの暗号化", + "ko": "미디어 암호화", + "de": "Medienverschlüsselung", + "fr": "Cryptage multimédia", + "es": "Cifrado de medios", + "pt-BR": "Criptografia de mídia", + "ru": "Шифрование мультимедиа" + }, + "字母数字": { + "zh-Hans": "字母数字", + "en": "Letters & numbers", + "ru": "Буквы и цифры", + "zh-Hant": "字母數字", + "ja": "英数字", + "ko": "문자·숫자", + "de": "Buchstaben & Zahlen", + "fr": "Lettres et chiffres", + "es": "Letras y números", + "pt-BR": "Letras e números" + }, + "守护进程(无头控制台中不生效)": { + "zh-Hans": "守护进程(无头控制台中不生效)", + "en": "Daemon (inactive in headless console)", + "ru": "Фоновый режим (не действует в консоли)", + "zh-Hant": "守護程序(無頭控制檯中不生效)", + "ja": "デーモン (ヘッドレス コンソールでは非アクティブ)", + "ko": "데몬(헤드리스 콘솔에서는 비활성)", + "de": "Daemon (in der Headless-Konsole inaktiv)", + "fr": "Démon (inactif dans la console sans tête)", + "es": "Daemon (inactivo en consola sin cabeza)", + "pt-BR": "Daemon (inativo no console headless)" + }, + "安全存储不可用,请解锁设备后重试": { + "zh-Hans": "安全存储不可用,请解锁设备后重试", + "en": "Secure storage is unavailable, please unlock the device and try again", + "zh-Hant": "安全儲存不可用,請解鎖裝置後重試", + "ja": "安全なストレージが利用できません。デバイスのロックを解除して、もう一度お試しください。", + "ko": "보안 저장소를 사용할 수 없습니다. 장치를 잠금 해제한 후 다시 시도해 주세요.", + "de": "Der sichere Speicher ist nicht verfügbar. Bitte entsperren Sie das Gerät und versuchen Sie es erneut", + "fr": "Le stockage sécurisé n'est pas disponible, veuillez déverrouiller l'appareil et réessayer", + "es": "El almacenamiento seguro no está disponible. Desbloquee el dispositivo e inténtelo nuevamente.", + "pt-BR": "O armazenamento seguro não está disponível. Desbloqueie o dispositivo e tente novamente", + "ru": "Безопасное хранилище недоступно. Разблокируйте устройство и повторите попытку." + }, + "安全存储或证书初始化失败,请重试或清除应用数据": { + "zh-Hans": "安全存储或证书初始化失败,请重试或清除应用数据", + "en": "Secure storage or certificate initialization failed, please try again or clear application data", + "zh-Hant": "安全儲存或證書初始化失敗,請重試或清除應用資料", + "ja": "安全なストレージまたは証明書の初期化に失敗しました。再試行するか、アプリケーション データをクリアしてください。", + "ko": "보안 저장 또는 인증서 초기화에 실패했습니다. 다시 시도하거나 애플리케이션 데이터를 삭제하세요.", + "de": "Der sichere Speicher oder die Initialisierung des Zertifikats ist fehlgeschlagen. Bitte versuchen Sie es erneut oder löschen Sie die Anwendungsdaten", + "fr": "Échec du stockage sécurisé ou de l'initialisation du certificat. Veuillez réessayer ou effacer les données de l'application.", + "es": "Error en el almacenamiento seguro o en la inicialización del certificado. Inténtelo de nuevo o borre los datos de la aplicación.", + "pt-BR": "Falha no armazenamento seguro ou na inicialização do certificado. Tente novamente ou limpe os dados do aplicativo", + "ru": "Не удалось инициализировать безопасное хранилище или сертификат. Повторите попытку или очистите данные приложения." + }, + "安装": { + "zh-Hans": "安装", + "en": "Install", + "ru": "Установить", + "zh-Hant": "安裝", + "ja": "インストール", + "ko": "설치", + "de": "Installieren", + "fr": "Installer", + "es": "Instalar", + "pt-BR": "Instalar" + }, + "安装 CrossDesk Service": { + "zh-Hans": "安装 CrossDesk Service", + "en": "Install CrossDesk Service", + "ru": "Установить CrossDesk Service", + "zh-Hant": "安裝 CrossDesk Service", + "ja": "CrossDeskサービスのインストール", + "ko": "CrossDesk서비스 설치", + "de": "Installieren Sie den CrossDesk-Dienst", + "fr": "Installer le service CrossDesk", + "es": "Instalar el servicio CrossDesk", + "pt-BR": "Instale o serviço CrossDesk" + }, + "安装更新": { + "zh-Hans": "安装更新", + "en": "Install update", + "ru": "Установить обновление", + "zh-Hant": "安裝更新", + "ja": "アップデートのインストール", + "ko": "업데이트 설치", + "de": "Update installieren", + "fr": "Installer la mise à jour", + "es": "Instalar actualización", + "pt-BR": "Instalar atualização" + }, + "完成": { + "zh-Hans": "完成", + "en": "Done", + "ru": "Готово", + "zh-Hant": "完成", + "ja": "完了", + "ko": "완료", + "de": "Fertig", + "fr": "Terminé", + "es": "Hecho", + "pt-BR": "Feito" + }, + "完成隐私授权后可检查更新": { + "zh-Hans": "完成隐私授权后可检查更新", + "en": "You can check for updates after completing privacy authorization", + "zh-Hant": "完成隱私授權後可檢查更新", + "ja": "プライバシー認証を完了すると、アップデートを確認できます", + "ko": "개인정보 동의 완료 후 업데이트 내용을 확인할 수 있습니다.", + "de": "Sie können nach Abschluss der Datenschutzautorisierung nach Updates suchen", + "fr": "Vous pouvez vérifier les mises à jour après avoir terminé l'autorisation de confidentialité", + "es": "Puede buscar actualizaciones después de completar la autorización de privacidad", + "pt-BR": "Você pode verificar se há atualizações após concluir a autorização de privacidade", + "ru": "Вы можете проверить наличие обновлений после завершения авторизации конфиденциальности." + }, + "完成隐私授权后登记本机身份": { + "zh-Hans": "完成隐私授权后登记本机身份", + "en": "Register the local identity after completing privacy authorization", + "zh-Hant": "完成隱私授權後登記本機身份", + "ja": "プライバシー認証完了後、ローカル ID を登録します", + "ko": "개인정보 인증 완료 후 로컬 신원 등록", + "de": "Registrieren Sie die lokale Identität, nachdem Sie die Datenschutzautorisierung abgeschlossen haben", + "fr": "Enregistrez l'identité locale après avoir terminé l'autorisation de confidentialité", + "es": "Registre la identidad local después de completar la autorización de privacidad", + "pt-BR": "Registre a identidade local após concluir a autorização de privacidade", + "ru": "Зарегистрируйте локальную личность после завершения авторизации конфиденциальности." + }, + "密码": { + "zh-Hans": "密码", + "en": "Password", + "ru": "Пароль", + "zh-Hant": "密碼", + "ja": "パスワード", + "ko": "비밀번호", + "de": "Passwort", + "fr": "Mot de passe", + "es": "Contraseña", + "pt-BR": "Senha" + }, + "密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。": { + "zh-Hans": "密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。", + "en": "The password is incorrect or has changed. Check the other desktop's current LAN password and try again.", + "ru": "Пароль неверен или изменён. Проверьте текущий пароль LAN другого компьютера и повторите попытку.", + "zh-Hant": "密碼不正確,或對方密碼已更新。請檢視對方的區域網訪問密碼後重試。", + "ja": "パスワードが間違っているか、変更されています。他のデスクトップの現在の LAN パスワードを確認し、再試行してください。", + "ko": "비밀번호가 틀리거나 변경되었습니다. 다른 데스크톱의 현재 LAN 비밀번호를 확인하고 다시 시도하세요.", + "de": "Das Passwort ist falsch oder wurde geändert. Überprüfen Sie das aktuelle LAN-Passwort des anderen Desktops und versuchen Sie es erneut.", + "fr": "Le mot de passe est incorrect ou a changé. Vérifiez le mot de passe LAN actuel de l'autre ordinateur de bureau et réessayez.", + "es": "La contraseña es incorrecta o ha cambiado. Verifique la contraseña LAN actual del otro escritorio e inténtelo nuevamente.", + "pt-BR": "A senha está incorreta ou foi alterada. Verifique a senha LAN atual da outra área de trabalho e tente novamente." + }, + "密码保存失败,本次连接仍可使用": { + "zh-Hans": "密码保存失败,本次连接仍可使用", + "en": "Password saving failed, this connection can still be used", + "zh-Hant": "密碼儲存失敗,本次連線仍可使用", + "ja": "パスワードの保存に失敗しました。この接続はまだ使用できます", + "ko": "비밀번호 저장에 실패했습니다. 이 연결은 계속 사용할 수 있습니다.", + "de": "Das Speichern des Passworts ist fehlgeschlagen. Diese Verbindung kann weiterhin verwendet werden", + "fr": "L'enregistrement du mot de passe a échoué, cette connexion peut toujours être utilisée", + "es": "Error al guardar la contraseña, esta conexión aún se puede utilizar", + "pt-BR": "Falha ao salvar a senha, esta conexão ainda pode ser usada", + "ru": "Не удалось сохранить пароль, это соединение все еще можно использовать." + }, + "密码修改正在处理中,请等待服务器确认。": { + "zh-Hans": "密码修改正在处理中,请等待服务器确认。", + "en": "Password change pending; wait for server confirmation.", + "ru": "Смена пароля выполняется. Дождитесь подтверждения сервера.", + "zh-Hant": "密碼修改正在處理中,請等待伺服器確認。", + "ja": "パスワード変更は保留中です。サーバーの確認を待ちます。", + "ko": "비밀번호 변경이 보류 중입니다. 서버 확인을 기다립니다.", + "de": "Passwortänderung steht aus; Warten Sie auf die Serverbestätigung.", + "fr": "Changement de mot de passe en attente ; attendez la confirmation du serveur.", + "es": "Cambio de contraseña pendiente; espere la confirmación del servidor.", + "pt-BR": "Alteração de senha pendente; aguarde a confirmação do servidor." + }, + "密码修改结果尚未确认,正在重新连接服务器核实。": { + "zh-Hans": "密码修改结果尚未确认,正在重新连接服务器核实。", + "en": "Password change not yet confirmed; reconnecting to verify.", + "ru": "Смена пароля не подтверждена. Повторное подключение для проверки.", + "zh-Hant": "密碼修改結果尚未確認,正在重新連線伺服器核實。", + "ja": "パスワードの変更はまだ確認されていません。再接続して確認します。", + "ko": "비밀번호 변경이 아직 확인되지 않았습니다. 확인을 위해 다시 연결하는 중입니다.", + "de": "Passwortänderung noch nicht bestätigt; Zur Überprüfung wird die Verbindung erneut hergestellt.", + "fr": "Changement de mot de passe pas encore confirmé ; reconnexion pour vérifier.", + "es": "Cambio de contraseña aún no confirmado; reconectándose para verificar.", + "pt-BR": "Alteração de senha ainda não confirmada; reconectando para verificar." + }, + "密码将加密保存在本机 Android Keystore 中": { + "zh-Hans": "密码将加密保存在本机 Android Keystore 中", + "en": "Passwords are saved encrypted in the native Android Keystore", + "zh-Hant": "密碼將加密儲存在本機 Android Keystore 中", + "ja": "パスワードは暗号化されてネイティブ Android キーストアに保存されます", + "ko": "비밀번호는 기본 Android 키 저장소에 암호화되어 저장됩니다.", + "de": "Passwörter werden verschlüsselt im nativen Android Keystore gespeichert", + "fr": "Les mots de passe sont enregistrés cryptés dans le Keystore Android natif", + "es": "Las contraseñas se guardan cifradas en el almacén de claves nativo de Android", + "pt-BR": "As senhas são salvas criptografadas no Android Keystore nativo", + "ru": "Пароли сохраняются в зашифрованном виде в собственном хранилище ключей Android." + }, + "密码将加密保存在此设备上": { + "zh-Hans": "密码将加密保存在此设备上", + "en": "Passwords will be stored encrypted on this device", + "zh-Hant": "密碼將加密儲存在此裝置上", + "ja": "パスワードはこのデバイスに暗号化されて保存されます", + "ko": "비밀번호는 이 장치에 암호화되어 저장됩니다.", + "de": "Passwörter werden auf diesem Gerät verschlüsselt gespeichert", + "fr": "Les mots de passe seront stockés cryptés sur cet appareil", + "es": "Las contraseñas se almacenarán cifradas en este dispositivo", + "pt-BR": "As senhas serão armazenadas criptografadas neste dispositivo", + "ru": "Пароли будут храниться на этом устройстве в зашифрованном виде." + }, + "密码将安全保存在本机 Keychain 中": { + "zh-Hans": "密码将安全保存在本机 Keychain 中", + "en": "Passwords will be safely stored in the local Keychain", + "zh-Hant": "密碼將安全儲存在本機 Keychain 中", + "ja": "パスワードはローカルのキーチェーンに安全に保存されます", + "ko": "비밀번호는 로컬 키체인에 안전하게 저장됩니다.", + "de": "Passwörter werden sicher im lokalen Schlüsselbund gespeichert", + "fr": "Les mots de passe seront stockés en toute sécurité dans le trousseau local", + "es": "Las contraseñas se almacenarán de forma segura en el llavero local.", + "pt-BR": "As senhas serão armazenadas com segurança no chaveiro local", + "ru": "Пароли будут безопасно храниться в локальной связке ключей." + }, + "密码必须为 6 位英文字母或数字。": { + "zh-Hans": "密码必须为 6 位英文字母或数字。", + "en": "Use exactly 6 letters (A–Z, a–z) or digits (0–9).", + "ru": "Пароль должен содержать ровно 6 латинских букв или цифр.", + "zh-Hant": "密碼必須為 6 位英文字母或數字。", + "ja": "正確に 6 つの文字 (A ~ Z、a ~ z) または数字 (0 ~ 9) を使用します。", + "ko": "정확히 6개의 문자(A~Z, a~z) 또는 숫자(0~9)를 사용하세요.", + "de": "Verwenden Sie genau 6 Buchstaben (A–Z, a–z) oder Ziffern (0–9).", + "fr": "Utilisez exactement 6 lettres (A–Z, a–z) ou chiffres (0–9).", + "es": "Utilice exactamente 6 letras (A–Z, a–z) o dígitos (0–9).", + "pt-BR": "Use exatamente 6 letras (A–Z, a–z) ou dígitos (0–9)." + }, + "密码必须是6位英文字母或数字,未提交修改。": { + "zh-Hans": "密码必须是6位英文字母或数字,未提交修改。", + "en": "Password must be 6 ASCII letters or digits; no change submitted.", + "ru": "Пароль должен содержать 6 латинских букв или цифр. Изменение не отправлено.", + "zh-Hant": "密碼必須是6位英文字母或數字,未提交修改。", + "ja": "パスワードは 6 文字の ASCII 文字または数字でなければなりません。変更は送信されませんでした。", + "ko": "비밀번호는 6자리 ASCII 문자 또는 숫자여야 합니다. 변경사항이 제출되지 않았습니다.", + "de": "Das Passwort muss aus 6 ASCII-Buchstaben oder -Ziffern bestehen. Keine Änderung eingereicht.", + "fr": "Le mot de passe doit contenir 6 lettres ou chiffres ASCII ; aucun changement soumis.", + "es": "La contraseña debe tener 6 letras o dígitos ASCII; no se envió ningún cambio.", + "pt-BR": "A senha deve ter 6 letras ou dígitos ASCII; nenhuma alteração enviada." + }, + "对方密码已更新,请使用新密码重试。": { + "zh-Hans": "对方密码已更新,请使用新密码重试。", + "en": "The password changed. Try again with the new password.", + "ru": "Пароль изменился. Повторите с новым паролем.", + "zh-Hant": "對方密碼已更新,請使用新密碼重試。", + "ja": "パスワードが変更されました。新しいパスワードを使用して再試行してください。", + "ko": "비밀번호가 변경되었습니다. 새 비밀번호로 다시 시도해 보세요.", + "de": "Das Passwort wurde geändert. Versuchen Sie es erneut mit dem neuen Passwort.", + "fr": "Le mot de passe a changé. Réessayez avec le nouveau mot de passe.", + "es": "La contraseña cambió. Vuelva a intentarlo con la nueva contraseña.", + "pt-BR": "A senha foi alterada. Tente novamente com a nova senha." + }, + "对端 ID": { + "zh-Hans": "对端 ID", + "en": "Remote ID", + "ru": "Удаленный ID", + "zh-Hant": "對端 ID", + "ja": "リモートID", + "ko": "원격 ID", + "de": "Remote-ID", + "fr": "ID à distance", + "es": "Identificación remota", + "pt-BR": "ID remoto" + }, + "对端 ID ": { + "zh-Hans": "对端 ID ", + "en": "Peer ID ", + "zh-Hant": "對端 ID ", + "ja": "ピアID ", + "ko": "피어 ID ", + "de": "Peer-ID ", + "fr": "Identification des pairs ", + "es": "Identificación de pares ", + "pt-BR": "ID do par ", + "ru": "Идентификатор узла " + }, + "对端 ID %1$@": { + "zh-Hans": "对端 ID %1$@", + "en": "Peer ID %1$@", + "zh-Hant": "對端 ID %1$@", + "ja": "ピアID%1$@", + "ko": "피어 ID%1$@", + "de": "Peer-ID %1$@", + "fr": "ID homologue %1$@", + "es": "ID de igual %1$@", + "pt-BR": "ID de par %1$@", + "ru": "Идентификатор узла %1$@" + }, + "对端 ID {0}": { + "zh-Hans": "对端 ID {0}", + "en": "Peer ID {0}", + "zh-Hant": "對端 ID {0}", + "ja": "ピアID{0}", + "ko": "피어 ID{0}", + "de": "Peer-ID {0}", + "fr": "ID homologue {0}", + "es": "ID de igual {0}", + "pt-BR": "ID de par {0}", + "ru": "Идентификатор узла {0}" + }, + "对等连接失败": { + "zh-Hans": "对等连接失败", + "en": "P2P Failed", + "ru": "Сбой P2P", + "zh-Hant": "對等連線失敗", + "ja": "P2P 失敗", + "ko": "P2P 실패", + "de": "P2P fehlgeschlagen", + "fr": "Échec du P2P", + "es": "P2P falló", + "pt-BR": "Falha no P2P" + }, + "对等连接已关闭": { + "zh-Hans": "对等连接已关闭", + "en": "P2P closed", + "ru": "P2P закрыто", + "zh-Hant": "對等連線已關閉", + "ja": "P2Pは終了しました", + "ko": "P2P 폐쇄", + "de": "P2P geschlossen", + "fr": "P2P fermé", + "es": "P2P cerrado", + "pt-BR": "P2P fechado" + }, + "对等连接已建立": { + "zh-Hans": "对等连接已建立", + "en": "P2P Connected", + "ru": "P2P подключено", + "zh-Hant": "對等連線已建立", + "ja": "P2P接続済み", + "ko": "P2P 연결됨", + "de": "P2P verbunden", + "fr": "P2P connecté", + "es": "P2P conectado", + "pt-BR": "Conectado P2P" + }, + "对等连接已断开": { + "zh-Hans": "对等连接已断开", + "en": "P2P Disconnected", + "ru": "P2P отключено", + "zh-Hant": "對等連線已斷開", + "ja": "P2Pが切断されました", + "ko": "P2P 연결 끊김", + "de": "P2P getrennt", + "fr": "P2P déconnecté", + "es": "P2P desconectado", + "pt-BR": "P2P desconectado" + }, + "将 ID 和密码分享给连接方": { + "zh-Hans": "将 ID 和密码分享给连接方", + "en": "Share your ID and password to get connected", + "ru": "Передайте ID и пароль для подключения", + "zh-Hant": "將 ID 和密碼分享給連線方", + "ja": "IDとパスワードを共有して接続する", + "ko": "연결을 위해 ID와 비밀번호를 공유하세요", + "de": "Teilen Sie Ihre ID und Ihr Passwort mit, um eine Verbindung herzustellen", + "fr": "Partagez votre identifiant et votre mot de passe pour vous connecter", + "es": "Comparte tu ID y contraseña para conectarte", + "pt-BR": "Compartilhe seu ID e senha para se conectar" + }, + "将 IP 和密码分享给连接方": { + "zh-Hans": "将 IP 和密码分享给连接方", + "en": "Share your IP and password to get connected", + "ru": "Передайте IP и пароль для подключения", + "zh-Hant": "將 IP 和密碼分享給連線方", + "ja": "IP とパスワードを共有して接続します", + "ko": "연결하려면 IP와 비밀번호를 공유하세요.", + "de": "Teilen Sie Ihre IP und Ihr Passwort mit, um eine Verbindung herzustellen", + "fr": "Partagez votre IP et votre mot de passe pour vous connecter", + "es": "Comparte tu IP y contraseña para conectarte", + "pt-BR": "Compartilhe seu IP e senha para se conectar" + }, + "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。": { + "zh-Hans": "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。", + "en": "Will stop the remote connection, close the screen preview save and clear the existing preview. The connection record and password will be retained, and authorization is required again before reconnecting.", + "zh-Hant": "將停止遠端連線、關閉畫面預覽儲存並清除已有預覽。連線記錄和密碼會保留,重新連線前需再次授權。", + "ja": "リモート接続を停止し、画面プレビューの保存を閉じて、既存のプレビューをクリアします。接続記録とパスワードは保持され、再接続する前に再度認証が必要になります。", + "ko": "원격 연결을 중지하고 화면 미리보기 저장을 닫은 후 기존 미리보기를 지웁니다. 접속 기록과 비밀번호는 유지되며, 재접속 전 다시 인증이 필요합니다.", + "de": "Stoppt die Remote-Verbindung, schließt die Bildschirmvorschau, speichert sie und löscht die vorhandene Vorschau. Der Verbindungsdatensatz und das Passwort bleiben erhalten und vor der erneuten Verbindung ist eine erneute Autorisierung erforderlich.", + "fr": "Arrêtera la connexion à distance, fermera la sauvegarde de l'aperçu de l'écran et effacera l'aperçu existant. L'enregistrement de connexion et le mot de passe seront conservés et une autorisation sera à nouveau requise avant de se reconnecter.", + "es": "Detendrá la conexión remota, cerrará la vista previa de la pantalla y borrará la vista previa existente. El registro de conexión y la contraseña se conservarán y se requerirá autorización nuevamente antes de volver a conectarse.", + "pt-BR": "Interromperá a conexão remota, fechará o salvamento da visualização da tela e limpará a visualização existente. O registro de conexão e a senha serão mantidos e será necessária autorização novamente antes de reconectar.", + "ru": "Остановит удаленное соединение, закроет сохранение предварительного просмотра экрана и очистит существующий предварительный просмотр. Запись о подключении и пароль будут сохранены, и перед повторным подключением потребуется повторная авторизация." + }, + "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。": { + "zh-Hans": "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。", + "en": "Will stop the remote connection, close the screen preview save and clear the existing preview. Connection records and received files will be retained, and existing server data will not be deleted. You can reauthorize at any time.", + "zh-Hant": "將停止遠端連線、關閉畫面預覽儲存並清除已有預覽。連線記錄和接收檔案會保留,已有服務端資料不會刪除。您可隨時重新授權。", + "ja": "リモート接続を停止し、画面プレビューの保存を閉じて、既存のプレビューをクリアします。接続記録と受信したファイルは保持され、既存のサーバー データは削除されません。いつでも再認証できます。", + "ko": "원격 연결을 중지하고 화면 미리보기 저장을 닫은 후 기존 미리보기를 지웁니다. 접속 기록 및 수신 파일은 그대로 유지되며, 기존 서버 데이터는 삭제되지 않습니다. 언제든지 재승인할 수 있습니다.", + "de": "Stoppt die Remote-Verbindung, schließt die Bildschirmvorschau, speichert sie und löscht die vorhandene Vorschau. Verbindungsdatensätze und empfangene Dateien bleiben erhalten und vorhandene Serverdaten werden nicht gelöscht. Sie können sich jederzeit erneut autorisieren.", + "fr": "Arrêtera la connexion à distance, fermera la sauvegarde de l'aperçu de l'écran et effacera l'aperçu existant. Les enregistrements de connexion et les fichiers reçus seront conservés et les données du serveur existantes ne seront pas supprimées. Vous pouvez réautoriser à tout moment.", + "es": "Detendrá la conexión remota, cerrará la vista previa de la pantalla y borrará la vista previa existente. Los registros de conexión y los archivos recibidos se conservarán y los datos existentes del servidor no se eliminarán. Puede volver a autorizar en cualquier momento.", + "pt-BR": "Interromperá a conexão remota, fechará o salvamento da visualização da tela e limpará a visualização existente. Os registros de conexão e os arquivos recebidos serão retidos e os dados existentes do servidor não serão excluídos. Você pode reautorizar a qualquer momento.", + "ru": "Остановит удаленное соединение, закроет сохранение предварительного просмотра экрана и очистит существующий предварительный просмотр. Записи подключений и полученные файлы сохранятся, а существующие данные сервера не будут удалены. Вы можете повторно авторизоваться в любое время." + }, + "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。": { + "zh-Hans": "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。", + "en": "All remote previews saved on this machine will be deleted, while connection records, passwords and received files will be retained.", + "zh-Hant": "將刪除本機儲存的所有遠端預覽圖,保留連線記錄、密碼和接收的檔案。", + "ja": "本機に保存されているリモートプレビューはすべて削除されますが、接続記録、パスワード、受信したファイルは保持されます。", + "ko": "이 기기에 저장된 원격 미리보기는 모두 삭제되지만 연결 기록, 비밀번호 및 수신된 파일은 유지됩니다.", + "de": "Alle auf diesem Computer gespeicherten Remote-Vorschauen werden gelöscht, während Verbindungsdatensätze, Passwörter und empfangene Dateien erhalten bleiben.", + "fr": "Tous les aperçus à distance enregistrés sur cette machine seront supprimés, tandis que les enregistrements de connexion, les mots de passe et les fichiers reçus seront conservés.", + "es": "Se eliminarán todas las vistas previas remotas guardadas en esta máquina, mientras que se conservarán los registros de conexión, las contraseñas y los archivos recibidos.", + "pt-BR": "Todas as visualizações remotas salvas nesta máquina serão excluídas, enquanto os registros de conexão, senhas e arquivos recebidos serão mantidos.", + "ru": "Все удаленные предварительные просмотры, сохраненные на этом компьютере, будут удалены, а записи подключений, пароли и полученные файлы сохранятся." + }, + "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。": { + "zh-Hans": "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。", + "en": "All remote previews saved on this machine will be deleted, while connection records, passwords and received files will be retained. Subsequent connections will still save new previews.", + "zh-Hant": "將刪除本機儲存的所有遠端預覽圖,保留連線記錄、密碼和接收的檔案。後續連線仍會儲存新的預覽圖。", + "ja": "本機に保存されているリモート プレビューはすべて削除されますが、接続記録、パスワード、受信したファイルは保持されます。後続の接続でも新しいプレビューが保存されます。", + "ko": "이 기기에 저장된 원격 미리보기는 모두 삭제되지만 연결 기록, 비밀번호 및 수신된 파일은 유지됩니다. 후속 연결에서는 계속해서 새로운 미리보기가 저장됩니다.", + "de": "Alle auf diesem Computer gespeicherten Remote-Vorschauen werden gelöscht, während Verbindungsdatensätze, Passwörter und empfangene Dateien erhalten bleiben. Bei späteren Verbindungen werden weiterhin neue Vorschauen gespeichert.", + "fr": "Tous les aperçus à distance enregistrés sur cette machine seront supprimés, tandis que les enregistrements de connexion, les mots de passe et les fichiers reçus seront conservés. Les connexions ultérieures enregistreront toujours les nouveaux aperçus.", + "es": "Se eliminarán todas las vistas previas remotas guardadas en esta máquina, mientras que se conservarán los registros de conexión, las contraseñas y los archivos recibidos. Las conexiones posteriores seguirán guardando nuevas vistas previas.", + "pt-BR": "Todas as visualizações remotas salvas nesta máquina serão excluídas, enquanto os registros de conexão, senhas e arquivos recebidos serão mantidos. As conexões subsequentes ainda salvarão novas visualizações.", + "ru": "Все удаленные предварительные просмотры, сохраненные на этом компьютере, будут удалены, а записи подключений, пароли и полученные файлы сохранятся. Последующие подключения по-прежнему будут сохранять новые предварительные просмотры." + }, + "将删除本机保存的所有远程预览图,保留连接记录和密码。": { + "zh-Hans": "将删除本机保存的所有远程预览图,保留连接记录和密码。", + "en": "All remote previews saved on this machine will be deleted, and the connection records and passwords will be retained.", + "zh-Hant": "將刪除本機儲存的所有遠端預覽圖,保留連線記錄和密碼。", + "ja": "本機に保存されているリモートプレビューはすべて削除され、接続記録とパスワードは保持されます。", + "ko": "이 기기에 저장된 원격 미리보기는 모두 삭제되며, 연결 기록과 비밀번호는 유지됩니다.", + "de": "Alle auf diesem Computer gespeicherten Remote-Vorschauen werden gelöscht und die Verbindungsdatensätze und Passwörter bleiben erhalten.", + "fr": "Tous les aperçus à distance enregistrés sur cette machine seront supprimés et les enregistrements de connexion et les mots de passe seront conservés.", + "es": "Se eliminarán todas las vistas previas remotas guardadas en esta máquina y se conservarán los registros de conexión y las contraseñas.", + "pt-BR": "Todas as visualizações remotas salvas nesta máquina serão excluídas e os registros de conexão e senhas serão mantidos.", + "ru": "Все удаленные просмотры, сохраненные на этом компьютере, будут удалены, а записи подключений и пароли сохранятся." + }, + "将清除此设备保存的所有远程画面预览,保留连接记录和访问密码。": { + "zh-Hans": "将清除此设备保存的所有远程画面预览,保留连接记录和访问密码。", + "en": "All remote screen previews saved by this device will be cleared, and connection records and access passwords will be retained.", + "zh-Hant": "將清除此裝置儲存的所有遠端畫面預覽,保留連線記錄和訪問密碼。", + "ja": "このデバイスによって保存されたすべてのリモート画面プレビューは消去され、接続記録とアクセス パスワードは保持されます。", + "ko": "이 기기에 저장된 원격 화면 미리보기는 모두 삭제되며, 연결 기록 및 접속 비밀번호는 유지됩니다.", + "de": "Alle von diesem Gerät gespeicherten Remote-Bildschirmvorschauen werden gelöscht und Verbindungsaufzeichnungen und Zugriffskennwörter bleiben erhalten.", + "fr": "Tous les aperçus d'écran à distance enregistrés par cet appareil seront effacés et les enregistrements de connexion et les mots de passe d'accès seront conservés.", + "es": "Se borrarán todas las vistas previas de pantalla remota guardadas por este dispositivo y se conservarán los registros de conexión y las contraseñas de acceso.", + "pt-BR": "Todas as visualizações de tela remotas salvas por este dispositivo serão apagadas e os registros de conexão e senhas de acesso serão retidos.", + "ru": "Все предварительные просмотры удаленного экрана, сохраненные на этом устройстве, будут удалены, а записи подключений и пароли доступа сохранятся." + }, + "尚未收到远端文本": { + "zh-Hans": "尚未收到远端文本", + "en": "Remote text not received yet", + "zh-Hant": "尚未收到遠端文字", + "ja": "リモートテキストがまだ受信されていません", + "ko": "원격 문자가 아직 수신되지 않았습니다.", + "de": "Remote-Text noch nicht empfangen", + "fr": "SMS distant pas encore reçu", + "es": "Texto remoto aún no recibido", + "pt-BR": "Texto remoto ainda não recebido", + "ru": "Удаленное сообщение еще не получено." + }, + "尚未连接服务器,暂时无法修改密码。": { + "zh-Hans": "尚未连接服务器,暂时无法修改密码。", + "en": "Connect to the server before changing the password.", + "ru": "Для смены пароля подключитесь к серверу.", + "zh-Hant": "尚未連線伺服器,暫時無法修改密碼。", + "ja": "パスワードを変更する前にサーバーに接続してください。", + "ko": "비밀번호를 변경하기 전에 서버에 접속하세요.", + "de": "Stellen Sie eine Verbindung zum Server her, bevor Sie das Passwort ändern.", + "fr": "Connectez-vous au serveur avant de modifier le mot de passe.", + "es": "Conéctese al servidor antes de cambiar la contraseña.", + "pt-BR": "Conecte-se ao servidor antes de alterar a senha." + }, + "尚未连接服务器,请稍后重试": { + "zh-Hans": "尚未连接服务器,请稍后重试", + "en": "Not connected to the server; try again shortly", + "ru": "Нет соединения с сервером. Повторите позже", + "zh-Hant": "尚未連線伺服器,請稍後重試", + "ja": "サーバーに接続されていません。すぐにもう一度試してください", + "ko": "서버에 연결되지 않았습니다. 잠시 후 다시 시도해 보세요", + "de": "Keine Verbindung zum Server; Versuchen Sie es in Kürze noch einmal", + "fr": "Non connecté au serveur ; réessayez sous peu", + "es": "No conectado al servidor; inténtalo de nuevo en breve", + "pt-BR": "Não conectado ao servidor; tente novamente em breve" + }, + "尝试次数过多,请等待倒计时结束后重试。": { + "zh-Hans": "尝试次数过多,请等待倒计时结束后重试。", + "en": "Too many attempts. Try again when the countdown ends.", + "ru": "Слишком много попыток. Дождитесь окончания обратного отсчёта.", + "zh-Hant": "嘗試次數過多,請等待倒計時結束後重試。", + "ja": "試行回数が多すぎます。カウントダウンが終了したらもう一度お試しください。", + "ko": "시도 횟수가 너무 많습니다. 카운트다운이 끝나면 다시 시도하세요.", + "de": "Zu viele Versuche. Versuchen Sie es erneut, wenn der Countdown abgelaufen ist.", + "fr": "Trop de tentatives. Réessayez une fois le compte à rebours terminé.", + "es": "Demasiados intentos. Inténtalo de nuevo cuando termine la cuenta regresiva.", + "pt-BR": "Muitas tentativas. Tente novamente quando a contagem regressiva terminar." + }, + "局域网端口": { + "zh-Hans": "局域网端口", + "en": "LAN port", + "ru": "Порт LAN", + "zh-Hant": "區域網埠", + "ja": "LANポート", + "ko": "LAN 포트", + "de": "LAN-Anschluss", + "fr": "Port LAN", + "es": "Puerto LAN", + "pt-BR": "Porta LAN" + }, + "屏幕录制权限": { + "zh-Hans": "屏幕录制权限", + "en": "Screen Recording Permission", + "ru": "Разрешение на запись экрана", + "zh-Hant": "螢幕錄製許可權", + "ja": "画面録画許可", + "ko": "화면 녹화 권한", + "de": "Erlaubnis zur Bildschirmaufzeichnung", + "fr": "Autorisation d'enregistrement d'écran", + "es": "Permiso de grabación de pantalla", + "pt-BR": "Permissão de gravação de tela" + }, + "屏幕方向": { + "zh-Hans": "屏幕方向", + "en": "Screen orientation", + "zh-Hant": "螢幕方向", + "ja": "画面の向き", + "ko": "화면 방향", + "de": "Bildschirmausrichtung", + "fr": "Orientation de l'écran", + "es": "Orientación de la pantalla", + "pt-BR": "Orientação da tela", + "ru": "Ориентация экрана" + }, + "展开控制栏": { + "zh-Hans": "展开控制栏", + "en": "Expand Control Bar", + "ru": "Развернуть панель управления", + "zh-Hant": "展開控制欄", + "ja": "コントロールバーを展開する", + "ko": "컨트롤 바 확장", + "de": "Erweitern Sie die Steuerleiste", + "fr": "Développer la barre de contrôle", + "es": "Expandir barra de control", + "pt-BR": "Expandir barra de controle" + }, + "展开远程控制菜单": { + "zh-Hans": "展开远程控制菜单", + "en": "Expand remote control menu", + "zh-Hant": "展開遠端控制選單", + "ja": "リモコンメニューを展開する", + "ko": "원격제어 메뉴 확장", + "de": "Fernbedienungsmenü erweitern", + "fr": "Développer le menu de la télécommande", + "es": "Ampliar el menú del control remoto", + "pt-BR": "Expandir menu de controle remoto", + "ru": "Развернуть меню пульта дистанционного управления" + }, + "已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。": { + "zh-Hans": "已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。", + "en": "You will not be reminded again. To enable remote control while locked later, click Install in Settings.", + "ru": "Напоминание отключено. Чтобы позже включить удаленное управление на экране блокировки, нажмите «Установить» в настройках.", + "zh-Hant": "已不再提醒。後續如需啟用鎖屏狀態下被遠端控制,可在設定中點選“安裝”。", + "ja": "再度通知されることはありません。後でロック中にリモート コントロールを有効にするには、[設定] で [インストール] をクリックします。", + "ko": "다시 알림을 받지 않습니다. 나중에 잠긴 상태에서 원격 제어를 활성화하려면 설정에서 설치를 클릭하세요.", + "de": "Sie werden nicht erneut erinnert. Um die Fernsteuerung später bei gesperrtem Gerät zu aktivieren, klicken Sie in den Einstellungen auf „Installieren“.", + "fr": "Vous ne recevrez plus de rappel. Pour activer le contrôle à distance tout en étant verrouillé ultérieurement, cliquez sur Installer dans Paramètres.", + "es": "No se te recordará más. Para habilitar el control remoto mientras está bloqueado más tarde, haga clic en Instalar en Configuración.", + "pt-BR": "Você não será lembrado novamente. Para ativar o controle remoto enquanto estiver bloqueado posteriormente, clique em Instalar em Configurações." + }, + "已从通知断开远程连接": { + "zh-Hans": "已从通知断开远程连接", + "en": "Remote connection disconnected from notification", + "zh-Hant": "已從通知斷開遠端連線", + "ja": "通知によりリモート接続が切断されました", + "ko": "알림으로 인해 원격 연결이 끊어졌습니다.", + "de": "Remote-Verbindung wegen Benachrichtigung getrennt", + "fr": "Connexion à distance déconnectée de la notification", + "es": "Conexión remota desconectada de la notificación", + "pt-BR": "Conexão remota desconectada da notificação", + "ru": "Удаленное соединение отключено из-за уведомления" + }, + "已保存密码": { + "zh-Hans": "已保存密码", + "en": "Password saved", + "ru": "Пароль сохранён", + "zh-Hant": "已儲存密碼", + "ja": "パスワード保存済み", + "ko": "비밀번호 저장됨", + "de": "Passwort gespeichert", + "fr": "Mot de passe enregistré", + "es": "Contraseña guardada", + "pt-BR": "Senha salva" + }, + "已保存密码无法读取,请重新输入": { + "zh-Hans": "已保存密码无法读取,请重新输入", + "en": "The saved password cannot be read, please re-enter it.", + "zh-Hant": "已儲存密碼無法讀取,請重新輸入", + "ja": "保存したパスワードが読み取れないため、再入力してください。", + "ko": "저장된 비밀번호를 읽을 수 없습니다. 다시 입력해 주세요.", + "de": "Das gespeicherte Passwort kann nicht gelesen werden, bitte geben Sie es erneut ein.", + "fr": "Le mot de passe enregistré ne peut pas être lu, veuillez le saisir à nouveau.", + "es": "La contraseña guardada no se puede leer; vuelva a ingresarla.", + "pt-BR": "A senha salva não pode ser lida, digite-a novamente.", + "ru": "Сохраненный пароль невозможно прочитать, введите его еще раз." + }, + "已保存并生效。": { + "zh-Hans": "已保存并生效。", + "en": "Saved and applied.", + "ru": "Сохранено и применено.", + "zh-Hant": "已儲存並生效。", + "ja": "保存して適用しました。", + "ko": "저장하고 적용했습니다.", + "de": "Gespeichert und angewendet.", + "fr": "Enregistré et appliqué.", + "es": "Guardado y aplicado.", + "pt-BR": "Salvo e aplicado." + }, + "已保存的密码未能保留,请重新输入一次": { + "zh-Hans": "已保存的密码未能保留,请重新输入一次", + "en": "The saved password cannot be retained, please re-enter it.", + "zh-Hant": "已儲存的密碼未能保留,請重新輸入一次", + "ja": "保存したパスワードは保持できませんので、再度入力してください。", + "ko": "저장된 비밀번호는 보관할 수 없으므로 다시 입력해 주세요.", + "de": "Das gespeicherte Passwort kann nicht beibehalten werden, bitte geben Sie es erneut ein.", + "fr": "Le mot de passe enregistré ne peut pas être conservé, veuillez le saisir à nouveau.", + "es": "La contraseña guardada no se puede conservar; vuelva a ingresarla.", + "pt-BR": "A senha salva não pode ser mantida, digite-a novamente.", + "ru": "Сохраненный пароль невозможно сохранить, введите его еще раз." + }, + "已保存,在下次图形桌面登录时生效。": { + "zh-Hans": "已保存,在下次图形桌面登录时生效。", + "en": "Saved; applies at the next graphical desktop login.", + "ru": "Сохранено. Будет применено при следующем входе в графический сеанс.", + "zh-Hant": "已儲存,在下次圖形桌面登入時生效。", + "ja": "保存されました。次回のグラフィカル デスクトップ ログイン時に適用されます。", + "ko": "저장되었습니다. 다음 그래픽 데스크탑 로그인 시 적용됩니다.", + "de": "Gespeichert; gilt beim nächsten grafischen Desktop-Login.", + "fr": "Enregistré ; s'applique à la prochaine connexion au bureau graphique.", + "es": "Guardado; se aplica en el siguiente inicio de sesión del escritorio gráfico.", + "pt-BR": "Salvo; aplica-se no próximo login da área de trabalho gráfica." + }, + "已保存,将用于后续接收的文件。": { + "zh-Hans": "已保存,将用于后续接收的文件。", + "en": "Saved; applies to subsequently received files.", + "ru": "Сохранено. Будет применено к следующим получаемым файлам.", + "zh-Hant": "已儲存,將用於後續接收的檔案。", + "ja": "保存されました。以降に受信したファイルに適用されます。", + "ko": "저장되었습니다. 이후에 수신된 파일에 적용됩니다.", + "de": "Gespeichert; gilt für später empfangene Dateien.", + "fr": "Enregistré ; s'applique aux fichiers reçus ultérieurement.", + "es": "Guardado; se aplica a los archivos recibidos posteriormente.", + "pt-BR": "Salvo; aplica-se a arquivos recebidos posteriormente." + }, + "已保存,将用于后续连接。": { + "zh-Hans": "已保存,将用于后续连接。", + "en": "Saved; applies to subsequent connections.", + "ru": "Сохранено. Будет применено к следующим подключениям.", + "zh-Hant": "已儲存,將用於後續連線。", + "ja": "保存されました。後続の接続に適用されます。", + "ko": "저장되었습니다. 후속 연결에 적용됩니다.", + "de": "Gespeichert; gilt für spätere Verbindungen.", + "fr": "Enregistré ; s’applique aux connexions ultérieures.", + "es": "Guardado; se aplica a las conexiones posteriores.", + "pt-BR": "Salvo; aplica-se a conexões subsequentes." + }, + "已保存,普通模式重启后生效;无头控制台仍保持前台运行。": { + "zh-Hans": "已保存,普通模式重启后生效;无头控制台仍保持前台运行。", + "en": "Saved for the next normal-mode start; the headless console stays in the foreground.", + "ru": "Сохранено для следующего запуска в обычном режиме. Консоль без графического интерфейса остаётся на переднем плане.", + "zh-Hant": "已儲存,普通模式重啟後生效;無頭控制檯仍保持前臺執行。", + "ja": "次回の通常モードの開始のために保存されます。ヘッドレス コンソールはフォアグラウンドに残ります。", + "ko": "다음 일반 모드 시작을 위해 저장되었습니다. 헤드리스 콘솔은 전경에 유지됩니다.", + "de": "Wird für den nächsten Start im Normalmodus gespeichert; Die Headless-Konsole bleibt im Vordergrund.", + "fr": "Enregistré pour le prochain démarrage en mode normal ; la console sans tête reste au premier plan.", + "es": "Guardado para el próximo inicio del modo normal; la consola sin cabeza permanece en primer plano.", + "pt-BR": "Salvo para a próxima inicialização no modo normal; o console sem cabeça permanece em primeiro plano." + }, + "已保存,正在重新连接服务器。": { + "zh-Hans": "已保存,正在重新连接服务器。", + "en": "Saved; reconnecting to the server.", + "ru": "Сохранено. Повторное подключение к серверу.", + "zh-Hant": "已儲存,正在重新連線伺服器。", + "ja": "保存されました。サーバーに再接続しています。", + "ko": "저장되었습니다. 서버에 다시 연결하는 중입니다.", + "de": "Gespeichert; erneute Verbindung zum Server herstellen.", + "fr": "Enregistré ; reconnexion au serveur.", + "es": "Guardado; reconectándose al servidor.", + "pt-BR": "Salvo; reconectando-se ao servidor." + }, + "已加密": { + "zh-Hans": "已加密", + "en": "Encrypted", + "ru": "Зашифровано", + "zh-Hant": "已加密", + "ja": "暗号化", + "ko": "암호화됨", + "de": "Verschlüsselt", + "fr": "Crypté", + "es": "Encriptado", + "pt-BR": "Criptografado" + }, + "已勾选": { + "zh-Hans": "已勾选", + "en": "Checked", + "zh-Hant": "已勾選", + "ja": "チェックあり", + "ko": "확인됨", + "de": "Geprüft", + "fr": "Vérifié", + "es": "Comprobado", + "pt-BR": "Verificado", + "ru": "Проверено" + }, + "已发送 Ctrl+Alt+Del": { + "zh-Hans": "已发送 Ctrl+Alt+Del", + "en": "Ctrl+Alt+Del sent", + "zh-Hant": "已傳送 Ctrl+Alt+Del", + "ja": "Ctrl+Alt+Delを送信しました", + "ko": "Ctrl+Alt+Del가 전송되었습니다.", + "de": "Ctrl+Alt+Del gesendet", + "fr": "Ctrl+Alt+Del envoyé", + "es": "Ctrl+Alt+Del enviado", + "pt-BR": "Ctrl+Alt+Del enviado", + "ru": "Ctrl+Alt+Del отправлено" + }, + "已发送本机剪贴板": { + "zh-Hans": "已发送本机剪贴板", + "en": "Local clipboard sent", + "ru": "Локальный буфер отправлен", + "zh-Hant": "已傳送本機剪貼簿", + "ja": "ローカルのクリップボードを送信しました", + "ko": "로컬 클립보드 전송됨", + "de": "Lokale Zwischenablage gesendet", + "fr": "Presse-papiers local envoyé", + "es": "Portapapeles local enviado", + "pt-BR": "Área de transferência local enviada" + }, + "已发送,请在远端粘贴": { + "zh-Hans": "已发送,请在远端粘贴", + "en": "Sent, please paste at the remote end", + "zh-Hant": "已傳送,請在遠端貼上", + "ja": "送信されました。リモート側で貼り付けてください", + "ko": "보냈습니다. 원격 끝에 붙여넣으세요.", + "de": "Gesendet, bitte am entfernten Ende einfügen", + "fr": "Envoyé, veuillez coller à l'extrémité distante", + "es": "Enviado, péguelo en el extremo remoto", + "pt-BR": "Enviado, cole no terminal remoto", + "ru": "Отправлено, вставьте на удаленном конце" + }, + "已取消": { + "zh-Hans": "已取消", + "en": "Cancelled", + "ru": "Отменено", + "zh-Hant": "已取消", + "ja": "キャンセル", + "ko": "취소됨", + "de": "Abgesagt", + "fr": "Annulé", + "es": "Cancelado", + "pt-BR": "Cancelado" + }, + "已取消修改。": { + "zh-Hans": "已取消修改。", + "en": "Change cancelled.", + "ru": "Изменение отменено.", + "zh-Hant": "已取消修改。", + "ja": "変更はキャンセルされました。", + "ko": "변경이 취소되었습니다.", + "de": "Änderung abgebrochen.", + "fr": "Modification annulée.", + "es": "Cambio cancelado.", + "pt-BR": "Alteração cancelada." + }, + "已启用后台保活,切换应用可继续保持连接": { + "zh-Hans": "已启用后台保活,切换应用可继续保持连接", + "en": "Background keep-alive is enabled, switching applications can continue to maintain the connection", + "zh-Hant": "已啟用後臺保活,切換應用可繼續保持連線", + "ja": "バックグラウンドキープアライブが有効になり、アプリケーションを切り替えて接続を維持し続けることができます。", + "ko": "백그라운드 연결 유지가 활성화되어 전환 애플리케이션이 계속 연결을 유지할 수 있습니다.", + "de": "Hintergrund-Keep-Alive ist aktiviert, wechselnde Anwendungen können die Verbindung weiterhin aufrechterhalten", + "fr": "Le maintien de l'activité en arrière-plan est activé, les applications de commutation peuvent continuer à maintenir la connexion.", + "es": "Mantener vivo en segundo plano está habilitado, cambiar de aplicación puede continuar manteniendo la conexión", + "pt-BR": "O keep-alive em segundo plano está habilitado, a troca de aplicativos pode continuar a manter a conexão", + "ru": "Фоновая поддержка активности включена, переключающиеся приложения могут продолжать поддерживать соединение." + }, + "已启用后台保活,可从连接通知返回或断开": { + "zh-Hans": "已启用后台保活,可从连接通知返回或断开", + "en": "Background keepalive enabled to return or disconnect from connection notifications", + "zh-Hant": "已啟用後臺保活,可從連線通知返回或斷開", + "ja": "バックグラウンドキープアライブを有効にして、接続通知を返すか接続を切断することができます", + "ko": "연결 알림에서 돌아가거나 연결을 끊기 위해 백그라운드 연결 유지가 활성화되었습니다.", + "de": "Hintergrund-Keepalive aktiviert, um Verbindungsbenachrichtigungen zurückzugeben oder zu trennen", + "fr": "Keepalive en arrière-plan activé pour revenir ou se déconnecter des notifications de connexion", + "es": "Keepalive en segundo plano habilitado para regresar o desconectarse de las notificaciones de conexión", + "pt-BR": "Manutenção de atividade em segundo plano habilitada para retornar ou desconectar das notificações de conexão", + "ru": "Фоновая поддержка активности включена для возврата или отключения от уведомлений о соединении." + }, + "已复制到剪贴板": { + "zh-Hans": "已复制到剪贴板", + "en": "Copied to clipboard", + "ru": "Скопировано в буфер обмена", + "zh-Hant": "已複製到剪貼簿", + "ja": "クリップボードにコピーされました", + "ko": "클립보드에 복사됨", + "de": "In die Zwischenablage kopiert", + "fr": "Copié dans le presse-papiers", + "es": "Copiado al portapapeles", + "pt-BR": "Copiado para a área de transferência" + }, + "已复制远端文本": { + "zh-Hans": "已复制远端文本", + "en": "Remote text copied", + "zh-Hant": "已複製遠端文字", + "ja": "リモートテキストをコピーしました", + "ko": "원격 텍스트 복사됨", + "de": "Remote-Text kopiert", + "fr": "Texte distant copié", + "es": "Texto remoto copiado", + "pt-BR": "Texto remoto copiado", + "ru": "Удаленный текст скопирован." + }, + "已安装": { + "zh-Hans": "已安装", + "en": "Installed", + "ru": "Установлена", + "zh-Hant": "已安裝", + "ja": "インストール済み", + "ko": "설치됨", + "de": "Installiert", + "fr": "Installé", + "es": "Instalado", + "pt-BR": "Instalado" + }, + "已完成": { + "zh-Hans": "已完成", + "en": "Completed", + "ru": "Завершено", + "zh-Hant": "已完成", + "ja": "完成", + "ko": "완료됨", + "de": "Abgeschlossen", + "fr": "Terminé", + "es": "Completado", + "pt-BR": "Concluído" + }, + "已开启": { + "zh-Hans": "已开启", + "en": "Enabled", + "ru": "Включён", + "zh-Hant": "已開啟", + "ja": "有効", + "ko": "활성화됨", + "de": "Aktiviert", + "fr": "Activé", + "es": "Habilitado", + "pt-BR": "Habilitado" + }, + "已授权": { + "zh-Hans": "已授权", + "en": "Granted", + "ru": "Разрешено", + "zh-Hant": "已授權", + "ja": "認められる", + "ko": "승인됨", + "de": "Zugegeben", + "fr": "Accordé", + "es": "Concedido", + "pt-BR": "Concedido" + }, + "已接收 %1$@": { + "zh-Hans": "已接收 %1$@", + "en": "Received %1$@", + "zh-Hant": "已接收 %1$@", + "ja": "%1$@を受け取りました", + "ko": "%1$@수신됨", + "de": "%1$@ erhalten", + "fr": "Reçu %1$@", + "es": "Recibido %1$@", + "pt-BR": "%1$@ recebido", + "ru": "Получено %1$@" + }, + "已接收远端剪贴板": { + "zh-Hans": "已接收远端剪贴板", + "en": "Remote clipboard received", + "zh-Hant": "已接收遠端剪貼簿", + "ja": "リモートクリップボードを受信しました", + "ko": "원격 클립보드 수신됨", + "de": "Remote-Zwischenablage empfangen", + "fr": "Presse-papiers distant reçu", + "es": "Portapapeles remoto recibido", + "pt-BR": "Área de transferência remota recebida", + "ru": "Получен удаленный буфер обмена." + }, + "已提交密码修改,正在等待服务器确认……": { + "zh-Hans": "已提交密码修改,正在等待服务器确认……", + "en": "Password change submitted; waiting for server confirmation...", + "ru": "Запрос смены пароля отправлен. Ожидание подтверждения...", + "zh-Hant": "已提交密碼修改,正在等待伺服器確認……", + "ja": "パスワード変更が送信されました。サーバーの確認を待っています...", + "ko": "비밀번호 변경이 제출되었습니다. 서버 확인을 기다리는 중...", + "de": "Passwortänderung übermittelt; warte auf Serverbestätigung...", + "fr": "Modification du mot de passe soumise ; en attente de confirmation du serveur...", + "es": "Cambio de contraseña enviado; esperando confirmación del servidor...", + "pt-BR": "Alteração de senha enviada; aguardando confirmação do servidor..." + }, + "已是最新版本": { + "zh-Hans": "已是最新版本", + "en": "You're up to date", + "ru": "Установлена последняя версия", + "zh-Hant": "已是最新版本", + "ja": "最新情報を入手しました", + "ko": "최신 상태입니다", + "de": "Du bist auf dem Laufenden", + "fr": "Vous êtes à jour", + "es": "Estás al día", + "pt-BR": "Você está atualizado" + }, + "已添加": { + "zh-Hans": "已添加", + "en": "Added", + "ru": "Добавлено", + "zh-Hant": "已新增", + "ja": "追加", + "ko": "추가됨", + "de": "Hinzugefügt", + "fr": "Ajouté", + "es": "Añadido", + "pt-BR": "Adicionado" + }, + "已清除预览": { + "zh-Hans": "已清除预览", + "en": "Preview cleared", + "zh-Hant": "已清除預覽", + "ja": "プレビューをクリアしました", + "ko": "미리보기가 삭제되었습니다.", + "de": "Vorschau gelöscht", + "fr": "Aperçu effacé", + "es": "Vista previa borrada", + "pt-BR": "Visualização apagada", + "ru": "Предварительный просмотр отключен." + }, + "已读": { + "zh-Hans": "已读", + "en": "Read", + "ru": "Прочитано", + "zh-Hant": "已讀", + "ja": "読む", + "ko": "읽기", + "de": "Lesen", + "fr": "Lire", + "es": "Leer", + "pt-BR": "Leia" + }, + "已读或删除状态保存失败,请重试": { + "zh-Hans": "已读或删除状态保存失败,请重试", + "en": "Failed to save read or deleted status, please try again", + "zh-Hant": "已讀或刪除狀態儲存失敗,請重試", + "ja": "既読または削除済みステータスの保存に失敗しました。もう一度お試しください。", + "ko": "읽은 상태나 삭제된 상태를 저장하지 못했습니다. 다시 시도해 주세요.", + "de": "Der Lese- oder Löschstatus konnte nicht gespeichert werden. Bitte versuchen Sie es erneut", + "fr": "Échec de l'enregistrement du statut lu ou supprimé, veuillez réessayer", + "es": "No se pudo guardar el estado leído o eliminado, inténtelo de nuevo", + "pt-BR": "Falha ao salvar o status de leitura ou exclusão. Tente novamente", + "ru": "Не удалось сохранить статус прочтения или удаления. Повторите попытку." + }, + "已连接": { + "zh-Hans": "已连接", + "en": "Connected", + "ru": "Подключено", + "zh-Hant": "已連線", + "ja": "接続されました", + "ko": "연결됨", + "de": "Verbunden", + "fr": "Connecté", + "es": "Conectado", + "pt-BR": "Conectado" + }, + "已连接 ": { + "zh-Hans": "已连接 ", + "en": "Connected ", + "zh-Hant": "已連線 ", + "ja": "接続されました ", + "ko": "연결됨 ", + "de": "Verbunden ", + "fr": "Connecté ", + "es": "Conectado ", + "pt-BR": "Conectado ", + "ru": "Подключено " + }, + "已连接服务器": { + "zh-Hans": "已连接服务器", + "en": "Connected to server", + "ru": "Подключено к серверу", + "zh-Hant": "已連線伺服器", + "ja": "サーバーに接続しました", + "ko": "서버에 연결됨", + "de": "Mit Server verbunden", + "fr": "Connecté au serveur", + "es": "Conectado al servidor", + "pt-BR": "Conectado ao servidor" + }, + "已连接设备 ": { + "zh-Hans": "已连接设备 ", + "en": "Connected devices ", + "ru": "Подключённые устройства ", + "zh-Hant": "已連線裝置 ", + "ja": "接続機器 ", + "ko": "연결된 장치 ", + "de": "Angeschlossene Geräte ", + "fr": "Appareils connectés ", + "es": "Dispositivos conectados ", + "pt-BR": "Dispositivos conectados " + }, + "已选 ": { + "zh-Hans": "已选 ", + "en": "Selected ", + "ru": "Выбрано ", + "zh-Hant": "已選 ", + "ja": "選択済み ", + "ko": "선택됨 ", + "de": "Ausgewählt ", + "fr": "Sélectionné ", + "es": "Seleccionado ", + "pt-BR": "Selecionado " + }, + "帧率": { + "zh-Hans": "帧率", + "en": "Frame rate", + "ru": "Частота кадров", + "zh-Hant": "幀率", + "ja": "フレームレート", + "ko": "프레임 속도", + "de": "Bildrate", + "fr": "Fréquence d'images", + "es": "Velocidad de fotogramas", + "pt-BR": "Taxa de quadros" + }, + "帧率优先": { + "zh-Hans": "帧率优先", + "en": "Smooth", + "ru": "Плавность", + "zh-Hant": "影格率優先", + "ja": "滑らかさ", + "ko": "부드러움", + "de": "Flüssig", + "fr": "Fluidité", + "es": "Fluidez", + "pt-BR": "Fluidez" + }, + "常规": { + "zh-Hans": "常规", + "en": "General", + "ru": "Общие", + "zh-Hant": "常規", + "ja": "一般", + "ko": "일반", + "de": "Allgemein", + "fr": "Général", + "es": "Generalidades", + "pt-BR": "Geral" + }, + "平衡": { + "zh-Hans": "平衡", + "en": "Balanced", + "ru": "Баланс", + "zh-Hant": "平衡", + "ja": "バランス", + "ko": "균형", + "de": "Balance", + "fr": "Équilibré", + "es": "Equilibrado", + "pt-BR": "Equilibrado" + }, + "应用中的许可文件缺失或损坏,请重新安装应用。": { + "zh-Hans": "应用中的许可文件缺失或损坏,请重新安装应用。", + "en": "The license file in the application is missing or damaged, please reinstall the application.", + "zh-Hant": "應用中的許可檔案缺失或損壞,請重新安裝應用。", + "ja": "アプリケーション内のライセンス ファイルが見つからないか破損しています。アプリケーションを再インストールしてください。", + "ko": "애플리케이션의 라이센스 파일이 없거나 손상되었습니다. 애플리케이션을 다시 설치하십시오.", + "de": "Die Lizenzdatei in der Anwendung fehlt oder ist beschädigt. Bitte installieren Sie die Anwendung neu.", + "fr": "Le fichier de licence dans l'application est manquant ou endommagé, veuillez réinstaller l'application.", + "es": "El archivo de licencia de la aplicación falta o está dañado; reinstale la aplicación.", + "pt-BR": "O arquivo de licença do aplicativo está ausente ou danificado. Reinstale o aplicativo.", + "ru": "Файл лицензии в приложении отсутствует или поврежден, переустановите приложение." + }, + "建立连接后,网络和画面信息将在此显示": { + "zh-Hans": "建立连接后,网络和画面信息将在此显示", + "en": "Network and video details appear here once connected", + "ru": "После подключения здесь появятся данные сети и видео", + "zh-Hant": "建立連線後,網路和畫面資訊將在此顯示", + "ja": "接続すると、ネットワークとビデオの詳細がここに表示されます", + "ko": "연결되면 여기에 네트워크 및 비디오 세부정보가 표시됩니다.", + "de": "Sobald die Verbindung hergestellt ist, werden hier Netzwerk- und Videodetails angezeigt", + "fr": "Les détails du réseau et de la vidéo apparaissent ici une fois connectés", + "es": "Los detalles de red y video aparecen aquí una vez conectado", + "pt-BR": "Os detalhes da rede e do vídeo aparecem aqui quando conectado" + }, + "建议使用 X11(Xorg)": { + "zh-Hans": "建议使用 X11(Xorg)", + "en": "X11 (Xorg) is recommended", + "ru": "Рекомендуем X11 (Xorg)", + "zh-Hant": "建議使用 X11(Xorg)", + "ja": "X11(Xorg)を推奨", + "ko": "X11(Xorg)을 권장합니다.", + "de": "X11 (Xorg) wird empfohlen", + "fr": "X11 (Xorg) est recommandé", + "es": "Se recomienda X11 (Xorg)", + "pt-BR": "X11 (Xorg) é recomendado" + }, + "建议升级被控端": { + "zh-Hans": "建议升级被控端", + "en": "Remote update recommended", + "ru": "Рекомендуем обновить удалённое устройство", + "zh-Hant": "建議升級被控端", + "ja": "リモートアップデートを推奨", + "ko": "원격 업데이트 권장", + "de": "Remote-Update empfohlen", + "fr": "Mise à jour à distance recommandée", + "es": "Se recomienda actualización remota", + "pt-BR": "Atualização remota recomendada" + }, + "开发版本包含尚未发布的修改,以下链接为基础版本源码。": { + "zh-Hans": "开发版本包含尚未发布的修改,以下链接为基础版本源码。", + "en": "The development version contains modifications that have not yet been released. The following link is the source code of the basic version.", + "zh-Hant": "開發版本包含尚未釋出的修改,以下連結為基礎版本原始碼。", + "ja": "開発バージョンには、まだリリースされていない修正が含まれています。以下のリンクは基本バージョンのソースコードです。", + "ko": "개발 버전에는 아직 출시되지 않은 수정 사항이 포함되어 있습니다. 다음 링크는 기본 버전의 소스 코드입니다.", + "de": "Die Entwicklungsversion enthält Änderungen, die noch nicht veröffentlicht wurden. Der folgende Link ist der Quellcode der Basisversion.", + "fr": "La version de développement contient des modifications qui n'ont pas encore été publiées. Le lien suivant est le code source de la version de base.", + "es": "La versión de desarrollo contiene modificaciones que aún no han sido publicadas. El siguiente enlace es el código fuente de la versión básica.", + "pt-BR": "A versão de desenvolvimento contém modificações que ainda não foram lançadas. O link a seguir é o código fonte da versão básica.", + "ru": "Версия для разработки содержит модификации, которые еще не были выпущены. По следующей ссылке приведен исходный код базовой версии." + }, + "开启": { + "zh-Hans": "开启", + "en": "Turn on", + "zh-Hant": "開啟", + "ja": "オンにする", + "ko": "켜다", + "de": "Einschalten", + "fr": "Allumer", + "es": "Encender", + "pt-BR": "Ligar", + "ru": "Включить" + }, + "开启保存": { + "zh-Hans": "开启保存", + "en": "Enable saving", + "ru": "Включить сохранение", + "zh-Hant": "啟用儲存", + "ja": "保存を有効にする", + "ko": "저장 사용", + "de": "Speichern aktivieren", + "fr": "Activer l’enregistrement", + "es": "Activar guardado", + "pt-BR": "Ativar salvamento" + }, + "开启群控": { + "zh-Hans": "开启群控", + "en": "Group control", + "ru": "Групп. ввод", + "zh-Hant": "開啟群控", + "ja": "グループ制御", + "ko": "그룹 제어", + "de": "Gruppenkontrolle", + "fr": "Contrôle de groupe", + "es": "Control de grupo", + "pt-BR": "Controle de grupo" + }, + "开启隐私屏": { + "zh-Hans": "开启隐私屏", + "en": "Enable privacy screen", + "ru": "Включить приватный экран", + "zh-Hant": "開啟隱私屏", + "ja": "プライバシー画面を有効にする", + "ko": "개인 정보 보호 화면 활성화", + "de": "Privatsphärenschutz aktivieren", + "fr": "Activer l'écran de confidentialité", + "es": "Habilitar pantalla de privacidad", + "pt-BR": "Habilitar tela de privacidade" + }, + "开机自启": { + "zh-Hans": "开机自启", + "en": "Auto Start", + "ru": "Автозапуск", + "zh-Hant": "開機自啟", + "ja": "オートスタート", + "ko": "자동 시작", + "de": "Autostart", + "fr": "Démarrage automatique", + "es": "Inicio automático", + "pt-BR": "Início automático" + }, + "开源组件": { + "zh-Hans": "开源组件", + "en": "Open-source components", + "ru": "Компоненты с открытым кодом", + "zh-Hant": "開源元件", + "ja": "オープンソースコンポーネント", + "ko": "오픈 소스 구성 요소", + "de": "Open-Source-Komponenten", + "fr": "Composants open source", + "es": "Componentes de código abierto", + "pt-BR": "Componentes de código aberto" + }, + "开源软件权利说明": { + "zh-Hans": "开源软件权利说明", + "en": "Open source software rights description", + "zh-Hant": "開源軟體權利說明", + "ja": "オープンソース ソフトウェアの権利の説明", + "ko": "오픈소스 소프트웨어 권리 설명", + "de": "Beschreibung der Open-Source-Softwarerechte", + "fr": "Description des droits sur les logiciels open source", + "es": "Descripción de los derechos del software de código abierto", + "pt-BR": "Descrição dos direitos de software de código aberto", + "ru": "Описание прав на программное обеспечение с открытым исходным кодом." + }, + "强制中继连接": { + "zh-Hans": "强制中继连接", + "en": "Force relay connection", + "ru": "Только через ретранслятор", + "zh-Hant": "強制中繼連線", + "ja": "強制リレー接続", + "ko": "강제 릴레이 연결", + "de": "Relaisverbindung erzwingen", + "fr": "Forcer la connexion du relais", + "es": "Conexión del relé de fuerza", + "pt-BR": "Forçar conexão do relé" + }, + "当前仍需要安全桌面专用采集/输入": { + "zh-Hans": "当前仍需要安全桌面专用采集/输入", + "en": "Secure desktop capture/input is still required", + "ru": "По-прежнему нужен отдельный захват/ввод для защищенного рабочего стола", + "zh-Hant": "當前仍需要安全桌面專用採集/輸入", + "ja": "安全なデスクトップ キャプチャ/入力が引き続き必要です", + "ko": "안전한 데스크톱 캡처/입력이 여전히 필요합니다.", + "de": "Eine sichere Desktop-Erfassung/-Eingabe ist weiterhin erforderlich", + "fr": "La capture/saisie sécurisée du bureau est toujours requise", + "es": "Aún se requiere captura/entrada de escritorio segura", + "pt-BR": "A captura/entrada segura da área de trabalho ainda é necessária" + }, + "当前已是最新版本": { + "zh-Hans": "当前已是最新版本", + "en": "This is currently the latest version", + "zh-Hant": "當前已是最新版本", + "ja": "これが現在の最新バージョンです", + "ko": "현재 최신 버전입니다.", + "de": "Dies ist derzeit die neueste Version", + "fr": "Il s'agit actuellement de la dernière version", + "es": "Esta es actualmente la última versión.", + "pt-BR": "Esta é atualmente a versão mais recente", + "ru": "На данный момент это последняя версия." + }, + "当前网络路径不支持 IP 连接,请检查双方的局域网连接。": { + "zh-Hans": "当前网络路径不支持 IP 连接,请检查双方的局域网连接。", + "en": "This network path does not support IP connections. Check both devices' LAN connections.", + "ru": "Этот сетевой маршрут не поддерживает IP-подключения. Проверьте подключения обоих устройств к LAN.", + "zh-Hant": "當前網路路徑不支援 IP 連線,請檢查雙方的區域網連線。", + "ja": "このネットワーク パスは IP 接続をサポートしていません。両方のデバイスの LAN 接続を確認します。", + "ko": "이 네트워크 경로는 IP 연결을 지원하지 않습니다. 두 장치의 LAN 연결을 확인하십시오.", + "de": "Dieser Netzwerkpfad unterstützt keine IP-Verbindungen. Überprüfen Sie die LAN-Verbindungen beider Geräte.", + "fr": "Ce chemin réseau ne prend pas en charge les connexions IP. Vérifiez les connexions LAN des deux appareils.", + "es": "Esta ruta de red no admite conexiones IP. Verifique las conexiones LAN de ambos dispositivos.", + "pt-BR": "Este caminho de rede não suporta conexões IP. Verifique as conexões LAN de ambos os dispositivos." + }, + "当前设备不支持开机自启动。": { + "zh-Hans": "当前设备不支持开机自启动。", + "en": "This device does not support auto start.", + "ru": "Это устройство не поддерживает автозапуск.", + "zh-Hant": "當前裝置不支援開機自啟動。", + "ja": "このデバイスは自動起動をサポートしていません。", + "ko": "이 장치는 자동 시작을 지원하지 않습니다.", + "de": "Dieses Gerät unterstützt keinen automatischen Start.", + "fr": "Cet appareil ne prend pas en charge le démarrage automatique.", + "es": "Este dispositivo no admite el inicio automático.", + "pt-BR": "Este dispositivo não suporta inicialização automática." + }, + "当前远程控制会话将结束。": { + "zh-Hans": "当前远程控制会话将结束。", + "en": "The current remote session will end.", + "ru": "Текущий сеанс удалённого управления будет завершён.", + "zh-Hant": "當前遠端控制會話將結束。", + "ja": "現在のリモートセッションが終了します。", + "ko": "현재 원격 세션이 종료됩니다.", + "de": "Die aktuelle Remote-Sitzung wird beendet.", + "fr": "La session à distance en cours se terminera.", + "es": "La sesión remota actual finalizará.", + "pt-BR": "A sessão remota atual será encerrada." + }, + "当前远端不支持直接输入此文本,请使用支持文本输入的被控端版本,或通过剪贴板发送": { + "zh-Hans": "当前远端不支持直接输入此文本,请使用支持文本输入的被控端版本,或通过剪贴板发送", + "en": "Currently, the remote end does not support direct input of this text. Please use a version of the controlled end that supports text input, or send it through the clipboard.", + "zh-Hant": "當前遠端不支援直接輸入此文字,請使用支援文字輸入的被控端版本,或透過剪貼簿傳送", + "ja": "現在、リモート エンドはこのテキストの直接入力をサポートしていません。テキスト入力をサポートするバージョンのコントロール エンドを使用するか、クリップボード経由で送信してください。", + "ko": "현재 원격측에서는 이 텍스트를 직접 입력하는 기능을 지원하지 않습니다. 텍스트 입력을 지원하는 제어된 버전을 사용하거나 클립보드를 통해 보내주세요.", + "de": "Derzeit unterstützt die Gegenstelle keine direkte Eingabe dieses Textes. Bitte verwenden Sie eine Version des gesteuerten Endes, die die Texteingabe unterstützt, oder senden Sie sie über die Zwischenablage.", + "fr": "Actuellement, l'extrémité distante ne prend pas en charge la saisie directe de ce texte. Veuillez utiliser une version de l'extrémité contrôlée qui prend en charge la saisie de texte ou envoyez-la via le presse-papiers.", + "es": "Actualmente, el extremo remoto no admite la entrada directa de este texto. Utilice una versión del extremo controlado que admita la entrada de texto o envíela a través del portapapeles.", + "pt-BR": "Atualmente, a extremidade remota não suporta a entrada direta deste texto. Use uma versão do final controlado que suporte entrada de texto ou envie-o através da área de transferência.", + "ru": "В настоящее время удаленный конец не поддерживает прямой ввод этого текста. Пожалуйста, используйте версию управляемого конца, поддерживающую ввод текста, или отправьте его через буфер обмена." + }, + "待添加 ": { + "zh-Hans": "待添加 ", + "en": "To add ", + "ru": "К добавлению ", + "zh-Hant": "待新增 ", + "ja": "追加するには ", + "ko": "추가하려면 ", + "de": "Zum Hinzufügen ", + "fr": "Pour ajouter ", + "es": "Para agregar ", + "pt-BR": "Para adicionar " + }, + "待确认": { + "zh-Hans": "待确认", + "en": "Unknown", + "ru": "Неизвестно", + "zh-Hant": "待確認", + "ja": "不明", + "ko": "알 수 없음", + "de": "Unbekannt", + "fr": "Inconnu", + "es": "Desconocido", + "pt-BR": "Desconhecido" + }, + "总计": { + "zh-Hans": "总计", + "en": "Total", + "ru": "Итого", + "zh-Hant": "總計", + "ja": "合計", + "ko": "합계", + "de": "Insgesamt", + "fr": "Total", + "es": "Total", + "pt-BR": "Total" + }, + "成功连接后,这里会显示最近的远程设备。": { + "zh-Hans": "成功连接后,这里会显示最近的远程设备。", + "en": "Upon successful connection, the nearest remote device will be displayed here.", + "zh-Hant": "成功連線後,這裡會顯示最近的遠端裝置。", + "ja": "接続に成功すると、最も近いリモート デバイスがここに表示されます。", + "ko": "성공적으로 연결되면 가장 가까운 원격 장치가 여기에 표시됩니다.", + "de": "Nach erfolgreicher Verbindung wird hier das nächstgelegene Remote-Gerät angezeigt.", + "fr": "Une fois la connexion réussie, l'appareil distant le plus proche sera affiché ici.", + "es": "Tras una conexión exitosa, aquí se mostrará el dispositivo remoto más cercano.", + "pt-BR": "Após a conexão bem-sucedida, o dispositivo remoto mais próximo será exibido aqui.", + "ru": "При успешном подключении здесь будет отображено ближайшее удаленное устройство." + }, + "成功连接后,这里会显示远端桌面的缩略图。": { + "zh-Hans": "成功连接后,这里会显示远端桌面的缩略图。", + "en": "After a successful connection, a thumbnail of the remote desktop will be displayed here.", + "zh-Hant": "成功連線後,這裡會顯示遠端桌面的縮圖。", + "ja": "接続に成功すると、ここにリモート デスクトップのサムネイルが表示されます。", + "ko": "성공적으로 연결되면 원격 데스크톱의 썸네일이 여기에 표시됩니다.", + "de": "Nach erfolgreicher Verbindung wird hier eine Miniaturansicht des Remote-Desktops angezeigt.", + "fr": "Après une connexion réussie, une vignette du bureau distant s'affichera ici.", + "es": "Después de una conexión exitosa, aquí se mostrará una miniatura del escritorio remoto.", + "pt-BR": "Após uma conexão bem-sucedida, uma miniatura da área de trabalho remota será exibida aqui.", + "ru": "После успешного подключения здесь отобразится миниатюра удаленного рабочего стола." + }, + "我已阅读并同意《隐私政策》": { + "zh-Hans": "我已阅读并同意《隐私政策》", + "en": "I have read and agreed to the Privacy Policy", + "zh-Hant": "我已閱讀並同意《隱私政策》", + "ja": "プライバシーポリシーを読んで同意します", + "ko": "개인정보 보호정책을 읽었으며 이에 동의합니다.", + "de": "Ich habe die Datenschutzerklärung gelesen und bin damit einverstanden", + "fr": "J'ai lu et accepté la politique de confidentialité", + "es": "He leído y acepto la Política de Privacidad", + "pt-BR": "Li e concordo com a Política de Privacidade", + "ru": "Я прочитал и согласен с Политикой конфиденциальности." + }, + "我已阅读并同意隐私政策": { + "zh-Hans": "我已阅读并同意隐私政策", + "en": "I have read and agree to the privacy policy", + "zh-Hant": "我已閱讀並同意隱私政策", + "ja": "プライバシーポリシーを読んで同意します", + "ko": "개인정보취급방침을 읽었으며 이에 동의합니다.", + "de": "Ich habe die Datenschutzbestimmungen gelesen und stimme ihnen zu", + "fr": "J'ai lu et j'accepte la politique de confidentialité", + "es": "He leído y acepto la política de privacidad", + "pt-BR": "Li e concordo com a política de privacidade", + "ru": "Я прочитал и согласен с политикой конфиденциальности." + }, + "我知道了": { + "zh-Hans": "我知道了", + "en": "Got it", + "ru": "Понятно", + "zh-Hant": "我知道了", + "ja": "分かりました", + "ko": "알겠습니다", + "de": "Verstanden", + "fr": "Compris", + "es": "Entendido", + "pt-BR": "Entendi" + }, + "或在主界面选择本机 IP。": { + "zh-Hans": "或在主界面选择本机 IP。", + "en": "or select a local IP on the main screen.", + "ru": "или выберите локальный IP в главном окне.", + "zh-Hant": "或在主介面選擇本機 IP。", + "ja": "またはメイン画面でローカル IP を選択します。", + "ko": "또는 메인 화면에서 로컬 IP를 선택하세요.", + "de": "oder wählen Sie im Hauptbildschirm eine lokale IP aus.", + "fr": "ou sélectionnez une adresse IP locale sur l'écran principal.", + "es": "o seleccione una IP local en la pantalla principal.", + "pt-BR": "ou selecione um IP local na tela principal." + }, + "所选文件(无法读取或空间不足)": { + "zh-Hans": "所选文件(无法读取或空间不足)", + "en": "Selected file (cannot be read or insufficient space)", + "zh-Hant": "所選檔案(無法讀取或空間不足)", + "ja": "選択したファイル(読み込み不可、または容量不足)", + "ko": "선택한 파일(읽을 수 없거나 공간이 부족함)", + "de": "Ausgewählte Datei (kann nicht gelesen werden oder nicht genügend Speicherplatz)", + "fr": "Fichier sélectionné (impossible en lecture ou espace insuffisant)", + "es": "Archivo seleccionado (no se puede leer o no hay suficiente espacio)", + "pt-BR": "Arquivo selecionado (não pode ser lido ou espaço insuficiente)", + "ru": "Выбранный файл (невозможно прочитать или недостаточно места)" + }, + "手动下载": { + "zh-Hans": "手动下载", + "en": "Download manually", + "ru": "Скачать вручную", + "zh-Hant": "手動下載", + "ja": "手動ダウンロード", + "ko": "수동으로 다운로드", + "de": "Manuell herunterladen", + "fr": "Télécharger manuellement", + "es": "Descargar manualmente", + "pt-BR": "Baixe manualmente" + }, + "打开隐私政策": { + "zh-Hans": "打开隐私政策", + "en": "Open privacy policy", + "zh-Hant": "開啟隱私政策", + "ja": "オープンなプライバシーポリシー", + "ko": "공개 개인 정보 보호 정책", + "de": "Datenschutzerklärung öffnen", + "fr": "Ouvrir la politique de confidentialité", + "es": "Abrir política de privacidad", + "pt-BR": "Política de privacidade aberta", + "ru": "Открытая политика конфиденциальности" + }, + "找不到该设备 ID": { + "zh-Hans": "找不到该设备 ID", + "en": "The device ID was not found", + "zh-Hant": "找不到該裝置 ID", + "ja": "デバイスIDが見つかりませんでした", + "ko": "장치 ID를 찾을 수 없습니다", + "de": "Die Geräte-ID wurde nicht gefunden", + "fr": "L'ID de l'appareil n'a pas été trouvé", + "es": "No se encontró el ID del dispositivo", + "pt-BR": "O ID do dispositivo não foi encontrado", + "ru": "Идентификатор устройства не найден." + }, + "拖到另一台设备上": { + "zh-Hans": "拖到另一台设备上", + "en": "Drag onto another device", + "ru": "Перетащите на другое устройство", + "zh-Hant": "拖到另一臺裝置上", + "ja": "別のデバイス上にドラッグします", + "ko": "다른 장치로 드래그", + "de": "Auf ein anderes Gerät ziehen", + "fr": "Faire glisser sur un autre appareil", + "es": "Arrastrar a otro dispositivo", + "pt-BR": "Arraste para outro dispositivo" + }, + "拖动表格分隔线,同步调整所有设备大小": { + "zh-Hans": "拖动表格分隔线,同步调整所有设备大小", + "en": "Drag a table divider to resize all devices", + "ru": "Потяните за разделитель таблицы, чтобы изменить размер всех устройств", + "zh-Hant": "拖動表格分隔線,同步調整所有裝置大小", + "ja": "テーブルの分割線をドラッグして、すべてのデバイスのサイズを変更します", + "ko": "모든 장치의 크기를 조정하려면 표 구분선을 드래그하세요.", + "de": "Ziehen Sie einen Tabellenteiler, um die Größe aller Geräte zu ändern", + "fr": "Faites glisser un séparateur de tableau pour redimensionner tous les appareils", + "es": "Arrastre un divisor de tabla para cambiar el tamaño de todos los dispositivos", + "pt-BR": "Arraste um divisor de mesa para redimensionar todos os dispositivos" + }, + "拖动键盘": { + "zh-Hans": "拖动键盘", + "en": "Drag keyboard", + "zh-Hant": "拖動鍵盤", + "ja": "キーボードをドラッグする", + "ko": "키보드 드래그", + "de": "Tastatur ziehen", + "fr": "Faites glisser le clavier", + "es": "Arrastrar teclado", + "pt-BR": "Arraste o teclado", + "ru": "Перетащите клавиатуру" + }, + "指令发送失败,请重试": { + "zh-Hans": "指令发送失败,请重试", + "en": "Command sending failed, please try again", + "zh-Hant": "指令傳送失敗,請重試", + "ja": "コマンドの送信に失敗しました。もう一度お試しください。", + "ko": "명령 전송에 실패했습니다. 다시 시도해 주세요.", + "de": "Das Senden des Befehls ist fehlgeschlagen. Bitte versuchen Sie es erneut", + "fr": "L'envoi de la commande a échoué, veuillez réessayer", + "es": "Error al enviar el comando, inténtelo de nuevo", + "pt-BR": "Falha no envio do comando, tente novamente", + "ru": "Не удалось отправить команду. Повторите попытку." + }, + "指令已发送,等待电脑确认…": { + "zh-Hans": "指令已发送,等待电脑确认…", + "en": "The command has been sent, waiting for computer confirmation...", + "zh-Hant": "指令已傳送,等待電腦確認…", + "ja": "コマンドが送信され、コンピューターの確認を待っています...", + "ko": "명령이 전송되었으며 컴퓨터 확인을 기다리고 있습니다...", + "de": "Der Befehl wurde gesendet und wartet auf die Bestätigung des Computers ...", + "fr": "La commande a été envoyée, en attente de confirmation informatique...", + "es": "El comando ha sido enviado, esperando confirmación por computadora...", + "pt-BR": "O comando foi enviado, aguardando confirmação do computador...", + "ru": "Команда отправлена, ждём подтверждения от компьютера..." + }, + "按下快捷键,解除隐私屏": { + "zh-Hans": "按下快捷键,解除隐私屏", + "en": "To turn off the privacy screen, press", + "ru": "Чтобы отключить приватный экран, нажмите", + "zh-Hant": "按下快捷鍵,解除隱私屏", + "ja": "プライバシー画面をオフにするには、 を押します。", + "ko": "개인정보 보호 화면을 끄려면 다음을 누르세요.", + "de": "Um den Datenschutzbildschirm auszuschalten, drücken Sie", + "fr": "Pour désactiver l'écran de confidentialité, appuyez sur", + "es": "Para desactivar la pantalla de privacidad, presione", + "pt-BR": "Para desligar a tela de privacidade, pressione" + }, + "按住并拖动,可滑出按键范围,松开结束拖拽": { + "zh-Hans": "按住并拖动,可滑出按键范围,松开结束拖拽", + "en": "Press and drag to slide out of the key range, release to end dragging", + "zh-Hant": "按住並拖動,可滑出按鍵範圍,鬆開結束拖拽", + "ja": "押してドラッグするとキー範囲からスライドし、放すとドラッグが終了します", + "ko": "누르고 드래그하여 키 범위 밖으로 슬라이드하고, 드래그를 종료하려면 놓습니다.", + "de": "Drücken und ziehen Sie, um aus dem Tastenbereich zu gleiten, und lassen Sie los, um das Ziehen zu beenden", + "fr": "Appuyez et faites glisser pour sortir de la plage de touches, relâchez pour terminer le glissement", + "es": "Presione y arrastre para deslizarse fuera del rango de teclas, suelte para finalizar el arrastre", + "pt-BR": "Pressione e arraste para deslizar para fora do intervalo de teclas, solte para encerrar o arrasto", + "ru": "Нажмите и перетащите, чтобы выйти за пределы диапазона клавиш, отпустите, чтобы завершить перетаскивание." + }, + "换位未保存,请重试": { + "zh-Hans": "换位未保存,请重试", + "en": "Couldn't save positions. Please try again.", + "ru": "Не удалось сохранить порядок. Повторите попытку.", + "zh-Hant": "換位未儲存,請重試", + "ja": "ポジションを保存できませんでした。もう一度試してください。", + "ko": "위치를 저장할 수 없습니다. 다시 시도해 주세요.", + "de": "Positionen konnten nicht gespeichert werden. Bitte versuchen Sie es erneut.", + "fr": "Impossible d'enregistrer les positions. Veuillez réessayer.", + "es": "No se pudieron guardar posiciones. Por favor inténtalo de nuevo.", + "pt-BR": "Não foi possível salvar posições. Por favor, tente novamente." + }, + "授权后可使用远程连接。": { + "zh-Hans": "授权后可使用远程连接。", + "en": "Remote connections are available after authorization.", + "zh-Hant": "授權後可使用遠端連線。", + "ja": "認証後、リモート接続が可能になります。", + "ko": "인증 후 원격접속이 가능합니다.", + "de": "Remote-Verbindungen sind nach Autorisierung verfügbar.", + "fr": "Les connexions à distance sont disponibles après autorisation.", + "es": "Las conexiones remotas están disponibles después de la autorización.", + "pt-BR": "Conexões remotas estão disponíveis após autorização.", + "ru": "Удаленные подключения доступны после авторизации." + }, + "授权状态": { + "zh-Hans": "授权状态", + "en": "Authorization status", + "zh-Hant": "授權狀態", + "ja": "認可ステータス", + "ko": "인증상태", + "de": "Autorisierungsstatus", + "fr": "Statut d'autorisation", + "es": "Estado de autorización", + "pt-BR": "Status de autorização", + "ru": "Статус авторизации" + }, + "接收": { + "zh-Hans": "接收", + "en": "Receive", + "ru": "Приём", + "zh-Hant": "接收", + "ja": "受信", + "ko": "수신", + "de": "Empfangen", + "fr": "Réception", + "es": "Recibir", + "pt-BR": "Receber" + }, + "接收 ": { + "zh-Hans": "接收 ", + "en": "receive ", + "zh-Hant": "接收 ", + "ja": "受け取る ", + "ko": "받다 ", + "de": "erhalten ", + "fr": "recevoir ", + "es": "recibir ", + "pt-BR": "receber ", + "ru": "получить " + }, + "接管操控": { + "zh-Hans": "接管操控", + "en": "Control", + "ru": "Управлять", + "zh-Hant": "接管操控", + "ja": "コントロール", + "ko": "제어", + "de": "Kontrolle", + "fr": "Contrôle", + "es": "controlar", + "pt-BR": "Controle" + }, + "控制模式": { + "zh-Hans": "控制模式", + "en": "Control mode", + "zh-Hant": "控制模式", + "ja": "制御モード", + "ko": "제어 모드", + "de": "Steuermodus", + "fr": "Mode de contrôle", + "es": "Modo de control", + "pt-BR": "Modo de controle", + "ru": "Режим управления" + }, + "控制端:": { + "zh-Hans": "控制端:", + "en": "Controller:", + "ru": "Контроллер:", + "zh-Hant": "控制端:", + "ja": "コントローラー:", + "ko": "컨트롤러:", + "de": "Verantwortlicher:", + "fr": "Contrôleur :", + "es": "Controlador:", + "pt-BR": "Controlador:" + }, + "控制端解码器": { + "zh-Hans": "控制端解码器", + "en": "Local decoder", + "ru": "Локальный декодер", + "zh-Hant": "控制端解碼器", + "ja": "ローカルデコーダ", + "ko": "로컬 디코더", + "de": "Lokaler Decoder", + "fr": "Décodeur local", + "es": "Decodificador local", + "pt-BR": "Decodificador local" + }, + "控制端解码器 ": { + "zh-Hans": "控制端解码器 ", + "en": "Local decoder ", + "ru": "Локальный декодер ", + "zh-Hant": "控制端解碼器 ", + "ja": "ローカルデコーダ ", + "ko": "로컬 디코더 ", + "de": "Lokaler Decoder ", + "fr": "Décodeur local ", + "es": "Decodificador local ", + "pt-BR": "Decodificador local " + }, + "控制鼠标": { + "zh-Hans": "控制鼠标", + "en": "Control Mouse", + "ru": "Управление мышью", + "zh-Hant": "控制滑鼠", + "ja": "コントロールマウス", + "ko": "마우스 제어", + "de": "Maus steuern", + "fr": "Contrôler la souris", + "es": "Controlar el ratón", + "pt-BR": "Controle do mouse" + }, + "撤回": { + "zh-Hans": "撤回", + "en": "Withdraw", + "ru": "Отозвать", + "zh-Hant": "撤回", + "ja": "撤回", + "ko": "철회", + "de": "Widerrufen", + "fr": "Retirer", + "es": "Retirar", + "pt-BR": "Revogar" + }, + "撤回后将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。": { + "zh-Hans": "撤回后将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。", + "en": "After withdrawing, the remote connection will be stopped, the screen preview will be closed and the existing preview will be cleared. The connection record and password will be retained, and authorization is required again before reconnecting.", + "zh-Hant": "撤回後將停止遠端連線、關閉畫面預覽儲存並清除已有預覽。連線記錄和密碼會保留,重新連線前需再次授權。", + "ja": "退会後はリモート接続が停止され、画面プレビューが閉じられ、既存のプレビューが消去されます。接続記録とパスワードは保持され、再接続する前に再度認証が必要になります。", + "ko": "탈퇴 후에는 원격접속이 중단되며 화면 미리보기가 닫히고 기존 미리보기는 지워집니다. 접속 기록과 비밀번호는 유지되며, 재접속 전 다시 인증이 필요합니다.", + "de": "Nach dem Abheben wird die Fernverbindung beendet, die Bildschirmvorschau geschlossen und die bestehende Vorschau gelöscht. Der Verbindungsdatensatz und das Passwort bleiben erhalten und vor der erneuten Verbindung ist eine erneute Autorisierung erforderlich.", + "fr": "Après le retrait, la connexion à distance sera arrêtée, l'aperçu de l'écran sera fermé et l'aperçu existant sera effacé. L'enregistrement de connexion et le mot de passe seront conservés et une autorisation sera à nouveau requise avant de se reconnecter.", + "es": "Después de retirarse, se detendrá la conexión remota, se cerrará la vista previa de la pantalla y se borrará la vista previa existente. El registro de conexión y la contraseña se conservarán y se requerirá autorización nuevamente antes de volver a conectarse.", + "pt-BR": "Após a retirada, a conexão remota será interrompida, a visualização da tela será fechada e a visualização existente será apagada. O registro de conexão e a senha serão mantidos e será necessária autorização novamente antes de reconectar.", + "ru": "После выхода удаленное соединение будет остановлено, предварительный просмотр экрана закроется, а существующий предварительный просмотр будет очищен. Запись о подключении и пароль будут сохранены, и перед повторным подключением потребуется повторная авторизация." + }, + "撤回授权": { + "zh-Hans": "撤回授权", + "en": "Withdraw authorization", + "zh-Hant": "撤回授權", + "ja": "認可の撤回", + "ko": "철회 승인", + "de": "Autorisierung entziehen", + "fr": "Retirer l'autorisation", + "es": "Retirar autorización", + "pt-BR": "Retirar autorização", + "ru": "Отозвать разрешение" + }, + "撤回联网授权": { + "zh-Hans": "撤回联网授权", + "en": "Withdraw network authorization", + "zh-Hant": "撤回聯網授權", + "ja": "ネットワーク認証の撤回", + "ko": "네트워크 승인 철회", + "de": "Netzwerkberechtigung entziehen", + "fr": "Retirer l'autorisation réseau", + "es": "Retirar la autorización de red", + "pt-BR": "Retirar autorização de rede", + "ru": "Отозвать сетевую авторизацию" + }, + "撤回联网授权?": { + "zh-Hans": "撤回联网授权?", + "en": "Withdraw network authorization?", + "zh-Hant": "撤回聯網授權?", + "ja": "ネットワーク認証を取り消しますか?", + "ko": "네트워크 승인을 철회하시겠습니까?", + "de": "Netzwerkberechtigung entziehen?", + "fr": "Retirer l'autorisation réseau ?", + "es": "¿Retirar la autorización de la red?", + "pt-BR": "Retirar a autorização da rede?", + "ru": "Отозвать сетевую авторизацию?" + }, + "撤回隐私授权": { + "zh-Hans": "撤回隐私授权", + "en": "Withdraw privacy authorization", + "zh-Hant": "撤回隱私授權", + "ja": "プライバシー認証の撤回", + "ko": "개인정보 승인 철회", + "de": "Datenschutzberechtigung entziehen", + "fr": "Retirer l'autorisation de confidentialité", + "es": "Retirar la autorización de privacidad", + "pt-BR": "Retirar autorização de privacidade", + "ru": "Отозвать разрешение на конфиденциальность" + }, + "播放声音": { + "zh-Hans": "播放声音", + "en": "Play audio", + "ru": "Воспроизведение звука", + "zh-Hant": "播放聲音", + "ja": "音声を再生する", + "ko": "오디오 재생", + "de": "Audio abspielen", + "fr": "Lire l'audio", + "es": "Reproducir audio", + "pt-BR": "Reproduzir áudio" + }, + "操作失败": { + "zh-Hans": "操作失败", + "en": "Operation failed", + "zh-Hant": "操作失敗", + "ja": "操作が失敗しました", + "ko": "작업 실패", + "de": "Der Vorgang ist fehlgeschlagen", + "fr": "Échec de l'opération", + "es": "Operación fallida", + "pt-BR": "Operação falhou", + "ru": "Операция не удалась" + }, + "收发速率": { + "zh-Hans": "收发速率", + "en": "Transfer rate", + "ru": "Скорость", + "zh-Hant": "收發速率", + "ja": "転送速度", + "ko": "전송률", + "de": "Übertragungsrate", + "fr": "Taux de transfert", + "es": "Tasa de transferencia", + "pt-BR": "Taxa de transferência" + }, + "收起控制栏": { + "zh-Hans": "收起控制栏", + "en": "Collapse Control Bar", + "ru": "Свернуть панель управления", + "zh-Hant": "收起控制欄", + "ja": "コントロールバーを折りたたむ", + "ko": "축소 컨트롤 바", + "de": "Steuerleiste ausblenden", + "fr": "Réduire la barre de contrôle", + "es": "Contraer barra de control", + "pt-BR": "Recolher barra de controle" + }, + "收起电脑键盘": { + "zh-Hans": "收起电脑键盘", + "en": "Hide computer keyboard", + "ru": "Скрыть клавиатуру ПК", + "zh-Hant": "收起電腦鍵盤", + "ja": "PC キーボードを隠す", + "ko": "PC 키보드 숨기기", + "de": "PC-Tastatur ausblenden", + "fr": "Masquer le clavier du PC", + "es": "Ocultar teclado del PC", + "pt-BR": "Ocultar teclado do PC" + }, + "收起系统键盘": { + "zh-Hans": "收起系统键盘", + "en": "Collapse system keyboard", + "zh-Hant": "收起系統鍵盤", + "ja": "システムキーボードを折りたたむ", + "ko": "시스템 키보드 축소", + "de": "Systemtastatur einklappen", + "fr": "Réduire le clavier système", + "es": "Contraer teclado del sistema", + "pt-BR": "Recolher o teclado do sistema", + "ru": "Свернуть системную клавиатуру" + }, + "收起远程控制菜单": { + "zh-Hans": "收起远程控制菜单", + "en": "Collapse remote control menu", + "zh-Hant": "收起遠端控制選單", + "ja": "リモコンメニューを折りたたむ", + "ko": "리모컨 메뉴 접기", + "de": "Fernbedienungsmenü einklappen", + "fr": "Réduire le menu de la télécommande", + "es": "Contraer menú de control remoto", + "pt-BR": "Recolher menu de controle remoto", + "ru": "Свернуть меню пульта дистанционного управления" + }, + "收起键盘": { + "zh-Hans": "收起键盘", + "en": "Hide keyboard", + "zh-Hant": "收起鍵盤", + "ja": "キーボードを隠す", + "ko": "키보드 숨기기", + "de": "Tastatur ausblenden", + "fr": "Masquer le clavier", + "es": "Ocultar teclado", + "pt-BR": "Ocultar teclado", + "ru": "Скрыть клавиатуру" + }, + "收起鼠标": { + "zh-Hans": "收起鼠标", + "en": "Hide mouse", + "ru": "Скрыть мышь", + "zh-Hant": "收起滑鼠", + "ja": "マウスを隠す", + "ko": "마우스 숨기기", + "de": "Maus ausblenden", + "fr": "Masquer la souris", + "es": "Ocultar ratón", + "pt-BR": "Ocultar mouse" + }, + "数据": { + "zh-Hans": "数据", + "en": "Data", + "ru": "Данные", + "zh-Hant": "資料", + "ja": "データ", + "ko": "데이터", + "de": "Daten", + "fr": "Données", + "es": "Datos", + "pt-BR": "Dados" + }, + "文件传输:": { + "zh-Hans": "文件传输:", + "en": "File Transfer:", + "ru": "Передача файлов:", + "zh-Hant": "檔案傳輸:", + "ja": "ファイル転送:", + "ko": "파일 전송:", + "de": "Dateiübertragung:", + "fr": "Transfert de fichiers :", + "es": "Transferencia de archivos:", + "pt-BR": "Transferência de arquivos:" + }, + "文件传输进度": { + "zh-Hans": "文件传输进度", + "en": "File Transfer Progress", + "ru": "Прогресс передачи файлов", + "zh-Hant": "檔案傳輸進度", + "ja": "ファイル転送の進行状況", + "ko": "파일 전송 진행", + "de": "Dateiübertragungsfortschritt", + "fr": "Progression du transfert de fichiers", + "es": "Progreso de la transferencia de archivos", + "pt-BR": "Progresso da transferência de arquivos" + }, + "文件保存失败,请重试": { + "zh-Hans": "文件保存失败,请重试", + "en": "File saving failed, please try again", + "zh-Hant": "檔案儲存失敗,請重試", + "ja": "ファイルの保存に失敗しました。もう一度お試しください。", + "ko": "파일 저장에 실패했습니다. 다시 시도해 주세요.", + "de": "Das Speichern der Datei ist fehlgeschlagen. Bitte versuchen Sie es erneut", + "fr": "L'enregistrement du fichier a échoué, veuillez réessayer", + "es": "Error al guardar el archivo, inténtelo de nuevo", + "pt-BR": "Falha ao salvar o arquivo, tente novamente", + "ru": "Не удалось сохранить файл. Повторите попытку." + }, + "文件保存目录": { + "zh-Hans": "文件保存目录", + "en": "Received file directory", + "ru": "Каталог получаемых файлов", + "zh-Hant": "檔案儲存目錄", + "ja": "受信ファイルディレクトリ", + "ko": "수신된 파일 디렉터리", + "de": "Verzeichnis der empfangenen Dateien", + "fr": "Répertoire des fichiers reçus", + "es": "Directorio de archivos recibidos", + "pt-BR": "Diretório de arquivo recebido" + }, + "文件发送进度": { + "zh-Hans": "文件发送进度", + "en": "File Sending Progress", + "ru": "Отправка файла", + "zh-Hant": "檔案傳送進度", + "ja": "ファイル送信の進行状況", + "ko": "파일 전송 진행 상황", + "de": "Fortschritt beim Senden der Datei", + "fr": "Progression de l'envoi du fichier", + "es": "Progreso del envío de archivos", + "pt-BR": "Progresso do envio de arquivos" + }, + "文件已保存": { + "zh-Hans": "文件已保存", + "en": "File saved", + "zh-Hant": "檔案已儲存", + "ja": "ファイルを保存しました", + "ko": "파일이 저장되었습니다", + "de": "Datei gespeichert", + "fr": "Fichier enregistré", + "es": "Archivo guardado", + "pt-BR": "Arquivo salvo", + "ru": "Файл сохранен." + }, + "文件接收保存路径": { + "zh-Hans": "文件接收保存路径", + "en": "File Transfer Save Path", + "ru": "Путь сохранения файлов", + "zh-Hant": "檔案接收儲存路徑", + "ja": "ファイル転送の保存パス", + "ko": "파일 전송 저장 경로", + "de": "Speicherpfad für die Dateiübertragung", + "fr": "Chemin d'enregistrement du transfert de fichiers", + "es": "Ruta para guardar la transferencia de archivos", + "pt-BR": "Caminho para salvar transferência de arquivos" + }, + "文件接收进度": { + "zh-Hans": "文件接收进度", + "en": "File Receiving Progress", + "ru": "Получение файла", + "zh-Hant": "檔案接收進度", + "ja": "ファイル受信進捗状況", + "ko": "파일 수신 진행 상황", + "de": "Fortschritt des Dateiempfangs", + "fr": "Progression de la réception des fichiers", + "es": "Progreso de recepción de archivos", + "pt-BR": "Progresso do recebimento de arquivos" + }, + "文件选择已超时,会话已结束": { + "zh-Hans": "文件选择已超时,会话已结束", + "en": "File selection timed out and session ended", + "zh-Hant": "檔案選擇已超時,會話已結束", + "ja": "ファイル選択がタイムアウトし、セッションが終了しました", + "ko": "파일 선택 시간이 초과되어 세션이 종료되었습니다.", + "de": "Zeitüberschreitung bei der Dateiauswahl und Sitzung beendet", + "fr": "La sélection de fichier a expiré et la session s'est terminée", + "es": "Se agotó el tiempo de selección de archivos y la sesión finalizó", + "pt-BR": "A seleção do arquivo expirou e a sessão foi encerrada", + "ru": "Тайм-аут выбора файла истек, сеанс завершен." + }, + "文本超过 128 KB": { + "zh-Hans": "文本超过 128 KB", + "en": "Text exceeds 128 KB", + "zh-Hant": "文字超過 128 KB", + "ja": "テキストが128KBを超えています", + "ko": "텍스트가 128KB를 초과합니다.", + "de": "Der Text ist größer als 128 KB", + "fr": "Le texte dépasse 128 Ko", + "es": "El texto supera los 128 KB", + "pt-BR": "O texto excede 128 KB", + "ru": "Размер текста превышает 128 КБ." + }, + "断开": { + "zh-Hans": "断开", + "en": "Disconnect", + "ru": "Отключить", + "zh-Hant": "斷開", + "ja": "切断", + "ko": "연결 끊기", + "de": "Trennen", + "fr": "Déconnecter", + "es": "Desconectar", + "pt-BR": "Desconectar" + }, + "断开后将返回首页": { + "zh-Hans": "断开后将返回首页", + "en": "Will return to the homepage after disconnecting", + "zh-Hant": "斷開後將返回首頁", + "ja": "切断後ホームページに戻ります", + "ko": "연결을 끊으면 홈페이지로 돌아갑니다.", + "de": "Kehrt nach dem Trennen der Verbindung zur Startseite zurück", + "fr": "Reviendra à la page d'accueil après la déconnexion", + "es": "Volverá a la página de inicio después de desconectarse", + "pt-BR": "Retornará à página inicial após desconectar", + "ru": "Вернется на домашнюю страницу после отключения." + }, + "断开后将返回首页。": { + "zh-Hans": "断开后将返回首页。", + "en": "Will return to the homepage after disconnecting.", + "zh-Hant": "斷開後將返回首頁。", + "ja": "切断後、ホームページに戻ります。", + "ko": "연결이 끊어지면 홈페이지로 돌아갑니다.", + "de": "Kehrt nach dem Trennen der Verbindung zur Startseite zurück.", + "fr": "Reviendra à la page d'accueil après la déconnexion.", + "es": "Volverá a la página de inicio después de desconectarse.", + "pt-BR": "Retornará à página inicial após desconectar.", + "ru": "Вернется на домашнюю страницу после отключения." + }, + "断开当前连接?": { + "zh-Hans": "断开当前连接?", + "en": "Disconnect this session?", + "ru": "Отключить текущий сеанс?", + "zh-Hant": "斷開當前連線?", + "ja": "このセッションを切断しますか?", + "ko": "이 세션을 연결 해제하시겠습니까?", + "de": "Diese Sitzung trennen?", + "fr": "Déconnecter cette session ?", + "es": "¿Desconectar esta sesión?", + "pt-BR": "Desconectar esta sessão?" + }, + "断开所有控制端的连接?": { + "zh-Hans": "断开所有控制端的连接?", + "en": "Disconnect all controllers?", + "ru": "Отключить все контроллеры?", + "zh-Hant": "斷開所有控制端的連線?", + "ja": "すべてのコントローラーを切断しますか?", + "ko": "모든 컨트롤러를 연결 해제하시겠습니까?", + "de": "Alle Controller abklemmen?", + "fr": "Déconnecter tous les contrôleurs ?", + "es": "¿Desconectar todos los controladores?", + "pt-BR": "Desconectar todos os controladores?" + }, + "断开远程连接?": { + "zh-Hans": "断开远程连接?", + "en": "Disconnect remote connection?", + "zh-Hant": "斷開遠端連線?", + "ja": "リモート接続を切断しますか?", + "ko": "원격 연결을 끊으시겠습니까?", + "de": "Remote-Verbindung trennen?", + "fr": "Déconnecter la connexion à distance ?", + "es": "¿Desconectar la conexión remota?", + "pt-BR": "Desconectar a conexão remota?", + "ru": "Отключить удаленное соединение?" + }, + "断开连接": { + "zh-Hans": "断开连接", + "en": "Disconnect", + "ru": "Отключить", + "zh-Hant": "中斷連線", + "ja": "切断", + "ko": "연결 해제", + "de": "Trennen", + "fr": "Déconnecter", + "es": "Desconectar", + "pt-BR": "Desconectar" + }, + "新建分组(可选)": { + "zh-Hans": "新建分组(可选)", + "en": "New group (optional)", + "ru": "Новая группа (необязательно)", + "zh-Hant": "新建分組(可選)", + "ja": "新しいグループ (オプション)", + "ko": "새 그룹(선택 사항)", + "de": "Neue Gruppe (optional)", + "fr": "Nouveau groupe (facultatif)", + "es": "Nuevo grupo (opcional)", + "pt-BR": "Novo grupo (opcional)" + }, + "新版本": { + "zh-Hans": "新版本", + "en": "New version", + "ru": "Новая версия", + "zh-Hant": "新版本", + "ja": "新しいバージョン", + "ko": "새 버전", + "de": "Neue Version", + "fr": "Nouvelle version", + "es": "Nueva versión", + "pt-BR": "Nova versão" + }, + "新版本 ●": { + "zh-Hans": "新版本 ●", + "en": "New version ●", + "zh-Hant": "新版本 ●", + "ja": "新バージョン●", + "ko": "새 버전 ●", + "de": "Neue Version ●", + "fr": "Nouvelle version ●", + "es": "Nueva versión ●", + "pt-BR": "Nova versão ●", + "ru": "Новая версия ●" + }, + "新版本包含功能改进和性能优化,建议将被控端升级至最新版本。": { + "zh-Hans": "新版本包含功能改进和性能优化,建议将被控端升级至最新版本。", + "en": "Update the remote device to the latest version for improved features and performance.", + "ru": "В новой версии улучшены функции и производительность. Рекомендуем обновить CrossDesk на удалённом устройстве до последней версии.", + "zh-Hant": "新版本包含功能改進和效能最佳化,建議將被控端升級至最新版本。", + "ja": "機能とパフォーマンスを向上させるために、リモート デバイスを最新バージョンに更新します。", + "ko": "향상된 기능과 성능을 위해 원격 장치를 최신 버전으로 업데이트하세요.", + "de": "Aktualisieren Sie das Remote-Gerät auf die neueste Version, um verbesserte Funktionen und Leistung zu erhalten.", + "fr": "Mettez à jour le périphérique distant vers la dernière version pour des fonctionnalités et des performances améliorées.", + "es": "Actualice el dispositivo remoto a la última versión para mejorar las funciones y el rendimiento.", + "pt-BR": "Atualize o dispositivo remoto para a versão mais recente para obter recursos e desempenho aprimorados." + }, + "新版本可用": { + "zh-Hans": "新版本可用", + "en": "New Version Available", + "ru": "Доступна новая версия", + "zh-Hant": "新版本可用", + "ja": "新しいバージョンが利用可能になりました", + "ko": "새 버전 출시", + "de": "Neue Version verfügbar", + "fr": "Nouvelle version disponible", + "es": "Nueva versión disponible", + "pt-BR": "Nova versão disponível" + }, + "新版本可用:v": { + "zh-Hans": "新版本可用:v", + "en": "New version available: v", + "zh-Hant": "新版本可用:v", + "ja": "利用可能な新しいバージョン: v", + "ko": "새 버전 사용 가능: v", + "de": "Neue Version verfügbar: v", + "fr": "Nouvelle version disponible : v", + "es": "Nueva versión disponible :v", + "pt-BR": "Nova versão disponível: v", + "ru": "Доступна новая версия: v" + }, + "新版本可用:v%1$@": { + "zh-Hans": "新版本可用:v%1$@", + "en": "New version available: v%1$@", + "zh-Hant": "新版本可用:v%1$@", + "ja": "利用可能な新しいバージョン: v%1$@", + "ko": "새 버전 사용 가능: v%1$@", + "de": "Neue Version verfügbar: v%1$@", + "fr": "Nouvelle version disponible : v%1$@", + "es": "Nueva versión disponible: v%1$@", + "pt-BR": "Nova versão disponível: v%1$@", + "ru": "Доступна новая версия: v%1$@" + }, + "无效": { + "zh-Hans": "无效", + "en": "Invalid", + "zh-Hant": "無效", + "ja": "無効", + "ko": "유효하지 않음", + "de": "Ungültig", + "fr": "Invalide", + "es": "Inválido", + "pt-BR": "Inválido", + "ru": "Недействительно" + }, + "无效的选项或值,未保存。请按菜单列出的格式输入。": { + "zh-Hans": "无效的选项或值,未保存。请按菜单列出的格式输入。", + "en": "Invalid setting or value; not saved. Use the format shown in the menu.", + "ru": "Неверный параметр или значение. Ничего не сохранено. Используйте указанный формат.", + "zh-Hant": "無效的選項或值,未儲存。請按選單列出的格式輸入。", + "ja": "無効な設定または値です。保存されていません。メニューに表示される形式を使用します。", + "ko": "잘못된 설정 또는 값입니다. 저장되지 않았습니다. 메뉴에 표시된 형식을 사용하십시오.", + "de": "Ungültige Einstellung oder ungültiger Wert; nicht gespeichert. Verwenden Sie das im Menü angezeigte Format.", + "fr": "Paramètre ou valeur invalide ; pas sauvegardé. Utilisez le format indiqué dans le menu.", + "es": "Configuración o valor no válido; no salvo. Utilice el formato que se muestra en el menú.", + "pt-BR": "Configuração ou valor inválido; não salvo. Use o formato mostrado no menu." + }, + "无未读公告": { + "zh-Hans": "无未读公告", + "en": "No unread announcements", + "zh-Hant": "無未讀公告", + "ja": "未読のお知らせはありません", + "ko": "읽지 않은 공지사항 없음", + "de": "Keine ungelesenen Ankündigungen", + "fr": "Aucune annonce non lue", + "es": "No hay anuncios no leídos", + "pt-BR": "Nenhum anúncio não lido", + "ru": "Нет непрочитанных объявлений" + }, + "无此 ID": { + "zh-Hans": "无此 ID", + "en": "No such ID", + "ru": "ID не найден", + "zh-Hant": "無此 ID", + "ja": "そのようなIDはありません", + "ko": "해당 아이디가 없습니다.", + "de": "Kein solcher Ausweis", + "fr": "Aucune pièce d'identité de ce type", + "es": "No existe tal identificación", + "pt-BR": "Não existe tal ID" + }, + "无法": { + "zh-Hans": "无法", + "en": "Unable to", + "zh-Hant": "無法", + "ja": "できません", + "ko": "할 수 없다", + "de": "Unfähig", + "fr": "Impossible de", + "es": "No puedo", + "pt-BR": "Incapaz de", + "ru": "Невозможно" + }, + "无法使用此端口,": { + "zh-Hans": "无法使用此端口,", + "en": "Cannot use this port.", + "ru": "Порт недоступен.", + "zh-Hant": "無法使用此埠,", + "ja": "このポートは使用できません。", + "ko": "이 포트를 사용할 수 없습니다.", + "de": "Dieser Port kann nicht verwendet werden.", + "fr": "Impossible d'utiliser ce port.", + "es": "No se puede utilizar este puerto.", + "pt-BR": "Não é possível usar esta porta." + }, + "无法保存 IP 连接设置,请重试。": { + "zh-Hans": "无法保存 IP 连接设置,请重试。", + "en": "Could not save IP connection settings. Try again.", + "ru": "Не удалось сохранить настройки подключения по IP. Повторите попытку.", + "zh-Hant": "無法儲存 IP 連線設定,請重試。", + "ja": "IP接続設定を保存できませんでした。もう一度やり直してください。", + "ko": "IP 연결 설정을 저장할 수 없습니다. 다시 시도해 보세요.", + "de": "IP-Verbindungseinstellungen konnten nicht gespeichert werden. Versuchen Sie es erneut.", + "fr": "Impossible d'enregistrer les paramètres de connexion IP. Essayer à nouveau.", + "es": "No se pudo guardar la configuración de la conexión IP. Intentar otra vez.", + "pt-BR": "Não foi possível salvar as configurações de conexão IP. Tente novamente." + }, + "无法保存密码修改记录,未提交修改。请检查日志。": { + "zh-Hans": "无法保存密码修改记录,未提交修改。请检查日志。", + "en": "Unable to save password recovery record; no change submitted. Check the log.", + "ru": "Не удалось сохранить запись восстановления пароля. Изменение не отправлено. Проверьте журнал.", + "zh-Hant": "無法儲存密碼修改記錄,未提交修改。請檢查日誌。", + "ja": "パスワード回復記録を保存できません。変更は送信されませんでした。ログを確認してください。", + "ko": "비밀번호 복구 기록을 저장할 수 없습니다. 변경사항이 제출되지 않았습니다. 로그를 확인하세요.", + "de": "Der Datensatz zur Passwortwiederherstellung konnte nicht gespeichert werden. Keine Änderung eingereicht. Überprüfen Sie das Protokoll.", + "fr": "Impossible d'enregistrer l'enregistrement de récupération du mot de passe ; aucun changement soumis. Vérifiez le journal.", + "es": "No se puede guardar el registro de recuperación de contraseña; no se envió ningún cambio. Consulta el registro.", + "pt-BR": "Não foi possível salvar o registro de recuperação de senha; nenhuma alteração enviada. Verifique o registro." + }, + "无法保存断开后锁屏设置,请重试。": { + "zh-Hans": "无法保存断开后锁屏设置,请重试。", + "en": "Could not save lock-on-disconnect settings. Try again.", + "ru": "Не удалось сохранить настройку блокировки при отключении. Повторите попытку.", + "zh-Hant": "無法儲存斷開後鎖屏設定,請重試。", + "ja": "切断時ロック設定を保存できませんでした。もう一度やり直してください。", + "ko": "연결 해제 시 잠금 설정을 저장할 수 없습니다. 다시 시도해 보세요.", + "de": "Lock-on-Disconnect-Einstellungen konnten nicht gespeichert werden. Versuchen Sie es erneut.", + "fr": "Impossible d'enregistrer les paramètres de verrouillage à la déconnexion. Essayer à nouveau.", + "es": "No se pudo guardar la configuración de bloqueo al desconectar. Intentar otra vez.", + "pt-BR": "Não foi possível salvar as configurações de bloqueio ao desconectar. Tente novamente." + }, + "无法保存本地阅读状态,请重试。": { + "zh-Hans": "无法保存本地阅读状态,请重试。", + "en": "Unable to save reading status locally. Please try again.", + "ru": "Не удалось сохранить статус чтения локально. Повторите попытку.", + "zh-Hant": "無法儲存本地閱讀狀態,請重試。", + "ja": "読み取りステータスをローカルに保存できません。もう一度試してください。", + "ko": "읽기 상태를 로컬에 저장할 수 없습니다. 다시 시도해 주세요.", + "de": "Lesestatus kann nicht lokal gespeichert werden. Bitte versuchen Sie es erneut.", + "fr": "Impossible d'enregistrer l'état de lecture localement. Veuillez réessayer.", + "es": "No se puede guardar el estado de lectura localmente. Por favor inténtalo de nuevo.", + "pt-BR": "Não é possível salvar o status de leitura localmente. Por favor, tente novamente." + }, + "无法保存联网授权,请重试": { + "zh-Hans": "无法保存联网授权,请重试", + "en": "Unable to save network authorization, please try again", + "zh-Hant": "無法儲存聯網授權,請重試", + "ja": "ネットワーク認証を保存できません。もう一度お試しください。", + "ko": "네트워크 인증을 저장할 수 없습니다. 다시 시도해 주세요.", + "de": "Die Netzwerkautorisierung konnte nicht gespeichert werden. Bitte versuchen Sie es erneut", + "fr": "Impossible d'enregistrer l'autorisation réseau, veuillez réessayer", + "es": "No se puede guardar la autorización de red, inténtelo de nuevo", + "pt-BR": "Não foi possível salvar a autorização de rede. Tente novamente", + "ru": "Невозможно сохранить сетевую авторизацию. Повторите попытку." + }, + "无法保存连接模式,下次启动可能不会恢复当前模式。": { + "zh-Hans": "无法保存连接模式,下次启动可能不会恢复当前模式。", + "en": "Could not save the connection mode. It may not be restored on the next launch.", + "ru": "Не удалось сохранить режим подключения. При следующем запуске он может не восстановиться.", + "zh-Hant": "無法儲存連線模式,下次啟動可能不會恢復當前模式。", + "ja": "接続モードを保存できませんでした。次回起動時には復元されない可能性があります。", + "ko": "연결 모드를 저장할 수 없습니다. 다음 실행 시 복원되지 않을 수 있습니다.", + "de": "Der Verbindungsmodus konnte nicht gespeichert werden. Es kann sein, dass es beim nächsten Start nicht wiederhergestellt wird.", + "fr": "Impossible d'enregistrer le mode de connexion. Il se peut qu'il ne soit pas restauré au prochain lancement.", + "es": "No se pudo guardar el modo de conexión. Es posible que no se restablezca en el próximo lanzamiento.", + "pt-BR": "Não foi possível salvar o modo de conexão. Pode não ser restaurado na próxima inicialização." + }, + "无法保存隐私屏解锁设置,请重试。": { + "zh-Hans": "无法保存隐私屏解锁设置,请重试。", + "en": "Could not save privacy unlock settings. Try again.", + "ru": "Не удалось сохранить настройку разблокировки. Повторите попытку.", + "zh-Hant": "無法儲存隱私屏解鎖設定,請重試。", + "ja": "プライバシーロック解除設定を保存できませんでした。もう一度やり直してください。", + "ko": "개인 정보 잠금 해제 설정을 저장할 수 없습니다. 다시 시도해 보세요.", + "de": "Die Einstellungen zum Entsperren der Privatsphäre konnten nicht gespeichert werden. Versuchen Sie es erneut.", + "fr": "Impossible d'enregistrer les paramètres de déverrouillage de la confidentialité. Essayer à nouveau.", + "es": "No se pudo guardar la configuración de desbloqueo de privacidad. Intentar otra vez.", + "pt-BR": "Não foi possível salvar as configurações de desbloqueio de privacidade. Tente novamente." + }, + "无法准备远程会话,请稍后重试。": { + "zh-Hans": "无法准备远程会话,请稍后重试。", + "en": "Could not prepare the remote session. Try again shortly.", + "ru": "Не удалось подготовить удалённый сеанс. Повторите позже.", + "zh-Hant": "無法準備遠端會話,請稍後重試。", + "ja": "リモートセッションを準備できませんでした。しばらくしてからもう一度お試しください。", + "ko": "원격 세션을 준비할 수 없습니다. 잠시 후 다시 시도하세요.", + "de": "Die Remote-Sitzung konnte nicht vorbereitet werden. Versuchen Sie es in Kürze noch einmal.", + "fr": "Impossible de préparer la session à distance. Réessayez sous peu.", + "es": "No se pudo preparar la sesión remota. Vuelve a intentarlo en breve.", + "pt-BR": "Não foi possível preparar a sessão remota. Tente novamente em breve." + }, + "无法删除已保存的凭据": { + "zh-Hans": "无法删除已保存的凭据", + "en": "Unable to delete saved credentials", + "zh-Hant": "無法刪除已儲存的憑據", + "ja": "保存した認証情報を削除できない", + "ko": "저장된 자격 증명을 삭제할 수 없습니다", + "de": "Gespeicherte Anmeldeinformationen können nicht gelöscht werden", + "fr": "Impossible de supprimer les informations d'identification enregistrées", + "es": "No se pueden eliminar las credenciales guardadas", + "pt-BR": "Não é possível excluir credenciais salvas", + "ru": "Невозможно удалить сохраненные учетные данные." + }, + "无法删除这条公告,请重试。": { + "zh-Hans": "无法删除这条公告,请重试。", + "en": "Unable to delete this announcement. Please try again.", + "ru": "Не удалось удалить объявление. Повторите попытку.", + "zh-Hant": "無法刪除這條公告,請重試。", + "ja": "このお知らせは削除できません。もう一度試してください。", + "ko": "이 공지를 삭제할 수 없습니다. 다시 시도해 주세요.", + "de": "Diese Ankündigung kann nicht gelöscht werden. Bitte versuchen Sie es erneut.", + "fr": "Impossible de supprimer cette annonce. Veuillez réessayer.", + "es": "No se puede eliminar este anuncio. Por favor inténtalo de nuevo.", + "pt-BR": "Não é possível excluir este anúncio. Por favor, tente novamente." + }, + "无法发起远程连接": { + "zh-Hans": "无法发起远程连接", + "en": "Unable to initiate remote connection", + "zh-Hant": "無法發起遠端連線", + "ja": "リモート接続を開始できません", + "ko": "원격 연결을 시작할 수 없습니다", + "de": "Remote-Verbindung konnte nicht initiiert werden", + "fr": "Impossible d'établir une connexion à distance", + "es": "No se puede iniciar la conexión remota", + "pt-BR": "Não é possível iniciar a conexão remota", + "ru": "Невозможно инициировать удаленное соединение." + }, + "无法建立加密连接,请检查双方网络并重试。": { + "zh-Hans": "无法建立加密连接,请检查双方网络并重试。", + "en": "Could not establish an encrypted connection. Check both devices' networks and try again.", + "ru": "Не удалось установить зашифрованное соединение. Проверьте сеть на обоих устройствах и повторите попытку.", + "zh-Hant": "無法建立加密連線,請檢查雙方網路並重試。", + "ja": "暗号化接続を確立できませんでした。両方のデバイスのネットワークを確認して、再試行してください。", + "ko": "암호화된 연결을 설정할 수 없습니다. 두 기기의 네트워크를 모두 확인하고 다시 시도하세요.", + "de": "Es konnte keine verschlüsselte Verbindung hergestellt werden. Überprüfen Sie die Netzwerke beider Geräte und versuchen Sie es erneut.", + "fr": "Impossible d'établir une connexion cryptée. Vérifiez les réseaux des deux appareils et réessayez.", + "es": "No se pudo establecer una conexión cifrada. Verifique las redes de ambos dispositivos e inténtelo nuevamente.", + "pt-BR": "Não foi possível estabelecer uma conexão criptografada. Verifique as redes de ambos os dispositivos e tente novamente." + }, + "无法打开网页": { + "zh-Hans": "无法打开网页", + "en": "Unable to open web page", + "zh-Hant": "無法開啟網頁", + "ja": "Webページを開けません", + "ko": "웹페이지를 열 수 없습니다", + "de": "Webseite kann nicht geöffnet werden", + "fr": "Impossible d'ouvrir la page Web", + "es": "No se puede abrir la página web", + "pt-BR": "Não é possível abrir a página da web", + "ru": "Невозможно открыть веб-страницу." + }, + "无法生成随机密码,请重试。": { + "zh-Hans": "无法生成随机密码,请重试。", + "en": "Unable to generate a random password; try again.", + "ru": "Не удалось создать случайный пароль. Повторите попытку.", + "zh-Hant": "無法生成隨機密碼,請重試。", + "ja": "ランダムなパスワードを生成できません。もう一度やり直してください。", + "ko": "임의의 비밀번호를 생성할 수 없습니다. 다시 시도해 보세요.", + "de": "Es kann kein zufälliges Passwort generiert werden; versuchen Sie es erneut.", + "fr": "Impossible de générer un mot de passe aléatoire ; essayer à nouveau.", + "es": "No se puede generar una contraseña aleatoria; intentar otra vez.", + "pt-BR": "Não foi possível gerar uma senha aleatória; tente novamente." + }, + "无法确认此端口是否可用,": { + "zh-Hans": "无法确认此端口是否可用,", + "en": "Could not check this port.", + "ru": "Не удалось проверить порт.", + "zh-Hant": "無法確認此埠是否可用,", + "ja": "このポートを確認できませんでした。", + "ko": "이 포트를 확인할 수 없습니다.", + "de": "Dieser Port konnte nicht überprüft werden.", + "fr": "Impossible de vérifier ce port.", + "es": "No se pudo verificar este puerto.", + "pt-BR": "Não foi possível verificar esta porta." + }, + "无法访问本机登录凭据,请解锁后重试": { + "zh-Hans": "无法访问本机登录凭据,请解锁后重试", + "en": "Unable to access local login credentials, please unlock and try again", + "zh-Hant": "無法訪問本機登入憑據,請解鎖後重試", + "ja": "ローカル ログイン資格情報にアクセスできません。ロックを解除して再試行してください。", + "ko": "로컬 로그인 자격 증명에 액세스할 수 없습니다. 잠금을 해제하고 다시 시도하십시오.", + "de": "Der Zugriff auf die lokalen Anmeldedaten ist nicht möglich. Bitte entsperren Sie die Sperre und versuchen Sie es erneut", + "fr": "Impossible d'accéder aux informations de connexion locales, veuillez déverrouiller et réessayer", + "es": "No se puede acceder a las credenciales de inicio de sesión locales, desbloquee e intente nuevamente", + "pt-BR": "Não é possível acessar as credenciais de login locais, desbloqueie e tente novamente", + "ru": "Невозможно получить доступ к локальным учетным данным для входа. Разблокируйте и повторите попытку." + }, + "无法读取开源许可": { + "zh-Hans": "无法读取开源许可", + "en": "Unable to read open source license", + "zh-Hant": "無法讀取開源許可", + "ja": "オープンソースライセンスを読み取れません", + "ko": "오픈소스 라이선스를 읽을 수 없습니다.", + "de": "Open-Source-Lizenz kann nicht gelesen werden", + "fr": "Impossible de lire la licence open source", + "es": "No se puede leer la licencia de código abierto", + "pt-BR": "Não é possível ler a licença de código aberto", + "ru": "Невозможно прочитать лицензию с открытым исходным кодом." + }, + "无法读取所选文件或存储空间不足": { + "zh-Hans": "无法读取所选文件或存储空间不足", + "en": "The selected file cannot be read or there is insufficient storage space.", + "zh-Hant": "無法讀取所選檔案或儲存空間不足", + "ja": "選択したファイルが読み込めないか、ストレージ容量が不足しています。", + "ko": "선택한 파일을 읽을 수 없거나 저장공간이 부족합니다.", + "de": "Die ausgewählte Datei kann nicht gelesen werden oder es ist nicht genügend Speicherplatz vorhanden.", + "fr": "Le fichier sélectionné ne peut pas être lu ou l'espace de stockage est insuffisant.", + "es": "El archivo seleccionado no se puede leer o no hay suficiente espacio de almacenamiento.", + "pt-BR": "O arquivo selecionado não pode ser lido ou não há espaço de armazenamento suficiente.", + "ru": "Выбранный файл не может быть прочитан или недостаточно места для хранения." + }, + "无法读取所选文件,请重试": { + "zh-Hans": "无法读取所选文件,请重试", + "en": "Unable to read selected file, please try again", + "zh-Hant": "無法讀取所選檔案,請重試", + "ja": "選択したファイルを読み取れません。もう一度お試しください。", + "ko": "선택한 파일을 읽을 수 없습니다. 다시 시도해 주세요.", + "de": "Die ausgewählte Datei konnte nicht gelesen werden. Bitte versuchen Sie es erneut", + "fr": "Impossible de lire le fichier sélectionné, veuillez réessayer", + "es": "No se puede leer el archivo seleccionado, inténtelo de nuevo", + "pt-BR": "Não foi possível ler o arquivo selecionado, tente novamente", + "ru": "Невозможно прочитать выбранный файл, попробуйте еще раз." + }, + "无法读取文档": { + "zh-Hans": "无法读取文档", + "en": "Unable to read document", + "zh-Hant": "無法讀取文件", + "ja": "文書を読み取れません", + "ko": "문서를 읽을 수 없습니다", + "de": "Dokument kann nicht gelesen werden", + "fr": "Impossible de lire le document", + "es": "No se puede leer el documento", + "pt-BR": "Não é possível ler o documento", + "ru": "Невозможно прочитать документ." + }, + "无法读取系统状态。请刷新重试,或在系统设置中核对。": { + "zh-Hans": "无法读取系统状态。请刷新重试,或在系统设置中核对。", + "en": "Could not read the system status. Refresh to retry, or check System Settings.", + "ru": "Не удалось прочитать состояние. Повторите попытку или проверьте настройки системы.", + "zh-Hant": "無法讀取系統狀態。請重新整理重試,或在系統設定中核對。", + "ja": "システムステータスを読み取れませんでした。更新して再試行するか、システム設定を確認してください。", + "ko": "시스템 상태를 읽을 수 없습니다. 다시 시도하려면 새로고침하거나 시스템 설정을 확인하세요.", + "de": "Der Systemstatus konnte nicht gelesen werden. Aktualisieren Sie, um es noch einmal zu versuchen, oder überprüfen Sie die Systemeinstellungen.", + "fr": "Impossible de lire l'état du système. Actualisez pour réessayer ou vérifiez les paramètres système.", + "es": "No se pudo leer el estado del sistema. Actualice para volver a intentarlo o verifique la Configuración del sistema.", + "pt-BR": "Não foi possível ler o status do sistema. Atualize para tentar novamente ou verifique as configurações do sistema." + }, + "无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。": { + "zh-Hans": "无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。", + "en": "Could not connect. Check the IP, whether the other desktop is running CrossDesk, and its firewall settings.", + "ru": "Не удалось подключиться. Проверьте IP, работу CrossDesk на другом компьютере и брандмауэр.", + "zh-Hant": "無法連線,請檢查對方 IP、程式是否執行,以及防火牆是否放行。", + "ja": "接続できませんでした。 IP、他のデスクトップがCrossDeskを実行しているかどうか、およびそのファイアウォール設定を確認してください。", + "ko": "연결할 수 없습니다. IP, 다른 데스크톱이CrossDesk를 실행 중인지 여부 및 방화벽 설정을 확인하세요.", + "de": "Verbindung konnte nicht hergestellt werden. Überprüfen Sie die IP, ob auf dem anderen Desktop CrossDesk ausgeführt wird, und seine Firewall-Einstellungen.", + "fr": "Impossible de se connecter. Vérifiez l'adresse IP, si l'autre bureau exécute CrossDesk et ses paramètres de pare-feu.", + "es": "No se pudo conectar. Verifique la IP, si el otro escritorio está ejecutando CrossDesk y su configuración de firewall.", + "pt-BR": "Não foi possível conectar. Verifique o IP, se o outro desktop está executando CrossDesk e suas configurações de firewall." + }, + "无法验证对方设备的身份,请确认连接地址和对方设备后重试。": { + "zh-Hans": "无法验证对方设备的身份,请确认连接地址和对方设备后重试。", + "en": "Could not verify the remote device's identity. Check the address and the remote device before retrying.", + "ru": "Не удалось проверить подлинность удалённого устройства. Проверьте адрес и устройство перед повторной попыткой.", + "zh-Hant": "無法驗證對方裝置的身份,請確認連線地址和對方裝置後重試。", + "ja": "リモート デバイスの ID を確認できませんでした。再試行する前に、アドレスとリモート デバイスを確認してください。", + "ko": "원격 장치의 신원을 확인할 수 없습니다. 다시 시도하기 전에 주소와 원격 장치를 확인하십시오.", + "de": "Die Identität des Remote-Geräts konnte nicht überprüft werden. Überprüfen Sie die Adresse und das Remote-Gerät, bevor Sie es erneut versuchen.", + "fr": "Impossible de vérifier l'identité du périphérique distant. Vérifiez l'adresse et le périphérique distant avant de réessayer.", + "es": "No se pudo verificar la identidad del dispositivo remoto. Verifique la dirección y el dispositivo remoto antes de volver a intentarlo.", + "pt-BR": "Não foi possível verificar a identidade do dispositivo remoto. Verifique o endereço e o dispositivo remoto antes de tentar novamente." + }, + "日志文件": { + "zh-Hans": "日志文件", + "en": "Log file", + "ru": "Файл журнала", + "zh-Hant": "日誌檔案", + "ja": "ログファイル", + "ko": "로그 파일", + "de": "Protokolldatei", + "fr": "Fichier journal", + "es": "Archivo de registro", + "pt-BR": "Arquivo de registro" + }, + "是否撤回隐私授权?": { + "zh-Hans": "是否撤回隐私授权?", + "en": "Withdraw privacy authorization?", + "zh-Hant": "是否撤回隱私授權?", + "ja": "プライバシー認証を取り消しますか?", + "ko": "개인정보 보호 승인을 철회하시겠습니까?", + "de": "Datenschutzberechtigung entziehen?", + "fr": "Retirer l'autorisation de confidentialité ?", + "es": "¿Retirar la autorización de privacidad?", + "pt-BR": "Retirar autorização de privacidade?", + "ru": "Отозвать разрешение на конфиденциальность?" + }, + "显示主界面": { + "zh-Hans": "显示主界面", + "en": "Show Main Window", + "ru": "Показать главное окно", + "zh-Hant": "顯示主介面", + "ja": "メインウィンドウを表示", + "ko": "메인 창 표시", + "de": "Hauptfenster anzeigen", + "fr": "Afficher la fenêtre principale", + "es": "Mostrar ventana principal", + "pt-BR": "Mostrar janela principal" + }, + "显示器": { + "zh-Hans": "显示器", + "en": "Display", + "ru": "Экран", + "zh-Hant": "顯示器", + "ja": "ディスプレイ", + "ko": "디스플레이", + "de": "Bildschirm", + "fr": "Écran", + "es": "Pantalla", + "pt-BR": "Tela" + }, + "显示器 %1$@": { + "zh-Hans": "显示器 %1$@", + "en": "Monitor %1$@", + "zh-Hant": "顯示器 %1$@", + "ja": "モニター%1$@", + "ko": "모니터%1$@", + "de": "Monitor %1$@", + "fr": "Moniteur %1$@", + "es": "Monitorizar %1$@", + "pt-BR": "Monitor %1$@", + "ru": "Монитор %1$@" + }, + "显示器 1": { + "zh-Hans": "显示器 1", + "en": "Monitor 1", + "zh-Hant": "顯示器 1", + "ja": "モニター1", + "ko": "모니터 1", + "de": "Monitor 1", + "fr": "Moniteur 1", + "es": "Monitor 1", + "pt-BR": "Monitor 1", + "ru": "Монитор 1" + }, + "显示密码": { + "zh-Hans": "显示密码", + "en": "Show password", + "ru": "Показать пароль", + "zh-Hant": "顯示密碼", + "ja": "パスワードを表示", + "ko": "비밀번호 표시", + "de": "Passwort anzeigen", + "fr": "Afficher le mot de passe", + "es": "Mostrar contraseña", + "pt-BR": "Mostrar senha" + }, + "显示屏": { + "zh-Hans": "显示屏", + "en": "Display", + "ru": "Экран", + "zh-Hant": "顯示屏", + "ja": "表示", + "ko": "디스플레이", + "de": "Anzeige", + "fr": "Affichage", + "es": "Pantalla", + "pt-BR": "Exibição" + }, + "显示网络状态": { + "zh-Hans": "显示网络状态", + "en": "Show network status", + "ru": "Показать состояние сети", + "zh-Hant": "顯示網路狀態", + "ja": "ネットワークの状態を表示する", + "ko": "네트워크 상태 표시", + "de": "Netzwerkstatus anzeigen", + "fr": "Afficher l'état du réseau", + "es": "Mostrar estado de la red", + "pt-BR": "Mostrar status da rede" + }, + "暂不同意": { + "zh-Hans": "暂不同意", + "en": "Not now", + "ru": "Не сейчас", + "zh-Hant": "暫不同意", + "ja": "今は同意しない", + "ko": "나중에", + "de": "Jetzt nicht", + "fr": "Pas maintenant", + "es": "Ahora no", + "pt-BR": "Agora não" + }, + "暂无公告": { + "zh-Hans": "暂无公告", + "en": "No announcements", + "ru": "Нет объявлений", + "zh-Hant": "暫無公告", + "ja": "アナウンスはありません", + "ko": "공지 없음", + "de": "Keine Ankündigungen", + "fr": "Aucune annonce", + "es": "Sin anuncios", + "pt-BR": "Sem anúncios" + }, + "暂无已连接设备": { + "zh-Hans": "暂无已连接设备", + "en": "No connected devices", + "ru": "Нет подключённых устройств", + "zh-Hant": "暫無已連線裝置", + "ja": "接続されているデバイスがありません", + "ko": "연결된 장치가 없습니다", + "de": "Keine angeschlossenen Geräte", + "fr": "Aucun appareil connecté", + "es": "No hay dispositivos conectados", + "pt-BR": "Nenhum dispositivo conectado" + }, + "暂无设备,退出精简模式后可添加": { + "zh-Hans": "暂无设备,退出精简模式后可添加", + "en": "No devices. Exit compact mode to add devices", + "ru": "Нет устройств. Выйдите из компактного режима, чтобы добавить их", + "zh-Hant": "暫無裝置,退出精簡模式後可新增", + "ja": "デバイスはありません。コンパクト モードを終了してデバイスを追加します", + "ko": "장치가 없습니다. 기기를 추가하려면 컴팩트 모드를 종료하세요.", + "de": "Keine Geräte. Verlassen Sie den Kompaktmodus, um Geräte hinzuzufügen", + "fr": "Aucun appareil. Quitter le mode compact pour ajouter des appareils", + "es": "Sin dispositivos. Salga del modo compacto para agregar dispositivos", + "pt-BR": "Nenhum dispositivo. Saia do modo compacto para adicionar dispositivos" + }, + "暂无近期 IP 连接": { + "zh-Hans": "暂无近期 IP 连接", + "en": "No recent IP connections", + "ru": "Нет недавних IP-подключений", + "zh-Hant": "暫無近期 IP 連線", + "ja": "最近の IP 接続はありません", + "ko": "최근 IP 연결이 없습니다", + "de": "Keine aktuellen IP-Verbindungen", + "fr": "Aucune connexion IP récente", + "es": "No hay conexiones IP recientes", + "pt-BR": "Nenhuma conexão IP recente" + }, + "暂无近期连接": { + "zh-Hans": "暂无近期连接", + "en": "No recent connections", + "ru": "Нет недавних подключений", + "zh-Hant": "暫無近期連線", + "ja": "最近の接続はありません", + "ko": "최근 연결 없음", + "de": "Keine aktuellen Verbindungen", + "fr": "Aucune connexion récente", + "es": "No hay conexiones recientes", + "pt-BR": "Nenhuma conexão recente" + }, + "暂无鸿蒙版本信息,请稍后重试": { + "zh-Hans": "暂无鸿蒙版本信息,请稍后重试", + "en": "There is currently no Hongmeng version information, please try again later.", + "zh-Hant": "暫無鴻蒙版本資訊,請稍後重試", + "ja": "現在、Hongmeng のバージョン情報はありません。後でもう一度お試しください。", + "ko": "현재 홍멍 버전 정보가 없습니다. 나중에 다시 시도해 주세요.", + "de": "Derzeit liegen keine Hongmeng-Versionsinformationen vor. Bitte versuchen Sie es später erneut.", + "fr": "Il n'y a actuellement aucune information sur la version de Hongmeng, veuillez réessayer plus tard.", + "es": "Actualmente no hay información sobre la versión de Hongmeng, inténtelo de nuevo más tarde.", + "pt-BR": "Atualmente não há informações sobre a versão do Hongmeng, tente novamente mais tarde.", + "ru": "На данный момент информации о версии Hongmeng нет. Повторите попытку позже." + }, + "更多": { + "zh-Hans": "更多", + "en": "More", + "ru": "Ещё", + "zh-Hant": "更多", + "ja": "詳細", + "ko": "더보기", + "de": "Mehr", + "fr": "Plus", + "es": "Más", + "pt-BR": "Mais" + }, + "更多操作": { + "zh-Hans": "更多操作", + "en": "More actions", + "ru": "Другие действия", + "zh-Hant": "更多操作", + "ja": "その他のアクション", + "ko": "추가 작업", + "de": "Weitere Aktionen", + "fr": "Plus d'actions", + "es": "Más acciones", + "pt-BR": "Mais ações" + }, + "更新": { + "zh-Hans": "更新", + "en": "Update", + "ru": "Обновить", + "zh-Hant": "更新", + "ja": "アップデート", + "ko": "업데이트", + "de": "Aktualisieren", + "fr": "Mise à jour", + "es": "Actualización", + "pt-BR": "Atualização" + }, + "更新内容": { + "zh-Hans": "更新内容", + "en": "Release Notes", + "ru": "Содержание обновления", + "zh-Hant": "更新內容", + "ja": "リリースノート", + "ko": "릴리스 노트", + "de": "Versionshinweise", + "fr": "Notes de version", + "es": "Notas de la versión", + "pt-BR": "Notas de versão" + }, + "更新日志": { + "zh-Hans": "更新日志", + "en": "Release notes", + "ru": "История изменений", + "zh-Hant": "更新日誌", + "ja": "リリースノート", + "ko": "릴리스 노트", + "de": "Versionshinweise", + "fr": "Notes de version", + "es": "Notas de la versión", + "pt-BR": "Notas de lançamento" + }, + "更新未完成,可重试或手动安装。": { + "zh-Hans": "更新未完成,可重试或手动安装。", + "en": "Update did not complete. Retry or install manually.", + "ru": "Обновление не завершено. Повторите или установите вручную.", + "zh-Hant": "更新未完成,可重試或手動安裝。", + "ja": "アップデートが完了しませんでした。再試行するか、手動でインストールしてください。", + "ko": "업데이트가 완료되지 않았습니다. 다시 시도하거나 수동으로 설치하세요.", + "de": "Das Update wurde nicht abgeschlossen. Versuchen Sie es erneut oder installieren Sie es manuell.", + "fr": "La mise à jour n'a pas été effectuée. Réessayez ou installez manuellement.", + "es": "La actualización no se completó. Vuelva a intentarlo o instálelo manualmente.", + "pt-BR": "A atualização não foi concluída. Tente novamente ou instale manualmente." + }, + "最后一个远程控制端断开后,自动锁定本机。": { + "zh-Hans": "最后一个远程控制端断开后,自动锁定本机。", + "en": "Lock this device when the last remote controller disconnects.", + "ru": "Блокировать это устройство после отключения последнего управляющего клиента.", + "zh-Hant": "最後一個遠端控制端斷開後,自動鎖定本機。", + "ja": "最後の送信機が切断されたときに、このデバイスをロックします。", + "ko": "마지막 리모컨의 연결이 끊어지면 이 장치를 잠급니다.", + "de": "Sperren Sie dieses Gerät, wenn die letzte Fernbedienung getrennt wird.", + "fr": "Verrouillez cet appareil lorsque la dernière télécommande se déconnecte.", + "es": "Bloquee este dispositivo cuando se desconecte el último control remoto.", + "pt-BR": "Bloqueie este dispositivo quando o último controle remoto for desconectado." + }, + "最大化": { + "zh-Hans": "最大化", + "en": "Maximize", + "ru": "Развернуть", + "zh-Hant": "最大化", + "ja": "最大化", + "ko": "최대화", + "de": "Maximieren", + "fr": "Maximiser", + "es": "Maximizar", + "pt-BR": "Maximizar" + }, + "最小化": { + "zh-Hans": "最小化", + "en": "Minimize", + "ru": "Свернуть", + "zh-Hant": "最小化", + "ja": "最小化", + "ko": "최소화", + "de": "Minimieren", + "fr": "Réduire", + "es": "Minimizar", + "pt-BR": "Minimizar" + }, + "最近连接": { + "zh-Hans": "最近连接", + "en": "Recent connections", + "zh-Hant": "最近連線", + "ja": "最近の接続", + "ko": "최근 연결", + "de": "Letzte Verbindungen", + "fr": "Connexions récentes", + "es": "Conexiones recientes", + "pt-BR": "Conexões recentes", + "ru": "Недавние связи" + }, + "有远程会话或密码修改正在进行,暂时不能更改连接设置。": { + "zh-Hans": "有远程会话或密码修改正在进行,暂时不能更改连接设置。", + "en": "Connection settings cannot change during a remote session or password change.", + "ru": "Нельзя менять параметры подключения во время удалённого сеанса или смены пароля.", + "zh-Hant": "有遠端會話或密碼修改正在進行,暫時不能更改連線設定。", + "ja": "リモート セッション中またはパスワード変更中に接続設定を変更することはできません。", + "ko": "원격 세션이나 비밀번호 변경 중에는 연결 설정을 변경할 수 없습니다.", + "de": "Verbindungseinstellungen können während einer Remote-Sitzung oder Passwortänderung nicht geändert werden.", + "fr": "Les paramètres de connexion ne peuvent pas changer pendant une session à distance ou un changement de mot de passe.", + "es": "La configuración de conexión no puede cambiar durante una sesión remota o un cambio de contraseña.", + "pt-BR": "As configurações de conexão não podem ser alteradas durante uma sessão remota ou alteração de senha." + }, + "服务器": { + "zh-Hans": "服务器", + "en": "Server", + "zh-Hant": "伺服器", + "ja": "サーバー", + "ko": "서버", + "de": "Server", + "fr": "Serveur", + "es": "Servidor", + "pt-BR": "Servidor", + "ru": "Сервер" + }, + "服务器 TLS 证书校验失败": { + "zh-Hans": "服务器 TLS 证书校验失败", + "en": "Server TLS certificate verification failed", + "zh-Hant": "伺服器 TLS 證書校驗失敗", + "ja": "ServerTLS証明書の検証に失敗しました", + "ko": "ServerTLS인증서 확인 실패", + "de": "Server TLS certificate-Überprüfung fehlgeschlagen", + "fr": "La vérification du certificat Server TLS a échoué", + "es": "Error en la verificación del certificado Server TLS", + "pt-BR": "Falha na verificação do certificado Server TLS", + "ru": "Проверка Server TLS certificate не удалась." + }, + "服务器地址": { + "zh-Hans": "服务器地址", + "en": "Server Address", + "ru": "Адрес сервера", + "zh-Hant": "伺服器地址", + "ja": "サーバーアドレス", + "ko": "서버 주소", + "de": "Serveradresse", + "fr": "Adresse du serveur", + "es": "Dirección del servidor", + "pt-BR": "Endereço do servidor" + }, + "服务器已断开": { + "zh-Hans": "服务器已断开", + "en": "Server disconnected", + "zh-Hant": "伺服器已斷開", + "ja": "サーバーが切断されました", + "ko": "서버 연결이 끊어졌습니다.", + "de": "Serververbindung getrennt", + "fr": "Serveur déconnecté", + "es": "Servidor desconectado", + "pt-BR": "Servidor desconectado", + "ru": "Сервер отключен" + }, + "服务器已确认密码修改,正在重新连接。": { + "zh-Hans": "服务器已确认密码修改,正在重新连接。", + "en": "Server confirmed the password change; reconnecting.", + "ru": "Сервер подтвердил смену пароля. Повторное подключение.", + "zh-Hant": "伺服器已確認密碼修改,正在重新連線。", + "ja": "サーバーはパスワードの変更を確認しました。再接続中。", + "ko": "서버가 비밀번호 변경을 확인했습니다. 다시 연결 중.", + "de": "Der Server hat die Passwortänderung bestätigt. wieder verbinden.", + "fr": "Le serveur a confirmé le changement de mot de passe ; reconnexion.", + "es": "El servidor confirmó el cambio de contraseña; reconectando.", + "pt-BR": "O servidor confirmou a alteração da senha; reconectando." + }, + "服务器未接受密码修改,原密码保持不变。详情见日志。": { + "zh-Hans": "服务器未接受密码修改,原密码保持不变。详情见日志。", + "en": "Server rejected the password change; the original password remains. See the log.", + "ru": "Сервер отклонил смену пароля. Старый пароль сохранён. См. журнал.", + "zh-Hant": "伺服器未接受密碼修改,原密碼保持不變。詳情見日誌。", + "ja": "サーバーがパスワードの変更を拒否しました。元のパスワードはそのまま残ります。ログを参照してください。", + "ko": "서버가 비밀번호 변경을 거부했습니다. 원래 비밀번호는 그대로 유지됩니다. 로그를 참조하세요.", + "de": "Der Server hat die Passwortänderung abgelehnt. das ursprüngliche Passwort bleibt erhalten. Siehe das Protokoll.", + "fr": "Le serveur a rejeté le changement de mot de passe ; le mot de passe d'origine reste. Voir le journal.", + "es": "El servidor rechazó el cambio de contraseña; la contraseña original permanece. Ver el registro.", + "pt-BR": "O servidor rejeitou a alteração da senha; a senha original permanece. Veja o registro." + }, + "服务器登录失败,请检查服务器地址和网络": { + "zh-Hans": "服务器登录失败,请检查服务器地址和网络", + "en": "Server login failed, please check the server address and network", + "zh-Hant": "伺服器登入失敗,請檢查伺服器地址和網路", + "ja": "サーバーへのログインに失敗しました。サーバーのアドレスとネットワークを確認してください。", + "ko": "서버 로그인에 실패했습니다. 서버 주소와 네트워크를 확인해주세요.", + "de": "Die Serveranmeldung ist fehlgeschlagen. Bitte überprüfen Sie die Serveradresse und das Netzwerk", + "fr": "Échec de la connexion au serveur, veuillez vérifier l'adresse du serveur et le réseau", + "es": "Error al iniciar sesión en el servidor; verifique la dirección y la red del servidor", + "pt-BR": "Falha no login do servidor, verifique o endereço do servidor e a rede", + "ru": "Не удалось войти на сервер, проверьте адрес сервера и сеть." + }, + "服务器端口": { + "zh-Hans": "服务器端口", + "en": "Server port", + "zh-Hant": "伺服器埠", + "ja": "サーバーポート", + "ko": "서버 포트", + "de": "Server-Port", + "fr": "Port du serveur", + "es": "Puerto del servidor", + "pt-BR": "Porta do servidor", + "ru": "Порт сервера" + }, + "服务器证书校验失败": { + "zh-Hans": "服务器证书校验失败", + "en": "Server certificate verification failed", + "zh-Hant": "伺服器證書校驗失敗", + "ja": "サーバー証明書の検証に失敗しました", + "ko": "서버 인증서 확인 실패", + "de": "Die Überprüfung des Serverzertifikats ist fehlgeschlagen", + "fr": "La vérification du certificat du serveur a échoué", + "es": "Error en la verificación del certificado del servidor", + "pt-BR": "Falha na verificação do certificado do servidor", + "ru": "Проверка сертификата сервера не удалась." + }, + "服务器连接超时,请检查服务器地址和网络": { + "zh-Hans": "服务器连接超时,请检查服务器地址和网络", + "en": "Server connection timed out, please check the server address and network", + "zh-Hant": "伺服器連線超時,請檢查伺服器地址和網路", + "ja": "サーバー接続がタイムアウトしました。サーバーのアドレスとネットワークを確認してください。", + "ko": "서버 연결 시간이 초과되었습니다. 서버 주소와 네트워크를 확인하세요.", + "de": "Zeitüberschreitung bei der Serververbindung. Bitte überprüfen Sie die Serveradresse und das Netzwerk", + "fr": "La connexion au serveur a expiré, veuillez vérifier l'adresse du serveur et le réseau", + "es": "Se agotó el tiempo de espera de la conexión del servidor; verifique la dirección y la red del servidor.", + "pt-BR": "A conexão do servidor expirou, verifique o endereço do servidor e a rede", + "ru": "Тайм-аут подключения к серверу истек, проверьте адрес сервера и сеть." + }, + "服务器配置无效": { + "zh-Hans": "服务器配置无效", + "en": "Invalid server configuration", + "zh-Hant": "伺服器配置無效", + "ja": "無効なサーバー構成", + "ko": "잘못된 서버 구성", + "de": "Ungültige Serverkonfiguration", + "fr": "Configuration du serveur invalide", + "es": "Configuración del servidor no válida", + "pt-BR": "Configuração de servidor inválida", + "ru": "Неверная конфигурация сервера." + }, + "服务安装失败。请确认 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位于同一便携目录中,并在系统弹窗中允许管理员权限。": { + "zh-Hans": "服务安装失败。请确认 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位于同一便携目录中,并在系统弹窗中允许管理员权限。", + "en": "Service installation failed. Make sure CrossDesk.exe, crossdesk_service.exe, and crossdesk_session_helper.exe are in the same portable folder, then approve the administrator prompt.", + "ru": "Не удалось установить службу. Убедитесь, что CrossDesk.exe, crossdesk_service.exe и crossdesk_session_helper.exe находятся в одной папке портативной версии, затем подтвердите запрос прав администратора.", + "zh-Hant": "服務安裝失敗。請確認 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位於同一便攜目錄中,並在系統彈窗中允許管理員許可權。", + "ja": "サービスのインストールに失敗しました。CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe が同じポータブル フォルダー内にあることを確認し、管理者プロンプトを承認します。", + "ko": "서비스 설치에 실패했습니다.CrossDesk.exe, crossdesk_service.exe 및 crossdesk_session_helper.exe가 동일한 휴대용 폴더에 있는지 확인한 다음 관리자 프롬프트를 승인하십시오.", + "de": "Die Installation des Dienstes ist fehlgeschlagen. Stellen Sie sicher, dass sich CrossDesk.exe, crossdesk_service.exe und crossdesk_session_helper.exe im selben tragbaren Ordner befinden, und genehmigen Sie dann die Administratoraufforderung.", + "fr": "L'installation du service a échoué. Assurez-vous que CrossDesk.exe, crossdesk_service.exe et crossdesk_session_helper.exe se trouvent dans le même dossier portable, puis approuvez l'invite de l'administrateur.", + "es": "Error en la instalación del servicio. Asegúrese de que CrossDesk.exe, crossdesk_service.exe y crossdesk_session_helper.exe estén en la misma carpeta portátil y luego apruebe el mensaje del administrador.", + "pt-BR": "Falha na instalação do serviço. Certifique-se de que CrossDesk.exe, crossdesk_service.exe e crossdesk_session_helper.exe estejam na mesma pasta portátil e aprove o prompt do administrador." + }, + "服务已安装并启动": { + "zh-Hans": "服务已安装并启动", + "en": "Service installed and started", + "ru": "Служба установлена и запущена", + "zh-Hant": "服務已安裝並啟動", + "ja": "サービスのインストールと開始", + "ko": "서비스 설치 및 시작", + "de": "Dienst installiert und gestartet", + "fr": "Service installé et démarré", + "es": "Servicio instalado e iniciado", + "pt-BR": "Serviço instalado e iniciado" + }, + "未分组": { + "zh-Hans": "未分组", + "en": "Ungrouped", + "ru": "Без группы", + "zh-Hant": "未分組", + "ja": "グループ化されていない", + "ko": "그룹 해제됨", + "de": "Nicht gruppiert", + "fr": "Non groupé", + "es": "Desagrupado", + "pt-BR": "Desagrupado" + }, + "未加密": { + "zh-Hans": "未加密", + "en": "Unencrypted", + "ru": "Без шифр.", + "zh-Hant": "未加密", + "ja": "非暗号化", + "ko": "암호화되지 않음", + "de": "Unverschlüsselt", + "fr": "Non crypté", + "es": "Sin cifrar", + "pt-BR": "Não criptografado" + }, + "未勾选": { + "zh-Hans": "未勾选", + "en": "Not checked", + "zh-Hant": "未勾選", + "ja": "チェックなし", + "ko": "체크하지 않음", + "de": "Nicht überprüft", + "fr": "Non coché", + "es": "No marcado", + "pt-BR": "Não verificado", + "ru": "Не отмечено" + }, + "未启用": { + "zh-Hans": "未启用", + "en": "Not enabled", + "zh-Hant": "未啟用", + "ja": "有効ではありません", + "ko": "활성화되지 않음", + "de": "Nicht aktiviert", + "fr": "Non activé", + "es": "No habilitado", + "pt-BR": "Não habilitado", + "ru": "Не включено" + }, + "未开启": { + "zh-Hans": "未开启", + "en": "Disabled", + "ru": "Выключен", + "zh-Hant": "未開啟", + "ja": "無効", + "ko": "비활성화됨", + "de": "Deaktiviert", + "fr": "Désactivé", + "es": "Deshabilitado", + "pt-BR": "Desativado" + }, + "未找到可打开链接的浏览器": { + "zh-Hans": "未找到可打开链接的浏览器", + "en": "No browser found to open the link", + "zh-Hant": "未找到可開啟連結的瀏覽器", + "ja": "リンクを開くブラウザが見つかりませんでした", + "ko": "링크를 열 수 있는 브라우저가 없습니다.", + "de": "Es wurde kein Browser zum Öffnen des Links gefunden", + "fr": "Aucun navigateur trouvé pour ouvrir le lien", + "es": "No se encontró ningún navegador para abrir el enlace.", + "pt-BR": "Nenhum navegador encontrado para abrir o link", + "ru": "Не найден браузер, в котором можно было бы открыть ссылку." + }, + "未找到可用的局域网连接。": { + "zh-Hans": "未找到可用的局域网连接。", + "en": "No local network connection was found.", + "ru": "Нет доступного подключения к LAN.", + "zh-Hant": "未找到可用的區域網連線。", + "ja": "ローカル ネットワーク接続が見つかりませんでした。", + "ko": "로컬 네트워크 연결을 찾을 수 없습니다.", + "de": "Es wurde keine lokale Netzwerkverbindung gefunden.", + "fr": "Aucune connexion au réseau local n'a été trouvée.", + "es": "No se encontró ninguna conexión de red local.", + "pt-BR": "Nenhuma conexão de rede local foi encontrada." + }, + "未授权": { + "zh-Hans": "未授权", + "en": "Unauthorized", + "zh-Hant": "未授權", + "ja": "無許可", + "ko": "무단", + "de": "Nicht autorisiert", + "fr": "Non autorisé", + "es": "No autorizado", + "pt-BR": "Não autorizado", + "ru": "Несанкционированное" + }, + "未知": { + "zh-Hans": "未知", + "en": "Unknown", + "ru": "Неизвестно", + "zh-Hant": "未知", + "ja": "不明", + "ko": "알 수 없음", + "de": "Unbekannt", + "fr": "Inconnu", + "es": "Desconocido", + "pt-BR": "Desconhecido" + }, + "未知信令状态": { + "zh-Hans": "未知信令状态", + "en": "Unknown signaling status", + "zh-Hant": "未知信令狀態", + "ja": "不明な信号ステータス", + "ko": "알 수 없는 신호 상태", + "de": "Unbekannter Signalisierungsstatus", + "fr": "État de signalisation inconnu", + "es": "Estado de señalización desconocido", + "pt-BR": "Status de sinalização desconhecido", + "ru": "Неизвестный статус сигнализации" + }, + "未知命令,输入 help 查看帮助。": { + "zh-Hans": "未知命令,输入 help 查看帮助。", + "en": "Unknown command. Enter help for commands.", + "ru": "Неизвестная команда. Введите help для справки.", + "zh-Hant": "未知命令,輸入 help 檢視幫助。", + "ja": "不明なコマンドです。コマンドのヘルプを入力します。", + "ko": "알 수 없는 명령입니다. 명령에 대한 도움말을 입력합니다.", + "de": "Unbekannter Befehl. Geben Sie Hilfe für Befehle ein.", + "fr": "Commande inconnue. Entrez l'aide pour les commandes.", + "es": "Comando desconocido. Ingrese ayuda para los comandos.", + "pt-BR": "Comando desconhecido. Insira ajuda para comandos." + }, + "未知平台": { + "zh-Hans": "未知平台", + "en": "Unknown platform", + "ru": "Неизвестная платформа", + "zh-Hant": "未知平臺", + "ja": "不明なプラットフォーム", + "ko": "알 수 없는 플랫폼", + "de": "Unbekannte Plattform", + "fr": "Plateforme inconnue", + "es": "Plataforma desconocida", + "pt-BR": "Plataforma desconhecida" + }, + "未知连接状态": { + "zh-Hans": "未知连接状态", + "en": "Unknown connection status", + "zh-Hant": "未知連線狀態", + "ja": "不明な接続ステータス", + "ko": "알 수 없는 연결 상태", + "de": "Unbekannter Verbindungsstatus", + "fr": "État de connexion inconnu", + "es": "Estado de conexión desconocido", + "pt-BR": "Status de conexão desconhecido", + "ru": "Неизвестный статус соединения" + }, + "未读": { + "zh-Hans": "未读", + "en": "Unread", + "ru": "Не прочитано", + "zh-Hant": "未讀", + "ja": "未読", + "ko": "읽지 않음", + "de": "Ungelesen", + "fr": "Non lu", + "es": "No leído", + "pt-BR": "Não lido" + }, + "未连接": { + "zh-Hans": "未连接", + "en": "Not connected", + "ru": "Нет соединения", + "zh-Hant": "未連線", + "ja": "接続されていません", + "ko": "연결되지 않음", + "de": "Nicht verbunden", + "fr": "Non connecté", + "es": "No conectado", + "pt-BR": "Não conectado" + }, + "未连接服务器": { + "zh-Hans": "未连接服务器", + "en": "Disconnected from server", + "ru": "Нет подключения к серверу", + "zh-Hant": "未連線伺服器", + "ja": "サーバーから切断されました", + "ko": "서버와의 연결이 끊겼습니다.", + "de": "Vom Server getrennt", + "fr": "Déconnecté du serveur", + "es": "Desconectado del servidor", + "pt-BR": "Desconectado do servidor" + }, + "未连接服务器 · 点击重试": { + "zh-Hans": "未连接服务器 · 点击重试", + "en": "Server not connected · Click to try again", + "zh-Hant": "未連線伺服器 · 點選重試", + "ja": "サーバーが接続されていません · クリックして再試行してください", + "ko": "서버가 연결되지 않았습니다. · 다시 시도하려면 클릭하세요.", + "de": "Server nicht verbunden · Klicken Sie, um es erneut zu versuchen", + "fr": "Serveur non connecté · Cliquez pour réessayer", + "es": "Servidor no conectado · Haga clic para intentar nuevamente", + "pt-BR": "Servidor não conectado · Clique para tentar novamente", + "ru": "Сервер не подключен · Нажмите, чтобы повторить попытку." + }, + "本地存储": { + "zh-Hans": "本地存储", + "en": "Local storage", + "ru": "Локальное хранение", + "zh-Hant": "本地儲存", + "ja": "ローカルストレージ", + "ko": "로컬 스토리지", + "de": "Lokaler Speicher", + "fr": "Stockage local", + "es": "Almacenamiento local", + "pt-BR": "Armazenamento local" + }, + "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。": { + "zh-Hans": "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", + "en": "This application uses OpenFEC for forward error correction under CeCILL-C 1.0, which provides limited warranties and limits liability. See the full license for details.", + "ru": "Приложение использует OpenFEC для прямого исправления ошибок по лицензии CeCILL-C 1.0 с ограниченной гарантией и ответственностью. Подробности — в тексте лицензии.", + "zh-Hant": "本應用使用 OpenFEC 提供前向糾錯功能,遵循 CeCILL-C 1.0 許可。該許可規定了有限保證及責任限制,詳情見許可全文。", + "ja": "このアプリケーションは、限定保証を提供し、責任を制限するCeCILL-C1.0 に基づく前方誤り訂正にOpenFECを使用します。詳細については、完全なライセンスを参照してください。", + "ko": "이 애플리케이션은 제한된 보증과 책임 제한을 제공하는CeCILL-C1.0에 따라 순방향 오류 수정을 위해OpenFEC를 사용합니다. 자세한 내용은 전체 라이센스를 참조하세요.", + "de": "Diese Anwendung verwendet OpenFEC zur Vorwärtsfehlerkorrektur unterCeCILL-C1.0, was eingeschränkte Garantien und Haftungsbeschränkungen bietet. Einzelheiten finden Sie in der vollständigen Lizenz.", + "fr": "Cette application utilise OpenFEC pour la correction d'erreur directe sousCeCILL-C1.0, qui offre des garanties limitées et limite la responsabilité. Consultez la licence complète pour plus de détails.", + "es": "Esta aplicación utiliza OpenFEC para la corrección de errores directos bajoCeCILL-C1.0, que proporciona garantías limitadas y limita la responsabilidad. Consulte la licencia completa para obtener más detalles.", + "pt-BR": "Este aplicativo usa OpenFEC para correção direta de erros noCeCILL-C1.0, que fornece garantias limitadas e limita a responsabilidade. Veja a licença completa para detalhes." + }, + "本机 ID": { + "zh-Hans": "本机 ID", + "en": "Local ID", + "ru": "Локальный ID", + "zh-Hant": "本機 ID", + "ja": "ローカルID", + "ko": "로컬 ID", + "de": "Lokale ID", + "fr": "ID local", + "es": "Identificación local", + "pt-BR": "ID local" + }, + "本机 ID ": { + "zh-Hans": "本机 ID ", + "en": "Local ID ", + "zh-Hant": "本機 ID ", + "ja": "ローカルID ", + "ko": "로컬 ID ", + "de": "Lokale ID ", + "fr": "ID local ", + "es": "Identificación local ", + "pt-BR": "ID local ", + "ru": "Местный идентификатор " + }, + "本机 ID %1$@": { + "zh-Hans": "本机 ID %1$@", + "en": "Local ID %1$@", + "zh-Hant": "本機 ID %1$@", + "ja": "ローカルID%1$@", + "ko": "로컬 ID%1$@", + "de": "Lokale ID %1$@", + "fr": "ID local %1$@", + "es": "ID local %1$@", + "pt-BR": "ID local %1$@", + "ru": "Локальный идентификатор %1$@" + }, + "本机 ID {0}": { + "zh-Hans": "本机 ID {0}", + "en": "Local ID {0}", + "zh-Hant": "本機 ID {0}", + "ja": "ローカルID{0}", + "ko": "로컬 ID{0}", + "de": "Lokale ID {0}", + "fr": "ID local {0}", + "es": "ID local {0}", + "pt-BR": "ID local {0}", + "ru": "Локальный идентификатор {0}" + }, + "本机 IP / 端口": { + "zh-Hans": "本机 IP / 端口", + "en": "Local IP / Port", + "ru": "IP / Порт", + "zh-Hant": "本機 IP / 埠", + "ja": "ローカルIP/ポート", + "ko": "로컬 IP / 포트", + "de": "Lokale IP/Port", + "fr": "IP/Port local", + "es": "IP local/puerto", + "pt-BR": "IP/Porta Local" + }, + "本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。": { + "zh-Hans": "本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。", + "en": "The login credentials for this machine are temporarily insecure. Please unlock your device and click \"Apply\" in settings to try again.", + "zh-Hant": "本機登入憑據暫時無法安全存取。請解鎖裝置後,在設定中點選“應用”重試。", + "ja": "このマシンのログイン資格情報は一時的に安全ではありません。デバイスのロックを解除し、設定で「適用」をクリックして再試行してください。", + "ko": "이 시스템의 로그인 자격 증명은 일시적으로 안전하지 않습니다. 기기를 잠금 해제하고 설정에서 '적용'을 클릭하여 다시 시도하세요.", + "de": "Die Anmeldeinformationen für diesen Computer sind vorübergehend unsicher. Bitte entsperren Sie Ihr Gerät und klicken Sie in den Einstellungen auf „Übernehmen“, um es erneut zu versuchen.", + "fr": "Les informations de connexion pour cette machine ne sont temporairement pas sécurisées. Veuillez déverrouiller votre appareil et cliquer sur « Appliquer » dans les paramètres pour réessayer.", + "es": "Las credenciales de inicio de sesión para esta máquina son temporalmente inseguras. Desbloquee su dispositivo y haga clic en \"Aplicar\" en la configuración para volver a intentarlo.", + "pt-BR": "As credenciais de login desta máquina são temporariamente inseguras. Desbloqueie seu dispositivo e clique em \"Aplicar\" nas configurações para tentar novamente.", + "ru": "Учетные данные для входа на этот компьютер временно небезопасны. Пожалуйста, разблокируйте свое устройство и нажмите «Применить» в настройках, чтобы повторить попытку." + }, + "本桌面": { + "zh-Hans": "本桌面", + "en": "Local Desktop", + "ru": "Локальный рабочий стол", + "zh-Hant": "本桌面", + "ja": "ローカルデスクトップ", + "ko": "로컬 데스크톱", + "de": "Lokaler Desktop", + "fr": "Bureau local", + "es": "Escritorio local", + "pt-BR": "Área de trabalho local" + }, + "本版本源码与构建说明": { + "zh-Hans": "本版本源码与构建说明", + "en": "Source code and build instructions for this version", + "zh-Hant": "本版本原始碼與構建說明", + "ja": "このバージョンのソース コードとビルド手順", + "ko": "이 버전의 소스 코드 및 빌드 지침", + "de": "Quellcode und Build-Anweisungen für diese Version", + "fr": "Code source et instructions de construction pour cette version", + "es": "Código fuente e instrucciones de compilación para esta versión", + "pt-BR": "Código-fonte e instruções de construção para esta versão", + "ru": "Исходный код и инструкции по сборке этой версии." + }, + "本版本源码信息暂不可用。": { + "zh-Hans": "本版本源码信息暂不可用。", + "en": "Source revision is unavailable for this build.", + "ru": "Ревизия исходного кода этой сборки недоступна.", + "zh-Hant": "本版本原始碼資訊暫不可用。", + "ja": "このビルドではソース リビジョンが利用できません。", + "ko": "이 빌드에는 소스 개정을 사용할 수 없습니다.", + "de": "Die Quellrevision ist für diesen Build nicht verfügbar.", + "fr": "La révision source n'est pas disponible pour cette version.", + "es": "La revisión fuente no está disponible para esta compilación.", + "pt-BR": "A revisão fonte não está disponível para esta compilação." + }, + "本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。": { + "zh-Hans": "本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", + "en": "License text is not bundled for this component. Use View source code to read its license and copyright notices.", + "ru": "Текст лицензии не включён. Откройте исходный код для просмотра лицензии и авторских прав.", + "zh-Hant": "本元件未內建許可文字,請透過“檢視原始碼”查閱許可與版權宣告。", + "ja": "このコンポーネントにはライセンス テキストはバンドルされていません。 [ソース コードの表示] を使用して、ライセンスと著作権表示を確認します。", + "ko": "이 구성 요소에 대한 라이센스 텍스트는 번들로 제공되지 않습니다. 라이센스 및 저작권 고지를 읽으려면 소스 코드 보기를 사용하십시오.", + "de": "Der Lizenztext ist für diese Komponente nicht gebündelt. Verwenden Sie „Quellcode anzeigen“, um die Lizenz- und Urheberrechtshinweise zu lesen.", + "fr": "Le texte de la licence n'est pas regroupé pour ce composant. Utilisez Afficher le code source pour lire ses avis de licence et de droits d'auteur.", + "es": "El texto de la licencia no está incluido para este componente. Utilice Ver código fuente para leer sus avisos de licencia y derechos de autor.", + "pt-BR": "O texto da licença não está incluído neste componente. Use Exibir código-fonte para ler seus avisos de licença e direitos autorais." + }, + "权限请求": { + "zh-Hans": "权限请求", + "en": "Request Permissions", + "ru": "Запрос разрешений", + "zh-Hant": "許可權請求", + "ja": "権限のリクエスト", + "ko": "권한 요청", + "de": "Berechtigungen anfordern", + "fr": "Demander des autorisations", + "es": "Solicitar permisos", + "pt-BR": "Solicitar permissões" + }, + "松开刷新": { + "zh-Hans": "松开刷新", + "en": "Release to refresh", + "zh-Hant": "鬆開重新整理", + "ja": "放してリフレッシュ", + "ko": "새로고침하려면 릴리즈하세요", + "de": "Zum Aktualisieren loslassen", + "fr": "Relâchez pour actualiser", + "es": "Suelte para actualizar", + "pt-BR": "Solte para atualizar", + "ru": "Отпустите, чтобы обновить" + }, + "松开鼠标交换位置": { + "zh-Hans": "松开鼠标交换位置", + "en": "Release to swap", + "ru": "Отпустите для обмена", + "zh-Hant": "鬆開滑鼠交換位置", + "ja": "リリースしてスワップする", + "ko": "스왑으로 릴리스", + "de": "Zum Tauschen loslassen", + "fr": "Relâcher pour échanger", + "es": "Liberar para intercambiar", + "pt-BR": "Liberar para trocar" + }, + "构建文档": { + "zh-Hans": "构建文档", + "en": "Build documentation", + "zh-Hant": "構建文件", + "ja": "ビルドドキュメント", + "ko": "문서 작성", + "de": "Build-Dokumentation", + "fr": "Construire la documentation", + "es": "Documentación de compilación", + "pt-BR": "Documentação de construção", + "ru": "Документация по сборке" + }, + "构建说明": { + "zh-Hans": "构建说明", + "en": "Build instructions", + "ru": "Инструкции по сборке", + "zh-Hant": "構建說明", + "ja": "組み立て説明書", + "ko": "빌드 지침", + "de": "Bauanleitung", + "fr": "Instructions de construction", + "es": "Instrucciones de construcción", + "pt-BR": "Instruções de construção" + }, + "构建配方与项目补丁": { + "zh-Hans": "构建配方与项目补丁", + "en": "Build recipes and project patches", + "zh-Hant": "構建配方與專案補丁", + "ja": "ビルドレシピとプロジェクトパッチ", + "ko": "레시피 및 프로젝트 패치 빌드", + "de": "Erstellen Sie Rezepte und Projekt-Patches", + "fr": "Créer des recettes et des correctifs de projet", + "es": "Crear recetas y parches de proyectos", + "pt-BR": "Crie receitas e patches de projeto", + "ru": "Рецепты сборки и исправления проектов." + }, + "查看源码": { + "zh-Hans": "查看源码", + "en": "View source code", + "ru": "Открыть исходный код", + "zh-Hant": "檢視原始碼", + "ja": "ソースコードを表示する", + "ko": "소스코드 보기", + "de": "Quellcode anzeigen", + "fr": "Afficher le code source", + "es": "Ver código fuente", + "pt-BR": "Ver código-fonte" + }, + "查看联网说明": { + "zh-Hans": "查看联网说明", + "en": "View networking instructions", + "zh-Hant": "檢視聯網說明", + "ja": "ネットワークの手順を表示する", + "ko": "네트워킹 지침 보기", + "de": "Netzwerkanweisungen anzeigen", + "fr": "Afficher les instructions de mise en réseau", + "es": "Ver instrucciones de red", + "pt-BR": "Ver instruções de rede", + "ru": "Просмотр инструкций по работе в сети" + }, + "桌面": { + "zh-Hans": "桌面", + "en": "Desktop", + "ru": "Рабочий стол", + "zh-Hant": "桌面", + "ja": "デスクトップ", + "ko": "데스크탑", + "de": "Desktop", + "fr": "Bureau", + "es": "Escritorio", + "pt-BR": "Área de Trabalho" + }, + "桌面墙": { + "zh-Hans": "桌面墙", + "en": "DeskHub", + "ru": "DeskHub", + "zh-Hant": "桌面牆", + "ja": "DeskHub", + "ko": "DeskHub", + "de": "DeskHub", + "fr": "DeskHub", + "es": "DeskHub", + "pt-BR": "DeskHub" + }, + "检查失败,请稍后重试": { + "zh-Hans": "检查失败,请稍后重试", + "en": "Check failed. Please try again later.", + "ru": "Не удалось проверить обновления. Повторите позже.", + "zh-Hant": "檢查失敗,請稍後重試", + "ja": "チェックに失敗しました。後でもう一度試してください。", + "ko": "확인에 실패했습니다. 나중에 다시 시도해 주세요.", + "de": "Prüfung fehlgeschlagen. Bitte versuchen Sie es später noch einmal.", + "fr": "La vérification a échoué. Veuillez réessayer plus tard.", + "es": "La verificación falló. Inténtelo de nuevo más tarde.", + "pt-BR": "Falha na verificação. Por favor, tente novamente mais tarde." + }, + "检查更新": { + "zh-Hans": "检查更新", + "en": "Check for updates", + "ru": "Проверить обновления", + "zh-Hant": "檢查更新", + "ja": "アップデートを確認する", + "ko": "업데이트 확인", + "de": "Suchen Sie nach Updates", + "fr": "Rechercher des mises à jour", + "es": "Buscar actualizaciones", + "pt-BR": "Verifique se há atualizações" + }, + "检测到当前桌面会话使用 Wayland。": { + "zh-Hans": "检测到当前桌面会话使用 Wayland。", + "en": "The current desktop session uses Wayland.", + "ru": "Текущий сеанс рабочего стола использует Wayland.", + "zh-Hant": "檢測到當前桌面會話使用 Wayland。", + "ja": "現在のデスクトップ セッションは Wayland を使用しています。", + "ko": "현재 데스크톱 세션은 Wayland를 사용합니다.", + "de": "Die aktuelle Desktop-Sitzung verwendet Wayland.", + "fr": "La session de bureau actuelle utilise Wayland.", + "es": "La sesión de escritorio actual utiliza Wayland.", + "pt-BR": "A sessão atual da área de trabalho usa Wayland." + }, + "正在传输": { + "zh-Hans": "正在传输", + "en": "Sending", + "ru": "Передача", + "zh-Hant": "正在傳輸", + "ja": "送信", + "ko": "보내는 중", + "de": "Senden", + "fr": "Envoi", + "es": "Envío", + "pt-BR": "Envio" + }, + "正在关闭隐私屏…": { + "zh-Hans": "正在关闭隐私屏…", + "en": "Closing privacy screen…", + "zh-Hant": "正在關閉隱私屏…", + "ja": "プライバシー画面を閉じています…", + "ko": "개인정보 보호 화면을 닫는 중…", + "de": "Sichtschutz wird geschlossen…", + "fr": "Fermeture de l'écran de confidentialité…", + "es": "Cerrando la pantalla de privacidad...", + "pt-BR": "Fechando a tela de privacidade…", + "ru": "Закрытие экрана конфиденциальности…" + }, + "正在准备更新…": { + "zh-Hans": "正在准备更新…", + "en": "Preparing update…", + "ru": "Подготовка обновления…", + "zh-Hant": "正在準備更新…", + "ja": "アップデートを準備しています…", + "ko": "업데이트 준비 중…", + "de": "Update wird vorbereitet…", + "fr": "Préparation de la mise à jour…", + "es": "Preparando actualización…", + "pt-BR": "Preparando atualização…" + }, + "正在准备连接…": { + "zh-Hans": "正在准备连接…", + "en": "Preparing to connect...", + "zh-Hant": "正在準備連線…", + "ja": "接続準備中...", + "ko": "연결 준비 중...", + "de": "Verbindung wird vorbereitet...", + "fr": "Préparation de la connexion...", + "es": "Preparándose para conectarse...", + "pt-BR": "Preparando para conectar...", + "ru": "Подготовка к подключению..." + }, + "正在加载…": { + "zh-Hans": "正在加载…", + "en": "Loading…", + "ru": "Загрузка…", + "zh-Hant": "正在載入…", + "ja": "読み込み中…", + "ko": "로드 중…", + "de": "Laden…", + "fr": "Chargement…", + "es": "Cargando…", + "pt-BR": "Carregando…" + }, + "正在发送 %1$@": { + "zh-Hans": "正在发送 %1$@", + "en": "Sending %1$@", + "zh-Hant": "正在傳送 %1$@", + "ja": "%1$@の送信", + "ko": "%1$@보내기", + "de": "Senden von %1$@", + "fr": "Envoi de %1$@", + "es": "Envío de %1$@", + "pt-BR": "Enviando %1$@", + "ru": "Отправка %1$@" + }, + "正在发送 Ctrl+Alt+Del…": { + "zh-Hans": "正在发送 Ctrl+Alt+Del…", + "en": "Sending Ctrl+Alt+Del…", + "zh-Hant": "正在傳送 Ctrl+Alt+Del…", + "ja": "Ctrl+Alt+Delを送信中 …", + "ko": "Ctrl+Alt+Del를 보내는 중…", + "de": "Senden von Ctrl+Alt+Del…", + "fr": "Envoi de Ctrl+Alt+Del…", + "es": "Enviando Ctrl+Alt+Del…", + "pt-BR": "Enviando Ctrl+Alt+Del…", + "ru": "Отправка Ctrl+Alt+Del…" + }, + "正在取回远程画面…": { + "zh-Hans": "正在取回远程画面…", + "en": "Retrieving remote screen...", + "zh-Hant": "正在取回遠端畫面…", + "ja": "リモート画面を取得中...", + "ko": "원격 화면을 검색하는 중...", + "de": "Remote-Bildschirm abrufen...", + "fr": "Récupération de l'écran distant...", + "es": "Recuperando la pantalla remota...", + "pt-BR": "Recuperando tela remota...", + "ru": "Получение удаленного экрана..." + }, + "正在取消": { + "zh-Hans": "正在取消", + "en": "Cancelling", + "ru": "Отмена…", + "zh-Hant": "正在取消", + "ja": "キャンセルする", + "ko": "취소 중", + "de": "Abbrechen", + "fr": "Annulation", + "es": "Cancelando", + "pt-BR": "Cancelando" + }, + "正在安装服务...": { + "zh-Hans": "正在安装服务...", + "en": "Installing service...", + "ru": "Установка службы...", + "zh-Hant": "正在安裝服務...", + "ja": "サービスをインストール中…", + "ko": "서비스 설치 중...", + "de": "Dienst wird installiert...", + "fr": "Installation du service...", + "es": "Instalando servicio...", + "pt-BR": "Instalando serviço..." + }, + "正在应用…": { + "zh-Hans": "正在应用…", + "en": "Applying…", + "ru": "Применение…", + "zh-Hant": "正在應用…", + "ja": "申請中…", + "ko": "신청 중…", + "de": "Bewerbung…", + "fr": "Candidature…", + "es": "Aplicando...", + "pt-BR": "Aplicando…" + }, + "正在建立安全连接…": { + "zh-Hans": "正在建立安全连接…", + "en": "Establishing secure connection…", + "zh-Hant": "正在建立安全連線…", + "ja": "安全な接続を確立中…", + "ko": "보안 연결 설정 중…", + "de": "Sichere Verbindung wird hergestellt…", + "fr": "Établir une connexion sécurisée…", + "es": "Estableciendo una conexión segura...", + "pt-BR": "Estabelecendo conexão segura…", + "ru": "Установление безопасного соединения…" + }, + "正在建立对等连接...": { + "zh-Hans": "正在建立对等连接...", + "en": "P2P Connecting ...", + "ru": "Подключение P2P...", + "zh-Hant": "正在建立對等連線...", + "ja": "P2P接続中...", + "ko": "P2P 연결중...", + "de": "P2P-Verbindung ...", + "fr": "Connexion P2P...", + "es": "Conexión P2P...", + "pt-BR": "Conexão P2P..." + }, + "正在建立远程连接": { + "zh-Hans": "正在建立远程连接", + "en": "Establishing remote connection", + "zh-Hant": "正在建立遠端連線", + "ja": "リモート接続の確立", + "ko": "원격 연결 설정", + "de": "Remote-Verbindung aufbauen", + "fr": "Établissement d'une connexion à distance", + "es": "Establecer conexión remota", + "pt-BR": "Estabelecendo conexão remota", + "ru": "Установление удаленного соединения" + }, + "正在开启隐私屏…": { + "zh-Hans": "正在开启隐私屏…", + "en": "Turning on privacy screen...", + "zh-Hant": "正在開啟隱私屏…", + "ja": "プライバシー画面を有効化中…", + "ko": "개인정보 보호 화면을 켜는 중...", + "de": "Privatsphärenschutz einschalten...", + "fr": "Activation de l'écran de confidentialité...", + "es": "Activando la pantalla de privacidad...", + "pt-BR": "Ativando a tela de privacidade...", + "ru": "Включение экрана конфиденциальности..." + }, + "正在接收": { + "zh-Hans": "正在接收", + "en": "Receiving", + "ru": "Получение", + "zh-Hant": "正在接收", + "ja": "受信中", + "ko": "수신", + "de": "Empfangen", + "fr": "Réception", + "es": "Recepción", + "pt-BR": "Recebendo" + }, + "正在操控": { + "zh-Hans": "正在操控", + "en": "Controlling", + "ru": "Управление", + "zh-Hant": "正在操控", + "ja": "制御する", + "ko": "제어", + "de": "Kontrollieren", + "fr": "Contrôler", + "es": "Controlar", + "pt-BR": "Controle" + }, + "正在收集 ICE 候选": { + "zh-Hans": "正在收集 ICE 候选", + "en": "Collecting ICE candidates", + "zh-Hant": "正在收集 ICE 候選", + "ja": "ICE 候補を収集中", + "ko": "ICE후보 수집", + "de": "Sammeln von ICE-Kandidaten", + "fr": "Collecte des candidats ICE", + "es": "Recopilación de candidatos de ICE", + "pt-BR": "Coletando candidatos do ICE", + "ru": "Сбор кандидатов ICE" + }, + "正在收集候选地址...": { + "zh-Hans": "正在收集候选地址...", + "en": "Gathering candidates ...", + "ru": "Сбор кандидатов...", + "zh-Hant": "正在收集候選地址...", + "ja": "候補者を集めて…", + "ko": "후보자를 모으는 중...", + "de": "Kandidaten sammeln ...", + "fr": "Rassembler les candidats...", + "es": "Reuniendo candidatos...", + "pt-BR": "Reunindo candidatos..." + }, + "正在检查…": { + "zh-Hans": "正在检查…", + "en": "Checking…", + "zh-Hant": "正在檢查…", + "ja": "確認中…", + "ko": "확인 중…", + "de": "Überprüfen…", + "fr": "Vérification…", + "es": "Comprobando…", + "pt-BR": "Verificando…", + "ru": "Проверка…" + }, + "正在检查更新…": { + "zh-Hans": "正在检查更新…", + "en": "Checking for updates…", + "ru": "Проверка обновлений…", + "zh-Hant": "正在檢查更新…", + "ja": "アップデートを確認しています…", + "ko": "업데이트 확인 중…", + "de": "Suche nach Updates…", + "fr": "Vérification des mises à jour…", + "es": "Buscando actualizaciones...", + "pt-BR": "Verificando atualizações…" + }, + "正在清除…": { + "zh-Hans": "正在清除…", + "en": "Clearing...", + "zh-Hant": "正在清除…", + "ja": "クリア中...", + "ko": "지우는 중...", + "de": "Löschen...", + "fr": "Effacement...", + "es": "Borrando...", + "pt-BR": "Limpando...", + "ru": "Очистка..." + }, + "正在确认设备状态…": { + "zh-Hans": "正在确认设备状态…", + "en": "Confirming device status...", + "zh-Hant": "正在確認裝置狀態…", + "ja": "機器の状態を確認しています...", + "ko": "기기 상태를 확인하는 중...", + "de": "Gerätestatus bestätigen...", + "fr": "Confirmation de l'état de l'appareil...", + "es": "Confirmando el estado del dispositivo...", + "pt-BR": "Confirmando o status do dispositivo...", + "ru": "Подтверждение статуса устройства..." + }, + "正在获取本机 ID…": { + "zh-Hans": "正在获取本机 ID…", + "en": "Obtaining local ID...", + "zh-Hant": "正在獲取本機 ID…", + "ja": "ローカルIDを取得中...", + "ko": "로컬 ID를 얻는 중...", + "de": "Lokale ID erhalten...", + "fr": "Obtention d'une pièce d'identité locale...", + "es": "Obtención de identificación local...", + "pt-BR": "Obtendo ID local...", + "ru": "Получение локального идентификатора..." + }, + "正在读取…": { + "zh-Hans": "正在读取…", + "en": "Checking…", + "ru": "Проверка…", + "zh-Hant": "正在讀取…", + "ja": "確認中…", + "ko": "확인 중…", + "de": "Überprüfen…", + "fr": "Vérification…", + "es": "Comprobando…", + "pt-BR": "Verificando…" + }, + "正在读取所选文件…": { + "zh-Hans": "正在读取所选文件…", + "en": "Reading selected file...", + "zh-Hant": "正在讀取所選檔案…", + "ja": "選択したファイルを読み込み中...", + "ko": "선택한 파일을 읽는 중...", + "de": "Ausgewählte Datei wird gelesen...", + "fr": "Lecture du fichier sélectionné...", + "es": "Leyendo el archivo seleccionado...", + "pt-BR": "Lendo arquivo selecionado...", + "ru": "Чтение выбранного файла..." + }, + "正在连接": { + "zh-Hans": "正在连接", + "en": "Connecting", + "zh-Hant": "正在連線", + "ja": "接続する", + "ko": "연결 중", + "de": "Verbinden", + "fr": "Connexion", + "es": "Conexión", + "pt-BR": "Conectando", + "ru": "Подключение" + }, + "正在连接…": { + "zh-Hans": "正在连接…", + "en": "Connecting…", + "ru": "Подключение…", + "zh-Hant": "正在連線…", + "ja": "接続中…", + "ko": "연결 중…", + "de": "Verbinden…", + "fr": "Connexion…", + "es": "Conectando...", + "pt-BR": "Conectando…" + }, + "正在连接信令服务": { + "zh-Hans": "正在连接信令服务", + "en": "Connecting to signaling service", + "zh-Hant": "正在連線信令服務", + "ja": "シグナリングサービスへの接続", + "ko": "시그널링 서비스 연결", + "de": "Verbindung zum Signalisierungsdienst herstellen", + "fr": "Connexion au service de signalisation", + "es": "Conexión al servicio de señalización", + "pt-BR": "Conectando-se ao serviço de sinalização", + "ru": "Подключение к службе сигнализации" + }, + "正在连接信令服务器…": { + "zh-Hans": "正在连接信令服务器…", + "en": "Connecting to signaling server...", + "zh-Hant": "正在連線信令伺服器…", + "ja": "シグナリングサーバーに接続しています...", + "ko": "시그널링 서버에 연결 중...", + "de": "Verbindung zum Signalisierungsserver wird hergestellt...", + "fr": "Connexion au serveur de signalisation...", + "es": "Conectándose al servidor de señalización...", + "pt-BR": "Conectando ao servidor de sinalização...", + "ru": "Подключение к серверу сигнализации..." + }, + "正在连接服务器…": { + "zh-Hans": "正在连接服务器…", + "en": "Connecting to server...", + "zh-Hant": "正在連線伺服器…", + "ja": "サーバーに接続中...", + "ko": "서버에 연결하는 중...", + "de": "Verbindung zum Server herstellen...", + "fr": "Connexion au serveur...", + "es": "Conectándose al servidor...", + "pt-BR": "Conectando ao servidor...", + "ru": "Подключение к серверу..." + }, + "正在退出 CrossDesk……": { + "zh-Hans": "正在退出 CrossDesk……", + "en": "Exiting CrossDesk...", + "ru": "Выход из CrossDesk...", + "zh-Hant": "正在退出 CrossDesk……", + "ja": "CrossDeskを終了します ...", + "ko": "CrossDesk종료 중...", + "de": "CrossDesk wird beendet ...", + "fr": "Sortie de CrossDesk...", + "es": "Saliendo de CrossDesk...", + "pt-BR": "Saindo de CrossDesk..." + }, + "正在重新连接...": { + "zh-Hans": "正在重新连接...", + "en": "Reconnecting...", + "ru": "Переподключение...", + "zh-Hant": "正在重新連線...", + "ja": "再接続中...", + "ko": "다시 연결하는 중...", + "de": "Verbindung wird wiederhergestellt...", + "fr": "Reconnexion...", + "es": "Reconectando...", + "pt-BR": "Reconectando..." + }, + "正在重连…": { + "zh-Hans": "正在重连…", + "en": "Reconnecting...", + "zh-Hant": "正在重連…", + "ja": "再接続中...", + "ko": "다시 연결하는 중...", + "de": "Verbindung wird wiederhergestellt...", + "fr": "Reconnexion...", + "es": "Reconectando...", + "pt-BR": "Reconectando...", + "ru": "Повторное подключение..." + }, + "正在重连服务器…": { + "zh-Hans": "正在重连服务器…", + "en": "Reconnecting to server...", + "zh-Hant": "正在重連伺服器…", + "ja": "サーバーに再接続中...", + "ko": "서버에 재접속하는 중...", + "de": "Verbindung zum Server wird wiederhergestellt...", + "fr": "Reconnexion au serveur...", + "es": "Reconectándose al servidor...", + "pt-BR": "Reconectando ao servidor...", + "ru": "Повторное подключение к серверу..." + }, + "此公告将从列表中移除。": { + "zh-Hans": "此公告将从列表中移除。", + "en": "This announcement will be removed from the list.", + "zh-Hant": "此公告將從列表中移除。", + "ja": "この発表はリストから削除されます。", + "ko": "이 공지는 목록에서 제거됩니다.", + "de": "Diese Ankündigung wird aus der Liste entfernt.", + "fr": "Cette annonce sera supprimée de la liste.", + "es": "Este anuncio será eliminado de la lista.", + "pt-BR": "Este anúncio será removido da lista.", + "ru": "Это объявление будет удалено из списка." + }, + "此端口已被占用,": { + "zh-Hans": "此端口已被占用,", + "en": "This port is in use.", + "ru": "Порт занят.", + "zh-Hant": "此埠已被佔用,", + "ja": "このポートは使用中です。", + "ko": "이 포트는 사용 중입니다.", + "de": "Dieser Port wird verwendet.", + "fr": "Ce port est utilisé.", + "es": "Este puerto está en uso.", + "pt-BR": "Esta porta está em uso." + }, + "此设备没有可用的文件选择器": { + "zh-Hans": "此设备没有可用的文件选择器", + "en": "No file picker available for this device", + "zh-Hant": "此裝置沒有可用的檔案選擇器", + "ja": "このデバイスでは使用できるファイル ピッカーがありません", + "ko": "이 장치에 사용할 수 있는 파일 선택기가 없습니다.", + "de": "Für dieses Gerät ist keine Dateiauswahl verfügbar", + "fr": "Aucun sélecteur de fichiers disponible pour cet appareil", + "es": "No hay selector de archivos disponible para este dispositivo", + "pt-BR": "Nenhum seletor de arquivos disponível para este dispositivo", + "ru": "Для этого устройства средство выбора файлов недоступно." + }, + "此设备被控中": { + "zh-Hans": "此设备被控中", + "en": "This device is controlled", + "ru": "Устройство под управлением", + "zh-Hant": "此裝置被控中", + "ja": "このデバイスは制御されています", + "ko": "이 장치는 제어됩니다", + "de": "Dieses Gerät wird gesteuert", + "fr": "Cet appareil est contrôlé", + "es": "Este dispositivo está controlado", + "pt-BR": "Este dispositivo é controlado" + }, + "每次共享均需本机授权": { + "zh-Hans": "每次共享均需本机授权", + "en": "Local approval required each time", + "ru": "Разрешение требуется каждый раз", + "zh-Hant": "每次共享均需本機授權", + "ja": "都度現地の承認が必要", + "ko": "매번 현지 승인 필요", + "de": "Jedes Mal ist eine örtliche Genehmigung erforderlich", + "fr": "Approbation locale requise à chaque fois", + "es": "Se requiere aprobación local cada vez", + "pt-BR": "Aprovação local necessária sempre" + }, + "消息": { + "zh-Hans": "消息", + "en": "Messages", + "ru": "Сообщения", + "zh-Hant": "訊息", + "ja": "メッセージ", + "ko": "메시지", + "de": "Nachrichten", + "fr": "Messages", + "es": "Mensajes", + "pt-BR": "Mensagens" + }, + "添加": { + "zh-Hans": "添加", + "en": "Add", + "ru": "Добавить", + "zh-Hant": "新增", + "ja": "追加", + "ko": "추가", + "de": "Hinzufügen", + "fr": "Ajouter", + "es": "Agregar", + "pt-BR": "Adicionar" + }, + "添加并连接": { + "zh-Hans": "添加并连接", + "en": "Add and connect", + "ru": "Добавить и подключить", + "zh-Hant": "新增並連線", + "ja": "追加して接続する", + "ko": "추가 및 연결", + "de": "Hinzufügen und verbinden", + "fr": "Ajouter et connecter", + "es": "Agregar y conectar", + "pt-BR": "Adicionar e conectar" + }, + "添加设备": { + "zh-Hans": "添加设备", + "en": "Add device", + "ru": "Добавить устройство", + "zh-Hant": "新增裝置", + "ja": "デバイスの追加", + "ko": "장치 추가", + "de": "Gerät hinzufügen", + "fr": "Ajouter un appareil", + "es": "Agregar dispositivo", + "pt-BR": "Adicionar dispositivo" + }, + "添加设备,建立你的桌面墙": { + "zh-Hans": "添加设备,建立你的桌面墙", + "en": "Add devices to build your DeskHub", + "ru": "Добавьте устройства в DeskHub", + "zh-Hant": "新增裝置,建立你的桌面牆", + "ja": "デバイスを追加してDeskHubを構築します", + "ko": "DeskHub를 구축하기 위한 장치 추가", + "de": "Fügen Sie Geräte hinzu, um Ihr DeskHub zu erstellen", + "fr": "Ajoutez des appareils pour créer votre DeskHub", + "es": "Agregue dispositivos para construir su DeskHub", + "pt-BR": "Adicione dispositivos para construir seu DeskHub" + }, + "清除": { + "zh-Hans": "清除", + "en": "Clear", + "zh-Hant": "清除", + "ja": "クリア", + "ko": "클리어", + "de": "Klar", + "fr": "Effacer", + "es": "Borrar", + "pt-BR": "Limpar", + "ru": "Очистить" + }, + "清除预览图": { + "zh-Hans": "清除预览图", + "en": "Clear previews", + "ru": "Удалить превью", + "zh-Hant": "清除預覽圖", + "ja": "プレビューを削除", + "ko": "미리보기 삭제", + "de": "Vorschaubilder löschen", + "fr": "Supprimer les aperçus", + "es": "Borrar vistas previas", + "pt-BR": "Limpar prévias" + }, + "清除预览图?": { + "zh-Hans": "清除预览图?", + "en": "Clear previews?", + "ru": "Удалить превью?", + "zh-Hant": "清除預覽圖?", + "ja": "プレビューを削除しますか?", + "ko": "미리보기를 삭제할까요?", + "de": "Vorschaubilder löschen?", + "fr": "Supprimer les aperçus ?", + "es": "¿Borrar vistas previas?", + "pt-BR": "Limpar prévias?" + }, + "源码与构建说明": { + "zh-Hans": "源码与构建说明", + "en": "Source code and build instructions", + "ru": "Исходный код и сборка", + "zh-Hant": "原始碼與構建說明", + "ja": "ソースコードとビルド手順", + "ko": "소스 코드 및 빌드 지침", + "de": "Quellcode und Build-Anweisungen", + "fr": "Code source et instructions de construction", + "es": "Código fuente e instrucciones de compilación", + "pt-BR": "Código-fonte e instruções de construção" + }, + "源码版本": { + "zh-Hans": "源码版本", + "en": "Source code version", + "zh-Hant": "原始碼版本", + "ja": "ソースコードのバージョン", + "ko": "소스코드 버전", + "de": "Quellcode-Version", + "fr": "Version du code source", + "es": "Versión del código fuente", + "pt-BR": "Versão do código-fonte", + "ru": "Версия исходного кода" + }, + "源码版本:": { + "zh-Hans": "源码版本:", + "en": "Source revision: ", + "ru": "Ревизия исходного кода: ", + "zh-Hant": "原始碼版本:", + "ja": "ソース改訂:", + "ko": "소스 개정:", + "de": "Überarbeitung der Quelle:", + "fr": "Révision de la source :", + "es": "Revisión de la fuente:", + "pt-BR": "Revisão da fonte:" + }, + "滚轮,上下滑动": { + "zh-Hans": "滚轮,上下滑动", + "en": "Scroll wheel; swipe up or down", + "ru": "Колесо: проведите вверх или вниз", + "zh-Hant": "滾輪,上下滑動", + "ja": "ホイール:上下にスワイプ", + "ko": "휠: 위아래로 스와이프", + "de": "Mausrad; nach oben oder unten wischen", + "fr": "Molette : balayez vers le haut ou le bas", + "es": "Rueda: desliza arriba o abajo", + "pt-BR": "Roda: deslize para cima ou para baixo" + }, + "点击修改端口": { + "zh-Hans": "点击修改端口", + "en": "Click to edit the port", + "ru": "Нажмите, чтобы изменить порт", + "zh-Hant": "點選修改埠", + "ja": "クリックしてポートを編集します", + "ko": "포트를 편집하려면 클릭하세요.", + "de": "Klicken Sie, um den Port zu bearbeiten", + "fr": "Cliquez pour modifier le port", + "es": "Haga clic para editar el puerto.", + "pt-BR": "Clique para editar a porta" + }, + "点击切换本机 IP": { + "zh-Hans": "点击切换本机 IP", + "en": "Click to switch the local IP", + "ru": "Нажмите, чтобы сменить IP", + "zh-Hant": "點選切換本機 IP", + "ja": "クリックしてローカルIPを切り替えます", + "ko": "로컬 IP를 전환하려면 클릭하세요.", + "de": "Klicken Sie hier, um die lokale IP zu wechseln", + "fr": "Cliquez pour changer l'adresse IP locale", + "es": "Haga clic para cambiar la IP local", + "pt-BR": "Clique para mudar o IP local" + }, + "爱发电": { + "zh-Hans": "爱发电", + "en": "AFDIAN", + "ru": "AFDIAN", + "zh-Hant": "愛發電", + "ja": "AFDIAN", + "ko": "아디안", + "de": "AFDIAN", + "fr": "AFDIEN", + "es": "AFDIANO", + "pt-BR": "AFDIAN" + }, + "版本": { + "zh-Hans": "版本", + "en": "Version", + "ru": "Версия", + "zh-Hant": "版本", + "ja": "バージョン", + "ko": "버전", + "de": "Version", + "fr": "Version", + "es": "Versión", + "pt-BR": "Versão" + }, + "版权与许可声明": { + "zh-Hans": "版权与许可声明", + "en": "Copyright and License Statement", + "zh-Hant": "版權與許可宣告", + "ja": "著作権およびライセンスに関する声明", + "ko": "저작권 및 라이선스 정책", + "de": "Urheberrechts- und Lizenzerklärung", + "fr": "Déclaration de droits d'auteur et de licence", + "es": "Declaración de derechos de autor y licencia", + "pt-BR": "Declaração de direitos autorais e licença", + "ru": "Положение об авторских правах и лицензии." + }, + "状态": { + "zh-Hans": "状态", + "en": "Status", + "ru": "Состояние", + "zh-Hant": "狀態", + "ja": "ステータス", + "ko": "상태", + "de": "Status", + "fr": "Statut", + "es": "Estado", + "pt-BR": "Estado" + }, + "电脑": { + "zh-Hans": "电脑", + "en": "Computer", + "zh-Hant": "電腦", + "ja": "コンピューター", + "ko": "컴퓨터", + "de": "Computer", + "fr": "Ordinateur", + "es": "Computadora", + "pt-BR": "Computador", + "ru": "Компьютер" + }, + "电脑键盘": { + "zh-Hans": "电脑键盘", + "en": "Computer keyboard", + "zh-Hant": "電腦鍵盤", + "ja": "コンピューターのキーボード", + "ko": "컴퓨터 키보드", + "de": "Computertastatur", + "fr": "Clavier d'ordinateur", + "es": "Teclado de computadora", + "pt-BR": "Teclado de computador", + "ru": "Компьютерная клавиатура" + }, + "画中画已关闭": { + "zh-Hans": "画中画已关闭", + "en": "Picture-in-picture is turned off", + "zh-Hant": "畫中畫已關閉", + "ja": "ピクチャーインピクチャーがオフになっています", + "ko": "PIP(Picture-in-Picture)가 꺼졌습니다.", + "de": "Bild-in-Bild ist ausgeschaltet", + "fr": "L'image dans l'image est désactivée", + "es": "La imagen en imagen está desactivada", + "pt-BR": "Picture-in-picture está desativado", + "ru": "Функция «Картинка в картинке» отключена." + }, + "画中画未能开启,请保持应用在前台后重试。": { + "zh-Hans": "画中画未能开启,请保持应用在前台后重试。", + "en": "Picture-in-picture failed to open, please keep the application in the foreground and try again.", + "zh-Hant": "畫中畫未能開啟,請保持應用在前臺後重試。", + "ja": "ピクチャーインピクチャーを開けませんでした。アプリケーションをフォアグラウンドに保ち、もう一度お試しください。", + "ko": "PIP(Picture-in-Picture)를 열지 못했습니다. 애플리케이션을 포그라운드에 두고 다시 시도하십시오.", + "de": "Bild-in-Bild konnte nicht geöffnet werden. Bitte lassen Sie die Anwendung im Vordergrund und versuchen Sie es erneut.", + "fr": "L'image dans l'image n'a pas pu s'ouvrir. Veuillez conserver l'application au premier plan et réessayer.", + "es": "No se pudo abrir la imagen en imagen. Mantenga la aplicación en primer plano e inténtelo nuevamente.", + "pt-BR": "Falha ao abrir o Picture-in-picture. Mantenha o aplicativo em primeiro plano e tente novamente.", + "ru": "Не удалось открыть функцию «Картинка в картинке». Оставьте приложение на переднем плане и повторите попытку." + }, + "画质优先": { + "zh-Hans": "画质优先", + "en": "Quality", + "ru": "Качество", + "zh-Hant": "畫質優先", + "ja": "画質", + "ko": "화질", + "de": "Qualität", + "fr": "Qualité", + "es": "Calidad", + "pt-BR": "Qualidade" + }, + "画面": { + "zh-Hans": "画面", + "en": "Video", + "ru": "Видео", + "zh-Hant": "畫面", + "ja": "ビデオ", + "ko": "영상", + "de": "Video", + "fr": "Vidéo", + "es": "Vídeo", + "pt-BR": "Vídeo" + }, + "画面传输": { + "zh-Hans": "画面传输", + "en": "Video transmission", + "ru": "Передача видео", + "zh-Hant": "畫面傳輸", + "ja": "ビデオ送信", + "ko": "영상 전송", + "de": "Videoübertragung", + "fr": "Transmission vidéo", + "es": "Transmisión de vídeo", + "pt-BR": "Transmissão de vídeo" + }, + "画面偏好": { + "zh-Hans": "画面偏好", + "en": "Video Preference", + "ru": "Режим видео", + "zh-Hant": "畫面偏好", + "ja": "ビデオ設定", + "ko": "영상 선호도", + "de": "Videopräferenz", + "fr": "Préférence vidéo", + "es": "Preferencia de vídeo", + "pt-BR": "Preferência de vídeo" + }, + "画面已停留": { + "zh-Hans": "画面已停留", + "en": "Frame stale", + "ru": "Кадр устарел", + "zh-Hant": "畫面已停留", + "ja": "フレームが古い", + "ko": "프레임 부실", + "de": "Rahmen veraltet", + "fr": "Cadre obsolète", + "es": "Marco obsoleto", + "pt-BR": "Quadro obsoleto" + }, + "画面延时": { + "zh-Hans": "画面延时", + "en": "Video latency", + "ru": "Задержка видео", + "zh-Hant": "畫面延遲", + "ja": "映像遅延", + "ko": "영상 지연", + "de": "Videolatenz", + "fr": "Latence vidéo", + "es": "Latencia de vídeo", + "pt-BR": "Latência do vídeo" + }, + "画面接收中...": { + "zh-Hans": "画面接收中...", + "en": "Receiving screen...", + "ru": "Получение изображения...", + "zh-Hant": "畫面接收中...", + "ja": "受信画面…", + "ko": "수신화면...", + "de": "Empfangsbildschirm...", + "fr": "Écran de réception...", + "es": "Pantalla de recepción...", + "pt-BR": "Recebendo tela..." + }, + "画面设置": { + "zh-Hans": "画面设置", + "en": "Video settings", + "ru": "Настройки видео", + "zh-Hant": "畫面設定", + "ja": "ビデオ設定", + "ko": "영상 설정", + "de": "Videoeinstellungen", + "fr": "Paramètres vidéo", + "es": "Configuración de vídeo", + "pt-BR": "Configurações de vídeo" + }, + "画面质量": { + "zh-Hans": "画面质量", + "en": "Video Quality", + "ru": "Качество видео", + "zh-Hant": "畫面質量", + "ja": "ビデオ品質", + "ko": "비디오 품질", + "de": "Videoqualität", + "fr": "Qualité vidéo", + "es": "Calidad de vídeo", + "pt-BR": "Qualidade de vídeo" + }, + "画面采集帧率": { + "zh-Hans": "画面采集帧率", + "en": "Video Capture Frame Rate", + "ru": "Частота захвата видео", + "zh-Hant": "畫面採集幀率", + "ja": "ビデオキャプチャフレームレート", + "ko": "비디오 캡처 프레임 속도", + "de": "Bildrate der Videoaufnahme", + "fr": "Fréquence d'images de capture vidéo", + "es": "Velocidad de fotogramas de captura de vídeo", + "pt-BR": "Taxa de quadros de captura de vídeo" + }, + "界面": { + "zh-Hans": "界面", + "en": "Interface", + "ru": "Интерфейс", + "zh-Hant": "介面", + "ja": "インターフェース", + "ko": "인터페이스", + "de": "Oberfläche", + "fr": "Interfaces", + "es": "Interfaz", + "pt-BR": "Interface" + }, + "登录桌面时自启": { + "zh-Hans": "登录桌面时自启", + "en": "Start at desktop login", + "ru": "Запуск при входе в систему", + "zh-Hant": "登入桌面時自啟", + "ja": "デスクトップログインで起動", + "ko": "데스크톱 로그인에서 시작", + "de": "Beginnen Sie mit der Desktop-Anmeldung", + "fr": "Démarrer lors de la connexion au bureau", + "es": "Iniciar sesión en el escritorio", + "pt-BR": "Comece no login da área de trabalho" + }, + "登录状态已失效,请重新连接。": { + "zh-Hans": "登录状态已失效,请重新连接。", + "en": "Signaling login expired. Please reconnect.", + "ru": "Сеанс входа истёк. Подключитесь заново.", + "zh-Hant": "登入狀態已失效,請重新連線。", + "ja": "シグナリングログインの有効期限が切れました。再接続してください。", + "ko": "시그널링 로그인이 만료되었습니다. 다시 연결해 주세요.", + "de": "Signalisierungsanmeldung abgelaufen. Bitte stellen Sie die Verbindung wieder her.", + "fr": "La connexion de signalisation a expiré. Veuillez vous reconnecter.", + "es": "El inicio de sesión de señalización expiró. Por favor vuelva a conectarse.", + "pt-BR": "O login de sinalização expirou. Por favor, reconecte." + }, + "直连": { + "zh-Hans": "直连", + "en": "Direct", + "ru": "Прямой", + "zh-Hant": "直連", + "ja": "直接", + "ko": "다이렉트", + "de": "Direkt", + "fr": "Direct", + "es": "Directo", + "pt-BR": "Direto" + }, + "相对位置": { + "zh-Hans": "相对位置", + "en": "Trackpad", + "ru": "Тачпад", + "zh-Hant": "相對位置", + "ja": "トラックパッド", + "ko": "트랙패드", + "de": "Touchpad", + "fr": "Pavé tactile", + "es": "Panel táctil", + "pt-BR": "Touchpad" + }, + "相对鼠标": { + "zh-Hans": "相对鼠标", + "en": "Relative mouse", + "zh-Hant": "相對滑鼠", + "ja": "相対マウス", + "ko": "상대 마우스", + "de": "Relative Maus", + "fr": "Souris relative", + "es": "Ratón relativo", + "pt-BR": "Rato relativo", + "ru": "Родственная мышь" + }, + "知道了": { + "zh-Hans": "知道了", + "en": "Got it", + "ru": "Понятно", + "zh-Hant": "知道了", + "ja": "分かりました", + "ko": "알겠습니다", + "de": "Verstanden", + "fr": "Compris", + "es": "Entendido", + "pt-BR": "Entendi" + }, + "确定": { + "zh-Hans": "确定", + "en": "OK", + "zh-Hant": "確定", + "ja": "OK", + "ko": "알았어", + "de": "Okay", + "fr": "D'accord", + "es": "Aceptar", + "pt-BR": "OK", + "ru": "ОК" + }, + "确认": { + "zh-Hans": "确认", + "en": "Confirm", + "ru": "Подтвердить", + "zh-Hant": "確認", + "ja": "確認する", + "ko": "확인", + "de": "Bestätigen", + "fr": "Confirmer", + "es": "Confirmar", + "pt-BR": "Confirmar" + }, + "确认删除此连接": { + "zh-Hans": "确认删除此连接", + "en": "Delete this connection?", + "ru": "Удалить это подключение?", + "zh-Hant": "確認刪除此連線", + "ja": "この接続を削除しますか?", + "ko": "이 연결을 삭제하시겠습니까?", + "de": "Diese Verbindung löschen?", + "fr": "Supprimer cette connexion ?", + "es": "¿Eliminar esta conexión?", + "pt-BR": "Excluir esta conexão?" + }, + "确认执行": { + "zh-Hans": "确认执行", + "en": "Continue", + "ru": "Продолжить", + "zh-Hant": "確認執行", + "ja": "続き", + "ko": "계속", + "de": "Weiter", + "fr": "Continuer", + "es": "Continuar", + "pt-BR": "Continuar" + }, + "确认断开": { + "zh-Hans": "确认断开", + "en": "Disconnect", + "ru": "Отключить", + "zh-Hant": "確認斷開", + "ja": "切断", + "ko": "연결 끊기", + "de": "Trennen", + "fr": "Déconnecter", + "es": "Desconectar", + "pt-BR": "Desconectar" + }, + "确认断开连接?": { + "zh-Hans": "确认断开连接?", + "en": "Disconnect this session?", + "ru": "Отключить этот сеанс?", + "zh-Hant": "確認斷開連線?", + "ja": "このセッションを切断しますか?", + "ko": "이 세션을 연결 해제하시겠습니까?", + "de": "Diese Sitzung trennen?", + "fr": "Déconnecter cette session ?", + "es": "¿Desconectar esta sesión?", + "pt-BR": "Desconectar esta sessão?" + }, + "确认连接": { + "zh-Hans": "确认连接", + "en": "Confirm connection", + "zh-Hant": "確認連線", + "ja": "接続を確認する", + "ko": "연결 확인", + "de": "Verbindung bestätigen", + "fr": "Confirmer la connexion", + "es": "Confirmar conexión", + "pt-BR": "Confirme a conexão", + "ru": "Подтвердите соединение" + }, + "离线": { + "zh-Hans": "离线", + "en": "Offline", + "ru": "Не в сети", + "zh-Hant": "離線", + "ja": "オフライン", + "ko": "오프라인", + "de": "Offline", + "fr": "Hors ligne", + "es": "Sin conexión", + "pt-BR": "Off-line" + }, + "空格": { + "zh-Hans": "空格", + "en": "Space", + "ru": "Пробел", + "zh-Hant": "空白鍵", + "ja": "スペース", + "ko": "스페이스", + "de": "Leertaste", + "fr": "Espace", + "es": "Espacio", + "pt-BR": "Espaço" + }, + "端口": { + "zh-Hans": "端口", + "en": "Port", + "zh-Hant": "埠", + "ja": "港", + "ko": "포트", + "de": "Hafen", + "fr": "Port", + "es": "Puerto", + "pt-BR": "Porto", + "ru": "Порт" + }, + "端口范围为 1–65535": { + "zh-Hans": "端口范围为 1–65535", + "en": "Port range is 1–65535", + "zh-Hant": "埠範圍為 1–65535", + "ja": "ポート範囲は 1 ~ 65535 です。", + "ko": "포트 범위는 1~65535입니다.", + "de": "Der Portbereich liegt zwischen 1 und 65535", + "fr": "La plage de ports est comprise entre 1 et 65 535.", + "es": "El rango de puertos es 1–65535", + "pt-BR": "O intervalo de portas é 1–65535", + "ru": "Диапазон портов: 1–65535." + }, + "符号功能": { + "zh-Hans": "符号功能", + "en": "Symbols & keys", + "ru": "Символы и клавиши", + "zh-Hant": "符號功能", + "ja": "記号・機能", + "ko": "기호·기능", + "de": "Symbole & Tasten", + "fr": "Symboles et touches", + "es": "Símbolos y teclas", + "pt-BR": "Símbolos e teclas" + }, + "等待分配": { + "zh-Hans": "等待分配", + "en": "Waiting for assignment", + "ru": "Ожидание назначения", + "zh-Hant": "等待分配", + "ja": "割り当て待ち", + "ko": "과제를 기다리는 중", + "de": "Warten auf Zuweisung", + "fr": "En attente d'affectation", + "es": "Esperando asignación", + "pt-BR": "Aguardando atribuição" + }, + "等待电脑端确认…": { + "zh-Hans": "等待电脑端确认…", + "en": "Waiting for confirmation from the computer...", + "zh-Hant": "等待電腦端確認…", + "ja": "コンピューターからの確認を待っています...", + "ko": "컴퓨터의 확인을 기다리는 중...", + "de": "Warten auf Bestätigung vom Computer...", + "fr": "En attente de confirmation de l'ordinateur...", + "es": "Esperando confirmación del ordenador...", + "pt-BR": "Aguardando confirmação do computador...", + "ru": "Ожидание подтверждения от компьютера..." + }, + "等待电脑返回隐私屏状态;旧版电脑端可能不支持": { + "zh-Hans": "等待电脑返回隐私屏状态;旧版电脑端可能不支持", + "en": "Wait for the computer to return to the privacy screen state; older computers may not support it.", + "zh-Hant": "等待電腦返回隱私屏狀態;舊版電腦端可能不支援", + "ja": "コンピューターがプライバシー画面の状態に戻るまで待ちます。古いコンピューターではサポートされていない可能性があります。", + "ko": "컴퓨터가 개인 정보 보호 화면 상태로 돌아갈 때까지 기다립니다. 오래된 컴퓨터에서는 이를 지원하지 않을 수 있습니다.", + "de": "Warten Sie, bis der Computer in den Datenschutzstatus zurückkehrt. Ältere Computer unterstützen dies möglicherweise nicht.", + "fr": "Attendez que l'ordinateur revienne à l'état de l'écran de confidentialité ; les ordinateurs plus anciens peuvent ne pas le prendre en charge.", + "es": "Espere a que la computadora vuelva al estado de pantalla de privacidad; Es posible que las computadoras más antiguas no lo admitan.", + "pt-BR": "Aguarde o computador retornar ao estado da tela de privacidade; computadores mais antigos podem não suportá-lo.", + "ru": "Подождите, пока компьютер вернется в состояние экрана конфиденциальности; старые компьютеры могут его не поддерживать." + }, + "等待画面": { + "zh-Hans": "等待画面", + "en": "Waiting for video", + "ru": "Ожидание видео", + "zh-Hant": "等待畫面", + "ja": "ビデオ待機中", + "ko": "영상을 기다리는 중", + "de": "Warten auf Video", + "fr": "En attente de la vidéo", + "es": "Esperando vídeo", + "pt-BR": "Aguardando vídeo" + }, + "等待统计": { + "zh-Hans": "等待统计", + "en": "Awaiting stats", + "ru": "Ожидание статистики", + "zh-Hant": "等待統計", + "ja": "統計待ち", + "ko": "통계 대기 중", + "de": "Warten auf Statistiken", + "fr": "En attente de statistiques", + "es": "En espera de estadísticas", + "pt-BR": "Aguardando estatísticas" + }, + "等待远端屏幕信息": { + "zh-Hans": "等待远端屏幕信息", + "en": "Waiting for remote screen information", + "zh-Hant": "等待遠端螢幕資訊", + "ja": "リモート画面情報待ち", + "ko": "원격 화면 정보를 기다리는 중", + "de": "Warten auf Remote-Bildschirminformationen", + "fr": "En attente d'informations sur l'écran distant", + "es": "Esperando información de la pantalla remota", + "pt-BR": "Aguardando informações da tela remota", + "ru": "Ожидание информации об удаленном экране." + }, + "等待远端画面…": { + "zh-Hans": "等待远端画面…", + "en": "Waiting for the remote screen...", + "zh-Hant": "等待遠端畫面…", + "ja": "リモート画面を待っています...", + "ko": "원격 화면을 기다리는 중...", + "de": "Warten auf den Remote-Bildschirm ...", + "fr": "En attente de l'écran distant...", + "es": "Esperando la pantalla remota...", + "pt-BR": "Aguardando a tela remota...", + "ru": "Ожидание удаленного экрана..." + }, + "等待连接": { + "zh-Hans": "等待连接", + "en": "Waiting for connection", + "zh-Hant": "等待連線", + "ja": "接続待ち", + "ko": "연결 대기 중", + "de": "Warten auf Verbindung", + "fr": "En attente de connexion", + "es": "Esperando conexión", + "pt-BR": "Aguardando conexão", + "ru": "Ожидание соединения" + }, + "等待隐私授权": { + "zh-Hans": "等待隐私授权", + "en": "Waiting for privacy authorization", + "zh-Hant": "等待隱私授權", + "ja": "プライバシー認証待ち", + "ko": "개인정보 인증 대기 중", + "de": "Datenschutzzustimmung ausstehend", + "fr": "En attente d'une autorisation de confidentialité", + "es": "Esperando autorización de privacidad", + "pt-BR": "Aguardando autorização de privacidade", + "ru": "Ожидание разрешения на конфиденциальность." + }, + "粘贴": { + "zh-Hans": "粘贴", + "en": "Paste", + "zh-Hant": "貼上", + "ja": "貼り付け", + "ko": "붙여넣기", + "de": "Einfügen", + "fr": "Coller", + "es": "Pegar", + "pt-BR": "Colar", + "ru": "Вставить" + }, + "粘贴到远端": { + "zh-Hans": "粘贴到远端", + "en": "Paste to remote", + "zh-Hant": "貼上到遠端", + "ja": "接続先に貼り付け", + "ko": "원격에 붙여넣기", + "de": "Auf Fernbedienung einfügen", + "fr": "Coller sur la télécommande", + "es": "Pegar en remoto", + "pt-BR": "Colar no controle remoto", + "ru": "Вставить на пульт" + }, + "精简模式": { + "zh-Hans": "精简模式", + "en": "Compact", + "ru": "Компактно", + "zh-Hant": "精簡模式", + "ja": "コンパクト", + "ko": "콤팩트", + "de": "Kompakt", + "fr": "Compacte", + "es": "Compacto", + "pt-BR": "Compacto" + }, + "系统已停止后台会话": { + "zh-Hans": "系统已停止后台会话", + "en": "The system has stopped the background session", + "zh-Hant": "系統已停止後臺會話", + "ja": "システムはバックグラウンド セッションを停止しました", + "ko": "시스템이 백그라운드 세션을 중지했습니다.", + "de": "Das System hat die Hintergrundsitzung gestoppt", + "fr": "Le système a arrêté la session en arrière-plan", + "es": "El sistema ha detenido la sesión en segundo plano.", + "pt-BR": "O sistema interrompeu a sessão em segundo plano", + "ru": "Система остановила фоновый сеанс." + }, + "系统未允许后台会话,连接已断开": { + "zh-Hans": "系统未允许后台会话,连接已断开", + "en": "Background session not allowed by system, connection disconnected", + "zh-Hant": "系統未允許後臺會話,連線已斷開", + "ja": "バックグラウンド セッションがシステムによって許可されていないため、接続が切断されました", + "ko": "시스템에서 백그라운드 세션을 허용하지 않아 연결이 끊어졌습니다.", + "de": "Hintergrundsitzung vom System nicht zugelassen, Verbindung getrennt", + "fr": "Session en arrière-plan non autorisée par le système, connexion déconnectée", + "es": "Sesión en segundo plano no permitida por el sistema, conexión desconectada", + "pt-BR": "Sessão em segundo plano não permitida pelo sistema, conexão desconectada", + "ru": "Фоновый сеанс запрещен системой, соединение прервано." + }, + "系统键盘": { + "zh-Hans": "系统键盘", + "en": "System keyboard", + "zh-Hant": "系統鍵盤", + "ja": "システムキーボード", + "ko": "시스템 키보드", + "de": "Systemtastatur", + "fr": "Clavier système", + "es": "Teclado del sistema", + "pt-BR": "Teclado do sistema", + "ru": "Системная клавиатура" + }, + "绝对位置": { + "zh-Hans": "绝对位置", + "en": "Direct touch", + "ru": "Касание", + "zh-Hant": "絕對位置", + "ja": "直接タッチ", + "ko": "직접 터치", + "de": "Direkte Berührung", + "fr": "Toucher direct", + "es": "Toque directo", + "pt-BR": "Toque direto" + }, + "绝对鼠标": { + "zh-Hans": "绝对鼠标", + "en": "Absolute Mouse", + "zh-Hant": "絕對滑鼠", + "ja": "アブソリュートマウス", + "ko": "앱솔루트 마우스", + "de": "Absolute Maus", + "fr": "Souris absolue", + "es": "Ratón absoluto", + "pt-BR": "Rato Absoluto", + "ru": "Абсолютная мышь" + }, + "编辑": { + "zh-Hans": "编辑", + "en": "Edit", + "ru": "Изменить", + "zh-Hant": "編輯", + "ja": "編集", + "ko": "편집", + "de": "Bearbeiten", + "fr": "Modifier", + "es": "Editar", + "pt-BR": "Editar" + }, + "网络状态": { + "zh-Hans": "网络状态", + "en": "Network", + "ru": "Сеть", + "zh-Hant": "網路狀態", + "ja": "ネットワーク", + "ko": "네트워크", + "de": "Netzwerk", + "fr": "Réseau", + "es": "Red", + "pt-BR": "Rede" + }, + "网络连接": { + "zh-Hans": "网络连接", + "en": "Network", + "ru": "Сеть", + "zh-Hant": "網路連線", + "ja": "ネットワーク", + "ko": "네트워크", + "de": "Netzwerk", + "fr": "Réseau", + "es": "Red", + "pt-BR": "Rede" + }, + "网络连接已中断,请重新连接。": { + "zh-Hans": "网络连接已中断,请重新连接。", + "en": "The network connection has been interrupted, please reconnect.", + "zh-Hant": "網路連線已中斷,請重新連線。", + "ja": "ネットワーク接続が切断されました。再接続してください。", + "ko": "네트워크 연결이 중단되었습니다. 다시 연결해 주세요.", + "de": "Die Netzwerkverbindung wurde unterbrochen. Bitte stellen Sie die Verbindung wieder her.", + "fr": "La connexion réseau a été interrompue, veuillez vous reconnecter.", + "es": "La conexión de red ha sido interrumpida, vuelva a conectarse.", + "pt-BR": "A conexão de rede foi interrompida, reconecte.", + "ru": "Сетевое соединение прервано, подключитесь заново." + }, + "群控中": { + "zh-Hans": "群控中", + "en": "Group control", + "ru": "Групп. управление", + "zh-Hant": "群控中", + "ja": "グループ制御", + "ko": "그룹 제어", + "de": "Gruppenkontrolle", + "fr": "Contrôle de groupe", + "es": "Control de grupo", + "pt-BR": "Controle de grupo" + }, + "群控中 · 所有已连接设备": { + "zh-Hans": "群控中 · 所有已连接设备", + "en": "Group control · All connected devices", + "ru": "Групповое управление · Все подключения", + "zh-Hant": "群控中 · 所有已連線裝置", + "ja": "グループ制御・接続されているすべてのデバイス", + "ko": "그룹 제어 · 연결된 모든 장치", + "de": "Gruppensteuerung · Alle angeschlossenen Geräte", + "fr": "Contrôle de groupe · Tous les appareils connectés", + "es": "Control de grupo · Todos los dispositivos conectados", + "pt-BR": "Controle de grupo · Todos os dispositivos conectados" + }, + "自动": { + "zh-Hans": "自动", + "en": "Auto", + "ru": "Авто", + "zh-Hant": "自動", + "ja": "オート", + "ko": "자동", + "de": "Automatisch", + "fr": "Automatique", + "es": "Automático", + "pt-BR": "Automático" + }, + "自定义": { + "zh-Hans": "自定义", + "en": "Custom", + "zh-Hant": "自定義", + "ja": "カスタム", + "ko": "커스텀", + "de": "Benutzerdefiniert", + "fr": "Personnalisé", + "es": "Personalizado", + "pt-BR": "Personalizado", + "ru": "Пользовательский" + }, + "自托管": { + "zh-Hans": "自托管", + "en": "Self-hosted server", + "ru": "Собственный сервер", + "zh-Hant": "自託管", + "ja": "セルフホストサーバー", + "ko": "자체 호스팅 서버", + "de": "Selbstgehosteter Server", + "fr": "Serveur auto-hébergé", + "es": "Servidor autohospedado", + "pt-BR": "Servidor auto-hospedado" + }, + "自托管设置": { + "zh-Hans": "自托管设置", + "en": "Self-hosted server settings", + "ru": "Настройки своего сервера", + "zh-Hant": "自託管設定", + "ja": "セルフホストサーバーの設定", + "ko": "자체 호스팅 서버 설정", + "de": "Selbstgehostete Servereinstellungen", + "fr": "Paramètres du serveur auto-hébergé", + "es": "Configuración del servidor autohospedado", + "pt-BR": "Configurações do servidor auto-hospedado" + }, + "自托管配置": { + "zh-Hans": "自托管配置", + "en": "Self-hosted server", + "ru": "Собственный сервер", + "zh-Hant": "自託管配置", + "ja": "セルフホストサーバー", + "ko": "자체 호스팅 서버", + "de": "Selbstgehosteter Server", + "fr": "Serveur auto-hébergé", + "es": "Servidor autohospedado", + "pt-BR": "Servidor auto-hospedado" + }, + "虚拟鼠标": { + "zh-Hans": "虚拟鼠标", + "en": "Virtual mouse", + "zh-Hant": "虛擬滑鼠", + "ja": "仮想マウス", + "ko": "가상마우스", + "de": "Virtuelle Maus", + "fr": "Souris virtuelle", + "es": "Ratón virtual", + "pt-BR": "Rato virtual", + "ru": "Виртуальная мышь" + }, + "被控中": { + "zh-Hans": "被控中", + "en": "Controlled", + "ru": "Под управлением", + "zh-Hant": "被控中", + "ja": "制御済み", + "ko": "제어됨", + "de": "Kontrolliert", + "fr": "Contrôlé", + "es": "Controlado", + "pt-BR": "Controlado" + }, + "被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴": { + "zh-Hans": "被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴", + "en": "The controlled terminal does not support direct input of Chinese, please update the macOS controlled terminal; you can also copy the text first, send it through the clipboard of the remote control menu and then paste it", + "zh-Hant": "被控端不支援直接輸入中文,請更新 macOS 被控端;也可先複製文字,透過遠控選單的剪貼簿傳送後貼上", + "ja": "制御端末は中国語の直接入力をサポートしていません。macOS 制御端末を更新してください。最初にテキストをコピーし、リモート コントロール メニューのクリップボード経由で送信してから貼り付けることもできます。", + "ko": "제어 터미널은 중국어 직접 입력을 지원하지 않습니다. macOS 제어 터미널을 업데이트하세요. 텍스트를 먼저 복사한 후 리모컨 메뉴의 클립보드를 통해 전송한 후 붙여넣을 수도 있습니다.", + "de": "Das gesteuerte Terminal unterstützt keine direkte Eingabe von Chinesisch. Bitte aktualisieren Sie das von macOS gesteuerte Terminal. Sie können den Text auch zunächst kopieren, über die Zwischenablage des Fernbedienungsmenüs senden und dann einfügen", + "fr": "Le terminal contrôlé ne prend pas en charge la saisie directe du chinois, veuillez mettre à jour le terminal contrôlé par macOS ; vous pouvez également d'abord copier le texte, l'envoyer via le presse-papiers du menu de la télécommande, puis le coller", + "es": "El terminal controlado no admite la entrada directa de chino; actualice el terminal controlado por macOS; También puedes copiar el texto primero, enviarlo a través del portapapeles del menú del control remoto y luego pegarlo.", + "pt-BR": "O terminal controlado não suporta entrada direta de chinês. Atualize o terminal controlado pelo macOS; você também pode copiar o texto primeiro, enviá-lo pela área de transferência do menu do controle remoto e depois colá-lo", + "ru": "Управляемый терминал не поддерживает прямой ввод китайского языка, обновите управляемый терминал macOS; вы также можете сначала скопировать текст, отправить его через буфер обмена меню пульта дистанционного управления, а затем вставить" + }, + "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。": { + "zh-Hans": "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", + "en": "The remote privacy screen was unlocked using the local shortcut. Lock it again to restore privacy and disable local shortcut unlocking.", + "ru": "Приватный экран отключён локальным сочетанием клавиш. Заблокируйте его снова, чтобы восстановить защиту и запретить локальную разблокировку.", + "zh-Hant": "被控端已透過組合鍵解除隱私屏。點選“鎖定”將重新開啟隱私屏,並禁止本機使用組合鍵解鎖。", + "ja": "ローカル ショートカットを使用してリモート プライバシー画面のロックが解除されました。再度ロックするとプライバシーが回復され、ローカル ショートカットのロック解除が無効になります。", + "ko": "로컬 단축키를 사용하여 원격 개인정보 보호 화면을 잠금 해제했습니다. 개인정보 보호를 복원하고 로컬 바로가기 잠금 해제를 비활성화하려면 다시 잠그세요.", + "de": "Der Remote-Datenschutzbildschirm wurde über die lokale Verknüpfung entsperrt. Sperren Sie es erneut, um die Privatsphäre wiederherzustellen und das Entsperren lokaler Verknüpfungen zu deaktivieren.", + "fr": "L'écran de confidentialité à distance a été déverrouillé à l'aide du raccourci local. Verrouillez-le à nouveau pour restaurer la confidentialité et désactiver le déverrouillage des raccourcis locaux.", + "es": "La pantalla de privacidad remota se desbloqueó usando el acceso directo local. Bloquéelo nuevamente para restaurar la privacidad y deshabilitar el desbloqueo de accesos directos locales.", + "pt-BR": "A tela de privacidade remota foi desbloqueada usando o atalho local. Bloqueie-o novamente para restaurar a privacidade e desativar o desbloqueio de atalhos locais." + }, + "被控端平台:%1$@": { + "zh-Hans": "被控端平台:%1$@", + "en": "Controlled terminal platform:%1$@", + "zh-Hant": "被控端平臺:%1$@", + "ja": "制御端末プラットフォーム:%1$@", + "ko": "제어 터미널 플랫폼:%1$@", + "de": "Kontrollierte Terminalplattform:%1$@", + "fr": "Plateforme terminale contrôlée :%1$@", + "es": "Plataforma terminal controlada:%1$@", + "pt-BR": "Plataforma de terminal controlada:%1$@", + "ru": "Управляемая терминальная платформа:%1$@." + }, + "被控端版本过低,请升级到最新版本。": { + "zh-Hans": "被控端版本过低,请升级到最新版本。", + "en": "The controlled version is too low, please upgrade to the latest version.", + "zh-Hant": "被控端版本過低,請升級到最新版本。", + "ja": "管理されているバージョンが低すぎるため、最新バージョンにアップグレードしてください。", + "ko": "제어 버전이 너무 낮습니다. 최신 버전으로 업그레이드하세요.", + "de": "Die kontrollierte Version ist zu niedrig, bitte aktualisieren Sie auf die neueste Version.", + "fr": "La version contrôlée est trop basse, veuillez mettre à niveau vers la dernière version.", + "es": "La versión controlada es demasiado baja; actualice a la última versión.", + "pt-BR": "A versão controlada é muito baixa, atualize para a versão mais recente.", + "ru": "Управляемая версия слишком низкая, обновите ее до последней версии." + }, + "被控端编码器": { + "zh-Hans": "被控端编码器", + "en": "Remote encoder", + "ru": "Кодер удалённой стороны", + "zh-Hant": "被控端編碼器", + "ja": "リモートエンコーダー", + "ko": "리모트 엔코더", + "de": "Remote-Encoder", + "fr": "Encodeur déporté", + "es": "Codificador remoto", + "pt-BR": "Codificador remoto" + }, + "被控端编码器 ": { + "zh-Hans": "被控端编码器 ", + "en": "Remote encoder ", + "ru": "Удалённый кодер ", + "zh-Hant": "被控端編碼器 ", + "ja": "リモートエンコーダー ", + "ko": "리모트 엔코더 ", + "de": "Remote-Encoder ", + "fr": "Encodeur déporté ", + "es": "Codificador remoto ", + "pt-BR": "Codificador remoto " + }, + "被连接时开启隐私屏": { + "zh-Hans": "被连接时开启隐私屏", + "en": "Privacy screen on incoming connection", + "ru": "Приватный экран при подключении", + "zh-Hant": "被連線時開啟隱私屏", + "ja": "着信接続時のプライバシー画面", + "ko": "연결 수신 시 개인정보 보호 화면", + "de": "Datenschutzbildschirm bei eingehender Verbindung", + "fr": "Écran de confidentialité sur la connexion entrante", + "es": "Pantalla de privacidad en la conexión entrante", + "pt-BR": "Tela de privacidade na conexão de entrada" + }, + "要发送到远端的文本": { + "zh-Hans": "要发送到远端的文本", + "en": "Text to be sent to the remote end", + "zh-Hant": "要傳送到遠端的文字", + "ja": "相手側に送信するテキスト", + "ko": "원격지로 보낼 텍스트", + "de": "Text, der an die Gegenstelle gesendet werden soll", + "fr": "Texte à envoyer à l'extrémité distante", + "es": "Texto a enviar al extremo remoto", + "pt-BR": "Texto a ser enviado para o terminal remoto", + "ru": "Текст для отправки на удаленный конец" + }, + "视频": { + "zh-Hans": "视频", + "en": "Video", + "ru": "Видео", + "zh-Hant": "影片", + "ja": "ビデオ", + "ko": "영상", + "de": "Video", + "fr": "Vidéo", + "es": "Vídeo", + "pt-BR": "Vídeo" + }, + "视频 %1$@×%2$@ · %3$@ 帧": { + "zh-Hans": "视频 %1$@×%2$@ · %3$@ 帧", + "en": "Video %1$@×%2$@·%3$@ frames", + "zh-Hant": "影片 %1$@×%2$@ · %3$@ 幀", + "ja": "ビデオ%1$@×%2$@・%3$@フレーム", + "ko": "비디오%1$@×%2$@·%3$@프레임", + "de": "Video %1$@×%2$@·%3$@-Frames", + "fr": "Vidéo %1$@×%2$@· Images %3$@", + "es": "Vídeo %1$@×%2$@· Cuadros %3$@", + "pt-BR": "Vídeo %1$@×%2$@· Quadros %3$@", + "ru": "Видео %1$@×%2$@·%3$@ кадры" + }, + "视频延时": { + "zh-Hans": "视频延时", + "en": "Video latency", + "ru": "Задержка видео", + "zh-Hant": "影片延時", + "ja": "ビデオの遅延", + "ko": "영상 지연", + "de": "Videolatenz", + "fr": "Latence vidéo", + "es": "Latencia de vídeo", + "pt-BR": "Latência de vídeo" + }, + "视频总带宽": { + "zh-Hans": "视频总带宽", + "en": "Total bandwidth", + "ru": "Общий битрейт", + "zh-Hant": "影片總頻寬", + "ja": "総帯域幅", + "ko": "총 대역폭", + "de": "Gesamtbandbreite", + "fr": "Bande passante totale", + "es": "Ancho de banda total", + "pt-BR": "Largura de banda total" + }, + "视频编码": { + "zh-Hans": "视频编码", + "en": "Video codec", + "ru": "Видеокодек", + "zh-Hant": "影片編碼", + "ja": "ビデオコーデック", + "ko": "비디오 코덱", + "de": "Videocodec", + "fr": "Codec vidéo", + "es": "Códec de vídeo", + "pt-BR": "Codec de vídeo" + }, + "视频编码格式": { + "zh-Hans": "视频编码格式", + "en": "Video codec", + "ru": "Видеокодек", + "zh-Hant": "影片編碼格式", + "ja": "ビデオコーデック", + "ko": "비디오 코덱", + "de": "Videocodec", + "fr": "Codec vidéo", + "es": "Códec de vídeo", + "pt-BR": "Codec de vídeo" + }, + "触摸位置直接对应远端屏幕位置,适合快速定位。": { + "zh-Hans": "触摸位置直接对应远端屏幕位置,适合快速定位。", + "en": "The touch position directly corresponds to the remote screen position, which is suitable for quick positioning.", + "zh-Hant": "觸控位置直接對應遠端螢幕位置,適合快速定位。", + "ja": "タッチ位置はリモート画面位置に直接対応するため、素早い位置決めに適しています。", + "ko": "터치 위치는 원격 화면 위치와 직접적으로 일치하므로 빠른 위치 지정에 적합합니다.", + "de": "Die Berührungsposition entspricht direkt der Remote-Bildschirmposition, die für eine schnelle Positionierung geeignet ist.", + "fr": "La position tactile correspond directement à la position de l'écran distant, ce qui convient à un positionnement rapide.", + "es": "La posición táctil corresponde directamente a la posición de la pantalla remota, que es adecuada para un posicionamiento rápido.", + "pt-BR": "A posição de toque corresponde diretamente à posição da tela remota, que é adequada para posicionamento rápido.", + "ru": "Положение касания напрямую соответствует положению удаленного экрана, что подходит для быстрого позиционирования." + }, + "认证服务繁忙,请稍后重试。": { + "zh-Hans": "认证服务繁忙,请稍后重试。", + "en": "Authentication service busy. Try again later.", + "ru": "Сервис проверки занят. Повторите позже.", + "zh-Hant": "認證服務繁忙,請稍後重試。", + "ja": "認証サービスがビジー状態です。後でもう一度試してください。", + "ko": "인증 서비스가 사용 중입니다. 나중에 다시 시도하세요.", + "de": "Authentifizierungsdienst ausgelastet. Versuchen Sie es später noch einmal.", + "fr": "Service d'authentification occupé. Réessayez plus tard.", + "es": "Servicio de autenticación ocupado. Vuelve a intentarlo más tarde.", + "pt-BR": "Serviço de autenticação ocupado. Tente novamente mais tarde." + }, + "记住密码": { + "zh-Hans": "记住密码", + "en": "Remember password", + "ru": "Запомнить пароль", + "zh-Hant": "記住密碼", + "ja": "パスワードを記憶する", + "ko": "비밀번호 기억하기", + "de": "Passwort merken", + "fr": "Mémoriser le mot de passe", + "es": "Recordar contraseña", + "pt-BR": "Lembrar senha" + }, + "记录或密码删除失败,请重试": { + "zh-Hans": "记录或密码删除失败,请重试", + "en": "Record or password deletion failed, please try again", + "zh-Hant": "記錄或密碼刪除失敗,請重試", + "ja": "レコードまたはパスワードの削除に失敗しました。もう一度お試しください。", + "ko": "기록 또는 비밀번호 삭제에 실패했습니다. 다시 시도해 주세요.", + "de": "Datensatz oder Passwort konnten nicht gelöscht werden. Bitte versuchen Sie es erneut", + "fr": "La suppression de l'enregistrement ou du mot de passe a échoué, veuillez réessayer", + "es": "Error al eliminar el registro o la contraseña, inténtelo de nuevo", + "pt-BR": "Falha ao excluir registro ou senha, tente novamente", + "ru": "Не удалось удалить запись или пароль. Повторите попытку." + }, + "许可": { + "zh-Hans": "许可", + "en": "License", + "zh-Hant": "許可", + "ja": "ライセンス", + "ko": "라이센스", + "de": "Lizenz", + "fr": "Licence", + "es": "Licencia", + "pt-BR": "Licença", + "ru": "Лицензия" + }, + "许可与版权声明": { + "zh-Hans": "许可与版权声明", + "en": "Licenses and copyright notices", + "ru": "Лицензии и авторские права", + "zh-Hant": "許可與版權宣告", + "ja": "ライセンスと著作権表示", + "ko": "라이센스 및 저작권 고지", + "de": "Lizenzen und Urheberrechtshinweise", + "fr": "Licences et mentions de droits d'auteur", + "es": "Licencias y avisos de derechos de autor", + "pt-BR": "Licenças e avisos de direitos autorais" + }, + "许可与版权声明可离线查阅。": { + "zh-Hans": "许可与版权声明可离线查阅。", + "en": "The license and copyright notice are available offline.", + "zh-Hant": "許可與版權宣告可離線查閱。", + "ja": "ライセンスと著作権表示はオフラインでも利用できます。", + "ko": "라이센스 및 저작권 고지는 오프라인에서 확인할 수 있습니다.", + "de": "Die Lizenz- und Urheberrechtshinweise sind offline verfügbar.", + "fr": "La licence et la notice de copyright sont disponibles hors ligne.", + "es": "La licencia y el aviso de derechos de autor están disponibles sin conexión.", + "pt-BR": "A licença e o aviso de direitos autorais estão disponíveis offline.", + "ru": "Лицензия и уведомление об авторских правах доступны в автономном режиме." + }, + "设备": { + "zh-Hans": "设备", + "en": "device", + "ru": "устройство", + "zh-Hant": "裝置", + "ja": "デバイス", + "ko": "장치", + "de": "Gerät", + "fr": "appareil", + "es": "dispositivo", + "pt-BR": "dispositivo" + }, + "设备 / ID": { + "zh-Hans": "设备 / ID", + "en": "Device / ID", + "ru": "Устройство / ID", + "zh-Hant": "裝置 / ID", + "ja": "デバイス/ID", + "ko": "기기/ID", + "de": "Gerät / ID", + "fr": "Appareil/ID", + "es": "Dispositivo/ID", + "pt-BR": "Dispositivo/ID" + }, + "设备 ID": { + "zh-Hans": "设备 ID", + "en": "Device ID", + "ru": "ID", + "zh-Hant": "裝置 ID", + "ja": "デバイスID", + "ko": "장치 ID", + "de": "Geräte-ID", + "fr": "ID de l'appareil", + "es": "ID del dispositivo", + "pt-BR": "ID do dispositivo" + }, + "设备不支持": { + "zh-Hans": "设备不支持", + "en": "Unsupported", + "ru": "Не поддерживается", + "zh-Hant": "裝置不支援", + "ja": "サポートされていません", + "ko": "지원되지 않음", + "de": "Nicht unterstützt", + "fr": "Non pris en charge", + "es": "No compatible", + "pt-BR": "Não suportado" + }, + "设备名称": { + "zh-Hans": "设备名称", + "en": "Device Name", + "ru": "Имя устройства", + "zh-Hant": "裝置名稱", + "ja": "デバイス名", + "ko": "장치 이름", + "de": "Gerätename", + "fr": "Nom de l'appareil", + "es": "Nombre del dispositivo", + "pt-BR": "Nome do dispositivo" + }, + "设备正忙,请稍后重试。": { + "zh-Hans": "设备正忙,请稍后重试。", + "en": "The desktop is busy. Try again shortly.", + "ru": "Компьютер занят. Повторите позже.", + "zh-Hant": "裝置正忙,請稍後重試。", + "ja": "デスクトップはビジー状態です。しばらくしてからもう一度お試しください。", + "ko": "데스크톱이 사용 중입니다. 잠시 후 다시 시도하세요.", + "de": "Der Desktop ist beschäftigt. Versuchen Sie es in Kürze noch einmal.", + "fr": "Le bureau est occupé. Réessayez sous peu.", + "es": "El escritorio está ocupado. Vuelve a intentarlo en breve.", + "pt-BR": "A área de trabalho está ocupada. Tente novamente em breve." + }, + "设备离线": { + "zh-Hans": "设备离线", + "en": "Device Offline", + "ru": "Устройство не в сети", + "zh-Hant": "裝置離線", + "ja": "デバイスがオフライン", + "ko": "장치 오프라인", + "de": "Gerät offline", + "fr": "Appareil hors ligne", + "es": "Dispositivo sin conexión", + "pt-BR": "Dispositivo off-line" + }, + "设备网络状态": { + "zh-Hans": "设备网络状态", + "en": "Device network status", + "ru": "Состояние сети устройств", + "zh-Hant": "裝置網路狀態", + "ja": "デバイスのネットワーク状態", + "ko": "기기 네트워크 상태", + "de": "Netzwerkstatus des Geräts", + "fr": "État du réseau de l'appareil", + "es": "Estado de la red del dispositivo", + "pt-BR": "Status da rede do dispositivo" + }, + "设备身份保存失败,请检查安全存储": { + "zh-Hans": "设备身份保存失败,请检查安全存储", + "en": "Device identity failed to save, please check secure storage", + "zh-Hant": "裝置身份儲存失敗,請檢查安全儲存", + "ja": "デバイス ID を保存できませんでした。安全なストレージを確認してください。", + "ko": "기기 ID를 저장하지 못했습니다. 보안 저장소를 확인하세요.", + "de": "Die Geräteidentität konnte nicht gespeichert werden. Bitte überprüfen Sie den sicheren Speicher", + "fr": "L'identité de l'appareil n'a pas pu être enregistrée. Veuillez vérifier le stockage sécurisé.", + "es": "No se pudo guardar la identidad del dispositivo; verifique el almacenamiento seguro", + "pt-BR": "Falha ao salvar a identidade do dispositivo. Verifique o armazenamento seguro", + "ru": "Не удалось сохранить идентификационные данные устройства. Проверьте безопасное хранилище." + }, + "设备身份及选择保存的访问密码使用 Android Keystore 加密。连接记录仅保存在本机,不纳入设备备份。剪贴板内容在结束会话时清除。离开应用后通过画中画或连接通知保持会话,可在应用或通知中断开。": { + "zh-Hans": "设备身份及选择保存的访问密码使用 Android Keystore 加密。连接记录仅保存在本机,不纳入设备备份。剪贴板内容在结束会话时清除。离开应用后通过画中画或连接通知保持会话,可在应用或通知中断开。", + "en": "Device identity and selected saved access passwords are encrypted using Android Keystore. Connection records are only saved locally and are not included in device backup. The clipboard contents are cleared when the session is ended. Stay in session with picture-in-picture or connected notifications after leaving the app, and disconnect within the app or notifications.", + "zh-Hant": "裝置身份及選擇儲存的訪問密碼使用 Android Keystore 加密。連線記錄僅儲存在本機,不納入裝置備份。剪貼簿內容在結束會話時清除。離開應用後透過畫中畫或連線通知保持會話,可在應用或通知中斷開。", + "ja": "デバイス ID と選択された保存されたアクセス パスワードは、Android キーストアを使用して暗号化されます。接続記録はローカルにのみ保存され、デバイスのバックアップには含まれません。クリップボードの内容はセッションが終了するとクリアされます。アプリを終了した後もピクチャーインピクチャーまたは接続された通知でセッションを維持し、アプリまたは通知内で切断します。", + "ko": "기기 ID와 선택된 저장된 액세스 비밀번호는 Android Keystore를 사용하여 암호화됩니다. 연결 기록은 로컬에만 저장되며 장치 백업에는 포함되지 않습니다. 세션이 종료되면 클립보드 내용이 지워집니다. 앱을 종료한 후에도 PIP(picture-in-picture) 또는 연결된 알림으로 세션을 유지하고 앱 또는 알림 내에서 연결을 끊습니다.", + "de": "Geräteidentität und ausgewählte gespeicherte Zugangskennwörter werden mit Android Keystore verschlüsselt. Verbindungsdatensätze werden nur lokal gespeichert und sind nicht in der Gerätesicherung enthalten. Der Inhalt der Zwischenablage wird gelöscht, wenn die Sitzung beendet wird. Bleiben Sie mit Bild-in-Bild- oder verbundenen Benachrichtigungen in der Sitzung, nachdem Sie die App verlassen haben, und trennen Sie die Verbindung innerhalb der App oder der Benachrichtigungen.", + "fr": "L'identité de l'appareil et les mots de passe d'accès enregistrés sélectionnés sont cryptés à l'aide d'Android Keystore. Les enregistrements de connexion sont uniquement enregistrés localement et ne sont pas inclus dans la sauvegarde de l'appareil. Le contenu du presse-papiers est effacé à la fin de la session. Restez en session avec des notifications d'image dans l'image ou connectées après avoir quitté l'application, et déconnectez-vous de l'application ou des notifications.", + "es": "La identidad del dispositivo y las contraseñas de acceso guardadas seleccionadas se cifran mediante Android Keystore. Los registros de conexión solo se guardan localmente y no se incluyen en la copia de seguridad del dispositivo. El contenido del portapapeles se borra cuando finaliza la sesión. Manténgase en sesión con imagen en imagen o notificaciones conectadas después de salir de la aplicación y desconéctese dentro de la aplicación o las notificaciones.", + "pt-BR": "A identidade do dispositivo e as senhas de acesso salvas selecionadas são criptografadas usando o Android Keystore. Os registros de conexão são salvos apenas localmente e não são incluídos no backup do dispositivo. O conteúdo da área de transferência é apagado quando a sessão é encerrada. Mantenha a sessão com notificações picture-in-picture ou conectadas depois de sair do aplicativo e desconecte-se do aplicativo ou das notificações.", + "ru": "Идентификатор устройства и выбранные сохраненные пароли доступа шифруются с помощью хранилища ключей Android. Записи подключений сохраняются только локально и не включаются в резервную копию устройства. Содержимое буфера обмена очищается после завершения сеанса. Оставайтесь в сеансе с помощью «картинка в картинке» или подключенных уведомлений после выхода из приложения и отключайтесь внутри приложения или уведомлений." + }, + "设备身份及选择保存的访问密码加密保存在本机。画面预览默认关闭,开启后从下一次连接起保存。剪贴板内容在结束会话时清除。离开应用后通过画中画或后台任务保持会话,可随时返回应用断开。": { + "zh-Hans": "设备身份及选择保存的访问密码加密保存在本机。画面预览默认关闭,开启后从下一次连接起保存。剪贴板内容在结束会话时清除。离开应用后通过画中画或后台任务保持会话,可随时返回应用断开。", + "en": "The device identity and the access password selected to be saved are encrypted and stored locally. Screen preview is turned off by default and will be saved from the next connection after it is turned on. The clipboard contents are cleared when the session is ended. Maintain the session through picture-in-picture or background tasks after leaving the app, and return to the app at any time to disconnect.", + "zh-Hant": "裝置身份及選擇儲存的訪問密碼加密儲存在本機。畫面預覽預設關閉,開啟後從下一次連線起儲存。剪貼簿內容在結束會話時清除。離開應用後透過畫中畫或後臺任務保持會話,可隨時返回應用斷開。", + "ja": "保存するように選択されたデバイス ID とアクセス パスワードは、暗号化されてローカルに保存されます。画面プレビューはデフォルトではオフになっており、オンにすると次回の接続から保存されます。クリップボードの内容はセッションが終了するとクリアされます。アプリを終了した後も、ピクチャ イン ピクチャまたはバックグラウンド タスクを通じてセッションを維持し、いつでもアプリに戻って切断します。", + "ko": "저장하기 위해 선택한 기기 ID와 접속 비밀번호는 암호화되어 로컬에 저장됩니다. 화면 미리보기는 기본적으로 꺼져 있으며, 켜진 후 다음 연결부터 저장됩니다. 세션이 종료되면 클립보드 내용이 지워집니다. 앱을 종료한 후에도 PIP 또는 백그라운드 작업을 통해 세션을 유지하고, 언제든지 앱으로 돌아와 연결을 끊을 수 있습니다.", + "de": "Die Geräteidentität und das zum Speichern ausgewählte Zugangspasswort werden verschlüsselt und lokal gespeichert. Die Bildschirmvorschau ist standardmäßig deaktiviert und wird nach dem Einschalten bei der nächsten Verbindung gespeichert. Der Inhalt der Zwischenablage wird gelöscht, wenn die Sitzung beendet wird. Halten Sie die Sitzung durch Bild-in-Bild- oder Hintergrundaufgaben aufrecht, nachdem Sie die App verlassen haben, und kehren Sie jederzeit zur App zurück, um die Verbindung zu trennen.", + "fr": "L'identité de l'appareil et le mot de passe d'accès sélectionnés pour être enregistrés sont cryptés et stockés localement. L'aperçu de l'écran est désactivé par défaut et sera enregistré à partir de la prochaine connexion après son activation. Le contenu du presse-papiers est effacé à la fin de la session. Maintenez la session via des tâches d'image dans l'image ou en arrière-plan après avoir quitté l'application, et revenez à l'application à tout moment pour vous déconnecter.", + "es": "La identidad del dispositivo y la contraseña de acceso seleccionada para guardar se cifran y almacenan localmente. La vista previa de la pantalla está desactivada de forma predeterminada y se guardará en la siguiente conexión después de activarla. El contenido del portapapeles se borra cuando finaliza la sesión. Mantenga la sesión mediante tareas de imagen en imagen o en segundo plano después de salir de la aplicación y regrese a la aplicación en cualquier momento para desconectarse.", + "pt-BR": "A identidade do dispositivo e a senha de acesso selecionada para ser salva são criptografadas e armazenadas localmente. A visualização da tela está desativada por padrão e será salva na próxima conexão após ser ativada. O conteúdo da área de transferência é apagado quando a sessão é encerrada. Mantenha a sessão por meio de tarefas picture-in-picture ou em segundo plano após sair do aplicativo e retorne ao aplicativo a qualquer momento para desconectar.", + "ru": "Идентификатор устройства и выбранный для сохранения пароль доступа шифруются и хранятся локально. Предварительный просмотр экрана по умолчанию отключен и будет сохранен при следующем подключении после включения. Содержимое буфера обмена очищается после завершения сеанса. Поддерживайте сеанс с помощью функции «картинка в картинке» или фоновых задач после выхода из приложения и возвращайтесь в приложение в любое время, чтобы отключиться." + }, + "设备连接密码": { + "zh-Hans": "设备连接密码", + "en": "Device password", + "ru": "Пароль устройства", + "zh-Hant": "裝置連線密碼", + "ja": "デバイスパスワード", + "ko": "기기 비밀번호", + "de": "Gerätepasswort", + "fr": "Mot de passe de l'appareil", + "es": "Contraseña del dispositivo", + "pt-BR": "Senha do dispositivo" + }, + "设置": { + "zh-Hans": "设置", + "en": "Settings", + "ru": "Настройки", + "zh-Hant": "設定", + "ja": "設定", + "ko": "설정", + "de": "Einstellungen", + "fr": "Réglages", + "es": "Ajustes", + "pt-BR": "Configurações" + }, + "设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。": { + "zh-Hans": "设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。", + "en": "Settings → Apps & services → App startup management\n\nEnable: choose Add app, select CrossDesk, then choose Done.\n\nDisable: find this app in the startup list and choose Remove.", + "ru": "Настройки → Приложения и сервисы → Управление запуском\n\nВключить: добавьте CrossDesk в список и подтвердите выбор.\n\nВыключить: удалите приложение из списка автозапуска.", + "zh-Hant": "設定 → 應用和元服務 → 應用啟動管理\n\n開啟:點選“新增應用”,選擇 CrossDesk,然後點選“完成”。\n\n關閉:在自啟動列表中找到本應用,點選“移除”。", + "ja": "[設定] → [アプリとサービス] → [アプリ起動管理]\n\n有効にする: [アプリの追加] を選択し、 [CrossDesk] を選択して、 [完了] を選択します。\n\n無効にする: スタートアップ リストでこのアプリを見つけて、[削除] を選択します。", + "ko": "설정 → 앱 및 서비스 → 앱 시작 관리\n\n활성화: 앱 추가를 선택하고CrossDesk를 선택한 다음 완료를 선택합니다.\n\n비활성화: 시작 목록에서 이 앱을 찾아 제거를 선택합니다.", + "de": "Einstellungen → Apps & Dienste → App-Startup-Verwaltung\n\nAktivieren: Wählen Sie „App hinzufügen“, wählen Sie CrossDesk und dann „Fertig“.\n\nDeaktivieren: Suchen Sie diese App in der Startliste und wählen Sie „Entfernen“.", + "fr": "Paramètres → Applications et services → Gestion du démarrage des applications\n\nActiver : choisissez Ajouter une application, sélectionnez CrossDesk, puis choisissez Terminé.\n\nDésactiver : recherchez cette application dans la liste de démarrage et choisissez Supprimer.", + "es": "Configuración → Aplicaciones y servicios → Gestión de inicio de aplicaciones\n\nHabilitar: elija Agregar aplicación, seleccione CrossDesk y luego elija Listo.\n\nDesactivar: busque esta aplicación en la lista de inicio y elija Eliminar.", + "pt-BR": "Configurações → Aplicativos e serviços → Gerenciamento de inicialização de aplicativos\n\nAtivar: escolha Adicionar aplicativo, selecione CrossDesk e escolha Concluído.\n\nDesativar: encontre este aplicativo na lista de inicialização e escolha Remover." + }, + "设置尚未初始化,请稍后重试。": { + "zh-Hans": "设置尚未初始化,请稍后重试。", + "en": "Settings are not ready; try again shortly.", + "ru": "Настройки ещё не готовы. Повторите позже.", + "zh-Hant": "設定尚未初始化,請稍後重試。", + "ja": "設定の準備ができていません。すぐにもう一度試してください。", + "ko": "설정이 준비되지 않았습니다. 잠시 후 다시 시도해 보세요.", + "de": "Einstellungen sind nicht bereit; Versuchen Sie es in Kürze noch einmal.", + "fr": "Les paramètres ne sont pas prêts ; réessayez sous peu.", + "es": "Las configuraciones no están listas; Inténtalo de nuevo en breve.", + "pt-BR": "As configurações não estão prontas; tente novamente em breve." + }, + "设置开机自启动": { + "zh-Hans": "设置开机自启动", + "en": "Set up auto start", + "ru": "Настройка автозапуска", + "zh-Hant": "設定開機自啟動", + "ja": "自動起動の設定", + "ko": "자동 시작 설정", + "de": "Automatischen Start einrichten", + "fr": "Configurer le démarrage automatique", + "es": "Configurar el inicio automático", + "pt-BR": "Configurar início automático" + }, + "设置未改变。": { + "zh-Hans": "设置未改变。", + "en": "Setting unchanged.", + "ru": "Настройка не изменилась.", + "zh-Hant": "設定未改變。", + "ja": "設定は変更されません。", + "ko": "설정은 변경되지 않습니다.", + "de": "Einstellung unverändert.", + "fr": "Paramètre inchangé.", + "es": "Configuración sin cambios.", + "pt-BR": "Configuração inalterada." + }, + "设置(修改后立即保存)": { + "zh-Hans": "设置(修改后立即保存)", + "en": "Settings (each change is saved immediately)", + "ru": "Настройки (изменения сохраняются сразу)", + "zh-Hant": "設定(修改後立即儲存)", + "ja": "設定 (各変更はすぐに保存されます)", + "ko": "설정(각 변경 사항은 즉시 저장됩니다)", + "de": "Einstellungen (jede Änderung wird sofort gespeichert)", + "fr": "Paramètres (chaque modification est enregistrée immédiatement)", + "es": "Configuración (cada cambio se guarda inmediatamente)", + "pt-BR": "Configurações (cada alteração é salva imediatamente)" + }, + "设置,有新版本": { + "zh-Hans": "设置,有新版本", + "en": "Settings, there is a new version", + "zh-Hant": "設定,有新版本", + "ja": "設定、新しいバージョンがあります", + "ko": "설정, 새 버전이 있습니다", + "de": "Einstellungen, es gibt eine neue Version", + "fr": "Paramètres, il existe une nouvelle version", + "es": "Configuración, hay una nueva versión.", + "pt-BR": "Configurações, há uma nova versão", + "ru": "Настройки, есть новая версия" + }, + "访问官网: ": { + "zh-Hans": "访问官网: ", + "en": "Access Website: ", + "ru": "Официальный сайт: ", + "zh-Hant": "訪問官網: ", + "ja": "ウェブサイトにアクセス: ", + "ko": "웹사이트 접속: ", + "de": "Zugriff auf die Website: ", + "fr": "Accéder au site Web : ", + "es": "Acceder al sitio web: ", + "pt-BR": "Acesse o site: " + }, + "访问密码": { + "zh-Hans": "访问密码", + "en": "Access password", + "zh-Hant": "訪問密碼", + "ja": "アクセスパスワード", + "ko": "접속 비밀번호", + "de": "Zugangspasswort", + "fr": "Mot de passe d'accès", + "es": "Contraseña de acceso", + "pt-BR": "Senha de acesso", + "ru": "Пароль доступа" + }, + "访问密码必须为 6 位英文字母或数字,区分大小写。": { + "zh-Hans": "访问密码必须为 6 位英文字母或数字,区分大小写。", + "en": "Use exactly 6 letters (A–Z, a–z) or digits (0–9). Case-sensitive.", + "ru": "Пароль: ровно 6 латинских букв или цифр. Регистр учитывается.", + "zh-Hant": "訪問密碼必須為 6 位英文字母或數字,區分大小寫。", + "ja": "正確に 6 つの文字 (A ~ Z、a ~ z) または数字 (0 ~ 9) を使用してください。大文字と小文字を区別。", + "ko": "정확히 6개의 문자(A–Z, a–z) 또는 숫자(0–9)를 사용하세요. 대소문자를 구분합니다.", + "de": "Verwenden Sie genau 6 Buchstaben (A–Z, a–z) oder Ziffern (0–9). Groß- und Kleinschreibung beachten.", + "fr": "Utilisez exactement 6 lettres (A–Z, a–z) ou chiffres (0–9). Sensible aux majuscules et minuscules.", + "es": "Utilice exactamente 6 letras (A–Z, a–z) o dígitos (0–9). Distingue mayúsculas y minúsculas.", + "pt-BR": "Use exatamente 6 letras (A–Z, a–z) ou dígitos (0–9). Maiúsculas e minúsculas." + }, + "访问密码错误": { + "zh-Hans": "访问密码错误", + "en": "Wrong access password", + "zh-Hant": "訪問密碼錯誤", + "ja": "アクセスパスワードが間違っています", + "ko": "접속 비밀번호가 잘못되었습니다.", + "de": "Falsches Zugangspasswort", + "fr": "Mot de passe d'accès erroné", + "es": "Contraseña de acceso incorrecta", + "pt-BR": "Senha de acesso errada", + "ru": "Неправильный пароль доступа." + }, + "访问密码错误,请重新输入": { + "zh-Hans": "访问密码错误,请重新输入", + "en": "The access password is wrong, please re-enter it.", + "zh-Hant": "訪問密碼錯誤,請重新輸入", + "ja": "アクセスパスワードが間違っていますので、再度入力してください。", + "ko": "접속비밀번호가 잘못되었습니다. 다시 입력해 주세요.", + "de": "Das Zugangspasswort ist falsch, bitte geben Sie es erneut ein.", + "fr": "Le mot de passe d'accès est erroné, veuillez le saisir à nouveau.", + "es": "La contraseña de acceso es incorrecta, por favor vuelva a ingresarla.", + "pt-BR": "A senha de acesso está errada, digite-a novamente.", + "ru": "Неверный пароль доступа, пожалуйста, введите его еще раз." + }, + "访问密码错误,请重新输入。": { + "zh-Hans": "访问密码错误,请重新输入。", + "en": "The access password is wrong, please re-enter it.", + "zh-Hant": "訪問密碼錯誤,請重新輸入。", + "ja": "アクセスパスワードが間違っていますので、再度入力してください。", + "ko": "접속비밀번호가 잘못되었습니다. 다시 입력해 주세요.", + "de": "Das Zugangspasswort ist falsch, bitte geben Sie es erneut ein.", + "fr": "Le mot de passe d'accès est erroné, veuillez le saisir à nouveau.", + "es": "La contraseña de acceso es incorrecta, por favor vuelva a ingresarla.", + "pt-BR": "A senha de acesso está errada, digite-a novamente.", + "ru": "Неверный пароль доступа, пожалуйста, введите его еще раз." + }, + "证书校验失败 · 点击重试": { + "zh-Hans": "证书校验失败 · 点击重试", + "en": "Certificate verification failed · Click to try again", + "zh-Hant": "證書校驗失敗 · 點選重試", + "ja": "証明書の検証に失敗しました · クリックして再試行してください", + "ko": "인증서 확인 실패 · 다시 시도하려면 클릭하세요.", + "de": "Zertifikatsüberprüfung fehlgeschlagen · Klicken Sie, um es erneut zu versuchen", + "fr": "Échec de la vérification du certificat · Cliquez pour réessayer", + "es": "Error en la verificación del certificado · Haga clic para intentar nuevamente", + "pt-BR": "Falha na verificação do certificado · Clique para tentar novamente", + "ru": "Не удалось проверить сертификат · Нажмите, чтобы повторить попытку." + }, + "证书验证失败,请重新安装自托管根证书": { + "zh-Hans": "证书验证失败,请重新安装自托管根证书", + "en": "Certificate verification failed. Reinstall the self-hosted root certificate.", + "ru": "Ошибка проверки сертификата. Переустановите корневой сертификат собственного сервера.", + "zh-Hant": "證書驗證失敗,請重新安裝自託管根證書", + "ja": "証明書の検証に失敗しました。セルフホスト型ルート証明書を再インストールします。", + "ko": "인증서 확인에 실패했습니다. 자체 호스팅 루트 인증서를 다시 설치합니다.", + "de": "Die Zertifikatsüberprüfung ist fehlgeschlagen. Installieren Sie das selbstgehostete Stammzertifikat neu.", + "fr": "La vérification du certificat a échoué. Réinstallez le certificat racine auto-hébergé.", + "es": "Falló la verificación del certificado. Reinstale el certificado raíz autohospedado.", + "pt-BR": "Falha na verificação do certificado. Reinstale o certificado raiz auto-hospedado." + }, + "该分组暂无近期连接": { + "zh-Hans": "该分组暂无近期连接", + "en": "No recent connections in this group", + "ru": "В этой группе нет недавних подключений", + "zh-Hant": "該分組暫無近期連線", + "ja": "このグループには最近の接続がありません", + "ko": "이 그룹에는 최근 연결이 없습니다.", + "de": "Keine aktuellen Verbindungen in dieser Gruppe", + "fr": "Aucune connexion récente dans ce groupe", + "es": "No hay conexiones recientes en este grupo.", + "pt-BR": "Nenhuma conexão recente neste grupo" + }, + "该应用需要授权以下权限:": { + "zh-Hans": "该应用需要授权以下权限:", + "en": "The application requires the following permissions:", + "ru": "Для работы приложения требуются следующие разрешения:", + "zh-Hant": "該應用需要授權以下許可權:", + "ja": "アプリケーションには次の権限が必要です。", + "ko": "애플리케이션에는 다음 권한이 필요합니다.", + "de": "Die Anwendung erfordert die folgenden Berechtigungen:", + "fr": "L'application nécessite les autorisations suivantes :", + "es": "La aplicación requiere los siguientes permisos:", + "pt-BR": "O aplicativo requer as seguintes permissões:" + }, + "该设备正在连接,请稍候": { + "zh-Hans": "该设备正在连接,请稍候", + "en": "This device is already connecting", + "ru": "Устройство уже подключается", + "zh-Hant": "該裝置正在連線,請稍候", + "ja": "このデバイスはすでに接続されています", + "ko": "이 장치는 이미 연결되어 있습니다", + "de": "Dieses Gerät stellt bereits eine Verbindung her", + "fr": "Cet appareil est déjà connecté", + "es": "Este dispositivo ya se está conectando", + "pt-BR": "Este dispositivo já está conectado" + }, + "该选项由系统或控制端管理,不可在此修改。": { + "zh-Hans": "该选项由系统或控制端管理,不可在此修改。", + "en": "This option is managed by the system or controller and is read-only here.", + "ru": "Этот параметр управляется системой или клиентом и здесь недоступен для изменения.", + "zh-Hant": "該選項由系統或控制端管理,不可在此修改。", + "ja": "このオプションはシステムまたはコントローラーによって管理され、ここでは読み取り専用です。", + "ko": "이 옵션은 시스템이나 컨트롤러에 의해 관리되며 여기서는 읽기 전용입니다.", + "de": "Diese Option wird vom System oder Controller verwaltet und ist hier schreibgeschützt.", + "fr": "Cette option est gérée par le système ou le contrôleur et est ici en lecture seule.", + "es": "Esta opción es administrada por el sistema o controlador y aquí es de solo lectura.", + "pt-BR": "Esta opção é gerenciada pelo sistema ou controlador e é somente leitura aqui." + }, + "语言": { + "zh-Hans": "语言", + "en": "Language", + "ru": "Язык", + "zh-Hant": "語言", + "ja": "言語", + "ko": "언어", + "de": "Sprache", + "fr": "Langue", + "es": "Idioma", + "pt-BR": "Idioma" + }, + "请先完成联网授权": { + "zh-Hans": "请先完成联网授权", + "en": "Please complete the online authorization first", + "zh-Hant": "請先完成聯網授權", + "ja": "最初にオンライン認証を完了してください", + "ko": "먼저 온라인 인증을 완료해주세요.", + "de": "Bitte füllen Sie zunächst die Online-Autorisierung aus", + "fr": "Veuillez d'abord remplir l'autorisation en ligne", + "es": "Primero complete la autorización en línea", + "pt-BR": "Por favor, preencha primeiro a autorização online", + "ru": "Сначала пройдите онлайн-авторизацию." + }, + "请先设置有效的服务器地址和端口,再启用自托管。": { + "zh-Hans": "请先设置有效的服务器地址和端口,再启用自托管。", + "en": "Set a valid server host and port before enabling self-hosting.", + "ru": "Укажите адрес и порт сервера перед включением собственного сервера.", + "zh-Hant": "請先設定有效的伺服器地址和埠,再啟用自託管。", + "ja": "セルフホスティングを有効にする前に、有効なサーバー ホストとポートを設定します。", + "ko": "셀프 호스팅을 활성화하기 전에 유효한 서버 호스트와 포트를 설정하세요.", + "de": "Legen Sie einen gültigen Serverhost und -port fest, bevor Sie das Selbsthosting aktivieren.", + "fr": "Définissez un hôte et un port de serveur valides avant d'activer l'auto-hébergement.", + "es": "Configure un host y un puerto de servidor válidos antes de habilitar el autohospedaje.", + "pt-BR": "Defina um host e uma porta de servidor válidos antes de ativar a auto-hospedagem." + }, + "请在 %d 秒后重试。": { + "zh-Hans": "请在 %d 秒后重试。", + "en": "Retry in %d seconds.", + "ru": "Повторите через %d сек.", + "zh-Hant": "請在 %d 秒後重試。", + "ja": "%d秒後に再試行します。", + "ko": "%d초 후에 다시 시도하세요.", + "de": "Wiederholen Sie den Vorgang in%dSekunden.", + "fr": "Réessayez dans%dsecondes.", + "es": "Reintentar en%dsegundos.", + "pt-BR": "Tente novamente em%dsegundos." + }, + "请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。": { + "zh-Hans": "请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。", + "en": "Allow CrossDesk access in System Settings. Reopen the app if macOS asks you to.", + "ru": "Разрешите доступ для CrossDesk в Системных настройках. Перезапустите приложение, если macOS попросит об этом.", + "zh-Hant": "請在系統設定中允許 CrossDesk 訪問。如系統提示重新開啟應用,請按提示操作。", + "ja": "システム設定でCrossDeskアクセスを許可します。 macOS が要求した場合は、アプリを再度開きます。", + "ko": "시스템 설정에서CrossDesk액세스를 허용합니다. macOS에서 요청하면 앱을 다시 엽니다.", + "de": "Erlauben Sie den CrossDesk-Zugriff in den Systemeinstellungen. Öffnen Sie die App erneut, wenn macOS Sie dazu auffordert.", + "fr": "Autoriser l'accès à CrossDesk dans les paramètres système. Rouvrez l'application si macOS vous le demande.", + "es": "Permitir el acceso a CrossDesk en Configuración del sistema. Vuelva a abrir la aplicación si macOS se lo solicita.", + "pt-BR": "Permitir acesso CrossDesk nas configurações do sistema. Abra novamente o aplicativo se o macOS solicitar." + }, + "请在系统设置中添加或移除本应用,返回后会自动刷新状态。": { + "zh-Hans": "请在系统设置中添加或移除本应用,返回后会自动刷新状态。", + "en": "Add or remove this app in system Settings. The status refreshes when you return.", + "ru": "Добавьте или удалите приложение в настройках системы. После возвращения статус обновится.", + "zh-Hant": "請在系統設定中新增或移除本應用,返回後會自動重新整理狀態。", + "ja": "システム設定でこのアプリを追加または削除します。戻るとステータスが更新されます。", + "ko": "시스템 설정에서 이 앱을 추가하거나 제거하세요. 돌아오면 상태가 새로 고쳐집니다.", + "de": "Fügen Sie diese App in den Systemeinstellungen hinzu oder entfernen Sie sie. Der Status wird aktualisiert, wenn Sie zurückkehren.", + "fr": "Ajoutez ou supprimez cette application dans les paramètres système. Le statut s'actualise à votre retour.", + "es": "Agregue o elimine esta aplicación en la Configuración del sistema. El estado se actualiza cuando regresa.", + "pt-BR": "Adicione ou remova este aplicativo nas configurações do sistema. O status é atualizado quando você retorna." + }, + "请在远端启用 CrossDesk 系统服务后重试": { + "zh-Hans": "请在远端启用 CrossDesk 系统服务后重试", + "en": "Please enable the CrossDesk system service on the remote end and try again", + "zh-Hant": "請在遠端啟用 CrossDesk 系統服務後重試", + "ja": "リモート エンドでCrossDeskシステム サービスを有効にして、再試行してください。", + "ko": "원격 측에서CrossDesk시스템 서비스를 활성화하고 다시 시도하십시오.", + "de": "Bitte aktivieren Sie den CrossDesk-Systemdienst auf der Gegenseite und versuchen Sie es erneut", + "fr": "Veuillez activer le service système CrossDesk sur l'extrémité distante et réessayer.", + "es": "Habilite el servicio del sistema CrossDesk en el extremo remoto y vuelva a intentarlo.", + "pt-BR": "Ative o serviço do sistema CrossDesk na extremidade remota e tente novamente", + "ru": "Пожалуйста, включите системную службу CrossDesk на удаленном конце и повторите попытку." + }, + "请更换端口。": { + "zh-Hans": "请更换端口。", + "en": "Choose another port.", + "ru": "Выберите другой порт.", + "zh-Hant": "請更換埠。", + "ja": "別のポートを選択します。", + "ko": "다른 포트를 선택하세요.", + "de": "Wählen Sie einen anderen Port.", + "fr": "Choisissez un autre port.", + "es": "Elija otro puerto.", + "pt-BR": "Escolha outra porta." + }, + "请求超时,尚未确认电脑的隐私屏状态": { + "zh-Hans": "请求超时,尚未确认电脑的隐私屏状态", + "en": "The request timed out and the computer's privacy screen status has not been confirmed.", + "zh-Hant": "請求超時,尚未確認電腦的隱私屏狀態", + "ja": "リクエストがタイムアウトし、コンピュータのプライバシー画面の状態が確認できませんでした。", + "ko": "요청 시간이 초과되어 컴퓨터의 개인 정보 보호 화면 상태가 확인되지 않았습니다.", + "de": "Die Anfrage ist abgelaufen und der Datenschutzstatus des Computers wurde nicht bestätigt.", + "fr": "Le délai de demande a expiré et l'état de l'écran de confidentialité de l'ordinateur n'a pas été confirmé.", + "es": "Se agotó el tiempo de espera de la solicitud y no se ha confirmado el estado de la pantalla de privacidad de la computadora.", + "pt-BR": "A solicitação expirou e o status da tela de privacidade do computador não foi confirmado.", + "ru": "Время ожидания запроса истекло, а состояние экрана конфиденциальности компьютера не подтверждено." + }, + "请点击主界面密码旁的修改按钮设置密码。": { + "zh-Hans": "请点击主界面密码旁的修改按钮设置密码。", + "en": "Set a password using Edit next to the password on the main screen.", + "ru": "Задайте пароль кнопкой редактирования рядом с паролем в главном окне.", + "zh-Hant": "請點選主介面密碼旁的修改按鈕設定密碼。", + "ja": "メイン画面のパスワード横の「編集」でパスワードを設定します。", + "ko": "메인 화면의 비밀번호 옆에 있는 편집을 이용하여 비밀번호를 설정하세요.", + "de": "Legen Sie mit „Bearbeiten“ neben dem Passwort auf dem Hauptbildschirm ein Passwort fest.", + "fr": "Définissez un mot de passe en utilisant Modifier à côté du mot de passe sur l'écran principal.", + "es": "Establezca una contraseña usando Editar junto a la contraseña en la pantalla principal.", + "pt-BR": "Defina uma senha usando Editar ao lado da senha na tela principal." + }, + "请等待当前文件发送完成": { + "zh-Hans": "请等待当前文件发送完成", + "en": "Please wait for the current file to be sent.", + "zh-Hant": "請等待當前檔案傳送完成", + "ja": "現在のファイルが送信されるまでお待ちください。", + "ko": "현재 파일이 전송될 때까지 기다려 주십시오.", + "de": "Bitte warten Sie, bis die aktuelle Datei gesendet wird.", + "fr": "Veuillez attendre que le fichier actuel soit envoyé.", + "es": "Espere a que se envíe el archivo actual.", + "pt-BR": "Aguarde o envio do arquivo atual.", + "ru": "Пожалуйста, дождитесь отправки текущего файла." + }, + "请输入 1–6 位英文字母或数字密码": { + "zh-Hans": "请输入 1–6 位英文字母或数字密码", + "en": "Use 1–6 letters (A–Z, a–z) or digits (0–9)", + "ru": "Пароль: 1–6 латинских букв или цифр", + "zh-Hant": "請輸入 1–6 位英文字母或數字密碼", + "ja": "1 ~ 6 個の文字 (A ~ Z、a ~ z) または数字 (0 ~ 9) を使用します。", + "ko": "1~6자의 문자(A~Z, a~z) 또는 숫자(0~9)를 사용하세요.", + "de": "Verwenden Sie 1–6 Buchstaben (A–Z, a–z) oder Ziffern (0–9)", + "fr": "Utilisez 1 à 6 lettres (A à Z, a à z) ou chiffres (0 à 9)", + "es": "Utilice de 1 a 6 letras (A–Z, a–z) o dígitos (0–9)", + "pt-BR": "Use 1–6 letras (A–Z, a–z) ou dígitos (0–9)" + }, + "请输入 1–65535 之间的整数端口。": { + "zh-Hans": "请输入 1–65535 之间的整数端口。", + "en": "Enter a port number from 1 to 65535.", + "ru": "Введите целый номер порта от 1 до 65535.", + "zh-Hant": "請輸入 1–65535 之間的整數埠。", + "ja": "ポート番号を1~65535まで入力します。", + "ko": "1~65535 사이의 포트 번호를 입력하세요.", + "de": "Geben Sie eine Portnummer von 1 bis 65535 ein.", + "fr": "Entrez un numéro de port compris entre 1 et 65535.", + "es": "Ingrese un número de puerto del 1 al 65535.", + "pt-BR": "Insira um número de porta de 1 a 65535." + }, + "请输入 1–65535 范围内的信令端口。": { + "zh-Hans": "请输入 1–65535 范围内的信令端口。", + "en": "Enter a signaling port between 1 and 65535.", + "ru": "Введите порт сигнального сервиса от 1 до 65535.", + "zh-Hant": "請輸入 1–65535 範圍內的信令埠。", + "ja": "1 ~ 65535 のシグナリング ポートを入力します。", + "ko": "1~65535 사이의 신호 포트를 입력하세요.", + "de": "Geben Sie einen Signalisierungsport zwischen 1 und 65535 ein.", + "fr": "Entrez un port de signalisation compris entre 1 et 65535.", + "es": "Ingrese un puerto de señalización entre 1 y 65535.", + "pt-BR": "Insira uma porta de sinalização entre 1 e 65535." + }, + "请输入 1–65535 范围内的端口": { + "zh-Hans": "请输入 1–65535 范围内的端口", + "en": "Please enter a port in the range 1–65535", + "zh-Hant": "請輸入 1–65535 範圍內的埠", + "ja": "1 ~ 65535 の範囲でポートを入力してください", + "ko": "1~65535 범위의 포트를 입력하세요.", + "de": "Bitte geben Sie einen Port im Bereich 1–65535 ein", + "fr": "Veuillez saisir un port compris entre 1 et 65535.", + "es": "Ingrese un puerto en el rango 1–65535", + "pt-BR": "Insira uma porta no intervalo 1–65535", + "ru": "Введите порт в диапазоне 1–65535." + }, + "请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。": { + "zh-Hans": "请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。", + "en": "Please enter a port in the range 1–65535, or turn off \"Use custom server\".", + "zh-Hant": "請輸入 1–65535 範圍內的埠,或關閉“使用自定義伺服器”。", + "ja": "1 ~ 65535 の範囲でポートを入力するか、「カスタム サーバーを使用する」をオフにしてください。", + "ko": "1~65535 범위의 포트를 입력하거나 \"사용자 정의 서버 사용\"을 꺼주세요.", + "de": "Bitte geben Sie einen Port im Bereich 1–65535 ein oder deaktivieren Sie „Benutzerdefinierten Server verwenden“.", + "fr": "Veuillez saisir un port compris entre 1 et 65 535 ou désactivez « Utiliser un serveur personnalisé ».", + "es": "Ingrese un puerto en el rango 1–65535 o desactive \"Usar servidor personalizado\".", + "pt-BR": "Insira uma porta no intervalo de 1 a 65535 ou desative \"Usar servidor personalizado\".", + "ru": "Введите порт в диапазоне 1–65535 или отключите параметр «Использовать собственный сервер»." + }, + "请输入 9 位设备 ID": { + "zh-Hans": "请输入 9 位设备 ID", + "en": "Enter a 9-digit device ID", + "ru": "Введите ID из 9 цифр", + "zh-Hant": "請輸入 9 位裝置 ID", + "ja": "9桁のデバイスIDを入力", + "ko": "기기 ID 9자리를 입력하세요.", + "de": "Geben Sie eine 9-stellige Geräte-ID ein", + "fr": "Saisissez un identifiant d'appareil à 9 chiffres", + "es": "Ingrese una ID de dispositivo de 9 dígitos", + "pt-BR": "Insira um ID de dispositivo de 9 dígitos" + }, + "请输入六位密码:": { + "zh-Hans": "请输入六位密码:", + "en": "Enter a six-character password:", + "ru": "Введите пароль из 6 символов:", + "zh-Hant": "請輸入六位密碼:", + "ja": "6 文字のパスワードを入力します。", + "ko": "6자리 비밀번호를 입력하세요.", + "de": "Geben Sie ein sechsstelliges Passwort ein:", + "fr": "Saisissez un mot de passe à six caractères :", + "es": "Ingrese una contraseña de seis caracteres:", + "pt-BR": "Digite uma senha de seis caracteres:" + }, + "请输入密码:": { + "zh-Hans": "请输入密码:", + "en": "Please input password:", + "ru": "Введите пароль:", + "zh-Hant": "請輸入密碼:", + "ja": "パスワードを入力してください:", + "ko": "비밀번호를 입력해주세요:", + "de": "Bitte geben Sie das Passwort ein:", + "fr": "Veuillez saisir le mot de passe :", + "es": "Por favor ingrese la contraseña:", + "pt-BR": "Insira a senha:" + }, + "请输入有效的 9 位设备 ID": { + "zh-Hans": "请输入有效的 9 位设备 ID", + "en": "Enter a valid 9-digit device ID", + "ru": "Введите корректный 9-значный ID устройства", + "zh-Hant": "請輸入有效的 9 位裝置 ID", + "ja": "有効な9桁のデバイスIDを入力してください", + "ko": "유효한 9자리 장치 ID를 입력하세요.", + "de": "Geben Sie eine gültige 9-stellige Geräte-ID ein", + "fr": "Entrez un identifiant d'appareil valide à 9 chiffres", + "es": "Ingrese una ID de dispositivo válida de 9 dígitos", + "pt-BR": "Insira um ID de dispositivo válido de 9 dígitos" + }, + "请输入有效的 IPv4 或 IPv4:端口": { + "zh-Hans": "请输入有效的 IPv4 或 IPv4:端口", + "en": "Enter a valid IPv4 or IPv4:port", + "ru": "Укажите IPv4 или IPv4:порт", + "zh-Hant": "請輸入有效的 IPv4 或 IPv4:埠", + "ja": "有効な IPv4 または IPv4:port を入力してください", + "ko": "유효한 IPv4 또는 IPv4:포트를 입력하세요.", + "de": "Geben Sie einen gültigen IPv4- oder IPv4:Port ein", + "fr": "Entrez un port IPv4 ou IPv4 valide", + "es": "Ingrese un IPv4 válido o IPv4:puerto", + "pt-BR": "Insira um IPv4 ou IPv4:porta válido" + }, + "请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。": { + "zh-Hans": "请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。", + "en": "Enter a valid IPv4 address such as 192.168.1.20, or IPv4:port (1–65535).", + "ru": "Введите IPv4, например 192.168.1.20, или IPv4:порт (1–65535).", + "zh-Hant": "請輸入有效的 IPv4,例如 192.168.1.20;指定埠可用 IPv4:埠,埠範圍 1–65535。", + "ja": "192.168.1.20 または IPv4:port (1 ~ 65535) などの有効な IPv4 アドレスを入力します。", + "ko": "192.168.1.20 또는 IPv4:포트(1~65535)와 같은 유효한 IPv4 주소를 입력하세요.", + "de": "Geben Sie eine gültige IPv4-Adresse ein, z. B. 192.168.1.20 oder IPv4:Port (1–65535).", + "fr": "Saisissez une adresse IPv4 valide telle que 192.168.1.20 ou IPv4:port (1–65535).", + "es": "Ingrese una dirección IPv4 válida como 192.168.1.20 o IPv4:puerto (1–65535).", + "pt-BR": "Insira um endereço IPv4 válido, como 192.168.1.20 ou IPv4:porta (1–65535)." + }, + "请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。": { + "zh-Hans": "请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。", + "en": "Enter a valid host, IP, or HTTPS/WSS signaling URL. Paths are supported.", + "ru": "Введите имя хоста, IP или HTTPS/WSS-адрес сигнального сервиса. Путь допустим.", + "zh-Hant": "請輸入有效的主機名、IP 或 HTTPS/WSS 信令地址,可包含路徑。", + "ja": "有効なホスト、IP、または HTTPS/WSS シグナリング URL を入力します。パスがサポートされています。", + "ko": "유효한 호스트, IP 또는 HTTPS/WSS 신호 URL을 입력하세요. 경로가 지원됩니다.", + "de": "Geben Sie eine gültige Host-, IP- oder HTTPS/WSS-Signalisierungs-URL ein. Pfade werden unterstützt.", + "fr": "Entrez une URL de signalisation d'hôte, d'adresse IP ou HTTPS/WSS valide. Les chemins sont pris en charge.", + "es": "Ingrese un host válido, IP o URL de señalización HTTPS/WSS. Se admiten caminos.", + "pt-BR": "Insira um URL de sinalização de host, IP ou HTTPS/WSS válido. Caminhos são suportados." + }, + "请输入有效的服务器地址和端口": { + "zh-Hans": "请输入有效的服务器地址和端口", + "en": "Please enter a valid server address and port", + "zh-Hant": "請輸入有效的伺服器地址和埠", + "ja": "有効なサーバー アドレスとポートを入力してください", + "ko": "유효한 서버 주소와 포트를 입력하세요", + "de": "Bitte geben Sie eine gültige Serveradresse und einen gültigen Port ein", + "fr": "Veuillez saisir une adresse de serveur et un port valides", + "es": "Ingrese una dirección de servidor y un puerto válidos", + "pt-BR": "Insira um endereço de servidor e porta válidos", + "ru": "Введите действительный адрес и порт сервера." + }, + "请输入有效的访问密码": { + "zh-Hans": "请输入有效的访问密码", + "en": "Please enter a valid access password", + "zh-Hant": "請輸入有效的訪問密碼", + "ja": "有効なアクセスパスワードを入力してください", + "ko": "유효한 접속 비밀번호를 입력해주세요", + "de": "Bitte geben Sie ein gültiges Zugangspasswort ein", + "fr": "Veuillez saisir un mot de passe d'accès valide", + "es": "Por favor ingrese una contraseña de acceso válida", + "pt-BR": "Insira uma senha de acesso válida", + "ru": "Пожалуйста, введите действительный пароль доступа." + }, + "请输入有效访问密码": { + "zh-Hans": "请输入有效访问密码", + "en": "Please enter a valid access password", + "zh-Hant": "請輸入有效訪問密碼", + "ja": "有効なアクセスパスワードを入力してください", + "ko": "유효한 접속 비밀번호를 입력해주세요", + "de": "Bitte geben Sie ein gültiges Zugangspasswort ein", + "fr": "Veuillez saisir un mot de passe d'accès valide", + "es": "Por favor ingrese una contraseña de acceso válida", + "pt-BR": "Por favor, insira uma senha de acesso válida", + "ru": "Пожалуйста, введите действительный пароль доступа." + }, + "请输入服务器地址,或关闭“使用自定义服务器”。": { + "zh-Hans": "请输入服务器地址,或关闭“使用自定义服务器”。", + "en": "Please enter the server address, or turn off \"Use a custom server\".", + "zh-Hant": "請輸入伺服器地址,或關閉“使用自定義伺服器”。", + "ja": "サーバーアドレスを入力するか、「カスタムサーバーを使用する」をオフにしてください。", + "ko": "서버 주소를 입력하시거나, \"커스텀 서버 사용\"을 꺼주세요.", + "de": "Bitte geben Sie die Serveradresse ein oder deaktivieren Sie „Benutzerdefinierten Server verwenden“.", + "fr": "Veuillez saisir l'adresse du serveur ou désactiver « Utiliser un serveur personnalisé ».", + "es": "Ingrese la dirección del servidor o desactive \"Usar un servidor personalizado\".", + "pt-BR": "Insira o endereço do servidor ou desative \"Usar um servidor personalizado\".", + "ru": "Введите адрес сервера или отключите параметр «Использовать собственный сервер»." + }, + "请输入远程设备 ID": { + "zh-Hans": "请输入远程设备 ID", + "en": "Please enter the remote device ID", + "zh-Hant": "請輸入遠端裝置 ID", + "ja": "リモートデバイスIDを入力してください", + "ko": "원격장치 ID를 입력해주세요.", + "de": "Bitte geben Sie die Remote-Geräte-ID ein", + "fr": "Veuillez saisir l'ID de l'appareil distant", + "es": "Ingrese el ID del dispositivo remoto", + "pt-BR": "Insira o ID do dispositivo remoto", + "ru": "Введите идентификатор удаленного устройства." + }, + "请输入连接名称:": { + "zh-Hans": "请输入连接名称:", + "en": "Please input connection name:", + "ru": "Введите имя подключения:", + "zh-Hant": "請輸入連線名稱:", + "ja": "接続名を入力してください:", + "ko": "연결 이름을 입력하세요:", + "de": "Bitte geben Sie den Verbindungsnamen ein:", + "fr": "Veuillez saisir le nom de la connexion :", + "es": "Ingrese el nombre de la conexión:", + "pt-BR": "Insira o nome da conexão:" + }, + "请连接 Wi-Fi 或网线,": { + "zh-Hans": "请连接 Wi-Fi 或网线,", + "en": "Connect to Wi-Fi or Ethernet,", + "ru": "Подключитесь к Wi-Fi или Ethernet", + "zh-Hant": "請連線 Wi-Fi 或網線,", + "ja": "Wi-Fiまたはイーサネットに接続し、", + "ko": "Wi-Fi 또는 이더넷에 연결하고,", + "de": "Mit WLAN oder Ethernet verbinden,", + "fr": "Connectez-vous au Wi-Fi ou à Ethernet,", + "es": "Conéctese a Wi-Fi o Ethernet,", + "pt-BR": "Conecte-se a Wi-Fi ou Ethernet," + }, + "请选择其他端口或检查系统权限。": { + "zh-Hans": "请选择其他端口或检查系统权限。", + "en": "Choose another port or check system permissions.", + "ru": "Смените порт или проверьте разрешения.", + "zh-Hant": "請選擇其他埠或檢查系統許可權。", + "ja": "別のポートを選択するか、システム権限を確認してください。", + "ko": "다른 포트를 선택하거나 시스템 권한을 확인하세요.", + "de": "Wählen Sie einen anderen Port oder überprüfen Sie die Systemberechtigungen.", + "fr": "Choisissez un autre port ou vérifiez les autorisations du système.", + "es": "Elija otro puerto o verifique los permisos del sistema.", + "pt-BR": "Escolha outra porta ou verifique as permissões do sistema." + }, + "请选择已存在且可写的绝对目录路径;default 使用默认目录。": { + "zh-Hans": "请选择已存在且可写的绝对目录路径;default 使用默认目录。", + "en": "Use an existing writable absolute directory, or default for the default location.", + "ru": "Укажите существующий доступный для записи абсолютный путь к каталогу или default.", + "zh-Hant": "請選擇已存在且可寫的絕對目錄路徑;default 使用預設目錄。", + "ja": "既存の書き込み可能な絶対ディレクトリを使用するか、デフォルトの場所にはデフォルトを使用します。", + "ko": "기존의 쓰기 가능한 절대 디렉토리를 사용하거나 기본 위치로 기본값을 사용하십시오.", + "de": "Verwenden Sie ein vorhandenes beschreibbares absolutes Verzeichnis oder Standard für den Standardspeicherort.", + "fr": "Utilisez un répertoire absolu accessible en écriture existant, ou par défaut pour l'emplacement par défaut.", + "es": "Utilice un directorio absoluto grabable existente o el predeterminado para la ubicación predeterminada.", + "pt-BR": "Use um diretório absoluto gravável existente ou padrão para o local padrão." + }, + "请重新输入密码": { + "zh-Hans": "请重新输入密码", + "en": "Please input password again", + "ru": "Повторно введите пароль", + "zh-Hant": "請重新輸入密碼", + "ja": "パスワードを再度入力してください", + "ko": "비밀번호를 다시 입력해주세요", + "de": "Bitte geben Sie das Passwort erneut ein", + "fr": "Veuillez saisir à nouveau le mot de passe", + "es": "Ingrese la contraseña nuevamente", + "pt-BR": "Insira a senha novamente" + }, + "请重试或检查本机防火墙。": { + "zh-Hans": "请重试或检查本机防火墙。", + "en": "Retry or check the local firewall.", + "ru": "Повторите попытку или проверьте брандмауэр.", + "zh-Hant": "請重試或檢查本機防火牆。", + "ja": "再試行するか、ローカル ファイアウォールを確認します。", + "ko": "로컬 방화벽을 다시 시도하거나 확인하세요.", + "de": "Versuchen Sie es erneut oder überprüfen Sie die lokale Firewall.", + "fr": "Réessayez ou vérifiez le pare-feu local.", + "es": "Vuelva a intentarlo o verifique el firewall local.", + "pt-BR": "Tente novamente ou verifique o firewall local." + }, + "读取失败": { + "zh-Hans": "读取失败", + "en": "Read failed", + "ru": "Ошибка чтения", + "zh-Hant": "讀取失敗", + "ja": "読み取りに失敗しました", + "ko": "읽기 실패", + "de": "Lesen fehlgeschlagen", + "fr": "Échec de la lecture", + "es": "Error de lectura", + "pt-BR": "Falha na leitura" + }, + "调整失败,请重试。": { + "zh-Hans": "调整失败,请重试。", + "en": "Could not apply settings. Try again.", + "ru": "Не удалось применить настройки. Повторите попытку.", + "zh-Hant": "調整失敗,請重試。", + "ja": "設定を適用できませんでした。もう一度やり直してください。", + "ko": "설정을 적용할 수 없습니다. 다시 시도해 보세요.", + "de": "Einstellungen konnten nicht angewendet werden. Versuchen Sie es erneut.", + "fr": "Impossible d'appliquer les paramètres. Essayer à nouveau.", + "es": "No se pudieron aplicar las configuraciones. Intentar otra vez.", + "pt-BR": "Não foi possível aplicar as configurações. Tente novamente." + }, + "赞助支持": { + "zh-Hans": "赞助支持", + "en": "Sponsorship", + "ru": "Поддержка проекта", + "zh-Hant": "贊助支援", + "ja": "開発を支援", + "ko": "후원", + "de": "Sponsoring", + "fr": "Parrainage", + "es": "Patrocinio", + "pt-BR": "Patrocínio" + }, + "跟随系统": { + "zh-Hans": "跟随系统", + "en": "Follow system", + "ru": "Как в системе", + "zh-Hant": "跟隨系統", + "ja": "システム設定に従う", + "ko": "시스템 설정 따르기", + "de": "Systemsprache", + "fr": "Langue du système", + "es": "Idioma del sistema", + "pt-BR": "Idioma do sistema" + }, + "跟随设备设置": { + "zh-Hans": "跟随设备设置", + "en": "Follow device settings", + "ru": "Настройки устройства", + "zh-Hant": "跟隨裝置設定", + "ja": "デバイスの設定に従ってください", + "ko": "기기 설정을 따르세요.", + "de": "Befolgen Sie die Geräteeinstellungen", + "fr": "Suivre les paramètres de l'appareil", + "es": "Siga la configuración del dispositivo", + "pt-BR": "Siga as configurações do dispositivo" + }, + "跨页 ": { + "zh-Hans": "跨页 ", + "en": "Other pages ", + "ru": "Вне страницы ", + "zh-Hant": "跨頁 ", + "ja": "その他のページ ", + "ko": "기타 페이지 ", + "de": "Andere Seiten ", + "fr": "Autres pages ", + "es": "Otras páginas ", + "pt-BR": "Outras páginas " + }, + "软件许可": { + "zh-Hans": "软件许可", + "en": "Software license", + "ru": "Лицензия программы", + "zh-Hant": "軟體許可", + "ja": "ソフトウェアライセンス", + "ko": "소프트웨어 라이센스", + "de": "Softwarelizenz", + "fr": "Licence du logiciel", + "es": "Licencia de software", + "pt-BR": "Licença de software" + }, + "辅助功能权限": { + "zh-Hans": "辅助功能权限", + "en": "Accessibility Permission", + "ru": "Разрешение специальных возможностей", + "zh-Hant": "輔助功能許可權", + "ja": "アクセシビリティ許可", + "ko": "접근성 권한", + "de": "Zugänglichkeitsgenehmigung", + "fr": "Autorisation d'accessibilité", + "es": "Permiso de accesibilidad", + "pt-BR": "Permissão de acessibilidade" + }, + "输入": { + "zh-Hans": "输入", + "en": "In", + "ru": "Вход", + "zh-Hant": "輸入", + "ja": "で", + "ko": "인", + "de": "In", + "fr": "Dans", + "es": "En", + "pt-BR": "Em" + }, + "输入 IP:端口,通过局域网连接": { + "zh-Hans": "输入 IP:端口,通过局域网连接", + "en": "Enter IP:port to connect over LAN", + "ru": "Введите IP:порт для подключения по LAN", + "zh-Hant": "輸入 IP:埠,透過區域網連線", + "ja": "LAN経由で接続するIP:ポートを入力します。", + "ko": "LAN을 통해 연결하려면 IP:포트를 입력하세요.", + "de": "Geben Sie IP:Port ein, um eine Verbindung über LAN herzustellen", + "fr": "Entrez IP:port pour vous connecter via LAN", + "es": "Ingrese IP: puerto para conectarse a través de LAN", + "pt-BR": "Digite IP:porta para conectar pela LAN" + }, + "输入新值(cancel 取消)": { + "zh-Hans": "输入新值(cancel 取消)", + "en": "Enter a new value (cancel to abort)", + "ru": "Введите новое значение (cancel — отмена)", + "zh-Hant": "輸入新值(cancel 取消)", + "ja": "新しい値を入力します(中止するにはキャンセル)", + "ko": "새 값을 입력하세요(중단하려면 취소하세요).", + "de": "Geben Sie einen neuen Wert ein (Abbrechen zum Abbrechen)", + "fr": "Entrez une nouvelle valeur (annuler pour abandonner)", + "es": "Ingrese un nuevo valor (cancelar para cancelar)", + "pt-BR": "Insira um novo valor (cancelar para abortar)" + }, + "输入新密码(6位英文字母或数字;输入 cancel 取消):": { + "zh-Hans": "输入新密码(6位英文字母或数字;输入 cancel 取消):", + "en": "New password (6 ASCII letters or digits; cancel to abort):", + "ru": "Новый пароль (6 латинских букв или цифр; cancel — отмена):", + "zh-Hant": "輸入新密碼(6位英文字母或數字;輸入 cancel 取消):", + "ja": "新しいパスワード (6 つの ASCII 文字または数字、中止するにはキャンセル):", + "ko": "새 비밀번호(ASCII 문자 또는 숫자 6개, 중단하려면 취소):", + "de": "Neues Passwort (6 ASCII-Buchstaben oder Ziffern; Abbrechen zum Abbrechen):", + "fr": "Nouveau mot de passe (6 lettres ou chiffres ASCII ; annuler pour abandonner) :", + "es": "Nueva contraseña (6 letras o dígitos ASCII; cancelar para cancelar):", + "pt-BR": "Nova senha (6 letras ou dígitos ASCII; cancelar para abortar):" + }, + "输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。": { + "zh-Hans": "输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。", + "en": "Enter an item number or key; back to return. Shortcut: settings set KEY VALUE.", + "ru": "Введите номер или имя параметра; back — назад. Команда: settings set KEY VALUE.", + "zh-Hant": "輸入編號或選項名稱修改;back 返回。也可使用 settings set 名稱 值。", + "ja": "項目番号またはキーを入力します。戻って戻る。ショートカット: 設定はキー値を設定します。", + "ko": "품목 번호나 키를 입력하세요. 다시 돌아가기 위해. 바로가기: 설정은 KEY VALUE를 설정합니다.", + "de": "Geben Sie eine Artikelnummer oder einen Schlüssel ein. zurück, um zurückzukehren. Verknüpfung: Einstellungen legen SCHLÜSSELWERT fest.", + "fr": "Entrez un numéro d'article ou une clé ; retour pour revenir. Raccourci : les paramètres définissent la VALEUR CLÉ.", + "es": "Ingrese un número de artículo o clave; volver para volver. Acceso directo: configuración establece VALOR CLAVE.", + "pt-BR": "Insira um número de item ou chave; voltar para voltar. Atalho: configurações definidas KEY VALUE." + }, + "输入设备 ID,连接远程桌面": { + "zh-Hans": "输入设备 ID,连接远程桌面", + "en": "Enter a device ID to start a remote session", + "ru": "Введите ID для удалённого подключения", + "zh-Hant": "輸入裝置 ID,連線遠端桌面", + "ja": "デバイスIDを入力してリモートセッションを開始します", + "ko": "원격 세션을 시작하려면 장치 ID를 입력하세요.", + "de": "Geben Sie eine Geräte-ID ein, um eine Remote-Sitzung zu starten", + "fr": "Entrez un identifiant d'appareil pour démarrer une session à distance", + "es": "Ingrese una ID de dispositivo para iniciar una sesión remota", + "pt-BR": "Insira um ID de dispositivo para iniciar uma sessão remota" + }, + "输出": { + "zh-Hans": "输出", + "en": "Out", + "ru": "Выход", + "zh-Hant": "輸出", + "ja": "アウト", + "ko": "아웃", + "de": "Raus", + "fr": "Sortie", + "es": "Fuera", + "pt-BR": "Fora" + }, + "近期连接": { + "zh-Hans": "近期连接", + "en": "Recent Connections", + "ru": "Недавние подключения", + "zh-Hant": "近期連線", + "ja": "最近の接続", + "ko": "최근 연결", + "de": "Aktuelle Verbindungen", + "fr": "Connexions récentes", + "es": "Conexiones recientes", + "pt-BR": "Conexões recentes" + }, + "返回": { + "zh-Hans": "返回", + "en": "Back", + "ru": "Назад", + "zh-Hant": "返回", + "ja": "戻る", + "ko": "뒤로", + "de": "Zurück", + "fr": "Retour", + "es": "Volver", + "pt-BR": "Voltar" + }, + "返回控制栏": { + "zh-Hans": "返回控制栏", + "en": "Return to control bar", + "zh-Hant": "返回控制欄", + "ja": "コントロールバーに戻る", + "ko": "컨트롤 바로 돌아가기", + "de": "Zurück zur Steuerleiste", + "fr": "Retour à la barre de contrôle", + "es": "Volver a la barra de control", + "pt-BR": "Retornar à barra de controle", + "ru": "Возврат к панели управления." + }, + "还原窗口": { + "zh-Hans": "还原窗口", + "en": "Restore window", + "ru": "Восстановить окно", + "zh-Hant": "還原視窗", + "ja": "復元ウィンドウ", + "ko": "복원 창", + "de": "Fenster „Wiederherstellen“.", + "fr": "Fenêtre de restauration", + "es": "Restaurar ventana", + "pt-BR": "Janela de restauração" + }, + "还没有连接记录": { + "zh-Hans": "还没有连接记录", + "en": "No connection record yet", + "zh-Hant": "還沒有連線記錄", + "ja": "まだ接続実績がありません", + "ko": "아직 접속기록이 없습니다", + "de": "Noch kein Verbindungsdatensatz", + "fr": "Aucun enregistrement de connexion pour l'instant", + "es": "Aún no hay registro de conexión", + "pt-BR": "Ainda não há registro de conexão", + "ru": "Пока нет записей о подключении" + }, + "这条公告已更新或删除,请返回公告列表查看。": { + "zh-Hans": "这条公告已更新或删除,请返回公告列表查看。", + "en": "This announcement has been updated or deleted, please return to the announcement list to view it.", + "zh-Hant": "這條公告已更新或刪除,請返回公告列表檢視。", + "ja": "このお知らせは更新または削除されました。表示するにはお知らせリストに戻ってください。", + "ko": "본 공지사항은 업데이트 또는 삭제되었습니다. 공지사항 목록으로 돌아가서 확인하시기 바랍니다.", + "de": "Diese Ankündigung wurde aktualisiert oder gelöscht. Bitte kehren Sie zur Ankündigungsliste zurück, um sie anzuzeigen.", + "fr": "Cette annonce a été mise à jour ou supprimée, veuillez revenir à la liste des annonces pour la consulter.", + "es": "Este anuncio ha sido actualizado o eliminado, regrese a la lista de anuncios para verlo.", + "pt-BR": "Este anúncio foi atualizado ou excluído. Volte à lista de anúncios para visualizá-lo.", + "ru": "Это объявление было обновлено или удалено. Чтобы просмотреть его, вернитесь к списку объявлений." + }, + "远程任务已关闭": { + "zh-Hans": "远程任务已关闭", + "en": "Remote task is closed", + "zh-Hant": "遠端任務已關閉", + "ja": "リモートタスクが終了しました", + "ko": "원격 작업이 종료되었습니다.", + "de": "Remote-Aufgabe ist geschlossen", + "fr": "La tâche distante est fermée", + "es": "La tarea remota está cerrada", + "pt-BR": "A tarefa remota está fechada", + "ru": "Удаленная задача закрыта." + }, + "远程控制菜单,拖动可移动": { + "zh-Hans": "远程控制菜单,拖动可移动", + "en": "Remote control menu, drag to move", + "zh-Hant": "遠端控制選單,拖動可移動", + "ja": "リモコンメニュー、ドラッグして移動", + "ko": "리모컨 메뉴, 드래그하여 이동", + "de": "Fernbedienungsmenü, zum Verschieben ziehen", + "fr": "Menu de la télécommande, faites glisser pour déplacer", + "es": "Menú de control remoto, arrastre para mover", + "pt-BR": "Menu de controle remoto, arraste para mover", + "ru": "Меню пульта дистанционного управления, перетаскивайте для перемещения." + }, + "远程桌面": { + "zh-Hans": "远程桌面", + "en": "Remote Desktop", + "ru": "Удаленный рабочий стол", + "zh-Hant": "遠端桌面", + "ja": "リモートデスクトップ", + "ko": "원격 데스크톱", + "de": "Remotedesktop", + "fr": "Bureau à distance", + "es": "Escritorio remoto", + "pt-BR": "Área de Trabalho Remota" + }, + "远程桌面触控区域": { + "zh-Hans": "远程桌面触控区域", + "en": "Remote desktop touch area", + "zh-Hant": "遠端桌面觸控區域", + "ja": "リモートデスクトップタッチエリア", + "ko": "원격 데스크톱 터치 영역", + "de": "Remote-Desktop-Touchbereich", + "fr": "Zone tactile du bureau à distance", + "es": "Área táctil del escritorio remoto", + "pt-BR": "Área de toque da área de trabalho remota", + "ru": "Сенсорная область удаленного рабочего стола" + }, + "远程桌面:轻触点击、长按右键、双指捏合缩放、放大后双指拖动画面,原始比例下双指滚动": { + "zh-Hans": "远程桌面:轻触点击、长按右键、双指捏合缩放、放大后双指拖动画面,原始比例下双指滚动", + "en": "Remote desktop: tap and click, long press the right button, pinch to zoom with two fingers, drag the screen with two fingers after zooming in, scroll with two fingers at the original ratio", + "zh-Hant": "遠端桌面:輕觸點選、長按右鍵、雙指捏合縮放、放大後雙指拖動畫面,原始比例下雙指滾動", + "ja": "リモートデスクトップ:タップ&クリック、右ボタン長押し、2本指でピンチして拡大、拡大後2本指で画面をドラッグ、2本指で元の比率でスクロール", + "ko": "원격 데스크톱: 탭 앤 클릭, 오른쪽 버튼 길게 누르기, 두 손가락으로 핀치하여 확대/축소, 확대 후 두 손가락으로 화면 드래그, 원래 비율로 두 손가락으로 스크롤", + "de": "Remote-Desktop: Tippen und klicken, die rechte Taste lange drücken, zum Zoomen mit zwei Fingern zusammenziehen, nach dem Vergrößern mit zwei Fingern über den Bildschirm ziehen, mit zwei Fingern im Originalverhältnis scrollen", + "fr": "Bureau à distance : appuyez et cliquez, appuyez longuement sur le bouton droit, pincez pour zoomer avec deux doigts, faites glisser l'écran avec deux doigts après avoir zoomé, faites défiler avec deux doigts au rapport d'origine", + "es": "Escritorio remoto: toque y haga clic, mantenga presionado el botón derecho, pellizque para hacer zoom con dos dedos, arrastre la pantalla con dos dedos después de hacer zoom, desplácese con dos dedos en la proporción original", + "pt-BR": "Área de trabalho remota: toque e clique, mantenha pressionado o botão direito, aperte para ampliar com dois dedos, arraste a tela com dois dedos após aumentar o zoom, role com dois dedos na proporção original", + "ru": "Удаленный рабочий стол: коснитесь и щелкните, нажмите и удерживайте правую кнопку, сведите два пальца для увеличения, перетащите экран двумя пальцами после увеличения, прокрутите двумя пальцами в исходном соотношении." + }, + "远程桌面:轻触点击,拖动移动,长按右键,双指捏合缩放,放大后双指拖动画面,原始比例下双指上下滑动滚动": { + "zh-Hans": "远程桌面:轻触点击,拖动移动,长按右键,双指捏合缩放,放大后双指拖动画面,原始比例下双指上下滑动滚动", + "en": "Remote desktop: Touch and click, drag to move, press and hold the right button, pinch to zoom, zoom in and drag the screen with two fingers, slide up and down with two fingers to scroll at the original scale", + "zh-Hant": "遠端桌面:輕觸點選,拖動移動,長按右鍵,雙指捏合縮放,放大後雙指拖動畫面,原始比例下雙指上下滑動滾動", + "ja": "リモート デスクトップ: タッチしてクリック、ドラッグして移動、右ボタンを押したまま、ピンチしてズーム、ズームインして 2 本の指で画面をドラッグ、2 本の指で上下にスライドして元のスケールでスクロール", + "ko": "원격 데스크톱: 터치하고 클릭하고, 드래그하여 이동하고, 오른쪽 버튼을 길게 누르고, 핀치하여 확대/축소하고, 두 손가락으로 화면을 확대하고 드래그하고, 두 손가락으로 위아래로 밀어 원래 크기로 스크롤합니다.", + "de": "Remote-Desktop: Berühren und klicken, zum Verschieben ziehen, die rechte Taste gedrückt halten, zum Zoomen zusammenziehen, hineinzoomen und den Bildschirm mit zwei Fingern ziehen, mit zwei Fingern nach oben und unten streichen, um im Originalmaßstab zu scrollen", + "fr": "Bureau à distance : touchez et cliquez, faites glisser pour déplacer, appuyez et maintenez le bouton droit enfoncé, pincez pour zoomer, zoomez et faites glisser l'écran avec deux doigts, faites glisser de haut en bas avec deux doigts pour faire défiler à l'échelle d'origine.", + "es": "Escritorio remoto: toque y haga clic, arrastre para mover, presione y mantenga presionado el botón derecho, pellizque para hacer zoom, acerque y arrastre la pantalla con dos dedos, deslice hacia arriba y hacia abajo con dos dedos para desplazarse a la escala original", + "pt-BR": "Área de trabalho remota: toque e clique, arraste para mover, pressione e segure o botão direito, aperte para ampliar, amplie e arraste a tela com dois dedos, deslize para cima e para baixo com dois dedos para rolar na escala original", + "ru": "Удаленный рабочий стол: коснитесь и щелкните, перетащите для перемещения, нажмите и удерживайте правую кнопку, сведите пальцы для масштабирования, увеличьте масштаб и перетащите экран двумя пальцами, проведите двумя пальцами вверх и вниз для прокрутки в исходном масштабе." + }, + "远程电脑": { + "zh-Hans": "远程电脑", + "en": "Remote computer", + "zh-Hant": "遠端電腦", + "ja": "リモートコンピュータ", + "ko": "원격 컴퓨터", + "de": "Remote-Computer", + "fr": "Ordinateur distant", + "es": "Computadora remota", + "pt-BR": "Computador remoto", + "ru": "Удаленный компьютер" + }, + "远程窗口已关闭,或后台保活未能启动,会话已结束": { + "zh-Hans": "远程窗口已关闭,或后台保活未能启动,会话已结束", + "en": "The remote window has been closed, or the background keepalive failed to start, and the session has ended.", + "zh-Hant": "遠端視窗已關閉,或後臺保活未能啟動,會話已結束", + "ja": "リモート ウィンドウが閉じられたか、バックグラウンド キープアライブの開始に失敗し、セッションが終了しました。", + "ko": "원격 창이 닫혔거나 백그라운드 Keepalive 시작에 실패하여 세션이 종료되었습니다.", + "de": "Das Remote-Fenster wurde geschlossen oder der Hintergrund-Keepalive konnte nicht gestartet werden und die Sitzung wurde beendet.", + "fr": "La fenêtre distante a été fermée ou le keepalive en arrière-plan n'a pas pu démarrer et la session est terminée.", + "es": "La ventana remota se cerró o el mantenimiento en segundo plano no se pudo iniciar y la sesión finalizó.", + "pt-BR": "A janela remota foi fechada ou a manutenção de atividade em segundo plano falhou ao iniciar e a sessão foi encerrada.", + "ru": "Удаленное окно было закрыто, или не удалось запустить фоновую проверку активности, и сеанс завершился." + }, + "远程设备 ID 不存在,请检查设备 ID。": { + "zh-Hans": "远程设备 ID 不存在,请检查设备 ID。", + "en": "Remote device ID does not exist, please check device ID.", + "zh-Hant": "遠端裝置 ID 不存在,請檢查裝置 ID。", + "ja": "リモートデバイス ID が存在しません。デバイス ID を確認してください。", + "ko": "원격 장치 ID가 존재하지 않습니다. 장치 ID를 확인하십시오.", + "de": "Remote-Geräte-ID existiert nicht, bitte überprüfen Sie die Geräte-ID.", + "fr": "L'ID de l'appareil distant n'existe pas, veuillez vérifier l'ID de l'appareil.", + "es": "La ID del dispositivo remoto no existe; verifique la ID del dispositivo.", + "pt-BR": "O ID do dispositivo remoto não existe, verifique o ID do dispositivo.", + "ru": "Идентификатор удаленного устройства не существует, проверьте идентификатор устройства." + }, + "远程设备当前不可用,请稍后重试。": { + "zh-Hans": "远程设备当前不可用,请稍后重试。", + "en": "The remote device is currently unavailable, please try again later.", + "zh-Hant": "遠端裝置當前不可用,請稍後重試。", + "ja": "リモート デバイスは現在利用できません。後でもう一度試してください。", + "ko": "현재 원격 장치를 사용할 수 없습니다. 나중에 다시 시도하십시오.", + "de": "Das Remote-Gerät ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut.", + "fr": "L'appareil distant est actuellement indisponible, veuillez réessayer plus tard.", + "es": "El dispositivo remoto no está disponible actualmente; inténtelo nuevamente más tarde.", + "pt-BR": "O dispositivo remoto não está disponível no momento. Tente novamente mais tarde.", + "ru": "Удаленное устройство в настоящее время недоступно. Повторите попытку позже." + }, + "远程连接": { + "zh-Hans": "远程连接", + "en": "Remote connection", + "zh-Hant": "遠端連線", + "ja": "リモート接続", + "ko": "원격 접속", + "de": "Remote-Verbindung", + "fr": "Connexion à distance", + "es": "Conexión remota", + "pt-BR": "Conexão remota", + "ru": "Удаленное подключение" + }, + "远程连接已结束。": { + "zh-Hans": "远程连接已结束。", + "en": "Remote connection ended.", + "zh-Hant": "遠端連線已結束。", + "ja": "リモート接続が終了しました。", + "ko": "원격 연결이 종료되었습니다.", + "de": "Remote-Verbindung beendet.", + "fr": "Connexion à distance terminée.", + "es": "La conexión remota finalizó.", + "pt-BR": "A conexão remota foi encerrada.", + "ru": "Удаленное соединение прервано." + }, + "远端 IP / 端口": { + "zh-Hans": "远端 IP / 端口", + "en": "Remote IP / Port", + "ru": "Удалённый IP / Порт", + "zh-Hant": "遠端 IP / 埠", + "ja": "リモートIP/ポート", + "ko": "원격 IP / 포트", + "de": "Remote-IP/Port", + "fr": "IP/port distant", + "es": "IP/puerto remoto", + "pt-BR": "IP/Porta Remota" + }, + "远端 Windows 服务不可用": { + "zh-Hans": "远端 Windows 服务不可用", + "en": "Remote Windows service unavailable", + "ru": "Служба Windows на удаленной стороне недоступна", + "zh-Hant": "遠端 Windows 服務不可用", + "ja": "リモート Windows サービスが利用できない", + "ko": "원격 Windows 서비스를 사용할 수 없습니다.", + "de": "Remote-Windows-Dienst nicht verfügbar", + "fr": "Service Windows distant indisponible", + "es": "Servicio remoto de Windows no disponible", + "pt-BR": "Serviço remoto do Windows indisponível" + }, + "远端处于锁屏封面,可发送 SAS": { + "zh-Hans": "远端处于锁屏封面,可发送 SAS", + "en": "Remote lock screen visible, send SAS", + "ru": "Удалённый экран заблокирован, можно отправить SAS", + "zh-Hant": "遠端處於鎖屏封面,可傳送 SAS", + "ja": "リモート ロック画面が表示され、SAS を送信", + "ko": "원격 잠금 화면 표시, SAS 전송", + "de": "Remote-Sperrbildschirm sichtbar, SAS senden", + "fr": "Écran de verrouillage à distance visible, envoyer SAS", + "es": "Pantalla de bloqueo remoto visible, enviar SAS", + "pt-BR": "Tela de bloqueio remoto visível, envie SAS" + }, + "远端密码框已出现": { + "zh-Hans": "远端密码框已出现", + "en": "Remote password box visible", + "ru": "На удалённом устройстве появилось поле пароля", + "zh-Hant": "遠端密碼框已出現", + "ja": "リモートパスワードボックスが表示されます", + "ko": "원격 비밀번호 상자 표시", + "de": "Remote-Passwortfeld sichtbar", + "fr": "Boîte de mot de passe distante visible", + "es": "Cuadro de contraseña remota visible", + "pt-BR": "Caixa de senha remota visível" + }, + "远端密码错误": { + "zh-Hans": "远端密码错误", + "en": "Incorrect remote password", + "zh-Hant": "遠端密碼錯誤", + "ja": "リモートパスワードが正しくありません", + "ko": "원격 비밀번호가 올바르지 않습니다.", + "de": "Falsches Remote-Passwort", + "fr": "Mot de passe distant incorrect", + "es": "Contraseña remota incorrecta", + "pt-BR": "Senha remota incorreta", + "ru": "Неверный удаленный пароль." + }, + "远端已关闭连接": { + "zh-Hans": "远端已关闭连接", + "en": "The remote end has closed the connection", + "zh-Hant": "遠端已關閉連線", + "ja": "リモートエンドが接続を閉じました", + "ko": "원격 측에서 연결을 종료했습니다.", + "de": "Die Gegenstelle hat die Verbindung geschlossen", + "fr": "L'extrémité distante a fermé la connexion", + "es": "El extremo remoto ha cerrado la conexión", + "pt-BR": "A extremidade remota fechou a conexão", + "ru": "Удаленная сторона закрыла соединение." + }, + "远端已进入安全桌面": { + "zh-Hans": "远端已进入安全桌面", + "en": "Remote secure desktop active", + "ru": "На удалённом устройстве активен защищённый рабочий стол", + "zh-Hant": "遠端已進入安全桌面", + "ja": "リモート セキュア デスクトップがアクティブです", + "ko": "원격 보안 데스크톱 활성화", + "de": "Remote Secure Desktop aktiv", + "fr": "Bureau sécurisé à distance actif", + "es": "Escritorio seguro remoto activo", + "pt-BR": "Área de trabalho remota segura ativa" + }, + "远端当前不可用": { + "zh-Hans": "远端当前不可用", + "en": "The remote end is currently unavailable", + "zh-Hant": "遠端當前不可用", + "ja": "リモートエンドは現在利用できません", + "ko": "현재 원격 끝을 사용할 수 없습니다.", + "de": "Die Gegenstelle ist derzeit nicht verfügbar", + "fr": "L'extrémité distante est actuellement indisponible", + "es": "El extremo remoto no está disponible actualmente", + "pt-BR": "A extremidade remota está indisponível no momento", + "ru": "Удаленный конец в настоящее время недоступен." + }, + "远端访问密码已失效,请重新连接": { + "zh-Hans": "远端访问密码已失效,请重新连接", + "en": "The remote access password has expired, please reconnect.", + "zh-Hant": "遠端訪問密碼已失效,請重新連線", + "ja": "リモートアクセスパスワードの有効期限が切れています。再接続してください。", + "ko": "원격 접속 비밀번호가 만료되었습니다. 다시 접속해 주세요.", + "de": "Das Passwort für den Fernzugriff ist abgelaufen. Bitte verbinden Sie sich erneut.", + "fr": "Le mot de passe d'accès à distance a expiré, veuillez vous reconnecter.", + "es": "La contraseña de acceso remoto ha caducado, vuelva a conectarse.", + "pt-BR": "A senha de acesso remoto expirou, reconecte.", + "ru": "Срок действия пароля удаленного доступа истек, подключитесь повторно." + }, + "连接": { + "zh-Hans": "连接", + "en": "Connect", + "ru": "Подключиться", + "zh-Hant": "連線", + "ja": "接続", + "ko": "연결", + "de": "Verbinden", + "fr": "Connecter", + "es": "Conectar", + "pt-BR": "Conectar" + }, + "连接 ": { + "zh-Hans": "连接 ", + "en": "Connection ", + "zh-Hant": "連線 ", + "ja": "接続 ", + "ko": "연결 ", + "de": "Verbindung ", + "fr": "Connexion ", + "es": "Conexión ", + "pt-BR": "Conexão ", + "ru": "Подключение " + }, + "连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。": { + "zh-Hans": "连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。", + "en": "Invalid connection negotiation data. Try again and check that both CrossDesk versions are compatible.", + "ru": "Неверные данные согласования соединения. Повторите попытку и проверьте совместимость версий CrossDesk.", + "zh-Hant": "連線協商資料無效,請重試並確認雙方 CrossDesk 版本相容。", + "ja": "接続ネゴシエーション データが無効です。もう一度試して、両方のCrossDeskバージョンに互換性があることを確認してください。", + "ko": "연결 협상 데이터가 잘못되었습니다. 다시 시도하여 두CrossDesk버전이 모두 호환되는지 확인하세요.", + "de": "Ungültige Verbindungsaushandlungsdaten. Versuchen Sie es erneut und prüfen Sie, ob beide CrossDesk-Versionen kompatibel sind.", + "fr": "Données de négociation de connexion invalides. Réessayez et vérifiez que les deux versions de CrossDesk sont compatibles.", + "es": "Datos de negociación de conexión no válidos. Inténtalo de nuevo y comprueba que ambas versiones de CrossDesk sean compatibles.", + "pt-BR": "Dados de negociação de conexão inválidos. Tente novamente e verifique se ambas as versões do CrossDesk são compatíveis." + }, + "连接地址或监听端口已更改,请确认最新地址后重试。": { + "zh-Hans": "连接地址或监听端口已更改,请确认最新地址后重试。", + "en": "The connection address or listening port has changed. Check the current address and try again.", + "ru": "Адрес подключения или порт прослушивания изменился. Проверьте текущий адрес и повторите попытку.", + "zh-Hant": "連線地址或監聽埠已更改,請確認最新地址後重試。", + "ja": "接続アドレスまたはリスニングポートが変更されました。現在のアドレスを確認して、再試行してください。", + "ko": "연결 주소 또는 수신 포트가 변경되었습니다. 현재 주소를 확인하고 다시 시도하세요.", + "de": "Die Verbindungsadresse oder der Überwachungsport hat sich geändert. Überprüfen Sie die aktuelle Adresse und versuchen Sie es erneut.", + "fr": "L'adresse de connexion ou le port d'écoute a changé. Vérifiez l'adresse actuelle et réessayez.", + "es": "La dirección de conexión o el puerto de escucha ha cambiado. Verifique la dirección actual e inténtelo nuevamente.", + "pt-BR": "O endereço de conexão ou porta de escuta foi alterado. Verifique o endereço atual e tente novamente." + }, + "连接失败": { + "zh-Hans": "连接失败", + "en": "Connection failed", + "zh-Hant": "連線失敗", + "ja": "接続に失敗しました", + "ko": "연결 실패", + "de": "Verbindung fehlgeschlagen", + "fr": "Échec de la connexion", + "es": "Error de conexión", + "pt-BR": "Falha na conexão", + "ru": "Соединение не удалось" + }, + "连接失败 · 点击重试": { + "zh-Hans": "连接失败 · 点击重试", + "en": "Connection failed · Click to try again", + "zh-Hant": "連線失敗 · 點選重試", + "ja": "接続に失敗しました · クリックして再試行してください", + "ko": "연결 실패 · 다시 시도하려면 클릭하세요.", + "de": "Verbindung fehlgeschlagen · Klicken Sie, um es erneut zu versuchen", + "fr": "Échec de la connexion · Cliquez pour réessayer", + "es": "Error de conexión · Haga clic para intentarlo de nuevo", + "pt-BR": "Falha na conexão · Clique para tentar novamente", + "ru": "Не удалось подключиться · Нажмите, чтобы повторить попытку." + }, + "连接密码": { + "zh-Hans": "连接密码", + "en": "Connection password", + "ru": "Пароль подключения", + "zh-Hant": "連線密碼", + "ja": "接続パスワード", + "ko": "연결 비밀번호", + "de": "Verbindungspasswort", + "fr": "Mot de passe de connexion", + "es": "Contraseña de conexión", + "pt-BR": "Senha de conexão" + }, + "连接已断开": { + "zh-Hans": "连接已断开", + "en": "Connection lost", + "zh-Hant": "連線已斷開", + "ja": "接続が失われました", + "ko": "연결 끊김", + "de": "Verbindung verloren", + "fr": "Connexion perdue", + "es": "Conexión perdida", + "pt-BR": "Conexão perdida", + "ru": "Соединение потеряно" + }, + "连接已结束": { + "zh-Hans": "连接已结束", + "en": "Connection ended", + "zh-Hant": "連線已結束", + "ja": "接続が終了しました", + "ko": "연결이 종료되었습니다", + "de": "Verbindung beendet", + "fr": "Connexion terminée", + "es": "Conexión finalizada", + "pt-BR": "Conexão encerrada", + "ru": "Соединение завершено" + }, + "连接延时": { + "zh-Hans": "连接延时", + "en": "Connection latency", + "ru": "Задержка соединения", + "zh-Hant": "連線延時", + "ja": "接続遅延", + "ko": "연결 지연", + "de": "Verbindungslatenz", + "fr": "Latence de connexion", + "es": "Latencia de conexión", + "pt-BR": "Latência de conexão" + }, + "连接延时(RTT)": { + "zh-Hans": "连接延时(RTT)", + "en": "Connection delay (RTT)", + "zh-Hant": "連線延時(RTT)", + "ja": "接続遅延 (RTT)", + "ko": "연결 지연(RTT)", + "de": "Verbindungsverzögerung (RTT)", + "fr": "Délai de connexion (RTT)", + "es": "Retardo de conexión (RTT)", + "pt-BR": "Atraso de conexão (RTT)", + "ru": "Задержка соединения (RTT)" + }, + "连接建立后可调整,需被控端支持。": { + "zh-Hans": "连接建立后可调整,需被控端支持。", + "en": "Available when connected to a supported remote device.", + "ru": "Доступно при подключении к поддерживаемому устройству.", + "zh-Hant": "連線建立後可調整,需被控端支援。", + "ja": "サポートされているリモート デバイスに接続されている場合に使用できます。", + "ko": "지원되는 원격 장치에 연결된 경우 사용할 수 있습니다.", + "de": "Verfügbar bei Verbindung mit einem unterstützten Remote-Gerät.", + "fr": "Disponible lors de la connexion à un appareil distant pris en charge.", + "es": "Disponible cuando se conecta a un dispositivo remoto compatible.", + "pt-BR": "Disponível quando conectado a um dispositivo remoto compatível." + }, + "连接建立后锁定横屏": { + "zh-Hans": "连接建立后锁定横屏", + "en": "Lock landscape screen after connection is established", + "zh-Hant": "連線建立後鎖定橫屏", + "ja": "接続完了後、横画面をロックする", + "ko": "연결 완료 후 가로 화면 잠금", + "de": "Querformatbildschirm sperren, nachdem die Verbindung hergestellt wurde", + "fr": "Verrouiller l'écran paysage une fois la connexion établie", + "es": "Bloquear la pantalla horizontal después de establecer la conexión", + "pt-BR": "Bloqueie a tela paisagem após a conexão ser estabelecida", + "ru": "Блокировка горизонтального экрана после установления соединения." + }, + "连接提示": { + "zh-Hans": "连接提示", + "en": "Connection prompt", + "zh-Hant": "連線提示", + "ja": "接続プロンプト", + "ko": "연결 프롬프트", + "de": "Verbindungsaufforderung", + "fr": "Invite de connexion", + "es": "Aviso de conexión", + "pt-BR": "Solicitação de conexão", + "ru": "Запрос на подключение" + }, + "连接断开后锁屏": { + "zh-Hans": "连接断开后锁屏", + "en": "Lock screen on disconnect", + "ru": "Блокировка при отключении", + "zh-Hant": "連線斷開後鎖屏", + "ja": "切断時のロック画面", + "ko": "연결 해제 시 잠금 화면", + "de": "Bildschirm beim Trennen sperren", + "fr": "Écran de verrouillage à la déconnexion", + "es": "Pantalla de bloqueo al desconectar", + "pt-BR": "Bloquear tela ao desconectar" + }, + "连接方式": { + "zh-Hans": "连接方式", + "en": "Connection method", + "zh-Hant": "連線方式", + "ja": "接続方法", + "ko": "연결 방법", + "de": "Verbindungsmethode", + "fr": "Méthode de connexion", + "es": "Método de conexión", + "pt-BR": "Método de conexão", + "ru": "Способ подключения" + }, + "连接时自动开启隐私屏": { + "zh-Hans": "连接时自动开启隐私屏", + "en": "Privacy screen on connection", + "ru": "Приватный экран при подключении", + "zh-Hant": "連線時自動開啟隱私屏", + "ja": "接続時のプライバシー画面", + "ko": "연결 시 개인정보 보호 화면", + "de": "Datenschutzbildschirm bei Verbindung", + "fr": "Écran de confidentialité lors de la connexion", + "es": "Pantalla de privacidad al conectarse", + "pt-BR": "Tela de privacidade na conexão" + }, + "连接服务器": { + "zh-Hans": "连接服务器", + "en": "Connect to server", + "zh-Hant": "連線伺服器", + "ja": "サーバーに接続する", + "ko": "서버에 접속", + "de": "Mit dem Server verbinden", + "fr": "Connectez-vous au serveur", + "es": "Conectarse al servidor", + "pt-BR": "Conecte-se ao servidor", + "ru": "Подключиться к серверу" + }, + "连接服务器后可获取最新公告。": { + "zh-Hans": "连接服务器后可获取最新公告。", + "en": "Connect to the server to get the latest announcements.", + "zh-Hant": "連線伺服器後可獲取最新公告。", + "ja": "サーバーに接続して最新のお知らせを取得します。", + "ko": "서버에 접속하여 최신 공지사항을 받아보세요.", + "de": "Stellen Sie eine Verbindung zum Server her, um die neuesten Ankündigungen zu erhalten.", + "fr": "Connectez-vous au serveur pour recevoir les dernières annonces.", + "es": "Conéctese al servidor para obtener los últimos anuncios.", + "pt-BR": "Conecte-se ao servidor para obter os anúncios mais recentes.", + "ru": "Подключитесь к серверу, чтобы получать последние объявления." + }, + "连接模式": { + "zh-Hans": "连接模式", + "en": "Connection mode", + "ru": "Режим подключения", + "zh-Hant": "連線模式", + "ja": "接続モード", + "ko": "연결 모드", + "de": "Verbindungsmodus", + "fr": "Mode de connexion", + "es": "Modo de conexión", + "pt-BR": "Modo de conexão" + }, + "连接状态:": { + "zh-Hans": "连接状态:", + "en": "Connection Status:", + "ru": "Состояние соединения:", + "zh-Hant": "連線狀態:", + "ja": "接続ステータス:", + "ko": "연결 상태:", + "de": "Verbindungsstatus:", + "fr": "État de la connexion :", + "es": "Estado de conexión:", + "pt-BR": "Status da conexão:" + }, + "连接超时,请检查设备 ID、服务器及远端在线状态": { + "zh-Hans": "连接超时,请检查设备 ID、服务器及远端在线状态", + "en": "Connection timed out, please check the device ID, server and remote online status", + "zh-Hant": "連線超時,請檢查裝置 ID、伺服器及遠端線上狀態", + "ja": "接続がタイムアウトしました。デバイス ID、サーバー、リモートのオンライン ステータスを確認してください。", + "ko": "연결 시간이 초과되었습니다. 장치 ID, 서버 및 원격 온라인 상태를 확인하십시오.", + "de": "Zeitüberschreitung bei der Verbindung. Bitte überprüfen Sie die Geräte-ID, den Server und den Remote-Online-Status", + "fr": "La connexion a expiré. Veuillez vérifier l'ID de l'appareil, le serveur et l'état en ligne à distance.", + "es": "Se agotó el tiempo de conexión; verifique el ID del dispositivo, el servidor y el estado en línea remoto", + "pt-BR": "A conexão expirou, verifique o ID do dispositivo, o servidor e o status on-line remoto", + "ru": "Тайм-аут соединения истек, проверьте идентификатор устройства, сервер и удаленный онлайн-статус." + }, + "连接过的设备会显示在这里,方便下次快速访问。": { + "zh-Hans": "连接过的设备会显示在这里,方便下次快速访问。", + "en": "Devices you connect to will appear here for quick access.", + "ru": "Устройства появятся здесь после первого подключения.", + "zh-Hant": "連線過的裝置會顯示在這裡,方便下次快速訪問。", + "ja": "接続しているデバイスがここに表示され、簡単にアクセスできます。", + "ko": "빠른 액세스를 위해 연결한 장치가 여기에 표시됩니다.", + "de": "Geräte, mit denen Sie eine Verbindung herstellen, werden hier angezeigt, damit Sie schnell darauf zugreifen können.", + "fr": "Les appareils auxquels vous vous connectez apparaîtront ici pour un accès rapide.", + "es": "Los dispositivos a los que te conectes aparecerán aquí para un acceso rápido.", + "pt-BR": "Os dispositivos aos quais você se conecta aparecerão aqui para acesso rápido." + }, + "连接远程桌面": { + "zh-Hans": "连接远程桌面", + "en": "Connect to remote desktop", + "zh-Hant": "連線遠端桌面", + "ja": "リモートデスクトップに接続する", + "ko": "원격 데스크톱에 연결", + "de": "Mit Remote-Desktop verbinden", + "fr": "Connectez-vous au bureau à distance", + "es": "Conectarse al escritorio remoto", + "pt-BR": "Conecte-se à área de trabalho remota", + "ru": "Подключение к удаленному рабочему столу" + }, + "退出": { + "zh-Hans": "退出", + "en": "Exit", + "ru": "Выход", + "zh-Hant": "退出", + "ja": "出口", + "ko": "종료", + "de": "Ausgang", + "fr": "Quitter", + "es": "Salir", + "pt-BR": "Sair" + }, + "退出全屏": { + "zh-Hans": "退出全屏", + "en": "Exit fullscreen", + "ru": "Выйти из полноэкранного режима", + "zh-Hant": "退出全屏", + "ja": "全画面表示を終了する", + "ko": "전체 화면 종료", + "de": "Vollbild beenden", + "fr": "Quitter le mode plein écran", + "es": "Salir de pantalla completa", + "pt-BR": "Sair da tela cheia" + }, + "退出精简": { + "zh-Hans": "退出精简", + "en": "Exit compact", + "ru": "Обычный вид", + "zh-Hant": "退出精簡", + "ja": "コンパクトに終了", + "ko": "컴팩트 종료", + "de": "Kompakt verlassen", + "fr": "Quitter le compact", + "es": "Salir compacto", + "pt-BR": "Sair do compacto" + }, + "退格": { + "zh-Hans": "退格", + "en": "Backspace", + "zh-Hant": "退格", + "ja": "バックスペース", + "ko": "백스페이스", + "de": "Rücktaste", + "fr": "Retour arrière", + "es": "Retroceso", + "pt-BR": "Retrocesso", + "ru": "Возврат" + }, + "选择": { + "zh-Hans": "选择", + "en": "Select", + "ru": "Выбрать", + "zh-Hant": "選擇", + "ja": "選択", + "ko": "선택", + "de": "Auswählen", + "fr": "Sélectionnez", + "es": "Seleccionar", + "pt-BR": "Selecione" + }, + "选择公告查看详情": { + "zh-Hans": "选择公告查看详情", + "en": "Select an announcement to read", + "ru": "Выберите объявление для просмотра", + "zh-Hant": "選擇公告檢視詳情", + "ja": "読むお知らせを選択してください", + "ko": "읽을 공지사항을 선택하세요.", + "de": "Wählen Sie eine Ankündigung zum Lesen aus", + "fr": "Sélectionnez une annonce à lire", + "es": "Seleccione un anuncio para leer", + "pt-BR": "Selecione um anúncio para ler" + }, + "选择分发文件": { + "zh-Hans": "选择分发文件", + "en": "Select a file to send", + "ru": "Выберите файл для отправки", + "zh-Hant": "選擇分發檔案", + "ja": "送信するファイルを選択する", + "ko": "보낼 파일을 선택하세요", + "de": "Wählen Sie eine Datei zum Senden aus", + "fr": "Sélectionnez un fichier à envoyer", + "es": "Seleccione un archivo para enviar", + "pt-BR": "Selecione um arquivo para enviar" + }, + "选择文件发送": { + "zh-Hans": "选择文件发送", + "en": "Select File to Send", + "ru": "Выбрать файл для отправки", + "zh-Hant": "選擇檔案傳送", + "ja": "送信するファイルの選択", + "ko": "보낼 파일 선택", + "de": "Wählen Sie die Datei zum Senden aus", + "fr": "Sélectionnez le fichier à envoyer", + "es": "Seleccionar archivo para enviar", + "pt-BR": "Selecione o arquivo para enviar" + }, + "选择显示器": { + "zh-Hans": "选择显示器", + "en": "Select Display", + "ru": "Выбрать дисплей", + "zh-Hant": "選擇顯示器", + "ja": "表示の選択", + "ko": "디스플레이 선택", + "de": "Wählen Sie Anzeige", + "fr": "Sélectionner l'affichage", + "es": "Seleccionar pantalla", + "pt-BR": "Selecionar exibição" + }, + "通知": { + "zh-Hans": "通知", + "en": "Notification", + "ru": "Уведомление", + "zh-Hant": "通知", + "ja": "お知らせ", + "ko": "알림", + "de": "Benachrichtigung", + "fr": "Notification", + "es": "Notificación", + "pt-BR": "Notificação" + }, + "通知公告": { + "zh-Hans": "通知公告", + "en": "Announcements", + "ru": "Объявления", + "zh-Hant": "通知公告", + "ja": "お知らせ", + "ko": "공지사항", + "de": "Mitteilungen", + "fr": "Annonces", + "es": "Anuncios", + "pt-BR": "Avisos" + }, + "通过 IP 连接过的设备会显示在这里。": { + "zh-Hans": "通过 IP 连接过的设备会显示在这里。", + "en": "Devices you connect to by IP will appear here.", + "ru": "Здесь появятся устройства, подключённые по IP.", + "zh-Hant": "透過 IP 連線過的裝置會顯示在這裡。", + "ja": "IP で接続するデバイスがここに表示されます。", + "ko": "IP로 연결한 장치가 여기에 표시됩니다.", + "de": "Geräte, mit denen Sie über IP eine Verbindung herstellen, werden hier angezeigt.", + "fr": "Les appareils auxquels vous vous connectez par IP apparaîtront ici.", + "es": "Los dispositivos a los que te conectas por IP aparecerán aquí.", + "pt-BR": "Os dispositivos aos quais você se conecta por IP aparecerão aqui." + }, + "通过设备 ID 添加": { + "zh-Hans": "通过设备 ID 添加", + "en": "Add by device ID", + "ru": "Добавить по ID устройства", + "zh-Hant": "透過裝置 ID 新增", + "ja": "デバイスIDによる追加", + "ko": "기기 ID로 추가", + "de": "Nach Geräte-ID hinzufügen", + "fr": "Ajouter par ID d'appareil", + "es": "Agregar por ID de dispositivo", + "pt-BR": "Adicionar por ID do dispositivo" + }, + "部分预览图未能清除,请重试。": { + "zh-Hans": "部分预览图未能清除,请重试。", + "en": "Some previews could not be cleared, please try again.", + "zh-Hant": "部分預覽圖未能清除,請重試。", + "ja": "一部のプレビューをクリアできませんでした。もう一度お試しください。", + "ko": "일부 미리보기를 삭제할 수 없습니다. 다시 시도해 주세요.", + "de": "Einige Vorschauen konnten nicht gelöscht werden. Bitte versuchen Sie es erneut.", + "fr": "Certains aperçus n'ont pas pu être effacés, veuillez réessayer.", + "es": "Algunas vistas previas no se pudieron borrar, inténtalo de nuevo.", + "pt-BR": "Não foi possível limpar algumas visualizações. Tente novamente.", + "ru": "Некоторые предварительные просмотры не удалось удалить. Повторите попытку." + }, + "配置保存失败,请检查配置目录是否可写后重试。": { + "zh-Hans": "配置保存失败,请检查配置目录是否可写后重试。", + "en": "Could not save settings. Check that the configuration directory is writable and retry.", + "ru": "Не удалось сохранить настройки. Проверьте доступ на запись в каталог конфигурации и повторите попытку.", + "zh-Hant": "配置儲存失敗,請檢查配置目錄是否可寫後重試。", + "ja": "設定を保存できませんでした。構成ディレクトリが書き込み可能であることを確認して、再試行してください。", + "ko": "설정을 저장할 수 없습니다. 구성 디렉터리가 쓰기 가능한지 확인하고 다시 시도하세요.", + "de": "Einstellungen konnten nicht gespeichert werden. Überprüfen Sie, ob das Konfigurationsverzeichnis beschreibbar ist, und versuchen Sie es erneut.", + "fr": "Impossible d'enregistrer les paramètres. Vérifiez que le répertoire de configuration est accessible en écriture et réessayez.", + "es": "No se pudo guardar la configuración. Compruebe que se pueda escribir en el directorio de configuración y vuelva a intentarlo.", + "pt-BR": "Não foi possível salvar as configurações. Verifique se o diretório de configuração é gravável e tente novamente." + }, + "采集方式": { + "zh-Hans": "采集方式", + "en": "Capture Method", + "ru": "Способ захвата", + "zh-Hant": "採集方式", + "ja": "捕獲方法", + "ko": "캡처 방법", + "de": "Erfassungsmethode", + "fr": "Méthode de capture", + "es": "Método de captura", + "pt-BR": "Método de Captura" + }, + "释放操控": { + "zh-Hans": "释放操控", + "en": "Release", + "ru": "Отпустить", + "zh-Hant": "釋放操控", + "ja": "リリース", + "ko": "출시", + "de": "Veröffentlichung", + "fr": "Libération", + "es": "Lanzamiento", + "pt-BR": "Liberação" + }, + "释放鼠标": { + "zh-Hans": "释放鼠标", + "en": "Release Mouse", + "ru": "Освободить мышь", + "zh-Hant": "釋放滑鼠", + "ja": "マウスを放します", + "ko": "마우스 놓기", + "de": "Lassen Sie die Maus los", + "fr": "Relâcher la souris", + "es": "Soltar el ratón", + "pt-BR": "Solte o mouse" + }, + "重启后生效": { + "zh-Hans": "重启后生效", + "en": "Takes effect after restart", + "ru": "Вступит в силу после перезапуска", + "zh-Hant": "重啟後生效", + "ja": "再起動後に有効になります", + "ko": "다시 시작하면 적용됩니다.", + "de": "Wird nach dem Neustart wirksam", + "fr": "Prend effet après le redémarrage", + "es": "Entra en vigor después del reinicio", + "pt-BR": "Entra em vigor após reiniciar" + }, + "重新连接": { + "zh-Hans": "重新连接", + "en": "Reconnect", + "ru": "Переподключиться", + "zh-Hant": "重新連線", + "ja": "再接続", + "ko": "다시 연결", + "de": "Erneut verbinden", + "fr": "Reconnecter", + "es": "Reconectar", + "pt-BR": "Reconectar" + }, + "重新连接确认:新密码已生效。": { + "zh-Hans": "重新连接确认:新密码已生效。", + "en": "Reconnection confirmed: the new password is active.", + "ru": "Повторное подключение подтвердило новый пароль.", + "zh-Hant": "重新連線確認:新密碼已生效。", + "ja": "再接続が確認されました: 新しいパスワードが有効です。", + "ko": "재연결 확인됨: 새 비밀번호가 활성화되었습니다.", + "de": "Wiederverbindung bestätigt: Das neue Passwort ist aktiv.", + "fr": "Reconnexion confirmée : le nouveau mot de passe est actif.", + "es": "Reconexión confirmada: la nueva contraseña está activa.", + "pt-BR": "Reconexão confirmada: a nova senha está ativa." + }, + "重新连接确认:继续使用原密码。": { + "zh-Hans": "重新连接确认:继续使用原密码。", + "en": "Reconnection confirmed: the original password remains active.", + "ru": "Повторное подключение подтвердило прежний пароль.", + "zh-Hant": "重新連線確認:繼續使用原密碼。", + "ja": "再接続が確認されました: 元のパスワードは有効のままです。", + "ko": "재연결 확인됨: 원래 비밀번호가 활성 상태로 유지됩니다.", + "de": "Wiederverbindung bestätigt: Das ursprüngliche Passwort bleibt aktiv.", + "fr": "Reconnexion confirmée : le mot de passe d'origine reste actif.", + "es": "Reconexión confirmada: la contraseña original permanece activa.", + "pt-BR": "Reconexão confirmada: a senha original permanece ativa." + }, + "重试": { + "zh-Hans": "重试", + "en": "Try again", + "zh-Hant": "重試", + "ja": "もう一度お試しください", + "ko": "다시 시도해 보세요", + "de": "Versuchen Sie es erneut", + "fr": "Réessayez", + "es": "Inténtalo de nuevo", + "pt-BR": "Tente novamente", + "ru": "Попробуйте еще раз" + }, + "重试保存阅读状态": { + "zh-Hans": "重试保存阅读状态", + "en": "Retry saving reading status", + "zh-Hant": "重試儲存閱讀狀態", + "ja": "読み取りステータスの保存をリトライする", + "ko": "읽은 상태 저장 다시 시도", + "de": "Versuchen Sie erneut, den Lesestatus zu speichern", + "fr": "Réessayez d'enregistrer l'état de lecture", + "es": "Reintentar guardar el estado de lectura", + "pt-BR": "Tente salvar novamente o status de leitura", + "ru": "Повторить попытку сохранения статуса чтения." + }, + "锁定": { + "zh-Hans": "锁定", + "en": "Lock", + "ru": "Заблокировать", + "zh-Hant": "鎖定", + "ja": "ロック", + "ko": "잠금", + "de": "Sperren", + "fr": "Verrouillage", + "es": "Bloquear", + "pt-BR": "Bloqueio" + }, + "锁定远端": { + "zh-Hans": "锁定远端", + "en": "Lock Remote", + "ru": "Заблокировать удалённое устройство", + "zh-Hant": "鎖定遠端", + "ja": "リモコンをロックする", + "ko": "원격 잠금", + "de": "Fernbedienung sperren", + "fr": "Verrouillage à distance", + "es": "Bloquear control remoto", + "pt-BR": "Bloquear remoto" + }, + "锁屏控制服务": { + "zh-Hans": "锁屏控制服务", + "en": "Lock-screen control service", + "ru": "Служба управления при блокировке", + "zh-Hant": "鎖屏控制服務", + "ja": "ロック画面コントロールサービス", + "ko": "잠금화면 제어 서비스", + "de": "Sperrbildschirm-Steuerungsdienst", + "fr": "Service de contrôle de l'écran de verrouillage", + "es": "Servicio de control de pantalla de bloqueo", + "pt-BR": "Serviço de controle de tela de bloqueio" + }, + "键盘": { + "zh-Hans": "键盘", + "en": "Keyboard", + "zh-Hant": "鍵盤", + "ja": "キーボード", + "ko": "키보드", + "de": "Tastatur", + "fr": "Clavier", + "es": "Teclado", + "pt-BR": "Teclado", + "ru": "Клавиатура" + }, + "键盘操作": { + "zh-Hans": "键盘操作", + "en": "Keyboard operation", + "zh-Hant": "鍵盤操作", + "ja": "キーボード操作", + "ko": "키보드 조작", + "de": "Tastaturbedienung", + "fr": "Fonctionnement du clavier", + "es": "Operación del teclado", + "pt-BR": "Operação do teclado", + "ru": "Работа с клавиатурой" + }, + "阅读并授权": { + "zh-Hans": "阅读并授权", + "en": "Read and authorize", + "zh-Hant": "閱讀並授權", + "ja": "読んで承認する", + "ko": "읽기 및 승인", + "de": "Lesen und autorisieren", + "fr": "Lire et autoriser", + "es": "Leer y autorizar", + "pt-BR": "Ler e autorizar", + "ru": "Прочитать и авторизоваться" + }, + "队列中": { + "zh-Hans": "队列中", + "en": "Queued", + "ru": "В очереди", + "zh-Hant": "佇列中", + "ja": "キューに入れられました", + "ko": "대기 중", + "de": "In der Warteschlange", + "fr": "En file d'attente", + "es": "En cola", + "pt-BR": "Na fila" + }, + "隐私": { + "zh-Hans": "隐私", + "en": "Privacy", + "zh-Hant": "隱私", + "ja": "プライバシー", + "ko": "개인 정보 보호", + "de": "Datenschutz", + "fr": "Confidentialité", + "es": "Privacidad", + "pt-BR": "Privacidade", + "ru": "Конфиденциальность" + }, + "隐私与授权": { + "zh-Hans": "隐私与授权", + "en": "Privacy and Authorization", + "zh-Hant": "隱私與授權", + "ja": "プライバシーと認証", + "ko": "개인 정보 보호 및 승인", + "de": "Datenschutz und Autorisierung", + "fr": "Confidentialité et autorisation", + "es": "Privacidad y autorización", + "pt-BR": "Privacidade e Autorização", + "ru": "Конфиденциальность и авторизация" + }, + "隐私保护": { + "zh-Hans": "隐私保护", + "en": "Privacy", + "ru": "Приватность", + "zh-Hant": "隱私保護", + "ja": "プライバシー", + "ko": "개인 정보 보호", + "de": "Datenschutz", + "fr": "Confidentialité", + "es": "Privacidad", + "pt-BR": "Privacidade" + }, + "隐私屏": { + "zh-Hans": "隐私屏", + "en": "Privacy screen", + "ru": "Приватный экран", + "zh-Hant": "隱私屏", + "ja": "プライバシー画面", + "ko": "개인정보 보호 화면", + "de": "Sichtschutz", + "fr": "Écran de confidentialité", + "es": "Pantalla de privacidad", + "pt-BR": "Tela de privacidade" + }, + "隐私屏已关闭": { + "zh-Hans": "隐私屏已关闭", + "en": "Privacy screen off", + "ru": "Приватный экран выкл.", + "zh-Hant": "隱私屏已關閉", + "ja": "プライバシー画面:オフ", + "ko": "화면 보호 꺼짐", + "de": "Sichtschutz aus", + "fr": "Confidentialité inactive", + "es": "Privacidad desactivada", + "pt-BR": "Privacidade desativada" + }, + "隐私屏已开启": { + "zh-Hans": "隐私屏已开启", + "en": "Privacy screen on", + "ru": "Приватный экран вкл.", + "zh-Hant": "隱私屏已開啟", + "ja": "プライバシー画面:オン", + "ko": "화면 보호 켜짐", + "de": "Sichtschutz an", + "fr": "Confidentialité active", + "es": "Privacidad activada", + "pt-BR": "Privacidade ativada" + }, + "隐私屏已开启,本机解锁已禁用": { + "zh-Hans": "隐私屏已开启,本机解锁已禁用", + "en": "Privacy screen is on. Local unlocking is disabled.", + "ru": "Приватный экран включён. Локальная разблокировка отключена.", + "zh-Hant": "隱私屏已開啟,本機解鎖已禁用", + "ja": "プライバシー画面がオンになっています。ローカルのロック解除は無効になっています。", + "ko": "개인정보 보호 화면이 켜져 있습니다. 로컬 잠금 해제가 비활성화되었습니다.", + "de": "Der Datenschutzbildschirm ist aktiviert. Die lokale Entsperrung ist deaktiviert.", + "fr": "L'écran de confidentialité est activé. Le déverrouillage local est désactivé.", + "es": "La pantalla de privacidad está activada. El desbloqueo local está deshabilitado.", + "pt-BR": "A tela de privacidade está ativada. O desbloqueio local está desativado." + }, + "隐私屏已被解锁": { + "zh-Hans": "隐私屏已被解锁", + "en": "Privacy screen unlocked", + "ru": "Приватный экран разблокирован", + "zh-Hant": "隱私屏已被解鎖", + "ja": "プライバシー画面のロックが解除されました", + "ko": "개인정보 보호 화면 잠금 해제됨", + "de": "Datenschutzbildschirm entsperrt", + "fr": "Écran de confidentialité déverrouillé", + "es": "Pantalla de privacidad desbloqueada", + "pt-BR": "Tela de privacidade desbloqueada" + }, + "隐私屏异常": { + "zh-Hans": "隐私屏异常", + "en": "Privacy screen abnormality", + "zh-Hant": "隱私屏異常", + "ja": "プライバシー画面異常", + "ko": "개인정보 화면 이상", + "de": "Anomalie des Sichtschutzbildschirms", + "fr": "Anomalie de l'écran de confidentialité", + "es": "Anormalidad en la pantalla de privacidad", + "pt-BR": "Anormalidade na tela de privacidade", + "ru": "Неисправность экрана конфиденциальности." + }, + "隐私屏暂不可用": { + "zh-Hans": "隐私屏暂不可用", + "en": "Privacy screen is temporarily unavailable", + "zh-Hant": "隱私屏暫不可用", + "ja": "プライバシー画面が一時的に利用できなくなります", + "ko": "개인 정보 보호 화면을 일시적으로 사용할 수 없습니다.", + "de": "Der Datenschutzbildschirm ist vorübergehend nicht verfügbar", + "fr": "L'écran de confidentialité est temporairement indisponible", + "es": "La pantalla de privacidad no está disponible temporalmente", + "pt-BR": "A tela de privacidade está temporariamente indisponível", + "ru": "Экран конфиденциальности временно недоступен." + }, + "隐私屏状态已过期,等待电脑确认": { + "zh-Hans": "隐私屏状态已过期,等待电脑确认", + "en": "Privacy screen status has expired, waiting for computer confirmation", + "zh-Hant": "隱私屏狀態已過期,等待電腦確認", + "ja": "プライバシー画面のステータスが期限切れになり、コンピュータの確認を待っています", + "ko": "개인 정보 보호 화면 상태가 만료되어 컴퓨터 확인을 기다리는 중입니다.", + "de": "Der Status des Datenschutzbildschirms ist abgelaufen und wartet auf Computerbestätigung", + "fr": "L'état de l'écran de confidentialité a expiré, en attente de confirmation par l'ordinateur", + "es": "El estado de la pantalla de privacidad ha caducado, esperando confirmación por computadora", + "pt-BR": "O status da tela de privacidade expirou, aguardando confirmação do computador", + "ru": "Срок действия статуса экрана конфиденциальности истек, ожидание подтверждения от компьютера." + }, + "隐私屏状态待确认": { + "zh-Hans": "隐私屏状态待确认", + "en": "Privacy screen status to be confirmed", + "zh-Hant": "隱私屏狀態待確認", + "ja": "プライバシー画面のステータスを確認する", + "ko": "개인정보 보호 화면 상태 확인 예정", + "de": "Status des Datenschutzbildschirms muss bestätigt werden", + "fr": "Statut de l'écran de confidentialité à confirmer", + "es": "Estado de la pantalla de privacidad por confirmar", + "pt-BR": "Status da tela de privacidade a ser confirmado", + "ru": "Статус экрана конфиденциальности подлежит подтверждению." + }, + "隐私屏:不可用": { + "zh-Hans": "隐私屏:不可用", + "en": "Privacy screen: unavailable", + "ru": "Приватный экран: недоступен", + "zh-Hant": "隱私屏:不可用", + "ja": "プライバシー画面:使用不可", + "ko": "개인 정보 보호 화면: 사용할 수 없음", + "de": "Datenschutzbildschirm: nicht verfügbar", + "fr": "Écran de confidentialité : indisponible", + "es": "Pantalla de privacidad: no disponible", + "pt-BR": "Tela de privacidade: indisponível" + }, + "隐私屏:已关闭": { + "zh-Hans": "隐私屏:已关闭", + "en": "Privacy screen: off", + "ru": "Приватный экран: выключен", + "zh-Hant": "隱私屏:已關閉", + "ja": "プライバシー画面:オフ", + "ko": "개인정보 보호 화면: 꺼짐", + "de": "Datenschutzbildschirm: aus", + "fr": "Écran de confidentialité : désactivé", + "es": "Pantalla de privacidad: desactivada", + "pt-BR": "Tela de privacidade: desativada" + }, + "隐私屏:已开启": { + "zh-Hans": "隐私屏:已开启", + "en": "Privacy screen: on", + "ru": "Приватный экран: включён", + "zh-Hant": "隱私屏:已開啟", + "ja": "プライバシー画面:オン", + "ko": "개인정보 보호 화면: 켜짐", + "de": "Datenschutzbildschirm: ein", + "fr": "Écran de confidentialité : activé", + "es": "Pantalla de privacidad: activada", + "pt-BR": "Tela de privacidade: ativada" + }, + "隐私政策": { + "zh-Hans": "隐私政策", + "en": "Privacy Policy", + "zh-Hant": "隱私政策", + "ja": "プライバシーポリシー", + "ko": "개인정보 보호정책", + "de": "Datenschutzrichtlinie", + "fr": "Politique de confidentialité", + "es": "Política de privacidad", + "pt-BR": "Política de Privacidade", + "ru": "Политика конфиденциальности" + }, + "隐私政策无法读取,请重新安装应用": { + "zh-Hans": "隐私政策无法读取,请重新安装应用", + "en": "Privacy policy cannot be read, please reinstall the app", + "zh-Hant": "隱私政策無法讀取,請重新安裝應用", + "ja": "プライバシーポリシーが読めない場合はアプリを再インストールしてください", + "ko": "개인정보취급방침을 읽을 수 없습니다. 앱을 다시 설치해 주세요.", + "de": "Datenschutzbestimmungen können nicht gelesen werden, bitte installieren Sie die App neu", + "fr": "La politique de confidentialité ne peut pas être lue, veuillez réinstaller l'application", + "es": "No se puede leer la política de privacidad; reinstale la aplicación", + "pt-BR": "A política de privacidade não pode ser lida, reinstale o aplicativo", + "ru": "Невозможно прочитать политику конфиденциальности, переустановите приложение." + }, + "隐私政策暂时无法读取,请拒绝联网并重新安装应用。": { + "zh-Hans": "隐私政策暂时无法读取,请拒绝联网并重新安装应用。", + "en": "The privacy policy cannot be read temporarily. Please refuse to connect to the Internet and reinstall the application.", + "zh-Hant": "隱私政策暫時無法讀取,請拒絕聯網並重新安裝應用。", + "ja": "一時的にプライバシーポリシーが閲覧できなくなります。インターネットへの接続を拒否し、アプリケーションを再インストールしてください。", + "ko": "개인정보취급방침은 일시적으로 열람할 수 없습니다. 인터넷 연결을 거부하고 애플리케이션을 다시 설치하십시오.", + "de": "Die Datenschutzerklärung kann vorübergehend nicht gelesen werden. Bitte verweigern Sie die Verbindung zum Internet und installieren Sie die Anwendung neu.", + "fr": "La politique de confidentialité ne peut pas être lue temporairement. Veuillez refuser de vous connecter à Internet et réinstaller l'application.", + "es": "La política de privacidad no se puede leer temporalmente. Rechace conectarse a Internet y reinstale la aplicación.", + "pt-BR": "A política de privacidade não pode ser lida temporariamente. Recuse-se a se conectar à Internet e reinstale o aplicativo.", + "ru": "Политику конфиденциальности временно невозможно прочитать. Пожалуйста, откажитесь от подключения к Интернету и переустановите приложение." + }, + "隐藏密码": { + "zh-Hans": "隐藏密码", + "en": "Hide password", + "ru": "Скрыть пароль", + "zh-Hant": "隱藏密碼", + "ja": "パスワードを隠す", + "ko": "비밀번호 숨기기", + "de": "Passwort verbergen", + "fr": "Masquer le mot de passe", + "es": "Ocultar contraseña", + "pt-BR": "Ocultar senha" + }, + "隐藏网络状态": { + "zh-Hans": "隐藏网络状态", + "en": "Hide network status", + "ru": "Скрыть состояние сети", + "zh-Hant": "隱藏網路狀態", + "ja": "ネットワークステータスを非表示にする", + "ko": "네트워크 상태 숨기기", + "de": "Netzwerkstatus ausblenden", + "fr": "Masquer l'état du réseau", + "es": "Ocultar estado de la red", + "pt-BR": "Ocultar status da rede" + }, + "需要密码": { + "zh-Hans": "需要密码", + "en": "Password required", + "ru": "Нужен пароль", + "zh-Hant": "需要密碼", + "ja": "パスワードが必要です", + "ko": "비밀번호가 필요합니다", + "de": "Passwort erforderlich", + "fr": "Mot de passe requis", + "es": "Se requiere contraseña", + "pt-BR": "Senha necessária" + }, + "静音": { + "zh-Hans": "静音", + "en": "Mute", + "ru": "Без звука", + "zh-Hant": "靜音", + "ja": "ミュート", + "ko": "음소거", + "de": "Stumm", + "fr": "Muet", + "es": "Silencio", + "pt-BR": "Mudo" + }, + "音频": { + "zh-Hans": "音频", + "en": "Audio", + "ru": "Аудио", + "zh-Hant": "音訊", + "ja": "オーディオ", + "ko": "오디오", + "de": "Audio", + "fr": "Audio", + "es": "Audio", + "pt-BR": "Áudio" + }, + "项目主页": { + "zh-Hans": "项目主页", + "en": "Project website", + "ru": "Сайт проекта", + "zh-Hant": "專案主頁", + "ja": "プロジェクトWebサイト", + "ko": "프로젝트 홈페이지", + "de": "Projektwebsite", + "fr": "Site Web du projet", + "es": "Sitio web del proyecto", + "pt-BR": "Site do projeto" + }, + "预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。": { + "zh-Hans": "预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。", + "en": "Previews may contain personal or work information from the remote computer. After turning it on, each connection will automatically save a picture on the machine and display it in recent connections. You can close and clear at any time.", + "zh-Hant": "預覽可能包含遠端電腦上的個人或工作資訊。開啟後,每次連線會自動將一張畫面儲存在本機並顯示在最近連線中。你可以隨時關閉並清除。", + "ja": "プレビューには、リモート コンピューターからの個人情報または仕事情報が含まれる場合があります。オンにすると、接続するたびにマシンに写真が自動的に保存され、最近の接続で表示されます。いつでも閉じてクリアできます。", + "ko": "미리보기에는 원격 컴퓨터의 개인 정보나 업무 정보가 포함될 수 있습니다. 전원을 켜면 각 연결이 자동으로 기기에 사진을 저장하고 최근 연결에 표시됩니다. 언제든지 닫고 지울 수 있습니다.", + "de": "Vorschauen können persönliche oder geschäftliche Informationen vom Remote-Computer enthalten. Nach dem Einschalten speichert jede Verbindung automatisch ein Bild auf dem Gerät und zeigt es in den letzten Verbindungen an. Sie können jederzeit schließen und löschen.", + "fr": "Les aperçus peuvent contenir des informations personnelles ou professionnelles provenant de l'ordinateur distant. Après l'avoir allumé, chaque connexion enregistrera automatiquement une image sur la machine et l'affichera dans les connexions récentes. Vous pouvez fermer et effacer à tout moment.", + "es": "Las vistas previas pueden contener información personal o laboral de la computadora remota. Después de encenderlo, cada conexión guardará automáticamente una imagen en la máquina y la mostrará en las conexiones recientes. Puedes cerrar y borrar en cualquier momento.", + "pt-BR": "As visualizações podem conter informações pessoais ou de trabalho do computador remoto. Após ligá-lo, cada conexão salvará automaticamente uma imagem na máquina e a exibirá nas conexões recentes. Você pode fechar e limpar a qualquer momento.", + "ru": "Предварительный просмотр может содержать личную или рабочую информацию с удаленного компьютера. После его включения каждое подключение будет автоматически сохранять изображение на устройстве и отображать его при последних подключениях. Вы можете закрыть и очистить в любое время." + }, + "预览可能包含远程设备上的敏感内容。仅保存在本机,从下一次连接起生效,可随时关闭并清除。": { + "zh-Hans": "预览可能包含远程设备上的敏感内容。仅保存在本机,从下一次连接起生效,可随时关闭并清除。", + "en": "The preview may contain sensitive content on the remote device. It is only saved locally and takes effect from the next connection. It can be closed and cleared at any time.", + "zh-Hant": "預覽可能包含遠端裝置上的敏感內容。僅儲存在本機,從下一次連線起生效,可隨時關閉並清除。", + "ja": "プレビューには、リモート デバイス上の機密コンテンツが含まれる可能性があります。これはローカルにのみ保存され、次回の接続から有効になります。いつでも閉じたりクリアしたりできます。", + "ko": "미리보기에는 원격 장치의 민감한 콘텐츠가 포함될 수 있습니다. 로컬에만 저장되며 다음 연결부터 적용됩니다. 언제든지 닫고 지울 수 있습니다.", + "de": "Die Vorschau enthält möglicherweise vertrauliche Inhalte auf dem Remote-Gerät. Es wird nur lokal gespeichert und ist ab der nächsten Verbindung wirksam. Es kann jederzeit geschlossen und geräumt werden.", + "fr": "L'aperçu peut contenir du contenu sensible sur l'appareil distant. Il est uniquement enregistré localement et prend effet dès la prochaine connexion. Il peut être fermé et effacé à tout moment.", + "es": "La vista previa puede contener contenido confidencial en el dispositivo remoto. Sólo se guarda localmente y entra en vigor a partir de la siguiente conexión. Se puede cerrar y borrar en cualquier momento.", + "pt-BR": "A visualização pode conter conteúdo confidencial no dispositivo remoto. Ele é salvo apenas localmente e entra em vigor na próxima conexão. Pode ser fechado e limpo a qualquer momento.", + "ru": "Предварительный просмотр может содержать конфиденциальный контент на удаленном устройстве. Он сохраняется только локально и вступает в силу при следующем подключении. Его можно закрыть и очистить в любой момент." + }, + "验证密码中...": { + "zh-Hans": "验证密码中...", + "en": "Validating password...", + "ru": "Проверка пароля...", + "zh-Hant": "驗證密碼中...", + "ja": "パスワードを検証中...", + "ko": "비밀번호 확인 중...", + "de": "Passwort wird validiert...", + "fr": "Validation du mot de passe...", + "es": "Validando contraseña...", + "pt-BR": "Validando senha..." + }, + "验证尝试过于频繁,请稍后重试。": { + "zh-Hans": "验证尝试过于频繁,请稍后重试。", + "en": "Too many authentication attempts. Try again later.", + "ru": "Слишком много попыток аутентификации. Повторите позже.", + "zh-Hant": "驗證嘗試過於頻繁,請稍後重試。", + "ja": "認証試行が多すぎます。後でもう一度試してください。", + "ko": "인증 시도 횟수가 너무 많습니다. 나중에 다시 시도하세요.", + "de": "Zu viele Authentifizierungsversuche. Versuchen Sie es später noch einmal.", + "fr": "Trop de tentatives d'authentification. Réessayez plus tard.", + "es": "Demasiados intentos de autenticación. Vuelve a intentarlo más tarde.", + "pt-BR": "Muitas tentativas de autenticação. Tente novamente mais tarde." + }, + "高": { + "zh-Hans": "高", + "en": "High", + "ru": "Высокое", + "zh-Hant": "高", + "ja": "高", + "ko": "높음", + "de": "Hoch", + "fr": "Élevée", + "es": "Alta", + "pt-BR": "Alta" + }, + "默认": { + "zh-Hans": "默认", + "en": "Default", + "zh-Hant": "預設", + "ja": "デフォルト", + "ko": "기본값", + "de": "Standard", + "fr": "Par défaut", + "es": "Predeterminado", + "pt-BR": "Padrão", + "ru": "По умолчанию" + }, + "默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。": { + "zh-Hans": "默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。", + "en": "Off by default. When turned on, the iPhone goes into and stays in landscape orientation when connected; when turned off, it follows the device orientation. iPads are not affected.", + "zh-Hant": "預設關閉。開啟後,iPhone 連線時進入並保持橫屏;關閉時跟隨裝置方向。iPad 不受影響。", + "ja": "デフォルトではオフです。オンにすると、iPhone は接続時に横向きになり、横向きのままになります。オフにすると、デバイスの向きに従います。 iPad は影響を受けません。", + "ko": "기본적으로 꺼져 있습니다. iPhone을 켜면 연결 시 iPhone이 가로 방향으로 전환되어 유지됩니다. 꺼지면 장치 방향을 따릅니다. iPad는 영향을 받지 않습니다.", + "de": "Standardmäßig deaktiviert. Beim Einschalten wechselt das iPhone in die Querformatausrichtung und bleibt beim Anschließen im Querformat. Im ausgeschalteten Zustand folgt es der Ausrichtung des Geräts. iPads sind nicht betroffen.", + "fr": "Désactivé par défaut. Lorsqu'il est allumé, l'iPhone passe et reste en orientation paysage lorsqu'il est connecté ; lorsqu'il est éteint, il suit l'orientation de l'appareil. Les iPad ne sont pas concernés.", + "es": "Desactivado de forma predeterminada. Cuando se enciende, el iPhone entra y permanece en orientación horizontal cuando está conectado; cuando está apagado, sigue la orientación del dispositivo. Los iPad no se ven afectados.", + "pt-BR": "Desligado por padrão. Quando ligado, o iPhone entra e permanece na orientação paisagem quando conectado; quando desligado, segue a orientação do dispositivo. Os iPads não são afetados.", + "ru": "По умолчанию выключено. При включении iPhone переходит в альбомную ориентацию и остается при подключении; в выключенном состоянии он следует ориентации устройства. iPad не затрагивается." + }, + "默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。": { + "zh-Hans": "默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。", + "en": "Off by default. When turned on, the screen will enter and remain in landscape orientation when the phone is connected; when turned off, it will follow the direction of the device. Tablets and multi-windows are not affected.", + "zh-Hant": "預設關閉。開啟後,手機連線時進入並保持橫屏;關閉時跟隨裝置方向。平板和多視窗不受影響。", + "ja": "デフォルトではオフです。オンにすると、電話が接続されているときに画面が横向きになり、横向きのままになります。オフにすると、デバイスの方向に従います。タブレットやマルチウィンドウは影響を受けません。", + "ko": "기본적으로 꺼져 있습니다. 전원을 켜면 휴대폰이 연결되면 화면이 가로 방향으로 전환되고 유지됩니다. 꺼지면 장치의 방향을 따릅니다. 태블릿과 멀티 윈도우는 영향을 받지 않습니다.", + "de": "Standardmäßig deaktiviert. Wenn es eingeschaltet ist, wird der Bildschirm angezeigt und bleibt im Querformat, wenn das Telefon angeschlossen ist. Wenn es ausgeschaltet ist, folgt es der Richtung des Geräts. Tablets und Multi-Windows sind nicht betroffen.", + "fr": "Désactivé par défaut. Lorsqu'il est allumé, l'écran entre et reste en orientation paysage lorsque le téléphone est connecté ; lorsqu'il est éteint, il suivra la direction de l'appareil. Les tablettes et multi-fenêtres ne sont pas concernées.", + "es": "Desactivado de forma predeterminada. Cuando esté encendido, la pantalla entrará y permanecerá en orientación horizontal cuando el teléfono esté conectado; cuando esté apagado, seguirá la dirección del dispositivo. Las tabletas y las ventanas múltiples no se ven afectadas.", + "pt-BR": "Desligado por padrão. Quando ligado, a tela entrará e permanecerá na orientação paisagem quando o telefone estiver conectado; quando desligado, seguirá a direção do dispositivo. Tablets e janelas múltiplas não são afetados.", + "ru": "По умолчанию выключено. При включении экран войдет и останется в альбомной ориентации при подключении телефона; в выключенном состоянии он будет следовать направлению устройства. Планшеты и мультиокна не затронуты." + }, + "鼠标右键": { + "zh-Hans": "鼠标右键", + "en": "Right mouse button", + "zh-Hant": "滑鼠右鍵", + "ja": "マウスの右ボタン", + "ko": "마우스 오른쪽 버튼", + "de": "Rechte Maustaste", + "fr": "Bouton droit de la souris", + "es": "Botón derecho del ratón", + "pt-BR": "Botão direito do mouse", + "ru": "Правая кнопка мыши" + }, + "鼠标右键,按住并拖动,松开结束拖拽": { + "zh-Hans": "鼠标右键,按住并拖动,松开结束拖拽", + "en": "Right mouse button, press and drag, release to end dragging", + "zh-Hant": "滑鼠右鍵,按住並拖動,鬆開結束拖拽", + "ja": "マウスの右ボタンを押してドラッグし、放してドラッグを終了します", + "ko": "마우스 오른쪽 버튼을 누르고 드래그한 후 떼면 드래그가 종료됩니다.", + "de": "Rechte Maustaste, drücken und ziehen, loslassen, um das Ziehen zu beenden", + "fr": "Bouton droit de la souris, appuyez et faites glisser, relâchez pour terminer le glisser", + "es": "Botón derecho del mouse, presione y arrastre, suelte para finalizar el arrastre", + "pt-BR": "Botão direito do mouse, pressione e arraste, solte para finalizar o arrasto", + "ru": "Правая кнопка мыши, нажмите и перетащите, отпустите, чтобы завершить перетаскивание." + }, + "鼠标右键,按住拖动": { + "zh-Hans": "鼠标右键,按住拖动", + "en": "Right mouse button, hold down and drag", + "zh-Hant": "滑鼠右鍵,按住拖動", + "ja": "マウスの右ボタンを押したままドラッグします", + "ko": "마우스 오른쪽 버튼을 누르고 드래그하세요.", + "de": "Rechte Maustaste, gedrückt halten und ziehen", + "fr": "Bouton droit de la souris, maintenez enfoncé et faites glisser", + "es": "Botón derecho del ratón, mantén pulsado y arrastra", + "pt-BR": "Botão direito do mouse, mantenha pressionado e arraste", + "ru": "Правая кнопка мыши, удерживайте ее и перетащите" + }, + "鼠标左键": { + "zh-Hans": "鼠标左键", + "en": "Left mouse button", + "zh-Hant": "滑鼠左鍵", + "ja": "マウスの左ボタン", + "ko": "마우스 왼쪽 버튼", + "de": "Linke Maustaste", + "fr": "Bouton gauche de la souris", + "es": "Botón izquierdo del ratón", + "pt-BR": "Botão esquerdo do mouse", + "ru": "Левая кнопка мыши" + }, + "鼠标左键,按住并拖动,松开结束拖拽": { + "zh-Hans": "鼠标左键,按住并拖动,松开结束拖拽", + "en": "Left mouse button, press and drag, release to end dragging", + "zh-Hant": "滑鼠左鍵,按住並拖動,鬆開結束拖拽", + "ja": "マウスの左ボタンを押してドラッグし、放してドラッグを終了します", + "ko": "마우스 왼쪽 버튼을 누르고 드래그한 후 떼면 드래그가 종료됩니다.", + "de": "Linke Maustaste, drücken und ziehen, loslassen, um das Ziehen zu beenden", + "fr": "Bouton gauche de la souris, appuyez et faites glisser, relâchez pour terminer le glisser", + "es": "Botón izquierdo del mouse, presione y arrastre, suelte para finalizar el arrastre", + "pt-BR": "Botão esquerdo do mouse, pressione e arraste, solte para finalizar o arrasto", + "ru": "Левую кнопку мыши нажмите и перетащите, отпустите, чтобы завершить перетаскивание." + }, + "鼠标左键,按住拖动": { + "zh-Hans": "鼠标左键,按住拖动", + "en": "Left mouse button, hold down and drag", + "zh-Hant": "滑鼠左鍵,按住拖動", + "ja": "マウスの左ボタンを押したままドラッグします", + "ko": "마우스 왼쪽 버튼을 누른 채 드래그", + "de": "Linke Maustaste, gedrückt halten und ziehen", + "fr": "Bouton gauche de la souris, maintenez enfoncé et faites glisser", + "es": "Botón izquierdo del ratón, mantén pulsado y arrastra", + "pt-BR": "Botão esquerdo do mouse, mantenha pressionado e arraste", + "ru": "Левая кнопка мыши, удерживая ее, перетащите" + }, + "鼠标控制": { + "zh-Hans": "鼠标控制", + "en": "Mouse control", + "zh-Hant": "滑鼠控制", + "ja": "マウスコントロール", + "ko": "마우스 제어", + "de": "Maussteuerung", + "fr": "Contrôle de la souris", + "es": "Control del ratón", + "pt-BR": "Controle do mouse", + "ru": "Управление мышью" + }, + "鼠标滚轮": { + "zh-Hans": "鼠标滚轮", + "en": "Mouse wheel", + "zh-Hant": "滑鼠滾輪", + "ja": "マウスホイール", + "ko": "마우스 휠", + "de": "Mausrad", + "fr": "Molette de la souris", + "es": "Rueda del ratón", + "pt-BR": "Roda do mouse", + "ru": "Колесо мыши" + }, + "鼠标滚轮,上下滑动,可滑出按键范围": { + "zh-Hans": "鼠标滚轮,上下滑动,可滑出按键范围", + "en": "Mouse wheel, slide up and down to slide out of the key range", + "zh-Hant": "滑鼠滾輪,上下滑動,可滑出按鍵範圍", + "ja": "マウスホイール、上下にスライドしてキー範囲外にスライドします", + "ko": "마우스 휠, 위아래로 밀어 키 범위 밖으로 슬라이드", + "de": "Mausrad, nach oben und unten schieben, um aus dem Tastenbereich zu gleiten", + "fr": "Molette de la souris, faites-la glisser de haut en bas pour sortir de la plage de touches", + "es": "Rueda del mouse, deslícela hacia arriba y hacia abajo para salir del rango de teclas", + "pt-BR": "Roda do mouse, deslize para cima e para baixo para sair do intervalo de teclas", + "ru": "Колесо мыши: проведите вверх и вниз, чтобы выйти за пределы диапазона клавиш." + }, + "(仅在交互终端显示)": { + "zh-Hans": "(仅在交互终端显示)", + "en": "(shown only in an interactive terminal)", + "ru": "(виден только в интерактивном терминале)", + "zh-Hant": "(僅在互動終端顯示)", + "ja": "(対話型端末でのみ表示)", + "ko": "(대화형 터미널에만 표시됨)", + "de": "(wird nur in einem interaktiven Terminal angezeigt)", + "fr": "(affiché uniquement dans un terminal interactif)", + "es": "(se muestra solo en una terminal interactiva)", + "pt-BR": "(mostrado apenas em um terminal interativo)" + }, + ",丢包率 ": { + "zh-Hans": ",丢包率 ", + "en": ", packet loss rate ", + "zh-Hant": ",丟包率 ", + "ja": "、パケットロス率 ", + "ko": ", 패킷 손실률 ", + "de": ", Paketverlustrate ", + "fr": ", taux de perte de paquets ", + "es": ", tasa de pérdida de paquetes ", + "pt-BR": ", taxa de perda de pacotes ", + "ru": ", коэффициент потери пакетов " + }, + ",发送 ": { + "zh-Hans": ",发送 ", + "en": ", send ", + "zh-Hant": ",傳送 ", + "ja": "、送信します ", + "ko": ", 보내다 ", + "de": ", senden ", + "fr": ", envoyer ", + "es": ", enviar ", + "pt-BR": ", enviar ", + "ru": ", отправить " + }, + ",已保存密码": { + "zh-Hans": ",已保存密码", + "en": ", password saved", + "zh-Hant": ",已儲存密碼", + "ja": "、パスワードが保存されました", + "ko": ", 비밀번호가 저장되었습니다", + "de": ", Passwort gespeichert", + "fr": ", mot de passe enregistré", + "es": ", contraseña guardada", + "pt-BR": ", senha salva", + "ru": ", пароль сохранен" + }, + ",接收 ": { + "zh-Hans": ",接收 ", + "en": ", receive ", + "zh-Hant": ",接收 ", + "ja": "、受け取ります ", + "ko": ", 수신 ", + "de": ", empfangen ", + "fr": ", recevoir ", + "es": ", recibir ", + "pt-BR": ", receba ", + "ru": ", получить " + }, + ",点击重试": { + "zh-Hans": ",点击重试", + "en": ", click Retry", + "zh-Hant": ",點選重試", + "ja": "、「再試行」をクリックします", + "ko": ", 재시도를 클릭하세요.", + "de": ", klicken Sie auf Wiederholen", + "fr": ", cliquez sur Réessayer", + "es": ", haga clic en Reintentar", + "pt-BR": ", clique em Tentar novamente", + "ru": "нажмите «Повторить»." + }, + ":同步键鼠到所有已连接设备": { + "zh-Hans": ":同步键鼠到所有已连接设备", + "en": ": mirror input to all connected devices", + "ru": ": ввод на всех подключённых устройствах", + "zh-Hant": ":同步鍵鼠到所有已連線裝置", + "ja": ": 接続されているすべてのデバイスへのミラー入力", + "ko": ": 연결된 모든 장치에 대한 미러 입력", + "de": ": Eingang auf alle angeschlossenen Geräte spiegeln", + "fr": ": entrée miroir sur tous les appareils connectés", + "es": ": entrada espejo para todos los dispositivos conectados", + "pt-BR": ": entrada espelhada para todos os dispositivos conectados" + }, + "请在 {0} 秒后重试": { + "zh-Hans": "请在 {0} 秒后重试", + "en": "Try again in {0} s", + "ru": "Повторите через {0} с", + "zh-Hant": "請在 {0} 秒後重試", + "ja": "{0} 秒後に再試行してください", + "ko": "{0}초 후 다시 시도하세요", + "de": "In {0} s erneut versuchen", + "fr": "Réessayez dans {0} s", + "es": "Reintentar en {0} s", + "pt-BR": "Tente novamente em {0} s" + }, + "{0} 条未读": { + "zh-Hans": "{0} 条未读", + "en": "{0} unread items", + "zh-Hant": "{0} 條未讀", + "ja": "{0}の未読アイテム", + "ko": "{0}읽지 않은 항목", + "de": "{0} ungelesene Elemente", + "fr": "Éléments non lus {0}", + "es": "{0} elementos no leídos", + "pt-BR": "Itens não lidos {0}", + "ru": "{0} непрочитанные элементы" + }, + "共 {0} 条 · {1} 条未读": { + "zh-Hans": "共 {0} 条 · {1} 条未读", + "en": "Total {0} items ·{1} unread items", + "zh-Hant": "共 {0} 條 · {1} 條未讀", + "ja": "合計{0}個のアイテム ·{1}個の未読アイテム", + "ko": "총{0}항목 ·{1}읽지 않은 항목", + "de": "Insgesamt {0} Artikel ·{1} ungelesene Artikel", + "fr": "Total des éléments {0}· Éléments non lus {1}", + "es": "Total de elementos {0}· Elementos no leídos {1}", + "pt-BR": "Total de itens {0}· Itens não lidos {1}", + "ru": "Всего элементов {0}· Непрочитанные элементы {1}" + }, + "新版本可用:v{0}": { + "zh-Hans": "新版本可用:v{0}", + "en": "New version available: v{0}", + "zh-Hant": "新版本可用:v{0}", + "ja": "利用可能な新しいバージョン: v{0}", + "ko": "새 버전 사용 가능: v{0}", + "de": "Neue Version verfügbar: v{0}", + "fr": "Nouvelle version disponible : v{0}", + "es": "Nueva versión disponible: v{0}", + "pt-BR": "Nova versão disponível: v{0}", + "ru": "Доступна новая версия: v{0}" + }, + "{0},接收 {1},发送 {2},丢包率 {3}": { + "zh-Hans": "{0},接收 {1},发送 {2},丢包率 {3}", + "en": "{0}, receiving {1}, sending {2}, packet loss rate {3}", + "zh-Hant": "{0},接收 {1},傳送 {2},丟包率 {3}", + "ja": "{0}、受信{1}、送信{2}、パケットロス率{3}", + "ko": "{0}, 수신{1}, 송신{2}, 패킷 손실률{3}", + "de": "{0}, Empfangen von {1}, Senden von {2}, Paketverlustrate {3}", + "fr": "{0}, réception de {1}, envoi de {2}, taux de perte de paquets {3}", + "es": "{0}, recepción de {1}, envío de {2}, tasa de pérdida de paquetes {3}", + "pt-BR": "{0}, recebendo {1}, enviando {2}, taxa de perda de pacotes {3}", + "ru": "{0}, прием {1}, отправка {2}, скорость потери пакетов {3}" + }, + "远程控制连接中,保留连接以确认或取消关机。": { + "zh-Hans": "远程控制连接中,保留连接以确认或取消关机。", + "en": "Remote session active. Keeping the connection available to confirm or cancel shutdown.", + "ru": "Удалённый сеанс активен. Соединение сохранено для подтверждения или отмены выключения.", + "zh-Hant": "遠端控制連線中,保留連線以確認或取消關機。", + "ja": "リモート接続中です。シャットダウンの確認または取り消しのため、接続を維持しています。", + "ko": "원격 세션이 활성화되어 있습니다. 종료 확인 또는 취소를 위해 연결을 유지합니다.", + "de": "Remotesitzung aktiv. Die Verbindung bleibt zum Bestätigen oder Abbrechen des Herunterfahrens bestehen.", + "fr": "Session distante active. La connexion reste disponible pour confirmer ou annuler l’arrêt.", + "es": "Sesión remota activa. Se mantiene la conexión para confirmar o cancelar el apagado.", + "pt-BR": "Sessão remota ativa. A conexão é mantida para confirmar ou cancelar o desligamento." + } + }, + "desktop": { + "window_minimize": "最小化", + "window_maximize": "最大化", + "window_restore": "还原窗口", + "window_close": "关闭窗口", + "save": "保存", + "copyright_notice": "© 2026 JUNKUN DI。保留所有权利。", + "license_notice": "依据 GNU GPL v3 许可发布。", + "messages": "消息", + "message_unread": "未读", + "message_read": "已读", + "message_read_all": "全部已读", + "message_empty": "暂无公告", + "message_select": "选择公告查看详情", + "message_loading": "正在加载…", + "message_read_save_error": "无法保存本地阅读状态,请重试。", + "message_close": "关闭", + "message_delete": "删除", + "message_delete_title": "删除公告", + "message_delete_confirmation": "删除这条公告?", + "message_delete_error": "无法删除这条公告,请重试。", + "console_cli_help": "Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n", + "console_title": "CrossDesk 无头控制台", + "console_log_file": "日志文件", + "console_help": "命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出", + "console_status": "状态", + "console_online": "在线", + "console_offline": "未连接服务器", + "console_id": "设备 ID", + "console_password": "连接密码", + "console_waiting": "等待分配", + "console_password_hidden": "(仅在交互终端显示)", + "console_cancelled": "已取消修改。", + "console_password_invalid": "密码必须是6位英文字母或数字,未提交修改。", + "console_password_offline": "尚未连接服务器,暂时无法修改密码。", + "console_password_prompt": "输入新密码(6位英文字母或数字;输入 cancel 取消):", + "console_quitting": "正在退出 CrossDesk……", + "console_unknown_command": "未知命令,输入 help 查看帮助。", + "console_line_too_long": "命令过长,已忽略。", + "console_random_failed": "无法生成随机密码,请重试。", + "console_password_pending": "密码修改正在处理中,请等待服务器确认。", + "console_password_stage_failed": "无法保存密码修改记录,未提交修改。请检查日志。", + "console_password_send_failed": "发送密码修改请求失败,请等待连接恢复后重试。", + "console_password_submitted": "已提交密码修改,正在等待服务器确认……", + "console_password_uncertain": "密码修改结果尚未确认,正在重新连接服务器核实。", + "console_password_rejected": "服务器未接受密码修改,原密码保持不变。详情见日志。", + "console_password_confirmed": "服务器已确认密码修改,正在重新连接。", + "console_password_recovered": "重新连接确认:新密码已生效。", + "console_password_retained": "重新连接确认:继续使用原密码。", + "console_exited": "CrossDesk 已退出。", + "console_stopped": "CrossDesk 已停止,退出码", + "console_settings_title": "设置(修改后立即保存)", + "console_settings_prompt": "输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。", + "console_settings_value": "输入新值(cancel 取消)", + "console_settings_unavailable": "设置尚未初始化,请稍后重试。", + "console_settings_invalid": "无效的选项或值,未保存。请按菜单列出的格式输入。", + "console_settings_save_failed": "保存设置失败,原设置保持不变。请检查日志。", + "console_settings_busy": "有远程会话或密码修改正在进行,暂时不能更改连接设置。", + "console_settings_saved": "已保存并生效。", + "console_settings_unchanged": "设置未改变。", + "console_settings_reconnect": "已保存,正在重新连接服务器。", + "console_settings_next_connection": "已保存,将用于后续连接。", + "console_settings_next_file": "已保存,将用于后续接收的文件。", + "console_settings_autostart": "已保存,在下次图形桌面登录时生效。", + "console_settings_daemon": "已保存,普通模式重启后生效;无头控制台仍保持前台运行。", + "console_settings_server_required": "请先设置有效的服务器地址和端口,再启用自托管。", + "console_settings_path_invalid": "请选择已存在且可写的绝对目录路径;default 使用默认目录。", + "console_settings_readonly": "该选项由系统或控制端管理,不可在此修改。", + "console_setting_language": "语言", + "console_setting_codec": "视频编码", + "console_setting_turn": "中继模式", + "console_setting_self_hosted": "自托管", + "console_setting_host": "服务器地址", + "console_setting_port": "信令端口", + "console_setting_privacy": "连接时自动开启隐私屏", + "console_setting_files": "文件保存目录", + "console_setting_autostart": "登录桌面时自启", + "console_setting_daemon": "守护进程(无头控制台中不生效)", + "save_remote_previews": "保存远程画面预览", + "unknown_platform": "未知平台", + "privacy_screen": "隐私屏", + "privacy_enable": "开启隐私屏", + "privacy_disable": "关闭隐私屏", + "privacy_on": "隐私屏:已开启", + "privacy_off": "隐私屏:已关闭", + "privacy_unsupported": "隐私屏:不可用", + "local_desktop": "本桌面", + "local_id": "本机 ID", + "local_id_copied_to_clipboard": "已复制到剪贴板", + "password": "密码", + "refresh_password": "刷新随机密码", + "password_format_invalid": "密码必须为 6 位英文字母或数字。", + "remote_desktop": "远程桌面", + "device_name": "设备名称", + "remote_id": "对端 ID", + "connect": "连接", + "recent_connections": "近期连接", + "disconnect": "断开连接", + "stream_confirm_disconnect": "断开当前连接?", + "stream_disconnect_description": "当前远程控制会话将结束。", + "select_display": "选择显示器", + "display_screen": "显示屏", + "expand_control_bar": "展开控制栏", + "collapse_control_bar": "收起控制栏", + "fullscreen": "全屏", + "show_net_traffic_stats": "显示网络状态", + "hide_net_traffic_stats": "隐藏网络状态", + "video": "视频", + "audio": "音频", + "data": "数据", + "total": "总计", + "in": "输入", + "out": "输出", + "loss_rate": "丢包率", + "exit_fullscreen": "退出全屏", + "control_mouse": "控制鼠标", + "release_mouse": "释放鼠标", + "audio_capture": "播放声音", + "mute": "静音", + "send_shortcut": "发送组合键", + "send_sas": "发送 SAS", + "lock_remote": "锁定远端", + "remote_password_box_visible": "远端密码框已出现", + "remote_lock_screen_hint": "远端处于锁屏封面,可发送 SAS", + "remote_secure_desktop_active": "远端已进入安全桌面", + "remote_service_unavailable": "远端 Windows 服务不可用", + "windows_service_setup_title": "安装 CrossDesk Service", + "windows_service_setup_message": "为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk Service。\n未安装该服务不影响 CrossDesk 正常使用,仅无法在锁屏状态下控制本机。", + "install_windows_service": "安装", + "windows_service_settings_label": "锁屏控制服务", + "windows_service_installed": "已安装", + "do_not_remind_again": "不再提醒", + "windows_service_prompt_suppressed_message": "已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。", + "installing_windows_service": "正在安装服务...", + "windows_service_install_success": "服务已安装并启动", + "windows_service_install_failed": "服务安装失败。请确认 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位于同一便携目录中,并在系统弹窗中允许管理员权限。", + "remote_unlock_requires_secure_desktop": "当前仍需要安全桌面专用采集/输入", + "settings": "设置", + "language": "语言", + "screen_capture_method": "采集方式", + "screen_capture_method_auto": "自动", + "video_settings": "画面设置", + "remote_update_title": "建议升级被控端", + "remote_update": "新版本包含功能改进和性能优化,建议将被控端升级至最新版本。", + "remote_update_dismiss": "知道了", + "video_settings_pending": "正在应用…", + "video_settings_failed": "调整失败,请重试。", + "video_settings_unavailable": "连接建立后可调整,需被控端支持。", + "video_quality": "画面质量", + "video_frame_rate": "画面采集帧率", + "video_adaptation_policy": "画面偏好", + "video_priority_frame_rate": "帧率优先", + "video_priority_quality": "画质优先", + "video_priority_balanced": "平衡", + "video_quality_high": "高", + "video_quality_medium": "中", + "video_quality_low": "低", + "video_encode_format": "视频编码格式", + "av1": "AV1", + "h264": "H.264", + "force_relay": "强制中继连接", + "self_hosted_server_config": "自托管配置", + "self_hosted_server_settings": "自托管设置", + "self_hosted_server_address": "服务器地址", + "self_hosted_server_port": "信令服务端口", + "self_hosted_address_invalid": "请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。", + "self_hosted_port_invalid": "请输入 1–65535 范围内的信令端口。", + "self_hosted_save_failed": "配置保存失败,请检查配置目录是否可写后重试。", + "ok": "确认", + "cancel": "取消", + "new_password": "请输入六位密码:", + "input_password": "请输入密码:", + "validate_password": "验证密码中...", + "reinput_password": "请重新输入密码", + "remember_password": "记住密码", + "signal_connected": "已连接服务器", + "signal_disconnected": "未连接服务器", + "signal_reconnect": "重新连接", + "signal_reconnecting": "正在重新连接...", + "signal_tls_cert_error": "证书验证失败,请重新安装自托管根证书", + "p2p_connected": "对等连接已建立", + "p2p_disconnected": "对等连接已断开", + "p2p_connecting": "正在建立对等连接...", + "p2p_gathering": "正在收集候选地址...", + "receiving_screen": "画面接收中...", + "p2p_failed": "对等连接失败", + "connection_auth_throttled": "验证尝试过于频繁,请稍后重试。", + "connection_service_busy": "认证服务繁忙,请稍后重试。", + "connection_not_authenticated": "登录状态已失效,请重新连接。", + "connection_retry_after": "请在 %d 秒后重试。", + "p2p_closed": "对等连接已关闭", + "no_such_id": "无此 ID", + "about": "关于", + "sponsorship_title": "赞助支持", + "sponsorship_message": "如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!", + "sponsorship_dismiss_hint": "关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。", + "sponsor_via_afdian": "爱发电", + "notification": "通知", + "new_version": "新版本", + "new_version_available": "新版本可用", + "check_for_updates": "检查更新", + "checking_for_updates": "正在检查更新…", + "up_to_date": "已是最新版本", + "update_check_failed": "检查失败,请稍后重试", + "release_notes": "更新内容", + "view_release_notes": "更新日志", + "version": "版本", + "release_date": "发布日期: ", + "access_website": "访问官网: ", + "update": "更新", + "install_update": "安装更新", + "manual_download": "手动下载", + "install_update_confirm": "下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?", + "update_preparing": "正在准备更新…", + "update_install_failed": "更新未完成,可重试或手动安装。", + "connection_alias": "修改名称", + "delete_connection": "删除连接", + "connect_to_this_connection": "发起连接", + "input_connection_alias": "请输入连接名称:", + "confirm_delete_connection": "确认删除此连接", + "enable_autostart": "开机自启", + "enable_daemon": "启用守护进程", + "privacy_on_connect": "被连接时开启隐私屏", + "lock_on_disconnect": "连接断开后锁屏", + "takes_effect_after_restart": "重启后生效", + "select_file": "选择文件发送", + "file_transfer_progress": "文件传输进度", + "file_sending_progress": "文件发送进度", + "file_receiving_progress": "文件接收进度", + "queued": "队列中", + "sending": "正在传输", + "receiving": "正在接收", + "completed": "已完成", + "failed": "失败", + "cancelling": "正在取消", + "cancelled": "已取消", + "controller": "控制端:", + "server_controlled": "被控中", + "server_heading": "此设备被控中", + "server_connected": "已连接", + "server_send_file": "发送文件", + "server_disconnect": "断开", + "server_disconnect_all": "全部断开", + "server_confirm_disconnect": "断开所有控制端的连接?", + "file_transfer": "文件传输:", + "connection_status": "连接状态:", + "file_transfer_save_path": "文件接收保存路径", + "default_desktop": "桌面", + "resolution": "分辨率", + "video_latency": "视频延时", + "connection_latency": "连接延时", + "connection_mode": "连接模式", + "connection_mode_direct": "直连", + "connection_mode_relay": "中继", + "transport_encryption": "加密传输", + "remote_video_encoder": "被控端编码器", + "local_video_decoder": "控制端解码器", + "transport_encryption_enabled": "已开启", + "transport_encryption_disabled": "未开启", + "online": "在线", + "offline": "离线", + "device_offline": "设备离线", + "request_permissions": "权限请求", + "screen_recording_permission": "屏幕录制权限", + "accessibility_permission": "辅助功能权限", + "permission_required_message": "该应用需要授权以下权限:", + "wayland_notice_title": "Wayland 会话提示", + "wayland_notice_subtitle": "检测到当前桌面会话使用 Wayland。", + "wayland_permission_title": "每次共享均需本机授权", + "wayland_notice_message": "受 Wayland 安全机制限制,每次启动远程桌面共享时,均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。", + "wayland_recommendation_title": "建议使用 X11(Xorg)", + "wayland_recommendation_message": "为便于持续使用远程桌面,建议注销当前桌面会话,在登录界面选择 X11(Xorg)会话后重新登录。", + "wayland_notice_acknowledge": "我知道了", + "show_main_window": "显示主界面", + "privacy_local_unlock": "允许被控时解锁隐私屏", + "privacy_screen_locked_hint": "隐私屏已开启,本机解锁已禁用", + "privacy_unlocked_title": "隐私屏已被解锁", + "privacy_unlocked_message": "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", + "privacy_unlock_confirm": "确认", + "privacy_unlock_lock": "锁定", + "privacy_screen_unlock_hint": "按下快捷键,解除隐私屏", + "exit_program": "退出", + "shutdown_reason": "远程控制连接中,保留连接以确认或取消关机。" + }, + "slint": [ + "此端口已被占用,", + "请更换端口。", + "原设置已保留。", + "无法确认此端口是否可用,", + "请重试或检查本机防火墙。", + "无法使用此端口,", + "请选择其他端口或检查系统权限。", + "未找到可用的局域网连接。", + "请连接 Wi-Fi 或网线,", + "或在主界面选择本机 IP。", + "", + "密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。", + "尝试次数过多,请等待倒计时结束后重试。", + "对方密码已更新,请使用新密码重试。", + "设备正忙,请稍后重试。", + "访问密码必须为 6 位英文字母或数字,区分大小写。", + "无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。", + "请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。", + "请输入 1–65535 之间的整数端口。", + "请点击主界面密码旁的修改按钮设置密码。", + "IP 连接数量已达上限,请先断开部分连接后重试。", + "当前网络路径不支持 IP 连接,请检查双方的局域网连接。", + "双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。", + "无法验证对方设备的身份,请确认连接地址和对方设备后重试。", + "无法建立加密连接,请检查双方网络并重试。", + "连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。", + "连接地址或监听端口已更改,请确认最新地址后重试。", + "无法准备远程会话,请稍后重试。", + "复制失败,请重试。", + "IP 连接操作失败,详情:", + "修改分组", + "未分组", + "新建分组(可选)", + "取消", + "保存", + "修改名称", + "断开", + "连接", + "待确认", + "已加密", + "未加密", + "画面", + "收发速率", + "视频延时", + "丢包 ", + "被控端编码器 ", + "控制端解码器 ", + "暂无已连接设备", + "建立连接后,网络和画面信息将在此显示", + "设备网络状态", + "关闭", + "已连接设备 ", + " 台", + "设备 / ID", + "桌面墙", + "请输入有效的 IPv4 或 IPv4:端口", + "正在连接…", + "全部设备", + "正在读取…", + "已开启", + "未开启", + "设备不支持", + "读取失败", + "切换到 ID 连接模式", + "切换到 IP 连接模式", + "IP 连接模式", + "IP 连接", + "ID 连接", + "更多", + "将 IP 和密码分享给连接方", + "将 ID 和密码分享给连接方", + "本机 IP / 端口", + "切换 IP", + "修改端口", + "切换本机 IP", + "局域网端口", + "复制 IP 和端口", + "复制本机 ID", + "点击切换本机 IP", + "点击修改端口", + "隐藏密码", + "显示密码", + "修改密码", + "输入 IP:端口,通过局域网连接", + "输入设备 ID,连接远程桌面", + "远端 IP / 端口", + "请输入 9 位设备 ID", + "不填端口时,默认使用 52888", + "暂无近期 IP 连接", + "暂无近期连接", + "该分组暂无近期连接", + "通过 IP 连接过的设备会显示在这里。", + "连接过的设备会显示在这里,方便下次快速访问。", + "切换设备分组,查看其他连接记录。", + "更多操作", + "删除记录", + "断开连接", + "IP 连接已启用", + "IP 连接准备中…", + "IP 连接未就绪", + "未知", + "分组", + "复制失败,请重试", + "IP 和端口已复制", + "从当前分组移除此设备?", + "从桌面墙移除此设备?", + "确认断开连接?", + "当前远程控制会话将结束。", + "允许远程键盘和鼠标控制", + "允许共享此 Mac 的屏幕画面", + "前往设置", + "已授权", + "请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。", + "常规", + "界面", + "视频", + "网络连接", + "启用 IP 连接", + "编辑", + "关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。", + "隐私保护", + "最后一个远程控制端断开后,自动锁定本机。", + "本地存储", + "启动与后台", + "设置开机自启动", + "当前设备不支持开机自启动。", + "无法读取系统状态。请刷新重试,或在系统设置中核对。", + "请在系统设置中添加或移除本应用,返回后会自动刷新状态。", + "设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。", + "刷新状态", + "软件许可", + "开源组件", + "源码与构建说明", + "许可与版权声明", + "查看源码", + "返回", + "以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", + "OpenFEC 告知", + "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", + "OpenFEC 许可与源码", + "本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", + "源码版本:", + "本版本源码信息暂不可用。", + "构建说明", + "项目主页", + "画面传输", + "分辨率上限", + "自动", + "原始分辨率", + "帧率", + "跟随设备设置", + "视频总带宽", + " 台已连接", + "添加", + "通过设备 ID 添加", + "从近期连接添加", + "已选 ", + "跨页 ", + "取消全选", + "全选", + "取消静音", + "静音", + "分发文件", + "选择", + "完成", + "拖动表格分隔线,同步调整所有设备大小", + "在线", + "离线", + "从桌面墙移除", + "暂无设备,退出精简模式后可添加", + "添加设备,建立你的桌面墙", + "群控中", + "正在操控", + "只读预览", + "关闭群控", + "开启群控", + ":同步键鼠到所有已连接设备", + "释放操控", + "接管操控", + "上下拖动,调整缩略图与主画面大小", + "群控中 · 所有已连接设备", + "网络状态", + "退出精简", + "精简模式", + "退出全屏", + "全屏", + "停留翻页,松开取消", + "松开鼠标交换位置", + "拖到另一台设备上", + "换位未保存,请重试", + "添加设备", + "设备 ID", + "9 位设备 ID", + "密码", + "设备连接密码", + "分组名称(可选)", + "记住密码", + "添加并连接", + "加入桌面墙后,可通过批量选择连接", + "待添加 ", + "已添加", + "加入桌面墙", + "已连接", + "未连接", + "确认断开", + "确认执行" + ], + "platforms": { + "desktop": [ + "", + " 台", + " 台已连接", + "9 位设备 ID", + "AV1", + "CrossDesk 已停止,退出码", + "CrossDesk 已退出。", + "CrossDesk 无头控制台", + "H.264", + "ID 连接", + "IP 和端口已复制", + "IP 连接", + "IP 连接准备中…", + "IP 连接已启用", + "IP 连接操作失败,详情:", + "IP 连接数量已达上限,请先断开部分连接后重试。", + "IP 连接未就绪", + "IP 连接模式", + "Linux 无头运行选项:\n --headless 自动选择已有桌面并启用控制台\n --headless-display DISPLAY 高级:指定已有显示会话\n --headless-size WIDTHxHEIGHT 新建虚拟屏幕;默认1920x1080,偶数尺寸320..8192\n --headless-session EXECUTABLE 启动桌面环境(startxfce4;none 仅启动裸屏幕)\n --no-headless 禁用自动回退\n正常启动会自动选择已有桌面,无需填写显示编号。控制台输入 settings 管理设置。\n", + "OpenFEC 告知", + "OpenFEC 许可与源码", + "Wayland 会话提示", + "© 2026 JUNKUN DI。保留所有权利。", + "上下拖动,调整缩略图与主画面大小", + "下载完成后将关闭 CrossDesk 并安装更新,当前连接和文件传输会中断。安装需要系统授权,完成后重新启动。是否继续?", + "不再提醒", + "不填端口时,默认使用 52888", + "丢包 ", + "丢包率", + "中", + "中继", + "中继模式", + "为便于持续使用远程桌面,建议注销当前桌面会话,在登录界面选择 X11(Xorg)会话后重新登录。", + "为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk Service。\n未安装该服务不影响 CrossDesk 正常使用,仅无法在锁屏状态下控制本机。", + "从当前分组移除此设备?", + "从桌面墙移除", + "从桌面墙移除此设备?", + "从近期连接添加", + "以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", + "低", + "依据 GNU GPL v3 许可发布。", + "保存", + "保存失败,请重试", + "保存设置失败,原设置保持不变。请检查日志。", + "保存远程画面预览", + "信令服务端口", + "信令端口", + "修改分组", + "修改名称", + "修改密码", + "修改端口", + "停留翻页,松开取消", + "允许共享此 Mac 的屏幕画面", + "允许被控时解锁隐私屏", + "允许远程键盘和鼠标控制", + "全屏", + "全选", + "全部已读", + "全部断开", + "全部设备", + "关于", + "关闭", + "关闭 IP 连接将隐藏模式按钮,并断开 IP 连接会话。", + "关闭后本版本不再提示,升级后再次显示。赞助入口仍在「关于」中。", + "关闭窗口", + "关闭群控", + "关闭隐私屏", + "分发文件", + "分组", + "分组名称(可选)", + "分辨率", + "分辨率上限", + "切换 IP", + "切换到 ID 连接模式", + "切换到 IP 连接模式", + "切换本机 IP", + "切换设备分组,查看其他连接记录。", + "删除", + "删除公告", + "删除记录", + "删除这条公告?", + "删除连接", + "刷新状态", + "刷新随机密码", + "前往设置", + "加入桌面墙", + "加入桌面墙后,可通过批量选择连接", + "加密传输", + "原始分辨率", + "原设置已保留。", + "双方的协议或加密能力不兼容,请将双方 CrossDesk 升级至最新版本后重试。", + "发布日期: ", + "发起连接", + "发送 SAS", + "发送密码修改请求失败,请等待连接恢复后重试。", + "发送文件", + "发送组合键", + "取消", + "取消全选", + "取消静音", + "受 Wayland 安全机制限制,每次启动远程桌面共享时,均需在本机手动授权屏幕共享与远程控制,授权后方可正常使用。", + "只读预览", + "台设备", + "启动与后台", + "启用 IP 连接", + "启用守护进程", + "命令: status 查看 ID/密码/状态;settings 设置;password 修改密码;random 随机密码;help 帮助;quit 退出", + "命令过长,已忽略。", + "在线", + "复制 IP 和端口", + "复制失败,请重试", + "复制失败,请重试。", + "复制本机 ID", + "失败", + "如果 CrossDesk 对你有帮助,欢迎赞助支持项目的持续开发、跨平台测试与日常维护。感谢你的支持!", + "守护进程(无头控制台中不生效)", + "安装", + "安装 CrossDesk Service", + "安装更新", + "完成", + "密码", + "密码不正确,或对方密码已更新。请查看对方的局域网访问密码后重试。", + "密码修改正在处理中,请等待服务器确认。", + "密码修改结果尚未确认,正在重新连接服务器核实。", + "密码必须为 6 位英文字母或数字。", + "密码必须是6位英文字母或数字,未提交修改。", + "对方密码已更新,请使用新密码重试。", + "对端 ID", + "对等连接失败", + "对等连接已关闭", + "对等连接已建立", + "对等连接已断开", + "将 ID 和密码分享给连接方", + "将 IP 和密码分享给连接方", + "尚未连接服务器,暂时无法修改密码。", + "尚未连接服务器,请稍后重试", + "尝试次数过多,请等待倒计时结束后重试。", + "局域网端口", + "屏幕录制权限", + "展开控制栏", + "已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。", + "已保存并生效。", + "已保存,在下次图形桌面登录时生效。", + "已保存,将用于后续接收的文件。", + "已保存,将用于后续连接。", + "已保存,普通模式重启后生效;无头控制台仍保持前台运行。", + "已保存,正在重新连接服务器。", + "已加密", + "已取消", + "已取消修改。", + "已复制到剪贴板", + "已安装", + "已完成", + "已开启", + "已授权", + "已提交密码修改,正在等待服务器确认……", + "已是最新版本", + "已添加", + "已读", + "已连接", + "已连接服务器", + "已连接设备 ", + "已选 ", + "帧率", + "帧率优先", + "常规", + "平衡", + "建立连接后,网络和画面信息将在此显示", + "建议使用 X11(Xorg)", + "建议升级被控端", + "开启群控", + "开启隐私屏", + "开机自启", + "开源组件", + "强制中继连接", + "当前仍需要安全桌面专用采集/输入", + "当前网络路径不支持 IP 连接,请检查双方的局域网连接。", + "当前设备不支持开机自启动。", + "当前远程控制会话将结束。", + "待添加 ", + "待确认", + "总计", + "我知道了", + "或在主界面选择本机 IP。", + "手动下载", + "拖到另一台设备上", + "拖动表格分隔线,同步调整所有设备大小", + "按下快捷键,解除隐私屏", + "换位未保存,请重试", + "接管操控", + "控制端:", + "控制端解码器", + "控制端解码器 ", + "控制鼠标", + "播放声音", + "收发速率", + "收起控制栏", + "数据", + "文件传输:", + "文件传输进度", + "文件保存目录", + "文件发送进度", + "文件接收保存路径", + "文件接收进度", + "断开", + "断开当前连接?", + "断开所有控制端的连接?", + "断开连接", + "新建分组(可选)", + "新版本", + "新版本包含功能改进和性能优化,建议将被控端升级至最新版本。", + "新版本可用", + "无效的选项或值,未保存。请按菜单列出的格式输入。", + "无此 ID", + "无法使用此端口,", + "无法保存 IP 连接设置,请重试。", + "无法保存密码修改记录,未提交修改。请检查日志。", + "无法保存断开后锁屏设置,请重试。", + "无法保存本地阅读状态,请重试。", + "无法保存连接模式,下次启动可能不会恢复当前模式。", + "无法保存隐私屏解锁设置,请重试。", + "无法准备远程会话,请稍后重试。", + "无法删除这条公告,请重试。", + "无法建立加密连接,请检查双方网络并重试。", + "无法生成随机密码,请重试。", + "无法确认此端口是否可用,", + "无法读取系统状态。请刷新重试,或在系统设置中核对。", + "无法连接,请检查对方 IP、程序是否运行,以及防火墙是否放行。", + "无法验证对方设备的身份,请确认连接地址和对方设备后重试。", + "日志文件", + "显示主界面", + "显示密码", + "显示屏", + "显示网络状态", + "暂无公告", + "暂无已连接设备", + "暂无设备,退出精简模式后可添加", + "暂无近期 IP 连接", + "暂无近期连接", + "更多", + "更多操作", + "更新", + "更新内容", + "更新日志", + "更新未完成,可重试或手动安装。", + "最后一个远程控制端断开后,自动锁定本机。", + "最大化", + "最小化", + "有远程会话或密码修改正在进行,暂时不能更改连接设置。", + "服务器地址", + "服务器已确认密码修改,正在重新连接。", + "服务器未接受密码修改,原密码保持不变。详情见日志。", + "服务安装失败。请确认 CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe 位于同一便携目录中,并在系统弹窗中允许管理员权限。", + "服务已安装并启动", + "未分组", + "未加密", + "未开启", + "未找到可用的局域网连接。", + "未知", + "未知命令,输入 help 查看帮助。", + "未知平台", + "未读", + "未连接", + "未连接服务器", + "本地存储", + "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", + "本机 ID", + "本机 IP / 端口", + "本桌面", + "本版本源码信息暂不可用。", + "本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", + "权限请求", + "松开鼠标交换位置", + "构建说明", + "查看源码", + "桌面", + "桌面墙", + "检查失败,请稍后重试", + "检查更新", + "检测到当前桌面会话使用 Wayland。", + "正在传输", + "正在准备更新…", + "正在加载…", + "正在取消", + "正在安装服务...", + "正在应用…", + "正在建立对等连接...", + "正在接收", + "正在操控", + "正在收集候选地址...", + "正在检查更新…", + "正在读取…", + "正在连接…", + "正在退出 CrossDesk……", + "正在重新连接...", + "此端口已被占用,", + "此设备被控中", + "每次共享均需本机授权", + "消息", + "添加", + "添加并连接", + "添加设备", + "添加设备,建立你的桌面墙", + "源码与构建说明", + "源码版本:", + "点击修改端口", + "点击切换本机 IP", + "爱发电", + "版本", + "状态", + "画质优先", + "画面", + "画面传输", + "画面偏好", + "画面已停留", + "画面接收中...", + "画面设置", + "画面质量", + "画面采集帧率", + "界面", + "登录桌面时自启", + "登录状态已失效,请重新连接。", + "直连", + "知道了", + "确认", + "确认删除此连接", + "确认执行", + "确认断开", + "确认断开连接?", + "离线", + "等待分配", + "等待画面", + "等待统计", + "精简模式", + "编辑", + "网络状态", + "网络连接", + "群控中", + "群控中 · 所有已连接设备", + "自动", + "自托管", + "自托管设置", + "自托管配置", + "被控中", + "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", + "被控端编码器", + "被控端编码器 ", + "被连接时开启隐私屏", + "视频", + "视频延时", + "视频总带宽", + "视频编码", + "视频编码格式", + "认证服务繁忙,请稍后重试。", + "记住密码", + "许可与版权声明", + "设备", + "设备 / ID", + "设备 ID", + "设备不支持", + "设备名称", + "设备正忙,请稍后重试。", + "设备离线", + "设备网络状态", + "设备连接密码", + "设置", + "设置 → 应用和元服务 → 应用启动管理\n\n开启:点击“添加应用”,选择 CrossDesk,然后点击“完成”。\n\n关闭:在自启动列表中找到本应用,点击“移除”。", + "设置尚未初始化,请稍后重试。", + "设置开机自启动", + "设置未改变。", + "设置(修改后立即保存)", + "访问官网: ", + "访问密码必须为 6 位英文字母或数字,区分大小写。", + "证书验证失败,请重新安装自托管根证书", + "该分组暂无近期连接", + "该应用需要授权以下权限:", + "该设备正在连接,请稍候", + "该选项由系统或控制端管理,不可在此修改。", + "语言", + "请先设置有效的服务器地址和端口,再启用自托管。", + "请在 %d 秒后重试。", + "请在 {0} 秒后重试", + "请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。", + "请在系统设置中添加或移除本应用,返回后会自动刷新状态。", + "请更换端口。", + "请点击主界面密码旁的修改按钮设置密码。", + "请输入 1–6 位英文字母或数字密码", + "请输入 1–65535 之间的整数端口。", + "请输入 1–65535 范围内的信令端口。", + "请输入 9 位设备 ID", + "请输入六位密码:", + "请输入密码:", + "请输入有效的 9 位设备 ID", + "请输入有效的 IPv4 或 IPv4:端口", + "请输入有效的 IPv4,例如 192.168.1.20;指定端口可用 IPv4:端口,端口范围 1–65535。", + "请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。", + "请输入连接名称:", + "请连接 Wi-Fi 或网线,", + "请选择其他端口或检查系统权限。", + "请选择已存在且可写的绝对目录路径;default 使用默认目录。", + "请重新输入密码", + "请重试或检查本机防火墙。", + "读取失败", + "调整失败,请重试。", + "赞助支持", + "跟随系统", + "跟随设备设置", + "跨页 ", + "软件许可", + "辅助功能权限", + "输入", + "输入 IP:端口,通过局域网连接", + "输入新值(cancel 取消)", + "输入新密码(6位英文字母或数字;输入 cancel 取消):", + "输入编号或选项名称修改;back 返回。也可使用 settings set 名称 值。", + "输入设备 ID,连接远程桌面", + "输出", + "近期连接", + "返回", + "还原窗口", + "远程控制连接中,保留连接以确认或取消关机。", + "远程桌面", + "远端 IP / 端口", + "远端 Windows 服务不可用", + "远端处于锁屏封面,可发送 SAS", + "远端密码框已出现", + "远端已进入安全桌面", + "连接", + "连接协商数据无效,请重试并确认双方 CrossDesk 版本兼容。", + "连接地址或监听端口已更改,请确认最新地址后重试。", + "连接密码", + "连接延时", + "连接建立后可调整,需被控端支持。", + "连接断开后锁屏", + "连接时自动开启隐私屏", + "连接模式", + "连接状态:", + "连接过的设备会显示在这里,方便下次快速访问。", + "退出", + "退出全屏", + "退出精简", + "选择", + "选择公告查看详情", + "选择分发文件", + "选择文件发送", + "选择显示器", + "通知", + "通过 IP 连接过的设备会显示在这里。", + "通过设备 ID 添加", + "配置保存失败,请检查配置目录是否可写后重试。", + "采集方式", + "释放操控", + "释放鼠标", + "重启后生效", + "重新连接", + "重新连接确认:新密码已生效。", + "重新连接确认:继续使用原密码。", + "锁定", + "锁定远端", + "锁屏控制服务", + "队列中", + "隐私保护", + "隐私屏", + "隐私屏已开启,本机解锁已禁用", + "隐私屏已被解锁", + "隐私屏:不可用", + "隐私屏:已关闭", + "隐私屏:已开启", + "隐藏密码", + "隐藏网络状态", + "需要密码", + "静音", + "音频", + "项目主页", + "验证密码中...", + "验证尝试过于频繁,请稍后重试。", + "高", + "(仅在交互终端显示)", + ":同步键鼠到所有已连接设备" + ], + "android": [ + " · 已完成", + " 传输失败", + " 台设备", + " 条 · ", + " 条未读", + "CrossDesk 远程连接", + "GNU GPL 第 3 版", + "OpenFEC 告知", + "OpenFEC 许可与源码", + "P2P 直连", + "SRTP 已启用", + "TURN 中继", + "{0} 传输失败", + "{0} 台设备", + "{0} 条未读", + "{0},接收 {1},发送 {2},丢包率 {3}", + "● 已连接", + "下拉刷新", + "丢包率", + "中", + "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。", + "低", + "使用自定义服务器", + "保存密码", + "保存收到的文件", + "保存远程画面预览", + "保存远程画面预览?", + "信令连接中断,请重新连接", + "公告加载失败,请重试。", + "公告详情", + "共 ", + "共 {0} 条 · {1} 条未读", + "关于", + "关于 CrossDesk", + "关于,有新版本", + "关闭", + "关闭控制栏", + "关闭隐私屏", + "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。", + "分辨率", + "删除", + "删除公告", + "删除记录", + "删除这条公告?", + "刷新公告", + "剪贴板", + "加载中…", + "加载更多", + "升级提示", + "原生连接初始化失败", + "发送", + "发送 ", + "发送后,在远程键盘中点击“粘贴”。接收的远端文本可手动复制到本机。", + "发送文件", + "发送文本", + "取消", + "取消连接", + "各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。", + "合计", + "同意并继续", + "后台保持连接,点按返回远程桌面", + "后台保活未能启动,请保持应用在前台", + "后台保活未能启动,请保持应用在前台后重新连接", + "后台连接已结束,请重新连接", + "后台连接服务已停止,请重新连接", + "后续连接仍会保存新的预览图。", + "在线", + "填写主机名或 IPv4 地址,不含协议和路径", + "声音", + "复制远端文本", + "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。", + "媒体加密", + "字母数字", + "安全存储或证书初始化失败,请重试或清除应用数据", + "完成", + "完成隐私授权后可检查更新", + "完成隐私授权后登记本机身份", + "密码保存失败,本次连接仍可使用", + "密码将加密保存在本机 Android Keystore 中", + "对端 ID", + "对端 ID ", + "对端 ID {0}", + "将删除本机保存的所有远程预览图,保留连接记录和密码。", + "屏幕方向", + "展开远程控制菜单", + "已从通知断开远程连接", + "已保存密码", + "已保存密码无法读取,请重新输入", + "已保存的密码未能保留,请重新输入一次", + "已发送 Ctrl+Alt+Del", + "已启用后台保活,切换应用可继续保持连接", + "已启用后台保活,可从连接通知返回或断开", + "已授权", + "已读", + "已连接 ", + "已连接服务器", + "帧率", + "帧率优先", + "平衡", + "应用中的许可文件缺失或损坏,请重新安装应用。", + "开发版本包含尚未发布的修改,以下链接为基础版本源码。", + "开启保存", + "开启隐私屏", + "开源组件", + "开源软件权利说明", + "当前已是最新版本", + "当前远端不支持直接输入此文本,请使用支持文本输入的被控端版本,或通过剪贴板发送", + "成功连接后,这里会显示最近的远程设备。", + "我已阅读并同意《隐私政策》", + "所选文件(无法读取或空间不足)", + "找不到该设备 ID", + "指令发送失败,请重试", + "指令已发送,等待电脑确认…", + "授权状态", + "接收", + "接收 ", + "控制端解码器", + "撤回", + "撤回后将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。", + "撤回联网授权", + "撤回联网授权?", + "收起远程控制菜单", + "收起键盘", + "收起鼠标", + "数据", + "文件保存失败,请重试", + "文件已保存", + "文件选择已超时,会话已结束", + "文本超过 128 KB", + "断开", + "断开后将返回首页", + "断开远程连接?", + "断开连接", + "新版本", + "新版本可用:v", + "新版本可用:v{0}", + "无未读公告", + "无法保存本地阅读状态,请重试。", + "无法删除这条公告,请重试。", + "无法发起远程连接", + "无法读取开源许可", + "显示器", + "显示密码", + "暂不同意", + "暂无公告", + "最近连接", + "服务器", + "服务器 TLS 证书校验失败", + "服务器地址", + "服务器登录失败,请检查服务器地址和网络", + "服务器端口", + "服务器连接超时,请检查服务器地址和网络", + "未启用", + "未找到可打开链接的浏览器", + "未授权", + "未读", + "未连接服务器 · 点击重试", + "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", + "本机 ID ", + "本机 ID {0}", + "本版本源码与构建说明", + "本版本源码信息暂不可用。", + "松开刷新", + "构建说明", + "构建配方与项目补丁", + "查看源码", + "检查失败,请稍后重试", + "检查更新", + "正在关闭隐私屏…", + "正在建立安全连接…", + "正在开启隐私屏…", + "正在检查更新…", + "正在清除…", + "正在获取本机 ID…", + "正在读取所选文件…", + "正在连接", + "正在连接信令服务器…", + "正在连接服务器…", + "正在重连服务器…", + "此设备没有可用的文件选择器", + "清除", + "清除预览图", + "清除预览图?", + "源码与构建说明", + "源码版本", + "版本", + "版权与许可声明", + "电脑键盘", + "画质优先", + "画面偏好", + "画面延时", + "画面设置", + "画面质量", + "画面采集帧率", + "相对位置", + "相对鼠标", + "知道了", + "确定", + "确认", + "确认连接", + "离线", + "空格", + "端口范围为 1–65535", + "符号功能", + "等待电脑返回隐私屏状态;旧版电脑端可能不支持", + "等待远端屏幕信息", + "等待远端画面…", + "等待隐私授权", + "系统键盘", + "绝对位置", + "绝对鼠标", + "网络状态", + "自定义", + "虚拟鼠标", + "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", + "被控端版本过低,请升级到最新版本。", + "被控端编码器", + "要发送到远端的文本", + "视频", + "许可", + "许可与版权声明", + "许可与版权声明可离线查阅。", + "设备身份保存失败,请检查安全存储", + "设备身份及选择保存的访问密码使用 Android Keystore 加密。连接记录仅保存在本机,不纳入设备备份。剪贴板内容在结束会话时清除。离开应用后通过画中画或连接通知保持会话,可在应用或通知中断开。", + "设置", + "设置,有新版本", + "访问密码", + "访问密码错误,请重新输入", + "证书校验失败 · 点击重试", + "请先完成联网授权", + "请在远端启用 CrossDesk 系统服务后重试", + "请求超时,尚未确认电脑的隐私屏状态", + "请等待当前文件发送完成", + "请输入 1–65535 范围内的端口", + "请输入 9 位设备 ID", + "请输入有效访问密码", + "调整失败,请重试。", + "软件许可", + "返回", + "返回控制栏", + "还没有连接记录", + "这条公告已更新或删除,请返回公告列表查看。", + "远程任务已关闭", + "远程桌面", + "远程桌面触控区域", + "远程桌面:轻触点击,拖动移动,长按右键,双指捏合缩放,放大后双指拖动画面,原始比例下双指上下滑动滚动", + "远程电脑", + "远程窗口已关闭,或后台保活未能启动,会话已结束", + "远程连接", + "远端密码错误", + "远端已关闭连接", + "远端当前不可用", + "远端访问密码已失效,请重新连接", + "连接", + "连接 ", + "连接失败", + "连接失败 · 点击重试", + "连接已断开", + "连接已结束", + "连接延时(RTT)", + "连接建立后可调整,需被控端支持。", + "连接建立后锁定横屏", + "连接提示", + "连接方式", + "连接服务器", + "连接服务器后可获取最新公告。", + "连接超时,请检查设备 ID、服务器及远端在线状态", + "连接远程桌面", + "退格", + "通知公告", + "部分预览图未能清除,请重试。", + "重试", + "重试保存阅读状态", + "锁定", + "键盘", + "阅读并授权", + "隐私", + "隐私与授权", + "隐私屏", + "隐私屏已关闭", + "隐私屏已开启", + "隐私屏已被解锁", + "隐私屏异常", + "隐私屏暂不可用", + "隐私屏状态已过期,等待电脑确认", + "隐私屏状态待确认", + "隐私政策", + "隐私政策暂时无法读取,请拒绝联网并重新安装应用。", + "静音", + "音频", + "项目主页", + "预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。", + "高", + "默认", + "默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。", + "鼠标右键,按住并拖动,松开结束拖拽", + "鼠标左键,按住并拖动,松开结束拖拽", + "鼠标控制", + "鼠标滚轮,上下滑动,可滑出按键范围", + ",丢包率 ", + ",发送 ", + ",已保存密码", + ",接收 ", + ",点击重试" + ], + "ios": [ + "%1$@ 传输失败", + "%1$@ 台设备", + "%1$@ 条未读", + "%1$@键盘页", + "%1$@,接收 %2$@,发送 %3$@,丢包率 %4$@", + "CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。", + "Ctrl+Alt+Del 需要远端启用 Windows 系统服务", + "GNU GPL 第 3 版", + "OpenFEC 告知", + "OpenFEC 许可与源码", + "P2P 直连", + "P2P/TURN 建链失败,请检查网络后重试。", + "SRTP 已启用", + "TLS 证书校验失败", + "TURN 中继", + "上下滑动,可滑出按键范围", + "丢包率", + "中", + "优先保持画面流畅,带宽或编码压力较大时会更积极地降低分辨率。", + "低", + "使用自定义服务器", + "保存密码", + "保存远程画面预览", + "保存远程画面预览?", + "信令服务器已关闭连接", + "信令服务重连中", + "信令连接失败", + "信令连接已关闭", + "偏好模式", + "像触控板一样滑动光标,点击时操作当前光标位置。", + "公告加载失败,请重试。", + "公告详情", + "共 %1$@ 条 · %2$@ 条未读", + "关于", + "关于 CrossDesk", + "关于,有新版本", + "关闭", + "关闭控制栏", + "关闭隐私屏", + "兼顾清晰度和流畅度,只在持续压力下逐步降低分辨率。", + "分辨率", + "切换到电脑键盘", + "切换到系统键盘", + "删除", + "删除公告", + "删除记录", + "删除这条公告?", + "刷新公告", + "剪贴板", + "剪贴板中没有文本", + "剪贴板文本超过 128 KiB", + "加载中…", + "加载更多", + "升级提示", + "单次输入最多 16 KiB,且不能包含空字符", + "发送", + "发送文件", + "取消", + "取消连接", + "各组件遵循所列开源许可证,其授予的权利不受本应用普通使用条款限制。查看源码需要网络连接。", + "合计", + "同意并继续", + "回车", + "在线", + "地址", + "填写服务器地址", + "填写端口", + "声音", + "失败", + "始终保持较高分辨率,带宽不足时通过降低帧率来保证画面清晰度。", + "媒体加密", + "字母数字", + "完成", + "完成隐私授权后可检查更新", + "完成隐私授权后登记本机身份", + "密码将安全保存在本机 Keychain 中", + "对端 ID", + "对端 ID %1$@", + "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和接收文件会保留,已有服务端数据不会删除。您可随时重新授权。", + "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。", + "将删除本机保存的所有远程预览图,保留连接记录、密码和接收的文件。后续连接仍会保存新的预览图。", + "屏幕方向", + "展开远程控制菜单", + "已保存密码", + "已勾选", + "已发送 Ctrl+Alt+Del", + "已发送本机剪贴板", + "已授权", + "已接收 %1$@", + "已接收远端剪贴板", + "已读", + "已连接", + "已连接服务器", + "帧率", + "帧率优先", + "平衡", + "应用中的许可文件缺失或损坏,请重新安装应用。", + "开发版本包含尚未发布的修改,以下链接为基础版本源码。", + "开启保存", + "开启隐私屏", + "开源组件", + "开源软件权利说明", + "当前已是最新版本", + "成功连接后,这里会显示远端桌面的缩略图。", + "我已阅读并同意《隐私政策》", + "我已阅读并同意隐私政策", + "打开隐私政策", + "指令发送失败,请重试", + "指令已发送,等待电脑确认…", + "按住并拖动,可滑出按键范围,松开结束拖拽", + "授权后可使用远程连接。", + "授权状态", + "接收", + "控制模式", + "控制端解码器", + "撤回授权", + "撤回隐私授权", + "收起电脑键盘", + "收起系统键盘", + "收起远程控制菜单", + "收起鼠标", + "数据", + "断开后将返回首页", + "断开远程连接?", + "断开连接", + "新版本", + "新版本可用:v%1$@", + "无效", + "无未读公告", + "无法", + "无法保存本地阅读状态,请重试。", + "无法删除这条公告,请重试。", + "无法访问本机登录凭据,请解锁后重试", + "无法读取开源许可", + "无法读取所选文件,请重试", + "是否撤回隐私授权?", + "显示器", + "显示器 %1$@", + "显示器 1", + "显示密码", + "暂不同意", + "暂无公告", + "最近连接", + "服务器", + "服务器地址", + "服务器端口", + "服务器配置无效", + "未勾选", + "未启用", + "未授权", + "未知", + "未知信令状态", + "未知连接状态", + "未读", + "未连接", + "本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", + "本机 ID %1$@", + "本机登录凭据暂时无法安全存取。请解锁设备后,在设置中点击“应用”重试。", + "本版本源码与构建说明", + "本版本源码信息暂不可用。", + "构建说明", + "构建配方与项目补丁", + "查看源码", + "检查失败,请稍后重试", + "检查更新", + "正在关闭隐私屏…", + "正在准备连接…", + "正在发送 %1$@", + "正在发送 Ctrl+Alt+Del…", + "正在取回远程画面…", + "正在建立远程连接", + "正在开启隐私屏…", + "正在收集 ICE 候选", + "正在检查更新…", + "正在清除…", + "正在确认设备状态…", + "正在获取本机 ID…", + "正在连接", + "正在连接信令服务", + "清除", + "清除预览图", + "清除预览图?", + "源码与构建说明", + "源码版本", + "版本", + "版权与许可声明", + "电脑键盘", + "画中画未能开启,请保持应用在前台后重试。", + "画质优先", + "画面偏好", + "画面延时", + "画面设置", + "画面质量", + "画面采集帧率", + "相对位置", + "相对鼠标", + "知道了", + "确定", + "确认", + "离线", + "空格", + "端口", + "符号功能", + "等待电脑返回隐私屏状态;旧版电脑端可能不支持", + "等待连接", + "等待隐私授权", + "系统键盘", + "绝对位置", + "绝对鼠标", + "网络状态", + "网络连接已中断,请重新连接。", + "自定义", + "虚拟鼠标", + "被控端不支持直接输入中文,请更新 macOS 被控端;也可先复制文字,通过远控菜单的剪贴板发送后粘贴", + "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", + "被控端平台:%1$@", + "被控端版本过低,请升级到最新版本。", + "被控端编码器", + "视频", + "视频 %1$@×%2$@ · %3$@ 帧", + "触摸位置直接对应远端屏幕位置,适合快速定位。", + "许可", + "许可与版权声明", + "许可与版权声明可离线查阅。", + "设备离线", + "设置", + "设置,有新版本", + "访问密码", + "访问密码错误,请重新输入。", + "请求超时,尚未确认电脑的隐私屏状态", + "请输入 1–65535 范围内的端口,或关闭“使用自定义服务器”。", + "请输入服务器地址,或关闭“使用自定义服务器”。", + "请输入远程设备 ID", + "调整失败,请重试。", + "软件许可", + "返回控制栏", + "还没有连接记录", + "这条公告已更新或删除,请返回公告列表查看。", + "远程桌面", + "远程设备 ID 不存在,请检查设备 ID。", + "远程设备当前不可用,请稍后重试。", + "远程连接已结束。", + "连接", + "连接延时(RTT)", + "连接建立后可调整,需被控端支持。", + "连接建立后锁定横屏", + "连接提示", + "连接方式", + "连接远程桌面", + "退格", + "通知公告", + "部分预览图未能清除,请重试。", + "重试", + "重试保存阅读状态", + "锁定", + "键盘", + "键盘操作", + "阅读并授权", + "隐私", + "隐私与授权", + "隐私屏", + "隐私屏已关闭", + "隐私屏已开启", + "隐私屏已被解锁", + "隐私屏异常", + "隐私屏暂不可用", + "隐私屏状态已过期,等待电脑确认", + "隐私屏状态待确认", + "隐私政策", + "隐私政策暂时无法读取,请拒绝联网并重新安装应用。", + "隐藏密码", + "静音", + "音频", + "项目主页", + "预览可能包含远程电脑上的个人或工作信息。开启后,每次连接会自动将一张画面保存在本机并显示在最近连接中。你可以随时关闭并清除。", + "高", + "默认", + "默认关闭。开启后,iPhone 连接时进入并保持横屏;关闭时跟随设备方向。iPad 不受影响。", + "鼠标右键", + "鼠标左键", + "鼠标控制", + "鼠标滚轮" + ], + "harmony": [ + "OpenFEC 告知", + "OpenFEC 提供前向纠错能力,遵循 CeCILL-C 1.0 许可。其许可规定了有限保证及责任限制,请阅读组件详情。", + "P2P 直连", + "SRTP 已启用", + "TURN 中继", + "{0} 传输失败", + "{0} 台设备", + "丢包率", + "中", + "中文等文本请通过剪贴板发送,再点击粘贴", + "低", + "使用自定义服务器", + "保存密码", + "保存收到的文件", + "保存远程画面预览", + "保存远程画面预览?", + "全选", + "公告详情", + "关于", + "关于 CrossDesk", + "关闭", + "关闭控制栏", + "分辨率", + "删除", + "删除公告", + "删除公告?", + "删除记录", + "删除记录?", + "刷新公告", + "剪贴板", + "加载失败,点击重试", + "加载更多", + "升级提示", + "原生通信库不可用,请重新构建并安装", + "发现新版本 {0}", + "发送", + "发送 {0} · 0%", + "发送文件", + "发送文本", + "发送文本后,点击“粘贴到远端”使用。", + "取消", + "取消连接", + "各组件遵循所列开源许可证。许可与版权声明可离线查阅,查看源码需要网络连接。", + "合计", + "同意并继续", + "同意联网后可查看公告", + "同时删除该设备保存的密码和预览。", + "在线", + "声音", + "复制", + "复制失败,请重试", + "复制远端文本", + "媒体加密", + "安全存储不可用,请解锁设备后重试", + "完成", + "密码保存失败,本次连接仍可使用", + "密码将加密保存在此设备上", + "对端 ID", + "对端 ID {0}", + "将停止远程连接、关闭画面预览保存并清除已有预览。连接记录和密码会保留,重新连接前需再次授权。", + "将清除此设备保存的所有远程画面预览,保留连接记录和访问密码。", + "尚未收到远端文本", + "屏幕方向", + "已保存密码", + "已保存密码无法读取,请重新输入", + "已发送,请在远端粘贴", + "已复制远端文本", + "已授权", + "已是最新版本", + "已清除预览", + "已读或删除状态保存失败,请重试", + "已连接", + "帧率", + "帧率优先", + "平衡", + "开发版本包含尚未发布的修改,以下链接为基础版本源码。", + "开启", + "开源组件", + "开源软件权利说明", + "成功连接后,这里会显示最近的远程设备。", + "我已阅读并同意《隐私政策》", + "我已阅读并同意隐私政策", + "找不到该设备 ID", + "拖动键盘", + "指令发送失败,请重试", + "指令已发送,等待电脑确认…", + "授权状态", + "接收", + "控制端解码器", + "撤回授权", + "撤回联网授权", + "撤回联网授权?", + "操作失败", + "收起键盘", + "收起鼠标", + "数据", + "文件保存失败,请重试", + "文件已保存", + "文本超过 128 KB", + "断开后将返回首页。", + "断开远程连接?", + "断开连接", + "新版本 ●", + "新版本可用", + "无法保存联网授权,请重试", + "无法删除已保存的凭据", + "无法打开网页", + "无法读取所选文件或存储空间不足", + "无法读取文档", + "显示器", + "显示密码", + "暂不同意", + "暂无公告", + "暂无鸿蒙版本信息,请稍后重试", + "最近连接", + "服务器", + "服务器地址", + "服务器已断开", + "服务器端口", + "服务器证书校验失败", + "未启用", + "未授权", + "未连接", + "本机 ID {0}", + "本版本源码与构建说明", + "构建文档", + "查看源码", + "查看联网说明", + "检查失败,请稍后重试", + "检查更新", + "正在关闭隐私屏…", + "正在建立安全连接…", + "正在开启隐私屏…", + "正在检查…", + "正在连接", + "正在连接…", + "正在重连…", + "此公告将从列表中移除。", + "清除", + "清除预览图", + "清除预览图?", + "源码与构建说明", + "源码版本", + "滚轮,上下滑动", + "版本", + "电脑", + "画中画已关闭", + "画质优先", + "画面偏好", + "画面延时", + "画面设置", + "画面质量", + "画面采集帧率", + "相对位置", + "相对鼠标", + "知道了", + "确认", + "离线", + "空格", + "等待电脑端确认…", + "等待电脑返回隐私屏状态;旧版电脑端可能不支持", + "等待远端屏幕信息", + "等待远端画面…", + "粘贴", + "粘贴到远端", + "系统已停止后台会话", + "系统未允许后台会话,连接已断开", + "绝对位置", + "绝对鼠标", + "网络状态", + "自定义", + "虚拟鼠标", + "被控端已通过组合键解除隐私屏。点击“锁定”将重新开启隐私屏,并禁止本机使用组合键解锁。", + "被控端版本过低,请升级到最新版本。", + "被控端编码器", + "要发送到远端的文本", + "视频", + "记录或密码删除失败,请重试", + "许可", + "许可与版权声明", + "许可与版权声明可离线查阅。", + "设备身份保存失败,请检查安全存储", + "设备身份及选择保存的访问密码加密保存在本机。画面预览默认关闭,开启后从下一次连接起保存。剪贴板内容在结束会话时清除。离开应用后通过画中画或后台任务保持会话,可随时返回应用断开。", + "设置", + "访问密码", + "访问密码错误", + "访问密码错误,请重新输入", + "请在远端启用 CrossDesk 系统服务后重试", + "请求超时,尚未确认电脑的隐私屏状态", + "请等待当前文件发送完成", + "请输入 9 位设备 ID", + "请输入有效的服务器地址和端口", + "请输入有效的访问密码", + "调整失败,请重试。", + "软件许可", + "返回", + "返回控制栏", + "还没有连接记录", + "远程控制菜单,拖动可移动", + "远程桌面", + "远程桌面:轻触点击、长按右键、双指捏合缩放、放大后双指拖动画面,原始比例下双指滚动", + "远程电脑", + "远端已关闭连接", + "远端当前不可用", + "连接", + "连接失败", + "连接已断开", + "连接已结束", + "连接延时(RTT)", + "连接建立后可调整,需被控端支持。", + "连接建立后锁定横屏", + "连接提示", + "连接方式", + "连接远程桌面", + "通知公告", + "锁定", + "键盘", + "阅读并授权", + "隐私", + "隐私与授权", + "隐私屏", + "隐私屏已关闭", + "隐私屏已开启", + "隐私屏已被解锁", + "隐私屏异常", + "隐私屏暂不可用", + "隐私屏状态已过期,等待电脑确认", + "隐私屏状态待确认", + "隐私政策", + "隐私政策无法读取,请重新安装应用", + "隐藏密码", + "静音", + "音频", + "预览可能包含远程设备上的敏感内容。仅保存在本机,从下一次连接起生效,可随时关闭并清除。", + "高", + "默认", + "默认关闭。开启后,手机连接时进入并保持横屏;关闭时跟随设备方向。平板和多窗口不受影响。", + "鼠标右键,按住拖动", + "鼠标左键,按住拖动", + "鼠标控制" + ] + } +} diff --git a/localization/generate.py b/localization/generate.py new file mode 100644 index 00000000..365a4997 --- /dev/null +++ b/localization/generate.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""Generate offline UI resources from catalog.json. No network access required.""" +import argparse +from collections import Counter +import hashlib +import json +import re +import sys +from pathlib import Path +from xml.sax.saxutils import escape + +ROOT = Path(__file__).resolve().parents[1] +CATALOG = Path(__file__).with_name('catalog.json') + +def quoted(value): + return json.dumps(value, ensure_ascii=False) + +def resource_id(key): + return 'text_' + hashlib.sha256(key.encode()).hexdigest()[:16] + +def render(data): + languages = data['languages'] + strings = data['strings'] + def translated(key, language): + return strings[key].get(language, strings[key].get('en', key)) + outputs = {} + header = '''/* + * @Author: DI JUNKUN + * @Date: 2024-05-29 + * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _LOCALIZATION_DATA_H_ +#define _LOCALIZATION_DATA_H_ + +// Generated by localization/generate.py. Edit localization/catalog.json. +namespace crossdesk { +namespace localization { +namespace detail { +struct TranslationRow { const char* key; const char* text[10]; }; +inline constexpr TranslationRow kTranslationRows[] = { +''' + for key in data['platforms']['desktop']: + header += ' {' + quoted(key) + ', {' + ', '.join(quoted(translated(key, lang)) for lang in languages) + '}},\n' + header += '};\n\nstruct NamedTranslation { const char* name; const char* literal; };\ninline constexpr NamedTranslation kNamedTranslations[] = {\n' + for name,key in data['desktop'].items(): + header += ' {' + quoted(name) + ', ' + quoted(key) + '},\n' + header += '};\ninline constexpr const char* kSlintLiterals[] = {\n' + header += ''.join(' ' + quoted(key) + ',\n' for key in data['slint']) + header += '};\n} // namespace detail\n\n#define CROSSDESK_LOCALIZATION_ALL(X) \\\n' + header += ' \\\n'.join(' X(' + name + ')' for name in data['desktop']) + header += '\n\n} // namespace localization\n} // namespace crossdesk\n\n#endif\n' + outputs['apps/desktop/src/gui/assets/localization/localization_data.h'] = header + # Android resources participate in native locale matching and per-app language settings. + qualifiers = {'en':'values','zh-Hans':'values-b+zh+Hans','zh-Hant':'values-b+zh+Hant','pt-BR':'values-pt'} + for language in languages: + text = '\n\n\n' + for key in data['platforms']['android']: + value = translated(key,language).replace('\\','\\\\').replace('\n','\\n').replace('\t','\\t').replace('"','\\"').replace("'","\\'") + text += ' "'+escape(value)+'"\n' + text += '\n' + qualifier = qualifiers.get(language,'values-'+language) + outputs['apps/android/app/src/main/res/'+qualifier+'/strings.xml'] = text + android = '''package cn.crossdesk.mobile; + +import java.util.HashMap; +import java.util.Map; + +/** Generated resource keys; text and locale selection live in Android resources. */ +final class LocalizationKeys { + static final Map IDS = new HashMap<>(); + static { +''' + android += ''.join(' IDS.put('+quoted(key)+', R.string.'+resource_id(key)+');\n' for key in data['platforms']['android']) + android += ' }\n private LocalizationKeys() {}\n}\n' + outputs['apps/android/app/src/main/java/cn/crossdesk/mobile/LocalizationKeys.java'] = android + locales = ['en','zh-Hans','zh-Hant','ja','ko','de','fr','es','pt-BR','ru'] + outputs['apps/android/app/src/main/res/xml/locales_config.xml'] = '\n\n' + ''.join(' \n' for code in locales) + '\n' + # iOS uses Foundation/SwiftUI localization directly, including strings from models. + permission = 'CrossDesk 使用局域网发现并建立原生 P2P 远程控制连接。' + for language in languages: + directory = 'apps/ios/CrossDeskMobile/Resources/'+language+'.lproj/' + outputs[directory+'Localizable.strings'] = '// Generated by localization/generate.py.\n' + ''.join(quoted(key)+' = '+quoted(translated(key,language))+';\n' for key in data['platforms']['ios']) + outputs[directory+'InfoPlist.strings'] = '"NSLocalNetworkUsageDescription" = '+quoted(translated(permission,language))+';\n' + # A generic Portuguese fallback also serves Portuguese locales outside Brazil. + for name in ['Localizable.strings','InfoPlist.strings']: + outputs['apps/ios/CrossDeskMobile/Resources/pt.lproj/'+name] = outputs['apps/ios/CrossDeskMobile/Resources/pt-BR.lproj/'+name] + # Harmony keeps lookup pure; EntryAbility injects the system locale provider. + harmony = '// Generated by localization/generate.py.\nexport const translations: Record = {\n' + for key in data['platforms']['harmony']: + harmony += ' '+quoted(key)+': ['+', '.join(quoted(translated(key,lang)) for lang in languages)+'],\n' + harmony += '};\n' + outputs['apps/harmony/entry/src/main/ets/mobile/LocalizationData.ets'] = harmony + return outputs + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--check',action='store_true',help='check catalog completeness and generated resources without writing') + args=parser.parse_args() + data=json.loads(CATALOG.read_text()) + missing=[(key,lang) for key,values in data['strings'].items() for lang in data['languages'] if lang not in values] + if missing: + print(f'{len(missing)} translations missing',file=sys.stderr) + return 1 + token = re.compile(r'%(?:\d+\$)?[-+0 #]*\d*(?:\.\d+)?(?:ll|l|z)?[sduif@]|%%|\{\d+\}') + for key, values in data['strings'].items(): + expected = Counter(token.findall(key)) + for language, value in values.items(): + if Counter(token.findall(value)) != expected: + raise ValueError(f'Format placeholders differ: {language}: {key}') + if re.search(r'ZXQ\d+QXZ|[【[]\d+[】]]', value): + raise ValueError(f'Translation marker left in {language}: {key}') + for keys in data['platforms'].values(): + if len(keys) != len(set(keys)): + raise ValueError('Duplicate platform resource key') + for key in keys: + if key not in data['strings']: raise ValueError(f'Unknown resource: {key}') + mismatches=[] + for relative,content in render(data).items(): + path=ROOT/relative + if args.check: + if not path.exists() or path.read_text()!=content:mismatches.append(relative) + else: + if not path.exists() or path.read_text()!=content: + path.parent.mkdir(parents=True,exist_ok=True) + path.write_text(content) + if mismatches: + print('Stale generated resources:\n'+'\n'.join(mismatches),file=sys.stderr) + return 1 + print(f'{len(data["strings"])} strings, {len(data["languages"])} language variants; resources '+('verified' if args.check else 'generated')) + return 0 + +if __name__=='__main__': + raise SystemExit(main())