Здравствуйте! У меня есть хук, который возвращает переводы для компонентов на React. Вот его код: ```javascript import en from '../../locales/en.json' import ru from '../../locales/ru.json' const translations = { en, ru, } export type LanguageCode = 'en' | 'ru' export const useTranslation = (initialLanguage: LanguageCode = 'en') => { const [language, setLanguage] = useState<LanguageCode>(initialLanguage) const [texts, setTexts] = useState<(typeof translations)[LanguageCode]>( translations[initialLanguage] ) useEffect(() => { setTexts(translations[language]) }, [language]) const t = useCallback( (key: string): any => { const value = key.split('.').reduce((obj, keyPart) => { if (obj && typeof obj === 'object') { return obj[keyPart] } return undefined }, texts as Record<string, any>) //@ts-ignore return value }, [language] ) return { t, setLanguage, language } } ``` Однако у меня возникла проблема: при изменении языка переводы не обновляются. Переводы извлекаются с помощью функции `t(key)`. Как я могу обновлять переводы для этих компонентов? ```javascript interface Props {} const Component: FC<Props> = ({}) => { const { t, setLanguage } = useTranslation() return ( <> <div>{t('helloWorld')}</div> <button onClick={() => { setLanguage('ru') }} > {t('helloWorld')} </button> </> ) } export { Component } ```
Ваша проблема связана с тем, что функция `t(key)` кэширует текст на основе значения `language`, но это значение не обновляется при изменении языка. Когда `setLanguage` вызывается и язык меняется, `texts` обновляется, но функция `t(key)` не пересчитывает значение, потому что ее зависимость задана на `language`, а не на `texts`. Чтобы решить эту проблему, вам нужно добавить `texts` в зависимости `useCallback`, чтобы функция `t` перегенерировалась всякий раз, когда изменяется язык. Таким образом, `t(key)` будет использовать обновлённые переводы из `texts`. Вот как может выглядеть исправленный код: ```javascript import { useCallback, useEffect, useState } from 'react'; import en from '../../locales/en.json'; import ru from '../../locales/ru.json'; const translations = { en, ru, }; export type LanguageCode = 'en' | 'ru'; export const useTranslation = (initialLanguage: LanguageCode = 'en') => { const [language, setLanguage] = useState<LanguageCode>(initialLanguage); const [texts, setTexts] = useState<(typeof translations)[LanguageCode]>( translations[initialLanguage] ); useEffect(() => { setTexts(translations[language]); }, [language]); const t = useCallback( (key: string): any => { const value = key.split('.').reduce((obj, keyPart) => { if (obj && typeof obj === 'object') { return obj[keyPart]; } return undefined; }, texts as Record<string, any>); return value; // Убрали @ts-ignore }, [texts] // Изменили зависимость на texts ); return { t, setLanguage, language }; }; ``` Кроме того, в вашем компоненте `Component` вы сможете использовать функцию `t` для получения перевода, не повторяя нужный текст после нажатия кнопки. Обновленный код компонента будет выглядеть так: ```javascript import React, { FC } from 'react'; import { useTranslation } from './path/to/useTranslation'; interface Props {} const Component: FC<Props> = () => { const { t, setLanguage } = useTranslation(); return ( <> <div>{t('helloWorld')}</div> <button onClick={() => { setLanguage('ru'); }} > {t('helloWorld')} </button> </> ); }; export { Component }; ``` Теперь, когда вы изменяете язык, текст на кнопке будет обновляться в соответствии с новыми переводами.
У вас бак в хуке следующий:
в useEffect вы реагируете на смену языка, и задаёте новый texts. НО в useCallback у вас в зависимостях тоже language, в результате после смены texts он уже не отрабатывает. Замените в useCallback зависимость на texts.
PS если это не в рамках обучения, то не советую писать свой инструмент для локализации сайта, лучше возьмите готовый, например i18n
PPS для подсказки в таких багах пусть и ненадёжно, но полезно использовать нейронные сети, к примеру chatgpt в целом хорошо расписывает если дать ему код вашего Хука и попросить найти баг, только что проверил даёт неплохие подсказки для начала. НО помните, что без опыта с нейронками легко выстрелить себе в ногу, тк не заметите где она там напридумывала всякую дичь.
при изменении language у меня не меняются переводы
Меняются. С запаздыванием на один шаг. Потому чтоtexts
обновляется в эффекте, т.е., после того, как новая версияt
будет создана. Так чтоt
получает ссылку на старую версиюtexts
.
Никакогоtexts
не надо, доставайте вt
нужный объект изtranslations
напрямую:
const t = useCallback( key => key .split('.') .reduce((p, c) => p?.[c], translations[language]), [ language ] );