feat(frontend): i18n expansion, admin/profile i18n, grid/list view fix, empty state

- Add 5 new locales (hi, ar, ru, ja, ko) — now 14 total
- Admin panel: 117 i18n keys, confirm modal, animated tabs, no inline handlers
- Profile page: 58 i18n keys with data-i18n attributes
- Fix i18n safeT() shadowing bug and translationsLoaded timing
- Fix grid/list view: list header no longer shows in grid mode on login
- Fix classList.toggle hidden sync for view switching across all nav functions
- Revert .hidden important that broke login page rendering
- Add files empty state (no_files + empty_hint) with translations
- Fix language selector dropdown scroll and styling
- Fix admin panel scroll with sticky tabs
This commit is contained in:
Diocrafts
2026-03-09 00:08:34 +01:00
parent f409a9edd7
commit df336da679
43 changed files with 6645 additions and 2043 deletions
@@ -6,7 +6,7 @@
use crate::application::dtos::app_password_dto::CreateAppPasswordRequestDto;
use crate::common::di::AppState;
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::AuthUser;
use axum::extract::State;
use axum::routing::{delete, get, post};
use axum::{Json, Router};
@@ -26,7 +26,7 @@ pub fn app_password_routes() -> Router<Arc<AppState>> {
/// Returns the plain-text password ONCE. The user must copy it immediately.
async fn create_app_password(
State(state): State<Arc<AppState>>,
axum::Extension(user): axum::Extension<CurrentUser>,
user: AuthUser,
Json(request): Json<CreateAppPasswordRequestDto>,
) -> Result<Json<crate::application::dtos::app_password_dto::AppPasswordCreatedResponseDto>, AppError>
{
@@ -48,7 +48,7 @@ async fn create_app_password(
/// Never returns plain-text passwords (only prefix + metadata).
async fn list_app_passwords(
State(state): State<Arc<AppState>>,
axum::Extension(user): axum::Extension<CurrentUser>,
user: AuthUser,
) -> Result<Json<crate::application::dtos::app_password_dto::AppPasswordListResponseDto>, AppError>
{
let service = state
@@ -64,7 +64,7 @@ async fn list_app_passwords(
/// DELETE /api/auth/app-passwords/:id — Revoke an app password.
async fn revoke_app_password(
State(state): State<Arc<AppState>>,
axum::Extension(user): axum::Extension<CurrentUser>,
user: AuthUser,
axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<Json<crate::application::dtos::app_password_dto::AppPasswordRevokeResponseDto>, AppError>
{
@@ -35,7 +35,7 @@ use crate::application::ports::calendar_ports::CalendarUseCase;
use crate::application::services::calendar_service::CalendarService;
use crate::common::di::AppState;
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
const HEADER_DAV: HeaderName = HeaderName::from_static("dav");
@@ -138,10 +138,11 @@ fn reject_path_traversal(path: &str) -> Result<(), AppError> {
// ─── Helper: extract user from request ───────────────────────────────
fn extract_user(req: &Request<Body>) -> Result<CurrentUser, AppError> {
fn extract_user(req: &Request<Body>) -> Result<AuthUser, AppError> {
req.extensions()
.get::<Arc<CurrentUser>>()
.map(|arc| (**arc).clone())
.cloned()
.map(AuthUser)
.ok_or_else(|| AppError::unauthorized("Authentication required"))
}
@@ -35,7 +35,7 @@ use crate::application::ports::carddav_ports::{AddressBookUseCase, ContactUseCas
use crate::common::di::AppState;
use crate::infrastructure::adapters::contact_storage_adapter::ContactStorageAdapter;
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
const HEADER_DAV: HeaderName = HeaderName::from_static("dav");
@@ -126,10 +126,11 @@ fn reject_path_traversal(path: &str) -> Result<(), AppError> {
// ─── Helper: extract user from request ───────────────────────────────
fn extract_user(req: &Request<Body>) -> Result<CurrentUser, AppError> {
fn extract_user(req: &Request<Body>) -> Result<AuthUser, AppError> {
req.extensions()
.get::<Arc<CurrentUser>>()
.map(|arc| (**arc).clone())
.cloned()
.map(AuthUser)
.ok_or_else(|| AppError::unauthorized("Authentication required"))
}
@@ -28,7 +28,7 @@ use crate::application::services::folder_service::FolderService;
use crate::common::di::AppState;
use crate::infrastructure::services::path_resolver_service::ResolvedResource;
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
use percent_encoding::{AsciiSet, NON_ALPHANUMERIC, percent_decode_str, utf8_percent_encode};
use std::sync::Arc;
@@ -93,10 +93,11 @@ const PROPFIND_BATCH_SIZE: i64 = 500;
/// Every mutating or data-returning WebDAV handler **must** call this so
/// that the real `user.id` is available for ownership checks and for the
/// user-scoped `PathResolverService` methods.
fn extract_user(req: &Request<Body>) -> Result<CurrentUser, AppError> {
fn extract_user(req: &Request<Body>) -> Result<AuthUser, AppError> {
req.extensions()
.get::<Arc<CurrentUser>>()
.map(|arc| (**arc).clone())
.cloned()
.map(AuthUser)
.ok_or_else(|| AppError::unauthorized("Authentication required"))
}
+3 -5
View File
@@ -413,14 +413,12 @@ async fn authorize_wopi_access<S: FileRetrievalUseCase>(
/// This endpoint is behind normal auth middleware. The authenticated user
/// requests a WOPI session for a specific file.
pub async fn get_editor_url(
AuthUser {
id: user_id,
username,
..
}: AuthUser,
auth_user: AuthUser,
Query(params): Query<EditorUrlParams>,
State(state): State<WopiState>,
) -> Response {
let user_id = auth_user.id;
let username = &auth_user.username;
// Verify the caller owns the file (SQL-level check, no existence leak).
let (file, can_write) = match authorize_wopi_access(
state.app_state.applications.file_retrieval_service.as_ref(),
+15 -49
View File
@@ -20,12 +20,18 @@ use crate::application::ports::auth_ports::TokenServicePort;
#[derive(Clone, Copy, Debug)]
pub struct CookieAuthenticated;
// Structure for use in Axum extractors
// Newtype over Arc<CurrentUser> for zero-allocation extraction.
// `Deref<Target = CurrentUser>` lets handlers access `.id`, `.username`,
// `.email`, `.role` transparently — no signature changes needed.
#[derive(Clone, Debug)]
pub struct AuthUser {
pub id: Uuid,
pub username: String,
pub role: String,
pub struct AuthUser(pub Arc<CurrentUser>);
impl std::ops::Deref for AuthUser {
type Target = CurrentUser;
#[inline]
fn deref(&self) -> &CurrentUser {
&self.0
}
}
/// Reusable extractor that gets the user_id of the authenticated user.
@@ -38,7 +44,8 @@ pub struct AuthUser {
#[derive(Clone, Debug)]
pub struct CurrentUserId(pub Uuid);
// Implement FromRequestParts for AuthUser — allows using `auth_user: AuthUser` in handlers
// Implement FromRequestParts for AuthUser — allows using `auth_user: AuthUser` in handlers.
// Cost: 1 atomic increment (~1 ns) instead of 3 String clones (~100 ns + 3 mallocs).
impl<S> FromRequestParts<S> for AuthUser
where
S: Send + Sync,
@@ -49,29 +56,8 @@ where
parts
.extensions
.get::<Arc<CurrentUser>>()
.map(|cu| AuthUser {
id: cu.id,
username: cu.username.clone(),
role: cu.role.clone(),
})
.ok_or(AuthError::UserNotFound)
}
}
// Implement FromRequestParts for CurrentUser — full user extractor from extensions
// The middleware inserts Arc<CurrentUser>; this extractor cheaply clones the Arc
// (~1 ns atomic increment) instead of deep-cloning 4 Strings (~60-100 ns).
impl<S> FromRequestParts<S> for CurrentUser
where
S: Send + Sync,
{
type Rejection = AuthError;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
parts
.extensions
.get::<Arc<CurrentUser>>()
.map(|arc| (**arc).clone())
.cloned()
.map(AuthUser)
.ok_or(AuthError::UserNotFound)
}
}
@@ -113,27 +99,7 @@ where
}
}
/// Optional auth user extractor – never fails.
/// Yields `Some(AuthUser)` when auth middleware ran, `None` otherwise.
#[derive(Clone, Debug)]
pub struct OptionalAuthUser(pub Option<AuthUser>);
impl<S> FromRequestParts<S> for OptionalAuthUser
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
Ok(OptionalAuthUser(parts.extensions.get::<Arc<CurrentUser>>().map(
|cu| AuthUser {
id: cu.id,
username: cu.username.clone(),
role: cu.role.clone(),
},
)))
}
}
// Error for authentication operations
#[derive(Debug, thiserror::Error)]
+8 -8
View File
@@ -11,7 +11,7 @@ use crate::application::dtos::search_dto::SearchCriteriaDto;
use crate::application::ports::inbound::SearchUseCase;
use crate::application::ports::storage_ports::StorageUsagePort;
use crate::common::di::AppState;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::AuthUser;
/// Build an OCS success response with the given statuscode and data.
fn ocs_ok(statuscode: u16, data: serde_json::Value) -> serde_json::Value {
@@ -45,7 +45,7 @@ pub async fn handle_capabilities_v2(State(state): State<Arc<AppState>>) -> Respo
Json(payload).into_response()
}
pub async fn handle_user_info(State(state): State<Arc<AppState>>, user: CurrentUser) -> Response {
pub async fn handle_user_info(State(state): State<Arc<AppState>>, user: AuthUser) -> Response {
let quota: (i64, i64) = match state.storage_usage_service.as_ref() {
Some(service) => match service.get_user_storage_info(user.id).await {
Ok((used, total)) => (used, total),
@@ -86,7 +86,7 @@ pub async fn handle_user_info(State(state): State<Arc<AppState>>, user: CurrentU
pub async fn handle_user_provisioning_v1(
state: State<Arc<AppState>>,
path: Path<String>,
user: CurrentUser,
user: AuthUser,
) -> Response {
user_provisioning_response(state, path, user, 1).await
}
@@ -95,7 +95,7 @@ pub async fn handle_user_provisioning_v1(
pub async fn handle_user_provisioning_v2(
state: State<Arc<AppState>>,
path: Path<String>,
user: CurrentUser,
user: AuthUser,
) -> Response {
user_provisioning_response(state, path, user, 2).await
}
@@ -105,7 +105,7 @@ pub async fn handle_user_provisioning_v2(
async fn user_provisioning_response(
State(state): State<Arc<AppState>>,
Path(userid): Path<String>,
user: CurrentUser,
user: AuthUser,
ocs_version: u8,
) -> Response {
let statuscode = if ocs_version == 1 { 100 } else { 200 };
@@ -197,7 +197,7 @@ async fn user_provisioning_response(
pub async fn handle_revoke_apppassword(
State(state): State<Arc<AppState>>,
user: CurrentUser,
user: AuthUser,
headers: axum::http::HeaderMap,
) -> Response {
let nextcloud = match state.nextcloud.as_ref() {
@@ -249,7 +249,7 @@ pub async fn handle_recommendations() -> Response {
/// this endpoint and expects a well-formed OCS response rather than a 404.
pub async fn handle_sharees_search(
State(state): State<Arc<AppState>>,
user: CurrentUser,
user: AuthUser,
axum::extract::Query(params): axum::extract::Query<ShareeSearchParams>,
) -> Response {
let search = params.search.unwrap_or_default();
@@ -343,7 +343,7 @@ pub async fn handle_search(
State(state): State<Arc<AppState>>,
Path(provider_id): Path<String>,
axum::extract::Query(params): axum::extract::Query<UnifiedSearchParams>,
user: CurrentUser,
user: AuthUser,
) -> Response {
// Only the "files" provider is supported
if provider_id != "files" {
+2 -2
View File
@@ -15,7 +15,7 @@ use crate::application::ports::file_ports::FileRetrievalUseCase;
use crate::application::ports::storage_ports::FileReadPort;
use crate::application::ports::thumbnail_ports::{ThumbnailPort, ThumbnailSize};
use crate::common::di::AppState;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::AuthUser;
#[derive(Debug, Deserialize)]
pub struct PreviewParams {
@@ -34,7 +34,7 @@ pub struct PreviewParams {
/// - Size selection based on request dimensions and forceIcon param
pub async fn handle_preview(
State(state): State<Arc<AppState>>,
user: CurrentUser,
user: AuthUser,
Query(params): Query<PreviewParams>,
) -> impl IntoResponse {
// Parse the Nextcloud file ID — the NC app may append an instance suffix
+9 -9
View File
@@ -10,7 +10,7 @@ use axum::{
use std::sync::Arc;
use crate::common::di::AppState;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
use crate::interfaces::middleware::rate_limit::{RateLimiter, rate_limit_login};
use crate::interfaces::nextcloud::avatar_handler;
use crate::interfaces::nextcloud::basic_auth_middleware::basic_auth_middleware;
@@ -176,7 +176,7 @@ fn verify_url_user(url_user: &str, auth_user: &CurrentUser) -> Result<(), Respon
async fn handle_dav_files(
State(state): State<Arc<AppState>>,
Path((url_user, subpath)): Path<(String, String)>,
user_ext: CurrentUser,
user_ext: AuthUser,
req: Request<Body>,
) -> Result<Response, Response> {
verify_url_user(&url_user, &user_ext)?;
@@ -188,7 +188,7 @@ async fn handle_dav_files(
async fn handle_dav_files_root(
State(state): State<Arc<AppState>>,
Path(url_user): Path<String>,
user_ext: CurrentUser,
user_ext: AuthUser,
req: Request<Body>,
) -> Result<Response, Response> {
verify_url_user(&url_user, &user_ext)?;
@@ -200,7 +200,7 @@ async fn handle_dav_files_root(
async fn handle_dav_uploads(
State(state): State<Arc<AppState>>,
Path((url_user, upload_id, rest)): Path<(String, String, String)>,
user_ext: CurrentUser,
user_ext: AuthUser,
req: Request<Body>,
) -> Result<Response, Response> {
verify_url_user(&url_user, &user_ext)?;
@@ -212,7 +212,7 @@ async fn handle_dav_uploads(
async fn handle_dav_uploads_root(
State(state): State<Arc<AppState>>,
Path((url_user, upload_id)): Path<(String, String)>,
user_ext: CurrentUser,
user_ext: AuthUser,
req: Request<Body>,
) -> Result<Response, Response> {
verify_url_user(&url_user, &user_ext)?;
@@ -222,7 +222,7 @@ async fn handle_dav_uploads_root(
}
/// Legacy /remote.php/webdav/* — redirect to /remote.php/dav/files/{user}/*
async fn handle_legacy_webdav(Path(subpath): Path<String>, user_ext: CurrentUser) -> Response {
async fn handle_legacy_webdav(Path(subpath): Path<String>, user_ext: AuthUser) -> Response {
let location = format!("/remote.php/dav/files/{}/{}", user_ext.username, subpath);
Response::builder()
.status(StatusCode::MOVED_PERMANENTLY)
@@ -231,7 +231,7 @@ async fn handle_legacy_webdav(Path(subpath): Path<String>, user_ext: CurrentUser
.unwrap()
}
async fn handle_legacy_webdav_root(user_ext: CurrentUser) -> Response {
async fn handle_legacy_webdav_root(user_ext: AuthUser) -> Response {
let location = format!("/remote.php/dav/files/{}/", user_ext.username);
Response::builder()
.status(StatusCode::MOVED_PERMANENTLY)
@@ -243,7 +243,7 @@ async fn handle_legacy_webdav_root(user_ext: CurrentUser) -> Response {
async fn handle_dav_trashbin(
State(state): State<Arc<AppState>>,
Path((url_user, subpath)): Path<(String, String)>,
user_ext: CurrentUser,
user_ext: AuthUser,
req: Request<Body>,
) -> Result<Response, Response> {
verify_url_user(&url_user, &user_ext)?;
@@ -255,7 +255,7 @@ async fn handle_dav_trashbin(
async fn handle_dav_trashbin_root(
State(state): State<Arc<AppState>>,
Path(url_user): Path<String>,
user_ext: CurrentUser,
user_ext: AuthUser,
req: Request<Body>,
) -> Result<Response, Response> {
verify_url_user(&url_user, &user_ext)?;
+2 -2
View File
@@ -12,7 +12,7 @@ use std::sync::Arc;
use crate::application::ports::trash_ports::TrashUseCase;
use crate::common::di::AppState;
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
use crate::interfaces::nextcloud::webdav_handler::{
format_oc_id, resolve_file_id, resolve_folder_id, write_text_element,
};
@@ -25,7 +25,7 @@ const HEADER_DAV: HeaderName = HeaderName::from_static("dav");
pub async fn handle_nc_trashbin(
state: Arc<AppState>,
req: Request<Body>,
user: CurrentUser,
user: AuthUser,
subpath: String,
) -> Result<Response<Body>, AppError> {
let method = req.method().clone();
+2 -2
View File
@@ -9,7 +9,7 @@ use crate::application::ports::file_ports::{FileRetrievalUseCase, FileUploadUseC
use crate::common::di::AppState;
use crate::common::mime_detect::{filename_from_path, refine_content_type_from_file};
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
/// Dispatch Nextcloud chunked upload WebDAV requests.
///
@@ -21,7 +21,7 @@ use crate::interfaces::middleware::auth::CurrentUser;
pub async fn handle_nc_uploads(
state: Arc<AppState>,
req: Request<Body>,
user: CurrentUser,
user: AuthUser,
upload_id: String,
rest: String, // chunk name or ".file" or empty
) -> Result<Response<Body>, AppError> {
+2 -2
View File
@@ -22,7 +22,7 @@ use crate::application::ports::trash_ports::TrashUseCase;
use crate::common::di::AppState;
use crate::common::mime_detect::{filename_from_path, refine_content_type};
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::CurrentUser;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
/// Extension trait to map XML write errors to `String` concisely.
trait XmlResultExt<T> {
@@ -89,7 +89,7 @@ pub fn nc_href(username: &str, subpath: &str) -> String {
pub async fn handle_nc_webdav(
state: Arc<AppState>,
req: Request<Body>,
user: CurrentUser,
user: AuthUser,
subpath: String,
) -> Result<Response<Body>, AppError> {
let method = req.method().clone();
+99 -86
View File
@@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OxiCloud — Admin Panel</title>
<script src="/js/core/theme-init.js"></script>
<script src="/js/core/i18n.js" defer></script>
<script src="/js/core/icons.js" defer></script>
<script src="/js/core/formatters.js" defer></script>
<script src="/js/core/csrf.js" defer></script>
@@ -24,22 +25,22 @@
</div>
<span class="admin-title-text">OxiCloud</span>
</a>
<span class="admin-title-separator">· Admin</span>
<span class="admin-title-separator">· <span data-i18n="admin.tab_dashboard">Admin</span></span>
</div>
<div class="admin-header-right">
<a href="/"
><i class="fas fa-arrow-left"></i> Back to OxiCloud</a
><i class="fas fa-arrow-left"></i> <span data-i18n="admin.back_to_app">Back to OxiCloud</span></a
>
</div>
</div>
<div class="admin-container">
<div id="loading"><i class="fas fa-circle-notch"></i> Loading…</div>
<div id="loading"><i class="fas fa-circle-notch"></i> <span data-i18n="admin.loading">Loading…</span></div>
<div id="access-denied">
<div class="access-icon"><i class="fas fa-lock"></i></div>
<h2>Access Denied</h2>
<p>Administrator privileges required to access this panel.</p>
<a href="/login"><i class="fas fa-sign-in-alt"></i> Sign in</a>
<h2 data-i18n="admin.access_denied">Access Denied</h2>
<p data-i18n="admin.access_denied_desc">Administrator privileges required to access this panel.</p>
<a href="/login"><i class="fas fa-sign-in-alt"></i> <span data-i18n="admin.sign_in">Sign in</span></a>
</div>
<div id="main-content">
@@ -48,13 +49,13 @@
class="admin-tab active"
id="tab-btn-dashboard"
>
<i class="fas fa-chart-pie"></i> Dashboard
<i class="fas fa-chart-pie"></i> <span data-i18n="admin.tab_dashboard">Dashboard</span>
</button>
<button class="admin-tab" id="tab-btn-users">
<i class="fas fa-users"></i> Users
<i class="fas fa-users"></i> <span data-i18n="admin.tab_users">Users</span>
</button>
<button class="admin-tab" id="tab-btn-oidc">
<i class="fas fa-key"></i> SSO / OIDC
<i class="fas fa-key"></i> <span data-i18n="admin.tab_oidc">SSO / OIDC</span>
</button>
</div>
@@ -67,7 +68,7 @@
>
—
</div>
<div class="stat-label">Total Users</div>
<div class="stat-label" data-i18n="admin.total_users">Total Users</div>
</div>
<div class="stat-card">
<div
@@ -76,7 +77,7 @@
>
—
</div>
<div class="stat-label">Active Users</div>
<div class="stat-label" data-i18n="admin.active_users">Active Users</div>
</div>
<div class="stat-card">
<div
@@ -85,30 +86,30 @@
>
—
</div>
<div class="stat-label">Admins</div>
<div class="stat-label" data-i18n="admin.admins">Admins</div>
</div>
<div class="stat-card">
<div class="stat-value" id="ds-version">—</div>
<div class="stat-label">Version</div>
<div class="stat-label" data-i18n="admin.version">Version</div>
</div>
</div>
<div class="admin-card">
<h2><i class="fas fa-hdd"></i> Storage Overview</h2>
<h2><i class="fas fa-hdd"></i> <span data-i18n="admin.storage_overview">Storage Overview</span></h2>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value" id="ds-used">—</div>
<div class="stat-label">Used</div>
<div class="stat-label" data-i18n="admin.used">Used</div>
</div>
<div class="stat-card">
<div class="stat-value" id="ds-quota">—</div>
<div class="stat-label">Total Quota</div>
<div class="stat-label" data-i18n="admin.total_quota">Total Quota</div>
</div>
<div class="stat-card">
<div class="stat-value" id="ds-usage-pct">
—
</div>
<div class="stat-label">Usage %</div>
<div class="stat-label" data-i18n="admin.usage_pct">Usage %</div>
</div>
</div>
<div class="progress-bar">
@@ -126,7 +127,7 @@
>
0
</div>
<div class="stat-label">
<div class="stat-label" data-i18n="admin.users_over_80">
Users &gt;80% quota
</div>
</div>
@@ -140,7 +141,7 @@
>
0
</div>
<div class="stat-label">
<div class="stat-label" data-i18n="admin.users_over_quota">
Users over quota
</div>
</div>
@@ -149,21 +150,21 @@
</div>
<div class="admin-card">
<h2><i class="fas fa-server"></i> System</h2>
<h2><i class="fas fa-server"></i> <span data-i18n="admin.system">System</span></h2>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value" id="ds-auth">—</div>
<div class="stat-label">Auth</div>
<div class="stat-label" data-i18n="admin.auth_label">Auth</div>
</div>
<div class="stat-card">
<div class="stat-value" id="ds-oidc">—</div>
<div class="stat-label">OIDC</div>
<div class="stat-label" data-i18n="admin.oidc_label">OIDC</div>
</div>
<div class="stat-card">
<div class="stat-value" id="ds-quotas-flag">
—
</div>
<div class="stat-label">Quotas</div>
<div class="stat-label" data-i18n="admin.quotas_label">Quotas</div>
</div>
</div>
<div class="toggle-row toggle-row-strong">
@@ -171,22 +172,19 @@
><i
class="fas fa-user-plus icon-muted-right"
></i>
Allow public self-registration</label
<span data-i18n="admin.allow_registration">Allow public self-registration</span></label
>
<label class="switch"
><input
type="checkbox"
id="ds-registration"
checked
onchange="toggleRegistration(this.checked)" /><span
checked /><span
class="slider"
></span
></label>
</div>
<div class="warning" id="registration-warning">
<i class="fas fa-exclamation-triangle"></i> Public
registration is disabled. Only admins can create new
users.
<i class="fas fa-exclamation-triangle"></i> <span data-i18n="admin.registration_warning">Public registration is disabled. Only admins can create new users.</span>
</div>
</div>
</div>
@@ -195,26 +193,25 @@
<div class="admin-card">
<h2 class="h2-space-between">
<span
><i class="fas fa-users-cog"></i> User
Management</span
><i class="fas fa-users-cog"></i> <span data-i18n="admin.user_management">User Management</span></span
><button
class="btn btn-primary"
id="btn-create-user"
>
<i class="fas fa-user-plus"></i> Create User
<i class="fas fa-user-plus"></i> <span data-i18n="admin.create_user">Create User</span>
</button>
</h2>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>User</th>
<th>Role</th>
<th>Auth</th>
<th>Status</th>
<th>Storage</th>
<th>Last Login</th>
<th>Actions</th>
<th data-i18n="admin.col_user">User</th>
<th data-i18n="admin.col_role">Role</th>
<th data-i18n="admin.col_auth">Auth</th>
<th data-i18n="admin.col_status">Status</th>
<th data-i18n="admin.col_storage">Storage</th>
<th data-i18n="admin.col_last_login">Last Login</th>
<th data-i18n="admin.col_actions">Actions</th>
</tr>
</thead>
<tbody id="users-tbody">
@@ -226,7 +223,7 @@
<i
class="fas fa-spinner fa-spin"
></i>
Loading users…
<span data-i18n="admin.loading_users">Loading users…</span>
</td>
</tr>
</tbody>
@@ -240,13 +237,13 @@
id="prev-btn"
disabled
>
<i class="fas fa-chevron-left"></i> Prev
<i class="fas fa-chevron-left"></i> <span data-i18n="admin.prev">Prev</span>
</button>
<button
class="btn btn-sm btn-secondary"
id="next-btn"
>
Next <i class="fas fa-chevron-right"></i>
<span data-i18n="admin.next">Next</span> <i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
@@ -256,11 +253,10 @@
<div id="tab-oidc" class="tab-content">
<div class="admin-card">
<h2>
<i class="fas fa-shield-alt"></i> Single Sign-On
(OIDC / SSO)
<i class="fas fa-shield-alt"></i> <span data-i18n="admin.sso_title">Single Sign-On (OIDC / SSO)</span>
</h2>
<div class="toggle-row">
<label>Enable SSO Authentication</label>
<label data-i18n="admin.enable_sso">Enable SSO Authentication</label>
<label class="switch"
><input
type="checkbox"
@@ -272,7 +268,7 @@
<div id="oidc-form">
<div class="form-group">
<label
>Provider Name
><span data-i18n="admin.provider_name">Provider Name</span>
<span id="badge-provider_name"></span
></label>
<input
@@ -283,7 +279,7 @@
</div>
<div class="form-group">
<label
>Issuer URL
><span data-i18n="admin.issuer_url">Issuer URL</span>
<span id="badge-issuer_url"></span
></label>
<input
@@ -291,7 +287,7 @@
id="issuer-url"
placeholder="https://auth.example.com/application/o/oxicloud/"
/>
<small
<small data-i18n="admin.issuer_url_hint"
>OpenID Connect issuer URL of your identity
provider</small
>
@@ -301,13 +297,13 @@
class="btn btn-secondary btn-sm"
id="discover-btn"
>
<i class="fas fa-search"></i> Auto-discover
<i class="fas fa-search"></i> <span data-i18n="admin.auto_discover">Auto-discover</span>
</button>
</div>
<div id="discovery-result"></div>
<div class="form-group">
<label
>Client ID <span id="badge-client_id"></span
><span data-i18n="admin.client_id">Client ID</span> <span id="badge-client_id"></span
></label>
<input
type="text"
@@ -317,25 +313,26 @@
</div>
<div class="form-group">
<label
>Client Secret
><span data-i18n="admin.client_secret">Client Secret</span>
<span id="badge-client_secret"></span
></label>
<input
type="password"
id="client-secret"
placeholder="Leave empty to keep current value"
data-i18n-placeholder="admin.client_secret_placeholder"
/>
<small id="secret-hint"
><i
class="fas fa-check-circle secret-icon"
></i>
A client secret is already configured</small
<span data-i18n="admin.secret_configured">A client secret is already configured</span></small
>
</div>
<div class="form-group">
<label
>Callback URL
<small class="small-muted"
><span data-i18n="admin.callback_url">Callback URL</span>
<small class="small-muted" data-i18n="admin.callback_url_hint"
>(register in your IdP)</small
></label
>
@@ -354,11 +351,11 @@
<i
class="fas fa-sliders-h summary-icon-right"
></i>
Advanced Settings
<span data-i18n="admin.advanced_settings">Advanced Settings</span>
</summary>
<div class="form-group">
<label
>Scopes <span id="badge-scopes"></span
><span data-i18n="admin.scopes">Scopes</span> <span id="badge-scopes"></span>
></label>
<input
type="text"
@@ -367,7 +364,7 @@
/>
</div>
<div class="toggle-row">
<label
<label data-i18n="admin.auto_provision"
>Auto-provision users on first
login</label
>
@@ -382,21 +379,21 @@
</div>
<div class="form-group">
<label
>Admin Groups
<span id="badge-admin_groups"></span
><span data-i18n="admin.admin_groups">Admin Groups</span>
<span id="badge-admin_groups"></span>
></label>
<input
type="text"
id="admin-groups"
placeholder="e.g., oxicloud-admins"
/>
<small
<small data-i18n="admin.admin_groups_hint"
>Comma-separated OIDC group names that
map to admin role</small
>
</div>
<div class="toggle-row">
<label
<label data-i18n="admin.disable_password"
>Disable password login (OIDC
only)</label
>
@@ -410,7 +407,7 @@
</div>
<div class="warning" id="password-warning">
<i class="fas fa-exclamation-triangle"></i>
This will prevent ALL password-based logins!
<span data-i18n="admin.password_warning">This will prevent ALL password-based logins!</span>
</div>
</details>
<div class="oidc-actions">
@@ -418,13 +415,13 @@
class="btn btn-secondary"
id="btn-test-oidc"
>
<i class="fas fa-vial"></i> Test
<i class="fas fa-vial"></i> <span data-i18n="admin.test_btn">Test</span>
</button>
<button
class="btn btn-primary"
id="save-btn"
>
<i class="fas fa-save"></i> Save
<i class="fas fa-save"></i> <span data-i18n="admin.save_btn">Save</span>
</button>
</div>
<div id="oidc-status" class="alert"></div>
@@ -437,14 +434,13 @@
<div id="quota-modal" class="modal-overlay hidden">
<div class="modal">
<h3>
<i class="fas fa-box modal-title-icon"></i> Update Storage
Quota
<i class="fas fa-box modal-title-icon"></i> <span data-i18n="admin.quota_modal_title">Update Storage Quota</span>
</h3>
<div class="form-group">
<label>User: <strong id="qm-username"></strong></label>
<label><span data-i18n="admin.quota_user_label">User:</span> <strong id="qm-username"></strong></label>
</div>
<div class="form-group">
<label>New Quota</label>
<label data-i18n="admin.new_quota">New Quota</label>
<div class="quota-input-row">
<input
type="number"
@@ -459,17 +455,18 @@
<option value="1099511627776">TB</option>
</select>
</div>
<small>Set to 0 for unlimited</small>
<small data-i18n="admin.quota_unlimited_hint">Set to 0 for unlimited</small>
</div>
<div class="modal-actions">
<button
class="btn btn-secondary"
id="btn-close-quota"
data-i18n="admin.cancel"
>
Cancel
</button>
<button class="btn btn-primary" id="btn-save-quota">
<i class="fas fa-save"></i> Save
<i class="fas fa-save"></i> <span data-i18n="admin.save_btn">Save</span>
</button>
</div>
</div>
@@ -478,50 +475,52 @@
<div id="create-user-modal" class="modal-overlay hidden">
<div class="modal">
<h3>
<i class="fas fa-user-plus modal-title-icon"></i> Create New
User
<i class="fas fa-user-plus modal-title-icon"></i> <span data-i18n="admin.create_user_title">Create New User</span>
</h3>
<div class="form-group">
<label>Username *</label>
<label><span data-i18n="admin.username_label">Username</span> *</label>
<input
type="text"
id="cu-username"
placeholder="johndoe"
data-i18n-placeholder="admin.username_placeholder"
minlength="3"
maxlength="32"
/>
<small>3–32 characters</small>
<small data-i18n="admin.username_hint">3–32 characters</small>
</div>
<div class="form-group">
<label>Password *</label>
<label><span data-i18n="admin.password_label">Password</span> *</label>
<input
type="password"
id="cu-password"
placeholder="Min 8 characters"
data-i18n-placeholder="admin.password_placeholder"
minlength="8"
/>
</div>
<div class="form-group">
<label
>Email
<small class="small-muted">(optional)</small></label
><span data-i18n="admin.email_label">Email</span>
<small class="small-muted" data-i18n="admin.email_optional">(optional)</small></label
>
<input
type="text"
id="cu-email"
placeholder="user@example.com (auto-generated if empty)"
data-i18n-placeholder="admin.email_placeholder"
/>
</div>
<div class="form-row">
<div class="form-group flex-1">
<label>Role</label>
<label data-i18n="admin.role_label">Role</label>
<select id="cu-role" class="select-cu-role">
<option value="user">User</option>
<option value="admin">Admin</option>
<option value="user" data-i18n="admin.role_user">User</option>
<option value="admin" data-i18n="admin.role_admin">Admin</option>
</select>
</div>
<div class="form-group flex-1">
<label>Quota</label>
<label data-i18n="admin.quota_label">Quota</label>
<div class="quota-row">
<input
type="number"
@@ -547,6 +546,7 @@
<button
class="btn btn-secondary"
id="btn-close-create-user"
data-i18n="admin.cancel"
>
Cancel
</button>
@@ -554,7 +554,7 @@
class="btn btn-primary"
id="cu-submit"
>
<i class="fas fa-user-plus"></i> Create
<i class="fas fa-user-plus"></i> <span data-i18n="admin.create_user">Create</span>
</button>
</div>
</div>
@@ -563,13 +563,13 @@
<div id="reset-pw-modal" class="modal-overlay hidden">
<div class="modal">
<h3>
<i class="fas fa-key modal-title-icon"></i> Reset Password
<i class="fas fa-key modal-title-icon"></i> <span data-i18n="admin.reset_pw_title">Reset Password</span>
</h3>
<div class="form-group">
<label>User: <strong id="rp-username"></strong></label>
<label><span data-i18n="admin.quota_user_label">User:</span> <strong id="rp-username"></strong></label>
</div>
<div class="form-group">
<label>New Password</label>
<label data-i18n="admin.new_password_label">New Password</label>
<input
type="password"
id="rp-password"
@@ -582,6 +582,7 @@
<button
class="btn btn-secondary"
id="btn-close-reset-pw"
data-i18n="admin.cancel"
>
Cancel
</button>
@@ -589,12 +590,24 @@
class="btn btn-primary"
id="rp-submit"
>
<i class="fas fa-save"></i> Reset
<i class="fas fa-save"></i> <span data-i18n="admin.reset_btn">Reset</span>
</button>
</div>
</div>
</div>
<!-- Confirm modal -->
<div id="confirm-modal" class="modal-overlay hidden">
<div class="modal modal-confirm">
<h3 id="confirm-title"><i class="fas fa-exclamation-circle modal-title-icon"></i> <span data-i18n="admin.confirm_action">Confirm Action</span></h3>
<p id="confirm-message"></p>
<div class="modal-actions">
<button class="btn btn-secondary" id="confirm-cancel" data-i18n="admin.confirm_no">Cancel</button>
<button class="btn btn-danger" id="confirm-yes" data-i18n="admin.confirm_yes">Confirm</button>
</div>
</div>
</div>
<script src="/js/views/admin/admin.js" defer></script>
</body>
</html>
+26
View File
@@ -1,9 +1,35 @@
:root {
/* Backgrounds */
--color-bg-page: #f5f7fa;
--color-bg-surface: #ffffff;
--color-bg-input: #f9fafb;
--color-bg-hover: #f8fafc;
/* Borders */
--color-border: #e2e8f0;
--color-border-light: #f1f5f9;
/* Text */
--color-text: #2d3748;
--color-text-heading: #1e293b;
--color-text-muted: #718096;
--color-text-faint: #94a3b8;
/* Accent */
--color-accent: #ff5e3a;
--color-accent-hover: #e04520;
--color-accent-gradient: linear-gradient(135deg, #ff5e3a 0%, #ff2d55 100%);
--color-accent-shadow: rgba(255, 94, 58, 0.3);
--color-accent-ring: rgba(255, 94, 58, 0.1);
--color-accent-tint: #fff5f3;
/* Feedback */
--color-error-bg: #fee2e2;
--color-error-text: #b91c1c;
--color-success-bg: #dcfce7;
--color-success-text: #15803d;
/* Shadows */
--color-shadow: rgba(0, 0, 0, 0.1);
--color-shadow-lg: rgba(0, 0, 0, 0.12);
}
+25 -1
View File
@@ -51,6 +51,8 @@
top: calc(100% + 8px);
right: 0;
min-width: 160px;
max-height: 420px;
overflow-y: auto;
background-color: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
@@ -60,7 +62,22 @@
transform: translateY(-10px);
transition: all 0.2s ease;
z-index: 1000;
overflow: hidden;
}
/* Custom scrollbar */
.language-selector-dropdown::-webkit-scrollbar {
width: 6px;
}
.language-selector-dropdown::-webkit-scrollbar-track {
background: transparent;
margin: 8px 0;
}
.language-selector-dropdown::-webkit-scrollbar-thumb {
background-color: #cbd5e0;
border-radius: 3px;
}
.language-selector-dropdown::-webkit-scrollbar-thumb:hover {
background-color: #a0aec0;
}
.language-selector.open .language-selector-dropdown {
@@ -124,6 +141,13 @@
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
}
[data-theme="dark"] .language-selector-dropdown::-webkit-scrollbar-thumb {
background-color: #475569;
}
[data-theme="dark"] .language-selector-dropdown::-webkit-scrollbar-thumb:hover {
background-color: #64748b;
}
[data-theme="dark"] .language-option {
color: #cbd5e1;
}
+26
View File
@@ -1,11 +1,37 @@
[data-theme="dark"] {
/* Backgrounds */
--color-bg-page: #0f172a;
--color-bg-surface: #1e293b;
--color-bg-input: #0f172a;
--color-bg-hover: #162032;
/* Borders */
--color-border: #334155;
--color-border-light: #334155;
/* Text */
--color-text: #e2e8f0;
--color-text-heading: #f1f5f9;
--color-text-muted: #94a3b8;
--color-text-faint: #64748b;
/* Accent */
--color-accent: #ff5e3a;
--color-accent-hover: #ff7a5c;
--color-accent-gradient: linear-gradient(135deg, #ff5e3a 0%, #ff2d55 100%);
--color-accent-shadow: rgba(255, 94, 58, 0.3);
--color-accent-ring: rgba(255, 94, 58, 0.15);
--color-accent-tint: #2a1a15;
/* Feedback */
--color-error-bg: #3b1111;
--color-error-text: #fca5a5;
--color-success-bg: #052e16;
--color-success-text: #86efac;
/* Shadows */
--color-shadow: rgba(0, 0, 0, 0.3);
--color-shadow-lg: rgba(0, 0, 0, 0.3);
}
[data-theme="dark"] body {
+17 -4
View File
@@ -1,5 +1,5 @@
*{box-sizing:border-box;margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}
body{background:#f5f7fa;color:#1e293b;min-height:100vh;display:flex;flex-direction:column}
body{background:#f5f7fa;color:#1e293b;min-height:100vh;height:auto;display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden}
.hidden{display:none !important}
.show-block{display:block !important}
@@ -62,10 +62,10 @@ body{background:#f5f7fa;color:#1e293b;min-height:100vh;display:flex;flex-directi
.admin-header-right a:hover{color:#fff}
/* ── Container ── */
.admin-container{max-width:1080px;margin:0 auto;padding:28px 24px 60px;width:100%}
.admin-container{max-width:1080px;margin:0 auto;padding:28px 24px 60px;width:100%;flex:1}
/* ── Tabs ── */
.admin-tabs{display:flex;gap:6px;margin-bottom:28px;background:#fff;border-radius:14px;padding:6px;box-shadow:0 1px 4px rgba(0,0,0,.06)}
.admin-tabs{display:flex;gap:6px;margin-bottom:28px;background:#fff;border-radius:14px;padding:6px;box-shadow:0 1px 4px rgba(0,0,0,.06);position:sticky;top:64px;z-index:50}
.admin-tab{
padding:10px 22px;cursor:pointer;font-weight:600;font-size:13.5px;color:#64748b;
border:none;background:none;border-radius:10px;transition:all .2s;display:flex;align-items:center;gap:8px;
@@ -74,8 +74,12 @@ body{background:#f5f7fa;color:#1e293b;min-height:100vh;display:flex;flex-directi
.admin-tab.active{color:#fff;background:linear-gradient(135deg,#ff5e3a,#ff2d55);box-shadow:0 3px 12px rgba(255,94,58,.25)}
.admin-tab.active i{color:#fff}
.admin-tab i{font-size:14px;width:16px;text-align:center}
.tab-content{display:none}
.tab-content{display:none;animation:none}
.tab-content.active{display:block}
.tab-content.tab-fade-in{animation:tabFadeIn .22s ease-out}
.tab-content.tab-fade-out{animation:tabFadeOut .15s ease-in;display:block}
@keyframes tabFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
@keyframes tabFadeOut{from{opacity:1}to{opacity:0}}
/* ── Cards ── */
.admin-card{background:#fff;border-radius:16px;box-shadow:0 1px 4px rgba(0,0,0,.06),0 0 0 1px rgba(0,0,0,.03);padding:28px;margin-bottom:22px}
@@ -296,6 +300,15 @@ details[open] summary{margin-bottom:14px;color:#ff5e3a}
[data-theme="dark"] .pagination{color:#64748b}
[data-theme="dark"] #access-denied h2{color:#fca5a5}
[data-theme="dark"] #access-denied p{color:#94a3b8}
/* ── Confirm modal ── */
.modal-confirm{max-width:420px}
.modal-confirm h3{color:#dc2626}
.modal-confirm p{margin:14px 0 22px;font-size:14px;line-height:1.55;color:#475569}
.btn-danger{background:linear-gradient(135deg,#dc2626,#b91c1c);color:#fff;border:none;padding:10px 22px;border-radius:10px;font-weight:600;cursor:pointer;transition:opacity .15s}
.btn-danger:hover{opacity:.88}
[data-theme="dark"] .modal-confirm p{color:#94a3b8}
[data-theme="dark"] .btn-danger{background:linear-gradient(135deg,#ef4444,#dc2626)}
[data-theme="dark"] #access-denied .access-icon{background:#3b1111}
[data-theme="dark"] #loading{color:#64748b}
[data-theme="dark"] .toggle-row{border-top-color:#334155}
+125 -209
View File
@@ -1,4 +1,7 @@
/* Auth styles for OxiCloud */
/* ============================================================
Auth styles for OxiCloud — design tokens from variables.css
============================================================ */
.auth-container {
display: flex;
flex-direction: column;
@@ -6,17 +9,18 @@
justify-content: center;
height: 100vh;
width: 100%;
background-color: #f5f7fa;
background-color: var(--color-bg-page);
}
.auth-panel {
width: 400px;
width: 420px;
max-width: 90%;
margin: 0 auto;
background-color: white;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
padding: 30px;
background-color: var(--color-bg-surface);
border: 1px solid var(--color-border);
border-radius: 16px;
box-shadow: 0 8px 30px var(--color-shadow);
padding: 36px;
text-align: center;
}
@@ -28,15 +32,15 @@
}
.auth-logo-icon {
width: 50px;
height: 50px;
background: linear-gradient(135deg, #ff5e3a 0%, #ff2d55 100%);
border-radius: 12px;
width: 52px;
height: 52px;
background: var(--color-accent-gradient);
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
box-shadow: 0 4px 12px rgba(255, 94, 58, 0.3);
margin-right: 12px;
box-shadow: 0 4px 12px var(--color-accent-shadow);
}
.auth-logo-icon svg {
@@ -48,14 +52,14 @@
.auth-logo-text {
font-size: 24px;
font-weight: bold;
color: #2a3042;
color: var(--color-text);
}
.auth-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 25px;
color: #2a3042;
font-size: 22px;
font-weight: 700;
margin-bottom: 28px;
color: var(--color-text-heading);
}
.auth-form {
@@ -75,39 +79,55 @@
display: block;
margin-bottom: 8px;
font-size: 14px;
color: #4b5563;
font-weight: 500;
color: var(--color-text-heading);
font-weight: 600;
}
.auth-input {
width: 100%;
padding: 12px 15px;
border-radius: 8px;
border: 1px solid #e2e8f0;
font-size: 14px;
background-color: #f9fafb;
transition: border-color 0.2s;
padding: 14px 18px;
border-radius: 12px;
border: 2px solid var(--color-border);
font-size: 15px;
background-color: var(--color-bg-input);
color: var(--color-text);
transition: all 0.2s ease;
}
.auth-input::placeholder {
color: var(--color-text-faint);
}
.auth-input:hover {
border-color: var(--color-accent);
background-color: var(--color-bg-surface);
}
.auth-input:focus {
outline: none;
border-color: #ff5e3a;
box-shadow: 0 0 0 3px rgba(255, 94, 58, 0.1);
border-color: var(--color-accent);
background-color: var(--color-bg-surface);
box-shadow: 0 0 0 3px var(--color-accent-ring);
}
.auth-input[readonly] {
opacity: 0.7;
cursor: default;
}
.auth-button {
width: 100%;
padding: 12px 15px;
border-radius: 10px;
background: linear-gradient(135deg, #ff5e3a 0%, #ff2d55 100%);
padding: 14px 18px;
border-radius: 12px;
background: var(--color-accent-gradient);
color: white;
font-weight: bold;
font-weight: 700;
border: none;
cursor: pointer;
font-size: 16px;
transition: all 0.3s ease;
margin-top: 10px;
box-shadow: 0 4px 12px rgba(255, 94, 58, 0.3);
margin-top: 12px;
box-shadow: 0 4px 12px var(--color-accent-shadow);
}
.auth-button:hover {
@@ -118,15 +138,17 @@
.auth-button:active {
transform: translateY(0);
box-shadow: 0 2px 8px rgba(255, 94, 58, 0.3);
box-shadow: 0 2px 8px var(--color-accent-shadow);
}
.auth-button:disabled {
background-color: #f9a799;
opacity: 0.5;
cursor: not-allowed;
transform: none;
filter: none;
}
.auth-subtitle { margin: 20px 0; color: #6b7280; font-size: 14px; }
.auth-subtitle { margin: 20px 0; color: var(--color-text-muted); font-size: 14px; }
.auth-action-wrap { margin-top: 20px; }
/* SSO / OIDC button */
@@ -160,7 +182,7 @@
display: flex;
align-items: center;
margin: 20px 0;
color: #a0aec0;
color: var(--color-text-faint);
font-size: 13px;
}
@@ -169,7 +191,7 @@
content: '';
flex: 1;
height: 1px;
background: #e2e8f0;
background: var(--color-border);
}
.auth-divider span {
@@ -182,13 +204,13 @@
}
.auth-toggle {
margin-top: 20px;
margin-top: 22px;
font-size: 14px;
color: #718096;
color: var(--color-text-muted);
}
.auth-toggle-link {
color: #ff5e3a;
color: var(--color-accent);
cursor: pointer;
text-decoration: none;
font-weight: 500;
@@ -199,20 +221,20 @@
}
.auth-error {
background-color: #fee2e2;
color: #b91c1c;
padding: 10px 15px;
border-radius: 8px;
background-color: var(--color-error-bg);
color: var(--color-error-text);
padding: 12px 18px;
border-radius: 12px;
margin-bottom: 20px;
font-size: 14px;
display: none;
}
.auth-success {
background-color: #dcfce7;
color: #15803d;
padding: 10px 15px;
border-radius: 8px;
background-color: var(--color-success-bg);
color: var(--color-success-text);
padding: 12px 18px;
border-radius: 12px;
margin-bottom: 20px;
font-size: 14px;
display: none;
@@ -224,44 +246,50 @@
}
.setup-steps {
margin-bottom: 25px;
margin-bottom: 28px;
display: flex;
justify-content: space-between;
justify-content: center;
gap: 32px;
}
.setup-step {
display: flex;
flex-direction: column;
align-items: center;
width: 30%;
}
.step-number {
width: 30px;
height: 30px;
background-color: #e2e8f0;
width: 34px;
height: 34px;
background-color: var(--color-bg-input);
border: 2px solid var(--color-border);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #64748b;
font-weight: bold;
margin-bottom: 5px;
color: var(--color-text-faint);
font-weight: 700;
font-size: 14px;
margin-bottom: 6px;
transition: all 0.2s ease;
}
.step-number.active {
background-color: #ff5e3a;
background: var(--color-accent-gradient);
border-color: transparent;
color: white;
box-shadow: 0 2px 8px var(--color-accent-shadow);
}
.step-title {
font-size: 12px;
color: #64748b;
color: var(--color-text-faint);
font-weight: 500;
}
.step-title.active {
color: #1e293b;
font-weight: 500;
color: var(--color-text-heading);
font-weight: 600;
}
/* Language selector panel styles */
@@ -270,7 +298,7 @@
}
.language-subtitle {
color: #64748b;
color: var(--color-text-muted);
font-size: 16px;
margin-bottom: 24px;
}
@@ -286,25 +314,25 @@
display: flex;
align-items: center;
padding: 14px 18px;
border: 2px solid #e2e8f0;
border: 2px solid var(--color-border);
border-radius: 12px;
cursor: pointer;
background-color: #f9fafb;
background-color: var(--color-bg-input);
transition: all 0.2s ease;
user-select: none;
}
.lang-picker-selected:hover {
border-color: #ff5e3a;
background-color: #fff;
border-color: var(--color-accent);
background-color: var(--color-bg-surface);
}
.lang-picker.open .lang-picker-selected {
border-color: #ff5e3a;
background-color: #fff;
border-color: var(--color-accent);
background-color: var(--color-bg-surface);
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
box-shadow: 0 0 0 3px rgba(255, 94, 58, 0.1);
box-shadow: 0 0 0 3px var(--color-accent-ring);
}
.lang-picker-flag {
@@ -316,12 +344,12 @@
.lang-picker-name {
font-size: 16px;
font-weight: 600;
color: #1e293b;
color: var(--color-text-heading);
flex: 1;
}
.lang-picker-arrow {
color: #94a3b8;
color: var(--color-text-faint);
font-size: 13px;
transition: transform 0.2s ease;
flex-shrink: 0;
@@ -338,12 +366,12 @@
top: 100%;
left: 0;
right: 0;
background: #fff;
border: 2px solid #ff5e3a;
border-top: 1px solid #f1f5f9;
background: var(--color-bg-surface);
border: 2px solid var(--color-accent);
border-top: 1px solid var(--color-border-light);
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
box-shadow: 0 12px 32px var(--color-shadow-lg);
z-index: 100;
overflow: hidden;
}
@@ -362,7 +390,7 @@
.lang-picker-search {
position: relative;
padding: 10px 14px;
border-bottom: 1px solid #f1f5f9;
border-bottom: 1px solid var(--color-border-light);
}
.lang-picker-search i {
@@ -370,23 +398,29 @@
left: 26px;
top: 50%;
transform: translateY(-50%);
color: #94a3b8;
color: var(--color-text-faint);
font-size: 13px;
}
.lang-picker-search input {
width: 100%;
padding: 8px 12px 8px 32px;
border: 1px solid #e2e8f0;
border: 1px solid var(--color-border);
border-radius: 8px;
font-size: 14px;
outline: none;
box-sizing: border-box;
background-color: var(--color-bg-input);
color: var(--color-text);
transition: border-color 0.2s;
}
.lang-picker-search input::placeholder {
color: var(--color-text-faint);
}
.lang-picker-search input:focus {
border-color: #ff5e3a;
border-color: var(--color-accent);
}
/* Scrollable list */
@@ -405,12 +439,12 @@
}
.lang-picker-list::-webkit-scrollbar-thumb {
background: #cbd5e1;
background: var(--color-border);
border-radius: 3px;
}
.lang-picker-list::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
background: var(--color-text-faint);
}
/* Language item in dropdown */
@@ -425,11 +459,11 @@
}
.lang-picker-item:hover {
background: #f8fafc;
background: var(--color-bg-hover);
}
.lang-picker-item.selected {
background: #fff5f3;
background: var(--color-accent-tint);
}
.lang-picker-item-flag {
@@ -440,32 +474,32 @@
.lang-picker-item-name {
font-size: 15px;
font-weight: 500;
color: #1e293b;
color: var(--color-text-heading);
}
.lang-picker-item-english {
font-size: 13px;
color: #94a3b8;
color: var(--color-text-faint);
margin-left: auto;
}
.lang-picker-item-check {
color: #ff5e3a;
color: var(--color-accent);
font-size: 13px;
flex-shrink: 0;
}
.lang-picker-empty {
text-align: center;
color: #94a3b8;
color: var(--color-text-faint);
padding: 20px;
font-size: 14px;
}
@media (max-width: 480px) {
.auth-panel {
width: 90%;
padding: 20px;
width: 95%;
padding: 24px;
}
.lang-picker-selected {
@@ -476,121 +510,3 @@
max-height: 200px;
}
}
/* ============================================================
DARK MODE — Auth Pages
============================================================ */
[data-theme="dark"] .auth-container {
background-color: #0f172a;
}
[data-theme="dark"] .auth-panel {
background-color: #1e293b;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
}
[data-theme="dark"] .auth-logo-text {
color: #f1f5f9;
}
[data-theme="dark"] .auth-title {
color: #f1f5f9;
}
[data-theme="dark"] .auth-label {
color: #94a3b8;
}
[data-theme="dark"] .auth-input {
background-color: #0f172a;
border-color: #334155;
color: #e2e8f0;
}
[data-theme="dark"] .auth-input:focus {
border-color: #ff5e3a;
background-color: #0f172a;
box-shadow: 0 0 0 3px rgba(255, 94, 58, 0.15);
}
[data-theme="dark"] .auth-input::placeholder {
color: #64748b;
}
[data-theme="dark"] .auth-error {
background-color: #3b1111;
color: #fca5a5;
}
[data-theme="dark"] .auth-success {
background-color: #052e16;
color: #86efac;
}
[data-theme="dark"] .auth-toggle {
color: #94a3b8;
}
[data-theme="dark"] .auth-divider {
color: #64748b;
}
[data-theme="dark"] .auth-divider::before,
[data-theme="dark"] .auth-divider::after {
background: #334155;
}
[data-theme="dark"] .language-subtitle {
color: #94a3b8;
}
[data-theme="dark"] .lang-picker-selected {
background-color: #0f172a;
border-color: #334155;
}
[data-theme="dark"] .lang-picker-selected:hover {
border-color: #ff5e3a;
background-color: #162032;
}
[data-theme="dark"] .lang-picker.open .lang-picker-selected {
border-color: #ff5e3a;
background-color: #162032;
}
[data-theme="dark"] .lang-picker-name {
color: #f1f5f9;
}
[data-theme="dark"] .lang-picker-arrow {
color: #64748b;
}
[data-theme="dark"] .lang-picker-dropdown {
background: #1e293b;
border-color: #ff5e3a;
border-top-color: #334155;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3);
}
[data-theme="dark"] .lang-picker-search {
border-bottom-color: #334155;
}
[data-theme="dark"] .lang-picker-search input {
background-color: #0f172a;
border-color: #334155;
color: #e2e8f0;
}
[data-theme="dark"] .lang-picker-search input:focus {
border-color: #ff5e3a;
}
[data-theme="dark"] .lang-picker-search input::placeholder {
color: #64748b;
}
[data-theme="dark"] .lang-picker-list::-webkit-scrollbar-thumb {
background: #475569;
}
[data-theme="dark"] .lang-picker-item:hover {
background: #162032;
}
[data-theme="dark"] .lang-picker-item.selected {
background: #2a1a15;
}
[data-theme="dark"] .lang-picker-item-name {
color: #f1f5f9;
}
[data-theme="dark"] .lang-picker-item-english {
color: #64748b;
}
[data-theme="dark"] .lang-picker-empty {
color: #64748b;
}
/* Setup steps */
[data-theme="dark"] .step-number {
background-color: #334155;
color: #94a3b8;
}
[data-theme="dark"] .step-title {
color: #94a3b8;
}
+13 -2
View File
@@ -110,8 +110,19 @@ async function loadFiles(options = {}) {
const folderList = Array.isArray(listing.folders) ? listing.folders : [];
const fileList = Array.isArray(listing.files) ? listing.files : [];
window.ui.renderFolders(folderList);
window.ui.renderFiles(fileList);
if (folderList.length === 0 && fileList.length === 0) {
const emptyState = document.createElement('div');
emptyState.className = 'empty-state';
emptyState.innerHTML = `
<i class="fas fa-folder-open empty-state-icon"></i>
<p>${_t('files.no_files')}</p>
<p>${_t('files.empty_hint')}</p>
`;
elements.filesGrid.appendChild(emptyState);
} else {
window.ui.renderFolders(folderList);
window.ui.renderFiles(fileList);
}
console.log(`Loaded ${folderList.length} folders and ${fileList.length} files`);
} catch (error) {
+4 -2
View File
@@ -473,8 +473,8 @@ function setupEventListeners() {
// Show files containers (to be filled with trash)
const filesGrid = document.getElementById('files-grid');
const filesListView = document.getElementById('files-list-view');
if (filesGrid) filesGrid.style.display = app.currentView === 'grid' ? 'grid' : 'none';
if (filesListView) filesListView.style.display = app.currentView === 'list' ? 'block' : 'none';
if (filesGrid) { filesGrid.style.display = app.currentView === 'grid' ? 'grid' : 'none'; filesGrid.classList.toggle('hidden', app.currentView !== 'grid'); }
if (filesListView) { filesListView.style.display = app.currentView === 'list' ? 'flex' : 'none'; filesListView.classList.toggle('hidden', app.currentView !== 'list'); }
// Update UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.trash') : 'Trash';
@@ -494,6 +494,8 @@ function setupEventListeners() {
const savedView = localStorage.getItem('oxicloud-view');
if (savedView === 'list') {
ui.switchToListView();
} else {
ui.switchToGridView();
}
// User menu
+41 -5
View File
@@ -3,6 +3,34 @@
* Extracted from main.js to keep navigation concerns isolated.
*/
/**
* Sync the hidden class and inline display for the grid/list containers
* based on the current view preference.
*/
function syncViewContainers() {
const filesGrid = document.getElementById('files-grid');
const filesListView = document.getElementById('files-list-view');
const isGrid = window.app.currentView === 'grid';
if (filesGrid) {
filesGrid.style.display = isGrid ? 'grid' : 'none';
filesGrid.classList.toggle('hidden', !isGrid);
}
if (filesListView) {
filesListView.style.display = isGrid ? 'none' : 'flex';
filesListView.classList.toggle('hidden', isGrid);
}
}
/**
* Hide both grid and list containers (used when switching to non-file views).
*/
function hideFileContainers() {
const filesGrid = document.getElementById('files-grid');
const filesListView = document.getElementById('files-list-view');
if (filesGrid) { filesGrid.style.display = 'none'; filesGrid.classList.add('hidden'); }
if (filesListView) { filesListView.style.display = 'none'; filesListView.classList.add('hidden'); }
}
/**
* Mobile sidebar toggle functionality
*/
@@ -136,6 +164,8 @@ function switchToSharedView() {
const filesListView = document.getElementById('files-list-view');
if (filesGrid) filesGrid.style.display = 'none';
if (filesListView) filesListView.style.display = 'none';
if (filesGrid) filesGrid.classList.add('hidden');
if (filesListView) filesListView.classList.add('hidden');
// Show shared view
if (window.sharedView) {
@@ -157,7 +187,9 @@ function switchToFilesView() {
const filesGrid = document.getElementById('files-grid');
const filesListView = document.getElementById('files-list-view');
if (filesGrid) filesGrid.style.display = window.app.currentView === 'grid' ? 'grid' : 'none';
if (filesListView) filesListView.style.display = window.app.currentView === 'list' ? 'block' : 'none';
if (filesGrid) filesGrid.classList.toggle('hidden', window.app.currentView !== 'grid');
if (filesListView) filesListView.style.display = window.app.currentView === 'list' ? 'flex' : 'none';
if (filesListView) filesListView.classList.toggle('hidden', window.app.currentView !== 'list');
// Reset to home folder and update breadcrumb
window.app.currentPath = window.app.userHomeFolderId || '';
@@ -180,7 +212,9 @@ function switchToFavoritesView() {
const filesGrid = document.getElementById('files-grid');
const filesListView = document.getElementById('files-list-view');
if (filesGrid) filesGrid.style.display = window.app.currentView === 'grid' ? 'grid' : 'none';
if (filesListView) filesListView.style.display = window.app.currentView === 'list' ? 'block' : 'none';
if (filesGrid) filesGrid.classList.toggle('hidden', window.app.currentView !== 'grid');
if (filesListView) filesListView.style.display = window.app.currentView === 'list' ? 'flex' : 'none';
if (filesListView) filesListView.classList.toggle('hidden', window.app.currentView !== 'list');
if (window.favorites) {
window.favorites.displayFavorites();
@@ -211,7 +245,9 @@ function switchToRecentFilesView() {
const filesGrid = document.getElementById('files-grid');
const filesListView = document.getElementById('files-list-view');
if (filesGrid) filesGrid.style.display = window.app.currentView === 'grid' ? 'grid' : 'none';
if (filesListView) filesListView.style.display = window.app.currentView === 'list' ? 'block' : 'none';
if (filesGrid) filesGrid.classList.toggle('hidden', window.app.currentView !== 'grid');
if (filesListView) filesListView.style.display = window.app.currentView === 'list' ? 'flex' : 'none';
if (filesListView) filesListView.classList.toggle('hidden', window.app.currentView !== 'list');
if (window.recent) {
window.recent.displayRecentFiles();
@@ -242,8 +278,8 @@ function switchToPhotosView() {
// Hide file containers
const filesGrid = document.getElementById('files-grid');
const filesListView = document.getElementById('files-list-view');
if (filesGrid) filesGrid.style.display = 'none';
if (filesListView) filesListView.style.display = 'none';
if (filesGrid) { filesGrid.style.display = 'none'; filesGrid.classList.add('hidden'); }
if (filesListView) { filesListView.style.display = 'none'; filesListView.classList.add('hidden'); }
// Show photos view
if (window.photosView) {
+4
View File
@@ -450,7 +450,9 @@ const ui = {
this._hydrateViewIfNeeded('grid');
filesGrid.style.display = 'grid';
filesGrid.classList.remove('hidden');
filesListView.style.display = 'none';
filesListView.classList.add('hidden');
gridViewBtn.classList.add('active');
listViewBtn.classList.remove('active');
window.app.currentView = 'grid';
@@ -469,7 +471,9 @@ const ui = {
this._hydrateViewIfNeeded('list');
filesGrid.style.display = 'none';
filesGrid.classList.add('hidden');
filesListView.style.display = 'flex';
filesListView.classList.remove('hidden');
gridViewBtn.classList.remove('active');
listViewBtn.classList.add('active');
window.app.currentView = 'list';
+26 -10
View File
@@ -13,7 +13,7 @@ let currentLocale =
// Supported locales (languages that have locale files on the server)
// When a locale file is not found, the system gracefully falls back to English
const supportedLocales = ['en', 'es', 'zh', 'fa', 'fr', 'de', 'pt', 'nl'];
const supportedLocales = ['en', 'es', 'zh', 'fa', 'fr', 'de', 'pt', 'nl', 'it', 'hi', 'ar', 'ru', 'ja', 'ko'];
// Fallback to English if locale is not supported
if (!supportedLocales.includes(currentLocale)) {
@@ -225,6 +225,9 @@ async function initI18n() {
if (currentLocale !== 'en') {
await loadTranslations('en');
}
// Mark loaded BEFORE translatePage so safeT resolves properly
translationsLoaded = true;
// Translate the page
translatePage();
@@ -245,20 +248,23 @@ function translatePage() {
* @param {Element|Document} root - The root element to search within
*/
function translateElement(root) {
// Use safeT instead of bare t() to avoid issues when other scripts
// (e.g. admin.js) shadow the global t() function.
const resolve = safeT;
const el = root || document;
el.querySelectorAll('[data-i18n]').forEach(element => {
const key = element.getAttribute('data-i18n');
element.textContent = t(key);
element.textContent = resolve(key);
});
el.querySelectorAll('[data-i18n-placeholder]').forEach(element => {
const key = element.getAttribute('data-i18n-placeholder');
element.placeholder = t(key);
element.placeholder = resolve(key);
});
el.querySelectorAll('[data-i18n-title]').forEach(element => {
const key = element.getAttribute('data-i18n-title');
element.title = t(key);
element.title = resolve(key);
});
}
@@ -284,19 +290,29 @@ let translationsLoaded = false;
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', async () => {
await initI18n();
translationsLoaded = true;
// translationsLoaded already set inside initI18n
// Dispatch an event when translations are fully loaded
window.dispatchEvent(new Event('translationsLoaded'));
});
// Improved t function with fallback for early calls
// Self-contained t wrapper — does NOT call the global t() because other
// scripts (e.g. admin.js) may shadow it, which would cause infinite recursion.
function safeT(key, params = {}) {
if (!translationsLoaded) {
console.warn(`Translations for ${currentLocale} not loaded yet`);
// Return a default value or the key depending on context
const localeData = translations[currentLocale];
if (!localeData) {
// Translations not loaded yet — return humanised key suffix
return key.split('.').pop() || key;
}
return t(key, params);
let value = getNestedValue(localeData, key);
// Fallback to English
if (!value && currentLocale !== 'en' && translations['en']) {
value = getNestedValue(translations['en'], key);
}
if (!value) return key;
return interpolate(value, params);
}
// Export functions for use in other modules
+12 -3
View File
@@ -3,11 +3,20 @@
* Custom styled dropdown with flags
*/
// Locale files that actually exist (have full translations)
// Keep this list in sync when adding new locale JSON files
const AVAILABLE_LOCALES = new Set([
'en', 'es', 'zh', 'fa', 'fr', 'de', 'pt', 'it', 'nl',
'hi', 'ar', 'ru', 'ja', 'ko'
]);
// Language codes, names, and flag emojis
// Uses ALL_LANGUAGES from auth.js if available, otherwise fallback
// Only returns languages that have a real locale file
function getAvailableLanguages() {
if (typeof ALL_LANGUAGES !== 'undefined') {
return ALL_LANGUAGES.map(l => ({ code: l.code, name: l.nativeName, flag: l.flag }));
return ALL_LANGUAGES
.filter(l => AVAILABLE_LOCALES.has(l.code))
.map(l => ({ code: l.code, name: l.nativeName, flag: l.flag }));
}
return [
{ code: 'en', name: 'English', flag: '🇬🇧' },
@@ -23,7 +32,7 @@ function getAvailableLanguages() {
}
// RTL languages
const rtlLanguages = ['fa']; // ['fa', 'ar']
const rtlLanguages = ['fa', 'ar'];
// Update HTML lang attribute and dir for RTL languages
function updateHtmlAttributes(langCode) {
+60 -15
View File
@@ -19,8 +19,8 @@ const FIRST_RUN_KEY = 'oxicloud_first_run_completed';
// Language selector texts (used before i18n is loaded)
const LANGUAGE_TEXTS = {
en: {
title: 'Welcome to OxiCloud',
subtitle: 'Please select your language',
title: 'Welcome!',
subtitle: 'Select your language to continue',
continue: 'Continue',
autodetected: 'We detected your language',
moreLanguages: 'More languages...',
@@ -28,8 +28,8 @@ const LANGUAGE_TEXTS = {
searchPlaceholder: 'Search language...'
},
es: {
title: 'Bienvenido a OxiCloud',
subtitle: 'Por favor, selecciona tu idioma',
title: '¡Bienvenido!',
subtitle: 'Selecciona tu idioma para continuar',
continue: 'Continuar',
autodetected: 'Hemos detectado tu idioma',
moreLanguages: 'More languages...',
@@ -37,8 +37,8 @@ const LANGUAGE_TEXTS = {
searchPlaceholder: 'Buscar idioma...'
},
zh: {
title: '欢迎使用 OxiCloud',
subtitle: '请选择您的语言',
title: '欢迎!',
subtitle: '选择您的语言以继续',
continue: '继续',
autodetected: '我们检测到了您的语言',
moreLanguages: '更多语言...',
@@ -46,8 +46,8 @@ const LANGUAGE_TEXTS = {
searchPlaceholder: '搜索语言...'
},
fa: {
title: 'به OxiCloud خوش آمدید',
subtitle: 'لطفا زبان خود را انتخاب کنید',
title: '!خوش آمدید',
subtitle: 'زبان خود را برای ادامه انتخاب کنید',
continue: 'ادامه',
autodetected: 'زبان شما شناسایی شد',
moreLanguages: 'زبان‌های بیشتر...',
@@ -55,14 +55,59 @@ const LANGUAGE_TEXTS = {
searchPlaceholder: 'جستجوی زبان...'
},
nl: {
title: 'Welkom bij OxiCloud',
subtitle: 'Selecteer uw taal',
title: 'Welkom!',
subtitle: 'Selecteer uw taal om door te gaan',
continue: 'Doorgaan',
autodetected: 'We hebben uw taal gedetecteerd',
moreLanguages: 'Meer talen...',
modalTitle: 'Taal selecteren',
searchPlaceholder: 'Zoek taal...'
},
hi: {
title: 'स्वागत है!',
subtitle: 'जारी रखने के लिए अपनी भाषा चुनें',
continue: 'जारी रखें',
autodetected: 'हमने आपकी भाषा पहचान ली',
moreLanguages: 'और भाषाएँ...',
modalTitle: 'भाषा चुनें',
searchPlaceholder: 'भाषा खोजें...'
},
ar: {
title: '!مرحباً',
subtitle: 'اختر لغتك للمتابعة',
continue: 'متابعة',
autodetected: 'تم اكتشاف لغتك',
moreLanguages: 'المزيد من اللغات...',
modalTitle: 'اختر اللغة',
searchPlaceholder: 'ابحث عن لغة...'
},
ru: {
title: 'Добро пожаловать!',
subtitle: 'Выберите язык для продолжения',
continue: 'Продолжить',
autodetected: 'Мы определили ваш язык',
moreLanguages: 'Больше языков...',
modalTitle: 'Выберите язык',
searchPlaceholder: 'Поиск языка...'
},
ja: {
title: 'ようこそ!',
subtitle: '続行するには言語を選択してください',
continue: '続行',
autodetected: '言語を検出しました',
moreLanguages: 'その他の言語...',
modalTitle: '言語を選択',
searchPlaceholder: '言語を検索...'
},
ko: {
title: '환영합니다!',
subtitle: '계속하려면 언어를 선택하세요',
continue: '계속',
autodetected: '언어가 감지되었습니다',
moreLanguages: '더 많은 언어...',
modalTitle: '언어 선택',
searchPlaceholder: '언어 검색...'
},
};
// Complete language registry — add new languages here, they'll appear automatically
@@ -76,11 +121,11 @@ const ALL_LANGUAGES = [
{ code: 'de', name: 'German', nativeName: 'Deutsch', flag: '🇩🇪', popular: true },
{ code: 'pt', name: 'Portuguese', nativeName: 'Português', flag: '🇧🇷', popular: true },
{ code: 'it', name: 'Italian', nativeName: 'Italiano', flag: '🇮🇹', popular: true },
{ code: 'ru', name: 'Russian', nativeName: 'Русский', flag: '🇷🇺', popular: false },
{ code: 'ja', name: 'Japanese', nativeName: '日本語', flag: '🇯🇵', popular: false },
{ code: 'ko', name: 'Korean', nativeName: '한국어', flag: '🇰🇷', popular: false },
{ code: 'ar', name: 'Arabic', nativeName: 'العربية', flag: '🇸🇦', popular: false },
{ code: 'hi', name: 'Hindi', nativeName: 'हिन्दी', flag: '🇮🇳', popular: false },
{ code: 'ru', name: 'Russian', nativeName: 'Русский', flag: '🇷🇺', popular: true },
{ code: 'ja', name: 'Japanese', nativeName: '日本語', flag: '🇯🇵', popular: true },
{ code: 'ko', name: 'Korean', nativeName: '한국어', flag: '🇰🇷', popular: true },
{ code: 'ar', name: 'Arabic', nativeName: 'العربية', flag: '🇸🇦', popular: true },
{ code: 'hi', name: 'Hindi', nativeName: 'हिन्दी', flag: '🇮🇳', popular: true },
{ code: 'tr', name: 'Turkish', nativeName: 'Türkçe', flag: '🇹🇷', popular: false },
{ code: 'nl', name: 'Dutch', nativeName: 'Nederlands', flag: '🇳🇱', popular: false },
{ code: 'pl', name: 'Polish', nativeName: 'Polski', flag: '🇵🇱', popular: false },
+147 -61
View File
@@ -4,13 +4,19 @@ let usersPage = 0;
const PAGE_SIZE = 50;
let totalUsers = 0;
/** Escape a string for safe embedding inside a JS string literal within an HTML attribute.
* Converts all non-alphanumeric/space/dot/hyphen/underscore chars to \xHH escapes. */
/* ── i18n helper — falls back to key if i18n not ready ── */
function t(key, params) {
if (window.i18n && typeof window.i18n.t === 'function') return window.i18n.t(key, params);
// fallback: strip prefix and humanise
return key.split('.').pop().replace(/_/g, ' ');
}
/** Escape a string for safe embedding inside a JS string literal within an HTML attribute. */
function _escJs(s) {
if (typeof s !== 'string') return '';
return s.replace(/[^\w .\-]/g, function(c) {
return '\\x' + c.charCodeAt(0).toString(16).padStart(2, '0');
});
if (typeof s !== 'string') return '';
return s.replace(/[^\w .\-]/g, function(c) {
return '\\x' + c.charCodeAt(0).toString(16).padStart(2, '0');
});
}
function hideElement(id) {
@@ -43,22 +49,80 @@ function formatBytes(bytes) {
}
function timeAgo(dateStr) {
if (!dateStr) return 'Never';
if (!dateStr) return t('admin.never');
const d = new Date(dateStr);
const now = new Date();
const secs = Math.floor((now - d) / 1000);
if (secs < 60) return 'Just now';
if (secs < 3600) return Math.floor(secs/60) + 'm ago';
if (secs < 86400) return Math.floor(secs/3600) + 'h ago';
if (secs < 2592000) return Math.floor(secs/86400) + 'd ago';
if (secs < 60) return t('admin.just_now');
if (secs < 3600) return t('admin.minutes_ago', { n: Math.floor(secs / 60) });
if (secs < 86400) return t('admin.hours_ago', { n: Math.floor(secs / 3600) });
if (secs < 2592000) return t('admin.days_ago', { n: Math.floor(secs / 86400) });
return d.toLocaleDateString();
}
/* ── Custom confirm modal ── */
function showConfirm(message) {
return new Promise(function(resolve) {
var overlay = document.getElementById('confirm-modal');
var msgEl = document.getElementById('confirm-message');
var yesBtn = document.getElementById('confirm-yes');
var noBtn = document.getElementById('confirm-cancel');
msgEl.textContent = message;
overlay.classList.remove('hidden');
overlay.classList.add('show-flex');
function cleanup(result) {
overlay.classList.remove('show-flex');
overlay.classList.add('hidden');
yesBtn.removeEventListener('click', onYes);
noBtn.removeEventListener('click', onNo);
overlay.removeEventListener('click', onOverlay);
resolve(result);
}
function onYes() { cleanup(true); }
function onNo() { cleanup(false); }
function onOverlay(e) { if (e.target === overlay) cleanup(false); }
yesBtn.addEventListener('click', onYes);
noBtn.addEventListener('click', onNo);
overlay.addEventListener('click', onOverlay);
});
}
/* ── Tab switching with fade animation ── */
let activeTabName = 'dashboard';
function switchTab(name, el) {
document.querySelectorAll('.admin-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
document.getElementById('tab-' + name).classList.add('active');
if (name === activeTabName) return;
var oldTab = document.getElementById('tab-' + activeTabName);
var newTab = document.getElementById('tab-' + name);
document.querySelectorAll('.admin-tab').forEach(function(b) { b.classList.remove('active'); });
if (el) el.classList.add('active');
// Fade-out old tab
if (oldTab) {
oldTab.classList.add('tab-fade-out');
oldTab.addEventListener('animationend', function handler() {
oldTab.removeEventListener('animationend', handler);
oldTab.classList.remove('active', 'tab-fade-out');
// Fade-in new tab
if (newTab) {
newTab.classList.add('active', 'tab-fade-in');
newTab.addEventListener('animationend', function handler2() {
newTab.removeEventListener('animationend', handler2);
newTab.classList.remove('tab-fade-in');
});
}
});
} else if (newTab) {
newTab.classList.add('active', 'tab-fade-in');
newTab.addEventListener('animationend', function handler2() {
newTab.removeEventListener('animationend', handler2);
newTab.classList.remove('tab-fade-in');
});
}
activeTabName = name;
if (name === 'users') loadUsers();
if (name === 'dashboard') loadDashboard();
}
@@ -78,9 +142,9 @@ async function loadDashboard() {
const bar = document.getElementById('ds-bar');
bar.style.width = Math.min(d.storage_usage_percent, 100) + '%';
bar.className = 'progress-fill ' + (d.storage_usage_percent > 90 ? 'red' : d.storage_usage_percent > 70 ? 'orange' : 'green');
document.getElementById('ds-auth').textContent = d.auth_enabled ? 'Enabled' : 'Disabled';
document.getElementById('ds-oidc').textContent = d.oidc_configured ? 'Active' : 'Off';
document.getElementById('ds-quotas-flag').textContent = d.quotas_enabled ? 'Enabled' : 'Disabled';
document.getElementById('ds-auth').textContent = d.auth_enabled ? t('admin.enabled') : t('admin.disabled');
document.getElementById('ds-oidc').textContent = d.oidc_configured ? t('admin.active') : t('admin.off');
document.getElementById('ds-quotas-flag').textContent = d.quotas_enabled ? t('admin.enabled') : t('admin.disabled');
if (typeof d.registration_enabled !== 'undefined') {
document.getElementById('ds-registration').checked = d.registration_enabled;
@@ -101,14 +165,14 @@ async function loadDashboard() {
async function loadUsers() {
const tbody = document.getElementById('users-tbody');
tbody.innerHTML = '<tr><td colspan="7" class="table-loading-cell"><i class="fas fa-spinner fa-spin"></i> Loading…</td></tr>';
tbody.innerHTML = '<tr><td colspan="7" class="table-loading-cell"><i class="fas fa-spinner fa-spin"></i> ' + escapeHtml(t('admin.loading_users')) + '</td></tr>';
try {
const resp = await fetch(API + '/admin/users?limit=' + PAGE_SIZE + '&offset=' + (usersPage * PAGE_SIZE), { headers: headers(), credentials: 'same-origin' });
if (!resp.ok) { tbody.innerHTML = '<tr><td colspan="7" class="table-status-error"><i class="fas fa-exclamation-circle"></i> Failed to load users</td></tr>'; return; }
if (!resp.ok) { tbody.innerHTML = '<tr><td colspan="7" class="table-status-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(t('admin.failed_load_users')) + '</td></tr>'; return; }
const data = await resp.json();
totalUsers = data.total;
const users = data.users;
if (users.length === 0) { tbody.innerHTML = '<tr><td colspan="7" class="table-status-empty">No users found</td></tr>'; return; }
if (users.length === 0) { tbody.innerHTML = '<tr><td colspan="7" class="table-status-empty">' + escapeHtml(t('admin.no_users_found')) + '</td></tr>'; return; }
tbody.innerHTML = users.map(u => {
const quotaPct = u.storage_quota_bytes > 0 ? ((u.storage_used_bytes / u.storage_quota_bytes) * 100) : 0;
@@ -118,20 +182,20 @@ async function loadUsers() {
const isOidc = u.auth_provider && u.auth_provider !== 'local';
const authBadge = isOidc
? '<span class="badge badge-oidc" title="Authenticated via ' + escapeHtml(u.auth_provider) + '"><i class="fas fa-key badge-admin-icon-small"></i> ' + escapeHtml(u.auth_provider) + '</span>'
: '<span class="badge badge-local">Local</span>';
: '<span class="badge badge-local">' + escapeHtml(t('admin.local')) + '</span>';
return '<tr>' +
'<td><div class="user-info"><span class="user-name">' + escapeHtml(u.username) + (isSelf ? ' <span class="user-self-badge">(you)</span>' : '') + '</span><span class="user-email">' + escapeHtml(u.email) + '</span></div></td>' +
'<td><div class="user-info"><span class="user-name">' + escapeHtml(u.username) + (isSelf ? ' <span class="user-self-badge">' + escapeHtml(t('admin.you_badge')) + '</span>' : '') + '</span><span class="user-email">' + escapeHtml(u.email) + '</span></div></td>' +
'<td><span class="badge badge-' + escapeHtml(u.role) + '">' + (u.role === 'admin' ? '<i class="fas fa-shield-alt badge-admin-icon-small"></i> ' : '') + escapeHtml(u.role) + '</span></td>' +
'<td>' + authBadge + '</td>' +
'<td><span class="badge badge-' + (u.active ? 'active' : 'inactive') + '">' + (u.active ? 'Active' : 'Inactive') + '</span></td>' +
'<td><span class="badge badge-' + (u.active ? 'active' : 'inactive') + '">' + (u.active ? escapeHtml(t('admin.active')) : escapeHtml(t('admin.inactive'))) + '</span></td>' +
'<td><div class="quota-bar"><div class="progress-bar quota-progress-fixed"><div class="progress-fill ' + quotaColor + '" data-width="' + Math.min(quotaPct, 100) + '"></div></div><span class="quota-text">' + quotaText + '</span></div></td>' +
'<td class="user-last-login-cell">' + timeAgo(u.last_login_at) + '</td>' +
'<td><div class="actions-row">' +
'<button class="btn btn-sm btn-secondary admin-action-btn" data-action="quota" data-uid="' + _escJs(u.id) + '" data-uname="' + _escJs(u.username) + '" data-quota="' + u.storage_quota_bytes + '" title="Edit quota"><i class="fas fa-box"></i></button>' +
(isOidc ? '' : '<button class="btn btn-sm btn-secondary admin-action-btn" data-action="reset-pw" data-uid="' + _escJs(u.id) + '" data-uname="' + _escJs(u.username) + '" title="Reset password"><i class="fas fa-key"></i></button>') +
'<button class="btn btn-sm btn-secondary admin-action-btn" data-action="toggle-role" data-uid="' + _escJs(u.id) + '" data-role="' + _escJs(u.role) + '" title="Toggle role"' + (isSelf ? ' disabled' : '') + '><i class="fas fa-' + (u.role === 'admin' ? 'user' : 'crown') + '"></i></button>' +
'<button class="btn btn-sm ' + (u.active ? 'btn-danger' : 'btn-success') + ' admin-action-btn" data-action="toggle-active" data-uid="' + _escJs(u.id) + '" data-active="' + u.active + '" title="' + (u.active ? 'Deactivate' : 'Activate') + '"' + (isSelf && u.active ? ' disabled' : '') + '><i class="fas fa-' + (u.active ? 'ban' : 'check') + '"></i></button>' +
'<button class="btn btn-sm btn-danger admin-action-btn" data-action="delete" data-uid="' + _escJs(u.id) + '" data-uname="' + _escJs(u.username) + '" title="Delete"' + (isSelf ? ' disabled' : '') + '><i class="fas fa-trash-alt"></i></button>' +
'<button class="btn btn-sm btn-secondary admin-action-btn" data-action="quota" data-uid="' + _escJs(u.id) + '" data-uname="' + _escJs(u.username) + '" data-quota="' + u.storage_quota_bytes + '" title="' + escapeHtml(t('admin.edit_quota_title')) + '"><i class="fas fa-box"></i></button>' +
(isOidc ? '' : '<button class="btn btn-sm btn-secondary admin-action-btn" data-action="reset-pw" data-uid="' + _escJs(u.id) + '" data-uname="' + _escJs(u.username) + '" title="' + escapeHtml(t('admin.reset_password_title')) + '"><i class="fas fa-key"></i></button>') +
'<button class="btn btn-sm btn-secondary admin-action-btn" data-action="toggle-role" data-uid="' + _escJs(u.id) + '" data-role="' + _escJs(u.role) + '" title="' + escapeHtml(t('admin.toggle_role_title')) + '"' + (isSelf ? ' disabled' : '') + '><i class="fas fa-' + (u.role === 'admin' ? 'user' : 'crown') + '"></i></button>' +
'<button class="btn btn-sm ' + (u.active ? 'btn-danger' : 'btn-success') + ' admin-action-btn" data-action="toggle-active" data-uid="' + _escJs(u.id) + '" data-active="' + u.active + '" title="' + (u.active ? escapeHtml(t('admin.deactivate_title')) : escapeHtml(t('admin.activate_title'))) + '"' + (isSelf && u.active ? ' disabled' : '') + '><i class="fas fa-' + (u.active ? 'ban' : 'check') + '"></i></button>' +
'<button class="btn btn-sm btn-danger admin-action-btn" data-action="delete" data-uid="' + _escJs(u.id) + '" data-uname="' + _escJs(u.username) + '" title="' + escapeHtml(t('admin.delete_title')) + '"' + (isSelf ? ' disabled' : '') + '><i class="fas fa-trash-alt"></i></button>' +
'</div></td></tr>';
}).join('');
@@ -153,11 +217,13 @@ async function loadUsers() {
});
});
document.getElementById('users-info').textContent = 'Showing ' + (usersPage * PAGE_SIZE + 1) + '-' + Math.min((usersPage + 1) * PAGE_SIZE, totalUsers) + ' of ' + totalUsers;
const from = usersPage * PAGE_SIZE + 1;
const to = Math.min((usersPage + 1) * PAGE_SIZE, totalUsers);
document.getElementById('users-info').textContent = t('admin.showing_users', { from: from, to: to, total: totalUsers });
document.getElementById('prev-btn').disabled = usersPage === 0;
document.getElementById('next-btn').disabled = (usersPage + 1) * PAGE_SIZE >= totalUsers;
} catch (e) {
tbody.innerHTML = '<tr><td colspan="7" class="table-status-error"><i class="fas fa-exclamation-circle"></i> Error: ' + escapeHtml(e.message) + '</td></tr>';
tbody.innerHTML = '<tr><td colspan="7" class="table-status-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(t('admin.error_network', { message: e.message })) + '</td></tr>';
}
}
@@ -166,32 +232,35 @@ function nextPage() { if ((usersPage + 1) * PAGE_SIZE < totalUsers) { usersPage+
async function toggleRole(userId, currentRole) {
const newRole = currentRole === 'admin' ? 'user' : 'admin';
if (!confirm('Change role to ' + newRole + '?')) return;
const ok = await showConfirm(t('admin.confirm_role_change', { role: newRole }));
if (!ok) return;
try {
const resp = await fetch(API + '/admin/users/' + userId + '/role', {
method: 'PUT', headers: headers(), credentials: 'same-origin', body: JSON.stringify({ role: newRole })
});
if (resp.ok) loadUsers(); else { const e = await resp.json(); alert(e.message || 'Failed'); }
} catch (e) { alert('Error: ' + e.message); }
if (resp.ok) loadUsers(); else { const e = await resp.json(); alert(e.message || t('admin.error_generic')); }
} catch (e) { alert(t('admin.error_network', { message: e.message })); }
}
async function toggleActive(userId, currentActive) {
const action = currentActive ? 'deactivate' : 'activate';
if (!confirm('Are you sure you want to ' + action + ' this user?')) return;
const msg = currentActive ? t('admin.confirm_deactivate') : t('admin.confirm_activate');
const ok = await showConfirm(msg);
if (!ok) return;
try {
const resp = await fetch(API + '/admin/users/' + userId + '/active', {
method: 'PUT', headers: headers(), credentials: 'same-origin', body: JSON.stringify({ active: !currentActive })
});
if (resp.ok) loadUsers(); else { const e = await resp.json(); alert(e.message || 'Failed'); }
} catch (e) { alert('Error: ' + e.message); }
if (resp.ok) loadUsers(); else { const e = await resp.json(); alert(e.message || t('admin.error_generic')); }
} catch (e) { alert(t('admin.error_network', { message: e.message })); }
}
async function deleteUser(userId, username) {
if (!confirm('DELETE user "' + username + '"? This cannot be undone!')) return;
const ok = await showConfirm(t('admin.confirm_delete_user', { name: username }));
if (!ok) return;
try {
const resp = await fetch(API + '/admin/users/' + userId, { method: 'DELETE', headers: headers(), credentials: 'same-origin' });
if (resp.ok) { loadUsers(); loadDashboard(); } else { const e = await resp.json(); alert(e.message || 'Failed'); }
} catch (e) { alert('Error: ' + e.message); }
if (resp.ok) { loadUsers(); loadDashboard(); } else { const e = await resp.json(); alert(e.message || t('admin.error_generic')); }
} catch (e) { alert(t('admin.error_network', { message: e.message })); }
}
let quotaUserId = '';
@@ -214,8 +283,8 @@ async function saveQuota() {
method: 'PUT', headers: headers(), credentials: 'same-origin', body: JSON.stringify({ quota_bytes: bytes })
});
if (resp.ok) { closeQuotaModal(); loadUsers(); loadDashboard(); }
else { const e = await resp.json(); alert(e.message || 'Failed'); }
} catch (e) { alert('Error: ' + e.message); }
else { const e = await resp.json(); alert(e.message || t('admin.error_generic')); }
} catch (e) { alert(t('admin.error_network', { message: e.message })); }
}
function openCreateUserModal() {
@@ -242,11 +311,11 @@ async function submitCreateUser() {
const quotaBytes = Math.round(quotaVal * quotaUnit);
const errorEl = document.getElementById('cu-error');
if (username.length < 3) { errorEl.textContent = 'Username must be at least 3 characters'; errorEl.className = 'alert alert-error'; return; }
if (password.length < 8) { errorEl.textContent = 'Password must be at least 8 characters'; errorEl.className = 'alert alert-error'; return; }
if (username.length < 3) { errorEl.textContent = t('admin.error_username_short'); errorEl.className = 'alert alert-error'; return; }
if (password.length < 8) { errorEl.textContent = t('admin.error_password_short'); errorEl.className = 'alert alert-error'; return; }
const btn = document.getElementById('cu-submit');
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Creating…';
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> ' + escapeHtml(t('admin.creating'));
try {
const resp = await fetch(API + '/admin/users', {
method: 'POST', headers: headers(), credentials: 'same-origin',
@@ -258,14 +327,14 @@ async function submitCreateUser() {
loadDashboard();
} else {
const e = await resp.json().catch(() => ({}));
errorEl.textContent = e.message || 'Failed to create user';
errorEl.textContent = e.message || t('admin.error_create_user');
errorEl.className = 'alert alert-error';
}
} catch (e) {
errorEl.textContent = 'Network error: ' + e.message;
errorEl.textContent = t('admin.error_network', { message: e.message });
errorEl.className = 'alert alert-error';
}
btn.disabled = false; btn.innerHTML = '<i class="fas fa-user-plus"></i> Create';
btn.disabled = false; btn.innerHTML = '<i class="fas fa-user-plus"></i> ' + escapeHtml(t('admin.create_user'));
}
let resetPwUserId = '';
@@ -283,19 +352,19 @@ function closeResetPasswordModal() { hideElement('reset-pw-modal'); }
async function submitResetPassword() {
const password = document.getElementById('rp-password').value;
const errorEl = document.getElementById('rp-error');
if (password.length < 8) { errorEl.textContent = 'Password must be at least 8 characters'; errorEl.className = 'alert alert-error'; return; }
if (password.length < 8) { errorEl.textContent = t('admin.error_password_short'); errorEl.className = 'alert alert-error'; return; }
const btn = document.getElementById('rp-submit');
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Resetting…';
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> ' + escapeHtml(t('admin.resetting'));
try {
const resp = await fetch(API + '/admin/users/' + resetPwUserId + '/password', {
method: 'PUT', headers: headers(), credentials: 'same-origin',
body: JSON.stringify({ new_password: password })
});
if (resp.ok) { closeResetPasswordModal(); }
else { const e = await resp.json().catch(() => ({})); errorEl.textContent = e.message || 'Failed'; errorEl.className = 'alert alert-error'; }
} catch (e) { errorEl.textContent = 'Error: ' + e.message; errorEl.className = 'alert alert-error'; }
btn.disabled = false; btn.innerHTML = '<i class="fas fa-save"></i> Reset';
else { const e = await resp.json().catch(() => ({})); errorEl.textContent = e.message || t('admin.error_generic'); errorEl.className = 'alert alert-error'; }
} catch (e) { errorEl.textContent = t('admin.error_network', { message: e.message }); errorEl.className = 'alert alert-error'; }
btn.disabled = false; btn.innerHTML = '<i class="fas fa-save"></i> ' + escapeHtml(t('admin.reset_btn'));
}
async function toggleRegistration(enabled) {
@@ -311,13 +380,13 @@ async function toggleRegistration(enabled) {
if (!enabled) showElement('registration-warning', 'flex');
else hideElement('registration-warning');
const e = await resp.json().catch(() => ({}));
alert(e.message || 'Failed to update registration setting');
alert(e.message || t('admin.error_generic'));
}
} catch (e) {
document.getElementById('ds-registration').checked = !enabled;
if (!enabled) showElement('registration-warning', 'flex');
else hideElement('registration-warning');
alert('Error: ' + e.message);
alert(t('admin.error_network', { message: e.message }));
}
}
@@ -345,7 +414,7 @@ async function testConnection() {
const url = document.getElementById('issuer-url').value.trim();
if (!url) { showOidcStatus('Enter an Issuer URL first', 'error'); return; }
const btn = document.getElementById('discover-btn');
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Discovering…';
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> ' + escapeHtml(t('admin.discovering'));
const resultDiv = document.getElementById('discovery-result');
try {
const resp = await fetch(API + '/admin/settings/oidc/test', { method: 'POST', headers: headers(), credentials: 'same-origin', body: JSON.stringify({ issuer_url: url }) });
@@ -357,12 +426,12 @@ async function testConnection() {
resultDiv.innerHTML = '<div class="discovery-result fail"><strong><i class="fas fa-times-circle"></i> ' + escapeHtml(r.message) + '</strong></div>';
}
} catch (e) { resultDiv.innerHTML = '<div class="discovery-result fail"><i class="fas fa-times-circle"></i> Error: ' + escapeHtml(e.message) + '</div>'; }
btn.disabled = false; btn.innerHTML = '<i class="fas fa-search"></i> Auto-discover';
btn.disabled = false; btn.innerHTML = '<i class="fas fa-search"></i> ' + escapeHtml(t('admin.auto_discover'));
}
async function saveOidcSettings() {
const btn = document.getElementById('save-btn');
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Saving…';
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> ' + escapeHtml(t('admin.saving'));
const body = {
enabled: document.getElementById('oidc-enabled').checked,
issuer_url: document.getElementById('issuer-url').value.trim(),
@@ -376,10 +445,14 @@ async function saveOidcSettings() {
};
try {
const resp = await fetch(API + '/admin/settings/oidc', { method: 'PUT', headers: headers(), credentials: 'same-origin', body: JSON.stringify(body) });
if (resp.ok) { showOidcStatus('Settings saved — OIDC is now ' + (body.enabled ? 'active' : 'disabled'), 'success'); loadDashboard(); }
if (resp.ok) {
const status = body.enabled ? t('admin.active').toLowerCase() : t('admin.disabled').toLowerCase();
showOidcStatus(t('admin.settings_saved', { status: status }), 'success');
loadDashboard();
}
else { const e = await resp.json().catch(()=>({})); showOidcStatus('Error: ' + (e.message || resp.statusText), 'error'); }
} catch (e) { showOidcStatus('Network error: ' + e.message, 'error'); }
btn.disabled = false; btn.innerHTML = '<i class="fas fa-save"></i> Save';
} catch (e) { showOidcStatus(t('admin.error_network', { message: e.message }), 'error'); }
btn.disabled = false; btn.innerHTML = '<i class="fas fa-save"></i> ' + escapeHtml(t('admin.save_btn'));
}
async function init() {
@@ -424,6 +497,19 @@ function showAccessDenied() {
showElement('access-denied');
}
/* ── Apply i18n when translations load / change ── */
document.addEventListener('translationsLoaded', function() {
if (window.i18n && window.i18n.translatePage) window.i18n.translatePage();
// Re-render dynamic content that uses t()
loadDashboard();
if (activeTabName === 'users') loadUsers();
});
document.addEventListener('localeChanged', function() {
if (window.i18n && window.i18n.translatePage) window.i18n.translatePage();
loadDashboard();
if (activeTabName === 'users') loadUsers();
});
init();
/* ── Event-listener wiring (replaces inline onclick/onchange) ── */
+37 -27
View File
@@ -1,5 +1,11 @@
const API = '/api';
/* ── i18n helper — falls back to key if i18n not ready ── */
function t(key, params) {
if (window.i18n && typeof window.i18n.t === 'function') return window.i18n.t(key, params);
return key.split('.').pop().replace(/_/g, ' ');
}
function headers() {
return { 'Content-Type': 'application/json', ...getCsrfHeaders() };
}
@@ -12,14 +18,14 @@ function formatBytes(bytes) {
}
function timeAgo(dateStr) {
if (!dateStr) return 'Never';
if (!dateStr) return t('profile.never');
const d = new Date(dateStr);
const now = new Date();
const secs = Math.floor((now - d) / 1000);
if (secs < 60) return 'Just now';
if (secs < 3600) return Math.floor(secs/60) + ' min ago';
if (secs < 86400) return Math.floor(secs/3600) + 'h ago';
if (secs < 2592000) return Math.floor(secs/86400) + ' days ago';
if (secs < 60) return t('profile.just_now');
if (secs < 3600) return t('profile.minutes_ago', { n: Math.floor(secs/60) });
if (secs < 86400) return t('profile.hours_ago', { n: Math.floor(secs/3600) });
if (secs < 2592000) return t('profile.days_ago', { n: Math.floor(secs/86400) });
return d.toLocaleDateString();
}
@@ -37,15 +43,15 @@ async function init() {
const badge = document.getElementById('p-role-badge');
if (user.role === 'admin') {
badge.className = 'role-badge role-badge-admin';
badge.innerHTML = '<i class="fas fa-shield-alt"></i> Administrator';
badge.innerHTML = '<i class="fas fa-shield-alt"></i> ' + t('profile.role_admin');
} else {
badge.className = 'role-badge role-badge-user';
badge.innerHTML = '<i class="fas fa-user"></i> User';
badge.innerHTML = '<i class="fas fa-user"></i> ' + t('profile.role_user');
}
document.getElementById('p-detail-username').textContent = user.username;
document.getElementById('p-detail-email').textContent = user.email || '—';
document.getElementById('p-detail-role').textContent = user.role === 'admin' ? 'Administrator' : 'User';
document.getElementById('p-detail-role').textContent = user.role === 'admin' ? t('profile.role_admin') : t('profile.role_user');
document.getElementById('p-detail-login').textContent = timeAgo(user.last_login_at);
const used = user.storage_used_bytes || 0;
@@ -59,7 +65,7 @@ async function init() {
const bar = document.getElementById('p-storage-bar');
bar.style.width = pct + '%';
bar.className = 'storage-fill ' + (pct > 90 ? 'red' : pct > 70 ? 'orange' : 'green');
document.getElementById('p-storage-text').textContent = formatBytes(used) + ' / ' + (quota > 0 ? formatBytes(quota) : 'Unlimited');
document.getElementById('p-storage-text').textContent = formatBytes(used) + ' / ' + (quota > 0 ? formatBytes(quota) : t('profile.unlimited'));
if (user.auth_provider && user.auth_provider !== 'local') {
document.getElementById('password-section').classList.add('hidden');
@@ -99,18 +105,18 @@ async function changePassword(e) {
const statusEl = document.getElementById('pw-status');
if (newPw !== confirmPw) {
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> Passwords do not match</div>';
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(t('profile.passwords_no_match')) + '</div>';
return false;
}
if (newPw.length < 8) {
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> Password must be at least 8 characters</div>';
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(t('profile.password_too_short')) + '</div>';
return false;
}
const btn = document.getElementById('pw-submit');
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Updating…';
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> ' + escapeHtml(t('profile.updating'));
try {
const resp = await fetch(API + '/auth/change-password', {
@@ -121,18 +127,18 @@ async function changePassword(e) {
});
if (resp.ok) {
statusEl.innerHTML = '<div class="alert alert-success"><i class="fas fa-check-circle"></i> Password updated successfully</div>';
statusEl.innerHTML = '<div class="alert alert-success"><i class="fas fa-check-circle"></i> ' + escapeHtml(t('profile.password_updated')) + '</div>';
document.getElementById('password-form').reset();
} else {
const err = await resp.json().catch(() => ({}));
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(err.message || 'Failed to change password') + '</div>';
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(err.message || t('profile.password_change_failed')) + '</div>';
}
} catch (err) {
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> Network error: ' + escapeHtml(err.message) + '</div>';
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(t('profile.error_network', { message: err.message })) + '</div>';
}
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-save"></i> Update Password';
btn.innerHTML = '<i class="fas fa-save"></i> ' + escapeHtml(t('profile.update_password'));
return false;
}
@@ -151,15 +157,15 @@ function renderPwRow(pw) {
const created = document.createElement('td');
created.textContent = new Date(pw.created_at).toLocaleDateString();
const lastUsed = document.createElement('td');
lastUsed.textContent = pw.last_used_at ? timeAgo(pw.last_used_at) : 'Never';
lastUsed.textContent = pw.last_used_at ? timeAgo(pw.last_used_at) : t('profile.never');
const status = document.createElement('td');
const badge = document.createElement('span');
if (pw.active !== false) {
badge.className = 'badge badge-active';
badge.textContent = 'Active';
badge.textContent = t('profile.active');
} else {
badge.className = 'badge badge-expired';
badge.textContent = 'Revoked';
badge.textContent = t('profile.revoked');
}
status.appendChild(badge);
const actions = document.createElement('td');
@@ -167,7 +173,7 @@ function renderPwRow(pw) {
const btn = document.createElement('button');
btn.className = 'btn btn-danger-sm';
btn.innerHTML = '<i class="fas fa-trash"></i>';
btn.title = 'Revoke';
btn.title = t('profile.revoke_title');
btn.addEventListener('click', function () { revokeAppPassword(pw.id, pw.label); });
actions.appendChild(btn);
}
@@ -232,12 +238,12 @@ async function createAppPassword() {
const btn = document.getElementById('app-pw-generate');
if (!label) {
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> Please enter a label</div>';
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(t('profile.error_label_required')) + '</div>';
return;
}
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Generating…';
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> ' + escapeHtml(t('profile.generating'));
statusEl.innerHTML = '';
try {
@@ -249,7 +255,7 @@ async function createAppPassword() {
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + (err.message || 'Failed to create app password') + '</div>';
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + escapeHtml(err.message || t('profile.error_create_pw')) + '</div>';
return;
}
const result = await resp.json();
@@ -262,7 +268,7 @@ async function createAppPassword() {
statusEl.innerHTML = '<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' + err.message + '</div>';
} finally {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-plus"></i> Generate';
btn.innerHTML = '<i class="fas fa-plus"></i> ' + escapeHtml(t('profile.generate'));
}
}
@@ -276,7 +282,7 @@ function copyAppPassword() {
}
async function revokeAppPassword(id, label) {
if (!confirm('Revoke app password "' + label + '"? Clients using this password will stop working.')) return;
if (!confirm(t('profile.confirm_revoke', { label: label }))) return;
try {
const resp = await fetch(API + '/auth/app-passwords/' + encodeURIComponent(id), {
method: 'DELETE',
@@ -288,10 +294,10 @@ async function revokeAppPassword(id, label) {
loadAppPasswords();
} else {
const err = await resp.json().catch(() => ({}));
alert(err.message || 'Failed to revoke app password');
alert(err.message || t('profile.error_revoke'));
}
} catch (err) {
alert('Network error: ' + err.message);
alert(t('profile.error_network', { message: err.message }));
}
}
@@ -308,3 +314,7 @@ document.getElementById('password-form').addEventListener('submit', changePasswo
document.getElementById('app-pw-generate').addEventListener('click', createAppPassword);
document.getElementById('app-pw-copy-btn').addEventListener('click', copyAppPassword);
document.getElementById('app-pw-auto-toggle').addEventListener('click', toggleAutoPasswords);
/* Re-render when language changes */
window.addEventListener('translationsLoaded', function () { init(); });
window.addEventListener('localeChanged', function () { init(); });
+555
View File
@@ -0,0 +1,555 @@
{
"app": {
"title": "OxiCloud",
"description": "نظام تخزين سحابي بسيط"
},
"nav": {
"files": "الملفات",
"shared": "المشترك",
"recent": "الأخيرة",
"favorites": "المفضلة",
"photos": "الصور",
"trash": "سلة المهملات"
},
"photos": {
"empty_state": "لا توجد صور بعد",
"empty_hint": "ارفع صوراً أو مقاطع فيديو لعرضها هنا",
"items_selected": "محدد",
"view_daily": "يوم",
"view_monthly": "شهر",
"view_yearly": "سنة"
},
"actions": {
"search": "البحث في الملفات...",
"new_folder": "مجلد جديد",
"upload": "رفع",
"upload_files": "رفع ملفات",
"upload_folder": "رفع مجلد",
"upload.uploading": "جارٍ الرفع...",
"upload.complete": "{count} / {total} تم رفعها",
"rename": "إعادة التسمية",
"move": "نقل إلى...",
"move_to": "نقل إلى",
"delete": "حذف",
"download": "تحميل",
"view": "عرض",
"cancel": "إلغاء",
"confirm": "تأكيد",
"share": "مشاركة",
"favorite": "إضافة للمفضلة",
"unfavorite": "إزالة من المفضلة",
"copy": "نسخ",
"notify": "إشعار",
"send": "إرسال",
"clear_recent": "مسح الأخيرة",
"logout": "تسجيل الخروج",
"create": "إنشاء",
"search_btn": "بحث",
"close": "إغلاق",
"delete_permanently": "حذف نهائياً",
"empty_trash": "تفريغ سلة المهملات"
},
"user_menu": {
"appearance": "المظهر",
"about": "حول OxiCloud",
"about_description": "منصة تخزين سحابي مبنية بـ Rust و Clean Architecture. سريعة وآمنة وخاصة.",
"admin_panel": "لوحة الإدارة",
"profile": "ملفي الشخصي",
"role_user": "مستخدم"
},
"share": {
"dialogTitle": "رابط المشاركة",
"linkLabel": "رابط المشاركة:",
"copyLink": "نسخ",
"permissions": "الصلاحيات:",
"permissionRead": "قراءة",
"permissionWrite": "كتابة",
"permissionReshare": "إعادة مشاركة",
"password": "حماية بكلمة مرور:",
"generatePassword": "توليد",
"expiration": "تاريخ انتهاء الصلاحية:",
"update": "تحديث المشاركة",
"remove": "إزالة المشاركة",
"notifyTitle": "إرسال إشعار",
"notifyEmailLabel": "عنوان البريد الإلكتروني:",
"notifyMessageLabel": "رسالة (اختياري):",
"notifySend": "إرسال الإشعار",
"shareWithOthers": "مشاركة مع آخرين",
"sharePublicly": "مشاركة عامة",
"shareSettings": "إعدادات المشاركة",
"shareCopied": "تم نسخ الرابط إلى الحافظة",
"shareCreated": "تم إنشاء رابط المشاركة بنجاح",
"shareUpdated": "تم تحديث إعدادات المشاركة بنجاح",
"shareRemoved": "تمت إزالة المشاركة بنجاح"
},
"share_dialogTitle": "رابط المشاركة",
"share_linkLabel": "رابط المشاركة:",
"share_copyLink": "نسخ",
"share_permissions": "الصلاحيات:",
"share_permissionRead": "قراءة",
"share_permissionWrite": "كتابة",
"share_permissionReshare": "إعادة مشاركة",
"share_password": "حماية بكلمة مرور:",
"share_generatePassword": "توليد",
"share_expiration": "تاريخ انتهاء الصلاحية:",
"share_update": "تحديث المشاركة",
"share_remove": "إزالة المشاركة",
"share_notifyTitle": "إرسال إشعار",
"share_notifyEmailLabel": "عنوان البريد الإلكتروني:",
"share_notifyMessageLabel": "رسالة (اختياري):",
"share_notifySend": "إرسال الإشعار",
"shared": {
"backToFiles": "العودة إلى الملفات",
"pageTitle": "الموارد المشتركة",
"pageDescription": "إدارة ملفاتك ومجلداتك المشتركة",
"filterType": "النوع:",
"filterAll": "الكل",
"filterFiles": "ملفات",
"filterFolders": "مجلدات",
"sortBy": "ترتيب حسب:",
"sortByName": "الاسم",
"sortByDate": "تاريخ المشاركة",
"sortByExpiration": "انتهاء الصلاحية",
"search": "بحث",
"colName": "الاسم",
"colType": "النوع",
"colDateShared": "تاريخ المشاركة",
"colExpiration": "انتهاء الصلاحية",
"colPermissions": "الصلاحيات",
"colPassword": "كلمة المرور",
"colActions": "الإجراءات",
"emptyStateTitle": "لا توجد موارد مشتركة بعد",
"emptyStateDesc": "عندما تشارك ملفات أو مجلدات، ستظهر هنا",
"goToFiles": "الذهاب إلى الملفات",
"typeFile": "ملف",
"typeFolder": "مجلد",
"noExpiration": "بدون انتهاء صلاحية",
"hasPassword": "نعم",
"noPassword": "لا",
"editShare": "تعديل المشاركة",
"notifyShare": "إشعار شخص ما",
"copyLink": "نسخ الرابط",
"removeShare": "إزالة المشاركة",
"linkCopied": "تم نسخ الرابط إلى الحافظة!",
"linkCopyFailed": "فشل نسخ الرابط",
"itemUpdated": "تم تحديث إعدادات المشاركة بنجاح",
"itemRemoved": "تمت إزالة المشاركة بنجاح",
"invalidEmail": "يرجى إدخال عنوان بريد إلكتروني صالح",
"notificationSent": "تم إرسال الإشعار بنجاح",
"notificationFailed": "فشل إرسال الإشعار",
"shared_backToFiles": "العودة إلى الملفات",
"shared_pageTitle": "الموارد المشتركة",
"shared_pageDescription": "إدارة ملفاتك ومجلداتك المشتركة",
"shared_filterType": "النوع:",
"shared_filterAll": "الكل",
"shared_filterFiles": "ملفات",
"shared_filterFolders": "مجلدات",
"shared_sortBy": "ترتيب حسب:",
"shared_sortByName": "الاسم",
"shared_sortByDate": "تاريخ المشاركة",
"shared_sortByExpiration": "انتهاء الصلاحية",
"shared_search": "بحث",
"shared_colName": "الاسم",
"shared_colType": "النوع",
"shared_colDateShared": "تاريخ المشاركة",
"shared_colExpiration": "انتهاء الصلاحية",
"shared_colPermissions": "الصلاحيات",
"shared_colPassword": "كلمة المرور",
"shared_colActions": "الإجراءات",
"shared_emptyStateTitle": "لا توجد موارد مشتركة بعد",
"shared_emptyStateDesc": "عندما تشارك ملفات أو مجلدات، ستظهر هنا",
"shared_goToFiles": "الذهاب إلى الملفات",
"shared_typeFile": "ملف",
"shared_typeFolder": "مجلد",
"shared_noExpiration": "بدون انتهاء صلاحية",
"shared_hasPassword": "نعم",
"shared_noPassword": "لا",
"shared_editShare": "تعديل المشاركة",
"shared_notifyShare": "إشعار شخص ما",
"shared_copyLink": "نسخ الرابط",
"shared_removeShare": "إزالة المشاركة",
"shared_linkCopied": "تم نسخ الرابط إلى الحافظة!",
"shared_linkCopyFailed": "فشل نسخ الرابط",
"shared_itemUpdated": "تم تحديث إعدادات المشاركة بنجاح",
"shared_itemRemoved": "تمت إزالة المشاركة بنجاح",
"shared_invalidEmail": "يرجى إدخال عنوان بريد إلكتروني صالح",
"shared_notificationSent": "تم إرسال الإشعار بنجاح",
"shared_notificationFailed": "فشل إرسال الإشعار"
},
"files": {
"name": "الاسم",
"type": "النوع",
"size": "الحجم",
"modified": "تاريخ التعديل",
"no_files": "لا توجد ملفات في هذا المجلد",
"empty_hint": "ارفع ملفات أو أنشئ مجلدات للبدء",
"loading": "جارٍ تحميل الملفات…",
"view_grid": "عرض شبكي",
"view_list": "عرض قائمة",
"file_types": {
"document": "مستند",
"image": "صورة",
"video": "فيديو",
"audio": "صوت",
"pdf": "PDF",
"text": "نص",
"folder": "مجلد",
"spreadsheet": "جدول بيانات",
"presentation": "عرض تقديمي",
"archive": "أرشيف",
"installer": "مثبّت",
"code": "كود"
}
},
"dialogs": {
"rename_folder": "إعادة تسمية المجلد",
"rename_file": "إعادة تسمية الملف",
"new_name": "الاسم الجديد",
"new_folder_title": "مجلد جديد",
"folder_name": "اسم المجلد",
"folder_placeholder": "مجلدي",
"rename_title": "إعادة التسمية",
"move_file": "نقل الملف",
"move_folder": "نقل المجلد",
"select_destination": "اختر المجلد الوجهة:",
"select_this_folder": "اختيار هذا المجلد",
"go_to_parent": ".. (المجلد الأعلى)",
"no_subfolders": "لا توجد مجلدات فرعية",
"root": "الجذر",
"delete_confirmation": "هل أنت متأكد أنك تريد حذف",
"and_contents": "وجميع محتوياته",
"no_undo": "لا يمكن التراجع عن هذا الإجراء",
"confirm_title": "تأكيد الإجراء",
"confirm_delete": "نقل إلى سلة المهملات",
"confirm_delete_file": "هل أنت متأكد أنك تريد نقل الملف \"{{name}}\" إلى سلة المهملات؟",
"confirm_delete_folder": "هل أنت متأكد أنك تريد نقل المجلد \"{{name}}\" وجميع محتوياته إلى سلة المهملات؟",
"confirm_permanent_delete": "حذف نهائي",
"confirm_permanent_delete_msg": "هل أنت متأكد أنك تريد حذف هذا العنصر نهائياً؟ لا يمكن التراجع عن هذا الإجراء.",
"confirm_empty_trash": "تفريغ سلة المهملات",
"confirm_delete_share": "حذف رابط المشاركة",
"confirm_delete_share_msg": "هل أنت متأكد أنك تريد حذف رابط المشاركة هذا؟",
"share_file": "مشاركة الملف",
"existing_shares": "المشاركات الحالية",
"share_options": "خيارات المشاركة",
"password": "كلمة المرور",
"expiration": "انتهاء الصلاحية",
"permissions": "الصلاحيات",
"generated_link": "الرابط المُنشأ",
"notify": "إرسال إشعار",
"recipient": "المستلم",
"message": "الرسالة"
},
"dropzone": {
"drag_files": "اسحب الملفات هنا أو انقر للاختيار",
"drop_files": "أسقط الملفات للرفع"
},
"permissions": {
"read": "قراءة",
"write": "كتابة",
"reshare": "إعادة مشاركة"
},
"errors": {
"file_not_found": "الملف غير موجود",
"folder_not_found": "المجلد غير موجود",
"delete_error": "خطأ في الحذف",
"upload_error": "خطأ في رفع الملف",
"rename_error": "خطأ في إعادة التسمية",
"move_error": "خطأ في النقل",
"empty_name": "لا يمكن أن يكون الاسم فارغاً",
"name_exists": "ملف أو مجلد بهذا الاسم موجود بالفعل",
"generic_error": "حدث خطأ"
},
"breadcrumb": {
"home": "الرئيسية"
},
"trash": {
"empty_trash": "تفريغ سلة المهملات",
"empty_state": "سلة المهملات فارغة",
"original_location": "الموقع الأصلي",
"deleted_date": "تاريخ الحذف",
"actions": "الإجراءات",
"restore": "استعادة",
"delete_permanently": "حذف نهائياً",
"empty_confirm": "هل أنت متأكد أنك تريد تفريغ سلة المهملات؟ سيتم حذف جميع العناصر نهائياً."
},
"auth": {
"login_title": "تسجيل الدخول",
"username": "اسم المستخدم",
"username_placeholder": "أدخل اسم المستخدم",
"password": "كلمة المرور",
"password_placeholder": "أدخل كلمة المرور",
"login_button": "تسجيل الدخول",
"no_account": "ليس لديك حساب؟",
"register": "إنشاء حساب",
"admin_setup": "أول مرة؟",
"setup": "إعداد المسؤول",
"register_title": "إنشاء حساب",
"email": "البريد الإلكتروني",
"email_placeholder": "أدخل بريدك الإلكتروني",
"confirm_password": "تأكيد كلمة المرور",
"confirm_password_placeholder": "أكد كلمة المرور",
"register_button": "إنشاء حساب",
"have_account": "لديك حساب بالفعل؟",
"login": "تسجيل الدخول",
"setup_title": "الإعداد الأولي",
"setup_step1": "المسؤول",
"setup_step2": "النظام",
"setup_step3": "مكتمل",
"admin_username": "اسم مستخدم المسؤول",
"admin_email": "بريد المسؤول الإلكتروني",
"admin_password": "كلمة مرور المسؤول",
"create_admin": "إنشاء حساب المسؤول",
"back_to_login": "تم الإعداد مسبقاً؟",
"admin_success": "تم إنشاء حساب المسؤول بنجاح! يمكنك الآن تسجيل الدخول.",
"account_success": "تم إنشاء الحساب بنجاح! يمكنك الآن تسجيل الدخول.",
"passwords_mismatch": "كلمات المرور غير متطابقة",
"admin_create_error": "خطأ في إنشاء حساب المسؤول",
"or": "أو",
"sso_login": "تسجيل الدخول عبر SSO",
"sso_login_provider": "تسجيل الدخول عبر {{provider}}"
},
"storage": {
"title": "التخزين",
"calculating": "جارٍ الحساب...",
"used": "{{percentage}}% مستخدم ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "لا يمكن معاينة هذا النوع من الملفات.",
"download_file": "تحميل الملف",
"zoom_in": "تكبير",
"zoom_out": "تصغير",
"zoom_reset": "إعادة تعيين التكبير"
},
"language_selector": {
"title": "!مرحباً",
"subtitle": "اختر لغتك للمتابعة",
"continue": "متابعة",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português",
"ar": "العربية"
}
},
"favorites": {
"empty_state": "لا توجد مفضلات بعد",
"empty_hint": "ضع نجمة على الملفات أو المجلدات لإضافتها إلى المفضلة",
"add": "إضافة للمفضلة",
"remove": "إزالة من المفضلة",
"added_title": "أُضيف للمفضلة",
"added_msg": "أُضيف للمفضلة",
"removed_title": "أُزيل من المفضلة",
"removed_msg": "أُزيل من المفضلة"
},
"recent": {
"title": "الأخيرة",
"clear": "مسح الأخيرة",
"accessed": "تم الوصول",
"empty_state": "لا توجد ملفات حديثة",
"empty_hint": "الملفات التي تفتحها ستظهر هنا"
},
"notifications": {
"file_renamed": "تمت إعادة تسمية الملف",
"file_renamed_to": "تمت إعادة تسمية الملف إلى \"{{name}}\"",
"folder_renamed": "تمت إعادة تسمية المجلد",
"folder_renamed_to": "تمت إعادة تسمية المجلد إلى \"{{name}}\"",
"file_uploaded": "تم رفع الملف",
"file_deleted": "تم نقل الملف إلى سلة المهملات",
"folder_deleted": "تم نقل المجلد إلى سلة المهملات",
"item_deleted_permanently": "تم حذف العنصر نهائياً",
"trash_emptied": "تم تفريغ سلة المهملات بنجاح",
"title": "الإشعارات",
"empty": "لا توجد إشعارات"
},
"batch": {
"one_selected": "عنصر واحد محدد",
"n_selected": "{{count}} عناصر محددة",
"confirm_delete": "هل أنت متأكد أنك تريد نقل {{count}} عنصر إلى سلة المهملات؟",
"move_title": "نقل {{count}} عنصر",
"add_favorites": "إضافة للمفضلة",
"move_copy": "نقل أو نسخ"
},
"admin": {
"page_title": "لوحة الإدارة",
"back_to_app": "العودة إلى OxiCloud",
"loading": "جارٍ التحميل…",
"access_denied": "الوصول مرفوض",
"access_denied_desc": "صلاحيات المسؤول مطلوبة.",
"sign_in": "تسجيل الدخول",
"tab_dashboard": "لوحة المعلومات",
"tab_users": "المستخدمون",
"tab_oidc": "SSO / OIDC",
"total_users": "إجمالي المستخدمين",
"active_users": "المستخدمون النشطون",
"admins": "المسؤولون",
"version": "الإصدار",
"storage_overview": "نظرة عامة على التخزين",
"used": "مستخدم",
"total_quota": "الحصة الإجمالية",
"usage_pct": "نسبة الاستخدام",
"users_over_80": "مستخدمون >80%",
"users_over_quota": "مستخدمون تجاوزوا الحصة",
"system": "النظام",
"auth_label": "المصادقة",
"oidc_label": "OIDC",
"quotas_label": "الحصص",
"enabled": "مفعّل",
"disabled": "معطّل",
"active": "نشط",
"off": "متوقف",
"allow_registration": "السماح بالتسجيل العام",
"registration_warning": "التسجيل العام معطّل. فقط المسؤولون يمكنهم إنشاء مستخدمين.",
"user_management": "إدارة المستخدمين",
"create_user": "إنشاء مستخدم",
"col_user": "المستخدم",
"col_role": "الدور",
"col_auth": "المصادقة",
"col_status": "الحالة",
"col_storage": "التخزين",
"col_last_login": "آخر دخول",
"col_actions": "الإجراءات",
"loading_users": "جارٍ تحميل المستخدمين…",
"failed_load_users": "فشل التحميل",
"no_users_found": "لم يتم العثور على مستخدمين",
"showing_users": "عرض {{from}}-{{to}} من {{total}}",
"prev": "السابق",
"next": "التالي",
"inactive": "غير نشط",
"you_badge": "(أنت)",
"local": "محلي",
"never": "أبداً",
"just_now": "الآن",
"minutes_ago": "منذ {{n}} دقيقة",
"hours_ago": "منذ {{n}} ساعة",
"days_ago": "منذ {{n}} يوم",
"edit_quota_title": "تعديل الحصة",
"reset_password_title": "إعادة تعيين كلمة المرور",
"toggle_role_title": "تبديل الدور",
"deactivate_title": "تعطيل",
"activate_title": "تفعيل",
"delete_title": "حذف",
"sso_title": "تسجيل الدخول الموحد (OIDC / SSO)",
"enable_sso": "تفعيل مصادقة SSO",
"provider_name": "اسم الموفر",
"issuer_url": "عنوان المُصدر",
"issuer_url_hint": "عنوان مُصدر OpenID Connect",
"auto_discover": "اكتشاف تلقائي",
"discovering": "جارٍ الاكتشاف…",
"client_id": "معرّف العميل",
"client_secret": "سر العميل",
"client_secret_placeholder": "اتركه فارغاً للاحتفاظ بالقيمة",
"secret_configured": "سر العميل مُهيأ بالفعل",
"callback_url": "عنوان الاستدعاء",
"callback_url_hint": "(سجّل في IdP)",
"advanced_settings": "إعدادات متقدمة",
"scopes": "النطاقات",
"auto_provision": "إنشاء تلقائي عند أول دخول",
"admin_groups": "مجموعات المسؤولين",
"admin_groups_hint": "أسماء مجموعات OIDC مفصولة بفواصل",
"disable_password": "تعطيل الدخول بكلمة المرور (OIDC فقط)",
"password_warning": "سيمنع جميع عمليات الدخول بالمرور!",
"test_btn": "اختبار",
"save_btn": "حفظ",
"saving": "جارٍ الحفظ…",
"settings_saved": "تم الحفظ — OIDC الآن {{status}}",
"quota_modal_title": "تحديث حصة التخزين",
"quota_user_label": "المستخدم:",
"new_quota": "حصة جديدة",
"quota_unlimited_hint": "0 لغير محدود",
"cancel": "إلغاء",
"create_user_title": "إنشاء مستخدم جديد",
"username_label": "اسم المستخدم",
"username_placeholder": "اسم_المستخدم",
"username_hint": "3–32 حرفاً",
"password_label": "كلمة المرور",
"password_placeholder": "8 أحرف على الأقل",
"email_label": "البريد",
"email_optional": "(اختياري)",
"email_placeholder": "user@example.com (يُنشأ تلقائياً)",
"role_label": "الدور",
"role_user": "مستخدم",
"role_admin": "مسؤول",
"quota_label": "الحصة",
"creating": "جارٍ الإنشاء…",
"reset_pw_title": "إعادة تعيين كلمة المرور",
"new_password_label": "كلمة مرور جديدة",
"resetting": "جارٍ إعادة التعيين…",
"reset_btn": "إعادة تعيين",
"confirm_role_change": "تغيير الدور إلى {{role}}؟",
"confirm_deactivate": "هل أنت متأكد من التعطيل؟",
"confirm_activate": "هل أنت متأكد من التفعيل؟",
"confirm_delete_user": "حذف المستخدم \"{{name}}\"؟ لا يمكن التراجع!",
"confirm_action": "تأكيد الإجراء",
"confirm_yes": "تأكيد",
"confirm_no": "إلغاء",
"error_username_short": "الاسم 3 أحرف على الأقل",
"error_password_short": "كلمة المرور 8 أحرف على الأقل",
"error_generic": "فشل",
"error_network": "خطأ في الشبكة: {{message}}",
"error_create_user": "فشل إنشاء المستخدم"
},
"profile": {
"page_title": "الملف الشخصي",
"back_to_app": "العودة إلى OxiCloud",
"loading": "جارٍ التحميل…",
"not_authenticated": "غير مُصادق",
"not_authenticated_desc": "سجّل الدخول لعرض ملفك الشخصي.",
"sign_in": "تسجيل الدخول",
"role_admin": "مسؤول",
"role_user": "مستخدم",
"account_details": "تفاصيل الحساب",
"username": "اسم المستخدم",
"email": "البريد الإلكتروني",
"role": "الدور",
"last_login": "آخر دخول",
"storage": "التخزين",
"used": "مستخدم",
"quota": "الحصة",
"usage": "الاستخدام",
"unlimited": "غير محدود",
"app_passwords": "كلمات مرور التطبيقات",
"app_pw_desc": "أنشئ كلمات مرور لعملاء WebDAV و CalDAV و CardDAV. تُعرض كل كلمة مرور مرة واحدة فقط.",
"app_pw_label_placeholder": "التسمية (مثلاً Thunderbird، macOS)",
"generate": "إنشاء",
"generating": "جارٍ الإنشاء…",
"new_password_for": "كلمة مرور جديدة لـ",
"copy_warning": "انسخ كلمة المرور الآن. لن تتمكن من رؤيتها مرة أخرى.",
"copy_to_clipboard": "نسخ إلى الحافظة",
"col_label": "التسمية",
"col_created": "تاريخ الإنشاء",
"col_last_used": "آخر استخدام",
"col_status": "الحالة",
"active": "نشط",
"revoked": "ملغى",
"revoke_title": "إلغاء",
"no_app_passwords": "لا توجد كلمات مرور تطبيقات بعد.",
"client_sessions": "جلسات العميل",
"client_sessions_desc": "تُنشأ تلقائيًا عند اتصال عميل متوافق مع Nextcloud.",
"col_client": "العميل",
"never": "أبداً",
"just_now": "الآن",
"minutes_ago": "منذ {{n}} دقيقة",
"hours_ago": "منذ {{n}} ساعة",
"days_ago": "منذ {{n}} يوم",
"change_password": "تغيير كلمة المرور",
"current_password": "كلمة المرور الحالية",
"new_password": "كلمة المرور الجديدة",
"min_8_chars": "8 أحرف على الأقل",
"confirm_password": "تأكيد كلمة المرور الجديدة",
"update_password": "تحديث كلمة المرور",
"updating": "جارٍ التحديث…",
"password_updated": "تم تحديث كلمة المرور بنجاح",
"passwords_no_match": "كلمتا المرور غير متطابقتين",
"password_too_short": "يجب أن تكون كلمة المرور 8 أحرف على الأقل",
"password_change_failed": "فشل تغيير كلمة المرور",
"error_network": "خطأ في الشبكة: {{message}}",
"error_label_required": "أدخل تسمية",
"error_create_pw": "فشل إنشاء كلمة المرور",
"confirm_revoke": "إلغاء كلمة المرور \"{{label}}\"؟ ستتوقف العملاء عن العمل.",
"error_revoke": "فشل الإلغاء"
}
}
+551 -371
View File
@@ -1,371 +1,551 @@
{
"app": {
"title": "OxiCloud",
"description": "Minimalistisches Cloud-Speichersystem"
},
"nav": {
"files": "Dateien",
"shared": "Geteilt",
"recent": "Zuletzt verwendet",
"favorites": "Favoriten",
"photos": "Fotos",
"trash": "Papierkorb"
},
"photos": {
"empty_state": "Noch keine Fotos",
"empty_hint": "Laden Sie Bilder oder Videos hoch, um sie hier zu sehen",
"items_selected": "ausgewählt",
"view_daily": "Tag",
"view_monthly": "Monat",
"view_yearly": "Jahr"
},
"actions": {
"search": "Dateien suchen...",
"new_folder": "Neuer Ordner",
"upload": "Hochladen",
"upload_files": "Dateien hochladen",
"upload_folder": "Ordner hochladen",
"upload.uploading": "Wird hochgeladen...",
"upload.complete": "{count} / {total} hochgeladen",
"rename": "Umbenennen",
"move": "Verschieben nach...",
"move_to": "Verschieben nach",
"delete": "Löschen",
"download": "Herunterladen",
"view": "Anzeigen",
"cancel": "Abbrechen",
"confirm": "Bestätigen",
"share": "Teilen",
"favorite": "Zu Favoriten hinzufügen",
"unfavorite": "Aus Favoriten entfernen",
"copy": "Kopieren",
"notify": "Benachrichtigen",
"send": "Senden",
"clear_recent": "Zuletzt verwendete löschen",
"logout": "Abmelden",
"create": "Erstellen",
"search_btn": "Suchen",
"close": "Schließen",
"delete_permanently": "Endgültig löschen",
"empty_trash": "Papierkorb leeren"
},
"user_menu": {
"appearance": "Erscheinungsbild",
"about": "Über OxiCloud",
"about_description": "Cloud-Speicherplattform mit Rust und Clean Architecture. Schnell, sicher und privat.",
"admin_panel": "Admin-Panel",
"profile": "Mein Profil",
"role_user": "Benutzer"
},
"share": {
"dialogTitle": "Link teilen",
"linkLabel": "Geteilter Link:",
"copyLink": "Kopieren",
"permissions": "Berechtigungen:",
"permissionRead": "Lesen",
"permissionWrite": "Schreiben",
"permissionReshare": "Weiterteilen",
"password": "Passwortschutz:",
"generatePassword": "Generieren",
"expiration": "Ablaufdatum:",
"update": "Freigabe aktualisieren",
"remove": "Freigabe entfernen",
"notifyTitle": "Benachrichtigung senden",
"notifyEmailLabel": "E-Mail-Adresse:",
"notifyMessageLabel": "Nachricht (optional):",
"notifySend": "Benachrichtigung senden",
"shareWithOthers": "Mit anderen teilen",
"sharePublicly": "Öffentlich teilen",
"shareSettings": "Freigabeeinstellungen",
"shareCopied": "Link in Zwischenablage kopiert",
"shareCreated": "Freigabelink erfolgreich erstellt",
"shareUpdated": "Freigabeeinstellungen aktualisiert",
"shareRemoved": "Freigabe erfolgreich entfernt"
},
"share_dialogTitle": "Link teilen",
"share_linkLabel": "Geteilter Link:",
"share_copyLink": "Kopieren",
"share_permissions": "Berechtigungen:",
"share_permissionRead": "Lesen",
"share_permissionWrite": "Schreiben",
"share_permissionReshare": "Weiterteilen",
"share_password": "Passwortschutz:",
"share_generatePassword": "Generieren",
"share_expiration": "Ablaufdatum:",
"share_update": "Freigabe aktualisieren",
"share_remove": "Freigabe entfernen",
"share_notifyTitle": "Benachrichtigung senden",
"share_notifyEmailLabel": "E-Mail-Adresse:",
"share_notifyMessageLabel": "Nachricht (optional):",
"share_notifySend": "Benachrichtigung senden",
"shared": {
"backToFiles": "Zurück zu Dateien",
"pageTitle": "Geteilte Ressourcen",
"pageDescription": "Verwalten Sie Ihre geteilten Dateien und Ordner",
"filterType": "Typ:",
"filterAll": "Alle",
"filterFiles": "Dateien",
"filterFolders": "Ordner",
"sortBy": "Sortieren nach:",
"sortByName": "Name",
"sortByDate": "Freigabedatum",
"sortByExpiration": "Ablaufdatum",
"search": "Suchen",
"colName": "Name",
"colType": "Typ",
"colDateShared": "Freigabedatum",
"colExpiration": "Ablaufdatum",
"colPermissions": "Berechtigungen",
"colPassword": "Passwort",
"colActions": "Aktionen",
"emptyStateTitle": "Noch keine geteilten Ressourcen",
"emptyStateDesc": "Wenn Sie Dateien oder Ordner teilen, werden sie hier angezeigt",
"goToFiles": "Zu Dateien gehen",
"typeFile": "Datei",
"typeFolder": "Ordner",
"noExpiration": "Kein Ablaufdatum",
"hasPassword": "Ja",
"noPassword": "Nein",
"editShare": "Freigabe bearbeiten",
"notifyShare": "Jemanden benachrichtigen",
"copyLink": "Link kopieren",
"removeShare": "Freigabe entfernen",
"linkCopied": "Link in Zwischenablage kopiert!",
"linkCopyFailed": "Link konnte nicht kopiert werden",
"itemUpdated": "Freigabeeinstellungen aktualisiert",
"itemRemoved": "Freigabe erfolgreich entfernt",
"invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
"notificationSent": "Benachrichtigung erfolgreich gesendet",
"notificationFailed": "Benachrichtigung konnte nicht gesendet werden"
},
"shared_backToFiles": "Zurück zu Dateien",
"shared_pageTitle": "Geteilte Ressourcen",
"shared_pageDescription": "Verwalten Sie Ihre geteilten Dateien und Ordner",
"shared_filterType": "Typ:",
"shared_filterAll": "Alle",
"shared_filterFiles": "Dateien",
"shared_filterFolders": "Ordner",
"shared_sortBy": "Sortieren nach:",
"shared_sortByName": "Name",
"shared_sortByDate": "Freigabedatum",
"shared_sortByExpiration": "Ablaufdatum",
"shared_search": "Suchen",
"shared_colName": "Name",
"shared_colType": "Typ",
"shared_colDateShared": "Freigabedatum",
"shared_colExpiration": "Ablaufdatum",
"shared_colPermissions": "Berechtigungen",
"shared_colPassword": "Passwort",
"shared_colActions": "Aktionen",
"shared_emptyStateTitle": "Noch keine geteilten Ressourcen",
"shared_emptyStateDesc": "Wenn Sie Dateien oder Ordner teilen, werden sie hier angezeigt",
"shared_goToFiles": "Zu Dateien gehen",
"shared_typeFile": "Datei",
"shared_typeFolder": "Ordner",
"shared_noExpiration": "Kein Ablaufdatum",
"shared_hasPassword": "Ja",
"shared_noPassword": "Nein",
"shared_editShare": "Freigabe bearbeiten",
"shared_notifyShare": "Jemanden benachrichtigen",
"shared_copyLink": "Link kopieren",
"shared_removeShare": "Freigabe entfernen",
"shared_linkCopied": "Link in Zwischenablage kopiert!",
"shared_linkCopyFailed": "Link konnte nicht kopiert werden",
"shared_itemUpdated": "Freigabeeinstellungen aktualisiert",
"shared_itemRemoved": "Freigabe erfolgreich entfernt",
"shared_invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
"shared_notificationSent": "Benachrichtigung erfolgreich gesendet",
"shared_notificationFailed": "Benachrichtigung konnte nicht gesendet werden",
"files": {
"name": "Name",
"type": "Typ",
"size": "Größe",
"modified": "Geändert",
"no_files": "Keine Dateien in diesem Ordner",
"loading": "Dateien werden geladen…",
"view_grid": "Rasteransicht",
"view_list": "Listenansicht",
"file_types": {
"document": "Dokument",
"image": "Bild",
"video": "Video",
"audio": "Audio",
"pdf": "PDF",
"text": "Text",
"folder": "Ordner",
"spreadsheet": "Tabelle",
"presentation": "Präsentation",
"archive": "Archiv",
"installer": "Installationsdatei",
"code": "Code"
}
},
"dialogs": {
"rename_folder": "Ordner umbenennen",
"rename_file": "Datei umbenennen",
"new_name": "Neuer Name",
"new_folder_title": "Neuer Ordner",
"folder_name": "Ordnername",
"folder_placeholder": "Mein Ordner",
"rename_title": "Umbenennen",
"move_file": "Datei verschieben",
"move_folder": "Ordner verschieben",
"select_destination": "Zielordner auswählen:",
"root": "Stammverzeichnis",
"delete_confirmation": "Sind Sie sicher, dass Sie löschen möchten",
"and_contents": "und den gesamten Inhalt",
"no_undo": "Diese Aktion kann nicht rückgängig gemacht werden",
"confirm_title": "Aktion bestätigen",
"confirm_delete": "In Papierkorb verschieben",
"confirm_delete_file": "Sind Sie sicher, dass Sie die Datei \"{{name}}\" in den Papierkorb verschieben möchten?",
"confirm_delete_folder": "Sind Sie sicher, dass Sie den Ordner \"{{name}}\" und seinen gesamten Inhalt in den Papierkorb verschieben möchten?",
"confirm_permanent_delete": "Endgültig löschen",
"confirm_permanent_delete_msg": "Sind Sie sicher, dass Sie dieses Element endgültig löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
"confirm_empty_trash": "Papierkorb leeren",
"confirm_delete_share": "Freigabelink löschen",
"confirm_delete_share_msg": "Sind Sie sicher, dass Sie diesen Freigabelink löschen möchten?",
"share_file": "Datei teilen",
"existing_shares": "Bestehende Freigaben",
"share_options": "Freigabeoptionen",
"password": "Passwort",
"expiration": "Ablaufdatum",
"permissions": "Berechtigungen",
"generated_link": "Generierter Link",
"notify": "Benachrichtigung senden",
"recipient": "Empfänger",
"message": "Nachricht"
},
"dropzone": {
"drag_files": "Dateien hierher ziehen oder klicken zum Auswählen",
"drop_files": "Dateien zum Hochladen ablegen"
},
"permissions": {
"read": "Lesen",
"write": "Schreiben",
"reshare": "Weiterteilen"
},
"errors": {
"file_not_found": "Datei nicht gefunden",
"folder_not_found": "Ordner nicht gefunden",
"delete_error": "Fehler beim Löschen",
"upload_error": "Fehler beim Hochladen",
"rename_error": "Fehler beim Umbenennen",
"move_error": "Fehler beim Verschieben",
"empty_name": "Der Name darf nicht leer sein",
"name_exists": "Eine Datei oder ein Ordner mit diesem Namen existiert bereits",
"generic_error": "Ein Fehler ist aufgetreten"
},
"breadcrumb": {
"home": "Startseite"
},
"trash": {
"empty_trash": "Papierkorb leeren",
"empty_state": "Der Papierkorb ist leer",
"original_location": "Ursprünglicher Speicherort",
"deleted_date": "Löschdatum",
"actions": "Aktionen",
"restore": "Wiederherstellen",
"delete_permanently": "Endgültig löschen",
"empty_confirm": "Sind Sie sicher, dass Sie den Papierkorb leeren möchten? Alle Elemente werden endgültig gelöscht."
},
"auth": {
"login_title": "Anmelden",
"username": "Benutzername",
"username_placeholder": "Geben Sie Ihren Benutzernamen ein",
"password": "Passwort",
"password_placeholder": "Geben Sie Ihr Passwort ein",
"login_button": "Anmelden",
"no_account": "Kein Konto?",
"register": "Registrieren",
"admin_setup": "Erstmalig?",
"setup": "Administrator einrichten",
"register_title": "Konto erstellen",
"email": "E-Mail",
"email_placeholder": "Geben Sie Ihre E-Mail ein",
"confirm_password": "Passwort bestätigen",
"confirm_password_placeholder": "Bestätigen Sie Ihr Passwort",
"register_button": "Konto erstellen",
"have_account": "Bereits ein Konto?",
"login": "Anmelden",
"setup_title": "Ersteinrichtung",
"setup_step1": "Admin",
"setup_step2": "System",
"setup_step3": "Abgeschlossen",
"admin_username": "Admin-Benutzername",
"admin_email": "Admin-E-Mail",
"admin_password": "Admin-Passwort",
"create_admin": "Administrator erstellen",
"back_to_login": "Bereits eingerichtet?",
"admin_success": "Administratorkonto erfolgreich erstellt! Sie können sich jetzt anmelden.",
"account_success": "Konto erfolgreich erstellt! Sie können sich jetzt anmelden.",
"passwords_mismatch": "Die Passwörter stimmen nicht überein",
"admin_create_error": "Fehler beim Erstellen des Administratorkontos",
"or": "oder",
"sso_login": "Mit SSO anmelden",
"sso_login_provider": "Mit {{provider}} anmelden"
},
"storage": {
"title": "Speicher",
"calculating": "Berechnung...",
"used": "{{percentage}}% verwendet ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Dieser Dateityp kann nicht in der Vorschau angezeigt werden.",
"download_file": "Datei herunterladen",
"zoom_in": "Vergrößern",
"zoom_out": "Verkleinern",
"zoom_reset": "Zoom zurücksetzen"
},
"language_selector": {
"title": "Willkommen bei OxiCloud",
"subtitle": "Bitte wählen Sie Ihre Sprache",
"continue": "Weiter",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português"
}
},
"favorites": {
"empty_state": "Noch keine Favoriten",
"empty_hint": "Markieren Sie Dateien oder Ordner mit einem Stern, um sie zu Ihren Favoriten hinzuzufügen",
"add": "Zu Favoriten hinzufügen",
"remove": "Aus Favoriten entfernen",
"added_title": "Zu Favoriten hinzugefügt",
"added_msg": "zu Favoriten hinzugefügt",
"removed_title": "Aus Favoriten entfernt",
"removed_msg": "aus Favoriten entfernt"
},
"recent": {
"title": "Zuletzt verwendet",
"clear": "Zuletzt verwendete löschen",
"accessed": "Zugegriffen",
"empty_state": "Keine zuletzt verwendeten Dateien",
"empty_hint": "Dateien, die Sie öffnen, werden hier angezeigt"
},
"notifications": {
"file_renamed": "Datei umbenannt",
"file_renamed_to": "Datei umbenannt in \"{{name}}\"",
"folder_renamed": "Ordner umbenannt",
"folder_renamed_to": "Ordner umbenannt in \"{{name}}\"",
"file_uploaded": "Datei hochgeladen",
"file_deleted": "Datei in Papierkorb verschoben",
"folder_deleted": "Ordner in Papierkorb verschoben",
"item_deleted_permanently": "Element endgültig gelöscht",
"trash_emptied": "Papierkorb erfolgreich geleert",
"title": "Benachrichtigungen",
"empty": "Keine Benachrichtigungen"
},
"batch": {
"one_selected": "1 Element ausgewählt",
"n_selected": "{{count}} Elemente ausgewählt",
"confirm_delete": "Möchten Sie wirklich {{count}} Elemente in den Papierkorb verschieben?",
"move_title": "{{count}} Element(e) verschieben",
"add_favorites": "Zu Favoriten hinzufügen",
"move_copy": "Verschieben oder kopieren"
}
}
{
"app": {
"title": "OxiCloud",
"description": "Minimalistisches Cloud-Speichersystem"
},
"nav": {
"files": "Dateien",
"shared": "Geteilt",
"recent": "Zuletzt verwendet",
"favorites": "Favoriten",
"photos": "Fotos",
"trash": "Papierkorb"
},
"photos": {
"empty_state": "Noch keine Fotos",
"empty_hint": "Laden Sie Bilder oder Videos hoch, um sie hier zu sehen",
"items_selected": "ausgewählt",
"view_daily": "Tag",
"view_monthly": "Monat",
"view_yearly": "Jahr"
},
"actions": {
"search": "Dateien suchen...",
"new_folder": "Neuer Ordner",
"upload": "Hochladen",
"upload_files": "Dateien hochladen",
"upload_folder": "Ordner hochladen",
"upload.uploading": "Wird hochgeladen...",
"upload.complete": "{count} / {total} hochgeladen",
"rename": "Umbenennen",
"move": "Verschieben nach...",
"move_to": "Verschieben nach",
"delete": "Löschen",
"download": "Herunterladen",
"view": "Anzeigen",
"cancel": "Abbrechen",
"confirm": "Bestätigen",
"share": "Teilen",
"favorite": "Zu Favoriten hinzufügen",
"unfavorite": "Aus Favoriten entfernen",
"copy": "Kopieren",
"notify": "Benachrichtigen",
"send": "Senden",
"clear_recent": "Zuletzt verwendete löschen",
"logout": "Abmelden",
"create": "Erstellen",
"search_btn": "Suchen",
"close": "Schließen",
"delete_permanently": "Endgültig löschen",
"empty_trash": "Papierkorb leeren"
},
"user_menu": {
"appearance": "Erscheinungsbild",
"about": "Über OxiCloud",
"about_description": "Cloud-Speicherplattform mit Rust und Clean Architecture. Schnell, sicher und privat.",
"admin_panel": "Admin-Panel",
"profile": "Mein Profil",
"role_user": "Benutzer"
},
"share": {
"dialogTitle": "Link teilen",
"linkLabel": "Geteilter Link:",
"copyLink": "Kopieren",
"permissions": "Berechtigungen:",
"permissionRead": "Lesen",
"permissionWrite": "Schreiben",
"permissionReshare": "Weiterteilen",
"password": "Passwortschutz:",
"generatePassword": "Generieren",
"expiration": "Ablaufdatum:",
"update": "Freigabe aktualisieren",
"remove": "Freigabe entfernen",
"notifyTitle": "Benachrichtigung senden",
"notifyEmailLabel": "E-Mail-Adresse:",
"notifyMessageLabel": "Nachricht (optional):",
"notifySend": "Benachrichtigung senden",
"shareWithOthers": "Mit anderen teilen",
"sharePublicly": "Öffentlich teilen",
"shareSettings": "Freigabeeinstellungen",
"shareCopied": "Link in Zwischenablage kopiert",
"shareCreated": "Freigabelink erfolgreich erstellt",
"shareUpdated": "Freigabeeinstellungen aktualisiert",
"shareRemoved": "Freigabe erfolgreich entfernt"
},
"share_dialogTitle": "Link teilen",
"share_linkLabel": "Geteilter Link:",
"share_copyLink": "Kopieren",
"share_permissions": "Berechtigungen:",
"share_permissionRead": "Lesen",
"share_permissionWrite": "Schreiben",
"share_permissionReshare": "Weiterteilen",
"share_password": "Passwortschutz:",
"share_generatePassword": "Generieren",
"share_expiration": "Ablaufdatum:",
"share_update": "Freigabe aktualisieren",
"share_remove": "Freigabe entfernen",
"share_notifyTitle": "Benachrichtigung senden",
"share_notifyEmailLabel": "E-Mail-Adresse:",
"share_notifyMessageLabel": "Nachricht (optional):",
"share_notifySend": "Benachrichtigung senden",
"shared": {
"backToFiles": "Zurück zu Dateien",
"pageTitle": "Geteilte Ressourcen",
"pageDescription": "Verwalten Sie Ihre geteilten Dateien und Ordner",
"filterType": "Typ:",
"filterAll": "Alle",
"filterFiles": "Dateien",
"filterFolders": "Ordner",
"sortBy": "Sortieren nach:",
"sortByName": "Name",
"sortByDate": "Freigabedatum",
"sortByExpiration": "Ablaufdatum",
"search": "Suchen",
"colName": "Name",
"colType": "Typ",
"colDateShared": "Freigabedatum",
"colExpiration": "Ablaufdatum",
"colPermissions": "Berechtigungen",
"colPassword": "Passwort",
"colActions": "Aktionen",
"emptyStateTitle": "Noch keine geteilten Ressourcen",
"emptyStateDesc": "Wenn Sie Dateien oder Ordner teilen, werden sie hier angezeigt",
"goToFiles": "Zu Dateien gehen",
"typeFile": "Datei",
"typeFolder": "Ordner",
"noExpiration": "Kein Ablaufdatum",
"hasPassword": "Ja",
"noPassword": "Nein",
"editShare": "Freigabe bearbeiten",
"notifyShare": "Jemanden benachrichtigen",
"copyLink": "Link kopieren",
"removeShare": "Freigabe entfernen",
"linkCopied": "Link in Zwischenablage kopiert!",
"linkCopyFailed": "Link konnte nicht kopiert werden",
"itemUpdated": "Freigabeeinstellungen aktualisiert",
"itemRemoved": "Freigabe erfolgreich entfernt",
"invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
"notificationSent": "Benachrichtigung erfolgreich gesendet",
"notificationFailed": "Benachrichtigung konnte nicht gesendet werden"
},
"shared_backToFiles": "Zurück zu Dateien",
"shared_pageTitle": "Geteilte Ressourcen",
"shared_pageDescription": "Verwalten Sie Ihre geteilten Dateien und Ordner",
"shared_filterType": "Typ:",
"shared_filterAll": "Alle",
"shared_filterFiles": "Dateien",
"shared_filterFolders": "Ordner",
"shared_sortBy": "Sortieren nach:",
"shared_sortByName": "Name",
"shared_sortByDate": "Freigabedatum",
"shared_sortByExpiration": "Ablaufdatum",
"shared_search": "Suchen",
"shared_colName": "Name",
"shared_colType": "Typ",
"shared_colDateShared": "Freigabedatum",
"shared_colExpiration": "Ablaufdatum",
"shared_colPermissions": "Berechtigungen",
"shared_colPassword": "Passwort",
"shared_colActions": "Aktionen",
"shared_emptyStateTitle": "Noch keine geteilten Ressourcen",
"shared_emptyStateDesc": "Wenn Sie Dateien oder Ordner teilen, werden sie hier angezeigt",
"shared_goToFiles": "Zu Dateien gehen",
"shared_typeFile": "Datei",
"shared_typeFolder": "Ordner",
"shared_noExpiration": "Kein Ablaufdatum",
"shared_hasPassword": "Ja",
"shared_noPassword": "Nein",
"shared_editShare": "Freigabe bearbeiten",
"shared_notifyShare": "Jemanden benachrichtigen",
"shared_copyLink": "Link kopieren",
"shared_removeShare": "Freigabe entfernen",
"shared_linkCopied": "Link in Zwischenablage kopiert!",
"shared_linkCopyFailed": "Link konnte nicht kopiert werden",
"shared_itemUpdated": "Freigabeeinstellungen aktualisiert",
"shared_itemRemoved": "Freigabe erfolgreich entfernt",
"shared_invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
"shared_notificationSent": "Benachrichtigung erfolgreich gesendet",
"shared_notificationFailed": "Benachrichtigung konnte nicht gesendet werden",
"files": {
"name": "Name",
"type": "Typ",
"size": "Größe",
"modified": "Geändert",
"no_files": "Keine Dateien in diesem Ordner",
"empty_hint": "Laden Sie Dateien hoch oder erstellen Sie Ordner, um loszulegen",
"loading": "Dateien werden geladen…",
"view_grid": "Rasteransicht",
"view_list": "Listenansicht",
"file_types": {
"document": "Dokument",
"image": "Bild",
"video": "Video",
"audio": "Audio",
"pdf": "PDF",
"text": "Text",
"folder": "Ordner",
"spreadsheet": "Tabelle",
"presentation": "Präsentation",
"archive": "Archiv",
"installer": "Installationsdatei",
"code": "Code"
}
},
"dialogs": {
"rename_folder": "Ordner umbenennen",
"rename_file": "Datei umbenennen",
"new_name": "Neuer Name",
"new_folder_title": "Neuer Ordner",
"folder_name": "Ordnername",
"folder_placeholder": "Mein Ordner",
"rename_title": "Umbenennen",
"move_file": "Datei verschieben",
"move_folder": "Ordner verschieben",
"select_destination": "Zielordner auswählen:",
"root": "Stammverzeichnis",
"delete_confirmation": "Sind Sie sicher, dass Sie löschen möchten",
"and_contents": "und den gesamten Inhalt",
"no_undo": "Diese Aktion kann nicht rückgängig gemacht werden",
"confirm_title": "Aktion bestätigen",
"confirm_delete": "In Papierkorb verschieben",
"confirm_delete_file": "Sind Sie sicher, dass Sie die Datei \"{{name}}\" in den Papierkorb verschieben möchten?",
"confirm_delete_folder": "Sind Sie sicher, dass Sie den Ordner \"{{name}}\" und seinen gesamten Inhalt in den Papierkorb verschieben möchten?",
"confirm_permanent_delete": "Endgültig löschen",
"confirm_permanent_delete_msg": "Sind Sie sicher, dass Sie dieses Element endgültig löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
"confirm_empty_trash": "Papierkorb leeren",
"confirm_delete_share": "Freigabelink löschen",
"confirm_delete_share_msg": "Sind Sie sicher, dass Sie diesen Freigabelink löschen möchten?",
"share_file": "Datei teilen",
"existing_shares": "Bestehende Freigaben",
"share_options": "Freigabeoptionen",
"password": "Passwort",
"expiration": "Ablaufdatum",
"permissions": "Berechtigungen",
"generated_link": "Generierter Link",
"notify": "Benachrichtigung senden",
"recipient": "Empfänger",
"message": "Nachricht"
},
"dropzone": {
"drag_files": "Dateien hierher ziehen oder klicken zum Auswählen",
"drop_files": "Dateien zum Hochladen ablegen"
},
"permissions": {
"read": "Lesen",
"write": "Schreiben",
"reshare": "Weiterteilen"
},
"errors": {
"file_not_found": "Datei nicht gefunden",
"folder_not_found": "Ordner nicht gefunden",
"delete_error": "Fehler beim Löschen",
"upload_error": "Fehler beim Hochladen",
"rename_error": "Fehler beim Umbenennen",
"move_error": "Fehler beim Verschieben",
"empty_name": "Der Name darf nicht leer sein",
"name_exists": "Eine Datei oder ein Ordner mit diesem Namen existiert bereits",
"generic_error": "Ein Fehler ist aufgetreten"
},
"breadcrumb": {
"home": "Startseite"
},
"trash": {
"empty_trash": "Papierkorb leeren",
"empty_state": "Der Papierkorb ist leer",
"original_location": "Ursprünglicher Speicherort",
"deleted_date": "Löschdatum",
"actions": "Aktionen",
"restore": "Wiederherstellen",
"delete_permanently": "Endgültig löschen",
"empty_confirm": "Sind Sie sicher, dass Sie den Papierkorb leeren möchten? Alle Elemente werden endgültig gelöscht."
},
"auth": {
"login_title": "Anmelden",
"username": "Benutzername",
"username_placeholder": "Geben Sie Ihren Benutzernamen ein",
"password": "Passwort",
"password_placeholder": "Geben Sie Ihr Passwort ein",
"login_button": "Anmelden",
"no_account": "Kein Konto?",
"register": "Registrieren",
"admin_setup": "Erstmalig?",
"setup": "Administrator einrichten",
"register_title": "Konto erstellen",
"email": "E-Mail",
"email_placeholder": "Geben Sie Ihre E-Mail ein",
"confirm_password": "Passwort bestätigen",
"confirm_password_placeholder": "Bestätigen Sie Ihr Passwort",
"register_button": "Konto erstellen",
"have_account": "Bereits ein Konto?",
"login": "Anmelden",
"setup_title": "Ersteinrichtung",
"setup_step1": "Admin",
"setup_step2": "System",
"setup_step3": "Abgeschlossen",
"admin_username": "Admin-Benutzername",
"admin_email": "Admin-E-Mail",
"admin_password": "Admin-Passwort",
"create_admin": "Administrator erstellen",
"back_to_login": "Bereits eingerichtet?",
"admin_success": "Administratorkonto erfolgreich erstellt! Sie können sich jetzt anmelden.",
"account_success": "Konto erfolgreich erstellt! Sie können sich jetzt anmelden.",
"passwords_mismatch": "Die Passwörter stimmen nicht überein",
"admin_create_error": "Fehler beim Erstellen des Administratorkontos",
"or": "oder",
"sso_login": "Mit SSO anmelden",
"sso_login_provider": "Mit {{provider}} anmelden"
},
"storage": {
"title": "Speicher",
"calculating": "Berechnung...",
"used": "{{percentage}}% verwendet ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Dieser Dateityp kann nicht in der Vorschau angezeigt werden.",
"download_file": "Datei herunterladen",
"zoom_in": "Vergrößern",
"zoom_out": "Verkleinern",
"zoom_reset": "Zoom zurücksetzen"
},
"language_selector": {
"title": "Willkommen!",
"subtitle": "Wählen Sie Ihre Sprache, um fortzufahren",
"continue": "Weiter",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português"
}
},
"favorites": {
"empty_state": "Noch keine Favoriten",
"empty_hint": "Markieren Sie Dateien oder Ordner mit einem Stern, um sie zu Ihren Favoriten hinzuzufügen",
"add": "Zu Favoriten hinzufügen",
"remove": "Aus Favoriten entfernen",
"added_title": "Zu Favoriten hinzugefügt",
"added_msg": "zu Favoriten hinzugefügt",
"removed_title": "Aus Favoriten entfernt",
"removed_msg": "aus Favoriten entfernt"
},
"recent": {
"title": "Zuletzt verwendet",
"clear": "Zuletzt verwendete löschen",
"accessed": "Zugegriffen",
"empty_state": "Keine zuletzt verwendeten Dateien",
"empty_hint": "Dateien, die Sie öffnen, werden hier angezeigt"
},
"notifications": {
"file_renamed": "Datei umbenannt",
"file_renamed_to": "Datei umbenannt in \"{{name}}\"",
"folder_renamed": "Ordner umbenannt",
"folder_renamed_to": "Ordner umbenannt in \"{{name}}\"",
"file_uploaded": "Datei hochgeladen",
"file_deleted": "Datei in Papierkorb verschoben",
"folder_deleted": "Ordner in Papierkorb verschoben",
"item_deleted_permanently": "Element endgültig gelöscht",
"trash_emptied": "Papierkorb erfolgreich geleert",
"title": "Benachrichtigungen",
"empty": "Keine Benachrichtigungen"
},
"batch": {
"one_selected": "1 Element ausgewählt",
"n_selected": "{{count}} Elemente ausgewählt",
"confirm_delete": "Möchten Sie wirklich {{count}} Elemente in den Papierkorb verschieben?",
"move_title": "{{count}} Element(e) verschieben",
"add_favorites": "Zu Favoriten hinzufügen",
"move_copy": "Verschieben oder kopieren"
},
"admin": {
"page_title": "Admin-Panel",
"back_to_app": "Zurück zu OxiCloud",
"loading": "Laden…",
"access_denied": "Zugriff verweigert",
"access_denied_desc": "Administratorrechte erforderlich.",
"sign_in": "Anmelden",
"tab_dashboard": "Dashboard",
"tab_users": "Benutzer",
"tab_oidc": "SSO / OIDC",
"total_users": "Benutzer gesamt",
"active_users": "Aktive Benutzer",
"admins": "Admins",
"version": "Version",
"storage_overview": "Speicherübersicht",
"used": "Verwendet",
"total_quota": "Gesamtkontingent",
"usage_pct": "Nutzung %",
"users_over_80": "Benutzer >80% Kontingent",
"users_over_quota": "Benutzer über Kontingent",
"system": "System",
"auth_label": "Auth",
"oidc_label": "OIDC",
"quotas_label": "Kontingente",
"enabled": "Aktiviert",
"disabled": "Deaktiviert",
"active": "Aktiv",
"off": "Aus",
"allow_registration": "Öffentliche Selbstregistrierung erlauben",
"registration_warning": "Öffentliche Registrierung ist deaktiviert. Nur Admins können neue Benutzer erstellen.",
"user_management": "Benutzerverwaltung",
"create_user": "Benutzer erstellen",
"col_user": "Benutzer",
"col_role": "Rolle",
"col_auth": "Auth",
"col_status": "Status",
"col_storage": "Speicher",
"col_last_login": "Letzter Login",
"col_actions": "Aktionen",
"loading_users": "Benutzer werden geladen…",
"failed_load_users": "Laden fehlgeschlagen",
"no_users_found": "Keine Benutzer gefunden",
"showing_users": "Zeige {{from}}-{{to}} von {{total}}",
"prev": "Zurück",
"next": "Weiter",
"inactive": "Inaktiv",
"you_badge": "(du)",
"local": "Lokal",
"never": "Nie",
"just_now": "Gerade eben",
"minutes_ago": "vor {{n}}Min",
"hours_ago": "vor {{n}}Std",
"days_ago": "vor {{n}}T",
"edit_quota_title": "Kontingent bearbeiten",
"reset_password_title": "Passwort zurücksetzen",
"toggle_role_title": "Rolle wechseln",
"deactivate_title": "Deaktivieren",
"activate_title": "Aktivieren",
"delete_title": "Löschen",
"sso_title": "Single Sign-On (OIDC / SSO)",
"enable_sso": "SSO-Authentifizierung aktivieren",
"provider_name": "Anbietername",
"issuer_url": "Aussteller-URL",
"issuer_url_hint": "OpenID Connect Aussteller-URL Ihres Identitätsanbieters",
"auto_discover": "Auto-Erkennung",
"discovering": "Erkennung…",
"client_id": "Client-ID",
"client_secret": "Client-Secret",
"client_secret_placeholder": "Leer lassen für aktuellen Wert",
"secret_configured": "Ein Client-Secret ist bereits konfiguriert",
"callback_url": "Callback-URL",
"callback_url_hint": "(bei IdP registrieren)",
"advanced_settings": "Erweiterte Einstellungen",
"scopes": "Scopes",
"auto_provision": "Benutzer bei erstem Login automatisch anlegen",
"admin_groups": "Admin-Gruppen",
"admin_groups_hint": "Kommagetrennte OIDC-Gruppennamen für Admin-Rolle",
"disable_password": "Passwort-Login deaktivieren (nur OIDC)",
"password_warning": "Dies verhindert ALLE passwortbasierten Anmeldungen!",
"test_btn": "Testen",
"save_btn": "Speichern",
"saving": "Speichern…",
"settings_saved": "Einstellungen gespeichert — OIDC ist jetzt {{status}}",
"quota_modal_title": "Speicherkontingent aktualisieren",
"quota_user_label": "Benutzer:",
"new_quota": "Neues Kontingent",
"quota_unlimited_hint": "0 für unbegrenzt",
"cancel": "Abbrechen",
"create_user_title": "Neuen Benutzer erstellen",
"username_label": "Benutzername",
"username_placeholder": "maxmuster",
"username_hint": "3–32 Zeichen",
"password_label": "Passwort",
"password_placeholder": "Min. 8 Zeichen",
"email_label": "E-Mail",
"email_optional": "(optional)",
"email_placeholder": "benutzer@beispiel.de (automatisch wenn leer)",
"role_label": "Rolle",
"role_user": "Benutzer",
"role_admin": "Admin",
"quota_label": "Kontingent",
"creating": "Erstellen…",
"reset_pw_title": "Passwort zurücksetzen",
"new_password_label": "Neues Passwort",
"resetting": "Zurücksetzen…",
"reset_btn": "Zurücksetzen",
"confirm_role_change": "Rolle zu {{role}} ändern?",
"confirm_deactivate": "Diesen Benutzer wirklich deaktivieren?",
"confirm_activate": "Diesen Benutzer wirklich aktivieren?",
"confirm_delete_user": "Benutzer \"{{name}}\" LÖSCHEN? Kann nicht rückgängig gemacht werden!",
"confirm_action": "Aktion bestätigen",
"confirm_yes": "Bestätigen",
"confirm_no": "Abbrechen",
"error_username_short": "Benutzername muss mindestens 3 Zeichen haben",
"error_password_short": "Passwort muss mindestens 8 Zeichen haben",
"error_generic": "Fehlgeschlagen",
"error_network": "Netzwerkfehler: {{message}}",
"error_create_user": "Benutzer erstellen fehlgeschlagen"
},
"profile": {
"page_title": "Profil",
"back_to_app": "Zurück zu OxiCloud",
"loading": "Laden…",
"not_authenticated": "Nicht authentifiziert",
"not_authenticated_desc": "Bitte melden Sie sich an, um Ihr Profil anzuzeigen.",
"sign_in": "Anmelden",
"role_admin": "Administrator",
"role_user": "Benutzer",
"account_details": "Kontodetails",
"username": "Benutzername",
"email": "E-Mail",
"role": "Rolle",
"last_login": "Letzter Login",
"storage": "Speicher",
"used": "Verwendet",
"quota": "Kontingent",
"usage": "Nutzung",
"unlimited": "Unbegrenzt",
"app_passwords": "App-Passwörter",
"app_pw_desc": "Passwörter für WebDAV-, CalDAV- und CardDAV-Clients generieren. Jedes Passwort wird nur einmal angezeigt.",
"app_pw_label_placeholder": "Bezeichnung (z.B. Thunderbird, macOS)",
"generate": "Generieren",
"generating": "Generieren…",
"new_password_for": "Neues Passwort für",
"copy_warning": "Kopieren Sie dieses Passwort jetzt. Sie können es nicht erneut anzeigen.",
"copy_to_clipboard": "In Zwischenablage kopieren",
"col_label": "Bezeichnung",
"col_created": "Erstellt",
"col_last_used": "Zuletzt verwendet",
"col_status": "Status",
"active": "Aktiv",
"revoked": "Widerrufen",
"revoke_title": "Widerrufen",
"no_app_passwords": "Noch keine App-Passwörter.",
"client_sessions": "Client-Sitzungen",
"client_sessions_desc": "Automatisch generiert beim Verbinden eines Nextcloud-kompatiblen Clients.",
"col_client": "Client",
"never": "Nie",
"just_now": "Gerade eben",
"minutes_ago": "vor {{n}} Min",
"hours_ago": "vor {{n}} Std",
"days_ago": "vor {{n}} Tagen",
"change_password": "Passwort ändern",
"current_password": "Aktuelles Passwort",
"new_password": "Neues Passwort",
"min_8_chars": "Mindestens 8 Zeichen",
"confirm_password": "Neues Passwort bestätigen",
"update_password": "Passwort aktualisieren",
"updating": "Aktualisierung…",
"password_updated": "Passwort erfolgreich aktualisiert",
"passwords_no_match": "Passwörter stimmen nicht überein",
"password_too_short": "Passwort muss mindestens 8 Zeichen haben",
"password_change_failed": "Passwort ändern fehlgeschlagen",
"error_network": "Netzwerkfehler: {{message}}",
"error_label_required": "Bitte Bezeichnung eingeben",
"error_create_pw": "App-Passwort erstellen fehlgeschlagen",
"confirm_revoke": "App-Passwort \"{{label}}\" widerrufen? Clients werden nicht mehr funktionieren.",
"error_revoke": "Widerrufen fehlgeschlagen"
}
}
+182 -2
View File
@@ -182,6 +182,7 @@
"size": "Size",
"modified": "Modified",
"no_files": "No files in this folder",
"empty_hint": "Upload files or create folders to get started",
"loading": "Loading files…",
"view_grid": "Grid view",
"view_list": "List view",
@@ -320,8 +321,8 @@
"zoom_reset": "Reset zoom"
},
"language_selector": {
"title": "Welcome to OxiCloud",
"subtitle": "Please select your language",
"title": "Welcome!",
"subtitle": "Select your language to continue",
"continue": "Continue",
"languages": {
"en": "English",
@@ -370,5 +371,184 @@
"move_title": "Move {{count}} item(s)",
"add_favorites": "Add to favorites",
"move_copy": "Move or copy"
},
"admin": {
"page_title": "Admin Panel",
"back_to_app": "Back to OxiCloud",
"loading": "Loading…",
"access_denied": "Access Denied",
"access_denied_desc": "Administrator privileges required to access this panel.",
"sign_in": "Sign in",
"tab_dashboard": "Dashboard",
"tab_users": "Users",
"tab_oidc": "SSO / OIDC",
"total_users": "Total Users",
"active_users": "Active Users",
"admins": "Admins",
"version": "Version",
"storage_overview": "Storage Overview",
"used": "Used",
"total_quota": "Total Quota",
"usage_pct": "Usage %",
"users_over_80": "Users >80% quota",
"users_over_quota": "Users over quota",
"system": "System",
"auth_label": "Auth",
"oidc_label": "OIDC",
"quotas_label": "Quotas",
"enabled": "Enabled",
"disabled": "Disabled",
"active": "Active",
"off": "Off",
"allow_registration": "Allow public self-registration",
"registration_warning": "Public registration is disabled. Only admins can create new users.",
"user_management": "User Management",
"create_user": "Create User",
"col_user": "User",
"col_role": "Role",
"col_auth": "Auth",
"col_status": "Status",
"col_storage": "Storage",
"col_last_login": "Last Login",
"col_actions": "Actions",
"loading_users": "Loading users…",
"failed_load_users": "Failed to load users",
"no_users_found": "No users found",
"showing_users": "Showing {{from}}-{{to}} of {{total}}",
"prev": "Prev",
"next": "Next",
"inactive": "Inactive",
"you_badge": "(you)",
"local": "Local",
"never": "Never",
"just_now": "Just now",
"minutes_ago": "{{n}}m ago",
"hours_ago": "{{n}}h ago",
"days_ago": "{{n}}d ago",
"edit_quota_title": "Edit quota",
"reset_password_title": "Reset password",
"toggle_role_title": "Toggle role",
"deactivate_title": "Deactivate",
"activate_title": "Activate",
"delete_title": "Delete",
"sso_title": "Single Sign-On (OIDC / SSO)",
"enable_sso": "Enable SSO Authentication",
"provider_name": "Provider Name",
"issuer_url": "Issuer URL",
"issuer_url_hint": "OpenID Connect issuer URL of your identity provider",
"auto_discover": "Auto-discover",
"discovering": "Discovering…",
"client_id": "Client ID",
"client_secret": "Client Secret",
"client_secret_placeholder": "Leave empty to keep current value",
"secret_configured": "A client secret is already configured",
"callback_url": "Callback URL",
"callback_url_hint": "(register in your IdP)",
"advanced_settings": "Advanced Settings",
"scopes": "Scopes",
"auto_provision": "Auto-provision users on first login",
"admin_groups": "Admin Groups",
"admin_groups_hint": "Comma-separated OIDC group names that map to admin role",
"disable_password": "Disable password login (OIDC only)",
"password_warning": "This will prevent ALL password-based logins!",
"test_btn": "Test",
"save_btn": "Save",
"saving": "Saving…",
"settings_saved": "Settings saved — OIDC is now {{status}}",
"quota_modal_title": "Update Storage Quota",
"quota_user_label": "User:",
"new_quota": "New Quota",
"quota_unlimited_hint": "Set to 0 for unlimited",
"cancel": "Cancel",
"create_user_title": "Create New User",
"username_label": "Username",
"username_placeholder": "johndoe",
"username_hint": "3–32 characters",
"password_label": "Password",
"password_placeholder": "Min 8 characters",
"email_label": "Email",
"email_optional": "(optional)",
"email_placeholder": "user@example.com (auto-generated if empty)",
"role_label": "Role",
"role_user": "User",
"role_admin": "Admin",
"quota_label": "Quota",
"creating": "Creating…",
"reset_pw_title": "Reset Password",
"new_password_label": "New Password",
"resetting": "Resetting…",
"reset_btn": "Reset",
"confirm_role_change": "Change role to {{role}}?",
"confirm_deactivate": "Are you sure you want to deactivate this user?",
"confirm_activate": "Are you sure you want to activate this user?",
"confirm_delete_user": "DELETE user \"{{name}}\"? This cannot be undone!",
"confirm_action": "Confirm Action",
"confirm_yes": "Confirm",
"confirm_no": "Cancel",
"error_username_short": "Username must be at least 3 characters",
"error_password_short": "Password must be at least 8 characters",
"error_generic": "Failed",
"error_network": "Network error: {{message}}",
"error_create_user": "Failed to create user"
},
"profile": {
"page_title": "Profile",
"back_to_app": "Back to OxiCloud",
"loading": "Loading…",
"not_authenticated": "Not Authenticated",
"not_authenticated_desc": "Please sign in to view your profile.",
"sign_in": "Sign in",
"role_admin": "Administrator",
"role_user": "User",
"account_details": "Account Details",
"username": "Username",
"email": "Email",
"role": "Role",
"last_login": "Last Login",
"storage": "Storage",
"used": "Used",
"quota": "Quota",
"usage": "Usage",
"unlimited": "Unlimited",
"app_passwords": "App Passwords",
"app_pw_desc": "Generate passwords for WebDAV, CalDAV, and CardDAV clients. Each password is shown only once.",
"app_pw_label_placeholder": "Label (e.g. Thunderbird, macOS)",
"generate": "Generate",
"generating": "Generating…",
"new_password_for": "New password for",
"copy_warning": "Copy this password now. You won't be able to see it again.",
"copy_to_clipboard": "Copy to clipboard",
"col_label": "Label",
"col_created": "Created",
"col_last_used": "Last Used",
"col_status": "Status",
"active": "Active",
"revoked": "Revoked",
"revoke_title": "Revoke",
"no_app_passwords": "No app passwords yet.",
"client_sessions": "Client sessions",
"client_sessions_desc": "Auto-generated when you connect a Nextcloud-compatible client.",
"col_client": "Client",
"never": "Never",
"just_now": "Just now",
"minutes_ago": "{{n}} min ago",
"hours_ago": "{{n}}h ago",
"days_ago": "{{n}} days ago",
"change_password": "Change Password",
"current_password": "Current Password",
"new_password": "New Password",
"min_8_chars": "At least 8 characters",
"confirm_password": "Confirm New Password",
"update_password": "Update Password",
"updating": "Updating…",
"password_updated": "Password updated successfully",
"passwords_no_match": "Passwords do not match",
"password_too_short": "Password must be at least 8 characters",
"password_change_failed": "Failed to change password",
"error_network": "Network error: {{message}}",
"error_label_required": "Please enter a label",
"error_create_pw": "Failed to create app password",
"confirm_revoke": "Revoke app password \"{{label}}\"? Clients using this password will stop working.",
"error_revoke": "Failed to revoke app password"
}
}
+183 -3
View File
@@ -182,6 +182,7 @@
"size": "Tamaño",
"modified": "Modificado",
"no_files": "No hay archivos en esta carpeta",
"empty_hint": "Sube archivos o crea carpetas para comenzar",
"loading": "Cargando archivos…",
"view_grid": "Vista de cuadrícula",
"view_list": "Vista de lista",
@@ -320,8 +321,8 @@
"zoom_reset": "Restablecer zoom"
},
"language_selector": {
"title": "Bienvenido a OxiCloud",
"subtitle": "Por favor, selecciona tu idioma",
"title": "¡Bienvenido!",
"subtitle": "Selecciona tu idioma para continuar",
"continue": "Continuar",
"languages": {
"en": "English",
@@ -370,5 +371,184 @@
"move_title": "Mover {{count}} elemento(s)",
"add_favorites": "Añadir a favoritos",
"move_copy": "Mover o copiar"
},
"admin": {
"page_title": "Panel de Administración",
"back_to_app": "Volver a OxiCloud",
"loading": "Cargando…",
"access_denied": "Acceso Denegado",
"access_denied_desc": "Se requieren privilegios de administrador para acceder a este panel.",
"sign_in": "Iniciar sesión",
"tab_dashboard": "Panel",
"tab_users": "Usuarios",
"tab_oidc": "SSO / OIDC",
"total_users": "Usuarios Totales",
"active_users": "Usuarios Activos",
"admins": "Administradores",
"version": "Versión",
"storage_overview": "Resumen de Almacenamiento",
"used": "Usado",
"total_quota": "Cuota Total",
"usage_pct": "Uso %",
"users_over_80": "Usuarios >80% cuota",
"users_over_quota": "Usuarios sobre cuota",
"system": "Sistema",
"auth_label": "Auth",
"oidc_label": "OIDC",
"quotas_label": "Cuotas",
"enabled": "Habilitado",
"disabled": "Deshabilitado",
"active": "Activo",
"off": "Inactivo",
"allow_registration": "Permitir registro público",
"registration_warning": "El registro público está deshabilitado. Solo los administradores pueden crear nuevos usuarios.",
"user_management": "Gestión de Usuarios",
"create_user": "Crear Usuario",
"col_user": "Usuario",
"col_role": "Rol",
"col_auth": "Auth",
"col_status": "Estado",
"col_storage": "Almacenamiento",
"col_last_login": "Último Acceso",
"col_actions": "Acciones",
"loading_users": "Cargando usuarios…",
"failed_load_users": "Error al cargar usuarios",
"no_users_found": "No se encontraron usuarios",
"showing_users": "Mostrando {{from}}-{{to}} de {{total}}",
"prev": "Anterior",
"next": "Siguiente",
"inactive": "Inactivo",
"you_badge": "(tú)",
"local": "Local",
"never": "Nunca",
"just_now": "Ahora mismo",
"minutes_ago": "hace {{n}}m",
"hours_ago": "hace {{n}}h",
"days_ago": "hace {{n}}d",
"edit_quota_title": "Editar cuota",
"reset_password_title": "Restablecer contraseña",
"toggle_role_title": "Cambiar rol",
"deactivate_title": "Desactivar",
"activate_title": "Activar",
"delete_title": "Eliminar",
"sso_title": "Inicio de Sesión Único (OIDC / SSO)",
"enable_sso": "Habilitar autenticación SSO",
"provider_name": "Nombre del Proveedor",
"issuer_url": "URL del Emisor",
"issuer_url_hint": "URL del emisor OpenID Connect de tu proveedor de identidad",
"auto_discover": "Auto-descubrir",
"discovering": "Descubriendo…",
"client_id": "Client ID",
"client_secret": "Client Secret",
"client_secret_placeholder": "Dejar vacío para mantener el valor actual",
"secret_configured": "Ya hay un client secret configurado",
"callback_url": "URL de Callback",
"callback_url_hint": "(registrar en tu IdP)",
"advanced_settings": "Configuración Avanzada",
"scopes": "Scopes",
"auto_provision": "Auto-provisionar usuarios en el primer inicio de sesión",
"admin_groups": "Grupos de Admin",
"admin_groups_hint": "Nombres de grupos OIDC separados por comas que mapean al rol de admin",
"disable_password": "Desactivar inicio de sesión con contraseña (solo OIDC)",
"password_warning": "¡Esto impedirá TODOS los inicios de sesión con contraseña!",
"test_btn": "Probar",
"save_btn": "Guardar",
"saving": "Guardando…",
"settings_saved": "Configuración guardada — OIDC ahora está {{status}}",
"quota_modal_title": "Actualizar Cuota de Almacenamiento",
"quota_user_label": "Usuario:",
"new_quota": "Nueva Cuota",
"quota_unlimited_hint": "Establecer 0 para ilimitado",
"cancel": "Cancelar",
"create_user_title": "Crear Nuevo Usuario",
"username_label": "Nombre de usuario",
"username_placeholder": "juanperez",
"username_hint": "3–32 caracteres",
"password_label": "Contraseña",
"password_placeholder": "Mín 8 caracteres",
"email_label": "Correo",
"email_optional": "(opcional)",
"email_placeholder": "usuario@ejemplo.com (auto-generado si vacío)",
"role_label": "Rol",
"role_user": "Usuario",
"role_admin": "Admin",
"quota_label": "Cuota",
"creating": "Creando…",
"reset_pw_title": "Restablecer Contraseña",
"new_password_label": "Nueva Contraseña",
"resetting": "Restableciendo…",
"reset_btn": "Restablecer",
"confirm_role_change": "¿Cambiar rol a {{role}}?",
"confirm_deactivate": "¿Estás seguro de que quieres desactivar este usuario?",
"confirm_activate": "¿Estás seguro de que quieres activar este usuario?",
"confirm_delete_user": "¿ELIMINAR usuario \"{{name}}\"? ¡Esto no se puede deshacer!",
"confirm_action": "Confirmar Acción",
"confirm_yes": "Confirmar",
"confirm_no": "Cancelar",
"error_username_short": "El nombre de usuario debe tener al menos 3 caracteres",
"error_password_short": "La contraseña debe tener al menos 8 caracteres",
"error_generic": "Error",
"error_network": "Error de red: {{message}}",
"error_create_user": "Error al crear usuario"
},
"profile": {
"page_title": "Perfil",
"back_to_app": "Volver a OxiCloud",
"loading": "Cargando…",
"not_authenticated": "No Autenticado",
"not_authenticated_desc": "Inicia sesión para ver tu perfil.",
"sign_in": "Iniciar sesión",
"role_admin": "Administrador",
"role_user": "Usuario",
"account_details": "Detalles de la Cuenta",
"username": "Nombre de usuario",
"email": "Correo electrónico",
"role": "Rol",
"last_login": "Último acceso",
"storage": "Almacenamiento",
"used": "Usado",
"quota": "Cuota",
"usage": "Uso",
"unlimited": "Ilimitado",
"app_passwords": "Contraseñas de Aplicación",
"app_pw_desc": "Genera contraseñas para clientes WebDAV, CalDAV y CardDAV. Cada contraseña se muestra solo una vez.",
"app_pw_label_placeholder": "Etiqueta (ej. Thunderbird, macOS)",
"generate": "Generar",
"generating": "Generando…",
"new_password_for": "Nueva contraseña para",
"copy_warning": "Copia esta contraseña ahora. No podrás verla de nuevo.",
"copy_to_clipboard": "Copiar al portapapeles",
"col_label": "Etiqueta",
"col_created": "Creado",
"col_last_used": "Último uso",
"col_status": "Estado",
"active": "Activa",
"revoked": "Revocada",
"revoke_title": "Revocar",
"no_app_passwords": "Aún no hay contraseñas de aplicación.",
"client_sessions": "Sesiones de cliente",
"client_sessions_desc": "Generadas automáticamente al conectar un cliente compatible con Nextcloud.",
"col_client": "Cliente",
"never": "Nunca",
"just_now": "Ahora mismo",
"minutes_ago": "hace {{n}} min",
"hours_ago": "hace {{n}}h",
"days_ago": "hace {{n}} días",
"change_password": "Cambiar Contraseña",
"current_password": "Contraseña Actual",
"new_password": "Nueva Contraseña",
"min_8_chars": "Al menos 8 caracteres",
"confirm_password": "Confirmar Nueva Contraseña",
"update_password": "Actualizar Contraseña",
"updating": "Actualizando…",
"password_updated": "Contraseña actualizada correctamente",
"passwords_no_match": "Las contraseñas no coinciden",
"password_too_short": "La contraseña debe tener al menos 8 caracteres",
"password_change_failed": "Error al cambiar la contraseña",
"error_network": "Error de red: {{message}}",
"error_label_required": "Introduce una etiqueta",
"error_create_pw": "Error al crear contraseña de aplicación",
"confirm_revoke": "¿Revocar contraseña \"{{label}}\"? Los clientes que la usen dejarán de funcionar.",
"error_revoke": "Error al revocar contraseña"
}
}
}
+185 -4
View File
@@ -180,6 +180,8 @@
"size": "اندازه",
"modified": "تاریخ تغییر",
"no_files": "هنوز هیچ پرونده‌ای در این پوشه وجود ندارد",
"empty_hint": "برای شروع، فایل‌ها را آپلود کنید یا پوشه بسازید",
"loading": "در حال بارگذاری فایل‌ها…",
"view_grid": "نمای شبکه‌ای",
"view_list": "نمای فهرستی",
"file_types": {
@@ -213,7 +215,7 @@
"share_file": "هم‌رسانی پرونده",
"existing_shares": "هم‌رسانی موجود",
"share_options": "گزینه‌های هم‌رسانی",
"password": "گذرواژه",
"password": "گذرواژه",
"expiration": "تاریخ انقضا",
"permissions": "دسترسی‌ها",
"generated_link": "پیوند تولید شده",
@@ -303,8 +305,8 @@
"zoom_reset": "بازنشانی بزرگ‌نمایی"
},
"language_selector": {
"title": "خوش آمدید به OxiCloud",
"subtitle": "لطفا زبان خود را انتخاب کنید",
"title": "!خوش آمدید",
"subtitle": "زبان خود را برای ادامه انتخاب کنید",
"continue": "ادامه",
"languages": {
"en": "English",
@@ -340,5 +342,184 @@
"move_title": "انتقال {{count}} مورد",
"add_favorites": "افزودن به موارد علاقه‌مند",
"move_copy": "انتقال یا کپی"
},
"admin": {
"page_title": "پنل مدیریت",
"back_to_app": "بازگشت به OxiCloud",
"loading": "در حال بارگذاری…",
"access_denied": "دسترسی ممنوع",
"access_denied_desc": "امتیازات مدیر لازم است.",
"sign_in": "ورود",
"tab_dashboard": "داشبورد",
"tab_users": "کاربران",
"tab_oidc": "SSO / OIDC",
"total_users": "کل کاربران",
"active_users": "کاربران فعال",
"admins": "مدیران",
"version": "نسخه",
"storage_overview": "نمای کلی فضا",
"used": "استفاده شده",
"total_quota": "سهمیه کل",
"usage_pct": "درصد استفاده",
"users_over_80": "کاربران بالای ۸۰٪",
"users_over_quota": "کاربران بالای سهمیه",
"system": "سیستم",
"auth_label": "احراز هویت",
"oidc_label": "OIDC",
"quotas_label": "سهمیه‌ها",
"enabled": "فعال",
"disabled": "غیرفعال",
"active": "فعال",
"off": "خاموش",
"allow_registration": "اجازه ثبت‌نام عمومی",
"registration_warning": "ثبت‌نام عمومی غیرفعال است. فقط مدیران می‌توانند کاربر جدید بسازند.",
"user_management": "مدیریت کاربران",
"create_user": "ایجاد کاربر",
"col_user": "کاربر",
"col_role": "نقش",
"col_auth": "احراز هویت",
"col_status": "وضعیت",
"col_storage": "فضا",
"col_last_login": "آخرین ورود",
"col_actions": "عملیات",
"loading_users": "در حال بارگذاری…",
"failed_load_users": "خطا در بارگذاری",
"no_users_found": "کاربری یافت نشد",
"showing_users": "نمایش {{from}}-{{to}} از {{total}}",
"prev": "قبلی",
"next": "بعدی",
"inactive": "غیرفعال",
"you_badge": "(شما)",
"local": "محلی",
"never": "هرگز",
"just_now": "همین الان",
"minutes_ago": "{{n}} دقیقه پیش",
"hours_ago": "{{n}} ساعت پیش",
"days_ago": "{{n}} روز پیش",
"edit_quota_title": "ویرایش سهمیه",
"reset_password_title": "بازنشانی رمز",
"toggle_role_title": "تغییر نقش",
"deactivate_title": "غیرفعال کردن",
"activate_title": "فعال کردن",
"delete_title": "حذف",
"sso_title": "ورود یکپارچه (OIDC / SSO)",
"enable_sso": "فعال‌سازی SSO",
"provider_name": "نام ارائه‌دهنده",
"issuer_url": "آدرس صادرکننده",
"issuer_url_hint": "آدرس صادرکننده OpenID Connect",
"auto_discover": "کشف خودکار",
"discovering": "در حال کشف…",
"client_id": "شناسه مشتری",
"client_secret": "رمز مشتری",
"client_secret_placeholder": "خالی بگذارید تا مقدار فعلی حفظ شود",
"secret_configured": "رمز مشتری قبلاً پیکربندی شده",
"callback_url": "آدرس بازگشت",
"callback_url_hint": "(در IdP ثبت کنید)",
"advanced_settings": "تنظیمات پیشرفته",
"scopes": "محدوده‌ها",
"auto_provision": "تامین خودکار کاربران",
"admin_groups": "گروه‌های مدیر",
"admin_groups_hint": "نام گروه‌های OIDC جدا شده با کاما",
"disable_password": "غیرفعال‌سازی ورود با رمز (فقط OIDC)",
"password_warning": "تمام ورودهای رمزی متوقف می‌شود!",
"test_btn": "آزمایش",
"save_btn": "ذخیره",
"saving": "در حال ذخیره…",
"settings_saved": "تنظیمات ذخیره شد — OIDC اکنون {{status}}",
"quota_modal_title": "به‌روزرسانی سهمیه",
"quota_user_label": "کاربر:",
"new_quota": "سهمیه جدید",
"quota_unlimited_hint": "۰ برای نامحدود",
"cancel": "انصراف",
"create_user_title": "ایجاد کاربر جدید",
"username_label": "نام کاربری",
"username_placeholder": "نام‌کاربری",
"username_hint": "۳ تا ۳۲ کاراکتر",
"password_label": "رمز عبور",
"password_placeholder": "حداقل ۸ کاراکتر",
"email_label": "ایمیل",
"email_optional": "(اختیاری)",
"email_placeholder": "user@example.com (خودکار اگر خالی)",
"role_label": "نقش",
"role_user": "کاربر",
"role_admin": "مدیر",
"quota_label": "سهمیه",
"creating": "در حال ایجاد…",
"reset_pw_title": "بازنشانی رمز عبور",
"new_password_label": "رمز عبور جدید",
"resetting": "در حال بازنشانی…",
"reset_btn": "بازنشانی",
"confirm_role_change": "نقش به {{role}} تغییر یابد؟",
"confirm_deactivate": "آیا از غیرفعال‌سازی این کاربر مطمئنید؟",
"confirm_activate": "آیا از فعال‌سازی این کاربر مطمئنید؟",
"confirm_delete_user": "کاربر «{{name}}» حذف شود؟ قابل بازگشت نیست!",
"confirm_action": "تأیید عملیات",
"confirm_yes": "تأیید",
"confirm_no": "انصراف",
"error_username_short": "نام کاربری حداقل ۳ کاراکتر",
"error_password_short": "رمز عبور حداقل ۸ کاراکتر",
"error_generic": "خطا",
"error_network": "خطای شبکه: {{message}}",
"error_create_user": "خطا در ایجاد کاربر"
},
"profile": {
"page_title": "پروفایل",
"back_to_app": "بازگشت به OxiCloud",
"loading": "در حال بارگذاری…",
"not_authenticated": "احراز هویت نشده",
"not_authenticated_desc": "برای مشاهده پروفایل وارد شوید.",
"sign_in": "ورود",
"role_admin": "مدیر",
"role_user": "کاربر",
"account_details": "جزئیات حساب",
"username": "نام کاربری",
"email": "ایمیل",
"role": "نقش",
"last_login": "آخرین ورود",
"storage": "فضای ذخیره‌سازی",
"used": "استفاده شده",
"quota": "سهمیه",
"usage": "مصرف",
"unlimited": "نامحدود",
"app_passwords": "رمزهای برنامه",
"app_pw_desc": "رمزهایی برای کلاینت‌های WebDAV، CalDAV و CardDAV ایجاد کنید. هر رمز فقط یک بار نمایش داده می‌شود.",
"app_pw_label_placeholder": "برچسب (مثلاً Thunderbird، macOS)",
"generate": "ایجاد",
"generating": "در حال ایجاد…",
"new_password_for": "رمز جدید برای",
"copy_warning": "این رمز را اکنون کپی کنید. دوباره قابل مشاهده نیست.",
"copy_to_clipboard": "کپی به کلیپ‌بورد",
"col_label": "برچسب",
"col_created": "ایجاد شده",
"col_last_used": "آخرین استفاده",
"col_status": "وضعیت",
"active": "فعال",
"revoked": "ابطال شده",
"revoke_title": "ابطال",
"no_app_passwords": "هنوز رمز برنامه‌ای وجود ندارد.",
"client_sessions": "نشست‌های کلاینت",
"client_sessions_desc": "هنگام اتصال کلاینت سازگار با Nextcloud به صورت خودکار ایجاد می‌شود.",
"col_client": "کلاینت",
"never": "هرگز",
"just_now": "همین الان",
"minutes_ago": "{{n}} دقیقه پیش",
"hours_ago": "{{n}} ساعت پیش",
"days_ago": "{{n}} روز پیش",
"change_password": "تغییر رمز عبور",
"current_password": "رمز فعلی",
"new_password": "رمز جدید",
"min_8_chars": "حداقل ۸ کاراکتر",
"confirm_password": "تأیید رمز جدید",
"update_password": "به‌روزرسانی رمز",
"updating": "در حال به‌روزرسانی…",
"password_updated": "رمز عبور با موفقیت به‌روز شد",
"passwords_no_match": "رمزها مطابقت ندارند",
"password_too_short": "رمز باید حداقل ۸ کاراکتر باشد",
"password_change_failed": "تغییر رمز ناموفق بود",
"error_network": "خطای شبکه: {{message}}",
"error_label_required": "لطفاً برچسب وارد کنید",
"error_create_pw": "ایجاد رمز ناموفق بود",
"confirm_revoke": "رمز «{{label}}» ابطال شود؟ کلاینت‌ها از کار می‌افتند.",
"error_revoke": "ابطال ناموفق بود"
}
}
}
+549 -369
View File
@@ -1,369 +1,549 @@
{
"app": {
"title": "OxiCloud",
"description": "Système de stockage cloud minimaliste"
},
"nav": {
"files": "Fichiers",
"shared": "Partagés",
"recent": "Récents",
"favorites": "Favoris",
"photos": "Photos",
"trash": "Corbeille"
},
"photos": {
"empty_state": "Pas encore de photos",
"empty_hint": "Téléchargez des images ou des vidéos pour les voir ici",
"items_selected": "sélectionnés",
"view_daily": "Jour",
"view_monthly": "Mois",
"view_yearly": "Année"
},
"actions": {
"search": "Rechercher des fichiers...",
"new_folder": "Nouveau dossier",
"upload": "Téléverser",
"upload_files": "Téléverser des fichiers",
"upload_folder": "Téléverser un dossier",
"upload.uploading": "Envoi en cours...",
"upload.complete": "{count} / {total} envoyés",
"rename": "Renommer",
"move": "Déplacer vers...",
"move_to": "Déplacer vers",
"delete": "Supprimer",
"download": "Télécharger",
"view": "Afficher",
"cancel": "Annuler",
"confirm": "Confirmer",
"share": "Partager",
"favorite": "Ajouter aux favoris",
"unfavorite": "Retirer des favoris",
"copy": "Copier",
"notify": "Notifier",
"send": "Envoyer",
"clear_recent": "Effacer les récents",
"logout": "Se déconnecter",
"create": "Créer",
"search_btn": "Rechercher",
"close": "Fermer",
"delete_permanently": "Supprimer définitivement",
"empty_trash": "Vider la corbeille"
},
"user_menu": {
"appearance": "Apparence",
"about": "À propos d'OxiCloud",
"about_description": "Plateforme de stockage cloud construite avec Rust et Architecture Propre. Rapide, sécurisée et privée.",
"admin_panel": "Panneau d'administration",
"profile": "Mon profil",
"role_user": "Utilisateur"
},
"share": {
"dialogTitle": "Lien de partage",
"linkLabel": "Lien partagé :",
"copyLink": "Copier",
"permissions": "Permissions :",
"permissionRead": "Lecture",
"permissionWrite": "Écriture",
"permissionReshare": "Repartager",
"password": "Protection par mot de passe :",
"generatePassword": "Générer",
"expiration": "Date d'expiration :",
"update": "Mettre à jour le partage",
"remove": "Supprimer le partage",
"notifyTitle": "Envoyer une notification",
"notifyEmailLabel": "Adresse e-mail :",
"notifyMessageLabel": "Message (facultatif) :",
"notifySend": "Envoyer la notification",
"shareWithOthers": "Partager avec d'autres",
"sharePublicly": "Partager publiquement",
"shareSettings": "Paramètres de partage",
"shareCopied": "Lien copié dans le presse-papiers",
"shareCreated": "Lien de partage créé avec succès",
"shareUpdated": "Paramètres de partage mis à jour",
"shareRemoved": "Partage supprimé avec succès"
},
"share_dialogTitle": "Lien de partage",
"share_linkLabel": "Lien partagé :",
"share_copyLink": "Copier",
"share_permissions": "Permissions :",
"share_permissionRead": "Lecture",
"share_permissionWrite": "Écriture",
"share_permissionReshare": "Repartager",
"share_password": "Protection par mot de passe :",
"share_generatePassword": "Générer",
"share_expiration": "Date d'expiration :",
"share_update": "Mettre à jour le partage",
"share_remove": "Supprimer le partage",
"share_notifyTitle": "Envoyer une notification",
"share_notifyEmailLabel": "Adresse e-mail :",
"share_notifyMessageLabel": "Message (facultatif) :",
"share_notifySend": "Envoyer la notification",
"shared": {
"backToFiles": "Retour aux fichiers",
"pageTitle": "Ressources partagées",
"pageDescription": "Gérez vos fichiers et dossiers partagés",
"filterType": "Type :",
"filterAll": "Tous",
"filterFiles": "Fichiers",
"filterFolders": "Dossiers",
"sortBy": "Trier par :",
"sortByName": "Nom",
"sortByDate": "Date de partage",
"sortByExpiration": "Expiration",
"search": "Rechercher",
"colName": "Nom",
"colType": "Type",
"colDateShared": "Date de partage",
"colExpiration": "Expiration",
"colPermissions": "Permissions",
"colPassword": "Mot de passe",
"colActions": "Actions",
"emptyStateTitle": "Aucune ressource partagée",
"emptyStateDesc": "Lorsque vous partagerez des fichiers ou dossiers, ils apparaîtront ici",
"goToFiles": "Aller aux fichiers",
"typeFile": "Fichier",
"typeFolder": "Dossier",
"noExpiration": "Sans expiration",
"hasPassword": "Oui",
"noPassword": "Non",
"editShare": "Modifier le partage",
"notifyShare": "Notifier quelqu'un",
"copyLink": "Copier le lien",
"removeShare": "Supprimer le partage",
"linkCopied": "Lien copié dans le presse-papiers !",
"linkCopyFailed": "Erreur lors de la copie du lien",
"itemUpdated": "Paramètres de partage mis à jour",
"itemRemoved": "Partage supprimé avec succès",
"invalidEmail": "Veuillez entrer une adresse e-mail valide",
"notificationSent": "Notification envoyée avec succès",
"notificationFailed": "Erreur lors de l'envoi de la notification"
},
"shared_backToFiles": "Retour aux fichiers",
"shared_pageTitle": "Ressources partagées",
"shared_pageDescription": "Gérez vos fichiers et dossiers partagés",
"shared_filterType": "Type :",
"shared_filterAll": "Tous",
"shared_filterFiles": "Fichiers",
"shared_filterFolders": "Dossiers",
"shared_sortBy": "Trier par :",
"shared_sortByName": "Nom",
"shared_sortByDate": "Date de partage",
"shared_sortByExpiration": "Expiration",
"shared_search": "Rechercher",
"shared_colName": "Nom",
"shared_colType": "Type",
"shared_colDateShared": "Date de partage",
"shared_colExpiration": "Expiration",
"shared_colPermissions": "Permissions",
"shared_colPassword": "Mot de passe",
"shared_colActions": "Actions",
"shared_emptyStateTitle": "Aucune ressource partagée",
"shared_emptyStateDesc": "Lorsque vous partagerez des fichiers ou dossiers, ils apparaîtront ici",
"shared_goToFiles": "Aller aux fichiers",
"shared_typeFile": "Fichier",
"shared_typeFolder": "Dossier",
"shared_noExpiration": "Sans expiration",
"shared_hasPassword": "Oui",
"shared_noPassword": "Non",
"shared_editShare": "Modifier le partage",
"shared_notifyShare": "Notifier quelqu'un",
"shared_copyLink": "Copier le lien",
"shared_removeShare": "Supprimer le partage",
"shared_linkCopied": "Lien copié dans le presse-papiers !",
"shared_linkCopyFailed": "Erreur lors de la copie du lien",
"shared_itemUpdated": "Paramètres de partage mis à jour",
"shared_itemRemoved": "Partage supprimé avec succès",
"shared_invalidEmail": "Veuillez entrer une adresse e-mail valide",
"shared_notificationSent": "Notification envoyée avec succès",
"shared_notificationFailed": "Erreur lors de l'envoi de la notification",
"files": {
"name": "Nom",
"type": "Type",
"size": "Taille",
"modified": "Modifié",
"no_files": "Aucun fichier dans ce dossier",
"loading": "Chargement des fichiers…",
"view_grid": "Vue en grille",
"view_list": "Vue en liste",
"file_types": {
"document": "Document",
"image": "Image",
"video": "Vidéo",
"audio": "Audio",
"pdf": "PDF",
"text": "Texte",
"folder": "Dossier",
"spreadsheet": "Tableur",
"presentation": "Présentation",
"archive": "Archive",
"installer": "Installateur",
"code": "Code"
}
},
"dialogs": {
"rename_folder": "Renommer le dossier",
"rename_file": "Renommer le fichier",
"new_name": "Nouveau nom",
"new_folder_title": "Nouveau dossier",
"folder_name": "Nom du dossier",
"folder_placeholder": "Mon dossier",
"rename_title": "Renommer",
"move_file": "Déplacer le fichier",
"move_folder": "Déplacer le dossier",
"select_destination": "Sélectionnez le dossier de destination :",
"root": "Racine",
"delete_confirmation": "Êtes-vous sûr de vouloir supprimer",
"and_contents": "et tout son contenu",
"no_undo": "Cette action est irréversible",
"confirm_title": "Confirmer l'action",
"confirm_delete": "Déplacer vers la corbeille",
"confirm_delete_file": "Êtes-vous sûr de vouloir déplacer le fichier « {{name}} » vers la corbeille ?",
"confirm_delete_folder": "Êtes-vous sûr de vouloir déplacer le dossier « {{name}} » et tout son contenu vers la corbeille ?",
"confirm_permanent_delete": "Supprimer définitivement",
"confirm_permanent_delete_msg": "Êtes-vous sûr de vouloir supprimer définitivement cet élément ? Cette action est irréversible.",
"confirm_empty_trash": "Vider la corbeille",
"confirm_delete_share": "Supprimer le lien de partage",
"confirm_delete_share_msg": "Êtes-vous sûr de vouloir supprimer ce lien de partage ?",
"share_file": "Partager le fichier",
"existing_shares": "Partages existants",
"share_options": "Options de partage",
"password": "Mot de passe",
"expiration": "Expiration",
"permissions": "Permissions",
"generated_link": "Lien généré",
"notify": "Envoyer une notification",
"recipient": "Destinataire",
"message": "Message"
},
"dropzone": {
"drag_files": "Glissez des fichiers ici ou cliquez pour sélectionner",
"drop_files": "Déposez les fichiers pour téléverser"
},
"permissions": {
"read": "Lecture",
"write": "Écriture",
"reshare": "Repartager"
},
"errors": {
"file_not_found": "Fichier introuvable",
"folder_not_found": "Dossier introuvable",
"delete_error": "Erreur lors de la suppression",
"upload_error": "Erreur lors du téléversement",
"rename_error": "Erreur lors du renommage",
"move_error": "Erreur lors du déplacement",
"empty_name": "Le nom ne peut pas être vide",
"name_exists": "Un fichier ou dossier portant ce nom existe déjà",
"generic_error": "Une erreur est survenue"
},
"breadcrumb": {
"home": "Accueil"
},
"trash": {
"empty_trash": "Vider la corbeille",
"empty_state": "La corbeille est vide",
"original_location": "Emplacement d'origine",
"deleted_date": "Date de suppression",
"actions": "Actions",
"restore": "Restaurer",
"delete_permanently": "Supprimer définitivement",
"empty_confirm": "Êtes-vous sûr de vouloir vider la corbeille ? Tous les éléments seront définitivement supprimés."
},
"auth": {
"login_title": "Se connecter",
"username": "Nom d'utilisateur",
"username_placeholder": "Entrez votre nom d'utilisateur",
"password": "Mot de passe",
"password_placeholder": "Entrez votre mot de passe",
"login_button": "Se connecter",
"no_account": "Vous n'avez pas de compte ?",
"register": "S'inscrire",
"admin_setup": "Première fois ?",
"setup": "Configurer l'administrateur",
"register_title": "Créer un compte",
"email": "E-mail",
"email_placeholder": "Entrez votre e-mail",
"confirm_password": "Confirmer le mot de passe",
"confirm_password_placeholder": "Confirmez votre mot de passe",
"register_button": "Créer un compte",
"have_account": "Vous avez déjà un compte ?",
"login": "Se connecter",
"setup_title": "Configuration initiale",
"setup_step1": "Admin",
"setup_step2": "Système",
"setup_step3": "Terminé",
"admin_username": "Nom d'utilisateur administrateur",
"admin_email": "E-mail administrateur",
"admin_password": "Mot de passe administrateur",
"create_admin": "Créer l'administrateur",
"back_to_login": "Déjà configuré ?",
"admin_success": "Compte administrateur créé avec succès ! Vous pouvez maintenant vous connecter.",
"account_success": "Compte créé avec succès ! Vous pouvez maintenant vous connecter.",
"passwords_mismatch": "Les mots de passe ne correspondent pas",
"admin_create_error": "Erreur lors de la création du compte administrateur",
"or": "ou",
"sso_login": "Se connecter avec SSO",
"sso_login_provider": "Se connecter avec {{provider}}"
},
"storage": {
"title": "Stockage",
"calculating": "Calcul en cours...",
"used": "{{percentage}}% utilisé ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Ce type de fichier ne peut pas être prévisualisé.",
"download_file": "Télécharger le fichier",
"zoom_in": "Zoom avant",
"zoom_out": "Zoom arrière",
"zoom_reset": "Réinitialiser le zoom"
},
"language_selector": {
"title": "Bienvenue sur OxiCloud",
"subtitle": "Veuillez sélectionner votre langue",
"continue": "Continuer",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português"
}
},
"favorites": {
"empty_state": "Aucun favori pour le moment",
"empty_hint": "Marquez des fichiers ou dossiers avec une étoile pour les ajouter à vos favoris",
"add": "Ajouter aux favoris",
"remove": "Retirer des favoris",
"added_title": "Ajouté aux favoris",
"added_msg": "ajouté aux favoris",
"removed_title": "Retiré des favoris",
"removed_msg": "retiré des favoris"
},
"recent": {
"title": "Récents",
"clear": "Effacer les récents",
"accessed": "Consulté",
"empty_state": "Aucun fichier récent",
"empty_hint": "Les fichiers que vous ouvrez apparaîtront ici"
},
"notifications": {
"file_renamed": "Fichier renommé",
"file_renamed_to": "Fichier renommé en « {{name}} »",
"folder_renamed": "Dossier renommé",
"folder_renamed_to": "Dossier renommé en « {{name}} »",
"file_uploaded": "Fichier téléversé",
"file_deleted": "Fichier déplacé vers la corbeille",
"folder_deleted": "Dossier déplacé vers la corbeille",
"item_deleted_permanently": "Élément supprimé définitivement",
"trash_emptied": "Corbeille vidée avec succès"
},
"batch": {
"one_selected": "1 élément sélectionné",
"n_selected": "{{count}} éléments sélectionnés",
"confirm_delete": "Voulez-vous vraiment déplacer {{count}} éléments vers la corbeille ?",
"move_title": "Déplacer {{count}} élément(s)",
"add_favorites": "Ajouter aux favoris",
"move_copy": "Déplacer ou copier"
}
}
{
"app": {
"title": "OxiCloud",
"description": "Système de stockage cloud minimaliste"
},
"nav": {
"files": "Fichiers",
"shared": "Partagés",
"recent": "Récents",
"favorites": "Favoris",
"photos": "Photos",
"trash": "Corbeille"
},
"photos": {
"empty_state": "Pas encore de photos",
"empty_hint": "Téléchargez des images ou des vidéos pour les voir ici",
"items_selected": "sélectionnés",
"view_daily": "Jour",
"view_monthly": "Mois",
"view_yearly": "Année"
},
"actions": {
"search": "Rechercher des fichiers...",
"new_folder": "Nouveau dossier",
"upload": "Téléverser",
"upload_files": "Téléverser des fichiers",
"upload_folder": "Téléverser un dossier",
"upload.uploading": "Envoi en cours...",
"upload.complete": "{count} / {total} envoyés",
"rename": "Renommer",
"move": "Déplacer vers...",
"move_to": "Déplacer vers",
"delete": "Supprimer",
"download": "Télécharger",
"view": "Afficher",
"cancel": "Annuler",
"confirm": "Confirmer",
"share": "Partager",
"favorite": "Ajouter aux favoris",
"unfavorite": "Retirer des favoris",
"copy": "Copier",
"notify": "Notifier",
"send": "Envoyer",
"clear_recent": "Effacer les récents",
"logout": "Se déconnecter",
"create": "Créer",
"search_btn": "Rechercher",
"close": "Fermer",
"delete_permanently": "Supprimer définitivement",
"empty_trash": "Vider la corbeille"
},
"user_menu": {
"appearance": "Apparence",
"about": "À propos d'OxiCloud",
"about_description": "Plateforme de stockage cloud construite avec Rust et Architecture Propre. Rapide, sécurisée et privée.",
"admin_panel": "Panneau d'administration",
"profile": "Mon profil",
"role_user": "Utilisateur"
},
"share": {
"dialogTitle": "Lien de partage",
"linkLabel": "Lien partagé :",
"copyLink": "Copier",
"permissions": "Permissions :",
"permissionRead": "Lecture",
"permissionWrite": "Écriture",
"permissionReshare": "Repartager",
"password": "Protection par mot de passe :",
"generatePassword": "Générer",
"expiration": "Date d'expiration :",
"update": "Mettre à jour le partage",
"remove": "Supprimer le partage",
"notifyTitle": "Envoyer une notification",
"notifyEmailLabel": "Adresse e-mail :",
"notifyMessageLabel": "Message (facultatif) :",
"notifySend": "Envoyer la notification",
"shareWithOthers": "Partager avec d'autres",
"sharePublicly": "Partager publiquement",
"shareSettings": "Paramètres de partage",
"shareCopied": "Lien copié dans le presse-papiers",
"shareCreated": "Lien de partage créé avec succès",
"shareUpdated": "Paramètres de partage mis à jour",
"shareRemoved": "Partage supprimé avec succès"
},
"share_dialogTitle": "Lien de partage",
"share_linkLabel": "Lien partagé :",
"share_copyLink": "Copier",
"share_permissions": "Permissions :",
"share_permissionRead": "Lecture",
"share_permissionWrite": "Écriture",
"share_permissionReshare": "Repartager",
"share_password": "Protection par mot de passe :",
"share_generatePassword": "Générer",
"share_expiration": "Date d'expiration :",
"share_update": "Mettre à jour le partage",
"share_remove": "Supprimer le partage",
"share_notifyTitle": "Envoyer une notification",
"share_notifyEmailLabel": "Adresse e-mail :",
"share_notifyMessageLabel": "Message (facultatif) :",
"share_notifySend": "Envoyer la notification",
"shared": {
"backToFiles": "Retour aux fichiers",
"pageTitle": "Ressources partagées",
"pageDescription": "Gérez vos fichiers et dossiers partagés",
"filterType": "Type :",
"filterAll": "Tous",
"filterFiles": "Fichiers",
"filterFolders": "Dossiers",
"sortBy": "Trier par :",
"sortByName": "Nom",
"sortByDate": "Date de partage",
"sortByExpiration": "Expiration",
"search": "Rechercher",
"colName": "Nom",
"colType": "Type",
"colDateShared": "Date de partage",
"colExpiration": "Expiration",
"colPermissions": "Permissions",
"colPassword": "Mot de passe",
"colActions": "Actions",
"emptyStateTitle": "Aucune ressource partagée",
"emptyStateDesc": "Lorsque vous partagerez des fichiers ou dossiers, ils apparaîtront ici",
"goToFiles": "Aller aux fichiers",
"typeFile": "Fichier",
"typeFolder": "Dossier",
"noExpiration": "Sans expiration",
"hasPassword": "Oui",
"noPassword": "Non",
"editShare": "Modifier le partage",
"notifyShare": "Notifier quelqu'un",
"copyLink": "Copier le lien",
"removeShare": "Supprimer le partage",
"linkCopied": "Lien copié dans le presse-papiers !",
"linkCopyFailed": "Erreur lors de la copie du lien",
"itemUpdated": "Paramètres de partage mis à jour",
"itemRemoved": "Partage supprimé avec succès",
"invalidEmail": "Veuillez entrer une adresse e-mail valide",
"notificationSent": "Notification envoyée avec succès",
"notificationFailed": "Erreur lors de l'envoi de la notification"
},
"shared_backToFiles": "Retour aux fichiers",
"shared_pageTitle": "Ressources partagées",
"shared_pageDescription": "Gérez vos fichiers et dossiers partagés",
"shared_filterType": "Type :",
"shared_filterAll": "Tous",
"shared_filterFiles": "Fichiers",
"shared_filterFolders": "Dossiers",
"shared_sortBy": "Trier par :",
"shared_sortByName": "Nom",
"shared_sortByDate": "Date de partage",
"shared_sortByExpiration": "Expiration",
"shared_search": "Rechercher",
"shared_colName": "Nom",
"shared_colType": "Type",
"shared_colDateShared": "Date de partage",
"shared_colExpiration": "Expiration",
"shared_colPermissions": "Permissions",
"shared_colPassword": "Mot de passe",
"shared_colActions": "Actions",
"shared_emptyStateTitle": "Aucune ressource partagée",
"shared_emptyStateDesc": "Lorsque vous partagerez des fichiers ou dossiers, ils apparaîtront ici",
"shared_goToFiles": "Aller aux fichiers",
"shared_typeFile": "Fichier",
"shared_typeFolder": "Dossier",
"shared_noExpiration": "Sans expiration",
"shared_hasPassword": "Oui",
"shared_noPassword": "Non",
"shared_editShare": "Modifier le partage",
"shared_notifyShare": "Notifier quelqu'un",
"shared_copyLink": "Copier le lien",
"shared_removeShare": "Supprimer le partage",
"shared_linkCopied": "Lien copié dans le presse-papiers !",
"shared_linkCopyFailed": "Erreur lors de la copie du lien",
"shared_itemUpdated": "Paramètres de partage mis à jour",
"shared_itemRemoved": "Partage supprimé avec succès",
"shared_invalidEmail": "Veuillez entrer une adresse e-mail valide",
"shared_notificationSent": "Notification envoyée avec succès",
"shared_notificationFailed": "Erreur lors de l'envoi de la notification",
"files": {
"name": "Nom",
"type": "Type",
"size": "Taille",
"modified": "Modifié",
"no_files": "Aucun fichier dans ce dossier",
"empty_hint": "Téléversez des fichiers ou créez des dossiers pour commencer",
"loading": "Chargement des fichiers…",
"view_grid": "Vue en grille",
"view_list": "Vue en liste",
"file_types": {
"document": "Document",
"image": "Image",
"video": "Vidéo",
"audio": "Audio",
"pdf": "PDF",
"text": "Texte",
"folder": "Dossier",
"spreadsheet": "Tableur",
"presentation": "Présentation",
"archive": "Archive",
"installer": "Installateur",
"code": "Code"
}
},
"dialogs": {
"rename_folder": "Renommer le dossier",
"rename_file": "Renommer le fichier",
"new_name": "Nouveau nom",
"new_folder_title": "Nouveau dossier",
"folder_name": "Nom du dossier",
"folder_placeholder": "Mon dossier",
"rename_title": "Renommer",
"move_file": "Déplacer le fichier",
"move_folder": "Déplacer le dossier",
"select_destination": "Sélectionnez le dossier de destination :",
"root": "Racine",
"delete_confirmation": "Êtes-vous sûr de vouloir supprimer",
"and_contents": "et tout son contenu",
"no_undo": "Cette action est irréversible",
"confirm_title": "Confirmer l'action",
"confirm_delete": "Déplacer vers la corbeille",
"confirm_delete_file": "Êtes-vous sûr de vouloir déplacer le fichier « {{name}} » vers la corbeille ?",
"confirm_delete_folder": "Êtes-vous sûr de vouloir déplacer le dossier « {{name}} » et tout son contenu vers la corbeille ?",
"confirm_permanent_delete": "Supprimer définitivement",
"confirm_permanent_delete_msg": "Êtes-vous sûr de vouloir supprimer définitivement cet élément ? Cette action est irréversible.",
"confirm_empty_trash": "Vider la corbeille",
"confirm_delete_share": "Supprimer le lien de partage",
"confirm_delete_share_msg": "Êtes-vous sûr de vouloir supprimer ce lien de partage ?",
"share_file": "Partager le fichier",
"existing_shares": "Partages existants",
"share_options": "Options de partage",
"password": "Mot de passe",
"expiration": "Expiration",
"permissions": "Permissions",
"generated_link": "Lien généré",
"notify": "Envoyer une notification",
"recipient": "Destinataire",
"message": "Message"
},
"dropzone": {
"drag_files": "Glissez des fichiers ici ou cliquez pour sélectionner",
"drop_files": "Déposez les fichiers pour téléverser"
},
"permissions": {
"read": "Lecture",
"write": "Écriture",
"reshare": "Repartager"
},
"errors": {
"file_not_found": "Fichier introuvable",
"folder_not_found": "Dossier introuvable",
"delete_error": "Erreur lors de la suppression",
"upload_error": "Erreur lors du téléversement",
"rename_error": "Erreur lors du renommage",
"move_error": "Erreur lors du déplacement",
"empty_name": "Le nom ne peut pas être vide",
"name_exists": "Un fichier ou dossier portant ce nom existe déjà",
"generic_error": "Une erreur est survenue"
},
"breadcrumb": {
"home": "Accueil"
},
"trash": {
"empty_trash": "Vider la corbeille",
"empty_state": "La corbeille est vide",
"original_location": "Emplacement d'origine",
"deleted_date": "Date de suppression",
"actions": "Actions",
"restore": "Restaurer",
"delete_permanently": "Supprimer définitivement",
"empty_confirm": "Êtes-vous sûr de vouloir vider la corbeille ? Tous les éléments seront définitivement supprimés."
},
"auth": {
"login_title": "Se connecter",
"username": "Nom d'utilisateur",
"username_placeholder": "Entrez votre nom d'utilisateur",
"password": "Mot de passe",
"password_placeholder": "Entrez votre mot de passe",
"login_button": "Se connecter",
"no_account": "Vous n'avez pas de compte ?",
"register": "S'inscrire",
"admin_setup": "Première fois ?",
"setup": "Configurer l'administrateur",
"register_title": "Créer un compte",
"email": "E-mail",
"email_placeholder": "Entrez votre e-mail",
"confirm_password": "Confirmer le mot de passe",
"confirm_password_placeholder": "Confirmez votre mot de passe",
"register_button": "Créer un compte",
"have_account": "Vous avez déjà un compte ?",
"login": "Se connecter",
"setup_title": "Configuration initiale",
"setup_step1": "Admin",
"setup_step2": "Système",
"setup_step3": "Terminé",
"admin_username": "Nom d'utilisateur administrateur",
"admin_email": "E-mail administrateur",
"admin_password": "Mot de passe administrateur",
"create_admin": "Créer l'administrateur",
"back_to_login": "Déjà configuré ?",
"admin_success": "Compte administrateur créé avec succès ! Vous pouvez maintenant vous connecter.",
"account_success": "Compte créé avec succès ! Vous pouvez maintenant vous connecter.",
"passwords_mismatch": "Les mots de passe ne correspondent pas",
"admin_create_error": "Erreur lors de la création du compte administrateur",
"or": "ou",
"sso_login": "Se connecter avec SSO",
"sso_login_provider": "Se connecter avec {{provider}}"
},
"storage": {
"title": "Stockage",
"calculating": "Calcul en cours...",
"used": "{{percentage}}% utilisé ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Ce type de fichier ne peut pas être prévisualisé.",
"download_file": "Télécharger le fichier",
"zoom_in": "Zoom avant",
"zoom_out": "Zoom arrière",
"zoom_reset": "Réinitialiser le zoom"
},
"language_selector": {
"title": "Bienvenue !",
"subtitle": "Sélectionnez votre langue pour continuer",
"continue": "Continuer",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português"
}
},
"favorites": {
"empty_state": "Aucun favori pour le moment",
"empty_hint": "Marquez des fichiers ou dossiers avec une étoile pour les ajouter à vos favoris",
"add": "Ajouter aux favoris",
"remove": "Retirer des favoris",
"added_title": "Ajouté aux favoris",
"added_msg": "ajouté aux favoris",
"removed_title": "Retiré des favoris",
"removed_msg": "retiré des favoris"
},
"recent": {
"title": "Récents",
"clear": "Effacer les récents",
"accessed": "Consulté",
"empty_state": "Aucun fichier récent",
"empty_hint": "Les fichiers que vous ouvrez apparaîtront ici"
},
"notifications": {
"file_renamed": "Fichier renommé",
"file_renamed_to": "Fichier renommé en « {{name}} »",
"folder_renamed": "Dossier renommé",
"folder_renamed_to": "Dossier renommé en « {{name}} »",
"file_uploaded": "Fichier téléversé",
"file_deleted": "Fichier déplacé vers la corbeille",
"folder_deleted": "Dossier déplacé vers la corbeille",
"item_deleted_permanently": "Élément supprimé définitivement",
"trash_emptied": "Corbeille vidée avec succès"
},
"batch": {
"one_selected": "1 élément sélectionné",
"n_selected": "{{count}} éléments sélectionnés",
"confirm_delete": "Voulez-vous vraiment déplacer {{count}} éléments vers la corbeille ?",
"move_title": "Déplacer {{count}} élément(s)",
"add_favorites": "Ajouter aux favoris",
"move_copy": "Déplacer ou copier"
},
"admin": {
"page_title": "Panneau d'administration",
"back_to_app": "Retour à OxiCloud",
"loading": "Chargement…",
"access_denied": "Accès refusé",
"access_denied_desc": "Privilèges d'administrateur requis.",
"sign_in": "Se connecter",
"tab_dashboard": "Tableau de bord",
"tab_users": "Utilisateurs",
"tab_oidc": "SSO / OIDC",
"total_users": "Utilisateurs totaux",
"active_users": "Utilisateurs actifs",
"admins": "Admins",
"version": "Version",
"storage_overview": "Aperçu du stockage",
"used": "Utilisé",
"total_quota": "Quota total",
"usage_pct": "Utilisation %",
"users_over_80": "Utilisateurs >80% quota",
"users_over_quota": "Utilisateurs dépassant le quota",
"system": "Système",
"auth_label": "Auth",
"oidc_label": "OIDC",
"quotas_label": "Quotas",
"enabled": "Activé",
"disabled": "Désactivé",
"active": "Actif",
"off": "Inactif",
"allow_registration": "Autoriser l'inscription publique",
"registration_warning": "L'inscription publique est désactivée. Seuls les admins peuvent créer des utilisateurs.",
"user_management": "Gestion des utilisateurs",
"create_user": "Créer un utilisateur",
"col_user": "Utilisateur",
"col_role": "Rôle",
"col_auth": "Auth",
"col_status": "Statut",
"col_storage": "Stockage",
"col_last_login": "Dernière connexion",
"col_actions": "Actions",
"loading_users": "Chargement des utilisateurs…",
"failed_load_users": "Échec du chargement",
"no_users_found": "Aucun utilisateur trouvé",
"showing_users": "Affichage {{from}}-{{to}} sur {{total}}",
"prev": "Précédent",
"next": "Suivant",
"inactive": "Inactif",
"you_badge": "(vous)",
"local": "Local",
"never": "Jamais",
"just_now": "À l'instant",
"minutes_ago": "il y a {{n}}min",
"hours_ago": "il y a {{n}}h",
"days_ago": "il y a {{n}}j",
"edit_quota_title": "Modifier le quota",
"reset_password_title": "Réinitialiser le mot de passe",
"toggle_role_title": "Changer de rôle",
"deactivate_title": "Désactiver",
"activate_title": "Activer",
"delete_title": "Supprimer",
"sso_title": "Authentification unique (OIDC / SSO)",
"enable_sso": "Activer l'authentification SSO",
"provider_name": "Nom du fournisseur",
"issuer_url": "URL de l'émetteur",
"issuer_url_hint": "URL de l'émetteur OpenID Connect",
"auto_discover": "Auto-découverte",
"discovering": "Découverte…",
"client_id": "Client ID",
"client_secret": "Client Secret",
"client_secret_placeholder": "Laisser vide pour conserver la valeur",
"secret_configured": "Un client secret est déjà configuré",
"callback_url": "URL de rappel",
"callback_url_hint": "(enregistrer dans votre IdP)",
"advanced_settings": "Paramètres avancés",
"scopes": "Scopes",
"auto_provision": "Provisionner automatiquement les utilisateurs",
"admin_groups": "Groupes admin",
"admin_groups_hint": "Noms de groupes OIDC séparés par des virgules",
"disable_password": "Désactiver la connexion par mot de passe (OIDC uniquement)",
"password_warning": "Cela empêchera TOUTES les connexions par mot de passe !",
"test_btn": "Tester",
"save_btn": "Enregistrer",
"saving": "Enregistrement…",
"settings_saved": "Paramètres enregistrés — OIDC est maintenant {{status}}",
"quota_modal_title": "Mettre à jour le quota",
"quota_user_label": "Utilisateur :",
"new_quota": "Nouveau quota",
"quota_unlimited_hint": "0 pour illimité",
"cancel": "Annuler",
"create_user_title": "Créer un nouvel utilisateur",
"username_label": "Nom d'utilisateur",
"username_placeholder": "jeandupont",
"username_hint": "3–32 caractères",
"password_label": "Mot de passe",
"password_placeholder": "Min 8 caractères",
"email_label": "E-mail",
"email_optional": "(facultatif)",
"email_placeholder": "utilisateur@exemple.com (auto-généré si vide)",
"role_label": "Rôle",
"role_user": "Utilisateur",
"role_admin": "Admin",
"quota_label": "Quota",
"creating": "Création…",
"reset_pw_title": "Réinitialiser le mot de passe",
"new_password_label": "Nouveau mot de passe",
"resetting": "Réinitialisation…",
"reset_btn": "Réinitialiser",
"confirm_role_change": "Changer le rôle en {{role}} ?",
"confirm_deactivate": "Voulez-vous vraiment désactiver cet utilisateur ?",
"confirm_activate": "Voulez-vous vraiment activer cet utilisateur ?",
"confirm_delete_user": "SUPPRIMER l'utilisateur \"{{name}}\" ? Irréversible !",
"confirm_action": "Confirmer l'action",
"confirm_yes": "Confirmer",
"confirm_no": "Annuler",
"error_username_short": "Le nom d'utilisateur doit contenir au moins 3 caractères",
"error_password_short": "Le mot de passe doit contenir au moins 8 caractères",
"error_generic": "Échec",
"error_network": "Erreur réseau : {{message}}",
"error_create_user": "Impossible de créer l'utilisateur"
},
"profile": {
"page_title": "Profil",
"back_to_app": "Retour à OxiCloud",
"loading": "Chargement…",
"not_authenticated": "Non authentifié",
"not_authenticated_desc": "Connectez-vous pour voir votre profil.",
"sign_in": "Se connecter",
"role_admin": "Administrateur",
"role_user": "Utilisateur",
"account_details": "Détails du compte",
"username": "Nom d'utilisateur",
"email": "E-mail",
"role": "Rôle",
"last_login": "Dernière connexion",
"storage": "Stockage",
"used": "Utilisé",
"quota": "Quota",
"usage": "Utilisation",
"unlimited": "Illimité",
"app_passwords": "Mots de passe d'application",
"app_pw_desc": "Générez des mots de passe pour les clients WebDAV, CalDAV et CardDAV. Chaque mot de passe n'est affiché qu'une seule fois.",
"app_pw_label_placeholder": "Libellé (ex. Thunderbird, macOS)",
"generate": "Générer",
"generating": "Génération…",
"new_password_for": "Nouveau mot de passe pour",
"copy_warning": "Copiez ce mot de passe maintenant. Vous ne pourrez plus le revoir.",
"copy_to_clipboard": "Copier dans le presse-papiers",
"col_label": "Libellé",
"col_created": "Créé",
"col_last_used": "Dernière utilisation",
"col_status": "Statut",
"active": "Actif",
"revoked": "Révoqué",
"revoke_title": "Révoquer",
"no_app_passwords": "Aucun mot de passe d'application.",
"client_sessions": "Sessions client",
"client_sessions_desc": "Générées automatiquement lors de la connexion d'un client compatible Nextcloud.",
"col_client": "Client",
"never": "Jamais",
"just_now": "À l'instant",
"minutes_ago": "il y a {{n}} min",
"hours_ago": "il y a {{n}}h",
"days_ago": "il y a {{n}} jours",
"change_password": "Changer le mot de passe",
"current_password": "Mot de passe actuel",
"new_password": "Nouveau mot de passe",
"min_8_chars": "Au moins 8 caractères",
"confirm_password": "Confirmer le nouveau mot de passe",
"update_password": "Mettre à jour le mot de passe",
"updating": "Mise à jour…",
"password_updated": "Mot de passe mis à jour avec succès",
"passwords_no_match": "Les mots de passe ne correspondent pas",
"password_too_short": "Le mot de passe doit contenir au moins 8 caractères",
"password_change_failed": "Échec du changement de mot de passe",
"error_network": "Erreur réseau : {{message}}",
"error_label_required": "Veuillez entrer un libellé",
"error_create_pw": "Impossible de créer le mot de passe",
"confirm_revoke": "Révoquer le mot de passe \"{{label}}\" ? Les clients l'utilisant ne fonctionneront plus.",
"error_revoke": "Échec de la révocation"
}
}
+555
View File
@@ -0,0 +1,555 @@
{
"app": {
"title": "OxiCloud",
"description": "न्यूनतम क्लाउड स्टोरेज सिस्टम"
},
"nav": {
"files": "फ़ाइलें",
"shared": "साझा",
"recent": "हाल ही में",
"favorites": "पसंदीदा",
"photos": "फ़ोटो",
"trash": "रद्दी"
},
"photos": {
"empty_state": "अभी कोई फ़ोटो नहीं",
"empty_hint": "यहाँ देखने के लिए चित्र या वीडियो अपलोड करें",
"items_selected": "चयनित",
"view_daily": "दिन",
"view_monthly": "महीना",
"view_yearly": "वर्ष"
},
"actions": {
"search": "फ़ाइलें खोजें...",
"new_folder": "नया फ़ोल्डर",
"upload": "अपलोड",
"upload_files": "फ़ाइलें अपलोड करें",
"upload_folder": "फ़ोल्डर अपलोड करें",
"upload.uploading": "अपलोड हो रहा है...",
"upload.complete": "{count} / {total} अपलोड हुईं",
"rename": "नाम बदलें",
"move": "यहाँ ले जाएँ...",
"move_to": "यहाँ ले जाएँ",
"delete": "हटाएँ",
"download": "डाउनलोड",
"view": "देखें",
"cancel": "रद्द करें",
"confirm": "पुष्टि करें",
"share": "साझा करें",
"favorite": "पसंदीदा में जोड़ें",
"unfavorite": "पसंदीदा से हटाएँ",
"copy": "कॉपी करें",
"notify": "सूचित करें",
"send": "भेजें",
"clear_recent": "हाल ही का साफ़ करें",
"logout": "लॉग आउट",
"create": "बनाएँ",
"search_btn": "खोजें",
"close": "बंद करें",
"delete_permanently": "स्थायी रूप से हटाएँ",
"empty_trash": "रद्दी खाली करें"
},
"user_menu": {
"appearance": "दिखावट",
"about": "OxiCloud के बारे में",
"about_description": "Rust और Clean Architecture से बना क्लाउड स्टोरेज प्लेटफ़ॉर्म। तेज़, सुरक्षित और निजी।",
"admin_panel": "एडमिन पैनल",
"profile": "मेरी प्रोफ़ाइल",
"role_user": "उपयोगकर्ता"
},
"share": {
"dialogTitle": "शेयर लिंक",
"linkLabel": "शेयर लिंक:",
"copyLink": "कॉपी",
"permissions": "अनुमतियाँ:",
"permissionRead": "पढ़ें",
"permissionWrite": "लिखें",
"permissionReshare": "पुनः साझा करें",
"password": "पासवर्ड सुरक्षा:",
"generatePassword": "जनरेट करें",
"expiration": "समाप्ति तिथि:",
"update": "शेयर अपडेट करें",
"remove": "शेयर हटाएँ",
"notifyTitle": "सूचना भेजें",
"notifyEmailLabel": "ईमेल पता:",
"notifyMessageLabel": "संदेश (वैकल्पिक):",
"notifySend": "सूचना भेजें",
"shareWithOthers": "दूसरों के साथ साझा करें",
"sharePublicly": "सार्वजनिक रूप से साझा करें",
"shareSettings": "साझा सेटिंग्स",
"shareCopied": "लिंक क्लिपबोर्ड पर कॉपी हुआ",
"shareCreated": "शेयर लिंक सफलतापूर्वक बनाया गया",
"shareUpdated": "शेयर सेटिंग्स सफलतापूर्वक अपडेट हुईं",
"shareRemoved": "शेयर सफलतापूर्वक हटाया गया"
},
"share_dialogTitle": "शेयर लिंक",
"share_linkLabel": "शेयर लिंक:",
"share_copyLink": "कॉपी",
"share_permissions": "अनुमतियाँ:",
"share_permissionRead": "पढ़ें",
"share_permissionWrite": "लिखें",
"share_permissionReshare": "पुनः साझा करें",
"share_password": "पासवर्ड सुरक्षा:",
"share_generatePassword": "जनरेट करें",
"share_expiration": "समाप्ति तिथि:",
"share_update": "शेयर अपडेट करें",
"share_remove": "शेयर हटाएँ",
"share_notifyTitle": "सूचना भेजें",
"share_notifyEmailLabel": "ईमेल पता:",
"share_notifyMessageLabel": "संदेश (वैकल्पिक):",
"share_notifySend": "सूचना भेजें",
"shared": {
"backToFiles": "फ़ाइलों पर वापस",
"pageTitle": "साझा संसाधन",
"pageDescription": "अपनी साझा फ़ाइलें और फ़ोल्डर प्रबंधित करें",
"filterType": "प्रकार:",
"filterAll": "सभी",
"filterFiles": "फ़ाइलें",
"filterFolders": "फ़ोल्डर",
"sortBy": "क्रमबद्ध:",
"sortByName": "नाम",
"sortByDate": "साझा तिथि",
"sortByExpiration": "समाप्ति",
"search": "खोजें",
"colName": "नाम",
"colType": "प्रकार",
"colDateShared": "साझा तिथि",
"colExpiration": "समाप्ति",
"colPermissions": "अनुमतियाँ",
"colPassword": "पासवर्ड",
"colActions": "कार्य",
"emptyStateTitle": "अभी कोई साझा संसाधन नहीं",
"emptyStateDesc": "जब आप फ़ाइलें या फ़ोल्डर साझा करेंगे, वे यहाँ दिखेंगे",
"goToFiles": "फ़ाइलों पर जाएँ",
"typeFile": "फ़ाइल",
"typeFolder": "फ़ोल्डर",
"noExpiration": "कोई समाप्ति नहीं",
"hasPassword": "हाँ",
"noPassword": "नहीं",
"editShare": "शेयर संपादित करें",
"notifyShare": "किसी को सूचित करें",
"copyLink": "लिंक कॉपी करें",
"removeShare": "शेयर हटाएँ",
"linkCopied": "लिंक क्लिपबोर्ड पर कॉपी हुआ!",
"linkCopyFailed": "लिंक कॉपी करने में विफल",
"itemUpdated": "शेयर सेटिंग्स सफलतापूर्वक अपडेट हुईं",
"itemRemoved": "शेयर सफलतापूर्वक हटाया गया",
"invalidEmail": "कृपया एक वैध ईमेल पता दर्ज करें",
"notificationSent": "सूचना सफलतापूर्वक भेजी गई",
"notificationFailed": "सूचना भेजने में विफल",
"shared_backToFiles": "फ़ाइलों पर वापस",
"shared_pageTitle": "साझा संसाधन",
"shared_pageDescription": "अपनी साझा फ़ाइलें और फ़ोल्डर प्रबंधित करें",
"shared_filterType": "प्रकार:",
"shared_filterAll": "सभी",
"shared_filterFiles": "फ़ाइलें",
"shared_filterFolders": "फ़ोल्डर",
"shared_sortBy": "क्रमबद्ध:",
"shared_sortByName": "नाम",
"shared_sortByDate": "साझा तिथि",
"shared_sortByExpiration": "समाप्ति",
"shared_search": "खोजें",
"shared_colName": "नाम",
"shared_colType": "प्रकार",
"shared_colDateShared": "साझा तिथि",
"shared_colExpiration": "समाप्ति",
"shared_colPermissions": "अनुमतियाँ",
"shared_colPassword": "पासवर्ड",
"shared_colActions": "कार्य",
"shared_emptyStateTitle": "अभी कोई साझा संसाधन नहीं",
"shared_emptyStateDesc": "जब आप फ़ाइलें या फ़ोल्डर साझा करेंगे, वे यहाँ दिखेंगे",
"shared_goToFiles": "फ़ाइलों पर जाएँ",
"shared_typeFile": "फ़ाइल",
"shared_typeFolder": "फ़ोल्डर",
"shared_noExpiration": "कोई समाप्ति नहीं",
"shared_hasPassword": "हाँ",
"shared_noPassword": "नहीं",
"shared_editShare": "शेयर संपादित करें",
"shared_notifyShare": "किसी को सूचित करें",
"shared_copyLink": "लिंक कॉपी करें",
"shared_removeShare": "शेयर हटाएँ",
"shared_linkCopied": "लिंक क्लिपबोर्ड पर कॉपी हुआ!",
"shared_linkCopyFailed": "लिंक कॉपी करने में विफल",
"shared_itemUpdated": "शेयर सेटिंग्स सफलतापूर्वक अपडेट हुईं",
"shared_itemRemoved": "शेयर सफलतापूर्वक हटाया गया",
"shared_invalidEmail": "कृपया एक वैध ईमेल पता दर्ज करें",
"shared_notificationSent": "सूचना सफलतापूर्वक भेजी गई",
"shared_notificationFailed": "सूचना भेजने में विफल"
},
"files": {
"name": "नाम",
"type": "प्रकार",
"size": "आकार",
"modified": "संशोधित",
"no_files": "इस फ़ोल्डर में कोई फ़ाइल नहीं",
"empty_hint": "शुरू करने के लिए ह़ैलें अपलोड करें या होल्डर बनाएँ",
"loading": "फ़ाइलें लोड हो रही हैं…",
"view_grid": "ग्रिड दृश्य",
"view_list": "सूची दृश्य",
"file_types": {
"document": "दस्तावेज़",
"image": "चित्र",
"video": "वीडियो",
"audio": "ऑडियो",
"pdf": "PDF",
"text": "टेक्स्ट",
"folder": "फ़ोल्डर",
"spreadsheet": "स्प्रेडशीट",
"presentation": "प्रेज़ेंटेशन",
"archive": "संग्रह",
"installer": "इंस्टॉलर",
"code": "कोड"
}
},
"dialogs": {
"rename_folder": "फ़ोल्डर का नाम बदलें",
"rename_file": "फ़ाइल का नाम बदलें",
"new_name": "नया नाम",
"new_folder_title": "नया फ़ोल्डर",
"folder_name": "फ़ोल्डर का नाम",
"folder_placeholder": "मेरा फ़ोल्डर",
"rename_title": "नाम बदलें",
"move_file": "फ़ाइल ले जाएँ",
"move_folder": "फ़ोल्डर ले जाएँ",
"select_destination": "गंतव्य फ़ोल्डर चुनें:",
"select_this_folder": "यह फ़ोल्डर चुनें",
"go_to_parent": ".. (पैरेंट फ़ोल्डर)",
"no_subfolders": "कोई सब-फ़ोल्डर नहीं",
"root": "रूट",
"delete_confirmation": "क्या आप वाकई हटाना चाहते हैं",
"and_contents": "और इसकी सभी सामग्री",
"no_undo": "यह कार्य पूर्ववत नहीं किया जा सकता",
"confirm_title": "कार्य की पुष्टि करें",
"confirm_delete": "रद्दी में भेजें",
"confirm_delete_file": "क्या आप वाकई फ़ाइल \"{{name}}\" को रद्दी में भेजना चाहते हैं?",
"confirm_delete_folder": "क्या आप वाकई फ़ोल्डर \"{{name}}\" और उसकी सभी सामग्री को रद्दी में भेजना चाहते हैं?",
"confirm_permanent_delete": "स्थायी रूप से हटाएँ",
"confirm_permanent_delete_msg": "क्या आप वाकई इस आइटम को स्थायी रूप से हटाना चाहते हैं? यह कार्य पूर्ववत नहीं किया जा सकता।",
"confirm_empty_trash": "रद्दी खाली करें",
"confirm_delete_share": "शेयर लिंक हटाएँ",
"confirm_delete_share_msg": "क्या आप वाकई इस शेयर लिंक को हटाना चाहते हैं?",
"share_file": "फ़ाइल साझा करें",
"existing_shares": "मौजूदा शेयर",
"share_options": "शेयर विकल्प",
"password": "पासवर्ड",
"expiration": "समाप्ति",
"permissions": "अनुमतियाँ",
"generated_link": "जनरेट किया गया लिंक",
"notify": "सूचना भेजें",
"recipient": "प्राप्तकर्ता",
"message": "संदेश"
},
"dropzone": {
"drag_files": "फ़ाइलें यहाँ खींचें या चुनने के लिए क्लिक करें",
"drop_files": "अपलोड करने के लिए फ़ाइलें छोड़ें"
},
"permissions": {
"read": "पढ़ें",
"write": "लिखें",
"reshare": "पुनः साझा करें"
},
"errors": {
"file_not_found": "फ़ाइल नहीं मिली",
"folder_not_found": "फ़ोल्डर नहीं मिला",
"delete_error": "हटाने में त्रुटि",
"upload_error": "फ़ाइल अपलोड करने में त्रुटि",
"rename_error": "नाम बदलने में त्रुटि",
"move_error": "ले जाने में त्रुटि",
"empty_name": "नाम खाली नहीं हो सकता",
"name_exists": "इस नाम की फ़ाइल या फ़ोल्डर पहले से मौजूद है",
"generic_error": "एक त्रुटि हुई है"
},
"breadcrumb": {
"home": "होम"
},
"trash": {
"empty_trash": "रद्दी खाली करें",
"empty_state": "रद्दी खाली है",
"original_location": "मूल स्थान",
"deleted_date": "हटाने की तिथि",
"actions": "कार्य",
"restore": "पुनर्स्थापित करें",
"delete_permanently": "स्थायी रूप से हटाएँ",
"empty_confirm": "क्या आप वाकई रद्दी खाली करना चाहते हैं? यह सभी आइटम स्थायी रूप से हटा देगा।"
},
"auth": {
"login_title": "साइन इन",
"username": "उपयोगकर्ता नाम",
"username_placeholder": "अपना उपयोगकर्ता नाम दर्ज करें",
"password": "पासवर्ड",
"password_placeholder": "अपना पासवर्ड दर्ज करें",
"login_button": "साइन इन",
"no_account": "खाता नहीं है?",
"register": "साइन अप करें",
"admin_setup": "पहली बार?",
"setup": "एडमिन सेटअप करें",
"register_title": "खाता बनाएँ",
"email": "ईमेल",
"email_placeholder": "अपना ईमेल दर्ज करें",
"confirm_password": "पासवर्ड की पुष्टि करें",
"confirm_password_placeholder": "अपना पासवर्ड पुष्टि करें",
"register_button": "खाता बनाएँ",
"have_account": "पहले से खाता है?",
"login": "साइन इन",
"setup_title": "प्रारंभिक सेटअप",
"setup_step1": "एडमिन",
"setup_step2": "सिस्टम",
"setup_step3": "पूर्ण",
"admin_username": "एडमिन उपयोगकर्ता नाम",
"admin_email": "एडमिन ईमेल",
"admin_password": "एडमिन पासवर्ड",
"create_admin": "एडमिन बनाएँ",
"back_to_login": "पहले से सेटअप है?",
"admin_success": "एडमिन खाता सफलतापूर्वक बनाया गया! अब आप साइन इन कर सकते हैं।",
"account_success": "खाता सफलतापूर्वक बनाया गया! अब आप साइन इन कर सकते हैं।",
"passwords_mismatch": "पासवर्ड मेल नहीं खाते",
"admin_create_error": "एडमिन खाता बनाने में त्रुटि",
"or": "या",
"sso_login": "SSO से साइन इन करें",
"sso_login_provider": "{{provider}} से साइन इन करें"
},
"storage": {
"title": "स्टोरेज",
"calculating": "गणना हो रही है...",
"used": "{{percentage}}% उपयोग ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "इस फ़ाइल प्रकार का पूर्वावलोकन नहीं किया जा सकता।",
"download_file": "फ़ाइल डाउनलोड करें",
"zoom_in": "ज़ूम इन",
"zoom_out": "ज़ूम आउट",
"zoom_reset": "ज़ूम रीसेट"
},
"language_selector": {
"title": "स्वागत है!",
"subtitle": "जारी रखने के लिए अपनी भाषा चुनें",
"continue": "आगे बढ़ें",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português",
"hi": "हिन्दी"
}
},
"favorites": {
"empty_state": "अभी कोई पसंदीदा नहीं",
"empty_hint": "पसंदीदा में जोड़ने के लिए फ़ाइलों या फ़ोल्डर को स्टार करें",
"add": "पसंदीदा में जोड़ें",
"remove": "पसंदीदा से हटाएँ",
"added_title": "पसंदीदा में जोड़ा गया",
"added_msg": "पसंदीदा में जोड़ा गया",
"removed_title": "पसंदीदा से हटाया गया",
"removed_msg": "पसंदीदा से हटाया गया"
},
"recent": {
"title": "हाल ही में",
"clear": "हाल ही का साफ़ करें",
"accessed": "एक्सेस किया",
"empty_state": "कोई हाल की फ़ाइलें नहीं",
"empty_hint": "जो फ़ाइलें आप खोलेंगे वे यहाँ दिखेंगी"
},
"notifications": {
"file_renamed": "फ़ाइल का नाम बदला गया",
"file_renamed_to": "फ़ाइल का नाम \"{{name}}\" रखा गया",
"folder_renamed": "फ़ोल्डर का नाम बदला गया",
"folder_renamed_to": "फ़ोल्डर का नाम \"{{name}}\" रखा गया",
"file_uploaded": "फ़ाइल अपलोड हुई",
"file_deleted": "फ़ाइल रद्दी में भेजी गई",
"folder_deleted": "फ़ोल्डर रद्दी में भेजा गया",
"item_deleted_permanently": "आइटम स्थायी रूप से हटाया गया",
"trash_emptied": "रद्दी सफलतापूर्वक खाली की गई",
"title": "सूचनाएँ",
"empty": "कोई सूचना नहीं"
},
"batch": {
"one_selected": "1 आइटम चयनित",
"n_selected": "{{count}} आइटम चयनित",
"confirm_delete": "क्या आप वाकई {{count}} आइटम रद्दी में भेजना चाहते हैं?",
"move_title": "{{count}} आइटम ले जाएँ",
"add_favorites": "पसंदीदा में जोड़ें",
"move_copy": "ले जाएँ या कॉपी करें"
},
"admin": {
"page_title": "एडमिन पैनल",
"back_to_app": "OxiCloud पर वापस",
"loading": "लोड हो रहा है…",
"access_denied": "पहुंच अस्वीकृत",
"access_denied_desc": "व्यवस्थापक विशेषाधिकार आवश्यक।",
"sign_in": "साइन इन",
"tab_dashboard": "डैशबोर्ड",
"tab_users": "उपयोगकर्ता",
"tab_oidc": "SSO / OIDC",
"total_users": "कुल उपयोगकर्ता",
"active_users": "सक्रिय उपयोगकर्ता",
"admins": "व्यवस्थापक",
"version": "संस्करण",
"storage_overview": "स्टोरेज अवलोकन",
"used": "उपयोग किया",
"total_quota": "कुल कोटा",
"usage_pct": "उपयोग %",
"users_over_80": ">80% कोटा वाले",
"users_over_quota": "कोटा से अधिक",
"system": "सिस्टम",
"auth_label": "प्रमाणीकरण",
"oidc_label": "OIDC",
"quotas_label": "कोटा",
"enabled": "सक्षम",
"disabled": "अक्षम",
"active": "सक्रिय",
"off": "बंद",
"allow_registration": "सार्वजनिक पंजीकरण की अनुमति",
"registration_warning": "सार्वजनिक पंजीकरण अक्षम है। केवल व्यवस्थापक उपयोगकर्ता बना सकते हैं।",
"user_management": "उपयोगकर्ता प्रबंधन",
"create_user": "उपयोगकर्ता बनाएं",
"col_user": "उपयोगकर्ता",
"col_role": "भूमिका",
"col_auth": "प्रमाणीकरण",
"col_status": "स्थिति",
"col_storage": "स्टोरेज",
"col_last_login": "अंतिम लॉगिन",
"col_actions": "कार्रवाई",
"loading_users": "उपयोगकर्ता लोड हो रहे हैं…",
"failed_load_users": "लोड करने में विफल",
"no_users_found": "कोई उपयोगकर्ता नहीं मिला",
"showing_users": "{{from}}-{{to}} / {{total}} दिखा रहे हैं",
"prev": "पिछला",
"next": "अगला",
"inactive": "निष्क्रिय",
"you_badge": "(आप)",
"local": "स्थानीय",
"never": "कभी नहीं",
"just_now": "अभी",
"minutes_ago": "{{n}} मिनट पहले",
"hours_ago": "{{n}} घंटे पहले",
"days_ago": "{{n}} दिन पहले",
"edit_quota_title": "कोटा संपादित करें",
"reset_password_title": "पासवर्ड रीसेट",
"toggle_role_title": "भूमिका बदलें",
"deactivate_title": "निष्क्रिय करें",
"activate_title": "सक्रिय करें",
"delete_title": "हटाएं",
"sso_title": "सिंगल साइन-ऑन (OIDC / SSO)",
"enable_sso": "SSO सक्षम करें",
"provider_name": "प्रदाता का नाम",
"issuer_url": "जारीकर्ता URL",
"issuer_url_hint": "OpenID Connect जारीकर्ता URL",
"auto_discover": "स्वतः खोज",
"discovering": "खोज रहे हैं…",
"client_id": "क्लाइंट ID",
"client_secret": "क्लाइंट सीक्रेट",
"client_secret_placeholder": "वर्तमान मान बनाए रखने के लिए खाली छोड़ें",
"secret_configured": "क्लाइंट सीक्रेट पहले से कॉन्फ़िगर है",
"callback_url": "कॉलबैक URL",
"callback_url_hint": "(अपने IdP में पंजीकृत करें)",
"advanced_settings": "उन्नत सेटिंग्स",
"scopes": "स्कोप",
"auto_provision": "पहले लॉगिन पर स्वतः प्रावधान",
"admin_groups": "व्यवस्थापक समूह",
"admin_groups_hint": "अल्पविराम-पृथक OIDC समूह नाम",
"disable_password": "पासवर्ड लॉगिन अक्षम (केवल OIDC)",
"password_warning": "सभी पासवर्ड लॉगिन रुक जाएंगे!",
"test_btn": "परीक्षण",
"save_btn": "सहेजें",
"saving": "सहेज रहे हैं…",
"settings_saved": "सेटिंग्स सहेजी गईं — OIDC अब {{status}}",
"quota_modal_title": "स्टोरेज कोटा अपडेट",
"quota_user_label": "उपयोगकर्ता:",
"new_quota": "नया कोटा",
"quota_unlimited_hint": "असीमित के लिए 0",
"cancel": "रद्द करें",
"create_user_title": "नया उपयोगकर्ता बनाएं",
"username_label": "उपयोगकर्ता नाम",
"username_placeholder": "username",
"username_hint": "3–32 अक्षर",
"password_label": "पासवर्ड",
"password_placeholder": "न्यूनतम 8 अक्षर",
"email_label": "ईमेल",
"email_optional": "(वैकल्पिक)",
"email_placeholder": "user@example.com (खाली होने पर स्वतः)",
"role_label": "भूमिका",
"role_user": "उपयोगकर्ता",
"role_admin": "व्यवस्थापक",
"quota_label": "कोटा",
"creating": "बना रहे हैं…",
"reset_pw_title": "पासवर्ड रीसेट",
"new_password_label": "नया पासवर्ड",
"resetting": "रीसेट हो रहा है…",
"reset_btn": "रीसेट",
"confirm_role_change": "भूमिका {{role}} में बदलें?",
"confirm_deactivate": "इस उपयोगकर्ता को निष्क्रिय करें?",
"confirm_activate": "इस उपयोगकर्ता को सक्रिय करें?",
"confirm_delete_user": "उपयोगकर्ता \"{{name}}\" हटाएं? पूर्ववत नहीं होगा!",
"confirm_action": "कार्रवाई की पुष्टि",
"confirm_yes": "पुष्टि",
"confirm_no": "रद्द",
"error_username_short": "नाम कम से कम 3 अक्षर",
"error_password_short": "पासवर्ड कम से कम 8 अक्षर",
"error_generic": "विफल",
"error_network": "नेटवर्क त्रुटि: {{message}}",
"error_create_user": "उपयोगकर्ता बनाने में विफल"
},
"profile": {
"page_title": "प्रोफ़ाइल",
"back_to_app": "OxiCloud पर वापस",
"loading": "लोड हो रहा है…",
"not_authenticated": "प्रमाणित नहीं",
"not_authenticated_desc": "अपना प्रोफ़ाइल देखने के लिए साइन इन करें।",
"sign_in": "साइन इन",
"role_admin": "व्यवस्थापक",
"role_user": "उपयोगकर्ता",
"account_details": "खाता विवरण",
"username": "उपयोगकर्ता नाम",
"email": "ईमेल",
"role": "भूमिका",
"last_login": "अंतिम लॉगिन",
"storage": "स्टोरेज",
"used": "उपयोग किया",
"quota": "कोटा",
"usage": "उपयोग",
"unlimited": "असीमित",
"app_passwords": "ऐप पासवर्ड",
"app_pw_desc": "WebDAV, CalDAV और CardDAV क्लाइंट के लिए पासवर्ड जनरेट करें। प्रत्येक पासवर्ड केवल एक बार दिखाया जाता है।",
"app_pw_label_placeholder": "लेबल (जैसे Thunderbird, macOS)",
"generate": "जनरेट करें",
"generating": "जनरेट हो रहा है…",
"new_password_for": "नया पासवर्ड",
"copy_warning": "इस पासवर्ड को अभी कॉपी करें। आप इसे दोबारा नहीं देख पाएंगे।",
"copy_to_clipboard": "क्लिपबोर्ड पर कॉपी करें",
"col_label": "लेबल",
"col_created": "बनाया गया",
"col_last_used": "अंतिम उपयोग",
"col_status": "स्थिति",
"active": "सक्रिय",
"revoked": "रद्द",
"revoke_title": "रद्द करें",
"no_app_passwords": "अभी तक कोई ऐप पासवर्ड नहीं।",
"client_sessions": "क्लाइंट सत्र",
"client_sessions_desc": "Nextcloud-संगत क्लाइंट कनेक्ट करने पर स्वतः जनरेट।",
"col_client": "क्लाइंट",
"never": "कभी नहीं",
"just_now": "अभी",
"minutes_ago": "{{n}} मिनट पहले",
"hours_ago": "{{n}} घंटे पहले",
"days_ago": "{{n}} दिन पहले",
"change_password": "पासवर्ड बदलें",
"current_password": "वर्तमान पासवर्ड",
"new_password": "नया पासवर्ड",
"min_8_chars": "कम से कम 8 अक्षर",
"confirm_password": "नया पासवर्ड पुष्टि करें",
"update_password": "पासवर्ड अपडेट करें",
"updating": "अपडेट हो रहा है…",
"password_updated": "पासवर्ड सफलतापूर्वक अपडेट हुआ",
"passwords_no_match": "पासवर्ड मेल नहीं खाते",
"password_too_short": "पासवर्ड कम से कम 8 अक्षर का होना चाहिए",
"password_change_failed": "पासवर्ड बदलने में विफल",
"error_network": "नेटवर्क त्रुटि: {{message}}",
"error_label_required": "कृपया एक लेबल दर्ज करें",
"error_create_pw": "ऐप पासवर्ड बनाने में विफल",
"confirm_revoke": "ऐप पासवर्ड \"{{label}}\" रद्द करें? इसका उपयोग करने वाले क्लाइंट काम करना बंद कर देंगे।",
"error_revoke": "रद्द करने में विफल"
}
}
+548 -368
View File
@@ -1,370 +1,550 @@
{
"app": {
"title": "OxiCloud",
"description": "Sistema di archiviazione cloud minimalista"
},
"nav": {
"files": "File",
"shared": "Condivisi",
"recent": "Recenti",
"favorites": "Preferiti",
"photos": "Foto",
"trash": "Cestino"
},
"photos": {
"empty_state": "Nessuna foto ancora",
"empty_hint": "Carica immagini o video per vederli qui",
"items_selected": "selezionati",
"view_daily": "Giorno",
"view_monthly": "Mese",
"view_yearly": "Anno"
},
"actions": {
"search": "Cerca file...",
"new_folder": "Nuova cartella",
"upload": "Carica",
"upload_files": "Carica file",
"upload_folder": "Carica cartella",
"upload.uploading": "Caricamento...",
"upload.complete": "{count} / {total} caricati",
"rename": "Rinomina",
"move": "Sposta in...",
"move_to": "Sposta in",
"delete": "Elimina",
"download": "Scarica",
"view": "Visualizza",
"cancel": "Annulla",
"confirm": "Conferma",
"share": "Condividi",
"favorite": "Aggiungi ai preferiti",
"unfavorite": "Rimuovi dai preferiti",
"copy": "Copia",
"notify": "Notifica",
"send": "Invia",
"clear_recent": "Cancella recenti",
"logout": "Disconnetti",
"create": "Crea",
"search_btn": "Cerca",
"close": "Chiudi",
"delete_permanently": "Elimina definitivamente",
"empty_trash": "Svuota il cestino"
},
"user_menu": {
"appearance": "Aspetto",
"about": "Informazioni su OxiCloud",
"about_description": "Piattaforma di archiviazione cloud realizzata con Rust & Architettura Pulita. Veloce, sicura e privata.",
"admin_panel": "Pannello di amministrazione",
"profile": "Il mio profilo",
"role_user": "Utente"
},
"share": {
"dialogTitle": "Link di condivisione",
"linkLabel": "Link di condivisione:",
"copyLink": "Copia",
"permissions": "Permessi:",
"permissionRead": "Lettura",
"permissionWrite": "Scrittura",
"permissionReshare": "Ricondivisione",
"password": "Protezione password:",
"generatePassword": "Genera",
"expiration": "Data di scadenza:",
"update": "Aggiorna condivisione",
"remove": "Rimuovi condivisione",
"notifyTitle": "Invia notifica",
"notifyEmailLabel": "Indirizzo email:",
"notifyMessageLabel": "Messaggio (opzionale):",
"notifySend": "Invia notifica",
"shareWithOthers": "Condividi con altri",
"sharePublicly": "Condividi pubblicamente",
"shareSettings": "Impostazioni di condivisione",
"shareCopied": "Link copiato negli appunti",
"shareCreated": "Link di condivisione creato con successo",
"shareUpdated": "Impostazioni di condivisione aggiornate con successo",
"shareRemoved": "Condivisione rimossa con successo"
},
"share_dialogTitle": "Link di condivisione",
"share_linkLabel": "Link di condivisione:",
"share_copyLink": "Copia",
"share_permissions": "Permessi:",
"share_permissionRead": "Lettura",
"share_permissionWrite": "Scrittura",
"share_permissionReshare": "Ricondivisione",
"share_password": "Protezione password:",
"share_generatePassword": "Genera",
"share_expiration": "Data di scadenza:",
"share_update": "Aggiorna condivisione",
"share_remove": "Rimuovi condivisione",
"share_notifyTitle": "Invia notifica",
"share_notifyEmailLabel": "Indirizzo email:",
"share_notifyMessageLabel": "Messaggio (opzionale):",
"share_notifySend": "Invia notifica",
"shared": {
"backToFiles": "Torna ai file",
"pageTitle": "Risorse condivise",
"pageDescription": "Gestisci i tuoi file e le tue cartelle condivise",
"filterType": "Tipo:",
"filterAll": "Tutti",
"filterFiles": "File",
"filterFolders": "Cartelle",
"sortBy": "Ordina per:",
"sortByName": "Nome",
"sortByDate": "Data di condivisione",
"sortByExpiration": "Scadenza",
"search": "Cerca",
"colName": "Nome",
"colType": "Tipo",
"colDateShared": "Data di condivisione",
"colExpiration": "Scadenza",
"colPermissions": "Permessi",
"colPassword": "Password",
"colActions": "Azioni",
"emptyStateTitle": "Ancora nessuna risorsa condivisa",
"emptyStateDesc": "Quando condividi file o cartelle, appariranno qui",
"goToFiles": "Vai ai file",
"typeFile": "File",
"typeFolder": "Cartella",
"noExpiration": "Nessuna scadenza",
"hasPassword": "Sì",
"noPassword": "No",
"editShare": "Modifica condivisione",
"notifyShare": "Notifica a qualcuno",
"copyLink": "Copia link",
"removeShare": "Rimuovi condivisione",
"linkCopied": "Link copiato negli appunti!",
"linkCopyFailed": "Impossibile copiare il link",
"itemUpdated": "Impostazioni di condivisione aggiornate con successo",
"itemRemoved": "Condivisione rimossa con successo",
"invalidEmail": "Inserisci un indirizzo email valido",
"notificationSent": "Notifica inviata con successo",
"notificationFailed": "Impossibile inviare la notifica",
"shared_backToFiles": "Torna ai file",
"shared_pageTitle": "Risorse condivise",
"shared_pageDescription": "Gestisci i tuoi file e le tue cartelle condivise",
"shared_filterType": "Tipo:",
"shared_filterAll": "Tutti",
"shared_filterFiles": "File",
"shared_filterFolders": "Cartelle",
"shared_sortBy": "Ordina per:",
"shared_sortByName": "Nome",
"shared_sortByDate": "Data di condivisione",
"shared_sortByExpiration": "Scadenza",
"shared_search": "Cerca",
"shared_colName": "Nome",
"shared_colType": "Tipo",
"shared_colDateShared": "Data di condivisione",
"shared_colExpiration": "Scadenza",
"shared_colPermissions": "Permessi",
"shared_colPassword": "Password",
"shared_colActions": "Azioni",
"shared_emptyStateTitle": "Ancora nessuna risorsa condivisa",
"shared_emptyStateDesc": "Quando condividi file o cartelle, appariranno qui",
"shared_goToFiles": "Vai ai file",
"shared_typeFile": "File",
"shared_typeFolder": "Cartella",
"shared_noExpiration": "Nessuna scadenza",
"shared_hasPassword": "Sì",
"shared_noPassword": "No",
"shared_editShare": "Modifica condivisione",
"shared_notifyShare": "Notifica a qualcuno",
"shared_copyLink": "Copia link",
"shared_removeShare": "Rimuovi condivisione",
"shared_linkCopied": "Link copiato negli appunti!",
"shared_linkCopyFailed": "Impossibile copiare il link",
"shared_itemUpdated": "Impostazioni di condivisione aggiornate con successo",
"shared_itemRemoved": "Condivisione rimossa con successo",
"shared_invalidEmail": "Inserisci un indirizzo email valido",
"shared_notificationSent": "Notifica inviata con successo",
"shared_notificationFailed": "Impossibile inviare la notifica"
},
"files": {
"name": "Nome",
"type": "Tipo",
"size": "Dimensione",
"modified": "Modificato",
"no_files": "Nessun file in questa cartella",
"loading": "Caricamento file…",
"view_grid": "Visualizzazione griglia",
"view_list": "Visualizzazione elenco",
"file_types": {
"document": "Documento",
"image": "Immagine",
"video": "Video",
"audio": "Audio",
"pdf": "PDF",
"text": "Testo",
"folder": "Cartella",
"spreadsheet": "Foglio di calcolo",
"presentation": "Presentazione",
"archive": "Archivio",
"installer": "Programma di installazione",
"code": "Codice"
}
},
"dialogs": {
"rename_folder": "Rinomina cartella",
"rename_file": "Rinomina file",
"new_name": "Nuovo nome",
"new_folder_title": "Nuova cartella",
"folder_name": "Nome cartella",
"folder_placeholder": "La mia cartella",
"rename_title": "Rinomina",
"move_file": "Sposta file",
"move_folder": "Sposta cartella",
"select_destination": "Seleziona cartella di destinazione:",
"root": "Root",
"delete_confirmation": "Sei sicuro di voler eliminare",
"and_contents": "e tutto il suo contenuto",
"no_undo": "Questa azione non può essere annullata",
"confirm_title": "Conferma azione",
"confirm_delete": "Sposta nel cestino",
"confirm_delete_file": "Sei sicuro di voler spostare il file \"{{name}}\" nel cestino?",
"confirm_delete_folder": "Sei sicuro di voler spostare la cartella \"{{name}}\" e tutto il suo contenuto nel cestino?",
"confirm_permanent_delete": "Elimina definitivamente",
"confirm_permanent_delete_msg": "Sei sicuro di voler eliminare definitivamente questo elemento? Questa azione non può essere annullata.",
"confirm_empty_trash": "Svuota il cestino",
"confirm_delete_share": "Elimina link di condivisione",
"confirm_delete_share_msg": "Sei sicuro di voler eliminare questo link di condivisione?",
"share_file": "Condividi File",
"existing_shares": "Condivisioni Esistenti",
"share_options": "Opzioni di Condivisione",
"password": "Password",
"expiration": "Scadenza",
"permissions": "Permessi",
"generated_link": "Link Generato",
"notify": "Invia Notifica",
"recipient": "Destinatario",
"message": "Messaggio"
},
"dropzone": {
"drag_files": "Trascina i file qui o clicca per selezionare",
"drop_files": "Rilascia i file per caricarli"
},
"permissions": {
"read": "Lettura",
"write": "Scrittura",
"reshare": "Ricondividi"
},
"errors": {
"file_not_found": "File non trovato",
"folder_not_found": "Cartella non trovata",
"delete_error": "Errore durante l'eliminazione",
"upload_error": "Errore durante il caricamento del file",
"rename_error": "Errore durante la rinomina",
"move_error": "Errore durante lo spostamento",
"empty_name": "Il nome non può essere vuoto",
"name_exists": "Un file o una cartella con quel nome esiste già",
"generic_error": "Si è verificato un errore"
},
"breadcrumb": {
"home": "Home"
},
"trash": {
"empty_trash": "Svuota il cestino",
"empty_state": "Il cestino è vuoto",
"original_location": "Posizione originale",
"deleted_date": "Data di eliminazione",
"actions": "Azioni",
"restore": "Ripristina",
"delete_permanently": "Elimina definitivamente",
"empty_confirm": "Sei sicuro di voler svuotare il cestino? Questa operazione eliminerà definitivamente tutti gli elementi."
},
"auth": {
"login_title": "Accedi",
"username": "Nome utente",
"username_placeholder": "Inserisci il tuo nome utente",
"password": "Password",
"password_placeholder": "Inserisci la tua password",
"login_button": "Accedi",
"no_account": "Non hai un account?",
"register": "Registrati",
"admin_setup": "È la prima volta?",
"setup": "Configura amministratore",
"register_title": "Crea account",
"email": "Email",
"email_placeholder": "Inserisci la tua email",
"confirm_password": "Conferma password",
"confirm_password_placeholder": "Conferma la tua password",
"register_button": "Crea account",
"have_account": "Hai già un account?",
"login": "Accedi",
"setup_title": "Configurazione iniziale",
"setup_step1": "Amministratore",
"setup_step2": "Sistema",
"setup_step3": "Completa",
"admin_username": "Nome utente amministratore",
"admin_email": "Email amministratore",
"admin_password": "Password amministratore",
"create_admin": "Crea amministratore",
"back_to_login": "Già configurato?",
"admin_success": "Account amministratore creato con successo! Ora puoi accedere.",
"account_success": "Account creato con successo! Ora puoi accedere.",
"passwords_mismatch": "Le password non corrispondono",
"admin_create_error": "Errore durante la creazione dell'account amministratore",
"or": "o",
"sso_login": "Accedi con SSO",
"sso_login_provider": "Accedi con {{provider}}"
},
"storage": {
"title": "Archiviazione",
"calculating": "Calcolo in corso...",
"used": "{{percentage}}% utilizzato ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Questo tipo di file non può essere visualizzato in anteprima.",
"download_file": "Scarica file",
"zoom_in": "Ingrandisci",
"zoom_out": "Riduci",
"zoom_reset": "Reimposta zoom"
},
"language_selector": {
"title": "Benvenuto in OxiCloud",
"subtitle": "Seleziona la tua lingua",
"continue": "Continua",
"languages": {
"en": "Inglese",
"es": "Spagnolo",
"zh": "Cinese",
"fa": "Persiano",
"fr": "Francese",
"de": "Tedesco",
"pt": "Portoghese",
"it": "Italiano"
}
},
"favorites": {
"empty_state": "Ancora nessun preferito",
"empty_hint": "Aggiungi file o cartelle ai preferiti per inserirli qui",
"add": "Aggiungi ai preferiti",
"remove": "Rimuovi dai preferiti",
"added_title": "Aggiunto ai preferiti",
"added_msg": "aggiunto ai preferiti",
"removed_title": "Rimosso dai preferiti",
"removed_msg": "rimosso dai preferiti"
},
"recent": {
"title": "Recenti",
"clear": "Cancella recenti",
"accessed": "Accesso",
"empty_state": "Nessun file recente",
"empty_hint": "I file che apri appariranno qui"
},
"notifications": {
"file_renamed": "File rinominato",
"file_renamed_to": "File rinominato in \"{{name}}\"",
"folder_renamed": "Cartella rinominata",
"folder_renamed_to": "Cartella rinominata in \"{{name}}\"",
"file_uploaded": "File caricato",
"file_deleted": "File spostato nel cestino",
"folder_deleted": "Cartella spostata nel cestino",
"item_deleted_permanently": "Elemento eliminato definitivamente",
"trash_emptied": "Cestino svuotato con successo"
},
"batch": {
"one_selected": "1 elemento selezionato",
"n_selected": "{{count}} elementi selezionati",
"confirm_delete": "Sei sicuro di voler spostare {{count}} elementi nel cestino?",
"move_title": "Sposta {{count}} elemento/i",
"add_favorites": "Aggiungi ai preferiti",
"move_copy": "Sposta o copia"
}
"app": {
"title": "OxiCloud",
"description": "Sistema di archiviazione cloud minimalista"
},
"nav": {
"files": "File",
"shared": "Condivisi",
"recent": "Recenti",
"favorites": "Preferiti",
"photos": "Foto",
"trash": "Cestino"
},
"photos": {
"empty_state": "Nessuna foto ancora",
"empty_hint": "Carica immagini o video per vederli qui",
"items_selected": "selezionati",
"view_daily": "Giorno",
"view_monthly": "Mese",
"view_yearly": "Anno"
},
"actions": {
"search": "Cerca file...",
"new_folder": "Nuova cartella",
"upload": "Carica",
"upload_files": "Carica file",
"upload_folder": "Carica cartella",
"upload.uploading": "Caricamento...",
"upload.complete": "{count} / {total} caricati",
"rename": "Rinomina",
"move": "Sposta in...",
"move_to": "Sposta in",
"delete": "Elimina",
"download": "Scarica",
"view": "Visualizza",
"cancel": "Annulla",
"confirm": "Conferma",
"share": "Condividi",
"favorite": "Aggiungi ai preferiti",
"unfavorite": "Rimuovi dai preferiti",
"copy": "Copia",
"notify": "Notifica",
"send": "Invia",
"clear_recent": "Cancella recenti",
"logout": "Disconnetti",
"create": "Crea",
"search_btn": "Cerca",
"close": "Chiudi",
"delete_permanently": "Elimina definitivamente",
"empty_trash": "Svuota il cestino"
},
"user_menu": {
"appearance": "Aspetto",
"about": "Informazioni su OxiCloud",
"about_description": "Piattaforma di archiviazione cloud realizzata con Rust & Architettura Pulita. Veloce, sicura e privata.",
"admin_panel": "Pannello di amministrazione",
"profile": "Il mio profilo",
"role_user": "Utente"
},
"share": {
"dialogTitle": "Link di condivisione",
"linkLabel": "Link di condivisione:",
"copyLink": "Copia",
"permissions": "Permessi:",
"permissionRead": "Lettura",
"permissionWrite": "Scrittura",
"permissionReshare": "Ricondivisione",
"password": "Protezione password:",
"generatePassword": "Genera",
"expiration": "Data di scadenza:",
"update": "Aggiorna condivisione",
"remove": "Rimuovi condivisione",
"notifyTitle": "Invia notifica",
"notifyEmailLabel": "Indirizzo email:",
"notifyMessageLabel": "Messaggio (opzionale):",
"notifySend": "Invia notifica",
"shareWithOthers": "Condividi con altri",
"sharePublicly": "Condividi pubblicamente",
"shareSettings": "Impostazioni di condivisione",
"shareCopied": "Link copiato negli appunti",
"shareCreated": "Link di condivisione creato con successo",
"shareUpdated": "Impostazioni di condivisione aggiornate con successo",
"shareRemoved": "Condivisione rimossa con successo"
},
"share_dialogTitle": "Link di condivisione",
"share_linkLabel": "Link di condivisione:",
"share_copyLink": "Copia",
"share_permissions": "Permessi:",
"share_permissionRead": "Lettura",
"share_permissionWrite": "Scrittura",
"share_permissionReshare": "Ricondivisione",
"share_password": "Protezione password:",
"share_generatePassword": "Genera",
"share_expiration": "Data di scadenza:",
"share_update": "Aggiorna condivisione",
"share_remove": "Rimuovi condivisione",
"share_notifyTitle": "Invia notifica",
"share_notifyEmailLabel": "Indirizzo email:",
"share_notifyMessageLabel": "Messaggio (opzionale):",
"share_notifySend": "Invia notifica",
"shared": {
"backToFiles": "Torna ai file",
"pageTitle": "Risorse condivise",
"pageDescription": "Gestisci i tuoi file e le tue cartelle condivise",
"filterType": "Tipo:",
"filterAll": "Tutti",
"filterFiles": "File",
"filterFolders": "Cartelle",
"sortBy": "Ordina per:",
"sortByName": "Nome",
"sortByDate": "Data di condivisione",
"sortByExpiration": "Scadenza",
"search": "Cerca",
"colName": "Nome",
"colType": "Tipo",
"colDateShared": "Data di condivisione",
"colExpiration": "Scadenza",
"colPermissions": "Permessi",
"colPassword": "Password",
"colActions": "Azioni",
"emptyStateTitle": "Ancora nessuna risorsa condivisa",
"emptyStateDesc": "Quando condividi file o cartelle, appariranno qui",
"goToFiles": "Vai ai file",
"typeFile": "File",
"typeFolder": "Cartella",
"noExpiration": "Nessuna scadenza",
"hasPassword": "Sì",
"noPassword": "No",
"editShare": "Modifica condivisione",
"notifyShare": "Notifica a qualcuno",
"copyLink": "Copia link",
"removeShare": "Rimuovi condivisione",
"linkCopied": "Link copiato negli appunti!",
"linkCopyFailed": "Impossibile copiare il link",
"itemUpdated": "Impostazioni di condivisione aggiornate con successo",
"itemRemoved": "Condivisione rimossa con successo",
"invalidEmail": "Inserisci un indirizzo email valido",
"notificationSent": "Notifica inviata con successo",
"notificationFailed": "Impossibile inviare la notifica",
"shared_backToFiles": "Torna ai file",
"shared_pageTitle": "Risorse condivise",
"shared_pageDescription": "Gestisci i tuoi file e le tue cartelle condivise",
"shared_filterType": "Tipo:",
"shared_filterAll": "Tutti",
"shared_filterFiles": "File",
"shared_filterFolders": "Cartelle",
"shared_sortBy": "Ordina per:",
"shared_sortByName": "Nome",
"shared_sortByDate": "Data di condivisione",
"shared_sortByExpiration": "Scadenza",
"shared_search": "Cerca",
"shared_colName": "Nome",
"shared_colType": "Tipo",
"shared_colDateShared": "Data di condivisione",
"shared_colExpiration": "Scadenza",
"shared_colPermissions": "Permessi",
"shared_colPassword": "Password",
"shared_colActions": "Azioni",
"shared_emptyStateTitle": "Ancora nessuna risorsa condivisa",
"shared_emptyStateDesc": "Quando condividi file o cartelle, appariranno qui",
"shared_goToFiles": "Vai ai file",
"shared_typeFile": "File",
"shared_typeFolder": "Cartella",
"shared_noExpiration": "Nessuna scadenza",
"shared_hasPassword": "Sì",
"shared_noPassword": "No",
"shared_editShare": "Modifica condivisione",
"shared_notifyShare": "Notifica a qualcuno",
"shared_copyLink": "Copia link",
"shared_removeShare": "Rimuovi condivisione",
"shared_linkCopied": "Link copiato negli appunti!",
"shared_linkCopyFailed": "Impossibile copiare il link",
"shared_itemUpdated": "Impostazioni di condivisione aggiornate con successo",
"shared_itemRemoved": "Condivisione rimossa con successo",
"shared_invalidEmail": "Inserisci un indirizzo email valido",
"shared_notificationSent": "Notifica inviata con successo",
"shared_notificationFailed": "Impossibile inviare la notifica"
},
"files": {
"name": "Nome",
"type": "Tipo",
"size": "Dimensione",
"modified": "Modificato",
"no_files": "Nessun file in questa cartella",
"empty_hint": "Carica file o crea cartelle per iniziare",
"loading": "Caricamento file…",
"view_grid": "Visualizzazione griglia",
"view_list": "Visualizzazione elenco",
"file_types": {
"document": "Documento",
"image": "Immagine",
"video": "Video",
"audio": "Audio",
"pdf": "PDF",
"text": "Testo",
"folder": "Cartella",
"spreadsheet": "Foglio di calcolo",
"presentation": "Presentazione",
"archive": "Archivio",
"installer": "Programma di installazione",
"code": "Codice"
}
},
"dialogs": {
"rename_folder": "Rinomina cartella",
"rename_file": "Rinomina file",
"new_name": "Nuovo nome",
"new_folder_title": "Nuova cartella",
"folder_name": "Nome cartella",
"folder_placeholder": "La mia cartella",
"rename_title": "Rinomina",
"move_file": "Sposta file",
"move_folder": "Sposta cartella",
"select_destination": "Seleziona cartella di destinazione:",
"root": "Root",
"delete_confirmation": "Sei sicuro di voler eliminare",
"and_contents": "e tutto il suo contenuto",
"no_undo": "Questa azione non può essere annullata",
"confirm_title": "Conferma azione",
"confirm_delete": "Sposta nel cestino",
"confirm_delete_file": "Sei sicuro di voler spostare il file \"{{name}}\" nel cestino?",
"confirm_delete_folder": "Sei sicuro di voler spostare la cartella \"{{name}}\" e tutto il suo contenuto nel cestino?",
"confirm_permanent_delete": "Elimina definitivamente",
"confirm_permanent_delete_msg": "Sei sicuro di voler eliminare definitivamente questo elemento? Questa azione non può essere annullata.",
"confirm_empty_trash": "Svuota il cestino",
"confirm_delete_share": "Elimina link di condivisione",
"confirm_delete_share_msg": "Sei sicuro di voler eliminare questo link di condivisione?",
"share_file": "Condividi File",
"existing_shares": "Condivisioni Esistenti",
"share_options": "Opzioni di Condivisione",
"password": "Password",
"expiration": "Scadenza",
"permissions": "Permessi",
"generated_link": "Link Generato",
"notify": "Invia Notifica",
"recipient": "Destinatario",
"message": "Messaggio"
},
"dropzone": {
"drag_files": "Trascina i file qui o clicca per selezionare",
"drop_files": "Rilascia i file per caricarli"
},
"permissions": {
"read": "Lettura",
"write": "Scrittura",
"reshare": "Ricondividi"
},
"errors": {
"file_not_found": "File non trovato",
"folder_not_found": "Cartella non trovata",
"delete_error": "Errore durante l'eliminazione",
"upload_error": "Errore durante il caricamento del file",
"rename_error": "Errore durante la rinomina",
"move_error": "Errore durante lo spostamento",
"empty_name": "Il nome non può essere vuoto",
"name_exists": "Un file o una cartella con quel nome esiste già",
"generic_error": "Si è verificato un errore"
},
"breadcrumb": {
"home": "Home"
},
"trash": {
"empty_trash": "Svuota il cestino",
"empty_state": "Il cestino è vuoto",
"original_location": "Posizione originale",
"deleted_date": "Data di eliminazione",
"actions": "Azioni",
"restore": "Ripristina",
"delete_permanently": "Elimina definitivamente",
"empty_confirm": "Sei sicuro di voler svuotare il cestino? Questa operazione eliminerà definitivamente tutti gli elementi."
},
"auth": {
"login_title": "Accedi",
"username": "Nome utente",
"username_placeholder": "Inserisci il tuo nome utente",
"password": "Password",
"password_placeholder": "Inserisci la tua password",
"login_button": "Accedi",
"no_account": "Non hai un account?",
"register": "Registrati",
"admin_setup": "È la prima volta?",
"setup": "Configura amministratore",
"register_title": "Crea account",
"email": "Email",
"email_placeholder": "Inserisci la tua email",
"confirm_password": "Conferma password",
"confirm_password_placeholder": "Conferma la tua password",
"register_button": "Crea account",
"have_account": "Hai già un account?",
"login": "Accedi",
"setup_title": "Configurazione iniziale",
"setup_step1": "Amministratore",
"setup_step2": "Sistema",
"setup_step3": "Completa",
"admin_username": "Nome utente amministratore",
"admin_email": "Email amministratore",
"admin_password": "Password amministratore",
"create_admin": "Crea amministratore",
"back_to_login": "Già configurato?",
"admin_success": "Account amministratore creato con successo! Ora puoi accedere.",
"account_success": "Account creato con successo! Ora puoi accedere.",
"passwords_mismatch": "Le password non corrispondono",
"admin_create_error": "Errore durante la creazione dell'account amministratore",
"or": "o",
"sso_login": "Accedi con SSO",
"sso_login_provider": "Accedi con {{provider}}"
},
"storage": {
"title": "Archiviazione",
"calculating": "Calcolo in corso...",
"used": "{{percentage}}% utilizzato ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Questo tipo di file non può essere visualizzato in anteprima.",
"download_file": "Scarica file",
"zoom_in": "Ingrandisci",
"zoom_out": "Riduci",
"zoom_reset": "Reimposta zoom"
},
"language_selector": {
"title": "Benvenuto!",
"subtitle": "Seleziona la tua lingua per continuare",
"continue": "Continua",
"languages": {
"en": "Inglese",
"es": "Spagnolo",
"zh": "Cinese",
"fa": "Persiano",
"fr": "Francese",
"de": "Tedesco",
"pt": "Portoghese",
"it": "Italiano"
}
},
"favorites": {
"empty_state": "Ancora nessun preferito",
"empty_hint": "Aggiungi file o cartelle ai preferiti per inserirli qui",
"add": "Aggiungi ai preferiti",
"remove": "Rimuovi dai preferiti",
"added_title": "Aggiunto ai preferiti",
"added_msg": "aggiunto ai preferiti",
"removed_title": "Rimosso dai preferiti",
"removed_msg": "rimosso dai preferiti"
},
"recent": {
"title": "Recenti",
"clear": "Cancella recenti",
"accessed": "Accesso",
"empty_state": "Nessun file recente",
"empty_hint": "I file che apri appariranno qui"
},
"notifications": {
"file_renamed": "File rinominato",
"file_renamed_to": "File rinominato in \"{{name}}\"",
"folder_renamed": "Cartella rinominata",
"folder_renamed_to": "Cartella rinominata in \"{{name}}\"",
"file_uploaded": "File caricato",
"file_deleted": "File spostato nel cestino",
"folder_deleted": "Cartella spostata nel cestino",
"item_deleted_permanently": "Elemento eliminato definitivamente",
"trash_emptied": "Cestino svuotato con successo"
},
"batch": {
"one_selected": "1 elemento selezionato",
"n_selected": "{{count}} elementi selezionati",
"confirm_delete": "Sei sicuro di voler spostare {{count}} elementi nel cestino?",
"move_title": "Sposta {{count}} elemento/i",
"add_favorites": "Aggiungi ai preferiti",
"move_copy": "Sposta o copia"
},
"admin": {
"page_title": "Pannello di Amministrazione",
"back_to_app": "Torna a OxiCloud",
"loading": "Caricamento…",
"access_denied": "Accesso Negato",
"access_denied_desc": "Privilegi di amministratore necessari.",
"sign_in": "Accedi",
"tab_dashboard": "Dashboard",
"tab_users": "Utenti",
"tab_oidc": "SSO / OIDC",
"total_users": "Utenti Totali",
"active_users": "Utenti Attivi",
"admins": "Amministratori",
"version": "Versione",
"storage_overview": "Panoramica Archiviazione",
"used": "Usato",
"total_quota": "Quota Totale",
"usage_pct": "Utilizzo %",
"users_over_80": "Utenti >80% quota",
"users_over_quota": "Utenti oltre la quota",
"system": "Sistema",
"auth_label": "Auth",
"oidc_label": "OIDC",
"quotas_label": "Quote",
"enabled": "Abilitato",
"disabled": "Disabilitato",
"active": "Attivo",
"off": "Spento",
"allow_registration": "Consenti registrazione pubblica",
"registration_warning": "La registrazione pubblica è disabilitata. Solo gli admin possono creare utenti.",
"user_management": "Gestione Utenti",
"create_user": "Crea Utente",
"col_user": "Utente",
"col_role": "Ruolo",
"col_auth": "Auth",
"col_status": "Stato",
"col_storage": "Archiviazione",
"col_last_login": "Ultimo Accesso",
"col_actions": "Azioni",
"loading_users": "Caricamento utenti…",
"failed_load_users": "Impossibile caricare",
"no_users_found": "Nessun utente trovato",
"showing_users": "Mostrando {{from}}-{{to}} di {{total}}",
"prev": "Precedente",
"next": "Successivo",
"inactive": "Inattivo",
"you_badge": "(tu)",
"local": "Locale",
"never": "Mai",
"just_now": "Proprio adesso",
"minutes_ago": "{{n}}min fa",
"hours_ago": "{{n}}h fa",
"days_ago": "{{n}}g fa",
"edit_quota_title": "Modifica quota",
"reset_password_title": "Reimposta password",
"toggle_role_title": "Cambia ruolo",
"deactivate_title": "Disattiva",
"activate_title": "Attiva",
"delete_title": "Elimina",
"sso_title": "Single Sign-On (OIDC / SSO)",
"enable_sso": "Abilita autenticazione SSO",
"provider_name": "Nome Provider",
"issuer_url": "URL Emittente",
"issuer_url_hint": "URL dell'emittente OpenID Connect",
"auto_discover": "Auto-scoperta",
"discovering": "Scoperta…",
"client_id": "Client ID",
"client_secret": "Client Secret",
"client_secret_placeholder": "Lascia vuoto per mantenere il valore",
"secret_configured": "Un client secret è già configurato",
"callback_url": "URL di Callback",
"callback_url_hint": "(registra nel tuo IdP)",
"advanced_settings": "Impostazioni Avanzate",
"scopes": "Scopes",
"auto_provision": "Provisioning automatico degli utenti",
"admin_groups": "Gruppi Admin",
"admin_groups_hint": "Nomi di gruppi OIDC separati da virgola",
"disable_password": "Disabilita accesso con password (solo OIDC)",
"password_warning": "Questo impedirà TUTTI gli accessi tramite password!",
"test_btn": "Test",
"save_btn": "Salva",
"saving": "Salvataggio…",
"settings_saved": "Impostazioni salvate — OIDC ora è {{status}}",
"quota_modal_title": "Aggiorna Quota",
"quota_user_label": "Utente:",
"new_quota": "Nuova Quota",
"quota_unlimited_hint": "0 per illimitato",
"cancel": "Annulla",
"create_user_title": "Crea Nuovo Utente",
"username_label": "Nome utente",
"username_placeholder": "mariorossi",
"username_hint": "3–32 caratteri",
"password_label": "Password",
"password_placeholder": "Min 8 caratteri",
"email_label": "Email",
"email_optional": "(facoltativo)",
"email_placeholder": "utente@esempio.com (auto-generata se vuoto)",
"role_label": "Ruolo",
"role_user": "Utente",
"role_admin": "Admin",
"quota_label": "Quota",
"creating": "Creazione…",
"reset_pw_title": "Reimposta Password",
"new_password_label": "Nuova Password",
"resetting": "Reimpostazione…",
"reset_btn": "Reimposta",
"confirm_role_change": "Cambiare ruolo a {{role}}?",
"confirm_deactivate": "Sei sicuro di voler disattivare questo utente?",
"confirm_activate": "Sei sicuro di voler attivare questo utente?",
"confirm_delete_user": "ELIMINARE l'utente \"{{name}}\"? Azione irreversibile!",
"confirm_action": "Conferma Azione",
"confirm_yes": "Conferma",
"confirm_no": "Annulla",
"error_username_short": "Il nome utente deve avere almeno 3 caratteri",
"error_password_short": "La password deve avere almeno 8 caratteri",
"error_generic": "Fallito",
"error_network": "Errore di rete: {{message}}",
"error_create_user": "Impossibile creare l'utente"
},
"profile": {
"page_title": "Profilo",
"back_to_app": "Torna a OxiCloud",
"loading": "Caricamento…",
"not_authenticated": "Non Autenticato",
"not_authenticated_desc": "Accedi per visualizzare il tuo profilo.",
"sign_in": "Accedi",
"role_admin": "Amministratore",
"role_user": "Utente",
"account_details": "Dettagli Account",
"username": "Nome utente",
"email": "Email",
"role": "Ruolo",
"last_login": "Ultimo accesso",
"storage": "Archiviazione",
"used": "Usato",
"quota": "Quota",
"usage": "Utilizzo",
"unlimited": "Illimitato",
"app_passwords": "Password Applicazione",
"app_pw_desc": "Genera password per client WebDAV, CalDAV e CardDAV. Ogni password viene mostrata una sola volta.",
"app_pw_label_placeholder": "Etichetta (es. Thunderbird, macOS)",
"generate": "Genera",
"generating": "Generazione…",
"new_password_for": "Nuova password per",
"copy_warning": "Copia questa password ora. Non potrai rivederla.",
"copy_to_clipboard": "Copia negli appunti",
"col_label": "Etichetta",
"col_created": "Creato",
"col_last_used": "Ultimo utilizzo",
"col_status": "Stato",
"active": "Attiva",
"revoked": "Revocata",
"revoke_title": "Revoca",
"no_app_passwords": "Nessuna password applicazione ancora.",
"client_sessions": "Sessioni client",
"client_sessions_desc": "Generate automaticamente quando connetti un client compatibile Nextcloud.",
"col_client": "Client",
"never": "Mai",
"just_now": "Proprio adesso",
"minutes_ago": "{{n}} min fa",
"hours_ago": "{{n}}h fa",
"days_ago": "{{n}} giorni fa",
"change_password": "Cambia Password",
"current_password": "Password Attuale",
"new_password": "Nuova Password",
"min_8_chars": "Almeno 8 caratteri",
"confirm_password": "Conferma Nuova Password",
"update_password": "Aggiorna Password",
"updating": "Aggiornamento…",
"password_updated": "Password aggiornata con successo",
"passwords_no_match": "Le password non corrispondono",
"password_too_short": "La password deve avere almeno 8 caratteri",
"password_change_failed": "Impossibile cambiare la password",
"error_network": "Errore di rete: {{message}}",
"error_label_required": "Inserisci un'etichetta",
"error_create_pw": "Impossibile creare la password",
"confirm_revoke": "Revocare la password \"{{label}}\"? I client che la usano smetteranno di funzionare.",
"error_revoke": "Revoca fallita"
}
}
+555
View File
@@ -0,0 +1,555 @@
{
"app": {
"title": "OxiCloud",
"description": "ミニマリストクラウドストレージシステム"
},
"nav": {
"files": "ファイル",
"shared": "共有",
"recent": "最近",
"favorites": "お気に入り",
"photos": "写真",
"trash": "ゴミ箱"
},
"photos": {
"empty_state": "写真はまだありません",
"empty_hint": "画像や動画をアップロードするとここに表示されます",
"items_selected": "件選択中",
"view_daily": "日",
"view_monthly": "月",
"view_yearly": "年"
},
"actions": {
"search": "ファイルを検索...",
"new_folder": "新しいフォルダ",
"upload": "アップロード",
"upload_files": "ファイルをアップロード",
"upload_folder": "フォルダをアップロード",
"upload.uploading": "アップロード中...",
"upload.complete": "{count} / {total} アップロード完了",
"rename": "名前を変更",
"move": "移動先...",
"move_to": "移動先",
"delete": "削除",
"download": "ダウンロード",
"view": "表示",
"cancel": "キャンセル",
"confirm": "確認",
"share": "共有",
"favorite": "お気に入りに追加",
"unfavorite": "お気に入りから削除",
"copy": "コピー",
"notify": "通知",
"send": "送信",
"clear_recent": "最近をクリア",
"logout": "ログアウト",
"create": "作成",
"search_btn": "検索",
"close": "閉じる",
"delete_permanently": "完全に削除",
"empty_trash": "ゴミ箱を空にする"
},
"user_menu": {
"appearance": "外観",
"about": "OxiCloudについて",
"about_description": "RustとClean Architectureで構築されたクラウドストレージプラットフォーム。高速・安全・プライベート。",
"admin_panel": "管理パネル",
"profile": "マイプロフィール",
"role_user": "ユーザー"
},
"share": {
"dialogTitle": "共有リンク",
"linkLabel": "共有リンク:",
"copyLink": "コピー",
"permissions": "権限:",
"permissionRead": "読み取り",
"permissionWrite": "書き込み",
"permissionReshare": "再共有",
"password": "パスワード保護:",
"generatePassword": "生成",
"expiration": "有効期限:",
"update": "共有を更新",
"remove": "共有を削除",
"notifyTitle": "通知を送信",
"notifyEmailLabel": "メールアドレス:",
"notifyMessageLabel": "メッセージ(任意):",
"notifySend": "通知を送信",
"shareWithOthers": "他のユーザーと共有",
"sharePublicly": "公開共有",
"shareSettings": "共有設定",
"shareCopied": "リンクがクリップボードにコピーされました",
"shareCreated": "共有リンクが正常に作成されました",
"shareUpdated": "共有設定が正常に更新されました",
"shareRemoved": "共有が正常に削除されました"
},
"share_dialogTitle": "共有リンク",
"share_linkLabel": "共有リンク:",
"share_copyLink": "コピー",
"share_permissions": "権限:",
"share_permissionRead": "読み取り",
"share_permissionWrite": "書き込み",
"share_permissionReshare": "再共有",
"share_password": "パスワード保護:",
"share_generatePassword": "生成",
"share_expiration": "有効期限:",
"share_update": "共有を更新",
"share_remove": "共有を削除",
"share_notifyTitle": "通知を送信",
"share_notifyEmailLabel": "メールアドレス:",
"share_notifyMessageLabel": "メッセージ(任意):",
"share_notifySend": "通知を送信",
"shared": {
"backToFiles": "ファイルに戻る",
"pageTitle": "共有リソース",
"pageDescription": "共有ファイルとフォルダの管理",
"filterType": "種類:",
"filterAll": "すべて",
"filterFiles": "ファイル",
"filterFolders": "フォルダ",
"sortBy": "並び替え:",
"sortByName": "名前",
"sortByDate": "共有日",
"sortByExpiration": "有効期限",
"search": "検索",
"colName": "名前",
"colType": "種類",
"colDateShared": "共有日",
"colExpiration": "有効期限",
"colPermissions": "権限",
"colPassword": "パスワード",
"colActions": "操作",
"emptyStateTitle": "共有リソースはまだありません",
"emptyStateDesc": "ファイルやフォルダを共有すると、ここに表示されます",
"goToFiles": "ファイルへ移動",
"typeFile": "ファイル",
"typeFolder": "フォルダ",
"noExpiration": "期限なし",
"hasPassword": "あり",
"noPassword": "なし",
"editShare": "共有を編集",
"notifyShare": "通知する",
"copyLink": "リンクをコピー",
"removeShare": "共有を削除",
"linkCopied": "リンクがクリップボードにコピーされました!",
"linkCopyFailed": "リンクのコピーに失敗しました",
"itemUpdated": "共有設定が正常に更新されました",
"itemRemoved": "共有が正常に削除されました",
"invalidEmail": "有効なメールアドレスを入力してください",
"notificationSent": "通知が正常に送信されました",
"notificationFailed": "通知の送信に失敗しました",
"shared_backToFiles": "ファイルに戻る",
"shared_pageTitle": "共有リソース",
"shared_pageDescription": "共有ファイルとフォルダの管理",
"shared_filterType": "種類:",
"shared_filterAll": "すべて",
"shared_filterFiles": "ファイル",
"shared_filterFolders": "フォルダ",
"shared_sortBy": "並び替え:",
"shared_sortByName": "名前",
"shared_sortByDate": "共有日",
"shared_sortByExpiration": "有効期限",
"shared_search": "検索",
"shared_colName": "名前",
"shared_colType": "種類",
"shared_colDateShared": "共有日",
"shared_colExpiration": "有効期限",
"shared_colPermissions": "権限",
"shared_colPassword": "パスワード",
"shared_colActions": "操作",
"shared_emptyStateTitle": "共有リソースはまだありません",
"shared_emptyStateDesc": "ファイルやフォルダを共有すると、ここに表示されます",
"shared_goToFiles": "ファイルへ移動",
"shared_typeFile": "ファイル",
"shared_typeFolder": "フォルダ",
"shared_noExpiration": "期限なし",
"shared_hasPassword": "あり",
"shared_noPassword": "なし",
"shared_editShare": "共有を編集",
"shared_notifyShare": "通知する",
"shared_copyLink": "リンクをコピー",
"shared_removeShare": "共有を削除",
"shared_linkCopied": "リンクがクリップボードにコピーされました!",
"shared_linkCopyFailed": "リンクのコピーに失敗しました",
"shared_itemUpdated": "共有設定が正常に更新されました",
"shared_itemRemoved": "共有が正常に削除されました",
"shared_invalidEmail": "有効なメールアドレスを入力してください",
"shared_notificationSent": "通知が正常に送信されました",
"shared_notificationFailed": "通知の送信に失敗しました"
},
"files": {
"name": "名前",
"type": "種類",
"size": "サイズ",
"modified": "更新日",
"no_files": "このフォルダにファイルはありません",
"empty_hint": "ファイルをアップロードするかフォルダを作成して始めましょう",
"loading": "ファイルを読み込み中…",
"view_grid": "グリッド表示",
"view_list": "リスト表示",
"file_types": {
"document": "ドキュメント",
"image": "画像",
"video": "動画",
"audio": "音声",
"pdf": "PDF",
"text": "テキスト",
"folder": "フォルダ",
"spreadsheet": "スプレッドシート",
"presentation": "プレゼンテーション",
"archive": "アーカイブ",
"installer": "インストーラー",
"code": "コード"
}
},
"dialogs": {
"rename_folder": "フォルダ名を変更",
"rename_file": "ファイル名を変更",
"new_name": "新しい名前",
"new_folder_title": "新しいフォルダ",
"folder_name": "フォルダ名",
"folder_placeholder": "マイフォルダ",
"rename_title": "名前を変更",
"move_file": "ファイルを移動",
"move_folder": "フォルダを移動",
"select_destination": "移動先フォルダを選択:",
"select_this_folder": "このフォルダを選択",
"go_to_parent": ".. (親フォルダ)",
"no_subfolders": "サブフォルダなし",
"root": "ルート",
"delete_confirmation": "本当に削除しますか",
"and_contents": "およびすべての内容",
"no_undo": "この操作は元に戻せません",
"confirm_title": "操作の確認",
"confirm_delete": "ゴミ箱に移動",
"confirm_delete_file": "ファイル「{{name}}」をゴミ箱に移動しますか?",
"confirm_delete_folder": "フォルダ「{{name}}」とそのすべての内容をゴミ箱に移動しますか?",
"confirm_permanent_delete": "完全に削除",
"confirm_permanent_delete_msg": "このアイテムを完全に削除しますか?この操作は元に戻せません。",
"confirm_empty_trash": "ゴミ箱を空にする",
"confirm_delete_share": "共有リンクを削除",
"confirm_delete_share_msg": "この共有リンクを削除しますか?",
"share_file": "ファイルを共有",
"existing_shares": "既存の共有",
"share_options": "共有オプション",
"password": "パスワード",
"expiration": "有効期限",
"permissions": "権限",
"generated_link": "生成されたリンク",
"notify": "通知を送信",
"recipient": "宛先",
"message": "メッセージ"
},
"dropzone": {
"drag_files": "ファイルをここにドラッグするか、クリックして選択",
"drop_files": "ファイルをドロップしてアップロード"
},
"permissions": {
"read": "読み取り",
"write": "書き込み",
"reshare": "再共有"
},
"errors": {
"file_not_found": "ファイルが見つかりません",
"folder_not_found": "フォルダが見つかりません",
"delete_error": "削除エラー",
"upload_error": "ファイルのアップロードエラー",
"rename_error": "名前変更エラー",
"move_error": "移動エラー",
"empty_name": "名前を空にすることはできません",
"name_exists": "同じ名前のファイルまたはフォルダが既に存在します",
"generic_error": "エラーが発生しました"
},
"breadcrumb": {
"home": "ホーム"
},
"trash": {
"empty_trash": "ゴミ箱を空にする",
"empty_state": "ゴミ箱は空です",
"original_location": "元の場所",
"deleted_date": "削除日",
"actions": "操作",
"restore": "復元",
"delete_permanently": "完全に削除",
"empty_confirm": "ゴミ箱を空にしますか?すべてのアイテムが完全に削除されます。"
},
"auth": {
"login_title": "サインイン",
"username": "ユーザー名",
"username_placeholder": "ユーザー名を入力",
"password": "パスワード",
"password_placeholder": "パスワードを入力",
"login_button": "サインイン",
"no_account": "アカウントをお持ちでないですか?",
"register": "登録",
"admin_setup": "初回ですか?",
"setup": "管理者をセットアップ",
"register_title": "アカウント作成",
"email": "メール",
"email_placeholder": "メールアドレスを入力",
"confirm_password": "パスワードの確認",
"confirm_password_placeholder": "パスワードを再入力",
"register_button": "アカウント作成",
"have_account": "既にアカウントをお持ちですか?",
"login": "サインイン",
"setup_title": "初期設定",
"setup_step1": "管理者",
"setup_step2": "システム",
"setup_step3": "完了",
"admin_username": "管理者ユーザー名",
"admin_email": "管理者メール",
"admin_password": "管理者パスワード",
"create_admin": "管理者を作成",
"back_to_login": "設定済みですか?",
"admin_success": "管理者アカウントが正常に作成されました!サインインできます。",
"account_success": "アカウントが正常に作成されました!サインインできます。",
"passwords_mismatch": "パスワードが一致しません",
"admin_create_error": "管理者アカウントの作成エラー",
"or": "または",
"sso_login": "SSOでサインイン",
"sso_login_provider": "{{provider}}でサインイン"
},
"storage": {
"title": "ストレージ",
"calculating": "計算中...",
"used": "{{percentage}}% 使用中 ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "このファイル形式はプレビューできません。",
"download_file": "ファイルをダウンロード",
"zoom_in": "拡大",
"zoom_out": "縮小",
"zoom_reset": "ズームリセット"
},
"language_selector": {
"title": "ようこそ!",
"subtitle": "続行するには言語を選択してください",
"continue": "続行",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português",
"ja": "日本語"
}
},
"favorites": {
"empty_state": "お気に入りはまだありません",
"empty_hint": "ファイルやフォルダにスターを付けてお気に入りに追加",
"add": "お気に入りに追加",
"remove": "お気に入りから削除",
"added_title": "お気に入りに追加しました",
"added_msg": "お気に入りに追加しました",
"removed_title": "お気に入りから削除しました",
"removed_msg": "お気に入りから削除しました"
},
"recent": {
"title": "最近",
"clear": "最近をクリア",
"accessed": "アクセス日",
"empty_state": "最近のファイルはありません",
"empty_hint": "開いたファイルがここに表示されます"
},
"notifications": {
"file_renamed": "ファイル名を変更しました",
"file_renamed_to": "ファイル名を「{{name}}」に変更しました",
"folder_renamed": "フォルダ名を変更しました",
"folder_renamed_to": "フォルダ名を「{{name}}」に変更しました",
"file_uploaded": "ファイルをアップロードしました",
"file_deleted": "ファイルをゴミ箱に移動しました",
"folder_deleted": "フォルダをゴミ箱に移動しました",
"item_deleted_permanently": "アイテムを完全に削除しました",
"trash_emptied": "ゴミ箱を正常に空にしました",
"title": "通知",
"empty": "通知はありません"
},
"batch": {
"one_selected": "1件選択中",
"n_selected": "{{count}}件選択中",
"confirm_delete": "{{count}}件のアイテムをゴミ箱に移動しますか?",
"move_title": "{{count}}件のアイテムを移動",
"add_favorites": "お気に入りに追加",
"move_copy": "移動またはコピー"
},
"admin": {
"page_title": "管理パネル",
"back_to_app": "OxiCloudに戻る",
"loading": "読み込み中…",
"access_denied": "アクセス拒否",
"access_denied_desc": "管理者権限が必要です。",
"sign_in": "サインイン",
"tab_dashboard": "ダッシュボード",
"tab_users": "ユーザー",
"tab_oidc": "SSO / OIDC",
"total_users": "総ユーザー数",
"active_users": "アクティブ",
"admins": "管理者",
"version": "バージョン",
"storage_overview": "ストレージ概要",
"used": "使用済み",
"total_quota": "合計クォータ",
"usage_pct": "使用率",
"users_over_80": "クォータ80%超",
"users_over_quota": "クォータ超過",
"system": "システム",
"auth_label": "認証",
"oidc_label": "OIDC",
"quotas_label": "クォータ",
"enabled": "有効",
"disabled": "無効",
"active": "アクティブ",
"off": "オフ",
"allow_registration": "公開セルフ登録を許可",
"registration_warning": "公開登録は無効です。管理者のみがユーザーを作成できます。",
"user_management": "ユーザー管理",
"create_user": "ユーザー作成",
"col_user": "ユーザー",
"col_role": "役割",
"col_auth": "認証",
"col_status": "ステータス",
"col_storage": "ストレージ",
"col_last_login": "最終ログイン",
"col_actions": "操作",
"loading_users": "ユーザーを読み込み中…",
"failed_load_users": "読み込み失敗",
"no_users_found": "ユーザーなし",
"showing_users": "{{from}}-{{to}} / {{total}} を表示",
"prev": "前へ",
"next": "次へ",
"inactive": "非アクティブ",
"you_badge": "(あなた)",
"local": "ローカル",
"never": "未ログイン",
"just_now": "たった今",
"minutes_ago": "{{n}}分前",
"hours_ago": "{{n}}時間前",
"days_ago": "{{n}}日前",
"edit_quota_title": "クォータを編集",
"reset_password_title": "パスワードリセット",
"toggle_role_title": "役割を切替",
"deactivate_title": "無効化",
"activate_title": "有効化",
"delete_title": "削除",
"sso_title": "シングルサインオン (OIDC / SSO)",
"enable_sso": "SSO認証を有効化",
"provider_name": "プロバイダー名",
"issuer_url": "発行者URL",
"issuer_url_hint": "OpenID Connect発行者URL",
"auto_discover": "自動検出",
"discovering": "検出中…",
"client_id": "クライアントID",
"client_secret": "クライアントシークレット",
"client_secret_placeholder": "現在の値を維持するには空に",
"secret_configured": "クライアントシークレット設定済み",
"callback_url": "コールバックURL",
"callback_url_hint": "(IdPに登録)",
"advanced_settings": "詳細設定",
"scopes": "スコープ",
"auto_provision": "初回ログイン時に自動プロビジョニング",
"admin_groups": "管理者グループ",
"admin_groups_hint": "カンマ区切りのOIDCグループ名",
"disable_password": "パスワードログイン無効化(OIDCのみ)",
"password_warning": "すべてのパスワードログインが無効に!",
"test_btn": "テスト",
"save_btn": "保存",
"saving": "保存中…",
"settings_saved": "設定が保存されました — OIDC: {{status}}",
"quota_modal_title": "ストレージクォータ更新",
"quota_user_label": "ユーザー:",
"new_quota": "新しいクォータ",
"quota_unlimited_hint": "0で無制限",
"cancel": "キャンセル",
"create_user_title": "新規ユーザー作成",
"username_label": "ユーザー名",
"username_placeholder": "taro",
"username_hint": "3〜32文字",
"password_label": "パスワード",
"password_placeholder": "8文字以上",
"email_label": "メール",
"email_optional": "(任意)",
"email_placeholder": "user@example.com(空なら自動生成)",
"role_label": "役割",
"role_user": "ユーザー",
"role_admin": "管理者",
"quota_label": "クォータ",
"creating": "作成中…",
"reset_pw_title": "パスワードリセット",
"new_password_label": "新しいパスワード",
"resetting": "リセット中…",
"reset_btn": "リセット",
"confirm_role_change": "役割を{{role}}に変更?",
"confirm_deactivate": "このユーザーを無効化しますか?",
"confirm_activate": "このユーザーを有効化しますか?",
"confirm_delete_user": "ユーザー「{{name}}」を削除?取り消せません!",
"confirm_action": "操作の確認",
"confirm_yes": "確認",
"confirm_no": "キャンセル",
"error_username_short": "ユーザー名は3文字以上",
"error_password_short": "パスワードは8文字以上",
"error_generic": "失敗",
"error_network": "ネットワークエラー: {{message}}",
"error_create_user": "ユーザー作成失敗"
},
"profile": {
"page_title": "プロフィール",
"back_to_app": "OxiCloudに戻る",
"loading": "読み込み中…",
"not_authenticated": "未認証",
"not_authenticated_desc": "プロフィールを表示するにはサインインしてください。",
"sign_in": "サインイン",
"role_admin": "管理者",
"role_user": "ユーザー",
"account_details": "アカウント詳細",
"username": "ユーザー名",
"email": "メール",
"role": "役割",
"last_login": "最終ログイン",
"storage": "ストレージ",
"used": "使用済み",
"quota": "クォータ",
"usage": "使用率",
"unlimited": "無制限",
"app_passwords": "アプリパスワード",
"app_pw_desc": "WebDAV、CalDAV、CardDAVクライアント用のパスワードを生成します。各パスワードは一度だけ表示されます。",
"app_pw_label_placeholder": "ラベル(例:Thunderbird、macOS)",
"generate": "生成",
"generating": "生成中…",
"new_password_for": "新しいパスワード:",
"copy_warning": "このパスワードを今コピーしてください。再度表示できません。",
"copy_to_clipboard": "クリップボードにコピー",
"col_label": "ラベル",
"col_created": "作成日",
"col_last_used": "最終使用",
"col_status": "ステータス",
"active": "アクティブ",
"revoked": "失効済み",
"revoke_title": "失効",
"no_app_passwords": "アプリパスワードはまだありません。",
"client_sessions": "クライアントセッション",
"client_sessions_desc": "Nextcloud互換クライアント接続時に自動生成されます。",
"col_client": "クライアント",
"never": "未ログイン",
"just_now": "たった今",
"minutes_ago": "{{n}}分前",
"hours_ago": "{{n}}時間前",
"days_ago": "{{n}}日前",
"change_password": "パスワード変更",
"current_password": "現在のパスワード",
"new_password": "新しいパスワード",
"min_8_chars": "8文字以上",
"confirm_password": "新しいパスワードの確認",
"update_password": "パスワードを更新",
"updating": "更新中…",
"password_updated": "パスワードが正常に更新されました",
"passwords_no_match": "パスワードが一致しません",
"password_too_short": "パスワードは8文字以上必要です",
"password_change_failed": "パスワードの変更に失敗しました",
"error_network": "ネットワークエラー: {{message}}",
"error_label_required": "ラベルを入力してください",
"error_create_pw": "アプリパスワードの作成に失敗しました",
"confirm_revoke": "アプリパスワード「{{label}}」を失効させますか?使用中のクライアントは動作しなくなります。",
"error_revoke": "失効に失敗しました"
}
}
+555
View File
@@ -0,0 +1,555 @@
{
"app": {
"title": "OxiCloud",
"description": "미니멀리스트 클라우드 스토리지 시스템"
},
"nav": {
"files": "파일",
"shared": "공유",
"recent": "최근",
"favorites": "즐겨찾기",
"photos": "사진",
"trash": "휴지통"
},
"photos": {
"empty_state": "아직 사진이 없습니다",
"empty_hint": "이미지나 동영상을 업로드하면 여기에 표시됩니다",
"items_selected": "개 선택됨",
"view_daily": "일",
"view_monthly": "월",
"view_yearly": "년"
},
"actions": {
"search": "파일 검색...",
"new_folder": "새 폴더",
"upload": "업로드",
"upload_files": "파일 업로드",
"upload_folder": "폴더 업로드",
"upload.uploading": "업로드 중...",
"upload.complete": "{count} / {total} 업로드 완료",
"rename": "이름 변경",
"move": "이동...",
"move_to": "이동 대상",
"delete": "삭제",
"download": "다운로드",
"view": "보기",
"cancel": "취소",
"confirm": "확인",
"share": "공유",
"favorite": "즐겨찾기 추가",
"unfavorite": "즐겨찾기 해제",
"copy": "복사",
"notify": "알림",
"send": "보내기",
"clear_recent": "최근 항목 지우기",
"logout": "로그아웃",
"create": "만들기",
"search_btn": "검색",
"close": "닫기",
"delete_permanently": "영구 삭제",
"empty_trash": "휴지통 비우기"
},
"user_menu": {
"appearance": "외관",
"about": "OxiCloud 정보",
"about_description": "Rust와 Clean Architecture로 구축된 클라우드 스토리지 플랫폼. 빠르고, 안전하고, 프라이빗합니다.",
"admin_panel": "관리자 패널",
"profile": "내 프로필",
"role_user": "사용자"
},
"share": {
"dialogTitle": "공유 링크",
"linkLabel": "공유 링크:",
"copyLink": "복사",
"permissions": "권한:",
"permissionRead": "읽기",
"permissionWrite": "쓰기",
"permissionReshare": "재공유",
"password": "비밀번호 보호:",
"generatePassword": "생성",
"expiration": "만료일:",
"update": "공유 업데이트",
"remove": "공유 삭제",
"notifyTitle": "알림 보내기",
"notifyEmailLabel": "이메일 주소:",
"notifyMessageLabel": "메시지 (선택사항):",
"notifySend": "알림 보내기",
"shareWithOthers": "다른 사용자와 공유",
"sharePublicly": "공개 공유",
"shareSettings": "공유 설정",
"shareCopied": "링크가 클립보드에 복사되었습니다",
"shareCreated": "공유 링크가 성공적으로 생성되었습니다",
"shareUpdated": "공유 설정이 성공적으로 업데이트되었습니다",
"shareRemoved": "공유가 성공적으로 삭제되었습니다"
},
"share_dialogTitle": "공유 링크",
"share_linkLabel": "공유 링크:",
"share_copyLink": "복사",
"share_permissions": "권한:",
"share_permissionRead": "읽기",
"share_permissionWrite": "쓰기",
"share_permissionReshare": "재공유",
"share_password": "비밀번호 보호:",
"share_generatePassword": "생성",
"share_expiration": "만료일:",
"share_update": "공유 업데이트",
"share_remove": "공유 삭제",
"share_notifyTitle": "알림 보내기",
"share_notifyEmailLabel": "이메일 주소:",
"share_notifyMessageLabel": "메시지 (선택사항):",
"share_notifySend": "알림 보내기",
"shared": {
"backToFiles": "파일로 돌아가기",
"pageTitle": "공유 리소스",
"pageDescription": "공유 파일 및 폴더 관리",
"filterType": "유형:",
"filterAll": "전체",
"filterFiles": "파일",
"filterFolders": "폴더",
"sortBy": "정렬:",
"sortByName": "이름",
"sortByDate": "공유일",
"sortByExpiration": "만료일",
"search": "검색",
"colName": "이름",
"colType": "유형",
"colDateShared": "공유일",
"colExpiration": "만료일",
"colPermissions": "권한",
"colPassword": "비밀번호",
"colActions": "작업",
"emptyStateTitle": "아직 공유된 리소스가 없습니다",
"emptyStateDesc": "파일이나 폴더를 공유하면 여기에 표시됩니다",
"goToFiles": "파일로 이동",
"typeFile": "파일",
"typeFolder": "폴더",
"noExpiration": "만료 없음",
"hasPassword": "있음",
"noPassword": "없음",
"editShare": "공유 편집",
"notifyShare": "알림",
"copyLink": "링크 복사",
"removeShare": "공유 삭제",
"linkCopied": "링크가 클립보드에 복사되었습니다!",
"linkCopyFailed": "링크 복사에 실패했습니다",
"itemUpdated": "공유 설정이 성공적으로 업데이트되었습니다",
"itemRemoved": "공유가 성공적으로 삭제되었습니다",
"invalidEmail": "유효한 이메일 주소를 입력하세요",
"notificationSent": "알림이 성공적으로 전송되었습니다",
"notificationFailed": "알림 전송에 실패했습니다",
"shared_backToFiles": "파일로 돌아가기",
"shared_pageTitle": "공유 리소스",
"shared_pageDescription": "공유 파일 및 폴더 관리",
"shared_filterType": "유형:",
"shared_filterAll": "전체",
"shared_filterFiles": "파일",
"shared_filterFolders": "폴더",
"shared_sortBy": "정렬:",
"shared_sortByName": "이름",
"shared_sortByDate": "공유일",
"shared_sortByExpiration": "만료일",
"shared_search": "검색",
"shared_colName": "이름",
"shared_colType": "유형",
"shared_colDateShared": "공유일",
"shared_colExpiration": "만료일",
"shared_colPermissions": "권한",
"shared_colPassword": "비밀번호",
"shared_colActions": "작업",
"shared_emptyStateTitle": "아직 공유된 리소스가 없습니다",
"shared_emptyStateDesc": "파일이나 폴더를 공유하면 여기에 표시됩니다",
"shared_goToFiles": "파일로 이동",
"shared_typeFile": "파일",
"shared_typeFolder": "폴더",
"shared_noExpiration": "만료 없음",
"shared_hasPassword": "있음",
"shared_noPassword": "없음",
"shared_editShare": "공유 편집",
"shared_notifyShare": "알림",
"shared_copyLink": "링크 복사",
"shared_removeShare": "공유 삭제",
"shared_linkCopied": "링크가 클립보드에 복사되었습니다!",
"shared_linkCopyFailed": "링크 복사에 실패했습니다",
"shared_itemUpdated": "공유 설정이 성공적으로 업데이트되었습니다",
"shared_itemRemoved": "공유가 성공적으로 삭제되었습니다",
"shared_invalidEmail": "유효한 이메일 주소를 입력하세요",
"shared_notificationSent": "알림이 성공적으로 전송되었습니다",
"shared_notificationFailed": "알림 전송에 실패했습니다"
},
"files": {
"name": "이름",
"type": "유형",
"size": "크기",
"modified": "수정일",
"no_files": "이 폴더에 파일이 없습니다",
"empty_hint": "파일을 업로드하거나 폴더를 만들어 시작하세요",
"loading": "파일 로딩 중…",
"view_grid": "그리드 보기",
"view_list": "목록 보기",
"file_types": {
"document": "문서",
"image": "이미지",
"video": "동영상",
"audio": "오디오",
"pdf": "PDF",
"text": "텍스트",
"folder": "폴더",
"spreadsheet": "스프레드시트",
"presentation": "프레젠테이션",
"archive": "아카이브",
"installer": "설치 프로그램",
"code": "코드"
}
},
"dialogs": {
"rename_folder": "폴더 이름 변경",
"rename_file": "파일 이름 변경",
"new_name": "새 이름",
"new_folder_title": "새 폴더",
"folder_name": "폴더 이름",
"folder_placeholder": "내 폴더",
"rename_title": "이름 변경",
"move_file": "파일 이동",
"move_folder": "폴더 이동",
"select_destination": "대상 폴더를 선택하세요:",
"select_this_folder": "이 폴더 선택",
"go_to_parent": ".. (상위 폴더)",
"no_subfolders": "하위 폴더 없음",
"root": "루트",
"delete_confirmation": "정말 삭제하시겠습니까",
"and_contents": "및 모든 내용",
"no_undo": "이 작업은 되돌릴 수 없습니다",
"confirm_title": "작업 확인",
"confirm_delete": "휴지통으로 이동",
"confirm_delete_file": "파일 «{{name}}»을(를) 휴지통으로 이동하시겠습니까?",
"confirm_delete_folder": "폴더 «{{name}}» 및 모든 내용을 휴지통으로 이동하시겠습니까?",
"confirm_permanent_delete": "영구 삭제",
"confirm_permanent_delete_msg": "이 항목을 영구적으로 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
"confirm_empty_trash": "휴지통 비우기",
"confirm_delete_share": "공유 링크 삭제",
"confirm_delete_share_msg": "이 공유 링크를 삭제하시겠습니까?",
"share_file": "파일 공유",
"existing_shares": "기존 공유",
"share_options": "공유 옵션",
"password": "비밀번호",
"expiration": "만료일",
"permissions": "권한",
"generated_link": "생성된 링크",
"notify": "알림 보내기",
"recipient": "수신자",
"message": "메시지"
},
"dropzone": {
"drag_files": "여기에 파일을 드래그하거나 클릭하여 선택하세요",
"drop_files": "파일을 놓아 업로드하세요"
},
"permissions": {
"read": "읽기",
"write": "쓰기",
"reshare": "재공유"
},
"errors": {
"file_not_found": "파일을 찾을 수 없습니다",
"folder_not_found": "폴더를 찾을 수 없습니다",
"delete_error": "삭제 오류",
"upload_error": "파일 업로드 오류",
"rename_error": "이름 변경 오류",
"move_error": "이동 오류",
"empty_name": "이름은 비워둘 수 없습니다",
"name_exists": "같은 이름의 파일 또는 폴더가 이미 존재합니다",
"generic_error": "오류가 발생했습니다"
},
"breadcrumb": {
"home": "홈"
},
"trash": {
"empty_trash": "휴지통 비우기",
"empty_state": "휴지통이 비어 있습니다",
"original_location": "원래 위치",
"deleted_date": "삭제일",
"actions": "작업",
"restore": "복원",
"delete_permanently": "영구 삭제",
"empty_confirm": "휴지통을 비우시겠습니까? 모든 항목이 영구적으로 삭제됩니다."
},
"auth": {
"login_title": "로그인",
"username": "사용자 이름",
"username_placeholder": "사용자 이름을 입력하세요",
"password": "비밀번호",
"password_placeholder": "비밀번호를 입력하세요",
"login_button": "로그인",
"no_account": "계정이 없으신가요?",
"register": "가입하기",
"admin_setup": "처음이신가요?",
"setup": "관리자 설정",
"register_title": "계정 만들기",
"email": "이메일",
"email_placeholder": "이메일 주소를 입력하세요",
"confirm_password": "비밀번호 확인",
"confirm_password_placeholder": "비밀번호를 다시 입력하세요",
"register_button": "계정 만들기",
"have_account": "이미 계정이 있으신가요?",
"login": "로그인",
"setup_title": "초기 설정",
"setup_step1": "관리자",
"setup_step2": "시스템",
"setup_step3": "완료",
"admin_username": "관리자 사용자 이름",
"admin_email": "관리자 이메일",
"admin_password": "관리자 비밀번호",
"create_admin": "관리자 생성",
"back_to_login": "이미 설정하셨나요?",
"admin_success": "관리자 계정이 성공적으로 생성되었습니다! 로그인할 수 있습니다.",
"account_success": "계정이 성공적으로 생성되었습니다! 로그인할 수 있습니다.",
"passwords_mismatch": "비밀번호가 일치하지 않습니다",
"admin_create_error": "관리자 계정 생성 오류",
"or": "또는",
"sso_login": "SSO로 로그인",
"sso_login_provider": "{{provider}}(으)로 로그인"
},
"storage": {
"title": "저장소",
"calculating": "계산 중...",
"used": "{{percentage}}% 사용 중 ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "이 파일 형식은 미리보기를 지원하지 않습니다.",
"download_file": "파일 다운로드",
"zoom_in": "확대",
"zoom_out": "축소",
"zoom_reset": "줌 초기화"
},
"language_selector": {
"title": "환영합니다!",
"subtitle": "계속하려면 언어를 선택하세요",
"continue": "계속",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português",
"ko": "한국어"
}
},
"favorites": {
"empty_state": "아직 즐겨찾기가 없습니다",
"empty_hint": "파일이나 폴더에 별표를 눌러 즐겨찾기에 추가하세요",
"add": "즐겨찾기 추가",
"remove": "즐겨찾기 해제",
"added_title": "즐겨찾기에 추가됨",
"added_msg": "즐겨찾기에 추가되었습니다",
"removed_title": "즐겨찾기에서 삭제됨",
"removed_msg": "즐겨찾기에서 삭제되었습니다"
},
"recent": {
"title": "최근",
"clear": "최근 항목 지우기",
"accessed": "접근일",
"empty_state": "최근 파일이 없습니다",
"empty_hint": "열어본 파일이 여기에 표시됩니다"
},
"notifications": {
"file_renamed": "파일 이름이 변경되었습니다",
"file_renamed_to": "파일 이름이 «{{name}}»(으)로 변경되었습니다",
"folder_renamed": "폴더 이름이 변경되었습니다",
"folder_renamed_to": "폴더 이름이 «{{name}}»(으)로 변경되었습니다",
"file_uploaded": "파일이 업로드되었습니다",
"file_deleted": "파일이 휴지통으로 이동되었습니다",
"folder_deleted": "폴더가 휴지통으로 이동되었습니다",
"item_deleted_permanently": "항목이 영구적으로 삭제되었습니다",
"trash_emptied": "휴지통이 성공적으로 비워졌습니다",
"title": "알림",
"empty": "알림이 없습니다"
},
"batch": {
"one_selected": "1개 선택됨",
"n_selected": "{{count}}개 선택됨",
"confirm_delete": "{{count}}개 항목을 휴지통으로 이동하시겠습니까?",
"move_title": "{{count}}개 항목 이동",
"add_favorites": "즐겨찾기에 추가",
"move_copy": "이동 또는 복사"
},
"admin": {
"page_title": "관리자 패널",
"back_to_app": "OxiCloud로 돌아가기",
"loading": "로딩 중…",
"access_denied": "접근 거부",
"access_denied_desc": "관리자 권한이 필요합니다.",
"sign_in": "로그인",
"tab_dashboard": "대시보드",
"tab_users": "사용자",
"tab_oidc": "SSO / OIDC",
"total_users": "전체 사용자",
"active_users": "활성 사용자",
"admins": "관리자",
"version": "버전",
"storage_overview": "스토리지 개요",
"used": "사용됨",
"total_quota": "총 할당량",
"usage_pct": "사용률",
"users_over_80": "할당량 80% 초과",
"users_over_quota": "할당량 초과",
"system": "시스템",
"auth_label": "인증",
"oidc_label": "OIDC",
"quotas_label": "할당량",
"enabled": "활성화됨",
"disabled": "비활성화됨",
"active": "활성",
"off": "꺼짐",
"allow_registration": "공개 자가 등록 허용",
"registration_warning": "공개 등록이 비활성화되어 있습니다. 관리자만 사용자를 만들 수 있습니다.",
"user_management": "사용자 관리",
"create_user": "사용자 생성",
"col_user": "사용자",
"col_role": "역할",
"col_auth": "인증",
"col_status": "상태",
"col_storage": "스토리지",
"col_last_login": "마지막 로그인",
"col_actions": "작업",
"loading_users": "사용자 로딩 중…",
"failed_load_users": "로드 실패",
"no_users_found": "사용자 없음",
"showing_users": "{{from}}-{{to}} / {{total}} 표시",
"prev": "이전",
"next": "다음",
"inactive": "비활성",
"you_badge": "(나)",
"local": "로컬",
"never": "없음",
"just_now": "방금",
"minutes_ago": "{{n}}분 전",
"hours_ago": "{{n}}시간 전",
"days_ago": "{{n}}일 전",
"edit_quota_title": "할당량 편집",
"reset_password_title": "비밀번호 재설정",
"toggle_role_title": "역할 전환",
"deactivate_title": "비활성화",
"activate_title": "활성화",
"delete_title": "삭제",
"sso_title": "싱글 사인온 (OIDC / SSO)",
"enable_sso": "SSO 인증 활성화",
"provider_name": "제공자 이름",
"issuer_url": "발급자 URL",
"issuer_url_hint": "OpenID Connect 발급자 URL",
"auto_discover": "자동 검색",
"discovering": "검색 중…",
"client_id": "클라이언트 ID",
"client_secret": "클라이언트 시크릿",
"client_secret_placeholder": "현재 값 유지하려면 비워두세요",
"secret_configured": "클라이언트 시크릿 구성됨",
"callback_url": "콜백 URL",
"callback_url_hint": "(IdP에 등록)",
"advanced_settings": "고급 설정",
"scopes": "스코프",
"auto_provision": "첫 로그인 시 자동 프로비저닝",
"admin_groups": "관리자 그룹",
"admin_groups_hint": "쉼표로 구분된 OIDC 그룹 이름",
"disable_password": "비밀번호 로그인 비활성화 (OIDC만)",
"password_warning": "모든 비밀번호 로그인이 차단됩니다!",
"test_btn": "테스트",
"save_btn": "저장",
"saving": "저장 중…",
"settings_saved": "설정 저장됨 — OIDC: {{status}}",
"quota_modal_title": "스토리지 할당량 업데이트",
"quota_user_label": "사용자:",
"new_quota": "새 할당량",
"quota_unlimited_hint": "무제한은 0",
"cancel": "취소",
"create_user_title": "새 사용자 생성",
"username_label": "사용자 이름",
"username_placeholder": "username",
"username_hint": "3–32자",
"password_label": "비밀번호",
"password_placeholder": "최소 8자",
"email_label": "이메일",
"email_optional": "(선택사항)",
"email_placeholder": "user@example.com (비어있으면 자동 생성)",
"role_label": "역할",
"role_user": "사용자",
"role_admin": "관리자",
"quota_label": "할당량",
"creating": "생성 중…",
"reset_pw_title": "비밀번호 재설정",
"new_password_label": "새 비밀번호",
"resetting": "재설정 중…",
"reset_btn": "재설정",
"confirm_role_change": "역할을 {{role}}(으)로 변경?",
"confirm_deactivate": "이 사용자를 비활성화하시겠습니까?",
"confirm_activate": "이 사용자를 활성화하시겠습니까?",
"confirm_delete_user": "사용자 \"{{name}}\" 삭제? 되돌릴 수 없습니다!",
"confirm_action": "작업 확인",
"confirm_yes": "확인",
"confirm_no": "취소",
"error_username_short": "사용자 이름 최소 3자",
"error_password_short": "비밀번호 최소 8자",
"error_generic": "실패",
"error_network": "네트워크 오류: {{message}}",
"error_create_user": "사용자 생성 실패"
},
"profile": {
"page_title": "프로필",
"back_to_app": "OxiCloud로 돌아가기",
"loading": "로딩 중…",
"not_authenticated": "인증되지 않음",
"not_authenticated_desc": "프로필을 보려면 로그인하세요.",
"sign_in": "로그인",
"role_admin": "관리자",
"role_user": "사용자",
"account_details": "계정 정보",
"username": "사용자 이름",
"email": "이메일",
"role": "역할",
"last_login": "마지막 로그인",
"storage": "스토리지",
"used": "사용됨",
"quota": "할당량",
"usage": "사용률",
"unlimited": "무제한",
"app_passwords": "앱 비밀번호",
"app_pw_desc": "WebDAV, CalDAV, CardDAV 클라이언트용 비밀번호를 생성합니다. 각 비밀번호는 한 번만 표시됩니다.",
"app_pw_label_placeholder": "라벨 (예: Thunderbird, macOS)",
"generate": "생성",
"generating": "생성 중…",
"new_password_for": "새 비밀번호:",
"copy_warning": "지금 이 비밀번호를 복사하세요. 다시 볼 수 없습니다.",
"copy_to_clipboard": "클립보드에 복사",
"col_label": "라벨",
"col_created": "생성일",
"col_last_used": "마지막 사용",
"col_status": "상태",
"active": "활성",
"revoked": "취소됨",
"revoke_title": "취소",
"no_app_passwords": "앱 비밀번호가 아직 없습니다.",
"client_sessions": "클라이언트 세션",
"client_sessions_desc": "Nextcloud 호환 클라이언트 연결 시 자동 생성됩니다.",
"col_client": "클라이언트",
"never": "없음",
"just_now": "방금",
"minutes_ago": "{{n}}분 전",
"hours_ago": "{{n}}시간 전",
"days_ago": "{{n}}일 전",
"change_password": "비밀번호 변경",
"current_password": "현재 비밀번호",
"new_password": "새 비밀번호",
"min_8_chars": "최소 8자",
"confirm_password": "새 비밀번호 확인",
"update_password": "비밀번호 업데이트",
"updating": "업데이트 중…",
"password_updated": "비밀번호가 성공적으로 업데이트되었습니다",
"passwords_no_match": "비밀번호가 일치하지 않습니다",
"password_too_short": "비밀번호는 최소 8자여야 합니다",
"password_change_failed": "비밀번호 변경 실패",
"error_network": "네트워크 오류: {{message}}",
"error_label_required": "라벨을 입력하세요",
"error_create_pw": "앱 비밀번호 생성 실패",
"confirm_revoke": "앱 비밀번호 \"{{label}}\"을(를) 취소하시겠습니까? 이 비밀번호를 사용하는 클라이언트가 작동하지 않게 됩니다.",
"error_revoke": "취소 실패"
}
}
+183 -3
View File
@@ -96,7 +96,7 @@
"share_remove": "Share verwijderen",
"share_notifyTitle": "Notificatie verzenden",
"share_notifyEmailLabel": "E-mailadres:",
"share_notifyMessageLabel": "Bericht (optioneel):",
"share_notifyMessageLabel": "Bericht (optioneel):",
"share_notifySend": "Notificatie verzenden",
"shared": {
"backToFiles": "Terug naar Bestanden",
@@ -182,6 +182,7 @@
"size": "Grootte",
"modified": "Gewijzigd",
"no_files": "Geen bestanden in deze map",
"empty_hint": "Upload bestanden of maak mappen aan om te beginnen",
"loading": "Bestanden laden…",
"view_grid": "Rasterweergave",
"view_list": "Lijstweergave",
@@ -317,8 +318,8 @@
"zoom_reset": "Zoom terugzetten"
},
"language_selector": {
"title": "Welkom bij OxiCloud",
"subtitle": "Selecteer je taal",
"title": "Welkom!",
"subtitle": "Selecteer je taal om door te gaan",
"continue": "Doorgaan",
"languages": {
"en": "English",
@@ -367,5 +368,184 @@
"move_title": "Verplaats {count} item(s)",
"add_favorites": "Toevoegen aan favorieten",
"move_copy": "Verplaatsen of kopiëren"
},
"admin": {
"page_title": "Beheerderspaneel",
"back_to_app": "Terug naar OxiCloud",
"loading": "Laden…",
"access_denied": "Toegang geweigerd",
"access_denied_desc": "Beheerdersrechten vereist.",
"sign_in": "Inloggen",
"tab_dashboard": "Dashboard",
"tab_users": "Gebruikers",
"tab_oidc": "SSO / OIDC",
"total_users": "Totaal gebruikers",
"active_users": "Actieve gebruikers",
"admins": "Beheerders",
"version": "Versie",
"storage_overview": "Opslagoverzicht",
"used": "Gebruikt",
"total_quota": "Totaal quotum",
"usage_pct": "Gebruik %",
"users_over_80": "Gebruikers >80% quotum",
"users_over_quota": "Gebruikers boven quotum",
"system": "Systeem",
"auth_label": "Auth",
"oidc_label": "OIDC",
"quotas_label": "Quota",
"enabled": "Ingeschakeld",
"disabled": "Uitgeschakeld",
"active": "Actief",
"off": "Uit",
"allow_registration": "Openbare zelfregistratie toestaan",
"registration_warning": "Openbare registratie is uitgeschakeld. Alleen beheerders kunnen gebruikers aanmaken.",
"user_management": "Gebruikersbeheer",
"create_user": "Gebruiker aanmaken",
"col_user": "Gebruiker",
"col_role": "Rol",
"col_auth": "Auth",
"col_status": "Status",
"col_storage": "Opslag",
"col_last_login": "Laatste login",
"col_actions": "Acties",
"loading_users": "Gebruikers laden…",
"failed_load_users": "Laden mislukt",
"no_users_found": "Geen gebruikers gevonden",
"showing_users": "Toont {{from}}-{{to}} van {{total}}",
"prev": "Vorige",
"next": "Volgende",
"inactive": "Inactief",
"you_badge": "(jij)",
"local": "Lokaal",
"never": "Nooit",
"just_now": "Zojuist",
"minutes_ago": "{{n}}min geleden",
"hours_ago": "{{n}}u geleden",
"days_ago": "{{n}}d geleden",
"edit_quota_title": "Quotum bewerken",
"reset_password_title": "Wachtwoord resetten",
"toggle_role_title": "Rol wisselen",
"deactivate_title": "Deactiveren",
"activate_title": "Activeren",
"delete_title": "Verwijderen",
"sso_title": "Single Sign-On (OIDC / SSO)",
"enable_sso": "SSO-authenticatie inschakelen",
"provider_name": "Providernaam",
"issuer_url": "Uitgever-URL",
"issuer_url_hint": "OpenID Connect uitgever-URL",
"auto_discover": "Auto-ontdekking",
"discovering": "Ontdekken…",
"client_id": "Client-ID",
"client_secret": "Client-secret",
"client_secret_placeholder": "Laat leeg om huidige waarde te behouden",
"secret_configured": "Een client-secret is al geconfigureerd",
"callback_url": "Callback-URL",
"callback_url_hint": "(registreer bij uw IdP)",
"advanced_settings": "Geavanceerde instellingen",
"scopes": "Scopes",
"auto_provision": "Gebruikers automatisch aanmaken bij eerste login",
"admin_groups": "Beheergroepen",
"admin_groups_hint": "Kommagescheiden OIDC-groepsnamen",
"disable_password": "Wachtwoord-login uitschakelen (alleen OIDC)",
"password_warning": "Dit voorkomt ALLE logins op basis van wachtwoord!",
"test_btn": "Testen",
"save_btn": "Opslaan",
"saving": "Opslaan…",
"settings_saved": "Instellingen opgeslagen — OIDC is nu {{status}}",
"quota_modal_title": "Opslagquotum bijwerken",
"quota_user_label": "Gebruiker:",
"new_quota": "Nieuw quotum",
"quota_unlimited_hint": "0 voor onbeperkt",
"cancel": "Annuleren",
"create_user_title": "Nieuwe gebruiker aanmaken",
"username_label": "Gebruikersnaam",
"username_placeholder": "jandevries",
"username_hint": "3–32 tekens",
"password_label": "Wachtwoord",
"password_placeholder": "Min 8 tekens",
"email_label": "E-mail",
"email_optional": "(optioneel)",
"email_placeholder": "gebruiker@voorbeeld.nl (automatisch indien leeg)",
"role_label": "Rol",
"role_user": "Gebruiker",
"role_admin": "Beheerder",
"quota_label": "Quotum",
"creating": "Aanmaken…",
"reset_pw_title": "Wachtwoord resetten",
"new_password_label": "Nieuw wachtwoord",
"resetting": "Resetten…",
"reset_btn": "Resetten",
"confirm_role_change": "Rol wijzigen naar {{role}}?",
"confirm_deactivate": "Weet u zeker dat u deze gebruiker wilt deactiveren?",
"confirm_activate": "Weet u zeker dat u deze gebruiker wilt activeren?",
"confirm_delete_user": "Gebruiker \"{{name}}\" VERWIJDEREN? Kan niet ongedaan worden gemaakt!",
"confirm_action": "Actie bevestigen",
"confirm_yes": "Bevestigen",
"confirm_no": "Annuleren",
"error_username_short": "Gebruikersnaam moet minimaal 3 tekens bevatten",
"error_password_short": "Wachtwoord moet minimaal 8 tekens bevatten",
"error_generic": "Mislukt",
"error_network": "Netwerkfout: {{message}}",
"error_create_user": "Kan gebruiker niet aanmaken"
},
"profile": {
"page_title": "Profiel",
"back_to_app": "Terug naar OxiCloud",
"loading": "Laden…",
"not_authenticated": "Niet geauthenticeerd",
"not_authenticated_desc": "Log in om uw profiel te bekijken.",
"sign_in": "Inloggen",
"role_admin": "Beheerder",
"role_user": "Gebruiker",
"account_details": "Accountgegevens",
"username": "Gebruikersnaam",
"email": "E-mail",
"role": "Rol",
"last_login": "Laatste login",
"storage": "Opslag",
"used": "Gebruikt",
"quota": "Quotum",
"usage": "Gebruik",
"unlimited": "Onbeperkt",
"app_passwords": "App-wachtwoorden",
"app_pw_desc": "Genereer wachtwoorden voor WebDAV-, CalDAV- en CardDAV-clients. Elk wachtwoord wordt slechts één keer getoond.",
"app_pw_label_placeholder": "Label (bijv. Thunderbird, macOS)",
"generate": "Genereren",
"generating": "Genereren…",
"new_password_for": "Nieuw wachtwoord voor",
"copy_warning": "Kopieer dit wachtwoord nu. U kunt het niet opnieuw bekijken.",
"copy_to_clipboard": "Kopiëren naar klembord",
"col_label": "Label",
"col_created": "Aangemaakt",
"col_last_used": "Laatst gebruikt",
"col_status": "Status",
"active": "Actief",
"revoked": "Ingetrokken",
"revoke_title": "Intrekken",
"no_app_passwords": "Nog geen app-wachtwoorden.",
"client_sessions": "Clientsessies",
"client_sessions_desc": "Automatisch gegenereerd bij het verbinden van een Nextcloud-compatibele client.",
"col_client": "Client",
"never": "Nooit",
"just_now": "Zojuist",
"minutes_ago": "{{n}} min geleden",
"hours_ago": "{{n}}u geleden",
"days_ago": "{{n}} dagen geleden",
"change_password": "Wachtwoord wijzigen",
"current_password": "Huidig wachtwoord",
"new_password": "Nieuw wachtwoord",
"min_8_chars": "Minimaal 8 tekens",
"confirm_password": "Bevestig nieuw wachtwoord",
"update_password": "Wachtwoord bijwerken",
"updating": "Bijwerken…",
"password_updated": "Wachtwoord succesvol bijgewerkt",
"passwords_no_match": "Wachtwoorden komen niet overeen",
"password_too_short": "Wachtwoord moet minimaal 8 tekens bevatten",
"password_change_failed": "Wachtwoord wijzigen mislukt",
"error_network": "Netwerkfout: {{message}}",
"error_label_required": "Voer een label in",
"error_create_pw": "App-wachtwoord aanmaken mislukt",
"confirm_revoke": "App-wachtwoord \"{{label}}\" intrekken? Clients die dit wachtwoord gebruiken zullen stoppen.",
"error_revoke": "Intrekken mislukt"
}
}
+549 -369
View File
@@ -1,369 +1,549 @@
{
"app": {
"title": "OxiCloud",
"description": "Sistema de armazenamento em nuvem minimalista"
},
"nav": {
"files": "Arquivos",
"shared": "Compartilhados",
"recent": "Recentes",
"favorites": "Favoritos",
"photos": "Fotos",
"trash": "Lixeira"
},
"photos": {
"empty_state": "Nenhuma foto ainda",
"empty_hint": "Envie imagens ou vídeos para vê-los aqui",
"items_selected": "selecionados",
"view_daily": "Dia",
"view_monthly": "Mês",
"view_yearly": "Ano"
},
"actions": {
"search": "Pesquisar arquivos...",
"new_folder": "Nova pasta",
"upload": "Enviar",
"upload_files": "Enviar arquivos",
"upload_folder": "Enviar pasta",
"upload.uploading": "Enviando...",
"upload.complete": "{count} / {total} enviados",
"rename": "Renomear",
"move": "Mover para...",
"move_to": "Mover para",
"delete": "Excluir",
"download": "Baixar",
"view": "Visualizar",
"cancel": "Cancelar",
"confirm": "Confirmar",
"share": "Compartilhar",
"favorite": "Adicionar aos favoritos",
"unfavorite": "Remover dos favoritos",
"copy": "Copiar",
"notify": "Notificar",
"send": "Enviar",
"clear_recent": "Limpar recentes",
"logout": "Sair",
"create": "Criar",
"search_btn": "Pesquisar",
"close": "Fechar",
"delete_permanently": "Excluir permanentemente",
"empty_trash": "Esvaziar lixeira"
},
"user_menu": {
"appearance": "Aparência",
"about": "Sobre o OxiCloud",
"about_description": "Plataforma de armazenamento em nuvem construída com Rust e Arquitetura Limpa. Rápida, segura e privada.",
"admin_panel": "Painel de administração",
"profile": "Meu perfil",
"role_user": "Usuário"
},
"share": {
"dialogTitle": "Link de compartilhamento",
"linkLabel": "Link compartilhado:",
"copyLink": "Copiar",
"permissions": "Permissões:",
"permissionRead": "Leitura",
"permissionWrite": "Escrita",
"permissionReshare": "Recompartilhar",
"password": "Proteção por senha:",
"generatePassword": "Gerar",
"expiration": "Data de expiração:",
"update": "Atualizar compartilhamento",
"remove": "Remover compartilhamento",
"notifyTitle": "Enviar notificação",
"notifyEmailLabel": "Endereço de e-mail:",
"notifyMessageLabel": "Mensagem (opcional):",
"notifySend": "Enviar notificação",
"shareWithOthers": "Compartilhar com outros",
"sharePublicly": "Compartilhar publicamente",
"shareSettings": "Configurações de compartilhamento",
"shareCopied": "Link copiado para a área de transferência",
"shareCreated": "Link de compartilhamento criado com sucesso",
"shareUpdated": "Configurações de compartilhamento atualizadas",
"shareRemoved": "Compartilhamento removido com sucesso"
},
"share_dialogTitle": "Link de compartilhamento",
"share_linkLabel": "Link compartilhado:",
"share_copyLink": "Copiar",
"share_permissions": "Permissões:",
"share_permissionRead": "Leitura",
"share_permissionWrite": "Escrita",
"share_permissionReshare": "Recompartilhar",
"share_password": "Proteção por senha:",
"share_generatePassword": "Gerar",
"share_expiration": "Data de expiração:",
"share_update": "Atualizar compartilhamento",
"share_remove": "Remover compartilhamento",
"share_notifyTitle": "Enviar notificação",
"share_notifyEmailLabel": "Endereço de e-mail:",
"share_notifyMessageLabel": "Mensagem (opcional):",
"share_notifySend": "Enviar notificação",
"shared": {
"backToFiles": "Voltar aos arquivos",
"pageTitle": "Recursos compartilhados",
"pageDescription": "Gerencie seus arquivos e pastas compartilhados",
"filterType": "Tipo:",
"filterAll": "Todos",
"filterFiles": "Arquivos",
"filterFolders": "Pastas",
"sortBy": "Ordenar por:",
"sortByName": "Nome",
"sortByDate": "Data de compartilhamento",
"sortByExpiration": "Expiração",
"search": "Pesquisar",
"colName": "Nome",
"colType": "Tipo",
"colDateShared": "Data de compartilhamento",
"colExpiration": "Expiração",
"colPermissions": "Permissões",
"colPassword": "Senha",
"colActions": "Ações",
"emptyStateTitle": "Nenhum recurso compartilhado ainda",
"emptyStateDesc": "Quando você compartilhar arquivos ou pastas, eles aparecerão aqui",
"goToFiles": "Ir para arquivos",
"typeFile": "Arquivo",
"typeFolder": "Pasta",
"noExpiration": "Sem expiração",
"hasPassword": "Sim",
"noPassword": "Não",
"editShare": "Editar compartilhamento",
"notifyShare": "Notificar alguém",
"copyLink": "Copiar link",
"removeShare": "Remover compartilhamento",
"linkCopied": "Link copiado para a área de transferência!",
"linkCopyFailed": "Falha ao copiar o link",
"itemUpdated": "Configurações de compartilhamento atualizadas",
"itemRemoved": "Compartilhamento removido com sucesso",
"invalidEmail": "Por favor, insira um endereço de e-mail válido",
"notificationSent": "Notificação enviada com sucesso",
"notificationFailed": "Falha ao enviar a notificação"
},
"shared_backToFiles": "Voltar aos arquivos",
"shared_pageTitle": "Recursos compartilhados",
"shared_pageDescription": "Gerencie seus arquivos e pastas compartilhados",
"shared_filterType": "Tipo:",
"shared_filterAll": "Todos",
"shared_filterFiles": "Arquivos",
"shared_filterFolders": "Pastas",
"shared_sortBy": "Ordenar por:",
"shared_sortByName": "Nome",
"shared_sortByDate": "Data de compartilhamento",
"shared_sortByExpiration": "Expiração",
"shared_search": "Pesquisar",
"shared_colName": "Nome",
"shared_colType": "Tipo",
"shared_colDateShared": "Data de compartilhamento",
"shared_colExpiration": "Expiração",
"shared_colPermissions": "Permissões",
"shared_colPassword": "Senha",
"shared_colActions": "Ações",
"shared_emptyStateTitle": "Nenhum recurso compartilhado ainda",
"shared_emptyStateDesc": "Quando você compartilhar arquivos ou pastas, eles aparecerão aqui",
"shared_goToFiles": "Ir para arquivos",
"shared_typeFile": "Arquivo",
"shared_typeFolder": "Pasta",
"shared_noExpiration": "Sem expiração",
"shared_hasPassword": "Sim",
"shared_noPassword": "Não",
"shared_editShare": "Editar compartilhamento",
"shared_notifyShare": "Notificar alguém",
"shared_copyLink": "Copiar link",
"shared_removeShare": "Remover compartilhamento",
"shared_linkCopied": "Link copiado para a área de transferência!",
"shared_linkCopyFailed": "Falha ao copiar o link",
"shared_itemUpdated": "Configurações de compartilhamento atualizadas",
"shared_itemRemoved": "Compartilhamento removido com sucesso",
"shared_invalidEmail": "Por favor, insira um endereço de e-mail válido",
"shared_notificationSent": "Notificação enviada com sucesso",
"shared_notificationFailed": "Falha ao enviar a notificação",
"files": {
"name": "Nome",
"type": "Tipo",
"size": "Tamanho",
"modified": "Modificado",
"no_files": "Nenhum arquivo nesta pasta",
"loading": "Carregando arquivos…",
"view_grid": "Visualização em grade",
"view_list": "Visualização em lista",
"file_types": {
"document": "Documento",
"image": "Imagem",
"video": "Vídeo",
"audio": "Áudio",
"pdf": "PDF",
"text": "Texto",
"folder": "Pasta",
"spreadsheet": "Planilha",
"presentation": "Apresentação",
"archive": "Arquivo compactado",
"installer": "Instalador",
"code": "Código"
}
},
"dialogs": {
"rename_folder": "Renomear pasta",
"rename_file": "Renomear arquivo",
"new_name": "Novo nome",
"new_folder_title": "Nova pasta",
"folder_name": "Nome da pasta",
"folder_placeholder": "Minha pasta",
"rename_title": "Renomear",
"move_file": "Mover arquivo",
"move_folder": "Mover pasta",
"select_destination": "Selecione a pasta de destino:",
"root": "Raiz",
"delete_confirmation": "Tem certeza de que deseja excluir",
"and_contents": "e todo o seu conteúdo",
"no_undo": "Esta ação não pode ser desfeita",
"confirm_title": "Confirmar ação",
"confirm_delete": "Mover para a lixeira",
"confirm_delete_file": "Tem certeza de que deseja mover o arquivo \"{{name}}\" para a lixeira?",
"confirm_delete_folder": "Tem certeza de que deseja mover a pasta \"{{name}}\" e todo o seu conteúdo para a lixeira?",
"confirm_permanent_delete": "Excluir permanentemente",
"confirm_permanent_delete_msg": "Tem certeza de que deseja excluir permanentemente este item? Esta ação não pode ser desfeita.",
"confirm_empty_trash": "Esvaziar lixeira",
"confirm_delete_share": "Excluir link de compartilhamento",
"confirm_delete_share_msg": "Tem certeza de que deseja excluir este link de compartilhamento?",
"share_file": "Compartilhar arquivo",
"existing_shares": "Compartilhamentos existentes",
"share_options": "Opções de compartilhamento",
"password": "Senha",
"expiration": "Expiração",
"permissions": "Permissões",
"generated_link": "Link gerado",
"notify": "Enviar notificação",
"recipient": "Destinatário",
"message": "Mensagem"
},
"dropzone": {
"drag_files": "Arraste arquivos aqui ou clique para selecionar",
"drop_files": "Solte os arquivos para enviar"
},
"permissions": {
"read": "Leitura",
"write": "Escrita",
"reshare": "Recompartilhar"
},
"errors": {
"file_not_found": "Arquivo não encontrado",
"folder_not_found": "Pasta não encontrada",
"delete_error": "Erro ao excluir",
"upload_error": "Erro ao enviar o arquivo",
"rename_error": "Erro ao renomear",
"move_error": "Erro ao mover",
"empty_name": "O nome não pode estar vazio",
"name_exists": "Já existe um arquivo ou pasta com esse nome",
"generic_error": "Ocorreu um erro"
},
"breadcrumb": {
"home": "Início"
},
"trash": {
"empty_trash": "Esvaziar lixeira",
"empty_state": "A lixeira está vazia",
"original_location": "Local original",
"deleted_date": "Data de exclusão",
"actions": "Ações",
"restore": "Restaurar",
"delete_permanently": "Excluir permanentemente",
"empty_confirm": "Tem certeza de que deseja esvaziar a lixeira? Todos os itens serão excluídos permanentemente."
},
"auth": {
"login_title": "Entrar",
"username": "Usuário",
"username_placeholder": "Digite seu nome de usuário",
"password": "Senha",
"password_placeholder": "Digite sua senha",
"login_button": "Entrar",
"no_account": "Não tem uma conta?",
"register": "Cadastre-se",
"admin_setup": "Primeira vez?",
"setup": "Configurar administrador",
"register_title": "Criar conta",
"email": "E-mail",
"email_placeholder": "Digite seu e-mail",
"confirm_password": "Confirmar senha",
"confirm_password_placeholder": "Confirme sua senha",
"register_button": "Criar conta",
"have_account": "Já tem uma conta?",
"login": "Entrar",
"setup_title": "Configuração inicial",
"setup_step1": "Admin",
"setup_step2": "Sistema",
"setup_step3": "Concluído",
"admin_username": "Usuário administrador",
"admin_email": "E-mail do administrador",
"admin_password": "Senha do administrador",
"create_admin": "Criar administrador",
"back_to_login": "Já configurado?",
"admin_success": "Conta de administrador criada com sucesso! Agora você pode entrar.",
"account_success": "Conta criada com sucesso! Agora você pode entrar.",
"passwords_mismatch": "As senhas não coincidem",
"admin_create_error": "Erro ao criar conta de administrador",
"or": "ou",
"sso_login": "Entrar com SSO",
"sso_login_provider": "Entrar com {{provider}}"
},
"storage": {
"title": "Armazenamento",
"calculating": "Calculando...",
"used": "{{percentage}}% usado ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Este tipo de arquivo não pode ser visualizado.",
"download_file": "Baixar arquivo",
"zoom_in": "Ampliar",
"zoom_out": "Reduzir",
"zoom_reset": "Redefinir zoom"
},
"language_selector": {
"title": "Bem-vindo ao OxiCloud",
"subtitle": "Por favor, selecione seu idioma",
"continue": "Continuar",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português"
}
},
"favorites": {
"empty_state": "Nenhum favorito ainda",
"empty_hint": "Marque arquivos ou pastas com estrela para adicioná-los aos seus favoritos",
"add": "Adicionar aos favoritos",
"remove": "Remover dos favoritos",
"added_title": "Adicionado aos favoritos",
"added_msg": "adicionado aos favoritos",
"removed_title": "Removido dos favoritos",
"removed_msg": "removido dos favoritos"
},
"recent": {
"title": "Recentes",
"clear": "Limpar recentes",
"accessed": "Acessado",
"empty_state": "Nenhum arquivo recente",
"empty_hint": "Os arquivos que você abrir aparecerão aqui"
},
"notifications": {
"file_renamed": "Arquivo renomeado",
"file_renamed_to": "Arquivo renomeado para \"{{name}}\"",
"folder_renamed": "Pasta renomeada",
"folder_renamed_to": "Pasta renomeada para \"{{name}}\"",
"file_uploaded": "Arquivo enviado",
"file_deleted": "Arquivo movido para a lixeira",
"folder_deleted": "Pasta movida para a lixeira",
"item_deleted_permanently": "Item excluído permanentemente",
"trash_emptied": "Lixeira esvaziada com sucesso"
},
"batch": {
"one_selected": "1 item selecionado",
"n_selected": "{{count}} itens selecionados",
"confirm_delete": "Tem certeza de que deseja mover {{count}} itens para a lixeira?",
"move_title": "Mover {{count}} item(ns)",
"add_favorites": "Adicionar aos favoritos",
"move_copy": "Mover ou copiar"
}
}
{
"app": {
"title": "OxiCloud",
"description": "Sistema de armazenamento em nuvem minimalista"
},
"nav": {
"files": "Arquivos",
"shared": "Compartilhados",
"recent": "Recentes",
"favorites": "Favoritos",
"photos": "Fotos",
"trash": "Lixeira"
},
"photos": {
"empty_state": "Nenhuma foto ainda",
"empty_hint": "Envie imagens ou vídeos para vê-los aqui",
"items_selected": "selecionados",
"view_daily": "Dia",
"view_monthly": "Mês",
"view_yearly": "Ano"
},
"actions": {
"search": "Pesquisar arquivos...",
"new_folder": "Nova pasta",
"upload": "Enviar",
"upload_files": "Enviar arquivos",
"upload_folder": "Enviar pasta",
"upload.uploading": "Enviando...",
"upload.complete": "{count} / {total} enviados",
"rename": "Renomear",
"move": "Mover para...",
"move_to": "Mover para",
"delete": "Excluir",
"download": "Baixar",
"view": "Visualizar",
"cancel": "Cancelar",
"confirm": "Confirmar",
"share": "Compartilhar",
"favorite": "Adicionar aos favoritos",
"unfavorite": "Remover dos favoritos",
"copy": "Copiar",
"notify": "Notificar",
"send": "Enviar",
"clear_recent": "Limpar recentes",
"logout": "Sair",
"create": "Criar",
"search_btn": "Pesquisar",
"close": "Fechar",
"delete_permanently": "Excluir permanentemente",
"empty_trash": "Esvaziar lixeira"
},
"user_menu": {
"appearance": "Aparência",
"about": "Sobre o OxiCloud",
"about_description": "Plataforma de armazenamento em nuvem construída com Rust e Arquitetura Limpa. Rápida, segura e privada.",
"admin_panel": "Painel de administração",
"profile": "Meu perfil",
"role_user": "Usuário"
},
"share": {
"dialogTitle": "Link de compartilhamento",
"linkLabel": "Link compartilhado:",
"copyLink": "Copiar",
"permissions": "Permissões:",
"permissionRead": "Leitura",
"permissionWrite": "Escrita",
"permissionReshare": "Recompartilhar",
"password": "Proteção por senha:",
"generatePassword": "Gerar",
"expiration": "Data de expiração:",
"update": "Atualizar compartilhamento",
"remove": "Remover compartilhamento",
"notifyTitle": "Enviar notificação",
"notifyEmailLabel": "Endereço de e-mail:",
"notifyMessageLabel": "Mensagem (opcional):",
"notifySend": "Enviar notificação",
"shareWithOthers": "Compartilhar com outros",
"sharePublicly": "Compartilhar publicamente",
"shareSettings": "Configurações de compartilhamento",
"shareCopied": "Link copiado para a área de transferência",
"shareCreated": "Link de compartilhamento criado com sucesso",
"shareUpdated": "Configurações de compartilhamento atualizadas",
"shareRemoved": "Compartilhamento removido com sucesso"
},
"share_dialogTitle": "Link de compartilhamento",
"share_linkLabel": "Link compartilhado:",
"share_copyLink": "Copiar",
"share_permissions": "Permissões:",
"share_permissionRead": "Leitura",
"share_permissionWrite": "Escrita",
"share_permissionReshare": "Recompartilhar",
"share_password": "Proteção por senha:",
"share_generatePassword": "Gerar",
"share_expiration": "Data de expiração:",
"share_update": "Atualizar compartilhamento",
"share_remove": "Remover compartilhamento",
"share_notifyTitle": "Enviar notificação",
"share_notifyEmailLabel": "Endereço de e-mail:",
"share_notifyMessageLabel": "Mensagem (opcional):",
"share_notifySend": "Enviar notificação",
"shared": {
"backToFiles": "Voltar aos arquivos",
"pageTitle": "Recursos compartilhados",
"pageDescription": "Gerencie seus arquivos e pastas compartilhados",
"filterType": "Tipo:",
"filterAll": "Todos",
"filterFiles": "Arquivos",
"filterFolders": "Pastas",
"sortBy": "Ordenar por:",
"sortByName": "Nome",
"sortByDate": "Data de compartilhamento",
"sortByExpiration": "Expiração",
"search": "Pesquisar",
"colName": "Nome",
"colType": "Tipo",
"colDateShared": "Data de compartilhamento",
"colExpiration": "Expiração",
"colPermissions": "Permissões",
"colPassword": "Senha",
"colActions": "Ações",
"emptyStateTitle": "Nenhum recurso compartilhado ainda",
"emptyStateDesc": "Quando você compartilhar arquivos ou pastas, eles aparecerão aqui",
"goToFiles": "Ir para arquivos",
"typeFile": "Arquivo",
"typeFolder": "Pasta",
"noExpiration": "Sem expiração",
"hasPassword": "Sim",
"noPassword": "Não",
"editShare": "Editar compartilhamento",
"notifyShare": "Notificar alguém",
"copyLink": "Copiar link",
"removeShare": "Remover compartilhamento",
"linkCopied": "Link copiado para a área de transferência!",
"linkCopyFailed": "Falha ao copiar o link",
"itemUpdated": "Configurações de compartilhamento atualizadas",
"itemRemoved": "Compartilhamento removido com sucesso",
"invalidEmail": "Por favor, insira um endereço de e-mail válido",
"notificationSent": "Notificação enviada com sucesso",
"notificationFailed": "Falha ao enviar a notificação"
},
"shared_backToFiles": "Voltar aos arquivos",
"shared_pageTitle": "Recursos compartilhados",
"shared_pageDescription": "Gerencie seus arquivos e pastas compartilhados",
"shared_filterType": "Tipo:",
"shared_filterAll": "Todos",
"shared_filterFiles": "Arquivos",
"shared_filterFolders": "Pastas",
"shared_sortBy": "Ordenar por:",
"shared_sortByName": "Nome",
"shared_sortByDate": "Data de compartilhamento",
"shared_sortByExpiration": "Expiração",
"shared_search": "Pesquisar",
"shared_colName": "Nome",
"shared_colType": "Tipo",
"shared_colDateShared": "Data de compartilhamento",
"shared_colExpiration": "Expiração",
"shared_colPermissions": "Permissões",
"shared_colPassword": "Senha",
"shared_colActions": "Ações",
"shared_emptyStateTitle": "Nenhum recurso compartilhado ainda",
"shared_emptyStateDesc": "Quando você compartilhar arquivos ou pastas, eles aparecerão aqui",
"shared_goToFiles": "Ir para arquivos",
"shared_typeFile": "Arquivo",
"shared_typeFolder": "Pasta",
"shared_noExpiration": "Sem expiração",
"shared_hasPassword": "Sim",
"shared_noPassword": "Não",
"shared_editShare": "Editar compartilhamento",
"shared_notifyShare": "Notificar alguém",
"shared_copyLink": "Copiar link",
"shared_removeShare": "Remover compartilhamento",
"shared_linkCopied": "Link copiado para a área de transferência!",
"shared_linkCopyFailed": "Falha ao copiar o link",
"shared_itemUpdated": "Configurações de compartilhamento atualizadas",
"shared_itemRemoved": "Compartilhamento removido com sucesso",
"shared_invalidEmail": "Por favor, insira um endereço de e-mail válido",
"shared_notificationSent": "Notificação enviada com sucesso",
"shared_notificationFailed": "Falha ao enviar a notificação",
"files": {
"name": "Nome",
"type": "Tipo",
"size": "Tamanho",
"modified": "Modificado",
"no_files": "Nenhum arquivo nesta pasta",
"empty_hint": "Envie arquivos ou crie pastas para começar",
"loading": "Carregando arquivos…",
"view_grid": "Visualização em grade",
"view_list": "Visualização em lista",
"file_types": {
"document": "Documento",
"image": "Imagem",
"video": "Vídeo",
"audio": "Áudio",
"pdf": "PDF",
"text": "Texto",
"folder": "Pasta",
"spreadsheet": "Planilha",
"presentation": "Apresentação",
"archive": "Arquivo compactado",
"installer": "Instalador",
"code": "Código"
}
},
"dialogs": {
"rename_folder": "Renomear pasta",
"rename_file": "Renomear arquivo",
"new_name": "Novo nome",
"new_folder_title": "Nova pasta",
"folder_name": "Nome da pasta",
"folder_placeholder": "Minha pasta",
"rename_title": "Renomear",
"move_file": "Mover arquivo",
"move_folder": "Mover pasta",
"select_destination": "Selecione a pasta de destino:",
"root": "Raiz",
"delete_confirmation": "Tem certeza de que deseja excluir",
"and_contents": "e todo o seu conteúdo",
"no_undo": "Esta ação não pode ser desfeita",
"confirm_title": "Confirmar ação",
"confirm_delete": "Mover para a lixeira",
"confirm_delete_file": "Tem certeza de que deseja mover o arquivo \"{{name}}\" para a lixeira?",
"confirm_delete_folder": "Tem certeza de que deseja mover a pasta \"{{name}}\" e todo o seu conteúdo para a lixeira?",
"confirm_permanent_delete": "Excluir permanentemente",
"confirm_permanent_delete_msg": "Tem certeza de que deseja excluir permanentemente este item? Esta ação não pode ser desfeita.",
"confirm_empty_trash": "Esvaziar lixeira",
"confirm_delete_share": "Excluir link de compartilhamento",
"confirm_delete_share_msg": "Tem certeza de que deseja excluir este link de compartilhamento?",
"share_file": "Compartilhar arquivo",
"existing_shares": "Compartilhamentos existentes",
"share_options": "Opções de compartilhamento",
"password": "Senha",
"expiration": "Expiração",
"permissions": "Permissões",
"generated_link": "Link gerado",
"notify": "Enviar notificação",
"recipient": "Destinatário",
"message": "Mensagem"
},
"dropzone": {
"drag_files": "Arraste arquivos aqui ou clique para selecionar",
"drop_files": "Solte os arquivos para enviar"
},
"permissions": {
"read": "Leitura",
"write": "Escrita",
"reshare": "Recompartilhar"
},
"errors": {
"file_not_found": "Arquivo não encontrado",
"folder_not_found": "Pasta não encontrada",
"delete_error": "Erro ao excluir",
"upload_error": "Erro ao enviar o arquivo",
"rename_error": "Erro ao renomear",
"move_error": "Erro ao mover",
"empty_name": "O nome não pode estar vazio",
"name_exists": "Já existe um arquivo ou pasta com esse nome",
"generic_error": "Ocorreu um erro"
},
"breadcrumb": {
"home": "Início"
},
"trash": {
"empty_trash": "Esvaziar lixeira",
"empty_state": "A lixeira está vazia",
"original_location": "Local original",
"deleted_date": "Data de exclusão",
"actions": "Ações",
"restore": "Restaurar",
"delete_permanently": "Excluir permanentemente",
"empty_confirm": "Tem certeza de que deseja esvaziar a lixeira? Todos os itens serão excluídos permanentemente."
},
"auth": {
"login_title": "Entrar",
"username": "Usuário",
"username_placeholder": "Digite seu nome de usuário",
"password": "Senha",
"password_placeholder": "Digite sua senha",
"login_button": "Entrar",
"no_account": "Não tem uma conta?",
"register": "Cadastre-se",
"admin_setup": "Primeira vez?",
"setup": "Configurar administrador",
"register_title": "Criar conta",
"email": "E-mail",
"email_placeholder": "Digite seu e-mail",
"confirm_password": "Confirmar senha",
"confirm_password_placeholder": "Confirme sua senha",
"register_button": "Criar conta",
"have_account": "Já tem uma conta?",
"login": "Entrar",
"setup_title": "Configuração inicial",
"setup_step1": "Admin",
"setup_step2": "Sistema",
"setup_step3": "Concluído",
"admin_username": "Usuário administrador",
"admin_email": "E-mail do administrador",
"admin_password": "Senha do administrador",
"create_admin": "Criar administrador",
"back_to_login": "Já configurado?",
"admin_success": "Conta de administrador criada com sucesso! Agora você pode entrar.",
"account_success": "Conta criada com sucesso! Agora você pode entrar.",
"passwords_mismatch": "As senhas não coincidem",
"admin_create_error": "Erro ao criar conta de administrador",
"or": "ou",
"sso_login": "Entrar com SSO",
"sso_login_provider": "Entrar com {{provider}}"
},
"storage": {
"title": "Armazenamento",
"calculating": "Calculando...",
"used": "{{percentage}}% usado ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Este tipo de arquivo não pode ser visualizado.",
"download_file": "Baixar arquivo",
"zoom_in": "Ampliar",
"zoom_out": "Reduzir",
"zoom_reset": "Redefinir zoom"
},
"language_selector": {
"title": "Bem-vindo!",
"subtitle": "Selecione seu idioma para continuar",
"continue": "Continuar",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português"
}
},
"favorites": {
"empty_state": "Nenhum favorito ainda",
"empty_hint": "Marque arquivos ou pastas com estrela para adicioná-los aos seus favoritos",
"add": "Adicionar aos favoritos",
"remove": "Remover dos favoritos",
"added_title": "Adicionado aos favoritos",
"added_msg": "adicionado aos favoritos",
"removed_title": "Removido dos favoritos",
"removed_msg": "removido dos favoritos"
},
"recent": {
"title": "Recentes",
"clear": "Limpar recentes",
"accessed": "Acessado",
"empty_state": "Nenhum arquivo recente",
"empty_hint": "Os arquivos que você abrir aparecerão aqui"
},
"notifications": {
"file_renamed": "Arquivo renomeado",
"file_renamed_to": "Arquivo renomeado para \"{{name}}\"",
"folder_renamed": "Pasta renomeada",
"folder_renamed_to": "Pasta renomeada para \"{{name}}\"",
"file_uploaded": "Arquivo enviado",
"file_deleted": "Arquivo movido para a lixeira",
"folder_deleted": "Pasta movida para a lixeira",
"item_deleted_permanently": "Item excluído permanentemente",
"trash_emptied": "Lixeira esvaziada com sucesso"
},
"batch": {
"one_selected": "1 item selecionado",
"n_selected": "{{count}} itens selecionados",
"confirm_delete": "Tem certeza de que deseja mover {{count}} itens para a lixeira?",
"move_title": "Mover {{count}} item(ns)",
"add_favorites": "Adicionar aos favoritos",
"move_copy": "Mover ou copiar"
},
"admin": {
"page_title": "Painel de Administração",
"back_to_app": "Voltar ao OxiCloud",
"loading": "Carregando…",
"access_denied": "Acesso Negado",
"access_denied_desc": "Privilégios de administrador necessários.",
"sign_in": "Entrar",
"tab_dashboard": "Painel",
"tab_users": "Usuários",
"tab_oidc": "SSO / OIDC",
"total_users": "Total de Usuários",
"active_users": "Usuários Ativos",
"admins": "Admins",
"version": "Versão",
"storage_overview": "Visão do Armazenamento",
"used": "Usado",
"total_quota": "Cota Total",
"usage_pct": "Uso %",
"users_over_80": "Usuários >80% cota",
"users_over_quota": "Usuários acima da cota",
"system": "Sistema",
"auth_label": "Auth",
"oidc_label": "OIDC",
"quotas_label": "Cotas",
"enabled": "Habilitado",
"disabled": "Desabilitado",
"active": "Ativo",
"off": "Inativo",
"allow_registration": "Permitir registro público",
"registration_warning": "O registro público está desabilitado. Apenas administradores podem criar novos usuários.",
"user_management": "Gerenciamento de Usuários",
"create_user": "Criar Usuário",
"col_user": "Usuário",
"col_role": "Função",
"col_auth": "Auth",
"col_status": "Status",
"col_storage": "Armazenamento",
"col_last_login": "Último Login",
"col_actions": "Ações",
"loading_users": "Carregando usuários…",
"failed_load_users": "Falha ao carregar",
"no_users_found": "Nenhum usuário encontrado",
"showing_users": "Mostrando {{from}}-{{to}} de {{total}}",
"prev": "Anterior",
"next": "Próximo",
"inactive": "Inativo",
"you_badge": "(você)",
"local": "Local",
"never": "Nunca",
"just_now": "Agora mesmo",
"minutes_ago": "{{n}}min atrás",
"hours_ago": "{{n}}h atrás",
"days_ago": "{{n}}d atrás",
"edit_quota_title": "Editar cota",
"reset_password_title": "Redefinir senha",
"toggle_role_title": "Alternar função",
"deactivate_title": "Desativar",
"activate_title": "Ativar",
"delete_title": "Excluir",
"sso_title": "Login Único (OIDC / SSO)",
"enable_sso": "Habilitar autenticação SSO",
"provider_name": "Nome do Provedor",
"issuer_url": "URL do Emissor",
"issuer_url_hint": "URL do emissor OpenID Connect",
"auto_discover": "Auto-descoberta",
"discovering": "Descobrindo…",
"client_id": "Client ID",
"client_secret": "Client Secret",
"client_secret_placeholder": "Deixe vazio para manter o valor atual",
"secret_configured": "Um client secret já está configurado",
"callback_url": "URL de Callback",
"callback_url_hint": "(registrar no seu IdP)",
"advanced_settings": "Configurações Avançadas",
"scopes": "Scopes",
"auto_provision": "Provisionar usuários automaticamente",
"admin_groups": "Grupos de Admin",
"admin_groups_hint": "Nomes de grupos OIDC separados por vírgula",
"disable_password": "Desabilitar login por senha (apenas OIDC)",
"password_warning": "Isso impedirá TODOS os logins por senha!",
"test_btn": "Testar",
"save_btn": "Salvar",
"saving": "Salvando…",
"settings_saved": "Configurações salvas — OIDC agora está {{status}}",
"quota_modal_title": "Atualizar Cota",
"quota_user_label": "Usuário:",
"new_quota": "Nova Cota",
"quota_unlimited_hint": "0 para ilimitado",
"cancel": "Cancelar",
"create_user_title": "Criar Novo Usuário",
"username_label": "Nome de usuário",
"username_placeholder": "joaosilva",
"username_hint": "3–32 caracteres",
"password_label": "Senha",
"password_placeholder": "Mín 8 caracteres",
"email_label": "E-mail",
"email_optional": "(opcional)",
"email_placeholder": "usuario@exemplo.com (gerado automaticamente se vazio)",
"role_label": "Função",
"role_user": "Usuário",
"role_admin": "Admin",
"quota_label": "Cota",
"creating": "Criando…",
"reset_pw_title": "Redefinir Senha",
"new_password_label": "Nova Senha",
"resetting": "Redefinindo…",
"reset_btn": "Redefinir",
"confirm_role_change": "Alterar função para {{role}}?",
"confirm_deactivate": "Tem certeza de que deseja desativar este usuário?",
"confirm_activate": "Tem certeza de que deseja ativar este usuário?",
"confirm_delete_user": "EXCLUIR usuário \"{{name}}\"? Não pode ser desfeito!",
"confirm_action": "Confirmar Ação",
"confirm_yes": "Confirmar",
"confirm_no": "Cancelar",
"error_username_short": "O nome de usuário deve ter pelo menos 3 caracteres",
"error_password_short": "A senha deve ter pelo menos 8 caracteres",
"error_generic": "Falha",
"error_network": "Erro de rede: {{message}}",
"error_create_user": "Falha ao criar usuário"
},
"profile": {
"page_title": "Perfil",
"back_to_app": "Voltar ao OxiCloud",
"loading": "Carregando…",
"not_authenticated": "Não Autenticado",
"not_authenticated_desc": "Faça login para ver seu perfil.",
"sign_in": "Entrar",
"role_admin": "Administrador",
"role_user": "Usuário",
"account_details": "Detalhes da Conta",
"username": "Nome de usuário",
"email": "E-mail",
"role": "Função",
"last_login": "Último login",
"storage": "Armazenamento",
"used": "Usado",
"quota": "Cota",
"usage": "Uso",
"unlimited": "Ilimitado",
"app_passwords": "Senhas de Aplicativo",
"app_pw_desc": "Gere senhas para clientes WebDAV, CalDAV e CardDAV. Cada senha é exibida apenas uma vez.",
"app_pw_label_placeholder": "Rótulo (ex. Thunderbird, macOS)",
"generate": "Gerar",
"generating": "Gerando…",
"new_password_for": "Nova senha para",
"copy_warning": "Copie esta senha agora. Você não poderá vê-la novamente.",
"copy_to_clipboard": "Copiar para área de transferência",
"col_label": "Rótulo",
"col_created": "Criado",
"col_last_used": "Último uso",
"col_status": "Status",
"active": "Ativa",
"revoked": "Revogada",
"revoke_title": "Revogar",
"no_app_passwords": "Nenhuma senha de aplicativo ainda.",
"client_sessions": "Sessões de cliente",
"client_sessions_desc": "Geradas automaticamente ao conectar um cliente compatível com Nextcloud.",
"col_client": "Cliente",
"never": "Nunca",
"just_now": "Agora mesmo",
"minutes_ago": "{{n}} min atrás",
"hours_ago": "{{n}}h atrás",
"days_ago": "{{n}} dias atrás",
"change_password": "Alterar Senha",
"current_password": "Senha Atual",
"new_password": "Nova Senha",
"min_8_chars": "Pelo menos 8 caracteres",
"confirm_password": "Confirmar Nova Senha",
"update_password": "Atualizar Senha",
"updating": "Atualizando…",
"password_updated": "Senha atualizada com sucesso",
"passwords_no_match": "As senhas não coincidem",
"password_too_short": "A senha deve ter pelo menos 8 caracteres",
"password_change_failed": "Falha ao alterar a senha",
"error_network": "Erro de rede: {{message}}",
"error_label_required": "Digite um rótulo",
"error_create_pw": "Falha ao criar senha de aplicativo",
"confirm_revoke": "Revogar senha \"{{label}}\"? Clientes que usam esta senha deixarão de funcionar.",
"error_revoke": "Falha ao revogar"
}
}
+555
View File
@@ -0,0 +1,555 @@
{
"app": {
"title": "OxiCloud",
"description": "Минималистичная система облачного хранения"
},
"nav": {
"files": "Файлы",
"shared": "Общие",
"recent": "Недавние",
"favorites": "Избранное",
"photos": "Фото",
"trash": "Корзина"
},
"photos": {
"empty_state": "Фотографий пока нет",
"empty_hint": "Загрузите изображения или видео, чтобы увидеть их здесь",
"items_selected": "выбрано",
"view_daily": "День",
"view_monthly": "Месяц",
"view_yearly": "Год"
},
"actions": {
"search": "Поиск файлов...",
"new_folder": "Новая папка",
"upload": "Загрузить",
"upload_files": "Загрузить файлы",
"upload_folder": "Загрузить папку",
"upload.uploading": "Загрузка...",
"upload.complete": "{count} / {total} загружено",
"rename": "Переименовать",
"move": "Переместить в...",
"move_to": "Переместить в",
"delete": "Удалить",
"download": "Скачать",
"view": "Просмотр",
"cancel": "Отмена",
"confirm": "Подтвердить",
"share": "Поделиться",
"favorite": "В избранное",
"unfavorite": "Из избранного",
"copy": "Копировать",
"notify": "Уведомить",
"send": "Отправить",
"clear_recent": "Очистить недавние",
"logout": "Выйти",
"create": "Создать",
"search_btn": "Найти",
"close": "Закрыть",
"delete_permanently": "Удалить навсегда",
"empty_trash": "Очистить корзину"
},
"user_menu": {
"appearance": "Оформление",
"about": "О OxiCloud",
"about_description": "Платформа облачного хранения на Rust с чистой архитектурой. Быстрая, безопасная и конфиденциальная.",
"admin_panel": "Панель администратора",
"profile": "Мой профиль",
"role_user": "Пользователь"
},
"share": {
"dialogTitle": "Ссылка для обмена",
"linkLabel": "Ссылка:",
"copyLink": "Копировать",
"permissions": "Разрешения:",
"permissionRead": "Чтение",
"permissionWrite": "Запись",
"permissionReshare": "Пересылка",
"password": "Защита паролем:",
"generatePassword": "Сгенерировать",
"expiration": "Срок действия:",
"update": "Обновить общий доступ",
"remove": "Удалить общий доступ",
"notifyTitle": "Отправить уведомление",
"notifyEmailLabel": "Адрес email:",
"notifyMessageLabel": "Сообщение (необязательно):",
"notifySend": "Отправить уведомление",
"shareWithOthers": "Поделиться с другими",
"sharePublicly": "Общий доступ",
"shareSettings": "Настройки общего доступа",
"shareCopied": "Ссылка скопирована в буфер обмена",
"shareCreated": "Ссылка для общего доступа успешно создана",
"shareUpdated": "Настройки общего доступа успешно обновлены",
"shareRemoved": "Общий доступ успешно удалён"
},
"share_dialogTitle": "Ссылка для обмена",
"share_linkLabel": "Ссылка:",
"share_copyLink": "Копировать",
"share_permissions": "Разрешения:",
"share_permissionRead": "Чтение",
"share_permissionWrite": "Запись",
"share_permissionReshare": "Пересылка",
"share_password": "Защита паролем:",
"share_generatePassword": "Сгенерировать",
"share_expiration": "Срок действия:",
"share_update": "Обновить общий доступ",
"share_remove": "Удалить общий доступ",
"share_notifyTitle": "Отправить уведомление",
"share_notifyEmailLabel": "Адрес email:",
"share_notifyMessageLabel": "Сообщение (необязательно):",
"share_notifySend": "Отправить уведомление",
"shared": {
"backToFiles": "Назад к файлам",
"pageTitle": "Общие ресурсы",
"pageDescription": "Управление общими файлами и папками",
"filterType": "Тип:",
"filterAll": "Все",
"filterFiles": "Файлы",
"filterFolders": "Папки",
"sortBy": "Сортировка:",
"sortByName": "Имя",
"sortByDate": "Дата",
"sortByExpiration": "Срок действия",
"search": "Поиск",
"colName": "Имя",
"colType": "Тип",
"colDateShared": "Дата общего доступа",
"colExpiration": "Срок действия",
"colPermissions": "Разрешения",
"colPassword": "Пароль",
"colActions": "Действия",
"emptyStateTitle": "Общих ресурсов пока нет",
"emptyStateDesc": "Когда вы поделитесь файлами или папками, они появятся здесь",
"goToFiles": "Перейти к файлам",
"typeFile": "Файл",
"typeFolder": "Папка",
"noExpiration": "Без срока",
"hasPassword": "Да",
"noPassword": "Нет",
"editShare": "Изменить общий доступ",
"notifyShare": "Уведомить",
"copyLink": "Копировать ссылку",
"removeShare": "Удалить общий доступ",
"linkCopied": "Ссылка скопирована в буфер обмена!",
"linkCopyFailed": "Не удалось скопировать ссылку",
"itemUpdated": "Настройки общего доступа обновлены",
"itemRemoved": "Общий доступ удалён",
"invalidEmail": "Укажите корректный адрес email",
"notificationSent": "Уведомление успешно отправлено",
"notificationFailed": "Не удалось отправить уведомление",
"shared_backToFiles": "Назад к файлам",
"shared_pageTitle": "Общие ресурсы",
"shared_pageDescription": "Управление общими файлами и папками",
"shared_filterType": "Тип:",
"shared_filterAll": "Все",
"shared_filterFiles": "Файлы",
"shared_filterFolders": "Папки",
"shared_sortBy": "Сортировка:",
"shared_sortByName": "Имя",
"shared_sortByDate": "Дата",
"shared_sortByExpiration": "Срок действия",
"shared_search": "Поиск",
"shared_colName": "Имя",
"shared_colType": "Тип",
"shared_colDateShared": "Дата общего доступа",
"shared_colExpiration": "Срок действия",
"shared_colPermissions": "Разрешения",
"shared_colPassword": "Пароль",
"shared_colActions": "Действия",
"shared_emptyStateTitle": "Общих ресурсов пока нет",
"shared_emptyStateDesc": "Когда вы поделитесь файлами или папками, они появятся здесь",
"shared_goToFiles": "Перейти к файлам",
"shared_typeFile": "Файл",
"shared_typeFolder": "Папка",
"shared_noExpiration": "Без срока",
"shared_hasPassword": "Да",
"shared_noPassword": "Нет",
"shared_editShare": "Изменить общий доступ",
"shared_notifyShare": "Уведомить",
"shared_copyLink": "Копировать ссылку",
"shared_removeShare": "Удалить общий доступ",
"shared_linkCopied": "Ссылка скопирована в буфер обмена!",
"shared_linkCopyFailed": "Не удалось скопировать ссылку",
"shared_itemUpdated": "Настройки общего доступа обновлены",
"shared_itemRemoved": "Общий доступ удалён",
"shared_invalidEmail": "Укажите корректный адрес email",
"shared_notificationSent": "Уведомление успешно отправлено",
"shared_notificationFailed": "Не удалось отправить уведомление"
},
"files": {
"name": "Имя",
"type": "Тип",
"size": "Размер",
"modified": "Изменён",
"no_files": "В этой папке нет файлов",
"empty_hint": "Загрузите файлы или создайте папки, чтобы начать",
"loading": "Загрузка файлов…",
"view_grid": "Сетка",
"view_list": "Список",
"file_types": {
"document": "Документ",
"image": "Изображение",
"video": "Видео",
"audio": "Аудио",
"pdf": "PDF",
"text": "Текст",
"folder": "Папка",
"spreadsheet": "Таблица",
"presentation": "Презентация",
"archive": "Архив",
"installer": "Установщик",
"code": "Код"
}
},
"dialogs": {
"rename_folder": "Переименовать папку",
"rename_file": "Переименовать файл",
"new_name": "Новое имя",
"new_folder_title": "Новая папка",
"folder_name": "Имя папки",
"folder_placeholder": "Моя папка",
"rename_title": "Переименовать",
"move_file": "Переместить файл",
"move_folder": "Переместить папку",
"select_destination": "Выберите папку назначения:",
"select_this_folder": "Выбрать эту папку",
"go_to_parent": ".. (родительская папка)",
"no_subfolders": "Нет подпапок",
"root": "Корень",
"delete_confirmation": "Вы уверены, что хотите удалить",
"and_contents": "и всё его содержимое",
"no_undo": "Это действие невозможно отменить",
"confirm_title": "Подтверждение действия",
"confirm_delete": "В корзину",
"confirm_delete_file": "Вы уверены, что хотите переместить файл \"{{name}}\" в корзину?",
"confirm_delete_folder": "Вы уверены, что хотите переместить папку \"{{name}}\" и всё её содержимое в корзину?",
"confirm_permanent_delete": "Удалить навсегда",
"confirm_permanent_delete_msg": "Вы уверены, что хотите навсегда удалить этот элемент? Это действие невозможно отменить.",
"confirm_empty_trash": "Очистить корзину",
"confirm_delete_share": "Удалить ссылку общего доступа",
"confirm_delete_share_msg": "Вы уверены, что хотите удалить эту ссылку общего доступа?",
"share_file": "Поделиться файлом",
"existing_shares": "Существующие общие доступы",
"share_options": "Параметры общего доступа",
"password": "Пароль",
"expiration": "Срок действия",
"permissions": "Разрешения",
"generated_link": "Сгенерированная ссылка",
"notify": "Отправить уведомление",
"recipient": "Получатель",
"message": "Сообщение"
},
"dropzone": {
"drag_files": "Перетащите файлы сюда или нажмите для выбора",
"drop_files": "Отпустите файлы для загрузки"
},
"permissions": {
"read": "Чтение",
"write": "Запись",
"reshare": "Пересылка"
},
"errors": {
"file_not_found": "Файл не найден",
"folder_not_found": "Папка не найдена",
"delete_error": "Ошибка удаления",
"upload_error": "Ошибка загрузки файла",
"rename_error": "Ошибка переименования",
"move_error": "Ошибка перемещения",
"empty_name": "Имя не может быть пустым",
"name_exists": "Файл или папка с таким именем уже существует",
"generic_error": "Произошла ошибка"
},
"breadcrumb": {
"home": "Главная"
},
"trash": {
"empty_trash": "Очистить корзину",
"empty_state": "Корзина пуста",
"original_location": "Исходное расположение",
"deleted_date": "Дата удаления",
"actions": "Действия",
"restore": "Восстановить",
"delete_permanently": "Удалить навсегда",
"empty_confirm": "Вы уверены, что хотите очистить корзину? Все элементы будут удалены навсегда."
},
"auth": {
"login_title": "Вход",
"username": "Имя пользователя",
"username_placeholder": "Введите имя пользователя",
"password": "Пароль",
"password_placeholder": "Введите пароль",
"login_button": "Войти",
"no_account": "Нет аккаунта?",
"register": "Зарегистрироваться",
"admin_setup": "Первый запуск?",
"setup": "Настроить администратора",
"register_title": "Создание аккаунта",
"email": "Email",
"email_placeholder": "Введите email",
"confirm_password": "Подтвердите пароль",
"confirm_password_placeholder": "Подтвердите пароль",
"register_button": "Создать аккаунт",
"have_account": "Уже есть аккаунт?",
"login": "Войти",
"setup_title": "Начальная настройка",
"setup_step1": "Админ",
"setup_step2": "Система",
"setup_step3": "Готово",
"admin_username": "Имя администратора",
"admin_email": "Email администратора",
"admin_password": "Пароль администратора",
"create_admin": "Создать администратора",
"back_to_login": "Уже настроено?",
"admin_success": "Аккаунт администратора успешно создан! Теперь вы можете войти.",
"account_success": "Аккаунт успешно создан! Теперь вы можете войти.",
"passwords_mismatch": "Пароли не совпадают",
"admin_create_error": "Ошибка создания аккаунта администратора",
"or": "или",
"sso_login": "Войти через SSO",
"sso_login_provider": "Войти через {{provider}}"
},
"storage": {
"title": "Хранилище",
"calculating": "Вычисление...",
"used": "{{percentage}}% использовано ({{used}} / {{total}})"
},
"viewer": {
"unsupported_file": "Предварительный просмотр этого типа файлов недоступен.",
"download_file": "Скачать файл",
"zoom_in": "Увеличить",
"zoom_out": "Уменьшить",
"zoom_reset": "Сбросить масштаб"
},
"language_selector": {
"title": "Добро пожаловать!",
"subtitle": "Выберите язык для продолжения",
"continue": "Продолжить",
"languages": {
"en": "English",
"es": "Español",
"zh": "中文",
"fa": "فارسی",
"fr": "Français",
"de": "Deutsch",
"pt": "Português",
"ru": "Русский"
}
},
"favorites": {
"empty_state": "Избранного пока нет",
"empty_hint": "Добавьте файлы или папки в избранное, нажав на звёздочку",
"add": "В избранное",
"remove": "Из избранного",
"added_title": "Добавлено в избранное",
"added_msg": "добавлено в избранное",
"removed_title": "Удалено из избранного",
"removed_msg": "удалено из избранного"
},
"recent": {
"title": "Недавние",
"clear": "Очистить недавние",
"accessed": "Открыт",
"empty_state": "Нет недавних файлов",
"empty_hint": "Открытые вами файлы будут отображаться здесь"
},
"notifications": {
"file_renamed": "Файл переименован",
"file_renamed_to": "Файл переименован в \"{{name}}\"",
"folder_renamed": "Папка переименована",
"folder_renamed_to": "Папка переименована в \"{{name}}\"",
"file_uploaded": "Файл загружен",
"file_deleted": "Файл перемещён в корзину",
"folder_deleted": "Папка перемещена в корзину",
"item_deleted_permanently": "Элемент удалён навсегда",
"trash_emptied": "Корзина успешно очищена",
"title": "Уведомления",
"empty": "Нет уведомлений"
},
"batch": {
"one_selected": "Выбран 1 элемент",
"n_selected": "Выбрано {{count}} элементов",
"confirm_delete": "Вы уверены, что хотите переместить {{count}} элементов в корзину?",
"move_title": "Переместить {{count}} элементов",
"add_favorites": "В избранное",
"move_copy": "Переместить или копировать"
},
"admin": {
"page_title": "Панель администратора",
"back_to_app": "Назад в OxiCloud",
"loading": "Загрузка…",
"access_denied": "Доступ запрещён",
"access_denied_desc": "Необходимы права администратора.",
"sign_in": "Войти",
"tab_dashboard": "Панель",
"tab_users": "Пользователи",
"tab_oidc": "SSO / OIDC",
"total_users": "Всего пользователей",
"active_users": "Активные",
"admins": "Администраторы",
"version": "Версия",
"storage_overview": "Обзор хранилища",
"used": "Использовано",
"total_quota": "Общая квота",
"usage_pct": "Использование %",
"users_over_80": "Пользователи >80%",
"users_over_quota": "Сверх квоты",
"system": "Система",
"auth_label": "Аутентификация",
"oidc_label": "OIDC",
"quotas_label": "Квоты",
"enabled": "Включено",
"disabled": "Отключено",
"active": "Активен",
"off": "Выкл",
"allow_registration": "Разрешить публичную регистрацию",
"registration_warning": "Публичная регистрация отключена. Только админы могут создавать пользователей.",
"user_management": "Управление пользователями",
"create_user": "Создать пользователя",
"col_user": "Пользователь",
"col_role": "Роль",
"col_auth": "Аутентификация",
"col_status": "Статус",
"col_storage": "Хранилище",
"col_last_login": "Последний вход",
"col_actions": "Действия",
"loading_users": "Загрузка пользователей…",
"failed_load_users": "Не удалось загрузить",
"no_users_found": "Пользователи не найдены",
"showing_users": "Показано {{from}}-{{to}} из {{total}}",
"prev": "Назад",
"next": "Далее",
"inactive": "Неактивен",
"you_badge": "(вы)",
"local": "Локальный",
"never": "Никогда",
"just_now": "Только что",
"minutes_ago": "{{n}} мин назад",
"hours_ago": "{{n}} ч назад",
"days_ago": "{{n}} дн назад",
"edit_quota_title": "Изменить квоту",
"reset_password_title": "Сбросить пароль",
"toggle_role_title": "Сменить роль",
"deactivate_title": "Деактивировать",
"activate_title": "Активировать",
"delete_title": "Удалить",
"sso_title": "Единый вход (OIDC / SSO)",
"enable_sso": "Включить SSO",
"provider_name": "Имя провайдера",
"issuer_url": "URL издателя",
"issuer_url_hint": "URL издателя OpenID Connect",
"auto_discover": "Авто-обнаружение",
"discovering": "Обнаружение…",
"client_id": "Client ID",
"client_secret": "Client Secret",
"client_secret_placeholder": "Оставьте пустым для сохранения",
"secret_configured": "Client secret уже настроен",
"callback_url": "URL обратного вызова",
"callback_url_hint": "(зарегистрируйте в IdP)",
"advanced_settings": "Расширенные настройки",
"scopes": "Области",
"auto_provision": "Автоматически создавать пользователей",
"admin_groups": "Группы администраторов",
"admin_groups_hint": "Имена групп OIDC через запятую",
"disable_password": "Отключить вход по паролю (только OIDC)",
"password_warning": "Это заблокирует ВСЕ входы по паролю!",
"test_btn": "Тест",
"save_btn": "Сохранить",
"saving": "Сохранение…",
"settings_saved": "Настройки сохранены — OIDC теперь {{status}}",
"quota_modal_title": "Обновить квоту",
"quota_user_label": "Пользователь:",
"new_quota": "Новая квота",
"quota_unlimited_hint": "0 для безлимитного",
"cancel": "Отмена",
"create_user_title": "Создать пользователя",
"username_label": "Имя пользователя",
"username_placeholder": "ivanov",
"username_hint": "3–32 символа",
"password_label": "Пароль",
"password_placeholder": "Мин. 8 символов",
"email_label": "Эл. почта",
"email_optional": "(необязательно)",
"email_placeholder": "user@example.com (автоматически если пусто)",
"role_label": "Роль",
"role_user": "Пользователь",
"role_admin": "Админ",
"quota_label": "Квота",
"creating": "Создание…",
"reset_pw_title": "Сбросить пароль",
"new_password_label": "Новый пароль",
"resetting": "Сброс…",
"reset_btn": "Сбросить",
"confirm_role_change": "Изменить роль на {{role}}?",
"confirm_deactivate": "Деактивировать этого пользователя?",
"confirm_activate": "Активировать этого пользователя?",
"confirm_delete_user": "УДАЛИТЬ пользователя \"{{name}}\"? Нельзя отменить!",
"confirm_action": "Подтвердить",
"confirm_yes": "Подтвердить",
"confirm_no": "Отмена",
"error_username_short": "Имя минимум 3 символа",
"error_password_short": "Пароль минимум 8 символов",
"error_generic": "Ошибка",
"error_network": "Ошибка сети: {{message}}",
"error_create_user": "Не удалось создать"
},
"profile": {
"page_title": "Профиль",
"back_to_app": "Назад в OxiCloud",
"loading": "Загрузка…",
"not_authenticated": "Не аутентифицирован",
"not_authenticated_desc": "Войдите, чтобы просмотреть свой профиль.",
"sign_in": "Войти",
"role_admin": "Администратор",
"role_user": "Пользователь",
"account_details": "Данные аккаунта",
"username": "Имя пользователя",
"email": "Эл. почта",
"role": "Роль",
"last_login": "Последний вход",
"storage": "Хранилище",
"used": "Использовано",
"quota": "Квота",
"usage": "Использование",
"unlimited": "Безлимитный",
"app_passwords": "Пароли приложений",
"app_pw_desc": "Создайте пароли для клиентов WebDAV, CalDAV и CardDAV. Каждый пароль показывается только один раз.",
"app_pw_label_placeholder": "Метка (напр. Thunderbird, macOS)",
"generate": "Создать",
"generating": "Создание…",
"new_password_for": "Новый пароль для",
"copy_warning": "Скопируйте пароль сейчас. Вы не сможете увидеть его снова.",
"copy_to_clipboard": "Копировать в буфер",
"col_label": "Метка",
"col_created": "Создан",
"col_last_used": "Последнее использование",
"col_status": "Статус",
"active": "Активен",
"revoked": "Отозван",
"revoke_title": "Отозвать",
"no_app_passwords": "Паролей приложений пока нет.",
"client_sessions": "Сессии клиентов",
"client_sessions_desc": "Автоматически создаются при подключении клиента, совместимого с Nextcloud.",
"col_client": "Клиент",
"never": "Никогда",
"just_now": "Только что",
"minutes_ago": "{{n}} мин назад",
"hours_ago": "{{n}} ч назад",
"days_ago": "{{n}} дн назад",
"change_password": "Изменить пароль",
"current_password": "Текущий пароль",
"new_password": "Новый пароль",
"min_8_chars": "Минимум 8 символов",
"confirm_password": "Подтвердите новый пароль",
"update_password": "Обновить пароль",
"updating": "Обновление…",
"password_updated": "Пароль успешно обновлён",
"passwords_no_match": "Пароли не совпадают",
"password_too_short": "Пароль должен быть не менее 8 символов",
"password_change_failed": "Не удалось изменить пароль",
"error_network": "Ошибка сети: {{message}}",
"error_label_required": "Введите метку",
"error_create_pw": "Не удалось создать пароль",
"confirm_revoke": "Отозвать пароль «{{label}}»? Клиенты перестанут работать.",
"error_revoke": "Не удалось отозвать"
}
}
+183 -2
View File
@@ -142,6 +142,8 @@
"size": "大小",
"modified": "修改日期",
"no_files": "此文件夹中没有文件",
"empty_hint": "上传文件或创建文件夹以开始使用",
"loading": "正在加载文件…",
"view_grid": "网格视图",
"view_list": "列表视图",
"file_types": {
@@ -265,8 +267,8 @@
"zoom_reset": "重置缩放"
},
"language_selector": {
"title": "欢迎使用 OxiCloud",
"subtitle": "请选择您的语言",
"title": "欢迎!",
"subtitle": "选择您的语言以继续",
"continue": "继续",
"languages": {
"en": "English",
@@ -302,5 +304,184 @@
"move_title": "移动 {{count}} 个项目",
"add_favorites": "添加到收藏夹",
"move_copy": "移动或复制"
},
"admin": {
"page_title": "管理面板",
"back_to_app": "返回 OxiCloud",
"loading": "加载中…",
"access_denied": "拒绝访问",
"access_denied_desc": "需要管理员权限。",
"sign_in": "登录",
"tab_dashboard": "仪表盘",
"tab_users": "用户",
"tab_oidc": "SSO / OIDC",
"total_users": "用户总数",
"active_users": "活跃用户",
"admins": "管理员",
"version": "版本",
"storage_overview": "存储概览",
"used": "已使用",
"total_quota": "总配额",
"usage_pct": "使用率",
"users_over_80": "超过80%配额",
"users_over_quota": "超过配额",
"system": "系统",
"auth_label": "认证",
"oidc_label": "OIDC",
"quotas_label": "配额",
"enabled": "已启用",
"disabled": "已禁用",
"active": "活跃",
"off": "关闭",
"allow_registration": "允许公开自助注册",
"registration_warning": "公开注册已禁用。只有管理员可以创建新用户。",
"user_management": "用户管理",
"create_user": "创建用户",
"col_user": "用户",
"col_role": "角色",
"col_auth": "认证",
"col_status": "状态",
"col_storage": "存储",
"col_last_login": "最后登录",
"col_actions": "操作",
"loading_users": "正在加载用户…",
"failed_load_users": "加载失败",
"no_users_found": "未找到用户",
"showing_users": "显示 {{from}}-{{to}} / {{total}}",
"prev": "上一页",
"next": "下一页",
"inactive": "未激活",
"you_badge": "(你)",
"local": "本地",
"never": "从未",
"just_now": "刚刚",
"minutes_ago": "{{n}}分钟前",
"hours_ago": "{{n}}小时前",
"days_ago": "{{n}}天前",
"edit_quota_title": "编辑配额",
"reset_password_title": "重置密码",
"toggle_role_title": "切换角色",
"deactivate_title": "停用",
"activate_title": "启用",
"delete_title": "删除",
"sso_title": "单点登录 (OIDC / SSO)",
"enable_sso": "启用 SSO 认证",
"provider_name": "提供商名称",
"issuer_url": "发行者 URL",
"issuer_url_hint": "您的身份提供商的 OpenID Connect 发行者 URL",
"auto_discover": "自动发现",
"discovering": "发现中…",
"client_id": "客户端 ID",
"client_secret": "客户端密钥",
"client_secret_placeholder": "留空以保留当前值",
"secret_configured": "已配置客户端密钥",
"callback_url": "回调 URL",
"callback_url_hint": "(在您的 IdP 中注册)",
"advanced_settings": "高级设置",
"scopes": "范围",
"auto_provision": "首次登录时自动配置用户",
"admin_groups": "管理组",
"admin_groups_hint": "映射到管理员角色的逗号分隔 OIDC 组名",
"disable_password": "禁用密码登录 (仅 OIDC)",
"password_warning": "这将阻止所有基于密码的登录!",
"test_btn": "测试",
"save_btn": "保存",
"saving": "保存中…",
"settings_saved": "设置已保存 — OIDC 现在 {{status}}",
"quota_modal_title": "更新存储配额",
"quota_user_label": "用户:",
"new_quota": "新配额",
"quota_unlimited_hint": "0表示无限制",
"cancel": "取消",
"create_user_title": "创建新用户",
"username_label": "用户名",
"username_placeholder": "zhangsan",
"username_hint": "3–32个字符",
"password_label": "密码",
"password_placeholder": "至少8个字符",
"email_label": "邮箱",
"email_optional": "(可选)",
"email_placeholder": "user@example.com (留空自动生成)",
"role_label": "角色",
"role_user": "用户",
"role_admin": "管理员",
"quota_label": "配额",
"creating": "创建中…",
"reset_pw_title": "重置密码",
"new_password_label": "新密码",
"resetting": "重置中…",
"reset_btn": "重置",
"confirm_role_change": "将角色更改为 {{role}}?",
"confirm_deactivate": "确定要停用此用户吗?",
"confirm_activate": "确定要启用此用户吗?",
"confirm_delete_user": "删除用户 \"{{name}}\"?此操作无法撤消!",
"confirm_action": "确认操作",
"confirm_yes": "确认",
"confirm_no": "取消",
"error_username_short": "用户名至少需要3个字符",
"error_password_short": "密码至少需要8个字符",
"error_generic": "失败",
"error_network": "网络错误:{{message}}",
"error_create_user": "创建用户失败"
},
"profile": {
"page_title": "个人资料",
"back_to_app": "返回 OxiCloud",
"loading": "加载中…",
"not_authenticated": "未认证",
"not_authenticated_desc": "请登录以查看您的个人资料。",
"sign_in": "登录",
"role_admin": "管理员",
"role_user": "用户",
"account_details": "账户详情",
"username": "用户名",
"email": "邮箱",
"role": "角色",
"last_login": "最后登录",
"storage": "存储",
"used": "已使用",
"quota": "配额",
"usage": "使用率",
"unlimited": "无限制",
"app_passwords": "应用密码",
"app_pw_desc": "为 WebDAV、CalDAV 和 CardDAV 客户端生成密码。每个密码只显示一次。",
"app_pw_label_placeholder": "标签(如 Thunderbird、macOS)",
"generate": "生成",
"generating": "生成中…",
"new_password_for": "新密码用于",
"copy_warning": "请立即复制此密码,之后将无法再次查看。",
"copy_to_clipboard": "复制到剪贴板",
"col_label": "标签",
"col_created": "创建时间",
"col_last_used": "最后使用",
"col_status": "状态",
"active": "活跃",
"revoked": "已撤销",
"revoke_title": "撤销",
"no_app_passwords": "暂无应用密码。",
"client_sessions": "客户端会话",
"client_sessions_desc": "连接 Nextcloud 兼容客户端时自动生成。",
"col_client": "客户端",
"never": "从未",
"just_now": "刚刚",
"minutes_ago": "{{n}}分钟前",
"hours_ago": "{{n}}小时前",
"days_ago": "{{n}}天前",
"change_password": "修改密码",
"current_password": "当前密码",
"new_password": "新密码",
"min_8_chars": "至少8个字符",
"confirm_password": "确认新密码",
"update_password": "更新密码",
"updating": "更新中…",
"password_updated": "密码更新成功",
"passwords_no_match": "密码不匹配",
"password_too_short": "密码至少需要8个字符",
"password_change_failed": "修改密码失败",
"error_network": "网络错误:{{message}}",
"error_label_required": "请输入标签",
"error_create_pw": "创建应用密码失败",
"confirm_revoke": "撤销应用密码\"{{label}}\"?使用此密码的客户端将停止工作。",
"error_revoke": "撤销失败"
}
}
+2 -2
View File
@@ -30,8 +30,8 @@
<div class="auth-logo-text">OxiCloud</div>
</div>
<h2 class="auth-title" id="language-title">Welcome to OxiCloud</h2>
<p class="language-subtitle" id="language-subtitle">Please select your language</p>
<h2 class="auth-title" id="language-title">Welcome!</h2>
<p class="language-subtitle" id="language-subtitle">Select your language to continue</p>
<!-- Single selected language box with inline dropdown -->
<div class="lang-picker" id="lang-picker">
+34 -33
View File
@@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OxiCloud — My Profile</title>
<script src="/js/core/theme-init.js"></script>
<script src="/js/core/i18n.js" defer></script>
<script src="/js/core/icons.js" defer></script>
<script src="/js/core/csrf.js" defer></script>
<link rel="stylesheet" href="/css/main.css">
@@ -22,20 +23,20 @@
</div>
<span class="profile-title-text">OxiCloud</span>
</a>
<span class="profile-title-separator">· Profile</span>
<span class="profile-title-separator">· <span data-i18n="profile.page_title">Profile</span></span>
</div>
<div class="profile-header-right">
<a href="/"><i class="fas fa-arrow-left"></i> Back to OxiCloud</a>
<a href="/"><i class="fas fa-arrow-left"></i> <span data-i18n="profile.back_to_app">Back to OxiCloud</span></a>
</div>
</div>
<div class="profile-container">
<div id="loading"><i class="fas fa-circle-notch"></i> Loading…</div>
<div id="loading"><i class="fas fa-circle-notch"></i> <span data-i18n="profile.loading">Loading…</span></div>
<div id="auth-error" class="hidden">
<div class="err-icon"><i class="fas fa-lock"></i></div>
<h2>Not Authenticated</h2>
<p>Please sign in to view your profile.</p>
<a href="/login"><i class="fas fa-sign-in-alt"></i> Sign in</a>
<h2 data-i18n="profile.not_authenticated">Not Authenticated</h2>
<p data-i18n="profile.not_authenticated_desc">Please sign in to view your profile.</p>
<a href="/login"><i class="fas fa-sign-in-alt"></i> <span data-i18n="profile.sign_in">Sign in</span></a>
</div>
<div id="main-content" class="hidden">
@@ -51,41 +52,41 @@
</div>
<div class="profile-card">
<h2><i class="fas fa-id-card"></i> Account Details</h2>
<h2><i class="fas fa-id-card"></i> <span data-i18n="profile.account_details">Account Details</span></h2>
<div class="info-grid">
<div class="info-item">
<div class="info-label"><i class="fas fa-user"></i> Username</div>
<div class="info-label"><i class="fas fa-user"></i> <span data-i18n="profile.username">Username</span></div>
<div class="info-value" id="p-detail-username">—</div>
</div>
<div class="info-item">
<div class="info-label"><i class="fas fa-envelope"></i> Email</div>
<div class="info-label"><i class="fas fa-envelope"></i> <span data-i18n="profile.email">Email</span></div>
<div class="info-value" id="p-detail-email">—</div>
</div>
<div class="info-item">
<div class="info-label"><i class="fas fa-shield-alt"></i> Role</div>
<div class="info-label"><i class="fas fa-shield-alt"></i> <span data-i18n="profile.role">Role</span></div>
<div class="info-value" id="p-detail-role">—</div>
</div>
<div class="info-item">
<div class="info-label"><i class="fas fa-clock"></i> Last Login</div>
<div class="info-label"><i class="fas fa-clock"></i> <span data-i18n="profile.last_login">Last Login</span></div>
<div class="info-value" id="p-detail-login">—</div>
</div>
</div>
</div>
<div class="profile-card">
<h2><i class="fas fa-hdd"></i> Storage</h2>
<h2><i class="fas fa-hdd"></i> <span data-i18n="profile.storage">Storage</span></h2>
<div class="storage-stats">
<div class="storage-stat">
<div class="stat-value" id="p-storage-used">—</div>
<div class="stat-label">Used</div>
<div class="stat-label" data-i18n="profile.used">Used</div>
</div>
<div class="storage-stat">
<div class="stat-value" id="p-storage-quota">—</div>
<div class="stat-label">Quota</div>
<div class="stat-label" data-i18n="profile.quota">Quota</div>
</div>
<div class="storage-stat">
<div class="stat-value" id="p-storage-pct">—</div>
<div class="stat-label">Usage</div>
<div class="stat-label" data-i18n="profile.usage">Usage</div>
</div>
</div>
<div class="storage-bar-wrap">
@@ -95,44 +96,44 @@
</div>
<div class="profile-card" id="app-passwords-section">
<h2><i class="fas fa-key"></i> App Passwords</h2>
<p class="app-pw-desc">Generate passwords for WebDAV, CalDAV, and CardDAV clients. Each password is shown only once.</p>
<h2><i class="fas fa-key"></i> <span data-i18n="profile.app_passwords">App Passwords</span></h2>
<p class="app-pw-desc" data-i18n="profile.app_pw_desc">Generate passwords for WebDAV, CalDAV, and CardDAV clients. Each password is shown only once.</p>
<div class="app-pw-create">
<input type="text" id="app-pw-label" placeholder="Label (e.g. Thunderbird, macOS)" maxlength="128">
<button class="btn btn-primary" id="app-pw-generate"><i class="fas fa-plus"></i> Generate</button>
<input type="text" id="app-pw-label" data-i18n-placeholder="profile.app_pw_label_placeholder" placeholder="Label (e.g. Thunderbird, macOS)" maxlength="128">
<button class="btn btn-primary" id="app-pw-generate"><i class="fas fa-plus"></i> <span data-i18n="profile.generate">Generate</span></button>
</div>
<div id="app-pw-created" class="app-pw-created hidden">
<div class="app-pw-created-label">New password for <strong id="app-pw-created-label"></strong>:</div>
<div class="app-pw-created-label"><span data-i18n="profile.new_password_for">New password for</span> <strong id="app-pw-created-label"></strong>:</div>
<div class="app-pw-created-value">
<code id="app-pw-created-password"></code>
<button class="btn btn-copy" id="app-pw-copy-btn" title="Copy to clipboard"><i class="fas fa-copy"></i></button>
<button class="btn btn-copy" id="app-pw-copy-btn" data-i18n-title="profile.copy_to_clipboard" title="Copy to clipboard"><i class="fas fa-copy"></i></button>
</div>
<small>Copy this password now. You won't be able to see it again.</small>
<small data-i18n="profile.copy_warning">Copy this password now. You won't be able to see it again.</small>
</div>
<div id="app-pw-status"></div>
<table class="app-pw-table" id="app-pw-table">
<thead>
<tr><th>Label</th><th>Created</th><th>Last Used</th><th>Status</th><th></th></tr>
<tr><th data-i18n="profile.col_label">Label</th><th data-i18n="profile.col_created">Created</th><th data-i18n="profile.col_last_used">Last Used</th><th data-i18n="profile.col_status">Status</th><th></th></tr>
</thead>
<tbody id="app-pw-tbody"></tbody>
</table>
<div id="app-pw-empty" class="app-pw-empty hidden">No app passwords yet.</div>
<div id="app-pw-empty" class="app-pw-empty hidden" data-i18n="profile.no_app_passwords">No app passwords yet.</div>
<div id="app-pw-auto-section" class="app-pw-auto-section hidden">
<button class="app-pw-auto-toggle" id="app-pw-auto-toggle">
<i class="fas fa-chevron-right" id="app-pw-auto-chevron"></i>
<span>Client sessions</span>
<span data-i18n="profile.client_sessions">Client sessions</span>
<span class="app-pw-auto-count" id="app-pw-auto-count">0</span>
</button>
<div id="app-pw-auto-body" class="hidden">
<p class="app-pw-auto-desc">Auto-generated when you connect a Nextcloud-compatible client.</p>
<p class="app-pw-auto-desc" data-i18n="profile.client_sessions_desc">Auto-generated when you connect a Nextcloud-compatible client.</p>
<table class="app-pw-table" id="app-pw-auto-table">
<thead>
<tr><th>Client</th><th>Created</th><th>Last Used</th><th></th></tr>
<tr><th data-i18n="profile.col_client">Client</th><th data-i18n="profile.col_created">Created</th><th data-i18n="profile.col_last_used">Last Used</th><th></th></tr>
</thead>
<tbody id="app-pw-auto-tbody"></tbody>
</table>
@@ -141,22 +142,22 @@
</div>
<div class="profile-card" id="password-section">
<h2><i class="fas fa-key"></i> Change Password</h2>
<h2><i class="fas fa-key"></i> <span data-i18n="profile.change_password">Change Password</span></h2>
<form id="password-form">
<div class="form-group">
<label for="current-password">Current Password</label>
<label for="current-password" data-i18n="profile.current_password">Current Password</label>
<input type="password" id="current-password" required autocomplete="current-password">
</div>
<div class="form-group">
<label for="new-password">New Password</label>
<label for="new-password" data-i18n="profile.new_password">New Password</label>
<input type="password" id="new-password" required minlength="8" autocomplete="new-password">
<small>At least 8 characters</small>
<small data-i18n="profile.min_8_chars">At least 8 characters</small>
</div>
<div class="form-group">
<label for="confirm-password">Confirm New Password</label>
<label for="confirm-password" data-i18n="profile.confirm_password">Confirm New Password</label>
<input type="password" id="confirm-password" required minlength="8" autocomplete="new-password">
</div>
<button type="submit" class="btn btn-primary" id="pw-submit"><i class="fas fa-save"></i> Update Password</button>
<button type="submit" class="btn btn-primary" id="pw-submit"><i class="fas fa-save"></i> <span data-i18n="profile.update_password">Update Password</span></button>
<div id="pw-status"></div>
</form>
</div>