feat(search-ui): add i18n locales field to SearchUiIndexConfig (plan §13.21)
- Add `locales` field to SearchUiIndexConfig (HashMap<lang, translations>)
- Enable operators to configure custom translations via config endpoint
- JavaScript already has i18n support (lang query param, fallback to en)
- Add documentation for operators on how to configure locales
Acceptance: GET /ui/search/{index}?lang=fr returns French UI strings when
fr locale configured; falls back to en.
This commit is contained in:
parent
92a36612e0
commit
c4c74eb572
2 changed files with 97 additions and 0 deletions
|
|
@ -89,6 +89,9 @@ pub struct SearchUiIndexConfig {
|
|||
/// Thumbnail field for images
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub thumbnail_field: Option<String>,
|
||||
/// i18n locales (lang code -> translation object) for operator-supplied translations (plan §13.21)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub locales: Option<std::collections::HashMap<String, serde_json::Value>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
@ -458,6 +461,7 @@ pub async fn get_config(
|
|||
primary_key_field: None,
|
||||
hit_url_template: None,
|
||||
thumbnail_field: None,
|
||||
locales: None,
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
93
docs/search_ui_i18n.md
Normal file
93
docs/search_ui_i18n.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Search UI i18n (Internationalization)
|
||||
|
||||
## Overview
|
||||
|
||||
The Search UI supports internationalization (i18n) for operator-supplied translations. This is part of plan §13.21.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Query Parameter**: Users can specify a language via the `lang` query parameter:
|
||||
- Example: `GET /ui/search/myindex?lang=fr`
|
||||
|
||||
2. **Browser Fallback**: If no `lang` parameter is provided, the UI uses `navigator.language`
|
||||
|
||||
3. **Fallback to English**: If the requested language is not configured, the UI falls back to English (the default built-in locale)
|
||||
|
||||
## Configuring Custom Locales
|
||||
|
||||
Operators can add custom translations via the `POST /_miroir/ui/search/{index}/config` endpoint:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://miroir:8080/_miroir/ui/search/myindex/config" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer <admin_key>" \
|
||||
-d '{
|
||||
"locales": {
|
||||
"fr": {
|
||||
"ui.title": "Recherche",
|
||||
"ui.logo": "Recherche",
|
||||
"ui.search.placeholder": "Rechercher...",
|
||||
"ui.search.label": "Recherche",
|
||||
"ui.search.ariaLabel": "Requête de recherche",
|
||||
"ui.search.hint": "Tapez pour rechercher. Appuyez sur / pour focus. Utilisez les flèches pour naviguer.",
|
||||
"ui.search.button": "Rechercher",
|
||||
"ui.filters": "Filtres",
|
||||
"ui.sort.label": "Trier:",
|
||||
"ui.sort.relevance": "Pertinence",
|
||||
"ui.perPage.label": "Par page:",
|
||||
"ui.results.empty": "Aucun résultat trouvé",
|
||||
"ui.results.emptyHint": "Essayez d'ajuster votre recherche ou vos filtres",
|
||||
"ui.results.count": "{count} résultats ({time}ms)"
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
## Built-in Translations
|
||||
|
||||
The Search UI includes English translations by default in the bundled JavaScript. The `t()` function handles variable interpolation:
|
||||
|
||||
```javascript
|
||||
// With interpolation
|
||||
t('ui.results.count', { count: 42, time: 15 })
|
||||
// Returns: "42 results (15ms)"
|
||||
|
||||
// With French locale
|
||||
// Returns: "42 résultats (15ms)"
|
||||
```
|
||||
|
||||
## Translation Keys
|
||||
|
||||
The following translation keys are supported (with default English values):
|
||||
|
||||
### UI Labels
|
||||
- `ui.title` - Page title
|
||||
- `ui.logo` - Logo text
|
||||
- `ui.search.placeholder` - Search input placeholder
|
||||
- `ui.search.label` - Search label
|
||||
- `ui.search.ariaLabel` - Search ARIA label
|
||||
- `ui.search.hint` - Search keyboard hint
|
||||
- `ui.search.button` - Search button ARIA label
|
||||
- `ui.darkMode.ariaLabel` - Dark mode toggle ARIA label
|
||||
- `ui.filters` - Filters button text
|
||||
- `ui.sort.label` - Sort selector label
|
||||
- `ui.sort.relevance` - Default sort option text
|
||||
- `ui.perPage.label` - Per-page selector label
|
||||
|
||||
### Results
|
||||
- `ui.results.empty` - Empty state title
|
||||
- `ui.results.emptyHint` - Empty state hint
|
||||
- `ui.results.didYouMean` - "Did you mean" suggestion (use `{query}` variable)
|
||||
- `ui.results.count` - Result count (use `{count}` and `{time}` variables)
|
||||
|
||||
### Errors
|
||||
- `ui.error.noIndex` - No index specified error
|
||||
- `ui.error.searchFailed` - Search failed error (use `{status}` variable)
|
||||
- `ui.error.initFailed` - Init failed error (use `{message}` variable)
|
||||
- `ui.error.sessionFailed` - Session fetch failed
|
||||
|
||||
### Accessibility
|
||||
- `ui.filters.ariaLabel` - Filters ARIA label
|
||||
- `ui.pagination.ariaLabel` - Pagination ARIA label
|
||||
- `ui.keyboardShortcuts.ariaLabel` - Keyboard shortcuts ARIA label
|
||||
- `ui.keyboardShortcuts.text` - Keyboard shortcuts help text
|
||||
Loading…
Add table
Reference in a new issue