Internationalization (i18n)
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
Internationalization (i18n) in the WhereIsLifeCheaper project is a multi-layered system designed to support a global user base comparing grocery and rent prices across diverse regions. The system facilitates multi-country data visualization, localized search through automated translation services, and SEO optimization tailored to specific locales. It encompasses both frontend UI translation using standard libraries and backend integration with external translation APIs to handle dynamic content like product names.
The scope of i18n covers currency localization, language-specific SEO meta tags, and bilingual search capabilities for administrative tasks such as product mapping. This ensures that users and administrators can interact with data from countries like Turkey, Montenegro, Spain, Uzbekistan, Ukraine, Kazakhstan, Germany, Malaysia, Albania, and Austria regardless of their primary language.
Sources: CLAUDE.md:3-8, frontend/src/hooks/useSEO.ts:60-70, frontend/src/pages/Home.tsx:11-20
Translation Architecture
The project utilizes a hybrid approach to translation, combining static UI translations with dynamic content translation via Google Translate API.
UI Localization
The frontend employs react-i18next for managing static UI strings. The application layout dynamically updates the HTML lang attribute based on the active language selected by the user, which is critical for search engine optimization.
The Layout component ensures that the lang attribute is always in sync with the current i18next language state.
Sources: frontend/src/components/layout/Layout.tsx:10-14, frontend/src/pages/Home.tsx:13-15
Dynamic Content Translation
For dynamic content, particularly during administrative product mapping, the system uses a dedicated translation service. When an administrator searches for a product in English, the system automatically translates the query into the target country's primary language to facilitate better matching with scraped local data.
Key Translation Components:
| Component | Description |
|---|---|
COUNTRY_LANGUAGE_MAP | A mapping of country codes (e.g., TR, ME, ES) to Google Translate language codes (e.g., tr, sr, es). |
translationCache | An in-memory cache (limit 10,000 entries) to store and reuse previous translations to reduce API costs. |
translateText | Backend function that interacts with the Google Translate V2 API. |
translateApi | Frontend service wrapper for the translation endpoints. |
Sources: src/api/routes/translate.ts:8-25, src/api/routes/translate.ts:31-33, frontend/src/services/api.ts:110-120
Search and Mapping Localization
The administrative "Mapping" interface utilizes i18n to bridge the gap between English-speaking administrators and local-language product data.
Bilingual Search Flow
When a search term is entered in the mapping dashboard, the system checks if the input is ASCII-only (typically English). If so, it fetches a translation for the selected target country's language and performs a combined search using both terms.
Supported Language Mappings
The backend route src/api/routes/translate.ts defines the relationship between supported countries and their translation codes:
| Country | Code | Target Language |
|---|---|---|
| Turkey | TR | tr |
| Montenegro | ME | sr (Serbian) |
| Spain | ES | es |
| Uzbekistan | UZ | uz |
| Ukraine | UA | uk |
| Kazakhstan | KZ | kk |
| Germany | DE | de |
| Albania | AL | sq |
Sources: src/api/routes/translate.ts:8-25
SEO and Metadata Internationalization
SEO is localized through the useSEO hook, which manages meta tags and Open Graph properties.
Localized Meta Tags
The useSEO hook explicitly sets og:locale to en_US by default but allows for dynamic title and description updates based on the page context. For example, the generateCountrySchema function creates structured data with localized descriptions such as "Browse [count] grocery products and prices in [Country Name]".
Structured Data (JSON-LD)
The system generates localized Schema.org markup for:
- WebSite: Global search actions.
- Country Pages: Specific identifiers for countries.
- FAQ: Localized questions and answers about the service.
Sources: frontend/src/hooks/useSEO.ts:69, frontend/src/hooks/useSEO.ts:121-135, frontend/src/pages/Home.tsx:24-40
Currency and Unit Formatting
While strictly part of formatting, currency handling is a core component of the project's internationalization strategy to ensure comparative accuracy.
Currency Metadata
The system maintains symbols and names for various global currencies to ensure proper display across the UI.
| Code | Symbol | Name |
|---|---|---|
| TRY | ₺ | Turkish Lira |
| UZS | so'm | Uzbek Som |
| UAH | ₴ | Ukrainian Hryvnia |
| KZT | ₸ | Kazakhstani Tenge |
| ALL | L | Albanian Lek |
Sources: frontend/src/components/comparison/CurrencyRatesTable.tsx:8-15, frontend/src/utils/currency.ts:46-56
Normalization of Units
Internationalization also extends to unit normalization, converting diverse local measurements (e.g., German "Stück") into standard internal formats like "pieces", "kg", or "L" for cross-country comparison.
Sources: src/scrapers/germany/ReweScraper.ts:606-640, frontend/src/utils/currency.ts:74-90
Conclusion
The internationalization system in WhereIsLifeCheaper is central to its mission of providing a cross-border cost-of-living comparison. By combining standardized UI localization frameworks with intelligent, cached dynamic translation services and localized SEO strategies, the project maintains high usability for administrators while providing relevant, localized information to global users. This architecture effectively bridges language barriers in data collection, processing, and presentation.