Update Hebrew RTL and translation patches
- translate-he.js: Add tab button translations (Sub-Goals, Projects, Issues etc. with counts), fix whitespace normalization for matching, add translateButtonLabels() for React tab buttons - rtl-override.css: Properties panel RTL fixes (row-reverse, text-align), timeline reverse order (newest first + comment box at top), truncation and panel width adjustments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -739,3 +739,325 @@ html[dir="rtl"] [class*="arrow-left"] svg,
|
||||
html[dir="rtl"] [class*="arrow-right"] svg {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
COMMENT HEADER — agent name + date row RTL alignment
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] .flex.items-center.justify-between.mb-1 {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [href*="/agents/"] {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
ACTIVITY LOG — RTL alignment
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] [id^="activity-"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id^="activity-"] .flex-1 {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id^="activity-"] .flex.items-start.gap-2\.5 {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
TABLES inside comments — RTL alignment
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] .paperclip-markdown table {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .paperclip-markdown table th,
|
||||
html[dir="rtl"] .paperclip-markdown table td {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .paperclip-markdown {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
GLOBAL RTL — all flex rows with gap should be RTL
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] [id^="run-"],
|
||||
html[dir="rtl"] [id^="activity-"],
|
||||
html[dir="rtl"] [id^="comment-"] {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id^="run-"] .flex,
|
||||
html[dir="rtl"] [id^="activity-"] .flex,
|
||||
html[dir="rtl"] [id^="comment-"] .flex {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id^="run-"] .flex.items-center {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id^="run-"] .flex.items-center.gap-2\.5 {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .min-w-0.flex-1 {
|
||||
text-align: right;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* Inner flex rows inside run/activity items — text flows RTL */
|
||||
html[dir="rtl"] .min-w-0.flex-1 > .flex {
|
||||
direction: rtl;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
/* The outer row: avatar on right, content on left */
|
||||
html[dir="rtl"] .flex.items-center.gap-2\.5.py-1\.5 {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* Same for items-start variant (activity log) */
|
||||
html[dir="rtl"] .flex.items-start.gap-2\.5.py-1\.5 {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
ACTIVITY TAB — global RTL for all activity content
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] [id*="-content-activity"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id*="-content-activity"] .flex {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id*="-content-activity"] .flex.items-center,
|
||||
html[dir="rtl"] [id*="-content-activity"] .flex.items-start {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [id*="-content-activity"] .min-w-0 {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
PROPERTIES PANEL — global RTL
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] [data-slot="sheet-content"],
|
||||
html[dir="rtl"] [role="dialog"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="sheet-content"] .flex,
|
||||
html[dir="rtl"] [role="dialog"] .flex {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="sheet-content"] label,
|
||||
html[dir="rtl"] [role="dialog"] label {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
GLOBAL CATCH-ALL — any remaining LTR flex containers in main content
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] main {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] main .flex.items-center {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] main .flex.items-start {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] main .min-w-0 {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] main .space-y-1\.5,
|
||||
html[dir="rtl"] main .space-y-2,
|
||||
html[dir="rtl"] main .space-y-3,
|
||||
html[dir="rtl"] main .space-y-4 {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
PROPERTIES SIDEBAR — the p-4 container with property rows
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] .p-4 .space-y-4,
|
||||
html[dir="rtl"] .p-4 .space-y-1 {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Property row: label (w-20) on right, value on left */
|
||||
html[dir="rtl"] .p-4 .flex.items-center.gap-3.py-1\.5 {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* The label span */
|
||||
html[dir="rtl"] .p-4 .shrink-0.w-20 {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
BREADCRUMB — RTL direction + flip chevron separator
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] [data-slot="breadcrumb"] {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="breadcrumb-list"] {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="breadcrumb-separator"] svg {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
/* Top header bar */
|
||||
html[dir="rtl"] .border-b.border-border .flex.items-center {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FILTER BAR — the "For [assignee] in [project]" row
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] .overflow-x-auto .inline-flex.items-center.gap-2 {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
PLUGIN PAGE + CARDS — RTL for all card content
|
||||
-------------------------------------------------------------------------- */
|
||||
html[dir="rtl"] [data-slot="tabs"][dir="ltr"] {
|
||||
direction: rtl !important;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="card"],
|
||||
html[dir="rtl"] [data-slot="card-header"],
|
||||
html[dir="rtl"] [data-slot="card-content"],
|
||||
html[dir="rtl"] [data-slot="card-title"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="card-content"] .flex.justify-between {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="card-content"] .flex.items-center.justify-between {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="card-content"] .grid {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] [data-slot="card-description"] {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Status change row: reverse order so old→new reads RTL */
|
||||
html[dir="rtl"] .flex.flex-wrap.items-center.gap-2.text-sm {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* Flip the arrow in status change rows */
|
||||
html[dir="rtl"] .flex.flex-wrap.items-center.gap-2.text-sm .lucide-arrow-right {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
PROPERTIES PANEL (aside) - RTL fixes
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/* Fix truncation direction: show start of text, not end */
|
||||
html[dir="rtl"] aside .truncate {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Widen properties panel to fill the gap */
|
||||
html[dir="rtl"] aside.hidden.md\:flex {
|
||||
width: 460px !important;
|
||||
}
|
||||
html[dir="rtl"] aside .w-80 {
|
||||
width: 460px;
|
||||
min-width: 460px;
|
||||
}
|
||||
|
||||
/* Ensure property labels don't shrink too much */
|
||||
html[dir="rtl"] aside .shrink-0.w-20 {
|
||||
width: 5.5rem;
|
||||
}
|
||||
|
||||
/* Properties panel rows: reverse flex so label is on the right */
|
||||
html[dir="rtl"] aside .flex.items-center.gap-3.py-1\.5 {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
/* Property value containers: align right */
|
||||
html[dir="rtl"] aside .flex.items-center.gap-1\.5.min-w-0.flex-1 {
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
/* Property buttons inside panel: reverse icon+text order */
|
||||
html[dir="rtl"] aside .flex.items-center.gap-1\.5.min-w-0.flex-1 button {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
/* Panel header */
|
||||
html[dir="rtl"] aside .flex.items-center.justify-between {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
/* Panel text alignment */
|
||||
html[dir="rtl"] aside .text-sm {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
html[dir="rtl"] aside .text-xs.text-muted-foreground.shrink-0 {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
TIMELINE + COMMENT BOX - comment box at top, newest first
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/* The tab content container that holds timeline + comment box: reverse order */
|
||||
html[dir="rtl"] [role="tabpanel"][id*="content-comments"] > .space-y-4 {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
/* Also target the parent of timeline + comment box */
|
||||
html[dir="rtl"] main .space-y-6 > .space-y-4:last-child {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Reverse timeline items so newest appears first */
|
||||
html[dir="rtl"] main .space-y-4 > .space-y-4 {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@@ -99,6 +99,301 @@
|
||||
"Configure": "הגדר",
|
||||
"Choose": "בחר",
|
||||
|
||||
// --- Activity Log ---
|
||||
"updated this task": "עדכן משימה זו",
|
||||
"created this task": "יצר משימה זו",
|
||||
"created this issue": "יצר משימה זו",
|
||||
"updated this issue": "עדכן משימה זו",
|
||||
"commented on this task": "הגיב על משימה זו",
|
||||
"commented on this issue": "הגיב על משימה זו",
|
||||
"assigned this task": "הקצה משימה זו",
|
||||
"assigned this issue": "הקצה משימה זו",
|
||||
"changed status": "שינה סטטוס",
|
||||
"changed priority": "שינה עדיפות",
|
||||
"unassigned this task": "ביטל הקצאת משימה",
|
||||
"checked out this task": "לקח משימה",
|
||||
"released this task": "שחרר משימה",
|
||||
"just now": "הרגע",
|
||||
"1m ago": "לפני דקה",
|
||||
"2m ago": "לפני 2 דקות",
|
||||
"3m ago": "לפני 3 דקות",
|
||||
"5m ago": "לפני 5 דקות",
|
||||
"10m ago": "לפני 10 דקות",
|
||||
"15m ago": "לפני 15 דקות",
|
||||
"20m ago": "לפני 20 דקות",
|
||||
"25m ago": "לפני 25 דקות",
|
||||
"28m ago": "לפני 28 דקות",
|
||||
"30m ago": "לפני 30 דקות",
|
||||
"45m ago": "לפני 45 דקות",
|
||||
"1h ago": "לפני שעה",
|
||||
"2h ago": "לפני שעתיים",
|
||||
"3h ago": "לפני 3 שעות",
|
||||
"yesterday": "אתמול",
|
||||
"You": "אני",
|
||||
"Copy as markdown": "העתק כ-markdown",
|
||||
|
||||
// --- Run Statuses ---
|
||||
"succeeded": "הצליח",
|
||||
"failed": "נכשל",
|
||||
"running": "רץ",
|
||||
"timed_out": "חרג מזמן",
|
||||
"queued": "בתור",
|
||||
"skipped": "דולג",
|
||||
"blocked": "חסום",
|
||||
"completed": "הושלם",
|
||||
"cancelled": "בוטל",
|
||||
"started": "התחיל",
|
||||
|
||||
// --- Activity Log Actions ---
|
||||
"started a run": "התחיל ריצה",
|
||||
"completed a run": "השלים ריצה",
|
||||
"checked out": "לקח לטיפול",
|
||||
"released": "שחרר",
|
||||
"moved to": "עבר ל",
|
||||
"changed status to": "שינה סטטוס ל",
|
||||
"assigned to": "הוקצה ל",
|
||||
"unassigned from": "בוטלה הקצאה מ",
|
||||
"added a comment": "הוסיף תגובה",
|
||||
"ran": "הריץ",
|
||||
"set priority": "קבע עדיפות",
|
||||
"set status": "קבע סטטוס",
|
||||
|
||||
// --- Run Details ---
|
||||
"Transcript": "תמליל",
|
||||
"No transcript captured": "לא נקלט תמליל",
|
||||
"No transcript captured.": "לא נקלט תמליל.",
|
||||
"Run details": "פרטי ריצה",
|
||||
"Duration": "משך",
|
||||
"Tokens": "טוקנים",
|
||||
"Cost": "עלות",
|
||||
"Model": "מודל",
|
||||
"Turns": "סיבובים",
|
||||
"Exit code": "קוד יציאה",
|
||||
"Error": "שגיאה",
|
||||
"Heartbeat": "פעימה",
|
||||
"Heartbeats": "פעימות",
|
||||
"Latest run": "ריצה אחרונה",
|
||||
"All runs": "כל הריצות",
|
||||
"No runs yet": "אין ריצות עדיין",
|
||||
"No runs yet.": "אין ריצות עדיין.",
|
||||
"Run": "ריצה",
|
||||
"Runs": "ריצות",
|
||||
"Input tokens": "טוקני קלט",
|
||||
"Output tokens": "טוקני פלט",
|
||||
"Cache read": "קריאה ממטמון",
|
||||
"Cache write": "כתיבה למטמון",
|
||||
"Total cost": "עלות כוללת",
|
||||
"Session": "סשן",
|
||||
"Agent": "סוכן",
|
||||
"Source": "מקור",
|
||||
"Trigger": "טריגר",
|
||||
"on_demand": "לפי דרישה",
|
||||
"manual": "ידני",
|
||||
"timer": "טיימר",
|
||||
"assignment": "הקצאה",
|
||||
"automation": "אוטומציה",
|
||||
|
||||
// --- Filter/Context ---
|
||||
"For": "עבור",
|
||||
"for": "עבור",
|
||||
"in": "ב",
|
||||
"In": "ב",
|
||||
"of": "של",
|
||||
"to": "ל",
|
||||
"by": "על ידי",
|
||||
"from": "מ",
|
||||
"with": "עם",
|
||||
"and": "ו",
|
||||
"or": "או",
|
||||
"on": "ב",
|
||||
"at": "ב",
|
||||
"as": "בתור",
|
||||
"via": "דרך",
|
||||
"No results": "אין תוצאות",
|
||||
"No results.": "אין תוצאות.",
|
||||
"No items": "אין פריטים",
|
||||
"No data": "אין נתונים",
|
||||
|
||||
// --- Settings Page ---
|
||||
"General Settings": "הגדרות כלליות",
|
||||
"Server Configuration": "הגדרות שרת",
|
||||
"Deployment Mode": "מצב פריסה",
|
||||
"Exposure": "חשיפה",
|
||||
"Allowed Hostnames": "שמות מארח מורשים",
|
||||
"Public Base URL": "כתובת URL ציבורית",
|
||||
"Disable Sign Up": "ביטול הרשמה",
|
||||
"Disable sign up": "ביטול הרשמה",
|
||||
"Backup Settings": "הגדרות גיבוי",
|
||||
"Backup Interval": "מרווח גיבוי",
|
||||
"Retention Days": "ימי שמירה",
|
||||
"Database Mode": "מצב מסד נתונים",
|
||||
"Embedded PostgreSQL": "PostgreSQL מובנה",
|
||||
"Storage Provider": "ספק אחסון",
|
||||
"Local Disk": "דיסק מקומי",
|
||||
"Secret Provider": "ספק סודות",
|
||||
"Logging Mode": "מצב לוגים",
|
||||
"Log Directory": "תיקיית לוגים",
|
||||
"Save Changes": "שמור שינויים",
|
||||
"Configuration saved": "ההגדרות נשמרו",
|
||||
"Configuration saved.": "ההגדרות נשמרו.",
|
||||
"Restart required": "נדרש הפעלה מחדש",
|
||||
"Instance": "מופע",
|
||||
"Server": "שרת",
|
||||
"Auth": "אימות",
|
||||
"Authentication": "אימות",
|
||||
"Sign-up": "הרשמה",
|
||||
"Allowed": "מורשה",
|
||||
"Port": "פורט",
|
||||
"Host": "מארח",
|
||||
"public": "ציבורי",
|
||||
"private": "פרטי",
|
||||
"authenticated": "מאומת",
|
||||
"enabled": "מופעל",
|
||||
"disabled": "מושבת",
|
||||
"Database": "מסד נתונים",
|
||||
"Backups": "גיבויים",
|
||||
"Storage": "אחסון",
|
||||
"Secrets": "סודות",
|
||||
"Logging": "לוגים",
|
||||
"Server port": "פורט שרת",
|
||||
"Listen host": "מארח האזנה",
|
||||
"Base URL": "כתובת בסיס",
|
||||
"Interval (minutes)": "מרווח (דקות)",
|
||||
"Retention (days)": "שמירה (ימים)",
|
||||
"Data directory": "תיקיית נתונים",
|
||||
"Backup directory": "תיקיית גיבוי",
|
||||
"Key file path": "נתיב קובץ מפתח",
|
||||
"Mode": "מצב",
|
||||
"Provider": "ספק",
|
||||
"Path": "נתיב",
|
||||
"Danger Zone": "אזור סכנה",
|
||||
|
||||
// --- Experimental Page ---
|
||||
"Opt into features that are still being evaluated before they become default behavior.": "הצטרף לפיצ׳רים שעדיין בהערכה לפני שהם הופכים לברירת מחדל.",
|
||||
"Enable Isolated Workspaces": "הפעל סביבות עבודה מבודדות",
|
||||
"Show execution workspace controls in project configuration and allow isolated workspace behavior for new and existing issue runs.": "הצג אפשרויות סביבת עבודה בהגדרות פרויקט ואפשר התנהגות מבודדת לריצות חדשות וקיימות.",
|
||||
"Auto-Restart Dev Server When Idle": "הפעלה מחדש אוטומטית של שרת פיתוח בזמן חוסר פעילות",
|
||||
"In `pnpm dev:once`, wait for all queued and running local agent runs to finish, then restart the server automatically when backend changes or migrations make the current boot stale.": "ב-pnpm dev:once, המתן לסיום כל ריצות הסוכנים בתור וברצף, ואז הפעל מחדש אוטומטית כששינויים בשרת הופכים את האתחול הנוכחי למיושן.",
|
||||
|
||||
// --- Plugin Status Page ---
|
||||
"Runtime Dashboard": "לוח בקרה תפעולי",
|
||||
"Worker process, scheduled jobs, and webhook deliveries": "תהליך עובד, משימות מתוזמנות ומשלוחי webhook",
|
||||
"Worker Process": "תהליך עובד",
|
||||
"Pending RPCs": "קריאות ממתינות",
|
||||
"Uptime": "זמן פעילות",
|
||||
"Recent Job Runs": "ריצות אחרונות",
|
||||
"Recent Webhook Deliveries": "משלוחי webhook אחרונים",
|
||||
"No webhook deliveries recorded yet.": "טרם נרשמו משלוחי webhook.",
|
||||
"Last checked": "בדיקה אחרונה",
|
||||
"Health Status": "מצב בריאות",
|
||||
"Overall": "כולל",
|
||||
"ready": "מוכן",
|
||||
"error": "שגיאה",
|
||||
"registry": "רישום",
|
||||
"manifest": "מניפסט",
|
||||
"error_state": "מצב שגיאה",
|
||||
"Permissions": "הרשאות",
|
||||
"Details": "פרטים",
|
||||
"Plugin ID": "מזהה תוסף",
|
||||
"Plugin Key": "מפתח תוסף",
|
||||
"NPM Package": "חבילת NPM",
|
||||
"Version": "גרסה",
|
||||
"Configuration": "הגדרות",
|
||||
"Status": "סטטוס",
|
||||
|
||||
// --- Action Buttons ---
|
||||
"Disable All": "השבת הכל",
|
||||
"Enable All": "הפעל הכל",
|
||||
"Disable all": "השבת הכל",
|
||||
"Enable all": "הפעל הכל",
|
||||
"Select All": "בחר הכל",
|
||||
"Select all": "בחר הכל",
|
||||
"Deselect All": "בטל בחירה",
|
||||
"Deselect all": "בטל בחירה",
|
||||
"Clear All": "נקה הכל",
|
||||
"Clear all": "נקה הכל",
|
||||
"Remove All": "הסר הכל",
|
||||
"Remove all": "הסר הכל",
|
||||
"Delete All": "מחק הכל",
|
||||
"Delete all": "מחק הכל",
|
||||
"Refresh": "רענן",
|
||||
"Reload": "טען מחדש",
|
||||
"Load More": "טען עוד",
|
||||
"Load more": "טען עוד",
|
||||
"Show More": "הצג עוד",
|
||||
"Show more": "הצג עוד",
|
||||
"Show Less": "הצג פחות",
|
||||
"Show less": "הצג פחות",
|
||||
"View All": "הצג הכל",
|
||||
"View all": "הצג הכל",
|
||||
"Expand All": "הרחב הכל",
|
||||
"Expand all": "הרחב הכל",
|
||||
"Collapse All": "צמצם הכל",
|
||||
"Collapse all": "צמצם הכל",
|
||||
"Copy ID": "העתק מזהה",
|
||||
"Copy URL": "העתק כתובת",
|
||||
"Go to": "עבור אל",
|
||||
"Jump to": "קפוץ אל",
|
||||
"Mark all": "סמן הכל",
|
||||
"Danger zone": "אזור סכנה",
|
||||
"Reset": "איפוס",
|
||||
"Reset instance": "איפוס מופע",
|
||||
"This action cannot be undone.": "לא ניתן לבטל פעולה זו.",
|
||||
"Are you sure?": "האם אתה בטוח?",
|
||||
|
||||
// --- Settings: General Tab ---
|
||||
"Configure instance-wide defaults that affect how operator-visible logs are displayed.": "הגדר ברירות מחדל ברמת המופע שמשפיעות על אופן הצגת הלוגים.",
|
||||
"Censor username in logs": "הסתר שם משתמש בלוגים",
|
||||
"Hide the username segment in home-directory paths and similar operator-visible log output. Standalone username mentions outside of paths are not yet masked in the live transcript view. This is off by default.": "הסתר את שם המשתמש בנתיבי תיקיות ובפלט לוגים. אזכורי שם משתמש עצמאיים מחוץ לנתיבים עדיין אינם מוסתרים בתצוגת התמליל החי. מושבת כברירת מחדל.",
|
||||
|
||||
// --- Settings: Keyboard Shortcuts ---
|
||||
"Keyboard Shortcuts": "קיצורי מקלדת",
|
||||
"Enable app keyboard shortcuts, including inbox navigation and global shortcuts like creating issues or toggling panels. This is off by default.": "הפעל קיצורי מקלדת באפליקציה, כולל ניווט בתיבת הדואר וקיצורים גלובליים כמו יצירת משימות או מעבר בין פנלים. מושבת כברירת מחדל.",
|
||||
|
||||
// --- Settings: AI Feedback ---
|
||||
"AI Feedback Sharing": "שיתוף משוב AI",
|
||||
"Control whether thumbs up and thumbs down votes can send the voted AI output to Paperclip Labs. Votes are always saved locally.": "קבע אם הצבעות אגודל למעלה ולמטה ישלחו את פלט ה-AI ל-Paperclip Labs. ההצבעות תמיד נשמרות מקומית.",
|
||||
"Read our Terms of Service": "קרא את תנאי השירות שלנו",
|
||||
"No default is saved yet. The next thumbs up or thumbs down choice will ask once and then save the answer here.": "טרם נשמרה בחירת ברירת מחדל. ההצבעה הבאה תשאל פעם אחת ותשמור את התשובה כאן.",
|
||||
"Always allow": "אפשר תמיד",
|
||||
"Always Allow": "אפשר תמיד",
|
||||
"Share voted AI outputs automatically.": "שתף פלטי AI שנבחרו אוטומטית.",
|
||||
"Never allow": "אל תאפשר",
|
||||
"Never Allow": "אל תאפשר",
|
||||
"Keep voted AI outputs local only.": "שמור פלטי AI שנבחרו מקומית בלבד.",
|
||||
"To retest the first-use prompt in local dev, remove the feedbackDataSharingPreference key from the instance_settings.general JSON row for this instance, or set it back to \"prompt\". Unset and \"prompt\" both mean no default has been chosen yet.": "לבדיקה מחדש של ההנחיה הראשונית, הסר את המפתח feedbackDataSharingPreference מטבלת instance_settings או החזר ל-prompt.",
|
||||
|
||||
// --- Tabs & Sections ---
|
||||
"Sub-issues": "תת-משימות",
|
||||
"Subissues": "תת-משימות",
|
||||
"sub-issues": "תת-משימות",
|
||||
"Work Products": "תוצרי עבודה",
|
||||
"Linked": "מקושר",
|
||||
"Related": "קשור",
|
||||
"Parent": "משימת אב",
|
||||
"Timeline": "ציר זמן",
|
||||
"History": "היסטוריה",
|
||||
"Approvals": "אישורים",
|
||||
|
||||
// --- Comments Section ---
|
||||
"No comments yet": "אין תגובות עדיין",
|
||||
"No comments yet.": "אין תגובות עדיין.",
|
||||
"Add a comment": "הוסף תגובה",
|
||||
"Write a comment": "כתוב תגובה",
|
||||
"Write a comment...": "כתוב תגובה...",
|
||||
"Type a comment": "הקלד תגובה",
|
||||
"Type a comment...": "הקלד תגובה...",
|
||||
|
||||
// --- Activity Section ---
|
||||
"No activity yet": "אין פעילות עדיין",
|
||||
"No activity yet.": "אין פעילות עדיין.",
|
||||
|
||||
// --- Sub-issues Section ---
|
||||
"No sub-issues": "אין תת-משימות",
|
||||
"No sub-issues.": "אין תת-משימות.",
|
||||
"Create sub-issue": "צור תת-משימה",
|
||||
"Add sub-issue": "הוסף תת-משימה",
|
||||
|
||||
// --- Action Buttons ---
|
||||
"Save changes": "שמור שינויים",
|
||||
"Save Configuration": "שמור הגדרות",
|
||||
@@ -503,6 +798,8 @@
|
||||
"No recent agent runs.": "אין הרצות סוכנים אחרונות.",
|
||||
"No recent issues.": "אין משימות אחרונות.",
|
||||
"No sub-goals.": "אין תת-יעדים.",
|
||||
"Sub-Goals": "תת-יעדים",
|
||||
"Sub Goal": "תת-יעד",
|
||||
"No sub-issues.": "אין תת-משימות.",
|
||||
"None": "ללא",
|
||||
"Unassigned": "לא מוקצה",
|
||||
@@ -739,14 +1036,65 @@
|
||||
* Translate a text string if a translation exists.
|
||||
* Uses exact match first, then case-insensitive.
|
||||
*/
|
||||
// Regex patterns for dynamic time strings
|
||||
const TIME_PATTERNS = [
|
||||
[/^(\d+)m ago$/, (m) => `לפני ${m[1]} דקות`],
|
||||
[/^(\d+)h ago$/, (m) => `לפני ${m[1]} שעות`],
|
||||
[/^(\d+)d ago$/, (m) => `לפני ${m[1]} ימים`],
|
||||
[/^(\d+)s ago$/, (m) => `לפני ${m[1]} שניות`],
|
||||
[/^(\d+) minutes? ago$/, (m) => `לפני ${m[1]} דקות`],
|
||||
[/^(\d+) hours? ago$/, (m) => `לפני ${m[1]} שעות`],
|
||||
[/^(\d+) days? ago$/, (m) => `לפני ${m[1]} ימים`],
|
||||
[/^just now$/, () => "הרגע"],
|
||||
[/^yesterday$/, () => "אתמול"],
|
||||
// Tabs with counts
|
||||
[/^Sub-Goals\s*\((\d+)\)$/, (m) => `תת-יעדים (${m[1]})`],
|
||||
[/^Projects\s*\((\d+)\)$/, (m) => `פרויקטים (${m[1]})`],
|
||||
[/^Issues\s*\((\d+)\)$/, (m) => `משימות (${m[1]})`],
|
||||
[/^Agents\s*\((\d+)\)$/, (m) => `סוכנים (${m[1]})`],
|
||||
[/^Members\s*\((\d+)\)$/, (m) => `חברים (${m[1]})`],
|
||||
[/^Comments\s*\((\d+)\)$/, (m) => `תגובות (${m[1]})`],
|
||||
[/^Documents\s*\((\d+)\)$/, (m) => `מסמכים (${m[1]})`],
|
||||
[/^Routines\s*\((\d+)\)$/, (m) => `שגרות (${m[1]})`],
|
||||
[/^Skills\s*\((\d+)\)$/, (m) => `כישורים (${m[1]})`],
|
||||
[/^Labels\s*\((\d+)\)$/, (m) => `תוויות (${m[1]})`],
|
||||
];
|
||||
|
||||
// Regex patterns for date strings
|
||||
const DATE_MONTHS = {
|
||||
"Jan": "ינו׳", "Feb": "פבר׳", "Mar": "מרץ", "Apr": "אפר׳",
|
||||
"May": "מאי", "Jun": "יוני", "Jul": "יולי", "Aug": "אוג׳",
|
||||
"Sep": "ספט׳", "Oct": "אוק׳", "Nov": "נוב׳", "Dec": "דצמ׳"
|
||||
};
|
||||
|
||||
function translate(text) {
|
||||
const trimmed = text.trim();
|
||||
const trimmed = text.trim().replace(/\s+/g, ' ');
|
||||
if (!trimmed) return null;
|
||||
// Exact match
|
||||
if (T[trimmed] !== undefined) return T[trimmed];
|
||||
// Case-insensitive match
|
||||
const lk = trimmed.toLowerCase();
|
||||
if (lowerMap[lk]) return T[lowerMap[lk]];
|
||||
// Regex time patterns
|
||||
for (const [pattern, replacer] of TIME_PATTERNS) {
|
||||
const match = trimmed.match(pattern);
|
||||
if (match) return replacer(match);
|
||||
}
|
||||
// Date format with time: "Apr 7, 2026, 6:02 PM" → "7 אפר׳ 2026, 18:02"
|
||||
const dateTimeMatch = trimmed.match(/^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d+),\s+(\d{4}),\s+(\d+):(\d+)\s+(AM|PM)$/);
|
||||
if (dateTimeMatch) {
|
||||
const [, mon, day, year, hr, min, ampm] = dateTimeMatch;
|
||||
let hour = parseInt(hr);
|
||||
if (ampm === "PM" && hour !== 12) hour += 12;
|
||||
if (ampm === "AM" && hour === 12) hour = 0;
|
||||
return `${day} ${DATE_MONTHS[mon] || mon} ${year}, ${hour.toString().padStart(2,"0")}:${min}`;
|
||||
}
|
||||
// Date format without time: "Apr 7, 2026" → "7 אפר׳ 2026"
|
||||
const dateMatch = trimmed.match(/^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d+),\s+(\d{4})$/);
|
||||
if (dateMatch) {
|
||||
const [, mon, day, year] = dateMatch;
|
||||
return `${day} ${DATE_MONTHS[mon] || mon} ${year}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -786,10 +1134,16 @@
|
||||
const original = node.nodeValue;
|
||||
const translated = translate(original);
|
||||
if (translated !== null && translated !== original) {
|
||||
// Add space when text follows a number in a sibling span (e.g. "0" + "active" → "0 פעיל")
|
||||
const prev = node.previousSibling;
|
||||
if (prev && prev.nodeType === 1 && /^\d+$/.test(prev.textContent.trim())) {
|
||||
node.nodeValue = " " + translated;
|
||||
} else {
|
||||
node.nodeValue = translated;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate placeholder and aria-label attributes.
|
||||
@@ -820,9 +1174,25 @@
|
||||
/**
|
||||
* Full translation pass on the entire document.
|
||||
*/
|
||||
/**
|
||||
* Translate tab buttons and other elements whose textContent contains
|
||||
* dynamic patterns like "Sub-Goals (0)" that text node walking misses.
|
||||
*/
|
||||
function translateButtonLabels(root) {
|
||||
const buttons = root.querySelectorAll('button[role="tab"], button[data-slot="tabs-trigger"]');
|
||||
buttons.forEach(function(btn) {
|
||||
const text = btn.textContent.trim().replace(/\s+/g, ' ');
|
||||
const t = translate(text);
|
||||
if (t && t !== text) {
|
||||
btn.textContent = t;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function translateAll() {
|
||||
translateTextNodes(document.body);
|
||||
translateAttributes(document.body);
|
||||
translateButtonLabels(document.body);
|
||||
// Translate page title
|
||||
if (document.title) {
|
||||
const t = translate(document.title);
|
||||
@@ -909,10 +1279,58 @@
|
||||
setTimeout(translateAll, 4000);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// COMMENT ORDER — newest first
|
||||
// =========================================================================
|
||||
function reverseComments() {
|
||||
// Find comment containers by anchor IDs
|
||||
const commentAnchors = document.querySelectorAll('[id^="comment-"]');
|
||||
if (!commentAnchors.length) return;
|
||||
|
||||
// Group by parent container
|
||||
const parents = new Set();
|
||||
commentAnchors.forEach(el => {
|
||||
const parent = el.parentElement;
|
||||
if (parent && !parent.dataset.reversed && parent.children.length > 1) {
|
||||
parents.add(parent);
|
||||
}
|
||||
});
|
||||
|
||||
parents.forEach(parent => {
|
||||
const children = Array.from(parent.children);
|
||||
children.reverse().forEach(child => parent.appendChild(child));
|
||||
parent.dataset.reversed = "true";
|
||||
});
|
||||
}
|
||||
|
||||
// Re-run on route changes (SPA)
|
||||
let lastUrl = location.href;
|
||||
const urlObserver = new MutationObserver(() => {
|
||||
if (location.href !== lastUrl) {
|
||||
lastUrl = location.href;
|
||||
// Reset reversed flags on navigation
|
||||
document.querySelectorAll('[data-reversed]').forEach(el => {
|
||||
delete el.dataset.reversed;
|
||||
});
|
||||
setTimeout(reverseComments, 500);
|
||||
}
|
||||
});
|
||||
|
||||
function initCommentOrder() {
|
||||
urlObserver.observe(document.body, { childList: true, subtree: true });
|
||||
// Also run after each mutation to catch late-loading comments
|
||||
const commentMutObs = new MutationObserver(() => {
|
||||
setTimeout(reverseComments, 200);
|
||||
});
|
||||
commentMutObs.observe(document.body, { childList: true, subtree: true });
|
||||
setTimeout(reverseComments, 1000);
|
||||
}
|
||||
|
||||
// Start when DOM is ready
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
document.addEventListener("DOMContentLoaded", () => { init(); initCommentOrder(); });
|
||||
} else {
|
||||
init();
|
||||
initCommentOrder();
|
||||
}
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user