Skip to content

feat(web): add multi-language support (en, fr, de, es, it)#142

Open
jjacque wants to merge 16 commits intomasterfrom
ai-multi-lang
Open

feat(web): add multi-language support (en, fr, de, es, it)#142
jjacque wants to merge 16 commits intomasterfrom
ai-multi-lang

Conversation

@jjacque
Copy link
Copy Markdown
Contributor

@jjacque jjacque commented Jan 2, 2026

Summary

This PR introduces comprehensive internationalization (i18n) support to the application, enabling users to view the interface in 5 languages: English, French, German, Spanish, and Italian.

Note: This PR is built on top of PR #140 and PR #143 (already merged)

Static Asset Size Analysis

Core Files (minified)

File Before After
(Minified)
After
(Minified & Gzipped)
Evolution Evolution
(Minified & Gzipped)
application.css 2,275 B 3,268 B 980 B +993 B (+43.6%) -1,295 B (-56.9%)
getmsg.html 2,848 B 2,575 B 773 B -273 B (-9.6%) -2,075 B (-72.9%)
getmsg.js 4,240 B 2,005 B 602 B -2,235 B (-52.7%) -3,638 B (-85.8%)
index.html 2,180 B 3,151 B 945 B +971 B (+44.6%) -1,235 B (-56.7%)
index.js 2,180 B 1,618 B 485 B -562 B (-25.8%) -1,695 B (-77.8%)
utils.js 351 B 2,579 B 774 B +2,228 B (+634.8%) +423 B (+120.5%)
Subtotal 14,074 B 15,196 B 4,559 B +1,122 B (+8.0%) -9,515 B (-67.6%)

New Translation Files

File Size Size
(Minified & Gzipped)
locales/de.json 1,098 B 330 B
locales/en.json 970 B 291 B
locales/es.json 1,042 B 313 B
locales/fr.json 1,077 B 323 B
locales/it.json 1,029 B 309 B
Subtotal 5,216 B 1,566 B

Total Impact

  • Total Before: 14,074 B (uncompressed)
  • Total After (Core + locales): 20,412 B uncompressed / 6,125 B gzipped
  • Total Evolution: +6,338 B (+45.0%) uncompressed / -7,949 B (-56.5%) gzipped
  • Core Files Only: +1122 B (+8.0%) uncompressed / 4,559 B (-67.6%) gzipped

Note: Translation files are loaded asynchronously on-demand (only the selected language is fetched), so the actual page load increases by only ~435 bytes uncompressed or ~280 bytes gzipped + one locale file (~300 bytes gzipped).

Gzip Compression: The Gzip middleware provides ~70% compression on text assets, reducing total transfer size from 20.4KB to 6.1KB. This makes the multi-language feature essentially bandwidth-neutral compared to the original.

Changes Overview

Core Features

  • ES6 Module Architecture: Refactored JavaScript to use modern ES6 modules with proper import/export
  • 5 Language Support: Complete translations for English, French, German, Spanish, Italian
  • CSP-Compliant: Removed all inline event handlers in favor of event listeners
  • Smart Language Detection: Automatically detects language from URL param → browser preference → defaults to English
  • Dynamic Translation: Switch languages without page reload
  • SEO Optimized: Updates HTML lang attribute, title, and meta tags dynamically
  • Gzip Compression: Added middleware for 70% bandwidth reduction on all text assets

Technical Details

utils.js Module:

  • detectLanguage(): Auto-detect from URL param ?lang=fr or browser
  • isValidLanguage(): Validate supported language codes (en, fr, de, es, it)
  • loadTranslations(): Fetch JSON translations asynchronously
  • applyTranslations(): Update DOM elements with data-i18n attributes
  • updateMetaTags(): Update title, description, Open Graph tags
  • switchLanguage(): Change language with URL persistence

CSP Compliance:

  • Replaced onchange="..." with addEventListener()
  • All JavaScript in external modules
  • No inline code execution

UI Improvements:

  • Custom styled file input (native inputs can't be translated)
  • Glassmorphism language selector in top-right corner
  • Proper accessibility with dynamic lang attribute updates

Performance Optimization:

  • Gzip middleware with Vary: Accept-Encoding headers
  • 70% compression on CSS, JS, HTML, and JSON
  • Tiered cache headers: 5min (JS/CSS), 1hr (JSON), 24hr (icons), 30d (fonts)

Testing

  • ✅ Language switching works without page reload
  • ✅ File input displays translated text
  • ✅ URL persistence: ?lang=fr maintains selection
  • ✅ Browser language detection works
  • ✅ All UI elements translate properly (23 keys per language)
  • ✅ CSP policy respected (no violations)
  • ✅ Async loading: only active language fetched
  • ✅ Gzip compression verified (70% reduction on text assets)

Related Commits

  1. c03c956 - Add minify step for static resources
  2. d3fe4fa - Add language header support in handlers
  3. 2a9bebf - Add multi-lang support (en,fr,es,de,it)

Performance Impact

  • Initial page load: +1,122 bytes uncompressed / -9,515 bytes gzipped for core files (vs before)
  • First language load: +~1KB uncompressed / ~300 bytes gzipped for selected locale JSON
  • Language switch: ~300 bytes gzipped fetch (cached by browser)
  • No additional requests for unchanged language
  • Net result: Despite adding 5 languages, gzipped payload is ~9.5KB smaller than before (when gzip is in use) (67.6% reduction)

@jjacque jjacque requested a review from a team as a code owner January 2, 2026 00:17
@jjacque jjacque force-pushed the ai-multi-lang branch 2 times, most recently from 7be3f1b to 470cb25 Compare January 2, 2026 00:38
@jjacque jjacque marked this pull request as draft January 2, 2026 08:08
@jjacque jjacque force-pushed the ai-multi-lang branch 2 times, most recently from 0ab952a to 6063a26 Compare January 2, 2026 10:07
@jjacque
Copy link
Copy Markdown
Contributor Author

jjacque commented Jan 2, 2026

Here is a manual test:
test_multi_lang

@jjacque jjacque force-pushed the ai-multi-lang branch 4 times, most recently from c6a7c7a to 7d373bc Compare January 2, 2026 21:43
@jjacque jjacque marked this pull request as ready for review January 19, 2026 15:10
@jjacque jjacque requested a review from Copilot March 13, 2026 09:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds client-side internationalization to the web UI (5 languages) and modernizes static asset delivery (ES modules, minification, gzip, and tiered caching) while updating docs and tests accordingly.

Changes:

  • Introduce i18n utilities + JSON locale packs and wire them into index.html/getmsg.html with a language selector.
  • Refactor frontend JS to ES6 modules and add UI tweaks (custom file input, language selector styling).
  • Add gzip middleware + tiered cache headers for static assets, plus Docker build-time minification and related tests/docs.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
web/static/utils.js Adds ES-module utilities including i18n detection/loading/application + meta tag updates
web/static/index.js Initializes i18n on the send page and adds custom file input behavior
web/static/getmsg.js Initializes i18n on the retrieve page and keeps CSP-safe event wiring
web/static/index.html Adds language selector, data-i18n hooks, and switches scripts to type="module"
web/static/getmsg.html Adds language selector, data-i18n hooks, and switches scripts to type="module"
web/static/locales/en.json English translation keys
web/static/locales/fr.json French translation keys
web/static/locales/de.json German translation keys
web/static/locales/es.json Spanish translation keys
web/static/locales/it.json Italian translation keys
web/static/application.css Styles language selector + custom file input
web/static/icons/manifest.json Fixes icon paths to /static/icons/...
web/static/icons/browserconfig.xml Fixes tile icon path to /static/icons/...
internal/server.go Enables gzip, updates rate limiting, and replaces static routing with cache-tier handlers
internal/handlers.go Adds HTML/static handlers with caching headers and basic language header handling
internal/server_test.go Updates rate-limit test and adds gzip compression test coverage
deploy/Dockerfile Adds a Node-based minification stage and copies minified static assets into the final image
README.md Documents multi-language support and updates frontend asset details/screenshots

You can also share your feedback on Copilot code review. Take the survey.

Comment thread internal/handlers.go
Comment thread internal/server.go
Comment thread web/static/getmsg.html
Comment thread deploy/Dockerfile Outdated
Comment thread web/static/utils.js Outdated
Comment thread internal/handlers.go Outdated
Comment thread internal/server_test.go Outdated
Comment thread web/static/index.html
Comment thread web/static/index.js
Comment thread internal/handlers.go Outdated
@jjacque jjacque requested a review from a team as a code owner March 25, 2026 12:46
@jjacque jjacque force-pushed the ai-multi-lang branch 2 times, most recently from 4149d9e to 8577b5c Compare March 25, 2026 14:01
jjacque added 2 commits March 25, 2026 15:13
…css)

Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds client-side internationalization to the web UI (5 languages) and adjusts server/static delivery to support the new asset layout and performance goals (tiered caching + gzip).

Changes:

  • Refactors frontend JS into ES modules and introduces a data-i18n-driven translation system with async-loaded locale JSON files.
  • Updates HTML/CSS to add a language selector and translate UI strings + meta tags.
  • Updates Go server routing/middleware for gzip compression and tiered caching of static assets; updates Docker build to minify web assets.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
web/static/utils.js Adds ES module utilities + i18n loading/detection/switching logic.
web/static/index.js Imports utils as a module, initializes i18n, updates custom file input behavior.
web/static/index.html Adds language selector, data-i18n attributes, switches script loading to ES modules.
web/static/getmsg.js Imports utils as a module, initializes i18n, minor handler refactors.
web/static/getmsg.html Adds language selector, data-i18n attributes, switches script loading to ES modules.
web/static/application.css Styles language selector and custom file input.
web/static/locales/en.json English translation keys for i18n.
web/static/locales/fr.json French translation keys for i18n.
web/static/locales/de.json German translation keys for i18n.
web/static/locales/es.json Spanish translation keys for i18n.
web/static/locales/it.json Italian translation keys for i18n.
web/static/icons/manifest.json Fixes icon paths to match /static/icons/....
web/static/icons/browserconfig.xml Fixes tile icon path to match /static/icons/....
internal/server.go Enables gzip middleware; replaces static serving with tiered-cache static routes.
internal/handlers.go Adds Vary helpers, HTML/static asset handlers with caching, language header handling.
internal/server_test.go Updates rate-limit test and adds gzip coverage.
deploy/Dockerfile Adds a Node-based stage to minify HTML/CSS/JS/JSON static assets during image build.
README.md Documents i18n feature and updates frontend dependency details/screenshots.

Comment thread web/static/getmsg.js
Comment thread internal/handlers.go
Comment thread internal/handlers.go Outdated
Comment thread internal/handlers.go
Comment thread web/static/utils.js
@jjacque jjacque force-pushed the ai-multi-lang branch 2 times, most recently from 5a476db to f645ed6 Compare March 26, 2026 08:26
@jjacque jjacque requested a review from Copilot March 26, 2026 08:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Comment thread web/static/getmsg.js Outdated
Comment thread web/static/utils.js
Comment thread internal/handlers.go Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

deploy/Dockerfile:82

  • The permissions step only applies chmod 644 to top-level entries under ./static/*, so files in nested directories (e.g. ./static/icons/*, ./static/locales/*, ./static/fonts/*) keep whatever permissions they had in the build stage. Consider switching to find ./static -type f -exec chmod 644 {} \; (and -type d for 755) so all copied static assets end up with consistent non-executable permissions.
# Set proper file permissions
RUN chmod 755 ./sup3rS3cretMes5age \
    && chmod 644 ./static/* \
    && find ./static -type d -exec chmod 755 {} \;

Comment thread internal/handlers.go
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

jjacque and others added 12 commits March 26, 2026 17:03
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
…JS arch

Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
… header

Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
…ge async and using monotonic request IDs to discard stale translation loads

Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
@jjacque jjacque force-pushed the ai-multi-lang branch 3 times, most recently from 4b13789 to a0c4afd Compare March 26, 2026 16:17
Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
…changes

Signed-off-by: Jeremy JACQUE <jeremy.jacque@algolia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants