WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Conversation

@navyansh007
Copy link

Adds new lingo.dev validate command for comprehensive configuration validation before running translations.

Features

Commands

  • lingo.dev validate - Basic validation
  • lingo.dev validate --strict - Treat missing target files as errors
  • lingo.dev validate --api-key <key> - Include authentication check

Validates

  • Configuration file existence and parseability
  • Source and target locale formats
  • Bucket types support
  • Source files existence and readability
  • Target files/directories accessibility and permissions

Output

Simple linear format with ✓ (success), ⚠ (warning), ✗ (error)

✓ Configuration file (i18n.json) exists
✓ Source locale 'en' is valid
✓ Target locales ['es', 'fr'] are valid
✓ Bucket type 'json' is supported
✓ Source file exists: src/locales/en/common.json
⚠ Target file missing: src/locales/es/common.json (will be created)
✓ All source files are readable
✓ Target directories are writable

Validation complete: 7 checks passed, 1 warning

Testing

  • 9 new tests, all passing
  • All existing CLI tests passing
  • Build successful with no TypeScript errors

Use Cases

  • Pre-translation validation
  • CI/CD quality gates
  • Configuration debugging
  • Team onboarding
  • Post-migration validation

Closes #1300

Screen.Recording.2025-10-30.at.8.34.52.PM.mov

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new lingo.dev validate command that performs comprehensive pre-flight configuration validation before running translations. The command validates configuration files, locale formats, bucket types, and file accessibility, providing users with clear feedback on potential issues.

Key changes:

  • Added validate command with --strict and --api-key options
  • Validates configuration file, locale codes, bucket types, and file accessibility
  • Comprehensive test suite with 9 new tests covering various validation scenarios

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
packages/cli/src/cli/index.ts Imports and registers the new validate command
packages/cli/src/cli/cmd/validate.ts Implements the validate command with configuration and file validation logic
packages/cli/src/cli/cmd/validate.spec.ts Test suite for the validate command functionality

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// Check source file
const sourceFilePath = path.resolve(
bucketPath.pathPattern.replaceAll("[locale]", sourceLocale),
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

[nitpick] Using replaceAll() is correct for replacing all occurrences, but consider using replace() with a placeholder substitution function or regex for safer replacement. If [locale] appears in unexpected places (e.g., within string values), this could lead to unintended replacements. However, if the pattern is strictly controlled, this is acceptable.

Suggested change
bucketPath.pathPattern.replaceAll("[locale]", sourceLocale),
bucketPath.pathPattern.replace(/\[locale\]/g, sourceLocale),

Copilot uses AI. Check for mistakes.
Comment on lines +203 to +213
try {
await bucketLoader.pull(sourceLocale);
fs.accessSync(sourceFilePath, fs.constants.R_OK);
console.log(
chalk.green("✓") + ` Source file exists: ${sourceFilePath}`,
);
checksPassedCount++;
} catch (error) {
console.log(
chalk.red("✗") +
` Source file exists but is not readable: ${sourceFilePath}`,
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

The code calls bucketLoader.pull() before checking file readability with fs.accessSync(). If the file is readable but the pull operation fails, this could be misleading. Consider checking file access first before attempting to pull, or handle the pull error separately to distinguish between file access issues and loader-specific problems.

Suggested change
try {
await bucketLoader.pull(sourceLocale);
fs.accessSync(sourceFilePath, fs.constants.R_OK);
console.log(
chalk.green("✓") + ` Source file exists: ${sourceFilePath}`,
);
checksPassedCount++;
} catch (error) {
console.log(
chalk.red("✗") +
` Source file exists but is not readable: ${sourceFilePath}`,
// First, check file readability
try {
fs.accessSync(sourceFilePath, fs.constants.R_OK);
} catch (error) {
console.log(
chalk.red("✗") +
` Source file exists but is not readable: ${sourceFilePath}`,
);
errorCount++;
allSourceFilesReadable = false;
continue;
}
// Then, try to pull with the loader
try {
await bucketLoader.pull(sourceLocale);
console.log(
chalk.green("✓") + ` Source file exists: ${sourceFilePath}`,
);
checksPassedCount++;
} catch (error) {
console.log(
chalk.red("✗") +
` Source file is readable but bucketLoader.pull failed: ${sourceFilePath}\n ${error instanceof Error ? error.message : error}`,

Copilot uses AI. Check for mistakes.
Comment on lines +237 to +263
try {
// Check read access
fs.accessSync(targetFilePath, fs.constants.R_OK);

// Check write access
try {
fs.accessSync(targetFilePath, fs.constants.W_OK);
console.log(
chalk.green("✓") +
` Target file exists: ${targetFilePath}`,
);
checksPassedCount++;
} catch (error) {
console.log(
chalk.red("✗") +
` Target file exists but is not writable: ${targetFilePath}`,
);
errorCount++;
allTargetDirsWritable = false;
}
} catch (error) {
console.log(
chalk.red("✗") +
` Target file exists but is not readable: ${targetFilePath}`,
);
errorCount++;
}
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

[nitpick] The read access check on line 239 is not wrapped in a try-catch, but it's within an outer try-catch block that starts at line 237. This means if the read access fails, it will be caught by the outer catch at line 257, which outputs 'not readable'. However, the nested try-catch for write access (lines 242-256) can make the control flow confusing. Consider restructuring to separate read and write access checks more clearly for better maintainability.

Suggested change
try {
// Check read access
fs.accessSync(targetFilePath, fs.constants.R_OK);
// Check write access
try {
fs.accessSync(targetFilePath, fs.constants.W_OK);
console.log(
chalk.green("✓") +
` Target file exists: ${targetFilePath}`,
);
checksPassedCount++;
} catch (error) {
console.log(
chalk.red("✗") +
` Target file exists but is not writable: ${targetFilePath}`,
);
errorCount++;
allTargetDirsWritable = false;
}
} catch (error) {
console.log(
chalk.red("✗") +
` Target file exists but is not readable: ${targetFilePath}`,
);
errorCount++;
}
// Check read access
try {
fs.accessSync(targetFilePath, fs.constants.R_OK);
} catch (error) {
console.log(
chalk.red("✗") +
` Target file exists but is not readable: ${targetFilePath}`,
);
errorCount++;
continue;
}
// Check write access
try {
fs.accessSync(targetFilePath, fs.constants.W_OK);
console.log(
chalk.green("✓") +
` Target file exists: ${targetFilePath}`,
);
checksPassedCount++;
} catch (error) {
console.log(
chalk.red("✗") +
` Target file exists but is not writable: ${targetFilePath}`,
);
errorCount++;
allTargetDirsWritable = false;
}

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,376 @@
import {
bucketTypeSchema,
I18nConfig,
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

Unused import I18nConfig.

Suggested change
I18nConfig,

Copilot uses AI. Check for mistakes.
import * as path from "path";
import { getConfig } from "../utils/config";
import { getSettings } from "../utils/settings";
import { CLIError } from "../utils/errors";
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

Unused import CLIError.

Suggested change
import { CLIError } from "../utils/errors";

Copilot uses AI. Check for mistakes.
@sumitsaurabh927
Copy link
Contributor

@navyansh007 please resolve the comments

@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

Hey @navyansh007! Just checking in - are you still working on this PR? We noticed there are some comments that may need addressing. If you need more time, no problem! Just let us know. If we don't hear back within a week, we'll close this to keep the repo tidy, but you can always reopen when ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Add lingo.dev validate command for configuration validation

2 participants