vite-pwa / nuxt

Zero-config PWA Plugin for Nuxt 3
https://vite-pwa-org.netlify.app/frameworks/nuxt
MIT License
454 stars 22 forks source link

How to handle i18n ? #142

Open ziadsarour opened 5 months ago

ziadsarour commented 5 months ago

Hi and thank you for this plugin !

I have an i18n website using @nuxtjs/i18n with a dropdown to switch locale. It's working fine on my website Inside my PWA, if I switch the locale manually and navigate through the app, it's working great. But whenever I close the app, I'm falling back to the default locale.

Here is my nuxt.config.ts

  i18n: {
    baseUrl: process.env.WEBSITE_URL,
    strategy: 'prefix_and_default',
    customRoutes: 'config',
    trailingSlash: false,
    lazy: true,
    skipSettingLocaleOnNavigate: false,
    debug: false,
    detectBrowserLanguage: {
      useCookie: true,
      cookieKey: 'swany.i18n',
      redirectOn: 'root',
    },
  },
  pwa: {
    strategies: 'generateSW',
    registerType: 'autoUpdate',
    devOptions: {
      enabled: mode !== 'production',
      type: 'module',
      navigateFallback: '/',
      suppressWarnings: true,
    },
    workbox: {
      navigateFallback: '/',
    },
    pwaAssets: {
      disabled: false,
      config: true,
    },
    manifest: {
      lang: 'en',
      name: 'name',
      short_name: 'name',
      description: 'description',
      id: '/blog',
      start_url: '/blog',
      scope: '/',
      display: 'standalone',
      orientation: 'portrait',
      background_color: '#FFF',
      theme_color: '#FFF',
      prefer_related_applications: true,
    },
  },

It think it's because start_url is pointing to the default locale, so I will always be opening my PWA using the default locale. I've seen someone suggesting localized webmanifests generation https://github.com/vite-pwa/nuxt/issues/52, would be great but once the PWA is installed it will not be possible to switch the locale because start_url is static.

I am thinking about checking at startup if I'm inside the PWA, if yes, redirect to the correct localized route using useI18n().locale.

But :

  1. I don't know how to check if I'm inside a PWA
  2. I'm not sure if the useI18n().locale will be set to the default locale before my check because of skipSettingLocaleOnNavigate: false

My questions :

  1. Should I use $pwa.isPWAInstalled or it is just a flag to know if I have the PWA installed on my device ?
  2. If useI18n().locale is not correct I will have to persist the user locale manually, how can I do this with a PWA ?
ziadsarour commented 5 months ago

After reviewing the code, I know $pwa.isPWAInstalled means "I'm inside a PWA" based on https://github.com/vite-pwa/nuxt/blob/106977993291d2443d52569b335f78e8a03e0a69/src/runtime/plugins/pwa.client.ts#L18-L29


I also have a local module which generate manifests based on the one generated by this plugin :

This local module is specific to my website but here is a snippet you could be inspired of :

...
  const directory = path.join(__dirname, '..', '.output', 'public');
  const baseManifest = getBaseManifest({ directory });

  for (const locale of locales) {
    saveManifest({
      directory,
      locale: locale.code,
      manifest: {
        ...baseManifest,
        description: t.description[locale.code] || baseManifest.description,
        start_url: locale.url,
      },
    });
  }
...

function getBaseManifest(options: {
  directory: string;
}) {
  const filepath = path.join(options.directory, 'manifest.webmanifest');
  const file = fs.readFileSync(filepath, { encoding: 'utf-8' });

  if (!file) {
    throw `module webmanifests: missing base manifest file`;
  }

  return JSON.parse(file);
}

function saveManifest(options: {
  directory: string;
  locale: RegionLocale['code'];
  manifest: any;
}) {
  const filepath = path.join(options.directory, options.locale, 'manifest.webmanifest');
  fs.writeFileSync(filepath, JSON.stringify(options.manifest), { encoding: 'utf-8' });
}

Be sure to remove your / and to manually set the correct head href manifest based on the user locale.


I now need to resolve 2.