- {group.label}
+ {t(group.labelKey)}
{filtered.map((s) => (
@@ -121,6 +135,7 @@ type SettingsContentProps = {
};
export const SettingsContent = ({ sections }: SettingsContentProps) => {
+ const { t } = useTranslation();
// The sidebar and this pane are two sibling panels that used to agree via a shared `useGlobal` key.
// They agree via the URL now, so neither has to be told about the other — and neither can be the one
// that seeds the slot, which is what made the old defaulting order matter (see §5.6).
@@ -130,7 +145,7 @@ export const SettingsContent = ({ sections }: SettingsContentProps) => {
if (!section) {
return (
-
Select a section
+
{t('settings.selectSection')}
);
}
@@ -139,9 +154,9 @@ export const SettingsContent = ({ sections }: SettingsContentProps) => {
-
{section.title}
+ {t(section.titleKey)}
-
{section.description}
+
{t(section.descriptionKey)}
{section.content}
);
@@ -166,7 +181,7 @@ export const SettingsRoute = ({ basePath, sections, children }: SettingsRoutePro
type CreateSettingsPanelParams = {
basePath: string;
sidebarIcon: LucideIcon;
- sidebarLabel: string;
+ sidebarLabelKey: AppTranslationKey;
sections?: SettingsSection[];
groups?: SettingsSectionGroup[];
};
@@ -174,7 +189,7 @@ type CreateSettingsPanelParams = {
export const createSettingsPanelComponents = ({
basePath,
sidebarIcon,
- sidebarLabel,
+ sidebarLabelKey,
sections = [],
groups,
}: CreateSettingsPanelParams) => {
@@ -183,7 +198,7 @@ export const createSettingsPanelComponents = ({
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx
index c8ae423c..d6a249b4 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx
@@ -12,44 +12,56 @@ import { OCRSection } from './ServerSettings/OCRSection';
const groups: SettingsSectionGroup[] = [
{
- label: 'AI',
+ labelKey: 'settings.groups.ai',
icon: Bot,
sections: [
{
key: 'tts',
icon: Volume2,
- title: 'Text to Speech',
- description: 'TTS provider and voice',
+ titleKey: 'settings.sections.tts.label',
+ descriptionKey: 'settings.sections.tts.description',
content:
,
},
- { key: 'stt', icon: Mic, title: 'Speech to Text', description: 'Whisper server URL', content:
},
+ {
+ key: 'stt',
+ icon: Mic,
+ titleKey: 'settings.sections.stt.label',
+ descriptionKey: 'settings.sections.stt.description',
+ content:
,
+ },
{
key: 'ocr',
icon: ScanText,
- title: 'OCR',
- description: 'Vision model for text extraction',
+ titleKey: 'settings.sections.ocr.label',
+ descriptionKey: 'settings.sections.ocr.description',
content:
,
},
],
},
{
- label: 'Maintenance',
+ labelKey: 'settings.groups.maintenance',
icon: Hammer,
sections: [
{
key: 'maintenance',
icon: Hammer,
- title: 'Rebuild & restart',
- description: 'Load changes without a terminal',
+ titleKey: 'settings.sections.maintenance.label',
+ descriptionKey: 'settings.sections.maintenance.description',
content:
,
},
],
},
{
- label: 'Email',
+ labelKey: 'settings.groups.email',
icon: Mail,
sections: [
- { key: 'smtp', icon: Mail, title: 'SMTP', description: 'Email delivery provider', content:
},
+ {
+ key: 'smtp',
+ icon: Mail,
+ titleKey: 'settings.sections.smtp.label',
+ descriptionKey: 'settings.sections.smtp.description',
+ content:
,
+ },
],
},
];
@@ -59,7 +71,7 @@ const BASE_PATH = '/settings/system';
const { Sidebar, Content, allSections } = createSettingsPanelComponents({
basePath: BASE_PATH,
sidebarIcon: Settings,
- sidebarLabel: 'System',
+ sidebarLabelKey: 'settings.nav.system',
groups,
});
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/UserManagement/index.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/UserManagement/index.tsx
index cfce829e..1ffc0ff2 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/UserManagement/index.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/UserManagement/index.tsx
@@ -15,15 +15,15 @@ const sections: SettingsSection[] = [
{
key: 'users',
icon: Users,
- title: 'Accounts',
- description: 'Who has access, and as what',
+ titleKey: 'settings.sections.accounts.label',
+ descriptionKey: 'settings.sections.accounts.description',
content:
,
},
{
key: 'permissions',
icon: ShieldCheck,
- title: 'Permissions',
- description: 'What each role can reach',
+ titleKey: 'settings.sections.permissions.label',
+ descriptionKey: 'settings.sections.permissions.description',
content:
,
},
];
@@ -33,7 +33,7 @@ const BASE_PATH = '/settings/user-management';
const { Sidebar, Content } = createSettingsPanelComponents({
basePath: BASE_PATH,
sidebarIcon: UserCog,
- sidebarLabel: 'Users',
+ sidebarLabelKey: 'settings.nav.users',
sections,
});
diff --git a/src/apps/officer-web/locales/en-GB.json b/src/apps/officer-web/locales/en-GB.json
index 7c58000a..45a4aa5a 100644
--- a/src/apps/officer-web/locales/en-GB.json
+++ b/src/apps/officer-web/locales/en-GB.json
@@ -50,74 +50,129 @@
"sections": {
"profile": {
"label": "Profile",
- "hint": "avatar, name, email"
+ "hint": "avatar, name, email",
+ "description": "Avatar, name, and email"
},
"changePassword": {
- "label": "Change password"
+ "label": "Change password",
+ "description": "Update your password"
},
"apiKeys": {
"label": "API keys",
- "hint": "keys that sign in as you"
+ "hint": "keys that sign in as you",
+ "description": "Keys that sign in as you, revocable one at a time"
},
"languages": {
"label": "Languages",
- "hint": "spoken and translation"
+ "hint": "spoken and translation",
+ "description": "Spoken, default, and translation"
},
"voice": {
"label": "Voice",
- "hint": "text-to-speech"
+ "hint": "text-to-speech",
+ "description": "Text-to-speech voice preference"
},
"dock": {
"label": "Dock",
- "hint": "choose and reorder"
+ "hint": "choose and reorder",
+ "description": "Choose and reorder dock items"
},
"myModels": {
- "label": "My Models"
+ "label": "My Models",
+ "description": "Show or hide models for yourself"
},
"channelModels": {
- "label": "Channel Models"
+ "label": "Channel Models",
+ "description": "Models reachable by non-owner accounts"
},
"defaultModels": {
- "label": "Default Models"
+ "label": "Default Models",
+ "description": "Default models for chat, projects, and tasks"
},
"providers": {
"label": "Providers",
- "hint": "harnesses"
+ "hint": "harnesses",
+ "description": "Remote and local AI providers"
},
"tts": {
- "label": "Text to Speech"
+ "label": "Text to Speech",
+ "description": "TTS provider and voice"
},
"stt": {
- "label": "Speech to Text"
+ "label": "Speech to Text",
+ "description": "Whisper server URL"
},
"ocr": {
- "label": "OCR"
+ "label": "OCR",
+ "description": "Vision model for text extraction"
},
"maintenance": {
"label": "Rebuild & restart",
- "hint": "maintenance"
+ "hint": "maintenance",
+ "description": "Load changes without a terminal"
},
"smtp": {
"label": "SMTP",
- "hint": "outgoing mail"
+ "hint": "outgoing mail",
+ "description": "Email delivery provider"
},
"googleOauth": {
- "label": "Google OAuth"
+ "label": "Google OAuth",
+ "description": "Client ID and secret for Google APIs"
},
"apify": {
- "label": "Apify"
+ "label": "Apify",
+ "description": "API token for web scraping actors"
},
"davSync": {
"label": "Calendar & Contacts sync",
- "hint": "app passwords"
+ "hint": "app passwords",
+ "description": "Per-device passwords for CalDAV/CardDAV clients"
},
"accounts": {
"label": "Accounts",
- "hint": "users"
+ "hint": "users",
+ "description": "Who has access, and as what"
},
"permissions": {
- "label": "Permissions"
+ "label": "Permissions",
+ "description": "What each role can reach"
}
+ },
+ "searchPlaceholder": "Search settings…",
+ "selectSection": "Select a section",
+ "groups": {
+ "models": "Models",
+ "defaults": "Defaults",
+ "providers": "Providers",
+ "ai": "AI",
+ "maintenance": "Maintenance",
+ "email": "Email"
+ },
+ "nav": {
+ "profile": "Profile",
+ "ai": "AI",
+ "system": "System",
+ "integrations": "Integrations",
+ "users": "Users"
+ },
+ "ai": {
+ "noModels": "No models available. Configure API keys in Providers.",
+ "dragToShow": "Drag models here to show",
+ "allVisible": "All models visible",
+ "dragToEnable": "Drag models here to enable",
+ "allEnabled": "All models enabled",
+ "visible": "Visible",
+ "hidden": "Hidden",
+ "enabled": "Enabled",
+ "disabled": "Disabled",
+ "refresh": "Refresh models from providers",
+ "refreshed": "Models refreshed",
+ "refreshFailed": "Failed to refresh models"
+ },
+ "integrations": {
+ "enterprise": "Enterprise",
+ "personal": "Personal"
}
},
"header": {
diff --git a/src/apps/officer-web/locales/pt-PT.json b/src/apps/officer-web/locales/pt-PT.json
index 8f4b1153..9b926e35 100644
--- a/src/apps/officer-web/locales/pt-PT.json
+++ b/src/apps/officer-web/locales/pt-PT.json
@@ -50,74 +50,129 @@
"sections": {
"profile": {
"label": "Perfil",
- "hint": "avatar, nome, email"
+ "hint": "avatar, nome, email",
+ "description": "Avatar, nome e email"
},
"changePassword": {
- "label": "Alterar palavra-passe"
+ "label": "Alterar palavra-passe",
+ "description": "Atualize a sua palavra-passe"
},
"apiKeys": {
"label": "Chaves de API",
- "hint": "chaves que iniciam sessão como você"
+ "hint": "chaves que iniciam sessão como você",
+ "description": "Chaves que iniciam sessão como você, revogáveis uma a uma"
},
"languages": {
"label": "Idiomas",
- "hint": "falados e tradução"
+ "hint": "falados e tradução",
+ "description": "Falados, predefinido e tradução"
},
"voice": {
"label": "Voz",
- "hint": "conversão de texto em fala"
+ "hint": "conversão de texto em fala",
+ "description": "Preferência de voz para conversão de texto em fala"
},
"dock": {
"label": "Dock",
- "hint": "escolher e reordenar"
+ "hint": "escolher e reordenar",
+ "description": "Escolher e reordenar os itens do dock"
},
"myModels": {
- "label": "Os meus modelos"
+ "label": "Os meus modelos",
+ "description": "Mostrar ou ocultar modelos para si"
},
"channelModels": {
- "label": "Modelos do canal"
+ "label": "Modelos do canal",
+ "description": "Modelos acessíveis a contas que não são do proprietário"
},
"defaultModels": {
- "label": "Modelos predefinidos"
+ "label": "Modelos predefinidos",
+ "description": "Modelos predefinidos para chat, projetos e tarefas"
},
"providers": {
"label": "Fornecedores",
- "hint": "harnesses"
+ "hint": "harnesses",
+ "description": "Fornecedores de IA remotos e locais"
},
"tts": {
- "label": "Texto para fala"
+ "label": "Texto para fala",
+ "description": "Fornecedor de TTS e voz"
},
"stt": {
- "label": "Fala para texto"
+ "label": "Fala para texto",
+ "description": "URL do servidor Whisper"
},
"ocr": {
- "label": "OCR"
+ "label": "OCR",
+ "description": "Modelo de visão para extração de texto"
},
"maintenance": {
"label": "Reconstruir e reiniciar",
- "hint": "manutenção"
+ "hint": "manutenção",
+ "description": "Carregar alterações sem um terminal"
},
"smtp": {
"label": "SMTP",
- "hint": "correio a enviar"
+ "hint": "correio a enviar",
+ "description": "Fornecedor de entrega de email"
},
"googleOauth": {
- "label": "Google OAuth"
+ "label": "Google OAuth",
+ "description": "Client ID e secret para as APIs Google"
},
"apify": {
- "label": "Apify"
+ "label": "Apify",
+ "description": "Token de API para atores de web scraping"
},
"davSync": {
"label": "Sincronização de Calendário e Contactos",
- "hint": "palavras-passe de aplicação"
+ "hint": "palavras-passe de aplicação",
+ "description": "Palavras-passe por dispositivo para clientes CalDAV/CardDAV"
},
"accounts": {
"label": "Contas",
- "hint": "utilizadores"
+ "hint": "utilizadores",
+ "description": "Quem tem acesso, e como"
},
"permissions": {
- "label": "Permissões"
+ "label": "Permissões",
+ "description": "O que cada função pode alcançar"
}
+ },
+ "searchPlaceholder": "Pesquisar definições…",
+ "selectSection": "Selecione uma secção",
+ "groups": {
+ "models": "Modelos",
+ "defaults": "Predefinições",
+ "providers": "Fornecedores",
+ "ai": "IA",
+ "maintenance": "Manutenção",
+ "email": "Email"
+ },
+ "nav": {
+ "profile": "Perfil",
+ "ai": "IA",
+ "system": "Sistema",
+ "integrations": "Integrações",
+ "users": "Utilizadores"
+ },
+ "ai": {
+ "noModels": "Nenhum modelo disponível. Configure as chaves de API em Fornecedores.",
+ "dragToShow": "Arraste modelos para aqui para os mostrar",
+ "allVisible": "Todos os modelos visíveis",
+ "dragToEnable": "Arraste modelos para aqui para os ativar",
+ "allEnabled": "Todos os modelos ativados",
+ "visible": "Visíveis",
+ "hidden": "Ocultos",
+ "enabled": "Ativados",
+ "disabled": "Desativados",
+ "refresh": "Atualizar modelos a partir dos fornecedores",
+ "refreshed": "Modelos atualizados",
+ "refreshFailed": "Falha ao atualizar modelos"
+ },
+ "integrations": {
+ "enterprise": "Empresa",
+ "personal": "Pessoal"
}
},
"header": {