-
Notifications
You must be signed in to change notification settings - Fork 0
TMS-1237: Add a custom Google Translate functionality to navigation #560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
eebbi
wants to merge
13
commits into
master
Choose a base branch
from
TMS-1237
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
752897c
TMS-1237: Add a custom Google Translate functionality to navigation
eebbi 87fb96c
TMS-1237: Add notranslate to lang nav
eebbi 2df7420
TMS-1237: Add cookie check for translate menu
eebbi 8c5ae31
TMS-1237: Add strings
eebbi 53fde94
TMS-1237: Minor changes to the js file
eebbi ac661cf
TMS-1237: Add cookiebot category to google translate script
eebbi 767cfc6
TMS-1237: Update js to prevent script loads before cookies are accepted
eebbi 8253067
TMS-1237: Add missing jsdoc description
eebbi 31c5e23
TMS-1237: Small change to js code
eebbi 2c4f881
TMS-1237: Allow dropdown to open without cookies
eebbi 0533cf7
TMS-1237: Changes to dropdowns text visibility logic
eebbi 1c4599a
TMS-1237: Change textx
eebbi 23c905d
TMS-1237: Small fixes
eebbi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,285 @@ | ||
| /** | ||
| * Google Translate Dropdown JS controller. | ||
| */ | ||
|
|
||
| // Use jQuery as $ within this file scope. | ||
| const $ = jQuery; | ||
|
|
||
| /** | ||
| * Class GtranslateDropdown | ||
| */ | ||
| export default class GtranslateDropdown { | ||
|
|
||
| constructor() { | ||
| this.isGoogleLoaded = false; | ||
| this.eventsAttached = false; | ||
| this.gtranslateCheckRetries = 0; | ||
| this.gtranslateCheckMaxRetries = 3; | ||
| this.gtranslateCheckDelay = 1500; | ||
| this.cookiebotEventsBound = false; | ||
| } | ||
|
|
||
| /** | ||
| * Check if Cookiebot consent allows loading Google Translate | ||
| * | ||
| * @return {boolean} True when consent permits loading Google Translate. | ||
| */ | ||
| hasConsentForGtranslate() { | ||
| if ( typeof window.Cookiebot === 'undefined' ) { | ||
| return true; | ||
| } | ||
|
|
||
| if ( ! window.Cookiebot.consent ) { | ||
| return false; | ||
| } | ||
|
|
||
| return Boolean( window.Cookiebot.consent.preferences ); | ||
| } | ||
|
|
||
| /** | ||
| * Toggle gtranslate text visibility | ||
| * | ||
| * @param {boolean} isVisible - Show or hide non-cookie paragraphs | ||
| * @return {void} | ||
| */ | ||
| setDropdownVisibility( isVisible ) { | ||
| const $dropdownContent = $( '.gtranslate-dropdown__content' ); | ||
| const $cookieTextContainer = $( '.gtranslate-cookie-text-container' ); | ||
|
|
||
| if ( ! $dropdownContent.length ) { | ||
| return; | ||
| } | ||
|
|
||
| const paragraphs = $dropdownContent.find( 'p:not(.gtranslate-cookie-text)' ); | ||
|
|
||
| if ( isVisible ) { | ||
| paragraphs.removeClass( 'is-hidden' ); | ||
| $cookieTextContainer.addClass( 'is-hidden' ); | ||
| } | ||
| else { | ||
| paragraphs.addClass( 'is-hidden' ); | ||
| $cookieTextContainer.removeClass( 'is-hidden' ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Attach dropdown event handlers once | ||
| * | ||
| * @return {void} | ||
| */ | ||
| attachEventsIfNeeded() { | ||
| if ( this.eventsAttached || ! $( '.gtranslate-trigger' ).length ) { | ||
| return; | ||
| } | ||
|
|
||
| // Handle gtranslate dropdown toggle | ||
| $( '.gtranslate-trigger' ).on( 'click', this.toggleGtranslateDropdown.bind( this ) ); | ||
|
|
||
| // Close gtranslate dropdown when clicking outside | ||
| $( document ).on( 'click', this.closeGtranslateOnOutsideClick.bind( this ) ); | ||
|
|
||
| // Handle ESC key | ||
| $( document ).on( 'keydown', this.handleEscKey.bind( this ) ); | ||
|
|
||
| this.eventsAttached = true; | ||
| } | ||
|
|
||
| /** | ||
| * Handle consent-dependent loading and visibility | ||
| * | ||
| * @return {void} | ||
| */ | ||
| handleConsentFlow() { | ||
| const hasConsent = this.hasConsentForGtranslate(); | ||
|
|
||
| this.attachEventsIfNeeded(); | ||
| this.setDropdownVisibility( hasConsent ); | ||
|
|
||
| if ( ! hasConsent ) { | ||
| return; | ||
| } | ||
|
|
||
| this.loadGoogleTranslateAPI(); | ||
| } | ||
|
|
||
| /** | ||
| * Bind Cookiebot consent events once | ||
| * | ||
| * @return {void} | ||
| */ | ||
| bindCookiebotEvents() { | ||
| if ( this.cookiebotEventsBound ) { | ||
| return; | ||
| } | ||
|
|
||
| window.addEventListener( 'CookiebotOnConsentReady', this.handleConsentFlow.bind( this ) ); | ||
| window.addEventListener( 'CookiebotOnAccept', this.handleConsentFlow.bind( this ) ); | ||
| window.addEventListener( 'CookiebotOnDecline', this.handleConsentFlow.bind( this ) ); | ||
|
|
||
| this.cookiebotEventsBound = true; | ||
| } | ||
|
|
||
| /** | ||
| * Toggle gtranslate dropdown | ||
| * | ||
| * @param {Event} event - Click event | ||
| * @return {void} | ||
| */ | ||
| toggleGtranslateDropdown( event ) { | ||
| event.preventDefault(); | ||
| const $dropdown = $( '#js-gtranslate-dropdown' ); | ||
| const $trigger = $( event.currentTarget ); | ||
|
|
||
| if ( $dropdown.hasClass( 'is-hidden' ) ) { | ||
| $dropdown.removeClass( 'is-hidden' ); | ||
| $trigger.attr( 'aria-expanded', 'true' ); | ||
| } | ||
| else { | ||
| $dropdown.addClass( 'is-hidden' ); | ||
| $trigger.attr( 'aria-expanded', 'false' ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Close gtranslate dropdown when clicking outside | ||
| * | ||
| * @param {Event} event - Click event | ||
| * @return {void} | ||
| */ | ||
| closeGtranslateOnOutsideClick( event ) { | ||
| const $dropdown = $( '#js-gtranslate-dropdown' ); | ||
| const $wrapper = $( '.gtranslate-wrapper' ); | ||
|
|
||
| if ( ! $dropdown.hasClass( 'is-hidden' ) | ||
| && ! $wrapper.is( event.target ) | ||
| && $wrapper.has( event.target ).length === 0 ) { | ||
| $dropdown.addClass( 'is-hidden' ); | ||
| $( '.gtranslate-trigger' ).attr( 'aria-expanded', 'false' ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Handle ESC key to close dropdown | ||
| * | ||
| * @param {Event} event - Keydown event | ||
| * @return {void} | ||
| */ | ||
| handleEscKey( event ) { | ||
| if ( event.key === 'Escape' || event.keyCode === 27 ) { | ||
| const $dropdown = $( '#js-gtranslate-dropdown' ); | ||
| if ( ! $dropdown.hasClass( 'is-hidden' ) ) { | ||
| $dropdown.addClass( 'is-hidden' ); | ||
| $( '.gtranslate-trigger' ).attr( 'aria-expanded', 'false' ).focus(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Load Google Translate API | ||
| * | ||
| * @return {void} | ||
| */ | ||
| loadGoogleTranslateAPI() { | ||
| if ( this.isGoogleLoaded || document.querySelector( 'script[src*="translate.google.com"]' ) ) { | ||
| return; | ||
| } | ||
|
|
||
| const script = document.createElement( 'script' ); | ||
| script.src = 'https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit'; | ||
| script.setAttribute( 'data-cookieconsent', 'preferences' ); | ||
| script.async = true; | ||
| document.head.appendChild( script ); | ||
| this.isGoogleLoaded = true; | ||
|
|
||
| // Define the callback function globally | ||
| window.googleTranslateElementInit = this.initGoogleTranslate.bind( this ); | ||
|
|
||
| // Check if the script loaded successfully after a short delay | ||
| setTimeout( () => { | ||
| this.checkGoogleTranslateLoaded(); | ||
| }, this.gtranslateCheckDelay ); | ||
| } | ||
|
|
||
| /** | ||
| * Initialize Google Translate | ||
| * | ||
| * @return {void} | ||
| */ | ||
| initGoogleTranslate() { | ||
| const container = document.getElementById( 'google_translate_element_custom' ); | ||
|
|
||
| // eslint-disable-next-line no-undef | ||
| if ( ! container || typeof google === 'undefined' || ! google.translate ) { | ||
| return; | ||
| } | ||
|
|
||
| // Get current language from data attribute or default to 'fi' | ||
| const currentLang = container.dataset.lang || 'fi'; | ||
|
|
||
| // eslint-disable-next-line no-undef | ||
| new google.translate.TranslateElement( { | ||
| pageLanguage: currentLang, | ||
| autoDisplay: false, | ||
| }, 'google_translate_element_custom' ); | ||
| } | ||
|
|
||
| /** | ||
| * Check if Google Translate loaded successfully, show cookie message if not | ||
| * | ||
| * @return {void} | ||
| */ | ||
| checkGoogleTranslateLoaded() { | ||
| const container = document.getElementById( 'google_translate_element_custom' ); | ||
|
|
||
| if ( container ) { | ||
| // Check if the container has been populated with Google Translate content | ||
| const hasGoogleContent = container.children.length > 0; | ||
|
|
||
| if ( ! hasGoogleContent && this.gtranslateCheckRetries < this.gtranslateCheckMaxRetries ) { | ||
| this.gtranslateCheckRetries += 1; | ||
| setTimeout( () => { | ||
| this.checkGoogleTranslateLoaded(); | ||
| }, this.gtranslateCheckDelay ); | ||
| return; | ||
| } | ||
|
|
||
| // If no Google Translate content, show cookie disabled message and hide other elements | ||
| if ( ! hasGoogleContent ) { | ||
| // Show the cookie message container | ||
| const cookieTextContainer = document.querySelector( '.gtranslate-cookie-text-container' ); | ||
| if ( cookieTextContainer ) { | ||
| cookieTextContainer.classList.remove( 'is-hidden' ); | ||
| } | ||
|
|
||
| // Hide other paragraph elements in the dropdown | ||
| const dropdownContent = document.querySelector( '.gtranslate-dropdown__content' ); | ||
| if ( dropdownContent ) { | ||
| const paragraphs = dropdownContent.querySelectorAll( 'p:not(.gtranslate-cookie-text)' ); | ||
| paragraphs.forEach( ( p ) => { | ||
| p.classList.add( 'is-hidden' ); | ||
| } ); | ||
| } | ||
| } | ||
| else { | ||
| const cookieTextContainer = document.querySelector( '.gtranslate-cookie-text-container' ); | ||
| if ( cookieTextContainer ) { | ||
| cookieTextContainer.classList.add( 'is-hidden' ); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Run when the document is ready. | ||
| * | ||
| * @return {void} | ||
| */ | ||
| docReady() { | ||
| if ( ! $( '#google_translate_element_custom' ).length ) { | ||
| return; | ||
| } | ||
|
|
||
| this.bindCookiebotEvents(); | ||
| this.handleConsentFlow(); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
assets/styles/ui-components/header/_gtranslate-dropdown.scss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| .gtranslate-wrapper { | ||
| .gtranslate-trigger { | ||
| border: none; | ||
| background-color: transparent; | ||
| width: 2.375rem; | ||
| height: 2.375rem; | ||
| border: 2px solid transparent; | ||
|
|
||
| &:hover { | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| &:hover, | ||
| &:focus { | ||
| border-color: $lang-nav-link-border; | ||
| } | ||
|
|
||
| @include from($tablet) { | ||
| width: 2.2359rem; | ||
| height: 2.2359rem; | ||
| } | ||
| } | ||
|
|
||
| .gtranslate-dropdown { | ||
| background-color: $color-vaalean-harmaa; | ||
| right: 0; | ||
| z-index: 1; | ||
|
|
||
| .is-small { | ||
| font-size: 11px; | ||
| } | ||
|
|
||
| .gtranslate-cookie-text-container { | ||
| width: 15rem; | ||
|
|
||
| @include from($tablet) { | ||
| width: 20rem; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| .gtranslate-wrapper, | ||
| .skiptranslate { | ||
| color: $black !important; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Google Translate callback (
window.googleTranslateElementInit) is assigned after the script tag is appended. Because the API script calls thecb=function as soon as it executes, there’s a race where the callback may be undefined. Define the global callback before appending the script (or setscript.onloadand initialize from there).