mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
Merge branch 'master' into feat/operation-logs
Integrate master branch updates into operation-logs feature branch: - Add heatmap components and scheduled date group pipe - Add task delete confirmation dialog and tests - Update Android focus mode and sound configuration - Add GitLab PAT authentication support - Merge translation keys and i18n updates
This commit is contained in:
commit
150fd074ab
80 changed files with 4117 additions and 9773 deletions
|
|
@ -8,13 +8,17 @@ on:
|
|||
types:
|
||||
- opened
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
welcome:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/first-interaction@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue_message: |
|
||||
Hello there ${{ github.actor }}! 👋
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ dependencies {
|
|||
implementation "com.google.androidbrowserhelper:androidbrowserhelper:2.5.0"
|
||||
implementation "com.google.code.gson:gson:2.10.1"
|
||||
implementation "androidx.core:core-ktx:1.16.0"
|
||||
implementation "androidx.localbroadcastmanager:localbroadcastmanager:1.1.0"
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.8.7'
|
||||
implementation 'androidx.preference:preference-ktx:1.2.1'
|
||||
implementation "com.anggrayudi:storage:1.5.4"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package com.superproductivity.superproductivity
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
|
|
@ -10,6 +13,7 @@ import android.view.View
|
|||
import android.webkit.WebView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.addCallback
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.anggrayudi.storage.SimpleStorageHelper
|
||||
import com.getcapacitor.BridgeActivity
|
||||
import com.superproductivity.superproductivity.plugins.SafBridgePlugin
|
||||
|
|
@ -36,6 +40,16 @@ class CapacitorMainActivity : BridgeActivity() {
|
|||
private val storageHelper =
|
||||
SimpleStorageHelper(this) // for scoped storage permission management on Android 10+
|
||||
|
||||
private val timerCompleteReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action == FocusModeForegroundService.ACTION_TIMER_COMPLETE) {
|
||||
val isBreak = intent.getBooleanExtra(FocusModeForegroundService.EXTRA_IS_BREAK, false)
|
||||
Log.d("SP_FOCUS", "Timer complete broadcast received, isBreak=$isBreak")
|
||||
callJSInterfaceFunctionIfExists("next", "onFocusModeTimerComplete$", isBreak.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun load() {
|
||||
val result = WebViewCompatibilityChecker.evaluate(this)
|
||||
webViewCompatibility = result
|
||||
|
|
@ -125,7 +139,12 @@ class CapacitorMainActivity : BridgeActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Register broadcast receiver for focus mode timer completion
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
timerCompleteReceiver,
|
||||
IntentFilter(FocusModeForegroundService.ACTION_TIMER_COMPLETE)
|
||||
)
|
||||
|
||||
// Handle initial intent (cold start)
|
||||
handleIntent(intent)
|
||||
}
|
||||
|
|
@ -252,6 +271,11 @@ class CapacitorMainActivity : BridgeActivity() {
|
|||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(timerCompleteReceiver)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val WINDOW_INTERFACE_PROPERTY: String = "SUPAndroid"
|
||||
const val WINDOW_PROPERTY_F_DROID: String = "SUPFDroid"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.os.IBinder
|
|||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
|
||||
class FocusModeForegroundService : Service() {
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ class FocusModeForegroundService : Service() {
|
|||
const val ACTION_RESUME = "com.superproductivity.ACTION_RESUME_FOCUS"
|
||||
const val ACTION_SKIP = "com.superproductivity.ACTION_SKIP_FOCUS"
|
||||
const val ACTION_COMPLETE = "com.superproductivity.ACTION_COMPLETE_FOCUS"
|
||||
const val ACTION_TIMER_COMPLETE = "com.superproductivity.ACTION_TIMER_COMPLETE_FOCUS"
|
||||
|
||||
const val EXTRA_TITLE = "title"
|
||||
const val EXTRA_TASK_TITLE = "task_title"
|
||||
|
|
@ -40,6 +42,7 @@ class FocusModeForegroundService : Service() {
|
|||
private var isBreak: Boolean = false
|
||||
private var isPaused: Boolean = false
|
||||
private var lastUpdateTimestamp: Long = 0
|
||||
private var hasNotifiedCompletion: Boolean = false
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val updateRunnable = object : Runnable {
|
||||
|
|
@ -52,7 +55,14 @@ class FocusModeForegroundService : Service() {
|
|||
|
||||
if (durationMs > 0) {
|
||||
// Countdown mode: decrease remaining time
|
||||
val previousRemaining = remainingMs
|
||||
remainingMs = (remainingMs - elapsed).coerceAtLeast(0)
|
||||
|
||||
// Check for timer completion (only in countdown mode, not Flowtime)
|
||||
if (remainingMs == 0L && previousRemaining > 0L && !hasNotifiedCompletion) {
|
||||
onTimerComplete()
|
||||
return // Stop the runnable, timer is done
|
||||
}
|
||||
} else {
|
||||
// Flowtime mode: increase elapsed time (remainingMs is actually elapsed)
|
||||
remainingMs += elapsed
|
||||
|
|
@ -123,6 +133,7 @@ class FocusModeForegroundService : Service() {
|
|||
Log.d(TAG, "Starting focus mode: title=$title, durationMs=$durationMs, remainingMs=$remainingMs, isBreak=$isBreak, isPaused=$isPaused")
|
||||
|
||||
isRunning = true
|
||||
hasNotifiedCompletion = false
|
||||
lastUpdateTimestamp = System.currentTimeMillis()
|
||||
|
||||
// Start foreground immediately to avoid ANR
|
||||
|
|
@ -174,6 +185,34 @@ class FocusModeForegroundService : Service() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun onTimerComplete() {
|
||||
Log.d(TAG, "Timer completed! isBreak=$isBreak, title=$title")
|
||||
hasNotifiedCompletion = true
|
||||
|
||||
// Show high-priority completion notification with sound
|
||||
val completionTitle = if (isBreak) "Break Complete" else "Session Complete"
|
||||
val completionMessage = if (isBreak) {
|
||||
"Time to get back to work!"
|
||||
} else {
|
||||
taskTitle?.let { "Great job on: $it" } ?: "Great job! Take a break."
|
||||
}
|
||||
FocusModeNotificationHelper.showCompletionNotification(
|
||||
this,
|
||||
completionTitle,
|
||||
completionMessage,
|
||||
isBreak
|
||||
)
|
||||
|
||||
// Notify the frontend via local broadcast
|
||||
val intent = Intent(ACTION_TIMER_COMPLETE).apply {
|
||||
putExtra(EXTRA_IS_BREAK, isBreak)
|
||||
}
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
|
||||
// Stop the foreground service (timer is done)
|
||||
stopFocusMode()
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
override fun onDestroy() {
|
||||
|
|
|
|||
|
|
@ -6,14 +6,21 @@ import android.app.NotificationManager
|
|||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.AudioAttributes
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.superproductivity.superproductivity.CapacitorMainActivity
|
||||
import com.superproductivity.superproductivity.R
|
||||
|
||||
object FocusModeNotificationHelper {
|
||||
private const val TAG = "FocusModeNotifHelper"
|
||||
const val CHANNEL_ID = "sp_focus_mode_channel"
|
||||
const val COMPLETION_CHANNEL_ID = "sp_focus_complete_channel"
|
||||
const val NOTIFICATION_ID = 1002
|
||||
const val COMPLETION_NOTIFICATION_ID = 1003
|
||||
|
||||
fun createChannel(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
|
|
@ -130,4 +137,95 @@ object FocusModeNotificationHelper {
|
|||
val seconds = totalSeconds % 60
|
||||
return String.format("%d:%02d", minutes, seconds)
|
||||
}
|
||||
|
||||
fun createCompletionChannel(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
|
||||
?: RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
|
||||
val audioAttributes = AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_ALARM)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.build()
|
||||
|
||||
val channel = NotificationChannel(
|
||||
COMPLETION_CHANNEL_ID,
|
||||
"Focus Mode Completion",
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
).apply {
|
||||
description = "Alerts when focus session or break completes"
|
||||
setShowBadge(true)
|
||||
enableVibration(true)
|
||||
vibrationPattern = longArrayOf(0, 500, 200, 500)
|
||||
setSound(alarmSound, audioAttributes)
|
||||
}
|
||||
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
fun showCompletionNotification(
|
||||
context: Context,
|
||||
title: String,
|
||||
message: String,
|
||||
isBreak: Boolean
|
||||
) {
|
||||
Log.d(TAG, "Showing completion notification: title=$title, isBreak=$isBreak")
|
||||
createCompletionChannel(context)
|
||||
|
||||
val contentIntent = Intent(context, CapacitorMainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
}
|
||||
val contentPendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
20,
|
||||
contentIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, COMPLETION_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_stat_sp)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setContentIntent(contentPendingIntent)
|
||||
.setAutoCancel(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setCategory(NotificationCompat.CATEGORY_ALARM)
|
||||
|
||||
if (isBreak) {
|
||||
val skipIntent = Intent(context, CapacitorMainActivity::class.java).apply {
|
||||
action = FocusModeForegroundService.ACTION_SKIP
|
||||
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
}
|
||||
val skipPendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
21,
|
||||
skipIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
builder.addAction(0, "Skip Break", skipPendingIntent)
|
||||
} else {
|
||||
val completeIntent = Intent(context, CapacitorMainActivity::class.java).apply {
|
||||
action = FocusModeForegroundService.ACTION_COMPLETE
|
||||
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
}
|
||||
val completePendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
22,
|
||||
completeIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
builder.addAction(0, "Complete", completePendingIntent)
|
||||
}
|
||||
|
||||
try {
|
||||
NotificationManagerCompat.from(context).notify(COMPLETION_NOTIFICATION_ID, builder.build())
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "No permission to show completion notification", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelCompletionNotification(context: Context) {
|
||||
NotificationManagerCompat.from(context).cancel(COMPLETION_NOTIFICATION_ID)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
188
docs/unused-translations-analysis.md
Normal file
188
docs/unused-translations-analysis.md
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
# Unused Translations Deep Analysis
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Out of 350 "unused" translation keys, the analysis reveals:
|
||||
|
||||
| Category | Count | Root Cause | Recommended Action |
|
||||
| ------------------------- | ----- | --------------------------------- | ---------------------- |
|
||||
| **Orphan duplicates** | ~54 | Keys at wrong JSON path | Delete duplicates |
|
||||
| **Never implemented** | ~43 | Features never built | Delete |
|
||||
| **Dynamic object access** | ~18 | Scanner limitation | Keep (false positives) |
|
||||
| **Planned/incomplete** | ~50 | Prepared for future | Review case-by-case |
|
||||
| **Hardcoded strings** | ~5 | Code uses English instead of T.\* | Fix code |
|
||||
| **Needs investigation** | ~180 | Various causes | Case-by-case review |
|
||||
|
||||
---
|
||||
|
||||
## Category 1: Orphan Duplicates (Safe to Delete)
|
||||
|
||||
Keys that exist at the wrong JSON path - the correct keys exist elsewhere with actual translations.
|
||||
|
||||
### F.SAFETY_BACKUP.\* (32 keys)
|
||||
|
||||
**Problem:** Duplicates of `F.SYNC.SAFETY_BACKUP.*`
|
||||
**Evidence:** `F.SAFETY_BACKUP.*` has empty strings, `F.SYNC.SAFETY_BACKUP.*` has actual translations and is used in code.
|
||||
|
||||
```
|
||||
F.SAFETY_BACKUP.BACKUP_NOT_FOUND → Delete (F.SYNC.SAFETY_BACKUP.BACKUP_NOT_FOUND is used)
|
||||
F.SAFETY_BACKUP.BTN_CLEAR_ALL → Delete (F.SYNC.SAFETY_BACKUP.BTN_CLEAR_ALL is used)
|
||||
... (all 32 keys)
|
||||
```
|
||||
|
||||
### GCF.PAST.\* (11 keys)
|
||||
|
||||
**Problem:** Duplicates of `GLOBAL_RELATIVE_TIME.PAST.*`
|
||||
**Evidence:** `humanize-timestamp.ts` uses `T.GLOBAL_RELATIVE_TIME.PAST.*`, not `T.GCF.PAST.*`
|
||||
|
||||
```
|
||||
GCF.PAST.AN_HOUR → Delete (GLOBAL_RELATIVE_TIME.PAST.AN_HOUR is used)
|
||||
GCF.PAST.A_DAY → Delete (GLOBAL_RELATIVE_TIME.PAST.A_DAY is used)
|
||||
... (all 11 keys)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Category 2: Never Implemented Features (Safe to Delete)
|
||||
|
||||
### F.PROCRASTINATION.\* (32 keys)
|
||||
|
||||
**Problem:** Entire feature never implemented
|
||||
**Evidence:** No files exist in `src/app/features/procrastination/`, no component uses these keys
|
||||
|
||||
```
|
||||
F.PROCRASTINATION.BACK_TO_WORK
|
||||
F.PROCRASTINATION.COMP.INTRO
|
||||
F.PROCRASTINATION.COMP.L1-L4
|
||||
F.PROCRASTINATION.CUR.*
|
||||
F.PROCRASTINATION.REFRAME.*
|
||||
F.PROCRASTINATION.SPLIT_UP.*
|
||||
... (all 32 keys)
|
||||
```
|
||||
|
||||
### GCF.TIMELINE.\* (10 keys)
|
||||
|
||||
**Problem:** Timeline settings form never implemented
|
||||
**Evidence:** No `timeline-form.const.ts` exists, no code references these keys
|
||||
|
||||
```
|
||||
GCF.TIMELINE.CAL_PROVIDERS
|
||||
GCF.TIMELINE.L_IS_WORK_START_END_ENABLED
|
||||
... (all 10 keys)
|
||||
```
|
||||
|
||||
### WW.HELP_PROCRASTINATION (1 key)
|
||||
|
||||
**Problem:** Related to unimplemented procrastination feature
|
||||
|
||||
---
|
||||
|
||||
## Category 3: Dynamic Object Access (False Positives - Keep)
|
||||
|
||||
Scanner cannot detect when `T.F.SECTION` is assigned to a variable and children accessed dynamically.
|
||||
|
||||
### F.TAG_FOLDER.\* (9 keys)
|
||||
|
||||
**Evidence:** `folder-context-menu.component.ts:40`:
|
||||
|
||||
```typescript
|
||||
const folderNs =
|
||||
this.treeKind === MenuTreeKind.PROJECT ? T.F.PROJECT_FOLDER : T.F.TAG_FOLDER;
|
||||
// Then: folderNs.DIALOG.NAME_LABEL
|
||||
```
|
||||
|
||||
**Action:** Keep all 9 keys
|
||||
|
||||
### F.PROJECT_FOLDER.\* (9 keys)
|
||||
|
||||
**Evidence:** Same pattern as TAG_FOLDER
|
||||
**Action:** Keep all 9 keys
|
||||
|
||||
---
|
||||
|
||||
## Category 4: Hardcoded English Strings (Fix Code)
|
||||
|
||||
Translation keys exist but code uses hardcoded English instead.
|
||||
|
||||
### F.TASK*REPEAT.F.SCHEDULE_TYPE*\* (2 keys)
|
||||
|
||||
**Location:** `task-repeat-cfg-form.const.ts:126-133`
|
||||
**Problem:**
|
||||
|
||||
```typescript
|
||||
// Currently:
|
||||
{ value: false, label: `Fixed schedule (every ${repeatEvery} ${cycleName} from start date)` }
|
||||
// Should use:
|
||||
{ value: false, label: T.F.TASK_REPEAT.F.SCHEDULE_TYPE_FIXED }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Category 5: Planned/Incomplete Features (Review Case-by-Case)
|
||||
|
||||
### F.FOCUS_MODE.\* (11 unused keys)
|
||||
|
||||
Some focus mode keys are used, but these 11 appear to be for planned extensions:
|
||||
|
||||
- `F.FOCUS_MODE.GO_TO_PROCRASTINATION` - links to unimplemented feature
|
||||
- `F.FOCUS_MODE.CONTINUE_SESSION` - may be planned UI element
|
||||
- `F.FOCUS_MODE.CONGRATS` - may be planned celebration screen
|
||||
|
||||
### F.SYNC.\* (36 keys, excluding SAFETY_BACKUP)
|
||||
|
||||
Many sync-related keys for edge cases, error states, or dialogs that may be partially implemented.
|
||||
|
||||
### F.METRIC.\* (21 keys)
|
||||
|
||||
Evaluation form and reflection keys - some may be for planned features.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Cleanup Script
|
||||
|
||||
```javascript
|
||||
// Add to tools/cleanup-unused-translations.js
|
||||
|
||||
const SECTIONS_TO_REMOVE = [
|
||||
'ANDROID', // Already removed
|
||||
'THEMES', // Already removed
|
||||
'PROCRASTINATION', // Never implemented
|
||||
];
|
||||
|
||||
const NESTED_PATHS_TO_REMOVE = [
|
||||
['F', 'CALDAV', 'ISSUE_CONTENT'], // Already removed
|
||||
['F', 'SAFETY_BACKUP'], // Duplicate of F.SYNC.SAFETY_BACKUP
|
||||
['GCF', 'PAST'], // Duplicate of GLOBAL_RELATIVE_TIME.PAST
|
||||
['GCF', 'TIMELINE'], // Never implemented
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scanner Enhancement Recommendation
|
||||
|
||||
To reduce false positives from dynamic object access, enhance `find-unused-translations.js`:
|
||||
|
||||
```javascript
|
||||
// Add detection for pattern: T.F.SECTION_NAME (without trailing dot)
|
||||
// indicating the whole section object is referenced
|
||||
function detectDynamicObjectAccess(content) {
|
||||
const pattern = /T\.([A-Z_]+(?:\.[A-Z_]+)*)[^.A-Z_]/g;
|
||||
// ... mark all children of matched sections as "potentially used"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary of Immediate Safe Deletions
|
||||
|
||||
| Section | Keys | Reason |
|
||||
| ----------------------- | ------ | -------------------------------------- |
|
||||
| F.SAFETY_BACKUP.\* | 32 | Duplicate of F.SYNC.SAFETY_BACKUP |
|
||||
| F.PROCRASTINATION.\* | 32 | Feature never implemented |
|
||||
| GCF.PAST.\* | 11 | Duplicate of GLOBAL_RELATIVE_TIME.PAST |
|
||||
| GCF.TIMELINE.\* | 10 | Feature never implemented |
|
||||
| WW.HELP_PROCRASTINATION | 1 | Related to unimplemented feature |
|
||||
| **TOTAL** | **86** | Safe to delete immediately |
|
||||
|
||||
After this cleanup: ~264 keys remaining for case-by-case review.
|
||||
129
e2e/tests/task-basic/task-delete-confirmation.spec.ts
Normal file
129
e2e/tests/task-basic/task-delete-confirmation.spec.ts
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import { test, expect } from '../../fixtures/test.fixture';
|
||||
|
||||
/**
|
||||
* Tests for Issue #5942: Prevent Unintended Task Deletions via Backspace
|
||||
* Tests the confirmation dialog when deleting tasks
|
||||
*/
|
||||
test.describe('Task Delete Confirmation', () => {
|
||||
test('should show confirmation dialog when deleting task via context menu (default setting)', async ({
|
||||
page,
|
||||
workViewPage,
|
||||
}) => {
|
||||
// Setup: Create a task
|
||||
await workViewPage.waitForTaskList();
|
||||
await workViewPage.addTask('Task to delete');
|
||||
await expect(page.locator('task')).toHaveCount(1);
|
||||
|
||||
// Act: Right-click and select delete
|
||||
await page.locator('task').first().click({ button: 'right' });
|
||||
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
||||
|
||||
// Assert: Confirmation dialog should appear (isConfirmBeforeTaskDelete defaults to true)
|
||||
const dialog = page.locator('mat-dialog-container');
|
||||
await expect(dialog).toBeVisible({ timeout: 3000 });
|
||||
|
||||
// Verify dialog content mentions the task title
|
||||
await expect(dialog).toContainText('Task to delete');
|
||||
|
||||
// Verify confirm button exists
|
||||
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
||||
await expect(confirmBtn).toBeVisible();
|
||||
});
|
||||
|
||||
test('should delete task when confirmation is accepted', async ({
|
||||
page,
|
||||
workViewPage,
|
||||
}) => {
|
||||
// Setup: Create a task
|
||||
await workViewPage.waitForTaskList();
|
||||
await workViewPage.addTask('Task to delete');
|
||||
await expect(page.locator('task')).toHaveCount(1);
|
||||
|
||||
// Act: Right-click, select delete, and confirm
|
||||
await page.locator('task').first().click({ button: 'right' });
|
||||
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
||||
|
||||
// Wait for dialog and confirm
|
||||
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
||||
await confirmBtn.waitFor({ state: 'visible', timeout: 3000 });
|
||||
await confirmBtn.click();
|
||||
|
||||
// Assert: Task should be deleted
|
||||
await expect(page.locator('task')).toHaveCount(0, { timeout: 5000 });
|
||||
});
|
||||
|
||||
test('should NOT delete task when confirmation is cancelled', async ({
|
||||
page,
|
||||
workViewPage,
|
||||
}) => {
|
||||
// Setup: Create a task
|
||||
await workViewPage.waitForTaskList();
|
||||
await workViewPage.addTask('Task to keep');
|
||||
await expect(page.locator('task')).toHaveCount(1);
|
||||
|
||||
// Act: Right-click, select delete, but cancel
|
||||
await page.locator('task').first().click({ button: 'right' });
|
||||
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
||||
|
||||
// Wait for dialog and cancel
|
||||
const dialog = page.locator('mat-dialog-container');
|
||||
await dialog.waitFor({ state: 'visible', timeout: 3000 });
|
||||
|
||||
// Click cancel button (first button in dialog actions)
|
||||
const cancelBtn = dialog.locator('button').first();
|
||||
await cancelBtn.click();
|
||||
|
||||
// Assert: Task should NOT be deleted
|
||||
await expect(page.locator('task')).toHaveCount(1);
|
||||
await expect(page.locator('task')).toContainText('Task to keep');
|
||||
});
|
||||
|
||||
test('should delete task via keyboard shortcut with confirmation', async ({
|
||||
page,
|
||||
workViewPage,
|
||||
}) => {
|
||||
// Setup: Create a task
|
||||
await workViewPage.waitForTaskList();
|
||||
await workViewPage.addTask('Task to delete with keyboard');
|
||||
await expect(page.locator('task')).toHaveCount(1);
|
||||
|
||||
// Focus the task
|
||||
await page.locator('task').first().click();
|
||||
|
||||
// Act: Press Backspace (default delete shortcut)
|
||||
await page.keyboard.press('Backspace');
|
||||
|
||||
// Assert: Confirmation dialog should appear
|
||||
const dialog = page.locator('mat-dialog-container');
|
||||
await expect(dialog).toBeVisible({ timeout: 3000 });
|
||||
|
||||
// Confirm deletion
|
||||
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
||||
await confirmBtn.click();
|
||||
|
||||
// Task should be deleted
|
||||
await expect(page.locator('task')).toHaveCount(0, { timeout: 5000 });
|
||||
});
|
||||
|
||||
test('should show undo snackbar after confirmed deletion', async ({
|
||||
page,
|
||||
workViewPage,
|
||||
}) => {
|
||||
// Setup: Create a task
|
||||
await workViewPage.waitForTaskList();
|
||||
await workViewPage.addTask('Task with undo');
|
||||
await expect(page.locator('task')).toHaveCount(1);
|
||||
|
||||
// Act: Delete with confirmation
|
||||
await page.locator('task').first().click({ button: 'right' });
|
||||
await page.locator('.mat-mdc-menu-content button.color-warn').click();
|
||||
|
||||
const confirmBtn = page.locator('[e2e="confirmBtn"]');
|
||||
await confirmBtn.waitFor({ state: 'visible', timeout: 3000 });
|
||||
await confirmBtn.click();
|
||||
|
||||
// Assert: Undo snackbar should appear
|
||||
const snackbar = page.locator('mat-snack-bar-container');
|
||||
await expect(snackbar).toBeVisible({ timeout: 3000 });
|
||||
});
|
||||
});
|
||||
|
|
@ -76,6 +76,7 @@
|
|||
"int:clean": "ngx-translate-extract --input ./src --output ./src/assets/i18n/*.json --clean --sort --format namespaced-json --marker _",
|
||||
"int:find": "ngx-translate-extract --input ./src --output ./src/assets/i18n/*.json --sort --format namespaced-json --marker _",
|
||||
"int:test": "node ./tools/test-lng-files.js",
|
||||
"int:unused": "node ./tools/find-unused-translations.js",
|
||||
"int:watch": "node ./tools/extract-i18n-watch.js",
|
||||
"lint": "npm run lint:ts && npm run lint:scss",
|
||||
"lint:ts": "ng lint",
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ export interface AndroidInterface {
|
|||
onFocusResume$: Subject<void>;
|
||||
onFocusSkip$: Subject<void>;
|
||||
onFocusComplete$: Subject<void>;
|
||||
|
||||
// Focus mode timer completion (native service detected timer reached 0)
|
||||
onFocusModeTimerComplete$: Subject<boolean>; // boolean indicates isBreak
|
||||
}
|
||||
|
||||
// setInterval(() => {
|
||||
|
|
@ -118,6 +121,7 @@ if (IS_ANDROID_WEB_VIEW) {
|
|||
androidInterface.onFocusResume$ = new Subject();
|
||||
androidInterface.onFocusSkip$ = new Subject();
|
||||
androidInterface.onFocusComplete$ = new Subject();
|
||||
androidInterface.onFocusModeTimerComplete$ = new Subject();
|
||||
androidInterface.onShareWithAttachment$ = new ReplaySubject(1);
|
||||
androidInterface.isKeyboardShown$ = new BehaviorSubject(false);
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,29 @@ export class AndroidFocusModeEffects {
|
|||
),
|
||||
);
|
||||
|
||||
// Handle native timer completion (when native service detects timer reached 0 in background)
|
||||
handleNativeTimerComplete$ =
|
||||
IS_ANDROID_WEB_VIEW &&
|
||||
createEffect(() =>
|
||||
androidInterface.onFocusModeTimerComplete$.pipe(
|
||||
tap((isBreak) =>
|
||||
DroidLog.log(
|
||||
'AndroidFocusModeEffects: Native timer complete received, isBreak=' + isBreak,
|
||||
),
|
||||
),
|
||||
withLatestFrom(this._store.select(selectPausedTaskId)),
|
||||
map(([isBreak, pausedTaskId]) => {
|
||||
if (isBreak) {
|
||||
// Break timer completed, skip the break (go back to work)
|
||||
return focusModeActions.skipBreak({ pausedTaskId });
|
||||
} else {
|
||||
// Work session completed
|
||||
return focusModeActions.completeFocusSession({ isManual: false });
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
private _safeNativeCall(fn: () => void, errorMsg: string, showSnackbar = false): void {
|
||||
try {
|
||||
fn();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
class="width100"
|
||||
[hideRequiredMarker]="true"
|
||||
>
|
||||
<mat-label>{{ 'GCF.SOUND.VOLUME' | translate }}</mat-label>
|
||||
<mat-label>{{ T.GCF.SOUND.VOLUME | translate }}</mat-label>
|
||||
<mat-slider
|
||||
class="width100"
|
||||
[min]="0"
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
</mat-slider>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="width100">
|
||||
<mat-label>{{ 'GCF.SOUND.DONE_SOUND' | translate }}</mat-label>
|
||||
<mat-label>{{ T.GCF.SOUND.DONE_SOUND | translate }}</mat-label>
|
||||
<mat-select formControlName="doneSound">
|
||||
@for (sound of soundOpts; track sound) {
|
||||
<mat-option [value]="sound.value">{{ sound.label }}</mat-option>
|
||||
|
|
@ -42,11 +42,11 @@
|
|||
matInput
|
||||
[checked]="this.config?.isIncreaseDoneSoundPitch"
|
||||
formControlName="isIncreaseDoneSoundPitch"
|
||||
>{{ 'GCF.SOUND.IS_INCREASE_DONE_PITCH' | translate }}</mat-slide-toggle
|
||||
>{{ T.GCF.SOUND.IS_INCREASE_DONE_PITCH | translate }}</mat-slide-toggle
|
||||
>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="width100">
|
||||
<mat-label>{{ 'GCF.SOUND.BREAK_REMINDER_SOUND' | translate }}</mat-label>
|
||||
<mat-label>{{ T.GCF.SOUND.BREAK_REMINDER_SOUND | translate }}</mat-label>
|
||||
<mat-select formControlName="breakReminderSound">
|
||||
@for (sound of soundOpts; track sound) {
|
||||
<mat-option [value]="sound.value">{{ sound.label }}</mat-option>
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="width100">
|
||||
<mat-label>{{ 'GCF.SOUND.TRACK_TIME_SOUND' | translate }}</mat-label>
|
||||
<mat-label>{{ T.GCF.SOUND.TRACK_TIME_SOUND | translate }}</mat-label>
|
||||
<mat-select formControlName="trackTimeSound">
|
||||
@for (sound of soundOpts; track sound) {
|
||||
<mat-option [value]="sound.value">{{ sound.label }}</mat-option>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { MatSelect } from '@angular/material/select';
|
|||
import { MatOption } from '@angular/material/core';
|
||||
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
const sectionKey = 'sound';
|
||||
|
||||
|
|
@ -62,7 +63,8 @@ export class ConfigSoundFormComponent {
|
|||
|
||||
soundOpts = SOUND_OPTS;
|
||||
config?: SoundConfig;
|
||||
title = 'GCF.SOUND.TITLE';
|
||||
title = T.GCF.SOUND.TITLE;
|
||||
readonly T = T;
|
||||
private isInitializing = true;
|
||||
|
||||
constructor() {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
|
|||
misc: {
|
||||
isConfirmBeforeExit: false,
|
||||
isConfirmBeforeExitWithoutFinishDay: true,
|
||||
isConfirmBeforeTaskDelete: true,
|
||||
isAutMarkParentAsDone: false,
|
||||
isTurnOffMarkdown: false,
|
||||
isAutoAddWorkedOnToToday: true,
|
||||
|
|
@ -173,6 +174,7 @@ export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
|
|||
isCountdownBannerEnabled: true,
|
||||
countdownDuration: minute * 10,
|
||||
defaultTaskRemindOption: TaskReminderOptionId.AtStart, // The hard-coded default prior to this changeable setting
|
||||
isFocusWindow: false,
|
||||
},
|
||||
schedule: {
|
||||
isWorkStartEndEnabled: true,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ export const MISC_SETTINGS_FORM_CFG: ConfigFormSection<MiscConfig> = {
|
|||
},
|
||||
},
|
||||
]) as LimitedFormlyFieldConfig<MiscConfig>[]),
|
||||
{
|
||||
key: 'isConfirmBeforeTaskDelete',
|
||||
type: 'checkbox',
|
||||
templateOptions: {
|
||||
label: T.GCF.MISC.IS_CONFIRM_BEFORE_TASK_DELETE,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'isAutMarkParentAsDone',
|
||||
type: 'checkbox',
|
||||
|
|
|
|||
|
|
@ -40,5 +40,12 @@ export const REMINDER_FORM_CFG: ConfigFormSection<ReminderConfig> = {
|
|||
label: T.GCF.REMINDER.DISABLE_REMINDERS,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'isFocusWindow',
|
||||
type: 'checkbox',
|
||||
templateOptions: {
|
||||
label: T.GCF.REMINDER.IS_FOCUS_WINDOW,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export type MiscConfig = Readonly<{
|
|||
isAutMarkParentAsDone: boolean;
|
||||
isConfirmBeforeExit: boolean;
|
||||
isConfirmBeforeExitWithoutFinishDay: boolean;
|
||||
isConfirmBeforeTaskDelete?: boolean;
|
||||
isTurnOffMarkdown: boolean;
|
||||
isAutoAddWorkedOnToToday: boolean;
|
||||
isMinimizeToTray: boolean;
|
||||
|
|
@ -178,6 +179,7 @@ export type ReminderConfig = Readonly<{
|
|||
countdownDuration: number;
|
||||
defaultTaskRemindOption?: TaskReminderOptionId;
|
||||
disableReminders?: boolean;
|
||||
isFocusWindow?: boolean;
|
||||
}>;
|
||||
|
||||
export type TrackingReminderConfigOld = Readonly<{
|
||||
|
|
|
|||
|
|
@ -109,14 +109,14 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
)
|
||||
: issue.comments;
|
||||
|
||||
// TODO: we also need to handle the case when the user himself updated the issue, to also update the issue...
|
||||
const updates: number[] = [
|
||||
...commentsByOthers.map((comment) => new Date(comment.created_at).getTime()),
|
||||
issueUpdate,
|
||||
].sort();
|
||||
const lastRemoteUpdate = updates[updates.length - 1];
|
||||
const commentUpdates: number[] = commentsByOthers
|
||||
.map((comment) => new Date(comment.created_at).getTime())
|
||||
.sort();
|
||||
const newestCommentUpdate = commentUpdates[commentUpdates.length - 1];
|
||||
|
||||
const wasUpdated = lastRemoteUpdate > (task.issueLastUpdated || 0);
|
||||
const wasUpdated =
|
||||
(newestCommentUpdate && newestCommentUpdate > (task.issueLastUpdated || 0)) ||
|
||||
issueUpdate > (task.issueLastUpdated || 0);
|
||||
|
||||
if (wasUpdated) {
|
||||
return {
|
||||
|
|
@ -134,53 +134,27 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
async getFreshDataForIssueTasks(
|
||||
tasks: Task[],
|
||||
): Promise<{ task: Task; taskChanges: Partial<Task>; issue: GitlabIssue }[]> {
|
||||
const issueProviderId =
|
||||
tasks && tasks[0].issueProviderId ? tasks[0].issueProviderId : 0;
|
||||
if (!issueProviderId) {
|
||||
throw new Error('No issueProviderId');
|
||||
}
|
||||
|
||||
const cfg = await this._getCfgOnce$(issueProviderId).toPromise();
|
||||
|
||||
const updatedIssues: {
|
||||
task: Task;
|
||||
taskChanges: Partial<Task>;
|
||||
issue: GitlabIssue;
|
||||
}[] = [];
|
||||
|
||||
for (const task of tasks) {
|
||||
if (!task.issueId) {
|
||||
continue;
|
||||
}
|
||||
const issue = await this._gitlabApiService.getById$(task.issueId, cfg).toPromise();
|
||||
if (issue) {
|
||||
const issueUpdate: number = new Date(issue.updated_at).getTime();
|
||||
const commentsByOthers =
|
||||
cfg.filterUsername && cfg.filterUsername.length > 1
|
||||
? issue.comments.filter(
|
||||
(comment) => comment.author.username !== cfg.filterUsername,
|
||||
)
|
||||
: issue.comments;
|
||||
|
||||
const updates: number[] = [
|
||||
...commentsByOthers.map((comment) => new Date(comment.created_at).getTime()),
|
||||
issueUpdate,
|
||||
].sort();
|
||||
const lastRemoteUpdate = updates[updates.length - 1];
|
||||
const wasUpdated = lastRemoteUpdate > (task.issueLastUpdated || 0);
|
||||
if (wasUpdated) {
|
||||
updatedIssues.push({
|
||||
return Promise.all(
|
||||
tasks.map((task) =>
|
||||
this.getFreshDataForIssueTask(task).then((refreshDataForTask) => ({
|
||||
task,
|
||||
refreshDataForTask,
|
||||
})),
|
||||
),
|
||||
).then((items) => {
|
||||
return items
|
||||
.filter(({ refreshDataForTask }) => !!refreshDataForTask)
|
||||
.map(({ refreshDataForTask, task }) => {
|
||||
if (!refreshDataForTask) {
|
||||
throw new Error('No refresh data for task js error');
|
||||
}
|
||||
return {
|
||||
task,
|
||||
taskChanges: {
|
||||
...this.getAddTaskData(issue),
|
||||
issueWasUpdated: true,
|
||||
},
|
||||
issue,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return updatedIssues;
|
||||
taskChanges: refreshDataForTask.taskChanges,
|
||||
issue: refreshDataForTask.issue,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getAddTaskData(issue: GitlabIssue): Partial<Task> & { title: string } {
|
||||
|
|
|
|||
|
|
@ -20,47 +20,7 @@
|
|||
</div>
|
||||
|
||||
@if (heatmapData(); as data) {
|
||||
<div class="heatmap-container">
|
||||
<div class="heatmap-grid">
|
||||
<div class="day-labels">
|
||||
<div class="month-spacer"></div>
|
||||
@for (label of dayLabels(); track $index) {
|
||||
<div class="day-label">{{ label }}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="scrollable-content">
|
||||
<div class="heatmap-months">
|
||||
@for (month of data.monthLabels; track $index) {
|
||||
<div class="month-label">{{ month }}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="weeks">
|
||||
@for (week of data.weeks; track $index) {
|
||||
<div class="week">
|
||||
@for (day of week.days; track $index) {
|
||||
<div
|
||||
[class]="getDayClass(day)"
|
||||
[title]="getDayTitle(day)"
|
||||
></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="heatmap-legend">
|
||||
<span>Less</span>
|
||||
<div class="legend-item level-0"></div>
|
||||
<div class="legend-item level-1"></div>
|
||||
<div class="legend-item level-2"></div>
|
||||
<div class="legend-item level-3"></div>
|
||||
<div class="legend-item level-4"></div>
|
||||
<span>More</span>
|
||||
</div>
|
||||
</div>
|
||||
<heatmap [data]="data" />
|
||||
} @else {
|
||||
<p>{{ T.F.METRIC.CMP.NO_ADDITIONAL_DATA_YET | translate }}</p>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,215 +35,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.heatmap-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
background: var(--c-dark-10);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.heatmap-grid {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.scrollable-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
// Smooth scrolling
|
||||
scroll-behavior: smooth;
|
||||
|
||||
// Better scrollbar styling
|
||||
&::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--c-dark-10);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--c-dark-20);
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: var(--c-dark-30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.heatmap-months {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
height: 12px;
|
||||
color: var(--text-color-muted);
|
||||
flex-shrink: 0;
|
||||
|
||||
.month-label {
|
||||
flex: 0 0 auto;
|
||||
width: calc(4 * 12px + 4 * 2px); // 4 weeks * (cell width + gap)
|
||||
}
|
||||
}
|
||||
|
||||
.day-labels {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
font-size: 10px;
|
||||
color: var(--text-color-muted);
|
||||
padding-right: 4px;
|
||||
width: 40px;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
|
||||
.month-spacer {
|
||||
height: 17px; // 12px (heatmap-months height) + 8px (gap in scrollable-content)
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.day-label {
|
||||
height: 12px;
|
||||
line-height: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.weeks {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
flex-wrap: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.week {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.day {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.empty {
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&.level-0 {
|
||||
background: var(--c-dark-10);
|
||||
}
|
||||
|
||||
&.level-1 {
|
||||
background: color-mix(in srgb, var(--c-primary) 20%, transparent);
|
||||
}
|
||||
|
||||
&.level-2 {
|
||||
background: color-mix(in srgb, var(--c-primary) 40%, transparent);
|
||||
}
|
||||
|
||||
&.level-3 {
|
||||
background: color-mix(in srgb, var(--c-primary) 60%, transparent);
|
||||
}
|
||||
|
||||
&.level-4 {
|
||||
background: var(--c-primary);
|
||||
}
|
||||
|
||||
&:not(.empty):hover {
|
||||
transform: scale(1.3);
|
||||
outline: 1px solid var(--c-dark-20);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.heatmap-legend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
font-size: 11px;
|
||||
color: var(--text-color-muted);
|
||||
padding-right: 4px;
|
||||
|
||||
span {
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
|
||||
&.level-0 {
|
||||
background: var(--c-dark-10);
|
||||
}
|
||||
|
||||
&.level-1 {
|
||||
background: color-mix(in srgb, var(--c-primary) 20%, transparent);
|
||||
}
|
||||
|
||||
&.level-2 {
|
||||
background: color-mix(in srgb, var(--c-primary) 40%, transparent);
|
||||
}
|
||||
|
||||
&.level-3 {
|
||||
background: color-mix(in srgb, var(--c-primary) 60%, transparent);
|
||||
}
|
||||
|
||||
&.level-4 {
|
||||
background: var(--c-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dark theme support
|
||||
:host-context(.isDarkTheme) {
|
||||
.heatmap-container {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
|
||||
.scrollable-content {
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--c-light-10);
|
||||
|
||||
&:hover {
|
||||
background: var(--c-light-33);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.day {
|
||||
&.level-0 {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
|
||||
&:not(.empty):hover {
|
||||
outline-color: var(--c-light-10);
|
||||
}
|
||||
}
|
||||
|
||||
.heatmap-legend .legend-item.level-0 {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,25 +22,18 @@ import { MatIcon } from '@angular/material/icon';
|
|||
import { SnackService } from '../../../core/snack/snack.service';
|
||||
import { ShareService } from '../../../core/share/share.service';
|
||||
import { DateAdapter } from '@angular/material/core';
|
||||
|
||||
interface DayData {
|
||||
date: Date;
|
||||
dateStr: string;
|
||||
taskCount: number;
|
||||
timeSpent: number;
|
||||
level: number; // 0-4 for color intensity
|
||||
}
|
||||
|
||||
interface WeekData {
|
||||
days: (DayData | null)[];
|
||||
}
|
||||
import {
|
||||
DayData,
|
||||
WeekData,
|
||||
HeatmapComponent,
|
||||
} from '../../../ui/heatmap/heatmap.component';
|
||||
|
||||
@Component({
|
||||
selector: 'activity-heatmap',
|
||||
templateUrl: './activity-heatmap.component.html',
|
||||
styleUrls: ['./activity-heatmap.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [TranslatePipe, MatIconButton, MatTooltip, MatIcon],
|
||||
imports: [TranslatePipe, MatIconButton, MatTooltip, MatIcon, HeatmapComponent],
|
||||
})
|
||||
export class ActivityHeatmapComponent {
|
||||
private readonly _worklogService = inject(WorklogService);
|
||||
|
|
@ -410,30 +403,6 @@ export class ActivityHeatmapComponent {
|
|||
return { weeks, monthLabels };
|
||||
}
|
||||
|
||||
getDayClass(day: DayData | null): string {
|
||||
if (!day) {
|
||||
return 'day empty';
|
||||
}
|
||||
return `day level-${day.level}`;
|
||||
}
|
||||
|
||||
getDayTitle(day: DayData | null): string {
|
||||
if (!day) {
|
||||
return '';
|
||||
}
|
||||
return `${day.dateStr}: ${day.taskCount} tasks, ${this._formatTime(day.timeSpent)}`;
|
||||
}
|
||||
|
||||
private _formatTime(ms: number): string {
|
||||
const hours = Math.floor(ms / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60));
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`;
|
||||
}
|
||||
return `${minutes}m`;
|
||||
}
|
||||
|
||||
async shareHeatmap(): Promise<void> {
|
||||
const data = this.heatmapData();
|
||||
if (!data) {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
@if (enableTimeframeSelector()) {
|
||||
<div class="timeframe-selector">
|
||||
<span class="timeframe-label">
|
||||
{{ 'F.METRIC.CMP.TIME_FRAME_LABEL' | translate }}
|
||||
{{ T.F.METRIC.CMP.TIME_FRAME_LABEL | translate }}
|
||||
</span>
|
||||
<mat-radio-group
|
||||
class="timeframe-radios"
|
||||
[value]="selectedTimeframe()"
|
||||
(change)="onTimeframeRadioChange($event)"
|
||||
[attr.aria-label]="'F.METRIC.CMP.TIME_FRAME_LABEL' | translate"
|
||||
[attr.aria-label]="T.F.METRIC.CMP.TIME_FRAME_LABEL | translate"
|
||||
>
|
||||
@for (option of timeframeOptions; track option.id) {
|
||||
<mat-radio-button [value]="option.id">
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
type="button"
|
||||
(click)="shareChart()"
|
||||
[disabled]="!isModuleLoaded() || isSharing()"
|
||||
[matTooltip]="'Share Chart' | translate"
|
||||
[matTooltip]="T.G.SHARE | translate"
|
||||
>
|
||||
@if (isSharing()) {
|
||||
<mat-icon>hourglass_empty</mat-icon>
|
||||
|
|
|
|||
|
|
@ -47,17 +47,17 @@ interface TimeframeOption {
|
|||
const TIMEFRAME_OPTIONS: ReadonlyArray<TimeframeOption> = [
|
||||
{
|
||||
id: 'twoWeeks',
|
||||
labelKey: 'F.METRIC.CMP.TIME_FRAME_2_WEEKS',
|
||||
labelKey: T.F.METRIC.CMP.TIME_FRAME_2_WEEKS,
|
||||
limit: 14,
|
||||
},
|
||||
{
|
||||
id: 'oneMonth',
|
||||
labelKey: 'F.METRIC.CMP.TIME_FRAME_1_MONTH',
|
||||
labelKey: T.F.METRIC.CMP.TIME_FRAME_1_MONTH,
|
||||
limit: 30,
|
||||
},
|
||||
{
|
||||
id: 'max',
|
||||
labelKey: 'F.METRIC.CMP.TIME_FRAME_MAX',
|
||||
labelKey: T.F.METRIC.CMP.TIME_FRAME_MAX,
|
||||
limit: null,
|
||||
},
|
||||
];
|
||||
|
|
@ -98,6 +98,7 @@ export class LazyChartComponent implements OnDestroy {
|
|||
readonly isModuleLoaded = signal(false);
|
||||
readonly isSharing = signal(false);
|
||||
readonly timeframeOptions = TIMEFRAME_OPTIONS;
|
||||
readonly T = T;
|
||||
|
||||
readonly selectedTimeframe = signal<LazyChartTimeframe>('max');
|
||||
private readonly activeTimeframe = computed<LazyChartTimeframe>(() =>
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@ describe('DialogScheduleTaskComponent - Select Due Only Mode', () => {
|
|||
initialState: {
|
||||
[CONFIG_FEATURE_NAME]: {
|
||||
sync: {},
|
||||
localization: {
|
||||
lng: undefined,
|
||||
dateTimeLocale: undefined,
|
||||
firstDayOfWeek: 0,
|
||||
},
|
||||
} as any,
|
||||
},
|
||||
}),
|
||||
|
|
@ -170,6 +175,7 @@ describe('DialogScheduleTaskComponent - Select Due Only Mode', () => {
|
|||
});
|
||||
|
||||
it('should set selectedDate to targetDay on initialization', async () => {
|
||||
fixture.detectChanges();
|
||||
await component.ngAfterViewInit();
|
||||
|
||||
const expectedDate = dateStrToUtcDate('2024-01-15');
|
||||
|
|
@ -191,6 +197,7 @@ describe('DialogScheduleTaskComponent - Select Due Only Mode', () => {
|
|||
});
|
||||
|
||||
it('should not have initial selectedDate when no targetDay provided', async () => {
|
||||
fixture.detectChanges();
|
||||
await component.ngAfterViewInit();
|
||||
|
||||
// selectedDate should be null since no targetDay was provided
|
||||
|
|
|
|||
|
|
@ -31,12 +31,14 @@
|
|||
</div>
|
||||
|
||||
<mat-dialog-content>
|
||||
<mat-calendar
|
||||
(keydown)="onKeyDownOnCalendar($event)"
|
||||
[selected]="selectedDate"
|
||||
[minDate]="minDate"
|
||||
(selectedChange)="dateSelected($event)"
|
||||
></mat-calendar>
|
||||
@if (isConfigReady()) {
|
||||
<mat-calendar
|
||||
(keydown)="onKeyDownOnCalendar($event)"
|
||||
[selected]="selectedDate"
|
||||
[minDate]="minDate"
|
||||
(selectedChange)="dateSelected($event)"
|
||||
></mat-calendar>
|
||||
}
|
||||
|
||||
@if (isShowEnterMsg) {
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -75,6 +75,11 @@ describe('DialogScheduleTaskComponent', () => {
|
|||
initialState: {
|
||||
[CONFIG_FEATURE_NAME]: {
|
||||
sync: {},
|
||||
localization: {
|
||||
lng: undefined,
|
||||
dateTimeLocale: undefined,
|
||||
firstDayOfWeek: 0,
|
||||
},
|
||||
} as any,
|
||||
},
|
||||
}),
|
||||
|
|
@ -314,6 +319,7 @@ describe('DialogScheduleTaskComponent', () => {
|
|||
|
||||
component.data = { task: mockTask };
|
||||
component.task = mockTask;
|
||||
fixture.detectChanges();
|
||||
|
||||
await component.ngAfterViewInit();
|
||||
|
||||
|
|
@ -348,6 +354,7 @@ describe('DialogScheduleTaskComponent', () => {
|
|||
|
||||
component.data = { task: mockTask };
|
||||
component.task = mockTask;
|
||||
fixture.detectChanges();
|
||||
|
||||
await component.ngAfterViewInit();
|
||||
|
||||
|
|
@ -377,6 +384,7 @@ describe('DialogScheduleTaskComponent', () => {
|
|||
|
||||
component.data = { task: mockTask };
|
||||
component.task = mockTask;
|
||||
fixture.detectChanges();
|
||||
|
||||
await component.ngAfterViewInit();
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,12 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
|
|||
private _globalConfigService = inject(GlobalConfigService);
|
||||
private readonly _dateAdapter = inject(DateAdapter);
|
||||
|
||||
// Wait for localization config to be loaded before rendering calendar
|
||||
// This ensures DateAdapter.getFirstDayOfWeek() returns the correct value
|
||||
readonly isConfigReady = computed(
|
||||
() => this._globalConfigService.localization() !== undefined,
|
||||
);
|
||||
|
||||
T: typeof T = T;
|
||||
minDate = new Date();
|
||||
readonly calendar = viewChild.required(MatCalendar);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { T } from 'src/app/t.const';
|
|||
import { TaskWithReminderData } from '../tasks/task.model';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
|
||||
import { GlobalConfigService } from '../config/global-config.service';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
|
|
@ -42,6 +43,7 @@ export class ReminderModule {
|
|||
private readonly _taskService = inject(TaskService);
|
||||
private readonly _syncTriggerService = inject(SyncTriggerService);
|
||||
private readonly _store = inject(Store);
|
||||
private readonly _globalConfigService = inject(GlobalConfigService);
|
||||
|
||||
constructor() {
|
||||
// Initialize reminder service (runs migration in background)
|
||||
|
|
@ -80,7 +82,7 @@ export class ReminderModule {
|
|||
),
|
||||
)
|
||||
.subscribe((reminders: TaskWithReminderData[]) => {
|
||||
if (IS_ELECTRON) {
|
||||
if (IS_ELECTRON && this._globalConfigService.cfg()?.reminder?.isFocusWindow) {
|
||||
this._uiHelperService.focusApp();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -377,4 +377,131 @@ describe('ReminderService', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('duplicate reminder prevention', () => {
|
||||
let messageHandler: (msg: MessageEvent) => Promise<void>;
|
||||
let taskServiceSpy: jasmine.SpyObj<TaskService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Initialize service first to register the message handler
|
||||
await service.init();
|
||||
|
||||
// Capture the message handler registered on the worker
|
||||
const call = mockWorker.addEventListener.calls
|
||||
.all()
|
||||
.find((c) => c.args[0] === 'message');
|
||||
messageHandler = call?.args[1] as unknown as (msg: MessageEvent) => Promise<void>;
|
||||
|
||||
// Get TaskService spy to configure task responses
|
||||
taskServiceSpy = TestBed.inject(TaskService) as jasmine.SpyObj<TaskService>;
|
||||
});
|
||||
|
||||
it('should not emit duplicate reminders when worker sends same reminder twice', async () => {
|
||||
const testReminder = {
|
||||
id: 'reminder-dup-1',
|
||||
relatedId: 'task-dup-1',
|
||||
title: 'Duplicate Test',
|
||||
remindAt: Date.now() - 1000,
|
||||
type: 'TASK' as const,
|
||||
};
|
||||
|
||||
// Mock task exists and is not done
|
||||
taskServiceSpy.getByIdOnce$.and.returnValue(
|
||||
of({ id: 'task-dup-1', isDone: false } as any),
|
||||
);
|
||||
|
||||
const emissions: any[] = [];
|
||||
service.onRemindersActive$.subscribe((reminders) => {
|
||||
emissions.push(reminders);
|
||||
});
|
||||
|
||||
// Simulate worker sending same reminder twice (race condition)
|
||||
await messageHandler({ data: [testReminder] } as MessageEvent);
|
||||
await messageHandler({ data: [testReminder] } as MessageEvent);
|
||||
|
||||
// Should only have one emission
|
||||
expect(emissions.length).toBe(1);
|
||||
expect(emissions[0].length).toBe(1);
|
||||
expect(emissions[0][0].id).toBe('reminder-dup-1');
|
||||
});
|
||||
|
||||
it('should allow reminder to emit again after snooze', async () => {
|
||||
const reminderId = service.addReminder(
|
||||
'TASK',
|
||||
'task-snooze-emit',
|
||||
'Snooze Emit Test',
|
||||
Date.now() - 1000,
|
||||
);
|
||||
|
||||
const testReminder = {
|
||||
id: reminderId,
|
||||
relatedId: 'task-snooze-emit',
|
||||
title: 'Snooze Emit Test',
|
||||
remindAt: Date.now() - 1000,
|
||||
type: 'TASK' as const,
|
||||
};
|
||||
|
||||
// Mock task exists and is not done
|
||||
taskServiceSpy.getByIdOnce$.and.returnValue(
|
||||
of({ id: 'task-snooze-emit', isDone: false } as any),
|
||||
);
|
||||
|
||||
const emissions: any[] = [];
|
||||
service.onRemindersActive$.subscribe((reminders) => {
|
||||
emissions.push(reminders);
|
||||
});
|
||||
|
||||
// First activation
|
||||
await messageHandler({ data: [testReminder] } as MessageEvent);
|
||||
expect(emissions.length).toBe(1);
|
||||
|
||||
// Snooze the reminder (this should clear the processed state)
|
||||
service.snooze(reminderId, 5000);
|
||||
|
||||
// Update the reminder time for the "new" activation
|
||||
const snoozedReminder = { ...testReminder, remindAt: Date.now() - 500 };
|
||||
|
||||
// Second activation after snooze should work
|
||||
await messageHandler({ data: [snoozedReminder] } as MessageEvent);
|
||||
expect(emissions.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should clean up processed state after timeout', async () => {
|
||||
jasmine.clock().install();
|
||||
|
||||
const testReminder = {
|
||||
id: 'reminder-cleanup-1',
|
||||
relatedId: 'task-cleanup-1',
|
||||
title: 'Cleanup Test',
|
||||
remindAt: Date.now() - 1000,
|
||||
type: 'TASK' as const,
|
||||
};
|
||||
|
||||
taskServiceSpy.getByIdOnce$.and.returnValue(
|
||||
of({ id: 'task-cleanup-1', isDone: false } as any),
|
||||
);
|
||||
|
||||
const emissions: any[] = [];
|
||||
service.onRemindersActive$.subscribe((reminders) => {
|
||||
emissions.push(reminders);
|
||||
});
|
||||
|
||||
// First activation
|
||||
await messageHandler({ data: [testReminder] } as MessageEvent);
|
||||
expect(emissions.length).toBe(1);
|
||||
|
||||
// Second activation should be blocked
|
||||
await messageHandler({ data: [testReminder] } as MessageEvent);
|
||||
expect(emissions.length).toBe(1);
|
||||
|
||||
// Advance time by 61 seconds (cleanup happens at 60s)
|
||||
jasmine.clock().tick(61000);
|
||||
|
||||
// Third activation should work after cleanup
|
||||
await messageHandler({ data: [testReminder] } as MessageEvent);
|
||||
expect(emissions.length).toBe(2);
|
||||
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@
|
|||
</h1>
|
||||
|
||||
<mat-dialog-content>
|
||||
<!-- <h3 class="mat-h3">{{task.title}}</h3>-->
|
||||
@if (repeatCfgId(); as cfgId) {
|
||||
<repeat-task-heatmap [repeatCfgId]="cfgId" />
|
||||
}
|
||||
|
||||
<help-section>
|
||||
<p>{{ T.F.TASK_REPEAT.D_EDIT.HELP1 | translate }}</p>
|
||||
<p>{{ T.F.TASK_REPEAT.D_EDIT.HELP2 | translate }}</p>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { Component, input, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
|
@ -15,6 +15,17 @@ import { GlobalConfigService } from '../../config/global-config.service';
|
|||
import { DateTimeFormatService } from '../../../core/date-time-format/date-time-format.service';
|
||||
import { DEFAULT_TASK_REPEAT_CFG, TaskRepeatCfg } from '../task-repeat-cfg.model';
|
||||
import { TaskCopy } from '../../tasks/task.model';
|
||||
import { RepeatTaskHeatmapComponent } from '../repeat-task-heatmap/repeat-task-heatmap.component';
|
||||
|
||||
// Stub component to replace RepeatTaskHeatmapComponent which has heavy dependencies
|
||||
@Component({
|
||||
selector: 'repeat-task-heatmap',
|
||||
template: '',
|
||||
standalone: true,
|
||||
})
|
||||
class MockRepeatTaskHeatmapComponent {
|
||||
repeatCfgId = input.required<string>();
|
||||
}
|
||||
|
||||
describe('DialogEditTaskRepeatCfgComponent', () => {
|
||||
let mockDialogRef: jasmine.SpyObj<MatDialogRef<DialogEditTaskRepeatCfgComponent>>;
|
||||
|
|
@ -87,6 +98,7 @@ describe('DialogEditTaskRepeatCfgComponent', () => {
|
|||
TranslateModule.forRoot(),
|
||||
FormlyConfigModule,
|
||||
ReactiveFormsModule,
|
||||
MockRepeatTaskHeatmapComponent,
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [
|
||||
|
|
@ -98,7 +110,16 @@ describe('DialogEditTaskRepeatCfgComponent', () => {
|
|||
{ provide: GlobalConfigService, useValue: mockGlobalConfigService },
|
||||
{ provide: DateTimeFormatService, useValue: mockDateTimeFormatService },
|
||||
],
|
||||
}).compileComponents();
|
||||
})
|
||||
.overrideComponent(DialogEditTaskRepeatCfgComponent, {
|
||||
remove: {
|
||||
imports: [RepeatTaskHeatmapComponent],
|
||||
},
|
||||
add: {
|
||||
imports: [MockRepeatTaskHeatmapComponent],
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
return TestBed.createComponent(DialogEditTaskRepeatCfgComponent);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import { DialogConfirmComponent } from '../../../ui/dialog-confirm/dialog-confir
|
|||
import { GlobalConfigService } from '../../config/global-config.service';
|
||||
import { DEFAULT_GLOBAL_CONFIG } from '../../config/default-global-config.const';
|
||||
import { DateTimeFormatService } from 'src/app/core/date-time-format/date-time-format.service';
|
||||
import { RepeatTaskHeatmapComponent } from '../repeat-task-heatmap/repeat-task-heatmap.component';
|
||||
|
||||
// TASK_REPEAT_CFG_FORM_CFG
|
||||
@Component({
|
||||
|
|
@ -65,6 +66,7 @@ import { DateTimeFormatService } from 'src/app/core/date-time-format/date-time-f
|
|||
MatDialogActions,
|
||||
MatButton,
|
||||
MatIcon,
|
||||
RepeatTaskHeatmapComponent,
|
||||
],
|
||||
})
|
||||
export class DialogEditTaskRepeatCfgComponent {
|
||||
|
|
@ -95,6 +97,14 @@ export class DialogEditTaskRepeatCfgComponent {
|
|||
return false;
|
||||
});
|
||||
|
||||
repeatCfgId = computed(() => {
|
||||
const cfg = this.repeatCfg();
|
||||
if ('id' in cfg && cfg.id) {
|
||||
return cfg.id;
|
||||
}
|
||||
return this._data.repeatCfg?.id || this._data.task?.repeatCfgId || null;
|
||||
});
|
||||
|
||||
TASK_REPEAT_CFG_FORM_CFG_BEFORE_TAGS = signal<FormlyFieldConfig[]>([]);
|
||||
TASK_REPEAT_CFG_ADVANCED_FORM_CFG = signal<FormlyFieldConfig[]>(
|
||||
TASK_REPEAT_CFG_ADVANCED_FORM_CFG,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
@if (heatmapData(); as data) {
|
||||
<heatmap
|
||||
[data]="data"
|
||||
[showLegend]="false"
|
||||
[scrollToEnd]="true"
|
||||
/>
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
:host {
|
||||
display: block;
|
||||
max-width: 500px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
input,
|
||||
} from '@angular/core';
|
||||
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
|
||||
import { TaskService } from '../../tasks/task.service';
|
||||
import { TaskArchiveService } from '../../time-tracking/task-archive.service';
|
||||
import { from } from 'rxjs';
|
||||
import { filter, first, map, switchMap } from 'rxjs/operators';
|
||||
import { Task } from '../../tasks/task.model';
|
||||
import { DateAdapter } from '@angular/material/core';
|
||||
import {
|
||||
DayData,
|
||||
WeekData,
|
||||
HeatmapData,
|
||||
HeatmapComponent,
|
||||
} from '../../../ui/heatmap/heatmap.component';
|
||||
|
||||
@Component({
|
||||
selector: 'repeat-task-heatmap',
|
||||
templateUrl: './repeat-task-heatmap.component.html',
|
||||
styleUrls: ['./repeat-task-heatmap.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [HeatmapComponent],
|
||||
})
|
||||
export class RepeatTaskHeatmapComponent {
|
||||
private readonly _taskService = inject(TaskService);
|
||||
private readonly _taskArchiveService = inject(TaskArchiveService);
|
||||
private readonly _dateAdapter = inject(DateAdapter);
|
||||
|
||||
readonly repeatCfgId = input.required<string>();
|
||||
|
||||
private readonly _rawHeatmapData = toSignal(
|
||||
toObservable(this.repeatCfgId).pipe(
|
||||
filter((id): id is string => !!id),
|
||||
switchMap((repeatCfgId) => from(this._loadTasksForRepeatCfg(repeatCfgId))),
|
||||
map((tasks) => this._buildHeatmapData(tasks)),
|
||||
),
|
||||
{ initialValue: null },
|
||||
);
|
||||
|
||||
readonly heatmapData = computed<HeatmapData | null>(() => {
|
||||
const rawData = this._rawHeatmapData();
|
||||
const firstDay = this._dateAdapter.getFirstDayOfWeek();
|
||||
|
||||
if (!rawData || !rawData.dayMap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if there's any actual data
|
||||
if (!rawData.hasData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._buildWeeksGrid(
|
||||
rawData.dayMap,
|
||||
rawData.startDate,
|
||||
rawData.endDate,
|
||||
firstDay,
|
||||
);
|
||||
});
|
||||
|
||||
private async _loadTasksForRepeatCfg(repeatCfgId: string): Promise<Task[]> {
|
||||
const [archive, currentTasks] = await Promise.all([
|
||||
this._taskArchiveService.load(),
|
||||
this._taskService.allTasks$.pipe(first()).toPromise(),
|
||||
]);
|
||||
|
||||
const matchingTasks: Task[] = [];
|
||||
|
||||
// Filter current tasks by repeatCfgId
|
||||
if (currentTasks) {
|
||||
for (const task of currentTasks) {
|
||||
if (task.repeatCfgId === repeatCfgId) {
|
||||
matchingTasks.push(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter archived tasks by repeatCfgId
|
||||
if (archive && archive.ids) {
|
||||
for (const taskId of archive.ids) {
|
||||
const archivedTask = archive.entities[taskId];
|
||||
if (archivedTask && archivedTask.repeatCfgId === repeatCfgId) {
|
||||
matchingTasks.push(archivedTask as Task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchingTasks;
|
||||
}
|
||||
|
||||
private _buildHeatmapData(tasks: Task[]): {
|
||||
dayMap: Map<string, DayData>;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
hasData: boolean;
|
||||
} {
|
||||
const dayMap = new Map<string, DayData>();
|
||||
const now = new Date();
|
||||
const oneYearAgo = new Date(now);
|
||||
oneYearAgo.setFullYear(now.getFullYear() - 1);
|
||||
|
||||
// Initialize all days in the past year
|
||||
const currentDate = new Date(oneYearAgo);
|
||||
while (currentDate <= now) {
|
||||
const dateStr = this._getDateStr(currentDate);
|
||||
dayMap.set(dateStr, {
|
||||
date: new Date(currentDate),
|
||||
dateStr,
|
||||
taskCount: 0,
|
||||
timeSpent: 0,
|
||||
level: 0,
|
||||
});
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
|
||||
// Aggregate time spent from all tasks
|
||||
let maxTime = 0;
|
||||
let hasData = false;
|
||||
const taskCountPerDay = new Map<string, Set<string>>();
|
||||
|
||||
for (const task of tasks) {
|
||||
if (task.timeSpentOnDay) {
|
||||
for (const dateStr of Object.keys(task.timeSpentOnDay)) {
|
||||
const timeSpent = task.timeSpentOnDay[dateStr];
|
||||
const dayData = dayMap.get(dateStr);
|
||||
|
||||
if (dayData && timeSpent > 0) {
|
||||
dayData.timeSpent += timeSpent;
|
||||
maxTime = Math.max(maxTime, dayData.timeSpent);
|
||||
hasData = true;
|
||||
|
||||
// Track unique tasks per day
|
||||
if (!taskCountPerDay.has(dateStr)) {
|
||||
taskCountPerDay.set(dateStr, new Set());
|
||||
}
|
||||
taskCountPerDay.get(dateStr)!.add(task.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update task counts
|
||||
for (const [dateStr, taskIds] of taskCountPerDay) {
|
||||
const dayData = dayMap.get(dateStr);
|
||||
if (dayData) {
|
||||
dayData.taskCount = taskIds.size;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate levels (0-4) based on time spent
|
||||
for (const day of dayMap.values()) {
|
||||
if (day.timeSpent === 0) {
|
||||
day.level = 0;
|
||||
} else {
|
||||
const timeRatio = maxTime > 0 ? day.timeSpent / maxTime : 0;
|
||||
|
||||
if (timeRatio > 0.75) {
|
||||
day.level = 4;
|
||||
} else if (timeRatio > 0.5) {
|
||||
day.level = 3;
|
||||
} else if (timeRatio > 0.25) {
|
||||
day.level = 2;
|
||||
} else {
|
||||
day.level = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dayMap,
|
||||
startDate: oneYearAgo,
|
||||
endDate: now,
|
||||
hasData,
|
||||
};
|
||||
}
|
||||
|
||||
private _getDateStr(date: Date): string {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
private _buildWeeksGrid(
|
||||
dayMap: Map<string, DayData>,
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
firstDayOfWeek: number = 0,
|
||||
): HeatmapData {
|
||||
const weeks: WeekData[] = [];
|
||||
const monthLabels: string[] = [];
|
||||
const monthNames = this._dateAdapter.getMonthNames('short');
|
||||
let currentMonth = -1;
|
||||
|
||||
// Find the first day (based on firstDayOfWeek setting) before or on the start date
|
||||
const firstDay = new Date(startDate);
|
||||
const dayOfWeek = firstDay.getDay();
|
||||
const daysToGoBack = (dayOfWeek - firstDayOfWeek + 7) % 7;
|
||||
firstDay.setDate(firstDay.getDate() - daysToGoBack);
|
||||
|
||||
// Build weeks
|
||||
const currentDate = new Date(firstDay);
|
||||
let weekCount = 0;
|
||||
|
||||
while (currentDate <= endDate || weeks.length === 0) {
|
||||
const week: WeekData = { days: [] };
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const dateStr = this._getDateStr(currentDate);
|
||||
const dayData = dayMap.get(dateStr);
|
||||
|
||||
if (currentDate >= startDate && currentDate <= endDate) {
|
||||
week.days.push(dayData || null);
|
||||
|
||||
const month = currentDate.getMonth();
|
||||
if (month !== currentMonth && currentDate.getDate() <= 7 && weekCount > 0) {
|
||||
monthLabels.push(monthNames[month]);
|
||||
currentMonth = month;
|
||||
} else if (monthLabels.length === 0 && weekCount === 0) {
|
||||
monthLabels.push(monthNames[month]);
|
||||
currentMonth = month;
|
||||
}
|
||||
} else {
|
||||
week.days.push(null);
|
||||
}
|
||||
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
|
||||
weeks.push(week);
|
||||
weekCount++;
|
||||
|
||||
if (weeks.length > 54) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { weeks, monthLabels };
|
||||
}
|
||||
}
|
||||
|
|
@ -104,7 +104,6 @@
|
|||
@if (
|
||||
isFocusModeEnabled() &&
|
||||
isAdvancedControls() &&
|
||||
!IS_TOUCH_PRIMARY &&
|
||||
!task.isDone &&
|
||||
!task.subTaskIds.length
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -288,9 +288,35 @@ export class TaskContextMenuInnerComponent implements AfterViewInit {
|
|||
if (this._isTaskDeleteTriggered) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isConfirmBeforeTaskDelete =
|
||||
this._globalConfigService.cfg()?.misc?.isConfirmBeforeTaskDelete ?? true;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
this._matDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: this.task.title },
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.pipe(takeUntil(this._destroy$))
|
||||
.subscribe(async (isConfirm) => {
|
||||
if (isConfirm) {
|
||||
await this._performDelete();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await this._performDelete();
|
||||
}
|
||||
}
|
||||
|
||||
private async _performDelete(): Promise<void> {
|
||||
this._isTaskDeleteTriggered = true;
|
||||
const taskWithSubTasks = await this._getTaskWithSubtasks();
|
||||
this._taskService.remove(taskWithSubTasks);
|
||||
this._isTaskDeleteTriggered = true;
|
||||
}
|
||||
|
||||
startTask(): void {
|
||||
|
|
|
|||
200
src/app/features/tasks/task/task-delete-confirmation.spec.ts
Normal file
200
src/app/features/tasks/task/task-delete-confirmation.spec.ts
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
import { of } from 'rxjs';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { GlobalConfigService } from '../../config/global-config.service';
|
||||
import { TaskService } from '../task.service';
|
||||
import { DialogConfirmComponent } from '../../../ui/dialog-confirm/dialog-confirm.component';
|
||||
import { DEFAULT_TASK, TaskWithSubTasks } from '../task.model';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
/**
|
||||
* Tests for Issue #5942: Task Delete Confirmation
|
||||
* Tests the confirmation dialog logic for task deletion
|
||||
*/
|
||||
describe('Task Delete Confirmation Logic', () => {
|
||||
let mockDialog: jasmine.SpyObj<MatDialog>;
|
||||
let mockDialogRef: jasmine.SpyObj<MatDialogRef<DialogConfirmComponent>>;
|
||||
let mockConfigService: jasmine.SpyObj<GlobalConfigService>;
|
||||
let mockTaskService: jasmine.SpyObj<TaskService>;
|
||||
|
||||
const createMockTask = (): TaskWithSubTasks => ({
|
||||
...DEFAULT_TASK,
|
||||
id: 'test-task-1',
|
||||
title: 'Test Task',
|
||||
projectId: 'test-project-1',
|
||||
subTasks: [],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockDialogRef = jasmine.createSpyObj('MatDialogRef', ['afterClosed']);
|
||||
mockDialog = jasmine.createSpyObj('MatDialog', ['open']);
|
||||
mockDialog.open.and.returnValue(mockDialogRef);
|
||||
|
||||
mockConfigService = jasmine.createSpyObj('GlobalConfigService', ['cfg']);
|
||||
mockTaskService = jasmine.createSpyObj('TaskService', ['remove']);
|
||||
});
|
||||
|
||||
describe('when isConfirmBeforeTaskDelete is true', () => {
|
||||
beforeEach(() => {
|
||||
mockConfigService.cfg.and.returnValue({
|
||||
misc: { isConfirmBeforeTaskDelete: true },
|
||||
} as any);
|
||||
});
|
||||
|
||||
it('should open confirmation dialog', () => {
|
||||
mockDialogRef.afterClosed.and.returnValue(of(false));
|
||||
|
||||
const task = createMockTask();
|
||||
const isConfirmBeforeTaskDelete =
|
||||
mockConfigService.cfg()?.misc?.isConfirmBeforeTaskDelete;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
mockDialog.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: task.title },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
expect(mockDialog.open).toHaveBeenCalledWith(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: 'Test Task' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete task when dialog is confirmed', () => {
|
||||
mockDialogRef.afterClosed.and.returnValue(of(true));
|
||||
|
||||
const task = createMockTask();
|
||||
const isConfirmBeforeTaskDelete =
|
||||
mockConfigService.cfg()?.misc?.isConfirmBeforeTaskDelete;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
mockDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: task.title },
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((isConfirm) => {
|
||||
if (isConfirm) {
|
||||
mockTaskService.remove(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
expect(mockTaskService.remove).toHaveBeenCalledWith(task);
|
||||
});
|
||||
|
||||
it('should NOT delete task when dialog is cancelled', () => {
|
||||
mockDialogRef.afterClosed.and.returnValue(of(false));
|
||||
|
||||
const task = createMockTask();
|
||||
const isConfirmBeforeTaskDelete =
|
||||
mockConfigService.cfg()?.misc?.isConfirmBeforeTaskDelete;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
mockDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: task.title },
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((isConfirm) => {
|
||||
if (isConfirm) {
|
||||
mockTaskService.remove(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
expect(mockTaskService.remove).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when isConfirmBeforeTaskDelete is false', () => {
|
||||
beforeEach(() => {
|
||||
mockConfigService.cfg.and.returnValue({
|
||||
misc: { isConfirmBeforeTaskDelete: false },
|
||||
} as any);
|
||||
});
|
||||
|
||||
it('should NOT open confirmation dialog', () => {
|
||||
const task = createMockTask();
|
||||
const isConfirmBeforeTaskDelete =
|
||||
mockConfigService.cfg()?.misc?.isConfirmBeforeTaskDelete;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
mockDialog.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: task.title },
|
||||
},
|
||||
});
|
||||
} else {
|
||||
mockTaskService.remove(task);
|
||||
}
|
||||
|
||||
expect(mockDialog.open).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should delete task immediately', () => {
|
||||
const task = createMockTask();
|
||||
const isConfirmBeforeTaskDelete =
|
||||
mockConfigService.cfg()?.misc?.isConfirmBeforeTaskDelete;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
mockDialog.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: task.title },
|
||||
},
|
||||
});
|
||||
} else {
|
||||
mockTaskService.remove(task);
|
||||
}
|
||||
|
||||
expect(mockTaskService.remove).toHaveBeenCalledWith(task);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when isConfirmBeforeTaskDelete is undefined', () => {
|
||||
beforeEach(() => {
|
||||
mockConfigService.cfg.and.returnValue({
|
||||
misc: {},
|
||||
} as any);
|
||||
});
|
||||
|
||||
it('should treat undefined as falsy and delete immediately', () => {
|
||||
const task = createMockTask();
|
||||
const isConfirmBeforeTaskDelete =
|
||||
mockConfigService.cfg()?.misc?.isConfirmBeforeTaskDelete;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
mockDialog.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: task.title },
|
||||
},
|
||||
});
|
||||
} else {
|
||||
mockTaskService.remove(task);
|
||||
}
|
||||
|
||||
expect(mockDialog.open).not.toHaveBeenCalled();
|
||||
expect(mockTaskService.remove).toHaveBeenCalledWith(task);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -367,6 +367,31 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
if (this._isTaskDeleteTriggered) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isConfirmBeforeTaskDelete =
|
||||
this._configService.cfg()?.misc?.isConfirmBeforeTaskDelete ?? true;
|
||||
|
||||
if (isConfirmBeforeTaskDelete) {
|
||||
this._matDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
data: {
|
||||
okTxt: T.F.TASK.D_CONFIRM_DELETE.OK,
|
||||
message: T.F.TASK.D_CONFIRM_DELETE.MSG,
|
||||
translateParams: { title: this.task().title },
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((isConfirm) => {
|
||||
if (isConfirm) {
|
||||
this._performDelete(isClick);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._performDelete(isClick);
|
||||
}
|
||||
}
|
||||
|
||||
private _performDelete(isClick: boolean): void {
|
||||
// NOTE: in case we want the focus behaviour on click we could use:
|
||||
// this.focusSelf();
|
||||
if (!isClick) {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<h2 mat-dialog-title>{{ 'USER_PROFILES.DIALOG_TITLE' | translate }}</h2>
|
||||
<h2 mat-dialog-title>{{ T.USER_PROFILES.DIALOG_TITLE | translate }}</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
<!-- Create New Profile -->
|
||||
<div class="create-profile-section">
|
||||
<h3>{{ 'USER_PROFILES.CREATE_NEW_PROFILE' | translate }}</h3>
|
||||
<h3>{{ T.USER_PROFILES.CREATE_NEW_PROFILE | translate }}</h3>
|
||||
<div class="create-profile-form">
|
||||
<mat-form-field class="profile-name-input">
|
||||
<mat-label>{{ 'USER_PROFILES.PROFILE_NAME' | translate }}</mat-label>
|
||||
<mat-label>{{ T.USER_PROFILES.PROFILE_NAME | translate }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[(ngModel)]="newProfileName"
|
||||
(keydown.enter)="createProfile()"
|
||||
[placeholder]="'USER_PROFILES.PROFILE_NAME_PLACEHOLDER' | translate"
|
||||
[placeholder]="T.USER_PROFILES.PROFILE_NAME_PLACEHOLDER | translate"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<button
|
||||
|
|
@ -21,14 +21,14 @@
|
|||
[disabled]="!newProfileName() || isCreating()"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
{{ 'USER_PROFILES.CREATE' | translate }}
|
||||
{{ T.USER_PROFILES.CREATE | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Existing Profiles -->
|
||||
<div class="profiles-list-section">
|
||||
<h3>{{ 'USER_PROFILES.EXISTING_PROFILES' | translate }}</h3>
|
||||
<h3>{{ T.USER_PROFILES.EXISTING_PROFILES | translate }}</h3>
|
||||
<div class="profiles-list">
|
||||
@for (profile of profileService.profiles(); track profile.id) {
|
||||
<div
|
||||
|
|
@ -49,14 +49,14 @@
|
|||
<button
|
||||
mat-icon-button
|
||||
(click)="saveEdit(profile.id)"
|
||||
[matTooltip]="'USER_PROFILES.SAVE' | translate"
|
||||
[matTooltip]="T.USER_PROFILES.SAVE | translate"
|
||||
>
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="cancelEdit()"
|
||||
[matTooltip]="'USER_PROFILES.CANCEL' | translate"
|
||||
[matTooltip]="T.USER_PROFILES.CANCEL | translate"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
|
|
@ -68,12 +68,12 @@
|
|||
<strong>{{ profile.name }}</strong>
|
||||
@if (profile.id === profileService.activeProfile()?.id) {
|
||||
<span class="active-badge">{{
|
||||
'USER_PROFILES.ACTIVE' | translate
|
||||
T.USER_PROFILES.ACTIVE | translate
|
||||
}}</span>
|
||||
}
|
||||
</div>
|
||||
<div class="profile-meta">
|
||||
{{ 'USER_PROFILES.CREATED' | translate }}
|
||||
{{ T.USER_PROFILES.CREATED | translate }}
|
||||
{{ profile.createdAt | date: 'medium' }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
<button
|
||||
mat-icon-button
|
||||
(click)="startEdit(profile)"
|
||||
[matTooltip]="'USER_PROFILES.RENAME' | translate"
|
||||
[matTooltip]="T.USER_PROFILES.RENAME | translate"
|
||||
[disabled]="profileService.profiles().length === 1"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>
|
||||
|
|
@ -89,14 +89,14 @@
|
|||
<button
|
||||
mat-icon-button
|
||||
(click)="exportProfile(profile)"
|
||||
[matTooltip]="'USER_PROFILES.EXPORT_PROFILE' | translate"
|
||||
[matTooltip]="T.USER_PROFILES.EXPORT_PROFILE | translate"
|
||||
>
|
||||
<mat-icon>download</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="deleteProfile(profile)"
|
||||
[matTooltip]="'USER_PROFILES.DELETE_PROFILE' | translate"
|
||||
[matTooltip]="T.USER_PROFILES.DELETE_PROFILE | translate"
|
||||
[disabled]="
|
||||
profile.id === profileService.activeProfile()?.id ||
|
||||
profileService.profiles().length === 1
|
||||
|
|
@ -118,6 +118,6 @@
|
|||
mat-button
|
||||
(click)="close()"
|
||||
>
|
||||
{{ 'USER_PROFILES.CLOSE' | translate }}
|
||||
{{ T.USER_PROFILES.CLOSE | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { UserProfile } from '../user-profile.model';
|
|||
import { SnackService } from '../../../core/snack/snack.service';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { IS_ELECTRON } from '../../../app.constants';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
@Component({
|
||||
selector: 'dialog-user-profile-management',
|
||||
|
|
@ -51,6 +52,7 @@ export class DialogUserProfileManagementComponent {
|
|||
readonly isCreating = signal(false);
|
||||
|
||||
readonly isElectron = IS_ELECTRON;
|
||||
readonly T = T;
|
||||
|
||||
async createProfile(): Promise<void> {
|
||||
const name = this.newProfileName();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { DialogUserProfileManagementComponent } from '../dialog-user-profile-man
|
|||
import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
||||
import { MatDivider } from '@angular/material/divider';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
@Component({
|
||||
selector: 'user-profile-button',
|
||||
|
|
@ -60,7 +61,7 @@ import { TranslatePipe } from '@ngx-translate/core';
|
|||
(click)="openManagementDialog()"
|
||||
>
|
||||
<mat-icon>settings</mat-icon>
|
||||
<span>{{ 'USER_PROFILES.MANAGE_PROFILES' | translate }}</span>
|
||||
<span>{{ T.USER_PROFILES.MANAGE_PROFILES | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
`,
|
||||
|
|
@ -84,6 +85,7 @@ export class UserProfileButtonComponent {
|
|||
private readonly _matDialog = inject(MatDialog);
|
||||
|
||||
readonly isLoading = signal(false);
|
||||
readonly T = T;
|
||||
|
||||
async switchToProfile(profileId: string): Promise<void> {
|
||||
if (this.isLoading()) return;
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@
|
|||
@if (customized.grouped) {
|
||||
@for (group of customized.grouped | keyvalue; track group.key) {
|
||||
<collapsible
|
||||
[title]="group.key"
|
||||
[title]="group.key | scheduledDateGroup"
|
||||
[isIconBefore]="true"
|
||||
[isExpanded]="true"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
|
|||
import { TODAY_TAG } from '../tag/tag.const';
|
||||
import { LS } from '../../core/persistence/storage-keys.const';
|
||||
import { FinishDayBtnComponent } from './finish-day-btn/finish-day-btn.component';
|
||||
import { ScheduledDateGroupPipe } from '../../ui/pipes/scheduled-date-group.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'work-view',
|
||||
|
|
@ -92,6 +93,7 @@ import { FinishDayBtnComponent } from './finish-day-btn/finish-day-btn.component
|
|||
CollapsibleComponent,
|
||||
CommonModule,
|
||||
FinishDayBtnComponent,
|
||||
ScheduledDateGroupPipe,
|
||||
],
|
||||
})
|
||||
export class WorkViewComponent implements OnInit, OnDestroy {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
} from '../dialog-confirm-url-import/dialog-confirm-url-import.component';
|
||||
import { Log } from '../../core/log';
|
||||
import { DialogArchiveCompressionComponent } from '../../features/archive/dialog-archive-compression/dialog-archive-compression.component';
|
||||
import { DataValidationFailedError } from '../../op-log/core/errors/sync-errors';
|
||||
|
||||
@Component({
|
||||
selector: 'file-imex',
|
||||
|
|
@ -191,10 +192,19 @@ export class FileImexComponent implements OnInit {
|
|||
await this._router.navigate([`tag/${TODAY_TAG.id}/tasks`]);
|
||||
} catch (e) {
|
||||
Log.err('Import process failed', e);
|
||||
this._snackService.open({
|
||||
type: 'ERROR',
|
||||
msg: T.FILE_IMEX.S_ERR_IMPORT_FAILED,
|
||||
});
|
||||
|
||||
if (e instanceof DataValidationFailedError) {
|
||||
this._snackService.open({
|
||||
type: 'ERROR',
|
||||
msg: `Import failed: ${e.message}`,
|
||||
isSkipTranslate: true,
|
||||
});
|
||||
} else {
|
||||
this._snackService.open({
|
||||
type: 'ERROR',
|
||||
msg: T.FILE_IMEX.S_ERR_IMPORT_FAILED,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -451,7 +451,8 @@ export class DataValidationFailedError extends Error {
|
|||
additionalLog?: string;
|
||||
|
||||
constructor(validationResult: IValidation<unknown>) {
|
||||
super('DataValidationFailedError');
|
||||
const errorSummary = DataValidationFailedError._buildErrorSummary(validationResult);
|
||||
super(errorSummary);
|
||||
PFLog.log('validation result: ', validationResult);
|
||||
|
||||
try {
|
||||
|
|
@ -465,6 +466,23 @@ export class DataValidationFailedError extends Error {
|
|||
PFLog.err('Failed to stringify validation errors:', e);
|
||||
}
|
||||
}
|
||||
|
||||
private static _buildErrorSummary(validationResult: IValidation<unknown>): string {
|
||||
try {
|
||||
if ('errors' in validationResult && Array.isArray(validationResult.errors)) {
|
||||
const errors = validationResult.errors as IValidation.IError[];
|
||||
const paths = errors
|
||||
.slice(0, 3)
|
||||
.map((e) => e.path)
|
||||
.join(', ');
|
||||
const suffix = errors.length > 3 ? ` (+${errors.length - 3} more)` : '';
|
||||
return `Validation failed at: ${paths}${suffix}`;
|
||||
}
|
||||
} catch {
|
||||
// Fall through to default message
|
||||
}
|
||||
return 'Data validation failed';
|
||||
}
|
||||
}
|
||||
|
||||
export class ModelVersionToImportNewerThanLocalError extends AdditionalLogErrorBase {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export const autoFixTypiaErrors = (
|
|||
} else if (keys[0] === 'globalConfig') {
|
||||
const defaultValue = getValueByPath(DEFAULT_GLOBAL_CONFIG, keys.slice(1));
|
||||
setValueByPath(data, keys, defaultValue);
|
||||
alert(
|
||||
PFLog.warn(
|
||||
`Warning: ${path} had an invalid value and was set to default: ${defaultValue}`,
|
||||
);
|
||||
} else if (error.expected.includes('undefined') && value === null) {
|
||||
|
|
@ -85,6 +85,27 @@ export const autoFixTypiaErrors = (
|
|||
const orderValue = orderIndex >= 0 ? orderIndex : 0;
|
||||
setValueByPath(data, keys, orderValue);
|
||||
PFLog.err(`Fixed: ${path} from null to ${orderValue} for taskRepeatCfg order`);
|
||||
} else if (
|
||||
keys[0] === 'metric' &&
|
||||
keys[1] === 'entities' &&
|
||||
keys.length === 4 &&
|
||||
['obstructions', 'improvements', 'improvementsTomorrow'].includes(
|
||||
keys[3] as string,
|
||||
) &&
|
||||
error.expected.includes('Array<string>')
|
||||
) {
|
||||
// Fix deprecated metric array fields (obstructions, improvements, improvementsTomorrow)
|
||||
// These fields are marked "TODO remove" and will be removed in future
|
||||
setValueByPath(data, keys, []);
|
||||
PFLog.err(`Fixed: ${path} to empty array for deprecated metric field`);
|
||||
} else if (
|
||||
keys[0] === 'improvement' &&
|
||||
keys[1] === 'hiddenImprovementBannerItems' &&
|
||||
error.expected.includes('Array<string>')
|
||||
) {
|
||||
// Fix improvement.hiddenImprovementBannerItems (deprecated)
|
||||
setValueByPath(data, keys, []);
|
||||
PFLog.err(`Fixed: ${path} to empty array for deprecated improvement field`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
<mat-card class="info-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title
|
||||
>⚠️️️{{ 'PLUGINS.EXPERIMENTAL_WARNING_TITLE' | translate }}️️ ⚠️️️
|
||||
>⚠️️️{{ T.PLUGINS.EXPERIMENTAL_WARNING_TITLE | translate }}️️ ⚠️️️
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="warning-content">
|
||||
<p>{{ 'PLUGINS.SECURITY_WARNING' | translate }}</p>
|
||||
<p>{{ T.PLUGINS.SECURITY_WARNING | translate }}</p>
|
||||
<ul>
|
||||
<li>{{ 'PLUGINS.RISK_DATA_ACCESS' | translate }}</li>
|
||||
<li>{{ 'PLUGINS.RISK_MALICIOUS_CODE' | translate }}</li>
|
||||
<li>{{ 'PLUGINS.RISK_SYSTEM_ACCESS' | translate }}</li>
|
||||
<li>{{ 'PLUGINS.RISK_PERFORMANCE' | translate }}</li>
|
||||
<li>{{ T.PLUGINS.RISK_DATA_ACCESS | translate }}</li>
|
||||
<li>{{ T.PLUGINS.RISK_MALICIOUS_CODE | translate }}</li>
|
||||
<li>{{ T.PLUGINS.RISK_SYSTEM_ACCESS | translate }}</li>
|
||||
<li>{{ T.PLUGINS.RISK_PERFORMANCE | translate }}</li>
|
||||
</ul>
|
||||
<p class="recommendation">
|
||||
<mat-icon>security</mat-icon>
|
||||
{{ 'PLUGINS.RECOMMENDATION' | translate }}
|
||||
{{ T.PLUGINS.RECOMMENDATION | translate }}
|
||||
</p>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
|
|
@ -32,14 +32,14 @@
|
|||
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ 'PLUGINS.INSTALL_PLUGIN' | translate }}</mat-card-title>
|
||||
<mat-card-title>{{ T.PLUGINS.INSTALL_PLUGIN | translate }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="install-warning">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span>{{ 'PLUGINS.INSTALL_WARNING' | translate }}</span>
|
||||
<span>{{ T.PLUGINS.INSTALL_WARNING | translate }}</span>
|
||||
</div>
|
||||
<p>{{ 'PLUGINS.UPLOAD_PLUGIN_INSTRUCTION' | translate }}</p>
|
||||
<p>{{ T.PLUGINS.UPLOAD_PLUGIN_INSTRUCTION | translate }}</p>
|
||||
<input
|
||||
#fileInput
|
||||
type="file"
|
||||
|
|
@ -56,8 +56,8 @@
|
|||
<mat-icon>upload</mat-icon>
|
||||
{{
|
||||
isUploading()
|
||||
? ('PLUGINS.INSTALLING' | translate)
|
||||
: ('PLUGINS.CHOOSE_PLUGIN_FILE' | translate)
|
||||
? (T.PLUGINS.INSTALLING | translate)
|
||||
: (T.PLUGINS.CHOOSE_PLUGIN_FILE | translate)
|
||||
}}
|
||||
</button>
|
||||
@if (uploadError()) {
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
[disabled]="isUploading()"
|
||||
>
|
||||
<mat-icon>delete_sweep</mat-icon>
|
||||
{{ 'PLUGINS.CLEAR_PLUGIN_CACHE' | translate }}
|
||||
{{ T.PLUGINS.CLEAR_PLUGIN_CACHE | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
|
|
@ -116,7 +116,7 @@
|
|||
[disabled]="!canEnablePlugin(plugin) || isPluginLoading(plugin)"
|
||||
(change)="onPluginToggle(plugin, $event)"
|
||||
[attr.aria-label]="
|
||||
'PLUGINS.TOGGLE_PLUGIN' | translate: { pluginName: plugin.manifest.name }
|
||||
T.PLUGINS.TOGGLE_PLUGIN | translate: { pluginName: plugin.manifest.name }
|
||||
"
|
||||
>
|
||||
</mat-slide-toggle>
|
||||
|
|
@ -142,12 +142,12 @@
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th>{{ 'PLUGINS.ID' | translate }}</th>
|
||||
<th>{{ T.PLUGINS.ID | translate }}</th>
|
||||
<td>{{ plugin.manifest.id }}</td>
|
||||
</tr>
|
||||
@if (plugin.manifest.minSupVersion) {
|
||||
<tr>
|
||||
<th>{{ 'PLUGINS.MIN_VERSION' | translate }}</th>
|
||||
<th>{{ T.PLUGINS.MIN_VERSION | translate }}</th>
|
||||
<td>{{ plugin.manifest.minSupVersion }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
<collapsible [title]="getPermissionsHooksTitle(plugin)">
|
||||
@if (plugin.manifest.permissions && plugin.manifest.permissions.length > 0) {
|
||||
<div class="plugin-info-section">
|
||||
<div class="label">{{ 'PLUGINS.PERMISSIONS' | translate }}:</div>
|
||||
<div class="label">{{ T.PLUGINS.PERMISSIONS | translate }}:</div>
|
||||
<mat-chip-set>
|
||||
@for (permission of plugin.manifest.permissions; track permission) {
|
||||
<mat-chip>{{ permission }}</mat-chip>
|
||||
|
|
@ -170,7 +170,7 @@
|
|||
}
|
||||
@if (plugin.manifest.hooks && plugin.manifest.hooks.length > 0) {
|
||||
<div class="plugin-info-section">
|
||||
<div class="label">{{ 'PLUGINS.HOOKS' | translate }}:</div>
|
||||
<div class="label">{{ T.PLUGINS.HOOKS | translate }}:</div>
|
||||
<mat-chip-set>
|
||||
@for (hook of plugin.manifest.hooks; track hook) {
|
||||
<mat-chip>{{ hook }}</mat-chip>
|
||||
|
|
@ -191,7 +191,7 @@
|
|||
[disabled]="isUploading()"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
{{ 'PLUGINS.REMOVE' | translate }}
|
||||
{{ T.PLUGINS.REMOVE | translate }}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,4 @@
|
|||
const T = {
|
||||
ANDROID: {
|
||||
NOTIFICATIONS: {
|
||||
SYNC_CONFLICT_MSG: 'ANDROID.NOTIFICATIONS.SYNC_CONFLICT_MSG',
|
||||
SYNC_CONFLICT_TITLE: 'ANDROID.NOTIFICATIONS.SYNC_CONFLICT_TITLE',
|
||||
},
|
||||
PERMANENT_NOTIFICATION_MSGS: {
|
||||
INITIAL: 'ANDROID.PERMANENT_NOTIFICATION_MSGS.INITIAL',
|
||||
NO_ACTIVE_TASKS: 'ANDROID.PERMANENT_NOTIFICATION_MSGS.NO_ACTIVE_TASKS',
|
||||
SYNCING: 'ANDROID.PERMANENT_NOTIFICATION_MSGS.SYNCING',
|
||||
},
|
||||
},
|
||||
APP: {
|
||||
B_INSTALL: {
|
||||
IGNORE: 'APP.B_INSTALL.IGNORE',
|
||||
|
|
@ -21,8 +10,6 @@ const T = {
|
|||
CHANGE_BACKGROUND: 'APP.CONTEXT_MENU.CHANGE_BACKGROUND',
|
||||
},
|
||||
SKIP_SYNC_WAIT: 'APP.SKIP_SYNC_WAIT',
|
||||
UPDATE_MAIN_MODEL: 'APP.UPDATE_MAIN_MODEL',
|
||||
UPDATE_MAIN_MODEL_NO_UPDATE: 'APP.UPDATE_MAIN_MODEL_NO_UPDATE',
|
||||
UPDATE_WEB_APP: 'APP.UPDATE_WEB_APP',
|
||||
},
|
||||
BL: {
|
||||
|
|
@ -31,7 +18,6 @@ const T = {
|
|||
BN: {
|
||||
SHOW_ISSUE_PANEL: 'BN.SHOW_ISSUE_PANEL',
|
||||
SHOW_NOTES: 'BN.SHOW_NOTES',
|
||||
SHOW_TASK_VIEW_CUSTOMIZER_PANEL: 'BN.SHOW_TASK_VIEW_CUSTOMIZER_PANEL',
|
||||
},
|
||||
CONFIRM: {
|
||||
AUTO_FIX: 'CONFIRM.AUTO_FIX',
|
||||
|
|
@ -41,11 +27,7 @@ const T = {
|
|||
RESTORE_STRAY_BACKUP: 'CONFIRM.RESTORE_STRAY_BACKUP',
|
||||
},
|
||||
DATETIME_SCHEDULE: {
|
||||
LATER_TODAY: 'DATETIME_SCHEDULE.LATER_TODAY',
|
||||
NEXT_WEEK: 'DATETIME_SCHEDULE.NEXT_WEEK',
|
||||
PLACEHOLDER: 'DATETIME_SCHEDULE.PLACEHOLDER',
|
||||
PRESS_ENTER_AGAIN: 'DATETIME_SCHEDULE.PRESS_ENTER_AGAIN',
|
||||
TOMORROW: 'DATETIME_SCHEDULE.TOMORROW',
|
||||
},
|
||||
DIALOG_UNSPLASH_PICKER: {
|
||||
BY: 'DIALOG_UNSPLASH_PICKER.BY',
|
||||
|
|
@ -65,7 +47,6 @@ const T = {
|
|||
ADD_ATTACHMENT: 'F.ATTACHMENT.DIALOG_EDIT.ADD_ATTACHMENT',
|
||||
EDIT_ATTACHMENT: 'F.ATTACHMENT.DIALOG_EDIT.EDIT_ATTACHMENT',
|
||||
LABELS: {
|
||||
FILE: 'F.ATTACHMENT.DIALOG_EDIT.LABELS.FILE',
|
||||
IMG: 'F.ATTACHMENT.DIALOG_EDIT.LABELS.IMG',
|
||||
LINK: 'F.ATTACHMENT.DIALOG_EDIT.LABELS.LINK',
|
||||
},
|
||||
|
|
@ -81,7 +62,6 @@ const T = {
|
|||
DEFAULT: {
|
||||
DONE: 'F.BOARDS.DEFAULT.DONE',
|
||||
EISENHAUER_MATRIX: 'F.BOARDS.DEFAULT.EISENHAUER_MATRIX',
|
||||
IMPORTANT: 'F.BOARDS.DEFAULT.IMPORTANT',
|
||||
IN_PROGRESS: 'F.BOARDS.DEFAULT.IN_PROGRESS',
|
||||
KANBAN: 'F.BOARDS.DEFAULT.KANBAN',
|
||||
NOT_URGENT_IMPORTANT: 'F.BOARDS.DEFAULT.NOT_URGENT_IMPORTANT',
|
||||
|
|
@ -119,9 +99,7 @@ const T = {
|
|||
},
|
||||
},
|
||||
CALDAV: {
|
||||
DIALOG_INITIAL: {
|
||||
TITLE: 'F.CALDAV.DIALOG_INITIAL.TITLE',
|
||||
},
|
||||
DIALOG_INITIAL: {},
|
||||
FORM: {
|
||||
CALDAV_CATEGORY_FILTER: 'F.CALDAV.FORM.CALDAV_CATEGORY_FILTER',
|
||||
CALDAV_PASSWORD: 'F.CALDAV.FORM.CALDAV_PASSWORD',
|
||||
|
|
@ -132,27 +110,6 @@ const T = {
|
|||
},
|
||||
FORM_SECTION: {
|
||||
HELP: 'F.CALDAV.FORM_SECTION.HELP',
|
||||
TITLE: 'F.CALDAV.FORM_SECTION.TITLE',
|
||||
},
|
||||
ISSUE_CONTENT: {
|
||||
ASSIGNEE: 'F.CALDAV.ISSUE_CONTENT.ASSIGNEE',
|
||||
AT: 'F.CALDAV.ISSUE_CONTENT.AT',
|
||||
ATTACHMENTS: 'F.CALDAV.ISSUE_CONTENT.ATTACHMENTS',
|
||||
CHANGED: 'F.CALDAV.ISSUE_CONTENT.CHANGED',
|
||||
COMMENTS: 'F.CALDAV.ISSUE_CONTENT.COMMENTS',
|
||||
COMPONENTS: 'F.CALDAV.ISSUE_CONTENT.COMPONENTS',
|
||||
DESCRIPTION: 'F.CALDAV.ISSUE_CONTENT.DESCRIPTION',
|
||||
LABELS: 'F.CALDAV.ISSUE_CONTENT.LABELS',
|
||||
LIST_OF_CHANGES: 'F.CALDAV.ISSUE_CONTENT.LIST_OF_CHANGES',
|
||||
MARK_AS_CHECKED: 'F.CALDAV.ISSUE_CONTENT.MARK_AS_CHECKED',
|
||||
ON: 'F.CALDAV.ISSUE_CONTENT.ON',
|
||||
RELATED: 'F.CALDAV.ISSUE_CONTENT.RELATED',
|
||||
STATUS: 'F.CALDAV.ISSUE_CONTENT.STATUS',
|
||||
STORY_POINTS: 'F.CALDAV.ISSUE_CONTENT.STORY_POINTS',
|
||||
SUB_TASKS: 'F.CALDAV.ISSUE_CONTENT.SUB_TASKS',
|
||||
SUMMARY: 'F.CALDAV.ISSUE_CONTENT.SUMMARY',
|
||||
WORKLOG: 'F.CALDAV.ISSUE_CONTENT.WORKLOG',
|
||||
WRITE_A_COMMENT: 'F.CALDAV.ISSUE_CONTENT.WRITE_A_COMMENT',
|
||||
},
|
||||
S: {
|
||||
CALENDAR_NOT_FOUND: 'F.CALDAV.S.CALENDAR_NOT_FOUND',
|
||||
|
|
@ -195,10 +152,6 @@ const T = {
|
|||
},
|
||||
DROPBOX: {
|
||||
S: {
|
||||
ACCESS_TOKEN_ERROR: 'F.DROPBOX.S.ACCESS_TOKEN_ERROR',
|
||||
ACCESS_TOKEN_GENERATED: 'F.DROPBOX.S.ACCESS_TOKEN_GENERATED',
|
||||
AUTH_ERROR: 'F.DROPBOX.S.AUTH_ERROR',
|
||||
AUTH_ERROR_ACTION: 'F.DROPBOX.S.AUTH_ERROR_ACTION',
|
||||
OFFLINE: 'F.DROPBOX.S.OFFLINE',
|
||||
SYNC_ERROR: 'F.DROPBOX.S.SYNC_ERROR',
|
||||
UNABLE_TO_GENERATE_PKCE_CHALLENGE:
|
||||
|
|
@ -220,7 +173,6 @@ const T = {
|
|||
ADD_TIME_MINUTE: 'F.FOCUS_MODE.ADD_TIME_MINUTE',
|
||||
B: {
|
||||
BREAK_RUNNING: 'F.FOCUS_MODE.B.BREAK_RUNNING',
|
||||
END_BREAK: 'F.FOCUS_MODE.B.END_BREAK',
|
||||
END_SESSION: 'F.FOCUS_MODE.B.END_SESSION',
|
||||
PAUSE: 'F.FOCUS_MODE.B.PAUSE',
|
||||
POMODORO_BREAK_RUNNING: 'F.FOCUS_MODE.B.POMODORO_BREAK_RUNNING',
|
||||
|
|
@ -234,24 +186,18 @@ const T = {
|
|||
BREAK_RELAX_MSG: 'F.FOCUS_MODE.BREAK_RELAX_MSG',
|
||||
CLICK_TO_EDIT_DURATION: 'F.FOCUS_MODE.CLICK_TO_EDIT_DURATION',
|
||||
COMPLETE_FOCUS_SESSION: 'F.FOCUS_MODE.COMPLETE_FOCUS_SESSION',
|
||||
COMPLETE_SESSION: 'F.FOCUS_MODE.COMPLETE_SESSION',
|
||||
CONGRATS: 'F.FOCUS_MODE.CONGRATS',
|
||||
CONTINUE_SESSION: 'F.FOCUS_MODE.CONTINUE_SESSION',
|
||||
CONTINUE_TO_NEXT_SESSION: 'F.FOCUS_MODE.CONTINUE_TO_NEXT_SESSION',
|
||||
COUNTDOWN: 'F.FOCUS_MODE.COUNTDOWN',
|
||||
COUNTDOWN_HINT: 'F.FOCUS_MODE.COUNTDOWN_HINT',
|
||||
CURRENT_SESSION_TIME_TOOLTIP: 'F.FOCUS_MODE.CURRENT_SESSION_TIME_TOOLTIP',
|
||||
FINISH_TASK_AND_SELECT_NEXT: 'F.FOCUS_MODE.FINISH_TASK_AND_SELECT_NEXT',
|
||||
FLOWTIME: 'F.FOCUS_MODE.FLOWTIME',
|
||||
FLOWTIME_HINT: 'F.FOCUS_MODE.FLOWTIME_HINT',
|
||||
FOCUS_TIME_TOOLTIP: 'F.FOCUS_MODE.FOCUS_TIME_TOOLTIP',
|
||||
FOR_TASK: 'F.FOCUS_MODE.FOR_TASK',
|
||||
GET_READY: 'F.FOCUS_MODE.GET_READY',
|
||||
GOGOGO: 'F.FOCUS_MODE.GOGOGO',
|
||||
GO_TO_PROCRASTINATION: 'F.FOCUS_MODE.GO_TO_PROCRASTINATION',
|
||||
LONG_BREAK: 'F.FOCUS_MODE.LONG_BREAK',
|
||||
LONG_BREAK_TITLE: 'F.FOCUS_MODE.LONG_BREAK_TITLE',
|
||||
NEXT: 'F.FOCUS_MODE.NEXT',
|
||||
ON: 'F.FOCUS_MODE.ON',
|
||||
OPEN_ISSUE_IN_BROWSER: 'F.FOCUS_MODE.OPEN_ISSUE_IN_BROWSER',
|
||||
PAUSE_SESSION: 'F.FOCUS_MODE.PAUSE_SESSION',
|
||||
|
|
@ -266,12 +212,10 @@ const T = {
|
|||
PREP_STRETCH: 'F.FOCUS_MODE.PREP_STRETCH',
|
||||
REMOVE_TIME_MINUTE: 'F.FOCUS_MODE.REMOVE_TIME_MINUTE',
|
||||
RESUME_SESSION: 'F.FOCUS_MODE.RESUME_SESSION',
|
||||
SELECT_ANOTHER_TASK: 'F.FOCUS_MODE.SELECT_ANOTHER_TASK',
|
||||
SELECT_MODE: 'F.FOCUS_MODE.SELECT_MODE',
|
||||
SELECT_TASK: 'F.FOCUS_MODE.SELECT_TASK',
|
||||
SELECT_TASK_TO_FOCUS: 'F.FOCUS_MODE.SELECT_TASK_TO_FOCUS',
|
||||
SESSION_COMPLETED: 'F.FOCUS_MODE.SESSION_COMPLETED',
|
||||
SET_FOCUS_SESSION_DURATION: 'F.FOCUS_MODE.SET_FOCUS_SESSION_DURATION',
|
||||
SHORT_BREAK: 'F.FOCUS_MODE.SHORT_BREAK',
|
||||
SHORT_BREAK_TITLE: 'F.FOCUS_MODE.SHORT_BREAK_TITLE',
|
||||
SHOW_HIDE_NOTES_AND_ATTACHMENTS: 'F.FOCUS_MODE.SHOW_HIDE_NOTES_AND_ATTACHMENTS',
|
||||
|
|
@ -283,11 +227,8 @@ const T = {
|
|||
WORKED_FOR: 'F.FOCUS_MODE.WORKED_FOR',
|
||||
},
|
||||
GITEA: {
|
||||
DIALOG_INITIAL: {
|
||||
TITLE: 'F.GITEA.DIALOG_INITIAL.TITLE',
|
||||
},
|
||||
DIALOG_INITIAL: {},
|
||||
FORM: {
|
||||
FILTER_USER: 'F.GITEA.FORM.FILTER_USER',
|
||||
HOST: 'F.GITEA.FORM.HOST',
|
||||
REPO_FULL_NAME: 'F.GITEA.FORM.REPO_FULL_NAME',
|
||||
REPO_FULL_NAME_DESCRIPTION: 'F.GITEA.FORM.REPO_FULL_NAME_DESCRIPTION',
|
||||
|
|
@ -299,11 +240,9 @@ const T = {
|
|||
},
|
||||
FORM_SECTION: {
|
||||
HELP: 'F.GITEA.FORM_SECTION.HELP',
|
||||
TITLE: 'F.GITEA.FORM_SECTION.TITLE',
|
||||
},
|
||||
ISSUE_CONTENT: {
|
||||
ASSIGNEE: 'F.GITEA.ISSUE_CONTENT.ASSIGNEE',
|
||||
AT: 'F.GITEA.ISSUE_CONTENT.AT',
|
||||
DESCRIPTION: 'F.GITEA.ISSUE_CONTENT.DESCRIPTION',
|
||||
LABELS: 'F.GITEA.ISSUE_CONTENT.LABELS',
|
||||
MARK_AS_CHECKED: 'F.GITEA.ISSUE_CONTENT.MARK_AS_CHECKED',
|
||||
|
|
@ -312,14 +251,10 @@ const T = {
|
|||
SUMMARY: 'F.GITEA.ISSUE_CONTENT.SUMMARY',
|
||||
WRITE_A_COMMENT: 'F.GITEA.ISSUE_CONTENT.WRITE_A_COMMENT',
|
||||
},
|
||||
S: {
|
||||
ERR_UNKNOWN: 'F.GITEA.S.ERR_UNKNOWN',
|
||||
},
|
||||
S: {},
|
||||
},
|
||||
GITHUB: {
|
||||
DIALOG_INITIAL: {
|
||||
TITLE: 'F.GITHUB.DIALOG_INITIAL.TITLE',
|
||||
},
|
||||
DIALOG_INITIAL: {},
|
||||
FORM: {
|
||||
FILTER_USER: 'F.GITHUB.FORM.FILTER_USER',
|
||||
INVALID_TOKEN_MESSAGE: 'F.GITHUB.FORM.INVALID_TOKEN_MESSAGE',
|
||||
|
|
@ -329,7 +264,6 @@ const T = {
|
|||
},
|
||||
FORM_SECTION: {
|
||||
HELP: 'F.GITHUB.FORM_SECTION.HELP',
|
||||
TITLE: 'F.GITHUB.FORM_SECTION.TITLE',
|
||||
},
|
||||
ISSUE_CONTENT: {
|
||||
ASSIGNEE: 'F.GITHUB.ISSUE_CONTENT.ASSIGNEE',
|
||||
|
|
@ -351,9 +285,7 @@ const T = {
|
|||
},
|
||||
},
|
||||
GITLAB: {
|
||||
DIALOG_INITIAL: {
|
||||
TITLE: 'F.GITLAB.DIALOG_INITIAL.TITLE',
|
||||
},
|
||||
DIALOG_INITIAL: {},
|
||||
DIALOG_SUBMIT_WORKLOG: {
|
||||
PAST_DAY_INFO: 'F.GITLAB.DIALOG_SUBMIT_WORKLOG.PAST_DAY_INFO',
|
||||
TITLE: 'F.GITLAB.DIALOG_SUBMIT_WORKLOG.TITLE',
|
||||
|
|
@ -383,7 +315,6 @@ const T = {
|
|||
},
|
||||
FORM_SECTION: {
|
||||
HELP: 'F.GITLAB.FORM_SECTION.HELP',
|
||||
TITLE: 'F.GITLAB.FORM_SECTION.TITLE',
|
||||
},
|
||||
ISSUE_CONTENT: {
|
||||
ASSIGNEE: 'F.GITLAB.ISSUE_CONTENT.ASSIGNEE',
|
||||
|
|
@ -415,21 +346,14 @@ const T = {
|
|||
ATTACHMENTS: 'F.ISSUE.ISSUE_CONTENT.ATTACHMENTS',
|
||||
AUTHOR: 'F.ISSUE.ISSUE_CONTENT.AUTHOR',
|
||||
CATEGORY: 'F.ISSUE.ISSUE_CONTENT.CATEGORY',
|
||||
CHANGED: 'F.ISSUE.ISSUE_CONTENT.CHANGED',
|
||||
COMMENTS: 'F.ISSUE.ISSUE_CONTENT.COMMENTS',
|
||||
COMPONENTS: 'F.ISSUE.ISSUE_CONTENT.COMPONENTS',
|
||||
DESCRIPTION: 'F.ISSUE.ISSUE_CONTENT.DESCRIPTION',
|
||||
DONE_RATIO: 'F.ISSUE.ISSUE_CONTENT.DONE_RATIO',
|
||||
DUE_DATE: 'F.ISSUE.ISSUE_CONTENT.DUE_DATE',
|
||||
LABELS: 'F.ISSUE.ISSUE_CONTENT.LABELS',
|
||||
LAST_COMMENT: 'F.ISSUE.ISSUE_CONTENT.LAST_COMMENT',
|
||||
LIST_OF_CHANGES: 'F.ISSUE.ISSUE_CONTENT.LIST_OF_CHANGES',
|
||||
LOAD_ALL_COMMENTS: 'F.ISSUE.ISSUE_CONTENT.LOAD_ALL_COMMENTS',
|
||||
LOAD_DESCRIPTION_AND_ALL_COMMENTS:
|
||||
'F.ISSUE.ISSUE_CONTENT.LOAD_DESCRIPTION_AND_ALL_COMMENTS',
|
||||
LOCATION: 'F.ISSUE.ISSUE_CONTENT.LOCATION',
|
||||
MARK_AS_CHECKED: 'F.ISSUE.ISSUE_CONTENT.MARK_AS_CHECKED',
|
||||
ON: 'F.ISSUE.ISSUE_CONTENT.ON',
|
||||
PRIORITY: 'F.ISSUE.ISSUE_CONTENT.PRIORITY',
|
||||
RELATED: 'F.ISSUE.ISSUE_CONTENT.RELATED',
|
||||
START: 'F.ISSUE.ISSUE_CONTENT.START',
|
||||
|
|
@ -441,7 +365,6 @@ const T = {
|
|||
TYPE: 'F.ISSUE.ISSUE_CONTENT.TYPE',
|
||||
VERSION: 'F.ISSUE.ISSUE_CONTENT.VERSION',
|
||||
WORKLOG: 'F.ISSUE.ISSUE_CONTENT.WORKLOG',
|
||||
WRITE_A_COMMENT: 'F.ISSUE.ISSUE_CONTENT.WRITE_A_COMMENT',
|
||||
},
|
||||
S: {
|
||||
ERR_GENERIC: 'F.ISSUE.S.ERR_GENERIC',
|
||||
|
|
@ -449,13 +372,9 @@ const T = {
|
|||
ERR_NOT_CONFIGURED: 'F.ISSUE.S.ERR_NOT_CONFIGURED',
|
||||
IMPORTED_MULTIPLE_ISSUES: 'F.ISSUE.S.IMPORTED_MULTIPLE_ISSUES',
|
||||
IMPORTED_SINGLE_ISSUE: 'F.ISSUE.S.IMPORTED_SINGLE_ISSUE',
|
||||
ISSUE_DELETED_OR_CLOSED: 'F.ISSUE.S.ISSUE_DELETED_OR_CLOSED',
|
||||
ISSUE_NO_UPDATE_REQUIRED: 'F.ISSUE.S.ISSUE_NO_UPDATE_REQUIRED',
|
||||
ISSUE_UPDATE_MULTIPLE: 'F.ISSUE.S.ISSUE_UPDATE_MULTIPLE',
|
||||
ISSUE_UPDATE_SINGLE: 'F.ISSUE.S.ISSUE_UPDATE_SINGLE',
|
||||
MANUAL_UPDATE_ISSUE_SUCCESS: 'F.ISSUE.S.MANUAL_UPDATE_ISSUE_SUCCESS',
|
||||
MISSING_ISSUE_DATA: 'F.ISSUE.S.MISSING_ISSUE_DATA',
|
||||
NEW_COMMENT: 'F.ISSUE.S.NEW_COMMENT',
|
||||
POLLING_BACKLOG: 'F.ISSUE.S.POLLING_BACKLOG',
|
||||
POLLING_CHANGES: 'F.ISSUE.S.POLLING_CHANGES',
|
||||
},
|
||||
|
|
@ -498,7 +417,6 @@ const T = {
|
|||
CURRENT_STATUS: 'F.JIRA.DIALOG_TRANSITION.CURRENT_STATUS',
|
||||
TASK_NAME: 'F.JIRA.DIALOG_TRANSITION.TASK_NAME',
|
||||
TITLE: 'F.JIRA.DIALOG_TRANSITION.TITLE',
|
||||
UPDATE_STATUS: 'F.JIRA.DIALOG_TRANSITION.UPDATE_STATUS',
|
||||
},
|
||||
DIALOG_WORKLOG: {
|
||||
CHECKBOXES: {
|
||||
|
|
@ -579,9 +497,6 @@ const T = {
|
|||
EXTENSION_NOT_LOADED: 'F.JIRA.S.EXTENSION_NOT_LOADED',
|
||||
INSUFFICIENT_SETTINGS: 'F.JIRA.S.INSUFFICIENT_SETTINGS',
|
||||
INVALID_RESPONSE: 'F.JIRA.S.INVALID_RESPONSE',
|
||||
ISSUE_NO_UPDATE_REQUIRED: 'F.JIRA.S.ISSUE_NO_UPDATE_REQUIRED',
|
||||
MANUAL_UPDATE_ISSUE_SUCCESS: 'F.JIRA.S.MANUAL_UPDATE_ISSUE_SUCCESS',
|
||||
MISSING_ISSUE_DATA: 'F.JIRA.S.MISSING_ISSUE_DATA',
|
||||
NO_AUTO_IMPORT_JQL: 'F.JIRA.S.NO_AUTO_IMPORT_JQL',
|
||||
NO_VALID_TRANSITION: 'F.JIRA.S.NO_VALID_TRANSITION',
|
||||
TIMED_OUT: 'F.JIRA.S.TIMED_OUT',
|
||||
|
|
@ -607,9 +522,7 @@ const T = {
|
|||
DIALOG_TITLE: 'F.MARKDOWN_PASTE.DIALOG_TITLE',
|
||||
},
|
||||
METRIC: {
|
||||
BANNER: {
|
||||
CHECK: 'F.METRIC.BANNER.CHECK',
|
||||
},
|
||||
BANNER: {},
|
||||
CMP: {
|
||||
ACTIVITY_HEATMAP: 'F.METRIC.CMP.ACTIVITY_HEATMAP',
|
||||
AVG_BREAKS_PER_DAY: 'F.METRIC.CMP.AVG_BREAKS_PER_DAY',
|
||||
|
|
@ -621,7 +534,6 @@ const T = {
|
|||
DAYS_WORKED: 'F.METRIC.CMP.DAYS_WORKED',
|
||||
FOCUS_SESSION_TRENDS: 'F.METRIC.CMP.FOCUS_SESSION_TRENDS',
|
||||
GLOBAL_METRICS: 'F.METRIC.CMP.GLOBAL_METRICS',
|
||||
MOOD_PRODUCTIVITY_OVER_TIME: 'F.METRIC.CMP.MOOD_PRODUCTIVITY_OVER_TIME',
|
||||
NO_ADDITIONAL_DATA_YET: 'F.METRIC.CMP.NO_ADDITIONAL_DATA_YET',
|
||||
PRODUCTIVITY_BREAKDOWN_OVER_TIME: 'F.METRIC.CMP.PRODUCTIVITY_BREAKDOWN_OVER_TIME',
|
||||
SIMPLE_CLICK_COUNTERS_OVER_TIME: 'F.METRIC.CMP.SIMPLE_CLICK_COUNTERS_OVER_TIME',
|
||||
|
|
@ -637,7 +549,6 @@ const T = {
|
|||
TIME_SPENT: 'F.METRIC.CMP.TIME_SPENT',
|
||||
},
|
||||
EVAL_FORM: {
|
||||
ADD_NOTE_FOR_TOMORROW: 'F.METRIC.EVAL_FORM.ADD_NOTE_FOR_TOMORROW',
|
||||
DAILY_STATE: 'F.METRIC.EVAL_FORM.DAILY_STATE',
|
||||
DAILY_STATE_TOOLTIP: 'F.METRIC.EVAL_FORM.DAILY_STATE_TOOLTIP',
|
||||
ENERGY_LEVEL: 'F.METRIC.EVAL_FORM.ENERGY_LEVEL',
|
||||
|
|
@ -645,6 +556,8 @@ const T = {
|
|||
FOCUS_WORK_TIME: 'F.METRIC.EVAL_FORM.FOCUS_WORK_TIME',
|
||||
IMPACT_OF_WORK: 'F.METRIC.EVAL_FORM.IMPACT_OF_WORK',
|
||||
IMPACT_OF_WORK_HINT: 'F.METRIC.EVAL_FORM.IMPACT_OF_WORK_HINT',
|
||||
NOTES: 'F.METRIC.EVAL_FORM.NOTES',
|
||||
PRODUCTIVITY: 'F.METRIC.EVAL_FORM.PRODUCTIVITY',
|
||||
PRODUCTIVITY_SCORE: 'F.METRIC.EVAL_FORM.PRODUCTIVITY_SCORE',
|
||||
PRODUCTIVITY_SCORE_TOOLTIP: 'F.METRIC.EVAL_FORM.PRODUCTIVITY_SCORE_TOOLTIP',
|
||||
SCORE_BREAKDOWN_TITLE_PRODUCTIVITY:
|
||||
|
|
@ -695,14 +608,10 @@ const T = {
|
|||
REMIND_LABEL: 'F.METRIC.REFLECTION.REMIND_LABEL',
|
||||
TITLE: 'F.METRIC.REFLECTION.TITLE',
|
||||
},
|
||||
S: {
|
||||
SAVE_METRIC: 'F.METRIC.S.SAVE_METRIC',
|
||||
},
|
||||
S: {},
|
||||
},
|
||||
NOTE: {
|
||||
D_ADD: {
|
||||
NOTE_LABEL: 'F.NOTE.D_ADD.NOTE_LABEL',
|
||||
},
|
||||
D_ADD: {},
|
||||
D_FULLSCREEN: {
|
||||
TOOLBAR: {
|
||||
BOLD: 'F.NOTE.D_FULLSCREEN.TOOLBAR.BOLD',
|
||||
|
|
@ -752,9 +661,7 @@ const T = {
|
|||
'F.OPEN_PROJECT.CFG_CMP.SELECT_ISSUE_FOR_TRANSITIONS',
|
||||
TRANSITION: 'F.OPEN_PROJECT.CFG_CMP.TRANSITION',
|
||||
},
|
||||
DIALOG_INITIAL: {
|
||||
TITLE: 'F.OPEN_PROJECT.DIALOG_INITIAL.TITLE',
|
||||
},
|
||||
DIALOG_INITIAL: {},
|
||||
DIALOG_TRACK_TIME: {
|
||||
ACTIVITY: 'F.OPEN_PROJECT.DIALOG_TRACK_TIME.ACTIVITY',
|
||||
CURRENTLY_LOGGED: 'F.OPEN_PROJECT.DIALOG_TRACK_TIME.CURRENTLY_LOGGED',
|
||||
|
|
@ -772,7 +679,6 @@ const T = {
|
|||
PERCENTAGE_DONE: 'F.OPEN_PROJECT.DIALOG_TRANSITION.PERCENTAGE_DONE',
|
||||
TASK_NAME: 'F.OPEN_PROJECT.DIALOG_TRANSITION.TASK_NAME',
|
||||
TITLE: 'F.OPEN_PROJECT.DIALOG_TRANSITION.TITLE',
|
||||
UPDATE_STATUS: 'F.OPEN_PROJECT.DIALOG_TRANSITION.UPDATE_STATUS',
|
||||
},
|
||||
FORM: {
|
||||
FILTER_USER: 'F.OPEN_PROJECT.FORM.FILTER_USER',
|
||||
|
|
@ -792,7 +698,6 @@ const T = {
|
|||
},
|
||||
FORM_SECTION: {
|
||||
HELP: 'F.OPEN_PROJECT.FORM_SECTION.HELP',
|
||||
TITLE: 'F.OPEN_PROJECT.FORM_SECTION.TITLE',
|
||||
},
|
||||
ISSUE_CONTENT: {
|
||||
ASSIGNEE: 'F.OPEN_PROJECT.ISSUE_CONTENT.ASSIGNEE',
|
||||
|
|
@ -820,9 +725,7 @@ const T = {
|
|||
PLANNER: {
|
||||
D: {
|
||||
ADD_PLANNED: {
|
||||
ADD_TO_TODAY: 'F.PLANNER.D.ADD_PLANNED.ADD_TO_TODAY',
|
||||
RE_PLAN_ALL: 'F.PLANNER.D.ADD_PLANNED.RE_PLAN_ALL',
|
||||
TITLE: 'F.PLANNER.D.ADD_PLANNED.TITLE',
|
||||
},
|
||||
},
|
||||
EDIT_REPEATED_TASK: 'F.PLANNER.EDIT_REPEATED_TASK',
|
||||
|
|
@ -835,74 +738,20 @@ const T = {
|
|||
TASK_ALREADY_PLANNED: 'F.PLANNER.S.TASK_ALREADY_PLANNED',
|
||||
TASK_PLANNED_FOR: 'F.PLANNER.S.TASK_PLANNED_FOR',
|
||||
},
|
||||
TASK_DRAWER: 'F.PLANNER.TASK_DRAWER',
|
||||
},
|
||||
POMODORO: {
|
||||
BREAK_IS_DONE: 'F.POMODORO.BREAK_IS_DONE',
|
||||
},
|
||||
PROCRASTINATION: {
|
||||
BACK_TO_WORK: 'F.PROCRASTINATION.BACK_TO_WORK',
|
||||
COMP: {
|
||||
INTRO: 'F.PROCRASTINATION.COMP.INTRO',
|
||||
L1: 'F.PROCRASTINATION.COMP.L1',
|
||||
L2: 'F.PROCRASTINATION.COMP.L2',
|
||||
L3: 'F.PROCRASTINATION.COMP.L3',
|
||||
L4: 'F.PROCRASTINATION.COMP.L4',
|
||||
OUTRO: 'F.PROCRASTINATION.COMP.OUTRO',
|
||||
TITLE: 'F.PROCRASTINATION.COMP.TITLE',
|
||||
},
|
||||
CUR: {
|
||||
INTRO: 'F.PROCRASTINATION.CUR.INTRO',
|
||||
L1: 'F.PROCRASTINATION.CUR.L1',
|
||||
L2: 'F.PROCRASTINATION.CUR.L2',
|
||||
L3: 'F.PROCRASTINATION.CUR.L3',
|
||||
L4: 'F.PROCRASTINATION.CUR.L4',
|
||||
L5: 'F.PROCRASTINATION.CUR.L5',
|
||||
PROCRASTINATION_TRIGGERS_TEXT:
|
||||
'F.PROCRASTINATION.CUR.PROCRASTINATION_TRIGGERS_TEXT',
|
||||
PROCRASTINATION_TRIGGERS_TITLE:
|
||||
'F.PROCRASTINATION.CUR.PROCRASTINATION_TRIGGERS_TITLE',
|
||||
TITLE: 'F.PROCRASTINATION.CUR.TITLE',
|
||||
},
|
||||
H1: 'F.PROCRASTINATION.H1',
|
||||
INTRO: {
|
||||
AVOIDING: 'F.PROCRASTINATION.INTRO.AVOIDING',
|
||||
FEAR: 'F.PROCRASTINATION.INTRO.FEAR',
|
||||
STRESSED: 'F.PROCRASTINATION.INTRO.STRESSED',
|
||||
TITLE: 'F.PROCRASTINATION.INTRO.TITLE',
|
||||
},
|
||||
P1: 'F.PROCRASTINATION.P1',
|
||||
P2: 'F.PROCRASTINATION.P2',
|
||||
REFRAME: {
|
||||
INTRO: 'F.PROCRASTINATION.REFRAME.INTRO',
|
||||
TITLE: 'F.PROCRASTINATION.REFRAME.TITLE',
|
||||
TL1: 'F.PROCRASTINATION.REFRAME.TL1',
|
||||
TL2: 'F.PROCRASTINATION.REFRAME.TL2',
|
||||
TL3: 'F.PROCRASTINATION.REFRAME.TL3',
|
||||
},
|
||||
SPLIT_UP: {
|
||||
INTRO: 'F.PROCRASTINATION.SPLIT_UP.INTRO',
|
||||
OUTRO: 'F.PROCRASTINATION.SPLIT_UP.OUTRO',
|
||||
TITLE: 'F.PROCRASTINATION.SPLIT_UP.TITLE',
|
||||
},
|
||||
},
|
||||
PROJECT: {
|
||||
D_CONFIRM_DUPLICATE_BIG_PROJECT: {
|
||||
TITLE: 'F.PROJECT.D_CONFIRM_DUPLICATE_BIG_PROJECT.TITLE',
|
||||
CANCEL: 'F.PROJECT.D_CONFIRM_DUPLICATE_BIG_PROJECT.CANCEL',
|
||||
MSG: 'F.PROJECT.D_CONFIRM_DUPLICATE_BIG_PROJECT.MSG',
|
||||
OK: 'F.PROJECT.D_CONFIRM_DUPLICATE_BIG_PROJECT.OK',
|
||||
CANCEL: 'F.PROJECT.D_CONFIRM_DUPLICATE_BIG_PROJECT.CANCEL',
|
||||
TITLE: 'F.PROJECT.D_CONFIRM_DUPLICATE_BIG_PROJECT.TITLE',
|
||||
},
|
||||
D_CREATE: {
|
||||
CREATE: 'F.PROJECT.D_CREATE.CREATE',
|
||||
EDIT: 'F.PROJECT.D_CREATE.EDIT',
|
||||
SETUP_CALDAV: 'F.PROJECT.D_CREATE.SETUP_CALDAV',
|
||||
SETUP_GIT: 'F.PROJECT.D_CREATE.SETUP_GIT',
|
||||
SETUP_GITEA_PROJECT: 'F.PROJECT.D_CREATE.SETUP_GITEA_PROJECT',
|
||||
SETUP_GITLAB: 'F.PROJECT.D_CREATE.SETUP_GITLAB',
|
||||
SETUP_JIRA: 'F.PROJECT.D_CREATE.SETUP_JIRA',
|
||||
SETUP_OPEN_PROJECT: 'F.PROJECT.D_CREATE.SETUP_OPEN_PROJECT',
|
||||
SETUP_REDMINE_PROJECT: 'F.PROJECT.D_CREATE.SETUP_REDMINE_PROJECT',
|
||||
},
|
||||
D_DELETE: {
|
||||
MSG: 'F.PROJECT.D_DELETE.MSG',
|
||||
|
|
@ -914,7 +763,6 @@ const T = {
|
|||
TITLE: 'F.PROJECT.FORM_BASIC.TITLE',
|
||||
},
|
||||
FORM_THEME: {
|
||||
D_IS_DARK_THEME: 'F.PROJECT.FORM_THEME.D_IS_DARK_THEME',
|
||||
HELP: 'F.PROJECT.FORM_THEME.HELP',
|
||||
L_BACKGROUND_IMAGE_DARK: 'F.PROJECT.FORM_THEME.L_BACKGROUND_IMAGE_DARK',
|
||||
L_BACKGROUND_IMAGE_LIGHT: 'F.PROJECT.FORM_THEME.L_BACKGROUND_IMAGE_LIGHT',
|
||||
|
|
@ -926,18 +774,13 @@ const T = {
|
|||
L_HUE_WARN: 'F.PROJECT.FORM_THEME.L_HUE_WARN',
|
||||
L_IS_AUTO_CONTRAST: 'F.PROJECT.FORM_THEME.L_IS_AUTO_CONTRAST',
|
||||
L_IS_DISABLE_BACKGROUND_TINT: 'F.PROJECT.FORM_THEME.L_IS_DISABLE_BACKGROUND_TINT',
|
||||
L_IS_REDUCED_THEME: 'F.PROJECT.FORM_THEME.L_IS_REDUCED_THEME',
|
||||
L_THEME_COLOR: 'F.PROJECT.FORM_THEME.L_THEME_COLOR',
|
||||
L_TITLE: 'F.PROJECT.FORM_THEME.L_TITLE',
|
||||
TITLE: 'F.PROJECT.FORM_THEME.TITLE',
|
||||
},
|
||||
S: {
|
||||
ARCHIVED: 'F.PROJECT.S.ARCHIVED',
|
||||
CREATED: 'F.PROJECT.S.CREATED',
|
||||
DELETED: 'F.PROJECT.S.DELETED',
|
||||
E_EXISTS: 'F.PROJECT.S.E_EXISTS',
|
||||
E_INVALID_FILE: 'F.PROJECT.S.E_INVALID_FILE',
|
||||
ISSUE_PROVIDER_UPDATED: 'F.PROJECT.S.ISSUE_PROVIDER_UPDATED',
|
||||
UNARCHIVED: 'F.PROJECT.S.UNARCHIVED',
|
||||
UPDATED: 'F.PROJECT.S.UPDATED',
|
||||
},
|
||||
|
|
@ -967,9 +810,7 @@ const T = {
|
|||
WEEK_TITLE: 'F.QUICK_HISTORY.WEEK_TITLE',
|
||||
},
|
||||
REDMINE: {
|
||||
DIALOG_INITIAL: {
|
||||
TITLE: 'F.REDMINE.DIALOG_INITIAL.TITLE',
|
||||
},
|
||||
DIALOG_INITIAL: {},
|
||||
FORM: {
|
||||
API_KEY: 'F.REDMINE.FORM.API_KEY',
|
||||
HOST: 'F.REDMINE.FORM.HOST',
|
||||
|
|
@ -991,9 +832,7 @@ const T = {
|
|||
PRIORITY: 'F.REDMINE.ISSUE_CONTENT.PRIORITY',
|
||||
STATUS: 'F.REDMINE.ISSUE_CONTENT.STATUS',
|
||||
},
|
||||
S: {
|
||||
ERR_UNKNOWN: 'F.REDMINE.S.ERR_UNKNOWN',
|
||||
},
|
||||
S: {},
|
||||
},
|
||||
REFLECTION_NOTE: {
|
||||
ACTION_DISMISS: 'F.REFLECTION_NOTE.ACTION_DISMISS',
|
||||
|
|
@ -1001,7 +840,6 @@ const T = {
|
|||
},
|
||||
REMINDER: {
|
||||
COUNTDOWN_BANNER: {
|
||||
HIDE: 'F.REMINDER.COUNTDOWN_BANNER.HIDE',
|
||||
START_NOW: 'F.REMINDER.COUNTDOWN_BANNER.START_NOW',
|
||||
TXT: 'F.REMINDER.COUNTDOWN_BANNER.TXT',
|
||||
TXT_MULTIPLE: 'F.REMINDER.COUNTDOWN_BANNER.TXT_MULTIPLE',
|
||||
|
|
@ -1010,7 +848,6 @@ const T = {
|
|||
S_REMINDER_ERR: 'F.REMINDER.S_REMINDER_ERR',
|
||||
},
|
||||
SCHEDULE: {
|
||||
CONTINUED: 'F.SCHEDULE.CONTINUED',
|
||||
D_INITIAL: {
|
||||
TEXT: 'F.SCHEDULE.D_INITIAL.TEXT',
|
||||
TITLE: 'F.SCHEDULE.D_INITIAL.TITLE',
|
||||
|
|
@ -1025,16 +862,11 @@ const T = {
|
|||
PLAN_START_DAY: 'F.SCHEDULE.PLAN_START_DAY',
|
||||
SHIFT_KEY_INFO: 'F.SCHEDULE.SHIFT_KEY_INFO',
|
||||
START: 'F.SCHEDULE.START',
|
||||
TASK_PROJECTION_INFO: 'F.SCHEDULE.TASK_PROJECTION_INFO',
|
||||
WEEK: 'F.SCHEDULE.WEEK',
|
||||
},
|
||||
SEARCH_BAR: {
|
||||
INFO: 'F.SEARCH_BAR.INFO',
|
||||
INFO_ARCHIVED: 'F.SEARCH_BAR.INFO_ARCHIVED',
|
||||
NO_RESULTS: 'F.SEARCH_BAR.NO_RESULTS',
|
||||
PLACEHOLDER: 'F.SEARCH_BAR.PLACEHOLDER',
|
||||
PLACEHOLDER_ARCHIVED: 'F.SEARCH_BAR.PLACEHOLDER_ARCHIVED',
|
||||
TOO_MANY_RESULTS: 'F.SEARCH_BAR.TOO_MANY_RESULTS',
|
||||
},
|
||||
SIMPLE_COUNTER: {
|
||||
D_CONFIRM_REMOVE: {
|
||||
|
|
@ -1053,7 +885,6 @@ const T = {
|
|||
L_COUNTDOWN_DURATION: 'F.SIMPLE_COUNTER.FORM.L_COUNTDOWN_DURATION',
|
||||
L_DAILY_GOAL: 'F.SIMPLE_COUNTER.FORM.L_DAILY_GOAL',
|
||||
L_ICON: 'F.SIMPLE_COUNTER.FORM.L_ICON',
|
||||
L_ICON_ON: 'F.SIMPLE_COUNTER.FORM.L_ICON_ON',
|
||||
L_IS_ENABLED: 'F.SIMPLE_COUNTER.FORM.L_IS_ENABLED',
|
||||
L_TITLE: 'F.SIMPLE_COUNTER.FORM.L_TITLE',
|
||||
L_TRACK_STREAKS: 'F.SIMPLE_COUNTER.FORM.L_TRACK_STREAKS',
|
||||
|
|
@ -1071,20 +902,12 @@ const T = {
|
|||
},
|
||||
SYNC: {
|
||||
A: {
|
||||
ARCHIVE_ONLY_UPLOADED: 'F.SYNC.A.ARCHIVE_ONLY_UPLOADED',
|
||||
POSSIBLE_LEGACY_DATA: 'F.SYNC.A.POSSIBLE_LEGACY_DATA',
|
||||
REMOTE_MODEL_VERSION_NEWER: 'F.SYNC.A.REMOTE_MODEL_VERSION_NEWER',
|
||||
},
|
||||
BTN_SYNC_NOW: 'F.SYNC.BTN_SYNC_NOW',
|
||||
BTN_RESTORE_FROM_HISTORY: 'F.SYNC.BTN_RESTORE_FROM_HISTORY',
|
||||
C: {
|
||||
EMPTY_SYNC: 'F.SYNC.C.EMPTY_SYNC',
|
||||
FORCE_UPLOAD: 'F.SYNC.C.FORCE_UPLOAD',
|
||||
FORCE_UPLOAD_AFTER_ERROR: 'F.SYNC.C.FORCE_UPLOAD_AFTER_ERROR',
|
||||
MIGRATE_LEGACY: 'F.SYNC.C.MIGRATE_LEGACY',
|
||||
NO_REMOTE_DATA: 'F.SYNC.C.NO_REMOTE_DATA',
|
||||
TRY_LOAD_REMOTE_AGAIN: 'F.SYNC.C.TRY_LOAD_REMOTE_AGAIN',
|
||||
UNABLE_TO_LOAD_REMOTE_DATA: 'F.SYNC.C.UNABLE_TO_LOAD_REMOTE_DATA',
|
||||
},
|
||||
D_AUTH_CODE: {
|
||||
FOLLOW_LINK: 'F.SYNC.D_AUTH_CODE.FOLLOW_LINK',
|
||||
|
|
@ -1098,8 +921,6 @@ const T = {
|
|||
CHANGES_SINCE_LAST_SYNC: 'F.SYNC.D_CONFLICT.CHANGES_SINCE_LAST_SYNC',
|
||||
COMPARISON_RESULT: 'F.SYNC.D_CONFLICT.COMPARISON_RESULT',
|
||||
DATE: 'F.SYNC.D_CONFLICT.DATE',
|
||||
LAMPORT_CLOCK: 'F.SYNC.D_CONFLICT.LAMPORT_CLOCK',
|
||||
LAST_CHANGE: 'F.SYNC.D_CONFLICT.LAST_CHANGE',
|
||||
LAST_SYNC: 'F.SYNC.D_CONFLICT.LAST_SYNC',
|
||||
LAST_SYNCED: 'F.SYNC.D_CONFLICT.LAST_SYNCED',
|
||||
LAST_WRITE: 'F.SYNC.D_CONFLICT.LAST_WRITE',
|
||||
|
|
@ -1145,10 +966,6 @@ const T = {
|
|||
BTN_FORCE_UPLOAD: 'F.SYNC.D_INCOMPLETE_SYNC.BTN_FORCE_UPLOAD',
|
||||
P1: 'F.SYNC.D_INCOMPLETE_SYNC.P1',
|
||||
P2: 'F.SYNC.D_INCOMPLETE_SYNC.P2',
|
||||
P3: 'F.SYNC.D_INCOMPLETE_SYNC.P3',
|
||||
P4: 'F.SYNC.D_INCOMPLETE_SYNC.P4',
|
||||
P5: 'F.SYNC.D_INCOMPLETE_SYNC.P5',
|
||||
P6: 'F.SYNC.D_INCOMPLETE_SYNC.P6',
|
||||
T1: 'F.SYNC.D_INCOMPLETE_SYNC.T1',
|
||||
T2: 'F.SYNC.D_INCOMPLETE_SYNC.T2',
|
||||
T3: 'F.SYNC.D_INCOMPLETE_SYNC.T3',
|
||||
|
|
@ -1243,7 +1060,6 @@ const T = {
|
|||
},
|
||||
S: {
|
||||
ALREADY_IN_SYNC: 'F.SYNC.S.ALREADY_IN_SYNC',
|
||||
ALREADY_IN_SYNC_NO_LOCAL_CHANGES: 'F.SYNC.S.ALREADY_IN_SYNC_NO_LOCAL_CHANGES',
|
||||
BTN_CONFIGURE: 'F.SYNC.S.BTN_CONFIGURE',
|
||||
BTN_FORCE_OVERWRITE: 'F.SYNC.S.BTN_FORCE_OVERWRITE',
|
||||
CLOCK_DRIFT_WARNING: 'F.SYNC.S.CLOCK_DRIFT_WARNING',
|
||||
|
|
@ -1277,7 +1093,6 @@ const T = {
|
|||
STORAGE_QUOTA_EXCEEDED: 'F.SYNC.S.STORAGE_QUOTA_EXCEEDED',
|
||||
STORAGE_RECOVERED_AFTER_COMPACTION: 'F.SYNC.S.STORAGE_RECOVERED_AFTER_COMPACTION',
|
||||
SUCCESS_DOWNLOAD: 'F.SYNC.S.SUCCESS_DOWNLOAD',
|
||||
SUCCESS_IMPORT: 'F.SYNC.S.SUCCESS_IMPORT',
|
||||
SUCCESS_VIA_BUTTON: 'F.SYNC.S.SUCCESS_VIA_BUTTON',
|
||||
UNKNOWN_ERROR: 'F.SYNC.S.UNKNOWN_ERROR',
|
||||
UPLOAD_ERROR: 'F.SYNC.S.UPLOAD_ERROR',
|
||||
|
|
@ -1306,7 +1121,6 @@ const T = {
|
|||
TAG: {
|
||||
D_CREATE: {
|
||||
CREATE: 'F.TAG.D_CREATE.CREATE',
|
||||
EDIT: 'F.TAG.D_CREATE.EDIT',
|
||||
},
|
||||
D_DELETE: {
|
||||
CONFIRM_MSG: 'F.TAG.D_DELETE.CONFIRM_MSG',
|
||||
|
|
@ -1367,23 +1181,12 @@ const T = {
|
|||
},
|
||||
ADD_TASK_BAR: {
|
||||
ADD_EXISTING_TASK: 'F.TASK.ADD_TASK_BAR.ADD_EXISTING_TASK',
|
||||
ADD_ISSUE_TASK: 'F.TASK.ADD_TASK_BAR.ADD_ISSUE_TASK',
|
||||
ADD_TASK_TO_BOTTOM_OF_BACKLOG:
|
||||
'F.TASK.ADD_TASK_BAR.ADD_TASK_TO_BOTTOM_OF_BACKLOG',
|
||||
ADD_TASK_TO_BOTTOM_OF_TODAY: 'F.TASK.ADD_TASK_BAR.ADD_TASK_TO_BOTTOM_OF_TODAY',
|
||||
ADD_TASK_TO_TOP_OF_BACKLOG: 'F.TASK.ADD_TASK_BAR.ADD_TASK_TO_TOP_OF_BACKLOG',
|
||||
ADD_TASK_TO_TOP_OF_TODAY: 'F.TASK.ADD_TASK_BAR.ADD_TASK_TO_TOP_OF_TODAY',
|
||||
CREATE_NEW_TAGS: 'F.TASK.ADD_TASK_BAR.CREATE_NEW_TAGS',
|
||||
CREATE_TASK: 'F.TASK.ADD_TASK_BAR.CREATE_TASK',
|
||||
DUE_BUTTON: 'F.TASK.ADD_TASK_BAR.DUE_BUTTON',
|
||||
ESTIMATE_BUTTON: 'F.TASK.ADD_TASK_BAR.ESTIMATE_BUTTON',
|
||||
EXAMPLE: 'F.TASK.ADD_TASK_BAR.EXAMPLE',
|
||||
NO_DATE: 'F.TASK.ADD_TASK_BAR.NO_DATE',
|
||||
NO_TIME: 'F.TASK.ADD_TASK_BAR.NO_TIME',
|
||||
PLACEHOLDER_CREATE: 'F.TASK.ADD_TASK_BAR.PLACEHOLDER_CREATE',
|
||||
PLACEHOLDER_SEARCH: 'F.TASK.ADD_TASK_BAR.PLACEHOLDER_SEARCH',
|
||||
SEARCH_INFO_TEXT: 'F.TASK.ADD_TASK_BAR.SEARCH_INFO_TEXT',
|
||||
START: 'F.TASK.ADD_TASK_BAR.START',
|
||||
TAGS_BUTTON: 'F.TASK.ADD_TASK_BAR.TAGS_BUTTON',
|
||||
TODAY: 'F.TASK.ADD_TASK_BAR.TODAY',
|
||||
TOGGLE_ADD_TOP_OR_BOTTOM: 'F.TASK.ADD_TASK_BAR.TOGGLE_ADD_TOP_OR_BOTTOM',
|
||||
|
|
@ -1414,11 +1217,8 @@ const T = {
|
|||
DROP_ATTACHMENT: 'F.TASK.CMP.DROP_ATTACHMENT',
|
||||
DUPLICATE: 'F.TASK.CMP.DUPLICATE',
|
||||
EDIT_SCHEDULED: 'F.TASK.CMP.EDIT_SCHEDULED',
|
||||
EDIT_TAGS: 'F.TASK.CMP.EDIT_TAGS',
|
||||
EDIT_TASK_TITLE: 'F.TASK.CMP.EDIT_TASK_TITLE',
|
||||
FOCUS_SESSION: 'F.TASK.CMP.FOCUS_SESSION',
|
||||
MARK_DONE: 'F.TASK.CMP.MARK_DONE',
|
||||
MARK_UNDONE: 'F.TASK.CMP.MARK_UNDONE',
|
||||
MOVE_TO_BACKLOG: 'F.TASK.CMP.MOVE_TO_BACKLOG',
|
||||
MOVE_TO_OTHER_PROJECT: 'F.TASK.CMP.MOVE_TO_OTHER_PROJECT',
|
||||
MOVE_TO_REGULAR: 'F.TASK.CMP.MOVE_TO_REGULAR',
|
||||
|
|
@ -1427,9 +1227,7 @@ const T = {
|
|||
OPEN_ISSUE: 'F.TASK.CMP.OPEN_ISSUE',
|
||||
OPEN_TIME: 'F.TASK.CMP.OPEN_TIME',
|
||||
REMOVE_FROM_MY_DAY: 'F.TASK.CMP.REMOVE_FROM_MY_DAY',
|
||||
REPEAT_EDIT: 'F.TASK.CMP.REPEAT_EDIT',
|
||||
SCHEDULE: 'F.TASK.CMP.SCHEDULE',
|
||||
SHOW_UPDATES: 'F.TASK.CMP.SHOW_UPDATES',
|
||||
TOGGLE_ATTACHMENTS: 'F.TASK.CMP.TOGGLE_ATTACHMENTS',
|
||||
TOGGLE_DETAIL_PANEL: 'F.TASK.CMP.TOGGLE_DETAIL_PANEL',
|
||||
TOGGLE_DONE: 'F.TASK.CMP.TOGGLE_DONE',
|
||||
|
|
@ -1459,24 +1257,21 @@ const T = {
|
|||
DONE: 'F.TASK.D_REMINDER_VIEW.DONE',
|
||||
DUE_TASK: 'F.TASK.D_REMINDER_VIEW.DUE_TASK',
|
||||
DUE_TASKS: 'F.TASK.D_REMINDER_VIEW.DUE_TASKS',
|
||||
FOR_CURRENT: 'F.TASK.D_REMINDER_VIEW.FOR_CURRENT',
|
||||
FOR_OTHER: 'F.TASK.D_REMINDER_VIEW.FOR_OTHER',
|
||||
FROM_PROJECT: 'F.TASK.D_REMINDER_VIEW.FROM_PROJECT',
|
||||
FROM_TAG: 'F.TASK.D_REMINDER_VIEW.FROM_TAG',
|
||||
RESCHEDULE_EDIT: 'F.TASK.D_REMINDER_VIEW.RESCHEDULE_EDIT',
|
||||
RESCHEDULE_UNTIL_TOMORROW: 'F.TASK.D_REMINDER_VIEW.RESCHEDULE_UNTIL_TOMORROW',
|
||||
SNOOZE: 'F.TASK.D_REMINDER_VIEW.SNOOZE',
|
||||
SNOOZE_ALL: 'F.TASK.D_REMINDER_VIEW.SNOOZE_ALL',
|
||||
START: 'F.TASK.D_REMINDER_VIEW.START',
|
||||
SWITCH_CONTEXT_START: 'F.TASK.D_REMINDER_VIEW.SWITCH_CONTEXT_START',
|
||||
UNSCHEDULE: 'F.TASK.D_REMINDER_VIEW.UNSCHEDULE',
|
||||
UNSCHEDULE_ALL: 'F.TASK.D_REMINDER_VIEW.UNSCHEDULE_ALL',
|
||||
},
|
||||
D_CONFIRM_DELETE: {
|
||||
MSG: 'F.TASK.D_CONFIRM_DELETE.MSG',
|
||||
OK: 'F.TASK.D_CONFIRM_DELETE.OK',
|
||||
},
|
||||
D_SCHEDULE_TASK: {
|
||||
MOVE_TO_BACKLOG: 'F.TASK.D_SCHEDULE_TASK.MOVE_TO_BACKLOG',
|
||||
QA_NEXT_MONTH: 'F.TASK.D_SCHEDULE_TASK.QA_NEXT_MONTH',
|
||||
QA_NEXT_WEEK: 'F.TASK.D_SCHEDULE_TASK.QA_NEXT_WEEK',
|
||||
QA_REMOVE_TODAY: 'F.TASK.D_SCHEDULE_TASK.QA_REMOVE_TODAY',
|
||||
QA_TODAY: 'F.TASK.D_SCHEDULE_TASK.QA_TODAY',
|
||||
QA_TOMORROW: 'F.TASK.D_SCHEDULE_TASK.QA_TOMORROW',
|
||||
REMIND_AT: 'F.TASK.D_SCHEDULE_TASK.REMIND_AT',
|
||||
|
|
@ -1518,16 +1313,13 @@ const T = {
|
|||
CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK:
|
||||
'F.TASK.S.CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK',
|
||||
CREATED_FOR_PROJECT: 'F.TASK.S.CREATED_FOR_PROJECT',
|
||||
CREATED_FOR_PROJECT_ACTION: 'F.TASK.S.CREATED_FOR_PROJECT_ACTION',
|
||||
DELETED: 'F.TASK.S.DELETED',
|
||||
FOUND_MOVE_FROM_BACKLOG: 'F.TASK.S.FOUND_MOVE_FROM_BACKLOG',
|
||||
FOUND_MOVE_FROM_OTHER_LIST: 'F.TASK.S.FOUND_MOVE_FROM_OTHER_LIST',
|
||||
FOUND_RESTORE_FROM_ARCHIVE: 'F.TASK.S.FOUND_RESTORE_FROM_ARCHIVE',
|
||||
GO_TO_TASK: 'F.TASK.S.GO_TO_TASK',
|
||||
LAST_TAG_DELETION_WARNING: 'F.TASK.S.LAST_TAG_DELETION_WARNING',
|
||||
MOVED_TO_ARCHIVE: 'F.TASK.S.MOVED_TO_ARCHIVE',
|
||||
MOVED_TO_PROJECT: 'F.TASK.S.MOVED_TO_PROJECT',
|
||||
MOVED_TO_PROJECT_ACTION: 'F.TASK.S.MOVED_TO_PROJECT_ACTION',
|
||||
REMINDER_ADDED: 'F.TASK.S.REMINDER_ADDED',
|
||||
REMINDER_DELETED: 'F.TASK.S.REMINDER_DELETED',
|
||||
REMINDER_UPDATED: 'F.TASK.S.REMINDER_UPDATED',
|
||||
|
|
@ -1609,7 +1401,6 @@ const T = {
|
|||
FRIDAY: 'F.TASK_REPEAT.F.FRIDAY',
|
||||
INHERIT_SUBTASKS: 'F.TASK_REPEAT.F.INHERIT_SUBTASKS',
|
||||
INHERIT_SUBTASKS_DESCRIPTION: 'F.TASK_REPEAT.F.INHERIT_SUBTASKS_DESCRIPTION',
|
||||
IS_ADD_TO_BOTTOM: 'F.TASK_REPEAT.F.IS_ADD_TO_BOTTOM',
|
||||
MONDAY: 'F.TASK_REPEAT.F.MONDAY',
|
||||
NOTES: 'F.TASK_REPEAT.F.NOTES',
|
||||
ORDER: 'F.TASK_REPEAT.F.ORDER',
|
||||
|
|
@ -1627,12 +1418,7 @@ const T = {
|
|||
REMOVE_INSTANCE: 'F.TASK_REPEAT.F.REMOVE_INSTANCE',
|
||||
REPEAT_CYCLE: 'F.TASK_REPEAT.F.REPEAT_CYCLE',
|
||||
REPEAT_EVERY: 'F.TASK_REPEAT.F.REPEAT_EVERY',
|
||||
REPEAT_FROM_COMPLETION_DATE: 'F.TASK_REPEAT.F.REPEAT_FROM_COMPLETION_DATE',
|
||||
REPEAT_FROM_COMPLETION_DATE_DESCRIPTION:
|
||||
'F.TASK_REPEAT.F.REPEAT_FROM_COMPLETION_DATE_DESCRIPTION',
|
||||
SATURDAY: 'F.TASK_REPEAT.F.SATURDAY',
|
||||
SCHEDULE_TYPE_FIXED: 'F.TASK_REPEAT.F.SCHEDULE_TYPE_FIXED',
|
||||
SCHEDULE_TYPE_FLEXIBLE: 'F.TASK_REPEAT.F.SCHEDULE_TYPE_FLEXIBLE',
|
||||
SCHEDULE_TYPE_LABEL: 'F.TASK_REPEAT.F.SCHEDULE_TYPE_LABEL',
|
||||
START_DATE: 'F.TASK_REPEAT.F.START_DATE',
|
||||
START_TIME: 'F.TASK_REPEAT.F.START_TIME',
|
||||
|
|
@ -1652,6 +1438,7 @@ const T = {
|
|||
FILTER_BY: 'F.TASK_VIEW.CUSTOMIZER.FILTER_BY',
|
||||
FILTER_DEFAULT: 'F.TASK_VIEW.CUSTOMIZER.FILTER_DEFAULT',
|
||||
FILTER_ESTIMATED_TIME: 'F.TASK_VIEW.CUSTOMIZER.FILTER_ESTIMATED_TIME',
|
||||
FILTER_NOT_SPECIFIED: 'F.TASK_VIEW.CUSTOMIZER.FILTER_NOT_SPECIFIED',
|
||||
FILTER_PROJECT: 'F.TASK_VIEW.CUSTOMIZER.FILTER_PROJECT',
|
||||
FILTER_SCHEDULED_DATE: 'F.TASK_VIEW.CUSTOMIZER.FILTER_SCHEDULED_DATE',
|
||||
FILTER_TAG: 'F.TASK_VIEW.CUSTOMIZER.FILTER_TAG',
|
||||
|
|
@ -1678,9 +1465,7 @@ const T = {
|
|||
TIME_1HOUR: 'F.TASK_VIEW.CUSTOMIZER.TIME_1HOUR',
|
||||
TIME_2HOUR: 'F.TASK_VIEW.CUSTOMIZER.TIME_2HOUR',
|
||||
TIME_30MIN: 'F.TASK_VIEW.CUSTOMIZER.TIME_30MIN',
|
||||
FILTER_NOT_SPECIFIED: 'F.TASK_VIEW.CUSTOMIZER.FILTER_NOT_SPECIFIED',
|
||||
TIME_SPENT: 'F.TASK_VIEW.CUSTOMIZER.TIME_SPENT',
|
||||
TITLE: 'F.TASK_VIEW.CUSTOMIZER.TITLE',
|
||||
},
|
||||
},
|
||||
TIME_TRACKING: {
|
||||
|
|
@ -1715,7 +1500,6 @@ const T = {
|
|||
},
|
||||
D_TRACKING_REMINDER: {
|
||||
CREATE_AND_TRACK: 'F.TIME_TRACKING.D_TRACKING_REMINDER.CREATE_AND_TRACK',
|
||||
IDLE_FOR: 'F.TIME_TRACKING.D_TRACKING_REMINDER.IDLE_FOR',
|
||||
NOTIFICATION_TITLE: 'F.TIME_TRACKING.D_TRACKING_REMINDER.NOTIFICATION_TITLE',
|
||||
TASK: 'F.TIME_TRACKING.D_TRACKING_REMINDER.TASK',
|
||||
TRACK_TO: 'F.TIME_TRACKING.D_TRACKING_REMINDER.TRACK_TO',
|
||||
|
|
@ -1741,7 +1525,6 @@ const T = {
|
|||
DAYS_WORKED: 'F.WORKLOG.CMP.DAYS_WORKED',
|
||||
MONTH_WORKED: 'F.WORKLOG.CMP.MONTH_WORKED',
|
||||
REPEATING_TASK: 'F.WORKLOG.CMP.REPEATING_TASK',
|
||||
RESTORE_TASK_FROM_ARCHIVE: 'F.WORKLOG.CMP.RESTORE_TASK_FROM_ARCHIVE',
|
||||
TASKS: 'F.WORKLOG.CMP.TASKS',
|
||||
TOTAL_TIME: 'F.WORKLOG.CMP.TOTAL_TIME',
|
||||
WEEK_NR: 'F.WORKLOG.CMP.WEEK_NR',
|
||||
|
|
@ -1840,26 +1623,21 @@ const T = {
|
|||
HIDE: 'G.HIDE',
|
||||
ICON_INP_DESCRIPTION: 'G.ICON_INP_DESCRIPTION',
|
||||
INBOX_PROJECT_TITLE: 'G.INBOX_PROJECT_TITLE',
|
||||
LOGIN: 'G.LOGIN',
|
||||
LOGOUT: 'G.LOGOUT',
|
||||
MINUTES: 'G.MINUTES',
|
||||
MOVE_BACKWARD: 'G.MOVE_BACKWARD',
|
||||
MOVE_FORWARD: 'G.MOVE_FORWARD',
|
||||
NEXT: 'G.NEXT',
|
||||
NONE: 'G.NONE',
|
||||
NO_CON: 'G.NO_CON',
|
||||
NONE: 'G.NONE',
|
||||
OK: 'G.OK',
|
||||
OVERDUE: 'G.OVERDUE',
|
||||
PREVIOUS: 'G.PREVIOUS',
|
||||
REMOVE: 'G.REMOVE',
|
||||
RESET: 'G.RESET',
|
||||
SAVE: 'G.SAVE',
|
||||
SUBMIT: 'G.SUBMIT',
|
||||
TITLE: 'G.TITLE',
|
||||
TODAY_TAG_TITLE: 'G.TODAY_TAG_TITLE',
|
||||
TRACKING_INTERVAL_DESCRIPTION: 'G.TRACKING_INTERVAL_DESCRIPTION',
|
||||
UNDO: 'G.UNDO',
|
||||
UPDATE: 'G.UPDATE',
|
||||
WITHOUT_PROJECT: 'G.WITHOUT_PROJECT',
|
||||
YESTERDAY: 'G.YESTERDAY',
|
||||
},
|
||||
|
|
@ -1889,9 +1667,7 @@ const T = {
|
|||
CALENDARS: {
|
||||
BROWSER_WARNING: 'GCF.CALENDARS.BROWSER_WARNING',
|
||||
CAL_PATH: 'GCF.CALENDARS.CAL_PATH',
|
||||
CAL_PROVIDERS: 'GCF.CALENDARS.CAL_PROVIDERS',
|
||||
CHECK_UPDATES: 'GCF.CALENDARS.CHECK_UPDATES',
|
||||
DEFAULT_PROJECT: 'GCF.CALENDARS.DEFAULT_PROJECT',
|
||||
HELP: 'GCF.CALENDARS.HELP',
|
||||
SHOW_BANNER_THRESHOLD: 'GCF.CALENDARS.SHOW_BANNER_THRESHOLD',
|
||||
},
|
||||
|
|
@ -1901,13 +1677,12 @@ const T = {
|
|||
},
|
||||
FOCUS_MODE: {
|
||||
HELP: 'GCF.FOCUS_MODE.HELP',
|
||||
L_ALWAYS_OPEN_FOCUS_MODE: 'GCF.FOCUS_MODE.L_ALWAYS_OPEN_FOCUS_MODE',
|
||||
L_SYNC_SESSION_WITH_TRACKING: 'GCF.FOCUS_MODE.L_SYNC_SESSION_WITH_TRACKING',
|
||||
L_IS_PLAY_TICK: 'GCF.FOCUS_MODE.L_IS_PLAY_TICK',
|
||||
L_MANUAL_BREAK_START: 'GCF.FOCUS_MODE.L_MANUAL_BREAK_START',
|
||||
L_PAUSE_TRACKING_DURING_BREAK: 'GCF.FOCUS_MODE.L_PAUSE_TRACKING_DURING_BREAK',
|
||||
L_SKIP_PREPARATION_SCREEN: 'GCF.FOCUS_MODE.L_SKIP_PREPARATION_SCREEN',
|
||||
L_START_IN_BACKGROUND: 'GCF.FOCUS_MODE.L_START_IN_BACKGROUND',
|
||||
L_MANUAL_BREAK_START: 'GCF.FOCUS_MODE.L_MANUAL_BREAK_START',
|
||||
L_SYNC_SESSION_WITH_TRACKING: 'GCF.FOCUS_MODE.L_SYNC_SESSION_WITH_TRACKING',
|
||||
TITLE: 'GCF.FOCUS_MODE.TITLE',
|
||||
},
|
||||
IDLE: {
|
||||
|
|
@ -1960,7 +1735,6 @@ const T = {
|
|||
TASK_MOVE_TO_PROJECT: 'GCF.KEYBOARD.TASK_MOVE_TO_PROJECT',
|
||||
TASK_OPEN_CONTEXT_MENU: 'GCF.KEYBOARD.TASK_OPEN_CONTEXT_MENU',
|
||||
TASK_OPEN_ESTIMATION_DIALOG: 'GCF.KEYBOARD.TASK_OPEN_ESTIMATION_DIALOG',
|
||||
TASK_PLAN_FORDAY: 'GCF.KEYBOARD.TASK_PLAN_FORDAY',
|
||||
TASK_SCHEDULE: 'GCF.KEYBOARD.TASK_SCHEDULE',
|
||||
TASK_SHORTCUTS: 'GCF.KEYBOARD.TASK_SHORTCUTS',
|
||||
TASK_SHORTCUTS_INFO: 'GCF.KEYBOARD.TASK_SHORTCUTS_INFO',
|
||||
|
|
@ -1968,7 +1742,6 @@ const T = {
|
|||
TASK_TOGGLE_DONE: 'GCF.KEYBOARD.TASK_TOGGLE_DONE',
|
||||
TITLE: 'GCF.KEYBOARD.TITLE',
|
||||
TOGGLE_BACKLOG: 'GCF.KEYBOARD.TOGGLE_BACKLOG',
|
||||
TOGGLE_BOOKMARKS: 'GCF.KEYBOARD.TOGGLE_BOOKMARKS',
|
||||
TOGGLE_ISSUE_PANEL: 'GCF.KEYBOARD.TOGGLE_ISSUE_PANEL',
|
||||
TOGGLE_PLAY: 'GCF.KEYBOARD.TOGGLE_PLAY',
|
||||
TOGGLE_SIDE_NAV: 'GCF.KEYBOARD.TOGGLE_SIDE_NAV',
|
||||
|
|
@ -2003,8 +1776,8 @@ const T = {
|
|||
SV: 'GCF.LANG.SV',
|
||||
TIME_LOCALE: 'GCF.LANG.TIME_LOCALE',
|
||||
TIME_LOCALE_AUTO: 'GCF.LANG.TIME_LOCALE_AUTO',
|
||||
TIME_LOCALE_DESCRIPTION: 'GCF.LANG.TIME_LOCALE_DESCRIPTION',
|
||||
TIME_LOCALE_DE_DE: 'GCF.LANG.TIME_LOCALE_DE_DE',
|
||||
TIME_LOCALE_DESCRIPTION: 'GCF.LANG.TIME_LOCALE_DESCRIPTION',
|
||||
TIME_LOCALE_EN_GB: 'GCF.LANG.TIME_LOCALE_EN_GB',
|
||||
TIME_LOCALE_EN_US: 'GCF.LANG.TIME_LOCALE_EN_US',
|
||||
TIME_LOCALE_ES_ES: 'GCF.LANG.TIME_LOCALE_ES_ES',
|
||||
|
|
@ -2037,10 +1810,10 @@ const T = {
|
|||
IS_CONFIRM_BEFORE_EXIT: 'GCF.MISC.IS_CONFIRM_BEFORE_EXIT',
|
||||
IS_CONFIRM_BEFORE_EXIT_WITHOUT_FINISH_DAY:
|
||||
'GCF.MISC.IS_CONFIRM_BEFORE_EXIT_WITHOUT_FINISH_DAY',
|
||||
IS_CONFIRM_BEFORE_TASK_DELETE: 'GCF.MISC.IS_CONFIRM_BEFORE_TASK_DELETE',
|
||||
IS_DARK_MODE: 'GCF.MISC.IS_DARK_MODE',
|
||||
IS_DISABLE_ANIMATIONS: 'GCF.MISC.IS_DISABLE_ANIMATIONS',
|
||||
IS_DISABLE_CELEBRATION: 'GCF.MISC.IS_DISABLE_CELEBRATION',
|
||||
IS_HIDE_NAV: 'GCF.MISC.IS_HIDE_NAV',
|
||||
IS_MINIMIZE_TO_TRAY: 'GCF.MISC.IS_MINIMIZE_TO_TRAY',
|
||||
IS_OVERLAY_INDICATOR_ENABLED: 'GCF.MISC.IS_OVERLAY_INDICATOR_ENABLED',
|
||||
IS_SHOW_TIP_LONGER: 'GCF.MISC.IS_SHOW_TIP_LONGER',
|
||||
|
|
@ -2066,9 +1839,10 @@ const T = {
|
|||
REMINDER: {
|
||||
COUNTDOWN_DURATION: 'GCF.REMINDER.COUNTDOWN_DURATION',
|
||||
DEFAULT_TASK_REMIND_OPTION: 'GCF.REMINDER.DEFAULT_TASK_REMIND_OPTION',
|
||||
IS_COUNTDOWN_BANNER_ENABLED: 'GCF.REMINDER.IS_COUNTDOWN_BANNER_ENABLED',
|
||||
TITLE: 'GCF.REMINDER.TITLE',
|
||||
DISABLE_REMINDERS: 'GCF.REMINDER.DISABLE_REMINDERS',
|
||||
IS_COUNTDOWN_BANNER_ENABLED: 'GCF.REMINDER.IS_COUNTDOWN_BANNER_ENABLED',
|
||||
IS_FOCUS_WINDOW: 'GCF.REMINDER.IS_FOCUS_WINDOW',
|
||||
TITLE: 'GCF.REMINDER.TITLE',
|
||||
},
|
||||
SCHEDULE: {
|
||||
HELP: 'GCF.SCHEDULE.HELP',
|
||||
|
|
@ -2081,7 +1855,6 @@ const T = {
|
|||
L_WORK_START: 'GCF.SCHEDULE.L_WORK_START',
|
||||
MONTH: 'GCF.SCHEDULE.MONTH',
|
||||
TITLE: 'GCF.SCHEDULE.TITLE',
|
||||
WEEK: 'GCF.SCHEDULE.WEEK',
|
||||
WORK_START_END_DESCRIPTION: 'GCF.SCHEDULE.WORK_START_END_DESCRIPTION',
|
||||
},
|
||||
SHORT_SYNTAX: {
|
||||
|
|
@ -2164,7 +1937,6 @@ const T = {
|
|||
COPY_TO_CLIPPBOARD: 'GLOBAL_SNACK.COPY_TO_CLIPPBOARD',
|
||||
DUPLICATE_PROJECT_ERROR: 'GLOBAL_SNACK.DUPLICATE_PROJECT_ERROR',
|
||||
DUPLICATE_PROJECT_SUCCESS: 'GLOBAL_SNACK.DUPLICATE_PROJECT_SUCCESS',
|
||||
ERR_COMPRESSION: 'GLOBAL_SNACK.ERR_COMPRESSION',
|
||||
FILE_DOWNLOADED: 'GLOBAL_SNACK.FILE_DOWNLOADED',
|
||||
FILE_DOWNLOADED_BTN: 'GLOBAL_SNACK.FILE_DOWNLOADED_BTN',
|
||||
NAVIGATE_TO_TASK_ERR: 'GLOBAL_SNACK.NAVIGATE_TO_TASK_ERR',
|
||||
|
|
@ -2177,13 +1949,8 @@ const T = {
|
|||
SHARE_FAILED: 'GLOBAL_SNACK.SHARE_FAILED',
|
||||
SHARE_FAILED_FALLBACK: 'GLOBAL_SNACK.SHARE_FAILED_FALLBACK',
|
||||
SHARE_UNAVAILABLE_FALLBACK: 'GLOBAL_SNACK.SHARE_UNAVAILABLE_FALLBACK',
|
||||
SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG:
|
||||
'GLOBAL_SNACK.SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG',
|
||||
UNPLANNED_TODAY_TASKS: 'GLOBAL_SNACK.UNPLANNED_TODAY_TASKS',
|
||||
},
|
||||
GLOBAL: {
|
||||
COPY_SUFFIX: 'GLOBAL.COPY_SUFFIX',
|
||||
},
|
||||
GPB: {
|
||||
ASSETS: 'GPB.ASSETS',
|
||||
DBX_DOWNLOAD: 'GPB.DBX_DOWNLOAD',
|
||||
|
|
@ -2203,11 +1970,11 @@ const T = {
|
|||
BOARDS: 'MH.BOARDS',
|
||||
COPY_TASK_LIST_MARKDOWN: 'MH.COPY_TASK_LIST_MARKDOWN',
|
||||
CREATE_PROJECT: 'MH.CREATE_PROJECT',
|
||||
DUPLICATE_PROJECT: 'MH.DUPLICATE_PROJECT',
|
||||
CREATE_TAG: 'MH.CREATE_TAG',
|
||||
DELETE_PROJECT: 'MH.DELETE_PROJECT',
|
||||
DELETE_TAG: 'MH.DELETE_TAG',
|
||||
DONATE: 'MH.DONATE',
|
||||
DUPLICATE_PROJECT: 'MH.DUPLICATE_PROJECT',
|
||||
ENTER_FOCUS_MODE: 'MH.ENTER_FOCUS_MODE',
|
||||
GO_TO_TASK_LIST: 'MH.GO_TO_TASK_LIST',
|
||||
HELP: 'MH.HELP',
|
||||
|
|
@ -2226,6 +1993,7 @@ const T = {
|
|||
NOTES_PANEL_INFO: 'MH.NOTES_PANEL_INFO',
|
||||
NO_PROJECT_INFO: 'MH.NO_PROJECT_INFO',
|
||||
NO_TAG_INFO: 'MH.NO_TAG_INFO',
|
||||
NO_TASKS_TO_TRACK: 'MH.NO_TASKS_TO_TRACK',
|
||||
PLANNER: 'MH.PLANNER',
|
||||
PROCRASTINATE: 'MH.PROCRASTINATE',
|
||||
PROJECTS: 'MH.PROJECTS',
|
||||
|
|
@ -2236,7 +2004,6 @@ const T = {
|
|||
SEARCH: 'MH.SEARCH',
|
||||
SETTINGS: 'MH.SETTINGS',
|
||||
SHARE_TASK_LIST_MARKDOWN: 'MH.SHARE_TASK_LIST_MARKDOWN',
|
||||
SHOW_SEARCH_BAR: 'MH.SHOW_SEARCH_BAR',
|
||||
SIDE_PANEL_MENU: 'MH.SIDE_PANEL_MENU',
|
||||
TAGS: 'MH.TAGS',
|
||||
TASKS: 'MH.TASKS',
|
||||
|
|
@ -2245,7 +2012,6 @@ const T = {
|
|||
TOGGLE_SHOW_ISSUE_PANEL: 'MH.TOGGLE_SHOW_ISSUE_PANEL',
|
||||
TOGGLE_SHOW_NOTES: 'MH.TOGGLE_SHOW_NOTES',
|
||||
TOGGLE_TRACK_TIME: 'MH.TOGGLE_TRACK_TIME',
|
||||
NO_TASKS_TO_TRACK: 'MH.NO_TASKS_TO_TRACK',
|
||||
TRIGGER_SYNC: 'MH.TRIGGER_SYNC',
|
||||
UNPLAN_ALL_TASKS: 'MH.UNPLAN_ALL_TASKS',
|
||||
WORKLOG: 'MH.WORKLOG',
|
||||
|
|
@ -2323,9 +2089,7 @@ const T = {
|
|||
CONFIGURATION: 'PLUGINS.CONFIGURATION',
|
||||
CONFIGURE: 'PLUGINS.CONFIGURE',
|
||||
CONFIRM_REMOVE: 'PLUGINS.CONFIRM_REMOVE',
|
||||
DISABLED: 'PLUGINS.DISABLED',
|
||||
ELECTRON_API_NOT_AVAILABLE: 'PLUGINS.ELECTRON_API_NOT_AVAILABLE',
|
||||
ENABLED: 'PLUGINS.ENABLED',
|
||||
ERROR: 'PLUGINS.ERROR',
|
||||
ERROR_LOADING_PLUGIN: 'PLUGINS.ERROR_LOADING_PLUGIN',
|
||||
EXPERIMENTAL_WARNING: 'PLUGINS.EXPERIMENTAL_WARNING',
|
||||
|
|
@ -2359,16 +2123,6 @@ const T = {
|
|||
NODE_ONLY_DESKTOP: 'PLUGINS.NODE_ONLY_DESKTOP',
|
||||
NO_ADDITIONAL_INFO: 'PLUGINS.NO_ADDITIONAL_INFO',
|
||||
NO_CONTENT_PROVIDED: 'PLUGINS.NO_CONTENT_PROVIDED',
|
||||
NO_PLUGIN_CONTEXT_ACTION: 'PLUGINS.NO_PLUGIN_CONTEXT_ACTION',
|
||||
NO_PLUGIN_CONTEXT_HEADER_BUTTON: 'PLUGINS.NO_PLUGIN_CONTEXT_HEADER_BUTTON',
|
||||
NO_PLUGIN_CONTEXT_LOADING: 'PLUGINS.NO_PLUGIN_CONTEXT_LOADING',
|
||||
NO_PLUGIN_CONTEXT_MENU_ENTRY: 'PLUGINS.NO_PLUGIN_CONTEXT_MENU_ENTRY',
|
||||
NO_PLUGIN_CONTEXT_NODE: 'PLUGINS.NO_PLUGIN_CONTEXT_NODE',
|
||||
NO_PLUGIN_CONTEXT_PERSISTENCE: 'PLUGINS.NO_PLUGIN_CONTEXT_PERSISTENCE',
|
||||
NO_PLUGIN_CONTEXT_SHORTCUT: 'PLUGINS.NO_PLUGIN_CONTEXT_SHORTCUT',
|
||||
NO_PLUGIN_CONTEXT_SIDE_PANEL: 'PLUGINS.NO_PLUGIN_CONTEXT_SIDE_PANEL',
|
||||
NO_PLUGIN_CONTEXT_SYNC: 'PLUGINS.NO_PLUGIN_CONTEXT_SYNC',
|
||||
NO_PLUGIN_ID_PROVIDED_FOR_HTML: 'PLUGINS.NO_PLUGIN_ID_PROVIDED_FOR_HTML',
|
||||
NO_PLUGIN_MANIFEST_NODE: 'PLUGINS.NO_PLUGIN_MANIFEST_NODE',
|
||||
OK: 'PLUGINS.OK',
|
||||
PARENT_TASK_DOES_NOT_EXIST: 'PLUGINS.PARENT_TASK_DOES_NOT_EXIST',
|
||||
|
|
@ -2376,11 +2130,7 @@ const T = {
|
|||
PERMISSIONS: 'PLUGINS.PERMISSIONS',
|
||||
PLEASE_SELECT_ZIP_FILE: 'PLUGINS.PLEASE_SELECT_ZIP_FILE',
|
||||
PLUGIN_DIALOG_TITLE: 'PLUGINS.PLUGIN_DIALOG_TITLE',
|
||||
PLUGIN_DOES_NOT_SUPPORT_IFRAME: 'PLUGINS.PLUGIN_DOES_NOT_SUPPORT_IFRAME',
|
||||
PLUGIN_ID_NOT_PROVIDED: 'PLUGINS.PLUGIN_ID_NOT_PROVIDED',
|
||||
PLUGIN_JS_NOT_FOUND: 'PLUGINS.PLUGIN_JS_NOT_FOUND',
|
||||
PLUGIN_NOT_FOUND: 'PLUGINS.PLUGIN_NOT_FOUND',
|
||||
PLUGIN_SYSTEM_FAILED_INIT: 'PLUGINS.PLUGIN_SYSTEM_FAILED_INIT',
|
||||
PROJECT_DOES_NOT_EXIST: 'PLUGINS.PROJECT_DOES_NOT_EXIST',
|
||||
PROJECT_NOT_FOUND: 'PLUGINS.PROJECT_NOT_FOUND',
|
||||
RECOMMENDATION: 'PLUGINS.RECOMMENDATION',
|
||||
|
|
@ -2405,7 +2155,6 @@ const T = {
|
|||
UNABLE_TO_PERSIST_DATA: 'PLUGINS.UNABLE_TO_PERSIST_DATA',
|
||||
UNKNOWN_ERROR: 'PLUGINS.UNKNOWN_ERROR',
|
||||
UPLOAD_PLUGIN_INSTRUCTION: 'PLUGINS.UPLOAD_PLUGIN_INSTRUCTION',
|
||||
USER_DECLINED_NODE_PERMISSION: 'PLUGINS.USER_DECLINED_NODE_PERMISSION',
|
||||
VALIDATION_FAILED: 'PLUGINS.VALIDATION_FAILED',
|
||||
},
|
||||
PM: {
|
||||
|
|
@ -2413,14 +2162,12 @@ const T = {
|
|||
},
|
||||
PS: {
|
||||
GLOBAL_SETTINGS: 'PS.GLOBAL_SETTINGS',
|
||||
ISSUE_INTEGRATION: 'PS.ISSUE_INTEGRATION',
|
||||
NO_PLUGINS_INSTALLED: 'PS.NO_PLUGINS_INSTALLED',
|
||||
PLUGINS: 'PS.PLUGINS',
|
||||
PRIVACY_POLICY: 'PS.PRIVACY_POLICY',
|
||||
PRODUCTIVITY_HELPER: 'PS.PRODUCTIVITY_HELPER',
|
||||
PROJECT_SETTINGS: 'PS.PROJECT_SETTINGS',
|
||||
PROVIDE_FEEDBACK: 'PS.PROVIDE_FEEDBACK',
|
||||
RELOAD: 'PS.RELOAD',
|
||||
SYNC_EXPORT: 'PS.SYNC_EXPORT',
|
||||
TAG_SETTINGS: 'PS.TAG_SETTINGS',
|
||||
TOGGLE_DARK_MODE: 'PS.TOGGLE_DARK_MODE',
|
||||
|
|
@ -2469,21 +2216,18 @@ const T = {
|
|||
EXISTING_PROFILES: 'USER_PROFILES.EXISTING_PROFILES',
|
||||
EXPORT_PROFILE: 'USER_PROFILES.EXPORT_PROFILE',
|
||||
MANAGE_PROFILES: 'USER_PROFILES.MANAGE_PROFILES',
|
||||
OPEN_PROFILES_FOLDER: 'USER_PROFILES.OPEN_PROFILES_FOLDER',
|
||||
PROFILE_NAME: 'USER_PROFILES.PROFILE_NAME',
|
||||
PROFILE_NAME_PLACEHOLDER: 'USER_PROFILES.PROFILE_NAME_PLACEHOLDER',
|
||||
RENAME: 'USER_PROFILES.RENAME',
|
||||
SAVE: 'USER_PROFILES.SAVE',
|
||||
},
|
||||
V: {
|
||||
E_1TO10: 'V.E_1TO10',
|
||||
E_DATETIME: 'V.E_DATETIME',
|
||||
E_DURATION: 'V.E_DURATION',
|
||||
E_MAX: 'V.E_MAX',
|
||||
E_MAX_LENGTH: 'V.E_MAX_LENGTH',
|
||||
E_MIN: 'V.E_MIN',
|
||||
E_MIN_LENGTH: 'V.E_MIN_LENGTH',
|
||||
E_PATTERN: 'V.E_PATTERN',
|
||||
E_REQUIRED: 'V.E_REQUIRED',
|
||||
},
|
||||
WW: {
|
||||
|
|
@ -2494,10 +2238,7 @@ const T = {
|
|||
DONE_TASKS_IN_ARCHIVE: 'WW.DONE_TASKS_IN_ARCHIVE',
|
||||
ESTIMATE_REMAINING: 'WW.ESTIMATE_REMAINING',
|
||||
FINISH_DAY: 'WW.FINISH_DAY',
|
||||
FINISH_DAY_FOR_PROJECT: 'WW.FINISH_DAY_FOR_PROJECT',
|
||||
FINISH_DAY_FOR_TAG: 'WW.FINISH_DAY_FOR_TAG',
|
||||
FINISH_DAY_TOOLTIP: 'WW.FINISH_DAY_TOOLTIP',
|
||||
HELP_PROCRASTINATION: 'WW.HELP_PROCRASTINATION',
|
||||
LATER_TODAY: 'WW.LATER_TODAY',
|
||||
MOVE_DONE_TO_ARCHIVE: 'WW.MOVE_DONE_TO_ARCHIVE',
|
||||
NO_DONE_TASKS: 'WW.NO_DONE_TASKS',
|
||||
|
|
|
|||
48
src/app/ui/heatmap/heatmap.component.html
Normal file
48
src/app/ui/heatmap/heatmap.component.html
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
@if (data(); as heatmapData) {
|
||||
<div class="heatmap-container">
|
||||
<div class="heatmap-grid">
|
||||
<div class="day-labels">
|
||||
<div class="month-spacer"></div>
|
||||
@for (label of dayLabels(); track $index) {
|
||||
<div class="day-label">{{ label }}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="scrollable-content"
|
||||
#scrollableContent
|
||||
>
|
||||
<div class="heatmap-months">
|
||||
@for (month of heatmapData.monthLabels; track $index) {
|
||||
<div class="month-label">{{ month }}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="weeks">
|
||||
@for (week of heatmapData.weeks; track $index) {
|
||||
<div class="week">
|
||||
@for (day of week.days; track $index) {
|
||||
<div
|
||||
[class]="getDayClass(day)"
|
||||
[title]="getDayTitle(day)"
|
||||
></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (showLegend()) {
|
||||
<div class="heatmap-legend">
|
||||
<span>Less</span>
|
||||
<div class="legend-item level-0"></div>
|
||||
<div class="legend-item level-1"></div>
|
||||
<div class="legend-item level-2"></div>
|
||||
<div class="legend-item level-3"></div>
|
||||
<div class="legend-item level-4"></div>
|
||||
<span>More</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
211
src/app/ui/heatmap/heatmap.component.scss
Normal file
211
src/app/ui/heatmap/heatmap.component.scss
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
.heatmap-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
background: var(--c-dark-10);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.heatmap-grid {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.scrollable-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
// Smooth scrolling
|
||||
scroll-behavior: smooth;
|
||||
|
||||
// Better scrollbar styling
|
||||
&::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--c-dark-10);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--c-dark-20);
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: var(--c-dark-30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.heatmap-months {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
height: 12px;
|
||||
color: var(--text-color-muted);
|
||||
flex-shrink: 0;
|
||||
|
||||
.month-label {
|
||||
flex: 0 0 auto;
|
||||
width: calc(4 * 12px + 4 * 2px); // 4 weeks * (cell width + gap)
|
||||
}
|
||||
}
|
||||
|
||||
.day-labels {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
font-size: 10px;
|
||||
color: var(--text-color-muted);
|
||||
padding-right: 4px;
|
||||
width: 40px;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
|
||||
.month-spacer {
|
||||
height: 17px; // 12px (heatmap-months height) + 8px (gap in scrollable-content)
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.day-label {
|
||||
height: 12px;
|
||||
line-height: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.weeks {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
flex-wrap: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.week {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.day {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.empty {
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&.level-0 {
|
||||
background: var(--c-dark-10);
|
||||
}
|
||||
|
||||
&.level-1 {
|
||||
background: color-mix(in srgb, var(--c-primary) 20%, transparent);
|
||||
}
|
||||
|
||||
&.level-2 {
|
||||
background: color-mix(in srgb, var(--c-primary) 40%, transparent);
|
||||
}
|
||||
|
||||
&.level-3 {
|
||||
background: color-mix(in srgb, var(--c-primary) 60%, transparent);
|
||||
}
|
||||
|
||||
&.level-4 {
|
||||
background: var(--c-primary);
|
||||
}
|
||||
|
||||
&:not(.empty):hover {
|
||||
transform: scale(1.3);
|
||||
outline: 1px solid var(--c-dark-20);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.heatmap-legend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
font-size: 11px;
|
||||
color: var(--text-color-muted);
|
||||
padding-right: 4px;
|
||||
|
||||
span {
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
|
||||
&.level-0 {
|
||||
background: var(--c-dark-10);
|
||||
}
|
||||
|
||||
&.level-1 {
|
||||
background: color-mix(in srgb, var(--c-primary) 20%, transparent);
|
||||
}
|
||||
|
||||
&.level-2 {
|
||||
background: color-mix(in srgb, var(--c-primary) 40%, transparent);
|
||||
}
|
||||
|
||||
&.level-3 {
|
||||
background: color-mix(in srgb, var(--c-primary) 60%, transparent);
|
||||
}
|
||||
|
||||
&.level-4 {
|
||||
background: var(--c-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dark theme support
|
||||
:host-context(.isDarkTheme) {
|
||||
.heatmap-container {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
|
||||
.scrollable-content {
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--c-light-10);
|
||||
|
||||
&:hover {
|
||||
background: var(--c-light-33);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.day {
|
||||
&.level-0 {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
|
||||
&:not(.empty):hover {
|
||||
outline-color: var(--c-light-10);
|
||||
}
|
||||
}
|
||||
|
||||
.heatmap-legend .legend-item.level-0 {
|
||||
background: var(--c-light-05);
|
||||
}
|
||||
}
|
||||
90
src/app/ui/heatmap/heatmap.component.ts
Normal file
90
src/app/ui/heatmap/heatmap.component.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
effect,
|
||||
ElementRef,
|
||||
inject,
|
||||
input,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { DateAdapter } from '@angular/material/core';
|
||||
|
||||
export interface DayData {
|
||||
date: Date;
|
||||
dateStr: string;
|
||||
taskCount: number;
|
||||
timeSpent: number;
|
||||
level: number; // 0-4 for color intensity
|
||||
}
|
||||
|
||||
export interface WeekData {
|
||||
days: (DayData | null)[];
|
||||
}
|
||||
|
||||
export interface HeatmapData {
|
||||
weeks: WeekData[];
|
||||
monthLabels: string[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'heatmap',
|
||||
templateUrl: './heatmap.component.html',
|
||||
styleUrls: ['./heatmap.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [],
|
||||
})
|
||||
export class HeatmapComponent {
|
||||
private readonly _dateAdapter = inject(DateAdapter);
|
||||
|
||||
readonly data = input.required<HeatmapData | null>();
|
||||
readonly showLegend = input<boolean>(true);
|
||||
readonly scrollToEnd = input<boolean>(false);
|
||||
|
||||
private readonly _scrollableContent =
|
||||
viewChild<ElementRef<HTMLElement>>('scrollableContent');
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
const data = this.data();
|
||||
const scrollEl = this._scrollableContent()?.nativeElement;
|
||||
if (data && scrollEl && this.scrollToEnd()) {
|
||||
// Use setTimeout to ensure DOM is updated
|
||||
setTimeout(() => {
|
||||
scrollEl.scrollTo({ left: scrollEl.scrollWidth, behavior: 'instant' });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
readonly dayLabels = computed(() => {
|
||||
const allDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||
const firstDay = this._dateAdapter.getFirstDayOfWeek();
|
||||
return [...allDays.slice(firstDay), ...allDays.slice(0, firstDay)];
|
||||
});
|
||||
|
||||
getDayClass(day: DayData | null): string {
|
||||
if (!day) {
|
||||
return 'day empty';
|
||||
}
|
||||
return `day level-${day.level}`;
|
||||
}
|
||||
|
||||
getDayTitle(day: DayData | null): string {
|
||||
if (!day) {
|
||||
return '';
|
||||
}
|
||||
return `${day.dateStr}: ${day.taskCount} tasks, ${this._formatTime(day.timeSpent)}`;
|
||||
}
|
||||
|
||||
private _formatTime(ms: number): string {
|
||||
const hours = Math.floor(ms / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60));
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`;
|
||||
}
|
||||
return `${minutes}m`;
|
||||
}
|
||||
}
|
||||
98
src/app/ui/pipes/scheduled-date-group.pipe.spec.ts
Normal file
98
src/app/ui/pipes/scheduled-date-group.pipe.spec.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
import { ScheduledDateGroupPipe } from './scheduled-date-group.pipe';
|
||||
import { DateTimeFormatService } from '../../core/date-time-format/date-time-format.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { getDbDateStr } from '../../util/get-db-date-str';
|
||||
|
||||
describe('ScheduledDateGroupPipe', () => {
|
||||
let pipe: ScheduledDateGroupPipe;
|
||||
let mockDateTimeFormatService: jasmine.SpyObj<DateTimeFormatService>;
|
||||
let mockTranslateService: jasmine.SpyObj<TranslateService>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockDateTimeFormatService = jasmine.createSpyObj('DateTimeFormatService', [], {
|
||||
currentLocale: 'en-US',
|
||||
});
|
||||
mockTranslateService = jasmine.createSpyObj('TranslateService', ['instant']);
|
||||
mockTranslateService.instant.and.callFake((key: string) => {
|
||||
if (key === 'G.TODAY_TAG_TITLE') return 'Today';
|
||||
return key;
|
||||
});
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
ScheduledDateGroupPipe,
|
||||
{ provide: DateTimeFormatService, useValue: mockDateTimeFormatService },
|
||||
{ provide: TranslateService, useValue: mockTranslateService },
|
||||
],
|
||||
});
|
||||
|
||||
pipe = TestBed.inject(ScheduledDateGroupPipe);
|
||||
});
|
||||
|
||||
it('should create the pipe', () => {
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should format date string with weekday', () => {
|
||||
// Wednesday, January 15, 2025
|
||||
const result = pipe.transform('2025-01-15');
|
||||
expect(result).toMatch(/Wed/i);
|
||||
expect(result).toContain('1');
|
||||
expect(result).toContain('15');
|
||||
});
|
||||
|
||||
it('should return "No date" unchanged', () => {
|
||||
const result = pipe.transform('No date');
|
||||
expect(result).toBe('No date');
|
||||
});
|
||||
|
||||
it('should return null for null input', () => {
|
||||
const result = pipe.transform(null);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null for undefined input', () => {
|
||||
const result = pipe.transform(undefined);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle "Today" translation for today\'s date', () => {
|
||||
const todayStr = getDbDateStr();
|
||||
const result = pipe.transform(todayStr);
|
||||
expect(result).toBe('Today');
|
||||
expect(mockTranslateService.instant).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should format weekend dates correctly', () => {
|
||||
// Saturday, January 18, 2025
|
||||
const saturdayResult = pipe.transform('2025-01-18');
|
||||
expect(saturdayResult).toMatch(/Sat/i);
|
||||
|
||||
// Sunday, January 19, 2025
|
||||
const sundayResult = pipe.transform('2025-01-19');
|
||||
expect(sundayResult).toMatch(/Sun/i);
|
||||
});
|
||||
|
||||
it('should respect configured locale for weekday names', () => {
|
||||
// Change locale to German
|
||||
Object.defineProperty(mockDateTimeFormatService, 'currentLocale', {
|
||||
get: () => 'de-DE',
|
||||
});
|
||||
|
||||
// Wednesday in German is "Mi" (Mittwoch)
|
||||
const result = pipe.transform('2025-01-15');
|
||||
expect(result).toMatch(/Mi/i);
|
||||
});
|
||||
|
||||
it('should pass through non-date strings that are not "No date"', () => {
|
||||
// "No tag", "No project" etc. should pass through unchanged
|
||||
const result = pipe.transform('No tag');
|
||||
expect(result).toBe('No tag');
|
||||
});
|
||||
|
||||
it('should handle invalid date strings gracefully', () => {
|
||||
const result = pipe.transform('invalid-date');
|
||||
expect(result).toBe('invalid-date');
|
||||
});
|
||||
});
|
||||
57
src/app/ui/pipes/scheduled-date-group.pipe.ts
Normal file
57
src/app/ui/pipes/scheduled-date-group.pipe.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { inject, Pipe, PipeTransform } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { T } from 'src/app/t.const';
|
||||
import { getDbDateStr } from '../../util/get-db-date-str';
|
||||
import { dateStrToUtcDate } from '../../util/date-str-to-utc-date';
|
||||
import { DateTimeFormatService } from '../../core/date-time-format/date-time-format.service';
|
||||
|
||||
const DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
/**
|
||||
* Pipe that formats scheduled date group keys with day of week.
|
||||
* Input: YYYY-MM-DD date string or special strings like "No date"
|
||||
* Output: "Wed 1/15" or "Today" or passthrough for non-date strings
|
||||
*/
|
||||
@Pipe({
|
||||
name: 'scheduledDateGroup',
|
||||
standalone: true,
|
||||
pure: false,
|
||||
})
|
||||
export class ScheduledDateGroupPipe implements PipeTransform {
|
||||
private _dateTimeFormatService = inject(DateTimeFormatService);
|
||||
private _translateService = inject(TranslateService);
|
||||
|
||||
transform(value: unknown): string | null {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure value is a string
|
||||
if (typeof value !== 'string') {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
// Check if it's a date string (YYYY-MM-DD format)
|
||||
if (!DATE_REGEX.test(value)) {
|
||||
// Pass through non-date strings like "No date", "No tag", etc.
|
||||
return value;
|
||||
}
|
||||
|
||||
const todayStr = getDbDateStr();
|
||||
if (value === todayStr) {
|
||||
return this._translateService.instant(T.G.TODAY_TAG_TITLE);
|
||||
}
|
||||
|
||||
const date = dateStrToUtcDate(value);
|
||||
const locale = this._dateTimeFormatService.currentLocale;
|
||||
|
||||
// Format with weekday and date: "Wed 1/15"
|
||||
const formatter = new Intl.DateTimeFormat(locale, {
|
||||
weekday: 'short',
|
||||
month: 'numeric',
|
||||
day: 'numeric',
|
||||
});
|
||||
|
||||
return formatter.format(date);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,15 +1,4 @@
|
|||
{
|
||||
"ANDROID": {
|
||||
"NOTIFICATIONS": {
|
||||
"SYNC_CONFLICT_MSG": "Zkontrolujte a rozhodněte se, co udělat.",
|
||||
"SYNC_CONFLICT_TITLE": "Došlo k synchronizačnímu konfliktu"
|
||||
},
|
||||
"PERMANENT_NOTIFICATION_MSGS": {
|
||||
"INITIAL": "Aplikace běží na pozadí pro povolení synchronizace, pokud je povolena",
|
||||
"NO_ACTIVE_TASKS": "Žádné aktivní úkoly",
|
||||
"SYNCING": "Probíhá synchronizace"
|
||||
}
|
||||
},
|
||||
"APP": {
|
||||
"B_INSTALL": {
|
||||
"IGNORE": "Ignorovat",
|
||||
|
|
@ -17,8 +6,6 @@
|
|||
"MSG": "Chcete nainstalovat Super Produktivitu jako PWA?"
|
||||
},
|
||||
"B_OFFLINE": "Jste odpojeni od internetu. Synchronizace a požadavky na data poskytovatele problémů nebudou fungovat.",
|
||||
"UPDATE_MAIN_MODEL": "Super Produktivita byla aktualizována! Pro vaše data jsou vyžadovány některé migrace. Všimněte si, že to činí vaše data nekompatibilní s předchozími verzemi aplikace.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "Nebyla vybrána žádná aktualizace modelu. Všimněte si, že buď musíte downgradovat na poslední verzi, nebo provést aktualizaci modelu.",
|
||||
"UPDATE_WEB_APP": "K dispozici je nová verze. Načíst novou verzi?"
|
||||
},
|
||||
"BL": {
|
||||
|
|
@ -32,11 +19,7 @@
|
|||
"RESTORE_STRAY_BACKUP": "Během poslední synchronizace mohla nastat chyba. Chcete obnovit poslední zálohu?"
|
||||
},
|
||||
"DATETIME_SCHEDULE": {
|
||||
"LATER_TODAY": "Později dnes",
|
||||
"NEXT_WEEK": "Příští týden",
|
||||
"PLACEHOLDER": "Vyberte prosím datum",
|
||||
"PRESS_ENTER_AGAIN": "Stiskněte enter znovu pro uložení",
|
||||
"TOMORROW": "Zítra"
|
||||
"PRESS_ENTER_AGAIN": "Stiskněte enter znovu pro uložení"
|
||||
},
|
||||
"F": {
|
||||
"ATTACHMENT": {
|
||||
|
|
@ -44,7 +27,6 @@
|
|||
"ADD_ATTACHMENT": "Přidat přílohu",
|
||||
"EDIT_ATTACHMENT": "Upravit přílohu",
|
||||
"LABELS": {
|
||||
"FILE": "Cesta k souboru",
|
||||
"IMG": "Obrázek",
|
||||
"LINK": "URL"
|
||||
},
|
||||
|
|
@ -57,9 +39,7 @@
|
|||
}
|
||||
},
|
||||
"CALDAV": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Nastavení CalDav pro projekt"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"CALDAV_CATEGORY_FILTER": "Kategorie pro filtrování úkolů (nechte prázdné pro žádné)",
|
||||
"CALDAV_PASSWORD": "Vaše heslo CalDav",
|
||||
|
|
@ -69,15 +49,7 @@
|
|||
"IS_TRANSITION_ISSUES_ENABLED": "Automaticky dokončovat úkoly CalDav při dokončení úkolu"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity tak, aby v seznamu úkolů pro konkrétní projekt v panelu vytváření úkolů v denním plánovacím zobrazení zobrazoval neukončené úkoly CalDav. Budou uvedeny jako návrhy a poskytnou odkaz na úkol a další informace o něm.</p> <p>Kromě toho můžete automaticky přidat a synchronizovat všechny neukončené úkoly do vašeho backlogu úkolů.</p><p>Aby to fungovalo v Nextcloud ve webové aplikaci, možná budete muset přidat „https://app.super-productivity.com“ na bílý seznam pomocí aplikace Nextcloud <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword</a>.</p>",
|
||||
"TITLE": "CalDav"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"DESCRIPTION": "Popis",
|
||||
"LABELS": "Kategorie",
|
||||
"MARK_AS_CHECKED": "Označit aktualizace jako kontrolované",
|
||||
"STATUS": "Stav",
|
||||
"SUMMARY": "Souhrn"
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity tak, aby v seznamu úkolů pro konkrétní projekt v panelu vytváření úkolů v denním plánovacím zobrazení zobrazoval neukončené úkoly CalDav. Budou uvedeny jako návrhy a poskytnou odkaz na úkol a další informace o něm.</p> <p>Kromě toho můžete automaticky přidat a synchronizovat všechny neukončené úkoly do vašeho backlogu úkolů.</p><p>Aby to fungovalo v Nextcloud ve webové aplikaci, možná budete muset přidat „https://app.super-productivity.com“ na bílý seznam pomocí aplikace Nextcloud <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword</a>.</p>"
|
||||
},
|
||||
"S": {
|
||||
"CALENDAR_NOT_FOUND": "CalDav: Kalendář „{{calendarName}}“ nebyl nalezen",
|
||||
|
|
@ -101,10 +73,6 @@
|
|||
},
|
||||
"DROPBOX": {
|
||||
"S": {
|
||||
"ACCESS_TOKEN_ERROR": "Dropbox: Nelze vygenerovat přístupový token z ověřovacího kódu",
|
||||
"ACCESS_TOKEN_GENERATED": "Dropbox: Přístupový token vygenerován z ověřovacího kódu",
|
||||
"AUTH_ERROR": "Dropbox: Poskytnut neplatný přístupový token",
|
||||
"AUTH_ERROR_ACTION": "Změnit token",
|
||||
"OFFLINE": "Dropbox: Nelze synchronizovat, protože je offline",
|
||||
"SYNC_ERROR": "Dropbox: Chyba při synchronizaci"
|
||||
}
|
||||
|
|
@ -116,32 +84,23 @@
|
|||
},
|
||||
"FOCUS_MODE": {
|
||||
"BACK_TO_PLANNING": "Zpět na plánování",
|
||||
"CONGRATS": "Gratulujeme k dokončení této relace!",
|
||||
"CONTINUE_FOCUS_SESSION": "Pokračovat v režimu zaměření",
|
||||
"FINISH_TASK_AND_SELECT_NEXT": "Dokončit úkol a vybrat další",
|
||||
"GET_READY": "Připravte se na svou relaci zaměření!!!",
|
||||
"GO_TO_PROCRASTINATION": "Získejte pomoc, když odkládáte",
|
||||
"GOGOGO": "Jděte, jděte, jděte!!!",
|
||||
"NEXT": "Další",
|
||||
"ON": "zapnuto",
|
||||
"OPEN_ISSUE_IN_BROWSER": "Otevřít problém v prohlížeči",
|
||||
"PREP_GET_MENTALLY_READY": "Připravte se mentálně na zaměření a produktivitu",
|
||||
"PREP_SIT_UPRIGHT": "Sedět (nebo stát) vzpřímeně",
|
||||
"PREP_STRETCH": "Zahřejte se lehkým protažením",
|
||||
"SELECT_ANOTHER_TASK": "Vyberte jiný úkol",
|
||||
"SELECT_TASK": "Vyberte úkol, na který se zaměříte",
|
||||
"SET_FOCUS_SESSION_DURATION": "Nastavit délku relace zaměření",
|
||||
"SHOW_HIDE_NOTES_AND_ATTACHMENTS": "Zobrazit/skrýt poznámky a přílohy k úkolu",
|
||||
"START_FOCUS_SESSION": "Spustit relaci zaměření",
|
||||
"START_NEXT_FOCUS_SESSION": "Spustit další relaci zaměření",
|
||||
"WORKED_FOR": "Pracovali jste"
|
||||
},
|
||||
"GITEA": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Nastavit Gitea pro projekt"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Uživatelské jméno (např. pro filtrování změn od vás)",
|
||||
"HOST": "Hostitel (např.: https://try.gitea.io)",
|
||||
"REPO_FULL_NAME": "Uživatelské jméno nebo název organizace/projektu",
|
||||
"REPO_FULL_NAME_DESCRIPTION": "Lze nalézt jako část adresy URL při prohlížení projektu v prohlížeči.",
|
||||
|
|
@ -152,12 +111,10 @@
|
|||
"TOKEN": "Přístupový token"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity tak, aby zobrazoval otevřené problémy Gitea pro konkrétní repozitář v panelu vytváření úkolů v denním plánovacím zobrazení. Budou uvedeny jako návrhy a poskytnou odkaz na problém a další informace o něm.</p> <p>Kromě toho můžete automaticky přidat a importovat všechny otevřené problémy.</p><p>Pro překročení omezení a přístup můžete poskytnout přístupový token.",
|
||||
"TITLE": "Gitea"
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity tak, aby zobrazoval otevřené problémy Gitea pro konkrétní repozitář v panelu vytváření úkolů v denním plánovacím zobrazení. Budou uvedeny jako návrhy a poskytnou odkaz na problém a další informace o něm.</p> <p>Kromě toho můžete automaticky přidat a importovat všechny otevřené problémy.</p><p>Pro překročení omezení a přístup můžete poskytnout přístupový token."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Přiřazený",
|
||||
"AT": "u",
|
||||
"DESCRIPTION": "Popis",
|
||||
"LABELS": "Štítky",
|
||||
"MARK_AS_CHECKED": "Označit změny jako zkontrolované",
|
||||
|
|
@ -166,14 +123,10 @@
|
|||
"SUMMARY": "Shrnutí",
|
||||
"WRITE_A_COMMENT": "Napsat komentář"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Gitea: Neznámá chyba {{statusCode}} {{errorMsg}}. Byl překročen limit volání API?"
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"GITHUB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Nastavit GitHub pro projekt"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Uživatelské jméno (např. pro filtrování změn od vás)",
|
||||
"IS_ASSIGNEE_FILTER": "Filtrovat úkoly přiřazené mně",
|
||||
|
|
@ -181,8 +134,7 @@
|
|||
"TOKEN": "Přístupový token"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity tak, aby zobrazoval otevřené problémy GitHubu pro konkrétní repozitář v panelu vytváření úkolů v denním plánovacím zobrazení. Budou uvedeny jako návrhy a poskytnou odkaz na problém a další informace o něm.</p> <p>Kromě toho můžete automaticky importovat všechny otevřené problémy.</p><p>Pro překročení omezení použití a k přístupu můžete poskytnout přístupový token. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>Více informací o jeho rozsahu naleznete zde</a>.",
|
||||
"TITLE": "GitHub"
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity tak, aby zobrazoval otevřené problémy GitHubu pro konkrétní repozitář v panelu vytváření úkolů v denním plánovacím zobrazení. Budou uvedeny jako návrhy a poskytnou odkaz na problém a další informace o něm.</p> <p>Kromě toho můžete automaticky importovat všechny otevřené problémy.</p><p>Pro překročení omezení použití a k přístupu můžete poskytnout přístupový token. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>Více informací o jeho rozsahu naleznete zde</a>."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"DESCRIPTION": "Popis",
|
||||
|
|
@ -194,9 +146,7 @@
|
|||
}
|
||||
},
|
||||
"GITLAB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Nastavení GitLab pro projekt"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"DIALOG_SUBMIT_WORKLOG": {
|
||||
"PAST_DAY_INFO": "Předvyplněná doba obsahuje nezaznamenaná data z minulých dní.",
|
||||
"T_ALREADY_TRACKED": "Již sledováno",
|
||||
|
|
@ -224,8 +174,7 @@
|
|||
"TOKEN": "Přístupový token"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Zde můžete konfigurovat SuperProductivity pro zobrazení otevřených úkolů GitLabu (buď online verze nebo self-hosted instance) pro konkrétní projekt v panelu vytváření úkolů v denním plánovacím zobrazení. Budou uvedeny jako návrhy a poskytnou odkaz na úkol a další informace o něm.</p> <p>Kromě toho můžete automaticky importovat všechny otevřené úkoly.</p>",
|
||||
"TITLE": "GitLab"
|
||||
"HELP": "<p>Zde můžete konfigurovat SuperProductivity pro zobrazení otevřených úkolů GitLabu (buď online verze nebo self-hosted instance) pro konkrétní projekt v panelu vytváření úkolů v denním plánovacím zobrazení. Budou uvedeny jako návrhy a poskytnou odkaz na úkol a další informace o něm.</p> <p>Kromě toho můžete automaticky importovat všechny otevřené úkoly.</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Přiřazeno",
|
||||
|
|
@ -252,13 +201,9 @@
|
|||
"ERR_NOT_CONFIGURED": "{{issueProviderName}}: Není správně nakonfigurováno",
|
||||
"IMPORTED_MULTIPLE_ISSUES": "{{issueProviderName}}: Importováno {{nr}} nových {{issuesStr}}",
|
||||
"IMPORTED_SINGLE_ISSUE": "{{issueProviderName}}: Importován {{issueStr}} \"{{issueTitle}}\"",
|
||||
"ISSUE_DELETED_OR_CLOSED": "{{issueProviderName}}: {{issueStrC}} \"{{issueTitle}}\" zdá se, že byl smazán nebo uzavřen",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "{{issueProviderName}}: Aktualizace není nutná",
|
||||
"ISSUE_UPDATE_MULTIPLE": "{{issueProviderName}}: Aktualizována data pro {{nr}} {{issuesStr}}",
|
||||
"ISSUE_UPDATE_SINGLE": "{{issueProviderName}}: Aktualizována data pro \"{{issueTitle}}\"",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "{{issueProviderName}}: Aktualizována data pro \"{{issueTitle}}\"",
|
||||
"MISSING_ISSUE_DATA": "{{issueProviderName}}: Úkoly s chybějícími daty {{issueStr}} byly nalezeny. Obnovuji.",
|
||||
"NEW_COMMENT": "{{issueProviderName}}: Nový komentář k \"{{issueTitle}}\"",
|
||||
"POLLING_BACKLOG": "{{issueProviderName}}: Sledování nových {{issuesStr}}",
|
||||
"POLLING_CHANGES": "{{issueProviderName}}: Sledování změn v {{issuesStr}}"
|
||||
}
|
||||
|
|
@ -295,8 +240,7 @@
|
|||
"CURRENT_ASSIGNEE": "Aktuálně přiřazeno:",
|
||||
"CURRENT_STATUS": "Aktuální stav:",
|
||||
"TASK_NAME": "Název úkolu:",
|
||||
"TITLE": "Jira: Aktualizovat stav",
|
||||
"UPDATE_STATUS": "Aktualizovat stav"
|
||||
"TITLE": "Jira: Aktualizovat stav"
|
||||
},
|
||||
"DIALOG_WORKLOG": {
|
||||
"CHECKBOXES": {
|
||||
|
|
@ -331,8 +275,7 @@
|
|||
"HOST": "Hostitel (např.: http://muj-host.de:1234)",
|
||||
"PASSWORD": "Token / Heslo",
|
||||
"USE_PAT": "Použít osobní přístupový token místo hesla",
|
||||
"USER_NAME": "E-mail / Uživatelské jméno",
|
||||
"WONKY_COOKIE_MODE": "Režim náhrady autentizace Wonky Cookie (pouze desktopová aplikace)"
|
||||
"USER_NAME": "E-mail / Uživatelské jméno"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"ADV_CFG": "Pokročilá konfigurace",
|
||||
|
|
@ -374,29 +317,16 @@
|
|||
"EXTENSION_NOT_LOADED": "Rozšíření Super Productivity není načteno. Obnovení stránky by mohlo pomoci",
|
||||
"INSUFFICIENT_SETTINGS": "Nedostatečná nastavení pro Jiru",
|
||||
"INVALID_RESPONSE": "Jira: Odpověď obsahovala neplatná data",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "Jira: „{{issueText}}“ je již aktuální",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "Jira: Aktualizována data pro „{{issueText}}“",
|
||||
"MISSING_ISSUE_DATA": "Jira: Úkoly s chybějícími údaji o problému nalezeny. Obnovení.",
|
||||
"NO_AUTO_IMPORT_JQL": "Jira: Není definován žádný dotaz pro automatický import",
|
||||
"NO_VALID_TRANSITION": "Jira: Není nastaven platný přechod",
|
||||
"TIMED_OUT": "Jira: Časový limit žádosti vypršel",
|
||||
"TRANSITION": "Jira: Nastavit úkol „{{issueKey}}“ na „{{name}}“",
|
||||
"TRANSITION_SUCCESS": "Jira: Nastavit úkol {{issueKey}} na <strong>{{chosenTransition}}</strong>",
|
||||
"TRANSITIONS_LOADED": "Jira: Přechody načteny. Použijte níže uvedená pole pro jejich přiřazení",
|
||||
"UNABLE_TO_REASSIGN": "Jira: Nelze znovu přiřadit lístek vám, protože jste neuvedli uživatelské jméno. Prosím, navštivte nastavení."
|
||||
},
|
||||
"STEPPER": {
|
||||
"CREDENTIALS": "Přihlašovací údaje",
|
||||
"DONE": "Jste nyní hotovi.",
|
||||
"LOGIN_SUCCESS": "Přihlášení bylo úspěšné!",
|
||||
"TEST_CREDENTIALS": "Otestovat přihlašovací údaje",
|
||||
"WELCOME_USER": "Vítejte, {{user}}!"
|
||||
"TRANSITIONS_LOADED": "Jira: Přechody načteny. Použijte níže uvedená pole pro jejich přiřazení"
|
||||
}
|
||||
},
|
||||
"METRIC": {
|
||||
"BANNER": {
|
||||
"CHECK": "Zvládl jsem to!"
|
||||
},
|
||||
"BANNER": {},
|
||||
"CMP": {
|
||||
"AVG_BREAKS_PER_DAY": "Průměrný počet přestávek za den",
|
||||
"AVG_TASKS_PER_DAY_WORKED": "Průměrný počet úkolů za den práce",
|
||||
|
|
@ -406,7 +336,6 @@
|
|||
"COUNTING_SUBTASKS": "(počítání podúkolů)",
|
||||
"DAYS_WORKED": "Odpracované dny",
|
||||
"GLOBAL_METRICS": "Celosvětová měřítka",
|
||||
"MOOD_PRODUCTIVITY_OVER_TIME": "Nálada a produktivita v čase",
|
||||
"NO_ADDITIONAL_DATA_YET": "Zatím nebyla shromážděna žádná další data. Použijte formulář na panelu „Hodnocení“ denního souhrnu k tomu.",
|
||||
"SIMPLE_CLICK_COUNTERS_OVER_TIME": "Počítadla kliknutí v čase",
|
||||
"SIMPLE_COUNTERS": "Jednoduchá počítadla",
|
||||
|
|
@ -416,30 +345,13 @@
|
|||
"TIME_SPENT": "Strávený čas"
|
||||
},
|
||||
"EVAL_FORM": {
|
||||
"ADD_NOTE_FOR_TOMORROW": "Přidat poznámku na zítra",
|
||||
"DISABLE_REPEAT_EVERY_DAY": "Vypnout opakování každý den",
|
||||
"ENABLE_REPEAT_EVERY_DAY": "Opakovat každý den",
|
||||
"HELP_H1": "Proč bych měl/a dbát?",
|
||||
"HELP_LINK_TXT": "Přejít na sekci metrik",
|
||||
"HELP_P1": "Čas na malé zhodnocení sebe sama! Vaše odpovědi jsou zde uloženy a poskytnou vám trochu statistiky o tom, jak pracujete, v sekci metrik. Navíc se návrhy na zítřek zobrazí nad seznamem vašich úkolů následující den.",
|
||||
"HELP_P2": "Mělo by jít méně o výpočty přesných metrik nebo o to, stát se strojem účinným ve všem, co děláte, než o to, jak zlepšit svůj pocit z práce. Může být užitečné zhodnotit bolestivé body ve vaší každodenní rutině, stejně jako najít faktory, které vám pomáhají. Snad nám malé systematické přístupy pomohou lépe porozumět a zlepšit to, co můžeme.",
|
||||
"IMPROVEMENTS": "Co zlepšilo vaši produktivitu?",
|
||||
"IMPROVEMENTS_TOMORROW": "Co byste mohli udělat pro zlepšení zítra?",
|
||||
"MOOD": "Jak se cítíte?",
|
||||
"MOOD_HINT": "1: Hrozně – 10: Skvěle",
|
||||
"NOTES": "Poznámky na zítra",
|
||||
"OBSTRUCTIONS": "Co bránilo vaší produktivitě?",
|
||||
"PRODUCTIVITY": "Jak efektivně jste pracoval/a?",
|
||||
"PRODUCTIVITY_HINT": "1: Ještě jsem nezačal/a – 10: Nenápadně efektivní"
|
||||
"PRODUCTIVITY": "Jak efektivně jste pracoval/a?"
|
||||
},
|
||||
"S": {
|
||||
"SAVE_METRIC": "Metrika byla úspěšně uložena"
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"NOTE": {
|
||||
"D_ADD": {
|
||||
"NOTE_LABEL": "Zadejte text pro uložení jako poznámku (můžete použít markdown)..."
|
||||
},
|
||||
"D_ADD": {},
|
||||
"D_FULLSCREEN": {
|
||||
"VIEW_PARSED": "Zobrazit jako parsovaný (neupravitelný) markdown",
|
||||
"VIEW_SPLIT": "Zobrazit rozdělený pohled pro parsovaný a neparsovaný markdown",
|
||||
|
|
@ -468,9 +380,7 @@
|
|||
"SELECT_ISSUE_FOR_TRANSITIONS": "Vyberte úkol pro načtení dostupných přechodů",
|
||||
"TRANSITION": "Řízení přechodu"
|
||||
},
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Nastavení OpenProject pro projekt"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"DIALOG_TRACK_TIME": {
|
||||
"ACTIVITY": "Aktivita",
|
||||
"CURRENTLY_LOGGED": "Aktuálně zaznamenaný čas: ",
|
||||
|
|
@ -487,8 +397,7 @@
|
|||
"CURRENT_STATUS": "Současný stav:",
|
||||
"PERCENTAGE_DONE": "Postup:",
|
||||
"TASK_NAME": "Název úkolu:",
|
||||
"TITLE": "OpenProject: Aktualizovat stav",
|
||||
"UPDATE_STATUS": "Aktualizovat stav"
|
||||
"TITLE": "OpenProject: Aktualizovat stav"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Uživatelské jméno (např. k filtrování změn od vás)",
|
||||
|
|
@ -505,8 +414,7 @@
|
|||
"TOKEN": "Přístupový token"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity k zobrazení otevřených pracovních balíčků OpenProject. Upozorňujeme, že pro toto fungování v prohlížeči pravděpodobně musíte nakonfigurovat CORS pro váš server OpenProject, aby umožnil přístup z app.super-productivity.com</p>",
|
||||
"TITLE": "OpenProject"
|
||||
"HELP": "<p>Zde můžete nakonfigurovat SuperProductivity k zobrazení otevřených pracovních balíčků OpenProject. Upozorňujeme, že pro toto fungování v prohlížeči pravděpodobně musíte nakonfigurovat CORS pro váš server OpenProject, aby umožnil přístup z app.super-productivity.com</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Přiřazený",
|
||||
|
|
@ -534,61 +442,10 @@
|
|||
"POMODORO": {
|
||||
"BREAK_IS_DONE": "Vaše přestávka skončila!"
|
||||
},
|
||||
"PROCRASTINATION": {
|
||||
"BACK_TO_WORK": "Zpět do práce!",
|
||||
"COMP": {
|
||||
"INTRO": "Lidé s vysokou mírou odkládání obvykle mají nízkou sebeúctu. Takže ji praktikujte! Zlepšuje váš pocit vlastní hodnoty, podporuje pozitivní emoce a může vám pomoci překonat odkládání, samozřejmě. Vyzkoušejte malý cvičební program:",
|
||||
"L1": "Posaďte se na chvíli a protáhněte se, pokud chcete, trochu se uklidněte",
|
||||
"L2": "Zkuste poslouchat myšlenky a pocity, které vznikají",
|
||||
"L3": "Reagujete na sebe tak, jak byste reagovali na přítele?",
|
||||
"L4": "Pokud je odpověď ne, představte si svého přítele ve své situaci. Co byste jim řekli? Co byste pro ně udělali?",
|
||||
"OUTRO": "Další cvičení <a target=\"_blank\" href=\"https://drsoph.com/blog/2018/9/17/3-exercises-in-self-compassion\" target=\"_blank\">najdete zde</a> nebo na <a target=\"_blank\" href=\"https://www.google.com/search?q=self+compassion+exercises&oq=self+compassion+excers&aqs=chrome.1.69i57j0l5.4303j0j7&sourceid=chrome&ie=UTF-8\" target=\"_blank\">google</a>.",
|
||||
"TITLE": "Sebelítost"
|
||||
},
|
||||
"CUR": {
|
||||
"INTRO": "Není odkládání zajímavé? Nezdá se, že by mělo smysl to dělat, protože to vůbec není ve vašem dlouhodobém zájmu. Ale přesto to dělá každý. Pomáhá hodně zkoumat a lépe porozumět, jak to pro vás osobně funguje! Několik základních otázek, které byste si měli položit, může být:",
|
||||
"L1": "Jaké pocity vyvolává vaše pokušení odkládat?",
|
||||
"L2": "Kde je ve vašem těle cítíte?",
|
||||
"L3": "Na co vás připomínají?",
|
||||
"L4": "Co se děje s myšlenkou na odkládání, když ji pozorujete? Zesiluje se? Zaniká? Vyvolává další emoce?",
|
||||
"L5": "Jak se mění pocity ve vašem těle, když na ně pokračujete v pozorování?",
|
||||
"PROCRASTINATION_TRIGGERS_TEXT": "Další velmi účinnou metodou je zaznamenat, co spustilo vaši touhu odkládat. Například já osobně často pociťuji touhu rychle přejít na reddit nebo svou oblíbenou zpravodajskou stránku, kdykoliv se můj prohlížeč dostane do popředí. Od té doby, co jsem začal zaznamenávat své spouštěče v jednoduchém prázdném textovém dokumentu, uvědomil jsem si, jak pevně zakořeněný byl tento vzor, a pomohl mi experimentovat s různými opatřeními.",
|
||||
"PROCRASTINATION_TRIGGERS_TITLE": "Zapsání spouštěčů vašeho odkládání",
|
||||
"TITLE": "Zvědavost"
|
||||
},
|
||||
"H1": "Dejte si pokoj!",
|
||||
"INTRO": {
|
||||
"AVOIDING": "Vyhnout se úkolu",
|
||||
"FEAR": "Strach ze selhání",
|
||||
"STRESSED": "Stresovaný z toho, že se nedaří věci dokončit",
|
||||
"TITLE": "Úvod"
|
||||
},
|
||||
"P1": "Za prvé: uklidněte se! Každý odkládá občas. A pokud neděláte to, co byste měli, měli byste to aspoň užít!",
|
||||
"P2": "Pamatujte: <b>Odkládání je problém s regulací emocí, ne problém s řízením času.</b> To znamená, že sebitloukání není řešením, je to součást problému. Nechte si to zapadnout a pak se podívejte na další karty zde pro další pomoc.",
|
||||
"REFRAME": {
|
||||
"INTRO": "Přemýšlejte o tom, co by mohlo být pozitivního na úkolu navzdory jeho nedostatkům.",
|
||||
"TITLE": "Přeformulování",
|
||||
"TL1": "Co by na tom mohlo být zajímavé?",
|
||||
"TL2": "Co získáte, pokud to dokončíte?",
|
||||
"TL3": "Jak se budete k tomu cítit, pokud to dokončíte?"
|
||||
},
|
||||
"SPLIT_UP": {
|
||||
"INTRO": "Rozdělte úkol na co nejvíce malých částí, jak jen to půjde.",
|
||||
"OUTRO": "Hotovo? Pak o tom přemýšlejte. Jak by to bylo – striktně teoreticky – první věc, kterou byste udělali <i>pokud</i> byste začali pracovat na úkolu? Jen o tom přemýšlejte...",
|
||||
"TITLE": "Rozdělte to!"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "Vytvořit projekt",
|
||||
"EDIT": "Upravit projekt",
|
||||
"SETUP_CALDAV": "Nastavit integrovanou integraci",
|
||||
"SETUP_GIT": "Nastavit GitHub integraci",
|
||||
"SETUP_GITEA_PROJECT": "Nastavit integraci Gitea",
|
||||
"SETUP_GITLAB": "Nastavit GitLab integraci",
|
||||
"SETUP_JIRA": "Nastavit Jira integraci",
|
||||
"SETUP_OPEN_PROJECT": "Nastavit integraci OpenProject",
|
||||
"SETUP_REDMINE_PROJECT": "Nastavit integraci Redmine"
|
||||
"EDIT": "Upravit projekt"
|
||||
},
|
||||
"FORM_BASIC": {
|
||||
"L_ENABLE_BACKLOG": "Povolit projektový backlog",
|
||||
|
|
@ -597,7 +454,6 @@
|
|||
"TITLE": "Základní nastavení"
|
||||
},
|
||||
"FORM_THEME": {
|
||||
"D_IS_DARK_THEME": "Nebude použito, pokud systém podporuje globální tmavý režim.",
|
||||
"HELP": "Nastavení tématu pro váš projekt.",
|
||||
"L_BACKGROUND_IMAGE_DARK": "Adresa URL obrázku pozadí (tmavé téma)",
|
||||
"L_BACKGROUND_IMAGE_LIGHT": "Adresa URL obrázku pozadí (světlé téma)",
|
||||
|
|
@ -609,18 +465,13 @@
|
|||
"L_HUE_WARN": "Práh pro tmavý text na pozadí varovné barvy",
|
||||
"L_IS_AUTO_CONTRAST": "Automaticky nastavit barvy textu pro nejlepší čitelnost",
|
||||
"L_IS_DISABLE_BACKGROUND_TINT": "Vypnout barevný pozadí",
|
||||
"L_IS_REDUCED_THEME": "Použít zjednodušené uživatelské rozhraní (bez rámečků kolem úkolů)",
|
||||
"L_THEME_COLOR": "Barva tématu",
|
||||
"L_TITLE": "Název",
|
||||
"TITLE": "Téma"
|
||||
},
|
||||
"S": {
|
||||
"ARCHIVED": "Archivovaný projekt",
|
||||
"CREATED": "Projekt <strong>{{title}}</strong> byl vytvořen. Můžete jej vybrat z menu vlevo nahoře.",
|
||||
"DELETED": "Odstraněný projekt",
|
||||
"E_EXISTS": "Projekt „{{title}}“ již existuje",
|
||||
"E_INVALID_FILE": "Neplatná data pro projektový soubor",
|
||||
"ISSUE_PROVIDER_UPDATED": "Aktualizovány nastavení projektu pro <strong>{{issueProviderKey}}</strong>",
|
||||
"UNARCHIVED": "Obnovený projekt",
|
||||
"UPDATED": "Aktualizovány nastavení projektu"
|
||||
}
|
||||
|
|
@ -631,9 +482,7 @@
|
|||
"WEEK_TITLE": "Týden {{nr}} ({{timeSpent}})"
|
||||
},
|
||||
"REDMINE": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Nastavit Redmine pro projekt"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"API_KEY": "API klíč přístupu",
|
||||
"HOST": "Hostitel (např.: https://redmine.org)",
|
||||
|
|
@ -653,32 +502,22 @@
|
|||
"MARK_AS_CHECKED": "Označit změny jako zkontrolované",
|
||||
"PRIORITY": "Priorita"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Redmine: Neznámá chyba {{statusCode}} {{errorMsg}}."
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"REMINDER": {
|
||||
"S_REMINDER_ERR": "Chyba rozhraní pro upomínky"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"CONTINUED": "pokračovalo",
|
||||
"D_INITIAL": {
|
||||
"TEXT": "<p>Myšlenkou časové osy je poskytnout lepší přehled o tom, jak se plánované úkoly vyvíjejí v čase. Automaticky vychází z vašich úkolů a rozlišuje dvě různé věci: <strong>naplánované úkoly</strong>, které jsou zobrazeny v jejich plánovaný čas, a <strong>běžné úkoly</strong>, které by se měly pohybovat kolem těchto pevných událostí. Všechny úkoly zohledňují časové odhady, které jim přiřadíte.</p><p>Kromě toho můžete zadat čas začátku a konce práce. Pokud jsou nakonfigurovány, běžné úkoly se nikdy nezobrazí mimo tyto časy. Všimněte si, že časová osa zahrnuje pouze příštích 30 dnů.</p>",
|
||||
"TITLE": "Časová osa"
|
||||
},
|
||||
"END": "Konec práce",
|
||||
"LUNCH_BREAK": "Obední přestávka",
|
||||
"NO_TASKS": "Momentálně zde nejsou žádné úkoly. Přidejte nějaké úkoly pomocí tlačítka + v horní liště.",
|
||||
"NOW": "Nyní",
|
||||
"START": "Začátek práce",
|
||||
"TASK_PROJECTION_INFO": "Budoucí projekce naplánovaného opakovatelného úkolu"
|
||||
"START": "Začátek práce"
|
||||
},
|
||||
"SEARCH_BAR": {
|
||||
"INFO": "Klikněte na ikonu seznamu pro vyhledávání archivovaných úkolů",
|
||||
"INFO_ARCHIVED": "Klikněte na ikonu archivu pro vyhledávání běžných úkolů",
|
||||
"PLACEHOLDER": "Hledejte úkol nebo popis úkolu",
|
||||
"PLACEHOLDER_ARCHIVED": "Hledejte archivované úkoly",
|
||||
"TOO_MANY_RESULTS": "Příliš mnoho výsledků, prosím, zúžte své hledání"
|
||||
"PLACEHOLDER": "Hledejte úkol nebo popis úkolu"
|
||||
},
|
||||
"SIMPLE_COUNTER": {
|
||||
"D_CONFIRM_REMOVE": {
|
||||
|
|
@ -692,7 +531,6 @@
|
|||
"ADD_NEW": "Přidat jednoduchý čítač",
|
||||
"HELP": "Zde můžete konfigurovat jednoduchá tlačítka, která se objeví v pravém horním rohu. Mohou to být buď časovače nebo jednoduchý čítač, který se zvyšuje stisknutím.",
|
||||
"L_ICON": "Ikona",
|
||||
"L_ICON_ON": "Ikona při přepnutí",
|
||||
"L_IS_ENABLED": "Povoleno",
|
||||
"L_TITLE": "Název",
|
||||
"L_TYPE": "Typ",
|
||||
|
|
@ -703,12 +541,7 @@
|
|||
},
|
||||
"SYNC": {
|
||||
"C": {
|
||||
"EMPTY_SYNC": "Zkoušíte synchronizovat prázdný datový objekt. Pokud se snažíte nastavit synchronizaci z nové instance aplikace, stačí stisknout OK pro načtení dat ze serveru. Jinak zkontrolujte svá data.",
|
||||
"FORCE_UPLOAD": "Přesto nahrát lokální data?",
|
||||
"FORCE_UPLOAD_AFTER_ERROR": "Při nahrávání vašich lokálních dat došlo k chybě. Chcete provést nucenou aktualizaci?",
|
||||
"MIGRATE_LEGACY": "Detekována stará data při importu. Chcete je zkusit převést?",
|
||||
"NO_REMOTE_DATA": "Nebyla nalezena žádná vzdálená data. Nahrát lokální na vzdálený server?",
|
||||
"TRY_LOAD_REMOTE_AGAIN": "Zkusit znovu načíst data ze vzdáleného serveru?"
|
||||
"FORCE_UPLOAD": "Přesto nahrát lokální data?"
|
||||
},
|
||||
"D_AUTH_CODE": {
|
||||
"FOLLOW_LINK": "Otevřete prosím následující odkaz a zkopírujte autentifikační kód do pole níže.",
|
||||
|
|
@ -717,7 +550,6 @@
|
|||
"TITLE": "Přihlášení: {{provider}}"
|
||||
},
|
||||
"D_CONFLICT": {
|
||||
"LAST_CHANGE": "Poslední změna:",
|
||||
"LAST_SYNC": "Poslední synchronizace:",
|
||||
"LOCAL": "Místní",
|
||||
"LOCAL_REMOTE": "Místní -> Vzdálené",
|
||||
|
|
@ -727,26 +559,14 @@
|
|||
"USE_LOCAL": "Ponechat lokální",
|
||||
"USE_REMOTE": "Ponechat vzdálené"
|
||||
},
|
||||
"D_PERMISSION": {
|
||||
"DISABLE_SYNC": "Zakázat synchronizaci",
|
||||
"PERM_FILE": "Udělit oprávnění",
|
||||
"TEXT": "<p>Bylo vám odebráno oprávnění k místní synchronizaci souborů.</p>",
|
||||
"TITLE": "Synchronizace: Odmítnutí oprávnění k souboru"
|
||||
},
|
||||
"FORM": {
|
||||
"DROPBOX": {
|
||||
"L_ACCESS_TOKEN": "Přístupový token (vygenerován z autentifikačního kódu)"
|
||||
},
|
||||
"GOOGLE": {
|
||||
"L_SYNC_FILE_NAME": "Název souboru pro synchronizaci"
|
||||
},
|
||||
"DROPBOX": {},
|
||||
"GOOGLE": {},
|
||||
"L_ENABLE_COMPRESSION": "Povolit kompresi (rychlejší přenos dat)",
|
||||
"L_ENABLE_SYNCING": "Povolit synchronizaci",
|
||||
"L_SYNC_INTERVAL": "Interval synchronizace",
|
||||
"L_SYNC_PROVIDER": "Poskytovatel synchronizace",
|
||||
"LOCAL_FILE": {
|
||||
"L_SYNC_FILE_PATH_PERMISSION_VALIDATION": "Vyžaduje oprávnění k přístupu k souboru"
|
||||
},
|
||||
"LOCAL_FILE": {},
|
||||
"TITLE": "Synchronizace",
|
||||
"WEB_DAV": {
|
||||
"CORS_INFO": "<strong>Jak to funguje v prohlížeči:</strong> Aby to fungovalo v prohlížeči, musíte povolit Super Productivity pro CORS požadavky pro vaši instanci Nextcloud. To může mít negativní bezpečnostní dopady! Podívejte se na <a href='https://github.com/nextcloud/server/issues/3131'>tuto diskuzi pro více informací</a>. Jeden z přístupů k tomu, aby to fungovalo na mobilu, je povolení \"https://app.super-productivity.com\" prostřednictvím aplikace Nextcloud <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword<a>. Používejte na vlastní nebezpečí!</p>",
|
||||
|
|
@ -756,21 +576,14 @@
|
|||
}
|
||||
},
|
||||
"S": {
|
||||
"ERROR_FALLBACK_TO_BACKUP": "Při importu dat došlo k chybě. Vracíme se k lokální záloze.",
|
||||
"ERROR_INVALID_DATA": "Chyba při synchronizaci. Neplatná data",
|
||||
"IMPORTING": "Importují se data",
|
||||
"INCOMPLETE_CFG": "Ověření selhalo. Zkontrolujte svou konfiguraci!",
|
||||
"INITIAL_SYNC_ERROR": "Počáteční synchronizace selhala",
|
||||
"SUCCESS_IMPORT": "Data byla importována",
|
||||
"SUCCESS_VIA_BUTTON": "Data úspěšně synchronizována",
|
||||
"UNKNOWN_ERROR": "Neznámá chyba synchronizace: {{err}}",
|
||||
"UPLOAD_ERROR": "Neznámá chyba při nahrávání (jsou nastavení správná?): {{err}}"
|
||||
"UNKNOWN_ERROR": "Neznámá chyba synchronizace: {{err}}"
|
||||
}
|
||||
},
|
||||
"TAG": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "Vytvořit značku",
|
||||
"EDIT": "Upravit značku"
|
||||
"CREATE": "Vytvořit značku"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"CONFIRM_MSG": "Opravdu chcete smazat značku \"{{tagName}}\"? Bude odstraněna ze všech úkolů. Nelze vrátit zpět."
|
||||
|
|
@ -792,27 +605,15 @@
|
|||
},
|
||||
"TASK": {
|
||||
"ADD_TASK_BAR": {
|
||||
"ADD_EXISTING_TASK": "Přidat existující úkol „{{taskTitle}}“",
|
||||
"ADD_ISSUE_TASK": "Přidat problém č. {{issueNr}} z {{issueType}}",
|
||||
"ADD_TASK_TO_BOTTOM_OF_BACKLOG": "Přidat úkol na konec zásobníku",
|
||||
"ADD_TASK_TO_BOTTOM_OF_TODAY": "Přidat úkol na konec seznamu",
|
||||
"ADD_TASK_TO_TOP_OF_BACKLOG": "Přidat úkol na začátek zásobníku",
|
||||
"ADD_TASK_TO_TOP_OF_TODAY": "Přidat úkol na začátek seznamu",
|
||||
"CREATE_TASK": "Vytvořit nový úkol",
|
||||
"EXAMPLE": "Příklad: „Nějaký název úkolu @pá 16:00 +název projektu #nějaká značka #další značka 10m/3h“",
|
||||
"START": "Stiskněte Enter ještě jednou k zahájení",
|
||||
"TOGGLE_ADD_TO_BACKLOG_TODAY": "Přepnout přidání úkolu do zásobníku / seznamu na dnešek'",
|
||||
"TOGGLE_ADD_TOP_OR_BOTTOM": "Přepnout přidání úkolu na začátek a konec seznamu"
|
||||
"ADD_EXISTING_TASK": "Přidat existující úkol „{{taskTitle}}“"
|
||||
},
|
||||
"ADDITIONAL_INFO": {
|
||||
"ADD_ATTACHMENT": "Přidat přílohu",
|
||||
"ADD_SUB_TASK": "Přidat podúkol",
|
||||
"ATTACHMENTS": "Přílohy ({{nr}})",
|
||||
"FROM_PARENT": "(od rodiče)",
|
||||
"LOCAL_ATTACHMENTS": "Místní přílohy",
|
||||
"NOTES": "Popis",
|
||||
"PARENT": "Rodič",
|
||||
"REMINDER": "Připomenutí",
|
||||
"REPEAT": "Opakovat",
|
||||
"SCHEDULE_TASK": "Naplánovat úkol",
|
||||
"SUB_TASKS": "Podúkoly ({{nr}})",
|
||||
|
|
@ -831,9 +632,7 @@
|
|||
"DELETE_REPEAT_INSTANCE": "Smazat opakující se instanci úkolu",
|
||||
"DROP_ATTACHMENT": "Přetáhněte sem pro připojení k „{{title}}“",
|
||||
"EDIT_SCHEDULED": "Upravit připomenutí",
|
||||
"EDIT_TAGS": "Upravit značky",
|
||||
"MARK_DONE": "Označit jako hotové",
|
||||
"MARK_UNDONE": "Označit jako nehotové",
|
||||
"MOVE_TO_BACKLOG": "Přesunout do zásobníku",
|
||||
"MOVE_TO_OTHER_PROJECT": "Přesunout do jiného projektu",
|
||||
"MOVE_TO_REGULAR": "Přesunout na seznam dnešních úkolů",
|
||||
|
|
@ -841,9 +640,7 @@
|
|||
"OPEN_ISSUE": "Otevřít v prohlížeči",
|
||||
"OPEN_TIME": "Sledování času",
|
||||
"REMOVE_FROM_MY_DAY": "Odebrat z mého dne",
|
||||
"REPEAT_EDIT": "Upravit opakující se konfiguraci úkolu",
|
||||
"SCHEDULE": "Naplánovat úkol",
|
||||
"SHOW_UPDATES": "Zobrazit aktualizace",
|
||||
"TOGGLE_ATTACHMENTS": "Zobrazit/Skrýt přílohy",
|
||||
"TOGGLE_DETAIL_PANEL": "Zobrazit/Skrýt další informace",
|
||||
"TOGGLE_DONE": "Označit jako hotové/nehotoé",
|
||||
|
|
@ -860,19 +657,13 @@
|
|||
"DONE": "Hotovo",
|
||||
"DUE_TASK": "Úkol k dokončení",
|
||||
"DUE_TASKS": "Plánované úkoly",
|
||||
"FOR_CURRENT": "Úkol má termín dokončení. Chcete na něm začít pracovat?",
|
||||
"FOR_OTHER": "Úkol má termín dokončení. Chcete na něm začít pracovat?",
|
||||
"FROM_PROJECT": "Z projektu: „{{title}}“",
|
||||
"FROM_TAG": "Značky: „{{title}}“",
|
||||
"RESCHEDULE_EDIT": "Upravit (znovu naplánovat)",
|
||||
"RESCHEDULE_UNTIL_TOMORROW": "Znovu naplánovat na zítřek",
|
||||
"SNOOZE": "Odložit",
|
||||
"SNOOZE_ALL": "Odložit vše",
|
||||
"START": "Začít",
|
||||
"SWITCH_CONTEXT_START": "Změnit kontext a začít"
|
||||
"START": "Začít"
|
||||
},
|
||||
"D_SCHEDULE_TASK": {
|
||||
"MOVE_TO_BACKLOG": "Přesunout úkol do zásobníku do doby naplánování",
|
||||
"REMIND_AT": "Připomenout v",
|
||||
"RO_1H": "1 hodinu před začátkem",
|
||||
"RO_5M": "5 minut před začátkem",
|
||||
|
|
@ -909,7 +700,6 @@
|
|||
"FOUND_MOVE_FROM_BACKLOG": "Přesunut úkol <strong>{{title}}</strong> ze zásobníku do seznamu úkolů na dnešek",
|
||||
"FOUND_MOVE_FROM_OTHER_LIST": "Přidán úkol <strong>{{title}}</strong> z <strong>{{contextTitle}}</strong> do aktuálního seznamu",
|
||||
"FOUND_RESTORE_FROM_ARCHIVE": "Obnoven úkol <strong>{{title}}</strong> související s problémem ze archivu",
|
||||
"LAST_TAG_DELETION_WARNING": "Snažíte se odebrat poslední značku u úkolu, který není projektový. To není povoleno!",
|
||||
"REMINDER_ADDED": "Naplánován úkol „{{title}}“",
|
||||
"REMINDER_DELETED": "Smazáno připomenutí k úkolu",
|
||||
"REMINDER_UPDATED": "Aktualizováno připomenutí k úkolu „{{title}}“",
|
||||
|
|
@ -977,7 +767,6 @@
|
|||
"C_YEAR": "Rok",
|
||||
"DEFAULT_ESTIMATE": "Výchozí odhad",
|
||||
"FRIDAY": "Pátek",
|
||||
"IS_ADD_TO_BOTTOM": "Přesunout úkol na konec seznamu",
|
||||
"MONDAY": "Pondělí",
|
||||
"NOTES": "Výchozí poznámky",
|
||||
"ORDER": "Pořadí",
|
||||
|
|
@ -1030,7 +819,6 @@
|
|||
},
|
||||
"D_TRACKING_REMINDER": {
|
||||
"CREATE_AND_TRACK": "<em>Vytvořit</em> a sledovat k",
|
||||
"IDLE_FOR": "Byli jste nečinní po dobu:",
|
||||
"TASK": "Úkol",
|
||||
"TRACK_TO": "Sledovat k:",
|
||||
"UNTRACKED_TIME": "Nesledovaný čas:"
|
||||
|
|
@ -1041,7 +829,6 @@
|
|||
"DAYS_WORKED": "Odpracované dny:",
|
||||
"MONTH_WORKED": "Pracovaný měsíc:",
|
||||
"REPEATING_TASK": "Opakovatelný úkol",
|
||||
"RESTORE_TASK_FROM_ARCHIVE": "Obnovit úkol z archivu",
|
||||
"TASKS": "Úkoly",
|
||||
"TOTAL_TIME": "Celkově strávený čas:",
|
||||
"WEEK_NR": "Týden {{nr}}",
|
||||
|
|
@ -1125,22 +912,16 @@
|
|||
"ENABLED": "Povoleno",
|
||||
"EXAMPLE_VAL": "klikněte pro úpravu",
|
||||
"EXTENSION_INFO": "Prosím, <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> stáhněte rozšíření pro Chrome</a> pro umožnění komunikace s rozhraním Jira Api a zacházením s nečinným časem. Upozornění, tato funkce nefunguje na mobilních zařízeních.",
|
||||
"LOGIN": "Přihlásit",
|
||||
"LOGOUT": "Odhlásit",
|
||||
"MINUTES": "{{m}} minut",
|
||||
"NEXT": "Další",
|
||||
"NO_CON": "Momentálně jste offline. Připojte se prosím k internetu.",
|
||||
"NONE": "Žádné",
|
||||
"OK": "Ok",
|
||||
"PREVIOUS": "Předchozí",
|
||||
"REMOVE": "Odebrat",
|
||||
"RESET": "Obnovit",
|
||||
"SAVE": "Uložit",
|
||||
"SUBMIT": "Odeslat",
|
||||
"TITLE": "Název",
|
||||
"TODAY_TAG_TITLE": "Dnes",
|
||||
"UNDO": "Vrátit",
|
||||
"UPDATE": "Aktualizovat",
|
||||
"WITHOUT_PROJECT": "Bez projektu",
|
||||
"YESTERDAY": "Včera"
|
||||
},
|
||||
|
|
@ -1157,7 +938,6 @@
|
|||
},
|
||||
"FOCUS_MODE": {
|
||||
"HELP": "Režim zaměření otevírá obrazovku bez rušení, abyste se mohli soustředit na svůj aktuální úkol.",
|
||||
"L_ALWAYS_OPEN_FOCUS_MODE": "Vždy otevřít režim zaměření při sledování",
|
||||
"L_SKIP_PREPARATION_SCREEN": "Přeskočit úvodní obrazovku (protahování atd.)",
|
||||
"TITLE": "Režim zaměření"
|
||||
},
|
||||
|
|
@ -1215,7 +995,6 @@
|
|||
"TASK_TOGGLE_DONE": "Přepnout stav hotovo",
|
||||
"TITLE": "Klávesové zkratky",
|
||||
"TOGGLE_BACKLOG": "Zobrazit/skrýt zásobník úkolů",
|
||||
"TOGGLE_BOOKMARKS": "Zobrazit/skrýt panel záložek",
|
||||
"TOGGLE_PLAY": "Spustit/zastavit úkol",
|
||||
"TOGGLE_SIDE_NAV": "Zobrazit & zaměřit/skrýt boční navigaci",
|
||||
"ZOOM_DEFAULT": "Přiblížit výchozí (pouze pro desktop)",
|
||||
|
|
@ -1233,7 +1012,6 @@
|
|||
"IS_DARK_MODE": "Temný režim",
|
||||
"IS_DISABLE_ANIMATIONS": "Vypnout všechny animace",
|
||||
"IS_DISABLE_CELEBRATION": "Vypnout oslavy v denním přehledu",
|
||||
"IS_HIDE_NAV": "Skrýt navigaci, dokud není nadpis záhlaví aktivován (pouze pro desktop)",
|
||||
"IS_MINIMIZE_TO_TRAY": "Minimalizovat do oznamovací oblasti (pouze pro desktop)",
|
||||
"IS_TRAY_SHOW_CURRENT_TASK": "Zobrazit aktuální úkol v oznamovací oblasti/menu stavu (pouze pro desktop Mac/Windows)",
|
||||
"IS_TURN_OFF_MARKDOWN": "Vypnout zpracování markdown pro poznámky k úkolům",
|
||||
|
|
@ -1281,13 +1059,11 @@
|
|||
},
|
||||
"GLOBAL_SNACK": {
|
||||
"COPY_TO_CLIPPBOARD": "Zkopírováno do schránky",
|
||||
"ERR_COMPRESSION": "Chyba rozhraní pro kompresi",
|
||||
"FILE_DOWNLOADED": "{{fileName}} staženo",
|
||||
"FILE_DOWNLOADED_BTN": "Otevřít složku",
|
||||
"PERSISTENCE_DISALLOWED": "Data nebudou trvale ukládána. Buďte si vědomi, že to může vést k ztrátě dat!!",
|
||||
"PERSISTENCE_ERROR": "Chyba při žádosti o trvalé ukládání dat: {{err}}",
|
||||
"RUNNING_X": "Spouští se „{{str}}“.",
|
||||
"SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG": "{{keyCombo}} stisknuto, ale zkratka pro otevření záložek je k dispozici pouze v rámci projektového kontextu."
|
||||
"RUNNING_X": "Spouští se „{{str}}“."
|
||||
},
|
||||
"GPB": {
|
||||
"ASSETS": "Načítání prostředků...",
|
||||
|
|
@ -1309,19 +1085,11 @@
|
|||
"GO_TO_TASK_LIST": "Přejít na seznam úkolů",
|
||||
"HELP": "Nápověda",
|
||||
"METRICS": "Metryky",
|
||||
"NOTES": "Poznámky",
|
||||
"NOTES_PANEL_INFO": "Poznámky lze zobrazit pouze z časové osy a standardního pohledu na seznam úkolů.",
|
||||
"PROCRASTINATE": "Odkládat",
|
||||
"PROJECT_MENU": "Menu projektu",
|
||||
"PROJECT_SETTINGS": "Nastavení projektu",
|
||||
"PROJECTS": "Projekty",
|
||||
"QUICK_HISTORY": "Rychlá historie",
|
||||
"SETTINGS": "Nastavení",
|
||||
"SHOW_SEARCH_BAR": "Zobrazit vyhledávací lištu",
|
||||
"TAGS": "Štítky",
|
||||
"TASK_LIST": "Seznam úkolů",
|
||||
"TASKS": "Úkoly",
|
||||
"TOGGLE_SHOW_BOOKMARKS": "Zobrazit/Skrýt záložky",
|
||||
"TOGGLE_SHOW_NOTES": "Zobrazit/Skrýt poznámky k projektu",
|
||||
"TOGGLE_TRACK_TIME": "Spustit/Zastavit sledování času",
|
||||
"TRIGGER_SYNC": "Spustit synchronizaci ručně",
|
||||
|
|
@ -1363,48 +1131,25 @@
|
|||
},
|
||||
"PS": {
|
||||
"GLOBAL_SETTINGS": "Celková nastavení",
|
||||
"ISSUE_INTEGRATION": "Integrace s problémy",
|
||||
"PRIVACY_POLICY": "Zásady ochrany osobních údajů",
|
||||
"PRODUCTIVITY_HELPER": "Pomocník produktivity",
|
||||
"PROJECT_SETTINGS": "Nastavení specifické pro projekt",
|
||||
"PROVIDE_FEEDBACK": "Poskytnout zpětnou vazbu",
|
||||
"SYNC_EXPORT": "Synchronizace a export",
|
||||
"TAG_SETTINGS": "Nastavení specifické pro štítek",
|
||||
"TOGGLE_DARK_MODE": "Přepnout do tmavého režimu"
|
||||
"TAG_SETTINGS": "Nastavení specifické pro štítek"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"NO_REPEATABLE_TASKS": "Momentálně nejsou žádné opakující se úkoly. Úkol můžete naplánovat v postranním panelu úkolu volbou „Opakovat úkol“. K otevření klikněte na nejpravější ikonu, která se zobrazí po najetí myší na úkol (nebo jednoduše na úkol klepněte na mobilu).",
|
||||
"NO_SCHEDULED": "Momentálně nejsou naplánovány žádné úkoly. Úkol můžete naplánovat v nabídce kontextového menu úkolu volbou „Naplánovat úkol“. K otevření použijte pravé tlačítko myši (nebo dlouhý stisk na mobilu) na úkolu.",
|
||||
"REPEATED_TASKS": "Opakující se úkoly",
|
||||
"SCHEDULED_TASKS": "Naplánované úkoly",
|
||||
"START_TASK": "Spustit úkol a odebrat připomínku"
|
||||
},
|
||||
"THEMES": {
|
||||
"amber": "žlutá",
|
||||
"blue": "modrá",
|
||||
"blue-grey": "modro-šedá",
|
||||
"cyan": "azurová",
|
||||
"deep-orange": "hluboká oranžová",
|
||||
"deep-purple": "hluboká fialová",
|
||||
"green": "zelená",
|
||||
"indigo": "indigová",
|
||||
"light-blue": "světle modrá",
|
||||
"light-green": "světle zelená",
|
||||
"lime": "limetková",
|
||||
"pink": "růžová",
|
||||
"purple": "fialová",
|
||||
"SELECT_THEME": "Vyberte téma",
|
||||
"teal": "tyrkysová",
|
||||
"yellow": "žlutá"
|
||||
"SCHEDULED_TASKS": "Naplánované úkoly"
|
||||
},
|
||||
"V": {
|
||||
"E_1TO10": "Zadejte prosím hodnotu mezi 1 a 10",
|
||||
"E_DATETIME": "Zadaná hodnota není datum a čas!",
|
||||
"E_MAX": "Nemělo by být větší než {{val}}",
|
||||
"E_MAX_LENGTH": "Mělo by být maximálně {{val}} znaků dlouhé",
|
||||
"E_MIN": "Mělo by být menší než {{val}}",
|
||||
"E_MIN_LENGTH": "Mělo by být minimálně {{val}} znaků dlouhé",
|
||||
"E_PATTERN": "Neplatný vstup",
|
||||
"E_REQUIRED": "Toto pole je povinné"
|
||||
},
|
||||
"USER_PROFILES": {
|
||||
|
|
@ -1421,7 +1166,6 @@
|
|||
"RENAME": "Přejmenovat",
|
||||
"EXPORT_PROFILE": "Exportovat profil",
|
||||
"DELETE_PROFILE": "Smazat profil",
|
||||
"OPEN_PROFILES_FOLDER": "Otevřít složku profilů",
|
||||
"CLOSE": "Zavřít",
|
||||
"MANAGE_PROFILES": "Spravovat profily..."
|
||||
},
|
||||
|
|
@ -1431,10 +1175,7 @@
|
|||
"ADD_SOME_TASKS": "Přidejte nějaké úkoly pro plánování svého dne!",
|
||||
"ESTIMATE_REMAINING": "Odhad zbývajícího času:",
|
||||
"FINISH_DAY": "Ukončit den",
|
||||
"FINISH_DAY_FOR_PROJECT": "Ukončit den pro tento projekt",
|
||||
"FINISH_DAY_FOR_TAG": "Ukončit den pro tento štítek",
|
||||
"FINISH_DAY_TOOLTIP": "Zhodnoťte svůj den, přesuňte všechny hotové úkoly do archivu (volitelně) a/nebo naplánujte svůj další den.",
|
||||
"HELP_PROCRASTINATION": "Pomoc, prokrastinuji!",
|
||||
"NO_PLANNED_TASKS": "Žádné naplánované úkoly",
|
||||
"READY_TO_WORK": "Připraven k práci!",
|
||||
"RESET_BREAK_TIMER": "Resetovat bez přerušení časovače",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,15 +1,4 @@
|
|||
{
|
||||
"ANDROID": {
|
||||
"NOTIFICATIONS": {
|
||||
"SYNC_CONFLICT_MSG": "Provjeri i odluči što uraditi.",
|
||||
"SYNC_CONFLICT_TITLE": "Dogodila se greška u sinkronizaciji"
|
||||
},
|
||||
"PERMANENT_NOTIFICATION_MSGS": {
|
||||
"INITIAL": "Program radi u pozadini kako bi se omogućila sinkronizacija, ukoliko je aktivirana",
|
||||
"NO_ACTIVE_TASKS": "Nema aktivnih zadataka",
|
||||
"SYNCING": "Sinkronizacija u tijeku"
|
||||
}
|
||||
},
|
||||
"APP": {
|
||||
"B_INSTALL": {
|
||||
"IGNORE": "Zanemari",
|
||||
|
|
@ -17,8 +6,6 @@
|
|||
"MSG": "Želiš li instalirati Super Productivity kao PWA (progresivni web-program)?"
|
||||
},
|
||||
"B_OFFLINE": "Ne postoji veza s internetom. Sinkronizacija i traženje podataka pružatelja usluge za praćenje problema neće funkcionirati.",
|
||||
"UPDATE_MAIN_MODEL": "Postoji nova verzija za Super Productivity! Potrebne su neke migracije za tvoje podatke. Imaj na umu da će zbog toga tvoji podaci biti nekompatibilni sa starijim verzijama programa.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "Aktualiziranje modela nije odabrano. Imaj na umu da se moraš vratiti na prethodnu verziju ako ne želiš izvršiti aktualiziranje modela.",
|
||||
"UPDATE_WEB_APP": "Postoji nova verzija. Želiš li učitati novu veziju?"
|
||||
},
|
||||
"BL": {
|
||||
|
|
@ -32,11 +19,7 @@
|
|||
"RESTORE_STRAY_BACKUP": "Tijekom zadnje sinkronizacije je možda došlo do greške. Želiš li obnoviti zadnju sigurnosnu kopiju?"
|
||||
},
|
||||
"DATETIME_SCHEDULE": {
|
||||
"LATER_TODAY": "Kasnije danas",
|
||||
"NEXT_WEEK": "Sljedeći tjedan",
|
||||
"PLACEHOLDER": "Odaberi datum",
|
||||
"PRESS_ENTER_AGAIN": "Za spremanje ponovo pritisni tipku enter",
|
||||
"TOMORROW": "Sutra"
|
||||
"PRESS_ENTER_AGAIN": "Za spremanje ponovo pritisni tipku enter"
|
||||
},
|
||||
"F": {
|
||||
"ATTACHMENT": {
|
||||
|
|
@ -44,7 +27,6 @@
|
|||
"ADD_ATTACHMENT": "Dodaj prilog",
|
||||
"EDIT_ATTACHMENT": "Uredi prilog",
|
||||
"LABELS": {
|
||||
"FILE": "Staza datoteke",
|
||||
"IMG": "Slika",
|
||||
"LINK": "Url"
|
||||
},
|
||||
|
|
@ -60,7 +42,6 @@
|
|||
"DEFAULT": {
|
||||
"DONE": "Fè",
|
||||
"EISENHAUER_MATRIX": "Eisenhower Matrix",
|
||||
"IMPORTANT": "Enpòtan",
|
||||
"IN_PROGRESS": "Nan Pwogrè",
|
||||
"KANBAN": "Kanban",
|
||||
"NOT_URGENT_IMPORTANT": "Pa Ijan ak enpòtan",
|
||||
|
|
@ -97,9 +78,6 @@
|
|||
}
|
||||
},
|
||||
"CALDAV": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Postavi CalDav za projekt"
|
||||
},
|
||||
"FORM": {
|
||||
"CALDAV_CATEGORY_FILTER": "Kategorija za izdvajanje problema (ostavi prazno za nikoju)",
|
||||
"CALDAV_PASSWORD": "Tvoja CalDav lozinka",
|
||||
|
|
@ -109,28 +87,7 @@
|
|||
"IS_TRANSITION_ISSUES_ENABLED": "Automatski završi CalDav zadatke nakon završavanja zadatka"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih CalDav zadataka za određeni projekt na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti zadaci navesti kao prijedlozi s poveznicom na zadatak te s daljnjim informacija o zadatku.</p> <p>Osim toga, sve nezavršene zadatke možeš automatski dodati u odlagalište zadataka i sinkronizirati ih.</p><p>Da bi to za nextcloud radilo na mobilnom uređaju i webu, možda ćeš morati staviti „https://app.super-productivity.com” na popis dopuštenih putem nextcloud programa <a href='https://apps.nextcloud. com/apps/webapppassword'>webapppassword<a>.</p>",
|
||||
"TITLE": "CalDav"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Devwa",
|
||||
"AT": "alèz",
|
||||
"ATTACHMENTS": "Atachman",
|
||||
"CHANGED": "Chanje",
|
||||
"COMMENTS": "Kòmantè",
|
||||
"COMPONENTS": "Eleman",
|
||||
"DESCRIPTION": "Opis",
|
||||
"LABELS": "Kategorije",
|
||||
"LIST_OF_CHANGES": "Lis chanjman yo",
|
||||
"MARK_AS_CHECKED": "Označi aktualiziranja kao provjerena",
|
||||
"ON": "Sou",
|
||||
"RELATED": "Fanmi",
|
||||
"STATUS": "Stanje",
|
||||
"STORY_POINTS": "Pwen istwa",
|
||||
"SUB_TASKS": "Subtasks",
|
||||
"SUMMARY": "Sažetak",
|
||||
"WORKLOG": "Travay",
|
||||
"WRITE_A_COMMENT": "Ekri yon kòmantè"
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih CalDav zadataka za određeni projekt na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti zadaci navesti kao prijedlozi s poveznicom na zadatak te s daljnjim informacija o zadatku.</p> <p>Osim toga, sve nezavršene zadatke možeš automatski dodati u odlagalište zadataka i sinkronizirati ih.</p><p>Da bi to za nextcloud radilo na mobilnom uređaju i webu, možda ćeš morati staviti „https://app.super-productivity.com” na popis dopuštenih putem nextcloud programa <a href='https://apps.nextcloud. com/apps/webapppassword'>webapppassword<a>.</p>"
|
||||
},
|
||||
"S": {
|
||||
"CALENDAR_NOT_FOUND": "CalDav: Kalendar „{{calendarName}}” nije pronađen",
|
||||
|
|
@ -141,7 +98,6 @@
|
|||
"CALENDARS": {
|
||||
"BANNER": {
|
||||
"ADD_AS_TASK": "Dodaj kao zadatak",
|
||||
"FOCUS_TASK": "Fokusiraj zadatak",
|
||||
"TXT": "<strong>{{title}}</strong> počinje <strong>{{start}}</strong>!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> počinje <strong>{{start}}</strong>!<br> (i {{nrOfOtherBanners}} druga događaja su u tijeku)",
|
||||
"TXT_PAST": "<strong>{{title}}</strong> je počeo <strong>{{start}}</strong>!",
|
||||
|
|
@ -175,10 +131,6 @@
|
|||
},
|
||||
"DROPBOX": {
|
||||
"S": {
|
||||
"ACCESS_TOKEN_ERROR": "Dropbox: Nije moguće generirati token za pristup iz koda autentifikacije",
|
||||
"ACCESS_TOKEN_GENERATED": "Dropbox: Token za pristup je generiran iz koda autentifikacije",
|
||||
"AUTH_ERROR": "Dropbox: Naveden je nevažeći token za pristup",
|
||||
"AUTH_ERROR_ACTION": "Promijeni token",
|
||||
"OFFLINE": "Dropbox: Sinkronizacija nije moguća jer računalo nije povezano s internetom",
|
||||
"SYNC_ERROR": "Dropbox: Greška tijekom sinkoronizacije",
|
||||
"UNABLE_TO_GENERATE_PKCE_CHALLENGE": "Dropbox: Pa kapab jenere defi PKCE."
|
||||
|
|
@ -195,36 +147,25 @@
|
|||
"TO_FOCUS_OVERLAY": "Konsantre sou sipriz"
|
||||
},
|
||||
"BACK_TO_PLANNING": "Natrag na planiranje",
|
||||
"CONGRATS": "Čestitamo na obavljanju ove sesije!",
|
||||
"CONTINUE_FOCUS_SESSION": "Nastavi sesiju fokusa",
|
||||
"COUNTDOWN": "Dekont",
|
||||
"FINISH_TASK_AND_SELECT_NEXT": "Završi zadatak i odaberi sljedeći",
|
||||
"FLOWTIME": "Koule",
|
||||
"FOR_TASK": "pou travay",
|
||||
"GET_READY": "Pripremi se za tvoju sesiju fokusa!!!",
|
||||
"GO_TO_PROCRASTINATION": "Dobij pomoć kad odugovlačiš",
|
||||
"GOGOGO": "Kreni!!!",
|
||||
"NEXT": "Sljedeći",
|
||||
"ON": "na",
|
||||
"OPEN_ISSUE_IN_BROWSER": "Otvori problem u pregledniku",
|
||||
"PREP_GET_MENTALLY_READY": "Mentalno se pripremi na fokusiran i produktivan rad",
|
||||
"PREP_SIT_UPRIGHT": "Sjedni (ili ustani) uspravno",
|
||||
"PREP_STRETCH": "Malo se protegni",
|
||||
"SELECT_ANOTHER_TASK": "Odaberi jedan drugi zadatak",
|
||||
"SELECT_TASK": "Odaberi zadatak na koji se želiš fokusirati",
|
||||
"SESSION_COMPLETED": "Konsantre Sesyon ranpli!",
|
||||
"SET_FOCUS_SESSION_DURATION": "Postavi trajanje sesije fokusa",
|
||||
"SHOW_HIDE_NOTES_AND_ATTACHMENTS": "Prikaži/Sakrij bilješke zadataka i priloge",
|
||||
"START_FOCUS_SESSION": "Pokreni sesiju fokusa",
|
||||
"START_NEXT_FOCUS_SESSION": "Pokreni sljedeću sesiju fokusa",
|
||||
"WORKED_FOR": "Radio/la si"
|
||||
},
|
||||
"GITEA": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Postavi Gitea za projekt"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Korisničko ime (npr. za izdvajanje vlastito izrađenih promjena)",
|
||||
"HOST": "Host računalo (npr.: https://try.gitea.io)",
|
||||
"REPO_FULL_NAME": "Korisničko ime ili ime organizacije/projekta",
|
||||
"REPO_FULL_NAME_DESCRIPTION": "Može se pronaći kao dio url-a prilikom pregledavanja projekta u pregledniku.",
|
||||
|
|
@ -235,12 +176,10 @@
|
|||
"TOKEN": "Token za pristup"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih Gitea problema za određeni repozitorij na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti problemi navesti kao prijedlozi s poveznicom na problem te s daljnjim informacija o problemu.</p> <p>Osim toga, sve neriješene probleme možeš automatski u odlagalište zadataka i sinkronizirati ih.</p><p>Za dobivanje ograničenja korištenja i za pristupanje možeš navesti token za pristup.",
|
||||
"TITLE": "Gitea"
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih Gitea problema za određeni repozitorij na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti problemi navesti kao prijedlozi s poveznicom na problem te s daljnjim informacija o problemu.</p> <p>Osim toga, sve neriješene probleme možeš automatski u odlagalište zadataka i sinkronizirati ih.</p><p>Za dobivanje ograničenja korištenja i za pristupanje možeš navesti token za pristup."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Odgovorna osoba",
|
||||
"AT": "pri",
|
||||
"DESCRIPTION": "Opis",
|
||||
"LABELS": "Etikete",
|
||||
"MARK_AS_CHECKED": "Označi aktualiziranja kao provjerena",
|
||||
|
|
@ -248,15 +187,9 @@
|
|||
"STATUS": "Stanje",
|
||||
"SUMMARY": "Sažetak",
|
||||
"WRITE_A_COMMENT": "Upiši komentar"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Gitea: Nepoznata greška {{statusCode}} {{errorMsg}}. Je li stopa API-ja prekoračena?"
|
||||
}
|
||||
},
|
||||
"GITHUB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Postavi GitHub za projekt"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Korisničko ime (npr. za izdvajanje vlastitih promjena)",
|
||||
"INVALID_TOKEN_MESSAGE": "Pa yon siy GitHub valab. Li dwe kòmanse ak \"ghp_\".",
|
||||
|
|
@ -265,8 +198,7 @@
|
|||
"TOKEN": "Token za pristup"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih GitHub problema (online verzija ili instanca vlastitog histinga) za određeni projekt na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti problemi navesti kao prijedlozi s poveznicom na problem te s daljnjim informacija o problemu.</p> <p>Osim toga, sve neriješene probleme možeš automatski dodati u odlagalište zadataka i sinkronizirati ih.</p><p>Za zaobilaženje ograničenja upotrebe i za pristupanje, možeš zadati pristupni token. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>Više informacija mogu se pronaći odvje</a>.",
|
||||
"TITLE": "GitHub"
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih GitHub problema (online verzija ili instanca vlastitog histinga) za određeni projekt na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti problemi navesti kao prijedlozi s poveznicom na problem te s daljnjim informacija o problemu.</p> <p>Osim toga, sve neriješene probleme možeš automatski dodati u odlagalište zadataka i sinkronizirati ih.</p><p>Za zaobilaženje ograničenja upotrebe i za pristupanje, možeš zadati pristupni token. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>Više informacija mogu se pronaći odvje</a>."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Odgovorna osoba",
|
||||
|
|
@ -287,9 +219,6 @@
|
|||
}
|
||||
},
|
||||
"GITLAB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Postavi GitLab za projekt"
|
||||
},
|
||||
"DIALOG_SUBMIT_WORKLOG": {
|
||||
"PAST_DAY_INFO": "Unaprijed zapisano trajanje sadrži nepraćene podatke od prošlih dana.",
|
||||
"T_ALREADY_TRACKED": "Već je pračeno",
|
||||
|
|
@ -318,8 +247,7 @@
|
|||
"TOKEN": "Token za pristup"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih GitLab problema (online verzija ili instanca vlastitog histinga) za određeni projekt na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti problemi navesti kao prijedlozi s poveznicom na problem te s daljnjim informacija o problemu.</p> <p>Osim toga, sve neriješene probleme možeš automatski dodati u odlagalište zadataka i sinkronizirati ih.</p>",
|
||||
"TITLE": "GitLab"
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa nezavršenih GitLab problema (online verzija ili instanca vlastitog histinga) za određeni projekt na ploči za stvaranje zadataka u prikazu dnevnog planiranja. U popisu će se ti problemi navesti kao prijedlozi s poveznicom na problem te s daljnjim informacija o problemu.</p> <p>Osim toga, sve neriješene probleme možeš automatski dodati u odlagalište zadataka i sinkronizirati ih.</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Odgovorna osoba",
|
||||
|
|
@ -351,20 +279,14 @@
|
|||
"ATTACHMENTS": "Atachman",
|
||||
"AUTHOR": "Otè",
|
||||
"CATEGORY": "Kategori",
|
||||
"CHANGED": "Chanje",
|
||||
"COMMENTS": "Kòmantè",
|
||||
"COMPONENTS": "Eleman",
|
||||
"DESCRIPTION": "Deskripsyon",
|
||||
"DONE_RATIO": "Fèee Rattpoude",
|
||||
"DUE_DATE": "Dat limit pou",
|
||||
"LABELS": "Etikèt yo",
|
||||
"LAST_COMMENT": "Dènye kòmantè",
|
||||
"LIST_OF_CHANGES": "Lis chanjman yo",
|
||||
"LOAD_ALL_COMMENTS": "Chaj tout kòmantè {{nr}} ",
|
||||
"LOAD_DESCRIPTION_AND_ALL_COMMENTS": "Deskripsyon chaj - tout kòmantè",
|
||||
"LOCATION": "Kote",
|
||||
"MARK_AS_CHECKED": "Mak dènye nouvèl kòm tcheke",
|
||||
"ON": "Sou",
|
||||
"PRIORITY": "Priyorite",
|
||||
"RELATED": "Fanmi",
|
||||
"START": "Kòmanse",
|
||||
|
|
@ -375,8 +297,7 @@
|
|||
"TIME_SPENT": "Tan pase",
|
||||
"TYPE": "Tip",
|
||||
"VERSION": "Vèsyon",
|
||||
"WORKLOG": "Travay",
|
||||
"WRITE_A_COMMENT": "Ekri yon kòmantè"
|
||||
"WORKLOG": "Travay"
|
||||
},
|
||||
"S": {
|
||||
"ERR_GENERIC": "{{issueProviderName}} Erè: {{errTxt}}",
|
||||
|
|
@ -384,13 +305,9 @@
|
|||
"ERR_NOT_CONFIGURED": "{{issueProviderName}}: Nije ispravno konfigurirano",
|
||||
"IMPORTED_MULTIPLE_ISSUES": "{{issueProviderName}}: Uvezeno {{nr}} novih problema {{issuesStr}} u odlagalište",
|
||||
"IMPORTED_SINGLE_ISSUE": "{{issueProviderName}}: Uvezen problem {{issueStr}} „{{issueTitle}}” u odlagalište",
|
||||
"ISSUE_DELETED_OR_CLOSED": "{{issueProviderName}}: Problem {{issueStrC}} „{{issueTitle}}” je vjerojatno izbrisan ili riješen",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "{{issueProviderName}}: Aktualiziranje nije potrebno",
|
||||
"ISSUE_UPDATE_MULTIPLE": "{{issueProviderName}}: Aktualizirani su podaci za problem {{nr}} {{issuesStr}}",
|
||||
"ISSUE_UPDATE_SINGLE": "{{issueProviderName}}: Aktualizirani su podaci za problem „{{issueTitle}}”",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "{{issueProviderName}}: Aktualizirani su podaci za problem „{{issueTitle}}”",
|
||||
"MISSING_ISSUE_DATA": "{{issueProviderName}}: Pronađeni su problemi s podacima problema {{issueStr}}. Ponovo se učitavaju.",
|
||||
"NEW_COMMENT": "{{issueProviderName}}: Novi komentar za „{{issueTitle}}”",
|
||||
"POLLING_BACKLOG": "{{issueProviderName}}: Anketiranje za novi problem {{issuesStr}}",
|
||||
"POLLING_CHANGES": "{{issueProviderName}}: Promjene anketiranja za problem {{issuesStr}}"
|
||||
}
|
||||
|
|
@ -427,8 +344,7 @@
|
|||
"CURRENT_ASSIGNEE": "Trenutačno odgovorna osoba:",
|
||||
"CURRENT_STATUS": "Trenutačno stanje:",
|
||||
"TASK_NAME": "Ime zadatka:",
|
||||
"TITLE": "Jira: Aktualiziraj stanje",
|
||||
"UPDATE_STATUS": "Aktualiziraj stanje"
|
||||
"TITLE": "Jira: Aktualiziraj stanje"
|
||||
},
|
||||
"DIALOG_WORKLOG": {
|
||||
"CHECKBOXES": {
|
||||
|
|
@ -463,8 +379,7 @@
|
|||
"HOST": "Host (npr.: http://my-host.de:1234)",
|
||||
"PASSWORD": "Token / Lozinka",
|
||||
"USE_PAT": "Za pristup koristi osobni token umjesto lozinke",
|
||||
"USER_NAME": "E-mail adresa / Korisničko ime",
|
||||
"WONKY_COOKIE_MODE": "Wonky Cookie rezervna autentifikacija (samo program desktop računala)"
|
||||
"USER_NAME": "E-mail adresa / Korisničko ime"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"ADV_CFG": "Napredna konfiguracija",
|
||||
|
|
@ -506,23 +421,12 @@
|
|||
"EXTENSION_NOT_LOADED": "Proširenje za Super Productivity nije učitano. Ponovno učitavanje stranice može pomoći",
|
||||
"INSUFFICIENT_SETTINGS": "Nedovoljne postavke dostavljene za Jira",
|
||||
"INVALID_RESPONSE": "Jira: Odgovor je sadržao neispravne podatke",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "Jira: „{{issueText}}” je već aktualiziran",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "Jira: Aktualizirani su podaci za „{{issueText}}”",
|
||||
"MISSING_ISSUE_DATA": "Jira: Pronađeni su zadaci s nedostajućim podacima problema. Učitavanje se ponavlja.",
|
||||
"NO_AUTO_IMPORT_JQL": "Jira: Upit za pretragu nije definiran za automatski uvoz",
|
||||
"NO_VALID_TRANSITION": "Jira: Nema ispravno konfigurirane tranzicije",
|
||||
"TIMED_OUT": "Jira: Prekoračeno je vrijeme zahtjeva",
|
||||
"TRANSITION": "Jira: Postavi problem „{{issueKey}}” u „{{name}}”",
|
||||
"TRANSITION_SUCCESS": "Jira: Postavi problem {{issueKey}} na <strong>{{chosenTransition}}</strong>",
|
||||
"TRANSITIONS_LOADED": "Jira: Tranzicije su učitane. Koristi donje mogućnosti za njihovo dodijeljivanje",
|
||||
"UNABLE_TO_REASSIGN": "Jira: Nije moguće ponovo sebi dodijeliti tiket, jer nisi odredio/la korisničko ime. Pogledaj postavke."
|
||||
},
|
||||
"STEPPER": {
|
||||
"CREDENTIALS": "Zahvale",
|
||||
"DONE": "Sada si gotov/a.",
|
||||
"LOGIN_SUCCESS": "Prijava je uspjela!",
|
||||
"TEST_CREDENTIALS": "Testiraj podatke za prijavu",
|
||||
"WELCOME_USER": "Zdravo {{user}}!"
|
||||
"TRANSITIONS_LOADED": "Jira: Tranzicije su učitane. Koristi donje mogućnosti za njihovo dodijeljivanje"
|
||||
}
|
||||
},
|
||||
"MARKDOWN_PASTE": {
|
||||
|
|
@ -534,9 +438,6 @@
|
|||
"DIALOG_TITLE": "Lis Sot pase yo Makdown Lis detekte!"
|
||||
},
|
||||
"METRIC": {
|
||||
"BANNER": {
|
||||
"CHECK": "Obavljeno!"
|
||||
},
|
||||
"CMP": {
|
||||
"AVG_BREAKS_PER_DAY": "Prosječni broj pauza na dan",
|
||||
"AVG_TASKS_PER_DAY_WORKED": "Prosječni broj zadataka po radnom danu",
|
||||
|
|
@ -546,7 +447,6 @@
|
|||
"COUNTING_SUBTASKS": "(brojenje podzadataka)",
|
||||
"DAYS_WORKED": "Broj radnih dana",
|
||||
"GLOBAL_METRICS": "Globalni mjerni podaci",
|
||||
"MOOD_PRODUCTIVITY_OVER_TIME": "Raspoloženje i produktivnost tijekom vremena",
|
||||
"NO_ADDITIONAL_DATA_YET": "Još nisu prikupljeni dodatni podaci. Koristi obrazac na ploči dnevnog sažetka „Evaluacija” za prikupljanje dodatnih podataka.",
|
||||
"SIMPLE_CLICK_COUNTERS_OVER_TIME": "Brojači pritiskanja namjesto vremena",
|
||||
"SIMPLE_COUNTERS": "Jednostavni brojači",
|
||||
|
|
@ -556,30 +456,11 @@
|
|||
"TIME_SPENT": "Utrošeno vrijeme"
|
||||
},
|
||||
"EVAL_FORM": {
|
||||
"ADD_NOTE_FOR_TOMORROW": "Dodaj bilješku za sutra",
|
||||
"DISABLE_REPEAT_EVERY_DAY": "Deaktiviraj svakodnevno ponavljanje",
|
||||
"ENABLE_REPEAT_EVERY_DAY": "Ponavljaj svaki dan",
|
||||
"HELP_H1": "Zašto je to važno?",
|
||||
"HELP_LINK_TXT": "Idi na odjeljak mjernih podataka",
|
||||
"HELP_P1": "Vrijeme je za evaluaciju vlastitog rada! Tvoji ovdje zapisani odgovori su spremljeni i pružaju statistiku tvog rada u odjeljku metričkih podataka. Nadalje, prijedlozi za sutra će se sljedećeg dana pojaviti iznad tvog popisa zadataka.",
|
||||
"HELP_P2": "Namjera nije izračunavanje točnih metričkih podataka ili strojna produktivnost u svemu što radiš, nego poboljšanje osjećaja o vlatitom radu. Može biti korisno za procjenjivanje problema u tvojoj svakodnevnoj rutini, kao i za pronalaženje čimbenika koji ti pomažu u obavjanju posla. Uz ponešto sistematike može pomoći bolje svladati i poboljšati tvoje poslove.",
|
||||
"IMPROVEMENTS": "Što je poboljšalo tvoju produktivnost?",
|
||||
"IMPROVEMENTS_TOMORROW": "Što možeš sutra poboljšati?",
|
||||
"MOOD": "Kako se osjećaš?",
|
||||
"MOOD_HINT": "1: Grozno – 10: Super",
|
||||
"NOTES": "Bilješke za sutra",
|
||||
"OBSTRUCTIONS": "Što je omelo tvoju produktivnost?",
|
||||
"PRODUCTIVITY": "Stupanj produktivnosti tvog rada?",
|
||||
"PRODUCTIVITY_HINT": "1: Još nisam ni počeo/la – 10: Visoka efektivnost"
|
||||
},
|
||||
"S": {
|
||||
"SAVE_METRIC": "Metrični podaci su uspješno spremljeni"
|
||||
"PRODUCTIVITY": "Stupanj produktivnosti tvog rada?"
|
||||
}
|
||||
},
|
||||
"NOTE": {
|
||||
"D_ADD": {
|
||||
"NOTE_LABEL": "Za spremanje bilješke upiši neki tekst (možeš koristiti markdown) …"
|
||||
},
|
||||
"D_FULLSCREEN": {
|
||||
"VIEW_PARSED": "Prikaži kao obrađeni (nepromjenjiv) markdown",
|
||||
"VIEW_SPLIT": "Prikaži obrađeni i neobrađeni markdown u podijeljenom prikazu",
|
||||
|
|
@ -611,9 +492,6 @@
|
|||
"SELECT_ISSUE_FOR_TRANSITIONS": "Odaberi problem za učitavanje dostupnih tranzicija",
|
||||
"TRANSITION": "Baratanje tranzicijama"
|
||||
},
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Postavi OpenProject za projekt"
|
||||
},
|
||||
"DIALOG_TRACK_TIME": {
|
||||
"ACTIVITY": "Aktivnost",
|
||||
"CURRENTLY_LOGGED": "Trenutačno zapisano vrijeme: ",
|
||||
|
|
@ -630,8 +508,7 @@
|
|||
"CURRENT_STATUS": "Trenutačno stanje:",
|
||||
"PERCENTAGE_DONE": "Napredak:",
|
||||
"TASK_NAME": "Ime zadatka:",
|
||||
"TITLE": "OpenProject: Stanje aktualiziranja",
|
||||
"UPDATE_STATUS": "Stanje aktualiziranja"
|
||||
"TITLE": "OpenProject: Stanje aktualiziranja"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Korisničko ime (npr. za izdvajanje tvojih promjena)",
|
||||
|
|
@ -648,8 +525,7 @@
|
|||
"TOKEN": "Token za pristup"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa otvorenih radnih OpenProject paketa. Da bi ovo funkcioniralo u pregledniku, vjerojatno ćeš morati konfigurirati CORS za tvoj OpenProject poslužitelj da bi se dozvolio pristup s app.super-productivity.com</p>",
|
||||
"TITLE": "OpenProject"
|
||||
"HELP": "<p>Ovdje možeš konfigurirati Super Productivity za prikaz popisa otvorenih radnih OpenProject paketa. Da bi ovo funkcioniralo u pregledniku, vjerojatno ćeš morati konfigurirati CORS za tvoj OpenProject poslužitelj da bi se dozvolio pristup s app.super-productivity.com</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Odgovorna osoba",
|
||||
|
|
@ -677,9 +553,7 @@
|
|||
"PLANNER": {
|
||||
"D": {
|
||||
"ADD_PLANNED": {
|
||||
"ADD_TO_TODAY": "Ajoute jodi a",
|
||||
"RE_PLAN_ALL": "Repwodiksyon tout",
|
||||
"TITLE": "Ajoute travay ki planifye jodi a"
|
||||
"RE_PLAN_ALL": "Repwodiksyon tout"
|
||||
}
|
||||
},
|
||||
"EDIT_REPEATED_TASK": "Edite repete travay '{{taskName}}'",
|
||||
|
|
@ -691,67 +565,15 @@
|
|||
"REMOVED_PLAN_DATE": "Retire dat plan pou travay '{{taskTitle}}'",
|
||||
"TASK_ALREADY_PLANNED": "Travay la deja planifye pou {{date}}",
|
||||
"TASK_PLANNED_FOR": "Travay ki te planifye pou <strong>{{date}}</strong>{{extra}}"
|
||||
},
|
||||
"TASK_DRAWER": "Tiwa Objektif Travay la"
|
||||
}
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_IS_DONE": "Tvoja pauza je gotova!"
|
||||
},
|
||||
"PROCRASTINATION": {
|
||||
"BACK_TO_WORK": "Vrati se na posao!",
|
||||
"COMP": {
|
||||
"INTRO": "Ljudi s visokom razinom odugovlačenja obično imaju nisku razinu samosuosjećanja. Stoga vježbaj! Poboljšava osjećaj vlastite vrijednosti, potiče pozitivne emocije i naravno može pomoći u prevladavanju odugovlačenja. Isprobaj kratku vježbu:",
|
||||
"L1": "Sjedni i rastegni se, ako želiš, smiri se",
|
||||
"L2": "Razmotri vlatite misli i osjećaje",
|
||||
"L3": "Odgovaraš li sebi na način na koji bi odgovorio/la prijatelju?",
|
||||
"L4": "Ako je odgovor ne, zamisli prijatelja u tvojoj situaciji. Što bi mu rekao/la? Kako bi mu pomogao/la?",
|
||||
"OUTRO": "Daljnje vježbe <a target=\"_blank\" href=\"https://drsoph.com/blog/2018/9/17/3-exercises-in-self-compassion\" target=\"_blank\">možeš naći ovdje</a> ili na <a target=\"_blank\" href=\"https://www.google.com/search?q=self+compassion+exercises&oq=self+compassion+excers&aqs=chrome.1.69i57j0l5.4303j0j7&sourceid=chrome&ie=UTF-8\" target=\"_blank\">google</a>.",
|
||||
"TITLE": "Samosuosjećanje"
|
||||
},
|
||||
"CUR": {
|
||||
"INTRO": "Odugovlačenje je zanimljivo, zar ne? Mada nema smisla. Naročito ne dugoročno. Svejedno svi to rade. Uživaj i istraži!",
|
||||
"L1": "Koji osjećaji izazivaju tvoje iskušenje za odgađanjem?",
|
||||
"L2": "Gdje ih osjećaš u tvom tijelu?",
|
||||
"L3": "Na što te podsjećaju?",
|
||||
"L4": "Što se događa tijekom pomisli o odgađanju? Pojačava li se? Raspršuje se? Izaziva druge emocije?",
|
||||
"L5": "Kako se mijenjanju osjećaji u tvom tijelu dok se i dalje fokusiraš na njih?",
|
||||
"PROCRASTINATION_TRIGGERS_TEXT": "Još jedna vrlo učinkovita metoda je zapisivanje onoga što te je natjeralo da odugovlačiš. Na primjer, osobno često imam potrebu za brzim prelaskom na reddit ili moju omiljenu stranicu s vijestima kad god mi se prikaže prozor preglednika. Otkako sam počeo zapisivati svoje okidače u prazan tekstualni dokument, shvatio sam problematiku i to mi je pomoglo u eksperimentiranju s različitim protumjerama.",
|
||||
"PROCRASTINATION_TRIGGERS_TITLE": "Zapisivanje tvojih okidače odugovlačenja",
|
||||
"TITLE": "Znatiželja"
|
||||
},
|
||||
"H1": "Oslobodi se pritiska!",
|
||||
"INTRO": {
|
||||
"AVOIDING": "Izbjegavanje zadatka",
|
||||
"FEAR": "Strah od neuspjeha",
|
||||
"STRESSED": "Pod stresom zbog ne obavljanja zadataka",
|
||||
"TITLE": "Uvod"
|
||||
},
|
||||
"P1": "Kao prvo, opusti se! Svatko to čini s vremena na vrijeme. A ako ne radiš ono što bi trebao/la, barem uživaj u tome! Zatim pogledaj sljedeće odjeljke za nešto korisno.",
|
||||
"P2": "Zapampti: Odugovlačenje je emotivan problem reguliranja, a ne problem upravljanja vremena.",
|
||||
"REFRAME": {
|
||||
"INTRO": "Razmisli što bi moglo biti pozitivno u vezi sa zadatkom unatoč njegovim nedostacima.",
|
||||
"TITLE": "Preispitivanje",
|
||||
"TL1": "Što bi moglo biti zanimljivo u zadatku?",
|
||||
"TL2": "Koja je dobit ako ga završiš?",
|
||||
"TL3": "Kako ćeš se osjećati ako ga završiš?"
|
||||
},
|
||||
"SPLIT_UP": {
|
||||
"INTRO": "Podijeli zadatak na što više moguće manje dijelove.",
|
||||
"OUTRO": "Gotov/a? Razmisli o tome. Što bi bila – čisto teoretski – prva stvar koju bi uradio/la <i>ako</i> bi počeo/la obavljati zadatak? Jednostavno razmisli o tome …",
|
||||
"TITLE": "Podijeli zadatak!"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "Stvori projekt",
|
||||
"EDIT": "Uredi projekt",
|
||||
"SETUP_CALDAV": "Postavi Caldav integraciju",
|
||||
"SETUP_GIT": "Postavi GitHub integraciju",
|
||||
"SETUP_GITEA_PROJECT": "Postavi Gitea integraciju",
|
||||
"SETUP_GITLAB": "Postavi GitLab integraciju",
|
||||
"SETUP_JIRA": "Postavi Jira integraciju",
|
||||
"SETUP_OPEN_PROJECT": "Postavi OpenProject integraciju",
|
||||
"SETUP_REDMINE_PROJECT": "Postavi Redmine integraciju"
|
||||
"EDIT": "Uredi projekt"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"MSG": "Èske w sèten ou vle efase pwojè \"{{title}}\"?"
|
||||
|
|
@ -763,7 +585,6 @@
|
|||
"TITLE": "Osnovne ostavke"
|
||||
},
|
||||
"FORM_THEME": {
|
||||
"D_IS_DARK_THEME": "Neće se koristiti ako sustav podržava globalni tamni modus.",
|
||||
"HELP": "Postavke teme za tvoj projekt.",
|
||||
"L_BACKGROUND_IMAGE_DARK": "Url slike pozadine (tamna tema)",
|
||||
"L_BACKGROUND_IMAGE_LIGHT": "Url slike pozadine (svijetla tema)",
|
||||
|
|
@ -775,18 +596,13 @@
|
|||
"L_HUE_WARN": "Prag za tamni tekst na boji upozorenja pozadine",
|
||||
"L_IS_AUTO_CONTRAST": "Automatski postavi boju teksta za najbolju čitljivost",
|
||||
"L_IS_DISABLE_BACKGROUND_TINT": "Deaktiviraj prijelaz boja pozadine",
|
||||
"L_IS_REDUCED_THEME": "Koristi reducirano korisničko sučelje (bez okvira okolo zadataka)",
|
||||
"L_THEME_COLOR": "Boja teme",
|
||||
"L_TITLE": "Naslov",
|
||||
"TITLE": "Tema"
|
||||
},
|
||||
"S": {
|
||||
"ARCHIVED": "Arhivirani projekt",
|
||||
"CREATED": "Stvoren je projekt <strong>{{title}}</strong>. Možeš ga odabrati u gornjem lijevom izborniku.",
|
||||
"DELETED": "Izbrisani projekt",
|
||||
"E_EXISTS": "Projekt „{{title}}” već postoji",
|
||||
"E_INVALID_FILE": "Neispravni podaci za datoteku projekta",
|
||||
"ISSUE_PROVIDER_UPDATED": "Postavke projekta su aktualizirane za <strong>{{issueProviderKey}}</strong>",
|
||||
"UNARCHIVED": "Nearhivirani projekt",
|
||||
"UPDATED": "Aktualizirane postavke projekta"
|
||||
}
|
||||
|
|
@ -797,9 +613,6 @@
|
|||
"WEEK_TITLE": "{{nr}}. tjedan ({{timeSpent}})"
|
||||
},
|
||||
"REDMINE": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Postavi Redmine za projekt"
|
||||
},
|
||||
"FORM": {
|
||||
"API_KEY": "Ključ za pritup API-u",
|
||||
"HOST": "Host računalo (npr.: https://redmine.org)",
|
||||
|
|
@ -820,14 +633,10 @@
|
|||
"MARK_AS_CHECKED": "Označi aktualiziranja kao provjerena",
|
||||
"PRIORITY": "Prioritet",
|
||||
"STATUS": "Stanje"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Redmine: Nepoznata greška {{statusCode}} {{errorMsg}}."
|
||||
}
|
||||
},
|
||||
"REMINDER": {
|
||||
"COUNTDOWN_BANNER": {
|
||||
"HIDE": "Sakrij",
|
||||
"START_NOW": "Pokreni sada",
|
||||
"TXT": "<strong>{{title}}</strong> počinje <strong>{{start}}</strong>!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> počinje <strong>{{start}}</strong>!<br> (i {{nrOfOtherBanners}} drugih zadataka u tijeku)"
|
||||
|
|
@ -836,27 +645,19 @@
|
|||
"S_REMINDER_ERR": "Greška za sučelje podsjetnika"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"CONTINUED": "nastavljeno",
|
||||
"D_INITIAL": {
|
||||
"TEXT": "<p>Ideja vremenske trake je pružiti bolju sliku o tome kako se nečiji terminirani zadaci odvijaju tijekom vremena. Automatski se generira iz tvojih zadataka i razlikuje dvije stvari: <strong>terminirane zadatke</strong> koji se prikazuju u planirano vrijeme i <strong>redovne zadatke</strong> koji bi se trebali odvijati oko tih fiksnih događaja. Svi zadaci uzimaju u obzir dodijejene procjene vremena.</p><p>Osim toga moguće je navesti vrijeme početka i kraja rada. Ako su konfigurirani, redovni zadaci se nikada neće pojaviti izvan njih. Imaj na umu da vremenska traka uključuje samo idućih 30 dana.</p>",
|
||||
"TITLE": "Vremenska traka"
|
||||
},
|
||||
"END": "Kraj rada",
|
||||
"LUNCH_BREAK": "Pauza za ručak",
|
||||
"NO_TASKS": "Trenutačno nema zadataka. Dodaj zadatke putem gumba + u gornjoj traci.",
|
||||
"NOW": "Sada",
|
||||
"PLAN_END_DAY": "Planifye nan fen jounen an",
|
||||
"PLAN_START_DAY": "Planifye nan kòmansman jounen an",
|
||||
"START": "Početak rada",
|
||||
"TASK_PROJECTION_INFO": "Projekcija u budućnosti terminiranog ponavljajućeg zadatka"
|
||||
"START": "Početak rada"
|
||||
},
|
||||
"SEARCH_BAR": {
|
||||
"INFO": "Pritisni ikonu popisa za traženje arhiviranih zadataka",
|
||||
"INFO_ARCHIVED": "Pritisni ikonu arhive za traženje normalnih zadataka",
|
||||
"NO_RESULTS": "Pa gen travay yo te jwenn matche ak rechèch ou an",
|
||||
"PLACEHOLDER": "Traži zadatak ili opis zadatka",
|
||||
"PLACEHOLDER_ARCHIVED": "Traži arhivirane zadatke",
|
||||
"TOO_MANY_RESULTS": "Previše rezultata. Suzi pretragu"
|
||||
"PLACEHOLDER": "Traži zadatak ili opis zadatka"
|
||||
},
|
||||
"SIMPLE_COUNTER": {
|
||||
"D_CONFIRM_REMOVE": {
|
||||
|
|
@ -875,7 +676,6 @@
|
|||
"L_COUNTDOWN_DURATION": "Countdown dire",
|
||||
"L_DAILY_GOAL": "Objektif chak jou pou yon seri siksè",
|
||||
"L_ICON": "Ikona",
|
||||
"L_ICON_ON": "Ikona kad je uključeno",
|
||||
"L_IS_ENABLED": "Aktivirano",
|
||||
"L_TITLE": "Naslov",
|
||||
"L_TRACK_STREAKS": "Track Streaks",
|
||||
|
|
@ -893,18 +693,10 @@
|
|||
},
|
||||
"SYNC": {
|
||||
"A": {
|
||||
"ARCHIVE_ONLY_UPLOADED": "Done ou yo te telechaje sèlman pasyèlman. Tanpri eseye ankò pita! Sinon ou pa pral kapab senkronize done ou ak lòt aparèy.",
|
||||
"POSSIBLE_LEGACY_DATA": "Super Pwodiktivite te amelyore senkronize kounye a lè l sèvi avèk de dosye separe olye ke yon sèl, sa ki pèmèt pou anpil mwens transfè done. Li rekòmande pou mete ajou tout sikonstans Super Pwodiktivite ak premye senkronize done ki soti nan egzanp aplikasyon an kote done yo se dernye. Si sa a se done ki soti nan aparèy lokal ou a, tanpri inyore avètisman sa a epi jis kontinye telechaje li pa konfime pwochen dyalòg la.",
|
||||
"REMOTE_MODEL_VERSION_NEWER": "Vèsyon an modèl alekite se pi nouvo pase yon sèl lokal la. Tanpri mete ajou app lokal ou a nan vèsyon an pi nouvo!"
|
||||
},
|
||||
"C": {
|
||||
"EMPTY_SYNC": "Pokušavaš sinkronizirati prazan objekt podataka. Ako pokušavaš postaviti sinkronizaciju iz nove instance programa, jednostavno pritisni „U redu” za učitavanje podataka s poslužitelja. U suprotnom, provjeri tvoje podatke.",
|
||||
"FORCE_UPLOAD": "Svejedno učitati podatke lokalnog uređaja?",
|
||||
"FORCE_UPLOAD_AFTER_ERROR": "Dogodila se greška tijekom učitavanja podataka lokalnog uređaja. Želiš li pokušati prisilno aktualizirati?",
|
||||
"MIGRATE_LEGACY": "Otkriveni su stari podaci tijekom uvoza. Želiš li ih pokušati migrirati?",
|
||||
"NO_REMOTE_DATA": "Podaci udaljenog uređaja nisu pronađeni. Želiš li učitati lokalne podatke na udaljeni uređaj?",
|
||||
"TRY_LOAD_REMOTE_AGAIN": "Želiš li ponovo pokušati učitati podatke s udaljenog uređaja?",
|
||||
"UNABLE_TO_LOAD_REMOTE_DATA": "Pa kapab chaje done ki soti nan remote. Èske ou vle eseye ranplase done aleka yo ak done lokal ou a? Tout done aleka yo pral pèdi nan pwosesis la."
|
||||
"FORCE_UPLOAD": "Svejedno učitati podatke lokalnog uređaja?"
|
||||
},
|
||||
"D_AUTH_CODE": {
|
||||
"FOLLOW_LINK": "Otvori sljedeću poveznicu i kopiraj autentifikacijski kod koji je tamo naveden u donje polje unosa.",
|
||||
|
|
@ -913,8 +705,6 @@
|
|||
"TITLE": "Prijava: {{provider}}"
|
||||
},
|
||||
"D_CONFLICT": {
|
||||
"LAMPORT_CLOCK": "Revizyon",
|
||||
"LAST_CHANGE": "Zadnja promjena:",
|
||||
"LAST_SYNC": "Zadnja sinkronizacija:",
|
||||
"LOCAL": "Lokalni uređaj",
|
||||
"LOCAL_REMOTE": "Lokalni uređaj -> Udaljeni uređaj",
|
||||
|
|
@ -938,10 +728,6 @@
|
|||
"BTN_FORCE_UPLOAD": "Force Upload lokal",
|
||||
"P1": "Done yo senk aleka se inosan!",
|
||||
"P2": "Modèl ki afekte:",
|
||||
"P3": "Ou gen 2 Opsyon:",
|
||||
"P4": "1. Ale nan lòt aparèy ou an epi eseye fè yon senk konplè la.",
|
||||
"P5": "2. Overwrite done yo aleka ak done lokal ou yo. Tout chanjman aleka yo pral pèdi!",
|
||||
"P6": "Kreye yon backup nan done yo ou rekòmande!!",
|
||||
"T1": "Dènye senkronizasyon te enkonplè!",
|
||||
"T2": "Done achiv ou yo pa t byen telechaje pandan dènye senkronizasyon an:",
|
||||
"T3": "Ou gen 2 Opsyon:",
|
||||
|
|
@ -953,19 +739,7 @@
|
|||
"SAVE_AND_ENABLE": "Sove - Pèmèt Senk",
|
||||
"TITLE": "Configure Sync"
|
||||
},
|
||||
"D_PERMISSION": {
|
||||
"DISABLE_SYNC": "Deaktiviraj sinkronizaciju",
|
||||
"PERM_FILE": "Daj dozvole",
|
||||
"TEXT": "<p>Tvoja dozvola za lokalno sinkroniziranje je opozvana.</p>",
|
||||
"TITLE": "Sinkronizacija: Odbijena dozvola za lokalne datoteke"
|
||||
},
|
||||
"FORM": {
|
||||
"DROPBOX": {
|
||||
"L_ACCESS_TOKEN": "Token za pristup (generiran iz koda autentifikacije)"
|
||||
},
|
||||
"GOOGLE": {
|
||||
"L_SYNC_FILE_NAME": "Ime datoteke sinkronizacije"
|
||||
},
|
||||
"L_ENABLE_COMPRESSION": "Aktiviraj komprimiranje (brži prijenos podataka)",
|
||||
"L_ENABLE_ENCRYPTION": "Pèmèt chifreman fen-a-fen (eksperimantal) - Fè done ou yo pa aksesib pou founisè senkronizasyon ou a",
|
||||
"L_ENABLE_SYNCING": "Aktiviraj sinkronizaciju",
|
||||
|
|
@ -974,7 +748,6 @@
|
|||
"L_SYNC_INTERVAL": "Interval sinkronizacije",
|
||||
"L_SYNC_PROVIDER": "Usluga sinkronizacije",
|
||||
"LOCAL_FILE": {
|
||||
"L_SYNC_FILE_PATH_PERMISSION_VALIDATION": "Treba dozvolu za pristup datotekama",
|
||||
"L_SYNC_FOLDER_PATH": "Sync folder chemen"
|
||||
},
|
||||
"TITLE": "Sinkronizacija",
|
||||
|
|
@ -988,28 +761,18 @@
|
|||
},
|
||||
"S": {
|
||||
"ALREADY_IN_SYNC": "Već je sinkronizirano",
|
||||
"ALREADY_IN_SYNC_NO_LOCAL_CHANGES": "Nema lokalnih promjena – Već je sinkronizirano",
|
||||
"BTN_CONFIGURE": "Configure",
|
||||
"BTN_FORCE_OVERWRITE": "Fòs Overrit",
|
||||
"ERROR_DATA_IS_CURRENTLY_WRITTEN": "Done aleka se kounye a ke yo te ekri",
|
||||
"ERROR_FALLBACK_TO_BACKUP": "Greška tijekom sinkronizacije uvoza podataka. Obnavlja se lokalna sigurnosna kopija.",
|
||||
"ERROR_INVALID_DATA": "Greška tijekom sinkronizacije. Neispravni podaci",
|
||||
"ERROR_NO_REV": "Pa gen rev valab pou dosye aleka",
|
||||
"ERROR_UNABLE_TO_READ_REMOTE_DATA": "Erè pandan senkronize. Pa kapab li done aleka. Petèt ou te pèmèt chifreman ak modpas lokal ou a pa matche ak sa yo itilize pou ankripte done yo aleka?",
|
||||
"IMPORTING": "Uvoz podataka",
|
||||
"INCOMPLETE_CFG": "Autentifikacija za sinkronizaciju neuspjela. Provjeri konfiguraciju!",
|
||||
"INITIAL_SYNC_ERROR": "Izvorna sinkronizacija neuspjela",
|
||||
"SUCCESS_DOWNLOAD": "Senkrete done ki sòti nan aleka",
|
||||
"SUCCESS_IMPORT": "Podaci su uvezeni",
|
||||
"SUCCESS_VIA_BUTTON": "Podaci su uspješno sinkronizirani",
|
||||
"UNKNOWN_ERROR": "Nepoznata greška sinkronizacije: {{err}}",
|
||||
"UPLOAD_ERROR": "Nepoznata greška prenošenja podataka (Jesu li ostavke ispravne?): {{err}}"
|
||||
"UNKNOWN_ERROR": "Nepoznata greška sinkronizacije: {{err}}"
|
||||
}
|
||||
},
|
||||
"TAG": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "Stvori oznaku",
|
||||
"EDIT": "Uredi oznaku"
|
||||
"CREATE": "Stvori oznaku"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"CONFIRM_MSG": "Stavrno želiš izbrisati oznaku „{{tagName}}”? Uklonit će se iz svih zadataka. Ovo je nepovratna radnja."
|
||||
|
|
@ -1034,28 +797,16 @@
|
|||
},
|
||||
"TASK": {
|
||||
"ADD_TASK_BAR": {
|
||||
"ADD_EXISTING_TASK": "Dodaj postojeći zadatak „{{taskTitle}}”",
|
||||
"ADD_ISSUE_TASK": "Dodaj problem broj {{issueNr}} vrste {{issueType}}",
|
||||
"ADD_TASK_TO_BOTTOM_OF_BACKLOG": "Dodaj zadatak na kraj odlagališta",
|
||||
"ADD_TASK_TO_BOTTOM_OF_TODAY": "Dodaj zadatak na kraj popisa",
|
||||
"ADD_TASK_TO_TOP_OF_BACKLOG": "Dodaj zadatak na vrh odlagališta",
|
||||
"ADD_TASK_TO_TOP_OF_TODAY": "Dodaj zadatak na vrh popisa",
|
||||
"CREATE_TASK": "Stvori novi zadatak",
|
||||
"EXAMPLE": "Primjer: „Naslov nekog zadatka +ime projekta #jedna oznaka #jedna druga oznaka 10 m/3 h”",
|
||||
"START": "Za pokretanje pritisni tipku enter još jednom",
|
||||
"TOGGLE_ADD_TO_BACKLOG_TODAY": "Toggle adding task to backlog / today's list'",
|
||||
"TOGGLE_ADD_TOP_OR_BOTTOM": "Toggle adding task to top & bottom of list"
|
||||
"ADD_EXISTING_TASK": "Dodaj postojeći zadatak „{{taskTitle}}”"
|
||||
},
|
||||
"ADDITIONAL_INFO": {
|
||||
"ADD_ATTACHMENT": "Dodaj prilog",
|
||||
"ADD_SUB_TASK": "Dodaj podzadatak",
|
||||
"ATTACHMENTS": "Broj priloga ({{nr}})",
|
||||
"DUE": "Pwograme nan",
|
||||
"FROM_PARENT": "(od nadređenog)",
|
||||
"LOCAL_ATTACHMENTS": "Lokalni prilozi",
|
||||
"NOTES": "Opis",
|
||||
"PARENT": "Nadređeni zadatak",
|
||||
"REMINDER": "Podsjetnik",
|
||||
"REPEAT": "Ponovi",
|
||||
"SCHEDULE_TASK": "Terminiraj zadatak",
|
||||
"SUB_TASKS": "Broj podzadataka ({{nr}})",
|
||||
|
|
@ -1075,11 +826,8 @@
|
|||
"DELETE_REPEAT_INSTANCE": "Izbriši ponavljajuću instancu zadatka",
|
||||
"DROP_ATTACHMENT": "Ispusti ovdje za prilaganje naslovu „{{title}}”",
|
||||
"EDIT_SCHEDULED": "Uredi podsjetnik",
|
||||
"EDIT_TAGS": "Uredi oznake",
|
||||
"EDIT_TASK_TITLE": "Edit tit",
|
||||
"FOCUS_SESSION": "Kòmanse Sesyon Konsantre",
|
||||
"MARK_DONE": "Označi kao obavljen",
|
||||
"MARK_UNDONE": "Označi kao neobavljen",
|
||||
"MOVE_TO_BACKLOG": "Premjesti u odlagalište",
|
||||
"MOVE_TO_OTHER_PROJECT": "Premjesti u jedan drugi projekt",
|
||||
"MOVE_TO_REGULAR": "Premjesti u popis za danas",
|
||||
|
|
@ -1088,9 +836,7 @@
|
|||
"OPEN_ISSUE": "Otvori u pregledniku",
|
||||
"OPEN_TIME": "Praćenje vremena",
|
||||
"REMOVE_FROM_MY_DAY": "Ukloni iz „Moj dan”",
|
||||
"REPEAT_EDIT": "Uredi konfiguraciju za ponavljanje zadatka",
|
||||
"SCHEDULE": "Terminiraj zadatak",
|
||||
"SHOW_UPDATES": "Prikaži aktualiziranja",
|
||||
"TOGGLE_ATTACHMENTS": "Prikaži/Sakrij priloge",
|
||||
"TOGGLE_DETAIL_PANEL": "Prikaži/Sakrij dodatne informacije",
|
||||
"TOGGLE_DONE": "Označi kao obavljen/neobavljen",
|
||||
|
|
@ -1117,24 +863,17 @@
|
|||
"DONE": "Obavljeno",
|
||||
"DUE_TASK": "Dospio zadatak",
|
||||
"DUE_TASKS": "Dospjeli zadaci",
|
||||
"FOR_CURRENT": "Zadatak je dospio. Želiš li ga početi obrađivati?",
|
||||
"FOR_OTHER": "Zadatak je dospio. Želiš li ga početi obrađivati?",
|
||||
"FROM_PROJECT": "Od projekta: „{{title}}”",
|
||||
"FROM_TAG": "Od oznake: „{{title}}”",
|
||||
"RESCHEDULE_EDIT": "Uredi (promijeni termin)",
|
||||
"RESCHEDULE_UNTIL_TOMORROW": "Promijeni termin na sutra",
|
||||
"SNOOZE": "Odgodi",
|
||||
"SNOOZE_ALL": "Odgodi sve",
|
||||
"START": "Počni",
|
||||
"SWITCH_CONTEXT_START": "Zamijeni kontekst i počni",
|
||||
"UNSCHEDULE": "Deplase",
|
||||
"UNSCHEDULE_ALL": "Defèt tout"
|
||||
},
|
||||
"D_SCHEDULE_TASK": {
|
||||
"MOVE_TO_BACKLOG": "Premjesti zadatak u odlagalište dok se ne terminira",
|
||||
"QA_NEXT_MONTH": "Orè pou mwa pwochen",
|
||||
"QA_NEXT_WEEK": "Orè semèn pwochèn",
|
||||
"QA_REMOVE_TODAY": "Retire travay jodi a",
|
||||
"QA_TODAY": "Orè jodi a",
|
||||
"QA_TOMORROW": "Orè demen",
|
||||
"REMIND_AT": "Podsjeti",
|
||||
|
|
@ -1170,15 +909,12 @@
|
|||
"S": {
|
||||
"CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK": "Nije moguće dodijeliti projekt putem kratke sintakse za ponavljajuće zadatke!",
|
||||
"CREATED_FOR_PROJECT": "Deplase \"{{taskTitle}}\" pou pwojè \"{{projectTitle}}\"",
|
||||
"CREATED_FOR_PROJECT_ACTION": "Ale nan Pwojè",
|
||||
"DELETED": "Izbrisan je zadatak „{{title}}”",
|
||||
"FOUND_MOVE_FROM_BACKLOG": "Zadatak <strong>{{title}}</strong> je premješten iz odlagališta u popis današnjih zadataka",
|
||||
"FOUND_MOVE_FROM_OTHER_LIST": "Zadatak <strong>{{title}}</strong> je dodan iz <strong>{{contextTitle}}</strong> u trenutačni popis",
|
||||
"FOUND_RESTORE_FROM_ARCHIVE": "Obnovljeni zadatak <strong>{{title}}</strong> je povezan s problemom iz arhive",
|
||||
"LAST_TAG_DELETION_WARNING": "Pokušavaš ukloniti zadnju oznaku zadatka koji nije projekt. To nije dozvoljeno!",
|
||||
"MOVED_TO_ARCHIVE": "Deplase {{nr}} travay pou achiv",
|
||||
"MOVED_TO_PROJECT": "Deplase \"{{taskTitle}}\" pou pwojè \"{{projectTitle}}\"",
|
||||
"MOVED_TO_PROJECT_ACTION": "Ale nan Pwojè",
|
||||
"REMINDER_ADDED": "Terminirani zadatak „{{title}}”",
|
||||
"REMINDER_DELETED": "Izbrisan je podjsetnik za zadatak",
|
||||
"REMINDER_UPDATED": "Aktualiziran je podjsetnik za zadatak „{{title}}”",
|
||||
|
|
@ -1246,7 +982,6 @@
|
|||
"C_YEAR": "Godina",
|
||||
"DEFAULT_ESTIMATE": "Standardna procjena",
|
||||
"FRIDAY": "Petak",
|
||||
"IS_ADD_TO_BOTTOM": "Premjesti zadatak na kraj popisa",
|
||||
"MONDAY": "Ponedjeljak",
|
||||
"NOTES": "Standardne bilješke",
|
||||
"ORDER": "Redoslijed",
|
||||
|
|
@ -1298,7 +1033,6 @@
|
|||
"SCHEDULED_THIS_WEEK": "Semèn sa a",
|
||||
"SCHEDULED_TODAY": "Jodi a",
|
||||
"SCHEDULED_TOMORROW": "Demen",
|
||||
"SORT_BY": "Klase pa",
|
||||
"SORT_CREATION_DATE": "Dat kreyasyon",
|
||||
"SORT_DEFAULT": "Default",
|
||||
"SORT_NAME": "Fe-apel",
|
||||
|
|
@ -1307,8 +1041,7 @@
|
|||
"TIME_2HOUR": "> 2 èdtan",
|
||||
"TIME_10MIN": "> 10 minit",
|
||||
"TIME_30MIN": "> 30 minit",
|
||||
"TIME_SPENT": "Tan pase",
|
||||
"TITLE": "Customize Travay View"
|
||||
"TIME_SPENT": "Tan pase"
|
||||
}
|
||||
},
|
||||
"TIME_TRACKING": {
|
||||
|
|
@ -1338,7 +1071,6 @@
|
|||
},
|
||||
"D_TRACKING_REMINDER": {
|
||||
"CREATE_AND_TRACK": "<em>Stvori</em> i prati do",
|
||||
"IDLE_FOR": "Vrijeme tvoje neaktivnosti:",
|
||||
"NOTIFICATION_TITLE": "Swiv tan ou!",
|
||||
"TASK": "Zadatak",
|
||||
"TRACK_TO": "Prati do:",
|
||||
|
|
@ -1350,7 +1082,6 @@
|
|||
"DAYS_WORKED": "Broj radnih dana:",
|
||||
"MONTH_WORKED": "Radni mjesec:",
|
||||
"REPEATING_TASK": "Ponavljanje zadatka",
|
||||
"RESTORE_TASK_FROM_ARCHIVE": "Obnovi zadatak iz arhive",
|
||||
"TASKS": "Zadaci",
|
||||
"TOTAL_TIME": "Ukupno utrošeno vrijeme:",
|
||||
"WEEK_NR": "{{nr}}. tjedan",
|
||||
|
|
@ -1442,26 +1173,20 @@
|
|||
"HIDE": "Sakrij",
|
||||
"ICON_INP_DESCRIPTION": "Tout emoji utf-8 yo sipòte tou!",
|
||||
"INBOX_PROJECT_TITLE": "Bwat resepsyon",
|
||||
"LOGIN": "Prijava",
|
||||
"LOGOUT": "Odjava",
|
||||
"MINUTES": "{{m}} min",
|
||||
"MOVE_BACKWARD": "Deplase Backward",
|
||||
"MOVE_FORWARD": "Avanse pou pi devan",
|
||||
"NEXT": "Dalje",
|
||||
"NO_CON": "Trenutačno nemaš vezu s internetom. Ponovo se poveži s internetom.",
|
||||
"NONE": "Ništa",
|
||||
"OK": "U redu",
|
||||
"OVERDUE": "Depase dat",
|
||||
"PREVIOUS": "Prethodno",
|
||||
"REMOVE": "Ukloni",
|
||||
"RESET": "Obnovi",
|
||||
"SAVE": "Spremi",
|
||||
"SUBMIT": "Pošalji",
|
||||
"TITLE": "Naslov",
|
||||
"TODAY_TAG_TITLE": "Danas",
|
||||
"TRACKING_INTERVAL_DESCRIPTION": "Track tan lè l sèvi avèk entèval sa a an milisgond. Ou ta ka vle chanje sa a pou diminye ekriti disk. Gade pwoblèm #2355.",
|
||||
"UNDO": "Poništi",
|
||||
"UPDATE": "Aktualiziraj",
|
||||
"WITHOUT_PROJECT": "Bez projekta",
|
||||
"YESTERDAY": "Jučer"
|
||||
},
|
||||
|
|
@ -1475,9 +1200,7 @@
|
|||
"CALENDARS": {
|
||||
"BROWSER_WARNING": "<b>Ovo vjerojatno NEĆE funkcionirati s verzijom preglednika Super Productivity.<br/> Za korištenje ove funkcije <a href=\"https://super-productivity.com/download/\">preuzmi desktop verziju</a>!</b>",
|
||||
"CAL_PATH": "Url iCal izvora",
|
||||
"CAL_PROVIDERS": "Pružatelji kalendara (eksperimentalno i opcionalno)",
|
||||
"CHECK_UPDATES": "Traži eksterna aktualiziranja svakih X",
|
||||
"DEFAULT_PROJECT": "Standardni projekt za dodane zadatke kalendara",
|
||||
"HELP": "Kalendare za podsjetnik možeš integrirati i dodati ih kao zadatke unutar Super Productivity. Integracija radi pomoću iCal formata. Da bi ovo funkcioniralo, tvoji kalendari moraju biti dostupni putem interneta ili putem sustava datoteka.",
|
||||
"SHOW_BANNER_THRESHOLD": "Prikaži obavijest X prije događaja (prazno za deaktivirano)"
|
||||
},
|
||||
|
|
@ -1487,7 +1210,6 @@
|
|||
},
|
||||
"FOCUS_MODE": {
|
||||
"HELP": "Modus fokusa otvara jednostavan ekran koji ti pomaže pri fokusiranju na tvoj zadatak.",
|
||||
"L_ALWAYS_OPEN_FOCUS_MODE": "Uvijek otvori modus fokusa, kada pratiš",
|
||||
"L_SKIP_PREPARATION_SCREEN": "Preskoči ekran pripreme (rastezanje itd.)",
|
||||
"TITLE": "Modus fokusa"
|
||||
},
|
||||
|
|
@ -1539,7 +1261,6 @@
|
|||
"TASK_MOVE_TO_PROJECT": "Otvori premještanje zadatka u izbornik projekta",
|
||||
"TASK_OPEN_CONTEXT_MENU": "Otvori konteksni izbornik zadataka",
|
||||
"TASK_OPEN_ESTIMATION_DIALOG": "Uredi procjenu / utrošeno vrijeme",
|
||||
"TASK_PLAN_FORDAY": "Planifye pou jounen an",
|
||||
"TASK_SCHEDULE": "Terminiraj zadatak",
|
||||
"TASK_SHORTCUTS": "Zadaci",
|
||||
"TASK_SHORTCUTS_INFO": "Sljedeći prečaci primijenjuju se na trenutačno odabrani zadatak (odabran pomoću tabulatora ili miša).",
|
||||
|
|
@ -1547,7 +1268,6 @@
|
|||
"TASK_TOGGLE_DONE": "Uključi/Isključi obavljeno",
|
||||
"TITLE": "Tipkovni prečaci",
|
||||
"TOGGLE_BACKLOG": "Prikaži/Sakrij odlagalište",
|
||||
"TOGGLE_BOOKMARKS": "Prikaži/Sakrij traku straničnika",
|
||||
"TOGGLE_ISSUE_PANEL": "Montre/Kache Panel Pwoblèm",
|
||||
"TOGGLE_PLAY": "Počni/Prekini zadatak",
|
||||
"TOGGLE_SIDE_NAV": "Prikaži i fokusiraj/Sakrij bočnu navigaciju",
|
||||
|
|
@ -1594,13 +1314,11 @@
|
|||
"IS_DARK_MODE": "Tamni modus",
|
||||
"IS_DISABLE_ANIMATIONS": "Deaktiviraj sve animacije",
|
||||
"IS_DISABLE_CELEBRATION": "Onemogući proslavu u dnevnom sažetku",
|
||||
"IS_HIDE_NAV": "Sakrij navigaciju sve dok ne prijeđeš mišem preko naslova (samo za desktop računala)",
|
||||
"IS_MINIMIZE_TO_TRAY": "Sklopi u programsku traku (samo za desktop računala)",
|
||||
"IS_SHOW_TIP_LONGER": "Montre konsèy pwodiktivite sou app kòmanse yon ti tan ankò",
|
||||
"IS_TRAY_SHOW_CURRENT_COUNTDOWN": "Montre dekont aktyèl la nan meni an plato / estati (Desktop mac sèlman)",
|
||||
"IS_TRAY_SHOW_CURRENT_TASK": "Prikaži trenutačni zadatak u donjoj traci sustava / u izborniku stanja (samo mac/windows desktop računala)",
|
||||
"IS_TURN_OFF_MARKDOWN": "Isključi markdown obradu za bilješke",
|
||||
"IS_USE_MINIMAL_SIDE_NAV": "Sèvi ak ba navigasyon minim (montre sèlman ikon)",
|
||||
"START_OF_NEXT_DAY": "Vrijeme početka sljedećeg dana",
|
||||
"START_OF_NEXT_DAY_HINT": "U koje vrijeme (sat) želiš brojiti početak sljedećeg dana. Standardno je postavljena ponoć, što je 0.",
|
||||
"TASK_NOTES_TPL": "Predložak za opis zadatka",
|
||||
|
|
@ -1704,14 +1422,12 @@
|
|||
},
|
||||
"GLOBAL_SNACK": {
|
||||
"COPY_TO_CLIPPBOARD": "Kopirano u međuspremnik",
|
||||
"ERR_COMPRESSION": "Greška za komprimiranje sučelja",
|
||||
"FILE_DOWNLOADED": "{{fileName}} preuzeto",
|
||||
"FILE_DOWNLOADED_BTN": "Otvori mapu",
|
||||
"NAVIGATE_TO_TASK_ERR": "Neuspjelo fokusiranje na zadatak. Jesi li ga izrisao/la?",
|
||||
"PERSISTENCE_DISALLOWED": "Podaci se neće trajno zadržati. Imaj na umu da to može dovesti do gubitka podataka!!",
|
||||
"PERSISTENCE_ERROR": "Greška prilikom traženja zadržavanja podataka: {{err}}",
|
||||
"RUNNING_X": "Pokreće se „{{str}}”.",
|
||||
"SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG": "{{keyCombo}} pritisnut, ali je prečac za otvaranje straničnika dostupan samo u sadržaju projekta."
|
||||
"RUNNING_X": "Pokreće se „{{str}}”."
|
||||
},
|
||||
"GPB": {
|
||||
"ASSETS": "Učitavanje resursa …",
|
||||
|
|
@ -1748,24 +1464,14 @@
|
|||
"SYNC": "Kako: Konfiguriraj sinkronizaciju"
|
||||
},
|
||||
"METRICS": "Mjerni podaci",
|
||||
"NO_PROJECT_INFO": "Pa gen pwojè ki disponib. Ou ka kreye yon nouvo pwojè pa klike sou bouton \"Kreye Pwojè\" la.",
|
||||
"NO_TAG_INFO": "Trenutačno nema oznaka. Oznake možeš dodati unosom `#yourTagName` prilikom dodavanja ili uređivanja zadataka.",
|
||||
"NOTES": "Bilješke",
|
||||
"NOTES_PANEL_INFO": "Bilješke se mogu prikazati samo u prikazima vremenske trake i uobičajenih popisa zadataka.",
|
||||
"PLANNER": "Planifikatè",
|
||||
"PROCRASTINATE": "Odugovlači",
|
||||
"PROJECT_MENU": "Izbornik projekta",
|
||||
"PROJECT_SETTINGS": "Postavke projekta",
|
||||
"PROJECTS": "Projekti",
|
||||
"QUICK_HISTORY": "Brza povijest",
|
||||
"SCHEDULE": "Orè",
|
||||
"SEARCH": "Fouye",
|
||||
"SETTINGS": "Postavke",
|
||||
"SHOW_SEARCH_BAR": "Prikaži traku pretrage",
|
||||
"TAGS": "Oznake",
|
||||
"TASK_LIST": "Popis zadataka",
|
||||
"TASKS": "Zadaci",
|
||||
"TOGGLE_SHOW_BOOKMARKS": "Prikaži/Sakrij straničnike",
|
||||
"TOGGLE_SHOW_ISSUE_PANEL": "Montre/Kache Panel Pwoblèm",
|
||||
"TOGGLE_SHOW_NOTES": "Prikaži/Sakrij bilješke projekta",
|
||||
"TOGGLE_TRACK_TIME": "Počni/Prekini praćenje vremena",
|
||||
|
|
@ -1819,14 +1525,12 @@
|
|||
},
|
||||
"PS": {
|
||||
"GLOBAL_SETTINGS": "Globalne postavke",
|
||||
"ISSUE_INTEGRATION": "Problem s integracijom",
|
||||
"PRIVACY_POLICY": "Politika privatnosti",
|
||||
"PRODUCTIVITY_HELPER": "Pomoćnik produktivnosti",
|
||||
"PROJECT_SETTINGS": "Postavke određenog projekta",
|
||||
"PROVIDE_FEEDBACK": "Pošalji povratne informacije",
|
||||
"SYNC_EXPORT": "Sinkronizacija i izvoz",
|
||||
"TAG_SETTINGS": "Postavke određene oznake",
|
||||
"TOGGLE_DARK_MODE": "Uklj./Isklj. tamni modus"
|
||||
"TAG_SETTINGS": "Postavke određene oznake"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"NO_REPEATABLE_TASKS": "Trenutačno nema ponavljajućih zadataka. Zadatak možeš terminirati odabirom „Ponovi zadatak” u bočnoj ploči zadatka. Za otvaranje pritisni najdesniju ikonu koja će se prikazati kad pređeš mišem preko zadatka (ili jednostavno dodirni zadatak na mobitelu).",
|
||||
|
|
@ -1834,26 +1538,7 @@
|
|||
"NO_SCHEDULED_TITLE": "Travay ki pwograme pou jounen an",
|
||||
"REPEATED_TASKS": "Ponavljajući zadaci",
|
||||
"SCHEDULED_TASKS": "Terminirani zadaci",
|
||||
"SCHEDULED_TASKS_WITH_TIME": "Travay pwograme ak rapèl",
|
||||
"START_TASK": "Započni zadatak i ukloni podsjetnika"
|
||||
},
|
||||
"THEMES": {
|
||||
"amber": "jantar",
|
||||
"blue": "plava",
|
||||
"blue-grey": "plavosiva",
|
||||
"cyan": "cijan",
|
||||
"deep-orange": "tamnonarančasta",
|
||||
"deep-purple": "tamnoljubičasta",
|
||||
"green": "zelena",
|
||||
"indigo": "indigo",
|
||||
"light-blue": "svjetloplava",
|
||||
"light-green": "svjetlozelena",
|
||||
"lime": "limunasta",
|
||||
"pink": "ružičasta",
|
||||
"purple": "ljubičasta",
|
||||
"SELECT_THEME": "Odaberi temu",
|
||||
"teal": "plavozelena",
|
||||
"yellow": "žuta"
|
||||
"SCHEDULED_TASKS_WITH_TIME": "Travay pwograme ak rapèl"
|
||||
},
|
||||
"USER_PROFILES": {
|
||||
"ACTIVE": "Aktivan",
|
||||
|
|
@ -1867,21 +1552,18 @@
|
|||
"EXISTING_PROFILES": "Postojeći profili",
|
||||
"EXPORT_PROFILE": "Izvezi profil",
|
||||
"MANAGE_PROFILES": "Upravljaj profilima...",
|
||||
"OPEN_PROFILES_FOLDER": "Otvori mapu profila",
|
||||
"PROFILE_NAME": "Ime profila",
|
||||
"PROFILE_NAME_PLACEHOLDER": "npr. Posao, Osobno",
|
||||
"RENAME": "Preimenuj",
|
||||
"SAVE": "Spremi"
|
||||
},
|
||||
"V": {
|
||||
"E_1TO10": "Upiši vrijednost između 1 i 10",
|
||||
"E_DATETIME": "Upisana vrijednost nije vrijeme/datum!",
|
||||
"E_DURATION": "Tanpri antre nan yon dire valab (e.g. 1h)",
|
||||
"E_MAX": "Ne bi trebala biti veća od {{val}}",
|
||||
"E_MAX_LENGTH": "Trebala bi sadržati najviše {{val}} znakova",
|
||||
"E_MIN": "Trebala bi biti manja od {{val}}",
|
||||
"E_MIN_LENGTH": "Trebala bi sadržati barem {{val}} znakova",
|
||||
"E_PATTERN": "Neispravan unos",
|
||||
"E_REQUIRED": "Ovo je obavezno polje"
|
||||
},
|
||||
"WW": {
|
||||
|
|
@ -1892,10 +1574,7 @@
|
|||
"DONE_TASKS_IN_ARCHIVE": "Gen kounye a pa gen okenn travay fè isit la, men gen kèk achiv deja achiv.",
|
||||
"ESTIMATE_REMAINING": "Preostalo procijenjeno vrijeme:",
|
||||
"FINISH_DAY": "Završi dan",
|
||||
"FINISH_DAY_FOR_PROJECT": "Završi dan za ovaj projekt",
|
||||
"FINISH_DAY_FOR_TAG": "Završi dan za ovu oznaku",
|
||||
"FINISH_DAY_TOOLTIP": "Evaluiraj dan, premjesti sve obavljene zadatke u arhivu (opcionalno) i/ili planiraj sljedeći dan.",
|
||||
"HELP_PROCRASTINATION": "Upomoć, odugovlačim!",
|
||||
"MOVE_DONE_TO_ARCHIVE": "Deplase fè achiv",
|
||||
"NO_DONE_TASKS": "Kounye a pa gen okenn travay ki fèt kounye a",
|
||||
"NO_PLANNED_TASK_ALL_DONE": "tout travay yo fè",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,15 +1,4 @@
|
|||
{
|
||||
"ANDROID": {
|
||||
"NOTIFICATIONS": {
|
||||
"SYNC_CONFLICT_MSG": "확인 후 조치 방법을 결정하세요.",
|
||||
"SYNC_CONFLICT_TITLE": "동기화 충돌이 발생했습니다."
|
||||
},
|
||||
"PERMANENT_NOTIFICATION_MSGS": {
|
||||
"INITIAL": "앱이 백그라운드에서 실행되어 동기화를 허용하는 경우 활성화된 경우",
|
||||
"NO_ACTIVE_TASKS": "활성 작업 없음",
|
||||
"SYNCING": "동기화"
|
||||
}
|
||||
},
|
||||
"APP": {
|
||||
"B_INSTALL": {
|
||||
"IGNORE": "무시",
|
||||
|
|
@ -17,8 +6,6 @@
|
|||
"MSG": "PWA로 Super Productivity를 설치하시겠습니까?"
|
||||
},
|
||||
"B_OFFLINE": "인터넷 연결이 끊어졌습니다. 문제 제공자 데이터 동기화 및 요청이 작동하지 않습니다.",
|
||||
"UPDATE_MAIN_MODEL": "슈퍼 생산성이 대폭 업데이트되었습니다! 데이터에 대한 일부 마이그레이션이 필요합니다. 이로 인해 데이터가 이전 버전의 앱과 호환되지 않습니다.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "선택된 모델 업데이트가 없습니다. 모델 업그레이드를 수행하지 않으려면 마지막 버전으로 다운그레이드해야합니다.",
|
||||
"UPDATE_WEB_APP": "새 버전을 사용할 수 있습니다. 새 버전을 로드하시겠습니까?"
|
||||
},
|
||||
"BL": {
|
||||
|
|
@ -32,11 +19,7 @@
|
|||
"RESTORE_STRAY_BACKUP": "마지막 동기화 중에 오류가 발생했을 수 있습니다. 마지막 백업을 복원 하시겠습니까?"
|
||||
},
|
||||
"DATETIME_SCHEDULE": {
|
||||
"LATER_TODAY": "나중에 오늘",
|
||||
"NEXT_WEEK": "다음 주",
|
||||
"PLACEHOLDER": "날짜를 선택하십시오",
|
||||
"PRESS_ENTER_AGAIN": "Enter를 다시 눌러 저장하십시오.",
|
||||
"TOMORROW": "내일"
|
||||
"PRESS_ENTER_AGAIN": "Enter를 다시 눌러 저장하십시오."
|
||||
},
|
||||
"F": {
|
||||
"ATTACHMENT": {
|
||||
|
|
@ -44,7 +27,6 @@
|
|||
"ADD_ATTACHMENT": "첨부 파일 추가",
|
||||
"EDIT_ATTACHMENT": "첨부 파일 편집",
|
||||
"LABELS": {
|
||||
"FILE": "파일 경로",
|
||||
"IMG": "이미지",
|
||||
"LINK": "URL"
|
||||
},
|
||||
|
|
@ -60,7 +42,6 @@
|
|||
"DEFAULT": {
|
||||
"DONE": "수행",
|
||||
"EISENHAUER_MATRIX": "아이젠하우어 매트릭스",
|
||||
"IMPORTANT": "중요하다",
|
||||
"IN_PROGRESS": "진행 중",
|
||||
"KANBAN": "칸반",
|
||||
"NOT_URGENT_IMPORTANT": "긴급하지 않고 중요하지 않습니다.",
|
||||
|
|
@ -97,9 +78,6 @@
|
|||
}
|
||||
},
|
||||
"CALDAV": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "프로젝트 용 CalDav 설정"
|
||||
},
|
||||
"FORM": {
|
||||
"CALDAV_CATEGORY_FILTER": "문제를 필터링 할 카테고리 (없으면 비워 둡니다)",
|
||||
"CALDAV_PASSWORD": "CalDav 비밀번호",
|
||||
|
|
@ -109,28 +87,7 @@
|
|||
"IS_TRANSITION_ISSUES_ENABLED": "작업 완료시 CalDav 할 일을 자동으로 완료"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>여기에서 일일 계획 보기의 작업 생성 패널에서 특정 프로젝트에 대해 완료되지 않은 CalDav 할 일을 나열하도록 SuperProductivity를 구성할 수 있습니다. 제안 사항으로 나열되며 할 일에 대한 링크와 이에 대한 추가 정보를 제공합니다.</p> <p>또한 완료되지 않은 모든 할 일을 작업 백로그에 자동으로 추가하고 동기화할 수 있습니다.</p><p>모바일 및 웹의 nextcloud에서 작동하도록 하려면 nextcloud 앱 <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword<a>를 통해 \"https://app.super-productivity.com\"을 허용 목록에 추가해야 할 수 있습니다.</p>",
|
||||
"TITLE": "CalDav"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "담당자",
|
||||
"AT": "에",
|
||||
"ATTACHMENTS": "첨부 파일",
|
||||
"CHANGED": "변경",
|
||||
"COMMENTS": "코멘트",
|
||||
"COMPONENTS": "구성 요소",
|
||||
"DESCRIPTION": "기술",
|
||||
"LABELS": "카테고리",
|
||||
"LIST_OF_CHANGES": "변경 사항 목록",
|
||||
"MARK_AS_CHECKED": "체크 된대로 업데이트 표시",
|
||||
"ON": "에",
|
||||
"RELATED": "관련",
|
||||
"STATUS": "상태",
|
||||
"STORY_POINTS": "스토리 포인트",
|
||||
"SUB_TASKS": "하위",
|
||||
"SUMMARY": "개요",
|
||||
"WORKLOG": "작업 로그",
|
||||
"WRITE_A_COMMENT": "덧글 써"
|
||||
"HELP": "<p>여기에서 일일 계획 보기의 작업 생성 패널에서 특정 프로젝트에 대해 완료되지 않은 CalDav 할 일을 나열하도록 SuperProductivity를 구성할 수 있습니다. 제안 사항으로 나열되며 할 일에 대한 링크와 이에 대한 추가 정보를 제공합니다.</p> <p>또한 완료되지 않은 모든 할 일을 작업 백로그에 자동으로 추가하고 동기화할 수 있습니다.</p><p>모바일 및 웹의 nextcloud에서 작동하도록 하려면 nextcloud 앱 <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword<a>를 통해 \"https://app.super-productivity.com\"을 허용 목록에 추가해야 할 수 있습니다.</p>"
|
||||
},
|
||||
"S": {
|
||||
"CALENDAR_NOT_FOUND": "CalDav : 캘린더 \"{{calendarName}}\"을 (를) 찾을 수 없음",
|
||||
|
|
@ -141,7 +98,6 @@
|
|||
"CALENDARS": {
|
||||
"BANNER": {
|
||||
"ADD_AS_TASK": "작업으로 추가",
|
||||
"FOCUS_TASK": "집중 작업",
|
||||
"TXT": "<strong>{{title}}</strong> 는 <strong>에서 시작 {{start}}</strong>!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> 는 <strong>에서 시작 {{start}}</strong>!<br> (및 {{nrOfOtherBanners}} 개의 다른 이벤트가 마감됨)",
|
||||
"TXT_PAST": "<strong>{{title}}</strong> 는 <strong>에서 시작 {{start}}</strong>!",
|
||||
|
|
@ -175,10 +131,6 @@
|
|||
},
|
||||
"DROPBOX": {
|
||||
"S": {
|
||||
"ACCESS_TOKEN_ERROR": "Dropbox : 인증 코드에서 액세스 토큰을 생성 할 수 없습니다",
|
||||
"ACCESS_TOKEN_GENERATED": "Dropbox : 인증 코드에서 생성 된 액세스 토큰",
|
||||
"AUTH_ERROR": "보관 용 계정 : 잘못된 액세스 토큰 제공",
|
||||
"AUTH_ERROR_ACTION": "토큰 변경",
|
||||
"OFFLINE": "보관 용 계정 : 오프라인 상태이므로 동기화 할 수 없습니다",
|
||||
"SYNC_ERROR": "보관 용 계정 : 동기화 중 오류",
|
||||
"UNABLE_TO_GENERATE_PKCE_CHALLENGE": "Dropbox: PKCE 챌린지를 생성할 수 없습니다."
|
||||
|
|
@ -195,36 +147,25 @@
|
|||
"TO_FOCUS_OVERLAY": "오버레이에 초점을 맞추려면"
|
||||
},
|
||||
"BACK_TO_PLANNING": "계획으로 돌아가기",
|
||||
"CONGRATS": "이 세션을 완료해 주셔서 축하드립니다!",
|
||||
"CONTINUE_FOCUS_SESSION": "포커스 세션 계속하기",
|
||||
"COUNTDOWN": "카운트다운",
|
||||
"FINISH_TASK_AND_SELECT_NEXT": "작업 완료 후 다음 선택",
|
||||
"FLOWTIME": "플로우 타임",
|
||||
"FOR_TASK": "작업용",
|
||||
"GET_READY": "집중 세션을 준비하세요!",
|
||||
"GO_TO_PROCRASTINATION": "미루는 일이 있을 때 도움 받기",
|
||||
"GOGOGO": "가자, 가자, 가자!!!",
|
||||
"NEXT": "다음",
|
||||
"ON": "켜짐",
|
||||
"OPEN_ISSUE_IN_BROWSER": "브라우저에서 열린 이슈",
|
||||
"PREP_GET_MENTALLY_READY": "집중력과 생산성을 높이기 위한 정신적 준비",
|
||||
"PREP_SIT_UPRIGHT": "똑바로 앉거나 서기",
|
||||
"PREP_STRETCH": "가벼운 스트레칭하기",
|
||||
"SELECT_ANOTHER_TASK": "다른 작업 선택",
|
||||
"SELECT_TASK": "집중할 작업 선택",
|
||||
"SESSION_COMPLETED": "포커스 세션 완료!",
|
||||
"SET_FOCUS_SESSION_DURATION": "포커스 세션 기간 설정",
|
||||
"SHOW_HIDE_NOTES_AND_ATTACHMENTS": "작업 노트 및 첨부 파일 표시/숨기기",
|
||||
"START_FOCUS_SESSION": "포커스 세션 시작",
|
||||
"START_NEXT_FOCUS_SESSION": "다음 포커스 세션 시작",
|
||||
"WORKED_FOR": "근무처"
|
||||
},
|
||||
"GITEA": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "프로젝트용 Gitea 설정"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "사용자 아이디(예: 직접 변경 사항을 필터링하기 위해)",
|
||||
"HOST": "호스트(예: https://try.gitea.io)",
|
||||
"REPO_FULL_NAME": "사용자 이름 또는 조직 이름/프로젝트",
|
||||
"REPO_FULL_NAME_DESCRIPTION": "브라우저에서 프로젝트를 볼 때 URL의 일부로 찾을 수 있습니다.",
|
||||
|
|
@ -235,12 +176,10 @@
|
|||
"TOKEN": "액세스 토큰"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>여기에서 일일 계획 보기의 작업 만들기 패널에서 특정 리포지토리에 대해 열려 있는 Gitea 이슈를 나열하도록 SuperProductivity를 구성할 수 있습니다. 이슈는 제안 사항으로 나열되며 이슈에 대한 링크와 자세한 정보를 제공합니다.</p> <p>또한 열려 있는 모든 이슈를 자동으로 추가하고 가져올 수 있습니다.</p><p>사용량 제한을 통과하고 액세스하려면 액세스 토큰을 제공할 수 있습니다.",
|
||||
"TITLE": "Gitea"
|
||||
"HELP": "<p>여기에서 일일 계획 보기의 작업 만들기 패널에서 특정 리포지토리에 대해 열려 있는 Gitea 이슈를 나열하도록 SuperProductivity를 구성할 수 있습니다. 이슈는 제안 사항으로 나열되며 이슈에 대한 링크와 자세한 정보를 제공합니다.</p> <p>또한 열려 있는 모든 이슈를 자동으로 추가하고 가져올 수 있습니다.</p><p>사용량 제한을 통과하고 액세스하려면 액세스 토큰을 제공할 수 있습니다."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "담당자",
|
||||
"AT": "에서",
|
||||
"DESCRIPTION": "설명",
|
||||
"LABELS": "레이블",
|
||||
"MARK_AS_CHECKED": "업데이트 확인됨으로 표시",
|
||||
|
|
@ -248,15 +187,9 @@
|
|||
"STATUS": "상태",
|
||||
"SUMMARY": "요약",
|
||||
"WRITE_A_COMMENT": "댓글 작성"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Gitea: 알 수 없는 오류 {{statusCode}} {{errorMsg}}. API 속도 제한이 초과되었나요?"
|
||||
}
|
||||
},
|
||||
"GITHUB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "프로젝트를 위한 GitHub 설정"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "사용자 이름 (예 : 혼자서 변경 사항을 필터링)",
|
||||
"INVALID_TOKEN_MESSAGE": "유효한 GitHub 토큰이 아닙니다. \"ghp_\"로 시작해야 합니다.",
|
||||
|
|
@ -265,8 +198,7 @@
|
|||
"TOKEN": "액세스 토큰"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>여기서는 일일 계획 보기의 작업 만들기 패널에서 특정 리포지토리에 대한 열린 GitHub 문제를 나열하도록 SuperProductivity를 구성할 수 있습니다. 제안으로 나열 되며 문제에 대 한 링크 뿐만 아니라 그것에 대 한 자세한 정보를 제공 합니다.</p> <p>또한 자동으로 추가하고 작업 백로그에 열려있는 모든 문제를 동기화 할 수 있습니다.</p>",
|
||||
"TITLE": "Github"
|
||||
"HELP": "<p>여기서는 일일 계획 보기의 작업 만들기 패널에서 특정 리포지토리에 대한 열린 GitHub 문제를 나열하도록 SuperProductivity를 구성할 수 있습니다. 제안으로 나열 되며 문제에 대 한 링크 뿐만 아니라 그것에 대 한 자세한 정보를 제공 합니다.</p> <p>또한 자동으로 추가하고 작업 백로그에 열려있는 모든 문제를 동기화 할 수 있습니다.</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "담당자",
|
||||
|
|
@ -287,9 +219,6 @@
|
|||
}
|
||||
},
|
||||
"GITLAB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "프로젝트를위한 GitLab 설정"
|
||||
},
|
||||
"DIALOG_SUBMIT_WORKLOG": {
|
||||
"PAST_DAY_INFO": "미리 채워진 기간에는 지난 날짜의 추적되지 않은 데이터가 포함되어 있습니다.",
|
||||
"T_ALREADY_TRACKED": "이미 추적 중",
|
||||
|
|
@ -318,8 +247,7 @@
|
|||
"TOKEN": "액세스 토큰"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p> 일별 계획보기의 작업 생성 패널에서 특정 프로젝트에 대해 열린 GitLab (온라인 버전 또는 자체 호스팅 인스턴스) 문제를 나열하도록 SuperProductivity를 구성 할 수 있습니다. 제안으로 표시되며 문제에 대한 자세한 정보뿐만 아니라 문제에 대한 링크를 제공합니다. </p> <p> 또한 열려있는 모든 문제를 작업 백 로그에 자동으로 추가하고 동기화 할 수 있습니다. </p>",
|
||||
"TITLE": "GitLab"
|
||||
"HELP": "<p> 일별 계획보기의 작업 생성 패널에서 특정 프로젝트에 대해 열린 GitLab (온라인 버전 또는 자체 호스팅 인스턴스) 문제를 나열하도록 SuperProductivity를 구성 할 수 있습니다. 제안으로 표시되며 문제에 대한 자세한 정보뿐만 아니라 문제에 대한 링크를 제공합니다. </p> <p> 또한 열려있는 모든 문제를 작업 백 로그에 자동으로 추가하고 동기화 할 수 있습니다. </p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "담당자",
|
||||
|
|
@ -351,20 +279,14 @@
|
|||
"ATTACHMENTS": "첨부 파일",
|
||||
"AUTHOR": "저자",
|
||||
"CATEGORY": "범주",
|
||||
"CHANGED": "변경",
|
||||
"COMMENTS": "코멘트",
|
||||
"COMPONENTS": "구성 요소",
|
||||
"DESCRIPTION": "묘사",
|
||||
"DONE_RATIO": "완료 비율",
|
||||
"DUE_DATE": "마감일",
|
||||
"LABELS": "레이블",
|
||||
"LAST_COMMENT": "마지막 코멘트",
|
||||
"LIST_OF_CHANGES": "변경 사항 목록",
|
||||
"LOAD_ALL_COMMENTS": "모든 {{nr}} 댓글 불러오기",
|
||||
"LOAD_DESCRIPTION_AND_ALL_COMMENTS": "설명 &모든 의견 불러오기",
|
||||
"LOCATION": "위치",
|
||||
"MARK_AS_CHECKED": "업데이트를 선택된 것으로 표시",
|
||||
"ON": "에",
|
||||
"PRIORITY": "우선권",
|
||||
"RELATED": "관련",
|
||||
"START": "시작하다",
|
||||
|
|
@ -375,8 +297,7 @@
|
|||
"TIME_SPENT": "소요 시간",
|
||||
"TYPE": "형",
|
||||
"VERSION": "버전",
|
||||
"WORKLOG": "작업 로그",
|
||||
"WRITE_A_COMMENT": "덧글 써"
|
||||
"WORKLOG": "작업 로그"
|
||||
},
|
||||
"S": {
|
||||
"ERR_GENERIC": "{{issueProviderName}} 오류입니다: {{errTxt}}",
|
||||
|
|
@ -384,13 +305,9 @@
|
|||
"ERR_NOT_CONFIGURED": "{{issueProviderName}}: 제대로 구성되지 않음",
|
||||
"IMPORTED_MULTIPLE_ISSUES": "{{issueProviderName}}: 백로그에 {{nr}} 개의 새 {{issuesStr}} 가져오기",
|
||||
"IMPORTED_SINGLE_ISSUE": "{{issueProviderName}}: {{issueStr}} \"{{issueTitle}}\"을(를) 백로그로 가져왔습니다.",
|
||||
"ISSUE_DELETED_OR_CLOSED": "{{issueProviderName}}: {{issueStrC}} \"{{issueTitle}}\"이(가) 삭제되었거나 닫힌 것 같습니다.",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "{{issueProviderName}}: 업데이트 필요 없음",
|
||||
"ISSUE_UPDATE_MULTIPLE": "{{issueProviderName}}: {{nr}} {{issuesStr}}에 대한 업데이트된 데이터",
|
||||
"ISSUE_UPDATE_SINGLE": "{{issueProviderName}}: \"{{issueTitle}}\"에 대한 업데이트된 데이터",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "{{issueProviderName}}: \"{{issueTitle}}\"에 대한 업데이트된 데이터",
|
||||
"MISSING_ISSUE_DATA": "{{issueProviderName}}: 누락된 {{issueStr}} 데이터가 있는 작업을 찾았습니다. 다시 로드 중.",
|
||||
"NEW_COMMENT": "{{issueProviderName}}: \"{{issueTitle}}\"에 대한 새 댓글",
|
||||
"POLLING_BACKLOG": "{{issueProviderName}}: 새 {{issuesStr}}에 대한 폴링",
|
||||
"POLLING_CHANGES": "{{issueProviderName}}: {{issuesStr}}에 대한 폴링 변경 사항"
|
||||
}
|
||||
|
|
@ -427,8 +344,7 @@
|
|||
"CURRENT_ASSIGNEE": "현재 담당자 :",
|
||||
"CURRENT_STATUS": "현재 상태:",
|
||||
"TASK_NAME": "작업 이름:",
|
||||
"TITLE": "Jira : 업데이트 상태",
|
||||
"UPDATE_STATUS": "업데이트 상태"
|
||||
"TITLE": "Jira : 업데이트 상태"
|
||||
},
|
||||
"DIALOG_WORKLOG": {
|
||||
"CHECKBOXES": {
|
||||
|
|
@ -463,8 +379,7 @@
|
|||
"HOST": "호스트 (예 : http://my-host.de:1234)",
|
||||
"PASSWORD": "토큰 / 비밀번호",
|
||||
"USE_PAT": "비밀번호 대신 개인 액세스 토큰 사용",
|
||||
"USER_NAME": "이메일 / 사용자 이름",
|
||||
"WONKY_COOKIE_MODE": "Wonky Cookie Fallback Authentication (데스크톱 앱만 해당)"
|
||||
"USER_NAME": "이메일 / 사용자 이름"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"ADV_CFG": "고급 구성",
|
||||
|
|
@ -506,23 +421,12 @@
|
|||
"EXTENSION_NOT_LOADED": "Super Productivity Extension이로드되지 않았습니다. 페이지를 새로 고침하면 도움이 될 수 있습니다.",
|
||||
"INSUFFICIENT_SETTINGS": "Jira에 대한 설정이 충분하지 않음",
|
||||
"INVALID_RESPONSE": "Jira: 응답에 잘못된 데이터가 포함되어 있습니다.",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "Jira : \"{{issueText}}\"이 (가) 이미 업데이트되었습니다.",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "Jira : \"{{issueText}}\"에 대한 데이터가 업데이트되었습니다.",
|
||||
"MISSING_ISSUE_DATA": "Jira : 누락 된 문제 데이터가있는 작업이 발견되었습니다. 다시로드 중입니다.",
|
||||
"NO_AUTO_IMPORT_JQL": "Jira : 자동 가져 오기에 대해 정의 된 검색어가 없습니다.",
|
||||
"NO_VALID_TRANSITION": "Jira : 유효한 전환이 설정되지 않았습니다.",
|
||||
"TIMED_OUT": "Jira : 요청 시간이 초과되었습니다.",
|
||||
"TRANSITION": "Jira : \"{{issueKey}}\"문제를 \"{{name}}\"(으)로 설정하십시오.",
|
||||
"TRANSITION_SUCCESS": "Jira : {{issueKey}} 문제를 <strong>{{chosenTransition}}</strong>(으)로 설정하십시오.",
|
||||
"TRANSITIONS_LOADED": "Jira : 전환이로드되었습니다. 아래 선택을 사용하여 지정하십시오",
|
||||
"UNABLE_TO_REASSIGN": "Jira : 사용자 이름을 지정하지 않았기 때문에 자신에게 티켓을 재 할당 할 수 없습니다. 설정을 방문하십시오."
|
||||
},
|
||||
"STEPPER": {
|
||||
"CREDENTIALS": "신임장",
|
||||
"DONE": "이제 끝났어.",
|
||||
"LOGIN_SUCCESS": "성공적 로그인!",
|
||||
"TEST_CREDENTIALS": "자격증 명 테스트",
|
||||
"WELCOME_USER": "환영합니다, {{user}}!"
|
||||
"TRANSITIONS_LOADED": "Jira : 전환이로드되었습니다. 아래 선택을 사용하여 지정하십시오"
|
||||
}
|
||||
},
|
||||
"MARKDOWN_PASTE": {
|
||||
|
|
@ -534,9 +438,6 @@
|
|||
"DIALOG_TITLE": "붙여 넣은 마크 다운 목록이 감지되었습니다!"
|
||||
},
|
||||
"METRIC": {
|
||||
"BANNER": {
|
||||
"CHECK": "내가 해냈어!"
|
||||
},
|
||||
"CMP": {
|
||||
"AVG_BREAKS_PER_DAY": "평균 하루에 휴식",
|
||||
"AVG_TASKS_PER_DAY_WORKED": "평균 일일 작업 수",
|
||||
|
|
@ -546,7 +447,6 @@
|
|||
"COUNTING_SUBTASKS": "(하위 작업 수 계산)",
|
||||
"DAYS_WORKED": "근무일",
|
||||
"GLOBAL_METRICS": "글로벌 지표",
|
||||
"MOOD_PRODUCTIVITY_OVER_TIME": "시간 경과에 따른 기분과 생산성",
|
||||
"NO_ADDITIONAL_DATA_YET": "추가로 수집 된 데이터가 없습니다. 일일 요약 '평가'패널에있는 양식을 사용하십시오.",
|
||||
"SIMPLE_CLICK_COUNTERS_OVER_TIME": "시간 경과에 따른 클릭 카운터",
|
||||
"SIMPLE_COUNTERS": "간단한 카운터",
|
||||
|
|
@ -556,33 +456,14 @@
|
|||
"TIME_SPENT": "지출 된 시간"
|
||||
},
|
||||
"EVAL_FORM": {
|
||||
"ADD_NOTE_FOR_TOMORROW": "내일 메모 추가",
|
||||
"DISABLE_REPEAT_EVERY_DAY": "매일 반복 사용 안함",
|
||||
"ENABLE_REPEAT_EVERY_DAY": "매일 반복",
|
||||
"HELP_H1": "왜 내가 신경 써야하니?",
|
||||
"HELP_LINK_TXT": "통계 섹션으로 이동",
|
||||
"HELP_P1": "조금 자기 평가 시간! 여기에 귀하의 답변이 저장되어 메트릭 섹션에서 어떻게 작업하는지에 대한 통계를 제공합니다. 또한 내일을위한 제안은 다음날 작업 목록 위에 나타납니다.",
|
||||
"HELP_P2": "이는 정확한 측정 항목을 계산하거나 작업에 대한 사용자의 감각을 향상시키는 것보다 효율적이기는하지만 효율적인 작업이되도록하기위한 것입니다. 매일의 일상 생활에서 고통 점을 평가하는 것은 도움이 될뿐만 아니라 당신을 도울 요인을 찾는 것입니다. 그것에 대해 조금 체계적으로 다루기 만하면 이들에 대해 더 잘 이해하고 가능한 한 향상시키는 데 도움이되기를 바랍니다.",
|
||||
"IMPROVEMENTS": "무엇이 당신의 생산성을 향상 시켰습니까?",
|
||||
"IMPROVEMENTS_TOMORROW": "내일 개선하기 위해 당신은 무엇을 할 수 있습니까?",
|
||||
"MOOD": "기분 어때?",
|
||||
"MOOD_HINT": "1 : 끔찍 - 10 : 훌륭함",
|
||||
"NOTES": "내일위한주의 사항",
|
||||
"OBSTRUCTIONS": "당신의 생산성을 방해 한 것은 무엇입니까?",
|
||||
"PRODUCTIVITY": "얼마나 효율적으로 일 했습니까?",
|
||||
"PRODUCTIVITY_HINT": "1 : 시작조차하지 마라 - 10 : 매우 효율적이다."
|
||||
"PRODUCTIVITY": "얼마나 효율적으로 일 했습니까?"
|
||||
},
|
||||
"FOCUS_SESSION_DIALOG": {
|
||||
"ADD_BTN": "더하다"
|
||||
},
|
||||
"S": {
|
||||
"SAVE_METRIC": "측정 항목이 성공적으로 저장되었습니다."
|
||||
}
|
||||
},
|
||||
"NOTE": {
|
||||
"D_ADD": {
|
||||
"NOTE_LABEL": "메모로 저장할 텍스트를 입력하십시오 ..."
|
||||
},
|
||||
"D_FULLSCREEN": {
|
||||
"VIEW_PARSED": "구문 분석된(편집 불가) 마크다운으로 보기",
|
||||
"VIEW_SPLIT": "분할 보기에서 구문 분석된 마크다운과 구문 분석되지 않은 마크다운 보기",
|
||||
|
|
@ -614,9 +495,6 @@
|
|||
"SELECT_ISSUE_FOR_TRANSITIONS": "이슈를 선택하여 사용 가능한 전환을 로드합니다.",
|
||||
"TRANSITION": "전환 처리"
|
||||
},
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "프로젝트용 OpenProject 설정"
|
||||
},
|
||||
"DIALOG_TRACK_TIME": {
|
||||
"ACTIVITY": "활동",
|
||||
"CURRENTLY_LOGGED": "현재 기록 된 시간 :",
|
||||
|
|
@ -633,8 +511,7 @@
|
|||
"CURRENT_STATUS": "현재 상태:",
|
||||
"PERCENTAGE_DONE": "진행 상황:",
|
||||
"TASK_NAME": "작업 이름:",
|
||||
"TITLE": "오픈프로젝트: 업데이트 상태",
|
||||
"UPDATE_STATUS": "업데이트 상태"
|
||||
"TITLE": "오픈프로젝트: 업데이트 상태"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "사용자 이름 (예 : 혼자서 변경 사항을 필터링)",
|
||||
|
|
@ -651,8 +528,7 @@
|
|||
"TOKEN": "액세스 토큰"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>여기에서 열려 있는 OpenProject 작업 패키지를 나열하도록 SuperProductivity를 구성할 수 있습니다. 이것이 브라우저에서 작동하려면 app.super-productivity.com</p>에서 액세스를 허용하도록 OpenProject 서버에 대해 CORS를 구성해야 합니다.",
|
||||
"TITLE": "오픈프로젝트"
|
||||
"HELP": "<p>여기에서 열려 있는 OpenProject 작업 패키지를 나열하도록 SuperProductivity를 구성할 수 있습니다. 이것이 브라우저에서 작동하려면 app.super-productivity.com</p>에서 액세스를 허용하도록 OpenProject 서버에 대해 CORS를 구성해야 합니다."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "담당자",
|
||||
|
|
@ -680,9 +556,7 @@
|
|||
"PLANNER": {
|
||||
"D": {
|
||||
"ADD_PLANNED": {
|
||||
"ADD_TO_TODAY": "오늘에 추가",
|
||||
"RE_PLAN_ALL": "모두 일정 변경",
|
||||
"TITLE": "오늘에 계획된 작업 추가"
|
||||
"RE_PLAN_ALL": "모두 일정 변경"
|
||||
}
|
||||
},
|
||||
"EDIT_REPEATED_TASK": "반복 작업 편집 '{{taskName}}'",
|
||||
|
|
@ -694,67 +568,15 @@
|
|||
"REMOVED_PLAN_DATE": "작업 '{{taskTitle}}' 의 계획 날짜를 제거했습니다.",
|
||||
"TASK_ALREADY_PLANNED": "작업이 이미 {{date}}에 대해 계획되어 있습니다.",
|
||||
"TASK_PLANNED_FOR": " <strong>{{date}}</strong>{{extra}}에 대한 작업이 계획되었습니다."
|
||||
},
|
||||
"TASK_DRAWER": "작업 서랍"
|
||||
}
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_IS_DONE": "너의 휴식은 끝났어!"
|
||||
},
|
||||
"PROCRASTINATION": {
|
||||
"BACK_TO_WORK": "다시 일!",
|
||||
"COMP": {
|
||||
"INTRO": "연민을 보여주는 것은 언제나 좋은 생각입니다. 그것은 자기 가치 감을 향상시키고, 긍정적 인 감정을 키우며, 지연을 극복하는 데 도움을 줄 수 있습니다. 조금 연습 해보십시오.",
|
||||
"L1": "조금 앉아서 스트레칭을하고 싶다면, 조금이라도 진정하십시오.",
|
||||
"L2": "발생하는 생각과 느낌을 경청하십시오.",
|
||||
"L3": "친구에게 응답 할 수있는 방식으로 자신에게 응답하고 있습니까?",
|
||||
"L4": "대답이 '아니오'인 경우 친구의 상황을 상상해보십시오. 당신이 그들에게 뭐라고 말하겠습니까? 당신이 그들을 위해 무엇을 할 것입니까?",
|
||||
"OUTRO": "더 많은 연습 <a target=\"_blank\" href=\"https://drsoph.com/blog/2018/9/17/3-exercises-in-self-compassion\" target=\"_blank\">은</a> 또는 <a target=\"_blank\" href=\"https://www.google.com/search?q=self+compassion+exercises&oq=self+compassion+excers&aqs=chrome.1.69i57j0l5.4303j0j7&sourceid=chrome&ie=UTF-8\" target=\"_blank\">google</a>에 있습니다.",
|
||||
"TITLE": "자기 동정"
|
||||
},
|
||||
"CUR": {
|
||||
"INTRO": "지연은 흥미 롭, 안 그래? 그것을하는 것이 이치에 맞지 않습니다. 장기적으로는 관심이 없습니다. 그러나 여전히 모든 사람들이 그것을합니다. 즐기고 탐험 해보세요!",
|
||||
"L1": "어떤 감정이 당신의 유혹을 이끌어 내고 있습니까?",
|
||||
"L2": "당신의 몸에서 그들을 어디에서 느낄 수 있습니까?",
|
||||
"L3": "그들이 당신에게 무엇을 생각 나게 하죠?",
|
||||
"L4": "당신이 그것을 관찰 할 때 미루는 생각은 어떻게됩니까? 그것이 강화됩니까? 소산? 다른 감정이 발생합니까?",
|
||||
"L5": "당신이 그들에 대한 인식을 계속해서 쉬면서 몸의 감각은 어떻게 움직입니까?",
|
||||
"PROCRASTINATION_TRIGGERS_TEXT": "또 다른 매우 효과적인 방법은 미루고 싶은 충동을 유발하는 요인을 기록하는 것입니다. 예를 들어 저는 개인적으로 브라우저 창이 뜨면 Reddit이나 즐겨 찾는 뉴스 사이트로 빠르게 이동하고 싶은 충동을 자주 느낍니다. 간단한 빈 텍스트 문서에 충동을 유발하는 요인을 적기 시작한 후, 이 패턴이 얼마나 뿌리 깊은지 알게 되었고 다양한 대응책을 실험해보는 데 도움이 되었습니다.",
|
||||
"PROCRASTINATION_TRIGGERS_TITLE": "미루게 만드는 트리거를 적어보세요.",
|
||||
"TITLE": "호기심"
|
||||
},
|
||||
"H1": "여유를 가져요!",
|
||||
"INTRO": {
|
||||
"AVOIDING": "작업 피하기",
|
||||
"FEAR": "실패에 대한 두려움",
|
||||
"STRESSED": "일을 완수하지 못해서 스트레스",
|
||||
"TITLE": "소개"
|
||||
},
|
||||
"P1": "우선 긴장을 풀어 라! 모두가 한 번씩 그렇게합니다. 그리고 네가해야 할 일을하지 않는다면, 적어도 그것을 즐겨라! 그런 다음 아래 섹션에서 유용한 정보를 확인하십시오.",
|
||||
"P2": "기억하십시오 : 지연은 시간 관리 문제가 아닌 감정 조절 문제입니다.",
|
||||
"REFRAME": {
|
||||
"INTRO": "그 임무에도 불구하고 무엇이 긍정적인지를 생각해보십시오.",
|
||||
"TITLE": "재구성",
|
||||
"TL1": "그것에 대해 흥미로운 것은 무엇입니까?",
|
||||
"TL2": "당신이 그것을 완성한다면 무엇을 얻을 것입니까?",
|
||||
"TL3": "당신이 그것을 완성한다면 어떻게 느낄 것인가?"
|
||||
},
|
||||
"SPLIT_UP": {
|
||||
"INTRO": "가능한 한 많은 작은 덩어리로 작업을 분할하십시오.",
|
||||
"OUTRO": "끝난? 그런 다음 그것에 대해 생각해보십시오. - 엄격하게 이론적 인 것은 무엇입니까? - 당신이 작업에 착수하기 시작한 경우</i> 당신이 <i>할 첫 번째 일은 무엇입니까? 생각 해봐...",
|
||||
"TITLE": "그것을 나눠 라!"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "프로젝트 만들기",
|
||||
"EDIT": "프로젝트 수정",
|
||||
"SETUP_CALDAV": "Caldav 통합 설정",
|
||||
"SETUP_GIT": "GitHub 통합 설치",
|
||||
"SETUP_GITEA_PROJECT": "Gitea 통합 설정",
|
||||
"SETUP_GITLAB": "GitLab 통합 설치",
|
||||
"SETUP_JIRA": "Jira 통합 설정",
|
||||
"SETUP_OPEN_PROJECT": "OpenProject 통합 설정",
|
||||
"SETUP_REDMINE_PROJECT": "레드마인 통합 설정"
|
||||
"EDIT": "프로젝트 수정"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"MSG": "프로젝트 \"{{title}}\"을 삭제하시겠습니까?"
|
||||
|
|
@ -766,7 +588,6 @@
|
|||
"TITLE": "기본 설정"
|
||||
},
|
||||
"FORM_THEME": {
|
||||
"D_IS_DARK_THEME": "시스템이 글로벌 암 모드를 지원하면 사용되지 않습니다.",
|
||||
"HELP": "프로젝트의 테마 설정.",
|
||||
"L_BACKGROUND_IMAGE_DARK": "배경 이미지 URL (어두운 테마)",
|
||||
"L_BACKGROUND_IMAGE_LIGHT": "배경 이미지 URL (밝은 테마)",
|
||||
|
|
@ -778,18 +599,13 @@
|
|||
"L_HUE_WARN": "경고 색상 배경에 어두운 텍스트에 대한 임계 값",
|
||||
"L_IS_AUTO_CONTRAST": "최고의 가독성을위한 자동 텍스트 색상 설정",
|
||||
"L_IS_DISABLE_BACKGROUND_TINT": "컬러 배경 그라디언트 비활성화",
|
||||
"L_IS_REDUCED_THEME": "축소 된 UI 사용 (작업 주위의 상자 없음)",
|
||||
"L_THEME_COLOR": "테마 색",
|
||||
"L_TITLE": "제목",
|
||||
"TITLE": "테마"
|
||||
},
|
||||
"S": {
|
||||
"ARCHIVED": "보관 된 프로젝트",
|
||||
"CREATED": "생성 된 프로젝트 <strong>{{title}}</strong>. 왼쪽 상단의 메뉴에서 선택할 수 있습니다.",
|
||||
"DELETED": "삭제 된 프로젝트",
|
||||
"E_EXISTS": "프로젝트 \"{{title}}\"이 (가) 이미 있습니다.",
|
||||
"E_INVALID_FILE": "프로젝트 파일의 데이터가 잘못되었습니다.",
|
||||
"ISSUE_PROVIDER_UPDATED": " <strong>{{issueProviderKey}}</strong>에 대한 업데이트 된 프로젝트 설정",
|
||||
"UNARCHIVED": "아카이브되지 않은 프로젝트",
|
||||
"UPDATED": "프로젝트 설정 업데이트"
|
||||
}
|
||||
|
|
@ -805,9 +621,6 @@
|
|||
"WEEK_TITLE": " {{nr}} 주({{timeSpent}})"
|
||||
},
|
||||
"REDMINE": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "프로젝트용 레드마인 설정"
|
||||
},
|
||||
"FORM": {
|
||||
"API_KEY": "API 액세스 키",
|
||||
"HOST": "호스트(예: https://redmine.org)",
|
||||
|
|
@ -828,14 +641,10 @@
|
|||
"MARK_AS_CHECKED": "업데이트를 체크된 것으로 표시",
|
||||
"PRIORITY": "우선순위",
|
||||
"STATUS": "상태"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Redmine: 알 수 없는 오류 {{statusCode}} {{errorMsg}}."
|
||||
}
|
||||
},
|
||||
"REMINDER": {
|
||||
"COUNTDOWN_BANNER": {
|
||||
"HIDE": "숨기기",
|
||||
"START_NOW": "지금 시작하기",
|
||||
"TXT": "<strong>{{title}}</strong> 가 <strong>{{start}}</strong>에서 시작합니다!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> 는 <strong>에서 시작 {{start}}</strong>!<br> (및 {{nrOfOtherBanners}} 개의 다른 작업 마감일)"
|
||||
|
|
@ -844,29 +653,19 @@
|
|||
"S_REMINDER_ERR": "알림 인터페이스 오류"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"CONTINUED": "계속되는",
|
||||
"D_INITIAL": {
|
||||
"TEXT": "<p>타임 라인의 개념은 시간이 지남에 따라 계획된 작업이 어떻게 진행되는지에 대한 더 나은 그림을 제공하는 것입니다. 작업에서 자동으로 생성되며 두 가지 다른 항목을 구분합니다. <strong>예정된 작업</strong>은 계획된 시간에 표시되고 <strong>일반 작업</strong> 은 이러한 고정 이벤트를 중심으로 진행됩니다. 모든 작업은 할당 한 예상 시간을 고려합니다.</p><p>이 외에도 작업 시작 및 종료 시간을 제공 할 수 있습니다. 구성된 경우 일반 작업은 이러한 외부에 표시되지 않습니다. 타임 라인에는 향후 30 일만 포함됩니다.</p>",
|
||||
"TITLE": "타임 라인"
|
||||
},
|
||||
"END": "작업 종료",
|
||||
"LUNCH_BREAK": "점심 휴식",
|
||||
"MONTH": "달",
|
||||
"NO_TASKS": "현재 작업이 없습니다. 상단 표시 줄의 + 버튼을 통해 몇 가지 작업을 추가하세요.",
|
||||
"NOW": "지금",
|
||||
"PLAN_END_DAY": "하루 일과 종료 시 계획",
|
||||
"PLAN_START_DAY": "하루 시작 시 계획 세우기",
|
||||
"START": "작업 시작",
|
||||
"TASK_PROJECTION_INFO": "예약된 반복 작업의 미래 예측",
|
||||
"WEEK": "주"
|
||||
"START": "작업 시작"
|
||||
},
|
||||
"SEARCH_BAR": {
|
||||
"INFO": "보관된 작업을 검색하려면 목록 아이콘을 클릭하십시오.",
|
||||
"INFO_ARCHIVED": "일반 작업을 검색하려면 아카이브 아이콘을 클릭하십시오.",
|
||||
"NO_RESULTS": "검색어와 일치하는 작업을 찾을 수 없습니다.",
|
||||
"PLACEHOLDER": "작업 또는 작업 설명 검색",
|
||||
"PLACEHOLDER_ARCHIVED": "보관된 작업 검색",
|
||||
"TOO_MANY_RESULTS": "결과가 너무 많습니다. 검색 범위를 좁히십시오."
|
||||
"PLACEHOLDER": "작업 또는 작업 설명 검색"
|
||||
},
|
||||
"SIMPLE_COUNTER": {
|
||||
"D_CONFIRM_REMOVE": {
|
||||
|
|
@ -885,7 +684,6 @@
|
|||
"L_COUNTDOWN_DURATION": "카운트다운 기간",
|
||||
"L_DAILY_GOAL": "성공적인 연승을 위한 일일 목표",
|
||||
"L_ICON": "아이콘",
|
||||
"L_ICON_ON": "전환시 아이콘",
|
||||
"L_IS_ENABLED": "사용",
|
||||
"L_TITLE": "제목",
|
||||
"L_TRACK_STREAKS": "트랙 스트라이크",
|
||||
|
|
@ -903,18 +701,10 @@
|
|||
},
|
||||
"SYNC": {
|
||||
"A": {
|
||||
"ARCHIVE_ONLY_UPLOADED": "데이터가 일부만 업로드되었습니다. 나중에 다시 시도하세요! 그렇지 않으면 데이터를 다른 장치에 동기화할 수 없습니다.",
|
||||
"POSSIBLE_LEGACY_DATA": "슈퍼 생산성은 이제 하나의 파일이 아닌 두 개의 개별 파일을 사용하여 동기화를 개선하여 데이터 전송을 훨씬 더 적게 할 수 있습니다. 슈퍼 생산성의 모든 인스턴스를 업데이트하고 데이터가 가장 최신인 앱 인스턴스에서 먼저 데이터를 동기화하는 것이 좋습니다. 로컬 장치의 데이터인 경우에는 이 경고를 무시하고 다음 대화 상자를 확인하여 업로드를 진행하세요.",
|
||||
"REMOTE_MODEL_VERSION_NEWER": "원격 모델 버전이 로컬 버전보다 최신 버전입니다. 로컬 앱을 최신 버전으로 업데이트하세요!"
|
||||
},
|
||||
"C": {
|
||||
"EMPTY_SYNC": "빈 데이터 개체를 동기화하려고합니다. 이것이 (거의) 처녀 앱의 첫 번째 동기화입니까?",
|
||||
"FORCE_UPLOAD": "그래도 로컬 데이터를 업로드 하시겠습니까?",
|
||||
"FORCE_UPLOAD_AFTER_ERROR": "로컬 데이터를 업로드하는 동안 오류가 발생했습니다. 강제로 업데이트 하시겠습니까?",
|
||||
"MIGRATE_LEGACY": "가져오는 동안 기존 데이터가 감지되었습니다. 마이그레이션을 시도하시겠습니까?",
|
||||
"NO_REMOTE_DATA": "원격 데이터가 없습니다. 원격에 로컬을 업로드 하시겠습니까?",
|
||||
"TRY_LOAD_REMOTE_AGAIN": "원격에서 데이터를 다시로드 하시겠습니까?",
|
||||
"UNABLE_TO_LOAD_REMOTE_DATA": "원격에서 데이터를 로드할 수 없습니다. 원격 데이터를 로컬 데이터로 덮어쓰기를 시도하시겠습니까? 이 과정에서 모든 원격 데이터가 손실됩니다."
|
||||
"FORCE_UPLOAD": "그래도 로컬 데이터를 업로드 하시겠습니까?"
|
||||
},
|
||||
"D_AUTH_CODE": {
|
||||
"FOLLOW_LINK": "다음 링크를 열고 제공된 인증 코드를 아래 입력 필드에 복사하십시오.",
|
||||
|
|
@ -923,8 +713,6 @@
|
|||
"TITLE": "로그인 : {{provider}}"
|
||||
},
|
||||
"D_CONFLICT": {
|
||||
"LAMPORT_CLOCK": "개정판",
|
||||
"LAST_CHANGE": "마지막 변경:",
|
||||
"LAST_SYNC": "마지막 동기화 :",
|
||||
"LOCAL": "로컬",
|
||||
"LOCAL_REMOTE": "로컬-> 원격",
|
||||
|
|
@ -949,10 +737,6 @@
|
|||
"BTN_FORCE_UPLOAD": "로컬 업로드 강제",
|
||||
"P1": "원격 동기화 데이터가 일관성이 없습니다!",
|
||||
"P2": "영향을 받는 모델:",
|
||||
"P3": "2가지 옵션이 있습니다.",
|
||||
"P4": "1. 다른 장치로 이동하여 전체 동기화를 시도하십시오.",
|
||||
"P5": "2. 원격 데이터를 로컬 데이터로 덮어씁니다. 모든 원격 변경 사항이 손실됩니다!",
|
||||
"P6": "덮어쓰는 데이터의 백업을 만드는 것이 좋습니다!!",
|
||||
"T1": "마지막 동기화가 완료되지 않았습니다!",
|
||||
"T2": "마지막 동기화 중에 아카이브 데이터가 제대로 업로드되지 않았습니다:",
|
||||
"T3": "두 가지 옵션이 있습니다:",
|
||||
|
|
@ -964,19 +748,7 @@
|
|||
"SAVE_AND_ENABLE": "Save & Enable Sync",
|
||||
"TITLE": "동기화 구성"
|
||||
},
|
||||
"D_PERMISSION": {
|
||||
"DISABLE_SYNC": "동기화 비활성화",
|
||||
"PERM_FILE": "권한 부여",
|
||||
"TEXT": "<p>로컬 동기화에 대한 파일 권한이 해지되었습니다.</p>",
|
||||
"TITLE": "동기화: 로컬 파일 권한이 거부됨"
|
||||
},
|
||||
"FORM": {
|
||||
"DROPBOX": {
|
||||
"L_ACCESS_TOKEN": "액세스 토큰 (인증 코드에서 생성)"
|
||||
},
|
||||
"GOOGLE": {
|
||||
"L_SYNC_FILE_NAME": "파일 이름 동기화"
|
||||
},
|
||||
"L_ENABLE_COMPRESSION": "압축 사용(데이터 전송 속도 향상)",
|
||||
"L_ENABLE_ENCRYPTION": "종단 간 암호화 사용(실험 중) - 동기화 공급자가 데이터에 액세스할 수 없도록 설정합니다.",
|
||||
"L_ENABLE_SYNCING": "동기화 활성화",
|
||||
|
|
@ -985,7 +757,6 @@
|
|||
"L_SYNC_INTERVAL": "동기화 간격",
|
||||
"L_SYNC_PROVIDER": "동기화 제공자",
|
||||
"LOCAL_FILE": {
|
||||
"L_SYNC_FILE_PATH_PERMISSION_VALIDATION": "파일 액세스 권한 필요",
|
||||
"L_SYNC_FOLDER_PATH": "폴더 경로 동기화"
|
||||
},
|
||||
"TITLE": "동기화",
|
||||
|
|
@ -999,22 +770,13 @@
|
|||
},
|
||||
"S": {
|
||||
"ALREADY_IN_SYNC": "이미 동기화 중",
|
||||
"ALREADY_IN_SYNC_NO_LOCAL_CHANGES": "로컬 변경 사항 없음 - 이미 동기화 중",
|
||||
"BTN_CONFIGURE": "구성",
|
||||
"BTN_FORCE_OVERWRITE": "강제 덮어쓰기",
|
||||
"ERROR_DATA_IS_CURRENTLY_WRITTEN": "원격 데이터가 현재 작성 중입니다.",
|
||||
"ERROR_FALLBACK_TO_BACKUP": "데이터를 가져 오는 중에 문제가 발생했습니다. 로컬 백업으로 되돌아갑니다.",
|
||||
"ERROR_INVALID_DATA": "동기화하는 동안 오류가 발생했습니다. 유효하지 않은 데이터",
|
||||
"ERROR_NO_REV": "원격 파일에 유효한 수정본이 없습니다.",
|
||||
"ERROR_UNABLE_TO_READ_REMOTE_DATA": "동기화하는 동안 오류가 발생했습니다. 원격 데이터를 읽을 수 없습니다. 암호화를 사용 설정했는데 로컬 비밀번호가 원격 데이터를 암호화하는 데 사용된 비밀번호와 일치하지 않나요?",
|
||||
"IMPORTING": "데이터 가져 오기",
|
||||
"INCOMPLETE_CFG": "동기화 인증에 실패했습니다. 구성을 확인하십시오!",
|
||||
"INITIAL_SYNC_ERROR": "초기 동기화 실패",
|
||||
"SUCCESS_DOWNLOAD": "원격에서 동기화된 데이터",
|
||||
"SUCCESS_IMPORT": "가져온 데이터",
|
||||
"SUCCESS_VIA_BUTTON": "데이터가 성공적으로 동기화되었습니다.",
|
||||
"UNKNOWN_ERROR": "동기화하는 동안 알 수없는 오류가 발생했습니다. 콘솔을 확인하십시오.",
|
||||
"UPLOAD_ERROR": "알 수없는 업로드 오류 (설정이 맞습니까?) : {{err}}"
|
||||
"UNKNOWN_ERROR": "동기화하는 동안 알 수없는 오류가 발생했습니다. 콘솔을 확인하십시오."
|
||||
},
|
||||
"SAFETY_BACKUP": {
|
||||
"BTN_DELETE": "삭제하다"
|
||||
|
|
@ -1022,8 +784,7 @@
|
|||
},
|
||||
"TAG": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "태그 생성",
|
||||
"EDIT": "태그 편집"
|
||||
"CREATE": "태그 생성"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"CONFIRM_MSG": "태그 \"{{tagName}}\"을 (를) 정말로 삭제 하시겠습니까? 모든 작업에서 제거됩니다. 이 취소 할 수 없습니다."
|
||||
|
|
@ -1054,17 +815,7 @@
|
|||
"TASK": {
|
||||
"ADD_TASK_BAR": {
|
||||
"ADD_EXISTING_TASK": "기존 작업 \"{{taskTitle}}\"추가",
|
||||
"ADD_ISSUE_TASK": " {{issueType}}의{{issueNr}} 호 추가",
|
||||
"ADD_TASK_TO_BOTTOM_OF_BACKLOG": "백로그 하단에 작업 추가",
|
||||
"ADD_TASK_TO_BOTTOM_OF_TODAY": "목록 맨 아래에 작업 추가",
|
||||
"ADD_TASK_TO_TOP_OF_BACKLOG": "백로그 맨 위에 작업 추가",
|
||||
"ADD_TASK_TO_TOP_OF_TODAY": "목록 맨 위에 작업 추가",
|
||||
"CREATE_TASK": "새 할 일 만들기",
|
||||
"EXAMPLE": "예 : \"일부 작업 제목 + projectName #some-tag #some-other-tag 10m / 3h\"",
|
||||
"START": "시작하려면 한 번 더 입력하십시오.",
|
||||
"TODAY": "오늘",
|
||||
"TOGGLE_ADD_TO_BACKLOG_TODAY": "백로그/오늘의 목록에 작업 추가 토글하기'",
|
||||
"TOGGLE_ADD_TOP_OR_BOTTOM": "목록 상단 및 하단에 작업 추가 토글",
|
||||
"TOMORROW": "내일"
|
||||
},
|
||||
"ADDITIONAL_INFO": {
|
||||
|
|
@ -1072,11 +823,9 @@
|
|||
"ADD_SUB_TASK": "하위 작업 추가",
|
||||
"ATTACHMENTS": "첨부 파일 {{nr}}",
|
||||
"DUE": "예정된 날짜",
|
||||
"FROM_PARENT": "(부모님)",
|
||||
"LOCAL_ATTACHMENTS": "로컬 첨부 파일",
|
||||
"NOTES": "노트",
|
||||
"PARENT": "부모의",
|
||||
"REMINDER": "조언",
|
||||
"REPEAT": "반복",
|
||||
"SCHEDULE_TASK": "작업 예약",
|
||||
"SUB_TASKS": "하위 작업 ({{nr}})",
|
||||
|
|
@ -1096,11 +845,8 @@
|
|||
"DELETE_REPEAT_INSTANCE": "반복되는 작업 인스턴스 삭제",
|
||||
"DROP_ATTACHMENT": "'{{title}}'에 연결하려면 여기로 드래그하십시오.",
|
||||
"EDIT_SCHEDULED": "알림 수정",
|
||||
"EDIT_TAGS": "태그 편집",
|
||||
"EDIT_TASK_TITLE": "제목 수정",
|
||||
"FOCUS_SESSION": "포커스 세션 시작",
|
||||
"MARK_DONE": "완료로 표시",
|
||||
"MARK_UNDONE": "실행 취소로 표시",
|
||||
"MOVE_TO_BACKLOG": "백 로그로 이동",
|
||||
"MOVE_TO_OTHER_PROJECT": "다른 프로젝트로 이동",
|
||||
"MOVE_TO_REGULAR": "오늘의 목록으로 이동",
|
||||
|
|
@ -1109,9 +855,7 @@
|
|||
"OPEN_ISSUE": "새 브라우저 탭에서 문제 열기",
|
||||
"OPEN_TIME": "시간 예측 / 소요 시간 추가",
|
||||
"REMOVE_FROM_MY_DAY": "내 날에서 제거",
|
||||
"REPEAT_EDIT": "반복 작업 구성 편집",
|
||||
"SCHEDULE": "작업 예약",
|
||||
"SHOW_UPDATES": "업데이트 표시",
|
||||
"TOGGLE_ATTACHMENTS": "첨부 파일 표시 / 숨기기",
|
||||
"TOGGLE_DETAIL_PANEL": "추가 정보 표시 / 숨기기",
|
||||
"TOGGLE_DONE": "완료 / 실행 취소로 표시",
|
||||
|
|
@ -1138,24 +882,17 @@
|
|||
"DONE": "끝난",
|
||||
"DUE_TASK": "마감일",
|
||||
"DUE_TASKS": "마감일",
|
||||
"FOR_CURRENT": "작업이 완료되었습니다. 그것에 착수하고 싶니?",
|
||||
"FOR_OTHER": "작업이 완료되었습니다. 그것에 착수하고 싶니?",
|
||||
"FROM_PROJECT": "프로젝트에서",
|
||||
"FROM_TAG": "태그에서 : \"{{title}}\"",
|
||||
"RESCHEDULE_EDIT": "편집(일정 재조정)",
|
||||
"RESCHEDULE_UNTIL_TOMORROW": "내일까지",
|
||||
"SNOOZE": "다시 알림",
|
||||
"SNOOZE_ALL": "모두 다시 알림",
|
||||
"START": "작업 시작",
|
||||
"SWITCH_CONTEXT_START": "상황 전환 및 시작",
|
||||
"UNSCHEDULE": "비정기",
|
||||
"UNSCHEDULE_ALL": "모두 일정 해제"
|
||||
},
|
||||
"D_SCHEDULE_TASK": {
|
||||
"MOVE_TO_BACKLOG": "예약 될 때까지 작업을 백 로그로 이동하십시오.",
|
||||
"QA_NEXT_MONTH": "다음 달 일정",
|
||||
"QA_NEXT_WEEK": "다음 주 일정",
|
||||
"QA_REMOVE_TODAY": "오늘부터 작업 제거",
|
||||
"QA_TODAY": "오늘 예약하기",
|
||||
"QA_TOMORROW": "내일 일정",
|
||||
"REMIND_AT": "에 알림",
|
||||
|
|
@ -1191,15 +928,12 @@
|
|||
"S": {
|
||||
"CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK": "반복 가능한 작업의 경우 짧은 구문을 통해 프로젝트를 할당할 수 없습니다!",
|
||||
"CREATED_FOR_PROJECT": "작업 \"{{taskTitle}}\"를 프로젝트 \"{{projectTitle}}\"로 이동했습니다.",
|
||||
"CREATED_FOR_PROJECT_ACTION": "프로젝트로 이동",
|
||||
"DELETED": "\"{{title}}\"작업을 삭제했습니다.",
|
||||
"FOUND_MOVE_FROM_BACKLOG": "기존 작업 <strong>{{title}}</strong> 을 (를) 현재 작업 목록으로 이동했습니다.",
|
||||
"FOUND_MOVE_FROM_OTHER_LIST": " <strong>{{contextTitle}}</strong> 의 작업 <strong>{{title}}</strong> 을 (를) 현재 목록에 추가했습니다.",
|
||||
"FOUND_RESTORE_FROM_ARCHIVE": "아카이브의 문제와 관련된 복원 된 작업 <strong>{{title}}</strong> ",
|
||||
"LAST_TAG_DELETION_WARNING": "프로젝트가 아닌 작업의 마지막 태그를 제거하려고합니다. 이것은 허용되지 않습니다!",
|
||||
"MOVED_TO_ARCHIVE": " {{nr}} 작업을 보관으로 이동했습니다.",
|
||||
"MOVED_TO_PROJECT": "작업 \"{{taskTitle}}\"를 프로젝트 \"{{projectTitle}}\"로 이동했습니다.",
|
||||
"MOVED_TO_PROJECT_ACTION": "프로젝트로 이동",
|
||||
"REMINDER_ADDED": "예약 된 작업 \"{{title}}\"",
|
||||
"REMINDER_DELETED": "할 일 목록 삭제",
|
||||
"REMINDER_UPDATED": "\"{{title}}\"작업에 대한 알림이 업데이트되었습니다.",
|
||||
|
|
@ -1267,7 +1001,6 @@
|
|||
"C_YEAR": "연도",
|
||||
"DEFAULT_ESTIMATE": "기본 견적",
|
||||
"FRIDAY": "금요일",
|
||||
"IS_ADD_TO_BOTTOM": "작업을 목록의 맨 아래로 이동",
|
||||
"MONDAY": "월요일",
|
||||
"NOTES": "기본 노트",
|
||||
"ORDER": "주문",
|
||||
|
|
@ -1319,7 +1052,6 @@
|
|||
"SCHEDULED_THIS_WEEK": "이번 주",
|
||||
"SCHEDULED_TODAY": "오늘",
|
||||
"SCHEDULED_TOMORROW": "내일",
|
||||
"SORT_BY": "정렬 기준",
|
||||
"SORT_CREATION_DATE": "생성 날짜",
|
||||
"SORT_DEFAULT": "기본값",
|
||||
"SORT_NAME": "이름",
|
||||
|
|
@ -1328,8 +1060,7 @@
|
|||
"TIME_2HOUR": "> 2 시간",
|
||||
"TIME_10MIN": "> 10분",
|
||||
"TIME_30MIN": "> 30분",
|
||||
"TIME_SPENT": "소요 시간",
|
||||
"TITLE": "작업 보기 사용자 지정"
|
||||
"TIME_SPENT": "소요 시간"
|
||||
}
|
||||
},
|
||||
"TIME_TRACKING": {
|
||||
|
|
@ -1359,7 +1090,6 @@
|
|||
},
|
||||
"D_TRACKING_REMINDER": {
|
||||
"CREATE_AND_TRACK": "<em></em> 생성 및 추적",
|
||||
"IDLE_FOR": "당신은 유휴 상태였습니다.",
|
||||
"NOTIFICATION_TITLE": "시간을 추적하세요!",
|
||||
"TASK": "태스크",
|
||||
"TRACK_TO": "추적 대상 :",
|
||||
|
|
@ -1371,7 +1101,6 @@
|
|||
"DAYS_WORKED": "일한 날짜 :",
|
||||
"MONTH_WORKED": "월 근무일 :",
|
||||
"REPEATING_TASK": "반복 과제",
|
||||
"RESTORE_TASK_FROM_ARCHIVE": "아카이브에서 작업 복원",
|
||||
"TASKS": "할 일 목록",
|
||||
"TOTAL_TIME": "총 소요 시간 :",
|
||||
"WEEK_NR": "주 {{nr}}",
|
||||
|
|
@ -1463,26 +1192,20 @@
|
|||
"HIDE": "숨기기",
|
||||
"ICON_INP_DESCRIPTION": "모든 utf-8 이모티콘도 지원됩니다!",
|
||||
"INBOX_PROJECT_TITLE": "받은 편지함",
|
||||
"LOGIN": "로그인",
|
||||
"LOGOUT": "로그 아웃",
|
||||
"MINUTES": "{{m}} 분",
|
||||
"MOVE_BACKWARD": "뒤로 이동",
|
||||
"MOVE_FORWARD": "앞으로 나아가기",
|
||||
"NEXT": "다음",
|
||||
"NO_CON": "현재 오프라인 상태입니다. 인터넷에 다시 연결하십시오.",
|
||||
"NONE": "없음",
|
||||
"OK": "승인",
|
||||
"OVERDUE": "기한이 지난",
|
||||
"PREVIOUS": "이전",
|
||||
"REMOVE": "삭제",
|
||||
"RESET": "초기화",
|
||||
"SAVE": "저장",
|
||||
"SUBMIT": "제출하기",
|
||||
"TITLE": "제목",
|
||||
"TODAY_TAG_TITLE": "오늘",
|
||||
"TRACKING_INTERVAL_DESCRIPTION": "이 간격을 밀리초 단위로 사용하여 시간을 추적합니다. 디스크 쓰기를 줄이려면 이 값을 변경할 수 있습니다. 이슈 #2355를 참조하세요.",
|
||||
"UNDO": "취소",
|
||||
"UPDATE": "최신 정보",
|
||||
"WITHOUT_PROJECT": "프로젝트없이",
|
||||
"YESTERDAY": "어제"
|
||||
},
|
||||
|
|
@ -1496,9 +1219,7 @@
|
|||
"CALENDARS": {
|
||||
"BROWSER_WARNING": "교차 출처 제한 <b>으로 인해 브라우저 버전의 Super Productivity에서는 작동하지 않을 수 있습니다.<br /> 이 기능을 사용하려면 데스크톱 버전</a> 을 <a href=\"https://super-productivity.com/download/\">다운로드하세요!</b>",
|
||||
"CAL_PATH": "ICal 소스의 URL",
|
||||
"CAL_PROVIDERS": "캘린더 공급자(실험적 및 선택 사항)",
|
||||
"CHECK_UPDATES": "X마다 원격 업데이트 확인",
|
||||
"DEFAULT_PROJECT": "추가된 캘린더 작업의 기본 프로젝트",
|
||||
"HELP": "캘린더를 통합하여 알림을 받고 Super Productivity 내에서 작업으로 추가할 수 있습니다. 통합은 iCal 형식을 사용하여 작동합니다. 이 기능을 사용하려면 인터넷이나 파일 시스템을 통해 캘린더에 액세스할 수 있어야 합니다.",
|
||||
"SHOW_BANNER_THRESHOLD": "이벤트 전에 알림 X 표시(비활성화하면 비어 있음)"
|
||||
},
|
||||
|
|
@ -1508,7 +1229,6 @@
|
|||
},
|
||||
"FOCUS_MODE": {
|
||||
"HELP": "집중 모드에서는 방해 요소가 없는 화면을 열어 현재 작업에 집중할 수 있도록 도와줍니다.",
|
||||
"L_ALWAYS_OPEN_FOCUS_MODE": "추적 시 항상 초점 모드 열기",
|
||||
"L_SKIP_PREPARATION_SCREEN": "준비 화면 건너뛰기(스트레칭 등)",
|
||||
"TITLE": "초점 모드"
|
||||
},
|
||||
|
|
@ -1560,7 +1280,6 @@
|
|||
"TASK_MOVE_TO_PROJECT": "프로젝트 메뉴로 이동 작업 열기",
|
||||
"TASK_OPEN_CONTEXT_MENU": "작업 상황에 맞는 메뉴 열기",
|
||||
"TASK_OPEN_ESTIMATION_DIALOG": "견적 / 소요 시간 수정",
|
||||
"TASK_PLAN_FORDAY": "하루 계획",
|
||||
"TASK_SCHEDULE": "작업 예약",
|
||||
"TASK_SHORTCUTS": "할 일 목록",
|
||||
"TASK_SHORTCUTS_INFO": "다음 바로 가기가 현재 선택된 작업 (탭 또는 마우스를 통해 선택)에 적용됩니다.",
|
||||
|
|
@ -1568,7 +1287,6 @@
|
|||
"TASK_TOGGLE_DONE": "완료 여부 토글",
|
||||
"TITLE": "키보드 단축키",
|
||||
"TOGGLE_BACKLOG": "작업 백 로그 표시 / 숨기기",
|
||||
"TOGGLE_BOOKMARKS": "북마크 바 표시 / 숨기기",
|
||||
"TOGGLE_ISSUE_PANEL": "이슈 패널 표시/숨기기",
|
||||
"TOGGLE_PLAY": "작업 시작 / 중지",
|
||||
"TOGGLE_SIDE_NAV": "사이드 내비게이션 표시 및 초점 / 숨기기",
|
||||
|
|
@ -1617,19 +1335,15 @@
|
|||
"IS_DARK_MODE": "다크 모드",
|
||||
"IS_DISABLE_ANIMATIONS": "모든 애니메이션 비활성화",
|
||||
"IS_DISABLE_CELEBRATION": "일일 요약에서 축하 비활성화",
|
||||
"IS_HIDE_NAV": "기본 헤더가 올라갈 때까지 탐색을 숨 깁니다 (데스크톱 만 해당).",
|
||||
"IS_MINIMIZE_TO_TRAY": "트레이로 최소화 (데스크탑만 해당)",
|
||||
"IS_SHOW_TIP_LONGER": "앱 시작 시 생산성 팁 표시좀 더 오래",
|
||||
"IS_TRAY_SHOW_CURRENT_COUNTDOWN": "트레이/상태 메뉴에 현재 카운트다운 표시(데스크톱 Mac만 해당)",
|
||||
"IS_TRAY_SHOW_CURRENT_TASK": "트레이 / 상태 메뉴에 현재 작업 표시 (데스크톱 전용)",
|
||||
"IS_TURN_OFF_MARKDOWN": "노트에 대한 마크 다운 파싱 끄기",
|
||||
"IS_USE_MINIMAL_SIDE_NAV": "최소한의 탐색 모음 사용(아이콘만 표시)",
|
||||
"START_OF_NEXT_DAY": "다음 날 시작 시간",
|
||||
"START_OF_NEXT_DAY_HINT": "다음 날을 계산하려는 시점(시간 단위)부터 시작됩니다. 기본값은 0인 자정입니다.",
|
||||
"TASK_NOTES_TPL": "작업 설명 템플릿",
|
||||
"TITLE": "기타 설정",
|
||||
"USER_PROFILES": "사용자 프로필 활성화 (베타)",
|
||||
"USER_PROFILES_HINT": "각각 별도의 설정, 작업 및 동기화 구성을 가진 다른 사용자 프로필을 생성하고 전환할 수 있습니다. 활성화되면 프로필 관리 버튼이 오른쪽 상단에 나타납니다. 참고: 이 기능을 비활성화하면 UI가 숨겨지지만 프로필 데이터는 유지됩니다 (베타 기능, 보증 없음. 백업이 있는지 확인하십시오)."
|
||||
"TITLE": "기타 설정"
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_DURATION": "짧은 휴식 시간",
|
||||
|
|
@ -1651,9 +1365,7 @@
|
|||
"L_WORK_END": "근무일 종료",
|
||||
"L_WORK_START": "근무일 시작",
|
||||
"LUNCH_BREAK_START_END_DESCRIPTION": "예: 13:00",
|
||||
"MONTH": "달",
|
||||
"TITLE": "타임 라인",
|
||||
"WEEK": "주",
|
||||
"WORK_START_END_DESCRIPTION": "예 : 17:00"
|
||||
},
|
||||
"SHORT_SYNTAX": {
|
||||
|
|
@ -1731,14 +1443,12 @@
|
|||
},
|
||||
"GLOBAL_SNACK": {
|
||||
"COPY_TO_CLIPPBOARD": "클립 보드에 복사 됨",
|
||||
"ERR_COMPRESSION": "압축 인터페이스 오류",
|
||||
"FILE_DOWNLOADED": "{{fileName}} 다운로드됨",
|
||||
"FILE_DOWNLOADED_BTN": "폴더 열기",
|
||||
"NAVIGATE_TO_TASK_ERR": "작업에 집중할 수 없습니다. 삭제하셨나요?",
|
||||
"PERSISTENCE_DISALLOWED": "데이터는 영구적으로 유지되지 않습니다. 이로 인해 데이터가 손실 될 수 있습니다 !!",
|
||||
"PERSISTENCE_ERROR": "데이터 유지 요청 시 오류: {{err}}",
|
||||
"RUNNING_X": "\"{{str}}\"실행 중.",
|
||||
"SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG": "{{keyCombo}} 을 눌렀지만 북마크 열기 바로 가기는 프로젝트 컨텍스트에서만 사용할 수 있습니다."
|
||||
"RUNNING_X": "\"{{str}}\"실행 중."
|
||||
},
|
||||
"GPB": {
|
||||
"ASSETS": "자산로드 중 ...",
|
||||
|
|
@ -1775,24 +1485,14 @@
|
|||
"SYNC": "방법: 동기화 구성"
|
||||
},
|
||||
"METRICS": "측정 항목",
|
||||
"NO_PROJECT_INFO": "사용 가능한 프로젝트가 없습니다. \"프로젝트 만들기\" 버튼을 클릭하여 새 프로젝트를 만들 수 있습니다.",
|
||||
"NO_TAG_INFO": "현재 태그가 없습니다. 작업을 추가하거나 편집할 때 `#yourTagName`을 입력하여 태그를 추가할 수 있습니다.",
|
||||
"NOTES": "노트",
|
||||
"NOTES_PANEL_INFO": "메모는 일정 및 일반 작업 목록 보기에서만 표시할 수 있습니다.",
|
||||
"PLANNER": "플래너",
|
||||
"PROCRASTINATE": "미루다",
|
||||
"PROJECT_MENU": "프로젝트 메뉴",
|
||||
"PROJECT_SETTINGS": "프로젝트 설정",
|
||||
"PROJECTS": "프로젝트",
|
||||
"QUICK_HISTORY": "빠른 기록",
|
||||
"SCHEDULE": "일정",
|
||||
"SEARCH": "검색",
|
||||
"SETTINGS": "설정",
|
||||
"SHOW_SEARCH_BAR": "검색창 표시",
|
||||
"TAGS": "태그",
|
||||
"TASK_LIST": "작업 목록",
|
||||
"TASKS": "할 일 목록",
|
||||
"TOGGLE_SHOW_BOOKMARKS": "북마크 표시 / 숨기기",
|
||||
"TOGGLE_SHOW_ISSUE_PANEL": "이슈 패널 표시/숨기기",
|
||||
"TOGGLE_SHOW_NOTES": "프로젝트 노트 표시 / 숨기기",
|
||||
"TOGGLE_TRACK_TIME": "추적 시작 / 중지 시간",
|
||||
|
|
@ -1853,14 +1553,12 @@
|
|||
},
|
||||
"PS": {
|
||||
"GLOBAL_SETTINGS": "전체 설정",
|
||||
"ISSUE_INTEGRATION": "이슈 통합",
|
||||
"PRIVACY_POLICY": "개인 정책",
|
||||
"PRODUCTIVITY_HELPER": "생산성 도우미",
|
||||
"PROJECT_SETTINGS": "프로젝트 별 설정",
|
||||
"PROVIDE_FEEDBACK": "피드백을 제공하다",
|
||||
"SYNC_EXPORT": "동기화 및 내보내기",
|
||||
"TAG_SETTINGS": "태그 별 설정",
|
||||
"TOGGLE_DARK_MODE": "어두운 모드 전환"
|
||||
"TAG_SETTINGS": "태그 별 설정"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"NEXT": "다음",
|
||||
|
|
@ -1869,26 +1567,7 @@
|
|||
"NO_SCHEDULED_TITLE": "하루 동안 예약된 작업",
|
||||
"REPEATED_TASKS": "반복 작업",
|
||||
"SCHEDULED_TASKS": "예약된 작업",
|
||||
"SCHEDULED_TASKS_WITH_TIME": "미리 알림이 있는 예약된 작업",
|
||||
"START_TASK": "지금 작업을 시작하고 알림 제거"
|
||||
},
|
||||
"THEMES": {
|
||||
"amber": "호박색",
|
||||
"blue": "푸른",
|
||||
"blue-grey": "청회색",
|
||||
"cyan": "시안 색",
|
||||
"deep-orange": "진한 오렌지",
|
||||
"deep-purple": "딥 퍼플",
|
||||
"green": "녹색",
|
||||
"indigo": "남빛",
|
||||
"light-blue": "하늘색",
|
||||
"light-green": "연한 초록색",
|
||||
"lime": "라임",
|
||||
"pink": "담홍색",
|
||||
"purple": "자주색",
|
||||
"SELECT_THEME": "주제 선택",
|
||||
"teal": "물오리",
|
||||
"yellow": "노랑"
|
||||
"SCHEDULED_TASKS_WITH_TIME": "미리 알림이 있는 예약된 작업"
|
||||
},
|
||||
"USER_PROFILES": {
|
||||
"ACTIVE": "활성",
|
||||
|
|
@ -1902,21 +1581,18 @@
|
|||
"EXISTING_PROFILES": "기존 프로필",
|
||||
"EXPORT_PROFILE": "프로필 내보내기",
|
||||
"MANAGE_PROFILES": "프로필 관리...",
|
||||
"OPEN_PROFILES_FOLDER": "프로필 폴더 열기",
|
||||
"PROFILE_NAME": "프로필 이름",
|
||||
"PROFILE_NAME_PLACEHOLDER": "예: 직장, 개인",
|
||||
"RENAME": "이름 변경",
|
||||
"SAVE": "저장"
|
||||
},
|
||||
"V": {
|
||||
"E_1TO10": "1에서 10 사이의 값을 입력하십시오.",
|
||||
"E_DATETIME": "입력 된 값은 datetime이 아닙니다!",
|
||||
"E_DURATION": "유효한 기간을 입력하세요(예: 1시간).",
|
||||
"E_MAX": " {{val}}보다 크지 않아야합니다.",
|
||||
"E_MAX_LENGTH": "최대 {{val}} 자 여야합니다.",
|
||||
"E_MIN": " {{val}}보다 작아야합니다.",
|
||||
"E_MIN_LENGTH": "최소 {{val}} 자 이상이어야합니다.",
|
||||
"E_PATTERN": "잘못된 입력",
|
||||
"E_REQUIRED": "이 입력란은 필수 항목입니다."
|
||||
},
|
||||
"WW": {
|
||||
|
|
@ -1927,10 +1603,7 @@
|
|||
"DONE_TASKS_IN_ARCHIVE": "현재 여기에는 완료된 작업이 없지만 이미 보관된 작업이 있습니다.",
|
||||
"ESTIMATE_REMAINING": "예상 남은 시간 :",
|
||||
"FINISH_DAY": "피니시 데이",
|
||||
"FINISH_DAY_FOR_PROJECT": "이 프로젝트의 마감일",
|
||||
"FINISH_DAY_FOR_TAG": "이 태그의 마감일",
|
||||
"FINISH_DAY_TOOLTIP": "하루를 평가하고, 완료된 모든 작업을 아카이브로 옮기거나(선택 사항) 다음 날을 계획하세요.",
|
||||
"HELP_PROCRASTINATION": "내가 미루는 걸 도와주세요!",
|
||||
"MOVE_DONE_TO_ARCHIVE": "보관으로 이동 완료",
|
||||
"NO_DONE_TASKS": "현재 완료된 작업이 없습니다",
|
||||
"NO_PLANNED_TASK_ALL_DONE": "모든 작업 완료",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,15 +1,4 @@
|
|||
{
|
||||
"ANDROID": {
|
||||
"NOTIFICATIONS": {
|
||||
"SYNC_CONFLICT_MSG": "Перевірте та вирішіть, що робити.",
|
||||
"SYNC_CONFLICT_TITLE": "Конфлікт синхронізації"
|
||||
},
|
||||
"PERMANENT_NOTIFICATION_MSGS": {
|
||||
"INITIAL": "Застосунок працює у фоновому режимі для синхронізації, якщо вона увімкнена",
|
||||
"NO_ACTIVE_TASKS": "Немає активних завдань",
|
||||
"SYNCING": "Синхронізація"
|
||||
}
|
||||
},
|
||||
"APP": {
|
||||
"B_INSTALL": {
|
||||
"IGNORE": "Ігнорувати",
|
||||
|
|
@ -17,8 +6,6 @@
|
|||
"MSG": "Бажаєте встановити Super Productivity як PWA?"
|
||||
},
|
||||
"B_OFFLINE": "Ви не підключені до інтернету. Синхронізація та запит даних з провайдера завдань не працюватимуть.",
|
||||
"UPDATE_MAIN_MODEL": "Super Productivity отримав важливе оновлення! Потрібно виконати міграцію даних. Зверніть увагу, що це зробить ваші дані несумісними зі старішими версіями програми.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "Оновлення моделі не вибрано. Зауважте, що вам доведеться або понизити версію до попередньої, або виконати оновлення моделі.",
|
||||
"UPDATE_WEB_APP": "Доступна нова версія. Завантажити нову версію?"
|
||||
},
|
||||
"BL": {
|
||||
|
|
@ -32,11 +19,7 @@
|
|||
"RESTORE_STRAY_BACKUP": "Під час останньої синхронізації могла виникнути помилка. Бажаєте відновити останню резервну копію?"
|
||||
},
|
||||
"DATETIME_SCHEDULE": {
|
||||
"LATER_TODAY": "Пізніше сьогодні",
|
||||
"NEXT_WEEK": "Наступного тижня",
|
||||
"PLACEHOLDER": "Виберіть дату",
|
||||
"PRESS_ENTER_AGAIN": "Натисніть Enter ще раз, щоб зберегти",
|
||||
"TOMORROW": "Завтра"
|
||||
"PRESS_ENTER_AGAIN": "Натисніть Enter ще раз, щоб зберегти"
|
||||
},
|
||||
"F": {
|
||||
"ATTACHMENT": {
|
||||
|
|
@ -44,7 +27,6 @@
|
|||
"ADD_ATTACHMENT": "Додати вкладення",
|
||||
"EDIT_ATTACHMENT": "Редагувати вкладення",
|
||||
"LABELS": {
|
||||
"FILE": "Шлях до файлу",
|
||||
"IMG": "Зображення",
|
||||
"LINK": "Посилання"
|
||||
},
|
||||
|
|
@ -60,7 +42,6 @@
|
|||
"DEFAULT": {
|
||||
"DONE": "Зробити",
|
||||
"EISENHAUER_MATRIX": "Матриця Ейзенхауера",
|
||||
"IMPORTANT": "Важливий",
|
||||
"IN_PROGRESS": "В процесі",
|
||||
"KANBAN": "Канбан",
|
||||
"NOT_URGENT_IMPORTANT": "Не терміново і не важливо",
|
||||
|
|
@ -97,9 +78,7 @@
|
|||
}
|
||||
},
|
||||
"CALDAV": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Налаштувати CalDav для проекту"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"CALDAV_CATEGORY_FILTER": "Категорія для фільтрації завдань (залиште порожнім, якщо не потрібно)",
|
||||
"CALDAV_PASSWORD": "Ваш пароль CalDav",
|
||||
|
|
@ -109,28 +88,7 @@
|
|||
"IS_TRANSITION_ISSUES_ENABLED": "Автоматично завершувати завдання CalDav при завершенні завдання"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення незавершених завдань CalDav для конкретного проекту в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично додавати та синхронізувати всі незавершені завдання до вашого беклогу завдань.</p><p>Щоб це працювало для nextcloud у веб-додатку, вам може знадобитися додати в білий список \"https://app.super-productivity.com\" через застосунок nextcloud <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword<a>.</p>",
|
||||
"TITLE": "CalDav"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Правонаступник",
|
||||
"AT": "при",
|
||||
"ATTACHMENTS": "Вкладення",
|
||||
"CHANGED": "змінений",
|
||||
"COMMENTS": "Коментарі",
|
||||
"COMPONENTS": "Компоненти",
|
||||
"DESCRIPTION": "Опис",
|
||||
"LABELS": "Категорії",
|
||||
"LIST_OF_CHANGES": "Перелік змін",
|
||||
"MARK_AS_CHECKED": "Позначити оновлення як відмічені",
|
||||
"ON": "на",
|
||||
"RELATED": "Пов'язані",
|
||||
"STATUS": "Статус",
|
||||
"STORY_POINTS": "Сюжетні моменти",
|
||||
"SUB_TASKS": "Підзавдання",
|
||||
"SUMMARY": "Підсумок",
|
||||
"WORKLOG": "Робочий журнал",
|
||||
"WRITE_A_COMMENT": "Написати коментар"
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення незавершених завдань CalDav для конкретного проекту в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично додавати та синхронізувати всі незавершені завдання до вашого беклогу завдань.</p><p>Щоб це працювало для nextcloud у веб-додатку, вам може знадобитися додати в білий список \"https://app.super-productivity.com\" через застосунок nextcloud <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword<a>.</p>"
|
||||
},
|
||||
"S": {
|
||||
"CALENDAR_NOT_FOUND": "CalDav: Календар \"{{calendarName}}\" не знайдено",
|
||||
|
|
@ -141,7 +99,6 @@
|
|||
"CALENDARS": {
|
||||
"BANNER": {
|
||||
"ADD_AS_TASK": "Додати як завдання",
|
||||
"FOCUS_TASK": "Зосередитись на завданні",
|
||||
"TXT": "<strong>{{title}}</strong> починається о <strong>{{start}}</strong>!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> починається о <strong>{{start}}</strong>!<br> (і ще {{nrOfOtherBanners}} подій заплановано)",
|
||||
"TXT_PAST": "<strong>{{title}}</strong> почалося о <strong>{{start}}</strong>!",
|
||||
|
|
@ -175,10 +132,6 @@
|
|||
},
|
||||
"DROPBOX": {
|
||||
"S": {
|
||||
"ACCESS_TOKEN_ERROR": "Dropbox: Неможливо згенерувати токен доступу з коду авторизації",
|
||||
"ACCESS_TOKEN_GENERATED": "Dropbox: Токен доступу згенеровано з коду авторизації",
|
||||
"AUTH_ERROR": "Dropbox: Наданий недійсний токен доступу",
|
||||
"AUTH_ERROR_ACTION": "Змінити токен",
|
||||
"OFFLINE": "Dropbox: Неможливо синхронізувати, оскільки немає підключення",
|
||||
"SYNC_ERROR": "Dropbox: Помилка під час синхронізації",
|
||||
"UNABLE_TO_GENERATE_PKCE_CHALLENGE": "Dropbox: Неможливо згенерувати PKCE-виклик."
|
||||
|
|
@ -195,36 +148,26 @@
|
|||
"TO_FOCUS_OVERLAY": "Накладання фокуса"
|
||||
},
|
||||
"BACK_TO_PLANNING": "Повернутись до планування",
|
||||
"CONGRATS": "Вітаємо з завершенням цього сеансу!",
|
||||
"CONTINUE_FOCUS_SESSION": "Продовжити сеанс фокусування",
|
||||
"COUNTDOWN": "Відлік",
|
||||
"FINISH_TASK_AND_SELECT_NEXT": "Завершити завдання і вибрати наступне",
|
||||
"FLOWTIME": "Час протікання",
|
||||
"FOR_TASK": "для завдання",
|
||||
"GET_READY": "Приготуйтеся до сеансу фокусування!",
|
||||
"GO_TO_PROCRASTINATION": "Отримати допомогу при прокрастинації",
|
||||
"GOGOGO": "Вперед, вперед, вперед!!!",
|
||||
"NEXT": "Далі",
|
||||
"ON": "на",
|
||||
"OPEN_ISSUE_IN_BROWSER": "Відкрити завдання в браузері",
|
||||
"PREP_GET_MENTALLY_READY": "Підготуйтеся ментально бути зосередженим і продуктивним",
|
||||
"PREP_SIT_UPRIGHT": "Сядьте (або встаньте) прямо",
|
||||
"PREP_STRETCH": "Зробіть легку розтяжку",
|
||||
"SELECT_ANOTHER_TASK": "Вибрати інше завдання",
|
||||
"SELECT_TASK": "Виберіть завдання для фокусування",
|
||||
"SESSION_COMPLETED": "Фокус-сесія завершена!",
|
||||
"SET_FOCUS_SESSION_DURATION": "Встановити тривалість сеансу фокусування",
|
||||
"SHOW_HIDE_NOTES_AND_ATTACHMENTS": "Показати/приховати нотатки та вкладення завдання",
|
||||
"START_FOCUS_SESSION": "Розпочати сеанс фокусування",
|
||||
"START_NEXT_FOCUS_SESSION": "Розпочати наступний сеанс фокусування",
|
||||
"WORKED_FOR": "Ви працювали протягом"
|
||||
},
|
||||
"GITEA": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Налаштувати Gitea для проекту"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Ім'я користувача (наприклад, для фільтрації власних змін)",
|
||||
"HOST": "Хост (наприклад: https://try.gitea.io)",
|
||||
"REPO_FULL_NAME": "Ім'я користувача або назва організації/проекту",
|
||||
"REPO_FULL_NAME_DESCRIPTION": "Можна знайти як частину URL-адреси при перегляді проекту в браузері.",
|
||||
|
|
@ -235,12 +178,10 @@
|
|||
"TOKEN": "Токен доступу"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих завдань Gitea для конкретного репозиторію в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично додавати та імпортувати всі відкриті завдання.</p><p>Щоб обійти обмеження використання та отримати доступ, ви можете надати токен доступу.",
|
||||
"TITLE": "Gitea"
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих завдань Gitea для конкретного репозиторію в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично додавати та імпортувати всі відкриті завдання.</p><p>Щоб обійти обмеження використання та отримати доступ, ви можете надати токен доступу."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Призначено",
|
||||
"AT": "у",
|
||||
"DESCRIPTION": "Опис",
|
||||
"LABELS": "Мітки",
|
||||
"MARK_AS_CHECKED": "Позначити оновлення як відмічені",
|
||||
|
|
@ -249,14 +190,10 @@
|
|||
"SUMMARY": "Підсумок",
|
||||
"WRITE_A_COMMENT": "Написати коментар"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Gitea: Невідома помилка {{statusCode}} {{errorMsg}}. Перевищено ліміт API?"
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"GITHUB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Налаштувати GitHub для проекту"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Ім'я користувача (наприклад, для фільтрації власних змін)",
|
||||
"INVALID_TOKEN_MESSAGE": "Недійсний токен GitHub. Він повинен починатися з \"ghp_\".",
|
||||
|
|
@ -265,8 +202,7 @@
|
|||
"TOKEN": "Токен доступу"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих завдань GitHub для конкретного репозиторію в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично імпортувати всі відкриті завдання.</p><p>Щоб обійти обмеження використання та отримати доступ, ви можете надати токен доступу. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>Більше інформації про його області можна знайти тут</a>.",
|
||||
"TITLE": "GitHub"
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих завдань GitHub для конкретного репозиторію в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично імпортувати всі відкриті завдання.</p><p>Щоб обійти обмеження використання та отримати доступ, ви можете надати токен доступу. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>Більше інформації про його області можна знайти тут</a>."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Призначено",
|
||||
|
|
@ -287,9 +223,7 @@
|
|||
}
|
||||
},
|
||||
"GITLAB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Налаштувати GitLab для проекту"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"DIALOG_SUBMIT_WORKLOG": {
|
||||
"PAST_DAY_INFO": "Заповнений час містить невідстежені дані з минулих днів.",
|
||||
"T_ALREADY_TRACKED": "Вже відстежено",
|
||||
|
|
@ -318,8 +252,7 @@
|
|||
"TOKEN": "Токен доступу"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих завдань GitLab (онлайн-версія або власна інстанція) для конкретного проекту в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично імпортувати всі відкриті завдання.</p>",
|
||||
"TITLE": "GitLab"
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих завдань GitLab (онлайн-версія або власна інстанція) для конкретного проекту в панелі створення завдань у вікні щоденного планування. Вони будуть показані як пропозиції та надаватимуть посилання на завдання, а також додаткову інформацію про нього.</p> <p>Крім того, ви можете автоматично імпортувати всі відкриті завдання.</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Призначено",
|
||||
|
|
@ -351,20 +284,14 @@
|
|||
"ATTACHMENTS": "Вкладення",
|
||||
"AUTHOR": "Автор",
|
||||
"CATEGORY": "Категорія",
|
||||
"CHANGED": "змінений",
|
||||
"COMMENTS": "Коментарі",
|
||||
"COMPONENTS": "Компоненти",
|
||||
"DESCRIPTION": "Опис",
|
||||
"DONE_RATIO": "Коефіцієнт готовності",
|
||||
"DUE_DATE": "Термін виконання",
|
||||
"LABELS": "Етикетки",
|
||||
"LAST_COMMENT": "Останній коментар",
|
||||
"LIST_OF_CHANGES": "Перелік змін",
|
||||
"LOAD_ALL_COMMENTS": "Завантажити всі {{nr}} коментарі",
|
||||
"LOAD_DESCRIPTION_AND_ALL_COMMENTS": "Завантажити опис та всі коментарі",
|
||||
"LOCATION": "Місце",
|
||||
"MARK_AS_CHECKED": "Позначити оновлення як позначені",
|
||||
"ON": "на",
|
||||
"PRIORITY": "Пріоритет",
|
||||
"RELATED": "Пов'язані",
|
||||
"START": "Почати",
|
||||
|
|
@ -375,8 +302,7 @@
|
|||
"TIME_SPENT": "Витрачений час",
|
||||
"TYPE": "Тип",
|
||||
"VERSION": "Версія",
|
||||
"WORKLOG": "Робочий журнал",
|
||||
"WRITE_A_COMMENT": "Написати коментар"
|
||||
"WORKLOG": "Робочий журнал"
|
||||
},
|
||||
"S": {
|
||||
"ERR_GENERIC": "{{issueProviderName}} Помилка: {{errTxt}}",
|
||||
|
|
@ -384,13 +310,9 @@
|
|||
"ERR_NOT_CONFIGURED": "{{issueProviderName}}: Неправильно налаштовано",
|
||||
"IMPORTED_MULTIPLE_ISSUES": "{{issueProviderName}}: Імпортовано {{nr}} нових {{issuesStr}}",
|
||||
"IMPORTED_SINGLE_ISSUE": "{{issueProviderName}}: Імпортовано {{issueStr}} \"{{issueTitle}}\"",
|
||||
"ISSUE_DELETED_OR_CLOSED": "{{issueProviderName}}: {{issueStrC}} \"{{issueTitle}}\" здається видаленим або закритим",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "{{issueProviderName}}: Оновлення не потрібне",
|
||||
"ISSUE_UPDATE_MULTIPLE": "{{issueProviderName}}: Оновлено дані для {{nr}} {{issuesStr}}",
|
||||
"ISSUE_UPDATE_SINGLE": "{{issueProviderName}}: Оновлено дані для \"{{issueTitle}}\"",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "{{issueProviderName}}: Оновлено дані для \"{{issueTitle}}\"",
|
||||
"MISSING_ISSUE_DATA": "{{issueProviderName}}: Знайдено завдання з відсутніми даними {{issueStr}}. Перезавантаження.",
|
||||
"NEW_COMMENT": "{{issueProviderName}}: Новий коментар для \"{{issueTitle}}\"",
|
||||
"POLLING_BACKLOG": "{{issueProviderName}}: Опитування нових {{issuesStr}}",
|
||||
"POLLING_CHANGES": "{{issueProviderName}}: Опитування змін для {{issuesStr}}"
|
||||
}
|
||||
|
|
@ -427,8 +349,7 @@
|
|||
"CURRENT_ASSIGNEE": "Поточний виконавець:",
|
||||
"CURRENT_STATUS": "Поточний статус:",
|
||||
"TASK_NAME": "Назва завдання:",
|
||||
"TITLE": "Jira: Оновити статус",
|
||||
"UPDATE_STATUS": "Оновити статус"
|
||||
"TITLE": "Jira: Оновити статус"
|
||||
},
|
||||
"DIALOG_WORKLOG": {
|
||||
"CHECKBOXES": {
|
||||
|
|
@ -463,8 +384,7 @@
|
|||
"HOST": "Хост (наприклад: http://my-host.de:1234)",
|
||||
"PASSWORD": "Токен / Пароль",
|
||||
"USE_PAT": "Використовувати персональний токен доступу замість пароля",
|
||||
"USER_NAME": "Електронна пошта / Ім'я користувача",
|
||||
"WONKY_COOKIE_MODE": "Резервний режим автентифікації через Wonky Cookie (лише для десктопної версії)"
|
||||
"USER_NAME": "Електронна пошта / Ім'я користувача"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"ADV_CFG": "Розширені налаштування",
|
||||
|
|
@ -506,23 +426,12 @@
|
|||
"EXTENSION_NOT_LOADED": "Розширення Super Productivity не завантажено. Перезавантаження сторінки може допомогти",
|
||||
"INSUFFICIENT_SETTINGS": "Недостатньо налаштувань для Jira",
|
||||
"INVALID_RESPONSE": "Jira: Відповідь містила недійсні дані",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "Jira: \"{{issueText}}\" вже оновлено",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "Jira: Оновлено дані для \"{{issueText}}\"",
|
||||
"MISSING_ISSUE_DATA": "Jira: Знайдено завдання з відсутніми даними. Перезавантаження.",
|
||||
"NO_AUTO_IMPORT_JQL": "Jira: Не визначено пошуковий запит для автоматичного імпорту",
|
||||
"NO_VALID_TRANSITION": "Jira: Не налаштовано дійсний перехід",
|
||||
"TIMED_OUT": "Jira: Запит завершився з перевищенням часу очікування",
|
||||
"TRANSITION": "Jira: Встановлено завдання \"{{issueKey}}\" на \"{{name}}\"",
|
||||
"TRANSITION_SUCCESS": "Jira: Встановлено завдання {{issueKey}} на <strong>{{chosenTransition}}</strong>",
|
||||
"TRANSITIONS_LOADED": "Jira: Переходи завантажено. Використовуйте вибір нижче, щоб призначити їх",
|
||||
"UNABLE_TO_REASSIGN": "Jira: Неможливо перепризначити завдання собі, оскільки ви не вказали ім'я користувача. Будь ласка, відвідайте налаштування."
|
||||
},
|
||||
"STEPPER": {
|
||||
"CREDENTIALS": "Облікові дані",
|
||||
"DONE": "Ви завершили.",
|
||||
"LOGIN_SUCCESS": "Вхід успішний!",
|
||||
"TEST_CREDENTIALS": "Перевірити облікові дані",
|
||||
"WELCOME_USER": "Ласкаво просимо, {{user}}!"
|
||||
"TRANSITIONS_LOADED": "Jira: Переходи завантажено. Використовуйте вибір нижче, щоб призначити їх"
|
||||
}
|
||||
},
|
||||
"MARKDOWN_PASTE": {
|
||||
|
|
@ -534,9 +443,7 @@
|
|||
"DIALOG_TITLE": "Виявлено вставлений список Markdown!"
|
||||
},
|
||||
"METRIC": {
|
||||
"BANNER": {
|
||||
"CHECK": "Я це зробив!"
|
||||
},
|
||||
"BANNER": {},
|
||||
"CMP": {
|
||||
"AVG_BREAKS_PER_DAY": "Сер. перерв на день",
|
||||
"AVG_TASKS_PER_DAY_WORKED": "Сер. завдань на робочий день",
|
||||
|
|
@ -546,7 +453,6 @@
|
|||
"COUNTING_SUBTASKS": "(включаючи підзавдання)",
|
||||
"DAYS_WORKED": "Відпрацьовані дні",
|
||||
"GLOBAL_METRICS": "Глобальні метрики",
|
||||
"MOOD_PRODUCTIVITY_OVER_TIME": "Настрій та продуктивність з часом",
|
||||
"NO_ADDITIONAL_DATA_YET": "Додаткові дані ще не зібрані. Використовуйте форму на панелі \"Оцінка\" щоденного підсумку, щоб зробити це.",
|
||||
"SIMPLE_CLICK_COUNTERS_OVER_TIME": "Прості лічильники кліків з часом",
|
||||
"SIMPLE_COUNTERS": "Прості лічильники",
|
||||
|
|
@ -556,30 +462,13 @@
|
|||
"TIME_SPENT": "Витрачений час"
|
||||
},
|
||||
"EVAL_FORM": {
|
||||
"ADD_NOTE_FOR_TOMORROW": "Додати нотатку на завтра",
|
||||
"DISABLE_REPEAT_EVERY_DAY": "Вимкнути повторення щодня",
|
||||
"ENABLE_REPEAT_EVERY_DAY": "Повторювати щодня",
|
||||
"HELP_H1": "Чому це важливо?",
|
||||
"HELP_LINK_TXT": "Перейти до розділу метрик",
|
||||
"HELP_P1": "Час для невеликої самооцінки! Ваші відповіді тут зберігаються і надають вам невелику статистику про те, як ви працюєте, в розділі метрик. Крім того, пропозиції на завтра з'являться над вашим списком завдань наступного дня.",
|
||||
"HELP_P2": "Це призначено не стільки для обчислення точних метрик або досягнення машиноподібної ефективності у всьому, що ви робите, скільки для покращення того, як ви почуваєтеся щодо своєї роботи. Може бути корисно оцінити проблемні моменти у вашій щоденній рутині, а також знайти фактори, які вам допомагають. Бути трохи систематичним у цьому, сподіваємось, допоможе краще зрозуміти ці аспекти та покращити те, що можливо.",
|
||||
"IMPROVEMENTS": "Що покращило вашу продуктивність?",
|
||||
"IMPROVEMENTS_TOMORROW": "Що ви могли б зробити, щоб покращити завтрашній день?",
|
||||
"MOOD": "Як ви себе почуваєте?",
|
||||
"MOOD_HINT": "1: Жахливо – 10: Чудово",
|
||||
"NOTES": "Нотатки на завтра",
|
||||
"OBSTRUCTIONS": "Що заважало вашій продуктивності?",
|
||||
"PRODUCTIVITY": "Наскільки ефективно ви працювали?",
|
||||
"PRODUCTIVITY_HINT": "1: Навіть не починав – 10: Надзвичайно ефективно"
|
||||
"PRODUCTIVITY": "Наскільки ефективно ви працювали?"
|
||||
},
|
||||
"S": {
|
||||
"SAVE_METRIC": "Метрику успішно збережено"
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"NOTE": {
|
||||
"D_ADD": {
|
||||
"NOTE_LABEL": "Введіть текст для збереження як нотатку (ви можете використовувати markdown)..."
|
||||
},
|
||||
"D_ADD": {},
|
||||
"D_FULLSCREEN": {
|
||||
"VIEW_PARSED": "Переглянути як опрацьований (не редагований) markdown",
|
||||
"VIEW_SPLIT": "Переглянути опрацьований та неопрацьований markdown у розділеному вигляді",
|
||||
|
|
@ -611,9 +500,7 @@
|
|||
"SELECT_ISSUE_FOR_TRANSITIONS": "Виберіть завдання для завантаження доступних переходів",
|
||||
"TRANSITION": "Обробка переходів"
|
||||
},
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Налаштувати OpenProject для проекту"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"DIALOG_TRACK_TIME": {
|
||||
"ACTIVITY": "Діяльність",
|
||||
"CURRENTLY_LOGGED": "Наразі зареєстрований час: ",
|
||||
|
|
@ -630,8 +517,7 @@
|
|||
"CURRENT_STATUS": "Поточний статус:",
|
||||
"PERCENTAGE_DONE": "Прогрес:",
|
||||
"TASK_NAME": "Назва завдання:",
|
||||
"TITLE": "OpenProject: Оновити статус",
|
||||
"UPDATE_STATUS": "Оновити статус"
|
||||
"TITLE": "OpenProject: Оновити статус"
|
||||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Ім'я користувача (наприклад, для фільтрації власних змін)",
|
||||
|
|
@ -648,8 +534,7 @@
|
|||
"TOKEN": "Токен доступу"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих робочих пакетів OpenProject. Зверніть увагу, що для роботи в браузері вам, ймовірно, потрібно налаштувати CORS для вашого сервера OpenProject, щоб дозволити доступ з app.super-productivity.com</p>",
|
||||
"TITLE": "OpenProject"
|
||||
"HELP": "<p>Тут ви можете налаштувати SuperProductivity для відображення відкритих робочих пакетів OpenProject. Зверніть увагу, що для роботи в браузері вам, ймовірно, потрібно налаштувати CORS для вашого сервера OpenProject, щоб дозволити доступ з app.super-productivity.com</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Призначено",
|
||||
|
|
@ -677,9 +562,7 @@
|
|||
"PLANNER": {
|
||||
"D": {
|
||||
"ADD_PLANNED": {
|
||||
"ADD_TO_TODAY": "Додати до Сьогодні",
|
||||
"RE_PLAN_ALL": "Перенести всіх",
|
||||
"TITLE": "Додати заплановані завдання до Сьогодні"
|
||||
"RE_PLAN_ALL": "Перенести всіх"
|
||||
}
|
||||
},
|
||||
"EDIT_REPEATED_TASK": "Редагувати повторюване завдання '{{taskName}}'",
|
||||
|
|
@ -691,67 +574,15 @@
|
|||
"REMOVED_PLAN_DATE": "Видалено дату плану для завдання '{{taskTitle}}'",
|
||||
"TASK_ALREADY_PLANNED": "Завдання вже заплановано на {{date}}",
|
||||
"TASK_PLANNED_FOR": "Завдання заплановано на {{date}}"
|
||||
},
|
||||
"TASK_DRAWER": "Скринька завдань"
|
||||
}
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_IS_DONE": "Ваша перерва закінчилася!"
|
||||
},
|
||||
"PROCRASTINATION": {
|
||||
"BACK_TO_WORK": "Повертайтеся до роботи!",
|
||||
"COMP": {
|
||||
"INTRO": "Люди з високим рівнем прокрастинації зазвичай мають низьке самоспівчуття. Тож практикуйте його! Це покращує почуття власної гідності, сприяє позитивним емоціям і може допомогти подолати прокрастинацію, звичайно. Спробуйте невелику вправу:",
|
||||
"L1": "Присядьте трохи і потягніться, якщо хочете, трохи заспокойтеся",
|
||||
"L2": "Спробуйте прислухатися до думок і почуттів, які виникають",
|
||||
"L3": "Чи відповідаєте ви собі так, як відповіли б другу?",
|
||||
"L4": "Якщо відповідь ні, уявіть свого друга у вашій ситуації. Що б ви сказали йому? Що б ви зробили для нього?",
|
||||
"OUTRO": "Більше вправ <a target=\"_blank\" href=\"https://drsoph.com/blog/2018/9/17/3-exercises-in-self-compassion\" target=\"_blank\">можна знайти тут</a> або на <a target=\"_blank\" href=\"https://www.google.com/search?q=self+compassion+exercises&oq=self+compassion+excers&aqs=chrome.1.69i57j0l5.4303j0j7&sourceid=chrome&ie=UTF-8\" target=\"_blank\">Google</a>.",
|
||||
"TITLE": "Співчуття до себе"
|
||||
},
|
||||
"CUR": {
|
||||
"INTRO": "Хіба прокрастинація не цікава? Здається, що в ній немає жодного сенсу, оскільки вона зовсім не відповідає вашим довгостроковим інтересам. Але все ж всі це роблять. Дуже допомагає досліджувати і краще розуміти, як це працює для вас особисто! Деякі основні питання, які варто собі поставити:",
|
||||
"L1": "Які почуття викликають у вас спокусу прокрастинувати?",
|
||||
"L2": "Де ви відчуваєте їх у своєму тілі?",
|
||||
"L3": "Про що вони вам нагадують?",
|
||||
"L4": "Що відбувається з думкою про прокрастинацію, коли ви її спостерігаєте? Вона посилюється? Розсіюється? Викликає інші емоції?",
|
||||
"L5": "Як змінюються відчуття у вашому тілі, коли ви продовжуєте зосереджувати на них свою увагу?",
|
||||
"PROCRASTINATION_TRIGGERS_TEXT": "Інший дуже ефективний метод - записувати, що викликало ваше бажання прокрастинувати. Наприклад, я особисто часто маю бажання швидко перейти на Reddit або свій улюблений новинний сайт, коли вікно браузера потрапляє у фокус. З того часу, як я почав записувати свої тригери в простому порожньому текстовому документі, я усвідомив, наскільки вкоріненим був цей шаблон, і це допомогло мені експериментувати з різними контрзаходами.",
|
||||
"PROCRASTINATION_TRIGGERS_TITLE": "Запис ваших тригерів прокрастинації",
|
||||
"TITLE": "Цікавість"
|
||||
},
|
||||
"H1": "Дайте собі трохи спокою!",
|
||||
"INTRO": {
|
||||
"AVOIDING": "Уникнення завдання",
|
||||
"FEAR": "Страх невдачі",
|
||||
"STRESSED": "Стрес через невиконання справ",
|
||||
"TITLE": "Вступ"
|
||||
},
|
||||
"P1": "Перш за все: Розслабтеся! Кожен час від часу прокрастинує. І якщо ви не робите те, що повинні, ви принаймні повинні насолоджуватися цим!",
|
||||
"P2": "Пам'ятайте: <b>Прокрастинація - це проблема регулювання емоцій, а не управління часом.</b> Це означає, що самобичування не є рішенням, це частина проблеми. Нехай це осяде, а потім перегляньте інші вкладки тут для подальшої допомоги.",
|
||||
"REFRAME": {
|
||||
"INTRO": "Подумайте про те, що може бути позитивного в завданні, незважаючи на його недоліки.",
|
||||
"TITLE": "Переосмислення",
|
||||
"TL1": "Що може бути в ньому цікавого?",
|
||||
"TL2": "Що можна отримати, якщо його виконати?",
|
||||
"TL3": "Як ви будете почуватися, якщо виконаєте його?"
|
||||
},
|
||||
"SPLIT_UP": {
|
||||
"INTRO": "Розбийте завдання на якомога більше маленьких частин.",
|
||||
"OUTRO": "Готово? Тепер подумайте про це. Що було б - суто теоретично - першим, що ви б зробили, <i>якби</i> ви почали працювати над завданням? Просто подумайте про це...",
|
||||
"TITLE": "Розділити на частини!"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "Створити проект",
|
||||
"EDIT": "Редагувати проект",
|
||||
"SETUP_CALDAV": "Налаштувати інтеграцію CalDAV",
|
||||
"SETUP_GIT": "Налаштувати інтеграцію GitHub",
|
||||
"SETUP_GITEA_PROJECT": "Налаштувати інтеграцію Gitea",
|
||||
"SETUP_GITLAB": "Налаштувати інтеграцію GitLab",
|
||||
"SETUP_JIRA": "Налаштувати інтеграцію Jira",
|
||||
"SETUP_OPEN_PROJECT": "Налаштувати інтеграцію OpenProject",
|
||||
"SETUP_REDMINE_PROJECT": "Налаштувати інтеграцію Redmine"
|
||||
"EDIT": "Редагувати проект"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"MSG": "Ви впевнені, що хочете видалити проект \"{{title}}\"?"
|
||||
|
|
@ -763,7 +594,6 @@
|
|||
"TITLE": "Основні налаштування"
|
||||
},
|
||||
"FORM_THEME": {
|
||||
"D_IS_DARK_THEME": "Не буде використовуватись, якщо система підтримує глобальний темний режим.",
|
||||
"HELP": "Налаштування теми для вашого проекту.",
|
||||
"L_BACKGROUND_IMAGE_DARK": "URL фонового зображення (темна тема)",
|
||||
"L_BACKGROUND_IMAGE_LIGHT": "URL фонового зображення (світла тема)",
|
||||
|
|
@ -775,18 +605,13 @@
|
|||
"L_HUE_WARN": "Поріг для темного тексту на фоні кольору попередження",
|
||||
"L_IS_AUTO_CONTRAST": "Автоматично встановлювати кольори тексту для кращої читабельності",
|
||||
"L_IS_DISABLE_BACKGROUND_TINT": "Вимкнути кольоровий фоновий градієнт",
|
||||
"L_IS_REDUCED_THEME": "Використовувати спрощений інтерфейс (без рамок навколо завдань)",
|
||||
"L_THEME_COLOR": "Колір теми",
|
||||
"L_TITLE": "Назва",
|
||||
"TITLE": "Тема"
|
||||
},
|
||||
"S": {
|
||||
"ARCHIVED": "Проект архівовано",
|
||||
"CREATED": "Створено проект <strong>{{title}}</strong>. Ви можете вибрати його з меню зверху зліва.",
|
||||
"DELETED": "Проект видалено",
|
||||
"E_EXISTS": "Проект \"{{title}}\" вже існує",
|
||||
"E_INVALID_FILE": "Недійсні дані для файлу проекту",
|
||||
"ISSUE_PROVIDER_UPDATED": "Оновлено налаштування проекту для <strong>{{issueProviderKey}}</strong>",
|
||||
"UNARCHIVED": "Проект розархівовано",
|
||||
"UPDATED": "Оновлено налаштування проекту"
|
||||
}
|
||||
|
|
@ -797,9 +622,7 @@
|
|||
"WEEK_TITLE": "Тиждень {{nr}} ({{timeSpent}})"
|
||||
},
|
||||
"REDMINE": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Налаштувати Redmine для проекту"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"API_KEY": "Ключ доступу API",
|
||||
"HOST": "Хост (наприклад: https://redmine.org)",
|
||||
|
|
@ -821,13 +644,10 @@
|
|||
"PRIORITY": "Пріоритет",
|
||||
"STATUS": "Статус"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Redmine: Невідома помилка {{statusCode}} {{errorMsg}}."
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"REMINDER": {
|
||||
"COUNTDOWN_BANNER": {
|
||||
"HIDE": "Приховати",
|
||||
"START_NOW": "Почати зараз",
|
||||
"TXT": "<strong>{{title}}</strong> починається о <strong>{{start}}</strong>!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> починається о <strong>{{start}}</strong>!<br> (і ще {{nrOfOtherBanners}} завдань заплановано)"
|
||||
|
|
@ -836,27 +656,19 @@
|
|||
"S_REMINDER_ERR": "Помилка для інтерфейсу нагадувань"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"CONTINUED": "продовжено",
|
||||
"D_INITIAL": {
|
||||
"TEXT": "<p>Розклад повинен надати вам кращу картину того, як ваші заплановані завдання розгортаються в часі. Він автоматично генерується з ваших завдань і вимагає лише <strong>оцінок часу для них, щоб працювати</strong>.</p><p>Розрізняють два типи: <strong>Заплановані завдання</strong>, які показуються в їх запланований час, і <strong>Звичайні завдання</strong>, які повинні розташовуватися навколо цих фіксованих подій.</p><p>Якщо ви вказуєте час початку та закінчення роботи (рекомендовано), звичайні завдання ніколи не показуватимуться поза цими межами.</p>",
|
||||
"TITLE": "Розклад"
|
||||
},
|
||||
"END": "Кінець роботи",
|
||||
"LUNCH_BREAK": "Обідня перерва",
|
||||
"NO_TASKS": "Наразі немає завдань. Будь ласка, додайте деякі завдання за допомогою кнопки + у верхній панелі.",
|
||||
"NOW": "Зараз",
|
||||
"PLAN_END_DAY": "Запланувати в кінці дня",
|
||||
"PLAN_START_DAY": "Запланувати на початку дня",
|
||||
"START": "Початок роботи",
|
||||
"TASK_PROJECTION_INFO": "Майбутня проекція запланованого повторюваного завдання"
|
||||
"START": "Початок роботи"
|
||||
},
|
||||
"SEARCH_BAR": {
|
||||
"INFO": "Натисніть на іконку списку, щоб шукати архівовані завдання",
|
||||
"INFO_ARCHIVED": "Натисніть на іконку архіву, щоб шукати звичайні завдання",
|
||||
"NO_RESULTS": "Не знайдено завдань, які б відповідали вашому пошуку",
|
||||
"PLACEHOLDER": "Шукати завдання або опис завдання",
|
||||
"PLACEHOLDER_ARCHIVED": "Шукати архівовані завдання",
|
||||
"TOO_MANY_RESULTS": "Занадто багато результатів, будь ласка, уточніть пошук"
|
||||
"PLACEHOLDER": "Шукати завдання або опис завдання"
|
||||
},
|
||||
"SIMPLE_COUNTER": {
|
||||
"D_CONFIRM_REMOVE": {
|
||||
|
|
@ -875,7 +687,6 @@
|
|||
"L_COUNTDOWN_DURATION": "Тривалість зворотного відліку",
|
||||
"L_DAILY_GOAL": "Щоденна мета для успішної серії",
|
||||
"L_ICON": "Іконка",
|
||||
"L_ICON_ON": "Іконка при активації",
|
||||
"L_IS_ENABLED": "Увімкнено",
|
||||
"L_TITLE": "Назва",
|
||||
"L_TRACK_STREAKS": "Track Streaks",
|
||||
|
|
@ -893,18 +704,10 @@
|
|||
},
|
||||
"SYNC": {
|
||||
"A": {
|
||||
"ARCHIVE_ONLY_UPLOADED": "Ваші дані були завантажені лише частково. Будь ласка, спробуйте ще раз пізніше! Інакше ви не зможете синхронізувати свої дані з іншими пристроями.",
|
||||
"POSSIBLE_LEGACY_DATA": "Super Productivity тепер покращив синхронізацію, використовуючи два окремі файли замість одного, що дозволяє значно зменшити передачу даних. Рекомендується оновити всі екземпляри Super Productivity і спочатку синхронізувати дані з екземпляра додатку, де дані найновіші. Якщо це дані з вашого локального пристрою, то, будь ласка, ігноруйте це попередження і просто продовжуйте їх завантажувати, підтвердивши наступний діалог.",
|
||||
"REMOTE_MODEL_VERSION_NEWER": "Версія виносної моделі новіша за локальну. Будь ласка, оновіть свій локальний додаток до останньої версії!"
|
||||
},
|
||||
"C": {
|
||||
"EMPTY_SYNC": "Ви намагаєтесь синхронізувати порожній об'єкт даних. Якщо ви намагаєтесь налаштувати синхронізацію з нового екземпляра додатку, просто натисніть OK, щоб завантажити дані з сервера. В іншому випадку, будь ласка, перевірте свої дані.",
|
||||
"FORCE_UPLOAD": "Все одно завантажити локальні дані?",
|
||||
"FORCE_UPLOAD_AFTER_ERROR": "Виникла помилка під час завантаження ваших локальних даних. Спробувати примусово оновити?",
|
||||
"MIGRATE_LEGACY": "Виявлено застарілі дані під час імпорту, бажаєте спробувати їх мігрувати?",
|
||||
"NO_REMOTE_DATA": "Віддалені дані не знайдено. Завантажити локальні на віддалений сервер?",
|
||||
"TRY_LOAD_REMOTE_AGAIN": "Спробувати повторно завантажити дані з віддаленого сервера?",
|
||||
"UNABLE_TO_LOAD_REMOTE_DATA": "Неможливо завантажити дані з віддаленого сервера. Бажаєте спробувати перезаписати віддалені дані вашими локальними даними? Всі віддалені дані будуть втрачені в процесі."
|
||||
"FORCE_UPLOAD": "Все одно завантажити локальні дані?"
|
||||
},
|
||||
"D_AUTH_CODE": {
|
||||
"FOLLOW_LINK": "Будь ласка, відкрийте наступне посилання і скопіюйте код авторизації, наданий там, у поле введення нижче.",
|
||||
|
|
@ -913,8 +716,6 @@
|
|||
"TITLE": "Логін: {{provider}}"
|
||||
},
|
||||
"D_CONFLICT": {
|
||||
"LAMPORT_CLOCK": "Перегляд",
|
||||
"LAST_CHANGE": "Остання зміна:",
|
||||
"LAST_SYNC": "Остання синхронізація:",
|
||||
"LOCAL": "Локальні",
|
||||
"LOCAL_REMOTE": "Локальні -> Віддалені",
|
||||
|
|
@ -938,10 +739,6 @@
|
|||
"BTN_FORCE_UPLOAD": "Примусово завантажити локальні",
|
||||
"P1": "Дані віддаленої синхронізації незв'язні!",
|
||||
"P2": "Модель, на яку вплинула:",
|
||||
"P3": "У вас є 2 варіанти:",
|
||||
"P4": "1. Перейдіть на інший пристрій і спробуйте виконати там повну синхронізацію.",
|
||||
"P5": "2. Перезапишіть віддалені дані локальними даними. Всі віддалені зміни будуть втрачені!",
|
||||
"P6": "Рекомендується створити резервну копію даних, які ви перезаписуєте!!",
|
||||
"T1": "Остання синхронізація була неповною!",
|
||||
"T2": "Ваші архівні дані не були належним чином завантажені під час останньої синхронізації:",
|
||||
"T3": "У вас є 2 варіанти:",
|
||||
|
|
@ -953,19 +750,9 @@
|
|||
"SAVE_AND_ENABLE": "Зберегти та увімкнути синхронізацію",
|
||||
"TITLE": "Налаштуйте синхронізацію"
|
||||
},
|
||||
"D_PERMISSION": {
|
||||
"DISABLE_SYNC": "Вимкнути синхронізацію",
|
||||
"PERM_FILE": "Надати дозвіл",
|
||||
"TEXT": "<p>Ваш дозвіл на доступ до локального файлу для синхронізації було відкликано.</p>",
|
||||
"TITLE": "Синхронізація: Відмовлено в доступі до локального файлу"
|
||||
},
|
||||
"FORM": {
|
||||
"DROPBOX": {
|
||||
"L_ACCESS_TOKEN": "Токен доступу (згенерований з коду авторизації)"
|
||||
},
|
||||
"GOOGLE": {
|
||||
"L_SYNC_FILE_NAME": "Назва файлу синхронізації"
|
||||
},
|
||||
"DROPBOX": {},
|
||||
"GOOGLE": {},
|
||||
"L_ENABLE_COMPRESSION": "Увімкнути стиснення (швидша передача даних)",
|
||||
"L_ENABLE_ENCRYPTION": "Увімкнути наскрізне шифрування (експериментально) – Зробіть ваші дані недоступними для вашого провайдера синхронізації",
|
||||
"L_ENABLE_SYNCING": "Увімкнути синхронізацію",
|
||||
|
|
@ -974,7 +761,6 @@
|
|||
"L_SYNC_INTERVAL": "Інтервал синхронізації",
|
||||
"L_SYNC_PROVIDER": "Провайдер синхронізації",
|
||||
"LOCAL_FILE": {
|
||||
"L_SYNC_FILE_PATH_PERMISSION_VALIDATION": "Потрібен дозвіл на доступ до файлу",
|
||||
"L_SYNC_FOLDER_PATH": "Шлях до папки синхронізації"
|
||||
},
|
||||
"TITLE": "Синхронізація",
|
||||
|
|
@ -988,28 +774,18 @@
|
|||
},
|
||||
"S": {
|
||||
"ALREADY_IN_SYNC": "Вже синхронізовано",
|
||||
"ALREADY_IN_SYNC_NO_LOCAL_CHANGES": "Немає локальних змін – Вже синхронізовано",
|
||||
"BTN_CONFIGURE": "Настроїти",
|
||||
"BTN_FORCE_OVERWRITE": "Примусовий перезапис",
|
||||
"ERROR_DATA_IS_CURRENTLY_WRITTEN": "На даний момент ведеться запис віддалених даних",
|
||||
"ERROR_FALLBACK_TO_BACKUP": "Щось пішло не так під час імпорту даних. Повернення до локальної резервної копії.",
|
||||
"ERROR_INVALID_DATA": "Помилка під час синхронізації. Недійсні дані",
|
||||
"ERROR_NO_REV": "Немає дійсної версії для віддаленого файлу",
|
||||
"ERROR_UNABLE_TO_READ_REMOTE_DATA": "Помилка під час синхронізації. Неможливо прочитати віддалені дані. Можливо, ви увімкнули шифрування, і ваш локальний пароль не відповідає тому, що використовувався для шифрування віддалених даних?",
|
||||
"IMPORTING": "Імпорт даних",
|
||||
"INCOMPLETE_CFG": "Автентифікація для синхронізації не вдалася. Будь ласка, перевірте ваші налаштування!",
|
||||
"INITIAL_SYNC_ERROR": "Початкова синхронізація не вдалася",
|
||||
"SUCCESS_DOWNLOAD": "Синхронізація даних з віддаленого доступу",
|
||||
"SUCCESS_IMPORT": "Дані імпортовано",
|
||||
"SUCCESS_VIA_BUTTON": "Дані успішно синхронізовано",
|
||||
"UNKNOWN_ERROR": "Невідома помилка синхронізації: {{err}}",
|
||||
"UPLOAD_ERROR": "Невідома помилка завантаження (Налаштування правильні?): {{err}}"
|
||||
"UNKNOWN_ERROR": "Невідома помилка синхронізації: {{err}}"
|
||||
}
|
||||
},
|
||||
"TAG": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "Створити тег",
|
||||
"EDIT": "Редагувати тег"
|
||||
"CREATE": "Створити тег"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"CONFIRM_MSG": "Ви дійсно хочете видалити тег \"{{tagName}}\"? Він буде видалений з усіх завдань. Це не можна відмінити."
|
||||
|
|
@ -1034,28 +810,16 @@
|
|||
},
|
||||
"TASK": {
|
||||
"ADD_TASK_BAR": {
|
||||
"ADD_EXISTING_TASK": "Додати існуюче завдання \"{{taskTitle}}\"",
|
||||
"ADD_ISSUE_TASK": "Додати завдання #{{issueNr}} з {{issueType}}",
|
||||
"ADD_TASK_TO_BOTTOM_OF_BACKLOG": "Додати завдання в кінець беклогу",
|
||||
"ADD_TASK_TO_BOTTOM_OF_TODAY": "Додати завдання в кінець списку",
|
||||
"ADD_TASK_TO_TOP_OF_BACKLOG": "Додати завдання на початок беклогу",
|
||||
"ADD_TASK_TO_TOP_OF_TODAY": "Додати завдання на початок списку",
|
||||
"CREATE_TASK": "Створити нове завдання",
|
||||
"EXAMPLE": "Приклад: \"Якась назва завдання @fri 16:00 +назваПроекту #якийсь-тег #інший-тег 10m/3h\"",
|
||||
"START": "Натисніть Enter ще раз, щоб почати",
|
||||
"TOGGLE_ADD_TO_BACKLOG_TODAY": "Перемкнути додавання завдання до беклогу / Сьогодні",
|
||||
"TOGGLE_ADD_TOP_OR_BOTTOM": "Перемкнути додавання завдання на початок чи кінець списку"
|
||||
"ADD_EXISTING_TASK": "Додати існуюче завдання \"{{taskTitle}}\""
|
||||
},
|
||||
"ADDITIONAL_INFO": {
|
||||
"ADD_ATTACHMENT": "Додати вкладення",
|
||||
"ADD_SUB_TASK": "Додати підзавдання",
|
||||
"ATTACHMENTS": "Вкладення ({{nr}})",
|
||||
"DUE": "Заплановано на",
|
||||
"FROM_PARENT": "(від батьківського)",
|
||||
"LOCAL_ATTACHMENTS": "Локальні вкладення",
|
||||
"NOTES": "Опис",
|
||||
"PARENT": "Батько",
|
||||
"REMINDER": "Нагадування",
|
||||
"REPEAT": "Повторення",
|
||||
"SCHEDULE_TASK": "Запланувати завдання",
|
||||
"SUB_TASKS": "Підзавдання ({{nr}})",
|
||||
|
|
@ -1075,11 +839,8 @@
|
|||
"DELETE_REPEAT_INSTANCE": "Видалити екземпляр повторюваного завдання",
|
||||
"DROP_ATTACHMENT": "Перетягніть сюди, щоб прикріпити до \"{{title}}\"",
|
||||
"EDIT_SCHEDULED": "Перепланувати",
|
||||
"EDIT_TAGS": "Редагувати теги",
|
||||
"EDIT_TASK_TITLE": "Редагувати назву",
|
||||
"FOCUS_SESSION": "Розпочати сеанс фокусування",
|
||||
"MARK_DONE": "Позначити як виконане",
|
||||
"MARK_UNDONE": "Позначити як невиконане",
|
||||
"MOVE_TO_BACKLOG": "Перемістити до беклогу",
|
||||
"MOVE_TO_OTHER_PROJECT": "Перемістити до іншого проекту",
|
||||
"MOVE_TO_REGULAR": "Перемістити до Сьогодні",
|
||||
|
|
@ -1088,9 +849,7 @@
|
|||
"OPEN_ISSUE": "Відкрити в браузері",
|
||||
"OPEN_TIME": "Відстеження часу",
|
||||
"REMOVE_FROM_MY_DAY": "Видалити з Сьогодні",
|
||||
"REPEAT_EDIT": "Редагувати налаштування повторення завдання",
|
||||
"SCHEDULE": "Запланувати завдання",
|
||||
"SHOW_UPDATES": "Показати оновлення",
|
||||
"TOGGLE_ATTACHMENTS": "Показати/Приховати вкладення",
|
||||
"TOGGLE_DETAIL_PANEL": "Показати/Приховати додаткову інформацію",
|
||||
"TOGGLE_DONE": "Позначити як виконане/невиконане",
|
||||
|
|
@ -1117,24 +876,17 @@
|
|||
"DONE": "Виконано",
|
||||
"DUE_TASK": "Заплановане завдання",
|
||||
"DUE_TASKS": "Заплановані завдання",
|
||||
"FOR_CURRENT": "Строк завдання настав. Бажаєте почати роботу над ним?",
|
||||
"FOR_OTHER": "Строк завдання настав. Бажаєте почати роботу над ним?",
|
||||
"FROM_PROJECT": "З проекту: \"{{title}}\"",
|
||||
"FROM_TAG": "З тегу: \"{{title}}\"",
|
||||
"RESCHEDULE_EDIT": "Редагувати (Перепланувати)",
|
||||
"RESCHEDULE_UNTIL_TOMORROW": "Перепланувати на завтра",
|
||||
"SNOOZE": "Відкласти",
|
||||
"SNOOZE_ALL": "Відкласти всі",
|
||||
"START": "Почати",
|
||||
"SWITCH_CONTEXT_START": "Змінити контекст і почати",
|
||||
"UNSCHEDULE": "Поза графіком",
|
||||
"UNSCHEDULE_ALL": "Скасувати всі"
|
||||
},
|
||||
"D_SCHEDULE_TASK": {
|
||||
"MOVE_TO_BACKLOG": "Перемістити завдання до беклогу до запланованої дати",
|
||||
"QA_NEXT_MONTH": "Запланувати на наступний місяць",
|
||||
"QA_NEXT_WEEK": "Запланувати на наступний тиждень",
|
||||
"QA_REMOVE_TODAY": "Видалити завдання з сьогоднішнього дня",
|
||||
"QA_TODAY": "Запланувати на сьогодні",
|
||||
"QA_TOMORROW": "Запланувати на завтра",
|
||||
"REMIND_AT": "Нагадати о",
|
||||
|
|
@ -1170,15 +922,12 @@
|
|||
"S": {
|
||||
"CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK": "Неможливо призначити проект через короткий синтаксис для повторюваних завдань!",
|
||||
"CREATED_FOR_PROJECT": "Перенесено завдання \"{{taskTitle}}\" на проект \"{{projectTitle}}\"",
|
||||
"CREATED_FOR_PROJECT_ACTION": "Перейти до проекту",
|
||||
"DELETED": "Видалено завдання \"{{title}}\"",
|
||||
"FOUND_MOVE_FROM_BACKLOG": "Переміщено завдання <strong>{{title}}</strong> з беклогу до Сьогодні",
|
||||
"FOUND_MOVE_FROM_OTHER_LIST": "Додано завдання <strong>{{title}}</strong> з <strong>{{contextTitle}}</strong> до поточного списку",
|
||||
"FOUND_RESTORE_FROM_ARCHIVE": "Відновлено завдання <strong>{{title}}</strong>, пов'язане з проблемою, з архіву",
|
||||
"LAST_TAG_DELETION_WARNING": "Ви намагаєтесь видалити останній тег завдання, яке не належить до проекту. Це не дозволено!",
|
||||
"MOVED_TO_ARCHIVE": "Перенесено {{nr}} завдань в архів",
|
||||
"MOVED_TO_PROJECT": "Перенесено завдання \"{{taskTitle}}\" на проект \"{{projectTitle}}\"",
|
||||
"MOVED_TO_PROJECT_ACTION": "Перейти до проекту",
|
||||
"REMINDER_ADDED": "Заплановано завдання \"{{title}}\"",
|
||||
"REMINDER_DELETED": "Видалено нагадування для завдання",
|
||||
"REMINDER_UPDATED": "Оновлено нагадування для завдання \"{{title}}\"",
|
||||
|
|
@ -1246,7 +995,6 @@
|
|||
"C_YEAR": "Рік",
|
||||
"DEFAULT_ESTIMATE": "Стандартна оцінка",
|
||||
"FRIDAY": "П'ятниця",
|
||||
"IS_ADD_TO_BOTTOM": "Перемістити завдання в кінець списку",
|
||||
"MONDAY": "Понеділок",
|
||||
"NOTES": "Стандартні нотатки",
|
||||
"ORDER": "Порядок",
|
||||
|
|
@ -1297,7 +1045,6 @@
|
|||
"SCHEDULED_THIS_WEEK": "Цього тижня",
|
||||
"SCHEDULED_TODAY": "Сьогодні",
|
||||
"SCHEDULED_TOMORROW": "Завтра",
|
||||
"SORT_BY": "Сортувати за",
|
||||
"SORT_CREATION_DATE": "Дата створення",
|
||||
"SORT_DEFAULT": "За промовчанням",
|
||||
"SORT_NAME": "Ім'я",
|
||||
|
|
@ -1307,8 +1054,7 @@
|
|||
"TIME_10MIN": "> 10 хвилин",
|
||||
"TIME_30MIN": "> 30 хвилин",
|
||||
"FILTER_NOT_SPECIFIED": "Не вказано",
|
||||
"TIME_SPENT": "Витрачений час",
|
||||
"TITLE": "Налаштування перегляду завдань"
|
||||
"TIME_SPENT": "Витрачений час"
|
||||
}
|
||||
},
|
||||
"TIME_TRACKING": {
|
||||
|
|
@ -1338,7 +1084,6 @@
|
|||
},
|
||||
"D_TRACKING_REMINDER": {
|
||||
"CREATE_AND_TRACK": "<em>Створити</em> і відстежувати для",
|
||||
"IDLE_FOR": "Ви були неактивні протягом:",
|
||||
"NOTIFICATION_TITLE": "Слідкуйте за своїм часом!",
|
||||
"TASK": "Завдання",
|
||||
"TRACK_TO": "Відстежувати для:",
|
||||
|
|
@ -1350,7 +1095,6 @@
|
|||
"DAYS_WORKED": "Днів відпрацьовано:",
|
||||
"MONTH_WORKED": "Місяць відпрацьовано:",
|
||||
"REPEATING_TASK": "Повторюване завдання",
|
||||
"RESTORE_TASK_FROM_ARCHIVE": "Відновити завдання з архіву",
|
||||
"TASKS": "Завдання",
|
||||
"TOTAL_TIME": "Загальний витрачений час:",
|
||||
"WEEK_NR": "Тиждень {{nr}}",
|
||||
|
|
@ -1442,26 +1186,20 @@
|
|||
"HIDE": "Приховати",
|
||||
"ICON_INP_DESCRIPTION": "Також підтримуються всі emojis utf-8!",
|
||||
"INBOX_PROJECT_TITLE": "Вхідні",
|
||||
"LOGIN": "Увійти",
|
||||
"LOGOUT": "Вийти",
|
||||
"MINUTES": "{{m}} хвилин",
|
||||
"MOVE_BACKWARD": "Перейти назад",
|
||||
"MOVE_FORWARD": "Рухайтеся вперед",
|
||||
"NEXT": "Далі",
|
||||
"NO_CON": "Ви наразі від'єднані від Інтернету. Синхронізація та запит даних від провайдера завдань не працюватимуть.",
|
||||
"NONE": "Немає",
|
||||
"OK": "Гаразд",
|
||||
"OVERDUE": "Прострочені",
|
||||
"PREVIOUS": "Попередній",
|
||||
"REMOVE": "Видалити",
|
||||
"RESET": "Скинути",
|
||||
"SAVE": "Зберегти",
|
||||
"SUBMIT": "Надіслати",
|
||||
"TITLE": "Назва",
|
||||
"TODAY_TAG_TITLE": "Сьогодні",
|
||||
"TRACKING_INTERVAL_DESCRIPTION": "Відстежувати час з використанням цього інтервалу в мілісекундах. Можливо, ви захочете змінити це, щоб зменшити кількість записів на диск. Дивіться проблему #2355.",
|
||||
"UNDO": "Скасувати",
|
||||
"UPDATE": "Оновити",
|
||||
"WITHOUT_PROJECT": "Без проекту",
|
||||
"YESTERDAY": "Вчора"
|
||||
},
|
||||
|
|
@ -1475,9 +1213,7 @@
|
|||
"CALENDARS": {
|
||||
"BROWSER_WARNING": "<b>Це, ймовірно, НЕ працюватиме з версією браузера Super Productivity.<br /> Будь ласка, <a href=\"https://super-productivity.com/download/\">завантажте десктопну версію</a>, щоб використовувати цю функцію!</b>",
|
||||
"CAL_PATH": "URL джерела iCal",
|
||||
"CAL_PROVIDERS": "Провайдери календарів (експериментально та необов'язково)",
|
||||
"CHECK_UPDATES": "Перевіряти віддалені оновлення кожні X",
|
||||
"DEFAULT_PROJECT": "Проект за замовчуванням для доданих завдань календаря",
|
||||
"HELP": "Ви можете інтегрувати календарі, щоб отримувати нагадування та додавати їх як завдання в Super Productivity. Інтеграція працює за допомогою формату iCal. Для цього ваші календарі повинні бути доступні або через Інтернет, або через файлову систему.",
|
||||
"SHOW_BANNER_THRESHOLD": "Показувати сповіщення за X до події (порожнє для вимкнення)"
|
||||
},
|
||||
|
|
@ -1487,7 +1223,6 @@
|
|||
},
|
||||
"FOCUS_MODE": {
|
||||
"HELP": "Режим фокусування відкриває екран без відволікаючих факторів, щоб допомогти вам зосередитися на поточному завданні.",
|
||||
"L_ALWAYS_OPEN_FOCUS_MODE": "Завжди відкривати режим фокусування при відстеженні",
|
||||
"L_SKIP_PREPARATION_SCREEN": "Пропустити екран підготовки (розтяжка тощо)",
|
||||
"TITLE": "Режим фокусування"
|
||||
},
|
||||
|
|
@ -1539,7 +1274,6 @@
|
|||
"TASK_MOVE_TO_PROJECT": "Відкрити меню переміщення завдання до проекту",
|
||||
"TASK_OPEN_CONTEXT_MENU": "Відкрити контекстне меню завдання",
|
||||
"TASK_OPEN_ESTIMATION_DIALOG": "Редагувати запланований / витрачений час",
|
||||
"TASK_PLAN_FORDAY": "Запланувати на день",
|
||||
"TASK_SCHEDULE": "Запланувати завдання",
|
||||
"TASK_SHORTCUTS": "Завдання",
|
||||
"TASK_SHORTCUTS_INFO": "Наступні скорочення застосовуються для поточно вибраного завдання (вибраного за допомогою табуляції або миші).",
|
||||
|
|
@ -1547,7 +1281,6 @@
|
|||
"TASK_TOGGLE_DONE": "Перемкнути виконання",
|
||||
"TITLE": "Клавіатурні скорочення",
|
||||
"TOGGLE_BACKLOG": "Показати/Приховати беклог завдань",
|
||||
"TOGGLE_BOOKMARKS": "Показати/Приховати панель закладок",
|
||||
"TOGGLE_ISSUE_PANEL": "Показати/приховати панель проблем",
|
||||
"TOGGLE_PLAY": "Почати/Зупинити завдання",
|
||||
"TOGGLE_SIDE_NAV": "Показати і сфокусувати/Приховати бічну навігацію",
|
||||
|
|
@ -1594,13 +1327,11 @@
|
|||
"IS_DARK_MODE": "Темний режим",
|
||||
"IS_DISABLE_ANIMATIONS": "Вимкнути всі анімації",
|
||||
"IS_DISABLE_CELEBRATION": "Вимкнути святкування у щоденному зведенні",
|
||||
"IS_HIDE_NAV": "Приховувати навігацію, поки курсор не наведено на заголовок (тільки для десктопної версії)",
|
||||
"IS_MINIMIZE_TO_TRAY": "Згортати до системного трею (тільки для десктопної версії)",
|
||||
"IS_SHOW_TIP_LONGER": "Показувати поради щодо продуктивності на початку програми трохи довше",
|
||||
"IS_TRAY_SHOW_CURRENT_COUNTDOWN": "Показувати поточний зворотний відлік у треї / меню статусу (лише для настільного комп'ютера Mac)",
|
||||
"IS_TRAY_SHOW_CURRENT_TASK": "Показувати поточне завдання в системному треї / меню статусу (тільки для десктопної версії Mac/Windows)",
|
||||
"IS_TURN_OFF_MARKDOWN": "Вимкнути обробку markdown для нотаток завдань",
|
||||
"IS_USE_MINIMAL_SIDE_NAV": "Використовувати мінімальну панель навігації (показувати лише іконки)",
|
||||
"START_OF_NEXT_DAY": "Час початку наступного дня",
|
||||
"START_OF_NEXT_DAY_HINT": "з якого часу (в годинах) ви хочете вважати, що почався наступний день. За замовчуванням це опівніч, тобто 0.",
|
||||
"TASK_NOTES_TPL": "Шаблон опису завдання",
|
||||
|
|
@ -1704,14 +1435,12 @@
|
|||
},
|
||||
"GLOBAL_SNACK": {
|
||||
"COPY_TO_CLIPPBOARD": "Скопійовано в буфер обміну",
|
||||
"ERR_COMPRESSION": "Помилка інтерфейсу стиснення",
|
||||
"FILE_DOWNLOADED": "{{fileName}} завантажено",
|
||||
"FILE_DOWNLOADED_BTN": "Відкрити папку",
|
||||
"NAVIGATE_TO_TASK_ERR": "Не вдалося сфокусуватися на завданні. Ви його видалили?",
|
||||
"PERSISTENCE_DISALLOWED": "Дані не будуть зберігатися постійно. Зверніть увагу, що це може призвести до втрати даних!!",
|
||||
"PERSISTENCE_ERROR": "Помилка при запиті на збереження даних: {{err}}",
|
||||
"RUNNING_X": "Виконується \"{{str}}\".",
|
||||
"SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG": "{{keyCombo}} натиснуто, але скорочення для відкриття закладок доступне лише в контексті проекту."
|
||||
"RUNNING_X": "Виконується \"{{str}}\"."
|
||||
},
|
||||
"GPB": {
|
||||
"ASSETS": "Завантаження ресурсів...",
|
||||
|
|
@ -1748,24 +1477,14 @@
|
|||
"SYNC": "Як налаштувати синхронізацію"
|
||||
},
|
||||
"METRICS": "Метрики",
|
||||
"NO_PROJECT_INFO": "Немає доступних проектів. Ви можете створити новий проект, натиснувши кнопку \"Створити проект\".",
|
||||
"NO_TAG_INFO": "Наразі немає тегів. Ви можете додати теги, ввівши `#вашНазваТегу` при додаванні або редагуванні завдань.",
|
||||
"NOTES": "Нотатки",
|
||||
"NOTES_PANEL_INFO": "Нотатки можна показати лише з розкладу та звичайних списків завдань.",
|
||||
"PLANNER": "Планувальник",
|
||||
"PROCRASTINATE": "Прокрастинація",
|
||||
"PROJECT_MENU": "Меню проекту",
|
||||
"PROJECT_SETTINGS": "Налаштування проекту",
|
||||
"PROJECTS": "Проекти",
|
||||
"QUICK_HISTORY": "Швидка історія",
|
||||
"SCHEDULE": "Розклад",
|
||||
"SEARCH": "Шукати",
|
||||
"SETTINGS": "Налаштування",
|
||||
"SHOW_SEARCH_BAR": "Показати рядок пошуку",
|
||||
"TAGS": "Теги",
|
||||
"TASK_LIST": "Список завдань",
|
||||
"TASKS": "Завдання",
|
||||
"TOGGLE_SHOW_BOOKMARKS": "Показати/Приховати закладки",
|
||||
"TOGGLE_SHOW_ISSUE_PANEL": "Показати/приховати панель проблем",
|
||||
"TOGGLE_SHOW_NOTES": "Показати/Приховати нотатки проекту",
|
||||
"TOGGLE_TRACK_TIME": "Почати/Зупинити відстеження часу",
|
||||
|
|
@ -1819,14 +1538,12 @@
|
|||
},
|
||||
"PS": {
|
||||
"GLOBAL_SETTINGS": "Глобальні налаштування",
|
||||
"ISSUE_INTEGRATION": "Інтеграція завдань",
|
||||
"PRIVACY_POLICY": "Політика конфіденційності",
|
||||
"PRODUCTIVITY_HELPER": "Помічник продуктивності",
|
||||
"PROJECT_SETTINGS": "Налаштування конкретного проекту",
|
||||
"PROVIDE_FEEDBACK": "Надати відгук",
|
||||
"SYNC_EXPORT": "Синхронізація та експорт",
|
||||
"TAG_SETTINGS": "Налаштування конкретного тегу",
|
||||
"TOGGLE_DARK_MODE": "Перемкнути темний режим"
|
||||
"TAG_SETTINGS": "Налаштування конкретного тегу"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"NO_REPEATABLE_TASKS": "Наразі немає повторюваних завдань. Ви можете запланувати завдання, вибравши \"Повторити завдання\" на бічній панелі завдання. Щоб відкрити її, клацніть на крайній правій іконці, яка з'являється при наведенні на завдання (або просто натисніть на завдання на мобільному пристрої).",
|
||||
|
|
@ -1834,36 +1551,15 @@
|
|||
"NO_SCHEDULED_TITLE": "Заплановані завдання на день",
|
||||
"REPEATED_TASKS": "Повторювані завдання",
|
||||
"SCHEDULED_TASKS": "Заплановані завдання",
|
||||
"SCHEDULED_TASKS_WITH_TIME": "Заплановані завдання з нагадуванням",
|
||||
"START_TASK": "Почати завдання і видалити нагадування"
|
||||
},
|
||||
"THEMES": {
|
||||
"amber": "бурштиновий",
|
||||
"blue": "синій",
|
||||
"blue-grey": "синьо-сірий",
|
||||
"cyan": "блакитний",
|
||||
"deep-orange": "глибокий оранжевий",
|
||||
"deep-purple": "глибокий фіолетовий",
|
||||
"green": "зелений",
|
||||
"indigo": "індиго",
|
||||
"light-blue": "світло-синій",
|
||||
"light-green": "світло-зелений",
|
||||
"lime": "лаймовий",
|
||||
"pink": "рожевий",
|
||||
"purple": "фіолетовий",
|
||||
"SELECT_THEME": "Вибрати тему",
|
||||
"teal": "бірюзовий",
|
||||
"yellow": "жовтий"
|
||||
"SCHEDULED_TASKS_WITH_TIME": "Заплановані завдання з нагадуванням"
|
||||
},
|
||||
"V": {
|
||||
"E_1TO10": "Будь ласка, введіть значення від 1 до 10",
|
||||
"E_DATETIME": "Введене значення не є датою та часом!",
|
||||
"E_DURATION": "Будь ласка, введіть допустиму тривалість (наприклад, 1 годину)",
|
||||
"E_MAX": "Не повинно бути більше ніж {{val}}",
|
||||
"E_MAX_LENGTH": "Повинно бути максимум {{val}} символів",
|
||||
"E_MIN": "Не повинно бути менше ніж {{val}}",
|
||||
"E_MIN_LENGTH": "Повинно бути принаймні {{val}} символів",
|
||||
"E_PATTERN": "Некоректне введення",
|
||||
"E_REQUIRED": "Це поле обов'язкове"
|
||||
},
|
||||
"USER_PROFILES": {
|
||||
|
|
@ -1880,7 +1576,6 @@
|
|||
"RENAME": "Перейменувати",
|
||||
"EXPORT_PROFILE": "Експортувати профіль",
|
||||
"DELETE_PROFILE": "Видалити профіль",
|
||||
"OPEN_PROFILES_FOLDER": "Відкрити папку профілів",
|
||||
"CLOSE": "Закрити",
|
||||
"MANAGE_PROFILES": "Керувати профілями..."
|
||||
},
|
||||
|
|
@ -1892,10 +1587,7 @@
|
|||
"DONE_TASKS_IN_ARCHIVE": "Наразі тут немає виконаних завдань, але деякі вже заархівовані.",
|
||||
"ESTIMATE_REMAINING": "Залишилось за оцінкою:",
|
||||
"FINISH_DAY": "Завершити день",
|
||||
"FINISH_DAY_FOR_PROJECT": "Завершити день для цього проекту",
|
||||
"FINISH_DAY_FOR_TAG": "Завершити день для цього тегу",
|
||||
"FINISH_DAY_TOOLTIP": "Оцініть свій день, перемістіть всі виконані завдання до архіву (за бажанням) та/або заплануйте наступний день.",
|
||||
"HELP_PROCRASTINATION": "Допоможіть, я прокрастиную!",
|
||||
"MOVE_DONE_TO_ARCHIVE": "Перенести в архів",
|
||||
"NO_DONE_TASKS": "Наразі немає виконаних завдань",
|
||||
"NO_PLANNED_TASK_ALL_DONE": "Всі поставлені завдання виконані",
|
||||
|
|
|
|||
|
|
@ -1,15 +1,4 @@
|
|||
{
|
||||
"ANDROID": {
|
||||
"NOTIFICATIONS": {
|
||||
"SYNC_CONFLICT_MSG": "請檢查並決定該怎麼做。",
|
||||
"SYNC_CONFLICT_TITLE": "發生同步衝突"
|
||||
},
|
||||
"PERMANENT_NOTIFICATION_MSGS": {
|
||||
"INITIAL": "如果開啟,應用程式將會在背景運行以允許同步",
|
||||
"NO_ACTIVE_TASKS": "沒有活動任務",
|
||||
"SYNCING": "正在同步中"
|
||||
}
|
||||
},
|
||||
"APP": {
|
||||
"B_INSTALL": {
|
||||
"IGNORE": "忽略",
|
||||
|
|
@ -20,14 +9,11 @@
|
|||
"CONTEXT_MENU": {
|
||||
"CHANGE_BACKGROUND": "更改背景"
|
||||
},
|
||||
"UPDATE_MAIN_MODEL": "Super Productivity 有了重大更新!您的資料需要進行一些遷移。請注意,這會使您的資料與該應用的舊版本不相容。",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "未選擇模型更新。請注意,如果您不想執行模型升級,則必須降級到上一版本。",
|
||||
"UPDATE_WEB_APP": "有新版本可用。下載新版本?"
|
||||
},
|
||||
"BN": {
|
||||
"SHOW_ISSUE_PANEL": "顯示問題面板",
|
||||
"SHOW_NOTES": "顯示項目說明",
|
||||
"SHOW_TASK_VIEW_CUSTOMIZER_PANEL": "顯示篩選器/分組/排序面板"
|
||||
"SHOW_NOTES": "顯示項目說明"
|
||||
},
|
||||
"BL": {
|
||||
"NO_TASKS": "目前您的待辦事項中沒有任務"
|
||||
|
|
@ -40,11 +26,7 @@
|
|||
"RESTORE_STRAY_BACKUP": "在上次同步期間,可能有一些錯誤。您要還原上一個備份嗎?"
|
||||
},
|
||||
"DATETIME_SCHEDULE": {
|
||||
"LATER_TODAY": "今天稍晚",
|
||||
"NEXT_WEEK": "下周",
|
||||
"PLACEHOLDER": "請選擇一個日期",
|
||||
"PRESS_ENTER_AGAIN": "再次按 Enter 以儲存",
|
||||
"TOMORROW": "明天"
|
||||
"PRESS_ENTER_AGAIN": "再次按 Enter 以儲存"
|
||||
},
|
||||
"DIALOG_UNSPLASH_PICKER": {
|
||||
"TITLE": "從 Unsplash 選擇背景圖片",
|
||||
|
|
@ -59,7 +41,6 @@
|
|||
"ADD_ATTACHMENT": "添加附件",
|
||||
"EDIT_ATTACHMENT": "編輯附件",
|
||||
"LABELS": {
|
||||
"FILE": "檔案路徑",
|
||||
"IMG": "圖片",
|
||||
"LINK": "網址"
|
||||
},
|
||||
|
|
@ -75,7 +56,6 @@
|
|||
"DEFAULT": {
|
||||
"DONE": "完畢",
|
||||
"EISENHAUER_MATRIX": "艾森豪威爾矩陣",
|
||||
"IMPORTANT": "重要的",
|
||||
"IN_PROGRESS": "進行中",
|
||||
"KANBAN": "Kanban",
|
||||
"NOT_URGENT_IMPORTANT": "不緊急且不重要",
|
||||
|
|
@ -112,9 +92,7 @@
|
|||
}
|
||||
},
|
||||
"CALDAV": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Setup CalDav for Project"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"CALDAV_CATEGORY_FILTER": "Category to filter issues for (leave empty for none)",
|
||||
"CALDAV_PASSWORD": "Your CalDav password",
|
||||
|
|
@ -124,28 +102,7 @@
|
|||
"IS_TRANSITION_ISSUES_ENABLED": "Automatically complete CalDav todos on task completion"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list uncompleted CalDav todos for a specific project in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the todo as well as more information about it.</p> <p>In addition you can automatically add and sync all uncompleted todos to your task backlog.</p><p>To make it work for nextcloud in the webapp, you might need to whitelist \"https://app.super-productivity.com\" via the nextcloud app <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword<a>.</p>",
|
||||
"TITLE": "CalDav"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Assignee",
|
||||
"AT": "at",
|
||||
"ATTACHMENTS": "Attachments",
|
||||
"CHANGED": "changed",
|
||||
"COMMENTS": "Comments",
|
||||
"COMPONENTS": "Components",
|
||||
"DESCRIPTION": "Description",
|
||||
"LABELS": "Categories",
|
||||
"LIST_OF_CHANGES": "List of changes",
|
||||
"MARK_AS_CHECKED": "Mark updates as checked",
|
||||
"ON": "on",
|
||||
"RELATED": "Related",
|
||||
"STATUS": "Status",
|
||||
"STORY_POINTS": "Story Points",
|
||||
"SUB_TASKS": "Subtasks",
|
||||
"SUMMARY": "Summary",
|
||||
"WORKLOG": "Worklog",
|
||||
"WRITE_A_COMMENT": "Write a comment"
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list uncompleted CalDav todos for a specific project in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the todo as well as more information about it.</p> <p>In addition you can automatically add and sync all uncompleted todos to your task backlog.</p><p>To make it work for nextcloud in the webapp, you might need to whitelist \"https://app.super-productivity.com\" via the nextcloud app <a href='https://apps.nextcloud.com/apps/webapppassword'>webapppassword<a>.</p>"
|
||||
},
|
||||
"S": {
|
||||
"CALENDAR_NOT_FOUND": "CalDav: Calendar \"{{calendarName}}\" not found",
|
||||
|
|
@ -156,7 +113,6 @@
|
|||
"CALENDARS": {
|
||||
"BANNER": {
|
||||
"ADD_AS_TASK": "Add as Task",
|
||||
"FOCUS_TASK": "Focus Task",
|
||||
"TXT": "<strong>{{title}}</strong> starts at <strong>{{start}}</strong>!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> starts at <strong>{{start}}</strong>!<br> (and {{nrOfOtherBanners}} other events are due)",
|
||||
"TXT_PAST": "<strong>{{title}}</strong> started at <strong>{{start}}</strong>!",
|
||||
|
|
@ -194,10 +150,6 @@
|
|||
},
|
||||
"DROPBOX": {
|
||||
"S": {
|
||||
"ACCESS_TOKEN_ERROR": "Dropbox:無法從身份驗證代碼生成存取權杖",
|
||||
"ACCESS_TOKEN_GENERATED": "Dropbox:根據驗證碼生成的存取權杖",
|
||||
"AUTH_ERROR": "Dropbox:提供了無效的存取權杖",
|
||||
"AUTH_ERROR_ACTION": "更改權杖",
|
||||
"OFFLINE": "Dropbox:已離線,無法同步",
|
||||
"SYNC_ERROR": "Dropbox:同步時發生錯誤",
|
||||
"UNABLE_TO_GENERATE_PKCE_CHALLENGE": "Dropbox:無法產生 PKCE 挑戰。"
|
||||
|
|
@ -217,17 +169,13 @@
|
|||
"TO_FOCUS_OVERLAY": "To Focus Overlay"
|
||||
},
|
||||
"BACK_TO_PLANNING": "Back to Planning",
|
||||
"CONGRATS": "Congrats for completing this session!",
|
||||
"COUNTDOWN": "Countdown",
|
||||
"COUNTDOWN_HINT": "Focus until the clock hits zero",
|
||||
"FINISH_TASK_AND_SELECT_NEXT": "Finish task and select next",
|
||||
"FLOWTIME": "Flowtime",
|
||||
"FLOWTIME_HINT": "Flexible pacing without strict timers",
|
||||
"FOR_TASK": "for task",
|
||||
"GET_READY": "Get ready for your focus session!",
|
||||
"GO_TO_PROCRASTINATION": "Get help, when procrastinating",
|
||||
"GOGOGO": "Go, go, go!!!",
|
||||
"NEXT": "Next",
|
||||
"ON": "on",
|
||||
"OPEN_ISSUE_IN_BROWSER": "Open issue in Browser",
|
||||
"POMODORO": "Pomodoro",
|
||||
|
|
@ -235,12 +183,10 @@
|
|||
"PREP_GET_MENTALLY_READY": "Get mentally ready to be focused and productive",
|
||||
"PREP_SIT_UPRIGHT": "Sit (or stand) upright",
|
||||
"PREP_STRETCH": "Do some mild stretching",
|
||||
"SELECT_ANOTHER_TASK": "Select another Task",
|
||||
"SELECT_TASK": "Select Task to focus on",
|
||||
"SELECT_MODE": "Choose your focus mode",
|
||||
"SESSION_COMPLETED": "Focus Session Completed!",
|
||||
"POMODORO_SESSION_COMPLETED": "Pomodoro Session Completed!",
|
||||
"SET_FOCUS_SESSION_DURATION": "Set Focus Session Duration",
|
||||
"SHOW_HIDE_NOTES_AND_ATTACHMENTS": "Show/hide task notes and attachments",
|
||||
"START_FOCUS_SESSION": "Start Focus Session",
|
||||
"START_NEXT_FOCUS_SESSION": "Start next Focus Session",
|
||||
|
|
@ -249,20 +195,14 @@
|
|||
"SKIP_BREAK": "Skip Break",
|
||||
"CONTINUE_TO_NEXT_SESSION": "Continue to next Session",
|
||||
"FOCUS_TIME_TOOLTIP": "Focus time",
|
||||
"CURRENT_SESSION_TIME_TOOLTIP": "Current session time",
|
||||
"COMPLETE_SESSION": "Complete Session",
|
||||
"CONTINUE_SESSION": "Continue Session",
|
||||
"LONG_BREAK": "Long Break",
|
||||
"SHORT_BREAK": "Short Break",
|
||||
"LONG_BREAK_TITLE": "Long Break - Cycle {{cycle}}",
|
||||
"SHORT_BREAK_TITLE": "Short Break - Cycle {{cycle}}"
|
||||
},
|
||||
"GITEA": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Setup Gitea for Project"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Username (e.g. to filter out changes by yourself)",
|
||||
"HOST": "Host (e.g.: https://try.gitea.io)",
|
||||
"REPO_FULL_NAME": "Username or Organization name/project",
|
||||
"REPO_FULL_NAME_DESCRIPTION": "Can be found as part of the url, when viewing the project in the Browser.",
|
||||
|
|
@ -273,12 +213,10 @@
|
|||
"TOKEN": "Access Token"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open Gitea issues for a specific repository in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the issue as well as more information about it.</p> <p>In addition you can automatically add and import all open issues.</p><p>To get by usage limits and to access you can provide a an access token.",
|
||||
"TITLE": "Gitea"
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open Gitea issues for a specific repository in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the issue as well as more information about it.</p> <p>In addition you can automatically add and import all open issues.</p><p>To get by usage limits and to access you can provide a an access token."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Assignee",
|
||||
"AT": "at",
|
||||
"DESCRIPTION": "Description",
|
||||
"LABELS": "Labels",
|
||||
"MARK_AS_CHECKED": "Mark updates as checked",
|
||||
|
|
@ -287,14 +225,10 @@
|
|||
"SUMMARY": "紀要",
|
||||
"WRITE_A_COMMENT": "寫評論"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Gitea: Unknown error {{statusCode}} {{errorMsg}}. Api Rate limit exceeded?"
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"GITHUB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Setup GitHub for Project"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Username (e.g. to filter out changes by yourself)",
|
||||
"INVALID_TOKEN_MESSAGE": "Not a valid GitHub token. It must start with \"ghp_\".",
|
||||
|
|
@ -303,8 +237,7 @@
|
|||
"TOKEN": "Access Token"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open GitHub issues for a specific repository in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the issue as well as more information about it.</p> <p>In addition you can automatically import all open issues.</p><p>To get by usage limits and to access you can provide a an access token. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>More info about its scopes can be found here</a>.",
|
||||
"TITLE": "GitHub"
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open GitHub issues for a specific repository in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the issue as well as more information about it.</p> <p>In addition you can automatically import all open issues.</p><p>To get by usage limits and to access you can provide a an access token. <a href='https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps'>More info about its scopes can be found here</a>."
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "受讓人",
|
||||
|
|
@ -325,9 +258,7 @@
|
|||
}
|
||||
},
|
||||
"GITLAB": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Setup GitLab for Project"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"DIALOG_SUBMIT_WORKLOG": {
|
||||
"PAST_DAY_INFO": "The prefilled duration contains untracked data from past days.",
|
||||
"T_ALREADY_TRACKED": "已追蹤",
|
||||
|
|
@ -367,8 +298,7 @@
|
|||
"TOKEN": "Access Token"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open GitLab (either its the online version or a self-hosted instance) issues for a specific project in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the issue as well as more information about it.</p> <p>In addition you can automatically import all open issues.</p>",
|
||||
"TITLE": "GitLab"
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open GitLab (either its the online version or a self-hosted instance) issues for a specific project in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the issue as well as more information about it.</p> <p>In addition you can automatically import all open issues.</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "代理人",
|
||||
|
|
@ -400,20 +330,14 @@
|
|||
"ATTACHMENTS": "Attachments",
|
||||
"AUTHOR": "Author",
|
||||
"CATEGORY": "Category",
|
||||
"CHANGED": "changed",
|
||||
"COMMENTS": "Comments",
|
||||
"COMPONENTS": "Components",
|
||||
"DESCRIPTION": "Description",
|
||||
"DONE_RATIO": "Done Ratio",
|
||||
"DUE_DATE": "Due Date",
|
||||
"LABELS": "Labels",
|
||||
"LAST_COMMENT": "Last comment",
|
||||
"LIST_OF_CHANGES": "List of changes",
|
||||
"LOAD_ALL_COMMENTS": "Load all {{nr}} comments",
|
||||
"LOAD_DESCRIPTION_AND_ALL_COMMENTS": "Load description & all comments",
|
||||
"LOCATION": "Location",
|
||||
"MARK_AS_CHECKED": "Mark updates as checked",
|
||||
"ON": "on",
|
||||
"PRIORITY": "Priority",
|
||||
"RELATED": "Related",
|
||||
"START": "Start",
|
||||
|
|
@ -424,8 +348,7 @@
|
|||
"TIME_SPENT": "Time Spent",
|
||||
"TYPE": "Type",
|
||||
"VERSION": "Version",
|
||||
"WORKLOG": "Worklog",
|
||||
"WRITE_A_COMMENT": "Write a comment"
|
||||
"WORKLOG": "Worklog"
|
||||
},
|
||||
"S": {
|
||||
"ERR_GENERIC": "{{issueProviderName}} Error: {{errTxt}}",
|
||||
|
|
@ -433,13 +356,9 @@
|
|||
"ERR_NOT_CONFIGURED": "{{issueProviderName}}: Not properly configured",
|
||||
"IMPORTED_MULTIPLE_ISSUES": "{{issueProviderName}}: Imported {{nr}} new {{issuesStr}}",
|
||||
"IMPORTED_SINGLE_ISSUE": "{{issueProviderName}}: Imported {{issueStr}} \"{{issueTitle}}\"",
|
||||
"ISSUE_DELETED_OR_CLOSED": "{{issueProviderName}}: {{issueStrC}} \"{{issueTitle}}\" seems to be deleted or closed",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "{{issueProviderName}}:無需更新",
|
||||
"ISSUE_UPDATE_MULTIPLE": "{{issueProviderName}}: Updated data for {{nr}} {{issuesStr}}",
|
||||
"ISSUE_UPDATE_SINGLE": "{{issueProviderName}}: Updated data for \"{{issueTitle}}\"",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "{{issueProviderName}}: Updated data for \"{{issueTitle}}\"",
|
||||
"MISSING_ISSUE_DATA": "{{issueProviderName}}: Tasks with missing {{issueStr}} data found. Reloading.",
|
||||
"NEW_COMMENT": "{{issueProviderName}}: New comment for \"{{issueTitle}}\"",
|
||||
"POLLING_BACKLOG": "{{issueProviderName}}: Polling for new {{issuesStr}}",
|
||||
"POLLING_CHANGES": "{{issueProviderName}}: Polling Changes for {{issuesStr}}"
|
||||
}
|
||||
|
|
@ -473,8 +392,7 @@
|
|||
"CURRENT_ASSIGNEE": "Current Assignee:",
|
||||
"CURRENT_STATUS": "目前狀態:",
|
||||
"TASK_NAME": "任務名稱:",
|
||||
"TITLE": "Jira:更新狀態",
|
||||
"UPDATE_STATUS": "更新狀態"
|
||||
"TITLE": "Jira:更新狀態"
|
||||
},
|
||||
"DIALOG_WORKLOG": {
|
||||
"CHECKBOXES": {
|
||||
|
|
@ -509,8 +427,7 @@
|
|||
"HOST": "Host (e.g.: http://my-host.de:1234)",
|
||||
"PASSWORD": "令牌/密碼",
|
||||
"USE_PAT": "Use Personal Access Token instead (LEGACY)",
|
||||
"USER_NAME": "Email / Username",
|
||||
"WONKY_COOKIE_MODE": "Wonky Cookie Fallback Authentication (desktop app only)"
|
||||
"USER_NAME": "Email / Username"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"ADV_CFG": "Advanced Config",
|
||||
|
|
@ -552,23 +469,12 @@
|
|||
"EXTENSION_NOT_LOADED": "Super Productivity Extension not loaded. Reloading the page might help",
|
||||
"INSUFFICIENT_SETTINGS": "Insufficient Settings provided for Jira",
|
||||
"INVALID_RESPONSE": "Jira: Response contained invalid data",
|
||||
"ISSUE_NO_UPDATE_REQUIRED": "Jira: \"{{issueText}}\" already up to date",
|
||||
"MANUAL_UPDATE_ISSUE_SUCCESS": "Jira: Updated data for \"{{issueText}}\"",
|
||||
"MISSING_ISSUE_DATA": "Jira: Tasks with missing issue data found. Reloading.",
|
||||
"NO_AUTO_IMPORT_JQL": "Jira: No search query defined for auto import",
|
||||
"NO_VALID_TRANSITION": "Jira: No valid transition configured",
|
||||
"TIMED_OUT": "Jira: Request timed out",
|
||||
"TRANSITION": "Jira: Set issue \"{{issueKey}}\" to \"{{name}}\"",
|
||||
"TRANSITION_SUCCESS": "Jira: Set issue {{issueKey}} to <strong>{{chosenTransition}}</strong>",
|
||||
"TRANSITIONS_LOADED": "Jira: Transitions loaded. Use the selects below to assign them",
|
||||
"UNABLE_TO_REASSIGN": "Jira: Unable to reassign ticket to yourself, because you didn't specify a username. Please visit the settings."
|
||||
},
|
||||
"STEPPER": {
|
||||
"CREDENTIALS": "Credentials",
|
||||
"DONE": "You are now done.",
|
||||
"LOGIN_SUCCESS": "Login successful!",
|
||||
"TEST_CREDENTIALS": "Test Credentials",
|
||||
"WELCOME_USER": "Welcome {{user}}!"
|
||||
"TRANSITIONS_LOADED": "Jira: Transitions loaded. Use the selects below to assign them"
|
||||
}
|
||||
},
|
||||
"MARKDOWN_PASTE": {
|
||||
|
|
@ -580,9 +486,7 @@
|
|||
"DIALOG_TITLE": "Pasted Markdown List detected!"
|
||||
},
|
||||
"METRIC": {
|
||||
"BANNER": {
|
||||
"CHECK": "已完成!"
|
||||
},
|
||||
"BANNER": {},
|
||||
"CMP": {
|
||||
"AVG_BREAKS_PER_DAY": "平均休息次數",
|
||||
"AVG_TASKS_PER_DAY_WORKED": "平均完成任務數",
|
||||
|
|
@ -593,7 +497,6 @@
|
|||
"DAYS_WORKED": "持續天數",
|
||||
"GLOBAL_METRICS": "Global Metrics",
|
||||
"IMPROVEMENT_SELECTION_COUNT": "選擇積極因數的次數",
|
||||
"MOOD_PRODUCTIVITY_OVER_TIME": "情緒和效率的時間變化",
|
||||
"NO_ADDITIONAL_DATA_YET": "尚未收集其他資料,完成每日任務後通過添加\"評估\"來執行此操作。",
|
||||
"OBSTRUCTION_SELECTION_COUNT": "選擇消極因數的次數",
|
||||
"SIMPLE_CLICK_COUNTERS_OVER_TIME": "Click Counters over time",
|
||||
|
|
@ -604,30 +507,13 @@
|
|||
"TIME_SPENT": "花費時間"
|
||||
},
|
||||
"EVAL_FORM": {
|
||||
"ADD_NOTE_FOR_TOMORROW": "為明天添加建議",
|
||||
"DISABLE_REPEAT_EVERY_DAY": "停用每日重複",
|
||||
"ENABLE_REPEAT_EVERY_DAY": "每天重複",
|
||||
"HELP_H1": "我為什麼要在乎?",
|
||||
"HELP_LINK_TXT": "轉到指標部分",
|
||||
"HELP_P1": "花時間進行自我評估!此處的答案已儲存,併為您提供有關如何在指標部分工作的一些統計資料。此外,對明天的建議將在第二天出現在您的任務列表上方。",
|
||||
"HELP_P2": "這不僅僅是為了計算精確的指標,或是提高效率,而是為了改善您對工作的看法。評估日常生活中的自己的不足可能會對進步有所幫助。對它的清晰認識有助於更好地掌握這些並改善你的能力。",
|
||||
"IMPROVEMENTS": "什麼提高了你的效率生產力?",
|
||||
"IMPROVEMENTS_TOMORROW": "你能做些什麼來讓明天更高效?",
|
||||
"MOOD": "你覺得怎麼樣?",
|
||||
"MOOD_HINT": "1:太可怕了 - 10:太棒了",
|
||||
"NOTES": "明天的注意事項",
|
||||
"OBSTRUCTIONS": "是什麼阻礙了你的生產力?",
|
||||
"PRODUCTIVITY": "你的工作效率如何?",
|
||||
"PRODUCTIVITY_HINT": "1:幾乎未開始工作 - 10:非常有效率"
|
||||
"PRODUCTIVITY": "你的工作效率如何?"
|
||||
},
|
||||
"S": {
|
||||
"SAVE_METRIC": "評估已儲存"
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"NOTE": {
|
||||
"D_ADD": {
|
||||
"NOTE_LABEL": "請輸入提醒的內容..."
|
||||
},
|
||||
"D_ADD": {},
|
||||
"D_FULLSCREEN": {
|
||||
"VIEW_PARSED": "View as parsed (non editable) markdown",
|
||||
"VIEW_SPLIT": "View parsed and unparsed markdown in split view",
|
||||
|
|
@ -658,9 +544,7 @@
|
|||
"SELECT_ISSUE_FOR_TRANSITIONS": "Select issue to load available transitions",
|
||||
"TRANSITION": "Transition Handling"
|
||||
},
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Setup OpenProject for Project"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"DIALOG_TRACK_TIME": {
|
||||
"ACTIVITY": "Activity",
|
||||
"CURRENTLY_LOGGED": "Currently logged time: ",
|
||||
|
|
@ -686,8 +570,7 @@
|
|||
"SCOPE_CREATED": "Created by me"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open OpenProject work packages. Please Note that for this to work in the browser you need to probably configure CORS for your OpenProject server, to allow access from app.super-productivity.com</p>",
|
||||
"TITLE": "OpenProject"
|
||||
"HELP": "<p>Here you can configure SuperProductivity to list open OpenProject work packages. Please Note that for this to work in the browser you need to probably configure CORS for your OpenProject server, to allow access from app.super-productivity.com</p>"
|
||||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Assignee",
|
||||
|
|
@ -715,9 +598,7 @@
|
|||
"PLANNER": {
|
||||
"D": {
|
||||
"ADD_PLANNED": {
|
||||
"ADD_TO_TODAY": "添加到今天",
|
||||
"RE_PLAN_ALL": "Reschedule all",
|
||||
"TITLE": "將計劃任務添加到今天"
|
||||
"RE_PLAN_ALL": "Reschedule all"
|
||||
}
|
||||
},
|
||||
"EDIT_REPEATED_TASK": "Edit repeated task '{{taskName}}'",
|
||||
|
|
@ -729,67 +610,15 @@
|
|||
"REMOVED_PLAN_DATE": "已移除任務 '{{taskTitle}}' 的計劃日期",
|
||||
"TASK_ALREADY_PLANNED": "Task is already planned for {{date}}",
|
||||
"TASK_PLANNED_FOR": "任務計劃於 {{date}}"
|
||||
},
|
||||
"TASK_DRAWER": "Task Drawer"
|
||||
}
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_IS_DONE": "休息已完成!"
|
||||
},
|
||||
"PROCRASTINATION": {
|
||||
"BACK_TO_WORK": "Back to work!",
|
||||
"COMP": {
|
||||
"INTRO": "People with high procrastination levels usually have low self-compassion. So practice it! It improves your feeling of self-worth, fosters positive emotions and can help you overcome procrastination, of course. Try a little exercise:",
|
||||
"L1": "Sit down for bit and stretch yourself, if you like, calm down a little bit",
|
||||
"L2": "Try to listen to the thoughts and feelings that arise",
|
||||
"L3": "Are you responding to yourself in a way that you would respond to a friend?",
|
||||
"L4": "If the answer is no, imagine your friend in your situation. What you would say to them? What you would do for them?",
|
||||
"OUTRO": "More exercises <a target=\"_blank\" href=\"https://drsoph.com/blog/2018/9/17/3-exercises-in-self-compassion\" target=\"_blank\">can be found here</a> or on <a target=\"_blank\" href=\"https://www.google.com/search?q=self+compassion+exercises&oq=self+compassion+excers&aqs=chrome.1.69i57j0l5.4303j0j7&sourceid=chrome&ie=UTF-8\" target=\"_blank\">google</a>.",
|
||||
"TITLE": "Self Compassion"
|
||||
},
|
||||
"CUR": {
|
||||
"INTRO": "Isn't procrastination interesting? It doesn't seem to make any sense to do it, since it is not in your long term interest at all. But still everybody does. It helps a lot explore und gain a better understanding on how it works for you personally! Some basic questions to ask yourself could be:",
|
||||
"L1": "What feelings are eliciting your temptation to procrastinate?",
|
||||
"L2": "Where do you feel them in your body?",
|
||||
"L3": "What do they remind you of?",
|
||||
"L4": "What happens to the thought of procrastinating as you observe it? Does it intensify? Dissipate? Cause other emotions to arise?",
|
||||
"L5": "How are the sensations in your body shifting as you continue to rest your awareness on them?",
|
||||
"PROCRASTINATION_TRIGGERS_TEXT": "Another very effective method is to record, what triggered your urge to procrastinate. For example I personally often have the urge to quickly jump to reddit or my favorite news site whenever my browser window comes into focus. Since I started writing down my triggers in a simple empty text document, I became aware of how ingrained this pattern was and it helped me to experiment with different counter measures.",
|
||||
"PROCRASTINATION_TRIGGERS_TITLE": "Writing down your procrastination triggers",
|
||||
"TITLE": "Curiosity"
|
||||
},
|
||||
"H1": "Cut yourself some slack!",
|
||||
"INTRO": {
|
||||
"AVOIDING": "逃避任務",
|
||||
"FEAR": "害怕失敗",
|
||||
"STRESSED": "因無法完成任務而感到壓力",
|
||||
"TITLE": "簡介"
|
||||
},
|
||||
"P1": "First of all: Relax! Everybody does procrastinate once in a while. And if you're not doing what you should, you should at least enjoy it!",
|
||||
"P2": "Remember: <b>Procrastination is an emotion regulation problem, not a time management problem.</b> This means beating yourself up is not the solution, it is part of the problem. Let that sink in and then check the other tabs here for some further help.",
|
||||
"REFRAME": {
|
||||
"INTRO": "Think about what might be positive about the task despite its flaws.",
|
||||
"TITLE": "Reframing",
|
||||
"TL1": "What might be interesting about it?",
|
||||
"TL2": "What is to gain if you complete it?",
|
||||
"TL3": "How will you feel about it if you complete it?"
|
||||
},
|
||||
"SPLIT_UP": {
|
||||
"INTRO": "Split up the task into as many small chunks as you can.",
|
||||
"OUTRO": "Done? Then think about it. What would be – strictly theoretical – the first thing you would do <i>if</i> you were to start working on the task? Just think about it...",
|
||||
"TITLE": "Split it up!"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "建立項目",
|
||||
"EDIT": "編輯項目",
|
||||
"SETUP_CALDAV": "Setup Caldav Integration",
|
||||
"SETUP_GIT": "關聯 GitHub",
|
||||
"SETUP_GITEA_PROJECT": "Setup Gitea Integration",
|
||||
"SETUP_GITLAB": "關聯 GitLab",
|
||||
"SETUP_JIRA": "關聯 Jira",
|
||||
"SETUP_OPEN_PROJECT": "Setup OpenProject Integration",
|
||||
"SETUP_REDMINE_PROJECT": "Setup Redmine Integration"
|
||||
"EDIT": "編輯項目"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"MSG": "Are you sure you want to delete the project \"{{title}}\"?"
|
||||
|
|
@ -801,7 +630,6 @@
|
|||
"TITLE": "基本設置"
|
||||
},
|
||||
"FORM_THEME": {
|
||||
"D_IS_DARK_THEME": "如果系統支持全域深色模式,則不會使用。",
|
||||
"HELP": "項目主題設置。",
|
||||
"L_BACKGROUND_IMAGE_DARK": "背景圖片網址(深色主題)",
|
||||
"L_BACKGROUND_IMAGE_LIGHT": "背景圖片網址(淺色主題)",
|
||||
|
|
@ -813,18 +641,13 @@
|
|||
"L_HUE_WARN": "警告顏色背景上的黑深色文字的閾值",
|
||||
"L_IS_AUTO_CONTRAST": "自動設置文本顏色以獲得最佳可讀性",
|
||||
"L_IS_DISABLE_BACKGROUND_TINT": "停用彩色背景漸變",
|
||||
"L_IS_REDUCED_THEME": "使用縮減的UI(任務周圍沒有框)",
|
||||
"L_THEME_COLOR": "主題色",
|
||||
"L_TITLE": "標題",
|
||||
"TITLE": "主題"
|
||||
},
|
||||
"S": {
|
||||
"ARCHIVED": "存檔項目",
|
||||
"CREATED": "建立項目 <strong>{{title}}</strong>。您可以從左上角的菜單中選擇它。",
|
||||
"DELETED": "刪除項目",
|
||||
"E_EXISTS": "項目\"{{title}}\"已存在",
|
||||
"E_INVALID_FILE": "項目檔案的資料無效",
|
||||
"ISSUE_PROVIDER_UPDATED": "更新了 <strong>{{issueProviderKey}}</strong>的項目設置",
|
||||
"UNARCHIVED": "未歸檔的項目",
|
||||
"UPDATED": "更新了項目設置"
|
||||
}
|
||||
|
|
@ -872,9 +695,7 @@
|
|||
"WEEK_TITLE": "Week {{nr}} ({{timeSpent}})"
|
||||
},
|
||||
"REDMINE": {
|
||||
"DIALOG_INITIAL": {
|
||||
"TITLE": "Setup Redmine for Project"
|
||||
},
|
||||
"DIALOG_INITIAL": {},
|
||||
"FORM": {
|
||||
"API_KEY": "API access key",
|
||||
"HOST": "Host (e.g.: https://redmine.org)",
|
||||
|
|
@ -896,13 +717,10 @@
|
|||
"PRIORITY": "Priority",
|
||||
"STATUS": "Status"
|
||||
},
|
||||
"S": {
|
||||
"ERR_UNKNOWN": "Redmine: Unknown error {{statusCode}} {{errorMsg}}."
|
||||
}
|
||||
"S": {}
|
||||
},
|
||||
"REMINDER": {
|
||||
"COUNTDOWN_BANNER": {
|
||||
"HIDE": "隱藏",
|
||||
"START_NOW": "立即開始",
|
||||
"TXT": "<strong>{{title}}</strong> 將於 <strong>{{start}}</strong> 開始!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> 將於 <strong>{{start}}</strong> 開始!<br> (以及另外 {{nrOfOtherBanners}} 個任務到期)"
|
||||
|
|
@ -911,31 +729,21 @@
|
|||
"S_REMINDER_ERR": "提醒介面發生錯誤"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"CONTINUED": "continued",
|
||||
"D_INITIAL": {
|
||||
"TEXT": "<p>The Schedule should provide you with a better picture of how one's planned tasks play out over time. It is automatically generated from your Tasks and requires only <strong>time estimates on them to work</strong>.</p><p>Two things are distinguished: <strong>Scheduled Tasks</strong>, which are shown at their planned time and <strong>Regular Tasks</strong>, which should flow around those fixed events.</p><p>If you provide a work start and end time (recommended) regular tasks will never show up outside of these boundaries.</p>",
|
||||
"TITLE": "時間軸"
|
||||
},
|
||||
"END": "Work End",
|
||||
"LUNCH_BREAK": "午休",
|
||||
"MONTH": "Month",
|
||||
"NO_TASKS": "Currently there are no tasks. Please add some tasks via the + Button in the top bar.",
|
||||
"NOW": "Now",
|
||||
"INSERT_BEFORE": "Before",
|
||||
"PLAN_END_DAY": "End of {{date}}",
|
||||
"PLAN_START_DAY": "Start of {{date}}",
|
||||
"SHIFT_KEY_INFO": "Hold Shift to toggle day planning mode",
|
||||
"START": "Work Start",
|
||||
"TASK_PROJECTION_INFO": "Future projection of a scheduled repeatable task",
|
||||
"WEEK": "Week"
|
||||
"START": "Work Start"
|
||||
},
|
||||
"SEARCH_BAR": {
|
||||
"INFO": "Start typing to search for tasks",
|
||||
"INFO_ARCHIVED": "Click on the archive icon to search for normal tasks",
|
||||
"NO_RESULTS": "No tasks found matching your search",
|
||||
"PLACEHOLDER": "Search for task or task description",
|
||||
"PLACEHOLDER_ARCHIVED": "Search for archived tasks",
|
||||
"TOO_MANY_RESULTS": "Too many results, please narrow your search"
|
||||
"PLACEHOLDER": "Search for task or task description"
|
||||
},
|
||||
"SIMPLE_COUNTER": {
|
||||
"D_CONFIRM_REMOVE": {
|
||||
|
|
@ -954,7 +762,6 @@
|
|||
"L_COUNTDOWN_DURATION": "Countdown duration",
|
||||
"L_DAILY_GOAL": "Daily goal for successful streak",
|
||||
"L_ICON": "圖標",
|
||||
"L_ICON_ON": "切換後的圖標",
|
||||
"L_IS_ENABLED": "啟用",
|
||||
"L_TITLE": "標題",
|
||||
"L_TRACK_STREAKS": "Track Streaks",
|
||||
|
|
@ -972,19 +779,11 @@
|
|||
},
|
||||
"SYNC": {
|
||||
"A": {
|
||||
"ARCHIVE_ONLY_UPLOADED": "您的數據僅部分上傳。請稍後再試!否則,您將無法將數據同步到其他設備。",
|
||||
"POSSIBLE_LEGACY_DATA": "Super Productivity 現在使用兩個獨立的文件而不是單個文件來改進同步,這樣可以減少數據傳輸量。建議更新所有 Super Productivity 實例,並首先從數據最新的應用實例同步數據。如果這是您本地設備中的數據,則請忽略此警告,並通過確認下一個對話框來繼續上傳。",
|
||||
"REMOTE_MODEL_VERSION_NEWER": "The remote model version is newer than the local one. Please update your local app to the newest version!"
|
||||
},
|
||||
"BTN_SYNC_NOW": "Sync Now",
|
||||
"C": {
|
||||
"EMPTY_SYNC": "您正在嘗試同步一個空的資料對象。這是您(幾乎)原始應用程式的第一次同步嗎?",
|
||||
"FORCE_UPLOAD": "仍要上傳本地資料嗎?",
|
||||
"FORCE_UPLOAD_AFTER_ERROR": "上傳本地資料時發生錯誤。嘗試強制更新?",
|
||||
"MIGRATE_LEGACY": "Legacy data detected while importing, do you want to try to migrate it?",
|
||||
"NO_REMOTE_DATA": "找不到遠端資料。本地上傳到遠端嗎?",
|
||||
"TRY_LOAD_REMOTE_AGAIN": "嘗試再次從遠端重新載入資料?",
|
||||
"UNABLE_TO_LOAD_REMOTE_DATA": "無法從遠端加載數據。您想嘗試用本地數據覆蓋遠端數據嗎?此過程將導致所有遠端數據丟失。"
|
||||
"FORCE_UPLOAD": "仍要上傳本地資料嗎?"
|
||||
},
|
||||
"D_AUTH_CODE": {
|
||||
"FOLLOW_LINK": "Please open the following link and copy the auth code provided there into the input field below.",
|
||||
|
|
@ -994,8 +793,6 @@
|
|||
},
|
||||
"D_CONFLICT": {
|
||||
"COMPARISON_RESULT": "Comparison Result",
|
||||
"LAMPORT_CLOCK": "Revision",
|
||||
"LAST_CHANGE": "最後一次變更:",
|
||||
"LAST_SYNC": "上次同步:",
|
||||
"LAST_SYNCED": "Last Synced",
|
||||
"LAST_WRITE": "Last Write",
|
||||
|
|
@ -1035,10 +832,6 @@
|
|||
"BTN_FORCE_UPLOAD": "Force Upload Local",
|
||||
"P1": "The remote sync data is incoherent!",
|
||||
"P2": "Affected model:",
|
||||
"P3": "You have 2 Options:",
|
||||
"P4": "1. Go to your other device and attempt do a complete sync there.",
|
||||
"P5": "2. Overwrite the remote data with your local data. All remote changes will be lost!",
|
||||
"P6": "Creating a backup of the data you overwrite is recommended!!!",
|
||||
"T1": "Last sync was incomplete!",
|
||||
"T2": "Your archive data was not properly uploaded during last sync:",
|
||||
"T3": "You have 2 Options:",
|
||||
|
|
@ -1050,19 +843,9 @@
|
|||
"SAVE_AND_ENABLE": "Save & Enable Sync",
|
||||
"TITLE": "Configure Sync"
|
||||
},
|
||||
"D_PERMISSION": {
|
||||
"DISABLE_SYNC": "Disable sync",
|
||||
"PERM_FILE": "Give permission",
|
||||
"TEXT": "<p>Your file permission for local syncing has been revoked.</p>",
|
||||
"TITLE": "Sync: Local file permission denied"
|
||||
},
|
||||
"FORM": {
|
||||
"DROPBOX": {
|
||||
"L_ACCESS_TOKEN": "存取權杖(從身份驗證代碼生成)"
|
||||
},
|
||||
"GOOGLE": {
|
||||
"L_SYNC_FILE_NAME": "同步檔案名"
|
||||
},
|
||||
"DROPBOX": {},
|
||||
"GOOGLE": {},
|
||||
"L_ENABLE_COMPRESSION": "Enable Compression (faster data transfer)",
|
||||
"L_ENABLE_ENCRYPTION": "Enable end-to-end encryption (experimental) – Make your data inaccessible for your sync provider",
|
||||
"L_ENABLE_SYNCING": "啟用同步",
|
||||
|
|
@ -1071,7 +854,6 @@
|
|||
"L_SYNC_INTERVAL": "同步間隔",
|
||||
"L_SYNC_PROVIDER": "同步提供者",
|
||||
"LOCAL_FILE": {
|
||||
"L_SYNC_FILE_PATH_PERMISSION_VALIDATION": "Needs file access permission",
|
||||
"L_SYNC_FOLDER_PATH": "Sync folder path"
|
||||
},
|
||||
"TITLE": "同步",
|
||||
|
|
@ -1086,26 +868,16 @@
|
|||
},
|
||||
"S": {
|
||||
"ALREADY_IN_SYNC": "Already in sync",
|
||||
"ALREADY_IN_SYNC_NO_LOCAL_CHANGES": "No local changes – Already in sync",
|
||||
"BTN_CONFIGURE": "Configure",
|
||||
"BTN_FORCE_OVERWRITE": "Force Overwrite",
|
||||
"ERROR_CORS": "WebDAV Sync Error: Network request failed.\n\nThis might be a CORS issue. Please ensure:\n• Your WebDAV server allows Cross-Origin requests\n• The server URL is correct and accessible\n• You have a working internet connection",
|
||||
"ERROR_DATA_IS_CURRENTLY_WRITTEN": "Remote Data is currently being written",
|
||||
"ERROR_FALLBACK_TO_BACKUP": "匯入資料時發生錯誤了。回到本地備份。",
|
||||
"ERROR_INVALID_DATA": "同步時發生錯誤。無效資料",
|
||||
"ERROR_NO_REV": "No valid rev for remote file",
|
||||
"ERROR_UNABLE_TO_READ_REMOTE_DATA": "Error while syncing. Unable to read remote data. Maybe you enabled encryption and your local password does not match the one used to encrypt the remote data?",
|
||||
"IMPORTING": "匯入資料",
|
||||
"INCOMPLETE_CFG": "Authentication for sync failed. Please check your Config!",
|
||||
"INITIAL_SYNC_ERROR": "Initial Sync failed",
|
||||
"SUCCESS_DOWNLOAD": "Synced data from remote",
|
||||
"SUCCESS_IMPORT": "資料已匯入",
|
||||
"SUCCESS_VIA_BUTTON": "Data successfully synced",
|
||||
"UNKNOWN_ERROR": "同步時發生未知錯誤:{{err}}",
|
||||
"UPLOAD_ERROR": "未知的上傳錯誤(設置正確嗎?): {{err}}"
|
||||
"UNKNOWN_ERROR": "同步時發生未知錯誤:{{err}}"
|
||||
},
|
||||
"SAFETY_BACKUP": {
|
||||
"TITLE": "Sync Safety Backups",
|
||||
"DESCRIPTION": "Automatic backups are created before downloading data from remote during sync operations. Backups are organized in 4 smart slots: 2 most recent, 1 first from today, and 1 first from a day before today.",
|
||||
"BTN_CREATE_MANUAL": "Create Manual Backup",
|
||||
"BTN_REFRESH": "Refresh",
|
||||
|
|
@ -1125,11 +897,6 @@
|
|||
"REASON_MANUAL": "Manual backup",
|
||||
"REASON_BEFORE_UPDATE": "Automatic backup before sync",
|
||||
"LAST_CHANGE_PREFIX": "Last change:",
|
||||
"RESTORE_CONFIRM_TITLE": "Restore Backup",
|
||||
"RESTORE_CONFIRM_MSG": "Are you sure you want to restore the backup from {{timestamp}}?\n\nThis will COMPLETELY REPLACE all your current data!\n\nReason: {{reason}}\n\nClick OK to proceed or Cancel to abort.",
|
||||
"BACKUP_NOT_FOUND": "Backup with ID {{backupId}} not found",
|
||||
"RESTORE_FAILED": "Failed to restore backup: {{error}}",
|
||||
"INVALID_ID_ERROR": "Invalid backup ID generated",
|
||||
"CREATED_SUCCESS": "Manual backup created successfully",
|
||||
"RESTORED_SUCCESS": "Backup restored successfully",
|
||||
"DELETED_SUCCESS": "Backup deleted successfully",
|
||||
|
|
@ -1141,8 +908,7 @@
|
|||
},
|
||||
"TAG": {
|
||||
"D_CREATE": {
|
||||
"CREATE": "建立標籤",
|
||||
"EDIT": "編輯標籤"
|
||||
"CREATE": "建立標籤"
|
||||
},
|
||||
"D_DELETE": {
|
||||
"CONFIRM_MSG": "您是否真的要刪除標籤 \"{{tagName}}\"?它將從所有任務中刪除。這不能被撤消。"
|
||||
|
|
@ -1168,16 +934,6 @@
|
|||
"TASK": {
|
||||
"ADD_TASK_BAR": {
|
||||
"ADD_EXISTING_TASK": "添加現有任務\"{{taskTitle}}\"",
|
||||
"ADD_ISSUE_TASK": "從 {{issueType}}添加問題#{{issueNr}} ",
|
||||
"ADD_TASK_TO_BOTTOM_OF_BACKLOG": "Add task to bottom of backlog",
|
||||
"ADD_TASK_TO_BOTTOM_OF_TODAY": "Add task to bottom of list",
|
||||
"ADD_TASK_TO_TOP_OF_BACKLOG": "Add task to top of backlog",
|
||||
"ADD_TASK_TO_TOP_OF_TODAY": "Add task to top of list",
|
||||
"CREATE_TASK": "建立新任務",
|
||||
"EXAMPLE": "示例:\"某些任務標題+ projectName #一些標籤 #一些其他標籤10m/3h\"",
|
||||
"START": "再次按回車鍵開始",
|
||||
"TOGGLE_ADD_TO_BACKLOG_TODAY": "切換將任務添加到待辦/今天列表",
|
||||
"TOGGLE_ADD_TOP_OR_BOTTOM": "切換將任務添加到列表的頂部或底部",
|
||||
"PLACEHOLDER_SEARCH": "Add existing task or issues...",
|
||||
"PLACEHOLDER_CREATE": "A task title #tag @16:00",
|
||||
"TOOLTIP_ADD_TASK": "Add task",
|
||||
|
|
@ -1194,8 +950,6 @@
|
|||
"TOOLTIP_CLEAR_DATE": "Clear date",
|
||||
"TOOLTIP_CLEAR_TAGS": "Clear tags",
|
||||
"TOOLTIP_CLEAR_ESTIMATE": "Clear estimate",
|
||||
"NO_DATE": "No Date",
|
||||
"NO_TIME": "No Time",
|
||||
"TODAY": "Today",
|
||||
"TOMORROW": "Tomorrow",
|
||||
"CREATE_NEW_TAGS": "Create new tags"
|
||||
|
|
@ -1205,11 +959,9 @@
|
|||
"ADD_SUB_TASK": "添加子任務",
|
||||
"ATTACHMENTS": "附件 {{nr}}",
|
||||
"DUE": "计划时间",
|
||||
"FROM_PARENT": "(來自父任務)",
|
||||
"LOCAL_ATTACHMENTS": "本地附件",
|
||||
"NOTES": "筆記",
|
||||
"PARENT": "親",
|
||||
"REMINDER": "提醒",
|
||||
"REPEAT": "重複",
|
||||
"SCHEDULE_TASK": "安排任務",
|
||||
"SUB_TASKS": "子任務({{nr}})",
|
||||
|
|
@ -1230,11 +982,8 @@
|
|||
"DROP_ATTACHMENT": "放在此處以附加到\"{{title}}\"",
|
||||
"DUPLICATE": "Duplicate",
|
||||
"EDIT_SCHEDULED": "編輯提醒",
|
||||
"EDIT_TAGS": "編輯標籤",
|
||||
"EDIT_TASK_TITLE": "Edit title",
|
||||
"FOCUS_SESSION": "Start Focus Session",
|
||||
"MARK_DONE": "標記為已完成",
|
||||
"MARK_UNDONE": "標記為未完成",
|
||||
"MOVE_TO_BACKLOG": "轉到待辦事項",
|
||||
"MOVE_TO_OTHER_PROJECT": "轉到其他項目",
|
||||
"MOVE_TO_REGULAR": "轉到今天的列表",
|
||||
|
|
@ -1243,9 +992,7 @@
|
|||
"OPEN_ISSUE": "在新的瀏覽器選項卡中打開 Issue ",
|
||||
"OPEN_TIME": "估計時間/增加花費的已用時間",
|
||||
"REMOVE_FROM_MY_DAY": "從我的一天中刪除",
|
||||
"REPEAT_EDIT": "編輯重複任務",
|
||||
"SCHEDULE": "安排任務",
|
||||
"SHOW_UPDATES": "顯示更新",
|
||||
"TOGGLE_ATTACHMENTS": "顯示/隱藏附件",
|
||||
"TOGGLE_DETAIL_PANEL": "顯示/隱藏其他資訊",
|
||||
"TOGGLE_DONE": "標記為已完成/未完成",
|
||||
|
|
@ -1272,26 +1019,19 @@
|
|||
"DONE": "完成",
|
||||
"DUE_TASK": "到期任務",
|
||||
"DUE_TASKS": "到期任務",
|
||||
"FOR_CURRENT": "任務到期了,你想開始工作嗎?",
|
||||
"FOR_OTHER": "任務到期了。你想開始工作嗎?",
|
||||
"FROM_PROJECT": "來自項目",
|
||||
"FROM_TAG": "來自標籤:\"{{title}}\"",
|
||||
"RESCHEDULE_EDIT": "Edit (Re-schedule)",
|
||||
"RESCHEDULE_UNTIL_TOMORROW": "明天重新開始",
|
||||
"SNOOZE": "暫停",
|
||||
"SNOOZE_ALL": "全部暫停",
|
||||
"START": "開始任務",
|
||||
"SWITCH_CONTEXT_START": "切換內容上下文並開始",
|
||||
"UNSCHEDULE": "Unschedule",
|
||||
"UNSCHEDULE_ALL": "Unschedule all",
|
||||
"DISMISS_REMINDER_KEEP_TODAY": "Dismiss Reminder (Keep in Today)",
|
||||
"DISMISS_ALL_REMINDERS_KEEP_TODAY": "Dismiss All Reminders (Keep in Today)"
|
||||
},
|
||||
"D_SCHEDULE_TASK": {
|
||||
"MOVE_TO_BACKLOG": "在計劃時間到來後將任務移至待辦事項",
|
||||
"QA_NEXT_MONTH": "Schedule next Month",
|
||||
"QA_NEXT_WEEK": "Schedule next Week",
|
||||
"QA_REMOVE_TODAY": "Remove task from today",
|
||||
"QA_TODAY": "Schedule Today",
|
||||
"QA_TOMORROW": "Schedule Tomorrow",
|
||||
"REMIND_AT": "提醒時間",
|
||||
|
|
@ -1327,15 +1067,12 @@
|
|||
"S": {
|
||||
"CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK": "Cannot assign project via short syntax for repeatable tasks!",
|
||||
"CREATED_FOR_PROJECT": "Created task \"{{taskTitle}}\" for project \"{{projectTitle}}\"",
|
||||
"CREATED_FOR_PROJECT_ACTION": "Go to Project",
|
||||
"DELETED": "已刪除任務\"{{title}}\"",
|
||||
"FOUND_MOVE_FROM_BACKLOG": "將任務<strong>{{title}}</strong>移至今日任務列表",
|
||||
"FOUND_MOVE_FROM_OTHER_LIST": "已將任務<strong>{{title}}</strong>從<strong>{{contextTitle}}</strong>添加到當前列表",
|
||||
"FOUND_RESTORE_FROM_ARCHIVE": "已恢復的任務<strong>{{title}}</strong>與存檔 Issue 相關",
|
||||
"LAST_TAG_DELETION_WARNING": "您正在嘗試刪除非項目任務的最後一個標籤。這是不允許的!",
|
||||
"MOVED_TO_ARCHIVE": "Moved {{nr}} tasks to archive",
|
||||
"MOVED_TO_PROJECT": "Moved task \"{{taskTitle}}\" to project \"{{projectTitle}}\"",
|
||||
"MOVED_TO_PROJECT_ACTION": "Go to Project",
|
||||
"REMINDER_ADDED": "已計劃任務\"{{title}}\"",
|
||||
"REMINDER_DELETED": "已刪除任務提醒",
|
||||
"REMINDER_UPDATED": "更新了任務\"{{title}}\"的提醒",
|
||||
|
|
@ -1407,7 +1144,6 @@
|
|||
"C_YEAR": "Year",
|
||||
"DEFAULT_ESTIMATE": "預設預估用時",
|
||||
"FRIDAY": "星期️五",
|
||||
"IS_ADD_TO_BOTTOM": "將任務移到列表底部",
|
||||
"MONDAY": "星期一",
|
||||
"NOTES": "Default notes",
|
||||
"ORDER": "Order",
|
||||
|
|
@ -1464,7 +1200,6 @@
|
|||
"SCHEDULED_THIS_WEEK": "This Week",
|
||||
"SCHEDULED_TODAY": "Today",
|
||||
"SCHEDULED_TOMORROW": "Tomorrow",
|
||||
"SORT_BY": "Sort By",
|
||||
"SORT_CREATION_DATE": "Creation Date",
|
||||
"SORT_DEFAULT": "Default",
|
||||
"SORT_NAME": "Name",
|
||||
|
|
@ -1474,8 +1209,7 @@
|
|||
"TIME_10MIN": "> 10 Minutes",
|
||||
"TIME_30MIN": "> 30 Minutes",
|
||||
"FILTER_NOT_SPECIFIED": "未指定",
|
||||
"TIME_SPENT": "Time Spent",
|
||||
"TITLE": "Customize Task View"
|
||||
"TIME_SPENT": "Time Spent"
|
||||
}
|
||||
},
|
||||
"TIME_TRACKING": {
|
||||
|
|
@ -1508,7 +1242,6 @@
|
|||
},
|
||||
"D_TRACKING_REMINDER": {
|
||||
"CREATE_AND_TRACK": "<em>建立</em>並追蹤到",
|
||||
"IDLE_FOR": "你一直閑著:",
|
||||
"NOTIFICATION_TITLE": "Track your time!",
|
||||
"TASK": "任務",
|
||||
"TRACK_TO": "追蹤到:",
|
||||
|
|
@ -1520,7 +1253,6 @@
|
|||
"DAYS_WORKED": "工作日:",
|
||||
"MONTH_WORKED": "工作月份:",
|
||||
"REPEATING_TASK": "重複任務",
|
||||
"RESTORE_TASK_FROM_ARCHIVE": "從存檔還原任務",
|
||||
"TASKS": "任務",
|
||||
"TOTAL_TIME": "總花費時間:",
|
||||
"WEEK_NR": "{{nr}}周 ",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
"CONTEXT_MENU": {
|
||||
"CHANGE_BACKGROUND": "更改背景"
|
||||
},
|
||||
"SKIP_SYNC_WAIT": "立即使用,无需等待同步",
|
||||
"UPDATE_MAIN_MODEL": "超级生产力已进行重大更新!您的数据需要一些迁移。请注意,这会使您的数据与应用的旧版本不兼容。",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "未选择模型更新。请注意,如果您不想执行模型升级,则必须降级到上一个版本。",
|
||||
"UPDATE_WEB_APP": "有新版本可用。加载新版本?"
|
||||
|
|
@ -47,11 +48,11 @@
|
|||
"TOMORROW": "明天"
|
||||
},
|
||||
"DIALOG_UNSPLASH_PICKER": {
|
||||
"TITLE": "从 Unsplash 选择背景图片",
|
||||
"BY": "由",
|
||||
"NO_RESULTS": "没有找到图片。尝试不同的搜索词。",
|
||||
"SEARCH_LABEL": "搜索图片",
|
||||
"SEARCH_PLACEHOLDER": "例如,自然、山脉、抽象",
|
||||
"NO_RESULTS": "没有找到图片。尝试不同的搜索词。",
|
||||
"BY": "由"
|
||||
"TITLE": "从 Unsplash 选择背景图片"
|
||||
},
|
||||
"DONATE_PAGE": {
|
||||
"BUTTON_TEXT": "通过 GitHub Sponsors 捐赠",
|
||||
|
|
@ -161,6 +162,7 @@
|
|||
"CALENDARS": {
|
||||
"BANNER": {
|
||||
"ADD_AS_TASK": "添加为任务",
|
||||
"FOCUS_TASK": "专注任务",
|
||||
"SHOW_TASK": "显示任务",
|
||||
"TXT": "<strong>{{title}}</strong> 在 <strong>{{start}}</strong> 开始!",
|
||||
"TXT_MULTIPLE": "<strong>{{title}}</strong> 在 <strong>{{start}}</strong> 开始!<br> (以及 {{nrOfOtherBanners}} 个其他事件到期)",
|
||||
|
|
@ -233,6 +235,7 @@
|
|||
"COMPLETE_FOCUS_SESSION": "完成专注会话",
|
||||
"COMPLETE_SESSION": "完成会话",
|
||||
"CONGRATS": "恭喜完成此会话!",
|
||||
"CONTINUE_FOCUS_SESSION": "继续专注任务",
|
||||
"CONTINUE_SESSION": "继续会话",
|
||||
"CONTINUE_TO_NEXT_SESSION": "继续下一个会话",
|
||||
"COUNTDOWN": "倒计时",
|
||||
|
|
@ -273,6 +276,7 @@
|
|||
"SHORT_BREAK_TITLE": "短休息 - 第 {{cycle}} 轮",
|
||||
"SHOW_HIDE_NOTES_AND_ATTACHMENTS": "显示/隐藏任务备注和附件",
|
||||
"SKIP_BREAK": "跳过休息",
|
||||
"START_BREAK": "开始休息",
|
||||
"START_FOCUS_SESSION": "开始专注会话",
|
||||
"START_NEXT_FOCUS_SESSION": "开始下一个专注会话",
|
||||
"SWITCH_TASK": "切换任务",
|
||||
|
|
@ -628,18 +632,31 @@
|
|||
},
|
||||
"EVAL_FORM": {
|
||||
"ADD_NOTE_FOR_TOMORROW": "为明天添加备注",
|
||||
"FOCUS_WORK_TIME": "专注工作时间",
|
||||
"IMPACT_OF_WORK": "您如何评价您今天的工作所产生的影响?",
|
||||
"IMPACT_OF_WORK_HINT": "1:没有实质进展 — 4:显著影响",
|
||||
"PRODUCTIVITY_SCORE": "生产力评分",
|
||||
"PRODUCTIVITY_SCORE_TOOLTIP": "65% 影响力(1-4分)• 30% 专注度(以4小时为目标)• 5% 总工作时间(最多10小时)",
|
||||
"SUSTAINABILITY_SCORE": "可持续性评分",
|
||||
"SUSTAINABILITY_SCORE_TOOLTIP": "45% 精力水平 • 40% 合理工作时间(10小时为0分)• 15% 专注平衡(最佳为4小时)",
|
||||
"ENERGY_LEVEL": "您的精力如何?",
|
||||
"ENERGY_LEVEL_HINT": "😫 筋疲力尽 — 😐 还行 — 😊 很好",
|
||||
"TOTAL_WORK_TIME": "今天总工作时间",
|
||||
"DAILY_STATE": "每日状态",
|
||||
"DAILY_STATE_TOOLTIP": "基于两项评分的四象限系统(≥50为高分):深度专注(高/高)、过度驱动(高/低)、恢复调整(低/高)、漂移状态(低/低)",
|
||||
"DISABLE_REPEAT_EVERY_DAY": "",
|
||||
"ENABLE_REPEAT_EVERY_DAY": "允许每天重复",
|
||||
"ENERGY_LEVEL": "您的精力如何?",
|
||||
"ENERGY_LEVEL_HINT": "😫 筋疲力尽 — 😐 还行 — 😊 很好",
|
||||
"FOCUS_WORK_TIME": "专注工作时间",
|
||||
"HELP_H1": "",
|
||||
"HELP_LINK_TXT": "",
|
||||
"HELP_P1": "",
|
||||
"HELP_P2": "",
|
||||
"IMPACT_OF_WORK": "您如何评价您今天的工作所产生的影响?",
|
||||
"IMPACT_OF_WORK_HINT": "1:没有实质进展 — 4:显著影响",
|
||||
"IMPROVEMENTS": "",
|
||||
"IMPROVEMENTS_TOMORROW": "",
|
||||
"MOOD": "",
|
||||
"MOOD_HINT": "",
|
||||
"NOTES": "",
|
||||
"OBSTRUCTIONS": "",
|
||||
"PRODUCTIVITY": "",
|
||||
"PRODUCTIVITY_HINT": "",
|
||||
"PRODUCTIVITY_SCORE": "生产力评分",
|
||||
"PRODUCTIVITY_SCORE_TOOLTIP": "65% 影响力(1-4分)• 30% 专注度(以4小时为目标)• 5% 总工作时间(最多10小时)",
|
||||
"SCORE_BREAKDOWN_TITLE_PRODUCTIVITY": "7天生产力分解",
|
||||
"SCORE_BREAKDOWN_TITLE_SUSTAINABILITY": "7天可持续性分解",
|
||||
"STATE_DEEP_FLOW_HEADLINE": "深度专注:专注力强,节奏可持续。",
|
||||
"STATE_DEEP_FLOW_HINT": "您正处于最佳状态——反思是什么促成了这种理想组合。",
|
||||
"STATE_OVERDRIVE_HEADLINE": "过度驱动:高产但代价不小。",
|
||||
|
|
@ -652,8 +669,9 @@
|
|||
"STATE_STEADY_HINT": "平衡不错。您在保持动力的同时没有过度用力——继续滋养这种节奏的关键。",
|
||||
"STATE_IMPACT_MISMATCH_HEADLINE": "影响力不足:专注投入,但收效甚微。",
|
||||
"STATE_IMPACT_MISMATCH_HINT": "您投入了专注——现在将其导向更高影响力的工作,您会看到不同。",
|
||||
"SCORE_BREAKDOWN_TITLE_PRODUCTIVITY": "7天生产力分解",
|
||||
"SCORE_BREAKDOWN_TITLE_SUSTAINABILITY": "7天可持续性分解"
|
||||
"SUSTAINABILITY_SCORE": "可持续性评分",
|
||||
"SUSTAINABILITY_SCORE_TOOLTIP": "45% 精力水平 • 40% 合理工作时间(10小时为0分)• 15% 专注平衡(最佳为4小时)",
|
||||
"TOTAL_WORK_TIME": "今天总工作时间"
|
||||
},
|
||||
"FOCUS_SESSION_DIALOG": {
|
||||
"TITLE": "专注会话",
|
||||
|
|
@ -691,6 +709,23 @@
|
|||
"NOTE_LABEL": "输入一些文本保存为备注(您可以使用 Markdown)..."
|
||||
},
|
||||
"D_FULLSCREEN": {
|
||||
"TOOLBAR": {
|
||||
"BOLD": "粗体",
|
||||
"BULLET_LIST": "无序列表",
|
||||
"CODE_BLOCK": "代码块",
|
||||
"HEADING_1": "标题 1",
|
||||
"HEADING_2": "标题 2",
|
||||
"HEADING_3": "标题 3",
|
||||
"INLINE_CODE": "行内代码",
|
||||
"INSERT_IMAGE": "插入图片",
|
||||
"INSERT_LINK": "插入链接",
|
||||
"INSERT_TABLE": "插入表格",
|
||||
"ITALIC": "斜体",
|
||||
"NUMBERED_LIST": "有序列表",
|
||||
"QUOTE": "引用",
|
||||
"STRIKETHROUGH": "删除线",
|
||||
"TASK_LIST": "任务列表"
|
||||
},
|
||||
"VIEW_PARSED": "查看解析后的(不可编辑)Markdown",
|
||||
"VIEW_SPLIT": "在拆分视图中查看解析和未解析的 Markdown",
|
||||
"VIEW_TEXT_ONLY": "查看未解析的文本"
|
||||
|
|
@ -831,7 +866,7 @@
|
|||
},
|
||||
"H1": "放自己一马!",
|
||||
"INTRO": {
|
||||
"AVOIDING": "避免任务",
|
||||
"AVOIDING": "逃避任务",
|
||||
"FEAR": "害怕失败",
|
||||
"STRESSED": "因未完成事情而感到压力",
|
||||
"TITLE": "介绍"
|
||||
|
|
@ -920,8 +955,8 @@
|
|||
},
|
||||
"SELECT": {
|
||||
"LABEL": "文件夹",
|
||||
"PLACEHOLDER": "选择文件夹",
|
||||
"NO_PARENT": "无文件夹(根级别)"
|
||||
"NO_PARENT": "无文件夹(根级别)",
|
||||
"PLACEHOLDER": "选择文件夹"
|
||||
},
|
||||
"TOOLTIP_CREATE": "创建项目文件夹",
|
||||
"TOOLTIP_VISIBILITY": "显示/隐藏项目"
|
||||
|
|
@ -974,6 +1009,40 @@
|
|||
"S_ACTIVE_TASK_DUE": "您当前正在处理的任务现已到期!<br/> ({{title}})",
|
||||
"S_REMINDER_ERR": "提醒界面的错误"
|
||||
},
|
||||
"SAFETY_BACKUP": {
|
||||
"BACKUP_NOT_FOUND": "",
|
||||
"BTN_CLEAR_ALL": "",
|
||||
"BTN_CREATE_MANUAL": "",
|
||||
"BTN_DELETE": "",
|
||||
"BTN_REFRESH": "",
|
||||
"BTN_RESTORE": "",
|
||||
"CLEAR_FAILED": "",
|
||||
"CLEARED_SUCCESS": "",
|
||||
"CREATE_FAILED": "",
|
||||
"CREATED_SUCCESS": "",
|
||||
"DELETE_FAILED": "",
|
||||
"DELETED_SUCCESS": "",
|
||||
"DESCRIPTION": "",
|
||||
"INVALID_ID_ERROR": "",
|
||||
"LAST_CHANGE_PREFIX": "",
|
||||
"LOADING": "",
|
||||
"NO_BACKUPS": "",
|
||||
"REASON_BEFORE_UPDATE": "",
|
||||
"REASON_MANUAL": "",
|
||||
"RESTORE_CONFIRM_MSG": "",
|
||||
"RESTORE_CONFIRM_TITLE": "",
|
||||
"RESTORE_FAILED": "",
|
||||
"RESTORED_SUCCESS": "",
|
||||
"SLOT_BEFORE_TODAY": "",
|
||||
"SLOT_RECENT": "",
|
||||
"SLOT_TODAY": "",
|
||||
"TITLE": "",
|
||||
"TOOLTIP_CLEAR_ALL": "",
|
||||
"TOOLTIP_CREATE_MANUAL": "",
|
||||
"TOOLTIP_DELETE": "",
|
||||
"TOOLTIP_REFRESH": "",
|
||||
"TOOLTIP_RESTORE": ""
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"CONTINUED": "继续",
|
||||
"D_INITIAL": {
|
||||
|
|
@ -1148,6 +1217,7 @@
|
|||
"L_SYNC_FOLDER_PATH": "同步文件夹路径",
|
||||
"L_TEST_CONNECTION": "测试链接",
|
||||
"L_USER_NAME": "用户名",
|
||||
"S_FILL_ALL_FIELDS": "请先填入所有的 WebDAV 字段",
|
||||
"S_TEST_FAIL": "连接测试失败:{{error}} - 目标URL:{{url}}",
|
||||
"S_TEST_SUCCESS": "连接测试成功!目标URL:{{url}}"
|
||||
}
|
||||
|
|
@ -1434,6 +1504,7 @@
|
|||
"REMINDER_ADDED": "已安排 <strong>{{title}}</strong> 于 <strong>{{date}}</strong>",
|
||||
"REMINDER_DELETED": "已删除任务提醒",
|
||||
"REMINDER_UPDATED": "已更新任务“{{title}}”的提醒",
|
||||
"TASK_ALREADY_EXISTS": "任务 <strong>{{title}}</strong> 已经存在",
|
||||
"TASK_CREATED": "已创建任务“{{taskTitle}}”"
|
||||
},
|
||||
"SELECT_OR_CREATE": "选择或创建任务",
|
||||
|
|
@ -1548,6 +1619,7 @@
|
|||
"FILTER_BY": "筛选方式",
|
||||
"FILTER_DEFAULT": "无筛选",
|
||||
"FILTER_ESTIMATED_TIME": "预计时间",
|
||||
"FILTER_NOT_SPECIFIED": "未指定",
|
||||
"FILTER_PROJECT": "项目",
|
||||
"FILTER_SCHEDULED_DATE": "计划日期",
|
||||
"FILTER_TAG": "标签",
|
||||
|
|
@ -1564,17 +1636,17 @@
|
|||
"SCHEDULED_THIS_WEEK": "本周",
|
||||
"SCHEDULED_TODAY": "今天",
|
||||
"SCHEDULED_TOMORROW": "明天",
|
||||
"SORT_TEMPORARY": "排序 (临时)",
|
||||
"SORT_BY": "",
|
||||
"SORT_CREATION_DATE": "创建日期",
|
||||
"SORT_DEFAULT": "默认",
|
||||
"SORT_NAME": "名称",
|
||||
"SORT_PERMANENT": "排序 (永久)",
|
||||
"SORT_SCHEDULED_DATE": "计划日期",
|
||||
"SORT_TEMPORARY": "排序 (临时)",
|
||||
"TIME_1HOUR": "> 1 小时",
|
||||
"TIME_2HOUR": "> 2 小时",
|
||||
"TIME_10MIN": "> 10 分钟",
|
||||
"TIME_30MIN": "> 30 分钟",
|
||||
"FILTER_NOT_SPECIFIED": "未指定",
|
||||
"TIME_SPENT": "花费时间",
|
||||
"TITLE": "自定义任务视图"
|
||||
}
|
||||
|
|
@ -1708,6 +1780,7 @@
|
|||
"DISMISS": "忽略",
|
||||
"DO_IT": "做吧!",
|
||||
"DONT_SHOW_AGAIN": "不再显示",
|
||||
"DUPLICATE": "重复",
|
||||
"DURATION_DESCRIPTION": "例如 \"5h 23m\",结果为 5 小时 23 分钟",
|
||||
"EDIT": "编辑",
|
||||
"ENABLED": "启用",
|
||||
|
|
@ -1740,6 +1813,22 @@
|
|||
"YESTERDAY": "昨天"
|
||||
},
|
||||
"GCF": {
|
||||
"APP_FEATURES": {
|
||||
"BOARDS": "看板",
|
||||
"DONATE_PAGE": "捐赠页面",
|
||||
"FOCUS_MODE": "专注模式",
|
||||
"HELP": "在用户界面中全局启用或禁用特定的应用功能。",
|
||||
"ISSUES_PANEL": "问题面板",
|
||||
"PLANNER": "规划表",
|
||||
"PROJECT_NOTES": "项目笔记",
|
||||
"SCHEDULE": "日程",
|
||||
"SCHEDULE_DAY_PANEL": "日程面板",
|
||||
"SYNC_BUTTON": "同步按钮",
|
||||
"TIME_TRACKING": "秒表式时间追踪",
|
||||
"TITLE": "应用功能",
|
||||
"USER_PROFILES": "用户配置文件 (实验性)",
|
||||
"USER_PROFILES_HINT": "允许您创建和切换不同的用户配置文件,每个配置文件拥有独立的设置、任务和同步配置。启用后,配置文件管理按钮将出现在右上角。注意:禁用此功能将隐藏相关界面,但会保留您的配置文件数据。(此为实验性功能,不作保证。请确保您已备份数据。)"
|
||||
},
|
||||
"AUTO_BACKUPS": {
|
||||
"HELP": "自动将所有数据保存到您的应用文件夹,以防出现问题。",
|
||||
"LABEL_IS_ENABLED": "启用自动备份",
|
||||
|
|
@ -1762,11 +1851,12 @@
|
|||
"FOCUS_MODE": {
|
||||
"HELP": "专注模式打开一个无干扰的屏幕,以帮助您专注于当前任务。",
|
||||
"L_ALWAYS_OPEN_FOCUS_MODE": "始终在跟踪时打开专注模式",
|
||||
"L_SKIP_PREPARATION_SCREEN": "跳过准备屏幕(拉伸等)",
|
||||
"L_IS_PLAY_TICK": "专注时播放滴答声",
|
||||
"L_MANUAL_BREAK_START": "Manually start breaks (Pomodoro)",
|
||||
"L_PAUSE_TRACKING_DURING_BREAK": "休息期间暂停任务跟踪",
|
||||
"L_SKIP_PREPARATION_SCREEN": "跳过准备界面(火箭动画)",
|
||||
"L_START_IN_BACKGROUND": "仅以横幅开始专注时段(无覆盖层)",
|
||||
"L_SYNC_SESSION_WITH_TRACKING": "将专注会话与时间追踪同步",
|
||||
"TITLE": "专注模式"
|
||||
},
|
||||
"IDLE": {
|
||||
|
|
@ -1844,6 +1934,7 @@
|
|||
"EN": "English",
|
||||
"ES": "Español",
|
||||
"FA": "فارسی",
|
||||
"FI": "Suomi",
|
||||
"FR": "français",
|
||||
"HR": "Hrvatski",
|
||||
"ID": "Indonesian",
|
||||
|
|
@ -1858,26 +1949,27 @@
|
|||
"PT_BR": "Português (Brazil)",
|
||||
"RU": "Русский",
|
||||
"SK": "Slovak",
|
||||
"SV": "Svenska",
|
||||
"TIME_LOCALE": "时间格式区域",
|
||||
"TIME_LOCALE_AUTO": "系统默认",
|
||||
"TIME_LOCALE_DE_DE": "德语:24小时制,日.月.年",
|
||||
"TIME_LOCALE_DESCRIPTION": "注意:这些选项现在无法改变时间输入格式(12/24 小时),因为它由您的操作系统控制",
|
||||
"TIME_LOCALE_EN_US": "美式英语:12小时制(上午/下午),月/日/年",
|
||||
"TIME_LOCALE_EN_GB": "英式英语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_ES_ES": "西班牙语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_FR_FR": "法语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_IT_IT": "意大利语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_JA_JP": "日语:24小时制,年/月/日",
|
||||
"TIME_LOCALE_KO_KR": "韩语:12小时制(上午/下午),年. 月. 日",
|
||||
"TIME_LOCALE_PT_BR": "巴西葡萄牙语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_RU_RU": "俄语:24小时制,日.月.年",
|
||||
"TIME_LOCALE_TR_TR": "土耳其语:24小时制,日.月.年",
|
||||
"TIME_LOCALE_ZH_CN": "简体中文:24小时制,年/月/日",
|
||||
"TITLE": "Localization",
|
||||
"TR": "Türkçe",
|
||||
"UK": "Українська",
|
||||
"ZH": "中文(简体)",
|
||||
"ZH_TW": "中文(繁體)",
|
||||
"TIME_LOCALE": "时间格式区域",
|
||||
"TIME_LOCALE_DESCRIPTION": "注意:这些选项现在无法改变时间输入格式(12/24 小时),因为它由您的操作系统控制",
|
||||
"TIME_LOCALE_AUTO": "系统默认",
|
||||
"TIME_LOCALE_EN_US": "美式英语:12小时制(上午/下午),月/日/年",
|
||||
"TIME_LOCALE_EN_GB": "英式英语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_TR_TR": "土耳其语:24小时制,日.月.年",
|
||||
"TIME_LOCALE_DE_DE": "德语:24小时制,日.月.年",
|
||||
"TIME_LOCALE_FR_FR": "法语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_ES_ES": "西班牙语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_IT_IT": "意大利语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_PT_BR": "巴西葡萄牙语:24小时制,日/月/年",
|
||||
"TIME_LOCALE_RU_RU": "俄语:24小时制,日.月.年",
|
||||
"TIME_LOCALE_ZH_CN": "简体中文:24小时制,年/月/日",
|
||||
"TIME_LOCALE_JA_JP": "日语:24小时制,年/月/日",
|
||||
"TIME_LOCALE_KO_KR": "韩语:12小时制(上午/下午),年. 月. 日"
|
||||
"ZH_TW": "中文(繁體)"
|
||||
},
|
||||
"MISC": {
|
||||
"DARK_MODE": "深色模式",
|
||||
|
|
@ -1905,13 +1997,29 @@
|
|||
"IS_TURN_OFF_MARKDOWN": "关闭任务描述的 Markdown 解析",
|
||||
"IS_USE_CUSTOM_WINDOW_TITLE_BAR": "使用自定义标题栏(仅限Windows/Linux)",
|
||||
"IS_USE_CUSTOM_WINDOW_TITLE_BAR_HINT": "需要重启方可生效",
|
||||
"IS_USE_MINIMAL_SIDE_NAV": "",
|
||||
"START_OF_NEXT_DAY": "下一天的开始时间",
|
||||
"START_OF_NEXT_DAY_HINT": "从何时(小时)开始计算下一天已经开始。默认是午夜,即 0。",
|
||||
"TASK_NOTES_TPL": "任务描述模板",
|
||||
"THEME": "主题",
|
||||
"THEME_EXPERIMENTAL": "主题(实验性)",
|
||||
"THEME_SELECT_LABEL": "选择主题",
|
||||
"TITLE": "更多设置"
|
||||
"TITLE": "更多设置",
|
||||
"USER_PROFILES": "",
|
||||
"USER_PROFILES_HINT": ""
|
||||
},
|
||||
"PAST": {
|
||||
"A_DAY": "",
|
||||
"A_MINUTE": "",
|
||||
"A_MONTH": "",
|
||||
"A_YEAR": "",
|
||||
"AN_HOUR": "",
|
||||
"DAYS": "",
|
||||
"FEW_SECONDS": "",
|
||||
"HOURS": "",
|
||||
"MINUTES": "",
|
||||
"MONTHS": "",
|
||||
"YEARS": ""
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_DURATION": "短休息持续时间",
|
||||
|
|
@ -1921,10 +2029,10 @@
|
|||
},
|
||||
"REMINDER": {
|
||||
"COUNTDOWN_DURATION": "在实际提醒前 X 显示横幅",
|
||||
"IS_COUNTDOWN_BANNER_ENABLED": "提醒到期前显示倒计时横幅",
|
||||
"DEFAULT_TASK_REMIND_OPTION": "创建任务时默认选中的提醒方式",
|
||||
"TITLE": "提醒",
|
||||
"DISABLE_REMINDERS": "禁用所有提醒"
|
||||
"DISABLE_REMINDERS": "禁用所有提醒",
|
||||
"IS_COUNTDOWN_BANNER_ENABLED": "提醒到期前显示倒计时横幅",
|
||||
"TITLE": "提醒"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"HELP": "计划功能应为您快速概览计划任务如何随时间展开。您可以在左侧菜单 <a href='#/schedule'>'计划'</a> 下找到它。",
|
||||
|
|
@ -1984,23 +2092,22 @@
|
|||
"L_TRACKING_REMINDER_MIN_TIME": "在显示跟踪提醒横幅前等待的时间",
|
||||
"TITLE": "时间跟踪"
|
||||
},
|
||||
"APP_FEATURES": {
|
||||
"HELP": "启用或禁用整个界面中的特定应用功能。",
|
||||
"TITLE": "应用功能",
|
||||
"TIME_TRACKING": "秒表时间追踪",
|
||||
"FOCUS_MODE": "专注模式",
|
||||
"SCHEDULE": "日程",
|
||||
"PLANNER": "规划器",
|
||||
"BOARDS": "看板",
|
||||
"SCHEDULE_DAY_PANEL": "日程日面板",
|
||||
"ISSUES_PANEL": "问题面板",
|
||||
"PROJECT_NOTES": "项目笔记",
|
||||
"SYNC_BUTTON": "同步按钮",
|
||||
"DONATE_PAGE": "捐赠页面",
|
||||
"USER_PROFILES": "用户配置文件(实验性)",
|
||||
"USER_PROFILES_HINT": "允许您创建并切换不同的用户配置文件,每个配置文件拥有独立的设置、任务和同步配置。启用后,配置文件管理按钮将出现在右上角。注意:关闭此功能会隐藏界面,但您的配置文件数据将被保留(实验性功能,无法保证稳定性,请务必提前备份)。"
|
||||
"TIMELINE": {
|
||||
"CAL_PROVIDERS": "",
|
||||
"CAL_PROVIDERS_ADD": "",
|
||||
"CAL_PROVIDERS_INFO": "",
|
||||
"HELP": "",
|
||||
"L_CAL_PATH": "",
|
||||
"L_IS_WORK_START_END_ENABLED": "",
|
||||
"L_WORK_END": "",
|
||||
"L_WORK_START": "",
|
||||
"TITLE": "",
|
||||
"WORK_START_END_DESCRIPTION": ""
|
||||
}
|
||||
},
|
||||
"GLOBAL": {
|
||||
"COPY_SUFFIX": " (复制)"
|
||||
},
|
||||
"GLOBAL_RELATIVE_TIME": {
|
||||
"FUTURE": {
|
||||
"A_DAY": "一天内",
|
||||
|
|
@ -2033,23 +2140,20 @@
|
|||
"COPY_TO_CLIPPBOARD": "已复制到剪贴板",
|
||||
"DUPLICATE_PROJECT_ERROR": "该项目无法克隆",
|
||||
"DUPLICATE_PROJECT_SUCCESS": "项目克隆成功",
|
||||
"NO_TASKS_TO_COPY": "没有要复制的任务",
|
||||
"SHARE_UNAVAILABLE_FALLBACK": "已复制到剪贴板。",
|
||||
"SHARE_FAILED_FALLBACK": "共享失败。改为复制到剪贴板。",
|
||||
"SHARE_FAILED": "共享失败。请手动复制。",
|
||||
"ERR_COMPRESSION": "压缩接口错误",
|
||||
"FILE_DOWNLOADED": "{{fileName}} 已下载",
|
||||
"FILE_DOWNLOADED_BTN": "打开文件夹",
|
||||
"NAVIGATE_TO_TASK_ERR": "无法聚焦到任务。您是否删除了它?",
|
||||
"NO_TASKS_TO_COPY": "没有要复制的任务",
|
||||
"NO_TASKS_TO_UNPLAN": "没有任务需要取消",
|
||||
"PERSISTENCE_DISALLOWED": "数据将不会永久保留。请注意,这可能导致数据丢失!!",
|
||||
"PERSISTENCE_ERROR": "请求持久化数据时出错:{{err}}",
|
||||
"RUNNING_X": "正在运行 \"{{str}}\"。",
|
||||
"SHARE_UNAVAILABLE_FALLBACK": "已复制到剪贴板。",
|
||||
"SHARE_FAILED_FALLBACK": "共享失败。改为复制到剪贴板。",
|
||||
"SHARE_FAILED": "共享失败。请手动复制。",
|
||||
"SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG": "按下了 {{keyCombo}},但在项目上下文中才可使用打开书签快捷键。",
|
||||
"UNPLANNED_TODAY_TASKS": "取消今日所有的任务",
|
||||
"NO_TASKS_TO_UNPLAN": "没有任务需要取消"
|
||||
},
|
||||
"GLOBAL": {
|
||||
"COPY_SUFFIX": " (copy)"
|
||||
"UNPLANNED_TODAY_TASKS": "取消今日所有的任务"
|
||||
},
|
||||
"GPB": {
|
||||
"ASSETS": "正在加载资源...",
|
||||
|
|
@ -2091,6 +2195,7 @@
|
|||
"METRICS": "指标",
|
||||
"NO_PROJECT_INFO": "没有可用项目。您可以通过点击 \"创建项目\" 按钮创建新项目。",
|
||||
"NO_TAG_INFO": "当前没有标签。您可以通过在添加或编辑任务时输入 `#yourTagName` 来添加标签。",
|
||||
"NO_TASKS_TO_TRACK": "请先添加任务以开始时间追踪",
|
||||
"NOTES": "备注",
|
||||
"NOTES_PANEL_INFO": "只能从计划和常规任务列表视图中显示备注。",
|
||||
"PLANNER": "规划表",
|
||||
|
|
@ -2129,6 +2234,7 @@
|
|||
"SINGULAR": "已有 {{count}} 个已完成的父任务被归档",
|
||||
"PLURAL": "已有 {{count}} 个已完成的父任务被归档"
|
||||
},
|
||||
"BACK": "",
|
||||
"BREAK_LABEL": "休息(数量/时间)",
|
||||
"CELEBRATE": "花一点时间来 <i>庆祝!</i>",
|
||||
"CLEAR_ALL_CONTINUE": "清除所有已完成并继续",
|
||||
|
|
|
|||
370
tools/cleanup-unused-translations.js
Normal file
370
tools/cleanup-unused-translations.js
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/* eslint-env es6, node */
|
||||
/**
|
||||
* Removes specified unused translation keys from all language files.
|
||||
* After running this, run `npm run int` to regenerate t.const.ts.
|
||||
*
|
||||
* Usage: node tools/cleanup-unused-translations.js
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { globSync } = require('glob');
|
||||
|
||||
const I18N_DIR = path.join(__dirname, '../src/assets/i18n');
|
||||
|
||||
// Top-level sections to completely remove
|
||||
const SECTIONS_TO_REMOVE = ['ANDROID', 'THEMES'];
|
||||
|
||||
// Nested paths to remove (will remove the last key in the path)
|
||||
// Format: array of path segments, e.g., ['F', 'CALDAV', 'ISSUE_CONTENT'] removes F.CALDAV.ISSUE_CONTENT
|
||||
const NESTED_PATHS_TO_REMOVE = [
|
||||
// === Previously removed ===
|
||||
['F', 'CALDAV', 'ISSUE_CONTENT'],
|
||||
['F', 'SAFETY_BACKUP'],
|
||||
['F', 'PROCRASTINATION'],
|
||||
['GCF', 'PAST'],
|
||||
['GCF', 'TIMELINE'],
|
||||
['WW', 'HELP_PROCRASTINATION'],
|
||||
|
||||
// === Entire subsections - never implemented ===
|
||||
['F', 'JIRA', 'STEPPER'], // Setup wizard never implemented
|
||||
['F', 'SYNC', 'D_PERMISSION'], // Permission dialog never implemented
|
||||
['F', 'PROJECT', 'D_CREATE', 'SETUP_CALDAV'],
|
||||
['F', 'PROJECT', 'D_CREATE', 'SETUP_GIT'],
|
||||
['F', 'PROJECT', 'D_CREATE', 'SETUP_GITEA_PROJECT'],
|
||||
['F', 'PROJECT', 'D_CREATE', 'SETUP_GITLAB'],
|
||||
['F', 'PROJECT', 'D_CREATE', 'SETUP_JIRA'],
|
||||
['F', 'PROJECT', 'D_CREATE', 'SETUP_OPEN_PROJECT'],
|
||||
['F', 'PROJECT', 'D_CREATE', 'SETUP_REDMINE_PROJECT'],
|
||||
|
||||
// === F.FOCUS_MODE - planned features never implemented ===
|
||||
['F', 'FOCUS_MODE', 'B', 'END_BREAK'],
|
||||
['F', 'FOCUS_MODE', 'COMPLETE_SESSION'],
|
||||
['F', 'FOCUS_MODE', 'CONGRATS'],
|
||||
['F', 'FOCUS_MODE', 'CONTINUE_FOCUS_SESSION'],
|
||||
['F', 'FOCUS_MODE', 'CONTINUE_SESSION'],
|
||||
['F', 'FOCUS_MODE', 'CURRENT_SESSION_TIME_TOOLTIP'],
|
||||
['F', 'FOCUS_MODE', 'FOR_TASK'],
|
||||
['F', 'FOCUS_MODE', 'GO_TO_PROCRASTINATION'],
|
||||
['F', 'FOCUS_MODE', 'NEXT'],
|
||||
['F', 'FOCUS_MODE', 'SELECT_ANOTHER_TASK'],
|
||||
['F', 'FOCUS_MODE', 'SET_FOCUS_SESSION_DURATION'],
|
||||
['GCF', 'FOCUS_MODE', 'L_ALWAYS_OPEN_FOCUS_MODE'],
|
||||
|
||||
// === F.METRIC - planned features ===
|
||||
['F', 'METRIC', 'BANNER', 'CHECK'],
|
||||
['F', 'METRIC', 'CMP', 'MOOD_PRODUCTIVITY_OVER_TIME'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'ADD_NOTE_FOR_TOMORROW'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'DISABLE_REPEAT_EVERY_DAY'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'ENABLE_REPEAT_EVERY_DAY'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'HELP_H1'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'HELP_LINK_TXT'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'HELP_P1'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'HELP_P2'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'IMPROVEMENTS'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'IMPROVEMENTS_TOMORROW'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'MOOD'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'MOOD_HINT'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'OBSTRUCTIONS'],
|
||||
['F', 'METRIC', 'EVAL_FORM', 'PRODUCTIVITY_HINT'],
|
||||
['F', 'METRIC', 'REFLECTION', 'REMIND_LABEL'],
|
||||
['F', 'METRIC', 'REFLECTION', 'REMINDER_CREATED'],
|
||||
['F', 'METRIC', 'REFLECTION', 'REMINDER_ERROR'],
|
||||
['F', 'METRIC', 'REFLECTION', 'REMINDER_NEEDS_TEXT'],
|
||||
['F', 'METRIC', 'REFLECTION', 'REMINDER_TASK_TITLE'],
|
||||
['F', 'METRIC', 'S', 'SAVE_METRIC'],
|
||||
|
||||
// === F.SYNC - unused error states and dialogs ===
|
||||
['F', 'SYNC', 'A', 'ARCHIVE_ONLY_UPLOADED'],
|
||||
['F', 'SYNC', 'A', 'POSSIBLE_LEGACY_DATA'],
|
||||
['F', 'SYNC', 'C', 'EMPTY_SYNC'],
|
||||
['F', 'SYNC', 'C', 'FORCE_UPLOAD_AFTER_ERROR'],
|
||||
['F', 'SYNC', 'C', 'MIGRATE_LEGACY'],
|
||||
['F', 'SYNC', 'C', 'NO_REMOTE_DATA'],
|
||||
['F', 'SYNC', 'C', 'TRY_LOAD_REMOTE_AGAIN'],
|
||||
['F', 'SYNC', 'C', 'UNABLE_TO_LOAD_REMOTE_DATA'],
|
||||
['F', 'SYNC', 'D_CONFLICT', 'LAMPORT_CLOCK'],
|
||||
['F', 'SYNC', 'D_CONFLICT', 'LAST_CHANGE'],
|
||||
['F', 'SYNC', 'D_INCOMPLETE_SYNC', 'P3'],
|
||||
['F', 'SYNC', 'D_INCOMPLETE_SYNC', 'P4'],
|
||||
['F', 'SYNC', 'D_INCOMPLETE_SYNC', 'P5'],
|
||||
['F', 'SYNC', 'D_INCOMPLETE_SYNC', 'P6'],
|
||||
['F', 'SYNC', 'FORM', 'DROPBOX', 'L_ACCESS_TOKEN'],
|
||||
['F', 'SYNC', 'FORM', 'GOOGLE', 'L_SYNC_FILE_NAME'],
|
||||
['F', 'SYNC', 'FORM', 'LOCAL_FILE', 'L_SYNC_FILE_PATH_PERMISSION_VALIDATION'],
|
||||
['F', 'SYNC', 'S', 'ALREADY_IN_SYNC_NO_LOCAL_CHANGES'],
|
||||
['F', 'SYNC', 'S', 'ERROR_FALLBACK_TO_BACKUP'],
|
||||
['F', 'SYNC', 'S', 'ERROR_INVALID_DATA'],
|
||||
['F', 'SYNC', 'S', 'ERROR_NO_REV'],
|
||||
['F', 'SYNC', 'S', 'ERROR_UNABLE_TO_READ_REMOTE_DATA'],
|
||||
['F', 'SYNC', 'S', 'IMPORTING'],
|
||||
['F', 'SYNC', 'S', 'INITIAL_SYNC_ERROR'],
|
||||
['F', 'SYNC', 'S', 'SUCCESS_IMPORT'],
|
||||
['F', 'SYNC', 'S', 'UPLOAD_ERROR'],
|
||||
['F', 'SYNC', 'SAFETY_BACKUP', 'BACKUP_NOT_FOUND'],
|
||||
['F', 'SYNC', 'SAFETY_BACKUP', 'INVALID_ID_ERROR'],
|
||||
['F', 'SYNC', 'SAFETY_BACKUP', 'RESTORE_CONFIRM_MSG'],
|
||||
['F', 'SYNC', 'SAFETY_BACKUP', 'RESTORE_CONFIRM_TITLE'],
|
||||
['F', 'SYNC', 'SAFETY_BACKUP', 'RESTORE_FAILED'],
|
||||
['F', 'SYNC', 'SAFETY_BACKUP', 'TITLE'],
|
||||
|
||||
// === F.ISSUE - unused keys ===
|
||||
['F', 'ISSUE', 'ISSUE_CONTENT', 'CHANGED'],
|
||||
['F', 'ISSUE', 'ISSUE_CONTENT', 'COMMENTS'],
|
||||
['F', 'ISSUE', 'ISSUE_CONTENT', 'DONE_RATIO'],
|
||||
['F', 'ISSUE', 'ISSUE_CONTENT', 'LIST_OF_CHANGES'],
|
||||
['F', 'ISSUE', 'ISSUE_CONTENT', 'LOAD_DESCRIPTION_AND_ALL_COMMENTS'],
|
||||
['F', 'ISSUE', 'ISSUE_CONTENT', 'ON'],
|
||||
['F', 'ISSUE', 'ISSUE_CONTENT', 'WRITE_A_COMMENT'],
|
||||
['F', 'ISSUE', 'S', 'ISSUE_DELETED_OR_CLOSED'],
|
||||
['F', 'ISSUE', 'S', 'MANUAL_UPDATE_ISSUE_SUCCESS'],
|
||||
['F', 'ISSUE', 'S', 'MISSING_ISSUE_DATA'],
|
||||
['F', 'ISSUE', 'S', 'NEW_COMMENT'],
|
||||
|
||||
// === F.JIRA - unused keys ===
|
||||
['F', 'JIRA', 'DIALOG_TRANSITION', 'UPDATE_STATUS'],
|
||||
['F', 'JIRA', 'FORM_CRED', 'WONKY_COOKIE_MODE'],
|
||||
['F', 'JIRA', 'S', 'ISSUE_NO_UPDATE_REQUIRED'],
|
||||
['F', 'JIRA', 'S', 'MANUAL_UPDATE_ISSUE_SUCCESS'],
|
||||
['F', 'JIRA', 'S', 'MISSING_ISSUE_DATA'],
|
||||
['F', 'JIRA', 'S', 'UNABLE_TO_REASSIGN'],
|
||||
|
||||
// === Issue provider dialogs - never implemented ===
|
||||
['F', 'CALDAV', 'DIALOG_INITIAL', 'TITLE'],
|
||||
['F', 'CALDAV', 'FORM_SECTION', 'TITLE'],
|
||||
['F', 'GITEA', 'DIALOG_INITIAL', 'TITLE'],
|
||||
['F', 'GITEA', 'FORM', 'FILTER_USER'],
|
||||
['F', 'GITEA', 'FORM_SECTION', 'TITLE'],
|
||||
['F', 'GITEA', 'ISSUE_CONTENT', 'AT'],
|
||||
['F', 'GITEA', 'S', 'ERR_UNKNOWN'],
|
||||
['F', 'GITHUB', 'DIALOG_INITIAL', 'TITLE'],
|
||||
['F', 'GITHUB', 'FORM_SECTION', 'TITLE'],
|
||||
['F', 'GITLAB', 'DIALOG_INITIAL', 'TITLE'],
|
||||
['F', 'GITLAB', 'FORM_SECTION', 'TITLE'],
|
||||
['F', 'OPEN_PROJECT', 'DIALOG_INITIAL', 'TITLE'],
|
||||
['F', 'OPEN_PROJECT', 'DIALOG_TRANSITION', 'UPDATE_STATUS'],
|
||||
['F', 'OPEN_PROJECT', 'FORM_SECTION', 'TITLE'],
|
||||
['F', 'REDMINE', 'DIALOG_INITIAL', 'TITLE'],
|
||||
['F', 'REDMINE', 'S', 'ERR_UNKNOWN'],
|
||||
|
||||
// === F.DROPBOX - unused error states ===
|
||||
['F', 'DROPBOX', 'S', 'ACCESS_TOKEN_ERROR'],
|
||||
['F', 'DROPBOX', 'S', 'ACCESS_TOKEN_GENERATED'],
|
||||
['F', 'DROPBOX', 'S', 'AUTH_ERROR'],
|
||||
['F', 'DROPBOX', 'S', 'AUTH_ERROR_ACTION'],
|
||||
|
||||
// === F.TASK - unused keys ===
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'ADD_ISSUE_TASK'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'ADD_TASK_TO_BOTTOM_OF_BACKLOG'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'ADD_TASK_TO_BOTTOM_OF_TODAY'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'ADD_TASK_TO_TOP_OF_BACKLOG'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'ADD_TASK_TO_TOP_OF_TODAY'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'CREATE_TASK'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'EXAMPLE'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'NO_DATE'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'NO_TIME'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'START'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'TOGGLE_ADD_TO_BACKLOG_TODAY'],
|
||||
['F', 'TASK', 'ADD_TASK_BAR', 'TOGGLE_ADD_TOP_OR_BOTTOM'],
|
||||
['F', 'TASK', 'ADDITIONAL_INFO', 'FROM_PARENT'],
|
||||
['F', 'TASK', 'ADDITIONAL_INFO', 'REMINDER'],
|
||||
['F', 'TASK', 'CMP', 'EDIT_TAGS'],
|
||||
['F', 'TASK', 'CMP', 'EDIT_TASK_TITLE'],
|
||||
['F', 'TASK', 'CMP', 'MARK_UNDONE'],
|
||||
['F', 'TASK', 'CMP', 'REPEAT_EDIT'],
|
||||
['F', 'TASK', 'CMP', 'SHOW_UPDATES'],
|
||||
['F', 'TASK', 'D_REMINDER_VIEW', 'FOR_CURRENT'],
|
||||
['F', 'TASK', 'D_REMINDER_VIEW', 'FOR_OTHER'],
|
||||
['F', 'TASK', 'D_REMINDER_VIEW', 'FROM_PROJECT'],
|
||||
['F', 'TASK', 'D_REMINDER_VIEW', 'FROM_TAG'],
|
||||
['F', 'TASK', 'D_REMINDER_VIEW', 'SWITCH_CONTEXT_START'],
|
||||
['F', 'TASK', 'D_SCHEDULE_TASK', 'MOVE_TO_BACKLOG'],
|
||||
['F', 'TASK', 'D_SCHEDULE_TASK', 'QA_REMOVE_TODAY'],
|
||||
['F', 'TASK', 'S', 'CREATED_FOR_PROJECT_ACTION'],
|
||||
['F', 'TASK', 'S', 'LAST_TAG_DELETION_WARNING'],
|
||||
['F', 'TASK', 'S', 'MOVED_TO_PROJECT_ACTION'],
|
||||
|
||||
// === F.TASK_REPEAT - hardcoded strings in code ===
|
||||
['F', 'TASK_REPEAT', 'F', 'IS_ADD_TO_BOTTOM'],
|
||||
['F', 'TASK_REPEAT', 'F', 'REPEAT_FROM_COMPLETION_DATE'],
|
||||
['F', 'TASK_REPEAT', 'F', 'REPEAT_FROM_COMPLETION_DATE_DESCRIPTION'],
|
||||
['F', 'TASK_REPEAT', 'F', 'SCHEDULE_TYPE_FIXED'],
|
||||
['F', 'TASK_REPEAT', 'F', 'SCHEDULE_TYPE_FLEXIBLE'],
|
||||
|
||||
// === Other unused individual keys ===
|
||||
['APP', 'UPDATE_MAIN_MODEL'],
|
||||
['APP', 'UPDATE_MAIN_MODEL_NO_UPDATE'],
|
||||
['BN', 'SHOW_TASK_VIEW_CUSTOMIZER_PANEL'],
|
||||
['DATETIME_SCHEDULE', 'LATER_TODAY'],
|
||||
['DATETIME_SCHEDULE', 'NEXT_WEEK'],
|
||||
['DATETIME_SCHEDULE', 'PLACEHOLDER'],
|
||||
['DATETIME_SCHEDULE', 'TOMORROW'],
|
||||
['F', 'ATTACHMENT', 'DIALOG_EDIT', 'LABELS', 'FILE'],
|
||||
['F', 'BOARDS', 'DEFAULT', 'IMPORTANT'],
|
||||
['F', 'CALENDARS', 'BANNER', 'FOCUS_TASK'],
|
||||
['F', 'NOTE', 'D_ADD', 'NOTE_LABEL'],
|
||||
['F', 'PLANNER', 'D', 'ADD_PLANNED', 'ADD_TO_TODAY'],
|
||||
['F', 'PLANNER', 'D', 'ADD_PLANNED', 'TITLE'],
|
||||
['F', 'PLANNER', 'TASK_DRAWER'],
|
||||
['F', 'PROJECT', 'FORM_THEME', 'D_IS_DARK_THEME'],
|
||||
['F', 'PROJECT', 'FORM_THEME', 'L_IS_REDUCED_THEME'],
|
||||
['F', 'PROJECT', 'FORM_THEME', 'L_TITLE'],
|
||||
['F', 'PROJECT', 'S', 'E_EXISTS'],
|
||||
['F', 'PROJECT', 'S', 'E_INVALID_FILE'],
|
||||
['F', 'PROJECT', 'S', 'ISSUE_PROVIDER_UPDATED'],
|
||||
['F', 'REMINDER', 'COUNTDOWN_BANNER', 'HIDE'],
|
||||
['F', 'SCHEDULE', 'CONTINUED'],
|
||||
['F', 'SCHEDULE', 'LUNCH_BREAK'],
|
||||
['F', 'SCHEDULE', 'MONTH'],
|
||||
['F', 'SCHEDULE', 'NO_TASKS'],
|
||||
['F', 'SCHEDULE', 'NOW'],
|
||||
['F', 'SCHEDULE', 'TASK_PROJECTION_INFO'],
|
||||
['F', 'SCHEDULE', 'WEEK'],
|
||||
['F', 'SEARCH_BAR', 'INFO_ARCHIVED'],
|
||||
['F', 'SEARCH_BAR', 'PLACEHOLDER_ARCHIVED'],
|
||||
['F', 'SEARCH_BAR', 'TOO_MANY_RESULTS'],
|
||||
['F', 'SIMPLE_COUNTER', 'FORM', 'L_ICON_ON'],
|
||||
['F', 'TAG', 'D_CREATE', 'EDIT'],
|
||||
['F', 'TASK_VIEW', 'CUSTOMIZER', 'SORT_BY'],
|
||||
['F', 'TASK_VIEW', 'CUSTOMIZER', 'TITLE'],
|
||||
['F', 'TIME_TRACKING', 'D_TRACKING_REMINDER', 'IDLE_FOR'],
|
||||
['F', 'WORKLOG', 'CMP', 'RESTORE_TASK_FROM_ARCHIVE'],
|
||||
['G', 'DONT_SHOW_AGAIN'],
|
||||
['G', 'LOGIN'],
|
||||
['G', 'LOGOUT'],
|
||||
['G', 'NEXT'],
|
||||
['G', 'PREVIOUS'],
|
||||
['G', 'RESET'],
|
||||
['G', 'UPDATE'],
|
||||
['GCF', 'CALENDARS', 'CAL_PROVIDERS'],
|
||||
['GCF', 'CALENDARS', 'DEFAULT_PROJECT'],
|
||||
['GCF', 'KEYBOARD', 'TASK_PLAN_FORDAY'],
|
||||
['GCF', 'KEYBOARD', 'TOGGLE_BOOKMARKS'],
|
||||
['GCF', 'MISC', 'IS_HIDE_NAV'],
|
||||
['GCF', 'MISC', 'IS_USE_MINIMAL_SIDE_NAV'],
|
||||
['GCF', 'MISC', 'USER_PROFILES'],
|
||||
['GCF', 'MISC', 'USER_PROFILES_HINT'],
|
||||
['GCF', 'SCHEDULE', 'MONTH'],
|
||||
['GCF', 'SCHEDULE', 'WEEK'],
|
||||
['GLOBAL_SNACK', 'ERR_COMPRESSION'],
|
||||
['GLOBAL_SNACK', 'SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG'],
|
||||
['MH', 'NO_PROJECT_INFO'],
|
||||
['MH', 'NO_TAG_INFO'],
|
||||
['MH', 'NOTES'],
|
||||
['MH', 'NOTES_PANEL_INFO'],
|
||||
['MH', 'PROCRASTINATE'],
|
||||
['MH', 'PROJECT_SETTINGS'],
|
||||
['MH', 'SHOW_SEARCH_BAR'],
|
||||
['MH', 'TASK_LIST'],
|
||||
['MH', 'TASKS'],
|
||||
['MH', 'TOGGLE_SHOW_BOOKMARKS'],
|
||||
['PDS', 'BACK'],
|
||||
['PLUGINS', 'DISABLED'],
|
||||
['PLUGINS', 'ENABLED'],
|
||||
['PLUGINS', 'INDEX_HTML_NOT_LOADED'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_ACTION'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_HEADER_BUTTON'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_LOADING'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_MENU_ENTRY'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_NODE'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_PERSISTENCE'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_SHORTCUT'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_SIDE_PANEL'],
|
||||
['PLUGINS', 'NO_PLUGIN_CONTEXT_SYNC'],
|
||||
['PLUGINS', 'NO_PLUGIN_ID_PROVIDED_FOR_HTML'],
|
||||
['PLUGINS', 'PLUGIN_DOES_NOT_SUPPORT_IFRAME'],
|
||||
['PLUGINS', 'PLUGIN_ID_NOT_PROVIDED'],
|
||||
['PLUGINS', 'PLUGIN_NOT_FOUND'],
|
||||
['PLUGINS', 'PLUGIN_SYSTEM_FAILED_INIT'],
|
||||
['PLUGINS', 'USER_DECLINED_NODE_PERMISSION'],
|
||||
['PS', 'ISSUE_INTEGRATION'],
|
||||
['PS', 'RELOAD'],
|
||||
['PS', 'TOGGLE_DARK_MODE'],
|
||||
['SCHEDULE', 'START_TASK'],
|
||||
['USER_PROFILES', 'OPEN_PROFILES_FOLDER'],
|
||||
['V', 'E_1TO10'],
|
||||
['V', 'E_PATTERN'],
|
||||
['WW', 'FINISH_DAY_FOR_PROJECT'],
|
||||
['WW', 'FINISH_DAY_FOR_TAG'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Recursively remove a nested key from an object
|
||||
*/
|
||||
function removeNestedKey(obj, pathParts) {
|
||||
if (pathParts.length === 0) return false;
|
||||
|
||||
if (pathParts.length === 1) {
|
||||
if (obj && pathParts[0] in obj) {
|
||||
delete obj[pathParts[0]];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const [first, ...rest] = pathParts;
|
||||
if (obj && typeof obj[first] === 'object') {
|
||||
return removeNestedKey(obj[first], rest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove specified keys from a JSON object
|
||||
*/
|
||||
function removeKeys(obj) {
|
||||
let removedCount = 0;
|
||||
|
||||
// Remove top-level sections
|
||||
for (const section of SECTIONS_TO_REMOVE) {
|
||||
if (obj[section]) {
|
||||
delete obj[section];
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove nested keys
|
||||
for (const pathParts of NESTED_PATHS_TO_REMOVE) {
|
||||
if (removeNestedKey(obj, pathParts)) {
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return removedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all JSON language files
|
||||
*/
|
||||
function processJsonFiles() {
|
||||
const files = globSync('*.json', { cwd: I18N_DIR, absolute: true });
|
||||
|
||||
console.log(`Processing ${files.length} language files...\n`);
|
||||
|
||||
let totalRemoved = 0;
|
||||
for (const file of files) {
|
||||
const filename = path.basename(file);
|
||||
const content = JSON.parse(fs.readFileSync(file, 'utf8'));
|
||||
const removed = removeKeys(content);
|
||||
|
||||
if (removed > 0) {
|
||||
fs.writeFileSync(file, JSON.stringify(content, null, 2) + '\n', 'utf8');
|
||||
console.log(`${filename}: removed ${removed} key(s)`);
|
||||
totalRemoved += removed;
|
||||
} else {
|
||||
console.log(`${filename}: no changes needed`);
|
||||
}
|
||||
}
|
||||
|
||||
return totalRemoved;
|
||||
}
|
||||
|
||||
// Main
|
||||
console.log('=== Cleaning up unused translations ===\n');
|
||||
console.log(`Configured to remove ${NESTED_PATHS_TO_REMOVE.length} nested paths`);
|
||||
console.log(`and ${SECTIONS_TO_REMOVE.length} top-level sections\n`);
|
||||
|
||||
const total = processJsonFiles();
|
||||
|
||||
console.log(`\n=== Done! Removed ${total} total keys across all files ===`);
|
||||
console.log('\nNow run `npm run int` to regenerate t.const.ts');
|
||||
94
tools/find-unused-translations.js
Normal file
94
tools/find-unused-translations.js
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* eslint-env es6, node */
|
||||
/**
|
||||
* Finds unused translation keys by scanning the codebase.
|
||||
*
|
||||
* Usage: node tools/find-unused-translations.js
|
||||
*
|
||||
* Detects both patterns:
|
||||
* - T.KEY.PATH (preferred, type-safe)
|
||||
* - 'KEY.PATH' or "KEY.PATH" (string literals, legacy)
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { globSync } = require('glob');
|
||||
|
||||
const TRANSLATION_SRC = path.join(__dirname, '../src/assets/i18n/en.json');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
|
||||
/**
|
||||
* Recursively extract all flat keys from nested translation object
|
||||
* e.g., { A: { B: "val" } } -> ["A.B"]
|
||||
*/
|
||||
function extractKeys(obj, prefix = '') {
|
||||
let keys = [];
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const fullKey = prefix ? `${prefix}.${key}` : key;
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
keys = keys.concat(extractKeys(value, fullKey));
|
||||
} else {
|
||||
keys.push(fullKey);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all source file contents into a single string for fast searching
|
||||
*/
|
||||
function loadAllSourceContent() {
|
||||
const files = globSync('**/*.{ts,html}', {
|
||||
cwd: SRC_DIR,
|
||||
ignore: ['**/t.const.ts', '**/node_modules/**'],
|
||||
absolute: true,
|
||||
});
|
||||
|
||||
console.log(`Scanning ${files.length} source files...`);
|
||||
|
||||
return files.map((f) => fs.readFileSync(f, 'utf8')).join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a translation key is used in the codebase
|
||||
* Detects both T.KEY.PATH and 'KEY.PATH' / "KEY.PATH" patterns
|
||||
*/
|
||||
function isKeyUsed(key, content) {
|
||||
// Pattern 1: T.KEY.PATH (preferred)
|
||||
const tPattern = `T.${key}`;
|
||||
if (content.includes(tPattern)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 2: 'KEY.PATH' (string literal with single quotes)
|
||||
const singleQuotePattern = `'${key}'`;
|
||||
if (content.includes(singleQuotePattern)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pattern 3: "KEY.PATH" (string literal with double quotes)
|
||||
const doubleQuotePattern = `"${key}"`;
|
||||
if (content.includes(doubleQuotePattern)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Main
|
||||
const translations = JSON.parse(fs.readFileSync(TRANSLATION_SRC, 'utf8'));
|
||||
const allKeys = extractKeys(translations);
|
||||
const allContent = loadAllSourceContent();
|
||||
|
||||
console.log(`Checking ${allKeys.length} translation keys...\n`);
|
||||
|
||||
const unused = allKeys.filter((key) => !isKeyUsed(key, allContent));
|
||||
|
||||
if (unused.length === 0) {
|
||||
console.log('All translation keys are used!');
|
||||
} else {
|
||||
console.log(`=== Unused translations (${unused.length}) ===\n`);
|
||||
unused.forEach((k) => console.log(k));
|
||||
console.log(`\nTotal: ${unused.length} unused keys out of ${allKeys.length}`);
|
||||
}
|
||||
|
||||
process.exit(unused.length > 0 ? 1 : 0);
|
||||
Loading…
Add table
Add a link
Reference in a new issue