#
tokens: 49793/50000 72/626 files (page 3/16)
lines: off (toggle) GitHub
raw markdown copy
This is page 3 of 16. Use http://codebase.md/lingodotdev/lingo.dev?lines=false&page={x} to view the full context.

# Directory Structure

```
├── .changeset
│   ├── config.json
│   └── README.md
├── .claude
│   ├── agents
│   │   └── code-architect-reviewer.md
│   └── commands
│       ├── analyze-bucket-type.md
│       └── create-bucket-docs.md
├── .editorconfig
├── .github
│   ├── dependabot.yml
│   └── workflows
│       ├── docker.yml
│       ├── lingodotdev.yml
│       ├── pr-check.yml
│       ├── pr-lint.yml
│       └── release.yml
├── .gitignore
├── .husky
│   └── commit-msg
├── .npmrc
├── .prettierignore
├── .prettierrc
├── .vscode
│   ├── extensions.json
│   ├── launch.json
│   └── settings.json
├── action.yml
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── commitlint.config.js
├── composer.json
├── content
│   ├── banner.compiler.png
│   ├── banner.dark.png
│   └── banner.launch.png
├── CONTRIBUTING.md
├── DEBUGGING.md
├── demo
│   ├── adonisjs
│   │   ├── .editorconfig
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── ace.js
│   │   ├── adonisrc.ts
│   │   ├── app
│   │   │   ├── exceptions
│   │   │   │   └── handler.ts
│   │   │   └── middleware
│   │   │       └── container_bindings_middleware.ts
│   │   ├── bin
│   │   │   ├── console.ts
│   │   │   ├── server.ts
│   │   │   └── test.ts
│   │   ├── CHANGELOG.md
│   │   ├── config
│   │   │   ├── app.ts
│   │   │   ├── bodyparser.ts
│   │   │   ├── cors.ts
│   │   │   ├── hash.ts
│   │   │   ├── inertia.ts
│   │   │   ├── logger.ts
│   │   │   ├── session.ts
│   │   │   ├── shield.ts
│   │   │   ├── static.ts
│   │   │   └── vite.ts
│   │   ├── eslint.config.js
│   │   ├── inertia
│   │   │   ├── app
│   │   │   │   ├── app.tsx
│   │   │   │   └── ssr.tsx
│   │   │   ├── css
│   │   │   │   └── app.css
│   │   │   ├── lingo
│   │   │   │   ├── dictionary.js
│   │   │   │   └── meta.json
│   │   │   ├── pages
│   │   │   │   ├── errors
│   │   │   │   │   ├── not_found.tsx
│   │   │   │   │   └── server_error.tsx
│   │   │   │   └── home.tsx
│   │   │   └── tsconfig.json
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── resources
│   │   │   └── views
│   │   │       └── inertia_layout.edge
│   │   ├── start
│   │   │   ├── env.ts
│   │   │   ├── kernel.ts
│   │   │   └── routes.ts
│   │   ├── tests
│   │   │   └── bootstrap.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── next-app
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── eslint.config.mjs
│   │   ├── next.config.ts
│   │   ├── package.json
│   │   ├── postcss.config.mjs
│   │   ├── public
│   │   │   ├── file.svg
│   │   │   ├── globe.svg
│   │   │   ├── next.svg
│   │   │   ├── vercel.svg
│   │   │   └── window.svg
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── app
│   │   │   │   ├── client-component.tsx
│   │   │   │   ├── favicon.ico
│   │   │   │   ├── globals.css
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── lingo-dot-dev.tsx
│   │   │   │   ├── page.tsx
│   │   │   │   └── test
│   │   │   │       └── page.tsx
│   │   │   ├── components
│   │   │   │   ├── hero-actions.tsx
│   │   │   │   ├── hero-subtitle.tsx
│   │   │   │   ├── hero-title.tsx
│   │   │   │   └── index.ts
│   │   │   └── lingo
│   │   │       ├── dictionary.js
│   │   │       └── meta.json
│   │   └── tsconfig.json
│   ├── react-router-app
│   │   ├── .dockerignore
│   │   ├── .gitignore
│   │   ├── app
│   │   │   ├── app.css
│   │   │   ├── lingo
│   │   │   │   ├── dictionary.js
│   │   │   │   └── meta.json
│   │   │   ├── root.tsx
│   │   │   ├── routes
│   │   │   │   ├── home.tsx
│   │   │   │   └── test.tsx
│   │   │   ├── routes.ts
│   │   │   └── welcome
│   │   │       ├── lingo-dot-dev.tsx
│   │   │       ├── logo-dark.svg
│   │   │       ├── logo-light.svg
│   │   │       └── welcome.tsx
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   ├── public
│   │   │   └── favicon.ico
│   │   ├── react-router.config.ts
│   │   ├── README.md
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   └── vite-project
│       ├── .gitignore
│       ├── CHANGELOG.md
│       ├── eslint.config.js
│       ├── index.html
│       ├── package.json
│       ├── public
│       │   └── vite.svg
│       ├── README.md
│       ├── src
│       │   ├── App.css
│       │   ├── App.tsx
│       │   ├── assets
│       │   │   └── react.svg
│       │   ├── components
│       │   │   └── test.tsx
│       │   ├── index.css
│       │   ├── lingo
│       │   │   ├── dictionary.js
│       │   │   └── meta.json
│       │   ├── lingo-dot-dev.tsx
│       │   ├── main.tsx
│       │   └── vite-env.d.ts
│       ├── tsconfig.app.json
│       ├── tsconfig.json
│       ├── tsconfig.node.json
│       └── vite.config.ts
├── Dockerfile
├── i18n.json
├── i18n.lock
├── integrations
│   └── directus
│       ├── .gitignore
│       ├── CHANGELOG.md
│       ├── docker-compose.yml
│       ├── Dockerfile
│       ├── package.json
│       ├── README.md
│       ├── src
│       │   ├── api.ts
│       │   ├── app.ts
│       │   └── index.spec.ts
│       ├── tsconfig.json
│       ├── tsconfig.test.json
│       └── tsup.config.ts
├── ISSUE_TEMPLATE.md
├── legacy
│   ├── cli
│   │   ├── bin
│   │   │   └── cli.mjs
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   └── readme.md
│   └── sdk
│       ├── CHANGELOG.md
│       ├── index.d.ts
│       ├── index.js
│       ├── package.json
│       └── README.md
├── LICENSE.md
├── mcp.md
├── package.json
├── packages
│   ├── cli
│   │   ├── assets
│   │   │   ├── failure.mp3
│   │   │   └── success.mp3
│   │   ├── bin
│   │   │   └── cli.mjs
│   │   ├── CHANGELOG.md
│   │   ├── demo
│   │   │   ├── android
│   │   │   │   ├── en
│   │   │   │   │   └── example.xml
│   │   │   │   ├── es
│   │   │   │   │   └── example.xml
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── csv
│   │   │   │   ├── example.csv
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── demo.spec.ts
│   │   │   ├── ejs
│   │   │   │   ├── en
│   │   │   │   │   └── example.ejs
│   │   │   │   ├── es
│   │   │   │   │   └── example.ejs
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── flutter
│   │   │   │   ├── en
│   │   │   │   │   └── example.arb
│   │   │   │   ├── es
│   │   │   │   │   └── example.arb
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── html
│   │   │   │   ├── en
│   │   │   │   │   └── example.html
│   │   │   │   ├── es
│   │   │   │   │   └── example.html
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── json
│   │   │   │   ├── en
│   │   │   │   │   └── example.json
│   │   │   │   ├── es
│   │   │   │   │   └── example.json
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── json-dictionary
│   │   │   │   ├── example.json
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── json5
│   │   │   │   ├── en
│   │   │   │   │   └── example.json5
│   │   │   │   ├── es
│   │   │   │   │   └── example.json5
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── jsonc
│   │   │   │   ├── en
│   │   │   │   │   └── example.jsonc
│   │   │   │   ├── es
│   │   │   │   │   └── example.jsonc
│   │   │   │   ├── i18n.json
│   │   │   │   ├── i18n.lock
│   │   │   │   └── ru
│   │   │   │       └── example.jsonc
│   │   │   ├── markdoc
│   │   │   │   ├── en
│   │   │   │   │   └── example.markdoc
│   │   │   │   ├── es
│   │   │   │   │   └── example.markdoc
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── markdown
│   │   │   │   ├── en
│   │   │   │   │   └── example.md
│   │   │   │   ├── es
│   │   │   │   │   └── example.md
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── mdx
│   │   │   │   ├── en
│   │   │   │   │   └── example.mdx
│   │   │   │   ├── es
│   │   │   │   │   └── example.mdx
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── php
│   │   │   │   ├── en
│   │   │   │   │   └── example.php
│   │   │   │   ├── es
│   │   │   │   │   └── example.php
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── po
│   │   │   │   ├── en
│   │   │   │   │   └── example.po
│   │   │   │   ├── es
│   │   │   │   │   └── example.po
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── properties
│   │   │   │   ├── en
│   │   │   │   │   └── example.properties
│   │   │   │   ├── es
│   │   │   │   │   └── example.properties
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── run_i18n.sh
│   │   │   ├── srt
│   │   │   │   ├── en
│   │   │   │   │   └── example.srt
│   │   │   │   ├── es
│   │   │   │   │   └── example.srt
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── txt
│   │   │   │   ├── en
│   │   │   │   │   └── example.txt
│   │   │   │   ├── es
│   │   │   │   │   └── example.txt
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── typescript
│   │   │   │   ├── en
│   │   │   │   │   └── example.ts
│   │   │   │   ├── es
│   │   │   │   │   └── example.ts
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── vtt
│   │   │   │   ├── en
│   │   │   │   │   └── example.vtt
│   │   │   │   ├── es
│   │   │   │   │   └── example.vtt
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── vue-json
│   │   │   │   ├── example.vue
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── xcode-strings
│   │   │   │   ├── en
│   │   │   │   │   └── example.strings
│   │   │   │   ├── es
│   │   │   │   │   └── example.strings
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── xcode-stringsdict
│   │   │   │   ├── en
│   │   │   │   │   └── example.stringsdict
│   │   │   │   ├── es
│   │   │   │   │   └── example.stringsdict
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── xcode-xcstrings
│   │   │   │   ├── example.xcstrings
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── xcode-xcstrings-v2
│   │   │   │   ├── complex-example.xcstrings
│   │   │   │   ├── example.xcstrings
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── xliff
│   │   │   │   ├── en
│   │   │   │   │   ├── example-v1.2.xliff
│   │   │   │   │   └── example-v2.xliff
│   │   │   │   ├── es
│   │   │   │   │   ├── example-v1.2.xliff
│   │   │   │   │   ├── example-v2.xliff
│   │   │   │   │   └── example.xliff
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── xml
│   │   │   │   ├── en
│   │   │   │   │   └── example.xml
│   │   │   │   ├── es
│   │   │   │   │   └── example.xml
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   ├── yaml
│   │   │   │   ├── en
│   │   │   │   │   └── example.yml
│   │   │   │   ├── es
│   │   │   │   │   └── example.yml
│   │   │   │   ├── i18n.json
│   │   │   │   └── i18n.lock
│   │   │   └── yaml-root-key
│   │   │       ├── en
│   │   │       │   └── example.yml
│   │   │       ├── es
│   │   │       │   └── example.yml
│   │   │       ├── i18n.json
│   │   │       └── i18n.lock
│   │   ├── i18n.json
│   │   ├── i18n.lock
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── cli
│   │   │   │   ├── cmd
│   │   │   │   │   ├── auth.ts
│   │   │   │   │   ├── ci
│   │   │   │   │   │   ├── flows
│   │   │   │   │   │   │   ├── _base.ts
│   │   │   │   │   │   │   ├── in-branch.ts
│   │   │   │   │   │   │   └── pull-request.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── platforms
│   │   │   │   │   │       ├── _base.ts
│   │   │   │   │   │       ├── bitbucket.ts
│   │   │   │   │   │       ├── github.ts
│   │   │   │   │   │       ├── gitlab.ts
│   │   │   │   │   │       └── index.ts
│   │   │   │   │   ├── cleanup.ts
│   │   │   │   │   ├── config
│   │   │   │   │   │   ├── get.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── set.ts
│   │   │   │   │   │   └── unset.ts
│   │   │   │   │   ├── i18n.ts
│   │   │   │   │   ├── init.ts
│   │   │   │   │   ├── lockfile.ts
│   │   │   │   │   ├── login.ts
│   │   │   │   │   ├── logout.ts
│   │   │   │   │   ├── may-the-fourth.ts
│   │   │   │   │   ├── mcp.ts
│   │   │   │   │   ├── purge.ts
│   │   │   │   │   ├── run
│   │   │   │   │   │   ├── _const.ts
│   │   │   │   │   │   ├── _types.ts
│   │   │   │   │   │   ├── _utils.ts
│   │   │   │   │   │   ├── execute.spec.ts
│   │   │   │   │   │   ├── execute.ts
│   │   │   │   │   │   ├── frozen.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── plan.ts
│   │   │   │   │   │   ├── setup.ts
│   │   │   │   │   │   └── watch.ts
│   │   │   │   │   ├── show
│   │   │   │   │   │   ├── _shared-key-command.ts
│   │   │   │   │   │   ├── config.ts
│   │   │   │   │   │   ├── files.ts
│   │   │   │   │   │   ├── ignored-keys.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── locale.ts
│   │   │   │   │   │   └── locked-keys.ts
│   │   │   │   │   └── status.ts
│   │   │   │   ├── constants.ts
│   │   │   │   ├── index.spec.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── loaders
│   │   │   │   │   ├── _types.ts
│   │   │   │   │   ├── _utils.ts
│   │   │   │   │   ├── android.spec.ts
│   │   │   │   │   ├── android.ts
│   │   │   │   │   ├── csv.spec.ts
│   │   │   │   │   ├── csv.ts
│   │   │   │   │   ├── dato
│   │   │   │   │   │   ├── _base.ts
│   │   │   │   │   │   ├── _utils.ts
│   │   │   │   │   │   ├── api.ts
│   │   │   │   │   │   ├── extract.ts
│   │   │   │   │   │   ├── filter.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ejs.spec.ts
│   │   │   │   │   ├── ejs.ts
│   │   │   │   │   ├── ensure-key-order.spec.ts
│   │   │   │   │   ├── ensure-key-order.ts
│   │   │   │   │   ├── flat.spec.ts
│   │   │   │   │   ├── flat.ts
│   │   │   │   │   ├── flutter.spec.ts
│   │   │   │   │   ├── flutter.ts
│   │   │   │   │   ├── formatters
│   │   │   │   │   │   ├── _base.ts
│   │   │   │   │   │   ├── biome.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── prettier.ts
│   │   │   │   │   ├── html.ts
│   │   │   │   │   ├── icu-safety.spec.ts
│   │   │   │   │   ├── ignored-keys-buckets.spec.ts
│   │   │   │   │   ├── ignored-keys.spec.ts
│   │   │   │   │   ├── ignored-keys.ts
│   │   │   │   │   ├── index.spec.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── inject-locale.spec.ts
│   │   │   │   │   ├── inject-locale.ts
│   │   │   │   │   ├── json-dictionary.spec.ts
│   │   │   │   │   ├── json-dictionary.ts
│   │   │   │   │   ├── json-sorting.test.ts
│   │   │   │   │   ├── json-sorting.ts
│   │   │   │   │   ├── json.ts
│   │   │   │   │   ├── json5.spec.ts
│   │   │   │   │   ├── json5.ts
│   │   │   │   │   ├── jsonc.spec.ts
│   │   │   │   │   ├── jsonc.ts
│   │   │   │   │   ├── locked-keys.spec.ts
│   │   │   │   │   ├── locked-keys.ts
│   │   │   │   │   ├── locked-patterns.spec.ts
│   │   │   │   │   ├── locked-patterns.ts
│   │   │   │   │   ├── markdoc.spec.ts
│   │   │   │   │   ├── markdoc.ts
│   │   │   │   │   ├── markdown.ts
│   │   │   │   │   ├── mdx.spec.ts
│   │   │   │   │   ├── mdx.ts
│   │   │   │   │   ├── mdx2
│   │   │   │   │   │   ├── _types.ts
│   │   │   │   │   │   ├── _utils.ts
│   │   │   │   │   │   ├── code-placeholder.spec.ts
│   │   │   │   │   │   ├── code-placeholder.ts
│   │   │   │   │   │   ├── frontmatter-split.spec.ts
│   │   │   │   │   │   ├── frontmatter-split.ts
│   │   │   │   │   │   ├── localizable-document.spec.ts
│   │   │   │   │   │   ├── localizable-document.ts
│   │   │   │   │   │   ├── section-split.spec.ts
│   │   │   │   │   │   ├── section-split.ts
│   │   │   │   │   │   └── sections-split-2.ts
│   │   │   │   │   ├── passthrough.ts
│   │   │   │   │   ├── php.ts
│   │   │   │   │   ├── plutil-json-loader.ts
│   │   │   │   │   ├── po
│   │   │   │   │   │   ├── _types.ts
│   │   │   │   │   │   ├── index.spec.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── properties.ts
│   │   │   │   │   ├── root-key.ts
│   │   │   │   │   ├── srt.ts
│   │   │   │   │   ├── sync.ts
│   │   │   │   │   ├── text-file.ts
│   │   │   │   │   ├── txt.ts
│   │   │   │   │   ├── typescript
│   │   │   │   │   │   ├── cjs-interop.ts
│   │   │   │   │   │   ├── index.spec.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── unlocalizable.spec.ts
│   │   │   │   │   ├── unlocalizable.ts
│   │   │   │   │   ├── variable
│   │   │   │   │   │   ├── index.spec.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── vtt.ts
│   │   │   │   │   ├── vue-json.ts
│   │   │   │   │   ├── xcode-strings
│   │   │   │   │   │   ├── escape.ts
│   │   │   │   │   │   ├── parser.ts
│   │   │   │   │   │   ├── tokenizer.ts
│   │   │   │   │   │   └── types.ts
│   │   │   │   │   ├── xcode-strings.spec.ts
│   │   │   │   │   ├── xcode-strings.ts
│   │   │   │   │   ├── xcode-stringsdict.ts
│   │   │   │   │   ├── xcode-xcstrings-icu.spec.ts
│   │   │   │   │   ├── xcode-xcstrings-icu.ts
│   │   │   │   │   ├── xcode-xcstrings-lock-compatibility.spec.ts
│   │   │   │   │   ├── xcode-xcstrings-v2-loader.ts
│   │   │   │   │   ├── xcode-xcstrings.spec.ts
│   │   │   │   │   ├── xcode-xcstrings.ts
│   │   │   │   │   ├── xliff.spec.ts
│   │   │   │   │   ├── xliff.ts
│   │   │   │   │   ├── xml.ts
│   │   │   │   │   └── yaml.ts
│   │   │   │   ├── localizer
│   │   │   │   │   ├── _types.ts
│   │   │   │   │   ├── explicit.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── lingodotdev.ts
│   │   │   │   ├── processor
│   │   │   │   │   ├── _base.ts
│   │   │   │   │   ├── basic.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── lingo.ts
│   │   │   │   └── utils
│   │   │   │       ├── auth.ts
│   │   │   │       ├── buckets.spec.ts
│   │   │   │       ├── buckets.ts
│   │   │   │       ├── cache.ts
│   │   │   │       ├── cloudflare-status.ts
│   │   │   │       ├── config.ts
│   │   │   │       ├── delta.spec.ts
│   │   │   │       ├── delta.ts
│   │   │   │       ├── ensure-patterns.ts
│   │   │   │       ├── errors.ts
│   │   │   │       ├── exec.spec.ts
│   │   │   │       ├── exec.ts
│   │   │   │       ├── exit-gracefully.spec.ts
│   │   │   │       ├── exit-gracefully.ts
│   │   │   │       ├── exp-backoff.ts
│   │   │   │       ├── find-locale-paths.spec.ts
│   │   │   │       ├── find-locale-paths.ts
│   │   │   │       ├── fs.ts
│   │   │   │       ├── init-ci-cd.ts
│   │   │   │       ├── key-matching.spec.ts
│   │   │   │       ├── key-matching.ts
│   │   │   │       ├── lockfile.ts
│   │   │   │       ├── md5.ts
│   │   │   │       ├── observability.ts
│   │   │   │       ├── plutil-formatter.spec.ts
│   │   │   │       ├── plutil-formatter.ts
│   │   │   │       ├── settings.ts
│   │   │   │       ├── ui.ts
│   │   │   │       └── update-gitignore.ts
│   │   │   ├── compiler
│   │   │   │   └── index.ts
│   │   │   ├── locale-codes
│   │   │   │   └── index.ts
│   │   │   ├── react
│   │   │   │   ├── client.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── react-router.ts
│   │   │   │   └── rsc.ts
│   │   │   ├── sdk
│   │   │   │   └── index.ts
│   │   │   └── spec
│   │   │       └── index.ts
│   │   ├── tests
│   │   │   └── mock-storage.ts
│   │   ├── troubleshooting.md
│   │   ├── tsconfig.json
│   │   ├── tsconfig.test.json
│   │   ├── tsup.config.ts
│   │   ├── types
│   │   │   ├── vtt.d.ts
│   │   │   └── xliff.d.ts
│   │   ├── vitest.config.ts
│   │   └── WATCH_MODE.md
│   ├── compiler
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── _base.ts
│   │   │   ├── _const.ts
│   │   │   ├── _loader-utils.spec.ts
│   │   │   ├── _loader-utils.ts
│   │   │   ├── _utils.spec.ts
│   │   │   ├── _utils.ts
│   │   │   ├── client-dictionary-loader.ts
│   │   │   ├── i18n-directive.spec.ts
│   │   │   ├── i18n-directive.ts
│   │   │   ├── index.spec.ts
│   │   │   ├── index.ts
│   │   │   ├── jsx-attribute-flag.spec.ts
│   │   │   ├── jsx-attribute-flag.ts
│   │   │   ├── jsx-attribute-scope-inject.spec.ts
│   │   │   ├── jsx-attribute-scope-inject.ts
│   │   │   ├── jsx-attribute-scopes-export.spec.ts
│   │   │   ├── jsx-attribute-scopes-export.ts
│   │   │   ├── jsx-attribute.spec.ts
│   │   │   ├── jsx-attribute.ts
│   │   │   ├── jsx-fragment.spec.ts
│   │   │   ├── jsx-fragment.ts
│   │   │   ├── jsx-html-lang.spec.ts
│   │   │   ├── jsx-html-lang.ts
│   │   │   ├── jsx-provider.spec.ts
│   │   │   ├── jsx-provider.ts
│   │   │   ├── jsx-remove-attributes.spec.ts
│   │   │   ├── jsx-remove-attributes.ts
│   │   │   ├── jsx-root-flag.spec.ts
│   │   │   ├── jsx-root-flag.ts
│   │   │   ├── jsx-scope-flag.spec.ts
│   │   │   ├── jsx-scope-flag.ts
│   │   │   ├── jsx-scope-inject.spec.ts
│   │   │   ├── jsx-scope-inject.ts
│   │   │   ├── jsx-scopes-export.spec.ts
│   │   │   ├── jsx-scopes-export.ts
│   │   │   ├── lib
│   │   │   │   └── lcp
│   │   │   │       ├── api
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── prompt.spec.ts
│   │   │   │       │   ├── prompt.ts
│   │   │   │       │   ├── provider-details.spec.ts
│   │   │   │       │   ├── provider-details.ts
│   │   │   │       │   ├── shots.ts
│   │   │   │       │   ├── xml2obj.spec.ts
│   │   │   │       │   └── xml2obj.ts
│   │   │   │       ├── api.spec.ts
│   │   │   │       ├── cache.spec.ts
│   │   │   │       ├── cache.ts
│   │   │   │       ├── index.spec.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── schema.ts
│   │   │   │       ├── server.spec.ts
│   │   │   │       └── server.ts
│   │   │   ├── lingo-turbopack-loader.ts
│   │   │   ├── react-router-dictionary-loader.ts
│   │   │   ├── rsc-dictionary-loader.ts
│   │   │   └── utils
│   │   │       ├── ast-key.spec.ts
│   │   │       ├── ast-key.ts
│   │   │       ├── create-locale-import-map.spec.ts
│   │   │       ├── create-locale-import-map.ts
│   │   │       ├── env.spec.ts
│   │   │       ├── env.ts
│   │   │       ├── hash.spec.ts
│   │   │       ├── hash.ts
│   │   │       ├── index.spec.ts
│   │   │       ├── index.ts
│   │   │       ├── invokations.spec.ts
│   │   │       ├── invokations.ts
│   │   │       ├── jsx-attribute-scope.ts
│   │   │       ├── jsx-attribute.spec.ts
│   │   │       ├── jsx-attribute.ts
│   │   │       ├── jsx-content-whitespace.spec.ts
│   │   │       ├── jsx-content.spec.ts
│   │   │       ├── jsx-content.ts
│   │   │       ├── jsx-element.spec.ts
│   │   │       ├── jsx-element.ts
│   │   │       ├── jsx-expressions.test.ts
│   │   │       ├── jsx-expressions.ts
│   │   │       ├── jsx-functions.spec.ts
│   │   │       ├── jsx-functions.ts
│   │   │       ├── jsx-scope.spec.ts
│   │   │       ├── jsx-scope.ts
│   │   │       ├── jsx-variables.spec.ts
│   │   │       ├── jsx-variables.ts
│   │   │       ├── llm-api-key.ts
│   │   │       ├── llm-api-keys.spec.ts
│   │   │       ├── locales.spec.ts
│   │   │       ├── locales.ts
│   │   │       ├── module-params.spec.ts
│   │   │       ├── module-params.ts
│   │   │       ├── observability.spec.ts
│   │   │       ├── observability.ts
│   │   │       ├── rc.spec.ts
│   │   │       └── rc.ts
│   │   ├── tsconfig.json
│   │   ├── tsup.config.ts
│   │   └── vitest.config.ts
│   ├── locales
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── constants.ts
│   │   │   ├── index.ts
│   │   │   ├── names
│   │   │   │   ├── index.spec.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── integration.spec.ts
│   │   │   │   └── loader.ts
│   │   │   ├── parser.spec.ts
│   │   │   ├── parser.ts
│   │   │   ├── types.ts
│   │   │   ├── validation.spec.ts
│   │   │   └── validation.ts
│   │   ├── tsconfig.json
│   │   └── tsup.config.ts
│   ├── react
│   │   ├── build.config.ts
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── client
│   │   │   │   ├── attribute-component.spec.tsx
│   │   │   │   ├── attribute-component.tsx
│   │   │   │   ├── component.lingo-component.spec.tsx
│   │   │   │   ├── component.spec.tsx
│   │   │   │   ├── component.tsx
│   │   │   │   ├── context.spec.tsx
│   │   │   │   ├── context.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── loader.spec.ts
│   │   │   │   ├── loader.ts
│   │   │   │   ├── locale-switcher.spec.tsx
│   │   │   │   ├── locale-switcher.tsx
│   │   │   │   ├── locale.spec.ts
│   │   │   │   ├── locale.ts
│   │   │   │   ├── provider.spec.tsx
│   │   │   │   ├── provider.tsx
│   │   │   │   ├── utils.spec.ts
│   │   │   │   └── utils.ts
│   │   │   ├── core
│   │   │   │   ├── attribute-component.spec.tsx
│   │   │   │   ├── attribute-component.tsx
│   │   │   │   ├── component.spec.tsx
│   │   │   │   ├── component.tsx
│   │   │   │   ├── const.ts
│   │   │   │   ├── get-dictionary.spec.ts
│   │   │   │   ├── get-dictionary.ts
│   │   │   │   └── index.ts
│   │   │   ├── react-router
│   │   │   │   ├── index.ts
│   │   │   │   ├── loader.spec.ts
│   │   │   │   └── loader.ts
│   │   │   ├── rsc
│   │   │   │   ├── attribute-component.tsx
│   │   │   │   ├── component.lingo-component.spec.tsx
│   │   │   │   ├── component.spec.tsx
│   │   │   │   ├── component.tsx
│   │   │   │   ├── index.ts
│   │   │   │   ├── loader.spec.ts
│   │   │   │   ├── loader.ts
│   │   │   │   ├── provider.spec.tsx
│   │   │   │   ├── provider.tsx
│   │   │   │   ├── utils.spec.ts
│   │   │   │   └── utils.ts
│   │   │   └── test
│   │   │       └── setup.ts
│   │   ├── tsconfig.json
│   │   └── vitest.config.ts
│   ├── sdk
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── abort-controller.specs.ts
│   │   │   ├── index.spec.ts
│   │   │   └── index.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.test.json
│   │   └── tsup.config.ts
│   └── spec
│       ├── CHANGELOG.md
│       ├── package.json
│       ├── README.md
│       ├── src
│       │   ├── config.spec.ts
│       │   ├── config.ts
│       │   ├── formats.ts
│       │   ├── index.spec.ts
│       │   ├── index.ts
│       │   ├── json-schema.ts
│       │   ├── locales.spec.ts
│       │   └── locales.ts
│       ├── tsconfig.json
│       ├── tsconfig.test.json
│       └── tsup.config.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── readme
│   ├── ar.md
│   ├── bn.md
│   ├── de.md
│   ├── en.md
│   ├── es.md
│   ├── fa.md
│   ├── fr.md
│   ├── he.md
│   ├── hi.md
│   ├── it.md
│   ├── ja.md
│   ├── ko.md
│   ├── pl.md
│   ├── pt-BR.md
│   ├── ru.md
│   ├── tr.md
│   ├── uk-UA.md
│   └── zh-Hans.md
├── readme.md
├── scripts
│   ├── docs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── generate-cli-docs.ts
│   │   │   ├── generate-config-docs.ts
│   │   │   ├── json-schema
│   │   │   │   ├── markdown-renderer.test.ts
│   │   │   │   ├── markdown-renderer.ts
│   │   │   │   ├── parser.test.ts
│   │   │   │   ├── parser.ts
│   │   │   │   └── types.ts
│   │   │   ├── utils.test.ts
│   │   │   └── utils.ts
│   │   ├── tsconfig.json
│   │   └── vitest.config.ts
│   └── packagist-publish.php
└── turbo.json
```

# Files

--------------------------------------------------------------------------------
/packages/cli/demo/html/es/example.html:
--------------------------------------------------------------------------------

```html
<!DOCTYPE html>
<html lang="es">
  <head>
    <title>MyApp - Hola Mundo</title>

    <meta name="description" content="Una aplicación de demostración simple" />
    <meta property="og:title" content="Demostración de MyApp" />

    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta charset="UTF-8" />

    <style>
      body {
        font-family: Arial, sans-serif;
        color: #333;
      }
      .highlight::before {
        content: "★ Featured";
      }
    </style>

    <script>
      const message = "User session initialized";
      console.log(message);
    </script>
  </head>
  <body>
    <h1>Bienvenido a MyApp</h1>

    <p>
      ¡Hola, mundo! Esta es una demostración simple con
      <strong>texto en negrita</strong>
      y
      <em>texto en cursiva</em>
      .
    </p>

    <div>
      <div>
        <span>Contenido anidado aquí</span>
      </div>
    </div>

    <img src="example.jpg" alt="Imagen de ejemplo" />

    <img
      src="example.jpg"
      alt="Imagen de demostración"
      title="View product details"
    />

    <input type="text" placeholder="Ingresa texto aquí" />

    <input
      type="text"
      placeholder="Ingresa valor"
      value="Default search query"
    />

    <a href="#" title="Haz clic para más">Saber más</a>

    <a href="not-localized.html" data-info="Navigation link" title="Navegar">
      Ir a la página
    </a>

    <div class="content-area" data-value="Main content">Área de contenido</div>

    <script>
      const inlineScript = "Page analytics loaded";
    </script>

    <style>
      .inline-style {
        content: "Notice: ";
      }
    </style>
  </body>
</html>
```

--------------------------------------------------------------------------------
/packages/cli/demo/mdx/es/example.mdx:
--------------------------------------------------------------------------------

```markdown
---
title: "Reseña de restaurante: Bella Vista"
description: Nuestra experiencia gastronómica en el nuevo restaurante italiano del centro
author: not-localized-author
published: 2024-03-15
rating: 4.5
locked_key_1: This value should remain unchanged in all locales
---

# Cena en Bella Vista

Finalmente probamos el nuevo restaurante italiano que abrió el mes pasado en la calle Principal. Aquí está nuestra reseña honesta.

## El ambiente

El restaurante tiene un ambiente cálido y acogedor con:

- **Iluminación tenue** que crea un entorno íntimo
- _Música suave de jazz_ sonando de fondo
- Flores frescas en cada mesa

### Cómo hacer reservas

[Reserva tu mesa en línea](https://example.com) o llama durante el horario comercial.

> Consejo: Las reservas de fin de semana se agotan rápidamente, ¡así que reserva con anticipación!

## Destacados del menú

```javascript
// Restaurant website code - not localized
function displayMenu(category) {
  const items = "This code stays in original language";
  return renderMenuItems(items);
}
```

```css
/* Styling for menu display - not localized */
.menu-item {
  color: "This CSS remains unchanged";
}
```

## Nuestro pedido

Comenzamos con la tabla de antipasto y la ensalada de la casa.

La pasta estaba cocinada perfectamente - exactamente `al_dente` como debe ser.

## Calidad del servicio

El personal de servicio estuvo atento pero no abrumador.

Nuestro camarero nos atendió regularmente, manteniendo `service.quality = "excellent"` durante toda la noche.

## Veredicto final

| Plato              | Calificación |
| ------------------ | ------------ |
| Entrantes          | `stars(4)`   |
| Platos principales | `stars(5)`   |

```

--------------------------------------------------------------------------------
/packages/compiler/src/rsc-dictionary-loader.ts:
--------------------------------------------------------------------------------

```typescript
import path from "path";
import { createCodeMutation } from "./_base";
import { LCP_DICTIONARY_FILE_NAME, ModuleId } from "./_const";
import { getModuleExecutionMode, getOrCreateImport } from "./utils";
import { findInvokations } from "./utils/invokations";
import * as t from "@babel/types";
import { getDictionaryPath } from "./_utils";
import { createLocaleImportMap } from "./utils/create-locale-import-map";

export const rscDictionaryLoaderMutation = createCodeMutation((payload) => {
  const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
  if (mode === "client") {
    return payload;
  }

  const invokations = findInvokations(payload.ast, {
    moduleName: ModuleId.ReactRSC,
    functionName: "loadDictionary",
  });

  const allLocales = Array.from(
    new Set([payload.params.sourceLocale, ...payload.params.targetLocales]),
  );

  for (const invokation of invokations) {
    const internalDictionaryLoader = getOrCreateImport(payload.ast, {
      moduleName: ModuleId.ReactRSC,
      exportedName: "loadDictionary_internal",
    });

    // Replace the function identifier with internal version
    if (t.isIdentifier(invokation.callee)) {
      invokation.callee.name = internalDictionaryLoader.importedName;
    }

    const dictionaryPath = getDictionaryPath({
      sourceRoot: payload.params.sourceRoot,
      lingoDir: payload.params.lingoDir,
      relativeFilePath: payload.relativeFilePath,
    });

    // Create locale import map object
    const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);

    // Add the locale import map as the second argument
    invokation.arguments.push(localeImportMap);
  }

  return payload;
});

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/llm-api-keys.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import * as dotenv from "dotenv";
import * as path from "path";
import { getKeyFromEnv } from "./llm-api-key";

const ORIGINAL_ENV = { ...process.env };

vi.mock("dotenv");

describe("LLM API keys", () => {
  describe("getKeyFromEnv", () => {
    beforeEach(() => {
      vi.resetModules();
      process.env = { ...ORIGINAL_ENV };
    });

    afterEach(() => {
      process.env = { ...ORIGINAL_ENV };
      vi.restoreAllMocks();
    });

    it("returns API key from process.env if set", () => {
      process.env.FOOBAR_API_KEY = "env-key";
      expect(getKeyFromEnv("FOOBAR_API_KEY")).toBe("env-key");
    });

    it("returns API key from .env file if not in process.env", () => {
      delete process.env.FOOBAR_API_KEY;
      const fakeEnv = { FOOBAR_API_KEY: "file-key" };
      const configMock = vi
        .mocked(dotenv.config)
        .mockImplementation((opts: any) => {
          if (opts && opts.processEnv) {
            Object.assign(opts.processEnv, fakeEnv);
          }
          return { parsed: fakeEnv };
        });
      expect(getKeyFromEnv("FOOBAR_API_KEY")).toBe("file-key");
      expect(configMock).toHaveBeenCalledWith({
        path: [
          path.resolve(process.cwd(), ".env"),
          path.resolve(process.cwd(), ".env.local"),
          path.resolve(process.cwd(), ".env.development"),
        ],
      });
    });

    it("returns undefined if no GROQ_API_KEY in env or .env file", () => {
      delete process.env.GROQ_API_KEY;
      vi.mocked(dotenv.config).mockResolvedValue({ parsed: {} });
      expect(getKeyFromEnv("FOOBAR_API_KEY")).toBeUndefined();
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/observability.ts:
--------------------------------------------------------------------------------

```typescript
import { machineId } from "node-machine-id";
import { getRc } from "./rc";

export default async function trackEvent(
  event: string,
  properties?: Record<string, any>,
) {
  if (process.env.DO_NOT_TRACK) {
    return;
  }

  try {
    const actualId = await getActualId();

    const { PostHog } = await import("posthog-node");
    const posthog = new PostHog(
      "phc_eR0iSoQufBxNY36k0f0T15UvHJdTfHlh8rJcxsfhfXk",
      {
        host: "https://eu.i.posthog.com",
        flushAt: 1,
        flushInterval: 0,
      },
    );

    await posthog.capture({
      distinctId: actualId,
      event,
      properties: {
        ...properties,
        isByokMode: properties?.models !== "lingo.dev",
        meta: {
          version: process.env.npm_package_version,
          isCi: process.env.CI === "true",
        },
      },
    });

    await posthog.shutdown();
  } catch (error) {
    if (process.env.DEBUG) {
      console.error(error);
    }
  }
}

async function getActualId() {
  const rc = getRc();
  const apiKey = process.env.LINGODOTDEV_API_KEY || rc?.auth?.apiKey;
  const apiUrl =
    process.env.LINGODOTDEV_API_URL ||
    rc?.auth?.apiUrl ||
    "https://engine.lingo.dev";

  if (apiKey) {
    try {
      const res = await fetch(`${apiUrl}/whoami`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${apiKey}`,
          ContentType: "application/json",
        },
      });
      if (res.ok) {
        const payload = await res.json();
        if (payload?.email) {
          return payload.email;
        }
      }
    } catch (err) {
      // ignore, fallback to device id
    }
  }
  const id = await machineId();
  return `device-${id}`;
}

```

--------------------------------------------------------------------------------
/demo/next-app/src/app/client-component.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import { useState } from "react";

export function ClientComponent() {
  const [counter, setCounter] = useState(0);

  return (
    <div className="flex flex-col gap-4 bg-gray-300 p-4 rounded-lg">
      <span className="color-white">Interactive component</span>
      <div className="flex items-center gap-4 justify-center w-100 border-2 border-gray-300 rounded-lg p-6 bg-white">
        <button
          onClick={() => setCounter(counter - 1)}
          className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-auto whitespace-nowrap cursor-pointer"
        >
          - Decrement
        </button>
        <span className="text-4xl" title="This is current counter value">
          {counter}
        </span>
        <button
          onClick={() => setCounter(counter + 1)}
          className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-auto whitespace-nowrap cursor-pointer"
        >
          + Increment
        </button>
      </div>
      <div className="h-8">
        {counter < -3 && (
          <span className="text-red-500">
            <strong>Error:</strong> Counter too low!
          </span>
        )}
        {counter > 5 && (
          <span className="text-red-500">
            <strong>Error:</strong> Counter too high!
          </span>
        )}
      </div>
    </div>
  );
}

```

--------------------------------------------------------------------------------
/packages/compiler/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@lingo.dev/_compiler",
  "version": "0.7.15",
  "description": "Lingo.dev Compiler",
  "private": false,
  "publishConfig": {
    "access": "public"
  },
  "sideEffects": false,
  "type": "module",
  "main": "build/index.cjs",
  "types": "build/index.d.ts",
  "module": "build/index.mjs",
  "files": [
    "build"
  ],
  "scripts": {
    "dev": "tsup --watch",
    "build": "pnpm typecheck && tsup",
    "typecheck": "tsc --noEmit",
    "clean": "rm -rf build",
    "test": "vitest --run",
    "test:watch": "vitest -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/babel__generator": "^7.6.8",
    "@types/babel__traverse": "^7.20.6",
    "@types/ini": "^4.1.1",
    "@types/lodash": "^4.17.4",
    "@types/object-hash": "^3.0.6",
    "@types/react": "^18.3.18",
    "next": "15.2.4",
    "tsup": "^8.3.5",
    "typescript": "^5.4.5",
    "vitest": "^2.1.4"
  },
  "dependencies": {
    "@ai-sdk/google": "^1.2.19",
    "@ai-sdk/groq": "^1.2.3",
    "@ai-sdk/mistral": "^1.2.8",
    "@babel/generator": "^7.26.5",
    "@babel/parser": "^7.26.7",
    "@babel/traverse": "^7.27.4",
    "@babel/types": "^7.26.7",
    "@lingo.dev/_sdk": "workspace:*",
    "@lingo.dev/_spec": "workspace:*",
    "@openrouter/ai-sdk-provider": "^0.7.1",
    "@prettier/sync": "^0.6.1",
    "ai": "^4.2.10",
    "dedent": "^1.6.0",
    "dotenv": "^16.4.5",
    "fast-xml-parser": "^5.0.8",
    "ini": "^5.0.0",
    "lodash": "^4.17.21",
    "object-hash": "^3.0.0",
    "ollama-ai-provider": "^1.2.0",
    "prettier": "^3.4.2",
    "unplugin": "^2.1.2",
    "zod": "^3.25.76",
    "posthog-node": "^5.5.1",
    "node-machine-id": "^1.1.12"
  },
  "packageManager": "[email protected]"
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/jsx-root-flag.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import jsxRootFlagMutation from "./jsx-root-flag";
import { createPayload, createOutput, defaultParams } from "./_base";

// Helper function to run mutation and get result
function runMutation(code: string) {
  const input = createPayload({ code, params: defaultParams, fileKey: "test" });
  const mutated = jsxRootFlagMutation(input);
  if (!mutated) throw new Error("Mutation returned null");
  return createOutput(mutated).code;
}

describe("jsxRootFlagMutation", () => {
  it("should add data-jsx-root flag to a single root JSX element", () => {
    const input = `
function Component() {
  return <div>Hello</div>;
}
`.trim();

    const expected = `
function Component() {
  return <div data-jsx-root>Hello</div>;
}
`.trim();
    const result = runMutation(input);

    expect(result).toBe(expected.trim());
  });

  it("should add data-jsx-root flag to multiple root JSX elements", () => {
    const input = `
function Component() {
  if (condition) {
    return <div>True</div>;
  }
  return <span>False</span>;
}
`.trim();

    const expected = `
function Component() {
  if (condition) {
    return <div data-jsx-root>True</div>;
  }
  return <span data-jsx-root>False</span>;
}
`.trim();
    const result = runMutation(input);

    expect(result).toBe(expected.trim());
  });

  it("should not add data-jsx-root flag to nested JSX elements", () => {
    const input = `
function Component() {
  return <div>
      <span>Nested</span>
    </div>;
}
`.trim();

    const expected = `
function Component() {
  return <div data-jsx-root>
      <span>Nested</span>
    </div>;
}
`.trim();

    const result = runMutation(input);

    expect(result).toBe(expected.trim());
  });
});

```

--------------------------------------------------------------------------------
/demo/adonisjs/bin/test.ts:
--------------------------------------------------------------------------------

```typescript
/*
|--------------------------------------------------------------------------
| Test runner entrypoint
|--------------------------------------------------------------------------
|
| The "test.ts" file is the entrypoint for running tests using Japa.
|
| Either you can run this file directly or use the "test"
| command to run this file and monitor file changes.
|
*/

// @ts-expect-error 2540
process.env.NODE_ENV = 'test'

import 'reflect-metadata'
import { Ignitor, prettyPrintError } from '@adonisjs/core'
import { configure, processCLIArgs, run } from '@japa/runner'

/**
 * URL to the application root. AdonisJS need it to resolve
 * paths to file and directories for scaffolding commands
 */
const APP_ROOT = new URL('../', import.meta.url)

/**
 * The importer is used to import files in context of the
 * application.
 */
const IMPORTER = (filePath: string) => {
  if (filePath.startsWith('./') || filePath.startsWith('../')) {
    return import(new URL(filePath, APP_ROOT).href)
  }
  return import(filePath)
}

new Ignitor(APP_ROOT, { importer: IMPORTER })
  .tap((app) => {
    app.booting(async () => {
      await import('#start/env')
    })
    app.listen('SIGTERM', () => app.terminate())
    app.listenIf(app.managedByPm2, 'SIGINT', () => app.terminate())
  })
  .testRunner()
  .configure(async (app) => {
    const { runnerHooks, ...config } = await import('../tests/bootstrap.js')

    processCLIArgs(process.argv.splice(2))
    configure({
      ...app.rcFile.tests,
      ...config,
      ...{
        setup: runnerHooks.setup,
        teardown: runnerHooks.teardown.concat([() => app.terminate()]),
      },
    })
  })
  .run(() => run())
  .catch((error) => {
    process.exitCode = 1
    prettyPrintError(error)
  })

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/ast-key.ts:
--------------------------------------------------------------------------------

```typescript
import { NodePath } from "@babel/traverse";
import * as t from "@babel/types";
import traverse from "@babel/traverse";

export function getAstKey(nodePath: NodePath) {
  const keyChunks: any[] = [];

  let current: NodePath | null = nodePath;
  while (current) {
    keyChunks.push(current.key);
    current = current.parentPath;

    if (t.isProgram(current?.node)) {
      break;
    }
  }

  const result = keyChunks.reverse().join("/");
  return result;
}

export function getAstByKey(ast: t.File, key: string) {
  const programPath = _getProgramNodePath(ast);
  if (!programPath) {
    return null;
  }

  const keyParts = key.split("/").reverse();

  let result: NodePath = programPath;

  while (true) {
    let currentKeyPart = keyParts.pop();
    if (!currentKeyPart) {
      break;
    }
    const isIntegerPart = Number.isInteger(Number(currentKeyPart));
    if (isIntegerPart) {
      const maybeBodyItemsArray = result.get("body");
      const bodyItemsArray = Array.isArray(maybeBodyItemsArray)
        ? maybeBodyItemsArray
        : [maybeBodyItemsArray];
      const index = Number(currentKeyPart);
      const subResult = bodyItemsArray[index];
      result = subResult as NodePath;
    } else {
      const maybeSubResultArray = result.get(currentKeyPart);
      const subResultArray = Array.isArray(maybeSubResultArray)
        ? maybeSubResultArray
        : [maybeSubResultArray];
      const subResult = subResultArray[0];
      result = subResult;
    }
  }

  return result;
}

function _getProgramNodePath(ast: t.File): NodePath<t.Program> | null {
  let result: NodePath<t.Program> | null = null;

  traverse(ast, {
    Program(nodePath) {
      result = nodePath;
      nodePath.stop();
    },
  });

  return result;
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/jsx-element.ts:
--------------------------------------------------------------------------------

```typescript
import * as t from "@babel/types";
import { NodePath } from "@babel/traverse";

export function getJsxElementName(nodePath: NodePath<t.JSXElement>) {
  const openingElement = nodePath.node.openingElement;

  // elements with simple (string) name
  if (t.isJSXIdentifier(openingElement.name)) {
    return openingElement.name.name;
  }

  // elements with dots in name
  if (t.isJSXMemberExpression(openingElement.name)) {
    const memberExpr = openingElement.name;
    const parts: string[] = [];

    // Traverse the member expression to collect all parts
    let current: t.JSXMemberExpression | t.JSXIdentifier = memberExpr;
    while (t.isJSXMemberExpression(current)) {
      parts.unshift(current.property.name);
      current = current.object;
    }

    // Add the base identifier
    if (t.isJSXIdentifier(current)) {
      parts.unshift(current.name);
    }

    return parts.join(".");
  }
  return null;
}

export function getNestedJsxElements(nodePath: NodePath<t.JSXElement>) {
  const nestedElements: t.JSXElement[] = [];

  nodePath.traverse({
    JSXElement(path) {
      if (path.node !== nodePath.node) {
        nestedElements.push(path.node);
      }
    },
  });

  const arrayOfElements = nestedElements.map((element, index) => {
    // Create a function that takes children as param and returns the JSX element
    const param = t.identifier("children");

    // Replace the original children with the param
    const clonedElement = t.cloneNode(element);
    clonedElement.children = [t.jsxExpressionContainer(param)];

    return t.arrowFunctionExpression(
      [t.objectPattern([t.objectProperty(param, param, false, true)])],
      clonedElement,
    );
  });
  const result = t.arrayExpression(arrayOfElements);
  return result;
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/exit-gracefully.ts:
--------------------------------------------------------------------------------

```typescript
const STEP_WAIT_INTERVAL = 250;
const MAX_WAIT_INTERVAL = 2000;

export function exitGracefully(elapsedMs = 0) {
  // Check if there are any pending operations
  const hasPendingOperations = checkForPendingOperations();

  if (hasPendingOperations && elapsedMs < MAX_WAIT_INTERVAL) {
    // Wait a bit longer if there are pending operations
    setTimeout(
      () => exitGracefully(elapsedMs + STEP_WAIT_INTERVAL),
      STEP_WAIT_INTERVAL,
    );
  } else {
    // Exit immediately if no pending operations
    process.exit(0);
  }
}

function checkForPendingOperations(): boolean {
  // Check for active handles and requests using internal Node.js methods
  const activeHandles = (process as any)._getActiveHandles?.() || [];
  const activeRequests = (process as any)._getActiveRequests?.() || [];

  // Filter out standard handles that are always present
  const nonStandardHandles = activeHandles.filter((handle: any) => {
    // Skip standard handles like process.stdin, process.stdout, etc.
    if (
      handle === process.stdin ||
      handle === process.stdout ||
      handle === process.stderr
    ) {
      return false;
    }
    // Skip timers that are part of the normal process
    if (
      handle &&
      typeof handle === "object" &&
      "hasRef" in handle &&
      !handle.hasRef()
    ) {
      return false;
    }
    return true;
  });

  // Check if there are any file watchers or other async operations
  const hasFileWatchers = nonStandardHandles.some(
    (handle: any) => handle && typeof handle === "object" && "close" in handle,
  );

  // Check for pending promises or async operations
  const hasPendingPromises = activeRequests.length > 0;

  return nonStandardHandles.length > 0 || hasFileWatchers || hasPendingPromises;
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/lib/lcp/api/provider-details.ts:
--------------------------------------------------------------------------------

```typescript
import { openrouter } from "@openrouter/ai-sdk-provider";

export const providerDetails: Record<
  string,
  {
    name: string; // Display name (e.g., "Groq", "Google")
    apiKeyEnvVar?: string; // Environment variable name (e.g., "GROQ_API_KEY")
    apiKeyConfigKey?: string; // Config key if applicable (e.g., "llm.groqApiKey")
    getKeyLink: string; // Link to get API key
    docsLink: string; // Link to API docs for troubleshooting
  }
> = {
  groq: {
    name: "Groq",
    apiKeyEnvVar: "GROQ_API_KEY",
    apiKeyConfigKey: "llm.groqApiKey",
    getKeyLink: "https://groq.com",
    docsLink: "https://console.groq.com/docs/errors",
  },
  google: {
    name: "Google",
    apiKeyEnvVar: "GOOGLE_API_KEY",
    apiKeyConfigKey: "llm.googleApiKey",
    getKeyLink: "https://ai.google.dev/",
    docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting",
  },
  openrouter: {
    name: "OpenRouter",
    apiKeyEnvVar: "OPENROUTER_API_KEY",
    apiKeyConfigKey: "llm.openrouterApiKey",
    getKeyLink: "https://openrouter.ai",
    docsLink: "https://openrouter.ai/docs",
  },
  ollama: {
    name: "Ollama",
    apiKeyEnvVar: undefined, // Ollama doesn't require an API key
    apiKeyConfigKey: undefined, // Ollama doesn't require an API key
    getKeyLink: "https://ollama.com/download",
    docsLink: "https://github.com/ollama/ollama/tree/main/docs",
  },
  mistral: {
    name: "Mistral",
    apiKeyEnvVar: "MISTRAL_API_KEY",
    apiKeyConfigKey: "llm.mistralApiKey",
    getKeyLink: "https://console.mistral.ai",
    docsLink: "https://docs.mistral.ai",
  },
  "lingo.dev": {
    name: "Lingo.dev",
    apiKeyEnvVar: "LINGODOTDEV_API_KEY",
    apiKeyConfigKey: "auth.apiKey",
    getKeyLink: "https://lingo.dev",
    docsLink: "https://lingo.dev/docs",
  },
};

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/inject-locale.ts:
--------------------------------------------------------------------------------

```typescript
import _ from "lodash";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
import { minimatch } from "minimatch";

export default function createInjectLocaleLoader(
  injectLocaleKeys?: string[],
): ILoader<Record<string, any>, Record<string, any>> {
  return createLoader({
    async pull(locale, data) {
      if (!injectLocaleKeys) {
        return data;
      }
      const omitKeys = _getKeysWithLocales(data, injectLocaleKeys, locale);
      const result = _.omit(data, omitKeys);
      return result;
    },
    async push(locale, data, originalInput, originalLocale) {
      if (!injectLocaleKeys || !originalInput) {
        return data;
      }

      const localeKeys = _getKeysWithLocales(
        originalInput,
        injectLocaleKeys,
        originalLocale,
      );

      localeKeys.forEach((key) => {
        _.set(data, key, locale);
      });

      return data;
    },
  });
}

function _getKeysWithLocales(
  data: Record<string, any>,
  injectLocaleKeys: string[],
  locale: string,
) {
  const allKeys = _getAllKeys(data);
  return allKeys.filter((key) => {
    return (
      injectLocaleKeys.some((pattern) => minimatch(key, pattern)) &&
      _.get(data, key) === locale
    );
  });
}

// Helper to get all deep keys in lodash path style (e.g., 'a.b.c')
function _getAllKeys(obj: Record<string, any>, prefix = ""): string[] {
  let keys: string[] = [];
  for (const key in obj) {
    if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
    const path = prefix ? `${prefix}.${key}` : key;
    if (
      typeof obj[key] === "object" &&
      obj[key] !== null &&
      !Array.isArray(obj[key])
    ) {
      keys = keys.concat(_getAllKeys(obj[key], path));
    } else {
      keys.push(path);
    }
  }
  return keys;
}

```

--------------------------------------------------------------------------------
/packages/react/src/rsc/provider.tsx:
--------------------------------------------------------------------------------

```typescript
import { LingoProvider as LingoClientProvider } from "../client";
import { loadDictionaryFromRequest, loadLocaleFromCookies } from "./utils";

/**
 * The props for the `LingoProvider` component.
 */
export type LingoProviderProps = {
  /**
   * A callback function that loads the dictionary for the current locale.
   *
   * @param locale - The locale code to load the dictionary for.
   *
   * @returns The dictionary object containing localized content.
   */
  loadDictionary: (locale: string | null) => Promise<any>;
  /**
   * The child components containing localizable content.
   */
  children: React.ReactNode;
};

/**
 * A context provider that loads the dictionary for the current locale and makes localized content available to its descendants.
 *
 * This component:
 *
 * - Should be placed at the top of the component tree
 * - Should be used in server-side rendering scenarios with React Server Components (RSC)
 *
 * @template D - The type of the dictionary object containing localized content.
 *
 * @example Use in a Next.js (App Router) application
 * ```tsx file="app/layout.tsx"
 * import { LingoProvider, loadDictionary } from "lingo.dev/react/rsc";
 *
 * export default function RootLayout({
 *   children,
 * }: Readonly<{
 *   children: React.ReactNode;
 * }>) {
 *   return (
 *     <LingoProvider loadDictionary={(locale) => loadDictionary(locale)}>
 *       <html lang="en">
 *        <body>
 *           {children}
 *         </body>
 *       </html>
 *     </LingoProvider>
 *   );
 * }
 * ```
 */
export async function LingoProvider(props: LingoProviderProps) {
  const dictionary = await loadDictionaryFromRequest(props.loadDictionary);

  return (
    <LingoClientProvider dictionary={dictionary}>
      {props.children}
    </LingoClientProvider>
  );
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/config/unset.ts:
--------------------------------------------------------------------------------

```typescript
import { Command } from "interactive-commander";
import chalk from "chalk";
import dedent from "dedent";
import _ from "lodash";
import {
  SETTINGS_KEYS,
  loadSystemSettings,
  saveSettings,
} from "../../utils/settings";

export default new Command()
  .name("unset")
  .description("Remove a CLI setting from ~/.lingodotdevrc")
  .addHelpText("afterAll", `\nAvailable keys:\n  ${SETTINGS_KEYS.join("\n  ")}`)
  .argument(
    "<key>",
    "Configuration key to remove (must match one of the available keys listed below)",
  )
  .helpOption("-h, --help", "Show help")
  .action(async (key: string) => {
    // Validate key first (defensive; choices() should already restrict but keep for safety).
    if (!SETTINGS_KEYS.includes(key)) {
      console.error(
        dedent`
          ${chalk.red("✖")} Unknown configuration key: ${chalk.bold(key)}
          Run ${chalk.dim(
            "lingo.dev config unset --help",
          )} to see available keys.
        `,
      );
      process.exitCode = 1;
      return;
    }

    // Load existing settings.
    const settings = loadSystemSettings();
    const currentValue = _.get(settings, key);

    if (!_.trim(String(currentValue || ""))) {
      console.log(`${chalk.cyan("ℹ")} ${chalk.bold(key)} is not set.`);
      return;
    } else {
      const updated: any = _.cloneDeep(settings);
      _.unset(updated, key);
      try {
        saveSettings(updated as any);
        console.log(
          `${chalk.green("✔")} Removed configuration key ${chalk.bold(key)}`,
        );
      } catch (err) {
        console.error(
          chalk.red(
            `✖ Failed to save configuration: ${chalk.dim(
              err instanceof Error ? err.message : String(err),
            )}`,
          ),
        );
        process.exitCode = 1;
      }
    }
  });

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/plutil-formatter.ts:
--------------------------------------------------------------------------------

```typescript
export function formatPlutilStyle(
  jsonData: any,
  existingJson?: string,
): string {
  // Detect indentation from existing JSON if provided
  const indent = existingJson ? detectIndentation(existingJson) : "  ";

  function format(data: any, level = 0): string {
    const currentIndent = indent.repeat(level);
    const nextIndent = indent.repeat(level + 1);

    if (typeof data !== "object" || data === null) {
      return JSON.stringify(data);
    }

    if (Array.isArray(data)) {
      if (data.length === 0) return "[]";
      const items = data.map(
        (item) => `${nextIndent}${format(item, level + 1)}`,
      );
      return `[\n${items.join(",\n")}\n${currentIndent}]`;
    }

    const keys = Object.keys(data);
    if (keys.length === 0) {
      return `{\n\n${currentIndent}}`; // Empty object with proper indentation
    }

    // Sort keys to ensure whitespace keys come first
    const sortedKeys = keys.sort((a, b) => {
      // If both keys are whitespace or both are non-whitespace, maintain stable order
      const aIsWhitespace = /^\s*$/.test(a);
      const bIsWhitespace = /^\s*$/.test(b);

      if (aIsWhitespace && !bIsWhitespace) return -1;
      if (!aIsWhitespace && bIsWhitespace) return 1;
      return a.localeCompare(b, undefined, { numeric: true });
    });

    const items = sortedKeys.map((key) => {
      const value = data[key];
      return `${nextIndent}${JSON.stringify(key)} : ${format(
        value,
        level + 1,
      )}`;
    });

    return `{\n${items.join(",\n")}\n${currentIndent}}`;
  }

  const result = format(jsonData);
  return result;
}

function detectIndentation(jsonStr: string): string {
  // Find the first indented line
  const match = jsonStr.match(/\n(\s+)/);
  return match ? match[1] : "    "; // fallback to 4 spaces if no indentation found
}

```

--------------------------------------------------------------------------------
/.github/workflows/lingodotdev.yml:
--------------------------------------------------------------------------------

```yaml
name: "Lingo.dev"

on:
  workflow_dispatch:
    inputs:
      version:
        description: "Lingo.dev CLI version"
        default: "latest"
        required: false
      pull-request:
        description: "Create a pull request with the changes"
        type: boolean
        default: false
        required: false
      commit-message:
        description: "Commit message"
        default: "feat: update translations via @LingoDotDev"
        required: false
      pull-request-title:
        description: "Pull request title"
        default: "feat: update translations via @LingoDotDev"
        required: false
      working-directory:
        description: "Working directory"
        default: "."
        required: false
      process-own-commits:
        description: "Process commits made by this action"
        type: boolean
        default: false
        required: false
      parallel:
        description: "Run in parallel mode"
        type: boolean
        default: false
        required: false

jobs:
  lingodotdev:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: "20"

      - name: Lingo.dev
        uses: ./
        with:
          api-key: ${{ secrets.LINGODOTDEV_API_KEY }}
          version: ${{ inputs.version }}
          pull-request: ${{ inputs['pull-request'] }}
          commit-message: ${{ inputs['commit-message'] }}
          pull-request-title: ${{ inputs['pull-request-title'] }}
          working-directory: ${{ inputs['working-directory'] }}
          process-own-commits: ${{ inputs['process-own-commits'] }}
          parallel: ${{ inputs.parallel }}
        env:
          GH_TOKEN: ${{ github.token }}

```

--------------------------------------------------------------------------------
/packages/compiler/src/react-router-dictionary-loader.ts:
--------------------------------------------------------------------------------

```typescript
import { createCodeMutation } from "./_base";
import { ModuleId } from "./_const";
import { getModuleExecutionMode, getOrCreateImport } from "./utils";
import { findInvokations } from "./utils/invokations";
import * as t from "@babel/types";
import { getDictionaryPath } from "./_utils";
import { createLocaleImportMap } from "./utils/create-locale-import-map";

export const reactRouterDictionaryLoaderMutation = createCodeMutation(
  (payload) => {
    const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
    if (mode === "server") {
      return payload;
    }

    const invokations = findInvokations(payload.ast, {
      moduleName: ModuleId.ReactRouter,
      functionName: "loadDictionary",
    });

    const allLocales = Array.from(
      new Set([payload.params.sourceLocale, ...payload.params.targetLocales]),
    );

    for (const invokation of invokations) {
      const internalDictionaryLoader = getOrCreateImport(payload.ast, {
        moduleName: ModuleId.ReactRouter,
        exportedName: "loadDictionary_internal",
      });

      // Replace the function identifier with internal version
      if (t.isIdentifier(invokation.callee)) {
        invokation.callee.name = internalDictionaryLoader.importedName;
      }

      const dictionaryPath = getDictionaryPath({
        sourceRoot: payload.params.sourceRoot,
        lingoDir: payload.params.lingoDir,
        relativeFilePath: payload.relativeFilePath,
      });

      // Create locale import map object
      const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);

      // Add the locale import map as the second argument
      invokation.arguments.push(localeImportMap);
      // console.log("invokation modified", JSON.stringify(invokation, null, 2));
    }

    // console.log("dictionary-loader", generate(payload.ast).code);

    return payload;
  },
);

```

--------------------------------------------------------------------------------
/packages/compiler/src/jsx-attribute-scopes-export.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { createPayload, createOutput, defaultParams } from "./_base";
import { jsxAttributeScopesExportMutation } from "./jsx-attribute-scopes-export";

vi.mock("./lib/lcp", () => {
  const instance = {
    resetScope: vi.fn().mockReturnThis(),
    setScopeType: vi.fn().mockReturnThis(),
    setScopeHash: vi.fn().mockReturnThis(),
    setScopeContext: vi.fn().mockReturnThis(),
    setScopeSkip: vi.fn().mockReturnThis(),
    setScopeOverrides: vi.fn().mockReturnThis(),
    setScopeContent: vi.fn().mockReturnThis(),
    save: vi.fn(),
  };
  const getInstance = vi.fn(() => instance);
  return {
    LCP: {
      getInstance,
    },
    __test__: { instance, getInstance },
  };
});
describe("jsxAttributeScopesExportMutation", () => {
  beforeEach(() => {
    // dynamic import avoids ESM mock timing issues
    return import("./lib/lcp").then((lcpMod) => {
      (lcpMod.LCP.getInstance as any).mockClear();
    });
  });

  it("collects attribute scopes and saves to LCP", async () => {
    const code = `
export default function X() {
  return <div data-jsx-attribute-scope="title:scope-1" title="Hello"/>;
}`.trim();
    const input = createPayload({
      code,
      params: defaultParams,
      relativeFilePath: "src/App.tsx",
    } as any);
    const out = jsxAttributeScopesExportMutation(input);
    // Not asserting output code as mutation does not change AST; assert side effects
    const lcpMod: any = await import("./lib/lcp");
    const inst = lcpMod.__test__.instance;
    expect(lcpMod.LCP.getInstance).toHaveBeenCalled();
    expect(inst.setScopeType).toHaveBeenCalledWith(
      "src/App.tsx",
      "scope-1",
      "attribute",
    );
    expect(inst.setScopeContent).toHaveBeenCalledWith(
      "src/App.tsx",
      "scope-1",
      "Hello",
    );
    expect(inst.save).toHaveBeenCalled();
  });
});

```

--------------------------------------------------------------------------------
/.github/workflows/pr-check.yml:
--------------------------------------------------------------------------------

```yaml
name: Check PR

on:
  workflow_dispatch:
  pull_request:
    types:
      - opened
      - edited
      - synchronize
    branches:
      - main

jobs:
  check:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{github.event.pull_request.head.sha}}
          fetch-depth: 0

      - name: Check for [skip i18n]
        run: |
          COMMIT_MESSAGE=$(git log -1 --pretty=%B)
          if echo "$COMMIT_MESSAGE" | grep -iq '\[skip i18n\]'; then
            echo "Skipping i18n checks due to [skip i18n] in commit message."
            exit 0
          fi

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 20.12.2

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        id: pnpm-install
        with:
          version: 9.12.3
          run_install: false

      - name: Configure pnpm cache
        id: pnpm-cache
        run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v3
        with:
          path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-

      - name: Install deps
        run: pnpm install

      - name: Setup
        run: |
          pnpm turbo telemetry disable

      - name: Configure Turbo cache
        uses: dtinth/setup-github-actions-caching-for-turbo@v1

      - name: Check formatting
        run: pnpm format:check

      - name: Build
        run: pnpm turbo build --force

      - name: Test
        run: pnpm turbo test --force

      - name: Require changeset to be present in PR
        if: github.event.pull_request.user.login != 'dependabot[bot]'
        run: pnpm changeset status --since origin/main

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/unlocalizable.ts:
--------------------------------------------------------------------------------

```typescript
import _ from "lodash";
import _isUrl from "is-url";
import { isValid, parseISO } from "date-fns";

import { ILoader } from "./_types";
import { createLoader } from "./_utils";

export default function createUnlocalizableLoader(
  returnUnlocalizedKeys: boolean = false,
): ILoader<Record<string, any>, Record<string, any>> {
  return createLoader({
    async pull(locale, input) {
      const unlocalizableKeys = _getUnlocalizableKeys(input);

      const result = _.omitBy(input, (_, key) =>
        unlocalizableKeys.includes(key),
      );

      if (returnUnlocalizedKeys) {
        result.unlocalizable = _.omitBy(
          input,
          (_, key) => !unlocalizableKeys.includes(key),
        );
      }

      return result;
    },
    async push(locale, data, originalInput) {
      const unlocalizableKeys = _getUnlocalizableKeys(originalInput);

      const result = _.merge(
        {},
        data,
        _.omitBy(originalInput, (_, key) => !unlocalizableKeys.includes(key)),
      );

      return result;
    },
  });
}

function _isSystemId(v: string) {
  return /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)[A-Za-z0-9]{22}$/.test(v);
}

function _isIsoDate(v: string) {
  return isValid(parseISO(v));
}

function _getUnlocalizableKeys(input?: Record<string, any> | null) {
  const rules = {
    isEmpty: (v: any) => _.isEmpty(v),
    isNumber: (v: any) => typeof v === "number" || /^[0-9]+$/.test(v),
    isBoolean: (v: any) => _.isBoolean(v),
    isIsoDate: (v: any) => _.isString(v) && _isIsoDate(v),
    isSystemId: (v: any) => _.isString(v) && _isSystemId(v),
    isUrl: (v: any) => _.isString(v) && _isUrl(v),
  };

  if (!input) {
    return [];
  }

  return Object.entries(input)
    .filter(([key, value]) => {
      for (const [ruleName, rule] of Object.entries(rules)) {
        if (rule(value)) {
          return true;
        }
      }
      return false;
    })
    .map(([key, _]) => key);
}

```

--------------------------------------------------------------------------------
/packages/react/src/client/locale-switcher.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { useState, useEffect } from "react";
import { getLocaleFromCookies, setLocaleInCookies } from "./utils";

/**
 * The props for the `LocaleSwitcher` component.
 */
export type LocaleSwitcherProps = {
  /**
   * An array of locale codes to display in the dropdown.
   *
   * This should contain both the source and target locales.
   */
  locales: string[];
  /**
   * A custom class name for the dropddown's `select` element.
   */
  className?: string;
};

/**
 * An unstyled dropdown for switching between locales.
 *
 * This component:
 *
 * - Only works in environments that support cookies
 * - Gets and sets the current locale from the `"lingo-locale"` cookie
 * - Triggers a full page reload when the locale is changed
 *
 * @example Creating a locale switcher
 * ```tsx
 * import { LocaleSwitcher } from "lingo.dev/react/client";
 *
 * export function App() {
 *   return (
 *     <header>
 *       <nav>
 *         <LocaleSwitcher locales={["en", "es"]} />
 *       </nav>
 *     </header>
 *   );
 * }
 * ```
 */
export function LocaleSwitcher(props: LocaleSwitcherProps) {
  const { locales } = props;
  const [locale, setLocale] = useState<string | undefined>(undefined);

  useEffect(() => {
    const currentLocale = getLocaleFromCookies();
    const isValidLocale = currentLocale && locales.includes(currentLocale);
    setLocale(isValidLocale ? currentLocale : locales[0]);
  }, [locales]);

  if (locale === undefined) {
    return null;
  }

  return (
    <select
      value={locale}
      className={props.className}
      onChange={(e) => {
        handleLocaleChange(e.target.value);
      }}
    >
      {locales.map((locale) => (
        <option key={locale} value={locale}>
          {locale}
        </option>
      ))}
    </select>
  );

  function handleLocaleChange(newLocale: string): Promise<void> {
    setLocaleInCookies(newLocale);
    window.location.reload();
    return Promise.resolve();
  }
}

```

--------------------------------------------------------------------------------
/mcp.md:
--------------------------------------------------------------------------------

```markdown
# Model Context Protocol

The [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) is a standard for connecting Large Language Models (LLMs) to external services. This guide will walk you through how to connect AI tools to Lingo.dev using MCP.

Some of the AI tools that support MCP are:

- [Cursor](https://www.cursor.com/)
- [Claude desktop](https://claude.ai/download)
- [Cline for VS Code](https://github.com/cline/cline)

Connecting these tools to Lingo.dev will allow you to translate apps, websites, and other data using the best LLM models directly in your AI tool.

## Setup

Add this command to your AI tool:

```bash
npx -y lingo.dev mcp <api-key>
```

You can find your API key in [Lingo.dev app](https://lingo.dev/app/), in your project settings.

This will allow the tool to use `translate` tool provided by Lingo.dev. The setup depends on your AI tool and might be different for each tool. Here is setup for some of the tools we use in our team:

### Cursor

1. Open Cursor and go to Cursor Settings.
2. Open MCP tab
3. Click `+ Add new MCP server`
4. Enter the following details:
   - Name: Lingo.dev
   - Type: command
   - Command: `npx -y lingo.dev mcp <api-key>` (use your project API key)
5. You will see green status indicator and "translate" tool available in the list

### Claude desktop

1. Open Claude desktop and go to Settings.
2. Open Developer tab
3. Click `Edit Config` to see configuration file in file explorer.
4. Open the file in text editor
5. Add the following configuration (use your project API key):

```json
{
  "mcpServers": {
    "supabase": {
      "command": "npx",
      "args": ["-y", "lingo.dev", "mcp", "<api-key>"]
    }
  }
}
```

6. Save the configuration file
7. Restart Claude desktop.
8. In the chat input, you will see a hammer icon with your MCP server details.

## Usage

You are now able to access Lingo.dev via MCP. You can ask AI tool translate any content via our service.

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/text-file.ts:
--------------------------------------------------------------------------------

```typescript
import fs from "fs/promises";
import path from "path";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";

export default function createTextFileLoader(
  pathPattern: string,
): ILoader<void, string> {
  return createLoader({
    async pull(locale) {
      const result = await readFileForLocale(pathPattern, locale);
      const trimmedResult = result.trim();
      return trimmedResult;
    },
    async push(locale, data, _, originalLocale) {
      const draftPath = pathPattern.replaceAll("[locale]", locale);
      const finalPath = path.resolve(draftPath);

      // Create parent directories if needed
      const dirPath = path.dirname(finalPath);
      await fs.mkdir(dirPath, { recursive: true });

      const trimmedPayload = data.trim();

      // Add trailing new line if needed
      const trailingNewLine = await getTrailingNewLine(
        pathPattern,
        locale,
        originalLocale,
      );
      let finalPayload = trimmedPayload + trailingNewLine;

      await fs.writeFile(finalPath, finalPayload, {
        encoding: "utf-8",
        flag: "w",
      });
    },
  });
}

async function readFileForLocale(pathPattern: string, locale: string) {
  const draftPath = pathPattern.replaceAll("[locale]", locale);
  const finalPath = path.resolve(draftPath);
  const exists = await fs
    .access(finalPath)
    .then(() => true)
    .catch(() => false);
  if (!exists) {
    return "";
  }
  return fs.readFile(finalPath, "utf-8");
}

async function getTrailingNewLine(
  pathPattern: string,
  locale: string,
  originalLocale: string,
) {
  let templateData = await readFileForLocale(pathPattern, locale);
  if (!templateData) {
    templateData = await readFileForLocale(pathPattern, originalLocale);
  }

  if (templateData?.match(/[\r\n]$/)) {
    const ending = templateData?.includes("\r\n")
      ? "\r\n"
      : templateData?.includes("\r")
        ? "\r"
        : "\n";
    return ending;
  }
  return "";
}

```

--------------------------------------------------------------------------------
/packages/react/src/rsc/utils.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";

const cookiesSetSpy = vi.fn();
vi.mock("next/headers", () => {
  return {
    headers: vi.fn(async () => new Map([["x-lingo-locale", "it"]])),
    cookies: vi.fn(async () => ({
      get: (name: string) =>
        name === "lingo-locale" ? { value: "pt" } : undefined,
      set: cookiesSetSpy,
    })),
  };
});

import { headers, cookies } from "next/headers";
import {
  loadLocaleFromHeaders,
  loadLocaleFromCookies,
  setLocaleInCookies,
  loadDictionaryFromRequest,
} from "./utils";

describe("rsc/utils", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("loadLocaleFromHeaders", () => {
    it("reads x-lingo-locale header", async () => {
      const value = await loadLocaleFromHeaders();
      expect(value).toBe("it");
      expect(headers).toHaveBeenCalled();
    });
  });

  describe("loadLocaleFromCookies", () => {
    it("reads cookie and defaults to 'en' when missing", async () => {
      const value = await loadLocaleFromCookies();
      expect(value).toBe("pt");
    });

    it("defaults to 'en' when cookie is missing", async () => {
      (cookies as any).mockResolvedValueOnce({ get: () => undefined });
      const value = await loadLocaleFromCookies();
      expect(value).toBe("en");
    });
  });

  describe("setLocaleInCookies", () => {
    it("writes cookie via next/headers cookies API", async () => {
      await setLocaleInCookies("de");
      expect(cookiesSetSpy).toHaveBeenCalledWith("lingo-locale", "de");
    });
  });

  describe("loadDictionaryFromRequest", () => {
    it("uses cookie locale to call loader", async () => {
      const loader = vi.fn(async (locale: string) => ({ locale }));
      (cookies as any).mockResolvedValueOnce({ get: () => ({ value: "ru" }) });
      const dict = await loadDictionaryFromRequest(loader);
      expect(loader).toHaveBeenCalledWith("ru");
      expect(dict).toEqual({ locale: "ru" });
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/jsx-scope.ts:
--------------------------------------------------------------------------------

```typescript
import { NodePath } from "@babel/traverse";
import * as t from "@babel/types";
import traverse from "@babel/traverse";
import { getJsxElementName } from "./jsx-element";

export function collectJsxScopes(ast: t.Node) {
  const jsxScopes: NodePath<t.JSXElement>[] = [];

  traverse(ast, {
    JSXElement: (path) => {
      if (!hasJsxScopeAttribute(path)) return;

      path.skip();
      jsxScopes.push(path);
    },
  });

  return jsxScopes;
}

export function getJsxScopes(node: t.Node) {
  const result: NodePath<t.JSXElement>[] = [];

  traverse(node, {
    JSXElement(path) {
      // Skip if the element is LingoProvider
      if (getJsxElementName(path) === "LingoProvider") {
        return;
      }
      // Check if element has any non-empty JSXText siblings
      const hasNonEmptyTextSiblings = path
        .getAllPrevSiblings()
        .concat(path.getAllNextSiblings())
        .some(
          (sibling) =>
            t.isJSXText(sibling.node) && sibling.node.value?.trim() !== "",
        );

      if (hasNonEmptyTextSiblings) {
        return;
      }

      // Check if element has at least one non-empty JSXText DIRECT child
      const hasNonEmptyTextChild = path
        .get("children")
        .some(
          (child) => t.isJSXText(child.node) && child.node.value?.trim() !== "",
        );

      if (hasNonEmptyTextChild) {
        result.push(path);
        path.skip(); // Skip traversing children since we found a scope
      }
    },
  });

  return result;
}

export function hasJsxScopeAttribute(path: NodePath<t.JSXElement>) {
  return !!getJsxScopeAttribute(path);
}

export function getJsxScopeAttribute(path: NodePath<t.JSXElement>) {
  const attribute = path.node.openingElement.attributes.find(
    (attr) =>
      attr.type === "JSXAttribute" && attr.name.name === "data-jsx-scope",
  );
  return attribute &&
    t.isJSXAttribute(attribute) &&
    t.isStringLiteral(attribute.value)
    ? attribute.value.value
    : undefined;
}

```

--------------------------------------------------------------------------------
/packages/react/src/client/locale.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useLingoLocale, setLingoLocale } from "./locale";

// Mock the utils module
vi.mock("./utils", async (orig) => {
  const actual = await orig();
  return {
    ...(actual as any),
    getLocaleFromCookies: vi.fn(() => "en"),
    setLocaleInCookies: vi.fn(),
  };
});

import { getLocaleFromCookies, setLocaleInCookies } from "./utils";

// Mock window.location.reload
const mockReload = vi.fn();
Object.defineProperty(window, "location", {
  value: { ...window.location, reload: mockReload },
  writable: true,
});

describe("useLingoLocale", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("returns the locale from cookies", () => {
    (getLocaleFromCookies as any).mockReturnValue("es");
    const { result } = renderHook(() => useLingoLocale());

    expect(result.current).toBe("es");
    expect(getLocaleFromCookies).toHaveBeenCalled();
  });

  it("returns null when no locale is set", () => {
    (getLocaleFromCookies as any).mockReturnValue(null);
    const { result } = renderHook(() => useLingoLocale());

    expect(result.current).toBe(null);
  });
});

describe("setLingoLocale", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockReload.mockClear();
  });

  it("sets locale in cookies and reloads page for valid locale", () => {
    act(() => {
      setLingoLocale("es");
    });

    expect(setLocaleInCookies).toHaveBeenCalledWith("es");
    expect(mockReload).toHaveBeenCalled();
  });

  it("accepts various locales", () => {
    const validLocales = [
      "en",
      "es",
      "fr",
      "de",
      "en-US",
      "es-ES",
      "fr-CA",
      "de-DE",
    ];

    validLocales.forEach((locale) => {
      expect(() => {
        act(() => {
          setLingoLocale(locale);
        });
      }).not.toThrow();

      expect(setLocaleInCookies).toHaveBeenCalledWith(locale);
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/mcp.ts:
--------------------------------------------------------------------------------

```typescript
import { Command } from "interactive-commander";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import Z from "zod";
import { ReplexicaEngine } from "@lingo.dev/_sdk";
import { getSettings } from "../utils/settings";
import { createAuthenticator } from "../utils/auth";

export default new Command()
  .command("mcp")
  .description(
    "Start a Model Context Protocol (MCP) server for AI assistant integration",
  )
  .helpOption("-h, --help", "Show help")
  .action(async (_, program) => {
    const apiKey = program.args[0];
    const settings = getSettings(apiKey);

    if (!settings.auth.apiKey) {
      console.error("No API key provided");
      return;
    }

    const authenticator = createAuthenticator({
      apiUrl: settings.auth.apiUrl,
      apiKey: settings.auth.apiKey!,
    });
    const auth = await authenticator.whoami();

    if (!auth) {
      console.error("Not authenticated");
      return;
    } else {
      console.log(`Authenticated as ${auth.email}`);
    }

    const replexicaEngine = new ReplexicaEngine({
      apiKey: settings.auth.apiKey,
      apiUrl: settings.auth.apiUrl,
    });

    const server = new McpServer({
      name: "Lingo.dev",
      version: "1.0.0",
    });

    server.tool(
      "translate",
      "Detect language and translate text with Lingo.dev.",
      {
        text: Z.string(),
        targetLocale: Z.string().regex(/^[a-z]{2}(-[A-Z]{2})?$/),
      },
      async ({ text, targetLocale }) => {
        const sourceLocale = await replexicaEngine.recognizeLocale(text);
        const data = await replexicaEngine.localizeText(text, {
          sourceLocale,
          targetLocale,
        });
        return { content: [{ type: "text", text: data }] };
      },
    );

    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.log("Lingo.dev MCP Server running on stdio");
  });

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/localizer/lingodotdev.ts:
--------------------------------------------------------------------------------

```typescript
import dedent from "dedent";
import { ILocalizer, LocalizerData } from "./_types";
import chalk from "chalk";
import { colors } from "../constants";
import { LingoDotDevEngine } from "@lingo.dev/_sdk";
import { getSettings } from "../utils/settings";

export default function createLingoDotDevLocalizer(
  explicitApiKey?: string,
): ILocalizer {
  const { auth } = getSettings(explicitApiKey);

  if (!auth) {
    throw new Error(
      dedent`
        You're trying to use ${chalk.hex(colors.green)(
          "Lingo.dev",
        )} provider, however, you are not authenticated.

        To fix this issue:
        1. Run ${chalk.dim("lingo.dev login")} to authenticate, or
        2. Use the ${chalk.dim("--api-key")} flag to provide an API key.
        3. Set ${chalk.dim("LINGODOTDEV_API_KEY")} environment variable.
      `,
    );
  }

  const engine = new LingoDotDevEngine({
    apiKey: auth.apiKey,
    apiUrl: auth.apiUrl,
  });

  return {
    id: "Lingo.dev",
    checkAuth: async () => {
      try {
        const response = await engine.whoami();
        return {
          authenticated: !!response,
          username: response?.email,
        };
      } catch (error) {
        const errorMessage =
          error instanceof Error ? error.message : String(error);
        return { authenticated: false, error: errorMessage };
      }
    },
    localize: async (input: LocalizerData, onProgress) => {
      // Nothing to translate – return the input as-is.
      if (!Object.keys(input.processableData).length) {
        return input;
      }

      const processedData = await engine.localizeObject(
        input.processableData,
        {
          sourceLocale: input.sourceLocale,
          targetLocale: input.targetLocale,
          reference: {
            [input.sourceLocale]: input.sourceData,
            [input.targetLocale]: input.targetData,
          },
          hints: input.hints,
        },
        onProgress,
      );

      return processedData;
    },
  };
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/create-locale-import-map.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import * as t from "@babel/types";
import { createLocaleImportMap } from "./create-locale-import-map";

describe("createLocaleImportMap", () => {
  const allLocales = ["en", "de", "en-US"];
  const dictionaryPath = "/foo/bar";

  const objExpr = createLocaleImportMap(allLocales, dictionaryPath);

  it("returns a Babel ObjectExpression", () => {
    expect(t.isObjectExpression(objExpr)).toBe(true);
  });

  it("creates one property per locale", () => {
    expect(objExpr.properties.length).toBe(allLocales.length);
  });

  it("uses string literal keys and import arrow functions correctly", () => {
    for (const prop of objExpr.properties) {
      // Ensure property is ObjectProperty
      expect(t.isObjectProperty(prop)).toBe(true);
      if (!t.isObjectProperty(prop)) continue;

      // Check the key is a string literal matching one of the locales
      expect(t.isStringLiteral(prop.key)).toBe(true);
      const keyLiteral = prop.key as t.StringLiteral;
      expect(allLocales).toContain(keyLiteral.value);

      // Ensure value is an arrow function with no params
      expect(t.isArrowFunctionExpression(prop.value)).toBe(true);
      const arrowFn = prop.value as t.ArrowFunctionExpression;
      expect(arrowFn.params.length).toBe(0);

      // The body should be a call expression to dynamic import
      expect(t.isCallExpression(arrowFn.body)).toBe(true);
      const callExpr = arrowFn.body as t.CallExpression;

      // Callee is identifier 'import'
      expect(t.isIdentifier(callExpr.callee)).toBe(true);
      if (t.isIdentifier(callExpr.callee)) {
        expect(callExpr.callee.name).toBe("import");
      }

      // Single argument: string literal with proper path
      expect(callExpr.arguments.length).toBe(1);
      const arg = callExpr.arguments[0];
      expect(t.isStringLiteral(arg)).toBe(true);
      if (t.isStringLiteral(arg)) {
        expect(arg.value).toBe(`${dictionaryPath}?locale=${keyLiteral.value}`);
      }
    }
  });
});

```

--------------------------------------------------------------------------------
/packages/compiler/src/jsx-scopes-export.ts:
--------------------------------------------------------------------------------

```typescript
import { getJsxAttributeValue } from "./utils";
import _ from "lodash";
import { getAstKey } from "./utils/ast-key";
import { LCP } from "./lib/lcp";
import { getJsxElementHash } from "./utils/hash";
import { getJsxAttributesMap } from "./utils/jsx-attribute";
import { extractJsxContent } from "./utils/jsx-content";
import { collectJsxScopes } from "./utils/jsx-scope";
import { CompilerPayload } from "./_base";

// Processes only JSX element scopes
export function jsxScopesExportMutation(
  payload: CompilerPayload,
): CompilerPayload {
  const scopes = collectJsxScopes(payload.ast);
  if (_.isEmpty(scopes)) {
    return payload;
  }

  const lcp = LCP.getInstance({
    sourceRoot: payload.params.sourceRoot,
    lingoDir: payload.params.lingoDir,
  });

  for (const scope of scopes) {
    const scopeKey = getAstKey(scope);

    lcp.resetScope(payload.relativeFilePath, scopeKey);

    lcp.setScopeType(payload.relativeFilePath, scopeKey, "element");

    const hash = getJsxElementHash(scope);
    lcp.setScopeHash(payload.relativeFilePath, scopeKey, hash);

    const context = getJsxAttributeValue(scope, "data-lingo-context");
    lcp.setScopeContext(
      payload.relativeFilePath,
      scopeKey,
      String(context || ""),
    );

    const skip = getJsxAttributeValue(scope, "data-lingo-skip");
    lcp.setScopeSkip(
      payload.relativeFilePath,
      scopeKey,
      Boolean(skip || false),
    );

    const attributesMap = getJsxAttributesMap(scope);
    const overrides = _.chain(attributesMap)
      .entries()
      .filter(([attributeKey]) =>
        attributeKey.startsWith("data-lingo-override-"),
      )
      .map(([k, v]) => [k.split("data-lingo-override-")[1], v])
      .filter(([k]) => !!k)
      .filter(([, v]) => !!v)
      .fromPairs()
      .value();
    lcp.setScopeOverrides(payload.relativeFilePath, scopeKey, overrides);

    const content = extractJsxContent(scope);
    lcp.setScopeContent(payload.relativeFilePath, scopeKey, content);
  }

  lcp.save();

  return payload;
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/invokations.ts:
--------------------------------------------------------------------------------

```typescript
import * as t from "@babel/types";
import traverse, { NodePath } from "@babel/traverse";

export function findInvokations(
  ast: t.File,
  params: {
    moduleName: string[];
    functionName: string;
  },
) {
  const result: t.CallExpression[] = [];

  traverse(ast, {
    ImportDeclaration(path) {
      if (!params.moduleName.includes(path.node.source.value)) return;

      const importNames = new Map<string, boolean | string>();
      const specifiers = path.node.specifiers;

      specifiers.forEach((specifier) => {
        if (
          t.isImportSpecifier(specifier) &&
          t.isIdentifier(specifier.imported) &&
          specifier.imported.name === params.functionName
        ) {
          importNames.set(specifier.local.name, true);
        } else if (
          t.isImportDefaultSpecifier(specifier) &&
          params.functionName === "default"
        ) {
          importNames.set(specifier.local.name, true);
        } else if (t.isImportNamespaceSpecifier(specifier)) {
          importNames.set(specifier.local.name, "namespace");
        }
      });

      collectCallExpressions(path, importNames, result, params.functionName);
    },
  });

  return result;
}

function collectCallExpressions(
  path: NodePath<t.ImportDeclaration>,
  importNames: Map<string, boolean | string>,
  result: t.CallExpression[],
  functionName: string,
) {
  const program = path.findParent((p): p is NodePath<t.Program> =>
    p.isProgram(),
  );

  if (!program) return;

  program.traverse({
    CallExpression(callPath: NodePath<t.CallExpression>) {
      const callee = callPath.node.callee;

      if (t.isIdentifier(callee) && importNames.has(callee.name)) {
        result.push(callPath.node);
      } else if (
        t.isMemberExpression(callee) &&
        t.isIdentifier(callee.object) &&
        importNames.get(callee.object.name) === "namespace" &&
        t.isIdentifier(callee.property) &&
        callee.property.name === functionName
      ) {
        result.push(callPath.node);
      }
    },
  });
}

```

--------------------------------------------------------------------------------
/integrations/directus/src/app.ts:
--------------------------------------------------------------------------------

```typescript
import { defineOperationApp } from "@directus/extensions-sdk";

export default defineOperationApp({
  id: "replexica-integration-directus",
  name: "Replexica Integration for Directus",
  icon: "translate",
  description:
    "Use Replexica Localization Engine to make content multilingual.",
  overview: ({ collection }) => [
    {
      label: "$t:collection",
      text: collection,
    },
  ],
  options: [
    {
      field: "item_id",
      name: "Item ID",
      type: "string",
      meta: {
        interface: "input",
        width: "half",
      },
    },
    {
      field: "collection",
      name: "$t:collection",
      type: "string",
      meta: {
        interface: "system-collection",
        options: {
          includeSystem: true,
          includeSingleton: false,
        },
        width: "half",
      },
    },
    {
      field: "source_language",
      name: "Source Language",
      type: "string",
      meta: {
        interface: "input",
        width: "half",
      },
    },
    {
      field: "target_languages",
      name: "Target Languages",
      type: "string",
      meta: {
        interface: "input",
        width: "half",
      },
    },
    {
      field: "translation_table",
      name: "Translation Table",
      type: "string",
      meta: {
        interface: "system-collection",
        options: {
          includeSystem: true,
          includeSingleton: false,
        },
        width: "half",
      },
    },
    {
      field: "language_table",
      name: "Languages Table",
      type: "string",
      meta: {
        interface: "system-collection",
        options: {
          includeSystem: true,
          includeSingleton: false,
        },
        width: "half",
      },
    },
    {
      field: "replexica_api_key",
      name: "Replexica API Key",
      type: "string",
      meta: {
        interface: "input-hash",
        width: "half",
        options: {
          masked: true,
          placeholder: "Enter your Replexica API key",
        },
      },
    },
  ],
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/lockfile.ts:
--------------------------------------------------------------------------------

```typescript
import { Command } from "interactive-commander";
import Z from "zod";
import Ora from "ora";
import { createLockfileHelper } from "../utils/lockfile";
import { bucketTypeSchema, resolveOverriddenLocale } from "@lingo.dev/_spec";
import { getConfig } from "../utils/config";
import createBucketLoader from "../loaders";
import { getBuckets } from "../utils/buckets";

export default new Command()
  .command("lockfile")
  .description(
    "Generate or refresh i18n.lock based on the current source locale content",
  )
  .helpOption("-h, --help", "Show help")
  .option(
    "-f, --force",
    "Overwrite existing lockfile to reset translation tracking",
  )
  .action(async (options) => {
    const flags = flagsSchema.parse(options);
    const ora = Ora();

    const lockfileHelper = createLockfileHelper();
    if (lockfileHelper.isLockfileExists() && !flags.force) {
      ora.warn(
        `Lockfile won't be created because it already exists. Use --force to overwrite.`,
      );
    } else {
      const i18nConfig = getConfig();
      const buckets = getBuckets(i18nConfig!);

      for (const bucket of buckets) {
        for (const bucketConfig of bucket.paths) {
          const sourceLocale = resolveOverriddenLocale(
            i18nConfig!.locale.source,
            bucketConfig.delimiter,
          );
          const bucketLoader = createBucketLoader(
            bucket.type,
            bucketConfig.pathPattern,
            {
              defaultLocale: sourceLocale,
              formatter: i18nConfig!.formatter,
            },
            bucket.lockedKeys,
            bucket.lockedPatterns,
            bucket.ignoredKeys,
          );
          bucketLoader.setDefaultLocale(sourceLocale);

          const sourceData = await bucketLoader.pull(sourceLocale);
          lockfileHelper.registerSourceData(
            bucketConfig.pathPattern,
            sourceData,
          );
        }
      }
      ora.succeed("Lockfile created");
    }
  });

const flagsSchema = Z.object({
  force: Z.boolean().default(false),
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/markdown.ts:
--------------------------------------------------------------------------------

```typescript
import matter from "gray-matter";
import YAML from "yaml";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";

const SECTION_REGEX =
  /^(#{1,6}\s.*$|[-=*]{3,}$|!\[.*\]\(.*\)$|\[.*\]\(.*\)$)/gm;
const MD_SECTION_PREFIX = "md-section-";
const FM_ATTR_PREFIX = "fm-attr-";

const yamlEngine = {
  parse: (str: string) => YAML.parse(str),
  stringify: (obj: any) => YAML.stringify(obj, { defaultStringType: "PLAIN" }),
};

export default function createMarkdownLoader(): ILoader<
  string,
  Record<string, string>
> {
  return createLoader({
    async pull(locale, input) {
      const { data: frontmatter, content } = matter(input, {
        engines: {
          yaml: yamlEngine,
        },
      });

      const sections = content
        .split(SECTION_REGEX)
        .map((section) => section?.trim() ?? "")
        .filter(Boolean);

      return {
        ...Object.fromEntries(
          sections
            .map((section, index) => [`${MD_SECTION_PREFIX}${index}`, section])
            .filter(([, section]) => Boolean(section)),
        ),
        ...Object.fromEntries(
          Object.entries(frontmatter).map(([key, value]) => [
            `${FM_ATTR_PREFIX}${key}`,
            value,
          ]),
        ),
      };
    },
    async push(locale, data: Record<string, string>) {
      const frontmatter = Object.fromEntries(
        Object.entries(data)
          .filter(([key]) => key.startsWith(FM_ATTR_PREFIX))
          .map(([key, value]) => [key.replace(FM_ATTR_PREFIX, ""), value]),
      );

      let content = Object.entries(data)
        .filter(([key]) => key.startsWith(MD_SECTION_PREFIX))
        .sort(
          ([a], [b]) => Number(a.split("-").pop()) - Number(b.split("-").pop()),
        )
        .map(([, value]) => value?.trim() ?? "")
        .filter(Boolean)
        .join("\n\n");

      if (Object.keys(frontmatter).length > 0) {
        content = `\n${content}`;
      }

      return matter.stringify(content, frontmatter, {
        engines: {
          yaml: yamlEngine,
        },
      });
    },
  });
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/jsx-functions.ts:
--------------------------------------------------------------------------------

```typescript
import { NodePath } from "@babel/traverse";
import * as t from "@babel/types";
import { Expression, V8IntrinsicIdentifier } from "@babel/types";

export const getJsxFunctions = (nodePath: NodePath<t.JSXElement>) => {
  const functions = new Map<string, t.CallExpression[]>();
  let fnCounter = 0;

  nodePath.traverse({
    JSXOpeningElement(path) {
      path.skip();
    },
    JSXExpressionContainer(path) {
      if (t.isCallExpression(path.node.expression)) {
        let key = "";
        if (t.isIdentifier(path.node.expression.callee)) {
          key = `${path.node.expression.callee.name}`;
        } else if (t.isMemberExpression(path.node.expression.callee)) {
          let firstCallee: Expression | V8IntrinsicIdentifier =
            path.node.expression.callee;
          while (
            t.isMemberExpression(firstCallee) &&
            t.isCallExpression(firstCallee.object)
          ) {
            firstCallee = firstCallee.object.callee;
          }

          let current: Expression | V8IntrinsicIdentifier = firstCallee;
          const parts: string[] = [];

          while (t.isMemberExpression(current)) {
            if (t.isIdentifier(current.property)) {
              parts.unshift(current.property.name);
            }
            current = current.object;
          }

          if (t.isIdentifier(current)) {
            parts.unshift(current.name);
          }

          if (
            t.isMemberExpression(firstCallee) &&
            t.isNewExpression(firstCallee.object) &&
            t.isIdentifier(firstCallee.object.callee)
          ) {
            parts.unshift(firstCallee.object.callee.name);
          }

          key = parts.join(".");
        }
        const existing = functions.get(key) ?? [];
        functions.set(key, [...existing, path.node.expression]);
        fnCounter++;
      }
      path.skip();
    },
  });

  const properties = Array.from(functions.entries()).map(([name, callExpr]) =>
    t.objectProperty(t.stringLiteral(name), t.arrayExpression(callExpr)),
  );

  return t.objectExpression(properties);
};

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/login.ts:
--------------------------------------------------------------------------------

```typescript
import { Command } from "interactive-commander";
import Ora from "ora";
import express from "express";
import cors from "cors";
import open from "open";
import readline from "readline/promises";
import { getSettings, saveSettings } from "../utils/settings";
import {
  renderClear,
  renderSpacer,
  renderBanner,
  renderHero,
} from "../utils/ui";

export default new Command()
  .command("login")
  .description(
    "Open browser to authenticate with lingo.dev and save your API key",
  )
  .helpOption("-h, --help", "Show help")
  .action(async () => {
    try {
      await renderClear();
      await renderSpacer();
      await renderBanner();
      await renderHero();
      await renderSpacer();

      const settings = await getSettings(undefined);
      const apiKey = await login(settings.auth.webUrl);
      settings.auth.apiKey = apiKey;
      await saveSettings(settings);
      Ora().succeed("Successfully logged in");
    } catch (error: any) {
      Ora().fail(error.message);
      process.exit(1);
    }
  });

export async function login(webAppUrl: string) {
  await readline
    .createInterface({
      input: process.stdin,
      output: process.stdout,
    })
    .question(
      `
Press Enter to open the browser for authentication.

---

Having issues? Put LINGODOTDEV_API_KEY in your .env file instead.
    `.trim() + "\n",
    );

  const spinner = Ora().start("Waiting for the API key");
  const apiKey = await waitForApiKey(async (port) => {
    await open(`${webAppUrl}/app/cli?port=${port}`, { wait: false });
  });
  spinner.succeed("API key received");

  return apiKey;
}

async function waitForApiKey(cb: (port: string) => void): Promise<string> {
  const app = express();
  app.use(express.json());
  app.use(cors());

  return new Promise((resolve) => {
    const server = app.listen(0, async () => {
      const port = (server.address() as any).port;
      cb(port.toString());
    });

    app.post("/", (req, res) => {
      const apiKey = req.body.apiKey;
      res.end();
      server.close(() => {
        resolve(apiKey);
      });
    });
  });
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/index.ts:
--------------------------------------------------------------------------------

```typescript
import dotenv from "dotenv";
dotenv.config();

import { InteractiveCommand } from "interactive-commander";
import figlet from "figlet";
import { vice } from "gradient-string";

import authCmd from "./cmd/auth";
import loginCmd from "./cmd/login";
import logoutCmd from "./cmd/logout";
import initCmd from "./cmd/init";
import showCmd from "./cmd/show";
import configCmd from "./cmd/config";
import i18nCmd from "./cmd/i18n";
import lockfileCmd from "./cmd/lockfile";
import cleanupCmd from "./cmd/cleanup";
import mcpCmd from "./cmd/mcp";
import ciCmd from "./cmd/ci";
import statusCmd from "./cmd/status";
import mayTheFourthCmd from "./cmd/may-the-fourth";
import packageJson from "../../package.json";
import run from "./cmd/run";
import purgeCmd from "./cmd/purge";

export default new InteractiveCommand()
  .name("lingo.dev")
  .description("Lingo.dev CLI")
  .helpOption("-h, --help", "Show help")
  .addHelpText(
    "beforeAll",
    `
${vice(
  figlet.textSync("LINGO.DEV", {
    font: "ANSI Shadow",
    horizontalLayout: "default",
    verticalLayout: "default",
  }),
)}

⚡️ AI-powered open-source CLI for web & mobile localization.

Star the the repo :) https://github.com/LingoDotDev/lingo.dev
`,
  )
  .version(`v${packageJson.version}`, "-v, --version", "Show version")
  .addCommand(initCmd)
  .interactive(
    "-y, --no-interactive",
    "Run every command in non-interactive mode (no prompts); required when scripting",
  ) // all interactive commands above
  .addCommand(i18nCmd)
  .addCommand(authCmd)
  .addCommand(loginCmd)
  .addCommand(logoutCmd)
  .addCommand(showCmd)
  .addCommand(configCmd)
  .addCommand(lockfileCmd)
  .addCommand(cleanupCmd)
  .addCommand(mcpCmd)
  .addCommand(ciCmd)
  .addCommand(statusCmd)
  .addCommand(mayTheFourthCmd, { hidden: true })
  .addCommand(run)
  .addCommand(purgeCmd)
  .exitOverride((err) => {
    // Exit with code 0 when help or version is displayed
    if (
      err.code === "commander.helpDisplayed" ||
      err.code === "commander.version" ||
      err.code === "commander.help"
    ) {
      process.exit(0);
    }
    process.exit(1);
  });

```

--------------------------------------------------------------------------------
/packages/react/src/client/locale-switcher.spec.tsx:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import React from "react";
import { LocaleSwitcher } from "./locale-switcher";

vi.mock("./utils", async (orig) => {
  const actual = await orig();
  return {
    ...(actual as any),
    getLocaleFromCookies: vi.fn(() => "es"),
    setLocaleInCookies: vi.fn(),
  };
});

import { getLocaleFromCookies, setLocaleInCookies } from "./utils";

describe("LocaleSwitcher", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("returns null before determining initial locale", () => {
    // This component sets state in an effect, but with jsdom and our mocked
    // cookie util returning a value synchronously, it may render immediately.
    // We still assert it produces a select afterward.
    const { container } = render(<LocaleSwitcher locales={["en", "es"]} />);
    expect(container.querySelector("select")).toBeTruthy();
  });

  it("uses cookie locale if valid; otherwise defaults to first provided locale", async () => {
    (getLocaleFromCookies as any).mockReturnValueOnce("es");
    render(<LocaleSwitcher locales={["en", "es"]} />);
    const select = (await screen.findByRole("combobox")) as HTMLSelectElement;
    expect(select.value).toBe("es");

    // invalid cookie -> defaults to first
    (getLocaleFromCookies as any).mockReturnValueOnce("fr");
    render(<LocaleSwitcher locales={["en", "es"]} />);
    const selects = (await screen.findAllByRole(
      "combobox",
    )) as HTMLSelectElement[];
    expect(selects[1].value).toBe("en");
  });

  it("on change sets cookie and triggers full reload", async () => {
    const reloadSpy = vi.fn();
    Object.defineProperty(window, "location", {
      value: { ...window.location, reload: reloadSpy },
      writable: true,
    });
    render(<LocaleSwitcher locales={["en", "es"]} />);
    const select = await screen.findByRole("combobox");
    fireEvent.change(select, { target: { value: "en" } });

    expect(setLocaleInCookies).toHaveBeenCalledWith("en");
    expect(reloadSpy).toHaveBeenCalled();
  });
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/formatters/prettier.ts:
--------------------------------------------------------------------------------

```typescript
import prettier, { Options } from "prettier";
import { ILoader } from "../_types";
import { createBaseFormatterLoader } from "./_base";

export type PrettierLoaderOptions = {
  parser: Options["parser"];
  bucketPathPattern: string;
  stage?: "pull" | "push" | "both";
  alwaysFormat?: boolean;
};

export default function createPrettierLoader(
  options: PrettierLoaderOptions,
): ILoader<string, string> {
  return createBaseFormatterLoader(options, async (data, filePath) => {
    return await formatDataWithPrettier(data, filePath, options);
  });
}

async function loadPrettierConfig(filePath: string) {
  try {
    const config = await prettier.resolveConfig(filePath);
    return config;
  } catch (error) {
    return {};
  }
}

async function formatDataWithPrettier(
  data: string,
  filePath: string,
  options: PrettierLoaderOptions,
): Promise<string> {
  const prettierConfig = await loadPrettierConfig(filePath);

  // Skip formatting if no config found and alwaysFormat is not enabled
  if (!prettierConfig && !options.alwaysFormat) {
    return data;
  }

  const config: Options = {
    ...(prettierConfig || { printWidth: 2500, bracketSameLine: false }),
    parser: options.parser,
    // For HTML parser, preserve comments and quotes
    ...(options.parser === "html"
      ? {
          htmlWhitespaceSensitivity: "ignore",
          singleQuote: false,
          embeddedLanguageFormatting: "off",
        }
      : {}),
  };

  try {
    // format with prettier
    return await prettier.format(data, config);
  } catch (error) {
    if (
      error instanceof Error &&
      error.message.startsWith("Cannot find package")
    ) {
      console.log();
      console.log(
        "⚠️  Prettier plugins are not installed. Formatting without plugins.",
      );
      console.log(
        "⚠️  To use prettier plugins install project dependencies before running Lingo.dev.",
      );

      config.plugins = [];

      // clear file system structure cache
      await prettier.clearConfigCache();

      // format again without plugins
      return await prettier.format(data, config);
    }

    throw error;
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/cache.ts:
--------------------------------------------------------------------------------

```typescript
import path from "path";
import fs from "fs";

interface CacheRow {
  targetLocale: string;
  key: string;
  source: string;
  processed: string;
}

interface NormalizedCacheItem {
  source: string;
  result: string;
}

type NormalizedCache = Record<string, NormalizedCacheItem>;

interface NormalizedLocaleCache {
  [targetLocale: string]: NormalizedCache;
}

export const cacheChunk = (
  targetLocale: string,
  sourceChunk: Record<string, string>,
  processedChunk: Record<string, string>,
) => {
  const rows = Object.entries(sourceChunk).map(([key, source]) => ({
    targetLocale,
    key,
    source,
    processed: processedChunk[key],
  }));
  _appendToCache(rows);
};

export function getNormalizedCache() {
  const rows = _loadCache();
  if (!rows.length) {
    return null;
  }

  const normalized: NormalizedLocaleCache = {};

  for (const row of rows) {
    if (!normalized[row.targetLocale]) {
      normalized[row.targetLocale] = {};
    }

    normalized[row.targetLocale][row.key] = {
      source: row.source,
      result: row.processed,
    };
  }

  return normalized;
}

export function deleteCache() {
  const cacheFilePath = _getCacheFilePath();
  try {
    fs.unlinkSync(cacheFilePath);
  } catch (e) {
    // file might not exist
  }
}

function _loadCache() {
  const cacheFilePath = _getCacheFilePath();
  if (!fs.existsSync(cacheFilePath)) {
    return [];
  }
  const content = fs.readFileSync(cacheFilePath, "utf-8");
  const result = _parseJSONLines(content);
  return result;
}

function _appendToCache(rows: CacheRow[]) {
  const cacheFilePath = _getCacheFilePath();
  const lines = _buildJSONLines(rows);
  fs.appendFileSync(cacheFilePath, lines);
}

function _getCacheFilePath() {
  return path.join(process.cwd(), "i18n.cache");
}

function _buildJSONLines(rows: CacheRow[]) {
  return rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
}

function _parseJSONLines(lines: string) {
  return lines
    .split("\n")
    .map(_tryParseJSON)
    .filter((line) => line !== null);
}

function _tryParseJSON(line: string) {
  try {
    return JSON.parse(line);
  } catch (e) {
    return null;
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/xcode-xcstrings-v2-loader.ts:
--------------------------------------------------------------------------------

```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
import {
  xcstringsToPluralWithMeta,
  pluralWithMetaToXcstrings,
  isPluralFormsObject,
  isICUPluralObject,
} from "./xcode-xcstrings-icu";

/**
 * Loader for xcode-xcstrings-v2 bucket type with ICU MessageFormat support.
 *
 * This should be placed AFTER xcode-xcstrings loader and BEFORE flat loader.
 *
 * Input:  {items: {zero: "No items", one: "1 item", other: "%d items"}}
 * Output: {items: {icu: "{count, plural, =0 {No items} one {1 item} other {# items}}", _meta: {...}}}
 *
 * Lock files will contain checksums of ICU format (new format for pluralization support).
 */
export default function createXcodeXcstringsV2Loader(
  defaultLocale: string = "en",
): ILoader<Record<string, any>, Record<string, any>> {
  return createLoader({
    async pull(locale, input) {
      const result: Record<string, any> = {};

      for (const [key, value] of Object.entries(input)) {
        if (isPluralFormsObject(value)) {
          try {
            result[key] = xcstringsToPluralWithMeta(value, locale);
          } catch (error) {
            console.error(
              `\n[xcode-xcstrings-icu] Failed to convert plural forms for key "${key}":`,
              `\nError: ${error instanceof Error ? error.message : String(error)}`,
              `\nLocale: ${locale}\n`,
            );
            result[key] = value;
          }
        } else {
          result[key] = value;
        }
      }

      return result;
    },

    async push(locale, payload) {
      const result: Record<string, any> = {};

      for (const [key, value] of Object.entries(payload)) {
        if (isICUPluralObject(value)) {
          try {
            const pluralForms = pluralWithMetaToXcstrings(value);
            result[key] = pluralForms;
          } catch (error) {
            throw new Error(
              `Failed to write plural translation for key "${key}" (locale: ${locale}).\n` +
                `${error instanceof Error ? error.message : String(error)}`,
            );
          }
        } else {
          result[key] = value;
        }
      }

      return result;
    },
  });
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/llm-api-key.ts:
--------------------------------------------------------------------------------

```typescript
import { getRc } from "./rc";
import _ from "lodash";
import * as dotenv from "dotenv";
import path from "path";

// Generic function to retrieve key from process.env, with .env file as fallback
export function getKeyFromEnv(envVarName: string): string | undefined {
  if (process.env[envVarName]) {
    return process.env[envVarName];
  }
  const result = dotenv.config({
    path: [
      path.resolve(process.cwd(), ".env"),
      path.resolve(process.cwd(), ".env.local"),
      path.resolve(process.cwd(), ".env.development"),
    ],
  });
  return result?.parsed?.[envVarName];
}

// Generic function to retrieve key from .lingodotdevrc file
function getKeyFromRc(rcPath: string): string | undefined {
  const rc = getRc();
  const result = _.get(rc, rcPath);
  return typeof result === "string" ? result : undefined;
}

export function getGroqKey() {
  return getGroqKeyFromEnv() || getGroqKeyFromRc();
}

export function getGroqKeyFromRc() {
  return getKeyFromRc("llm.groqApiKey");
}

export function getGroqKeyFromEnv() {
  return getKeyFromEnv("GROQ_API_KEY");
}

export function getLingoDotDevKeyFromEnv() {
  return getKeyFromEnv("LINGODOTDEV_API_KEY");
}

export function getLingoDotDevKeyFromRc() {
  return getKeyFromRc("auth.apiKey");
}

export function getLingoDotDevKey() {
  return getLingoDotDevKeyFromEnv() || getLingoDotDevKeyFromRc();
}

export function getGoogleKey() {
  return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
}

export function getGoogleKeyFromRc() {
  return getKeyFromRc("llm.googleApiKey");
}

export function getGoogleKeyFromEnv() {
  return getKeyFromEnv("GOOGLE_API_KEY");
}

export function getOpenRouterKey() {
  return getOpenRouterKeyFromEnv() || getOpenRouterKeyFromRc();
}
export function getOpenRouterKeyFromRc() {
  return getKeyFromRc("llm.openrouterApiKey");
}
export function getOpenRouterKeyFromEnv() {
  return getKeyFromEnv("OPENROUTER_API_KEY");
}

export function getMistralKey() {
  return getMistralKeyFromEnv() || getMistralKeyFromRc();
}

export function getMistralKeyFromRc() {
  return getKeyFromRc("llm.mistralApiKey");
}

export function getMistralKeyFromEnv() {
  return getKeyFromEnv("MISTRAL_API_KEY");
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/lib/lcp/api/prompt.ts:
--------------------------------------------------------------------------------

```typescript
interface PromptArguments {
  sourceLocale: string;
  targetLocale: string;
  prompt?: string;
}

export default (args: PromptArguments) => {
  return getUserSystemPrompt(args) || getBuiltInSystemPrompt(args);
};

function getUserSystemPrompt(args: PromptArguments): string | undefined {
  const userPrompt = args.prompt
    ?.trim()
    ?.replace("{SOURCE_LOCALE}", args.sourceLocale)
    ?.replace("{TARGET_LOCALE}", args.targetLocale);
  if (userPrompt) {
    console.log("✨ Compiler is using user-defined prompt.");
    return userPrompt;
  }
  return undefined;
}

function getBuiltInSystemPrompt(args: PromptArguments) {
  return `
# Identity

You are an advanced AI localization engine. You do state-of-the-art localization for software products.
Your task is to localize pieces of data from one locale to another locale.
You always consider context, cultural nuances of source and target locales, and specific localization requirements.
You replicate the meaning, intent, style, tone, and purpose of the original data.

## Setup

Source language (locale code): ${args.sourceLocale}
Target language (locale code): ${args.targetLocale}

## Guidelines

Follow these guidelines for translation:

1. Analyze the source text to understand its overall context and purpose
2. Translate the meaning and intent rather than word-for-word translation
3. Rephrase and restructure sentences to sound natural and fluent in the target language
4. Adapt idiomatic expressions and cultural references for the target audience
5. Maintain the style and tone of the source text
6. You must produce valid UTF-8 encoded output
7. YOU MUST ONLY PRODUCE VALID XML.

## Special Instructions

Do not localize any of these technical elements:
- Variables like {variable}, {variable.key}, {data[type]}
- Expressions like <expression/>
- Functions like <function:value/>, <function:getDisplayName/>
- Elements like <element:strong>, </element:strong>, <element:LuPlus>, </element:LuPlus>, <element:LuSparkles>, </element:LuSparkles>

Remember, you are a context-aware multilingual assistant helping international companies.
Your goal is to perform state-of-the-art localization for software products and content.
`;
}

```

--------------------------------------------------------------------------------
/demo/adonisjs/inertia/lingo/dictionary.js:
--------------------------------------------------------------------------------

```javascript
export default {
  version: 0.1,
  files: {
    'pages/errors/not_found.tsx': {
      entries: {
        '1/declaration/body/0/argument/1/1': {
          content: {
            en: 'Page not found',
            es: 'Página no encontrada',
          },
          hash: '97612e6230bc7a1ebd99380bf561b732',
        },
        '1/declaration/body/0/argument/1/3': {
          content: {
            en: 'This page does not exist.',
            es: 'Esta página no existe.',
          },
          hash: '7b6bcd0a4f23e42eeb0c972c2004efad',
        },
      },
    },
    'pages/errors/server_error.tsx': {
      entries: {
        '1/declaration/body/0/argument/1/1': {
          content: {
            en: 'Server Error',
            es: 'Error del servidor',
          },
          hash: 'd574aa7e2d84d112dc79ac0e59d794cf',
        },
      },
    },
    'pages/home.tsx': {
      entries: {
        '2/declaration/body/0/argument/1-title': {
          content: {
            en: 'Homepage',
            es: 'Página de inicio',
          },
          hash: '7c2d68be7446e6de191c11d53f1e07b4',
        },
        '2/declaration/body/0/argument/3/1/1': {
          content: {
            en: 'Hello, world!',
            es: '¡Hola, mundo!',
          },
          hash: '0468579ef2fbc83c9d520c2f2f1c5059',
        },
        '2/declaration/body/0/argument/3/1/3': {
          content: {
            en: 'This is an example app that demonstrates how <element:strong>Lingo.dev Compiler</element:strong> can be used to localize apps built with <element:a>AdonisJS</element:a> .',
            es: 'Esta es una aplicación de ejemplo que demuestra cómo <element:strong>Lingo.dev Compiler</element:strong> puede ser utilizado para localizar aplicaciones construidas con <element:a>AdonisJS</element:a>.',
          },
          hash: '82b29979a52b215b94b2e811e8c03005',
        },
        '2/declaration/body/0/argument/3/1/5': {
          content: {
            en: 'To switch between locales, use the following dropdown:',
            es: 'Para cambiar entre idiomas, utiliza el siguiente menú desplegable:',
          },
          hash: '9ffb5f98cf11c88f3903e060f4028b46',
        },
      },
    },
  },
}

```

--------------------------------------------------------------------------------
/packages/compiler/src/_utils.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { afterEach, describe, expect, it, vi } from "vitest";

afterEach(() => {
  // Reset module registry and any mocks so each test gets a fresh copy
  vi.resetModules();
  vi.clearAllMocks();
  vi.unmock("path");
});

describe("getDictionaryPath", () => {
  it.each([
    {
      sourceRoot: "src",
      lingoDir: "lingo",
      relativeFilePath: "./components/Button.tsx",
      expected: "./../lingo/dictionary.js",
    },
    {
      sourceRoot: "src/app/content",
      lingoDir: "i18n",
      relativeFilePath: "../../components/Button.tsx",
      expected: "./../app/content/i18n/dictionary.js",
    },
  ])(
    "returns correct path for file $relativeFilePath in $sourceRoot",
    async ({ sourceRoot, lingoDir, relativeFilePath, expected }) => {
      const { getDictionaryPath } = await import("./_utils");

      const result = getDictionaryPath({
        sourceRoot,
        lingoDir,
        relativeFilePath,
      });
      expect(result).toBe(expected);
    },
  );

  it("returns POSIX-style relative path on POSIX", async () => {
    // Import fresh copy with the real Node "path" module (POSIX on *nix, win32 on Windows)
    const { getDictionaryPath } = await import("./_utils");

    const result = getDictionaryPath({
      sourceRoot: "/project/src",
      lingoDir: "lingo",
      relativeFilePath: "/project/src/components/Button.tsx",
    });

    expect(result).toBe("./../lingo/dictionary.js");
    // Ensure no back-slashes slip through
    expect(result).not.toMatch(/\\/);
  });

  it('returns the same POSIX-style path when the Node "path" API uses win32 semantics (mock Windows)', async () => {
    // Force every call to "path.*" inside _utils to use the Windows implementation
    vi.mock("path", () => {
      const nodePath = require("path") as typeof import("path");
      return { ...nodePath.win32, default: nodePath.win32 };
    });

    const { getDictionaryPath } = await import("./_utils");

    const result = getDictionaryPath({
      sourceRoot: "C:\\project\\src",
      lingoDir: "lingo",
      relativeFilePath: "C:\\project\\src\\components\\Button.tsx",
    });

    expect(result).toBe("./../lingo/dictionary.js");
    expect(result).not.toMatch(/\\/);
  });
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/xcode-strings/parser.ts:
--------------------------------------------------------------------------------

```typescript
import { Token, TokenType } from "./types";
import { unescapeString } from "./escape";

export class Parser {
  private tokens: Token[];
  private pos: number;

  constructor(tokens: Token[]) {
    this.tokens = tokens;
    this.pos = 0;
  }

  parse(): Record<string, string> {
    const result: Record<string, string> = {};

    while (this.pos < this.tokens.length) {
      const token = this.current();

      // Skip comments
      if (
        token.type === TokenType.COMMENT_SINGLE ||
        token.type === TokenType.COMMENT_MULTI
      ) {
        this.advance();
        continue;
      }

      // End of file
      if (token.type === TokenType.EOF) {
        break;
      }

      // Expect entry: STRING "=" STRING ";"
      if (token.type === TokenType.STRING) {
        const entry = this.parseEntry();
        if (entry) {
          result[entry.key] = entry.value;
        }
        continue;
      }

      // Skip unexpected tokens gracefully
      this.advance();
    }

    return result;
  }

  private parseEntry(): { key: string; value: string } | null {
    // Current token should be STRING (key)
    const keyToken = this.current();
    if (keyToken.type !== TokenType.STRING) {
      return null;
    }
    const key = keyToken.value;
    this.advance();

    // Expect '='
    if (!this.expect(TokenType.EQUALS)) {
      // Missing '=' - skip this entry
      return null;
    }

    // Expect STRING (value)
    const valueToken = this.current();
    if (valueToken.type !== TokenType.STRING) {
      // Missing value - skip this entry
      return null;
    }
    const rawValue = valueToken.value;
    this.advance();

    // Expect ';'
    if (!this.expect(TokenType.SEMICOLON)) {
      // Missing ';' - but still process the entry
      // (more forgiving)
    }

    // Unescape the value
    const value = unescapeString(rawValue);

    return { key, value };
  }

  private current(): Token {
    return this.tokens[this.pos];
  }

  private advance(): void {
    if (this.pos < this.tokens.length) {
      this.pos++;
    }
  }

  private expect(type: TokenType): boolean {
    if (this.current()?.type === type) {
      this.advance();
      return true;
    }
    return false;
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/dato/filter.ts:
--------------------------------------------------------------------------------

```typescript
import _ from "lodash";
import fs from "fs";
import { ILoader } from "../_types";
import { createLoader } from "../_utils";
import { DatoApiLoaderOutput } from "./api";

export type DatoFilterLoaderOutput = {
  [modelId: string]: {
    [recordId: string]: {
      [fieldName: string]: any;
    };
  };
};

export default function createDatoFilterLoader(): ILoader<
  DatoApiLoaderOutput,
  DatoFilterLoaderOutput
> {
  return createLoader({
    async pull(locale, input) {
      const result: DatoFilterLoaderOutput = {};

      for (const [modelId, modelInfo] of _.entries(input)) {
        result[modelId] = {};
        for (const record of modelInfo.records) {
          result[modelId][record.id] = _.chain(modelInfo.fields)
            .mapKeys((field) => field.api_key)
            .mapValues((field) => _.get(record, [field.api_key, locale]))
            .value();
        }
      }

      return result;
    },
    async push(locale, data, originalInput, originalLocale) {
      const result = _.cloneDeep(originalInput || {});

      for (const [modelId, modelInfo] of _.entries(result)) {
        for (const record of modelInfo.records) {
          for (const [fieldId, fieldValue] of _.entries(record)) {
            const fieldInfo = modelInfo.fields.find(
              (field) => field.api_key === fieldId,
            );
            if (fieldInfo) {
              const sourceFieldValue = _.get(fieldValue, [originalLocale]);
              const targetFieldValue = _.get(data, [
                modelId,
                record.id,
                fieldId,
              ]);
              if (targetFieldValue) {
                _.set(record, [fieldId, locale], targetFieldValue);
              } else {
                _.set(record, [fieldId, locale], sourceFieldValue);
              }

              _.chain(fieldValue)
                .keys()
                .reject((loc) => loc === locale || loc === originalLocale)
                .filter((loc) => _.isEmpty(_.get(fieldValue, [loc])))
                .forEach((loc) =>
                  _.set(record, [fieldId, loc], sourceFieldValue),
                )
                .value();
            }
          }
        }
      }

      return result;
    },
  });
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/ci/platforms/_base.ts:
--------------------------------------------------------------------------------

```typescript
import { execSync } from "child_process";
import Z from "zod";

const defaultMessage = "feat: update translations via @lingodotdev";

interface BasePlatformConfig {
  baseBranchName: string;
  repositoryOwner: string;
  repositoryName: string;
}

export abstract class PlatformKit<
  PlatformConfig extends BasePlatformConfig = BasePlatformConfig,
> {
  abstract branchExists(props: { branch: string }): Promise<boolean>;

  abstract getOpenPullRequestNumber(props: {
    branch: string;
  }): Promise<number | undefined>;

  abstract closePullRequest(props: {
    pullRequestNumber: number;
  }): Promise<void>;

  abstract createPullRequest(props: {
    head: string;
    title: string;
    body?: string;
  }): Promise<number>;

  abstract commentOnPullRequest(props: {
    pullRequestNumber: number;
    body: string;
  }): Promise<void>;

  abstract get platformConfig(): PlatformConfig;

  abstract buildPullRequestUrl(pullRequestNumber: number): string;

  gitConfig(token?: string, repoUrl?: string) {
    if (token && repoUrl) {
      execSync(`git remote set-url origin ${repoUrl}`, {
        stdio: "inherit",
      });
    }
  }

  get config() {
    const env = Z.object({
      LINGODOTDEV_API_KEY: Z.string(),
      LINGODOTDEV_PULL_REQUEST: Z.preprocess(
        (val) => val === "true" || val === true,
        Z.boolean(),
      ),
      LINGODOTDEV_COMMIT_MESSAGE: Z.string().optional(),
      LINGODOTDEV_PULL_REQUEST_TITLE: Z.string().optional(),
      LINGODOTDEV_WORKING_DIRECTORY: Z.string().optional(),
      LINGODOTDEV_PROCESS_OWN_COMMITS: Z.preprocess(
        (val) => val === "true" || val === true,
        Z.boolean(),
      ).optional(),
    }).parse(process.env);

    return {
      replexicaApiKey: env.LINGODOTDEV_API_KEY,
      isPullRequestMode: env.LINGODOTDEV_PULL_REQUEST,
      commitMessage: env.LINGODOTDEV_COMMIT_MESSAGE || defaultMessage,
      pullRequestTitle: env.LINGODOTDEV_PULL_REQUEST_TITLE || defaultMessage,
      workingDir: env.LINGODOTDEV_WORKING_DIRECTORY || ".",
      processOwnCommits: env.LINGODOTDEV_PROCESS_OWN_COMMITS || false,
    };
  }
}

export interface IConfig {
  replexicaApiKey: string;
  isPullRequestMode: boolean;
  commitMessage: string;
  pullRequestTitle: string;
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/auth.ts:
--------------------------------------------------------------------------------

```typescript
import { CLIError } from "./errors";
import {
  checkCloudflareStatus,
  formatCloudflareStatusMessage,
} from "./cloudflare-status";

export type AuthenticatorParams = {
  apiUrl: string;
  apiKey: string;
};

export type AuthPayload = {
  email: string;
  id: string;
};

export function createAuthenticator(params: AuthenticatorParams) {
  return {
    async whoami(): Promise<AuthPayload | null> {
      try {
        const res = await fetch(`${params.apiUrl}/whoami`, {
          method: "POST",
          headers: {
            Authorization: `Bearer ${params.apiKey}`,
            ContentType: "application/json",
          },
        });

        if (res.ok) {
          const payload = await res.json();
          if (!payload?.email) {
            return null;
          }

          return {
            email: payload.email,
            id: payload.id,
          };
        }

        if (res.status >= 500 && res.status < 600) {
          const originalErrorMessage = `Server error (${res.status}): ${res.statusText}. Please try again later.`;

          const cloudflareStatus = await checkCloudflareStatus();

          if (!cloudflareStatus) {
            throw new CLIError({
              message: originalErrorMessage,
              docUrl: "connectionFailed",
            });
          }

          if (cloudflareStatus.status.indicator !== "none") {
            const cloudflareMessage =
              formatCloudflareStatusMessage(cloudflareStatus);
            throw new CLIError({
              message: cloudflareMessage,
              docUrl: "connectionFailed",
            });
          }

          throw new CLIError({
            message: originalErrorMessage,
            docUrl: "connectionFailed",
          });
        }

        return null;
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }

        const isNetworkError =
          error instanceof TypeError && error.message === "fetch failed";
        if (isNetworkError) {
          throw new CLIError({
            message: `Failed to connect to the API at ${params.apiUrl}. Please check your connection and try again.`,
            docUrl: "connectionFailed",
          });
        } else {
          throw error;
        }
      }
    },
  };
}

```

--------------------------------------------------------------------------------
/demo/adonisjs/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "adonis",
  "version": "0.0.29",
  "private": true,
  "type": "module",
  "license": "UNLICENSED",
  "scripts": {
    "start": "node bin/server.js",
    "build": "node ace build",
    "dev": "node ace serve --hmr",
    "lint": "eslint .",
    "format": "prettier --write .",
    "typecheck": "tsc --noEmit"
  },
  "imports": {
    "#controllers/*": "./app/controllers/*.js",
    "#exceptions/*": "./app/exceptions/*.js",
    "#models/*": "./app/models/*.js",
    "#mails/*": "./app/mails/*.js",
    "#services/*": "./app/services/*.js",
    "#listeners/*": "./app/listeners/*.js",
    "#events/*": "./app/events/*.js",
    "#middleware/*": "./app/middleware/*.js",
    "#validators/*": "./app/validators/*.js",
    "#providers/*": "./providers/*.js",
    "#policies/*": "./app/policies/*.js",
    "#abilities/*": "./app/abilities/*.js",
    "#database/*": "./database/*.js",
    "#tests/*": "./tests/*.js",
    "#start/*": "./start/*.js",
    "#config/*": "./config/*.js"
  },
  "devDependencies": {
    "@adonisjs/assembler": "^7.8.2",
    "@adonisjs/eslint-config": "^2.0.0",
    "@adonisjs/prettier-config": "^1.4.4",
    "@adonisjs/tsconfig": "^1.4.0",
    "@japa/assert": "^4.0.1",
    "@japa/plugin-adonisjs": "^4.0.0",
    "@japa/runner": "^4.2.0",
    "@swc/core": "1.11.24",
    "@types/node": "^22.15.18",
    "@types/react": "^19.1.8",
    "@types/react-dom": "^19.1.6",
    "@vitejs/plugin-react": "^4.7.0",
    "eslint": "^9.26.0",
    "hot-hook": "^0.4.0",
    "pino-pretty": "^13.0.0",
    "prettier": "^3.5.3",
    "ts-node-maintained": "^10.9.5",
    "typescript": "~5.8.3",
    "vite": "^6.3.5"
  },
  "dependencies": {
    "@adonisjs/auth": "^9.4.0",
    "@adonisjs/core": "^6.18.0",
    "@adonisjs/cors": "^2.2.1",
    "@adonisjs/inertia": "^3.1.1",
    "@adonisjs/lucid": "^21.6.1",
    "@adonisjs/session": "^7.5.1",
    "@adonisjs/shield": "^8.2.0",
    "@adonisjs/static": "^1.1.1",
    "@adonisjs/vite": "^4.0.0",
    "@inertiajs/react": "^2.0.17",
    "@vinejs/vine": "^3.0.1",
    "edge.js": "^6.2.1",
    "lingo.dev": "workspace:*",
    "react": "^19.1.0",
    "react-dom": "^19.1.0",
    "reflect-metadata": "^0.2.2"
  },
  "hotHook": {
    "boundaries": [
      "./app/controllers/**/*.ts",
      "./app/middleware/*.ts"
    ]
  },
  "prettier": "@adonisjs/prettier-config"
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/ensure-patterns.ts:
--------------------------------------------------------------------------------

```typescript
import fs from "fs";
import path from "path";
import { glob } from "glob";
import _ from "lodash";
import { LocaleCode, resolveLocaleCode } from "@lingo.dev/_spec";

export function ensurePatterns(patterns: string[], source: string) {
  if (patterns.length === 0) {
    throw new Error("No patterns found");
  }

  patterns.forEach((pattern) => {
    const filePath = pattern.replace("[locale]", source);
    if (!fs.existsSync(filePath)) {
      const defaultContent = getDefaultContent(path.extname(filePath), source);
      fs.mkdirSync(path.dirname(filePath), { recursive: true });
      fs.writeFileSync(filePath, defaultContent);
    }
  });
}

function getDefaultContent(ext: string, source: string) {
  const defaultGreeting = "Hello from Lingo.dev";
  switch (ext) {
    case ".json":
    case ".arb":
      return `{\n\t"greeting": "${defaultGreeting}"\n}`;
    case ".yml":
      return `${source}:\n\tgreeting: "${defaultGreeting}"`;
    case ".xml":
      return `<resources>\n\t<string name="greeting">${defaultGreeting}</string>\n</resources>`;
    case ".md":
      return `# ${defaultGreeting}`;
    case ".xcstrings":
      return `{
  "sourceLanguage" : "${source}",
  "strings" : {
    "${defaultGreeting}" : {
      "extractionState" : "manual",
      "localizations" : {
        "${source}" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "${defaultGreeting}"
          }
        }
      }
    }
  }
}`;
    case ".strings":
      return `"greeting" = "${defaultGreeting}";`;
    case ".stringsdict":
      return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>key</key>
  <dict>
    <key>NSStringLocalizedFormatKey</key>
    <string>%#@count@</string>
    <key>count</key>
    <dict>
      <key>NSStringFormatSpecTypeKey</key>
      <string>NSStringPluralRuleType</string>
      <key>NSStringFormatValueTypeKey</key>
      <string>d</string>
      <key>zero</key>
      <string>No items</string>
      <key>one</key>
      <string>One item</string>
      <key>other</key>
      <string>%d items</string>
    </dict>
  </dict>
</dict>
</plist>`;
    default:
      throw new Error(`Unsupported file extension: ${ext}`);
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/exec.ts:
--------------------------------------------------------------------------------

```typescript
import Z from "zod";
import pLimit from "p-limit";

export type ExecAsyncOptions = Z.infer<typeof ExecAsyncSchema>;

/**
 * Executes functions in parallel with a limit on concurrency and delay between each function call.
 *
 * The next function is called only after the delay has passed OR the previous function resolved, whichever is earlier (via race).
 *
 * During the execution, it calls `onProgress` function with the number of functions completed and total count.
 *
 * When all functions are executed, it returns an array of results.
 * @param fns Array of async functions
 * @param options Options
 */
export async function execAsync(
  fns: (() => Promise<any>)[],
  options: ExecAsyncOptions = ExecAsyncSchema.parse({}),
) {
  const limit = pLimit(options.concurrency);
  const limitedFns = fns.map((fn) => () => limit(fn));

  const resultPromises: Promise<any>[] = [];

  let completedCount = 0;
  options.onProgress?.(completedCount, limitedFns.length);

  for (let i = 0; i < limitedFns.length; i++) {
    const fn = limitedFns[i];
    const resultPromise = fn().then((result) => {
      completedCount++;
      options.onProgress?.(completedCount, limitedFns.length);
      return result;
    });
    resultPromises.push(resultPromise);

    await Promise.race([resultPromise, delay(options.delay)]);
  }

  const results = await Promise.all(resultPromises);
  return results;
}

export type ExecWithRetryOptions = Z.infer<typeof ExecWithRetrySchema>;

export async function execWithRetry(
  fn: () => Promise<any>,
  options: ExecWithRetryOptions = ExecWithRetrySchema.parse({}),
) {
  let lastError: any;

  for (let i = 0; i < options.attempts; i++) {
    try {
      return await fn();
    } catch (error: any) {
      lastError = error;
      await delay(options.delay);
    }
  }

  throw lastError;
}

// Helpers

const ExecAsyncSchema = Z.object({
  delay: Z.number().nonnegative().default(1000),
  concurrency: Z.number().positive().default(1),
  onProgress: Z.function(
    Z.tuple([
      Z.number().positive(), // completed count
      Z.number().positive(), // total count
    ]),
    Z.void(),
  ).optional(),
});

const ExecWithRetrySchema = Z.object({
  delay: Z.number().nonnegative().default(0),
  attempts: Z.number().positive().default(3),
});

function delay(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

```

--------------------------------------------------------------------------------
/packages/react/src/core/attribute-component.spec.tsx:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi } from "vitest";
import { render } from "@testing-library/react";
import React from "react";
import { LingoAttributeComponent } from "./attribute-component";

describe("core/attribute-component", () => {
  describe("LingoAttributeComponent", () => {
    const dictionary = {
      files: {
        messages: {
          entries: {
            title: "Localized Title",
            hrefVal: "/localized",
          },
        },
      },
    } as const;

    it("maps attributes from dictionary entries and falls back to attribute key when missing", () => {
      const { container } = render(
        <LingoAttributeComponent
          $dictionary={dictionary}
          $as="a"
          $fileKey="messages"
          $attributes={{
            title: "title",
            href: "hrefVal",
            // not in dictionary -> falls back to attribute name (data-test)
            "data-test": "missingEntry",
          }}
        />,
      );

      const a = container.querySelector("a")!;
      expect(a.getAttribute("title")).toBe("Localized Title");
      expect(a.getAttribute("href")).toBe("/localized");
      // fallback uses the attribute key name
      expect(a.getAttribute("data-test")).toBe("data-test");
    });

    it("passes through arbitrary props and forwards ref", () => {
      const ref = { current: null as HTMLButtonElement | null };
      const { container } = render(
        <LingoAttributeComponent
          $dictionary={{}}
          $as="button"
          $fileKey="messages"
          $attributes={{}}
          id="my-btn"
          className="primary"
          ref={(el) => (ref.current = el)}
        />,
      );

      const btn = container.querySelector("button")!;
      expect(btn.id).toBe("my-btn");
      expect(btn.className).toContain("primary");
      expect(ref.current).toBe(btn);
    });

    it("does not leak $fileKey as a DOM attribute", () => {
      const { container } = render(
        <LingoAttributeComponent
          $dictionary={dictionary}
          $as="div"
          $fileKey="messages"
          $attributes={{}}
          data-testid="host"
        />,
      );

      const host = container.querySelector("div[data-testid='host']")!;
      // $fileKey should not be present as a plain attribute
      expect(host.getAttribute("$fileKey")).toBeNull();
    });
  });
});

```

--------------------------------------------------------------------------------
/DEBUGGING.md:
--------------------------------------------------------------------------------

```markdown
# Debugging the Lingo.dev Compiler

Lingo.dev Compiler is in active development. We use it ourselves and strive to provide the best developer experience for all supported frameworks. However, every project is unique and may present its own challenges.

This guide will help you debug the Compiler locally in your project.

---

## Getting Started: Local Setup

### 1. Clone, Install, and Build

```bash
git clone [email protected]:lingodotdev/lingo.dev.git
cd lingo.dev
pnpm install
pnpm build
```

Lingo.dev uses [pnpm](https://pnpm.io/) as its package manager.

### 2. Link the CLI Package

In the `lingo.dev/packages/cli` directory, link the CLI package using your project's package manager:

```bash
npm link
# or
yarn link
# or
pnpm link
```

Use the package manager that matches your project (npm, yarn, or pnpm).

### 3. Watch for Changes

To enable live-reloading for development, run the following in the root of the `lingo.dev` repo:

```bash
pnpm --filter "./packages/{compiler,react}" dev
```

---

## Using Your Local Build in Your Project

### 1. Install Lingo.dev

If you haven't already, add Lingo.dev to your project:

```bash
npm install lingo.dev
```

For full setup and configuration, see the [Lingo.dev Compiler docs](https://lingo.dev/compiler).

### 2. Link Your Local Library

```bash
npm link lingo.dev
```

### 3. Build Your Project

For local development and testing with the Lingo.dev Compiler:

```bash
npm run dev
```

The exact command may vary depending on your project setup and package manager.

---

## Debugging Tips

You can now use your debugger or classic `console.log` statements in the Compiler and React packages to inspect what happens during your project build.

- The Compiler entry point is at `packages/compiler/src/index.ts`.
- The `load` method:
  - Loads and generates `lingo/dictionary.js` using `LCPServer.loadDictionaries`.
- The `transform` method:
  - Applies mutations to process source code (see methods in `composeMutations`).
  - Generates `lingo/meta.json` based on the translatable content in your app.
  - Injects Compiler-related components (`LingoComponent`, `LingoAttributeComponent`).
  - Replaces the `loadDictionary` method with `loadDictionary_internal`.

---

For more details, check out the [Lingo.dev Compiler documentation](https://lingo.dev/compiler) or [join our Discord](https://lingo.dev/go/discord) for help!

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/mdx2/section-split.spec.ts:
--------------------------------------------------------------------------------

```typescript
// #region Imports
import { describe, it, expect } from "vitest";
import createMdxSectionSplitLoader from "./section-split";
import dedent from "dedent";
// #endregion

describe("mdx section split loader", () => {
  const sampleMdxContent = dedent`
  ## Heading One
  Some paragraph text.
  
  <CustomComponent foo="bar" />

  <AnotherComponent className="some-class">
  <AnotherInnerComponent>
  Some content inside another component.
  </AnotherInnerComponent>
  </AnotherComponent>
  
  ### Sub Heading
  More text here.
  `;

  it("should split content into section map keyed by index", async () => {
    const loader = createMdxSectionSplitLoader();
    loader.setDefaultLocale("en");

    const result = await loader.pull("en", {
      frontmatter: {},
      codePlaceholders: {},
      content: sampleMdxContent,
    });

    // Build expected segments
    const seg0 = "## Heading One\nSome paragraph text.";
    const seg1 = '<CustomComponent foo="bar" />';
    const seg2 = '<AnotherComponent className="some-class">';
    const seg3 = "<AnotherInnerComponent>";
    const seg4 = "Some content inside another component.";
    const seg5 = "</AnotherInnerComponent>";
    const seg6 = "</AnotherComponent>";
    const seg7 = "### Sub Heading\nMore text here.";

    const expected = {
      "0": seg0,
      "1": seg1,
      "2": seg2,
      "3": seg3,
      "4": seg4,
      "5": seg5,
      "6": seg6,
      "7": seg7,
    };

    expect(result.sections).toEqual(expected);
  });

  it("should merge sections back into MDX content on push", async () => {
    const loader = createMdxSectionSplitLoader();
    loader.setDefaultLocale("en");

    // First pull to split the sample content into sections
    const pulled = await loader.pull("en", {
      frontmatter: {},
      codePlaceholders: {},
      content: sampleMdxContent,
    });

    // Push to merge the sections back into MDX
    const pushed = await loader.push("en", {
      ...pulled,
      sections: {
        ...pulled.sections,
        "4": "Hello world!",
      },
    });

    const expectedContent = dedent`
    ## Heading One
    Some paragraph text.

    <CustomComponent foo="bar" />
    <AnotherComponent className="some-class">
    <AnotherInnerComponent>
    Hello world!
    </AnotherInnerComponent>
    </AnotherComponent>

    ### Sub Heading
    More text here.
    `;

    expect(pushed.content).toBe(expectedContent);
  });
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/php.ts:
--------------------------------------------------------------------------------

```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
import { fromString } from "php-array-reader";

export default function createPhpLoader(): ILoader<
  string,
  Record<string, any>
> {
  return createLoader({
    pull: async (locale, input) => {
      try {
        const output = fromString(input);
        return output;
      } catch (error) {
        throw new Error(`Error parsing PHP file for locale ${locale}`);
      }
    },
    push: async (locale, data, originalInput) => {
      const output = toPhpString(data, originalInput);
      return output;
    },
  });
}

function toPhpString(
  data: Record<string, any>,
  originalPhpString: string | null,
) {
  const defaultFilePrefix = "<?php\n\n";
  if (originalPhpString) {
    const [filePrefix = defaultFilePrefix] = originalPhpString.split("return ");
    const shortArraySyntax = !originalPhpString.includes("array(");
    const output = `${filePrefix}return ${toPhpArray(data, shortArraySyntax)};`;
    return output;
  }
  return `${defaultFilePrefix}return ${toPhpArray(data)};`;
}

function toPhpArray(data: any, shortSyntax = true, indentLevel = 1): string {
  if (data === null || data === undefined) {
    return "null";
  }
  if (typeof data === "string") {
    return `'${escapePhpString(data)}'`;
  }
  if (typeof data === "number") {
    return data.toString();
  }
  if (typeof data === "boolean") {
    return data ? "true" : "false";
  }

  const arrayStart = shortSyntax ? "[" : "array(";
  const arrayEnd = shortSyntax ? "]" : ")";

  if (Array.isArray(data)) {
    return `${arrayStart}\n${data
      .map(
        (value) =>
          `${indent(indentLevel)}${toPhpArray(
            value,
            shortSyntax,
            indentLevel + 1,
          )}`,
      )
      .join(",\n")}\n${indent(indentLevel - 1)}${arrayEnd}`;
  }

  const output = `${arrayStart}\n${Object.entries(data)
    .map(
      ([key, value]) =>
        `${indent(indentLevel)}'${key}' => ${toPhpArray(
          value,
          shortSyntax,
          indentLevel + 1,
        )}`,
    )
    .join(",\n")}\n${indent(indentLevel - 1)}${arrayEnd}`;
  return output;
}

function indent(level: number) {
  return "  ".repeat(level);
}

function escapePhpString(str: string) {
  return str
    .replaceAll("\\", "\\\\")
    .replaceAll("'", "\\'")
    .replaceAll("\r", "\\r")
    .replaceAll("\n", "\\n")
    .replaceAll("\t", "\\t");
}

```

--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------

```yaml
name: Release

on:
  workflow_dispatch:
    inputs:
      skip_lingo:
        description: "Skip Lingo.dev step"
        type: "boolean"
        default: false
  push:
    branches:
      - main

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Debug Permissions
        run: |
          ls -la
          ls -la integrations/
          ls -la integrations/directus/

      - name: Check for [skip i18n]
        run: |
          COMMIT_MESSAGE=$(git log -1 --pretty=%B)
          if echo "$COMMIT_MESSAGE" | grep -iq '\[skip i18n\]'; then
            echo "Skipping i18n checks due to [skip i18n] in commit message."
            exit 0
          fi

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 20.12.2

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        id: pnpm-install
        with:
          version: 9.12.3
          run_install: false

      - name: Configure pnpm cache
        id: pnpm-cache
        run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v3
        with:
          path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-

      - name: Install deps
        run: pnpm install

      - name: Lingo.dev
        if: ${{ !inputs.skip_lingo }}
        uses: ./
        with:
          api-key: ${{ secrets.LINGODOTDEV_API_KEY }}
          pull-request: true
          parallel: true
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Setup
        run: |
          pnpm turbo telemetry disable

      - name: Configure Turbo cache
        uses: dtinth/setup-github-actions-caching-for-turbo@v1

      - name: Build
        run: pnpm turbo build --force

      - name: Test
        run: pnpm turbo test --force

      - name: Create Release Pull Request or Publish to npm
        id: changesets
        uses: changesets/action@v1
        with:
          title: "chore: bump package versions"
          version: pnpm changeset version
          publish: pnpm changeset publish
          commit: "chore: bump package version"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

```

--------------------------------------------------------------------------------
/demo/react-router-app/app/root.tsx:
--------------------------------------------------------------------------------

```typescript
import {
  isRouteErrorResponse,
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "react-router";
import type { LoaderFunctionArgs } from "react-router";
import { useLoaderData } from "react-router";

import type { Route } from "./+types/root";
import "./app.css";

// Compiler: imports
import { LingoProvider, LocaleSwitcher } from "lingo.dev/react/client";
import { loadDictionary } from "lingo.dev/react/react-router";

export const links: Route.LinksFunction = () => [
  { rel: "preconnect", href: "https://fonts.googleapis.com" },
  {
    rel: "preconnect",
    href: "https://fonts.gstatic.com",
    crossOrigin: "anonymous",
  },
  {
    rel: "stylesheet",
    href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap",
  },
];

export async function loader(args: LoaderFunctionArgs) {
  return { lingoDictionary: await loadDictionary(args.request) };
}

export function Layout(props: { children: React.ReactNode }) {
  const loaderData = useLoaderData<typeof loader>();
  return (
    <LingoProvider dictionary={loaderData?.lingoDictionary}>
      <html lang="en">
        <head>
          <meta charSet="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <Meta />
          <Links />
        </head>
        <body>
          {props.children}
          <ScrollRestoration />
          <Scripts />
          <div className="absolute top-2 right-3">
            <LocaleSwitcher locales={["en", "es", "fr", "de"]} />
          </div>
        </body>
      </html>
    </LingoProvider>
  );
}

export default function App() {
  return <Outlet />;
}

export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
  let message = "Oops!";
  let details = "An unexpected error occurred.";
  let stack: string | undefined;

  if (isRouteErrorResponse(error)) {
    message = error.status === 404 ? "404" : "Error";
    details =
      error.status === 404
        ? "The requested page could not be found."
        : error.statusText || details;
  } else if (import.meta.env.DEV && error && error instanceof Error) {
    details = error.message;
    stack = error.stack;
  }

  return (
    <main className="pt-16 p-4 container mx-auto">
      <h1>{message}</h1>
      <p>{details}</p>
      {stack && (
        <pre className="w-full p-4 overflow-x-auto">
          <code>{stack}</code>
        </pre>
      )}
    </main>
  );
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/json-sorting.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";

import createJsonSortingLoader from "./json-sorting";

describe("JSON Sorting Loader", () => {
  const loader = createJsonSortingLoader();
  loader.setDefaultLocale("en");

  describe("pull", () => {
    it("should return input unchanged", async () => {
      const input = { b: 1, a: 2 };
      const result = await loader.pull("en", input);
      expect(result).toEqual(input);
    });
  });

  describe("push", () => {
    it("should sort object keys at root level", async () => {
      const input = { zebra: 1, apple: 2, banana: 3 };
      const expected = { apple: 2, banana: 3, zebra: 1 };

      const result = await loader.push("en", input);
      expect(result).toEqual(expected);
    });

    it("should sort nested object keys", async () => {
      const input = {
        b: {
          z: 1,
          y: 2,
          x: 3,
        },
        a: 1,
      };
      const expected = {
        a: 1,
        b: {
          x: 3,
          y: 2,
          z: 1,
        },
      };

      const result = await loader.push("en", input);
      expect(result).toEqual(expected);
    });

    it("should handle arrays by sorting their object elements", async () => {
      const input = {
        items: [
          { b: 1, a: 2 },
          { d: 3, c: 4 },
        ],
      };
      const expected = {
        items: [
          { a: 2, b: 1 },
          { c: 4, d: 3 },
        ],
      };

      const result = await loader.push("en", input);
      expect(result).toEqual(expected);
    });

    it("should handle mixed nested structures", async () => {
      const input = {
        zebra: [
          { beta: 2, alpha: 1 },
          { delta: 4, gamma: 3 },
        ],
        apple: {
          two: 2,
          one: 1,
        },
      };
      const expected = {
        apple: {
          one: 1,
          two: 2,
        },
        zebra: [
          { alpha: 1, beta: 2 },
          { delta: 4, gamma: 3 },
        ],
      };

      const result = await loader.push("en", input);
      expect(result).toEqual(expected);
    });

    it("should handle null and primitive values", async () => {
      const input = {
        c: null,
        b: "string",
        a: 123,
        d: true,
      };
      const expected = {
        a: 123,
        b: "string",
        c: null,
        d: true,
      };

      const result = await loader.push("en", input);
      expect(result).toEqual(expected);
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/plutil-formatter.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import { formatPlutilStyle } from "./plutil-formatter";

describe("plutil-formatter", () => {
  it("should format JSON matching Xcode style with existing indentation", () => {
    const existingJson = `{
    "sourceLanguage" : "en",
    "strings" : {
        "something" : {

        }
    }
}`;

    const input = {
      sourceLanguage: "en",
      strings: {
        complex_format: {
          extractionState: "manual",
          localizations: {
            ar: {
              stringUnit: {
                state: "translated",
                value: "المستخدم %1$@ لديه %2$lld نقطة ورصيد $%3$.2f",
              },
            },
          },
        },
        something: {},
      },
      version: "1.0",
    };

    const expected = `{
    "sourceLanguage" : "en",
    "strings" : {
        "complex_format" : {
            "extractionState" : "manual",
            "localizations" : {
                "ar" : {
                    "stringUnit" : {
                        "state" : "translated",
                        "value" : "المستخدم %1$@ لديه %2$lld نقطة ورصيد $%3$.2f"
                    }
                }
            }
        },
        "something" : {

        }
    },
    "version" : "1.0"
}`;
    const result = formatPlutilStyle(input, existingJson);

    expect(result).toBe(expected);
  });

  it("should detect and use 4-space indentation", () => {
    const existingJson = `{
    "foo": {
        "bar": {
        }
    }
}`;

    const input = {
      test: {
        nested: {},
      },
    };

    const expected = `{
    "test" : {
        "nested" : {

        }
    }
}`;

    const result = formatPlutilStyle(input, existingJson);
    expect(result).toBe(expected);
  });

  it("should fallback to 2 spaces when no existing JSON provided", () => {
    const input = {
      foo: {
        bar: {},
      },
    };

    const expected = `{
  "foo" : {
    "bar" : {

    }
  }
}`;

    const result = formatPlutilStyle(input);
    expect(result).toBe(expected);
  });

  it("should order keys correctly", () => {
    const input = {
      "2x": {},
      "3ABC": {},
      "3x": {},
      "4K": {},
      "7 min": {},
      "25": {},
      "30": {},
    };

    const expected = `{
  "2x" : {

  },
  "3ABC" : {

  },
  "3x" : {

  },
  "4K" : {

  },
  "7 min" : {

  },
  "25" : {

  },
  "30" : {

  }
}`;

    const result = formatPlutilStyle(input);
    expect(result).toBe(expected);
  });
});

```

--------------------------------------------------------------------------------
/scripts/docs/src/utils.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import {
  getRepoRoot,
  getGitHubToken,
  getGitHubRepo,
  getGitHubOwner,
  getGitHubPRNumber,
} from "./utils";

describe("utils", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  afterEach(() => {
    vi.unstubAllEnvs();
  });

  describe("getRepoRoot", () => {
    it("should find the repository root directory", () => {
      const result = getRepoRoot();
      expect(result).toBeDefined();
      expect(typeof result).toBe("string");
      expect(result.length).toBeGreaterThan(0);
    });
  });

  describe("getGitHubToken", () => {
    it("should return token when GITHUB_TOKEN is set", () => {
      vi.stubEnv("GITHUB_TOKEN", "test-token");

      const result = getGitHubToken();
      expect(result).toBe("test-token");
    });

    it("should throw error when GITHUB_TOKEN is not set", () => {
      vi.stubEnv("GITHUB_TOKEN", "");

      expect(() => getGitHubToken()).toThrow(
        "GITHUB_TOKEN environment variable is required.",
      );
    });
  });

  describe("getGitHubRepo", () => {
    it("should extract repo name from GITHUB_REPOSITORY", () => {
      vi.stubEnv("GITHUB_REPOSITORY", "owner/repo-name");

      const result = getGitHubRepo();
      expect(result).toBe("repo-name");
    });

    it("should throw error when GITHUB_REPOSITORY is not set", () => {
      vi.stubEnv("GITHUB_REPOSITORY", "");

      expect(() => getGitHubRepo()).toThrow(
        "GITHUB_REPOSITORY environment variable is missing.",
      );
    });
  });

  describe("getGitHubOwner", () => {
    it("should extract owner from GITHUB_REPOSITORY", () => {
      vi.stubEnv("GITHUB_REPOSITORY", "test-owner/repo-name");

      const result = getGitHubOwner();
      expect(result).toBe("test-owner");
    });

    it("should throw error when GITHUB_REPOSITORY is not set", () => {
      vi.stubEnv("GITHUB_REPOSITORY", "");

      expect(() => getGitHubOwner()).toThrow(
        "GITHUB_REPOSITORY environment variable is missing.",
      );
    });
  });

  describe("getGitHubPRNumber", () => {
    it("should return PR_NUMBER when set", () => {
      vi.stubEnv("PR_NUMBER", "123");

      const result = getGitHubPRNumber();
      expect(result).toBe(123);
    });

    it("should throw error when no PR number can be determined", () => {
      vi.stubEnv("PR_NUMBER", "");
      vi.stubEnv("GITHUB_EVENT_PATH", "");

      expect(() => getGitHubPRNumber()).toThrow(
        "Could not determine pull request number.",
      );
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/react/src/client/provider.spec.tsx:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import React from "react";
import { LingoProvider, LingoProviderWrapper } from "./provider";
import { LingoContext } from "./context";

vi.mock("./utils", async (orig) => {
  const actual = await orig();
  return {
    ...(actual as any),
    getLocaleFromCookies: vi.fn(() => "en"),
  };
});

describe("client/provider", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("LingoProvider", () => {
    it("throws when dictionary is missing", () => {
      expect(() =>
        render(
          <LingoProvider dictionary={undefined as any}>
            <div />
          </LingoProvider>,
        ),
      ).toThrowError(/dictionary is not provided/i);
    });

    it("provides dictionary via context", () => {
      const dict = { locale: "en", files: {} };
      const Probe = () => {
        return (
          <LingoContext.Consumer>
            {(value) => (
              <div data-testid="probe" data-locale={value.dictionary.locale} />
            )}
          </LingoContext.Consumer>
        );
      };

      render(
        <LingoProvider dictionary={dict}>
          <Probe />
        </LingoProvider>,
      );

      const el = screen.getByTestId("probe");
      expect(el.getAttribute("data-locale")).toBe("en");
    });
  });

  describe("LingoProviderWrapper", () => {
    it("loads dictionary and renders children; returns null while loading", async () => {
      const loadDictionary = vi
        .fn()
        .mockResolvedValue({ locale: "en", files: {} });

      const Child = () => <div data-testid="child">ok</div>;

      const { container, findByTestId } = render(
        <LingoProviderWrapper loadDictionary={loadDictionary}>
          <Child />
        </LingoProviderWrapper>,
      );

      // initially null during loading
      expect(container.firstChild).toBeNull();

      await waitFor(() => expect(loadDictionary).toHaveBeenCalled());
      const child = await findByTestId("child");
      expect(child != null).toBe(true);
    });

    it("swallows load errors and stays null", async () => {
      const loadDictionary = vi.fn().mockRejectedValue(new Error("boom"));
      const { container } = render(
        <LingoProviderWrapper loadDictionary={loadDictionary}>
          <div />
        </LingoProviderWrapper>,
      );

      await vi.waitFor(() => expect(loadDictionary).toHaveBeenCalled());
      expect(container.firstChild).toBeNull();
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/may-the-fourth.ts:
--------------------------------------------------------------------------------

```typescript
import { Command } from "interactive-commander";
import * as cp from "node:child_process";
import figlet from "figlet";
import chalk from "chalk";
import { vice } from "gradient-string";
import { setTimeout } from "node:timers/promises";

export const colors = {
  orange: "#ff6600",
  green: "#6ae300",
  blue: "#0090ff",
  yellow: "#ffcc00",
  grey: "#808080",
  red: "#ff0000",
};

export default new Command()
  .command("may-the-fourth")
  .description("May the Fourth be with you")
  .helpOption("-h, --help", "Show help")
  .action(async () => {
    await renderClear();
    await renderBanner();
    await renderSpacer();

    console.log(chalk.hex(colors.yellow)("Loading the Star Wars movie..."));
    await renderSpacer();

    await new Promise<void>((resolve, reject) => {
      const ssh = cp.spawn("ssh", ["starwarstel.net"], {
        stdio: "inherit",
      });

      ssh.on("close", (code) => {
        if (code !== 0) {
          console.error(`SSH process exited with code ${code}`);
          // Optionally reject the promise if the exit code is non-zero
          // reject(new Error(`SSH process exited with code ${code}`));
        }
        resolve(); // Resolve the promise when SSH closes
      });

      ssh.on("error", (err) => {
        console.error("Failed to start SSH process:", err);
        reject(err); // Reject the promise on error
      });
    });

    // This code now runs after the SSH process has finished
    await renderSpacer();
    console.log(
      `${chalk.hex(colors.green)("We hope you enjoyed it! :)")} ${chalk.hex(
        colors.blue,
      )("May the Fourth be with you! 🚀")}`,
    );
    await renderSpacer();
    console.log(chalk.dim(`---`));
    await renderSpacer();
    await renderHero();
  });

async function renderClear() {
  console.log("\x1Bc");
}

async function renderSpacer() {
  console.log(" ");
}

async function renderBanner() {
  console.log(
    vice(
      figlet.textSync("LINGO.DEV", {
        font: "ANSI Shadow",
        horizontalLayout: "default",
        verticalLayout: "default",
      }),
    ),
  );
}

async function renderHero() {
  console.log(
    `⚡️ ${chalk.hex(colors.green)(
      "Lingo.dev",
    )} - open-source, AI-powered i18n CLI for web & mobile localization.`,
  );
  console.log(" ");
  console.log(chalk.hex(colors.blue)("📚 Docs: https://lingo.dev/go/docs"));
  console.log(
    chalk.hex(colors.blue)("⭐ Star the repo: https://lingo.dev/go/gh"),
  );
  console.log(
    chalk.hex(colors.blue)("🎮 Join Discord: https://lingo.dev/go/discord"),
  );
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/lockfile.ts:
--------------------------------------------------------------------------------

```typescript
import fs from "fs";
import path from "path";
import Z from "zod";
import YAML from "yaml";
import { MD5 } from "object-hash";
import _ from "lodash";

export function createLockfileHelper() {
  return {
    isLockfileExists: () => {
      const lockfilePath = _getLockfilePath();
      return fs.existsSync(lockfilePath);
    },
    registerSourceData: (
      pathPattern: string,
      sourceData: Record<string, any>,
    ) => {
      const lockfile = _loadLockfile();

      const sectionKey = MD5(pathPattern);
      const sectionChecksums = _.mapValues(sourceData, (value) => MD5(value));

      lockfile.checksums[sectionKey] = sectionChecksums;

      _saveLockfile(lockfile);
    },
    registerPartialSourceData: (
      pathPattern: string,
      partialSourceData: Record<string, any>,
    ) => {
      const lockfile = _loadLockfile();

      const sectionKey = MD5(pathPattern);
      const sectionChecksums = _.mapValues(partialSourceData, (value) =>
        MD5(value),
      );

      lockfile.checksums[sectionKey] = _.merge(
        {},
        lockfile.checksums[sectionKey] ?? {},
        sectionChecksums,
      );

      _saveLockfile(lockfile);
    },
    extractUpdatedData: (
      pathPattern: string,
      sourceData: Record<string, any>,
    ) => {
      const lockfile = _loadLockfile();

      const sectionKey = MD5(pathPattern);
      const currentChecksums = _.mapValues(sourceData, (value) => MD5(value));

      const savedChecksums = lockfile.checksums[sectionKey] || {};
      const updatedData = _.pickBy(
        sourceData,
        (value, key) => savedChecksums[key] !== currentChecksums[key],
      );

      return updatedData;
    },
  };

  function _loadLockfile() {
    const lockfilePath = _getLockfilePath();
    if (!fs.existsSync(lockfilePath)) {
      return LockfileSchema.parse({});
    }
    const content = fs.readFileSync(lockfilePath, "utf-8");
    const result = LockfileSchema.parse(YAML.parse(content));
    return result;
  }

  function _saveLockfile(lockfile: Z.infer<typeof LockfileSchema>) {
    const lockfilePath = _getLockfilePath();
    const content = YAML.stringify(lockfile);
    fs.writeFileSync(lockfilePath, content);
  }

  function _getLockfilePath() {
    return path.join(process.cwd(), "i18n.lock");
  }
}

const LockfileSchema = Z.object({
  version: Z.literal(1).default(1),
  checksums: Z.record(
    Z.string(), // localizable files' keys
    Z.record(
      // checksums hashmap
      Z.string(), // key
      Z.string(), // checksum of the key's value in the source locale
    ).default({}),
  ).default({}),
});

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/show/files.ts:
--------------------------------------------------------------------------------

```typescript
import { Command } from "interactive-commander";
import _ from "lodash";
import Ora from "ora";
import { getConfig } from "../../utils/config";
import { CLIError } from "../../utils/errors";
import { getBuckets } from "../../utils/buckets";
import { resolveOverriddenLocale } from "@lingo.dev/_spec";

export default new Command()
  .command("files")
  .description(
    "Expand each bucket's path pattern into concrete source and target file paths",
  )
  .option(
    "--source",
    "Only list the source locale variant for each path pattern",
  )
  .option(
    "--target",
    "Only list the target locale variants for each configured locale",
  )
  .helpOption("-h, --help", "Show help")
  .action(async (type) => {
    const ora = Ora();
    try {
      try {
        const i18nConfig = await getConfig();

        if (!i18nConfig) {
          throw new CLIError({
            message:
              "i18n.json not found. Please run `lingo.dev init` to initialize the project.",
            docUrl: "i18nNotFound",
          });
        }

        const buckets = getBuckets(i18nConfig);
        for (const bucket of buckets) {
          for (const bucketConfig of bucket.paths) {
            const sourceLocale = resolveOverriddenLocale(
              i18nConfig.locale.source,
              bucketConfig.delimiter,
            );
            const sourcePath = bucketConfig.pathPattern.replace(
              /\[locale\]/g,
              sourceLocale,
            );
            const targetPaths = i18nConfig.locale.targets.map(
              (_targetLocale) => {
                const targetLocale = resolveOverriddenLocale(
                  _targetLocale,
                  bucketConfig.delimiter,
                );
                return bucketConfig.pathPattern.replace(
                  /\[locale\]/g,
                  targetLocale,
                );
              },
            );

            const result: string[] = [];
            if (!type.source && !type.target) {
              result.push(sourcePath, ...targetPaths);
            } else if (type.source) {
              result.push(sourcePath);
            } else if (type.target) {
              result.push(...targetPaths);
            }

            result.forEach((path) => {
              console.log(path);
            });
          }
        }
      } catch (error: any) {
        throw new CLIError({
          message: `Failed to expand placeholdered globs: ${error.message}`,
          docUrl: "placeHolderFailed",
        });
      }
    } catch (error: any) {
      ora.fail(error.message);
      process.exit(1);
    }
  });

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/jsx-expressions.test.ts:
--------------------------------------------------------------------------------

```typescript
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import { getJsxExpressions } from "./jsx-expressions";
import { describe, expect, it } from "vitest";
import * as t from "@babel/types";

function parseJSX(code: string) {
  return parse(code, {
    plugins: ["jsx"],
    sourceType: "module",
  });
}

describe("getJsxExpressions", () => {
  it("extracts simple expressions", () => {
    const ast = parseJSX("<div>{count + 1}</div>");
    let result;

    traverse(ast, {
      JSXElement(path) {
        result = getJsxExpressions(path);
        path.stop();
      },
    });

    expect(generate(result!).code).toBe("[count + 1]");
  });

  it("extracts multiple expressions", () => {
    const ast = parseJSX('<div>{count * 2} items in {category + "foo"}</div>');
    let result;

    traverse(ast, {
      JSXElement(path) {
        result = getJsxExpressions(path);
        path.stop();
      },
    });

    expect(generate(result!).code).toBe('[count * 2, category + "foo"]');
  });

  it("extracts complex expressions", () => {
    const ast = parseJSX('<div>{isAdmin ? "Admin" : user.role}</div>');
    let result;

    traverse(ast, {
      JSXElement(path) {
        result = getJsxExpressions(path);
        path.stop();
      },
    });

    expect(generate(result!).code).toBe('[isAdmin ? "Admin" : user.role]');
  });

  it("skips variables and member expressions", () => {
    const ast = parseJSX("<div>{count} items in {category.type}</div>");
    let result: t.ArrayExpression | undefined;

    traverse(ast, {
      JSXElement(path) {
        result = getJsxExpressions(path);
        path.stop();
      },
    });

    expect(generate(result!).code).toBe("[]");
  });

  it("skips function calls", () => {
    const ast = parseJSX("<div>{getName(user)} has {getCount()} items</div>");
    let result: t.ArrayExpression | undefined;

    traverse(ast, {
      JSXElement(path) {
        result = getJsxExpressions(path);
        path.stop();
      },
    });

    expect(generate(result!).code).toBe("[]");
  });

  it("extracts only expressions while skipping variables and functions", () => {
    const ast = parseJSX(
      '<div>{count + 1} by {user.name}, processed at {new Date().getTime() > 1000 ? "late" : "early"}</div>',
    );
    let result: t.ArrayExpression | undefined;

    traverse(ast, {
      JSXElement(path) {
        result = getJsxExpressions(path);
        path.stop();
      },
    });

    expect(generate(result!).code).toBe(
      '[count + 1, new Date().getTime() > 1000 ? "late" : "early"]',
    );
  });
});

```

--------------------------------------------------------------------------------
/packages/compiler/src/jsx-fragment.ts:
--------------------------------------------------------------------------------

```typescript
import { createCodeMutation } from "./_base";
import traverse from "@babel/traverse";
import * as t from "@babel/types";
import { getOrCreateImport } from "./utils";
import { CompilerPayload } from "./_base";

export function jsxFragmentMutation(
  payload: CompilerPayload,
): CompilerPayload | null {
  const { ast } = payload;

  let foundFragments = false;

  let fragmentImportName: string | null = null;

  traverse(ast, {
    ImportDeclaration(path) {
      if (path.node.source.value !== "react") return;

      for (const specifier of path.node.specifiers) {
        if (
          t.isImportSpecifier(specifier) &&
          t.isIdentifier(specifier.imported) &&
          specifier.imported.name === "Fragment"
        ) {
          fragmentImportName = specifier.local.name;
          path.stop();
        }
      }
    },
  });

  traverse(ast, {
    JSXFragment(path) {
      foundFragments = true;

      if (!fragmentImportName) {
        const result = getOrCreateImport(ast, {
          exportedName: "Fragment",
          moduleName: ["react"],
        });
        fragmentImportName = result.importedName;
      }

      const fragmentElement = t.jsxElement(
        t.jsxOpeningElement(t.jsxIdentifier(fragmentImportName), [], false),
        t.jsxClosingElement(t.jsxIdentifier(fragmentImportName)),
        path.node.children,
        false,
      );

      path.replaceWith(fragmentElement);
    },
  });

  return payload;
}

export function transformFragmentShorthand(ast: t.Node): boolean {
  let transformed = false;

  let fragmentImportName: string | null = null;

  traverse(ast, {
    ImportDeclaration(path) {
      if (path.node.source.value !== "react") return;

      for (const specifier of path.node.specifiers) {
        if (
          t.isImportSpecifier(specifier) &&
          t.isIdentifier(specifier.imported) &&
          specifier.imported.name === "Fragment"
        ) {
          fragmentImportName = specifier.local.name;
          path.stop();
        }
      }
    },
  });

  traverse(ast, {
    JSXFragment(path) {
      transformed = true;

      if (!fragmentImportName) {
        const result = getOrCreateImport(ast, {
          exportedName: "Fragment",
          moduleName: ["react"],
        });
        fragmentImportName = result.importedName;
      }

      const fragmentElement = t.jsxElement(
        t.jsxOpeningElement(t.jsxIdentifier(fragmentImportName), [], false),
        t.jsxClosingElement(t.jsxIdentifier(fragmentImportName)),
        path.node.children,
        false,
      );

      path.replaceWith(fragmentElement);
    },
  });

  return transformed;
}

```

--------------------------------------------------------------------------------
/demo/vite-project/src/lingo/meta.json:
--------------------------------------------------------------------------------

```json
{
  "version": 0.1,
  "files": {
    "App.tsx": {
      "scopes": {
        "7/body/1/argument/1/1/1-alt": {
          "type": "attribute",
          "hash": "4d15435212a4877c4226b33a8cae0488",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "Vite logo"
        },
        "7/body/1/argument/1/3/1-alt": {
          "type": "attribute",
          "hash": "b162441c9d07514a1c5124f9be178248",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "React logo"
        },
        "7/body/1/argument/3": {
          "type": "element",
          "hash": "dd6ddb089b0748e6c88b28c56c643d02",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "Lingo.dev loves Vite and React"
        },
        "7/body/1/argument/5": {
          "type": "element",
          "hash": "c6deea18ed327336cf526f7d5a268d18",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "Welcome to your new Vite & React application! This starter template includes everything you need to get started with Vite & React and Lingo.dev for internationalization."
        },
        "7/body/1/argument/7/1": {
          "type": "element",
          "hash": "c0057f8ebaf4debdf07033f51a6fd99d",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "count is {count}"
        },
        "7/body/1/argument/7/3": {
          "type": "element",
          "hash": "d373807bd0794bcfad789f038c92d8d4",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "Edit <element:code>src/App.tsx</element:code> and save to test HMR"
        },
        "7/body/1/argument/9": {
          "type": "element",
          "hash": "fee72ece6f86de4a1331fb2bbfb53919",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "Click on the logos above to learn more"
        }
      }
    },
    "components/test.tsx": {
      "scopes": {
        "0/declaration/0/init/body/0/argument/1": {
          "type": "element",
          "hash": "46316c70126692cd475cedb7a063803b",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "Testing Component"
        },
        "0/declaration/0/init/body/0/argument/3": {
          "type": "element",
          "hash": "eb0c9884ca11affbe842b0a8cd68d78f",
          "context": "",
          "skip": false,
          "overrides": {},
          "content": "This is a component intended for testing purposes."
        }
      }
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/typescript/cjs-interop.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Helpers for CommonJS ⇆ ES Module inter-op quirks.
 */

/**
 * Resolve the actual default export value of a CommonJS module that has been
 * imported via an ES-module `import` statement.
 *
 * Why is this needed?
 * -------------------
 * When a package that is published as **CommonJS** (for example, `@babel/traverse`)
 * is imported inside native **ESM** code (or via a bundler in ESM mode) the
 * runtime value you receive is not consistent across environments:
 *
 *   • **Node.js** (native ESM) wraps the CJS module in an object like
 *     `{ default: moduleExports, …namedReExports }`.
 *   • **esbuild / Vite / Vitest** may decide to mimic TypeScript's
 *     `esModuleInterop` behaviour and give you `moduleExports` directly.
 *   • Other tools can produce yet different shapes.
 *
 * If you blindly assume one shape, you will hit runtime errors such as
 * `TypeError: traverse is not a function` when the actual function lives on the
 * `.default` property — or the opposite, depending on the environment.
 *
 * This helper inspects the imported value at runtime and returns what looks like
 * the real default export regardless of how it was wrapped.  It hides the ugly
 * `typeof mod === "function" ? … : mod.default` branching behind a single call
 * site.
 *
 * Example
 * -------
 * ```ts
 * import traverseModule from "@babel/traverse";
 * import { resolveCjsExport } from "../utils/cjs-interop";
 *
 * const traverse = resolveCjsExport<typeof traverseModule>(
 *   traverseModule,
 *   "@babel/traverse",
 * );
 * ```
 *
 * @template T Expected type of the resolved export.
 * @param mod  The runtime value returned by the `import` statement.
 * @param name Friendly name of the module (for error messages).
 * @returns    The resolved default export value.
 */
export function resolveCjsExport<T = any>(mod: T, name: string = "module"): T {
  // If the module value itself is callable or clearly not an object, assume it's
  // already the export we want (covers most bundler scenarios).
  if (typeof mod === "function" || typeof mod !== "object" || mod === null) {
    return mod as T;
  }

  // Otherwise, look for a `.default` property which is common in Node's CJS->ESM
  // wrapper as well as in Babel's `interopRequireDefault` helpers.
  if ("default" in mod && typeof mod.default !== "undefined") {
    return mod.default as T;
  }

  // Give up: log the mysterious shape and throw to fail fast.
  /* eslint-disable no-console */
  console.error(
    `[resolveCjsExport] Unable to determine default export for ${name}.`,
    "Received value:",
    mod,
  );
  throw new Error(`Failed to resolve default export for ${name}.`);
}

```

--------------------------------------------------------------------------------
/packages/cli/demo/demo.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import fs from "fs";
import path from "path";
import { bucketTypes, parseI18nConfig } from "@lingo.dev/_spec";

type BucketType = (typeof bucketTypes)[number];

const SKIP_BUCKET_TYPES: BucketType[] = ["compiler", "dato"];

const TESTABLE_BUCKET_TYPES: BucketType[] = bucketTypes.filter(
  (type) => !SKIP_BUCKET_TYPES.includes(type),
);

describe("packages/cli/demo", () => {
  console.warn(
    `Bucket types are defined but not tested: ${SKIP_BUCKET_TYPES.join(", ")}`,
  );

  it("should include a demo for each bucket type", () => {
    const demoRoot = path.resolve(__dirname);
    const missingBuckets: string[] = [];

    for (const bucketType of new Set(TESTABLE_BUCKET_TYPES)) {
      const bucketPath = path.join(demoRoot, bucketType);
      const exists = fs.existsSync(bucketPath);
      if (!exists) {
        missingBuckets.push(bucketType);
      }
    }

    expect(missingBuckets).toEqual([]);
  });

  it("should have an i18n.json file in each bucket demo", () => {
    const demoRoot = path.resolve(__dirname);
    const missingFiles: string[] = [];

    for (const bucketType of new Set(TESTABLE_BUCKET_TYPES)) {
      const bucketPath = path.join(demoRoot, bucketType);
      const i18nJsonPath = path.join(bucketPath, "i18n.json");
      if (!fs.existsSync(i18nJsonPath)) {
        missingFiles.push(bucketType);
      }
    }

    expect(missingFiles).toEqual([]);
  });

  it("should have valid i18n.json config in each bucket demo", () => {
    const demoRoot = path.resolve(__dirname);
    const invalidConfigs: Array<{ bucketType: string; error: string }> = [];

    for (const bucketType of new Set(TESTABLE_BUCKET_TYPES)) {
      const bucketPath = path.join(demoRoot, bucketType);
      const i18nJsonPath = path.join(bucketPath, "i18n.json");
      try {
        const configContent = fs.readFileSync(i18nJsonPath, "utf-8");
        const rawConfig = JSON.parse(configContent);
        parseI18nConfig(rawConfig);
      } catch (error) {
        invalidConfigs.push({
          bucketType,
          error: error instanceof Error ? error.message : String(error),
        });
      }
    }

    expect(invalidConfigs).toEqual([]);
  });

  it("should have an i18n.lock file in each bucket demo", () => {
    const demoRoot = path.resolve(__dirname);
    const missingFiles: string[] = [];

    for (const bucketType of new Set(TESTABLE_BUCKET_TYPES)) {
      const bucketPath = path.join(demoRoot, bucketType);
      const i18nLockPath = path.join(bucketPath, "i18n.lock");
      if (!fs.existsSync(i18nLockPath)) {
        missingFiles.push(bucketType);
      }
    }

    expect(missingFiles).toEqual([]);
  });
});

```
Page 3/16FirstPrevNextLast