Troubleshooting

Common issues and solutions for Stringer CLI

Quick Solutions

Installation Issues

Problem: stringer: command not found
Solution: Install Stringer CLI globally:

npm install -g stringer-cli

Problem: Command still not found after installing (ZSH users)
Solution: Add npm's global bin directory to your PATH:

# Find where npm installs global packages
npm config get prefix

# Add to your ~/.zshrc (replace /usr/local with your prefix if different)
echo 'export PATH="$PATH:$(npm config get prefix)/bin"' >> ~/.zshrc

# Reload your shell
source ~/.zshrc

Problem: Permission denied during installation
Solution: Use sudo or fix npm permissions:

sudo npm install -g stringer-cli
# or
npm config set prefix ~/.npm-global

Authentication Issues

Problem: stringer login fails
Solution: Clear cache and re-authenticate:

stringer logout
stringer login

Framework Detection Issues

Problem: Framework not detected
Solution: Run stringer and manually select framework:

stringer
# Will prompt to select framework if detection fails

Conversion Issues

Strings Not Converting

Stringer focuses on user-facing strings. The following are not converted:

  • Code comments
  • Console logs and debug messages
  • Content inside <style> tags
  • Strings in /composables folders
  • Technical identifiers and constants

Composables Causing Errors

Strings in /composables are skipped because injected t() calls can cause errors depending on whether the composable runs client or server-side.

Solution: Move user-facing strings to components, pages, or inside defineEventHandler scope.

Server-Side Strings Outside Event Handlers

For Nuxt server routes, strings outside defineEventHandler are not converted because there's no event context.

// ❌ Won't work — function outside handler
function formatError(code: string) {
  return t('errors.' + code)
}

export default defineEventHandler(async (event) => {
  const t = await useTranslation(event)
  // ...
})

// ✅ Works — function inside handler
export default defineEventHandler(async (event) => {
  const t = await useTranslation(event)
  
  function formatError(code: string) {
    return t('errors.' + code)
  }
  // ...
})

Stringer automatically detects and skips legal documents (terms of service, privacy policies) to prevent accidental translation.

To speed up processing: Add // @stringer-ignore to legal files you know should be skipped.

To force conversion:

stringer --allow-legal-conversion

Lists Not Updating on Language Change

If dropdowns or menus don't update when language changes:

// ❌ Static array won't react
const menuItems = [
  { label: t('menu.home'), value: 'home' }
]

// ✅ Use computed
const menuItems = computed(() => [
  { label: t('menu.home'), value: 'home' }
])

Conversion Missed a String?

Use the Stringer VSCode Extension as a companion to the CLI for quick fixes:

  1. Select the string
  2. Right-click → "🌎 Add i18n key via Stringer"
  3. Run stringer align to sync across languages

The extension lets you one-click convert user-facing strings into Stringer i18n keys and trigger smart CLI commands (like align or url repairs) directly from VSCode, but it still relies on the CLI under the hood and is not a replacement for it.

Install the extension →


URL-based i18n Issues

404 Errors or Infinite Redirects

If you experience 404 errors, infinite redirects, or pages not loading after enabling URL-based routing:

Use the Repair feature:

  1. Run stringer
  2. Select Advanced
  3. Select Repair URL-based i18n routing

This repair flow fixes:

  • Middleware conflicts causing redirects
  • Incorrect route handling logic
  • i18n configuration issues
  • Missing localePath() wrappers on links

Additional Troubleshooting Steps

If the repair doesn't resolve your issue:

  1. Disable custom middleware temporarily to identify conflicts
  2. Check middleware order — Stringer locale middleware should run first
  3. Review excluded paths — API routes should be excluded from locale prefixing

Stringer wraps existing links automatically during conversion, but new links you add need manual wrapping.

Template Links:

<NuxtLink :to="localePath('/about')">About</NuxtLink>
<NuxtLink :to="localePath('/products/' + product.id)">{{ product.name }}</NuxtLink>

Programmatic Navigation:

// In components/pages
const localePath = useLocalePath()

// Navigate to a route
navigateTo(localePath('/dashboard'))

// With replace
navigateTo(localePath('/login'), { replace: true })

Server-Side Redirects:

// In server routes or middleware
export default defineEventHandler((event) => {
  // For server-side redirects, construct the path manually
  const locale = event.context.locale || 'en-us'
  return sendRedirect(event, `/${locale}/login`)
})

Middleware Redirects:

// In middleware
export default defineNuxtRouteMiddleware((to) => {
  const localePath = useLocalePath()
  
  if (!isAuthenticated()) {
    return navigateTo(localePath('/login'))
  }
})

Ignoring Content

Skip an Entire File

Add @stringer-ignore near the top:

<!-- @stringer-ignore -->
<template>
  <div>This file will be skipped</div>
</template>

Skip a Single Line

Add @stringer-ignore-next-line above the line:

<!-- @stringer-ignore-next-line -->
<p>This line won't be converted</p>

<p>But this line WILL be converted</p>

Skip From a Point Onwards

Add @stringer-ignore-from-here to skip everything below that point in the file:

<template>
  <p>This will be converted</p>
  
  <!-- @stringer-ignore-from-here -->
  <p>This won't be converted</p>
  <p>Neither will this</p>
</template>

Local Cache

Stringer caches converted files to avoid reprocessing.

Cache locations:

  • macOS: ~/Library/Caches/stringer-cli/parse-cache.json
  • Windows: %APPDATA%/stringer-cli/parse-cache.json
  • Linux: ~/.cache/stringer-cli/parse-cache.json

To clear the cache:

stringer --clear-cache

Supported Content Formats

Markdown and YAML Files

Stringer now supports translating Markdown (.md) and YAML (.yml, .yaml) files! These content files will be automatically detected and processed during translation, making it easy to localize your documentation and configuration files.


Common Error Messages

"Project not initialized"
Run stringer to set up your project.

"Framework not supported"
Ensure you're using Vue or Nuxt.


Billing Questions

Will I be charged for failed conversions?

No. You're only charged for files that are successfully converted.

How are tokens calculated?

Tokens are calculated after removing style blocks, imports, exports, and config files. You only pay for translatable code. See Pricing.


Still Need Help?