npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@i18n-micro/path-strategy

v1.3.0

Published

Shared strategy-based path and route name builder for Nuxt I18n Micro frontend routing.

Downloads

5,201

Readme

@i18n-micro/path-strategy

Runtime path and route strategies for Nuxt I18n Micro: locale resolution from URL, link generation, redirects, and SEO helpers. Use this package when you need a single routing strategy at build time so only the chosen implementation is bundled.


Overview

  • Strategies: no_prefix, prefix, prefix_except_default, prefix_and_default
  • API: resolveLocaleFromPath, getLocaleFromPath, localeRoute, switchLocaleRoute, getRedirect, getClientRedirect, shouldReturn404, getCanonicalPath, getRouteBaseName, getCurrentLocale, getPluginRouteName, formatPathForResolve
  • Framework-agnostic: Works with any router that implements the RouterAdapter interface (hasRoute, resolve); compatible with Vue Router and custom adapters.
  • Tree-shakeable: Subpath exports (/prefix, /no-prefix, etc.) let the bundler include only the selected strategy.

Package structure

| Path | Contents | |------|----------| | src/types.ts | All type definitions (PathStrategyContext, RouteLike, ResolvedRouteLike, RouterAdapter, PathStrategy, etc.) | | src/path.ts | Path utilities (normalizePath, joinUrl, buildUrl, getPathWithoutLocale, getLocaleFromPath, hasKeys, etc.) | | src/resolver.ts | Route analysis and resolution (analyzeRoute, getRouteBaseName, buildLocalizedName, isIndexRouteName, resolveCustomPath, etc.) | | src/helpers.ts | Strategy-agnostic helpers (shouldReturn404, preserveQueryAndHash, tryResolveByLocalizedName, etc.) | | src/strategies/ | BasePathStrategy, createPathStrategy factory, and strategy implementations: no-prefix, prefix, prefix-except-default, prefix-and-default | | src/strategies/common.ts | Shared strategy logic (defaultResolveLocaleRoute) |


Installation

pnpm add @i18n-micro/path-strategy @i18n-micro/types

Peer dependency: @i18n-micro/types.


Setup: Using a single strategy via Nuxt alias (build-time)

To ship only the selected strategy (no factory, no other implementations), wire a Nuxt alias at build time.

1. Configure the Nuxt module

In your Nuxt module's setup() (or in nuxt.config), set the alias to the strategy entry you want:

// src/module.ts (or nuxt.config.ts)

import type { Strategies } from '@i18n-micro/types'

const strategyEntries: Record<Strategies, string> = {
  no_prefix: '@i18n-micro/path-strategy/no-prefix',
  prefix: '@i18n-micro/path-strategy/prefix',
  prefix_except_default: '@i18n-micro/path-strategy/prefix-except-default',
  prefix_and_default: '@i18n-micro/path-strategy/prefix-and-default',
}

const selectedStrategy = strategyEntries[options.strategy] ?? strategyEntries.prefix_except_default

nuxt.options.alias['#i18n-strategy'] = selectedStrategy

2. Type declarations for #i18n-strategy

So that TypeScript and your IDE understand the alias, add a generated declaration in prepare:types:

import { resolve } from 'node:path'

nuxt.hook('prepare:types', ({ references }) => {
  nuxt.addTemplate({
    filename: 'i18n-strategy.d.ts',
    getContents: () => `
      import { BasePathStrategy } from '@i18n-micro/path-strategy'
      export class Strategy extends BasePathStrategy {}
    `,
  })
  references.push({ path: resolve(nuxt.options.buildDir, 'i18n-strategy.d.ts') })
})

If your setup already resolves types for this alias, you can skip this step.

3. Use in a plugin or composable

Import the strategy only via the alias so the bundler includes just that implementation:

// runtime/plugins/01.i18n-strategy.ts

import { Strategy } from '#i18n-strategy'
import type { PathStrategyContext } from '@i18n-micro/path-strategy/types'

export default defineNuxtPlugin((nuxtApp) => {
  const context: PathStrategyContext = {
    strategy: useRuntimeConfig().public.i18n.strategy,
    defaultLocale: 'en',
    locales: [/* ... */],
    localizedRouteNamePrefix: 'localized-',
    router: { hasRoute, resolve },
    // optional: globalLocaleRoutes, routeLocales, routesLocaleLinks, noPrefixRedirect
  }

  const pathStrategy = new Strategy(context)
  return { provide: { i18nStrategy: pathStrategy } }
})

Only the selected strategy and the base class are included in the bundle; the other strategies are tree-shaken out.

4. Package exports

| Entry | Contents | |-------|----------| | @i18n-micro/path-strategy | Main entry: types, factory, all strategies, resolver utils (getRouteBaseName, buildLocalizedName, isIndexRouteName, analyzeRoute) | | @i18n-micro/path-strategy/prefix | PrefixPathStrategy and Strategy alias | | @i18n-micro/path-strategy/no-prefix | NoPrefixPathStrategy and Strategy | | @i18n-micro/path-strategy/prefix-except-default | PrefixExceptDefaultPathStrategy and Strategy | | @i18n-micro/path-strategy/prefix-and-default | PrefixAndDefaultPathStrategy and Strategy | | @i18n-micro/path-strategy/types | Types only (PathStrategyContext, RouteLike, ResolvedRouteLike, RouterAdapter, etc.) |


API

Factory

  • createPathStrategy(ctx: PathStrategyContext) — Returns the strategy instance for ctx.strategy. Use for tests or server-side when you don't use the alias.

Resolver utilities (from main entry)

  • getRouteBaseName(route, options?) — Returns the base route name (without localized prefix/suffix).
  • buildLocalizedName(baseName, localeCode, prefix?) — Builds a localized route name (e.g. about + de + localized- -> localized-about-de).
  • isIndexRouteName(name, options?) — Returns whether the route name is the index route (e.g. index, localized-index-en).
  • analyzeRoute(route, ctx) — Returns a RouteAnalysis object with baseName, pathWithoutLocale, localeFromPath, and isIndex for a given route and context.

Strategy interface

Each strategy implements:

| Method | Description | |--------|-------------| | localeRoute(targetLocale, routeOrPath, currentRoute?) | Localized route for the target locale. Returns RouteLike with path and fullPath set. | | switchLocaleRoute(fromLocale, toLocale, route, options) | Route to navigate to when switching locale. Returns RouteLike or string. | | getRedirect(currentPath, targetLocale) | Path to redirect to on server, or null. | | getClientRedirect(currentPath, preferredLocale) | Path to redirect to on client (after hydration), or null. | | shouldReturn404(currentPath) | Returns a 404 redirect path if the current path is invalid, or null. | | getCanonicalPath(route, targetLocale) | Custom path for the route in that locale (from globalLocaleRoutes), or null. | | resolveLocaleFromPath(path) | Locale code from path (strategy-specific; e.g. no_prefix returns null). | | getLocaleFromPath(path) | Parses path and returns first segment if it is a locale code. | | getRouteBaseName(route) | Base name for the route (delegates to resolver with context). | | getCurrentLocale(route, defaultLocaleOverride?) | Determines current locale from route (considers strategy, hashMode, params, path). | | getPluginRouteName(route, locale) | Returns the base route name for translation loading. | | getCurrentLocaleName(route, defaultLocaleOverride?) | Returns displayName of the current locale, or null. | | setRouter(router) | Replaces the router adapter at runtime. | | formatPathForResolve(path, fromLocale, toLocale) | Transforms a path for cross-locale resolution. | | getDefaultLocale() | Returns the default locale code. | | getLocales() | Returns the configured locales array. | | getStrategy() | Returns the strategy name. |

Context (PathStrategyContext)

Import from @i18n-micro/path-strategy/types.

| Property | Description | |----------|-------------| | strategy, defaultLocale, locales, localizedRouteNamePrefix, router | Required. | | localeCodes | Pre-computed locale code strings. Set automatically in constructor from locales. | | globalLocaleRoutes | Record<string, Record<string, string> \| false>: custom path per route/locale; false = unlocalized. | | routeLocales | Record<string, string[]>: route path or base name -> list of locale codes; limits hreflang entries. | | routesLocaleLinks | Record<string, string>: base name -> key for routeLocales lookup (e.g. 'products-id' -> 'products'). | | noPrefixRedirect | When true (default), NoPrefixPathStrategy.getRedirect strips a leading locale segment (e.g. /en/about -> /about). Set to false to disable. | | hashMode | Locale stored in hash, no prefix in path. | | disablePageLocales | When true, all pages use only global translations (no page-specific loading). | | debug | Enable debug logging. |

Redirect behavior per strategy

  • prefix: root / -> /{locale}; paths without prefix get prefix; wrong prefix is replaced.
  • prefix_except_default: default locale with prefix (e.g. /en/about) -> path without prefix (/about); non-default without prefix -> add prefix; root with non-default -> /{locale}.
  • prefix_and_default: same as prefix (all locales have prefix in URL).
  • no_prefix: paths that start with a locale segment (e.g. /en/about) -> path without segment (/about), unless noPrefixRedirect is false.

Using getRedirect in middleware

const redirectPath = strategy.getRedirect(to.fullPath, detectedLocale)
if (redirectPath) return navigateTo(redirectPath)

Integration with Nuxt I18n Micro

The main Nuxt module (nuxt-i18n-micro) integrates path-strategy by default: it generates the strategy from the chosen strategy option, creates the instance with runtime config and router, and provides it as nuxtApp.$i18nStrategy. The redirect plugin calls strategy.getRedirect() (server) and strategy.getClientRedirect() (client) and redirects when a path is returned.


Testing

The package is tested with Jest. Tests include unit tests for each strategy, snapshot tests, a memory-leak test suite, and performance benchmarks.

# Unit tests
pnpm test

# Performance benchmarks (Node.js)
pnpm test:perf

# Performance benchmarks (real browsers — Chromium, Firefox, WebKit)
pnpm bench:browser:ci

# Single browser
pnpm bench:browser:ci -- --browser=firefox

# Interactive browser benchmark (opens dev server)
pnpm bench:browser

Browser benchmarks

The bench/ directory contains a browser-based performance benchmark that runs the same suite as the Node.js tests but in a real browser engine via Playwright. This measures actual client-side performance across V8 (Chromium), SpiderMonkey (Firefox), and JavaScriptCore (WebKit).

Results are saved as baselines per browser engine in tests/__perf__/baseline-browser-{engine}.json.


Performance optimizations

  • Pure functions over classes — Route resolution (analyzeRoute, resolveCustomPath, etc.) uses pure functions instead of a class-based RouteResolver, enabling better tree-shaking and V8 inlining.
  • Pre-computed context flagslocaleCodes, _hasGR (has global locale routes), and _hasRL (has route locales) are computed once in the constructor, avoiding Object.keys() allocations on hot paths.
  • Minimal object allocation — Route objects are constructed via direct property assignment instead of { ...spread } to reduce GC pressure.
  • Fast path utilitiesnormalizePath, joinUrl, and cleanDoubleSlashes use character-code checks and fast paths for common cases (e.g. simple paths without double slashes).
  • hasKeys() utility — O(1) check for whether an object has own keys, without Object.keys() array allocation.

License

MIT