Introduction
Integrating a translation feature in your React app can enhance accessibility and expand your audience. However, repeatedly fetching translations from APIs like Google Translate can increase latency and costs. We’ll combine React, Zustand, and the Google Translate API to build a performant, cache-enabled translation solution to tackle those issues.
In this article, you’ll learn how to do the following:
- Set up a Zustand store to cache translations and avoid redundant API calls.
- Use Google Translate API for dynamic translations.
- Implement the solution with React hooks for seamless integration.
Why Zustand?
Zustand is a lightweight state management library that simplifies state handling in React. Its simplicity and scalability make it ideal for managing and caching translations in memory.
Step 1: Creating the Zustand Store
Our Zustand store will manage:
- A cache for storing translations.
- yoA registry to track ongoing API requests and avoid duplicates.
- A method to fetch translations while leveraging the cache.
import { create } from "zustand";
interface TranslationStore {
translations: Record<string, string>;
ongoingRequests: Record<string, Promise<string>>;
getTranslation: (
text: string,
targetLang: string,
fetchTranslation: (text: string, targetLang: string) => Promise<string>,
) => Promise<string>;
}
export const useTranslationStore = create<TranslationStore>((set, get) => ({
translations: {},
ongoingRequests: {},
getTranslation: async (text, targetLang, fetchTranslation) => {
const cacheKey = `${text}_${targetLang}`;
const { translations, ongoingRequests } = get();
if (translations[cacheKey]) {
return translations[cacheKey];
}
if (await ongoingRequests[cacheKey]) {
return ongoingRequests[cacheKey];
}
const requestPromise = fetchTranslation(text, targetLang);
set((state) => ({
ongoingRequests: { ...state.ongoingRequests, [cacheKey]: requestPromise },
}));
try {
const translatedText = await requestPromise;
set((state) => ({
translations: { ...state.translations, [cacheKey]: translatedText },
}));
return translatedText;
} finally {
set((state) => {
const updatedRequests = { ...state.ongoingRequests };
delete updatedRequests[cacheKey];
return { ongoingRequests: updatedRequests };
});
}
},
}));
export default useTranslationStore;
Step 2: Integrating Google Translate API
Create a function to interact with the Google Translate API:
import { useCallback, useState } from "react";
import axios from "axios";
const API_KEY = `${process.env.GOOGLE_TRANSLATION_API_KEY}`!;
const API_URL = `${process.env.GOOGLE_TRANSLATION_API_URL}`!;
const useTranslateText = () => {
const translateText = useCallback(
async (text: string, targetLanguage: string) => {
try {
const response = await axios.post(`${API_URL}?key=${API_KEY}`, {
q: text,
target: targetLanguage,
});
const translated = response.data.data.translations[0].translatedText;
setTranslatedText(translated);
return translated;
} catch (err: any) {
return null;
}
},
[],
);
return { translateText };
};
export default useTranslateText;
Step 3: Using the Store in a React Component
Now, let’s build a component that uses the store to fetch and display translations:
import React, { useEffect, useState } from 'react';
import useTranslationStore from './useTranslationStore';
import { useTranslation } from "react-i18next";
const TranslationComponent = ({ text }: { text: string }) => {
const { i18n } = useTranslation();
const [translatedText, setTranslatedText] = useState('');
const { translateText } = useTranslateText();
const getTranslation = useTranslationStore((state) => state.getTranslation);
useEffect(() => {
const translateActions = async () => {
if (i18n.language === "en") return;
const result = await getTranslation(
"example text",
i18n.language,
translateText,
);
setTranslatedText(result);
}
fetchTranslation();
}, [text, getTranslation]);
return (
<div>
<h1>Original: {text}</h1>
<h2>Translated: {translatedText}</h2>
</div>
);
};
export default TranslationComponent;
Benefits of this Approach
- Performance Optimization: Translations are cached, reducing redundant API calls.
- Scalability: The approach is flexible and can handle additional languages or features.
- Ease of Maintenance: Zustand’s simple API makes state management clean and intuitive.
Conclusion
By integrating Zustand and the Google Translate API, we’ve built a highly efficient and scalable translation system. This solution minimizes API usage, improves user experience, and keeps your codebase organized. Start implementing this in your projects and elevate the global reach of your applications! 🚀