i18n icon indicating copy to clipboard operation
i18n copied to clipboard

Allow modules to modify route localization

Open icai opened this issue 6 months ago • 2 comments

Environment

  • Nuxt: ^3.x
  • @nuxtjs/i18n: ^9.x
  • Package manager: pnpm
  • Node: >=18
  • OS: macOS

Reproduction

🧩 What I'm trying to do

I want to dynamically disable translation for some pages, such as /admin or any route matching a certain pattern, by injecting into the i18n.pages config like this:

i18n: {
  customRoutes: 'config',
  pages: {
    'admin': false
  }
}

But I want to do this dynamically from another Nuxt module, based on logic like:

  • Whether route path starts with /admin
  • Whether the file name includes certain keywords
  • Optional user-defined exclude rule function

📌 Problem

The pages:extend hook gives access to all generated Nuxt pages, and I can detect which pages I want to exclude, then inject:

nuxt.options.i18n.pages = {
  ...nuxt.options.i18n.pages,
  ...detectedPagesToExclude
}

However, @nuxtjs/i18n appears to snapshot the config too early, likely before pages:extend runs, and generates i18n-options.mjs using an internal ctx.options, so my dynamic changes to nuxt.options.i18n.pages do not reflect in the generated options.


Describe the bug

❓Question

Is there an official or recommended way to dynamically inject/disable page translation settings (customRoutes: 'config' + pages) at runtime or module time?

More specifically:

  • Can you expose a Nuxt hook like i18n:extendPagesConfig(pages) before generating i18n-options.mjs?
  • Or is there a safe way to hook into ctx.options.pages in a custom module?
  • Or should we write a wrapper module that overrides the i18n module setup?

🧪 What I tried

nuxt.hook('pages:extend', pages => {
  for (const page of pages) {
    if (page.path.startsWith('/admin') && page.name) {
      nuxt.options.i18n.pages[page.name] = false
    }
  }
})

But this doesn't reflect in the generated .nuxt/i18n-options.mjs file.


🙏 Feature request?

Could you consider adding a hook like:

nuxt.hook('i18n:extendPagesConfig', (pages: NuxtPage[], currentConfig: Record<string, any>) => {
  // modify and return updated pages config
})

So that other modules (like i18n-exclude) can safely hook in and modify translation strategy for specific routes?


Let me know if there's already a supported way to do this.

Thanks a lot for the amazing work on @nuxtjs/i18n 🙌

Additional context

No response

Logs


icai avatar Jul 03 '25 16:07 icai

However, @nuxtjs/i18n appears to snapshot the config too early, likely before pages:extend runs, and generates i18n-options.mjs using an internal ctx.options, so my dynamic changes to nuxt.options.i18n.pages do not reflect in the generated options.

This is expected behavior since the configurations provided by all layers (inline + keyed) are merged at module setup, modifying i18n options after that will have no effect. The intended use of pages:extend or pages:resolved hooks are to modify pages through its argument so modifying nuxt options there would be unexpected.

Could you consider adding a hook

Providing a build-time hook to modify the custom routing configuration is something we might consider but I feel this may complicate configuration for end-users if a module decides to overwrite their config (it would be especially opaque if they use customRoutes: 'pages').

In v10 we support an additional custom route configuration method via route meta, I think it should be possible to directly set the route meta in the pages: hooks which should allow you to achieve the same thing.

Is there an official or recommended way to dynamically inject/disable page translation settings (customRoutes: 'config' + pages) at runtime or module time?

For customRoutes: 'config' I recommend using a layer to provide configuration so that options are merged and overwritten in a predictable way. For customRoutes: 'pages' there is no straightforward way to change user provided custom routes, but in the future this will likely be removed and replaced by the already mentioned customRoutes: 'meta' introduced in v10.

BobbieGoede avatar Jul 03 '25 17:07 BobbieGoede

@BobbieGoede
Does this mean I switch to v10, then I can use

nuxt.hook('pages:extend', (pages) => {
  for (const page of pages) {
    if (page.path.startsWith('/admin')) {
      page.meta = page.meta || {}
      page.meta.i18n = false // close i18n
    }
  }
})

Whether the configuration is customRoutes: 'pages' or customRoutes: 'config'

icai avatar Jul 03 '25 20:07 icai