|
1 | 1 | "use client"; |
2 | 2 |
|
3 | | -// TODO (AleksandrSl 21/11/2025): I think there should be a better type |
4 | | -import type { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime"; |
5 | 3 | import { |
6 | 4 | createContext, |
7 | 5 | type ReactNode, |
@@ -105,7 +103,7 @@ export interface TranslationProviderProps { |
105 | 103 | * If provided, calls router.refresh() after locale change |
106 | 104 | * This ensures Server Components re-render with new locale |
107 | 105 | */ |
108 | | - router?: AppRouterInstance; |
| 106 | + router?: { refresh: () => void }; |
109 | 107 |
|
110 | 108 | /** |
111 | 109 | * Development widget configuration |
@@ -303,16 +301,10 @@ function TranslationProvider__Dev({ |
303 | 301 | useState<Record<string, string>>(initialTranslations); |
304 | 302 | const [isLoading, setIsLoading] = useState(false); |
305 | 303 |
|
306 | | - // Track registered hashes from components (updated every render) |
307 | | - const registeredHashesRef = useRef<Set<string>>(new Set()); |
308 | | - |
309 | | - // Track all hashes that have been seen (for hot reload detection) |
310 | 304 | const [allSeenHashes, setAllSeenHashes] = useState<Set<string>>(new Set()); |
311 | | - |
312 | | - // Track which hashes are pending translation request |
| 305 | + const registeredHashesRef = useRef<Set<string>>(new Set()); |
313 | 306 | const pendingHashesRef = useRef<Set<string>>(new Set()); |
314 | | - |
315 | | - // Batch timer reference |
| 307 | + const erroredHashesRef = useRef<Set<string>>(new Set()); |
316 | 308 | const batchTimerRef = useRef<NodeJS.Timeout | null>(null); |
317 | 309 |
|
318 | 310 | // Use ref to track translations to avoid stale closures |
@@ -379,9 +371,12 @@ function TranslationProvider__Dev({ |
379 | 371 | [...allSeenHashes.values()], |
380 | 372 | [...pendingHashesRef.current.values()], |
381 | 373 | ); |
382 | | - logger.debug("translationsRef.current: ", translations); |
383 | 374 | for (const hash of allSeenHashes) { |
384 | | - if (!translations[hash] && !pendingHashesRef.current.has(hash)) { |
| 375 | + if ( |
| 376 | + !translations[hash] && |
| 377 | + !pendingHashesRef.current.has(hash) && |
| 378 | + !erroredHashesRef.current.has(hash) |
| 379 | + ) { |
385 | 380 | missingHashes.push(hash); |
386 | 381 | pendingHashesRef.current.add(hash); |
387 | 382 | } |
@@ -425,10 +420,13 @@ function TranslationProvider__Dev({ |
425 | 420 | registeredHashesRef.current.add(hash); |
426 | 421 | } |
427 | 422 | } catch (error) { |
428 | | - logger.error("Failed to fetch translations:", error); |
| 423 | + logger.warn( |
| 424 | + `Failed to fetch translations from translation server: ${error}.`, |
| 425 | + ); |
429 | 426 | // Remove from pending so they can be retried |
430 | 427 | for (const hash of hashesToFetch) { |
431 | 428 | pendingHashesRef.current.delete(hash); |
| 429 | + erroredHashesRef.current.add(hash); |
432 | 430 | } |
433 | 431 | } finally { |
434 | 432 | setIsLoading(false); |
@@ -470,6 +468,7 @@ function TranslationProvider__Dev({ |
470 | 468 | try { |
471 | 469 | logger.info(`Fetching translations for locale: ${newLocale}`); |
472 | 470 |
|
| 471 | + // TODO (AleksandrSl 08/12/2025): We should be fetching the existing cached translations here. |
473 | 472 | const translatedDict = await fetchTranslations( |
474 | 473 | newLocale, |
475 | 474 | [], |
|
0 commit comments