Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. Planned work is in ROADMAP.md.
Unreleased
2.1.0 - 2026-11-05
Production hardening. No breaking changes; see the Upgrade Guide.
Added
/testingentry point withinstallFakeGoogleTranslate()andresetGoogleTranslate(), so apps can test components that contain a switcher without loading Google's script. The package's own tests use the same fake.- The Nuxt module is now tested on Nuxt 4 as well as Nuxt 3, in CI.
- Documentation rewritten as a guide, with a running example, new Testing Your App and Accessibility chapters, and decision records for the main design choices.
Fixed
- WCAG contrast: the default blue (
#3b82f6) gave white text a contrast of 3.68:1, below the 4.5:1 WCAG AA requires (the "Translate" button in the browser-language prompt), and the dark theme's hover colour gave 2.54:1. The defaults are now#2563eb/#1d4ed8(5.17:1 / 6.7:1), and a test checks every default text and background pair in all three themes. - Nuxt module types:
ModuleOptions(thegoogleTranslatekey innuxt.config) resolved toanyin 2.0.0, because the published declarations imported a file that isn't in the package. It's now fully typed. - The published declarations no longer reference an internal constant (
CALLBACK_NAME), which broke type-checking for projects withskipLibCheck: false. - The Nuxt module's
useCookiecall type-checks on Nuxt 4.
Changed
- Development toolchain: Vite 7, Vitest 5, @vitejs/plugin-vue 6, vue-tsc 3, vite-plugin-dts 5, TypeScript 6, current GitHub Actions. The published files are unchanged in layout.
engines.nodeis set to>=18(needed by/server).
Internal
- CI packs the tarball, installs it into an empty project and checks every entry point as ESM, CommonJS and with strict types, before every release.
playground-nuxt/moved totests/fixtures/nuxt-app/; removed a leftover probe page fromplayground/.- Mutation testing with Stryker, weekly in CI (92.6% of mutants caught; fails below 90%). The tests it prompted cover the server's input validation boundaries, the subdomain-cookie fix and the vendor language-code mappings.
- 386 tests (from 235).
2.0.0 - 2026-11-02
The platform release: translation providers, an app-wide plugin, a Nuxt module, server handlers, and a documentation website. See the Upgrade Guide; most apps need no code changes.
Breaking
GoogleTranslateButton's deprecatedlanguageChangedevent was removed: usechange.- Flags are off by default (
showFlags: false). Addshow-flagsto keep them. themedefaults to'auto'(followshtml.dark/html.light, then the OS setting). Usetheme="light"for 1.x's look.- The stylesheet is only exported as
…/style.css(the…/dist/style.csspath was removed). - The UMD build was removed. ESM (
dist/index.js) and CommonJS (dist/index.cjs) remain;mainnow points todist/index.cjs.
Added
- Translation providers:
provideroption with a built-in DOM translation engine (batching, de-duplication,localStoragecache, follows content rendered later, instant restore).endpointProvider({ url })for your own server,libreTranslate({ url })for a LibreTranslate server.createDomTranslator,memoryCache,localStorageCachefor advanced use. - Server handlers (
…/server):createTranslateHandler(Fetch-standard, input validation, size limits,allowedTargets, upstream errors never sent to the browser) withdeepl,googleCloud,azureandlibreTranslateServerbackends. - Plugin:
createGoogleTranslate(config)sets app-wide defaults for every component and composable; props and options still win. - Nuxt module (
…/nuxt): auto-imports, stylesheet, server rendering of the saved language (cookie or?lang=),v-no-translateregistered globally. onTranslatehook for analytics,autoTranslateon the first visit,queryParameterfor shareable?lang=frlinks,initialLanguagefor SSR.pageLanguageon the composable's return value.- Documentation website (VitePress, with a live demo) and 24 documentation chapters in
docs/.
Fixed
v-no-translateno longer causes a hydration class mismatch: it renders onlytranslate="no"on the server (found while testing the Nuxt module).- Server-side rendering no longer shares translation state between requests.
1.2.0 - 2026-11-02
Polish: theming, dark mode, slots, RTL and more. Everything is opt-in except the RTL direction fix; nothing changes visually unless you use the new options.
Added
- Themes:
theme: 'light' | 'dark' | 'auto'(default'light').autofollowshtml.dark/html.light, then the OS setting. - CSS custom properties:
--gtw-color-*,--gtw-radius,--gtw-shadow,--gtw-font,--gtw-z-index,--gtw-offset, shared by both components. unstyledprop to style the components from scratch.- Slots: Widget
trigger,header,item,empty,footer; Button default slot anditem. - Widget
position(any corner) andoffset. labelsprop on the Widget for every remaining piece of text, including accessible names.display(native/english/both),pinned,rememberRecenton both components.suggestBrowserLanguageon the Widget: a "View this page in …?" prompt in the visitor's language.flagStyle: 'emoji': flags without network requests.lazy: load Google on first open instead of on mount.syncDocumentDir(defaulttrue) on the composable and components.v-no-translatedirective (vNoTranslate),flagEmoji(),DEFAULT_WIDGET_LABELS, and typesTheme,FlagStyle,LanguageDisplay,WidgetLabels.npm run sync:languagesand a weekly CI job that check Google's live language list against ours.
Changed
<html dir="rtl">is now set while the page is shown in a right-to-left language (Arabic, Hebrew, Persian, Urdu, …) and restored afterwards; Google only set a class, so layouts stayed left-to-right. Opt out withsyncDocumentDir: false.- The Widget's search icon is now a magnifying glass.
- The Button's dropdown aligns to the button's inline end, so it opens the right way in RTL layouts.
- Bundle budget: 12 kB JS / 3 kB CSS (now 11.2 / 2.5 kB brotli).
1.1.0 - 2026-11-02
Every bug in the roadmap's Phase 1 list (B1–B17) plus three found while testing against the real Google script. Behaviour changes are listed under Changed; nothing was removed.
Changed
- Languages switch in place, without reloading the page (
mode: 'live', the new default). 1.0 always reloaded: it rendered Google'sSIMPLElayout, which has no<select>, so its in-place code path never ran.mode: 'reload'keeps the old behaviour. - Choosing the page's original language restores it in place via Google's own "Show original" button, falling back to a reload if that isn't available (
reloadOnRestore: trueforces the reload). - Google's banner, tooltips and highlight are hidden automatically (
hideBranding, defaulttrue). The copy-paste CSS in the docs is no longer needed. changeLanguage()andinitializeTranslate()now return promises.changeLanguagerejects if Google can't apply the change;initializeTranslatenever rejects.- State is shared: every component and composable on a page sees the same current language and status.
- Hebrew and Javanese use Google's codes (
iw,jw);heandjvare still accepted. - Portuguese is now "Portuguese (Brazil)" (
pt, 🇧🇷), plus a new "Portuguese (Portugal)" (pt-PT). - Catalan, Basque and Galician use their regional flags; Esperanto and Kurdish show a code badge instead of a contested country flag.
- The components no longer render their own hidden
#google_translate_element; one shared host is created. - Secondary text colours darkened slightly for contrast.
- JavaScript bundle budget raised from 7.5 kB to 10 kB (now 9.2 kB brotli): the accessibility, error and live-switching code.
Added
status('idle' | 'loading' | 'ready' | 'error'),error,isReadyandrestoreOriginal()on the composable.- Component events
change,update:language(v-model:language),ready,error,open,close. - Props/options
mode,reloadOnRestore,hideBranding,scriptSrc,nonce,timeout,errorText,flagUrl;showFlagson the Button. languagesandincludedLanguagesare reactive (refs or getters).- Full keyboard support and ARIA roles: the Widget is a modal dialog with a combobox and listbox, focus trap, Esc to close and focus restore; the Button is a listbox popup with arrow, Home/End, Enter/Space and Esc.
- An error message in both popups when Google can't load.
- Exports
DEFAULT_LANGUAGES,LANGUAGE_CODE_ALIASES,toGoogleCode, and typesTranslateMode,TranslateStatus.
Fixed
- Click-outside listener in
GoogleTranslateButtonwas never removed (memory leak). (B1) - Two components, or two instances, created duplicate
#google_translate_elementids, and only the first instance's options were used. (B2) - Restoring the original language failed on subdomains because Google's parent-domain cookie wasn't cleared. (B4)
- Changing
includedLanguages/languagesafter mount had no effect. (B5) currentLanguagestarted as'en'regardless ofdefaultLanguageuntil Google loaded. (B6)- A blocked Google script (ad blocker, CSP) failed silently. (B7)
- Language detection polled every 100 ms for 5 s and wasn't cleaned up on unmount. (B8)
- Hebrew (
he) and Javanese (jv) never worked: Google only acceptsiwandjw. (B9) languageChangedfired before the change was applied; the Widget emitted no events. (B10)- Language items weren't keyboard accessible. (B11)
- The floating button's
aria-expandedwas alwaysfalse. (B12) - Google's script was loaded with a protocol-relative URL. (B13)
- The page behind the Widget's modal scrolled. (B15)
- Opening one
GoogleTranslateButtondidn't close another. (B17) - A
#googtrans(..)hash in the URL overrode a newly chosen language. (B18) - Google translated the language names in our own lists ("Deutsch" became "Allemand"). (B19)
- After choosing a language from the Button, keyboard focus fell back to
<body>. (B20)
1.0.2 - 2026-11-02
No behaviour changes: packaging, tooling and documentation only.
Fixed
- Repository, issues and homepage links pointed at
github.com/ken_de_nigerian, which doesn't exist. They now point atgithub.com/ken-de-nigerian/vue-google-translate-widget. - CommonJS consumers now get their own
index.d.ctstype declarations instead of the ESM ones. typesis listed first in eachexportscondition, so TypeScript always finds the declarations.
Added
@ken_de_nigerian/vue-google-translate-widget/style.cssexport (the old/dist/style.csspath still works).sideEffectsdeclaration so bundlers can tree-shake the JavaScript while keeping the stylesheet.LICENSEandCHANGELOG.mdare now included in the published package.- Test suite (Vitest + happy-dom) covering the composable and both components.
- CI on every push and pull request: lint, formatting, typecheck, build, publint, Are the Types Wrong?, bundle-size budget, and tests on Node 20/22/24 × Vue 3.3/3.4/3.5.
- Release workflow: tagging
vX.Y.Zpublishes to npm with provenance and creates a GitHub release. CONTRIBUTING.md,SECURITY.md,CODE_OF_CONDUCT.md, issue and pull request templates, Dependabot.
Changed
- Documentation no longer claims keyboard navigation or full SSR support; both are on the roadmap.
- Changelog rewritten to list only the versions that were actually published.
1.0.1 - 2025-11-30
Fixed
- Build configuration and generated type declarations.
Added
- MIT license.
- Documentation for hiding Google Translate's branding with global CSS.
1.0.0 - 2025-11-30
Added
- Initial release.
useGoogleTranslatecomposable.GoogleTranslateWidgetcomponent (floating button + searchable modal).GoogleTranslateButtoncomponent (dropdown) with alanguageChangedevent.- 109 languages with native names and flags.
- TypeScript definitions.