Repository: digitalocean/nginxconfig.io
File: src/nginxconfig/templates/app.vue (Vue)

Code before:

                // Set that we're waiting for changes to stop
                this.$data.confWatcherWaiting = true;
                this.$data.confFilesPrevious = oldConf;

                // Check next tick to see if anything has changed again
                this.$nextTick(() => this.checkChange(newConf));
            },
            '$data.global.app.lang': {
                handler(data) {
                    // Ensure valid pack
                    if (!(data.value in i18nPacks)) data.computed = data.default;

                    // Update the locale
                    this.$i18n.locale = data.computed;
                },
                deep: true,
            },
        },
        mounted() {
            // Import any data from the URL query params, defaulting to one domain
            // Fallback to the window hash if no search query params, from the Angular version of nginxconfig
            // The config file watcher will handle setting the app as ready
            const query = window.location.search || window.location.hash.slice(1);
            // Adaptive system language,The system language is not read after the language is set
            if (!query.includes('global.app.lang') && typeof navigator !== undefined){
                if (typeof navigator.language === 'string'){
                    let lang = navigator.language.match(/(\w+)/g).map(function(value){
                        return value.toUpperCase();
                    });
                    lang[0] = lang[0].toLowerCase();
                    lang = lang.join('');
                    if (lang in i18nPacks){
                        this.$data.global.app.lang.value = lang;
                        this.$data.global.app.lang.computed = lang;
                    }
                }
            }
            importData(query, this.$data.domains, this.$data.global, this.$nextTick);

            // Send an initial GA event for column mode
            this.splitColumnEvent(true);
        },
        methods: {
            changes(index) {
                const data = this.$data.domains[index];
                const changes = Object.entries(data).reduce((prev, current) => {
                    if (current[0] === 'presets') return prev; // Ignore changes from presets
                    if (!isObject(current[1])) return prev; // Ignore non-objects (things that aren't tabs)
                    prev += Object.keys(current[1]).filter(key => isChanged(current[1][key], current[0], key)).length;
                    return prev;

Review comment (suggestion):
```suggestion
            if (!query.includes('global.app.lang') && typeof window === 'object' && typeof window.navigator === 'object'){
```
We should use window instead of relying on things being global

Code after:
                // Set that we're waiting for changes to stop
                this.$data.confWatcherWaiting = true;
                this.$data.confFilesPrevious = oldConf;

                // Check next tick to see if anything has changed again
                this.$nextTick(() => this.checkChange(newConf));
            },
            '$data.global.app.lang': {
                handler(data) {
                    // Ensure valid pack
                    if (!(data.value in i18nPacks)) data.computed = 'en';

                    // Update the locale
                    this.$i18n.locale = data.computed;
                },
                deep: true,
            },
        },
        mounted() {
            // Import any data from the URL query params, defaulting to one domain
            // Fallback to the window hash if no search query params, from the Angular version of nginxconfig
            // The config file watcher will handle setting the app as ready
            const query = window.location.search || window.location.hash.slice(1);
            // Set language based on browser preferences
            if (!query.includes('global.app.lang') && typeof window === 'object' && typeof window.navigator === 'object'){
                const rawLangs = new Set();

                // Get the user language
                if (Array.isArray(window.navigator.languages))
                    window.navigator.languages.forEach(lang => rawLangs.add(lang));
                if (typeof window.navigator.language === 'string')
                    rawLangs.add(window.navigator.language);
                if (Intl && 'DateTimeFormat' in Intl)
                    rawLangs.add(Intl.DateTimeFormat().resolvedOptions().locale);

                const toPack = lang => lang.split('-')[0].toLowerCase() + lang.split('-').slice(1).map(x => x.toUpperCase()).join('-');

                // Get the support language
                const i18nPackLangs = Object.keys(i18nPacks);

                // Try to get an exact region match, or fallback to language match
                const exactMatch = [...rawLangs.values()].find(x => i18nPackLangs.includes(toPack(x)));
                const langMatch = [...rawLangs.values()].find(x => i18nPackLangs.includes(x.split('-')[0].toLowerCase())).split('-')[0].toLowerCase();

                if (exactMatch || langMatch) {
                    this.$data.global.app.lang.value = toPack(exactMatch) || langMatch.split('-')[0].toLowerCase();
                    this.$data.global.app.lang.computed = toPack(exactMatch) || langMatch.split('-')[0].toLowerCase();
                }
            }
            importData(query, this.$data.domains, this.$data.global, this.$nextTick);