Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions lib/patch-dom-translate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* global Node */

let translateActive = false

function detectDOMTranslate () {
const html = document.documentElement
if (!html) return false

// classes used by DOM translators
if (html.classList.contains('translated-ltr')) return true
if (html.classList.contains('translated-rtl')) return true
if (html.classList.contains('translated')) return true
Comment on lines +9 to +12
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

*only Chromium-based DOM translations, needs to be tested on Safari and Firefox.


return false
}

/**
* workaround for DOM translators, facebook/react#11538
* browser translation engines wrap text nodes in <font> tags,
* which desyncs React's reconciler from the real DOM and throws
* `NotFoundError` on `removeChild` and `insertBefore`
*
* We only suppress these errors while a DOM translator is active
*/
export function patchDOMTranslations () {
if (typeof Node === 'undefined' || typeof window === 'undefined') return
if (Node.prototype.__patchedDOMTranslations) return

Node.prototype.__patchedDOMTranslations = true

const originalRemoveChild = Node.prototype.removeChild
const originalInsertBefore = Node.prototype.insertBefore

Node.prototype.removeChild = function (child) {
if (child && child.parentNode !== this) {
if (translateActive) {
return child
}
}
return originalRemoveChild.call(this, child)
}

Node.prototype.insertBefore = function (newNode, referenceNode) {
if (referenceNode && referenceNode.parentNode !== this) {
if (translateActive) {
// append so the node still ends up under the expected parent, React will correct on the next render
return this.appendChild(newNode)
}
}
return originalInsertBefore.call(this, newNode, referenceNode)
}
Comment on lines +43 to +51
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We could technically fallback to appendChild here instead of creating phantom DOM nodes.

Comment thread
cursor[bot] marked this conversation as resolved.

const update = () => { translateActive = detectDOMTranslate() }
update()

const observer = new window.MutationObserver(update)
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class', 'lang']
})
}
3 changes: 3 additions & 0 deletions pages/_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ import { DomainProvider } from '@/components/territory-domains'
import { WalletsProvider } from '@/wallets/client/hooks'
import FaviconProvider from '@/components/favicon'
import { CookiesProvider } from '@/components/use-cookie'
import { patchDOMTranslations } from '@/lib/patch-dom-translate'

const PWAPrompt = dynamic(() => import('react-ios-pwa-prompt'), { ssr: false })

patchDOMTranslations()

NProgress.configure({
showSpinner: false
})
Expand Down
Loading