diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index 8be58d4..98f6d77 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -84,9 +84,9 @@ export function Sidebar({ user, collapsed, onToggle }: t.SidebarProps) {
>
-

+
- Admin Panel
+ {localize('com_auth_title')}
diff --git a/src/components/configuration/ConfigRow.tsx b/src/components/configuration/ConfigRow.tsx
index 21b76af..c3a0b16 100644
--- a/src/components/configuration/ConfigRow.tsx
+++ b/src/components/configuration/ConfigRow.tsx
@@ -53,7 +53,9 @@ export function ConfigRow({
) : null;
const pendingResetHint = isPendingReset ? (
- Pending reset
+
+ {localize('com_config_pending_reset')}
+
) : null;
const configuredDot =
diff --git a/src/components/configuration/ImportYamlDialog.tsx b/src/components/configuration/ImportYamlDialog.tsx
index 4f67130..0cdd5ae 100644
--- a/src/components/configuration/ImportYamlDialog.tsx
+++ b/src/components/configuration/ImportYamlDialog.tsx
@@ -410,7 +410,9 @@ export function ImportYamlDialog({
))}
{validationErrors.length > 10 && (
- ...and {validationErrors.length - 10} more
+ {localize('com_config_validation_more', {
+ count: String(validationErrors.length - 10),
+ })}
)}
diff --git a/src/components/configuration/ScopeSelector.tsx b/src/components/configuration/ScopeSelector.tsx
index 89eeb7e..b1bb4ba 100644
--- a/src/components/configuration/ScopeSelector.tsx
+++ b/src/components/configuration/ScopeSelector.tsx
@@ -123,10 +123,10 @@ export function ScopeSelector({
resetState();
} catch (err) {
setCreating(false);
- onError?.(err instanceof Error ? err.message : 'Failed to create scope');
+ onError?.(err instanceof Error ? err.message : localize('com_scope_create_error'));
}
},
- [creating, queryClient, resetState, onError],
+ [creating, queryClient, resetState, onError, localize],
);
const handleCreateForGroup = useCallback(
@@ -146,10 +146,10 @@ export function ScopeSelector({
resetState();
} catch (err) {
setCreating(false);
- onError?.(err instanceof Error ? err.message : 'Failed to create scope');
+ onError?.(err instanceof Error ? err.message : localize('com_scope_create_error'));
}
},
- [creating, queryClient, resetState, onError],
+ [creating, queryClient, resetState, onError, localize],
);
const handleDelete = useCallback(async () => {
@@ -174,9 +174,9 @@ export function ScopeSelector({
setDeleting(false);
} catch (err) {
setDeleting(false);
- onError?.(err instanceof Error ? err.message : 'Failed to delete scope');
+ onError?.(err instanceof Error ? err.message : localize('com_scope_delete_error'));
}
- }, [deleteTarget, deleting, queryClient, currentSelection, onSelect, onError]);
+ }, [deleteTarget, deleting, queryClient, currentSelection, onSelect, onError, localize]);
const roleScopes = useMemo(
() => scopes.filter((s) => s.principalType === PrincipalType.ROLE),
diff --git a/src/components/configuration/fields/ArrayObjectField.tsx b/src/components/configuration/fields/ArrayObjectField.tsx
index 1bc6007..ea8a0e9 100644
--- a/src/components/configuration/fields/ArrayObjectField.tsx
+++ b/src/components/configuration/fields/ArrayObjectField.tsx
@@ -4,14 +4,14 @@ import { ObjectEntryCard } from './ObjectEntryCard';
import { AddItemButton } from '@/components/shared';
import { useLocalize } from '@/hooks';
-function getEntryLabel(item: t.ConfigValue, index: number): string {
+function getEntryLabel(item: t.ConfigValue): string | null {
if (item && typeof item === 'object' && !Array.isArray(item)) {
const obj = item as Record;
if (typeof obj.name === 'string' && obj.name) return obj.name;
if (typeof obj.label === 'string' && obj.label) return obj.label;
if (typeof obj.group === 'string' && obj.group) return obj.group;
}
- return `Entry ${index + 1}`;
+ return null;
}
export function ArrayObjectField({
@@ -107,7 +107,7 @@ export function ArrayObjectField({
handleEntryChange(index, v)}
diff --git a/src/components/configuration/fields/KeyValueField.tsx b/src/components/configuration/fields/KeyValueField.tsx
index a27ea35..965aaea 100644
--- a/src/components/configuration/fields/KeyValueField.tsx
+++ b/src/components/configuration/fields/KeyValueField.tsx
@@ -6,11 +6,11 @@ import { AddItemButton, TrashButton } from '@/components/shared';
import { useLocalize } from '@/hooks';
const DEFAULT_TYPES: t.KVValueType[] = ['string', 'number', 'boolean'];
-const TYPE_LABELS: Record = {
- string: 'abc',
- number: '123',
- boolean: 'T/F',
- json: '{ }',
+const TYPE_LABEL_KEYS: Record = {
+ string: 'com_kv_type_string',
+ number: 'com_kv_type_number',
+ boolean: 'com_kv_type_boolean',
+ json: 'com_kv_type_json',
};
function LocalInput({
@@ -171,8 +171,8 @@ export function KeyValueField({
disabled={disabled}
aria-label={valueLabel}
>
- true
- false
+ {localize('com_ui_true')}
+ {localize('com_ui_false')}
) : (
@@ -195,7 +195,7 @@ export function KeyValueField({
>
{availableTypes.map((vt) => (
- {TYPE_LABELS[vt]}
+ {localize(TYPE_LABEL_KEYS[vt])}
))}
@@ -231,7 +231,7 @@ export function KeyValueField({
>
{availableTypes.map((vt) => (
- {TYPE_LABELS[vt]}
+ {localize(TYPE_LABEL_KEYS[vt])}
))}
diff --git a/src/components/shared/PermissionsUnavailable.tsx b/src/components/shared/PermissionsUnavailable.tsx
index 46df0ff..ee92351 100644
--- a/src/components/shared/PermissionsUnavailable.tsx
+++ b/src/components/shared/PermissionsUnavailable.tsx
@@ -1,18 +1,21 @@
+import { useLocalize } from '@/hooks';
+
export function PermissionsUnavailable() {
+ const localize = useLocalize();
return (
- Could not verify permissions
+ {localize('com_perm_unavailable_title')}
- The permissions service is temporarily unavailable. Please reload the page to try again.
+ {localize('com_perm_unavailable_desc')}
);
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index c58fe46..9719e25 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -1016,5 +1016,16 @@
"com_grants_assign_hint": "Roles and groups can be edited directly from the table above.",
"com_grants_assign_no_users": "No eligible users found",
"com_error_load_groups": "Failed to load groups. Please try again.",
- "com_error_load_members": "Failed to load members. Please try again."
+ "com_error_load_members": "Failed to load members. Please try again.",
+ "com_perm_unavailable_title": "Could not verify permissions",
+ "com_perm_unavailable_desc": "The permissions service is temporarily unavailable. Please reload the page to try again.",
+ "com_ui_reload": "Reload",
+ "com_config_pending_reset": "Pending reset",
+ "com_config_validation_more": "...and {{count}} more",
+ "com_scope_delete_error": "Failed to delete configuration",
+ "com_kv_type_string": "abc",
+ "com_kv_type_number": "123",
+ "com_kv_type_boolean": "T/F",
+ "com_kv_type_json": "{ }",
+ "com_a11y_logo_alt": "LibreChat logo"
}