- Published on
92% Smaller Bundle: How Smart Translation Loading Transformed Our International Website
- Authors
92% Smaller Bundle: How Smart Translation Loading Transformed Our International Website
The Problem: When "Multi-language Support" Becomes a Performance Killer
Our platform supports 11 international markets (Polish, English, German, Ukrainian, Russian, Hungarian, Romanian, French, Slovenian, Spanish, and Italian). What started as a competitive advantage was quietly destroying our user experience.
The brutal truth: Every visitor had to download 1MB of translation data (which keeps growing every day) before seeing anything meaningful. That's forcing users to download translations for admin panels they'd never see, product pages they might never visit, and error messages for scenarios that rarely occur.
The Shocking Transformation: Red to Green in One Change
Before: Performance Disaster 🔴
- Lighthouse Performance: Deep red scores
- First Contentful Paint: 4.8 seconds
- Time to Interactive: 6.2 seconds
- Initial Translation Bundle: 1MB
- Mobile Performance: Catastrophic
After: Google's Green Checkmarks ✅
- Lighthouse Performance: Blazing green across all metrics
- First Contentful Paint: 2.5 seconds (48% faster)
- Time to Interactive: 3.3 seconds (47% improvement)
- Initial Translation Bundle: 80KB (92% reduction)
- Mobile Performance: Outstanding
The 92% Solution: Load What You Need, When You Need It
Instead of forcing every visitor to download translations for every possible scenario, we implemented intelligent lazy loading that delivers only essential translations initially, then loads page-specific chunks on demand.
The Technical Architecture
1. Smart Nuxt i18n Configuration
// nuxt.config.ts
export default defineNuxtConfig({
i18n: {
locales: [
{
code: 'pl',
language: 'pl',
file: 'translation.ts',
name: 'Polski',
},
{
code: 'en',
language: 'en',
file: 'translation.ts',
name: 'English',
},
// ... 9 more languages
],
lazy: true, // 🚀 GAME CHANGER: 92% bundle reduction
langDir: 'lang',
defaultLocale: 'pl',
strategy: 'prefix_except_default',
vueI18n: './i18n.config.ts',
},
})
2. Intelligent Initial Loading
// lang/translation.ts
export default defineI18nLocale((locale) => {
const nuxt = useNuxtApp()
nuxt._vueI18n.__firstAccess = false
// Load only core translations (80KB vs previous 1MB)
return $fetch(`/api/public/locales/local?lang=${locale}`, {
method: 'get',
cache: 'no-store',
})
})
3. On-Demand Chunk Loading
// composables/useLocalesLoader.ts
export const useLocalesLoader = async (startsWith: string) => {
const { locale, setLocaleMessage, messages } = useCustomI18n()
const { data } = await useCustomQuery(`/api/public/locales/${startsWith}`, { startsWith })
watch(
[data],
([newData]) => {
if (newData) {
// Merge additional translations seamlessly
setLocaleMessage(locale.value, {
...messages.value[locale.value],
...newData,
})
}
},
{ immediate: true }
)
}
4. Page-Specific Translation Loading
<!-- pages/collections/[collectionName]/magnetic.vue -->
<script setup lang="ts">
// Load only this page's translations (5-15KB additional)
await useLocalesLoader('landing.magnetic')
const { t } = useCustomI18n()
useSeoMeta({
title: () => t('landing.magnetic.seo.title'),
description: () => t('landing.magnetic.seo.description'),
})
</script>
Backend Optimization Strategy
// server/api/public/locales/[startsWith].get.ts
export default defineCustomCacheEventHandler(async (event) => {
const { startsWith } = await getValidatedRouterParams(event, getLocaleParams.parse)
const lang = getLocale(event)
const select = getLocalizedSelect(lang)
// Targeted queries: only fetch what's needed
const data = await prisma.dictionaryEntry.findMany({
select: {
id: true,
translations: { select },
},
where: {
id: { startsWith }, // 🎯 Precision loading
},
})
return data.reduce(
(prev, { id, translations }) => ({
...prev,
[id]: translations[lang] ?? id,
}),
{}
)
})
Strategic Translation Organization
We restructured our translation architecture using intelligent prefixes:
// Strategic chunking for maximum efficiency
const translationStrategy = {
// Core translations (80KB) - loaded immediately
'local.navigation': 'Navigation menus and basic UI',
'local.common': 'Buttons, forms, essential interactions',
'local.seo': 'Critical SEO meta tags and descriptions',
// Page-specific chunks (5-15KB each) - loaded on demand
'landing.magnetic': 'Magnetic collection landing page',
'landing.thermostat': 'Thermostat product showcase',
dashboard: 'Admin interfaces (rarely accessed)',
}
Performance Revolution: The Numbers Don't Lie
Bundle Size Transformation:
- Initial download: 92% reduction (1MB → 80KB)
- Page-specific chunks: 5-15KB loaded as needed
- Total optimization: 920KB saved from initial load
Speed Improvements:
- First Contentful Paint: 48% faster (4.8s → 2.5s)
- Time to Interactive: 47% improvement (6.2s → 3.3s)
- Largest Contentful Paint: 61% better performance
- Mobile load times: 58% improvement across all devices
User Experience Gains:
- Bounce rate reduction: 28% improvement on international pages
- Mobile conversions: 35% increase in mobile transactions
- User satisfaction scores: 43% improvement in feedback
- Core Web Vitals: Perfect green scores across all metrics
Technical Implementation Details
Database Architecture Supporting Chunked Loading:
model DictionaryEntry {
id String @id // "landing.magnetic.seo.title"
translationId Int
translations Translation @relation(fields: [translationId])
}
model Translation {
id Int @id @default(autoincrement())
pl String? // Polish
en String? // English
de String? // German
uk String? // Ukrainian
ru String? // Russian
hu String? // Hungarian
ro String? // Romanian
fr String? // French
sl String? // Slovenian
es String? // Spanish
it String? // Italian
}
Server-Side Translation Support:
export const useServerTranslation = async (event: H3Event, startsWith: string) => {
const lang = getLocale(event)
const select = getLocalizedSelect(lang)
const response = await prisma.dictionaryEntry.findMany({
select: { id: true, translations: { select } },
where: { id: { startsWith } },
})
const localesMap = new Map()
response.forEach((option) => {
localesMap.set(option.id, option.translations[lang] ?? null)
})
return (key: string) => localesMap.get(key) ?? key
}
SEO-Optimized International Routing:
defineI18nRoute({
paths: {
pl: '/kolekcja/magnetic',
en: '/collection/magnetic',
de: '/kollektion/magnetic',
ru: '/kollektsiya/magnetic',
hu: '/gyujtemeny/magnetic',
ro: '/colectie/magnetic',
uk: '/kolektsiya/magnetic',
fr: '/collection/magnetic',
sl: '/zbirka/magnetic',
it: '/collezione/magnetic',
es: '/coleccion/magnetic',
},
})
Developer Experience Improvements
Translation Management Tools:
- Excel Import/Export: Bulk translation management
- Missing Translation Detection: Automated quality assurance
- Real-time Preview: Instant change visualization
- Translation History: Complete change tracking
- Performance Monitoring: Bundle size alerts and optimization suggestions
Fallback Strategy:
// Graceful degradation when translations are missing
return data.reduce(
(prev, { id, translations }) => ({
...prev,
[id]: translations[lang] ?? id, // Fallback to key name
}),
{}
)
Business Impact: Beyond Just Performance
SEO Transformation:
- Mobile-first indexing: Perfect compliance
- Core Web Vitals: All green across 11 markets
- Page Experience signals: Dramatic improvements
- International rankings: Visible improvements in all regions
Infrastructure Benefits:
- Server load: 55% reduction in translation-related requests
- Database queries: 75% fewer translation queries
- Memory usage: 65% improvement in application performance
- Error rates: 85% decrease in translation-related issues
The Scalability Advantage
This architecture grows with your business:
- New languages: Add without performance penalty
- New markets: Each gets optimized loading
- Content expansion: Translations stay chunked and efficient
- Team growth: Developers can easily add page-specific translations
Implementation Roadmap
Phase 1: Core Setup
✅ Enable lazy loading in i18n configuration
✅ Implement useLocalesLoader composable
✅ Create translation chunking strategy
Phase 2: Optimization
✅ Set up performance monitoring
✅ Implement fallback strategies
✅ Add developer tools
Phase 3: Scale
✅ Monitor bundle size growth
✅ Optimize chunk boundaries
✅ Expand to new markets efficiently
Key Lessons Learned
- Dramatic improvements possible: 92% bundle reduction with smart loading
- Performance equals user satisfaction: 47% faster loading drives engagement
- Strategic chunking works: Load what you need, when you need it
- International users benefit most: They often have slower connections
- Developer experience matters: Good tools make optimization sustainable
When You Need This Optimization
Red flags your site needs this:
- Lighthouse scores below 50
- Initial bundles over 500KB
- Multiple language support causing slowdowns
- High bounce rates in international markets
- Translation files loading unnecessarily
Perfect candidates:
- Multi-language e-commerce platforms
- International SaaS applications
- Content sites serving global audiences
- Any app with 3+ language variants
This optimization transformed our platform: 92% smaller initial bundle, 48% faster loading, and perfect Lighthouse scores across 11 international markets.
The breakthrough? Understanding that not every visitor needs every translation immediately. Smart loading delivers better performance, happier users, and a more scalable architecture.
Real performance improvements from translation optimization, serving customers across 11 European markets with 92% smaller initial bundles.