diff --git a/.changeset/nasty-nails-repair.md b/.changeset/nasty-nails-repair.md new file mode 100644 index 000000000..4278f0992 --- /dev/null +++ b/.changeset/nasty-nails-repair.md @@ -0,0 +1,5 @@ +--- +"lingo.dev": minor +--- + +feat: add init cursor command for .cursorrules setup diff --git a/packages/cli/assets/agents.md b/packages/cli/assets/agents.md new file mode 100644 index 000000000..50bb1713b --- /dev/null +++ b/packages/cli/assets/agents.md @@ -0,0 +1,13 @@ +# 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._ diff --git a/packages/cli/src/cli/cmd/init.ts b/packages/cli/src/cli/cmd/init.ts index fed7b41d0..40f7522f3 100644 --- a/packages/cli/src/cli/cmd/init.ts +++ b/packages/cli/src/cli/cmd/init.ts @@ -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); @@ -116,7 +117,6 @@ export default new InteractiveCommand() throw new Error(`Invalid path: ${p}`); } } - return values; }) .prompt(undefined) // make non-interactive @@ -258,4 +258,5 @@ export default new InteractiveCommand() if (!isInteractive) { Ora().info("Please see https://lingo.dev/cli"); } - }); + }) + .addCommand(cursorInitCmd); diff --git a/packages/cli/src/cli/cmd/init/cursor.ts b/packages/cli/src/cli/cmd/init/cursor.ts new file mode 100644 index 000000000..788b775cf --- /dev/null +++ b/packages/cli/src/cli/cmd/init/cursor.ts @@ -0,0 +1,58 @@ +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); + } + });