Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nasty-nails-repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"lingo.dev": minor
---

feat: add init cursor command for .cursorrules setup
10 changes: 10 additions & 0 deletions packages/cli/src/cli/cmd/assets/agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Cursor AI i18n Rules
The following rules and guidelines should be followed to ensure proper internationalization (i18n) support in Cursor AI agents:
1. **Use translation keys**: All user-facing strings must use translation keys instead of hardcoded text. Reference the appropriate key from your locale files.
2. **Locale files**: Store translations in locale-specific files (e.g., `en.json`, `fr.json`). Ensure all supported languages are kept in sync.
3. **Fallback language**: Always provide a fallback language (usually English) for missing translations.
4. **Pluralization and formatting**: Use i18n libraries that support pluralization, date, and number formatting according to the user's locale.
5. **No concatenation**: Avoid string concatenation for translatable text. Use interpolation features provided by your i18n library.
6. **Contextual translations**: Provide context for translators where necessary, especially for ambiguous terms.
7. **Testing**: Test agents in multiple locales to ensure all strings are translated and formatting is correct.
_For more details, refer to the Cursor AI i18n documentation or contact the localization team._
5 changes: 3 additions & 2 deletions packages/cli/src/cli/cmd/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ensurePatterns } from "../utils/ensure-patterns";
import updateGitignore from "../utils/update-gitignore";
import initCICD from "../utils/init-ci-cd";
import open from "open";
import cursorInitCmd from "./init/cursor";

const openUrl = (path: string) => {
const settings = getSettings(undefined);
Expand Down Expand Up @@ -116,7 +117,6 @@ export default new InteractiveCommand()
throw new Error(`Invalid path: ${p}`);
}
}

return values;
})
.prompt(undefined) // make non-interactive
Expand Down Expand Up @@ -258,4 +258,5 @@ export default new InteractiveCommand()
if (!isInteractive) {
Ora().info("Please see https://lingo.dev/cli");
}
});
})
.addCommand(cursorInitCmd);
54 changes: 54 additions & 0 deletions packages/cli/src/cli/cmd/init/cursor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { InteractiveCommand, InteractiveOption } from "interactive-commander";
import Ora from "ora";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { confirm } from "@inquirer/prompts";

// Get the directory of this file (works in both dev and production)
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Access agents.md from assets directory (bundled with published package)
const AGENTS_MD = path.resolve(__dirname, "../assets/agents.md");
// Create .cursorrules in user's current working directory (their project)
const CURSORRULES = path.resolve(process.cwd(), ".cursorrules");

export default new InteractiveCommand()
.command("cursor")
.description("Initialize .cursorrules with i18n-specific instructions for Cursor AI.")
.addOption(
new InteractiveOption("-f, --force", "Overwrite .cursorrules without prompt.")
.default(false)
)
.action(async (options) => {
const spinner = Ora();
// Read agents.md
let template: string;
try {
template = fs.readFileSync(AGENTS_MD, "utf-8");
} catch (err) {
spinner.fail("Template file agents.md not found. Please reinstall the package.");
return process.exit(1);
}
// Check for existing .cursorrules
const exists = fs.existsSync(CURSORRULES);
let shouldWrite;
if (exists && !options.force) {
shouldWrite = await confirm({
message: ".cursorrules already exists. Overwrite?",
});
if (!shouldWrite) {
spinner.info("Skipped: .cursorrules left unchanged.");
return;
}
}
try {
fs.writeFileSync(CURSORRULES, template);
spinner.succeed("Created .cursorrules");
spinner.info(
".cursorrules has been created with i18n-specific instructions for Cursor AI.",
);
} catch (err) {
spinner.fail(`Failed to write .cursorrules: ${err}`);
process.exit(1);
}
});