Namespace Strategy

aidiomix automatically organizes translations using namespaces based on the file structure. This helps keep your translations organized and prevents key conflicts.

Available Strategies

1. Full Path (default: 'full-path')

Uses the complete file path relative to sourceDirectories as the namespace.

Example:

  • File: ./app/components/ui/Button.tsx
  • Namespace: components.ui.Button
  • Translation key: components.ui.Button.hello_world

Pros:

  • Automatic organization by file structure
  • No key conflicts between different files
  • Easy to navigate and find translations

Cons:

  • Namespace changes when files are moved
  • Can create long namespaces for deeply nested files

2. Filename Only ('filename')

Uses only the filename (without path or extension) as the namespace.

Example:

  • File: ./app/components/ui/Button.tsx
  • Namespace: Button
  • Translation key: Button.hello_world

Pros:

  • Namespace never changes when moving files
  • Simple and readable

Cons:

  • Risk of key conflicts if multiple files have the same name
  • Less organization for large projects

3. X First Parent Directories ('x-first-parent')

Uses the first X parent directories as the namespace. Replace x with the number of directories you want.

Examples:

  • '1-first-parent': File ./app/components/ui/Button.tsx → Namespace: components (1 parent, filename excluded)
  • '2-first-parent': File ./app/components/ui/Button.tsx → Namespace: components.ui (2 parents, filename excluded)
  • '3-first-parent': File ./app/components/ui/Button.tsx → Namespace: components.ui (only 2 parents available, filename excluded)

Pros:

  • Flexible - choose exactly how many parent directories to include
  • More stable than full path
  • Good for organizing by top-level directories

Cons:

  • Still changes if moving between different parent directories
  • Need to choose the right number for your project structure

4. X Last Parent Directories ('x-last-parent')

Uses the last X parent directories (including filename) as the namespace. Replace x with the number of directories you want.

Examples:

  • '1-last-parent': File ./app/components/ui/Button.tsx → Namespace: Button (1 element: filename only)
  • '2-last-parent': File ./app/components/ui/Button.tsx → Namespace: ui.Button (2 elements: 1 parent + filename)
  • '2-last-parent': File ./app/[lang]/client/campaigns/[id]/page.tsx → Namespace: campaigns.id (2 elements: 1 parent + filename, normalized from campaigns.[id])
  • '3-last-parent': File ./app/components/ui/Button.tsx → Namespace: components.ui.Button (3 elements: 2 parents + filename)

Pros:

  • Flexible - choose exactly how many parent directories to include
  • Handles dynamic route segments well (e.g., [lang], [id])
  • More stable than full path
  • Ideal for Next.js App Router projects
  • Always includes the filename as the last part

Cons:

  • Still changes if moving between different parent directories
  • Need to choose the right number for your project structure

Handling Dynamic Route Segments: For files with dynamic route segments like [lang], [id], or [...slug], the brackets are automatically removed:

  • [lang]lang
  • [id]id
  • [...slug]slug

5. Global Namespace ('global')

No namespace prefix - all translations are at the root level.

Example:

  • File: ./app/components/Button.tsx
  • Namespace: `` (empty)
  • Translation key: hello_world (no namespace prefix)

Pros:

  • Simple, no namespace management
  • Shorter translation keys

Cons:

  • High risk of key conflicts
  • Harder to organize large projects
  • Not recommended for projects with many files

6. Content-Based Hash ('content-hash')

Uses a hash of the file content to create a stable namespace.

Example:

  • File: ./app/components/Button.tsx
  • Namespace: a1b2c3d4 (first 8 characters of MD5 hash)
  • Translation key: a1b2c3d4.hello_world

Pros:

  • Very stable - namespace never changes unless file content changes
  • No conflicts between different files

Cons:

  • Not human-readable
  • Harder to understand and navigate
  • Namespace changes if file content changes significantly

Explicit Namespace Comment

Regardless of the configured strategy, you can override the namespace by adding a comment at the top of your file:

Single-line comment:

// @namespace: common.buttons
// or
// @aidiomix-namespace: common.buttons

Multi-line comment:

/* @namespace: common.buttons */
/* or */
/* @aidiomix-namespace: common.buttons */

Example:

// @namespace: shared.components
const Button = () => {
  return <div>Hello World</div>;
};

The explicit namespace takes precedence over the configured strategy. This is useful when:

  • You want to group translations from multiple files under the same namespace
  • You need a specific namespace that doesn't match the file structure
  • You want to ensure stability regardless of file location

Per-Key Namespace Override

You can also specify a namespace for individual translation keys by combining directives on the same line. This gives you fine-grained control over how specific keys are organized.

Syntax:

// @aidiomix-translate @aidiomix-namespace: <namespace>
// or
// @translate @namespace: <namespace>

Examples:

String Literals

const message = "Hello"; // @aidiomix-translate @aidiomix-namespace: common
const button = "Click me"; // @translate @namespace: buttons

JSX Text

<div>
  {/* @aidiomix-translate @aidiomix-namespace: common */}
  Hello World
</div>

JSX Attributes

<Input 
  placeholder="Search..." // @aidiomix-translate @aidiomix-namespace: forms
/>

Mixed Namespaces in Same File

// File-level namespace: components.Button (from strategy)
const Button = () => {
  const title = "Welcome"; 
  // Uses file namespace: components.Button.text_xxx
  
  const commonText = "Hello"; // @aidiomix-translate @aidiomix-namespace: common
  // Uses specific namespace: common.text_xxx
  
  return (
    <div>
      <h1>{title}</h1>
      <p>{commonText}</p>
    </div>
  );
};

Behavior:

  • The per-key namespace takes precedence over both the file-level namespace comment and the configured strategy
  • If no per-key namespace is specified, the file-level namespace (or strategy) is used
  • Multiple directives can be combined on the same line
  • Useful when you want specific keys to be grouped differently from the rest of the file

Use cases:

  • Grouping common UI elements (buttons, labels) across different files
  • Separating shared translations from component-specific ones
  • Organizing translations by feature rather than file structure

Choosing the Right Strategy

Use full-path (default) when:

  • Files are rarely moved
  • You want maximum organization and no conflicts
  • You have a stable project structure

Use filename when:

  • Files are frequently moved
  • You have unique filenames across your project
  • You want simple, readable namespaces

Use x-first-parent when:

  • You organize code by top-level directories (e.g., components/, pages/, features/)
  • You want moderate stability with some organization
  • You want to control exactly how many parent directories to include

Use x-last-parent when:

  • You're using Next.js App Router with dynamic routes
  • You want good organization with better stability than full-path
  • You need to handle files with dynamic segments like [id] or [lang]
  • You want to control exactly how many parent directories to include from the end

Use global when:

  • You have a small project with few files
  • You want the simplest possible setup
  • You're okay managing potential key conflicts manually

Use content-hash when:

  • You need maximum stability regardless of file location
  • You don't need human-readable namespaces
  • You're building a tool or library where namespace readability isn't important