Skip to content

Add docs i18n support#50

Merged
KayleeWilliams merged 3 commits into
mainfrom
i18n-docs-support
May 14, 2026
Merged

Add docs i18n support#50
KayleeWilliams merged 3 commits into
mainfrom
i18n-docs-support

Conversation

@KayleeWilliams
Copy link
Copy Markdown
Collaborator

Summary

Adds first-class i18n support to the Leadtype docs pipeline.

  • Introduces leadtype/i18n with locale config normalization, localized URL helpers, locale detection, alternate link helpers, and i18n manifest types.
  • Threads optional locale metadata through source pages, navigation, search records, LLM artifacts, and Agent Readability manifests.
  • Updates leadtype generate to preserve default-locale URLs while generating locale-scoped artifacts under /docs/<locale>/... plus /docs/i18n-manifest.json.
  • Keeps search and LLM artifacts language-scoped by default while allowing navigation/source loading to mark default-locale fallbacks.

DX and Compatibility

  • Existing monolingual projects keep current behavior when i18n is absent.
  • Projects enabling i18n can keep default docs at root docs/*.mdx and add translations under folders like docs/zh/*.mdx.
  • Generation fails clearly if both root default docs and docs/<defaultLocale> default docs are present.

Validation

  • bunx vitest run src/i18n/i18n.test.ts --coverage --coverage.include=src/i18n/index.ts --coverage.thresholds.lines 90 --coverage.thresholds.functions 90 --coverage.thresholds.branches 90 --coverage.thresholds.statements 90
    • Statements 100%, Branches 90%, Functions 100%, Lines 100%
  • bun run --filter leadtype check-types
  • bun test packages/leadtype/src
  • bun x ultracite check
  • bun run --filter leadtype build

Closes #38.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • First-class docs i18n: locale-aware generation, per-locale artifacts (search, navigation, LLM, readability), locale routing, i18n manifest, and public i18n helper API.
  • Tests

    • Added coverage for locale normalization, URL/path handling, CLI/site generation across locales, search/LLM outputs, source selection and fallback, and package export surface.
  • Chores

    • Added Vitest coverage tool to dev dependencies.

Walkthrough

Adds a leadtype i18n helper module, publishes it via package exports/build, and threads normalized i18n through docs source selection, search indexing, LLM/readability artifact generation, and the CLI to produce per-locale outputs plus an i18n-manifest; includes tests and a changeset.

Changes

Multi-Language Documentation Support

Layer / File(s) Summary
i18n core: types, helpers, tests
packages/leadtype/src/i18n/index.ts, packages/leadtype/src/i18n/i18n.test.ts
Defines locale types/configs, normalization/validation, URL/path localization helpers, logical-path helpers, alternate-locale link generation, and tests for normalization, prefixing, path derivation, and alternate links.
Build inputs & package exports
packages/leadtype/package.json, packages/leadtype/rollup.config.ts, packages/leadtype/src/index.ts, packages/leadtype/src/llm/index.ts, packages/leadtype/src/internal/package-surface.test.ts, .changeset/*
Adds ./i18n Rollup input and ./i18n export subpath, re-exports i18n API from package root and LLM surface, updates package-surface test, and adds a changeset.
Dev dependency for tests
package.json
Adds @vitest/coverage-v8 v4.1.5 to devDependencies.
Docs source locale-aware selection
packages/leadtype/src/source/index.ts, packages/leadtype/src/source/source.test.ts
Introduces SelectedSourceFile/selectSourceFiles, enriches DocsPageMeta with locale/sourceLocale/isFallback/logicalPath, normalizes incoming slugs by stripping locale prefixes, validates ambiguous layouts/duplicates, and excludes fallback pages from search index; adds tests.
Search locale integration
packages/leadtype/src/search/node.ts, packages/leadtype/src/search/search.ts
Extends search config with i18n/locale, implements locale-aware markdown selection, computes localized id/urlPath, adds optional locale fields to document tuples and runtime tuple handling, and nests generated outputs under locale subdirectories.
LLM & readability locale integration
packages/leadtype/src/llm/llm.ts, packages/leadtype/src/llm/readability.ts, packages/leadtype/src/llm/llm.test.ts
Updates SourceDoc and LLM/readability configs to accept i18n/locale, selects localized source/markdown (with optional fallback), writes per-locale llms.txt/llms-full.txt and agent readability artifacts, updates manifests/robots/sitemaps to use locale-aware prefixes, and adds tests validating localized LLM outputs.
CLI generate command wiring & manifest
packages/leadtype/src/cli/generate.ts, packages/leadtype/src/cli.test.ts
Threads i18n through docs config validation and generate metadata, builds a versioned docs/i18n-manifest.json with per-locale artifact paths, validates navigation per-locale, copies default-locale aliases when needed, and orchestrates per-locale generation of search/LLM/readability artifacts; CLI tests verify manifest and locale-scoped artifacts.

Sequence Diagram

sequenceDiagram
  participant Config as docs.config.ts
  participant Generate as runGenerateCommand
  participant I18n as normalizeDocsI18nConfig
  participant Source as createDocsSource/readSourceDocs
  participant Manifest as buildI18nManifest
  participant Search as generateDocsSearchFiles
  participant LLM as generateLlmsTxt/generateLLMFullContextFiles
  Config->>Generate: provide i18n config (defaultLocale, locales)
  Generate->>I18n: normalize & validate i18n config
  I18n->>Generate: return NormalizedDocsI18nConfig
  Generate->>Source: create source with i18n for default locale
  Source->>Source: select localized pages per logical path
  Generate->>Manifest: build i18n-manifest with artifact URLs/paths
  Manifest->>Generate: write docs/i18n-manifest.json
  loop for each non-default locale
    Generate->>Source: create source with locale (use fallback rules)
    Generate->>Search: generate search index for locale
    Generate->>LLM: generate locale-scoped llms.txt and llms-full.txt
  end
  Generate->>Generate: return GenerateResult with i18nManifest path
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • inthhq/leadtype#35: Related changes to createDocsSource and the docs-source contracts that this PR extends for i18n-aware selection.
  • inthhq/leadtype#28: Overlaps in CLI/docs-config loading and generate metadata wiring now extended to capture/propagate i18n.
  • inthhq/leadtype#31: Related to mount/url-prefix routing logic that interacts with locale-prefixed docs URL generation.

"I hopped through folders, small and spry,
Wrote prefixes where the languages lie.
From en to zh, the docs now sing,
Little rabbit cheers — i18n's the thing! 🐇"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Add docs i18n support' clearly and concisely describes the primary change: introducing internationalization support for documentation.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, detailing the introduction of i18n support, threading locale metadata, and preservation of default-locale behavior.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #38: locale configuration normalization [packages/leadtype/src/i18n/index.ts], URL/routing handling with locale-scoped artifacts [packages/leadtype/src/cli/generate.ts], localized helpers and detection [packages/leadtype/src/i18n/index.ts], threading metadata through content/navigation/search/LLM [packages/leadtype/src/llm/llm.ts, search/node.ts, source/index.ts, readability.ts], language-scoped artifacts with fallback support [packages/leadtype/src/llm/llm.ts, search/node.ts], and clear failure for conflicting default-doc placements [packages/leadtype/src/llm/llm.ts].
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing i18n support as described in issue #38. The addition of @vitest/coverage-v8 dependency is a supporting change for test infrastructure and aligns with validation steps mentioned in the PR description.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch i18n-docs-support

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread packages/leadtype/src/source/index.ts Fixed
Comment thread packages/leadtype/src/source/index.ts Fixed
@KayleeWilliams KayleeWilliams marked this pull request as ready for review May 14, 2026 04:06
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2dfb231d72

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!normalized || locale === normalized.defaultLocale) {
return logicalPath.replace(MARKDOWN_EXTENSION_PATTERN, "");
}
return `${locale}/${logicalPath.replace(MARKDOWN_EXTENSION_PATTERN, "")}`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve mount prefixes in localized output paths

When i18n is combined with mounted docs sources, this prepends the locale before the logical path, so a mounted source like --docs-dir api=/reference with api/zh/intro.mdx is represented as zh/api/intro instead of api/zh/intro. The CLI copies mounted sources under the mount path before conversion (copySourceFiles writes source.mountPath first), and later link rendering resolves mounts from the start of relativePath, so localized mounted pages produce links such as /docs/zh/api/intro.md that do not match the actual mirrored /reference/zh/intro.md output.

Useful? React with 👍 / 👎.

Comment on lines +171 to +174
const pathnameSegments = splitUrlPath(pathname);
const afterPrefix = pathnameSegments.slice(prefixSegments.length);
const first = afterPrefix[0];
const matched = normalized.locales.find((locale) => locale.code === first);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Verify the docs prefix before resolving locale

For callers that pass site-wide pathnames into this helper, paths outside docsUrlPrefix can be misclassified because the code slices off prefixSegments.length without first checking that the pathname actually starts with those prefix segments. For example, with docsUrlPrefix = "/docs", /blog/fr/post returns fr when fr is configured, which can make non-doc routes look like localized docs routes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Root bun.lock is out of sync with package.json for the leadtype workspace devDep — CI on bun install --frozen-lockfile will fail. Also flagging a user-visible change to the search-index.json document id shape.

TL;DR — Adds optional i18n support to the docs pipeline: new leadtype/i18n subpackage with locale config + URL helpers, locale metadata threaded through source/search/LLM/agent-readability artifacts, and locale-scoped output paths under /docs/<locale>/... plus a top-level i18n-manifest.json. Monolingual projects are unaffected when i18n is absent.

Key changes

  • New leadtype/i18n subpackage — Locale config normalization, locale-aware URL helpers, alternate-link helpers, and the DocsI18nManifest type. Re-exported from leadtype root and leadtype/llm.
  • Locale-scoped artifact generation in generatecli/generate.ts runs the LLM/search/readability generators once per locale; default-locale outputs stay at root paths, non-default land under /docs/<locale>/.... Writes docs/i18n-manifest.json.
  • Localized source/markdown selectionselectLocalizedFiles (in llm/llm.ts and search/node.ts) and selectSourceFiles (in source/index.ts) key by logical path and pick the requested locale with optional default-locale fallback.
  • Schema bumps for downstream consumersAgentReadabilityManifest gains locale and i18n. DocsSearchDocumentEntry gains 4 trailing optional fields. DocsSearchDocument.id in search/node.ts now uses urlPath instead of stripDocsExtension(relativePath).
  • Ambiguity guard — Having both root docs/*.mdx and docs/<defaultLocale>/*.mdx throws "Ambiguous i18n default-locale layout" in source reads and post-conversion.

Summary | 18 files | 1 commit | base: maini18n-docs-support


Lockfile mismatch on root leadtype devDep

Before: bun.lock and package.json agreed on leadtype: workspace:*.
After: package.json still says workspace:* but bun.lock says ^0.1.2.

The workspace package itself bumped to 0.1.2, but the root devDep spec only moved positions in package.json — it still resolves through the workspace. The lockfile entry should still mirror that. bun install --frozen-lockfile (typical CI) will reject this; a plain bun install rewrites it.

bun.lock · package.json


Search index document id shape change

Before: id: stripDocsExtension(relativePath) → e.g. quickstart.
After: id: urlPath → e.g. /docs/quickstart.

This affects every project, not just i18n consumers. It does bring generateDocsSearchFiles in line with createDocsSource (which has always used meta.urlPath as the id), so the change is a normalization rather than a regression — but consumers reading search-index.json will see the document id and chunk documentId formats change. Worth a changelog callout.

packages/leadtype/src/search/node.ts


Ambiguity-check ordering across read paths

Before: readSourceDocs asserts unambiguous layout before selecting files; the path didn't exist for readMarkdownDocs.
After: readMarkdownDocs performs selectLocalizedFiles first, then runs assertUnambiguousDefaultLocaleLayout after.

Not a correctness bug — both branches still throw the expected error — but the inverted order in readMarkdownDocs (vs readSourceDocs) means the assertion runs after extra work that may be discarded. Worth aligning so a future reader doesn't infer a different invariant.

packages/leadtype/src/llm/llm.ts

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment thread bun.lock Outdated
"@vitest/coverage-v8": "4.1.5",
"husky": "^9.1.7",
"leadtype": "workspace:*",
"leadtype": "^0.1.2",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entry says "leadtype": "^0.1.2" but the matching package.json devDep is "leadtype": "workspace:*". The lockfile should mirror the manifest spec — bun install --frozen-lockfile (the typical CI setting) will fail here, and a plain bun install will silently overwrite this back to workspace:*. Re-run bun install locally and commit the regenerated lockfile.

: toDocsUrlPath(relativePath, mounts);
docs.push({
id: stripDocsExtension(relativePath),
id: urlPath,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id switched from stripDocsExtension(relativePath) to urlPath, which changes the document id and chunk documentId shape in search-index.json for every project (not just i18n ones). It does match what createDocsSource already emits, so this is a deliberate normalization — but please call it out in the changelog since downstream consumers reading the index may pin to the old quickstart-style ids.

Comment thread packages/leadtype/src/llm/llm.ts Outdated
localeCodes,
localeRead.i18n.defaultLocale
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readSourceDocs runs assertUnambiguousDefaultLocaleLayout before selectLocalizedFiles (lines 708-714), but here the assertion runs after selection. Both still throw correctly, but moving this check up keeps the invariant consistent across the two read paths and avoids doing selection work that will be discarded on the error path.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/leadtype/src/source/index.ts (1)

332-332: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Useless conditional: includeFallback is always true.

The includeFallback parameter (line 261) defaults to true and is never reassigned. Remove includeFallback && from the condition.

Simplified condition
     const fallback =
-      includeFallback && outputLocale !== normalized.defaultLocale
+      outputLocale !== normalized.defaultLocale
         ? localeFiles.get(normalized.defaultLocale)
         : undefined;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/leadtype/src/source/index.ts` at line 332, The conditional currently
checks "includeFallback && outputLocale !== normalized.defaultLocale" but
includeFallback defaults to true and is never changed; remove the redundant
"includeFallback &&" so the condition becomes just "outputLocale !==
normalized.defaultLocale" (update the condition where it appears in the code
referencing includeFallback, outputLocale, and normalized.defaultLocale).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/leadtype/src/i18n/index.ts`:
- Around line 170-175: The code slices pathnameSegments by prefixSegments length
without checking that pathname actually starts with docsUrlPrefix, so locales
can be resolved on non-docs URLs; update the logic in the function using
splitUrlPath, docsUrlPrefix, pathname, prefixSegments, pathnameSegments and
afterPrefix to first verify that pathnameSegments begins with prefixSegments
(e.g., compare each segment or check a starts-with condition) before computing
afterPrefix and reading first; if the pathname does not start with the docs
prefix, return normalized.defaultLocale immediately, otherwise proceed to find a
matching locale from normalized.locales by comparing locale.code and return
matched?.code ?? normalized.defaultLocale.

In `@packages/leadtype/src/llm/llm.ts`:
- Around line 839-845: Move the call to assertUnambiguousDefaultLocaleLayout so
it runs before selectLocalizedFiles to match readSourceDocs' ordering;
specifically, call assertUnambiguousDefaultLocaleLayout(relativePaths,
localeCodes, localeRead.i18n.defaultLocale) right after confirming
localeRead.i18n && localeRead.locale and before invoking selectLocalizedFiles,
so the assertion can fail fast and avoid doing work in selectLocalizedFiles.

---

Duplicate comments:
In `@packages/leadtype/src/source/index.ts`:
- Line 332: The conditional currently checks "includeFallback && outputLocale
!== normalized.defaultLocale" but includeFallback defaults to true and is never
changed; remove the redundant "includeFallback &&" so the condition becomes just
"outputLocale !== normalized.defaultLocale" (update the condition where it
appears in the code referencing includeFallback, outputLocale, and
normalized.defaultLocale).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 861b3749-0409-4544-a748-621f8bfcdc2c

📥 Commits

Reviewing files that changed from the base of the PR and between 844a94d and 2dfb231.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • package.json
  • packages/leadtype/package.json
  • packages/leadtype/rollup.config.ts
  • packages/leadtype/src/cli.test.ts
  • packages/leadtype/src/cli/generate.ts
  • packages/leadtype/src/i18n/i18n.test.ts
  • packages/leadtype/src/i18n/index.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/llm/llm.test.ts
  • packages/leadtype/src/llm/llm.ts
  • packages/leadtype/src/llm/readability.ts
  • packages/leadtype/src/search/node.ts
  • packages/leadtype/src/search/search.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/source/source.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/leadtype/rollup.config.ts
  • packages/leadtype/src/i18n/i18n.test.ts
  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/llm/llm.test.ts
  • packages/leadtype/src/source/source.test.ts
  • packages/leadtype/src/search/search.ts
  • packages/leadtype/src/cli.test.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/search/node.ts
  • packages/leadtype/src/cli/generate.ts
  • packages/leadtype/src/llm/readability.ts
  • packages/leadtype/src/i18n/index.ts
  • packages/leadtype/src/llm/llm.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code

Files:

  • packages/leadtype/rollup.config.ts
  • packages/leadtype/src/i18n/i18n.test.ts
  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/llm/llm.test.ts
  • packages/leadtype/src/source/source.test.ts
  • packages/leadtype/src/search/search.ts
  • packages/leadtype/src/cli.test.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/search/node.ts
  • packages/leadtype/src/cli/generate.ts
  • packages/leadtype/src/llm/readability.ts
  • packages/leadtype/src/i18n/index.ts
  • packages/leadtype/src/llm/llm.ts
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/leadtype/src/i18n/i18n.test.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/llm/llm.test.ts
  • packages/leadtype/src/source/source.test.ts
  • packages/leadtype/src/cli.test.ts
**/index.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/i18n/index.ts
🔇 Additional comments (35)
package.json (1)

8-10: LGTM!

packages/leadtype/rollup.config.ts (1)

10-10: LGTM!

packages/leadtype/src/i18n/index.ts (1)

1-169: LGTM!

Also applies to: 176-311

packages/leadtype/src/index.ts (1)

12-26: LGTM!

packages/leadtype/package.json (1)

36-39: LGTM!

packages/leadtype/src/internal/package-surface.test.ts (1)

13-13: LGTM!

packages/leadtype/src/i18n/i18n.test.ts (1)

1-173: LGTM!

packages/leadtype/src/llm/readability.ts (1)

9-9: LGTM!

Also applies to: 57-57, 84-84, 107-107, 115-116

packages/leadtype/src/llm/index.ts (1)

3-16: LGTM!

packages/leadtype/src/llm/llm.test.ts (2)

209-248: LGTM!


346-385: LGTM!

packages/leadtype/src/source/source.test.ts (1)

274-319: LGTM!

packages/leadtype/src/cli.test.ts (1)

330-419: LGTM!

packages/leadtype/src/cli/generate.ts (4)

717-727: LGTM!


729-764: LGTM!


766-807: LGTM!


937-1077: LGTM!

packages/leadtype/src/source/index.ts (2)

199-244: LGTM!

Also applies to: 469-474


504-523: LGTM!

packages/leadtype/src/search/node.ts (2)

97-209: LGTM!


276-351: LGTM!

packages/leadtype/src/search/search.ts (3)

1-1: LGTM!

Also applies to: 107-154, 210-210


750-770: LGTM!


808-869: LGTM!

packages/leadtype/src/llm/llm.ts (11)

11-20: LGTM!

Also applies to: 77-91, 147-158, 168-179, 181-201, 213-229, 231-238


569-683: LGTM!


685-800: LGTM!


1119-1160: LGTM!


1166-1209: LGTM!


1211-1259: LGTM!


1267-1345: LGTM!


1347-1408: LGTM!


1486-1519: LGTM!


1527-1569: LGTM!


1571-1598: LGTM!

Comment thread packages/leadtype/src/i18n/index.ts
Comment thread packages/leadtype/src/llm/llm.ts Outdated
Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new issues. Reviewed the following changes:

  • Removed the duplicate leadtype: ^0.1.2 entry from bun.lock so the workspace devDep again matches package.json's workspace:* spec.
  • Moved assertUnambiguousDefaultLocaleLayout ahead of selectLocalizedFiles in readMarkdownDocs, matching the ordering in readSourceDocs.
  • Called out the search-index document id shape change (stripDocsExtension(relativePath)urlPath) in the changeset.
  • Guarded resolveDocsLocale so paths outside the docs URL prefix return undefined instead of mis-resolving a locale, with a test for /blog/zh/quickstart.
  • Dropped the always-true includeFallback parameter from selectSourceFiles and simplified the fallback condition.

Pullfrog  | View workflow run | Using Claude Opus𝕏

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/leadtype/src/llm/llm.ts`:
- Around line 644-649: The current logic lets a later file overwrite an earlier
localized entry because you call localeFiles.set(resolvedSourceLocale, ...)
unconditionally; instead, before calling localeFiles.set(...) check whether
localeFiles already has(resolvedSourceLocale) for the same logicalPath and
reject/throw (or otherwise surface an error) when a duplicate is detected;
update the code surrounding byLogicalPath.get(logicalPath), localeFiles, and the
localeFiles.set(...) call to perform this guard using resolvedSourceLocale and
filePath so duplicates are rejected rather than silently winning.

In `@packages/leadtype/src/source/index.ts`:
- Around line 215-217: The slug is being derived from selected.logicalPath which
omits the locale; instead derive locale-prefixed slugs by passing the route that
includes the locale (e.g. urlPath or the localized relative path) into
deriveSlug so the slug matches the localized url; update the deriveSlug call(s)
(currently using selected.logicalPath + path.extname(relativePath)) to use the
locale-aware path (urlPath or relativePath that includes the /docs/<locale>/
segment) and apply the same change for the other occurrence referenced (lines
229-231) so listPages() returns locale-prefixed page.slug values.
- Around line 309-324: The code currently overwrites entries in byLogicalPath
when multiple files map to the same logicalPath and resolvedSourceLocale (e.g.,
.md and .mdx or duplicate locale files), losing the earlier file; update the
block that builds localeFiles (the Map assigned to localeFiles and set via
byLogicalPath.set) to detect an existing entry for the same resolvedSourceLocale
and throw or surface an error instead of calling localeFiles.set silently; use
the existing symbols resolvedSourceLocale, logicalPath, localeFiles, filePath
and outputRelativePathForLocale to produce a clear error message that includes
the conflicting file paths and the locale so duplicates are rejected early.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c7bb868a-321d-4597-9704-ffc8f854baef

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfb231 and 30c0dec.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .changeset/i18n-docs-support.md
  • packages/leadtype/src/i18n/i18n.test.ts
  • packages/leadtype/src/i18n/index.ts
  • packages/leadtype/src/llm/llm.ts
  • packages/leadtype/src/source/index.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/leadtype/src/i18n/i18n.test.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/i18n/index.ts
  • packages/leadtype/src/llm/llm.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code

Files:

  • packages/leadtype/src/i18n/i18n.test.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/i18n/index.ts
  • packages/leadtype/src/llm/llm.ts
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/leadtype/src/i18n/i18n.test.ts
**/index.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/i18n/index.ts
🪛 markdownlint-cli2 (0.22.1)
.changeset/i18n-docs-support.md

[warning] 5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

Comment thread packages/leadtype/src/llm/llm.ts
Comment on lines +774 to 775
relativePath: file.outputRelativePath,
groups,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Keep source-relative paths separate from localized output paths.

relativePath now holds values like zh/changelog/v1, but downstream markdown-link builders still treat it as the source-relative path used for mount resolution. That breaks localized mounted artifacts: a page under changelog/v1.mdx will stop matching pathPrefix: "changelog" and llms/readability links will be emitted under /docs/zh/... instead of /changelog/zh/....

Also applies to: 877-877

Comment thread packages/leadtype/src/source/index.ts Outdated
Comment thread packages/leadtype/src/source/index.ts
Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new issues. Reviewed the following changes:

  • Added duplicate-source-file detection in both selectLocalizedFiles (llm/llm.ts) and selectSourceFiles (source/index.ts) — colliding (logicalPath, sourceLocale) pairs now throw with a message naming both files instead of silently letting the later file win.
  • Switched readPageMeta slug derivation to selected.outputRelativePath, so localized pages emit locale-prefixed slugs (e.g. ["zh", "quickstart"]) matching their /docs/<locale>/... URLs.
  • Broadened loadPage slug resolution to try the slug as-is, then strip a leading locale segment, then prepend the active locale, so callers can address pages by logical, fully-qualified, or fallback paths.
  • Added integration tests for the duplicate-rejection paths and for the logical-path loadPage("setup")/docs/zh/setup fallback lookup.

Pullfrog  | View workflow run | Using Claude Opus𝕏

@KayleeWilliams KayleeWilliams merged commit c7fcbf6 into main May 14, 2026
2 of 3 checks passed
@KayleeWilliams KayleeWilliams deleted the i18n-docs-support branch May 14, 2026 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

i18n support

1 participant