feat(i18n): multi-language infrastructure for Hydrodactyl - #41
Conversation
This is a port of the completed i18n work from pyrodactyl-oss/pyrodactyl#90, adapted for the Hydrodactyl codebase. Phase 1 establishes the foundation. Backend: - Install i18next + react-i18next for frontend translation engine - Add lib/i18n.ts with i18next config, fetchSupportedLanguages(), fetchNamespace(), and loadTranslations() using /locales/locale.json - Add lib/localeMap.ts for automatic date-fns and cronstrue locale loading via dynamic imports (any new language works immediately) - Update LanguageMiddleware with nullsafe operator and admin-route bypass (admin always uses system default language) - Update LocaleController with AvailableLanguages trait and languages() method exposing available languages via JSON - Add GET /locales/languages.json route scanning lang/ directories so the frontend dropdown stays in sync with disk folders - Import pyrodactyl's complete Spanish (es/) translation folder Frontend: - Update App.tsx with I18nextProvider wrapper, i18n-ready loading state (spinner while translations load), and locale initialization Phase 2 (next PRs): language dropdown, API endpoint, component translations, Blade + PHP backend translations, daemon layer. Reference: pyrodactyl-oss/pyrodactyl#90
There was a problem hiding this comment.
Pull request overview
This PR introduces an i18n foundation for Hydrodactyl by exposing backend locale data over JSON and wiring a frontend i18next + react-i18next setup that can load translation namespaces and supported languages dynamically. It also ports a full Spanish (es) translation set into resources/lang.
Changes:
- Add public locale endpoints for fetching namespace JSON (
/locales/locale.json) and discovering supported languages (/locales/languages.json). - Add frontend i18next initialization plus runtime loading of translation namespaces and (optionally) date-fns/cronstrue locales.
- Add Spanish (
es) Laravel translation files across multiple namespaces, plus new JS dependencies/lock updates.
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| routes/base.php | Adds unauthenticated /locales/languages.json route alongside existing locale JSON endpoint. |
| app/Http/Middleware/LanguageMiddleware.php | Adjusts locale selection logic (admin uses system locale; null-safe user language). |
| app/Http/Controllers/Base/LocaleController.php | Adds languages() endpoint and hardens locale namespace loading with try/catch + placeholder conversion change. |
| resources/scripts/lib/i18n.ts | Adds i18next initialization + functions to fetch supported languages and load namespaces from backend. |
| resources/scripts/lib/localeMap.ts | Adds dynamic locale loading helpers for date-fns and cronstrue. |
| resources/scripts/components/App.tsx | Wraps app in I18nextProvider and adds i18n loading gate/spinner. |
| resources/lang/es/strings.php | Spanish translations for common UI strings. |
| resources/lang/es/auth.php | Spanish translations for authentication + emails. |
| resources/lang/es/dashboard.php | Spanish translations for dashboard/account UI. |
| resources/lang/es/server.php | Spanish translations for server management UI. |
| resources/lang/es/activity.php | Spanish translations for activity log event text. |
| resources/lang/es/exceptions.php | Spanish translations for exception/error messages. |
| resources/lang/es/validation.php | Spanish translations for Laravel validation messages/attributes. |
| resources/lang/es/passwords.php | Spanish translations for password reset messages. |
| resources/lang/es/pagination.php | Spanish translations for pagination labels. |
| resources/lang/es/command/messages.php | Spanish translations for Artisan command output/help. |
| resources/lang/es/admin/general.php | Spanish translations for admin panel general strings. |
| resources/lang/es/admin/node.php | Spanish translations for admin node management. |
| resources/lang/es/admin/server.php | Spanish translations for admin server management. |
| resources/lang/es/admin/nests.php | Spanish translations for admin nests/eggs management. |
| resources/lang/es/admin/user.php | Spanish translations for admin user management. |
| package.json | Adds i18next and react-i18next dependencies. |
| pnpm-lock.yaml | Locks new dependency graph for i18next/react-i18next. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 'two_factor' => [ | ||
| 'checkpoint_failed' => 'El punto de control de autenticación de dos factores falló. Inténtalo de nuevo.', | ||
| ], |
| 'database' => [ | ||
| 'duplicate_name' => 'Ya existe una base de datos con ese nombre para este servidor.', | ||
| ], |
| 'get_help' => 'Obtener ayuda', | ||
| 'via_discord' => '(vía Discord)', | ||
| 'documentation' => 'Documentación', | ||
| 'github' => 'Github', |
| useEffect(() => { | ||
| const userLang = HydrodactylUser?.language || SiteConfiguration?.locale || 'en'; | ||
| fetchSupportedLanguages().then(() => { | ||
| loadTranslations(userLang).then(() => { | ||
| i18n.changeLanguage(userLang); | ||
| loadLocaleForLanguage(userLang); | ||
| setI18nReady(true); | ||
| }); | ||
| }); | ||
| }, []); |
| 'api' => [ | ||
| 'no_permission' => 'Esta cuenta no tiene permiso para acceder a la API.', | ||
| 'ip_not_allowed' => 'La dirección IP (:ip) no tiene permiso para acceder a la API con estas credenciales.', | ||
| 'wrong_key_type' => 'Estás intentando usar una clave de API de aplicación en un endpoint que requiere una clave de API de cliente.', | ||
| 'resource_not_found' => 'El recurso solicitado no fue encontrado para este servidor.', | ||
| 'acl_resource_required' => 'Se debe definir un recurso ACL en las solicitudes de API.', | ||
| ], |
|
Finished or continued work by now? @Jaie55 |
|
@Jaie55 any update? |
|
No, sorry. I'm going through a really really tough time right now, just don't have the mental energy to keep working on this (or much of anything, honestly) feel free to close the PR if you want to. |
|
I'm sorry for that, I hope you feel better. If your ok with it. I could take it over? Just push anything you currently have and I'll merge it into it's own branch and finish it up! |
The text in quotes was generated by AI, for reference and the complete PR: pyrodactyl-oss/pyrodactyl#90
Obviously, in progress... I need to check everything again...
This is a port of the completed i18n work from pyrodactyl-oss/pyrodactyl#90, adapted for the Hydrodactyl codebase.
I would like to know if I should continue with this or discard it completely.