Здравствуйте! У меня есть хук, который возвращает переводы для компонентов на 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 };
```
Теперь, когда вы изменяете язык, текст на кнопке будет обновляться в соответствии с новыми переводами.
У вас бак в хуке следующий: <br/> в useEffect вы реагируете на смену языка, и задаёте новый texts. НО в useCallback у вас в зависимостях тоже language, в результате после смены texts он уже не отрабатывает. Замените в useCallback зависимость на texts. <br/> PS если это не в рамках обучения, то не советую писать свой инструмент для локализации сайта, лучше возьмите готовый, например i18n <br/> PPS для подсказки в таких багах пусть и ненадёжно, но полезно использовать нейронные сети, к примеру chatgpt в целом хорошо расписывает если дать ему код вашего Хука и попросить найти баг, только что проверил даёт неплохие подсказки для начала. НО помните, что без опыта с нейронками легко выстрелить себе в ногу, тк не заметите где она там напридумывала всякую дичь.
<blockquote>при изменении language у меня не меняются переводы</blockquote> <br/> Меняются. С запаздыванием на один шаг. Потому что <code>texts</code> обновляется в эффекте, т.е., после того, как новая версия <code>t</code> будет создана. Так что <code>t</code> получает ссылку на старую версию <code>texts</code> . <br/> <br/> Никакого <code>texts</code> не надо, доставайте в <code>t</code> нужный объект из <code>translations</code> напрямую: <br/> <br/> <pre><code class="javascript">const t = useCallback(
key => key
.split('.')
.reduce((p, c) => p?.[c], translations[language]),
[ language ]
);</code></pre>