xiCO2k / laravel-vue-i18n

Allows to connect your `Laravel` Framework translation files with `Vue`.
MIT License
606 stars 50 forks source link

Translations do not load if app is refreshed on certain pages #136

Closed chris-hud closed 1 year ago

chris-hud commented 1 year ago

I've gone through every existing issue and haven't been able to solve this yet. When my app initializes at certain pages, or is refreshed on certain pages, the translation files return as expected and everything works. However on some pages which I can't find any difference on, the translation files are not loaded.

I have attempted the config with SSR mode and with standard vite mode, as well as mounting the app after load as described here https://github.com/xiCO2k/laravel-vue-i18n/issues/93#issuecomment-1425683737

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {
        return createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(i18nVue, {
                resolve: async lang => {
                    const langs = import.meta.glob('../../lang/*.json');
                    return await langs[`../../lang/${lang}.json`]();
                }
            })
            ...
            ...
            ...
            .use(ZiggyVue, Ziggy)
            .mount(el);
    },
});

In looking in the chrome network tab, I can confirm that doing a refresh on the /profile page or the /leads page, the language file is not loaded, however doing the same refresh on the /messages or the /dashboard pages both will load the file. All of these pages are wrapped in the same layout. Once the file has been loaded on a page that loads it, all the pages work as expected unless a refresh is done on one of the other pages.

Any Ideas?

chris-hud commented 1 year ago

Still trying to work through this. if a user navigates to /login, everything works fine if they navigate to /register, it fails.

        resolve: async lang => {
                console.log('in resolve');
                const langs = import.meta.glob('../../lang/*.json');
                return await langs[`../../lang/${lang}.json`]();
            },

When I log this on login and register routes, it only prints on the login route. So this resolve for some reason is not always running.

chris-hud commented 1 year ago

If I install the plugin like this:

                .use(i18nVue, {       
                resolve: async lang => {
                    const langs = import.meta.glob('../../lang/*.json');
                    return await langs[`../../lang/${lang}.json`]();
                }
            })
            .use(ZiggyVue, Ziggy)
            .mount(el);

The login page works perfectly, but the register page loads with no translations.

If instead I mount the app in the onLoad of the plugin, like this:

            return app.use(i18nVue, {
                 resolve: async lang => {
                     const langs = import.meta.glob('../../lang/*.json');
                     return await langs[`../../lang/${lang}.json`]();
                 },
                onLoad: () => {
                    app.mount(el);
                }
            })

The login page still works perfectly, but now the register page does not render at all, and i see an error for Uncaught (in promise) TypeError: _ctx.$t is not a function

I notice that I get the same error if I comment out the app.use() of this plugin entirely. This is leading me to think that vue is not registering this plugin at all if the app is initialized on /register.

I'm not doing anything unique in my setup, very straightforward vite/inertia build as instructed in the inertia docs.

musiwei commented 1 year ago

I have the same issue. I'm using Laravel 10 Jetstream with Vite. If I press refresh on a page other than the homepage, all the translations are removed. @xiCO2k

I do not have any errors on the page.

xiCO2k commented 1 year ago

Hey I was unable to replicate that, its possible for you guys to set up a repo, where I can find that issue?

Thanks.

musiwei commented 1 year ago

I have provided a live url, and easy to copy/paste code in the end for you to repeat this issue.

First I would like to thank you for your help, and I need to correct my question above, I had a different issue which was page flickering. That has been fixed, but I run into a new issue on opening some URLs in a new tab, which returns the same error with Chris.

My dev environment:

I have made the below change to fix the flickering issue as mentioned and solved here:

Previous:

return app.use(i18nVue, {
                fallbackLang: 'cn',
                resolve: async lang => {
                    const langs = import.meta.glob('../../lang/*.json');
                    return await langs[`../../lang/${lang}.json`]();
                }
            }).mount(el);

Now (good!):

return app.use(i18nVue, {
                fallbackLang: 'cn',
                resolve: async lang => {
                    const langs = import.meta.glob('../../lang/*.json');
                    return await langs[`../../lang/${lang}.json`]();
                },
                onLoad: () => {
                    app.mount(el);
                }
            });

After I change the mount, it works fine for all the links I click on the page, but once you paste the URL other than homepage into browser, it shows: Uncaught (in promise) TypeError: _ctx.$t is not a function

image Note this does NOT happen for all the pages, but if it happens to one page, it happens all the time.

Here is my Vite setting (changing the order does not help):

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import i18n from 'laravel-vue-i18n/vite';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
        i18n(),
    ],
});

I find signed URL is easier to repeat the issue, which was originally where I found the issue, as you would always expect a signed URL to be opened directly in the browser. I provide two options for you to repeat the issue:

  1. go to a signed URL I created valid for 72 hours from now. Note this URL is 100% accessible if I click a link from my homepage to go to this URL, but it reports an error if opened in a new tab https://ipo-central.com.au/order/c1b1cacd-8fd5-4a1b-a5fc-a2d954ccd48a/self-serve/fill?expires=1689035945&signature=7299d88a880b5eed1ddb392cae3f8b6cea658dfc1073c79aa2c5bb7c5b0d7bb9&token=IaAfKCX4HZosexgygS29

  2. Simply:

    • paste it in routes/web.php,
    • go to /signed-url then copy the link into an incognito window:
Route::get('/signed-url', function () {
    $token = Str::random(20);
    $url = \Illuminate\Support\Facades\URL::temporarySignedRoute(
        'test', now()->addHours(2), ['token' => $token]
    );
    dd($url);
});

Route::get('/test', function () {
   // return to any of your front end component
})->name('test');

Related command at your disposal:

php artisan route:cache
musiwei commented 1 year ago

Hey Francis,

I found the solution and I think this may be helpful for you to patch it.

This should be beneficial to anyone who is suffering the same issue, too. @chris-hud I hope you see this too, brother.

Solution: do not use trans() in defineProps.

image

If you are curious how I end up setting the default value for label:

import { trans } from 'laravel-vue-i18n';

const getLabel = () => {
    if(props.label) {
        return trans(props.label)
    } else {
        return trans('FileUploadWidget.Files')
    }
}
xiCO2k commented 1 year ago

Yes that I don't think will work, but if you do like:

defineProps({
    label: {
        type: String,
        default: () => trans('FileUploadWidget.Files'),
    }
});

I think this should work, let me know.