Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions frontend/scripts/check-i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ async function extractSourceKeys() {
for (const match of matches) {
keys.add(match[1]);
}
const metadataMatches = content.matchAll(
/\b(?:name|description|label|title|subtitle)Key:\s*['"]([a-zA-Z][a-zA-Z0-9_.]+)['"]/g
);
for (const match of metadataMatches) {
keys.add(match[1]);
}
}

return keys;
Expand Down
29 changes: 16 additions & 13 deletions frontend/src/lib/layout/DashboardCustomizationSidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,26 @@
const categories = [
{
id: dashboardWidgetCategories.ACTIVITY,
name: 'Activity',
nameKey: 'dashboard.customization.activity.name',
icon: Clock,
description: 'Briefings, activity streams, and notifications',
descriptionKey: 'dashboard.customization.activity.description',
},
{
id: dashboardWidgetCategories.WORK,
name: 'Work',
nameKey: 'dashboard.customization.work.name',
icon: CheckSquare,
description: 'Items, milestones, and things assigned to you',
descriptionKey: 'dashboard.customization.work.description',
},
{
id: dashboardWidgetCategories.NAVIGATION,
name: 'Navigation',
nameKey: 'dashboard.customization.navigation.name',
icon: Compass,
description: 'Quick access to workspaces',
descriptionKey: 'dashboard.customization.navigation.description',
},
];

let currentWidgets = $derived(getDashboardWidgetsByCategory(activeCategory));
let currentCategory = $derived(categories.find((category) => category.id === activeCategory));

function handleKeydown(event) {
if (event.key === 'Escape' && isOpen) {
Expand Down Expand Up @@ -90,7 +91,8 @@
if (!isActive) e.currentTarget.style.cssText = 'color: var(--ds-text-subtle);';
}}
onclick={() => (activeCategory = category.id)}
title={category.name}
title={t(category.nameKey)}
aria-label={t(category.nameKey)}
>
<CategoryIcon class="w-5 h-5" />
</button>
Expand All @@ -100,8 +102,8 @@
<!-- Right content panel -->
<div class="w-96 flex flex-col" style="background-color: var(--ds-surface-raised);">
<ModalHeader
title={categories.find((c) => c.id === activeCategory)?.name || 'Widgets'}
subtitle={categories.find((c) => c.id === activeCategory)?.description || ''}
title={currentCategory ? t(currentCategory.nameKey) : t('dashboard.customization.widgets')}
subtitle={currentCategory ? t(currentCategory.descriptionKey) : ''}
onClose={() => (isOpen = false)}
/>

Expand Down Expand Up @@ -130,14 +132,14 @@
<IconComponent class="w-5 h-5 text-white" />
</div>
<div class="flex-1 min-w-0">
<h3 class="text-sm font-medium" style="color: var(--ds-text);">{widget.name}</h3>
<DescriptionText>{widget.description}</DescriptionText>
<h3 class="text-sm font-medium" style="color: var(--ds-text);">{t(widget.nameKey)}</h3>
<DescriptionText>{t(widget.descriptionKey)}</DescriptionText>
<div class="flex items-center gap-2 mt-2">
<span
class="text-xs px-2 py-0.5 rounded"
style="background-color: var(--ds-background-neutral); color: var(--ds-text-subtle);"
>
{widget.category}
{t(`dashboard.customization.${widget.category}.name`)}
</span>
<span class="text-xs" style="color: var(--ds-text-subtlest);">
{t('widgets.defaultWidth', {
Expand All @@ -163,7 +165,8 @@
style="background-color: var(--ds-background-neutral); border: 1px solid var(--ds-border);"
>
<p class="text-xs" style="color: var(--ds-text);">
<strong>Tip:</strong> Drag widgets from here into any section on your dashboard.
<strong>{t('dashboard.customization.tipLabel')}:</strong>
{t('dashboard.customization.tip')}
</p>
</div>
</div>
Expand Down
118 changes: 118 additions & 0 deletions frontend/src/lib/locales/ar/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
export default {
dashboard: {
salutation: {
withName: '{salutation}، {name}!',
withoutName: '{salutation}!',
},
sections: {
yourDay: {
title: 'يومك',
subtitle: 'نظرة سريعة على ما يحتاج إلى انتباهك',
},
work: {
title: 'العمل',
subtitle: 'قائمتك الشخصية والعناصر المسندة إليك',
},
workspaces: {
title: 'مساحات العمل',
subtitle: 'تابع من حيث توقفت',
},
},
widgetCatalog: {
dailyBriefing: {
name: 'الموجز اليومي',
description: 'ملخص مولد بالذكاء الاصطناعي لما يهمك اليوم',
},
yourActivity: {
name: 'نشاطك',
description: 'العناصر التي عرضتها أو عدلتها أو علقت عليها مؤخراً',
},
whatsNew: {
name: 'ما الجديد',
description: 'أحدث الإشعارات والتحديثات غير المقروءة',
},
personalTasks: {
name: 'المهام الشخصية',
description: 'عناصر من قائمة مهامك الشخصية',
},
savedSearch: {
name: 'بحث محفوظ',
description: 'عرض عناصر العمل من مجموعة محفوظة',
},
assignedToMe: {
name: 'مسند إليّ',
description: 'العناصر المفتوحة المسندة إليك في جميع مساحات العمل',
},
watchedItems: {
name: 'العناصر المراقبة',
description: 'العناصر التي تتابعها',
},
upcomingMilestones: {
name: 'المعالم القادمة',
description: 'المعالم ذات التواريخ المستهدفة القريبة',
},
recentWorkspaces: {
name: 'مساحات العمل الأخيرة',
description: 'مساحات العمل التي زرتها مؤخراً',
},
quickAccess: {
name: 'الوصول السريع',
description: 'روابط سريعة إلى مساحات العمل المتاحة لك',
},
},
customization: {
widgets: 'الأدوات',
activity: {
name: 'النشاط',
description: 'الموجزات وتدفقات النشاط والإشعارات',
},
work: {
name: 'العمل',
description: 'العناصر والمعالم والمهام المسندة إليك',
},
navigation: {
name: 'التنقل',
description: 'وصول سريع إلى مساحات العمل',
},
tipLabel: 'تلميح',
tip: 'اسحب الأدوات من هنا إلى أي قسم في لوحة المعلومات.',
},
editor: {
newSection: 'قسم جديد',
deleteSectionConfirm: 'هل تريد حذف هذا القسم؟ ستتم إزالة جميع الأدوات الموجودة فيه.',
doneEditing: 'إنهاء التحرير',
customize: 'تخصيص',
editModeDescription: 'وضع التحرير: أضف الأقسام والأدوات أو أعد تسميتها أو ترتيبها أو احذفها',
addSection: 'إضافة قسم',
sectionLabel: 'قسم لوحة المعلومات',
sectionTitlePlaceholder: 'عنوان القسم',
sectionSubtitlePlaceholder: 'العنوان الفرعي (اختياري)',
renameSection: 'إعادة تسمية القسم',
deleteSection: 'حذف القسم',
unknownWidgetType: 'نوع أداة غير معروف: {type}',
noWidgets: 'لا توجد أدوات في هذا القسم بعد',
addWidgetsHint: 'اختر تخصيص لإضافة أدوات',
noSections: 'لم يتم إعداد أي أقسام',
addSectionsHint: 'اختر تحرير لإضافة أقسام إلى لوحة المعلومات',
},
states: {
assignedLoadError: 'تعذر تحميل العناصر المسندة إليك',
assignedEmpty: 'لا يوجد شيء مسند إليك حالياً',
personalTasksLoadError: 'تعذر تحميل مهامك الشخصية',
personalTasksEmpty: 'قائمة مهامك الشخصية فارغة',
dailyBriefingUnavailable: 'موجزك اليومي غير متاح حالياً. يعتمد على تكامل للذكاء الاصطناعي. إذا أعددت تكاملاً للتو، فحاول مرة أخرى بعد قليل.',
updatedAt: 'تم التحديث في {time}',
priorityLabel: 'الأولوية: {priority}',
noWorkspaces: 'لا توجد مساحات عمل بعد',
createWorkspace: 'إنشاء مساحة',
workspaceAvatarAlt: 'الصورة الرمزية لـ {name}',
visited: 'تمت الزيارة {time}',
noUpcomingMilestones: 'لا توجد معالم قادمة',
milestoneProgress: 'تم إنجاز {done} من {total}',
daysOverdue: 'متأخر {days} أيام',
daysLeft: 'متبقي {days} أيام',
watchedItemsEmpty: 'أنت لا تراقب أي عناصر',
workspaceWithId: 'مساحة العمل {id}',
},
},
};
2 changes: 2 additions & 0 deletions frontend/src/lib/locales/ar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import workspace from './workspace.js';
import pages from './pages.js';
import teams from './teams.js';
import supplemental from './supplemental.js';
import dashboard from './dashboard.js';

export default createLocale({
common,
Expand All @@ -40,4 +41,5 @@ export default createLocale({
pages,
teams,
supplemental,
dashboard,
});
118 changes: 118 additions & 0 deletions frontend/src/lib/locales/de/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
export default {
dashboard: {
salutation: {
withName: '{salutation}, {name}!',
withoutName: '{salutation}!',
},
sections: {
yourDay: {
title: 'Ihr Tag',
subtitle: 'Ein schneller Überblick darüber, was Ihre Aufmerksamkeit braucht',
},
work: {
title: 'Arbeit',
subtitle: 'Ihre persönliche Liste und die Ihnen zugewiesenen Einträge',
},
workspaces: {
title: 'Arbeitsbereiche',
subtitle: 'Direkt weitermachen',
},
},
widgetCatalog: {
dailyBriefing: {
name: 'Täglicher Überblick',
description: 'KI-generierte Zusammenfassung dessen, was heute für Sie wichtig ist',
},
yourActivity: {
name: 'Ihre Aktivität',
description: 'Kürzlich angesehene, bearbeitete oder kommentierte Einträge',
},
whatsNew: {
name: 'Neuigkeiten',
description: 'Neueste Benachrichtigungen und ungelesene Aktualisierungen',
},
personalTasks: {
name: 'Persönliche Aufgaben',
description: 'Einträge aus Ihrer persönlichen Aufgabenliste',
},
savedSearch: {
name: 'Gespeicherte Suche',
description: 'Einträge aus einer gespeicherten Sammlung anzeigen',
},
assignedToMe: {
name: 'Mir zugewiesen',
description: 'Ihnen zugewiesene offene Einträge aus allen Arbeitsbereichen',
},
watchedItems: {
name: 'Beobachtete Einträge',
description: 'Einträge, denen Sie folgen',
},
upcomingMilestones: {
name: 'Anstehende Meilensteine',
description: 'Meilensteine mit nahendem Zieldatum',
},
recentWorkspaces: {
name: 'Letzte Arbeitsbereiche',
description: 'Kürzlich besuchte Arbeitsbereiche',
},
quickAccess: {
name: 'Schnellzugriff',
description: 'Direkte Verknüpfungen zu erreichbaren Arbeitsbereichen',
},
},
customization: {
widgets: 'Widgets',
activity: {
name: 'Aktivität',
description: 'Überblicke, Aktivitätsverläufe und Benachrichtigungen',
},
work: {
name: 'Arbeit',
description: 'Einträge, Meilensteine und Ihnen zugewiesene Aufgaben',
},
navigation: {
name: 'Navigation',
description: 'Schnellzugriff auf Arbeitsbereiche',
},
tipLabel: 'Tipp',
tip: 'Ziehen Sie Widgets von hier in einen beliebigen Bereich Ihres Dashboards.',
},
editor: {
newSection: 'Neuer Bereich',
deleteSectionConfirm: 'Diesen Bereich löschen? Alle darin enthaltenen Widgets werden entfernt.',
doneEditing: 'Bearbeitung beenden',
customize: 'Anpassen',
editModeDescription: 'Bearbeitungsmodus: Bereiche und Widgets hinzufügen, umbenennen, neu anordnen oder löschen',
addSection: 'Bereich hinzufügen',
sectionLabel: 'Dashboard-Bereich',
sectionTitlePlaceholder: 'Bereichstitel',
sectionSubtitlePlaceholder: 'Untertitel (optional)',
renameSection: 'Bereich umbenennen',
deleteSection: 'Bereich löschen',
unknownWidgetType: 'Unbekannter Widget-Typ: {type}',
noWidgets: 'Dieser Bereich enthält noch keine Widgets',
addWidgetsHint: 'Wählen Sie Anpassen, um Widgets hinzuzufügen',
noSections: 'Keine Bereiche konfiguriert',
addSectionsHint: 'Wählen Sie Bearbeiten, um Bereiche zum Dashboard hinzuzufügen',
},
states: {
assignedLoadError: 'Die Ihnen zugewiesenen Einträge konnten nicht geladen werden',
assignedEmpty: 'Ihnen ist derzeit nichts zugewiesen',
personalTasksLoadError: 'Ihre persönlichen Aufgaben konnten nicht geladen werden',
personalTasksEmpty: 'Ihre persönliche Aufgabenliste ist leer',
dailyBriefingUnavailable: 'Ihr täglicher Überblick ist derzeit nicht verfügbar. Er benötigt eine KI-Integration. Falls Sie gerade eine eingerichtet haben, versuchen Sie es in Kürze erneut.',
updatedAt: 'Aktualisiert: {time}',
priorityLabel: 'Priorität: {priority}',
noWorkspaces: 'Noch keine Arbeitsbereiche',
createWorkspace: 'Arbeitsbereich erstellen',
workspaceAvatarAlt: 'Avatar von {name}',
visited: 'besucht {time}',
noUpcomingMilestones: 'Keine anstehenden Meilensteine',
milestoneProgress: '{done} von {total} erledigt',
daysOverdue: '{days} Tage überfällig',
daysLeft: 'Noch {days} Tage',
watchedItemsEmpty: 'Sie beobachten derzeit keine Einträge',
workspaceWithId: 'Arbeitsbereich {id}',
},
},
};
2 changes: 2 additions & 0 deletions frontend/src/lib/locales/de/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import pages from './pages.js';
import supplemental from './supplemental.js';
import quality from './quality.js';
import review from './review.js';
import dashboard from './dashboard.js';

export default createLocale({
admin,
Expand All @@ -44,4 +45,5 @@ export default createLocale({
supplemental,
quality,
review,
dashboard,
});
Loading
Loading