feat: in-app updates (GitHub desktop, Play Android) + i18n fixes (#241)

* feat(desktop): share dialog on Linux/macOS via cloudreve://share deeplink

The Explorer context menu is Windows-only; the share dialog itself is
cross-platform but had no trigger elsewhere. cloudreve://share/<encoded
local path> now routes through the same ManagerCommand::ShareLink
pipeline, and desktop/linux/ ships a cloudreve-share helper plus
Nautilus script and Dolphin service-menu glue so file managers can
reach it. OAuth callback deeplinks are unaffected.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(desktop): don't drop share deep links at startup

Queue cloudreve://share/ links arriving before APP_STATE init and drain
after the sync service is up; also scan argv for a cloudreve:// URL so a
cold start launched by the file manager still opens the share dialog.
Nautilus script now reads NAUTILUS_SCRIPT_SELECTED_FILE_PATHS per line so
paths with spaces survive.

* feat(desktop): macOS share helper + file-manager install docs

cloudreve-share for macOS (open cloudreve://share/...) plus Shortcuts
Quick Action recipe for Finder. READMEs document Nautilus, Dolphin, and
Finder installation.

* feat: in-app updates (GitHub desktop, Play Android) + i18n fixes

Desktop (GitHub builds):
- tauri-plugin-updater wired to releases/latest/latest.json; minisign
  keypair generated, private key in TAURI_SIGNING_PRIVATE_KEY secrets
- Startup check prompts once per version (config.prompted_update_version);
  About page gains a manual 'Check for updates' entry
- New /update window: version + notes -> in-app download overlay with
  progress events -> install -> restart via app.restart()
- Release workflow signs updater artifacts, uploads .sig/.app.tar.gz/
  .AppImage.tar.gz, and a new updater-manifest job emits latest.json
  (desktop/scripts/gen_latest_json.py); tauri-action path signs natively
- Desktop version bumped 0.2.0 -> 0.3.0 so released updates register

Android (Play builds):
- Play in-app update check on resume -> in-app dialog -> official
  IMMEDIATE update sheet (app-update-ktx); once per version via prefs
- targetSdk/compileSdk 36 + AGP 8.9.3 (Play requires >= 36); bumped to
  versionCode 2 / 1.1.0 — uploaded and published on internal track

i18n:
- Desktop: translated share.* + settings.notificationSettings into all
  10 non-English locales; added update.* everywhere; popup time strings
  (justNow/minutesAgo/...) localized via i18n.t in utils
- Frontend: added 4 keys missing from en-US (raw-key rendering):
  modals.anonymous, modals.shareTargetsCount, common.save,
  file.selectUser (+ event.allEventTypes for zh-CN); fixed two
  mistyped keys (uplaoder->uploader, uploader:->application:uploader)

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
pull/3593/head
Tomáš Dvořák 2 weeks ago committed by GitHub
parent bb215ffd8b
commit 8c6cbe09a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -51,6 +51,10 @@ jobs:
- uses: tauri-apps/tauri-action@v0 - uses: tauri-apps/tauri-action@v0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# With the signing key set, tauri-action signs updater artifacts and
# publishes latest.json on the release — the in-app updater feed.
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with: with:
projectPath: desktop projectPath: desktop
tagName: ${{ github.ref_name }} tagName: ${{ github.ref_name }}

@ -77,6 +77,9 @@ jobs:
- name: Build desktop bundles - name: Build desktop bundles
working-directory: desktop working-directory: desktop
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: cargo tauri build run: cargo tauri build
- name: Publish bundles to GitHub release - name: Publish bundles to GitHub release
@ -92,8 +95,9 @@ jobs:
done done
gh release view "$TAG" >/dev/null gh release view "$TAG" >/dev/null
FILES=$(find desktop/target/release/bundle -type f \ FILES=$(find desktop/target/release/bundle -type f \
\( -name '*.deb' -o -name '*.AppImage' -o -name '*.msi' \ \( -name '*.deb' -o -name '*.AppImage' -o -name '*.AppImage.tar.gz' \
-o -name '*.exe' -o -name '*.dmg' -o -name '*.app.tar.gz' \)) -o -name '*.msi' -o -name '*.exe' -o -name '*.dmg' \
-o -name '*.app.tar.gz' -o -name '*.sig' \))
[ -n "$FILES" ] [ -n "$FILES" ]
echo "$FILES" | while read -r f; do echo "$FILES" | while read -r f; do
name="cloudreve-desktop-$(basename "$f")" name="cloudreve-desktop-$(basename "$f")"
@ -101,6 +105,23 @@ jobs:
gh release upload "$TAG" "$name" --clobber gh release upload "$TAG" "$name" --clobber
done done
updater-manifest:
needs: desktop
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and publish latest.json
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
run: |
set -e
mkdir -p sigs
gh release download "$TAG" -p '*.sig' -D sigs --clobber
python3 desktop/scripts/gen_latest_json.py "$TAG" sigs latest.json
gh release upload "$TAG" latest.json --clobber
android: android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
defaults: defaults:

@ -7,14 +7,14 @@ plugins {
android { android {
namespace = "org.cloudreve.android" namespace = "org.cloudreve.android"
compileSdk = 35 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "com.tdvorak.cloudreve" applicationId = "com.tdvorak.cloudreve"
minSdk = 28 minSdk = 28
targetSdk = 35 targetSdk = 36
versionCode = 1 versionCode = 2
versionName = "1.0.0" versionName = "1.1.0"
} }
signingConfigs { signingConfigs {
@ -94,4 +94,9 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
implementation("io.coil-kt:coil-compose:2.7.0") implementation("io.coil-kt:coil-compose:2.7.0")
// Play in-app updates — no-op on sideloaded/non-Play installs
implementation("com.google.android.play:app-update-ktx:2.1.0")
// ActivityResult API (update flow launcher) needs fragment >= 1.3.0
implementation("androidx.fragment:fragment-ktx:1.8.5")
} }

@ -4,7 +4,7 @@
<uses-sdk <uses-sdk
android:minSdkVersion="28" android:minSdkVersion="28"
android:targetSdkVersion="35" /> android:targetSdkVersion="36" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

@ -1,6 +1,7 @@
package org.cloudreve.android package org.cloudreve.android
import android.app.Application import android.app.Application
import com.google.android.play.core.appupdate.AppUpdateInfo
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import org.cloudreve.android.api.ApiClient import org.cloudreve.android.api.ApiClient
import org.cloudreve.android.data.CameraUploadSettings import org.cloudreve.android.data.CameraUploadSettings
@ -16,6 +17,9 @@ class CloudreveApp : Application() {
data class OAuthCallback(val code: String, val state: String) data class OAuthCallback(val code: String, val state: String)
val oauthCallback = MutableStateFlow<OAuthCallback?>(null) val oauthCallback = MutableStateFlow<OAuthCallback?>(null)
/** Pending Play in-app update, set by MainActivity's update check. */
val playUpdateAvailable = MutableStateFlow<AppUpdateInfo?>(null)
lateinit var sessionManager: SessionManager lateinit var sessionManager: SessionManager
private set private set
lateinit var apiClient: ApiClient lateinit var apiClient: ApiClient

@ -6,6 +6,11 @@ import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.UpdateAvailability
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -18,6 +23,9 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.cloudreve.android.api.RefreshTokenRequest import org.cloudreve.android.api.RefreshTokenRequest
import org.cloudreve.android.ui.files.FilesScreen import org.cloudreve.android.ui.files.FilesScreen
@ -30,6 +38,9 @@ import org.cloudreve.android.work.UploadWorker
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private val updateLauncher =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
@ -37,6 +48,39 @@ class MainActivity : ComponentActivity() {
setContent { App() } setContent { App() }
} }
override fun onResume() {
super.onResume()
checkForPlayUpdate()
}
// Ask Play for an update; if one is available and this install came from
// Play, surface the in-app prompt once per version, then hand off to the
// official IMMEDIATE update sheet.
private fun checkForPlayUpdate() {
val manager = AppUpdateManagerFactory.create(this)
manager.appUpdateInfo.addOnSuccessListener { info ->
if (info.updateAvailability() != UpdateAvailability.UPDATE_AVAILABLE ||
!info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) return@addOnSuccessListener
val version = info.availableVersionCode()
val prefs = getSharedPreferences("updates", MODE_PRIVATE)
if (prefs.getInt("prompted_version", -1) == version) return@addOnSuccessListener
prefs.edit().putInt("prompted_version", version).apply()
(application as CloudreveApp).playUpdateAvailable.value = info
}
}
fun launchPlayUpdate() {
val info = (application as CloudreveApp).playUpdateAvailable.value ?: return
runCatching {
AppUpdateManagerFactory.create(this).startUpdateFlowForResult(
info,
updateLauncher,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build(),
)
}
}
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent) super.onNewIntent(intent)
handleShareIntent(intent) handleShareIntent(intent)
@ -103,6 +147,25 @@ fun App() {
} }
CloudreveTheme { CloudreveTheme {
val updateInfo by app.playUpdateAvailable.collectAsState()
if (updateInfo != null) {
AlertDialog(
onDismissRequest = { app.playUpdateAvailable.value = null },
title = { Text("Update available") },
text = { Text("A new version of Cloudreve Mobile is available on Google Play.") },
confirmButton = {
TextButton(onClick = {
app.playUpdateAvailable.value = null
(context as? MainActivity)?.launchPlayUpdate()
}) { Text("Update") }
},
dismissButton = {
TextButton(onClick = { app.playUpdateAvailable.value = null }) {
Text("Later")
}
},
)
}
when (loggedIn) { when (loggedIn) {
null -> Unit // session store still loading; keep frame empty null -> Unit // session store still loading; keep frame empty
false -> NavHost(navController = nav, startDestination = "login") { false -> NavHost(navController = nav, startDestination = "login") {

@ -1,5 +1,5 @@
plugins { plugins {
id("com.android.application") version "8.7.3" apply false id("com.android.application") version "8.9.3" apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false id("org.jetbrains.kotlin.android") version "2.0.21" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.21" apply false id("org.jetbrains.kotlin.plugin.serialization") version "2.0.21" apply false

@ -66,6 +66,9 @@ pub struct AppConfig {
pub hide_tray_icon: bool, pub hide_tray_icon: bool,
/// Language/locale setting (e.g., "en-US", "zh-CN"). None means use system default. /// Language/locale setting (e.g., "en-US", "zh-CN"). None means use system default.
pub language: Option<String>, pub language: Option<String>,
/// Last app-update version the user was already prompted about. A new
/// version still prompts once; dismissing snoozes until the next release.
pub prompted_update_version: Option<String>,
} }
impl Default for AppConfig { impl Default for AppConfig {
@ -81,6 +84,7 @@ impl Default for AppConfig {
sync_delay_seconds: 0, sync_delay_seconds: 0,
hide_tray_icon: false, hide_tray_icon: false,
language: None, language: None,
prompted_update_version: None,
} }
} }
} }

@ -0,0 +1,73 @@
#!/usr/bin/env python3
"""Generate the Tauri updater manifest (latest.json) from release .sig assets.
Usage: gen_latest_json.py <tag> <sig_dir> <output.json>
Scans <sig_dir> for `*.sig` files downloaded from the GitHub release, maps each
to its updater platform, and emits the manifest the tauri-plugin-updater
expects. Asset URLs point at the release's renamed `cloudreve-desktop-*`
assets. The version is read from desktop/src-tauri/tauri.conf.json — desktop
has its own semver, independent of the repo's server release tags.
"""
import json
import os
import sys
PLATFORM_MAP = [
("_x64-setup.exe", "windows-x86_64"),
("_arm64-setup.exe", "windows-aarch64"),
("_aarch64.app.tar.gz", "darwin-aarch64"),
("_x64.app.tar.gz", "darwin-x86_64"),
("amd64.AppImage.tar.gz", "linux-x86_64"),
("aarch64.AppImage.tar.gz", "linux-aarch64"),
]
REPO = "Dvorinka/cloudreve"
def main() -> int:
tag, sig_dir, out_path = sys.argv[1], sys.argv[2], sys.argv[3]
conf = json.load(open("desktop/src-tauri/tauri.conf.json"))
version = conf["version"]
platforms = {}
for fname in sorted(os.listdir(sig_dir)):
if not fname.endswith(".sig"):
continue
# Release assets are renamed to `cloudreve-desktop-<basename>` at
# upload time, so the downloaded .sig name already is the asset name.
asset = fname[: -len(".sig")]
for marker, platform in PLATFORM_MAP:
if marker in asset:
signature = open(os.path.join(sig_dir, fname)).read().strip()
if not signature:
print(f"warning: empty signature in {fname}, skipping")
break
platforms[platform] = {
"signature": signature,
"url": (
f"https://github.com/{REPO}/releases/download/{tag}/"
f"{asset}"
),
}
break
if not platforms:
print("error: no updater artifacts found", file=sys.stderr)
return 1
manifest = {
"version": version,
"notes": f"Cloudreve Desktop {version}",
"pub_date": "",
"platforms": platforms,
}
with open(out_path, "w") as f:
json.dump(manifest, f, indent=2)
print(f"latest.json: version={version}, platforms={sorted(platforms)}")
return 0
if __name__ == "__main__":
sys.exit(main())

@ -1,6 +1,6 @@
[package] [package]
name = "cloudreve-desktop" name = "cloudreve-desktop"
version = "0.2.0" version = "0.3.0"
description = "Cloudreve Desktop Sync Client" description = "Cloudreve Desktop Sync Client"
authors = ["cloudreve"] authors = ["cloudreve"]
license = "" license = ""
@ -44,6 +44,7 @@ tauri-plugin-deep-link = "2.4.9"
tauri-plugin-dialog = "2.7.1" tauri-plugin-dialog = "2.7.1"
tauri-plugin-prevent-default = "4" tauri-plugin-prevent-default = "4"
tauri-plugin-os = "2" tauri-plugin-os = "2"
tauri-plugin-updater = "2"
tauri-plugin-frame = "1.1.6" tauri-plugin-frame = "1.1.6"
[target.'cfg(windows)'.dependencies.windows] [target.'cfg(windows)'.dependencies.windows]

@ -1471,3 +1471,161 @@ pub async fn open_log_folder() -> CommandResult<()> {
showfile::show_path_in_file_manager(format!("{}\\", log_dir.display())); showfile::show_path_in_file_manager(format!("{}\\", log_dir.display()));
Ok(()) Ok(())
} }
/// Metadata about an available app update, returned to the frontend.
#[derive(serde::Serialize)]
pub struct UpdateInfo {
pub version: String,
pub current_version: String,
pub notes: Option<String>,
pub date: Option<String>,
}
/// Progress payload emitted on `update-progress` while an update downloads.
#[derive(serde::Serialize, Clone)]
struct UpdateProgress {
downloaded: u64,
total: Option<u64>,
}
/// Check the configured update endpoint (GitHub releases `latest.json`) for a
/// newer desktop build. Returns `None` when already up to date or when no
/// signed updater artifact exists for this platform.
#[tauri::command]
pub async fn check_update(app: AppHandle) -> CommandResult<Option<UpdateInfo>> {
use tauri_plugin_updater::UpdaterExt;
let update = app
.updater()
.map_err(|e| e.to_string())?
.check()
.await
.map_err(|e| e.to_string())?;
Ok(update.map(|u| UpdateInfo {
version: u.version.clone(),
current_version: u.current_version.clone(),
notes: u.body.clone(),
date: u.date.map(|d| d.to_string()),
}))
}
/// Download the pending update, emit `update-progress` events, and install it.
/// The frontend should call `restart_app` afterwards.
#[tauri::command]
pub async fn install_update(app: AppHandle) -> CommandResult<()> {
use tauri::Emitter;
use tauri_plugin_updater::UpdaterExt;
let update = app
.updater()
.map_err(|e| e.to_string())?
.check()
.await
.map_err(|e| e.to_string())?
.ok_or_else(|| "No update available".to_string())?;
let app2 = app.clone();
let app3 = app.clone();
update
.download_and_install(
move |chunk_len, content_len| {
let _ = app2.emit(
"update-progress",
UpdateProgress {
downloaded: chunk_len as u64,
total: content_len,
},
);
},
move || {
let _ = app3.emit("update-finished", ());
},
)
.await
.map_err(|e| e.to_string())?;
Ok(())
}
/// Restart the application (used after a successful update install).
#[tauri::command]
pub fn restart_app(app: AppHandle) {
app.restart();
}
/// Show or create the in-app update window. The window itself runs the update
/// check so it works both for automatic prompts and manual "Check for
/// updates" from the About page.
pub fn show_update_window_impl(app: &AppHandle) {
// One update window at a time — refocus instead of stacking dialogs.
if let Some(window) = app.get_webview_window("update") {
let _ = window.unminimize();
let _ = window.show();
let _ = window.set_focus();
return;
}
let url_path = get_url_with_lang("index.html#/update");
#[cfg(windows)]
let effects = WindowEffectsConfig {
effects: vec![WindowEffect::Mica, WindowEffect::Acrylic],
state: None,
radius: None,
color: None,
};
let builder = WebviewWindowBuilder::new(app, "update", WebviewUrl::App(url_path.into()))
.title("Software Update")
.inner_size(460.0, 380.0)
.resizable(false)
.visible(false)
.decorations(false)
.minimizable(false);
#[cfg(not(windows))]
let builder = builder.background_color(Color(255, 255, 255, 255));
#[cfg(windows)]
let builder = builder.transparent(true);
#[cfg(target_os = "macos")]
let builder = builder
.title_bar_style(TitleBarStyle::Overlay)
.hidden_title(true);
let Some(builder) = apply_default_window_icon(builder, app, "update") else {
return;
};
match builder.build() {
Ok(window) => {
#[cfg(target_os = "macos")]
update_dock_on_window_close(&window);
#[cfg(windows)]
{
let _ = window.set_effects(effects);
}
move_window_safely(&window, Position::Center, "update");
#[cfg(windows)]
let _ = window.create_overlay_titlebar();
let _ = window.show();
let _ = window.set_focus();
#[cfg(target_os = "macos")]
crate::update_dock_visibility(app);
}
Err(e) => {
tracing::error!(target: "main", error = %e, "Failed to create update window");
}
}
}
/// Open the in-app update window (Settings → About → "Check for updates").
#[tauri::command]
pub async fn show_update_window(app: AppHandle) -> CommandResult<()> {
show_update_window_impl(&app);
Ok(())
}

@ -190,6 +190,29 @@ async fn init_sync_service(app: AppHandle) -> anyhow::Result<()> {
event_broadcaster.no_drive(); event_broadcaster.no_drive();
} }
// Check GitHub releases for a newer desktop build in the background. The
// prompt is shown once per version; dismissing it snoozes until the next
// release. Failures (offline, no updater artifact for this platform) are
// silent — the About page still offers a manual check.
{
let app = app.clone();
tauri::async_runtime::spawn(async move {
use tauri_plugin_updater::UpdaterExt;
tokio::time::sleep(std::time::Duration::from_secs(8)).await;
let Ok(updater) = app.updater() else { return };
let Ok(Some(update)) = updater.check().await else { return };
let config = ConfigManager::get().get_config();
if config.prompted_update_version.as_deref() == Some(update.version.as_str()) {
return;
}
let _ = ConfigManager::get()
.update(|c| c.prompted_update_version = Some(update.version.clone()));
commands::show_update_window_impl(&app);
});
}
tracing::info!(target: "main", "Tauri application setup complete"); tracing::info!(target: "main", "Tauri application setup complete");
Ok(()) Ok(())
@ -472,6 +495,7 @@ pub fn run() {
builder builder
.plugin(tauri_plugin_deep_link::init()) .plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_prevent_default::debug()) .plugin(tauri_plugin_prevent_default::debug())
@ -532,6 +556,10 @@ pub fn run() {
commands::get_file_icon, commands::get_file_icon,
commands::show_file_in_explorer, commands::show_file_in_explorer,
commands::create_share, commands::create_share,
commands::check_update,
commands::install_update,
commands::restart_app,
commands::show_update_window,
commands::show_add_drive_window, commands::show_add_drive_window,
commands::show_reauthorize_window, commands::show_reauthorize_window,
commands::show_settings_window, commands::show_settings_window,

@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Cloudreve", "productName": "Cloudreve",
"version": "0.2.0", "version": "0.3.0",
"identifier": "cloudreve.desktop", "identifier": "cloudreve.desktop",
"build": { "build": {
"frontendDist": "../ui/dist", "frontendDist": "../ui/dist",
@ -41,7 +41,9 @@
"targets": "all", "targets": "all",
"linux": { "linux": {
"deb": { "deb": {
"depends": ["fuse3"] "depends": [
"fuse3"
]
} }
}, },
"icon": [ "icon": [
@ -50,13 +52,25 @@
"icons/128x128@2x.png", "icons/128x128@2x.png",
"icons/icon.icns", "icons/icon.icns",
"icons/icon.ico" "icons/icon.ico"
] ],
"createUpdaterArtifacts": true
}, },
"plugins": { "plugins": {
"deep-link": { "deep-link": {
"desktop": { "desktop": {
"schemes": ["cloudreve"] "schemes": [
"cloudreve"
]
}
},
"updater": {
"endpoints": [
"https://github.com/Dvorinka/cloudreve/releases/latest/download/latest.json"
],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDIzRUE2QkM3NzJDQ0QxRjAKUldUdzBjeHl4MnZxSXloWjRaRmtqMXZkcXN1UlRYdk1PanliYis0WDlqWEdWczQ1RHZBcHMvV2cK",
"windows": {
"installMode": "passive"
} }
} }
} }
} }

@ -54,14 +54,18 @@
"processing": "Verarbeitung...", "processing": "Verarbeitung...",
"conflicts": "Konflikte", "conflicts": "Konflikte",
"conflictStatus": "{{count}} Konflikt(e) erfordern Aufmerksamkeit", "conflictStatus": "{{count}} Konflikt(e) erfordern Aufmerksamkeit",
"conflictDescription": "Die lokale Datei steht im Konflikt mit der Remote-Version", "conflictDescription": "Lokale Datei steht im Konflikt mit der Remote-Version",
"resolveConflict": "Konflikt lösen", "resolveConflict": "Konflikt lösen",
"resolving": "Wird gelöst...", "resolving": "Wird gelöst...",
"keepRemote": "Remote-Version behalten", "keepRemote": "Remote-Version behalten",
"overwriteRemote": "Remote-Version überschreiben", "overwriteRemote": "Remote-Version überschreiben",
"saveAsNew": "Als neue Datei speichern", "saveAsNew": "Als neue Datei speichern",
"keepAllRemote": "Alle Remote-Versionen behalten", "keepAllRemote": "Alle Remote-Versionen behalten",
"overwriteAllRemote": "Alle Remote-Versionen überschreiben" "overwriteAllRemote": "Alle Remote-Versionen überschreiben",
"justNow": "Gerade eben",
"minutesAgo": "vor {{count}} Min.",
"hoursAgo": "vor {{count}} Std.",
"daysAgo": "vor {{count}} Tagen"
}, },
"settings": { "settings": {
"title": "Einstellungen", "title": "Einstellungen",
@ -138,26 +142,40 @@
"yearsAgo": "Vor {{value}} Jahren" "yearsAgo": "Vor {{value}} Jahren"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "Freigabelink für {{name}}",
"linkReady": "Your share link is ready:", "linkReady": "Ihr Freigabelink ist bereit:",
"permission": "Sharing permissions", "permission": "Freigabeberechtigungen",
"permViewDownload": "View + Download", "permViewDownload": "Ansehen + Herunterladen",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "Nur Vorschau (kein Download)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "Ansehen + Herunterladen + Bearbeiten",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "Nur hochladen (Abgabebox)",
"expires": "Expires", "expires": "Läuft ab",
"expire_never": "Never expires", "expire_never": "Läuft nie ab",
"expire_oneHour": "1 hour", "expire_oneHour": "1 Stunde",
"expire_oneDay": "1 day", "expire_oneDay": "1 Tag",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 Tage",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 Tage",
"passwordProtect": "Protect with password", "passwordProtect": "Mit Passwort schützen",
"password": "Password", "password": "Passwort",
"downloadLimit": "Download limit", "downloadLimit": "Download-Limit",
"unlimited": "Unlimited", "unlimited": "Unbegrenzt",
"create": "Create share", "create": "Freigabe erstellen",
"cancel": "Cancel", "cancel": "Abbrechen",
"done": "Done", "done": "Fertig",
"copied": "Link copied to clipboard" "copied": "Link in die Zwischenablage kopiert"
},
"update": {
"title": "Software-Update",
"available": "Version {{version}} ist verfügbar (aktuell {{current}}).",
"downloading": "Update wird heruntergeladen…",
"ready": "Update installiert — zum Anwenden neu starten.",
"upToDate": "Sie sind auf dem neuesten Stand.",
"failed": "Update-Prüfung fehlgeschlagen.",
"updateNow": "Jetzt aktualisieren",
"later": "Später",
"restart": "Jetzt neu starten",
"close": "Schließen",
"checkNow": "Nach Updates suchen",
"downloadManually": "Manuell herunterladen"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "Overwrite remote", "overwriteRemote": "Overwrite remote",
"saveAsNew": "Save as new", "saveAsNew": "Save as new",
"keepAllRemote": "Keep all remote", "keepAllRemote": "Keep all remote",
"overwriteAllRemote": "Overwrite all remote" "overwriteAllRemote": "Overwrite all remote",
"justNow": "Just now",
"minutesAgo": "{{count}}m ago",
"hoursAgo": "{{count}}h ago",
"daysAgo": "{{count}}d ago"
}, },
"settings": { "settings": {
"title": "Settings", "title": "Settings",
@ -159,5 +163,19 @@
"cancel": "Cancel", "cancel": "Cancel",
"done": "Done", "done": "Done",
"copied": "Link copied to clipboard" "copied": "Link copied to clipboard"
},
"update": {
"title": "Software Update",
"available": "Version {{version}} is available (you have {{current}}).",
"downloading": "Downloading update…",
"ready": "Update installed — restart to apply.",
"upToDate": "You're up to date.",
"failed": "Update check failed.",
"updateNow": "Update now",
"later": "Later",
"restart": "Restart now",
"close": "Close",
"checkNow": "Check for updates",
"downloadManually": "Download manually"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "Sobrescribir remoto", "overwriteRemote": "Sobrescribir remoto",
"saveAsNew": "Guardar como nuevo", "saveAsNew": "Guardar como nuevo",
"keepAllRemote": "Conservar todas las remotas", "keepAllRemote": "Conservar todas las remotas",
"overwriteAllRemote": "Sobrescribir todas las remotas" "overwriteAllRemote": "Sobrescribir todas las remotas",
"justNow": "Ahora mismo",
"minutesAgo": "hace {{count}} min",
"hoursAgo": "hace {{count}} h",
"daysAgo": "hace {{count}} d"
}, },
"settings": { "settings": {
"title": "Configuración", "title": "Configuración",
@ -138,26 +142,40 @@
"yearsAgo": "Hace {{value}} años" "yearsAgo": "Hace {{value}} años"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "Enlace para compartir de {{name}}",
"linkReady": "Your share link is ready:", "linkReady": "Tu enlace para compartir está listo:",
"permission": "Sharing permissions", "permission": "Permisos de uso compartido",
"permViewDownload": "View + Download", "permViewDownload": "Ver + Descargar",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "Solo vista previa (sin descarga)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "Ver + Descargar + Editar",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "Solo subir (buzón)",
"expires": "Expires", "expires": "Caduca",
"expire_never": "Never expires", "expire_never": "Nunca caduca",
"expire_oneHour": "1 hour", "expire_oneHour": "1 hora",
"expire_oneDay": "1 day", "expire_oneDay": "1 día",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 días",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 días",
"passwordProtect": "Protect with password", "passwordProtect": "Proteger con contraseña",
"password": "Password", "password": "Contraseña",
"downloadLimit": "Download limit", "downloadLimit": "Límite de descargas",
"unlimited": "Unlimited", "unlimited": "Ilimitado",
"create": "Create share", "create": "Crear enlace",
"cancel": "Cancel", "cancel": "Cancelar",
"done": "Done", "done": "Hecho",
"copied": "Link copied to clipboard" "copied": "Enlace copiado al portapapeles"
},
"update": {
"title": "Actualización de software",
"available": "La versión {{version}} está disponible (tienes {{current}}).",
"downloading": "Descargando actualización…",
"ready": "Actualización instalada — reinicia para aplicar.",
"upToDate": "Estás al día.",
"failed": "Error al comprobar actualizaciones.",
"updateNow": "Actualizar ahora",
"later": "Más tarde",
"restart": "Reiniciar ahora",
"close": "Cerrar",
"checkNow": "Buscar actualizaciones",
"downloadManually": "Descargar manualmente"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "Écraser la version distante", "overwriteRemote": "Écraser la version distante",
"saveAsNew": "Enregistrer comme nouveau fichier", "saveAsNew": "Enregistrer comme nouveau fichier",
"keepAllRemote": "Conserver toutes les versions distantes", "keepAllRemote": "Conserver toutes les versions distantes",
"overwriteAllRemote": "Écraser toutes les versions distantes" "overwriteAllRemote": "Écraser toutes les versions distantes",
"justNow": "À l'instant",
"minutesAgo": "il y a {{count}} min",
"hoursAgo": "il y a {{count}} h",
"daysAgo": "il y a {{count}} j"
}, },
"settings": { "settings": {
"title": "Paramètres", "title": "Paramètres",
@ -138,26 +142,40 @@
"yearsAgo": "Il y a {{value}} ans" "yearsAgo": "Il y a {{value}} ans"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "Lien de partage pour {{name}}",
"linkReady": "Your share link is ready:", "linkReady": "Votre lien de partage est prêt :",
"permission": "Sharing permissions", "permission": "Permissions de partage",
"permViewDownload": "View + Download", "permViewDownload": "Voir + Télécharger",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "Aperçu uniquement (sans téléchargement)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "Voir + Télécharger + Modifier",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "Téléversement uniquement (boîte de dépôt)",
"expires": "Expires", "expires": "Expire",
"expire_never": "Never expires", "expire_never": "N'expire jamais",
"expire_oneHour": "1 hour", "expire_oneHour": "1 heure",
"expire_oneDay": "1 day", "expire_oneDay": "1 jour",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 jours",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 jours",
"passwordProtect": "Protect with password", "passwordProtect": "Protéger par mot de passe",
"password": "Password", "password": "Mot de passe",
"downloadLimit": "Download limit", "downloadLimit": "Limite de téléchargements",
"unlimited": "Unlimited", "unlimited": "Illimité",
"create": "Create share", "create": "Créer le partage",
"cancel": "Cancel", "cancel": "Annuler",
"done": "Done", "done": "Terminé",
"copied": "Link copied to clipboard" "copied": "Lien copié dans le presse-papiers"
},
"update": {
"title": "Mise à jour logicielle",
"available": "La version {{version}} est disponible (vous avez {{current}}).",
"downloading": "Téléchargement de la mise à jour…",
"ready": "Mise à jour installée — redémarrez pour l'appliquer.",
"upToDate": "Vous êtes à jour.",
"failed": "Échec de la vérification des mises à jour.",
"updateNow": "Mettre à jour",
"later": "Plus tard",
"restart": "Redémarrer",
"close": "Fermer",
"checkNow": "Rechercher des mises à jour",
"downloadManually": "Télécharger manuellement"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "Sovrascrivi remoto", "overwriteRemote": "Sovrascrivi remoto",
"saveAsNew": "Salva come nuovo", "saveAsNew": "Salva come nuovo",
"keepAllRemote": "Mantieni tutte le versioni remote", "keepAllRemote": "Mantieni tutte le versioni remote",
"overwriteAllRemote": "Sovrascrivi tutte le versioni remote" "overwriteAllRemote": "Sovrascrivi tutte le versioni remote",
"justNow": "Proprio ora",
"minutesAgo": "{{count}} min fa",
"hoursAgo": "{{count}} h fa",
"daysAgo": "{{count}} g fa"
}, },
"settings": { "settings": {
"title": "Impostazioni", "title": "Impostazioni",
@ -138,26 +142,40 @@
"yearsAgo": "{{value}} anni fa" "yearsAgo": "{{value}} anni fa"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "Link di condivisione per {{name}}",
"linkReady": "Your share link is ready:", "linkReady": "Il tuo link di condivisione è pronto:",
"permission": "Sharing permissions", "permission": "Permessi di condivisione",
"permViewDownload": "View + Download", "permViewDownload": "Visualizza + Scarica",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "Solo anteprima (senza download)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "Visualizza + Scarica + Modifica",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "Solo caricamento (casella di deposito)",
"expires": "Expires", "expires": "Scade",
"expire_never": "Never expires", "expire_never": "Non scade mai",
"expire_oneHour": "1 hour", "expire_oneHour": "1 ora",
"expire_oneDay": "1 day", "expire_oneDay": "1 giorno",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 giorni",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 giorni",
"passwordProtect": "Protect with password", "passwordProtect": "Proteggi con password",
"password": "Password", "password": "Password",
"downloadLimit": "Download limit", "downloadLimit": "Limite di download",
"unlimited": "Unlimited", "unlimited": "Illimitato",
"create": "Create share", "create": "Crea condivisione",
"cancel": "Cancel", "cancel": "Annulla",
"done": "Done", "done": "Fatto",
"copied": "Link copied to clipboard" "copied": "Link copiato negli appunti"
},
"update": {
"title": "Aggiornamento software",
"available": "La versione {{version}} è disponibile (hai la {{current}}).",
"downloading": "Download dell'aggiornamento…",
"ready": "Aggiornamento installato — riavvia per applicare.",
"upToDate": "Sei aggiornato.",
"failed": "Controllo aggiornamenti fallito.",
"updateNow": "Aggiorna ora",
"later": "Più tardi",
"restart": "Riavvia ora",
"close": "Chiudi",
"checkNow": "Controlla aggiornamenti",
"downloadManually": "Scarica manualmente"
} }
} }

@ -54,14 +54,18 @@
"processing": "処理中...", "processing": "処理中...",
"conflicts": "競合", "conflicts": "競合",
"conflictStatus": "{{count}} 件の競合に対応が必要です", "conflictStatus": "{{count}} 件の競合に対応が必要です",
"conflictDescription": "ローカルファイルがリモート版と競合しています", "conflictDescription": "ローカルファイルがリモートバージョンと競合しています",
"resolveConflict": "競合を解決", "resolveConflict": "競合を解決",
"resolving": "解決中...", "resolving": "解決中...",
"keepRemote": "リモート版を保持", "keepRemote": "リモート版を保持",
"overwriteRemote": "リモート版を上書き", "overwriteRemote": "リモート版を上書き",
"saveAsNew": "新しいファイルとして保存", "saveAsNew": "新しいファイルとして保存",
"keepAllRemote": "すべてリモートを保持", "keepAllRemote": "すべてリモートを保持",
"overwriteAllRemote": "すべてリモートで上書き" "overwriteAllRemote": "すべてリモートで上書き",
"justNow": "たった今",
"minutesAgo": "{{count}}分前",
"hoursAgo": "{{count}}時間前",
"daysAgo": "{{count}}日前"
}, },
"settings": { "settings": {
"title": "設定", "title": "設定",
@ -138,26 +142,40 @@
"yearsAgo": "{{value}} 年前" "yearsAgo": "{{value}} 年前"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "{{name}} の共有リンク",
"linkReady": "Your share link is ready:", "linkReady": "共有リンクの準備ができました:",
"permission": "Sharing permissions", "permission": "共有権限",
"permViewDownload": "View + Download", "permViewDownload": "表示 + ダウンロード",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "プレビューのみ (ダウンロード不可)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "表示 + ダウンロード + 編集",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "アップロードのみ (ドロップボックス)",
"expires": "Expires", "expires": "有効期限",
"expire_never": "Never expires", "expire_never": "無期限",
"expire_oneHour": "1 hour", "expire_oneHour": "1 時間",
"expire_oneDay": "1 day", "expire_oneDay": "1 日",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 日",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 日",
"passwordProtect": "Protect with password", "passwordProtect": "パスワードで保護",
"password": "Password", "password": "パスワード",
"downloadLimit": "Download limit", "downloadLimit": "ダウンロード上限",
"unlimited": "Unlimited", "unlimited": "無制限",
"create": "Create share", "create": "共有を作成",
"cancel": "Cancel", "cancel": "キャンセル",
"done": "Done", "done": "完了",
"copied": "Link copied to clipboard" "copied": "リンクをクリップボードにコピーしました"
},
"update": {
"title": "ソフトウェア更新",
"available": "バージョン {{version}} が利用可能です(現在 {{current}})。",
"downloading": "更新をダウンロード中…",
"ready": "更新をインストールしました — 再起動して適用します。",
"upToDate": "最新の状態です。",
"failed": "更新の確認に失敗しました。",
"updateNow": "今すぐ更新",
"later": "後で",
"restart": "今すぐ再起動",
"close": "閉じる",
"checkNow": "更新を確認",
"downloadManually": "手動でダウンロード"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "원격 버전 덮어쓰기", "overwriteRemote": "원격 버전 덮어쓰기",
"saveAsNew": "새 파일로 저장", "saveAsNew": "새 파일로 저장",
"keepAllRemote": "모두 원격 버전 유지", "keepAllRemote": "모두 원격 버전 유지",
"overwriteAllRemote": "모두 원격 버전으로 덮어쓰기" "overwriteAllRemote": "모두 원격 버전으로 덮어쓰기",
"justNow": "방금",
"minutesAgo": "{{count}}분 전",
"hoursAgo": "{{count}}시간 전",
"daysAgo": "{{count}}일 전"
}, },
"settings": { "settings": {
"title": "설정", "title": "설정",
@ -138,26 +142,40 @@
"yearsAgo": "{{value}}년 전" "yearsAgo": "{{value}}년 전"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "{{name}} 공유 링크",
"linkReady": "Your share link is ready:", "linkReady": "공유 링크가 준비되었습니다:",
"permission": "Sharing permissions", "permission": "공유 권한",
"permViewDownload": "View + Download", "permViewDownload": "보기 + 다운로드",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "미리보기 전용 (다운로드 불가)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "보기 + 다운로드 + 편집",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "업로드 전용 (드롭 박스)",
"expires": "Expires", "expires": "만료",
"expire_never": "Never expires", "expire_never": "만료 없음",
"expire_oneHour": "1 hour", "expire_oneHour": "1시간",
"expire_oneDay": "1 day", "expire_oneDay": "1일",
"expire_sevenDays": "7 days", "expire_sevenDays": "7일",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30일",
"passwordProtect": "Protect with password", "passwordProtect": "비밀번호로 보호",
"password": "Password", "password": "비밀번호",
"downloadLimit": "Download limit", "downloadLimit": "다운로드 제한",
"unlimited": "Unlimited", "unlimited": "제한 없음",
"create": "Create share", "create": "공유 만들기",
"cancel": "Cancel", "cancel": "취소",
"done": "Done", "done": "완료",
"copied": "Link copied to clipboard" "copied": "링크가 클립보드에 복사되었습니다"
},
"update": {
"title": "소프트웨어 업데이트",
"available": "버전 {{version}}을(를) 사용할 수 있습니다 (현재 {{current}}).",
"downloading": "업데이트 다운로드 중…",
"ready": "업데이트가 설치되었습니다 — 재시작하여 적용하세요.",
"upToDate": "최신 상태입니다.",
"failed": "업데이트 확인에 실패했습니다.",
"updateNow": "지금 업데이트",
"later": "나중에",
"restart": "지금 재시작",
"close": "닫기",
"checkNow": "업데이트 확인",
"downloadManually": "수동으로 다운로드"
} }
} }

@ -54,14 +54,18 @@
"processing": "Przetwarzanie...", "processing": "Przetwarzanie...",
"conflicts": "Konflikty", "conflicts": "Konflikty",
"conflictStatus": "{{count}} konflikt(y) wymagają uwagi", "conflictStatus": "{{count}} konflikt(y) wymagają uwagi",
"conflictDescription": "Plik lokalny jest w konflikcie z wersją zdalną", "conflictDescription": "Lokalny plik jest w konflikcie z wersją zdalną",
"resolveConflict": "Rozwiąż konflikt", "resolveConflict": "Rozwiąż konflikt",
"resolving": "Rozwiązywanie...", "resolving": "Rozwiązywanie...",
"keepRemote": "Zachowaj wersję zdalną", "keepRemote": "Zachowaj wersję zdalną",
"overwriteRemote": "Nadpisz wersję zdalną", "overwriteRemote": "Nadpisz wersję zdalną",
"saveAsNew": "Zapisz jako nowy plik", "saveAsNew": "Zapisz jako nowy plik",
"keepAllRemote": "Zachowaj wszystkie zdalne", "keepAllRemote": "Zachowaj wszystkie zdalne",
"overwriteAllRemote": "Nadpisz wszystkie zdalne" "overwriteAllRemote": "Nadpisz wszystkie zdalne",
"justNow": "Przed chwilą",
"minutesAgo": "{{count}} min temu",
"hoursAgo": "{{count}} godz. temu",
"daysAgo": "{{count}} dni temu"
}, },
"settings": { "settings": {
"title": "Ustawienia", "title": "Ustawienia",
@ -138,26 +142,40 @@
"yearsAgo": "{{value}} lat temu" "yearsAgo": "{{value}} lat temu"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "Link do udostępnienia dla {{name}}",
"linkReady": "Your share link is ready:", "linkReady": "Twój link do udostępnienia jest gotowy:",
"permission": "Sharing permissions", "permission": "Uprawnienia udostępniania",
"permViewDownload": "View + Download", "permViewDownload": "Podgląd + Pobieranie",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "Tylko podgląd (bez pobierania)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "Podgląd + Pobieranie + Edycja",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "Tylko przesyłanie (skrzynka nadawcza)",
"expires": "Expires", "expires": "Wygasa",
"expire_never": "Never expires", "expire_never": "Nigdy nie wygasa",
"expire_oneHour": "1 hour", "expire_oneHour": "1 godzina",
"expire_oneDay": "1 day", "expire_oneDay": "1 dzień",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 dni",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 dni",
"passwordProtect": "Protect with password", "passwordProtect": "Chroń hasłem",
"password": "Password", "password": "Hasło",
"downloadLimit": "Download limit", "downloadLimit": "Limit pobrań",
"unlimited": "Unlimited", "unlimited": "Bez limitu",
"create": "Create share", "create": "Utwórz udostępnienie",
"cancel": "Cancel", "cancel": "Anuluj",
"done": "Done", "done": "Gotowe",
"copied": "Link copied to clipboard" "copied": "Link skopiowany do schowka"
},
"update": {
"title": "Aktualizacja oprogramowania",
"available": "Dostępna jest wersja {{version}} (masz {{current}}).",
"downloading": "Pobieranie aktualizacji…",
"ready": "Aktualizacja zainstalowana — uruchom ponownie, aby zastosować.",
"upToDate": "Masz najnowszą wersję.",
"failed": "Sprawdzanie aktualizacji nie powiodło się.",
"updateNow": "Aktualizuj teraz",
"later": "Później",
"restart": "Uruchom ponownie",
"close": "Zamknij",
"checkNow": "Sprawdź aktualizacje",
"downloadManually": "Pobierz ręcznie"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "Перезаписать удалённую версию", "overwriteRemote": "Перезаписать удалённую версию",
"saveAsNew": "Сохранить как новый файл", "saveAsNew": "Сохранить как новый файл",
"keepAllRemote": "Оставить все удалённые", "keepAllRemote": "Оставить все удалённые",
"overwriteAllRemote": "Перезаписать все удалённые" "overwriteAllRemote": "Перезаписать все удалённые",
"justNow": "Только что",
"minutesAgo": "{{count}} мин назад",
"hoursAgo": "{{count}} ч назад",
"daysAgo": "{{count}} д назад"
}, },
"settings": { "settings": {
"title": "Настройки", "title": "Настройки",
@ -138,26 +142,40 @@
"yearsAgo": "{{value}} лет назад" "yearsAgo": "{{value}} лет назад"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "Ссылка на {{name}}",
"linkReady": "Your share link is ready:", "linkReady": "Ваша ссылка готова:",
"permission": "Sharing permissions", "permission": "Права доступа",
"permViewDownload": "View + Download", "permViewDownload": "Просмотр + Скачивание",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "Только просмотр (без скачивания)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "Просмотр + Скачивание + Редактирование",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "Только загрузка (ящик для файлов)",
"expires": "Expires", "expires": "Истекает",
"expire_never": "Never expires", "expire_never": "Без срока",
"expire_oneHour": "1 hour", "expire_oneHour": "1 час",
"expire_oneDay": "1 day", "expire_oneDay": "1 день",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 дней",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 дней",
"passwordProtect": "Protect with password", "passwordProtect": "Защитить паролем",
"password": "Password", "password": "Пароль",
"downloadLimit": "Download limit", "downloadLimit": "Лимит скачиваний",
"unlimited": "Unlimited", "unlimited": "Без ограничений",
"create": "Create share", "create": "Создать ссылку",
"cancel": "Cancel", "cancel": "Отмена",
"done": "Done", "done": "Готово",
"copied": "Link copied to clipboard" "copied": "Ссылка скопирована в буфер обмена"
},
"update": {
"title": "Обновление",
"available": "Доступна версия {{version}} (у вас {{current}}).",
"downloading": "Загрузка обновления…",
"ready": "Обновление установлено — перезапустите для применения.",
"upToDate": "У вас последняя версия.",
"failed": "Не удалось проверить обновления.",
"updateNow": "Обновить",
"later": "Позже",
"restart": "Перезапустить",
"close": "Закрыть",
"checkNow": "Проверить обновления",
"downloadManually": "Скачать вручную"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "覆盖远程版本", "overwriteRemote": "覆盖远程版本",
"saveAsNew": "另存为新文件", "saveAsNew": "另存为新文件",
"keepAllRemote": "全部保留远程", "keepAllRemote": "全部保留远程",
"overwriteAllRemote": "全部覆盖远程" "overwriteAllRemote": "全部覆盖远程",
"justNow": "刚刚",
"minutesAgo": "{{count}} 分钟前",
"hoursAgo": "{{count}} 小时前",
"daysAgo": "{{count}} 天前"
}, },
"settings": { "settings": {
"title": "设置", "title": "设置",
@ -159,5 +163,19 @@
"cancel": "取消", "cancel": "取消",
"done": "完成", "done": "完成",
"copied": "链接已复制到剪贴板" "copied": "链接已复制到剪贴板"
},
"update": {
"title": "软件更新",
"available": "新版本 {{version}} 可用(当前版本 {{current}})。",
"downloading": "正在下载更新…",
"ready": "更新已安装 — 重启以应用。",
"upToDate": "已是最新版本。",
"failed": "更新检查失败。",
"updateNow": "立即更新",
"later": "稍后",
"restart": "立即重启",
"close": "关闭",
"checkNow": "检查更新",
"downloadManually": "手动下载"
} }
} }

@ -61,7 +61,11 @@
"overwriteRemote": "覆蓋遠端版本", "overwriteRemote": "覆蓋遠端版本",
"saveAsNew": "另存為新檔案", "saveAsNew": "另存為新檔案",
"keepAllRemote": "全部保留遠端", "keepAllRemote": "全部保留遠端",
"overwriteAllRemote": "全部覆寫遠端" "overwriteAllRemote": "全部覆寫遠端",
"justNow": "剛剛",
"minutesAgo": "{{count}} 分鐘前",
"hoursAgo": "{{count}} 小時前",
"daysAgo": "{{count}} 天前"
}, },
"settings": { "settings": {
"title": "設定", "title": "設定",
@ -138,26 +142,40 @@
"yearsAgo": "{{value}} 年前" "yearsAgo": "{{value}} 年前"
}, },
"share": { "share": {
"title": "Share link for {{name}}", "title": "{{name}} 的分享連結",
"linkReady": "Your share link is ready:", "linkReady": "您的分享連結已就緒:",
"permission": "Sharing permissions", "permission": "分享權限",
"permViewDownload": "View + Download", "permViewDownload": "檢視 + 下載",
"permPreviewOnly": "Preview only (no download)", "permPreviewOnly": "僅預覽 (不可下載)",
"permAllowEdit": "View + Download + Edit", "permAllowEdit": "檢視 + 下載 + 編輯",
"permUploadOnly": "Upload only (drop box)", "permUploadOnly": "僅上傳 (收集箱)",
"expires": "Expires", "expires": "到期",
"expire_never": "Never expires", "expire_never": "永不過期",
"expire_oneHour": "1 hour", "expire_oneHour": "1 小時",
"expire_oneDay": "1 day", "expire_oneDay": "1 天",
"expire_sevenDays": "7 days", "expire_sevenDays": "7 天",
"expire_thirtyDays": "30 days", "expire_thirtyDays": "30 天",
"passwordProtect": "Protect with password", "passwordProtect": "使用密碼保護",
"password": "Password", "password": "密碼",
"downloadLimit": "Download limit", "downloadLimit": "下載次數限制",
"unlimited": "Unlimited", "unlimited": "無限制",
"create": "Create share", "create": "建立分享",
"cancel": "Cancel", "cancel": "取消",
"done": "Done", "done": "完成",
"copied": "Link copied to clipboard" "copied": "連結已複製到剪貼簿"
},
"update": {
"title": "軟體更新",
"available": "新版本 {{version}} 可用(目前版本 {{current}})。",
"downloading": "正在下載更新…",
"ready": "更新已安裝 — 重新啟動以套用。",
"upToDate": "已是最新版本。",
"failed": "更新檢查失敗。",
"updateNow": "立即更新",
"later": "稍後",
"restart": "立即重啟",
"close": "關閉",
"checkNow": "檢查更新",
"downloadManually": "手動下載"
} }
} }

@ -6,6 +6,7 @@ import {
useMediaQuery, useMediaQuery,
} from "@mui/material"; } from "@mui/material";
import { Routes, Route, HashRouter } from "react-router-dom"; import { Routes, Route, HashRouter } from "react-router-dom";
import Update from "./pages/Update";
import "@fontsource/roboto/300.css"; import "@fontsource/roboto/300.css";
import "@fontsource/roboto/400.css"; import "@fontsource/roboto/400.css";
import "@fontsource/roboto/500.css"; import "@fontsource/roboto/500.css";
@ -49,6 +50,7 @@ function App() {
<Route path="/popup" element={<Popup />} /> <Route path="/popup" element={<Popup />} />
<Route path="/settings" element={<Settings />} /> <Route path="/settings" element={<Settings />} />
<Route path="/share" element={<Share />} /> <Route path="/share" element={<Share />} />
<Route path="/update" element={<Update />} />
</Routes> </Routes>
</HashRouter> </HashRouter>
</ThemeProvider> </ThemeProvider>

@ -0,0 +1,227 @@
import {
Alert,
Box,
Button,
CircularProgress,
IconButton,
LinearProgress,
Typography,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { openUrl } from "@tauri-apps/plugin-opener";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { DenseFilledTextField } from "../common/StyledComponent";
type UpdateInfo = {
version: string;
current_version: string;
notes?: string | null;
date?: string | null;
};
type Phase = "checking" | "available" | "downloading" | "ready" | "uptodate" | "error";
const RELEASES_URL = "https://github.com/Dvorinka/cloudreve/releases";
export default function Update() {
const { t } = useTranslation();
const [phase, setPhase] = useState<Phase>("checking");
const [info, setInfo] = useState<UpdateInfo | null>(null);
const [progress, setProgress] = useState(0);
const [error, setError] = useState<string | null>(null);
const downloadedRef = useRef(0);
useEffect(() => {
const unProgress = listen<{ downloaded: number; total: number | null }>(
"update-progress",
(e) => {
downloadedRef.current += e.payload.downloaded;
if (e.payload.total) {
setProgress(
Math.min(100, (downloadedRef.current / e.payload.total) * 100)
);
}
}
);
const unFinished = listen("update-finished", () => setPhase("ready"));
invoke<UpdateInfo | null>("check_update")
.then((u) => {
setInfo(u);
setPhase(u ? "available" : "uptodate");
})
.catch((e) => {
setError(String(e));
setPhase("error");
});
return () => {
unProgress.then((f) => f());
unFinished.then((f) => f());
};
}, []);
const startUpdate = async () => {
setPhase("downloading");
setError(null);
downloadedRef.current = 0;
setProgress(0);
try {
await invoke("install_update");
// The ready phase is set by the update-finished listener; if the
// event raced past us, still land on ready.
setPhase((p) => (p === "downloading" ? "ready" : p));
} catch (e) {
setError(String(e));
setPhase("error");
}
};
return (
<Box
sx={{
height: "100vh",
display: "flex",
flexDirection: "column",
overflow: "hidden",
}}
>
<Box
data-tauri-drag-region
sx={{
px: 2,
pt: 1.5,
pb: 1,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
flexShrink: 0,
}}
>
<Typography variant="subtitle1" fontWeight={600} noWrap>
{t("update.title")}
</Typography>
<IconButton
size="small"
onClick={() => getCurrentWindow().close()}
sx={{ WebkitAppRegion: "no-drag", appRegion: "no-drag" }}
>
<CloseIcon fontSize="small" />
</IconButton>
</Box>
<Box
sx={{
flex: 1,
overflow: "auto",
px: 3,
pb: 2,
display: "flex",
flexDirection: "column",
justifyContent: "center",
gap: 1.5,
}}
>
{phase === "checking" && (
<Box sx={{ display: "flex", justifyContent: "center", py: 4 }}>
<CircularProgress size={28} />
</Box>
)}
{phase === "available" && info && (
<>
<Typography variant="body1" fontWeight={600}>
{t("update.available", {
version: info.version,
current: info.current_version,
})}
</Typography>
{info.notes && (
<DenseFilledTextField
fullWidth
multiline
minRows={3}
maxRows={6}
value={info.notes}
slotProps={{ input: { readOnly: true } }}
/>
)}
</>
)}
{phase === "downloading" && (
<>
<Typography variant="body2" color="text.secondary">
{t("update.downloading")}
</Typography>
<LinearProgress variant="determinate" value={progress} />
<Typography variant="caption" color="text.secondary">
{Math.round(progress)}%
</Typography>
</>
)}
{phase === "ready" && (
<Alert severity="success">{t("update.ready")}</Alert>
)}
{phase === "uptodate" && (
<Alert severity="info">{t("update.upToDate")}</Alert>
)}
{phase === "error" && (
<Alert severity="error">{error ?? t("update.failed")}</Alert>
)}
</Box>
<Box
sx={{
px: 3,
py: 2,
display: "flex",
justifyContent: "flex-end",
gap: 1,
flexShrink: 0,
}}
>
{phase === "available" && (
<>
<Button onClick={() => getCurrentWindow().close()}>
{t("update.later")}
</Button>
<Button variant="contained" onClick={startUpdate}>
{t("update.updateNow")}
</Button>
</>
)}
{phase === "ready" && (
<Button
variant="contained"
onClick={() => invoke("restart_app")}
>
{t("update.restart")}
</Button>
)}
{(phase === "uptodate" || phase === "checking") && (
<Button onClick={() => getCurrentWindow().close()}>
{t("update.close")}
</Button>
)}
{phase === "error" && (
<>
<Button onClick={() => getCurrentWindow().close()}>
{t("update.close")}
</Button>
<Button variant="outlined" onClick={() => openUrl(RELEASES_URL)}>
{t("update.downloadManually")}
</Button>
</>
)}
</Box>
</Box>
);
}

@ -1,3 +1,5 @@
import i18n from "../../i18n";
export function formatBytes(bytes: number): string { export function formatBytes(bytes: number): string {
if (bytes === 0) return "0 B"; if (bytes === 0) return "0 B";
const k = 1024; const k = 1024;
@ -10,10 +12,12 @@ export function formatRelativeTime(timestamp: number): string {
const now = Date.now() / 1000; const now = Date.now() / 1000;
const diff = now - timestamp; const diff = now - timestamp;
if (diff < 60) return "Just now"; if (diff < 60) return i18n.t("popup.justNow");
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`; if (diff < 3600)
if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`; return i18n.t("popup.minutesAgo", { count: Math.floor(diff / 60) });
return `${Math.floor(diff / 86400)}d ago`; if (diff < 86400)
return i18n.t("popup.hoursAgo", { count: Math.floor(diff / 3600) });
return i18n.t("popup.daysAgo", { count: Math.floor(diff / 86400) });
} }
export function getFileName(path: string): string { export function getFileName(path: string): string {

@ -1,10 +1,12 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Box, Typography, Link, Chip, Stack } from "@mui/material"; import { Box, Typography, Link, Chip, Stack, Button } from "@mui/material";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { getVersion } from "@tauri-apps/api/app"; import { getVersion } from "@tauri-apps/api/app";
import { invoke } from "@tauri-apps/api/core";
import GitHubIcon from "@mui/icons-material/GitHub"; import GitHubIcon from "@mui/icons-material/GitHub";
import BugReportIcon from "@mui/icons-material/BugReportRounded"; import BugReportIcon from "@mui/icons-material/BugReportRounded";
import ForumIcon from "@mui/icons-material/ForumRounded"; import ForumIcon from "@mui/icons-material/ForumRounded";
import SystemUpdateAltIcon from "@mui/icons-material/SystemUpdateAlt";
import logo from "../../assets/cloudreve.svg"; import logo from "../../assets/cloudreve.svg";
import { HomeRounded } from "@mui/icons-material"; import { HomeRounded } from "@mui/icons-material";
@ -33,12 +35,12 @@ export default function AboutSection() {
{ {
icon: <GitHubIcon fontSize="small" />, icon: <GitHubIcon fontSize="small" />,
label: "GitHub", label: "GitHub",
href: "https://github.com/cloudreve/desktop", href: "https://github.com/Dvorinka/cloudreve",
}, },
{ {
icon: <BugReportIcon fontSize="small" />, icon: <BugReportIcon fontSize="small" />,
label: t("about.reportIssue"), label: t("about.reportIssue"),
href: "https://github.com/cloudreve/desktop/issues", href: "https://github.com/Dvorinka/cloudreve/issues",
}, },
{ {
icon: <ForumIcon fontSize="small" />, icon: <ForumIcon fontSize="small" />,
@ -79,6 +81,16 @@ export default function AboutSection() {
</Box> </Box>
</Stack> </Stack>
<Button
variant="outlined"
size="small"
startIcon={<SystemUpdateAltIcon />}
onClick={() => invoke("show_update_window")}
sx={{ width: "fit-content", mb: 2 }}
>
{t("update.checkNow")}
</Button>
<Stack spacing={1}> <Stack spacing={1}>
{links.map((link) => ( {links.map((link) => (
<Link <Link

@ -599,7 +599,9 @@
"viewSetting": "اعدادات العرض", "viewSetting": "اعدادات العرض",
"saved": "تم الحفظ", "saved": "تم الحفظ",
"notSet": "لم يتم تعيينه", "notSet": "لم يتم تعيينه",
"deleteViewSetting": "حذف اعدادات العرض" "deleteViewSetting": "حذف اعدادات العرض",
"anonymous": "مجهول",
"shareTargetsCount": "{{count}} من الوجهات"
}, },
"uploader": { "uploader": {
"fileCopyName": "نسخة من ", "fileCopyName": "نسخة من ",
@ -979,8 +981,13 @@
"validDurationDays": "{{num}} يوم", "validDurationDays": "{{num}} يوم",
"reportTarget": "الذي تريد الإبلاغ عنه", "reportTarget": "الذي تريد الإبلاغ عنه",
"reportReason": "السبب", "reportReason": "السبب",
"reportReasonOptions": ["انتهاك حقوق الطبع والنشر", "محتوى ضار", "غير المرغوب به", "أخرى"], "reportReasonOptions": [
"انتهاك حقوق الطبع والنشر",
"محتوى ضار",
"غير المرغوب به",
"أخرى"
],
"reportDescription": "وصف إضافي", "reportDescription": "وصف إضافي",
"reportAbuseSuccess": "تم رفع التقرير." "reportAbuseSuccess": "تم رفع التقرير."
} }
} }

@ -102,5 +102,6 @@
"50005": "خطأ داخلي.", "50005": "خطأ داخلي.",
"50010": "العقدة المطلوبة غير متوفرة.", "50010": "العقدة المطلوبة غير متوفرة.",
"50011": "فشل في الاستعلام عن البيانات الوصفية للملف." "50011": "فشل في الاستعلام عن البيانات الوصفية للملف."
} },
} "save": "حفظ"
}

@ -1192,7 +1192,6 @@
"allowedHostsDes": "أسماء المضيفين أو عناوين IP المحددة (واحدة في كل سطر) التي يحق لها تجاوز التحقق من سلامة الرابط على هذه العقدة. يتم السماح دائمًا بأسماء المضيفات الخاصة بالموقع. استخدم هذه الميزة لإدراج اسم مضيف داخلي معين في القائمة البيضاء، بحيث يسمح للمستخدمين بالتنزيل منه.", "allowedHostsDes": "أسماء المضيفين أو عناوين IP المحددة (واحدة في كل سطر) التي يحق لها تجاوز التحقق من سلامة الرابط على هذه العقدة. يتم السماح دائمًا بأسماء المضيفات الخاصة بالموقع. استخدم هذه الميزة لإدراج اسم مضيف داخلي معين في القائمة البيضاء، بحيث يسمح للمستخدمين بالتنزيل منه.",
"allowedCIDRs": "نطاقات عناوين IP المسموح بها (CIDR)", "allowedCIDRs": "نطاقات عناوين IP المسموح بها (CIDR)",
"allowedCIDRsDes": "كتل CIDR (واحدة في كل سطر، IPv4 أو IPv6) التي يتم معاملة عناوين IP الخاصة بها على أنها آمنة حتى لو كان من المفترض رفضها عادةً. استخدم هذه الميزة لعرض شبكة فرعية LAN — على سبيل المثال جهاز NAS على 192.168.10.0/24 — دون تعطيل بقية إجراءات الفحص الأمني.", "allowedCIDRsDes": "كتل CIDR (واحدة في كل سطر، IPv4 أو IPv6) التي يتم معاملة عناوين IP الخاصة بها على أنها آمنة حتى لو كان من المفترض رفضها عادةً. استخدم هذه الميزة لعرض شبكة فرعية LAN — على سبيل المثال جهاز NAS على 192.168.10.0/24 — دون تعطيل بقية إجراءات الفحص الأمني.",
"webUIEndpoint": "نقطة نهاية Web UI",
"webUIEndpointDes": "نقطة نهاية Web UI لـ qBittorrent، مثل <0>http://127.0.0.1:8080/</0>.", "webUIEndpointDes": "نقطة نهاية Web UI لـ qBittorrent، مثل <0>http://127.0.0.1:8080/</0>.",
"tempPath": "مجلد التنزيل المؤقت", "tempPath": "مجلد التنزيل المؤقت",
"tempPathDes": "المجلد على العقدة الذي يستخدمه Aria2 كمجلد تنزيل مؤقت. تحتاج عملية Cloudreve على العقدة إلى أذونات القراءة والكتابة والتنفيذ على هذا المجلد، ويجب أن يتمكن برنامج التنزيل أيضًا من الوصول إليه. اتركه فارغًا لاستخدام مسار الملفات المؤقتة الافتراضي.", "tempPathDes": "المجلد على العقدة الذي يستخدمه Aria2 كمجلد تنزيل مؤقت. تحتاج عملية Cloudreve على العقدة إلى أذونات القراءة والكتابة والتنفيذ على هذا المجلد، ويجب أن يتمكن برنامج التنزيل أيضًا من الوصول إليه. اتركه فارغًا لاستخدام مسار الملفات المؤقتة الافتراضي.",
@ -1422,7 +1421,8 @@
"otherConditions": "شروط أخرى", "otherConditions": "شروط أخرى",
"shareLinkExisted": "لديه رابط مشاركة", "shareLinkExisted": "لديه رابط مشاركة",
"directLinkExisted": "لديه رابط مباشر", "directLinkExisted": "لديه رابط مباشر",
"isUploading": "قيد التحميل" "isUploading": "قيد التحميل",
"selectUser": "اختر مستخدمًا"
}, },
"entity": { "entity": {
"refenenceCount": "عدد المراجع", "refenenceCount": "عدد المراجع",
@ -1758,4 +1758,4 @@
"shareID": "معرف المشاركة", "shareID": "معرف المشاركة",
"reason": "السبب" "reason": "السبب"
} }
} }

@ -529,7 +529,7 @@
"everyone": "Alle anderen", "everyone": "Alle anderen",
"otherGroup": "Andere Benutzergruppen", "otherGroup": "Andere Benutzergruppen",
"sameGroup": "Dieselbe Benutzergruppe wie ich", "sameGroup": "Dieselbe Benutzergruppe wie ich",
"anonymous": "Anonyme Besucher", "anonymous": "Anonym",
"noResults": "Keine Ergebnisse", "noResults": "Keine Ergebnisse",
"searchGroupUser": "Benutzer oder Benutzergruppen suchen...", "searchGroupUser": "Benutzer oder Benutzergruppen suchen...",
"resetToDefault": "Auf Standard zurücksetzen", "resetToDefault": "Auf Standard zurücksetzen",
@ -664,7 +664,8 @@
"viewSetting": "Ansichtseinstellungen", "viewSetting": "Ansichtseinstellungen",
"saved": "Gespeichert", "saved": "Gespeichert",
"notSet": "Nicht gesetzt", "notSet": "Nicht gesetzt",
"deleteViewSetting": "Ansichtseinstellung löschen" "deleteViewSetting": "Ansichtseinstellung löschen",
"shareTargetsCount": "{{count}} Ziele"
}, },
"uploader": { "uploader": {
"fileCopyName": "Kopie_", "fileCopyName": "Kopie_",
@ -1108,7 +1109,12 @@
"report": "Missbrauch melden", "report": "Missbrauch melden",
"reportTarget": "Meldeobjekt", "reportTarget": "Meldeobjekt",
"reportReason": "Grund", "reportReason": "Grund",
"reportReasonOptions": ["Urheberrechtsverletzung", "Schädlicher Inhalt", "Spam", "Andere"], "reportReasonOptions": [
"Urheberrechtsverletzung",
"Schädlicher Inhalt",
"Spam",
"Andere"
],
"reportDescription": "Zusätzliche Beschreibung", "reportDescription": "Zusätzliche Beschreibung",
"reportAbuseSuccess": "Meldung eingereicht", "reportAbuseSuccess": "Meldung eingereicht",
"migrateStoragePolicy": "Speicherrichtlinie übertragen", "migrateStoragePolicy": "Speicherrichtlinie übertragen",
@ -1187,4 +1193,4 @@
"openPaymentLink": "Zahlungslink direkt öffnen", "openPaymentLink": "Zahlungslink direkt öffnen",
"creditReasonAdjust": "Manuelle Anpassung" "creditReasonAdjust": "Manuelle Anpassung"
} }
} }

@ -116,5 +116,6 @@
"40072": "Sie sind Administrator und können keine andere Gruppe erwerben.", "40072": "Sie sind Administrator und können keine andere Gruppe erwerben.",
"40084": "Ihr Konto ist passwortlos. Sie müssen mindestens ein verknüpftes Konto behalten.", "40084": "Ihr Konto ist passwortlos. Sie müssen mindestens ein verknüpftes Konto behalten.",
"40085": "Der Gesamtbetrag dieser Bestellung ist zu gering für den Checkout." "40085": "Der Gesamtbetrag dieser Bestellung ist zu gering für den Checkout."
} },
} "save": "Speichern"
}

@ -1428,7 +1428,8 @@
"otherConditions": "Andere Bedingungen", "otherConditions": "Andere Bedingungen",
"shareLinkExisted": "Hat Freigabe-Link", "shareLinkExisted": "Hat Freigabe-Link",
"directLinkExisted": "Hat direkten Link", "directLinkExisted": "Hat direkten Link",
"isUploading": "Wird hochgeladen" "isUploading": "Wird hochgeladen",
"selectUser": "Benutzer auswählen"
}, },
"entity": { "entity": {
"refenenceCount": "Referenzzähler", "refenenceCount": "Referenzzähler",
@ -1474,7 +1475,8 @@
"rawContent": "Roher Inhalt", "rawContent": "Roher Inhalt",
"confirmDelete": "Sind Sie sicher, dass Sie dieses Ereignis löschen möchten?", "confirmDelete": "Sind Sie sicher, dass Sie dieses Ereignis löschen möchten?",
"deleteXEvents": "{{num}} Ereignisse löschen", "deleteXEvents": "{{num}} Ereignisse löschen",
"confirmBatchDelete": "Sind Sie sicher, dass Sie {{num}} Ereignisse löschen möchten?" "confirmBatchDelete": "Sind Sie sicher, dass Sie {{num}} Ereignisse löschen möchten?",
"allEventTypes": "Alle Ereignistypen"
}, },
"share": { "share": {
"confirmBatchDelete": "Sind Sie sicher, dass Sie {{num}} Freigaben löschen möchten?", "confirmBatchDelete": "Sind Sie sicher, dass Sie {{num}} Freigaben löschen möchten?",
@ -1747,4 +1749,4 @@
"shareID": "Freigabe-ID", "shareID": "Freigabe-ID",
"reason": "Grund" "reason": "Grund"
} }
} }

@ -698,12 +698,13 @@
"notSet": "Not set", "notSet": "Not set",
"deleteViewSetting": "Delete view setting", "deleteViewSetting": "Delete view setting",
"shareTargets": "Share targets", "shareTargets": "Share targets",
"shareTargetsCount_one": "{{count}} file selected", "shareTargetsCount_one": "{{count}} target",
"shareTargetsCount_other": "{{count}} files selected", "shareTargetsCount_other": "{{count}} targets",
"publicListing": "List in public directory", "publicListing": "List in public directory",
"publicListingDes": "Show this share on the Discover page, visible to anyone including anonymous visitors. Not available for password-protected shares.", "publicListingDes": "Show this share on the Discover page, visible to anyone including anonymous visitors. Not available for password-protected shares.",
"hideReadme": "Hide readme file", "hideReadme": "Hide readme file",
"hideReadmeDes": "Keep the README file itself out of the share listing. Visitors still see the rendered readme." "hideReadmeDes": "Keep the README file itself out of the share listing. Visitors still see the rendered readme.",
"anonymous": "Anonymous"
}, },
"uploader": { "uploader": {
"fileCopyName": "Copy of ", "fileCopyName": "Copy of ",
@ -1218,4 +1219,4 @@
"discover": { "discover": {
"searchPlaceholder": "Search public shares" "searchPlaceholder": "Search public shares"
} }
} }

@ -105,5 +105,6 @@
"50010": "Desired node is unavailable.", "50010": "Desired node is unavailable.",
"50011": "Failed to query file metadata." "50011": "Failed to query file metadata."
}, },
"delete": "Delete" "delete": "Delete",
} "save": "Save"
}

@ -1611,7 +1611,8 @@
"isUploading": "Is uploading", "isUploading": "Is uploading",
"deletedState": "Deleted state", "deletedState": "Deleted state",
"liveOnly": "Live files only", "liveOnly": "Live files only",
"trashOnly": "Trash only" "trashOnly": "Trash only",
"selectUser": "Select user"
}, },
"entity": { "entity": {
"refenenceCount": "Reference count", "refenenceCount": "Reference count",

@ -529,7 +529,7 @@
"everyone": "Todos los demás", "everyone": "Todos los demás",
"otherGroup": "Otros grupos", "otherGroup": "Otros grupos",
"sameGroup": "Mismo grupo que yo", "sameGroup": "Mismo grupo que yo",
"anonymous": "Visitantes anónimos", "anonymous": "Anónimo",
"noResults": "Sin resultados", "noResults": "Sin resultados",
"searchGroupUser": "Buscar emails o grupos...", "searchGroupUser": "Buscar emails o grupos...",
"resetToDefault": "Restablecer a predeterminado", "resetToDefault": "Restablecer a predeterminado",
@ -660,7 +660,8 @@
"skipSoftDelete": "Eliminar permanentemente", "skipSoftDelete": "Eliminar permanentemente",
"skipSoftDeleteDes": "Omitir mover a papelera, eliminar permanentemente", "skipSoftDeleteDes": "Omitir mover a papelera, eliminar permanentemente",
"unlinkOnly": "Mantener archivos físicos", "unlinkOnly": "Mantener archivos físicos",
"unlinkOnlyDes": "Eliminar solo registros de archivos, los archivos físicos no serán eliminados." "unlinkOnlyDes": "Eliminar solo registros de archivos, los archivos físicos no serán eliminados.",
"shareTargetsCount": "{{count}} destinos"
}, },
"uploader": { "uploader": {
"fileCopyName": "Copia de ", "fileCopyName": "Copia de ",
@ -1106,7 +1107,12 @@
"report": "Reportar abuso", "report": "Reportar abuso",
"reportTarget": "Objeto del reporte", "reportTarget": "Objeto del reporte",
"reportReason": "Razón", "reportReason": "Razón",
"reportReasonOptions": ["Infracción de derechos de autor", "Contenido dañino", "Información basura", "Otro"], "reportReasonOptions": [
"Infracción de derechos de autor",
"Contenido dañino",
"Información basura",
"Otro"
],
"reportDescription": "Descripción adicional", "reportDescription": "Descripción adicional",
"reportAbuseSuccess": "Reporte enviado", "reportAbuseSuccess": "Reporte enviado",
"migrateStoragePolicy": "Transferir política de almacenamiento", "migrateStoragePolicy": "Transferir política de almacenamiento",
@ -1185,4 +1191,4 @@
"openPaymentLink": "Abrir enlace de pago directamente", "openPaymentLink": "Abrir enlace de pago directamente",
"creditReasonAdjust": "Ajuste manual" "creditReasonAdjust": "Ajuste manual"
} }
} }

@ -116,5 +116,6 @@
"40072": "Eres administrador, no puedes comprar otro grupo.", "40072": "Eres administrador, no puedes comprar otro grupo.",
"40084": "Tu cuenta no tiene contraseña, debes mantener al menos una cuenta vinculada.", "40084": "Tu cuenta no tiene contraseña, debes mantener al menos una cuenta vinculada.",
"40085": "El monto total de esta orden es demasiado pequeño para el pago." "40085": "El monto total de esta orden es demasiado pequeño para el pago."
} },
} "save": "Guardar"
}

@ -1421,7 +1421,8 @@
"otherConditions": "Otras condiciones", "otherConditions": "Otras condiciones",
"shareLinkExisted": "Tiene enlace de compartir", "shareLinkExisted": "Tiene enlace de compartir",
"directLinkExisted": "Tiene enlace directo", "directLinkExisted": "Tiene enlace directo",
"isUploading": "Está subiendo" "isUploading": "Está subiendo",
"selectUser": "Seleccionar usuario"
}, },
"entity": { "entity": {
"refenenceCount": "Conteo de referencia", "refenenceCount": "Conteo de referencia",
@ -1467,7 +1468,8 @@
"rawContent": "Contenido sin procesar", "rawContent": "Contenido sin procesar",
"confirmDelete": "¿Estás seguro de que quieres eliminar este evento?", "confirmDelete": "¿Estás seguro de que quieres eliminar este evento?",
"deleteXEvents": "Eliminar {{num}} eventos", "deleteXEvents": "Eliminar {{num}} eventos",
"confirmBatchDelete": "¿Estás seguro de que quieres eliminar {{num}} eventos?" "confirmBatchDelete": "¿Estás seguro de que quieres eliminar {{num}} eventos?",
"allEventTypes": "Todos los tipos de eventos"
}, },
"share": { "share": {
"confirmBatchDelete": "¿Estás seguro de que quieres eliminar {{num}} compartidos?", "confirmBatchDelete": "¿Estás seguro de que quieres eliminar {{num}} compartidos?",
@ -1756,4 +1758,4 @@
"shareID": "ID", "shareID": "ID",
"reason": "Razón" "reason": "Razón"
} }
} }

@ -529,7 +529,7 @@
"everyone": "Tous les autres", "everyone": "Tous les autres",
"otherGroup": "Autres groupes", "otherGroup": "Autres groupes",
"sameGroup": "Même groupe que moi", "sameGroup": "Même groupe que moi",
"anonymous": "Visiteurs anonymes", "anonymous": "Anonyme",
"noResults": "Aucun résultat", "noResults": "Aucun résultat",
"searchGroupUser": "Rechercher des e-mails ou des groupes...", "searchGroupUser": "Rechercher des e-mails ou des groupes...",
"resetToDefault": "Réinitialiser par défaut", "resetToDefault": "Réinitialiser par défaut",
@ -664,7 +664,8 @@
"viewSetting": "Paramètre de vue", "viewSetting": "Paramètre de vue",
"saved": "Enregistré", "saved": "Enregistré",
"notSet": "Non défini", "notSet": "Non défini",
"deleteViewSetting": "Supprimer le paramètre de vue" "deleteViewSetting": "Supprimer le paramètre de vue",
"shareTargetsCount": "{{count}} cibles"
}, },
"uploader": { "uploader": {
"fileCopyName": "Copie de ", "fileCopyName": "Copie de ",
@ -1110,7 +1111,12 @@
"report": "Signaler un abus", "report": "Signaler un abus",
"reportTarget": "Cible du signalement", "reportTarget": "Cible du signalement",
"reportReason": "Raison", "reportReason": "Raison",
"reportReasonOptions": ["Violation de droits d'auteur", "Contenu nuisible", "Spam", "Autre"], "reportReasonOptions": [
"Violation de droits d'auteur",
"Contenu nuisible",
"Spam",
"Autre"
],
"reportDescription": "Description supplémentaire", "reportDescription": "Description supplémentaire",
"reportAbuseSuccess": "Signalement soumis.", "reportAbuseSuccess": "Signalement soumis.",
"migrateStoragePolicy": "Migrer la stratégie de stockage", "migrateStoragePolicy": "Migrer la stratégie de stockage",
@ -1189,4 +1195,4 @@
"openPaymentLink": "Ouvrir le lien de paiement", "openPaymentLink": "Ouvrir le lien de paiement",
"creditReasonAdjust": "Ajustement manuel" "creditReasonAdjust": "Ajustement manuel"
} }
} }

@ -116,5 +116,6 @@
"40072": "Vous êtes administrateur, vous ne pouvez pas acheter d'autre groupe.", "40072": "Vous êtes administrateur, vous ne pouvez pas acheter d'autre groupe.",
"40084": "Votre compte est sans mot de passe, vous devez conserver au moins un compte lié.", "40084": "Votre compte est sans mot de passe, vous devez conserver au moins un compte lié.",
"40085": "Le montant total de cette commande est trop petit pour le paiement." "40085": "Le montant total de cette commande est trop petit pour le paiement."
} },
} "save": "Enregistrer"
}

@ -1421,7 +1421,8 @@
"otherConditions": "Autres conditions", "otherConditions": "Autres conditions",
"shareLinkExisted": "A un lien de partage", "shareLinkExisted": "A un lien de partage",
"directLinkExisted": "A un lien direct", "directLinkExisted": "A un lien direct",
"isUploading": "En cours de téléchargement" "isUploading": "En cours de téléchargement",
"selectUser": "Sélectionner un utilisateur"
}, },
"entity": { "entity": {
"refenenceCount": "Nombre de références", "refenenceCount": "Nombre de références",
@ -1467,7 +1468,8 @@
"rawContent": "Contenu brut", "rawContent": "Contenu brut",
"confirmDelete": "Êtes-vous sûr de vouloir supprimer cet événement ?", "confirmDelete": "Êtes-vous sûr de vouloir supprimer cet événement ?",
"deleteXEvents": "Supprimer {{num}} événements", "deleteXEvents": "Supprimer {{num}} événements",
"confirmBatchDelete": "Êtes-vous sûr de vouloir supprimer {{num}} événements ?" "confirmBatchDelete": "Êtes-vous sûr de vouloir supprimer {{num}} événements ?",
"allEventTypes": "Tous les types d'événements"
}, },
"share": { "share": {
"confirmBatchDelete": "Êtes-vous sûr de vouloir supprimer {{num}} partages ?", "confirmBatchDelete": "Êtes-vous sûr de vouloir supprimer {{num}} partages ?",
@ -1756,4 +1758,4 @@
"shareID": "ID partagé", "shareID": "ID partagé",
"reason": "Raison" "reason": "Raison"
} }
} }

@ -529,7 +529,7 @@
"everyone": "Tutti gli altri", "everyone": "Tutti gli altri",
"otherGroup": "Altri gruppi", "otherGroup": "Altri gruppi",
"sameGroup": "Stesso gruppo di me", "sameGroup": "Stesso gruppo di me",
"anonymous": "Visitatori anonimi", "anonymous": "Anonimo",
"noResults": "Nessun risultato", "noResults": "Nessun risultato",
"searchGroupUser": "Cerca email o gruppi...", "searchGroupUser": "Cerca email o gruppi...",
"resetToDefault": "Ripristina predefinito", "resetToDefault": "Ripristina predefinito",
@ -660,7 +660,8 @@
"skipSoftDelete": "Elimina permanentemente", "skipSoftDelete": "Elimina permanentemente",
"skipSoftDeleteDes": "Salta lo spostamento nel cestino, elimina permanentemente", "skipSoftDeleteDes": "Salta lo spostamento nel cestino, elimina permanentemente",
"unlinkOnly": "Mantieni file fisici", "unlinkOnly": "Mantieni file fisici",
"unlinkOnlyDes": "Elimina solo i record dei file, i file fisici non saranno eliminati." "unlinkOnlyDes": "Elimina solo i record dei file, i file fisici non saranno eliminati.",
"shareTargetsCount": "{{count}} destinazioni"
}, },
"uploader": { "uploader": {
"fileCopyName": "Copia di ", "fileCopyName": "Copia di ",
@ -1106,7 +1107,12 @@
"report": "Segnala abuso", "report": "Segnala abuso",
"reportTarget": "Target segnalazione", "reportTarget": "Target segnalazione",
"reportReason": "Motivo", "reportReason": "Motivo",
"reportReasonOptions": ["Violazione copyright", "Contenuto dannoso", "Spam", "Altro"], "reportReasonOptions": [
"Violazione copyright",
"Contenuto dannoso",
"Spam",
"Altro"
],
"reportDescription": "Descrizione aggiuntiva", "reportDescription": "Descrizione aggiuntiva",
"reportAbuseSuccess": "Segnalazione inviata.", "reportAbuseSuccess": "Segnalazione inviata.",
"migrateStoragePolicy": "Migra policy di archiviazione", "migrateStoragePolicy": "Migra policy di archiviazione",
@ -1183,4 +1189,4 @@
"openPaymentLink": "Apri link di pagamento", "openPaymentLink": "Apri link di pagamento",
"creditReasonAdjust": "Aggiustamento manuale" "creditReasonAdjust": "Aggiustamento manuale"
} }
} }

@ -116,5 +116,6 @@
"40072": "Sei amministratore, non puoi acquistare altri gruppi.", "40072": "Sei amministratore, non puoi acquistare altri gruppi.",
"40084": "Il tuo account è senza password, devi mantenere almeno un account collegato.", "40084": "Il tuo account è senza password, devi mantenere almeno un account collegato.",
"40085": "L'importo totale di questo ordine è troppo piccolo per il checkout." "40085": "L'importo totale di questo ordine è troppo piccolo per il checkout."
} },
} "save": "Salva"
}

@ -1420,7 +1420,8 @@
"otherConditions": "Altre condizioni", "otherConditions": "Altre condizioni",
"shareLinkExisted": "Ha link di condivisione", "shareLinkExisted": "Ha link di condivisione",
"directLinkExisted": "Ha link diretto", "directLinkExisted": "Ha link diretto",
"isUploading": "In caricamento" "isUploading": "In caricamento",
"selectUser": "Seleziona utente"
}, },
"entity": { "entity": {
"refenenceCount": "Conteggio riferimenti", "refenenceCount": "Conteggio riferimenti",
@ -1466,7 +1467,8 @@
"rawContent": "Contenuto raw", "rawContent": "Contenuto raw",
"confirmDelete": "Sei sicuro di voler eliminare questo evento?", "confirmDelete": "Sei sicuro di voler eliminare questo evento?",
"deleteXEvents": "Elimina {{num}} eventi", "deleteXEvents": "Elimina {{num}} eventi",
"confirmBatchDelete": "Sei sicuro di voler eliminare {{num}} eventi?" "confirmBatchDelete": "Sei sicuro di voler eliminare {{num}} eventi?",
"allEventTypes": "Tutti i tipi di evento"
}, },
"share": { "share": {
"confirmBatchDelete": "Sei sicuro di voler eliminare {{num}} condivisioni?", "confirmBatchDelete": "Sei sicuro di voler eliminare {{num}} condivisioni?",
@ -1755,4 +1757,4 @@
"shareID": "ID Condiviso", "shareID": "ID Condiviso",
"reason": "Motivo" "reason": "Motivo"
} }
} }

@ -611,7 +611,9 @@
"viewSetting": "表示設定", "viewSetting": "表示設定",
"saved": "保存されました", "saved": "保存されました",
"notSet": "未設定", "notSet": "未設定",
"deleteViewSetting": "表示設定の削除" "deleteViewSetting": "表示設定の削除",
"anonymous": "匿名",
"shareTargetsCount": "{{count}} 件の対象"
}, },
"uploader": { "uploader": {
"fileCopyName": "コピー_", "fileCopyName": "コピー_",
@ -994,8 +996,13 @@
"validDurationDays": "{{num}} 日", "validDurationDays": "{{num}} 日",
"reportTarget": "報告対象", "reportTarget": "報告対象",
"reportReason": "理由", "reportReason": "理由",
"reportReasonOptions": ["著作権侵害", "有害なコンテンツ", "スパム", "その他"], "reportReasonOptions": [
"著作権侵害",
"有害なコンテンツ",
"スパム",
"その他"
],
"reportDescription": "詳細説明", "reportDescription": "詳細説明",
"reportAbuseSuccess": "報告を受け付けました" "reportAbuseSuccess": "報告を受け付けました"
} }
} }

@ -102,5 +102,6 @@
"50005": "内部エラーが発生しました ({{message}})", "50005": "内部エラーが発生しました ({{message}})",
"50010": "対象ノードが利用できません", "50010": "対象ノードが利用できません",
"50011": "ファイルメタデータの取得に失敗しました" "50011": "ファイルメタデータの取得に失敗しました"
} },
} "save": "保存"
}

@ -1422,7 +1422,8 @@
"otherConditions": "その他の条件", "otherConditions": "その他の条件",
"shareLinkExisted": "共有リンクが存在", "shareLinkExisted": "共有リンクが存在",
"directLinkExisted": "直接リンクが存在", "directLinkExisted": "直接リンクが存在",
"isUploading": "アップロード中" "isUploading": "アップロード中",
"selectUser": "ユーザーを選択"
}, },
"entity": { "entity": {
"refenenceCount": "参照回数", "refenenceCount": "参照回数",
@ -1442,7 +1443,7 @@
"cleanupNotAfter": "この日付以前", "cleanupNotAfter": "この日付以前",
"cleanupEventTypes": "イベント種類", "cleanupEventTypes": "イベント種類",
"cleanupEventTypesDes": "イベント種類を選択してください。空の場合はすべての種類を削除します。", "cleanupEventTypesDes": "イベント種類を選択してください。空の場合はすべての種類を削除します。",
"allEventTypes": "すべてのイベントタイプ", "allEventTypes": "すべてのイベント種別",
"initiator": "発信者", "initiator": "発信者",
"event": "イベント", "event": "イベント",
"userID": "ユーザーID", "userID": "ユーザーID",
@ -1758,4 +1759,4 @@
"shareID": "共有 ID", "shareID": "共有 ID",
"reason": "原因" "reason": "原因"
} }
} }

@ -529,7 +529,7 @@
"everyone": "기타 모든 사람", "everyone": "기타 모든 사람",
"otherGroup": "다른 사용자 그룹", "otherGroup": "다른 사용자 그룹",
"sameGroup": "나와 같은 사용자 그룹", "sameGroup": "나와 같은 사용자 그룹",
"anonymous": "익명 방문자", "anonymous": "익명",
"noResults": "결과 없음", "noResults": "결과 없음",
"searchGroupUser": "사용자 또는 사용자 그룹 검색...", "searchGroupUser": "사용자 또는 사용자 그룹 검색...",
"resetToDefault": "기본값으로 재설정", "resetToDefault": "기본값으로 재설정",
@ -664,7 +664,8 @@
"viewSetting": "보기 설정", "viewSetting": "보기 설정",
"saved": "저장됨", "saved": "저장됨",
"notSet": "설정되지 않음", "notSet": "설정되지 않음",
"deleteViewSetting": "보기 설정 삭제" "deleteViewSetting": "보기 설정 삭제",
"shareTargetsCount": "대상 {{count}}개"
}, },
"uploader": { "uploader": {
"fileCopyName": "사본_", "fileCopyName": "사본_",
@ -1110,7 +1111,12 @@
"report": "남용 신고", "report": "남용 신고",
"reportTarget": "신고 대상", "reportTarget": "신고 대상",
"reportReason": "이유", "reportReason": "이유",
"reportReasonOptions": ["침해", "유해 콘텐츠", "스팸 정보", "기타"], "reportReasonOptions": [
"침해",
"유해 콘텐츠",
"스팸 정보",
"기타"
],
"reportDescription": "추가 설명", "reportDescription": "추가 설명",
"reportAbuseSuccess": "신고가 제출되었습니다", "reportAbuseSuccess": "신고가 제출되었습니다",
"migrateStoragePolicy": "저장 정책 전송", "migrateStoragePolicy": "저장 정책 전송",
@ -1189,4 +1195,4 @@
"openPaymentLink": "결제 링크 직접 열기", "openPaymentLink": "결제 링크 직접 열기",
"creditReasonAdjust": "수동 조정" "creditReasonAdjust": "수동 조정"
} }
} }

@ -116,5 +116,6 @@
"40072": "관리자는 다른 사용자 그룹으로 업그레이드할 수 없습니다", "40072": "관리자는 다른 사용자 그룹으로 업그레이드할 수 없습니다",
"40084": "귀하의 계정은 비밀번호가 없는 계정이므로 최소 하나의 연결된 계정을 유지해야 합니다", "40084": "귀하의 계정은 비밀번호가 없는 계정이므로 최소 하나의 연결된 계정을 유지해야 합니다",
"40085": "주문 금액이 너무 작아 결제를 계속할 수 없습니다" "40085": "주문 금액이 너무 작아 결제를 계속할 수 없습니다"
} },
} "save": "저장"
}

@ -1421,7 +1421,8 @@
"otherConditions": "기타 조건", "otherConditions": "기타 조건",
"shareLinkExisted": "공유 링크 존재", "shareLinkExisted": "공유 링크 존재",
"directLinkExisted": "중계 직접 링크 존재", "directLinkExisted": "중계 직접 링크 존재",
"isUploading": "업로드 중" "isUploading": "업로드 중",
"selectUser": "사용자 선택"
}, },
"entity": { "entity": {
"refenenceCount": "참조 횟수", "refenenceCount": "참조 횟수",
@ -1467,7 +1468,8 @@
"rawContent": "원본 기록", "rawContent": "원본 기록",
"confirmDelete": "이 이벤트를 삭제하시겠습니까?", "confirmDelete": "이 이벤트를 삭제하시겠습니까?",
"deleteXEvents": "{{num}}개 이벤트 삭제", "deleteXEvents": "{{num}}개 이벤트 삭제",
"confirmBatchDelete": "{{num}}개 이벤트를 삭제하시겠습니까?" "confirmBatchDelete": "{{num}}개 이벤트를 삭제하시겠습니까?",
"allEventTypes": "모든 이벤트 유형"
}, },
"share": { "share": {
"confirmBatchDelete": "{{num}}개 공유를 삭제하시겠습니까?", "confirmBatchDelete": "{{num}}개 공유를 삭제하시겠습니까?",
@ -1755,4 +1757,4 @@
"shareID": "공유 ID", "shareID": "공유 ID",
"reason": "원인" "reason": "원인"
} }
} }

@ -611,7 +611,9 @@
"viewSetting": "Ustawienia widoku", "viewSetting": "Ustawienia widoku",
"saved": "Zapisano", "saved": "Zapisano",
"notSet": "Nieustawione", "notSet": "Nieustawione",
"deleteViewSetting": "Usuń ustawienia widoku" "deleteViewSetting": "Usuń ustawienia widoku",
"anonymous": "Anonimowy",
"shareTargetsCount": "{{count}} cele"
}, },
"uploader": { "uploader": {
"fileCopyName": "Kopia ", "fileCopyName": "Kopia ",
@ -994,8 +996,13 @@
"validDurationDays": "{{num}} dni", "validDurationDays": "{{num}} dni",
"reportTarget": "Cel zgłoszenia", "reportTarget": "Cel zgłoszenia",
"reportReason": "Powód", "reportReason": "Powód",
"reportReasonOptions": ["Naruszenie praw autorskich", "Szkodliwa treść", "Spam", "Inne"], "reportReasonOptions": [
"Naruszenie praw autorskich",
"Szkodliwa treść",
"Spam",
"Inne"
],
"reportDescription": "Dodatkowy opis", "reportDescription": "Dodatkowy opis",
"reportAbuseSuccess": "Zgłoszenie przesłane." "reportAbuseSuccess": "Zgłoszenie przesłane."
} }
} }

@ -102,5 +102,6 @@
"50005": "Błąd wewnętrzny.", "50005": "Błąd wewnętrzny.",
"50010": "Żądany węzeł jest niedostępny.", "50010": "Żądany węzeł jest niedostępny.",
"50011": "Nie udało się pobrać metadanych pliku." "50011": "Nie udało się pobrać metadanych pliku."
} },
} "save": "Zapisz"
}

@ -1422,7 +1422,8 @@
"otherConditions": "Inne warunki", "otherConditions": "Inne warunki",
"shareLinkExisted": "Posiada link udostępniania", "shareLinkExisted": "Posiada link udostępniania",
"directLinkExisted": "Posiada link bezpośredni", "directLinkExisted": "Posiada link bezpośredni",
"isUploading": "Jest przesyłany" "isUploading": "Jest przesyłany",
"selectUser": "Wybierz użytkownika"
}, },
"entity": { "entity": {
"refenenceCount": "Liczba odniesień", "refenenceCount": "Liczba odniesień",
@ -1758,4 +1759,4 @@
"shareID": "ID Udostępnienia", "shareID": "ID Udostępnienia",
"reason": "Powód" "reason": "Powód"
} }
} }

@ -529,7 +529,7 @@
"everyone": "Todos os outros", "everyone": "Todos os outros",
"otherGroup": "Outros grupos", "otherGroup": "Outros grupos",
"sameGroup": "Mesmo grupo que eu", "sameGroup": "Mesmo grupo que eu",
"anonymous": "Visitantes anônimos", "anonymous": "Anônimo",
"noResults": "Nenhum resultado", "noResults": "Nenhum resultado",
"searchGroupUser": "Buscar por e-mails ou grupos...", "searchGroupUser": "Buscar por e-mails ou grupos...",
"resetToDefault": "Redefinir para padrão", "resetToDefault": "Redefinir para padrão",
@ -664,7 +664,8 @@
"viewSetting": "Configuração de visualização", "viewSetting": "Configuração de visualização",
"saved": "Salvo", "saved": "Salvo",
"notSet": "Não definido", "notSet": "Não definido",
"deleteViewSetting": "Excluir configuração de visualização" "deleteViewSetting": "Excluir configuração de visualização",
"shareTargetsCount": "{{count}} destinos"
}, },
"uploader": { "uploader": {
"fileCopyName": "Cópia de ", "fileCopyName": "Cópia de ",
@ -1110,7 +1111,12 @@
"report": "Denunciar abuso", "report": "Denunciar abuso",
"reportTarget": "Alvo da denúncia", "reportTarget": "Alvo da denúncia",
"reportReason": "Razão", "reportReason": "Razão",
"reportReasonOptions": ["Violação de direitos autorais", "Conteúdo prejudicial", "Spam", "Outro"], "reportReasonOptions": [
"Violação de direitos autorais",
"Conteúdo prejudicial",
"Spam",
"Outro"
],
"reportDescription": "Descrição adicional", "reportDescription": "Descrição adicional",
"reportAbuseSuccess": "Denúncia enviada.", "reportAbuseSuccess": "Denúncia enviada.",
"migrateStoragePolicy": "Migrar política de armazenamento", "migrateStoragePolicy": "Migrar política de armazenamento",
@ -1189,4 +1195,4 @@
"openPaymentLink": "Abrir link de pagamento", "openPaymentLink": "Abrir link de pagamento",
"creditReasonAdjust": "Ajuste manual" "creditReasonAdjust": "Ajuste manual"
} }
} }

@ -116,5 +116,6 @@
"40072": "Você é administrador, não pode comprar outro grupo.", "40072": "Você é administrador, não pode comprar outro grupo.",
"40084": "Sua conta não possui senha, você deve manter pelo menos uma conta vinculada.", "40084": "Sua conta não possui senha, você deve manter pelo menos uma conta vinculada.",
"40085": "O valor total deste pedido é muito pequeno para checkout." "40085": "O valor total deste pedido é muito pequeno para checkout."
} },
} "save": "Salvar"
}

@ -1421,7 +1421,8 @@
"otherConditions": "Outras condições", "otherConditions": "Outras condições",
"shareLinkExisted": "Tem link de compartilhamento", "shareLinkExisted": "Tem link de compartilhamento",
"directLinkExisted": "Tem link direto", "directLinkExisted": "Tem link direto",
"isUploading": "Está enviando" "isUploading": "Está enviando",
"selectUser": "Selecionar usuário"
}, },
"entity": { "entity": {
"refenenceCount": "Contagem de referência", "refenenceCount": "Contagem de referência",
@ -1467,7 +1468,8 @@
"rawContent": "Conteúdo bruto", "rawContent": "Conteúdo bruto",
"confirmDelete": "Tem certeza de que deseja excluir este evento?", "confirmDelete": "Tem certeza de que deseja excluir este evento?",
"deleteXEvents": "Excluir {{num}} eventos", "deleteXEvents": "Excluir {{num}} eventos",
"confirmBatchDelete": "Tem certeza de que deseja excluir {{num}} eventos?" "confirmBatchDelete": "Tem certeza de que deseja excluir {{num}} eventos?",
"allEventTypes": "Todos os tipos de evento"
}, },
"share": { "share": {
"confirmBatchDelete": "Tem certeza de que deseja excluir {{num}} compartilhamentos?", "confirmBatchDelete": "Tem certeza de que deseja excluir {{num}} compartilhamentos?",
@ -1756,4 +1758,4 @@
"shareID": "ID compartilhado", "shareID": "ID compartilhado",
"reason": "Razão" "reason": "Razão"
} }
} }

@ -529,7 +529,7 @@
"everyone": "Все остальные", "everyone": "Все остальные",
"otherGroup": "Другие группы пользователей", "otherGroup": "Другие группы пользователей",
"sameGroup": "Та же группа пользователей, что и я", "sameGroup": "Та же группа пользователей, что и я",
"anonymous": "Анонимные посетители", "anonymous": "Анонимный",
"noResults": "Нет результатов", "noResults": "Нет результатов",
"searchGroupUser": "Поиск пользователей или групп пользователей...", "searchGroupUser": "Поиск пользователей или групп пользователей...",
"resetToDefault": "Сбросить к значениям по умолчанию", "resetToDefault": "Сбросить к значениям по умолчанию",
@ -664,7 +664,8 @@
"viewSetting": "Настройки просмотра", "viewSetting": "Настройки просмотра",
"saved": "Сохранено", "saved": "Сохранено",
"notSet": "Не установлено", "notSet": "Не установлено",
"deleteViewSetting": "Удалить настройки просмотра" "deleteViewSetting": "Удалить настройки просмотра",
"shareTargetsCount": "{{count}} целей"
}, },
"uploader": { "uploader": {
"fileCopyName": "Копия_", "fileCopyName": "Копия_",
@ -1110,7 +1111,12 @@
"report": "Сообщить о злоупотреблении", "report": "Сообщить о злоупотреблении",
"reportTarget": "Объект жалобы", "reportTarget": "Объект жалобы",
"reportReason": "Причина", "reportReason": "Причина",
"reportReasonOptions": ["Нарушение авторских прав", "Вредоносный контент", "Спам", "Другое"], "reportReasonOptions": [
"Нарушение авторских прав",
"Вредоносный контент",
"Спам",
"Другое"
],
"reportDescription": "Дополнительное описание", "reportDescription": "Дополнительное описание",
"reportAbuseSuccess": "Жалоба подана", "reportAbuseSuccess": "Жалоба подана",
"migrateStoragePolicy": "Перенести политику хранения", "migrateStoragePolicy": "Перенести политику хранения",
@ -1189,4 +1195,4 @@
"openPaymentLink": "Открыть платёжную ссылку напрямую", "openPaymentLink": "Открыть платёжную ссылку напрямую",
"creditReasonAdjust": "Ручная корректировка" "creditReasonAdjust": "Ручная корректировка"
} }
} }

@ -116,5 +116,6 @@
"40072": "Администратор не может перейти в другую группу пользователей", "40072": "Администратор не может перейти в другую группу пользователей",
"40084": "Ваш аккаунт является беспарольным, вы должны оставить хотя бы один связанный аккаунт", "40084": "Ваш аккаунт является беспарольным, вы должны оставить хотя бы один связанный аккаунт",
"40085": "Сумма заказа слишком мала для продолжения оплаты" "40085": "Сумма заказа слишком мала для продолжения оплаты"
} },
} "save": "Сохранить"
}

@ -1422,7 +1422,8 @@
"otherConditions": "Другие условия", "otherConditions": "Другие условия",
"shareLinkExisted": "Существует ссылка для общего доступа", "shareLinkExisted": "Существует ссылка для общего доступа",
"directLinkExisted": "Существует прямая ссылка", "directLinkExisted": "Существует прямая ссылка",
"isUploading": "Загружается" "isUploading": "Загружается",
"selectUser": "Выбрать пользователя"
}, },
"entity": { "entity": {
"refenenceCount": "Количество ссылок", "refenenceCount": "Количество ссылок",
@ -1468,7 +1469,8 @@
"rawContent": "Исходная запись", "rawContent": "Исходная запись",
"confirmDelete": "Подтвердите удаление этого события?", "confirmDelete": "Подтвердите удаление этого события?",
"deleteXEvents": "Удалить {{num}} событий", "deleteXEvents": "Удалить {{num}} событий",
"confirmBatchDelete": "Подтвердите удаление {{num}} событий?" "confirmBatchDelete": "Подтвердите удаление {{num}} событий?",
"allEventTypes": "Все типы событий"
}, },
"share": { "share": {
"confirmBatchDelete": "Подтвердите удаление {{num}} общих доступов?", "confirmBatchDelete": "Подтвердите удаление {{num}} общих доступов?",
@ -1757,4 +1759,4 @@
"shareID": "ID общего ресурса", "shareID": "ID общего ресурса",
"reason": "Причина" "reason": "Причина"
} }
} }

@ -703,7 +703,9 @@
"publicListing": "收录到公开目录", "publicListing": "收录到公开目录",
"publicListingDes": "将此分享显示在“发现”页,任何人(包括未登录访客)可见。带密码的分享不可用。", "publicListingDes": "将此分享显示在“发现”页,任何人(包括未登录访客)可见。带密码的分享不可用。",
"hideReadme": "隐藏 README 文件", "hideReadme": "隐藏 README 文件",
"hideReadmeDes": "在分享文件列表中隐藏 README 文件本身,访客仍可看到渲染后的说明内容。" "hideReadmeDes": "在分享文件列表中隐藏 README 文件本身,访客仍可看到渲染后的说明内容。",
"anonymous": "匿名",
"shareTargetsCount": "{{count}} 个目标"
}, },
"uploader": { "uploader": {
"fileCopyName": "副本_", "fileCopyName": "副本_",
@ -1218,4 +1220,4 @@
"discover": { "discover": {
"searchPlaceholder": "搜索公开分享" "searchPlaceholder": "搜索公开分享"
} }
} }

@ -106,5 +106,6 @@
"50011": "文件元信息查询失败" "50011": "文件元信息查询失败"
}, },
"delete": "删除", "delete": "删除",
"40017": "该账号已被封禁。{{message}}" "40017": "该账号已被封禁。{{message}}",
} "save": "保存"
}

@ -1611,7 +1611,8 @@
"isUploading": "上传中", "isUploading": "上传中",
"deletedState": "删除状态", "deletedState": "删除状态",
"liveOnly": "仅未删除", "liveOnly": "仅未删除",
"trashOnly": "仅回收站" "trashOnly": "仅回收站",
"selectUser": "选择用户"
}, },
"entity": { "entity": {
"refenenceCount": "引用次数", "refenenceCount": "引用次数",
@ -1666,7 +1667,8 @@
"noEvents": "暂无事件记录", "noEvents": "暂无事件记录",
"confirmDelete": "确认要删除此事件?", "confirmDelete": "确认要删除此事件?",
"deleteXEvents": "删除 {{num}} 个事件", "deleteXEvents": "删除 {{num}} 个事件",
"confirmBatchDelete": "确认要删除 {{num}} 个事件?" "confirmBatchDelete": "确认要删除 {{num}} 个事件?",
"allEventTypes": "全部事件类型"
}, },
"share": { "share": {
"confirmBatchDelete": "确认要删除 {{num}} 个分享?", "confirmBatchDelete": "确认要删除 {{num}} 个分享?",

@ -611,7 +611,9 @@
"viewSetting": "視圖設定", "viewSetting": "視圖設定",
"saved": "已保存", "saved": "已保存",
"notSet": "未設定", "notSet": "未設定",
"deleteViewSetting": "刪除視圖設定" "deleteViewSetting": "刪除視圖設定",
"anonymous": "匿名",
"shareTargetsCount": "{{count}} 個目標"
}, },
"uploader": { "uploader": {
"fileCopyName": "副本_", "fileCopyName": "副本_",
@ -991,8 +993,13 @@
"validDurationDays": "{{num}} 天", "validDurationDays": "{{num}} 天",
"reportTarget": "舉報對象", "reportTarget": "舉報對象",
"reportReason": "原因", "reportReason": "原因",
"reportReasonOptions": ["侵權", "有害內容", "垃圾訊息", "其他"], "reportReasonOptions": [
"侵權",
"有害內容",
"垃圾訊息",
"其他"
],
"reportDescription": "補充說明", "reportDescription": "補充說明",
"reportAbuseSuccess": "舉報已提交" "reportAbuseSuccess": "舉報已提交"
} }
} }

@ -102,5 +102,6 @@
"50005": "內部錯誤 ({{message}})", "50005": "內部錯誤 ({{message}})",
"50010": "目標節點不可用", "50010": "目標節點不可用",
"50011": "檔案元資訊查詢失敗" "50011": "檔案元資訊查詢失敗"
} },
} "save": "儲存"
}

@ -1422,7 +1422,8 @@
"otherConditions": "其他條件", "otherConditions": "其他條件",
"shareLinkExisted": "有分享連結", "shareLinkExisted": "有分享連結",
"directLinkExisted": "有中轉直鏈", "directLinkExisted": "有中轉直鏈",
"isUploading": "上傳中" "isUploading": "上傳中",
"selectUser": "選擇使用者"
}, },
"entity": { "entity": {
"refenenceCount": "引用次數", "refenenceCount": "引用次數",
@ -1442,7 +1443,7 @@
"cleanupNotAfter": "在此日期之前", "cleanupNotAfter": "在此日期之前",
"cleanupEventTypes": "事件類型", "cleanupEventTypes": "事件類型",
"cleanupEventTypesDes": "選擇要清理的事件類型,留空表示清理所有類型。", "cleanupEventTypesDes": "選擇要清理的事件類型,留空表示清理所有類型。",
"allEventTypes": "所有事件類型", "allEventTypes": "全部事件類型",
"initiator": "發起者", "initiator": "發起者",
"event": "事件", "event": "事件",
"userID": "使用者 ID", "userID": "使用者 ID",
@ -1758,4 +1759,4 @@
"shareID": "分享 ID", "shareID": "分享 ID",
"reason": "原因" "reason": "原因"
} }
} }

@ -61,7 +61,7 @@ export const getTaskStatusText = (status: TaskStatus, t: TFunction) => {
case TaskStatus.completed: case TaskStatus.completed:
return t("application:setting.finished"); return t("application:setting.finished");
default: default:
return t("application:uplaoder.unknownStatus"); return t("application:uploader.unknownStatus");
} }
}; };

@ -125,7 +125,7 @@ const Uploader = () => {
if (e instanceof UploaderError) { if (e instanceof UploaderError) {
enqueueSnackbar(e.Message(), { variant: "warning" }); enqueueSnackbar(e.Message(), { variant: "warning" });
} else { } else {
enqueueSnackbar(t("uploader:unknownError", { msg: e.message }), { enqueueSnackbar(t("application:uploader.unknownError", { msg: e.message }), {
variant: "error", variant: "error",
}); });
} }

Loading…
Cancel
Save