Custom language for calendar block

If you need to show the calendar content block in your native language you can try this code;

  1. Add to your page custom code
  2. Change the ‘calendarBlockId’ with your own
  3. Target your desired browser language to run the translation script. In this sample target language is : “es-”
  4. Script is not yet perfect, but it can get you started.
  5. If you experience trouble with calendar misconfiguration, clear your site cache session and start over.
<script>
document.addEventListener("DOMContentLoaded", function () {

    const userLocale = navigator.languages && navigator.languages.length
    ? navigator.languages[0]
    : navigator.language;

    const dictionary = {
    "\\bJanuary\\b": "Enero",
    "\\bFebruary\\b": "Febrero",
    "\\bMarch\\b": "Marzo",
    "\\bApril\\b": "Abril",
    "\\bMay\\b": "Mayo",
    "\\bJune\\b": "Junio",
    "\\bJuly\\b": "Julio",
    "\\bAugust\\b": "Agosto",
    "\\bSeptember\\b": "Septiembre",
    "\\bOctober\\b": "Octubre",
    "\\bNovember\\b": "Noviembre",
    "\\bDecember\\b": "Diciembre",
    "Today": "Hoy",
    "Month":"Mensual",
    "Week": "Semanal",
    "Day": "Diario",
    "\\bMon\\b": "Lun",
    "\\bTue\\b": "Mar",
    "\\bWed\\b": "Mie",
    "\\bThu\\b": "Jue",
    "\\bFri\\b": "Vie",
    "\\bSat\\b": "Sab",
    "\\bSun\\b": "Dom"
    };

    const ids = ['calendarBlockId1', 'calendarBlockId12', 'calendarBlockId3'];

    const translateContent = function(element) {
        Array.from(element.childNodes).forEach(function(childElement) {
            if (childElement.nodeType === 3) {
               var newWords = childElement.nodeValue;

               for(const word in dictionary) {
                  const regex = new RegExp(word, "g")
                  newWords = newWords.replace(regex, dictionary[word]);
               }

               childElement.nodeValue = newWords;
           } else if (childElement.nodeType === 1) {
               translateContent(childElement);
           }
        });
    };

    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'childList') {
                translateContent(mutation.target);
            }
        });
    });

    if(userLocale.toLocaleLowerCase().startsWith("es-")) {
        setTimeout(function() {
            ids.forEach(function(id) {
               
                const element = document.getElementById(id);
                if (element) {
                    translateContent(element);

                    // Begin observing the changes to the targeted element
                    observer.observe(element, {attributes: false, childList: true, subtree: true, characterData: true});
                    
                }
            });
        }, 2000);
    }
});
</script>

calendar

3 Likes

Hello,

I try to use your script on my calendar block.
I can’t get it to work

Check for this condition on the script, and adjust it to your language, here is defined for browsers in Spanish ‘es-’ So the script will only play when browsing in Spanish.

J’ai modifié par “es-” par “fr-”.

Voici le script :

<script>
document.addEventListener("DOMContentLoaded", function () {

    const userLocale = navigator.languages && navigator.languages.length
    ? navigator.languages[0]
    : navigator.language;

    const dictionary = {
    "\\bJanuary\\b": "Janvier",
    "\\bFebruary\\b": "Février",
    "\\bMarch\\b": "Mars",
    "\\bApril\\b": "Avril",
    "\\bMay\\b": "MAi",
    "\\bJune\\b": "Juin",
    "\\bJuly\\b": "Juillet",
    "\\bAugust\\b": "Août",
    "\\bSeptember\\b": "Septembre",
    "\\bOctober\\b": "Octobre",
    "\\bNovember\\b": "Novembre",
    "\\bDecember\\b": "Décembre",
    "Today": "Aujourd'hui",
    "Month":"Mois",
    "Week": "Semaine",
    "Day": "Année",
    "\\bMon\\b": "Lun",
    "\\bTue\\b": "Mar",
    "\\bWed\\b": "Mer",
    "\\bThu\\b": "Jeu",
    "\\bFri\\b": "Ven",
    "\\bSat\\b": "Sam",
    "\\bSun\\b": "Dim"
    };

    const ids = ['calendarblockid1';

    const translateContent = function(element) {
        Array.from(element.childNodes).forEach(function(childElement) {
            if (childElement.nodeType === 3) {
               var newWords = childElement.nodeValue;

               for(const word in dictionary) {
                  const regex = new RegExp(word, "g")
                  newWords = newWords.replace(regex, dictionary[word]);
               }

               childElement.nodeValue = newWords;
           } else if (childElement.nodeType === 1) {
               translateContent(childElement);
           }
        });
    };

    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'childList') {
                translateContent(mutation.target);
            }
        });
    });

    if(userLocale.toLocaleLowerCase().startsWith("fr-")) {
        setTimeout(function() {
            ids.forEach(function(id) {
               
                const element = document.getElementById(id);
                if (element) {
                    translateContent(element);

                    // Begin observing the changes to the targeted element
                    observer.observe(element, {attributes: false, childList: true, subtree: true, characterData: true});
                    
                }
            });
        }, 2000);
    }
});
</script>```

It seems your const ids line lake of ]

must be

Thank you for your feedback.
The element should have been written as = const ids = [‘calendarblockid1’];

salut utiliser le même code mais cela ne fonctionne pas

<script>
document.addEventListener("DOMContentLoaded", function () {

    const userLocale = navigator.languages && navigator.languages.length
    ? navigator.languages[0]
    : navigator.language;

    const dictionary = {
    "\\bJanuary\\b": "Janvier",
    "\\bFebruary\\b": "Février",
    "\\bMarch\\b": "Mars",
    "\\bApril\\b": "Avril",
    "\\bMay\\b": "MAi",
    "\\bJune\\b": "Juin",
    "\\bJuly\\b": "Juillet",
    "\\bAugust\\b": "Août",
    "\\bSeptember\\b": "Septembre",
    "\\bOctober\\b": "Octobre",
    "\\bNovember\\b": "Novembre",
    "\\bDecember\\b": "Décembre",
    "Today": "Aujourd'hui",
    "Month":"Mois",
    "Week": "Semaine",
    "Day": "Année",
    "\\bMon\\b": "Lun",
    "\\bTue\\b": "Mar",
    "\\bWed\\b": "Mer",
    "\\bThu\\b": "Jeu",
    "\\bFri\\b": "Ven",
    "\\bSat\\b": "Sam",
    "\\bSun\\b": "Dim"
    };

    const ids = ['calendarblockid1'];

    const translateContent = function(element) {
        Array.from(element.childNodes).forEach(function(childElement) {
            if (childElement.nodeType === 3) {
               var newWords = childElement.nodeValue;

               for(const word in dictionary) {
                  const regex = new RegExp(word, "g")
                  newWords = newWords.replace(regex, dictionary[word]);
               }

               childElement.nodeValue = newWords;
           } else if (childElement.nodeType === 1) {
               translateContent(childElement);
           }
        });
    };

    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'childList') {
                translateContent(mutation.target);
            }
        });
    });

    if(userLocale.toLocaleLowerCase().startsWith("fr-")) {
        setTimeout(function() {
            ids.forEach(function(id) {
               
                const element = document.getElementById(id);
                if (element) {
                    translateContent(element);

                    // Begin observing the changes to the targeted element
                    observer.observe(element, {attributes: false, childList: true, subtree: true, characterData: true});
                    
                }
            });
        }, 2000);
    }
});
</script>```

Thank you for this script, works perfectly!

Since I always wanted to show the translations in Dutch language, I changed the script a bit and removed the conditional browser language check: see script below.

@acjnas one question though regarding the months translations: from what I understand only the current month is translated when this script loads - is that correct?

<script>
document.addEventListener("DOMContentLoaded", function () {
    const dictionary = {
    "\\bJanuary\\b": "Januari",
    "\\bFebruary\\b": "Februari",
    "\\bMarch\\b": "Maart",
    "\\bApril\\b": "April",
    "\\bMay\\b": "Mei",
    "\\bJune\\b": "Juni",
    "\\bJuly\\b": "Juli",
    "\\bAugust\\b": "Augustus",
    "\\bSeptember\\b": "September",
    "\\bOctober\\b": "October",
    "\\bNovember\\b": "November",
    "\\bDecember\\b": "December",
    "Today": "Vandaag",
    "Month":"Maand",
    "Week": "Week",
    "Day": "Dag",
    "\\bMon\\b": "Ma",
    "\\bTue\\b": "Di",
    "\\bWed\\b": "Woe",
    "\\bThu\\b": "Do",
    "\\bFri\\b": "Vr",
    "\\bSat\\b": "Za",
    "\\bSun\\b": "Zo"
    };
    const ids = ['calendar1'];
    const translateContent = function(element) {
        Array.from(element.childNodes).forEach(function(childElement) {
            if (childElement.nodeType === 3) {
               var newWords = childElement.nodeValue;
               for(const word in dictionary) {
                  const regex = new RegExp(word, "g")
                  newWords = newWords.replace(regex, dictionary[word]);
               }
               childElement.nodeValue = newWords;
           } else if (childElement.nodeType === 1) {
               translateContent(childElement);
           }
        });
    };
    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'childList') {
                translateContent(mutation.target);
            }
        });
    });
    
    // Deletes the conditional check browser session language
    setTimeout(function() {
        ids.forEach(function(id) {
           
            const element = document.getElementById(id);
            if (element) {
                translateContent(element);
                // Begin observing the changes to the targeted element
                observer.observe(element, {attributes: false, childList: true, subtree: true, characterData: true});
                
            }
        });
    }, 1000);
});
</script>
1 Like

Thanks for this Dutch version. I’ve adapted it to make it faster, more efficient and more versatile (with the help of chatGPT). You can now easily add other pages too, by adding their ID’s. Also I translated the 12 hour am/pm notation, since in the Netherlands we only use the 24 hour notation. Also changed some small spelling errors and translated the term “All day” too (be aware that “All day” needs to be translate before “Day” because otherwise “All day” would change into “All dag” which the script would then not be able to find)…

Regarding your question about only translating the current month: that’s happening to me also… seems to have to do with the script running only on the page that has already been loaded, not on the calendar parts that load after clicking the month-navigation arrows…
The same goes for the dropdown menu to choose Day/Week/Month…

Anyone have a solution for this?

document.addEventListener("DOMContentLoaded", function () {
    const dictionary = new Map([
        [/(\bJanuary\b)/g, "Januari"],
        [/(\bFebruary\b)/g, "Februari"],
        [/(\bMarch\b)/g, "Maart"],
        [/(\bApril\b)/g, "April"],
        [/(\bMay\b)/g, "Mei"],
        [/(\bJune\b)/g, "Juni"],
        [/(\bJuly\b)/g, "Juli"],
        [/(\bAugust\b)/g, "Augustus"],
        [/(\bSeptember\b)/g, "September"],
        [/(\bOctober\b)/g, "Oktober"],
        [/(\bNovember\b)/g, "November"],
        [/(\bDecember\b)/g, "December"],
        [/Today/g, "Vandaag"],
        [/Month/g, "Maand"],
        [/Week/g, "Week"],
        [/All Day/g, "Hele dag"],
        [/Day/g, "Dag"],
        [/\bMon\b/g, "Ma"],
        [/\bTue\b/g, "Di"],
        [/\bWed\b/g, "Wo"],
        [/\bThu\b/g, "Do"],
        [/\bFri\b/g, "Vr"],
        [/\bSat\b/g, "Za"],
        [/\bSun\b/g, "Zo"],
        [/\b(\d{1,2}) am\b/g, "$1:00"],
        [/\b12 pm\b/g, "12:00"],
        [/\b(\d{1,2}) pm\b/g, (match, p1) => `${parseInt(p1, 10) + 12}:00`]
    ]);

    const targetIds = ["calendar1", "calendar3"]; // Add calendar-ID's here

    function translateTextNodes(node) {
        const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
        let textNode;
        while ((textNode = walker.nextNode())) {
            let text = textNode.nodeValue;
            dictionary.forEach((replacement, regex) => {
                text = text.replace(regex, replacement);
            });
            textNode.nodeValue = text;
        }
    }

    function observeAndTranslate(id) {
        const target = document.getElementById(id);
        if (target) {
            translateTextNodes(target);
            new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            translateTextNodes(node);
                        } else if (node.nodeType === Node.TEXT_NODE) {
                            let text = node.nodeValue;
                            dictionary.forEach((replacement, regex) => {
                                text = text.replace(regex, replacement);
                            });
                            node.nodeValue = text;
                        }
                    });
                });
            }).observe(target, { childList: true, subtree: true });
        }
    }

    setTimeout(() => {
        targetIds.forEach(observeAndTranslate);
    }, 1000);
});
1 Like

I’ve found a solution to the not-translated months that load after clicking the navigation buttons! The corrected code:

<script>
document.addEventListener("DOMContentLoaded", function () {
    const dictionary = new Map([
        [/(\bJanuary\b)/g, "Januari"],
        [/(\bFebruary\b)/g, "Februari"],
        [/(\bMarch\b)/g, "Maart"],
        [/(\bApril\b)/g, "April"],
        [/(\bMay\b)/g, "Mei"],
        [/(\bJune\b)/g, "Juni"],
        [/(\bJuly\b)/g, "Juli"],
        [/(\bAugust\b)/g, "Augustus"],
        [/(\bSeptember\b)/g, "September"],
        [/(\bOctober\b)/g, "Oktober"],
        [/(\bNovember\b)/g, "November"],
        [/(\bDecember\b)/g, "December"],
        [/Today/g, "Vandaag"],
        [/Month/g, "Maand"],
        [/Week/g, "Week"],
        [/All Day/g, "Hele dag"],
        [/Day/g, "Dag"],
        [/\bMon\b/g, "Ma"],
        [/\bTue\b/g, "Di"],
        [/\bWed\b/g, "Wo"],
        [/\bThu\b/g, "Do"],
        [/\bFri\b/g, "Vr"],
        [/\bSat\b/g, "Za"],
        [/\bSun\b/g, "Zo"],
        [/\b(\d{1,2}) am\b/g, "$1:00"],
        [/\b12 pm\b/g, "12:00"],
        [/\b(\d{1,2}) pm\b/g, (match, p1) => `${parseInt(p1, 10) + 12}:00`],
        [/I agree to the/g, "Ik ga akkoord met de"],
        [/(\band\b)/g, "en"],
    ]);

    const targetIds = ["calendar1", "calendar3", "user-accounts3"]; // Voeg hier extra kalender-ID's toe

    function translateTextNodes(node) {
        const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
        let textNode;
        while ((textNode = walker.nextNode())) {
            let text = textNode.nodeValue;
            dictionary.forEach((replacement, regex) => {
                text = text.replace(regex, replacement);
            });
            textNode.nodeValue = text;
        }
    }

    function observeAndTranslate(id) {
        const target = document.getElementById(id);
        if (target) {
            translateTextNodes(target);
            // Polling: elke 500ms controleren of de maandnaam veranderd is
            setInterval(() => {
                translateTextNodes(target);
            }, 500);
        }
    }

    setTimeout(() => {
        targetIds.forEach(observeAndTranslate);
    }, 1000);
});
</script>

Furthermore, the Dutch word “Vandaag” takes more space than the English “Today”, so I added the the following ccs code in the footer section (just check if “.css-1er5o8w” is used in your code too…):

<style>
.css-1er5o8w {
    min-width: 90px !important;
}
</style>
1 Like

Thanks, works like a charm!

Via inspect>element I found that my css selector for ‘today’ was .css-arntqf, so that works now as well.

1 Like

I found out the a drawback of using the ccs-selector as reference: it changes (don’t know when or why). So it stops working…
Adjusted the code to be more dynamic:

<style>
.MuiButton-root.MuiButton-containedPrimary {
    min-width: 90px !important; /* adjust this to make sure the "Today"-button matches the translation in your language */
}
</style>
1 Like