#
tokens: 49751/50000 71/626 files (page 3/20)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 3 of 20. Use http://codebase.md/lingodotdev/lingo.dev?lines=true&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/react/build.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineBuildConfig } from "unbuild";
 2 | 
 3 | export default defineBuildConfig({
 4 |   /* Clean the output directory before each build */
 5 |   clean: true,
 6 | 
 7 |   /* Where generated files are written */
 8 |   outDir: "build",
 9 | 
10 |   /* Generate type declarations */
11 |   declaration: true,
12 | 
13 |   /* Generate source-maps */
14 |   sourcemap: true,
15 | 
16 |   /* Treat these as external – they must be provided by the host app */
17 |   externals: ["react", "next"],
18 | 
19 |   /* Transpile every file in src/ one-to-one into build/ keeping the folder structure */
20 |   entries: [
21 |     {
22 |       builder: "mkdist",
23 |       /* All TS/TSX/JS/JSX files under src become part of the build */
24 |       input: "./src",
25 |       /* Mirror the structure in the build directory */
26 |       outDir: "./build",
27 |       /* Emit ESM with the standard .js extension */
28 |       format: "esm",
29 |       ext: "js",
30 |       /* Produce matching .d.ts files next to their JS counterparts */
31 |       declaration: true,
32 |       /* Ensure relative imports inside declaration files include the .js extension */
33 |       addRelativeDeclarationExtensions: true,
34 |       /* Use React 17+ automatic JSX runtime so output imports jsx from react/jsx-runtime */
35 |       esbuild: {
36 |         jsx: "automatic",
37 |         jsxImportSource: "react",
38 |       },
39 |     },
40 |   ],
41 | });
42 | 
```

--------------------------------------------------------------------------------
/packages/compiler/src/lingo-turbopack-loader.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { loadDictionary, transformComponent } from "./_loader-utils";
 2 | 
 3 | // This loader handles component transformations and dictionary generation
 4 | export default async function (this: any, source: string) {
 5 |   const callback = this.async();
 6 |   const params = this.getOptions();
 7 |   const isDev = process.env.NODE_ENV !== "production";
 8 | 
 9 |   try {
10 |     // Dictionary loading
11 |     const dictionary = await loadDictionary({
12 |       resourcePath: this.resourcePath,
13 |       resourceQuery: this.resourceQuery,
14 |       params,
15 |       sourceRoot: params.sourceRoot,
16 |       lingoDir: params.lingoDir,
17 |       isDev,
18 |     });
19 | 
20 |     if (dictionary) {
21 |       const code = `export default ${JSON.stringify(dictionary, null, 2)};`;
22 |       return callback(null, code);
23 |     }
24 | 
25 |     // Component transformation
26 |     const result = transformComponent({
27 |       code: source,
28 |       params,
29 |       resourcePath: this.resourcePath,
30 |       sourceRoot: params.sourceRoot,
31 |     });
32 | 
33 |     return callback(
34 |       null,
35 |       result.code,
36 |       result.map ? JSON.stringify(result.map) : undefined,
37 |     );
38 |   } catch (error) {
39 |     console.error(
40 |       `⚠️  Lingo.dev compiler (Turbopack) failed for ${this.resourcePath}:`,
41 |     );
42 |     console.error("⚠️  Details:", error);
43 |     callback(error as Error);
44 |   }
45 | }
46 | 
```

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

```typescript
 1 | import { describe, it, expect, vi, beforeEach } from "vitest";
 2 | import compiler from "./index";
 3 | 
 4 | // Silence logs in tests
 5 | vi.spyOn(console, "log").mockImplementation(() => undefined as any);
 6 | vi.spyOn(console, "warn").mockImplementation(() => undefined as any);
 7 | 
 8 | vi.mock("./utils/env", () => ({ isRunningInCIOrDocker: () => true }));
 9 | vi.mock("./lib/lcp/cache", () => ({
10 |   LCPCache: { ensureDictionaryFile: vi.fn() },
11 | }));
12 | vi.mock("unplugin", () => ({
13 |   createUnplugin: () => ({
14 |     vite: vi.fn(() => ({ name: "test-plugin" })),
15 |     webpack: vi.fn(() => ({ name: "test-plugin" })),
16 |   }),
17 | }));
18 | 
19 | describe("compiler integration", () => {
20 |   beforeEach(() => {
21 |     (process as any).env = { ...process.env };
22 |   });
23 | 
24 |   it("next() returns a function and sets webpack wrapper when turbopack disabled", () => {
25 |     const cfg: any = { webpack: (c: any) => c };
26 |     const out = compiler.next({
27 |       sourceRoot: "src",
28 |       models: "lingo.dev",
29 |       turbopack: { enabled: false },
30 |     })(cfg);
31 |     expect(typeof out.webpack).toBe("function");
32 |   });
33 | 
34 |   it("vite() pushes plugin to front and detects framework label", () => {
35 |     const cfg: any = { plugins: [{ name: "react-router" }] };
36 |     const out = compiler.vite({})(cfg);
37 |     expect(out.plugins[0]).toBeDefined();
38 |   });
39 | });
40 | 
```

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

```typescript
 1 | import { describe, it, expect, vi } from "vitest";
 2 | import React from "react";
 3 | import { LingoContext } from "./context";
 4 | 
 5 | vi.mock("../core", () => {
 6 |   return {
 7 |     LingoAttributeComponent: (props: any) => {
 8 |       return React.createElement("div", {
 9 |         "data-testid": "core-attr",
10 |         "data-has-dictionary": props.$dictionary ? "yes" : "no",
11 |         "data-file": props.$fileKey,
12 |       });
13 |     },
14 |   };
15 | });
16 | 
17 | describe("client/attribute-component", () => {
18 |   describe("LingoAttributeComponent wrapper", () => {
19 |     it("injects dictionary from context into core attribute component", async () => {
20 |       const dictionary = { locale: "en" } as any;
21 |       const { LingoAttributeComponent } = await import("./attribute-component");
22 |       const { render, screen } = await import("@testing-library/react");
23 | 
24 |       render(
25 |         <LingoContext.Provider value={{ dictionary }}>
26 |           <LingoAttributeComponent
27 |             $attrAs="a"
28 |             $fileKey="messages"
29 |             $attributes={{ title: "title" }}
30 |           />
31 |         </LingoContext.Provider>,
32 |       );
33 | 
34 |       const el = await screen.findByTestId("core-attr");
35 |       expect(el.getAttribute("data-has-dictionary")).toBe("yes");
36 |       expect(el.getAttribute("data-file")).toBe("messages");
37 |     });
38 |   });
39 | });
40 | 
```

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

```typescript
 1 | /*
 2 | |--------------------------------------------------------------------------
 3 | | HTTP server entrypoint
 4 | |--------------------------------------------------------------------------
 5 | |
 6 | | The "server.ts" file is the entrypoint for starting the AdonisJS HTTP
 7 | | server. Either you can run this file directly or use the "serve"
 8 | | command to run this file and monitor file changes
 9 | |
10 | */
11 | 
12 | import 'reflect-metadata'
13 | import { Ignitor, prettyPrintError } from '@adonisjs/core'
14 | 
15 | /**
16 |  * URL to the application root. AdonisJS need it to resolve
17 |  * paths to file and directories for scaffolding commands
18 |  */
19 | const APP_ROOT = new URL('../', import.meta.url)
20 | 
21 | /**
22 |  * The importer is used to import files in context of the
23 |  * application.
24 |  */
25 | const IMPORTER = (filePath: string) => {
26 |   if (filePath.startsWith('./') || filePath.startsWith('../')) {
27 |     return import(new URL(filePath, APP_ROOT).href)
28 |   }
29 |   return import(filePath)
30 | }
31 | 
32 | new Ignitor(APP_ROOT, { importer: IMPORTER })
33 |   .tap((app) => {
34 |     app.booting(async () => {
35 |       await import('#start/env')
36 |     })
37 |     app.listen('SIGTERM', () => app.terminate())
38 |     app.listenIf(app.managedByPm2, 'SIGINT', () => app.terminate())
39 |   })
40 |   .httpServer()
41 |   .start()
42 |   .catch((error) => {
43 |     process.exitCode = 1
44 |     prettyPrintError(error)
45 |   })
46 | 
```

--------------------------------------------------------------------------------
/demo/adonisjs/config/bodyparser.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from '@adonisjs/core/bodyparser'
 2 | 
 3 | const bodyParserConfig = defineConfig({
 4 |   /**
 5 |    * The bodyparser middleware will parse the request body
 6 |    * for the following HTTP methods.
 7 |    */
 8 |   allowedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],
 9 | 
10 |   /**
11 |    * Config for the "application/x-www-form-urlencoded"
12 |    * content-type parser
13 |    */
14 |   form: {
15 |     convertEmptyStringsToNull: true,
16 |     types: ['application/x-www-form-urlencoded'],
17 |   },
18 | 
19 |   /**
20 |    * Config for the JSON parser
21 |    */
22 |   json: {
23 |     convertEmptyStringsToNull: true,
24 |     types: [
25 |       'application/json',
26 |       'application/json-patch+json',
27 |       'application/vnd.api+json',
28 |       'application/csp-report',
29 |     ],
30 |   },
31 | 
32 |   /**
33 |    * Config for the "multipart/form-data" content-type parser.
34 |    * File uploads are handled by the multipart parser.
35 |    */
36 |   multipart: {
37 |     /**
38 |      * Enabling auto process allows bodyparser middleware to
39 |      * move all uploaded files inside the tmp folder of your
40 |      * operating system
41 |      */
42 |     autoProcess: true,
43 |     convertEmptyStringsToNull: true,
44 |     processManually: [],
45 | 
46 |     /**
47 |      * Maximum limit of data to parse including all files
48 |      * and fields
49 |      */
50 |     limit: '20mb',
51 |     types: ['multipart/form-data'],
52 |   },
53 | })
54 | 
55 | export default bodyParserConfig
56 | 
```

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

```typescript
 1 | import { it, describe, expect } from "vitest";
 2 | import { parse } from "@babel/parser";
 3 | import traverse, { NodePath } from "@babel/traverse";
 4 | import { getAstKey, getAstByKey } from "./ast-key";
 5 | 
 6 | describe("ast key", () => {
 7 |   it("getAstKey should calc nodePath key", () => {
 8 |     const mockData = createMockData();
 9 | 
10 |     const key = getAstKey(mockData.testElementPath);
11 | 
12 |     expect(key).toBe(mockData.testElementKey);
13 |   });
14 | });
15 | 
16 | describe("getAstByKey", () => {
17 |   it("should retrieve correct node by key", () => {
18 |     const mockData = createMockData();
19 | 
20 |     const elementPath = getAstByKey(mockData.ast, mockData.testElementKey);
21 | 
22 |     expect(elementPath).toBe(mockData.testElementPath);
23 |   });
24 | });
25 | 
26 | // helpers
27 | 
28 | function createMockData() {
29 |   const ast = parse(
30 |     `
31 |     export function MyComponent() {
32 |       return <div>Hello world!</div>;
33 |     }
34 | `,
35 |     { sourceType: "module", plugins: ["jsx"] },
36 |   );
37 | 
38 |   let testElementPath: NodePath | null = null;
39 |   traverse(ast, {
40 |     JSXElement(nodePath) {
41 |       testElementPath = nodePath;
42 |     },
43 |   });
44 |   if (!testElementPath) {
45 |     throw new Error(
46 |       "testElementPath cannot be null - check test case definition",
47 |     );
48 |   }
49 | 
50 |   const testElementKey = `0/declaration/body/0/argument`;
51 | 
52 |   return {
53 |     ast,
54 |     testElementPath,
55 |     testElementKey,
56 |   };
57 | }
58 | 
```

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

```typescript
 1 | import webvtt from "node-webvtt";
 2 | import { ILoader } from "./_types";
 3 | import { createLoader } from "./_utils";
 4 | 
 5 | export default function createVttLoader(): ILoader<
 6 |   string,
 7 |   Record<string, any>
 8 | > {
 9 |   return createLoader({
10 |     async pull(locale, input) {
11 |       if (!input) {
12 |         return ""; // if VTT file does not exist yet we can not parse it - return empty string
13 |       }
14 |       const vtt = webvtt.parse(input)?.cues;
15 |       if (Object.keys(vtt).length === 0) {
16 |         return {};
17 |       } else {
18 |         return vtt.reduce((result: any, cue: any, index: number) => {
19 |           const key = `${index}#${cue.start}-${cue.end}#${cue.identifier}`;
20 |           result[key] = cue.text;
21 |           return result;
22 |         }, {});
23 |       }
24 |     },
25 |     async push(locale, payload) {
26 |       const output = Object.entries(payload).map(([key, text]) => {
27 |         const [id, timeRange, identifier] = key.split("#");
28 |         const [startTime, endTime] = timeRange.split("-");
29 | 
30 |         return {
31 |           end: Number(endTime),
32 |           identifier: identifier,
33 |           start: Number(startTime),
34 |           styles: "",
35 |           text: text,
36 |         };
37 |       });
38 | 
39 |       const input = {
40 |         valid: true,
41 |         strict: true,
42 |         cues: output,
43 |       };
44 | 
45 |       return webvtt.compile(input);
46 |     },
47 |   });
48 | }
49 | 
```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/mdx2/frontmatter-split.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import matter from "gray-matter";
 2 | import YAML from "yaml";
 3 | import { ILoader } from "../_types";
 4 | import { createLoader } from "../_utils";
 5 | import { RawMdx } from "./_types";
 6 | 
 7 | export default function createMdxFrontmatterSplitLoader(): ILoader<
 8 |   string,
 9 |   RawMdx
10 | > {
11 |   const fmEngine = createFmEngine();
12 | 
13 |   return createLoader({
14 |     async pull(locale, input) {
15 |       const source = input || "";
16 |       const { data: frontmatter, content } = fmEngine.parse(source);
17 | 
18 |       return {
19 |         frontmatter: frontmatter as Record<string, any>,
20 |         content,
21 |       };
22 |     },
23 | 
24 |     async push(locale, data) {
25 |       const { frontmatter = {}, content = "" } = data || ({} as RawMdx);
26 | 
27 |       const result = fmEngine.stringify(content, frontmatter).trim();
28 | 
29 |       return result;
30 |     },
31 |   });
32 | }
33 | 
34 | function createFmEngine() {
35 |   const yamlEngine = {
36 |     parse: (str: string) => YAML.parse(str),
37 |     stringify: (obj: any) =>
38 |       YAML.stringify(obj, { defaultStringType: "PLAIN" }),
39 |   };
40 | 
41 |   return {
42 |     parse: (input: string) =>
43 |       matter(input, {
44 |         engines: {
45 |           yaml: yamlEngine,
46 |         },
47 |       }),
48 |     stringify: (content: string, frontmatter: Record<string, any>) =>
49 |       matter.stringify(content, frontmatter, {
50 |         engines: {
51 |           yaml: yamlEngine,
52 |         },
53 |       }),
54 |   };
55 | }
56 | 
```

--------------------------------------------------------------------------------
/packages/react/src/rsc/loader.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { getDictionary } from "../core";
 2 | 
 3 | /**
 4 |  * A placeholder function for loading dictionaries that contain localized content.
 5 |  *
 6 |  * This function:
 7 |  *
 8 |  * - Should be used in React Server Components
 9 |  * - Should be passed into the `LingoProvider` component
10 |  * - Is transformed into functional code by Lingo.dev Compiler
11 |  *
12 |  * @param locale - The locale code for which to load the dictionary.
13 |  *
14 |  * @returns Promise that resolves to the dictionary object containing localized content.
15 |  *
16 |  * @example Use in a Next.js (App Router) application
17 |  * ```tsx file="app/layout.tsx"
18 |  * import { LingoProvider, loadDictionary } from "lingo.dev/react/rsc";
19 |  *
20 |  * export default function RootLayout({
21 |  *   children,
22 |  * }: Readonly<{
23 |  *   children: React.ReactNode;
24 |  * }>) {
25 |  *   return (
26 |  *     <LingoProvider loadDictionary={(locale) => loadDictionary(locale)}>
27 |  *       <html lang="en">
28 |  *        <body>
29 |  *           {children}
30 |  *         </body>
31 |  *       </html>
32 |  *     </LingoProvider>
33 |  *   );
34 |  * }
35 |  * ```
36 |  */
37 | export const loadDictionary = async (locale: string | null): Promise<any> => {
38 |   return {};
39 | };
40 | 
41 | export const loadDictionary_internal = async (
42 |   locale: string | null,
43 |   dictionaryLoaders: Record<string, () => Promise<any>> = {},
44 | ): Promise<any> => {
45 |   return getDictionary(locale, dictionaryLoaders);
46 | };
47 | 
```

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

```typescript
 1 | import { parseStringPromise, Builder } from "xml2js";
 2 | import { ILoader } from "./_types";
 3 | import { createLoader } from "./_utils";
 4 | 
 5 | function normalizeXMLString(xmlString: string): string {
 6 |   return xmlString
 7 |     .replace(/\s+/g, " ")
 8 |     .replace(/>\s+</g, "><")
 9 |     .replace("\n", "")
10 |     .trim();
11 | }
12 | 
13 | export default function createXmlLoader(): ILoader<
14 |   string,
15 |   Record<string, any>
16 | > {
17 |   return createLoader({
18 |     async pull(locale, input) {
19 |       let result: Record<string, any> = {};
20 | 
21 |       try {
22 |         const parsed = await parseStringPromise(input, {
23 |           explicitArray: false,
24 |           mergeAttrs: false,
25 |           normalize: true,
26 |           preserveChildrenOrder: true,
27 |           normalizeTags: true,
28 |           includeWhiteChars: true,
29 |           trim: true,
30 |         });
31 |         result = parsed;
32 |       } catch (error) {
33 |         console.error("Failed to parse XML:", error);
34 |         result = {};
35 |       }
36 | 
37 |       return result;
38 |     },
39 | 
40 |     async push(locale, data) {
41 |       try {
42 |         const builder = new Builder({ headless: true });
43 |         const xmlOutput = builder.buildObject(data);
44 |         const expectedOutput = normalizeXMLString(xmlOutput);
45 |         return expectedOutput;
46 |       } catch (error) {
47 |         console.error("Failed to build XML:", error);
48 |         return "";
49 |       }
50 |     },
51 |   });
52 | }
53 | 
```

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

```typescript
 1 | import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
 2 | import trackEvent from "./observability";
 3 | 
 4 | vi.mock("./rc", () => ({ getRc: () => ({ auth: {} }) }));
 5 | vi.mock("node-machine-id", () => ({ machineId: async () => "device-123" }));
 6 | 
 7 | // Mock PostHog client used by dynamic import inside trackEvent
 8 | const capture = vi.fn(async () => undefined);
 9 | const shutdown = vi.fn(async () => undefined);
10 | const PostHogMock = vi.fn((_key: string, _cfg: any) => ({ capture, shutdown }));
11 | vi.mock("posthog-node", () => ({ PostHog: PostHogMock }));
12 | 
13 | describe("trackEvent", () => {
14 |   const originalEnv = { ...process.env };
15 |   afterEach(() => {
16 |     process.env = originalEnv;
17 |   });
18 | 
19 |   it("captures the event with properties", async () => {
20 |     await trackEvent("test.event", { foo: "bar" });
21 |     expect(PostHogMock).toHaveBeenCalledTimes(1);
22 |     expect(capture).toHaveBeenCalledWith(
23 |       expect.objectContaining({
24 |         event: "test.event",
25 |         properties: expect.objectContaining({ foo: "bar" }),
26 |       }),
27 |     );
28 |     expect(shutdown).toHaveBeenCalledTimes(1);
29 |   });
30 | 
31 |   it("skips when DO_NOT_TRACK is set", async () => {
32 |     process.env = { ...originalEnv, DO_NOT_TRACK: "1" };
33 |     // Should not throw nor attempt network
34 |     await expect(trackEvent("test.event", { a: 1 })).resolves.toBeUndefined();
35 |   });
36 | });
37 | 
```

--------------------------------------------------------------------------------
/packages/compiler/src/jsx-remove-attributes.spec.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import { jsxRemoveAttributesMutation } from "./jsx-remove-attributes";
 3 | import { createPayload, createOutput, defaultParams } from "./_base";
 4 | 
 5 | // Helper function to run mutation and get result
 6 | function runMutation(code: string) {
 7 |   const input = createPayload({ code, params: defaultParams, fileKey: "test" });
 8 |   const mutated = jsxRemoveAttributesMutation(input);
 9 |   if (!mutated) return code; // Return original code if no changes made
10 |   return createOutput(mutated).code;
11 | }
12 | 
13 | describe("jsxRemoveAttributesMutation", () => {
14 |   it("should remove only attributes added by compiler", () => {
15 |     const input = `
16 | function Component() {
17 |   return <div data-jsx-root>
18 |     <p data-jsx-scope="foo" data-other="1">Hello world</p>
19 |     <p data-jsx-attribute-scope="bar" className="text-success">Good night moon</p>
20 |     <p data-jsx-scope="foobar" data-jsx-attribute-scope="barfoo" className="text-danger" data-other="2">Good morning sun</p>
21 |   </div>;
22 | }
23 | `.trim();
24 | 
25 |     const expected = `
26 | function Component() {
27 |   return <div>
28 |     <p data-other="1">Hello world</p>
29 |     <p className="text-success">Good night moon</p>
30 |     <p className="text-danger" data-other="2">Good morning sun</p>
31 |   </div>;
32 | }
33 | `.trim();
34 |     const result = runMutation(input);
35 |     expect(result).toBe(expected);
36 |   });
37 | });
38 | 
```

--------------------------------------------------------------------------------
/packages/react/src/client/loader.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { getDictionary } from "../core";
 2 | 
 3 | /**
 4 |  * A placeholder function for loading dictionaries that contain localized content.
 5 |  *
 6 |  * This function:
 7 |  *
 8 |  * - Should be used in client-side rendered applications (e.g., Vite-based apps)
 9 |  * - Should be passed into the `LingoProviderWrapper` component
10 |  * - Is transformed into functional code by Lingo.dev Compiler
11 |  *
12 |  * @param locale - The locale to load the dictionary for.
13 |  *
14 |  * @returns Promise that resolves to the dictionary object containing localized content.
15 |  *
16 |  * @example Use in a Vite application
17 |  * ```tsx
18 |  * import React from "react";
19 |  * import ReactDOM from "react-dom/client";
20 |  * import { LingoProviderWrapper, loadDictionary } from "lingo.dev/react/client";
21 |  * import { App } from "./App.tsx";
22 |  *
23 |  * ReactDOM.createRoot(document.getElementById("root")!).render(
24 |  *   <React.StrictMode>
25 |  *     <LingoProviderWrapper loadDictionary={(locale) => loadDictionary(locale)}>
26 |  *       <App />
27 |  *     </LingoProviderWrapper>
28 |  *   </React.StrictMode>,
29 |  * );
30 |  * ```
31 |  */
32 | export const loadDictionary = async (locale: string | null): Promise<any> => {
33 |   return {};
34 | };
35 | 
36 | export const loadDictionary_internal = async (
37 |   locale: string | null,
38 |   dictionaryLoaders: Record<string, () => Promise<any>> = {},
39 | ): Promise<any> => {
40 |   return getDictionary(locale, dictionaryLoaders);
41 | };
42 | 
```

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

```typescript
 1 | /*
 2 | |--------------------------------------------------------------------------
 3 | | Ace entry point
 4 | |--------------------------------------------------------------------------
 5 | |
 6 | | The "console.ts" file is the entrypoint for booting the AdonisJS
 7 | | command-line framework and executing commands.
 8 | |
 9 | | Commands do not boot the application, unless the currently running command
10 | | has "options.startApp" flag set to true.
11 | |
12 | */
13 | 
14 | import 'reflect-metadata'
15 | import { Ignitor, prettyPrintError } from '@adonisjs/core'
16 | 
17 | /**
18 |  * URL to the application root. AdonisJS need it to resolve
19 |  * paths to file and directories for scaffolding commands
20 |  */
21 | const APP_ROOT = new URL('../', import.meta.url)
22 | 
23 | /**
24 |  * The importer is used to import files in context of the
25 |  * application.
26 |  */
27 | const IMPORTER = (filePath: string) => {
28 |   if (filePath.startsWith('./') || filePath.startsWith('../')) {
29 |     return import(new URL(filePath, APP_ROOT).href)
30 |   }
31 |   return import(filePath)
32 | }
33 | 
34 | new Ignitor(APP_ROOT, { importer: IMPORTER })
35 |   .tap((app) => {
36 |     app.booting(async () => {
37 |       await import('#start/env')
38 |     })
39 |     app.listen('SIGTERM', () => app.terminate())
40 |     app.listenIf(app.managedByPm2, 'SIGINT', () => app.terminate())
41 |   })
42 |   .ace()
43 |   .handle(process.argv.splice(2))
44 |   .catch((error) => {
45 |     process.exitCode = 1
46 |     prettyPrintError(error)
47 |   })
48 | 
```

--------------------------------------------------------------------------------
/packages/react/src/client/component.lingo-component.spec.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect, vi } from "vitest";
 2 | import React from "react";
 3 | import { LingoContext } from "./context";
 4 | 
 5 | // Mock core LingoComponent to capture received props
 6 | vi.mock("../core", () => {
 7 |   return {
 8 |     LingoComponent: (props: any) => {
 9 |       return React.createElement("div", {
10 |         "data-testid": "core-lingo-component",
11 |         "data-has-dictionary": props.$dictionary ? "yes" : "no",
12 |         "data-entry": props.$entryKey,
13 |         "data-file": props.$fileKey,
14 |       });
15 |     },
16 |   };
17 | });
18 | 
19 | describe("client/component", () => {
20 |   describe("LingoComponent wrapper", () => {
21 |     it("renders core component with dictionary from context and forwards keys", async () => {
22 |       const dictionary = { locale: "en" } as any;
23 |       const { LingoComponent } = await import("./component");
24 |       const { render, screen } = await import("@testing-library/react");
25 | 
26 |       render(
27 |         <LingoContext.Provider value={{ dictionary }}>
28 |           <LingoComponent $as="span" $fileKey="messages" $entryKey="hello" />
29 |         </LingoContext.Provider>,
30 |       );
31 | 
32 |       const el = await screen.findByTestId("core-lingo-component");
33 |       expect(el.getAttribute("data-has-dictionary")).toBe("yes");
34 |       expect(el.getAttribute("data-file")).toBe("messages");
35 |       expect(el.getAttribute("data-entry")).toBe("hello");
36 |     });
37 |   });
38 | });
39 | 
```

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

```typescript
 1 | import { Command } from "interactive-commander";
 2 | import chalk from "chalk";
 3 | import _ from "lodash";
 4 | import { SETTINGS_KEYS, loadSystemSettings } from "../../utils/settings";
 5 | import dedent from "dedent";
 6 | 
 7 | export default new Command()
 8 |   .name("get")
 9 |   .description("Display the value of a CLI setting from ~/.lingodotdevrc")
10 |   .addHelpText("afterAll", `\nAvailable keys:\n  ${SETTINGS_KEYS.join("\n  ")}`)
11 |   .argument(
12 |     "<key>",
13 |     "Configuration key to read (choose from the available keys listed below)",
14 |   )
15 |   .helpOption("-h, --help", "Show help")
16 |   .action(async (key: string) => {
17 |     // Validate that the provided key is one of the recognised configuration keys.
18 |     if (!SETTINGS_KEYS.includes(key)) {
19 |       console.error(
20 |         dedent`
21 |           ${chalk.red("✖")} Unknown configuration key: ${chalk.bold(key)}
22 |           Run ${chalk.dim("lingo.dev config get --help")} to see available keys.
23 |         `,
24 |       );
25 |       process.exitCode = 1;
26 |       return;
27 |     }
28 | 
29 |     const settings = loadSystemSettings();
30 |     const value = _.get(settings, key);
31 | 
32 |     if (!value) {
33 |       // Key is valid but not set in the configuration file.
34 |       console.log(`${chalk.cyan("ℹ")} ${chalk.bold(key)} is not set.`);
35 |       return;
36 |     }
37 | 
38 |     if (typeof value === "object") {
39 |       console.log(JSON.stringify(value, null, 2));
40 |     } else {
41 |       console.log(value);
42 |     }
43 |   });
44 | 
```

--------------------------------------------------------------------------------
/demo/next-app/public/next.svg:
--------------------------------------------------------------------------------

```
1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
```

--------------------------------------------------------------------------------
/packages/react/src/rsc/component.lingo-component.spec.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect, vi } from "vitest";
 2 | import React from "react";
 3 | 
 4 | vi.mock("./utils", () => {
 5 |   return {
 6 |     loadDictionaryFromRequest: vi.fn(async (loader: any) => loader("es")),
 7 |   };
 8 | });
 9 | 
10 | // Mock core LingoComponent to capture props
11 | vi.mock("../core", () => {
12 |   return {
13 |     LingoComponent: (props: any) => {
14 |       return React.createElement("div", {
15 |         "data-testid": "core-lingo-component",
16 |         "data-dictionary-locale": props.$dictionary?.locale ?? "none",
17 |         "data-entry": props.$entryKey,
18 |         "data-file": props.$fileKey,
19 |       });
20 |     },
21 |   };
22 | });
23 | 
24 | describe("rsc/component", () => {
25 |   describe("LingoComponent wrapper", () => {
26 |     it("awaits dictionary and forwards props to core component", async () => {
27 |       const { LingoComponent } = await import("./component");
28 |       const { render, screen } = await import("@testing-library/react");
29 | 
30 |       render(
31 |         await LingoComponent({
32 |           $as: "span",
33 |           $fileKey: "messages",
34 |           $entryKey: "hello",
35 |           $loadDictionary: async (locale: string | null) => ({ locale }),
36 |         }),
37 |       );
38 | 
39 |       const el = await screen.findByTestId("core-lingo-component");
40 |       expect(el.getAttribute("data-dictionary-locale")).toBe("es");
41 |       expect(el.getAttribute("data-file")).toBe("messages");
42 |       expect(el.getAttribute("data-entry")).toBe("hello");
43 |     });
44 |   });
45 | });
46 | 
```

--------------------------------------------------------------------------------
/demo/adonisjs/start/kernel.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /*
 2 | |--------------------------------------------------------------------------
 3 | | HTTP kernel file
 4 | |--------------------------------------------------------------------------
 5 | |
 6 | | The HTTP kernel file is used to register the middleware with the server
 7 | | or the router.
 8 | |
 9 | */
10 | 
11 | import router from '@adonisjs/core/services/router'
12 | import server from '@adonisjs/core/services/server'
13 | 
14 | /**
15 |  * The error handler is used to convert an exception
16 |  * to an HTTP response.
17 |  */
18 | server.errorHandler(() => import('#exceptions/handler'))
19 | 
20 | /**
21 |  * The server middleware stack runs middleware on all the HTTP
22 |  * requests, even if there is no route registered for
23 |  * the request URL.
24 |  */
25 | server.use([
26 |   () => import('#middleware/container_bindings_middleware'),
27 |   () => import('@adonisjs/static/static_middleware'),
28 |   () => import('@adonisjs/cors/cors_middleware'),
29 |   () => import('@adonisjs/vite/vite_middleware'),
30 |   () => import('@adonisjs/inertia/inertia_middleware'),
31 | ])
32 | 
33 | /**
34 |  * The router middleware stack runs middleware on all the HTTP
35 |  * requests with a registered route.
36 |  */
37 | router.use([
38 |   () => import('@adonisjs/core/bodyparser_middleware'),
39 |   () => import('@adonisjs/session/session_middleware'),
40 |   () => import('@adonisjs/shield/shield_middleware'),
41 | ])
42 | 
43 | /**
44 |  * Named middleware collection must be explicitly assigned to
45 |  * the routes or the routes group.
46 |  */
47 | export const middleware = router.named({})
48 | 
```

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

```typescript
 1 | export function getInvalidLocales(
 2 |   localeModels: Record<string, string>,
 3 |   sourceLocale: string,
 4 |   targetLocales: string[],
 5 | ) {
 6 |   return targetLocales.filter((targetLocale) => {
 7 |     const { provider, model } = getLocaleModel(
 8 |       localeModels,
 9 |       sourceLocale,
10 |       targetLocale,
11 |     );
12 | 
13 |     return provider === undefined || model === undefined;
14 |   });
15 | }
16 | 
17 | export function getLocaleModel(
18 |   localeModels: Record<string, string>,
19 |   sourceLocale: string,
20 |   targetLocale: string,
21 | ): { provider?: string; model?: string } {
22 |   const localeKeys = [
23 |     `${sourceLocale}:${targetLocale}`,
24 |     `*:${targetLocale}`,
25 |     `${sourceLocale}:*`,
26 |     "*:*",
27 |   ];
28 |   const modelKey = localeKeys.find((key) => localeModels.hasOwnProperty(key));
29 |   if (modelKey) {
30 |     const value = localeModels[modelKey];
31 |     // Split only on the first colon
32 |     const firstColonIndex = value?.indexOf(":");
33 | 
34 |     if (value && firstColonIndex !== -1 && firstColonIndex !== undefined) {
35 |       const provider = value.substring(0, firstColonIndex);
36 |       const model = value.substring(firstColonIndex + 1);
37 | 
38 |       if (provider && model) {
39 |         return { provider, model };
40 |       }
41 |     }
42 | 
43 |     // Fallback for strings without a colon or other issues
44 |     const [provider, model] = value?.split(":") || [];
45 |     if (provider && model) {
46 |       return { provider, model };
47 |     }
48 |   }
49 |   return { provider: undefined, model: undefined };
50 | }
51 | 
```

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

```typescript
 1 | "use client";
 2 | 
 3 | import { useEffect, useState } from "react";
 4 | import { getLocaleFromCookies, setLocaleInCookies } from "./utils";
 5 | 
 6 | /**
 7 |  * Gets the current locale used by the Lingo compiler.
 8 |  *
 9 |  * @returns The current locale code, or `null` if no locale is set.
10 |  */
11 | export function useLingoLocale(): string | null {
12 |   const [locale, setLocale] = useState<string | null>(null);
13 |   useEffect(() => {
14 |     setLocale(getLocaleFromCookies());
15 |   }, []);
16 |   return locale;
17 | }
18 | 
19 | /**
20 |  * Sets the current locale used by the Lingo compiler.
21 |  *
22 |  * **Note:** This function triggers a full page reload to ensure all components
23 |  * are re-rendered with the new locale. This is necessary because locale changes
24 |  * affect the entire application state.
25 |  *
26 |  * @param locale - The locale code to set. Must be a valid locale code (e.g., "en", "es", "fr-CA").
27 | 
28 |  *
29 |  * @example Set the current locale
30 |  * ```tsx
31 |  * import { setLingoLocale } from "lingo.dev/react/client";
32 |  *
33 |  * export function LanguageSwitcher() {
34 |  *   const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
35 |  *     setLingoLocale(event.target.value);
36 |  *   };
37 |  *
38 |  *   return (
39 |  *     <select onChange={handleChange}>
40 |  *       <option value="en">English</option>
41 |  *       <option value="es">Spanish</option>
42 |  *     </select>
43 |  *   );
44 |  * }
45 |  * ```
46 |  */
47 | export function setLingoLocale(locale: string) {
48 |   setLocaleInCookies(locale);
49 |   window.location.reload();
50 | }
51 | 
```

--------------------------------------------------------------------------------
/packages/compiler/src/i18n-directive.spec.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import i18nDirectiveMutation from "./i18n-directive";
 3 | import { createPayload, CompilerParams, defaultParams } from "./_base";
 4 | 
 5 | describe("i18nDirectiveMutation", () => {
 6 |   it("should return payload when 'use i18n' directive is present", () => {
 7 |     const input = `
 8 | "use i18n";
 9 | function Component() {
10 |   return <div>Hello</div>;
11 | }
12 | `.trim();
13 | 
14 |     const result = createPayload({
15 |       code: input,
16 |       params: defaultParams,
17 |       fileKey: "test",
18 |     });
19 |     const mutated = i18nDirectiveMutation(result);
20 | 
21 |     expect(mutated).not.toBeNull();
22 |     expect(mutated).toEqual(result);
23 |   });
24 | 
25 |   it("should return null when 'use i18n' directive is not present", () => {
26 |     const input = `
27 | function Component() {
28 |   return <div>Hello</div>;
29 | }
30 | `.trim();
31 | 
32 |     const result = createPayload({
33 |       code: input,
34 |       params: { ...defaultParams, useDirective: true },
35 |       fileKey: "test",
36 |     });
37 |     const mutated = i18nDirectiveMutation(result);
38 | 
39 |     expect(mutated).toBeNull();
40 |   });
41 | 
42 |   it("should handle multiple directives correctly", () => {
43 |     const input = `
44 | "use strict";
45 | "use i18n";
46 | function Component() {
47 |   return <div>Hello</div>;
48 | }
49 | `.trim();
50 | 
51 |     const result = createPayload({
52 |       code: input,
53 |       params: defaultParams,
54 |       fileKey: "test",
55 |     });
56 |     const mutated = i18nDirectiveMutation(result);
57 | 
58 |     expect(mutated).not.toBeNull();
59 |     expect(mutated).toEqual(result);
60 |   });
61 | });
62 | 
```

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

```typescript
 1 | import { Command } from "interactive-commander";
 2 | import chalk from "chalk";
 3 | import dedent from "dedent";
 4 | import _ from "lodash";
 5 | import {
 6 |   SETTINGS_KEYS,
 7 |   loadSystemSettings,
 8 |   saveSettings,
 9 | } from "../../utils/settings";
10 | 
11 | export default new Command()
12 |   .name("set")
13 |   .description("Set or update a CLI setting in ~/.lingodotdevrc")
14 |   .addHelpText("afterAll", `\nAvailable keys:\n  ${SETTINGS_KEYS.join("\n  ")}`)
15 |   .argument(
16 |     "<key>",
17 |     "Configuration key to set (dot notation, e.g., auth.apiKey)",
18 |   )
19 |   .argument("<value>", "The configuration value to set")
20 |   .helpOption("-h, --help", "Show help")
21 |   .action(async (key: string, value: string) => {
22 |     if (!SETTINGS_KEYS.includes(key)) {
23 |       console.error(
24 |         dedent`
25 |           ${chalk.red("✖")} Unknown configuration key: ${chalk.bold(key)}
26 |           Run ${chalk.dim("lingo.dev config set --help")} to see available keys.
27 |         `,
28 |       );
29 |       process.exitCode = 1;
30 |       return;
31 |     }
32 | 
33 |     const current = loadSystemSettings();
34 |     const updated: any = _.cloneDeep(current);
35 |     _.set(updated, key, value);
36 | 
37 |     try {
38 |       saveSettings(updated as any);
39 |       console.log(`${chalk.green("✔")} Set ${chalk.bold(key)}`);
40 |     } catch (err) {
41 |       console.error(
42 |         chalk.red(
43 |           `✖ Failed to save configuration: ${chalk.dim(
44 |             err instanceof Error ? err.message : String(err),
45 |           )}`,
46 |         ),
47 |       );
48 |       process.exitCode = 1;
49 |     }
50 |   });
51 | 
```

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

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import createMdxFrontmatterSplitLoader from "./frontmatter-split";
 3 | import matter from "gray-matter";
 4 | 
 5 | const sampleMdx = `---
 6 | title: Hello
 7 | published: true
 8 | tags:
 9 |   - foo
10 |   - bar
11 | ---
12 | 
13 | # Heading
14 | 
15 | This is some text.`;
16 | 
17 | // Helper to derive expected content string from the original sample – this mirrors what gray-matter returns
18 | const { content: originalContent } = matter(sampleMdx);
19 | 
20 | describe("mdx frontmatter split loader", () => {
21 |   it("should split frontmatter and content on pull", async () => {
22 |     const loader = createMdxFrontmatterSplitLoader();
23 |     loader.setDefaultLocale("en");
24 | 
25 |     const result = await loader.pull("en", sampleMdx);
26 | 
27 |     expect(result).toEqual({
28 |       frontmatter: {
29 |         title: "Hello",
30 |         published: true,
31 |         tags: ["foo", "bar"],
32 |       },
33 |       content: originalContent,
34 |     });
35 |   });
36 | 
37 |   it("should merge frontmatter and content on push", async () => {
38 |     const loader = createMdxFrontmatterSplitLoader();
39 |     loader.setDefaultLocale("en");
40 | 
41 |     const pulled = await loader.pull("en", sampleMdx);
42 |     // modify the data
43 |     pulled.frontmatter.title = "Hola";
44 |     pulled.content = pulled.content.replace("# Heading", "# Título");
45 | 
46 |     const output = await loader.push("es", pulled);
47 | 
48 |     const expectedOutput = `
49 | ---
50 | title: Hola
51 | published: true
52 | tags:
53 |   - foo
54 |   - bar
55 | ---
56 | 
57 | # Título
58 | 
59 | This is some text.
60 | `.trim();
61 | 
62 |     expect(output).toBe(expectedOutput);
63 |   });
64 | });
65 | 
```

--------------------------------------------------------------------------------
/packages/compiler/src/lib/lcp/schema.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from "zod";
 2 | 
 3 | // LCP
 4 | 
 5 | export const lcpScope = z.object({
 6 |   type: z.enum(["element", "attribute"]),
 7 |   content: z.string(),
 8 |   hash: z.string(),
 9 |   context: z.string().optional(),
10 |   skip: z.boolean().optional(),
11 |   overrides: z.record(z.string(), z.string()).optional(),
12 | });
13 | 
14 | export type LCPScope = z.infer<typeof lcpScope>;
15 | 
16 | export const lcpFile = z.object({
17 |   scopes: z.record(z.string(), lcpScope).optional(),
18 | });
19 | 
20 | export type LCPFile = z.infer<typeof lcpFile>;
21 | 
22 | export const lcpSchema = z.object({
23 |   version: z.number().default(0.1),
24 |   files: z.record(z.string(), lcpFile).optional(),
25 | });
26 | 
27 | export type LCPSchema = z.infer<typeof lcpSchema>;
28 | 
29 | // Dictionary
30 | 
31 | export const dictionaryFile = z.object({
32 |   entries: z.record(z.string(), z.string()),
33 | });
34 | 
35 | export type DictionaryFile = z.infer<typeof dictionaryFile>;
36 | 
37 | export const dictionarySchema = z.object({
38 |   version: z.number().default(0.1),
39 |   locale: z.string(),
40 |   files: z.record(z.string(), dictionaryFile),
41 | });
42 | 
43 | export type DictionarySchema = z.infer<typeof dictionarySchema>;
44 | 
45 | // Dictionary Cache
46 | 
47 | export const dictionaryCacheFile = z.object({
48 |   entries: z.record(
49 |     z.string(),
50 |     z.object({
51 |       content: z.record(z.string(), z.string()),
52 |       hash: z.string(),
53 |     }),
54 |   ),
55 | });
56 | 
57 | export const dictionaryCacheSchema = z.object({
58 |   version: z.number().default(0.1),
59 |   files: z.record(z.string(), dictionaryCacheFile),
60 | });
61 | 
62 | export type DictionaryCacheSchema = z.infer<typeof dictionaryCacheSchema>;
63 | 
```

--------------------------------------------------------------------------------
/packages/react/src/core/get-dictionary.spec.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect, vi } from "vitest";
 2 | import { getDictionary } from "./get-dictionary";
 3 | 
 4 | describe("get-dictionary", () => {
 5 |   const mockLoaderEn = vi.fn().mockResolvedValue(
 6 |     Promise.resolve({
 7 |       default: { hello: "Hello", goodbye: "Goodbye" },
 8 |       otherExport: "ignored",
 9 |     }),
10 |   );
11 |   const mockLoaderEs = vi.fn().mockResolvedValue(
12 |     Promise.resolve({
13 |       default: { hello: "Hola", goodbye: "Adiós" },
14 |     }),
15 |   );
16 |   const loaders = {
17 |     en: mockLoaderEn,
18 |     es: mockLoaderEs,
19 |   };
20 | 
21 |   beforeEach(() => {
22 |     vi.clearAllMocks();
23 |   });
24 | 
25 |   describe("getDictionary", () => {
26 |     it("should load dictionary for specific locale using correct async loader", async () => {
27 |       const result = await getDictionary("es", loaders);
28 |       expect(mockLoaderEs).toHaveBeenCalledTimes(1);
29 |       expect(result).toEqual({ hello: "Hola", goodbye: "Adiós" });
30 |     });
31 | 
32 |     it("should fallback to first available loader when specific locale not found", async () => {
33 |       const result = await getDictionary("fr", loaders);
34 | 
35 |       expect(mockLoaderEn).toHaveBeenCalledTimes(1);
36 |       expect(result).toEqual({ hello: "Hello", goodbye: "Goodbye" });
37 |     });
38 | 
39 |     it("should throw error when no loaders are provided", async () => {
40 |       expect(() => getDictionary("en", {})).toThrow(
41 |         "No available dictionary loaders found",
42 |       );
43 |       expect(() => getDictionary("en")).toThrow(
44 |         "No available dictionary loaders found",
45 |       );
46 |     });
47 |   });
48 | });
49 | 
```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/locales.spec.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import { getInvalidLocales, getLocaleModel } from "./locales";
 3 | 
 4 | describe("utils/locales", () => {
 5 |   describe("getLocaleModel", () => {
 6 |     const models = {
 7 |       "en:es": "groq:llama3",
 8 |       "en:*": "google:g2",
 9 |       "*:es": "mistral:m-small",
10 |       "*:*": "openrouter:gpt",
11 |     };
12 | 
13 |     it.each([
14 |       ["en", "es", { provider: "groq", model: "llama3" }],
15 |       ["en", "fr", { provider: "google", model: "g2" }],
16 |       ["de", "es", { provider: "mistral", model: "m-small" }],
17 |       ["de", "fr", { provider: "openrouter", model: "gpt" }],
18 |     ])("resolves locales", (sourceLocale, targetLocale, expected) => {
19 |       expect(getLocaleModel(models, sourceLocale, targetLocale)).toEqual(
20 |         expected,
21 |       );
22 |     });
23 | 
24 |     it("returns undefined for missing mapping", () => {
25 |       expect(getLocaleModel({ "en:es": "groq:llama3" }, "en", "fr")).toEqual({
26 |         provider: undefined,
27 |         model: undefined,
28 |       });
29 |     });
30 | 
31 |     it("returns undefined for invalid value", () => {
32 |       expect(getLocaleModel({ "en:fr": "invalidFormat" }, "en", "fr")).toEqual({
33 |         provider: undefined,
34 |         model: undefined,
35 |       });
36 |     });
37 |   });
38 | 
39 |   describe("getInvalidLocales", () => {
40 |     it("returns targets with unresolved models", () => {
41 |       const models = { "en:es": "groq:llama3", "*:fr": "google:g2" };
42 |       const invalid = getInvalidLocales(models, "en", ["es", "fr", "de"]);
43 |       expect(invalid).toEqual(["de"]);
44 |     });
45 |   });
46 | });
47 | 
```

--------------------------------------------------------------------------------
/demo/vite-project/public/vite.svg:
--------------------------------------------------------------------------------

```
1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
```

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

```typescript
 1 | import { createCodeMutation } from "./_base";
 2 | import { ModuleId } from "./_const";
 3 | import { getOrCreateImport } from "./utils";
 4 | import { findInvokations } from "./utils/invokations";
 5 | import * as t from "@babel/types";
 6 | import { getDictionaryPath } from "./_utils";
 7 | import { createLocaleImportMap } from "./utils/create-locale-import-map";
 8 | 
 9 | export const clientDictionaryLoaderMutation = createCodeMutation((payload) => {
10 |   const invokations = findInvokations(payload.ast, {
11 |     moduleName: ModuleId.ReactClient,
12 |     functionName: "loadDictionary",
13 |   });
14 | 
15 |   const allLocales = Array.from(
16 |     new Set([payload.params.sourceLocale, ...payload.params.targetLocales]),
17 |   );
18 | 
19 |   for (const invokation of invokations) {
20 |     const internalDictionaryLoader = getOrCreateImport(payload.ast, {
21 |       moduleName: ModuleId.ReactClient,
22 |       exportedName: "loadDictionary_internal",
23 |     });
24 | 
25 |     // Replace the function identifier with internal version
26 |     if (t.isIdentifier(invokation.callee)) {
27 |       invokation.callee.name = internalDictionaryLoader.importedName;
28 |     }
29 | 
30 |     const dictionaryPath = getDictionaryPath({
31 |       sourceRoot: payload.params.sourceRoot,
32 |       lingoDir: payload.params.lingoDir,
33 |       relativeFilePath: payload.relativeFilePath,
34 |     });
35 | 
36 |     // Create locale import map object
37 |     const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);
38 | 
39 |     // Add the locale import map as the second argument
40 |     invokation.arguments.push(localeImportMap);
41 |   }
42 | 
43 |   return payload;
44 | });
45 | 
```

--------------------------------------------------------------------------------
/packages/react/src/client/utils.ts:
--------------------------------------------------------------------------------

```typescript
 1 | "use client";
 2 | 
 3 | import { LOCALE_COOKIE_NAME } from "../core";
 4 | import Cookies from "js-cookie";
 5 | 
 6 | /**
 7 |  * Gets the current locale from the `"lingo-locale"` cookie.
 8 |  *
 9 |  * Defaults to `"en"` if:
10 |  *
11 |  * - Running in an environment that doesn't support cookies
12 |  * - No `"lingo-locale"` cookie is found
13 |  *
14 |  * @returns The current locale code, or `"en"` as a fallback.
15 |  *
16 |  * @example Get the current locale
17 |  * ```tsx
18 |  * import { getLocaleFromCookies } from "lingo.dev/react/client";
19 |  *
20 |  * export function App() {
21 |  *   const currentLocale = getLocaleFromCookies();
22 |  *   return <div>Current locale: {currentLocale}</div>;
23 |  * }
24 |  * ```
25 |  */
26 | export function getLocaleFromCookies(): string | null {
27 |   if (typeof document === "undefined") return null;
28 | 
29 |   return Cookies.get(LOCALE_COOKIE_NAME) ?? null;
30 | }
31 | 
32 | /**
33 |  * Sets the current locale in the `"lingo-locale"` cookie.
34 |  *
35 |  * Does nothing in environments that don't support cookies.
36 |  *
37 |  * @param locale - The locale code to store in the `"lingo-locale"` cookie.
38 |  *
39 |  * @example Set the current locale
40 |  * ```tsx
41 |  * import { setLocaleInCookies } from "lingo.dev/react/client";
42 |  *
43 |  * export function LanguageButton() {
44 |  *   const handleClick = () => {
45 |  *     setLocaleInCookies("es");
46 |  *     window.location.reload();
47 |  *   };
48 |  *
49 |  *   return <button onClick={handleClick}>Switch to Spanish</button>;
50 |  * }
51 |  * ```
52 |  */
53 | export function setLocaleInCookies(locale: string): void {
54 |   if (typeof document === "undefined") return;
55 | 
56 |   Cookies.set(LOCALE_COOKIE_NAME, locale, {
57 |     path: "/",
58 |     expires: 365,
59 |     sameSite: "lax",
60 |   });
61 | }
62 | 
```

--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: "Lingo.Dev AI Localization"
 2 | description: Automated AI localization for dev teams.
 3 | author: Lingo.dev
 4 | 
 5 | branding:
 6 |   icon: "aperture"
 7 |   color: "black"
 8 | 
 9 | runs:
10 |   using: "composite"
11 |   steps:
12 |     - name: Run
13 |       run: |
14 |         npx lingo.dev@${{ inputs.version }} ci \
15 |           --api-key "${{ inputs.api-key }}" \
16 |           --pull-request "${{ inputs.pull-request }}" \
17 |           --commit-message "${{ inputs.commit-message }}" \
18 |           --pull-request-title "${{ inputs.pull-request-title }}" \
19 |           --working-directory "${{ inputs.working-directory }}" \
20 |           --process-own-commits "${{ inputs.process-own-commits }}" \
21 |           --parallel ${{ inputs.parallel }}
22 |       shell: bash
23 | inputs:
24 |   version:
25 |     description: "Lingo.dev CLI version"
26 |     default: "latest"
27 |     required: false
28 |   api-key:
29 |     description: "Lingo.dev Platform API Key"
30 |     required: true
31 |   pull-request:
32 |     description: "Create a pull request with the changes"
33 |     default: false
34 |     required: false
35 |   commit-message:
36 |     description: "Commit message"
37 |     default: "feat: update translations via @LingoDotDev"
38 |     required: false
39 |   pull-request-title:
40 |     description: "Pull request title"
41 |     default: "feat: update translations via @LingoDotDev"
42 |     required: false
43 |   working-directory:
44 |     description: "Working directory"
45 |     default: "."
46 |     required: false
47 |   process-own-commits:
48 |     description: "Process commits made by this action"
49 |     default: false
50 |     required: false
51 |   parallel:
52 |     description: "Run in parallel mode"
53 |     default: false
54 |     required: false
55 | 
```

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

```typescript
 1 | import { describe, it, expect, vi, beforeEach } from "vitest";
 2 | import { getLocaleFromCookies, setLocaleInCookies } from "./utils";
 3 | 
 4 | vi.mock("js-cookie", () => {
 5 |   return {
 6 |     default: {
 7 |       get: vi.fn(),
 8 |       set: vi.fn(),
 9 |     },
10 |   };
11 | });
12 | 
13 | // access mocked module
14 | import Cookies from "js-cookie";
15 | 
16 | describe("client/utils", () => {
17 |   beforeEach(() => {
18 |     vi.clearAllMocks();
19 |   });
20 | 
21 |   describe("getLocaleFromCookies", () => {
22 |     it("returns null when document is undefined (SSR)", () => {
23 |       const original = globalThis.document;
24 |       // @ts-ignore
25 |       delete (globalThis as any).document;
26 |       expect(getLocaleFromCookies()).toBeNull();
27 |       (globalThis as any).document = original;
28 |     });
29 | 
30 |     it("returns cookie value when present", () => {
31 |       (Cookies.get as any).mockReturnValue("es");
32 |       (globalThis as any).document = {} as any;
33 |       expect(getLocaleFromCookies()).toBe("es");
34 |     });
35 |   });
36 | 
37 |   describe("setLocaleInCookies", () => {
38 |     it("is no-op when document is undefined", () => {
39 |       const original = globalThis.document;
40 |       // @ts-ignore
41 |       delete (globalThis as any).document;
42 |       setLocaleInCookies("fr");
43 |       expect(Cookies.set).not.toHaveBeenCalled();
44 |       (globalThis as any).document = original;
45 |     });
46 | 
47 |     it("writes cookie with expected options", () => {
48 |       (globalThis as any).document = {} as any;
49 |       setLocaleInCookies("en");
50 |       expect(Cookies.set).toHaveBeenCalledWith("lingo-locale", "en", {
51 |         path: "/",
52 |         expires: 365,
53 |         sameSite: "lax",
54 |       });
55 |     });
56 |   });
57 | });
58 | 
```

--------------------------------------------------------------------------------
/demo/adonisjs/app/exceptions/handler.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import app from '@adonisjs/core/services/app'
 2 | import { HttpContext, ExceptionHandler } from '@adonisjs/core/http'
 3 | import type { StatusPageRange, StatusPageRenderer } from '@adonisjs/core/types/http'
 4 | 
 5 | export default class HttpExceptionHandler extends ExceptionHandler {
 6 |   /**
 7 |    * In debug mode, the exception handler will display verbose errors
 8 |    * with pretty printed stack traces.
 9 |    */
10 |   protected debug = !app.inProduction
11 | 
12 |   /**
13 |    * Status pages are used to display a custom HTML pages for certain error
14 |    * codes. You might want to enable them in production only, but feel
15 |    * free to enable them in development as well.
16 |    */
17 |   protected renderStatusPages = app.inProduction
18 | 
19 |   /**
20 |    * Status pages is a collection of error code range and a callback
21 |    * to return the HTML contents to send as a response.
22 |    */
23 |   protected statusPages: Record<StatusPageRange, StatusPageRenderer> = {
24 |     '404': (error, { inertia }) => inertia.render('errors/not_found', { error }),
25 |     '500..599': (error, { inertia }) => inertia.render('errors/server_error', { error }),
26 |   }
27 | 
28 |   /**
29 |    * The method is used for handling errors and returning
30 |    * response to the client
31 |    */
32 |   async handle(error: unknown, ctx: HttpContext) {
33 |     return super.handle(error, ctx)
34 |   }
35 | 
36 |   /**
37 |    * The method is used to report error to the logging service or
38 |    * the a third party error monitoring service.
39 |    *
40 |    * @note You should not attempt to send a response from this method.
41 |    */
42 |   async report(error: unknown, ctx: HttpContext) {
43 |     return super.report(error, ctx)
44 |   }
45 | }
46 | 
```

--------------------------------------------------------------------------------
/packages/react/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@lingo.dev/_react",
 3 |   "version": "0.5.0",
 4 |   "description": "Lingo.dev React Kit",
 5 |   "private": false,
 6 |   "publishConfig": {
 7 |     "access": "public"
 8 |   },
 9 |   "sideEffects": false,
10 |   "type": "module",
11 |   "exports": {
12 |     ".": {
13 |       "types": "./build/core/index.d.ts",
14 |       "import": "./build/core/index.js"
15 |     },
16 |     "./client": {
17 |       "types": "./build/client/index.d.ts",
18 |       "import": "./build/client/index.js"
19 |     },
20 |     "./rsc": {
21 |       "types": "./build/rsc/index.d.ts",
22 |       "import": "./build/rsc/index.js"
23 |     },
24 |     "./react-router": {
25 |       "types": "./build/react-router/index.d.ts",
26 |       "import": "./build/react-router/index.js"
27 |     }
28 |   },
29 |   "files": [
30 |     "build"
31 |   ],
32 |   "scripts": {
33 |     "dev": "unbuild && chokidar 'src/**/*' -c 'unbuild'",
34 |     "build": "pnpm typecheck && unbuild",
35 |     "typecheck": "tsc --noEmit",
36 |     "clean": "rm -rf build",
37 |     "test": "vitest --run",
38 |     "test:watch": "vitest -w"
39 |   },
40 |   "keywords": [],
41 |   "author": "",
42 |   "license": "ISC",
43 |   "devDependencies": {
44 |     "@testing-library/react": "^16.3.0",
45 |     "@types/js-cookie": "^3.0.6",
46 |     "@types/lodash": "^4.17.4",
47 |     "@types/react": "^18.3.18",
48 |     "@types/react-dom": "^19.1.7",
49 |     "@vitejs/plugin-react": "^4.4.1",
50 |     "chokidar-cli": "^3.0.0",
51 |     "next": "15.2.4",
52 |     "react": "^19.0.0",
53 |     "react-dom": "^19.0.0",
54 |     "tsup": "^8.3.5",
55 |     "typescript": "^5.4.5",
56 |     "unbuild": "^3.5.0",
57 |     "vitest": "^3.1.1"
58 |   },
59 |   "peerDependencies": {
60 |     "next": "15.2.4"
61 |   },
62 |   "dependencies": {
63 |     "js-cookie": "^3.0.5",
64 |     "lodash": "^4.17.21"
65 |   }
66 | }
67 | 
```

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

```typescript
 1 | import YAML, { ToStringOptions } from "yaml";
 2 | import { ILoader } from "./_types";
 3 | import { createLoader } from "./_utils";
 4 | 
 5 | export default function createYamlLoader(): ILoader<
 6 |   string,
 7 |   Record<string, any>
 8 | > {
 9 |   return createLoader({
10 |     async pull(locale, input) {
11 |       return YAML.parse(input) || {};
12 |     },
13 |     async push(locale, payload, originalInput) {
14 |       return YAML.stringify(payload, {
15 |         lineWidth: -1,
16 |         defaultKeyType: getKeyType(originalInput),
17 |         defaultStringType: getStringType(originalInput),
18 |       });
19 |     },
20 |   });
21 | }
22 | 
23 | // check if the yaml keys are using double quotes or single quotes
24 | function getKeyType(
25 |   yamlString: string | null,
26 | ): ToStringOptions["defaultKeyType"] {
27 |   if (yamlString) {
28 |     const lines = yamlString.split("\n");
29 |     const hasDoubleQuotes = lines.find((line) => {
30 |       return line.trim().startsWith('"') && line.trim().match('":');
31 |     });
32 |     if (hasDoubleQuotes) {
33 |       return "QUOTE_DOUBLE";
34 |     }
35 |   }
36 |   return "PLAIN";
37 | }
38 | 
39 | // check if the yaml string values are using double quotes or single quotes
40 | function getStringType(
41 |   yamlString: string | null,
42 | ): ToStringOptions["defaultStringType"] {
43 |   if (yamlString) {
44 |     const lines = yamlString.split("\n");
45 |     const hasDoubleQuotes = lines.find((line) => {
46 |       const trimmedLine = line.trim();
47 |       return (
48 |         (trimmedLine.startsWith('"') || trimmedLine.match(/:\s*"/)) &&
49 |         (trimmedLine.endsWith('"') || trimmedLine.endsWith('",'))
50 |       );
51 |     });
52 |     if (hasDoubleQuotes) {
53 |       return "QUOTE_DOUBLE";
54 |     }
55 |   }
56 |   return "PLAIN";
57 | }
58 | 
```

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

```markdown
 1 | ---
 2 | title: "Restaurant Review: Bella Vista"
 3 | description: "Our dining experience at the new Italian restaurant downtown"
 4 | author: "not-localized-author"
 5 | published: "2024-03-15"
 6 | rating: 4.5
 7 | locked_key_1: "This value should remain unchanged in all locales"
 8 | ignored_key_1: "This field should not appear in target locales"
 9 | ---
10 | 
11 | # Dinner at Bella Vista
12 | 
13 | We finally tried the new Italian restaurant that opened last month on Main Street. Here's our honest review.
14 | 
15 | ## The Atmosphere
16 | 
17 | The restaurant has a warm, inviting atmosphere with:
18 | 
19 | - **Dim lighting** that creates an intimate setting
20 | - *Soft jazz music* playing in the background
21 | - Fresh flowers on every table
22 | 
23 | ### Making Reservations
24 | 
25 | [Book your table online](https://example.com) or call during business hours.
26 | 
27 | > Tip: Weekend reservations fill up quickly, so book ahead!
28 | 
29 | ## Menu Highlights
30 | 
31 | ```javascript
32 | // Restaurant website code - not localized
33 | function displayMenu(category) {
34 |   const items = "This code stays in original language";
35 |   return renderMenuItems(items);
36 | }
37 | ```
38 | 
39 | ```css
40 | /* Styling for menu display - not localized */
41 | .menu-item {
42 |   color: "This CSS remains unchanged";
43 | }
44 | ```
45 | 
46 | ## Our Order
47 | 
48 | We started with the antipasto platter and house salad.
49 | 
50 | The pasta was cooked perfectly - exactly `al_dente` as it should be.
51 | 
52 | ## Service Quality
53 | 
54 | The waitstaff was attentive but not overwhelming.
55 | 
56 | Our server checked on us regularly, maintaining `service.quality = "excellent"` throughout the evening.
57 | 
58 | ## Final Verdict
59 | 
60 | | Course | Rating |
61 | |--------|--------|
62 | | Appetizers | `stars(4)` |
63 | | Main dishes | `stars(5)` |
64 | 
```

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

```typescript
 1 | /**
 2 |  * Unescape a string value from .strings file format
 3 |  * Handles: \", \\, \n, \t, etc.
 4 |  */
 5 | export function unescapeString(raw: string): string {
 6 |   let result = "";
 7 |   let i = 0;
 8 | 
 9 |   while (i < raw.length) {
10 |     if (raw[i] === "\\" && i + 1 < raw.length) {
11 |       const nextChar = raw[i + 1];
12 |       switch (nextChar) {
13 |         case '"':
14 |           result += '"';
15 |           i += 2;
16 |           break;
17 |         case "\\":
18 |           result += "\\";
19 |           i += 2;
20 |           break;
21 |         case "n":
22 |           result += "\n";
23 |           i += 2;
24 |           break;
25 |         case "t":
26 |           result += "\t";
27 |           i += 2;
28 |           break;
29 |         case "r":
30 |           result += "\r";
31 |           i += 2;
32 |           break;
33 |         default:
34 |           // Unknown escape - keep as-is
35 |           result += raw[i];
36 |           i++;
37 |           break;
38 |       }
39 |     } else {
40 |       result += raw[i];
41 |       i++;
42 |     }
43 |   }
44 | 
45 |   return result;
46 | }
47 | 
48 | /**
49 |  * Escape a string value for .strings file format
50 |  * Escapes: \, ", newlines to \n
51 |  */
52 | export function escapeString(str: string): string {
53 |   if (str == null) {
54 |     return "";
55 |   }
56 | 
57 |   let result = "";
58 | 
59 |   for (let i = 0; i < str.length; i++) {
60 |     const char = str[i];
61 |     switch (char) {
62 |       case "\\":
63 |         result += "\\\\";
64 |         break;
65 |       case '"':
66 |         result += '\\"';
67 |         break;
68 |       case "\n":
69 |         result += "\\n";
70 |         break;
71 |       case "\r":
72 |         result += "\\r";
73 |         break;
74 |       case "\t":
75 |         result += "\\t";
76 |         break;
77 |       default:
78 |         result += char;
79 |         break;
80 |     }
81 |   }
82 | 
83 |   return result;
84 | }
85 | 
```

--------------------------------------------------------------------------------
/packages/cli/demo/android/es/example.xml:
--------------------------------------------------------------------------------

```
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <string name="app_name">MyApp</string>
 4 |     <string name="welcome_message">¡Hola, mundo!</string>
 5 |     <string name="button_text">Comenzar</string>
 6 | 
 7 |     <string-array name="color_names">
 8 |         <item>Rojo</item>
 9 |         <item>Verde</item>
10 |         <item>¡Azul!</item>
11 |     </string-array>
12 | 
13 |     <plurals name="notification_count">
14 |         <item quantity="one">%d mensaje nuevo</item>
15 |         <item quantity="other">%d mensajes nuevos</item>
16 |     </plurals>
17 | 
18 |     <bool name="show_tutorial">true</bool>
19 |     <bool name="enable_animations">false</bool>
20 | 
21 |     <integer name="max_retry_attempts">3</integer>
22 |     <integer name="default_timeout">30</integer>
23 | 
24 |     <string name="html_snippet">&lt;b&gt;Negrita&lt;/b&gt;</string>
25 | 
26 |     <string name="apostrophe_example">¡No olvides!</string>
27 | 
28 |     <string name="cdata_example"><![CDATA[Los usuarios solo pueden ver tu comentario después de registrarse. <u>Más información.</u>]]></string>
29 | 
30 |     <string-array name="mixed_items">
31 |         <item>  Elemento con espacios  </item>
32 |         <item>    </item>
33 |     </string-array>
34 | 
35 |     <color name="primary_color">#FF6200EE</color>
36 |     <color name="secondary_color">#FF03DAC5</color>
37 | 
38 |     <dimen name="text_size">16sp</dimen>
39 |     <dimen name="margin">8dp</dimen>
40 | 
41 |     <integer-array name="numbers">
42 |         <item>1</item>
43 |         <item>2</item>
44 |         <item>3</item>
45 |     </integer-array>
46 | 
47 |     <array name="icons">
48 |         <item>@drawable/icon1</item>
49 |         <item>@drawable/icon2</item>
50 |     </array>
51 | 
52 |     <item type="id" name="button_ok"></item>
53 | 
54 | </resources>
```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/module-params.spec.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import { parseParametrizedModuleId } from "./module-params";
 3 | import _ from "lodash";
 4 | 
 5 | describe("parseParametrizedModuleId", () => {
 6 |   it("should extract the module id without parameters", () => {
 7 |     const result = parseParametrizedModuleId("test-module");
 8 | 
 9 |     expect(result).toEqual({
10 |       id: "test-module",
11 |       params: {},
12 |     });
13 |   });
14 | 
15 |   it("should extract the module id with a single parameter", () => {
16 |     const result = parseParametrizedModuleId("test-module?key=value");
17 | 
18 |     expect(result).toEqual({
19 |       id: "test-module",
20 |       params: { key: "value" },
21 |     });
22 |   });
23 | 
24 |   it("should extract the module id with multiple parameters", () => {
25 |     const result = parseParametrizedModuleId(
26 |       "test-module?key1=value1&key2=value2&key3=value3",
27 |     );
28 | 
29 |     expect(result).toEqual({
30 |       id: "test-module",
31 |       params: {
32 |         key1: "value1",
33 |         key2: "value2",
34 |         key3: "value3",
35 |       },
36 |     });
37 |   });
38 | 
39 |   it("should handle parameters with special characters", () => {
40 |     const result = parseParametrizedModuleId(
41 |       "test-module?key=value%20with%20spaces&special=%21%40%23",
42 |     );
43 | 
44 |     expect(result).toEqual({
45 |       id: "test-module",
46 |       params: {
47 |         key: "value with spaces",
48 |         special: "!@#",
49 |       },
50 |     });
51 |   });
52 | 
53 |   it("should handle module ids with path-like structure", () => {
54 |     const result = parseParametrizedModuleId(
55 |       "parent/child/module?version=1.0.0",
56 |     );
57 | 
58 |     expect(result).toEqual({
59 |       id: "parent/child/module",
60 |       params: { version: "1.0.0" },
61 |     });
62 |   });
63 | });
64 | 
```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/run/_types.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {
 2 |   bucketTypeSchema,
 3 |   I18nConfig,
 4 |   localeCodeSchema,
 5 |   bucketTypes,
 6 | } from "@lingo.dev/_spec";
 7 | import { z } from "zod";
 8 | import { ILocalizer } from "../../localizer/_types";
 9 | 
10 | export type CmdRunContext = {
11 |   flags: CmdRunFlags;
12 |   config: I18nConfig | null;
13 |   localizer: ILocalizer | null;
14 |   tasks: CmdRunTask[];
15 |   results: Map<CmdRunTask, CmdRunTaskResult>;
16 | };
17 | 
18 | export type CmdRunTaskResult = {
19 |   status: "success" | "error" | "skipped";
20 |   error?: Error;
21 |   pathPattern?: string;
22 |   sourceLocale?: string;
23 |   targetLocale?: string;
24 | };
25 | 
26 | export type CmdRunTask = {
27 |   sourceLocale: string;
28 |   targetLocale: string;
29 |   bucketType: (typeof bucketTypes)[number];
30 |   bucketPathPattern: string;
31 |   injectLocale: string[];
32 |   lockedKeys: string[];
33 |   lockedPatterns: string[];
34 |   ignoredKeys: string[];
35 |   onlyKeys: string[];
36 |   formatter?: "prettier" | "biome";
37 | };
38 | 
39 | export const flagsSchema = z.object({
40 |   bucket: z.array(bucketTypeSchema).optional(),
41 |   key: z.array(z.string()).optional(),
42 |   file: z.array(z.string()).optional(),
43 |   apiKey: z.string().optional(),
44 |   force: z.boolean().optional(),
45 |   frozen: z.boolean().optional(),
46 |   verbose: z.boolean().optional(),
47 |   strict: z.boolean().optional(),
48 |   interactive: z.boolean().default(false),
49 |   concurrency: z.number().positive().default(10),
50 |   debug: z.boolean().default(false),
51 |   sourceLocale: z.string().optional(),
52 |   targetLocale: z.array(z.string()).optional(),
53 |   watch: z.boolean().default(false),
54 |   debounce: z.number().positive().default(5000), // 5 seconds default
55 |   sound: z.boolean().optional(),
56 | });
57 | export type CmdRunFlags = z.infer<typeof flagsSchema>;
58 | 
```

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

```typescript
 1 | import { getJsxAttributeValue } from "./utils";
 2 | import { LCP } from "./lib/lcp";
 3 | import { getJsxAttributeValueHash } from "./utils/hash";
 4 | import { collectJsxAttributeScopes } from "./utils/jsx-attribute-scope";
 5 | import { CompilerPayload } from "./_base";
 6 | import _ from "lodash";
 7 | 
 8 | // Processes only JSX attribute scopes
 9 | export function jsxAttributeScopesExportMutation(
10 |   payload: CompilerPayload,
11 | ): CompilerPayload {
12 |   const attributeScopes = collectJsxAttributeScopes(payload.ast);
13 |   if (_.isEmpty(attributeScopes)) {
14 |     return payload;
15 |   }
16 | 
17 |   const lcp = LCP.getInstance({
18 |     sourceRoot: payload.params.sourceRoot,
19 |     lingoDir: payload.params.lingoDir,
20 |   });
21 | 
22 |   for (const [scope, attributes] of attributeScopes) {
23 |     for (const attributeDefinition of attributes) {
24 |       const [attribute, scopeKey] = attributeDefinition.split(":");
25 | 
26 |       lcp.resetScope(payload.relativeFilePath, scopeKey);
27 | 
28 |       const attributeValue = getJsxAttributeValue(scope, attribute);
29 |       if (!attributeValue) {
30 |         continue;
31 |       }
32 | 
33 |       lcp.setScopeType(payload.relativeFilePath, scopeKey, "attribute");
34 | 
35 |       const hash = getJsxAttributeValueHash(String(attributeValue));
36 |       lcp.setScopeHash(payload.relativeFilePath, scopeKey, hash);
37 | 
38 |       lcp.setScopeContext(payload.relativeFilePath, scopeKey, "");
39 |       lcp.setScopeSkip(payload.relativeFilePath, scopeKey, false);
40 |       lcp.setScopeOverrides(payload.relativeFilePath, scopeKey, {});
41 | 
42 |       lcp.setScopeContent(
43 |         payload.relativeFilePath,
44 |         scopeKey,
45 |         String(attributeValue),
46 |       );
47 |     }
48 |   }
49 | 
50 |   lcp.save();
51 | 
52 |   return payload;
53 | }
54 | 
```

--------------------------------------------------------------------------------
/demo/vite-project/src/App.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import { useState } from "react";
 2 | import reactLogo from "./assets/react.svg";
 3 | import viteLogo from "/vite.svg";
 4 | import { LingoDotDev } from "./lingo-dot-dev";
 5 | import "./App.css";
 6 | import { TestComponent } from "./components/test";
 7 | 
 8 | import { LocaleSwitcher } from "lingo.dev/react/client";
 9 | 
10 | function App() {
11 |   const [count, setCount] = useState(0);
12 | 
13 |   return (
14 |     <>
15 |       <div className="logo-container">
16 |         <a href="https://vite.dev" target="_blank">
17 |           <img src={viteLogo} className="logo" alt="Vite logo" />
18 |         </a>
19 |         <a href="https://react.dev" target="_blank">
20 |           <img src={reactLogo} className="logo react" alt="React logo" />
21 |         </a>
22 |         <a href="https://lingo.dev" target="_blank">
23 |           <LingoDotDev />
24 |         </a>
25 |       </div>
26 |       <h1>Lingo.dev loves Vite and React</h1>
27 |       <p className="welcome-text">
28 |         Welcome to your new Vite &amp; React application! This starter template
29 |         includes everything you need to get started with Vite &amp; React and
30 |         Lingo.dev for internationalization.
31 |       </p>
32 |       <div className="card">
33 |         <button onClick={() => setCount((count) => count + 1)}>
34 |           count is {count}
35 |         </button>
36 |         <p>
37 |           Edit <code>src/App.tsx</code> and save to test HMR
38 |         </p>
39 |       </div>
40 |       <p className="read-the-docs">Click on the logos above to learn more</p>
41 |       <TestComponent />
42 |       <div className="locale-switcher">
43 |         <LocaleSwitcher
44 |           locales={["en", "es", "fr", "ru", "de", "ja", "zh", "ar", "ko"]}
45 |         />
46 |       </div>
47 |     </>
48 |   );
49 | }
50 | 
51 | export default App;
52 | 
```

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

```html
 1 | <!DOCTYPE html>
 2 | <html lang="en">
 3 |   <head>
 4 |     <title>MyApp - Hello World</title>
 5 | 
 6 |     <meta name="description" content="A simple demo app" />
 7 |     <meta property="og:title" content="MyApp Demo" />
 8 | 
 9 |     <meta name="viewport" content="width=device-width, initial-scale=1" />
10 |     <meta charset="UTF-8" />
11 | 
12 |     <style>
13 |       body {
14 |         font-family: Arial, sans-serif;
15 |         color: #333;
16 |       }
17 |       .highlight::before {
18 |         content: "★ Featured";
19 |       }
20 |     </style>
21 | 
22 |     <script>
23 |       const message = "User session initialized";
24 |       console.log(message);
25 |     </script>
26 |   </head>
27 |   <body>
28 |     <h1>Welcome to MyApp</h1>
29 | 
30 |     <p>
31 |       Hello, world! This is a simple demo with
32 |       <strong>bold text</strong> and
33 |       <em>italic text</em>.
34 |     </p>
35 | 
36 |     <div>
37 |       <div>
38 |         <span>Nested content here</span>
39 |       </div>
40 |     </div>
41 | 
42 |     <img src="example.jpg" alt="Example image" />
43 | 
44 |     <img
45 |       src="example.jpg"
46 |       alt="Demo image"
47 |       title="View product details"
48 |     />
49 | 
50 |     <input type="text" placeholder="Enter text here" />
51 | 
52 |     <input
53 |       type="text"
54 |       placeholder="Enter value"
55 |       value="Default search query"
56 |     />
57 | 
58 |     <a href="#" title="Click for more">Learn more</a>
59 | 
60 |     <a
61 |       href="not-localized.html"
62 |       data-info="Navigation link"
63 |       title="Navigate"
64 |     >
65 |       Go to page
66 |     </a>
67 | 
68 |     <div class="content-area" data-value="Main content">
69 |       Content area
70 |     </div>
71 | 
72 |     <script>
73 |       const inlineScript = "Page analytics loaded";
74 |     </script>
75 | 
76 |     <style>
77 |       .inline-style {
78 |         content: "Notice: ";
79 |       }
80 |     </style>
81 |   </body>
82 | </html>
```

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

```typescript
 1 | import prompt from "./prompt";
 2 | import { describe, it, expect, vi } from "vitest";
 3 | 
 4 | const baseArgs = {
 5 |   sourceLocale: "en",
 6 |   targetLocale: "es",
 7 | };
 8 | 
 9 | describe("prompt", () => {
10 |   it("returns user-defined prompt with replacements", () => {
11 |     const args = {
12 |       ...baseArgs,
13 |       prompt: "Translate from {SOURCE_LOCALE} to {TARGET_LOCALE}.",
14 |     };
15 |     const result = prompt(args);
16 |     expect(result).toBe("Translate from en to es.");
17 |   });
18 | 
19 |   it("trims and replaces variables in user prompt", () => {
20 |     const args = {
21 |       ...baseArgs,
22 |       prompt: "  {SOURCE_LOCALE} => {TARGET_LOCALE}  ",
23 |     };
24 |     const result = prompt(args);
25 |     expect(result).toBe("en => es");
26 |   });
27 | 
28 |   it("falls back to built-in prompt if no user prompt", () => {
29 |     const args = { ...baseArgs };
30 |     const result = prompt(args);
31 |     expect(result).toContain("You are an advanced AI localization engine");
32 |     expect(result).toContain("Source language (locale code): en");
33 |     expect(result).toContain("Target language (locale code): es");
34 |   });
35 | 
36 |   it("logs when using user-defined prompt", () => {
37 |     const spy = vi.spyOn(console, "log");
38 |     const args = {
39 |       ...baseArgs,
40 |       prompt: "Prompt {SOURCE_LOCALE} {TARGET_LOCALE}",
41 |     };
42 |     prompt(args);
43 |     expect(spy).toHaveBeenCalledWith(
44 |       "✨ Compiler is using user-defined prompt.",
45 |     );
46 |     spy.mockRestore();
47 |   });
48 | 
49 |   it("returns built-in prompt if user prompt is empty or whitespace", () => {
50 |     const args = {
51 |       ...baseArgs,
52 |       prompt: "   ",
53 |     };
54 |     const result = prompt(args);
55 |     expect(result).toContain("You are an advanced AI localization engine");
56 |   });
57 | });
58 | 
```

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

```typescript
 1 | import { describe, it, expect, vi, beforeEach } from "vitest";
 2 | import { createPayload, defaultParams } from "./_base";
 3 | import { jsxScopesExportMutation } from "./jsx-scopes-export";
 4 | 
 5 | vi.mock("./lib/lcp", () => {
 6 |   const instance = {
 7 |     resetScope: vi.fn().mockReturnThis(),
 8 |     setScopeType: vi.fn().mockReturnThis(),
 9 |     setScopeHash: vi.fn().mockReturnThis(),
10 |     setScopeContext: vi.fn().mockReturnThis(),
11 |     setScopeSkip: vi.fn().mockReturnThis(),
12 |     setScopeOverrides: vi.fn().mockReturnThis(),
13 |     setScopeContent: vi.fn().mockReturnThis(),
14 |     save: vi.fn(),
15 |   };
16 |   const getInstance = vi.fn(() => instance);
17 |   return {
18 |     LCP: {
19 |       getInstance,
20 |     },
21 |     __test__: { instance, getInstance },
22 |   };
23 | });
24 | 
25 | describe("jsxScopesExportMutation", () => {
26 |   beforeEach(() => {
27 |     vi.clearAllMocks();
28 |   });
29 | 
30 |   it("exports element scope with hash/content/flags", async () => {
31 |     const code = `
32 | export default function X(){
33 |   return <div data-jsx-scope="scope-1">Foobar</div>
34 | }`.trim();
35 |     const input = createPayload({
36 |       code,
37 |       params: defaultParams,
38 |       relativeFilePath: "src/App.tsx",
39 |     } as any);
40 |     jsxScopesExportMutation(input);
41 |     const lcpMod: any = await import("./lib/lcp");
42 |     const inst = lcpMod.__test__.instance;
43 |     expect(lcpMod.LCP.getInstance).toHaveBeenCalled();
44 |     expect(inst.setScopeType).toHaveBeenCalledWith(
45 |       "src/App.tsx",
46 |       "0/declaration/body/0/argument",
47 |       "element",
48 |     );
49 |     expect(inst.setScopeContent).toHaveBeenCalledWith(
50 |       "src/App.tsx",
51 |       "0/declaration/body/0/argument",
52 |       "Foobar",
53 |     );
54 |     expect(inst.save).toHaveBeenCalled();
55 |   });
56 | });
57 | 
```

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

```typescript
 1 | import { NodePath } from "@babel/traverse";
 2 | import * as t from "@babel/types";
 3 | import { Expression } from "@babel/types";
 4 | 
 5 | export const getJsxVariables = (nodePath: NodePath<t.JSXElement>) => {
 6 |   /*
 7 |     example input:
 8 | 
 9 |     <div>You have {count} new messages.</div>
10 | 
11 |     example output:
12 | 
13 |     t.objectExpression([
14 |       t.objectProperty(t.identifier("count"), t.identifier("count")),
15 |     ])
16 |   */
17 | 
18 |   const variables = new Set<string>();
19 | 
20 |   nodePath.traverse({
21 |     JSXOpeningElement(path) {
22 |       path.skip();
23 |     },
24 |     JSXExpressionContainer(path) {
25 |       if (t.isIdentifier(path.node.expression)) {
26 |         variables.add(path.node.expression.name);
27 |       } else if (t.isMemberExpression(path.node.expression)) {
28 |         // Handle nested expressions like object.property.value
29 |         let current: Expression = path.node.expression;
30 |         const parts: string[] = [];
31 | 
32 |         while (t.isMemberExpression(current)) {
33 |           if (t.isIdentifier(current.property)) {
34 |             if (current.computed) {
35 |               parts.unshift(`[${current.property.name}]`);
36 |             } else {
37 |               parts.unshift(current.property.name);
38 |             }
39 |           }
40 |           current = current.object;
41 |         }
42 | 
43 |         if (t.isIdentifier(current)) {
44 |           parts.unshift(current.name);
45 |           variables.add(parts.join(".").replaceAll(".[", "["));
46 |         }
47 |       }
48 |       // Skip traversing inside the expression
49 |       path.skip();
50 |     },
51 |   });
52 | 
53 |   const properties = Array.from(variables).map((name) =>
54 |     t.objectProperty(t.stringLiteral(name), t.identifier(name)),
55 |   );
56 | 
57 |   const result = t.objectExpression(properties);
58 |   return result;
59 | };
60 | 
```

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

```typescript
 1 | import { Command } from "interactive-commander";
 2 | import Ora from "ora";
 3 | import { getSettings, saveSettings } from "../utils/settings";
 4 | import { createAuthenticator } from "../utils/auth";
 5 | 
 6 | export default new Command()
 7 |   .command("auth")
 8 |   .description("Show current authentication status and user email")
 9 |   .helpOption("-h, --help", "Show help")
10 |   // Deprecated options, safe to remove after September 2025
11 |   .option(
12 |     "--login",
13 |     "DEPRECATED: Shows deprecation warning and exits. Use `lingo.dev login` instead",
14 |   )
15 |   .option(
16 |     "--logout",
17 |     "DEPRECATED: Shows deprecation warning and exits. Use `lingo.dev logout` instead",
18 |   )
19 |   .action(async (options) => {
20 |     try {
21 |       // Handle deprecated login option
22 |       if (options.login) {
23 |         Ora().warn(
24 |           "⚠️  DEPRECATED: '--login' is deprecated. Please use 'lingo.dev login' instead.",
25 |         );
26 |         process.exit(1);
27 |       }
28 | 
29 |       // Handle deprecated logout option
30 |       if (options.logout) {
31 |         Ora().warn(
32 |           "⚠️  DEPRECATED: '--logout' is deprecated. Please use 'lingo.dev logout' instead.",
33 |         );
34 |         process.exit(1);
35 |       }
36 | 
37 |       // Default behavior: show authentication status
38 |       const settings = await getSettings(undefined);
39 |       const authenticator = createAuthenticator({
40 |         apiUrl: settings.auth.apiUrl,
41 |         apiKey: settings.auth.apiKey!,
42 |       });
43 |       const auth = await authenticator.whoami();
44 |       if (!auth) {
45 |         Ora().warn("Not authenticated");
46 |       } else {
47 |         Ora().succeed(`Authenticated as ${auth.email}`);
48 |       }
49 |     } catch (error: any) {
50 |       Ora().fail(error.message);
51 |       process.exit(1);
52 |     }
53 |   });
54 | 
```

--------------------------------------------------------------------------------
/packages/react/src/core/get-dictionary.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Loads a dictionary for the specified locale.
 3 |  *
 4 |  * This function attempts to load a dictionary using the provided loaders. If the specified
 5 |  * locale is not available, it falls back to the first available loader. The function
 6 |  * expects the loader to return a promise that resolves to an object with a `default` property
 7 |  * containing the dictionary data (the default export from dictionary file).
 8 |  *
 9 |  * @param locale - The locale to load the dictionary for. Can be null to use the first available loader.
10 |  * @param loaders - A record of locale keys to loader functions. Each loader should return a Promise
11 |  *                  that resolves to an object with a `default` property containing the dictionary.
12 |  * @returns A Promise that resolves to the dictionary data (the `default` export from the loader).
13 |  * @throws {Error} When no loaders are provided or available.
14 |  *
15 |  * @example
16 |  * ```typescript
17 |  * const loaders = {
18 |  *   'en': () => import('./en.json'),
19 |  *   'es': () => import('./es.json')
20 |  * };
21 |  *
22 |  * const dictionary = await loadDictionary('en', loaders);
23 |  * // Returns the default export from the English dictionary
24 |  * ```
25 |  */
26 | export function getDictionary(
27 |   locale: string | null,
28 |   loaders: Record<string, () => Promise<any>> = {},
29 | ) {
30 |   const loader = getDictionaryLoader(locale, loaders);
31 |   if (!loader) {
32 |     throw new Error("No available dictionary loaders found");
33 |   }
34 |   return loader().then((value) => value.default);
35 | }
36 | 
37 | function getDictionaryLoader(
38 |   locale: string | null,
39 |   loaders: Record<string, () => Promise<any>> = {},
40 | ) {
41 |   if (locale && loaders[locale]) {
42 |     return loaders[locale];
43 |   }
44 |   return Object.values(loaders)[0];
45 | }
46 | 
```

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

```html
 1 | <!DOCTYPE html>
 2 | <html lang="es">
 3 |   <head>
 4 |     <title>MyApp - Hola Mundo</title>
 5 | 
 6 |     <meta name="description" content="Una aplicación de demostración simple" />
 7 |     <meta property="og:title" content="Demostración de MyApp" />
 8 | 
 9 |     <meta name="viewport" content="width=device-width, initial-scale=1" />
10 |     <meta charset="UTF-8" />
11 | 
12 |     <style>
13 |       body {
14 |         font-family: Arial, sans-serif;
15 |         color: #333;
16 |       }
17 |       .highlight::before {
18 |         content: "★ Featured";
19 |       }
20 |     </style>
21 | 
22 |     <script>
23 |       const message = "User session initialized";
24 |       console.log(message);
25 |     </script>
26 |   </head>
27 |   <body>
28 |     <h1>Bienvenido a MyApp</h1>
29 | 
30 |     <p>
31 |       ¡Hola, mundo! Esta es una demostración simple con
32 |       <strong>texto en negrita</strong>
33 |       y
34 |       <em>texto en cursiva</em>
35 |       .
36 |     </p>
37 | 
38 |     <div>
39 |       <div>
40 |         <span>Contenido anidado aquí</span>
41 |       </div>
42 |     </div>
43 | 
44 |     <img src="example.jpg" alt="Imagen de ejemplo" />
45 | 
46 |     <img
47 |       src="example.jpg"
48 |       alt="Imagen de demostración"
49 |       title="View product details"
50 |     />
51 | 
52 |     <input type="text" placeholder="Ingresa texto aquí" />
53 | 
54 |     <input
55 |       type="text"
56 |       placeholder="Ingresa valor"
57 |       value="Default search query"
58 |     />
59 | 
60 |     <a href="#" title="Haz clic para más">Saber más</a>
61 | 
62 |     <a href="not-localized.html" data-info="Navigation link" title="Navegar">
63 |       Ir a la página
64 |     </a>
65 | 
66 |     <div class="content-area" data-value="Main content">Área de contenido</div>
67 | 
68 |     <script>
69 |       const inlineScript = "Page analytics loaded";
70 |     </script>
71 | 
72 |     <style>
73 |       .inline-style {
74 |         content: "Notice: ";
75 |       }
76 |     </style>
77 |   </body>
78 | </html>
```

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

```markdown
 1 | ---
 2 | title: "Reseña de restaurante: Bella Vista"
 3 | description: Nuestra experiencia gastronómica en el nuevo restaurante italiano del centro
 4 | author: not-localized-author
 5 | published: 2024-03-15
 6 | rating: 4.5
 7 | locked_key_1: This value should remain unchanged in all locales
 8 | ---
 9 | 
10 | # Cena en Bella Vista
11 | 
12 | Finalmente probamos el nuevo restaurante italiano que abrió el mes pasado en la calle Principal. Aquí está nuestra reseña honesta.
13 | 
14 | ## El ambiente
15 | 
16 | El restaurante tiene un ambiente cálido y acogedor con:
17 | 
18 | - **Iluminación tenue** que crea un entorno íntimo
19 | - _Música suave de jazz_ sonando de fondo
20 | - Flores frescas en cada mesa
21 | 
22 | ### Cómo hacer reservas
23 | 
24 | [Reserva tu mesa en línea](https://example.com) o llama durante el horario comercial.
25 | 
26 | > Consejo: Las reservas de fin de semana se agotan rápidamente, ¡así que reserva con anticipación!
27 | 
28 | ## Destacados del menú
29 | 
30 | ```javascript
31 | // Restaurant website code - not localized
32 | function displayMenu(category) {
33 |   const items = "This code stays in original language";
34 |   return renderMenuItems(items);
35 | }
36 | ```
37 | 
38 | ```css
39 | /* Styling for menu display - not localized */
40 | .menu-item {
41 |   color: "This CSS remains unchanged";
42 | }
43 | ```
44 | 
45 | ## Nuestro pedido
46 | 
47 | Comenzamos con la tabla de antipasto y la ensalada de la casa.
48 | 
49 | La pasta estaba cocinada perfectamente - exactamente `al_dente` como debe ser.
50 | 
51 | ## Calidad del servicio
52 | 
53 | El personal de servicio estuvo atento pero no abrumador.
54 | 
55 | Nuestro camarero nos atendió regularmente, manteniendo `service.quality = "excellent"` durante toda la noche.
56 | 
57 | ## Veredicto final
58 | 
59 | | Plato              | Calificación |
60 | | ------------------ | ------------ |
61 | | Entrantes          | `stars(4)`   |
62 | | Platos principales | `stars(5)`   |
63 | 
```

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

```typescript
 1 | import path from "path";
 2 | import { createCodeMutation } from "./_base";
 3 | import { LCP_DICTIONARY_FILE_NAME, ModuleId } from "./_const";
 4 | import { getModuleExecutionMode, getOrCreateImport } from "./utils";
 5 | import { findInvokations } from "./utils/invokations";
 6 | import * as t from "@babel/types";
 7 | import { getDictionaryPath } from "./_utils";
 8 | import { createLocaleImportMap } from "./utils/create-locale-import-map";
 9 | 
10 | export const rscDictionaryLoaderMutation = createCodeMutation((payload) => {
11 |   const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
12 |   if (mode === "client") {
13 |     return payload;
14 |   }
15 | 
16 |   const invokations = findInvokations(payload.ast, {
17 |     moduleName: ModuleId.ReactRSC,
18 |     functionName: "loadDictionary",
19 |   });
20 | 
21 |   const allLocales = Array.from(
22 |     new Set([payload.params.sourceLocale, ...payload.params.targetLocales]),
23 |   );
24 | 
25 |   for (const invokation of invokations) {
26 |     const internalDictionaryLoader = getOrCreateImport(payload.ast, {
27 |       moduleName: ModuleId.ReactRSC,
28 |       exportedName: "loadDictionary_internal",
29 |     });
30 | 
31 |     // Replace the function identifier with internal version
32 |     if (t.isIdentifier(invokation.callee)) {
33 |       invokation.callee.name = internalDictionaryLoader.importedName;
34 |     }
35 | 
36 |     const dictionaryPath = getDictionaryPath({
37 |       sourceRoot: payload.params.sourceRoot,
38 |       lingoDir: payload.params.lingoDir,
39 |       relativeFilePath: payload.relativeFilePath,
40 |     });
41 | 
42 |     // Create locale import map object
43 |     const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);
44 | 
45 |     // Add the locale import map as the second argument
46 |     invokation.arguments.push(localeImportMap);
47 |   }
48 | 
49 |   return payload;
50 | });
51 | 
```

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

```typescript
 1 | import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
 2 | import * as dotenv from "dotenv";
 3 | import * as path from "path";
 4 | import { getKeyFromEnv } from "./llm-api-key";
 5 | 
 6 | const ORIGINAL_ENV = { ...process.env };
 7 | 
 8 | vi.mock("dotenv");
 9 | 
10 | describe("LLM API keys", () => {
11 |   describe("getKeyFromEnv", () => {
12 |     beforeEach(() => {
13 |       vi.resetModules();
14 |       process.env = { ...ORIGINAL_ENV };
15 |     });
16 | 
17 |     afterEach(() => {
18 |       process.env = { ...ORIGINAL_ENV };
19 |       vi.restoreAllMocks();
20 |     });
21 | 
22 |     it("returns API key from process.env if set", () => {
23 |       process.env.FOOBAR_API_KEY = "env-key";
24 |       expect(getKeyFromEnv("FOOBAR_API_KEY")).toBe("env-key");
25 |     });
26 | 
27 |     it("returns API key from .env file if not in process.env", () => {
28 |       delete process.env.FOOBAR_API_KEY;
29 |       const fakeEnv = { FOOBAR_API_KEY: "file-key" };
30 |       const configMock = vi
31 |         .mocked(dotenv.config)
32 |         .mockImplementation((opts: any) => {
33 |           if (opts && opts.processEnv) {
34 |             Object.assign(opts.processEnv, fakeEnv);
35 |           }
36 |           return { parsed: fakeEnv };
37 |         });
38 |       expect(getKeyFromEnv("FOOBAR_API_KEY")).toBe("file-key");
39 |       expect(configMock).toHaveBeenCalledWith({
40 |         path: [
41 |           path.resolve(process.cwd(), ".env"),
42 |           path.resolve(process.cwd(), ".env.local"),
43 |           path.resolve(process.cwd(), ".env.development"),
44 |         ],
45 |       });
46 |     });
47 | 
48 |     it("returns undefined if no GROQ_API_KEY in env or .env file", () => {
49 |       delete process.env.GROQ_API_KEY;
50 |       vi.mocked(dotenv.config).mockResolvedValue({ parsed: {} });
51 |       expect(getKeyFromEnv("FOOBAR_API_KEY")).toBeUndefined();
52 |     });
53 |   });
54 | });
55 | 
```

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

```typescript
 1 | import { machineId } from "node-machine-id";
 2 | import { getRc } from "./rc";
 3 | 
 4 | export default async function trackEvent(
 5 |   event: string,
 6 |   properties?: Record<string, any>,
 7 | ) {
 8 |   if (process.env.DO_NOT_TRACK) {
 9 |     return;
10 |   }
11 | 
12 |   try {
13 |     const actualId = await getActualId();
14 | 
15 |     const { PostHog } = await import("posthog-node");
16 |     const posthog = new PostHog(
17 |       "phc_eR0iSoQufBxNY36k0f0T15UvHJdTfHlh8rJcxsfhfXk",
18 |       {
19 |         host: "https://eu.i.posthog.com",
20 |         flushAt: 1,
21 |         flushInterval: 0,
22 |       },
23 |     );
24 | 
25 |     await posthog.capture({
26 |       distinctId: actualId,
27 |       event,
28 |       properties: {
29 |         ...properties,
30 |         isByokMode: properties?.models !== "lingo.dev",
31 |         meta: {
32 |           version: process.env.npm_package_version,
33 |           isCi: process.env.CI === "true",
34 |         },
35 |       },
36 |     });
37 | 
38 |     await posthog.shutdown();
39 |   } catch (error) {
40 |     if (process.env.DEBUG) {
41 |       console.error(error);
42 |     }
43 |   }
44 | }
45 | 
46 | async function getActualId() {
47 |   const rc = getRc();
48 |   const apiKey = process.env.LINGODOTDEV_API_KEY || rc?.auth?.apiKey;
49 |   const apiUrl =
50 |     process.env.LINGODOTDEV_API_URL ||
51 |     rc?.auth?.apiUrl ||
52 |     "https://engine.lingo.dev";
53 | 
54 |   if (apiKey) {
55 |     try {
56 |       const res = await fetch(`${apiUrl}/whoami`, {
57 |         method: "POST",
58 |         headers: {
59 |           Authorization: `Bearer ${apiKey}`,
60 |           ContentType: "application/json",
61 |         },
62 |       });
63 |       if (res.ok) {
64 |         const payload = await res.json();
65 |         if (payload?.email) {
66 |           return payload.email;
67 |         }
68 |       }
69 |     } catch (err) {
70 |       // ignore, fallback to device id
71 |     }
72 |   }
73 |   const id = await machineId();
74 |   return `device-${id}`;
75 | }
76 | 
```

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

```typescript
 1 | "use client";
 2 | import { useState } from "react";
 3 | 
 4 | export function ClientComponent() {
 5 |   const [counter, setCounter] = useState(0);
 6 | 
 7 |   return (
 8 |     <div className="flex flex-col gap-4 bg-gray-300 p-4 rounded-lg">
 9 |       <span className="color-white">Interactive component</span>
10 |       <div className="flex items-center gap-4 justify-center w-100 border-2 border-gray-300 rounded-lg p-6 bg-white">
11 |         <button
12 |           onClick={() => setCounter(counter - 1)}
13 |           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"
14 |         >
15 |           - Decrement
16 |         </button>
17 |         <span className="text-4xl" title="This is current counter value">
18 |           {counter}
19 |         </span>
20 |         <button
21 |           onClick={() => setCounter(counter + 1)}
22 |           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"
23 |         >
24 |           + Increment
25 |         </button>
26 |       </div>
27 |       <div className="h-8">
28 |         {counter < -3 && (
29 |           <span className="text-red-500">
30 |             <strong>Error:</strong> Counter too low!
31 |           </span>
32 |         )}
33 |         {counter > 5 && (
34 |           <span className="text-red-500">
35 |             <strong>Error:</strong> Counter too high!
36 |           </span>
37 |         )}
38 |       </div>
39 |     </div>
40 |   );
41 | }
42 | 
```

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

```json
 1 | {
 2 |   "name": "@lingo.dev/_compiler",
 3 |   "version": "0.7.15",
 4 |   "description": "Lingo.dev Compiler",
 5 |   "private": false,
 6 |   "publishConfig": {
 7 |     "access": "public"
 8 |   },
 9 |   "sideEffects": false,
10 |   "type": "module",
11 |   "main": "build/index.cjs",
12 |   "types": "build/index.d.ts",
13 |   "module": "build/index.mjs",
14 |   "files": [
15 |     "build"
16 |   ],
17 |   "scripts": {
18 |     "dev": "tsup --watch",
19 |     "build": "pnpm typecheck && tsup",
20 |     "typecheck": "tsc --noEmit",
21 |     "clean": "rm -rf build",
22 |     "test": "vitest --run",
23 |     "test:watch": "vitest -w"
24 |   },
25 |   "keywords": [],
26 |   "author": "",
27 |   "license": "ISC",
28 |   "devDependencies": {
29 |     "@types/babel__generator": "^7.6.8",
30 |     "@types/babel__traverse": "^7.20.6",
31 |     "@types/ini": "^4.1.1",
32 |     "@types/lodash": "^4.17.4",
33 |     "@types/object-hash": "^3.0.6",
34 |     "@types/react": "^18.3.18",
35 |     "next": "15.2.4",
36 |     "tsup": "^8.3.5",
37 |     "typescript": "^5.4.5",
38 |     "vitest": "^2.1.4"
39 |   },
40 |   "dependencies": {
41 |     "@ai-sdk/google": "^1.2.19",
42 |     "@ai-sdk/groq": "^1.2.3",
43 |     "@ai-sdk/mistral": "^1.2.8",
44 |     "@babel/generator": "^7.26.5",
45 |     "@babel/parser": "^7.26.7",
46 |     "@babel/traverse": "^7.27.4",
47 |     "@babel/types": "^7.26.7",
48 |     "@lingo.dev/_sdk": "workspace:*",
49 |     "@lingo.dev/_spec": "workspace:*",
50 |     "@openrouter/ai-sdk-provider": "^0.7.1",
51 |     "@prettier/sync": "^0.6.1",
52 |     "ai": "^4.2.10",
53 |     "dedent": "^1.6.0",
54 |     "dotenv": "^16.4.5",
55 |     "fast-xml-parser": "^5.0.8",
56 |     "ini": "^5.0.0",
57 |     "lodash": "^4.17.21",
58 |     "object-hash": "^3.0.0",
59 |     "ollama-ai-provider": "^1.2.0",
60 |     "prettier": "^3.4.2",
61 |     "unplugin": "^2.1.2",
62 |     "zod": "^3.25.76",
63 |     "posthog-node": "^5.5.1",
64 |     "node-machine-id": "^1.1.12"
65 |   },
66 |   "packageManager": "[email protected]"
67 | }
68 | 
```

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

```typescript
 1 | import { describe, it, expect } from "vitest";
 2 | import jsxRootFlagMutation from "./jsx-root-flag";
 3 | import { createPayload, createOutput, defaultParams } from "./_base";
 4 | 
 5 | // Helper function to run mutation and get result
 6 | function runMutation(code: string) {
 7 |   const input = createPayload({ code, params: defaultParams, fileKey: "test" });
 8 |   const mutated = jsxRootFlagMutation(input);
 9 |   if (!mutated) throw new Error("Mutation returned null");
10 |   return createOutput(mutated).code;
11 | }
12 | 
13 | describe("jsxRootFlagMutation", () => {
14 |   it("should add data-jsx-root flag to a single root JSX element", () => {
15 |     const input = `
16 | function Component() {
17 |   return <div>Hello</div>;
18 | }
19 | `.trim();
20 | 
21 |     const expected = `
22 | function Component() {
23 |   return <div data-jsx-root>Hello</div>;
24 | }
25 | `.trim();
26 |     const result = runMutation(input);
27 | 
28 |     expect(result).toBe(expected.trim());
29 |   });
30 | 
31 |   it("should add data-jsx-root flag to multiple root JSX elements", () => {
32 |     const input = `
33 | function Component() {
34 |   if (condition) {
35 |     return <div>True</div>;
36 |   }
37 |   return <span>False</span>;
38 | }
39 | `.trim();
40 | 
41 |     const expected = `
42 | function Component() {
43 |   if (condition) {
44 |     return <div data-jsx-root>True</div>;
45 |   }
46 |   return <span data-jsx-root>False</span>;
47 | }
48 | `.trim();
49 |     const result = runMutation(input);
50 | 
51 |     expect(result).toBe(expected.trim());
52 |   });
53 | 
54 |   it("should not add data-jsx-root flag to nested JSX elements", () => {
55 |     const input = `
56 | function Component() {
57 |   return <div>
58 |       <span>Nested</span>
59 |     </div>;
60 | }
61 | `.trim();
62 | 
63 |     const expected = `
64 | function Component() {
65 |   return <div data-jsx-root>
66 |       <span>Nested</span>
67 |     </div>;
68 | }
69 | `.trim();
70 | 
71 |     const result = runMutation(input);
72 | 
73 |     expect(result).toBe(expected.trim());
74 |   });
75 | });
76 | 
```

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

```typescript
 1 | /*
 2 | |--------------------------------------------------------------------------
 3 | | Test runner entrypoint
 4 | |--------------------------------------------------------------------------
 5 | |
 6 | | The "test.ts" file is the entrypoint for running tests using Japa.
 7 | |
 8 | | Either you can run this file directly or use the "test"
 9 | | command to run this file and monitor file changes.
10 | |
11 | */
12 | 
13 | // @ts-expect-error 2540
14 | process.env.NODE_ENV = 'test'
15 | 
16 | import 'reflect-metadata'
17 | import { Ignitor, prettyPrintError } from '@adonisjs/core'
18 | import { configure, processCLIArgs, run } from '@japa/runner'
19 | 
20 | /**
21 |  * URL to the application root. AdonisJS need it to resolve
22 |  * paths to file and directories for scaffolding commands
23 |  */
24 | const APP_ROOT = new URL('../', import.meta.url)
25 | 
26 | /**
27 |  * The importer is used to import files in context of the
28 |  * application.
29 |  */
30 | const IMPORTER = (filePath: string) => {
31 |   if (filePath.startsWith('./') || filePath.startsWith('../')) {
32 |     return import(new URL(filePath, APP_ROOT).href)
33 |   }
34 |   return import(filePath)
35 | }
36 | 
37 | new Ignitor(APP_ROOT, { importer: IMPORTER })
38 |   .tap((app) => {
39 |     app.booting(async () => {
40 |       await import('#start/env')
41 |     })
42 |     app.listen('SIGTERM', () => app.terminate())
43 |     app.listenIf(app.managedByPm2, 'SIGINT', () => app.terminate())
44 |   })
45 |   .testRunner()
46 |   .configure(async (app) => {
47 |     const { runnerHooks, ...config } = await import('../tests/bootstrap.js')
48 | 
49 |     processCLIArgs(process.argv.splice(2))
50 |     configure({
51 |       ...app.rcFile.tests,
52 |       ...config,
53 |       ...{
54 |         setup: runnerHooks.setup,
55 |         teardown: runnerHooks.teardown.concat([() => app.terminate()]),
56 |       },
57 |     })
58 |   })
59 |   .run(() => run())
60 |   .catch((error) => {
61 |     process.exitCode = 1
62 |     prettyPrintError(error)
63 |   })
64 | 
```

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

```typescript
 1 | import { NodePath } from "@babel/traverse";
 2 | import * as t from "@babel/types";
 3 | import traverse from "@babel/traverse";
 4 | 
 5 | export function getAstKey(nodePath: NodePath) {
 6 |   const keyChunks: any[] = [];
 7 | 
 8 |   let current: NodePath | null = nodePath;
 9 |   while (current) {
10 |     keyChunks.push(current.key);
11 |     current = current.parentPath;
12 | 
13 |     if (t.isProgram(current?.node)) {
14 |       break;
15 |     }
16 |   }
17 | 
18 |   const result = keyChunks.reverse().join("/");
19 |   return result;
20 | }
21 | 
22 | export function getAstByKey(ast: t.File, key: string) {
23 |   const programPath = _getProgramNodePath(ast);
24 |   if (!programPath) {
25 |     return null;
26 |   }
27 | 
28 |   const keyParts = key.split("/").reverse();
29 | 
30 |   let result: NodePath = programPath;
31 | 
32 |   while (true) {
33 |     let currentKeyPart = keyParts.pop();
34 |     if (!currentKeyPart) {
35 |       break;
36 |     }
37 |     const isIntegerPart = Number.isInteger(Number(currentKeyPart));
38 |     if (isIntegerPart) {
39 |       const maybeBodyItemsArray = result.get("body");
40 |       const bodyItemsArray = Array.isArray(maybeBodyItemsArray)
41 |         ? maybeBodyItemsArray
42 |         : [maybeBodyItemsArray];
43 |       const index = Number(currentKeyPart);
44 |       const subResult = bodyItemsArray[index];
45 |       result = subResult as NodePath;
46 |     } else {
47 |       const maybeSubResultArray = result.get(currentKeyPart);
48 |       const subResultArray = Array.isArray(maybeSubResultArray)
49 |         ? maybeSubResultArray
50 |         : [maybeSubResultArray];
51 |       const subResult = subResultArray[0];
52 |       result = subResult;
53 |     }
54 |   }
55 | 
56 |   return result;
57 | }
58 | 
59 | function _getProgramNodePath(ast: t.File): NodePath<t.Program> | null {
60 |   let result: NodePath<t.Program> | null = null;
61 | 
62 |   traverse(ast, {
63 |     Program(nodePath) {
64 |       result = nodePath;
65 |       nodePath.stop();
66 |     },
67 |   });
68 | 
69 |   return result;
70 | }
71 | 
```

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

```typescript
 1 | import * as t from "@babel/types";
 2 | import { NodePath } from "@babel/traverse";
 3 | 
 4 | export function getJsxElementName(nodePath: NodePath<t.JSXElement>) {
 5 |   const openingElement = nodePath.node.openingElement;
 6 | 
 7 |   // elements with simple (string) name
 8 |   if (t.isJSXIdentifier(openingElement.name)) {
 9 |     return openingElement.name.name;
10 |   }
11 | 
12 |   // elements with dots in name
13 |   if (t.isJSXMemberExpression(openingElement.name)) {
14 |     const memberExpr = openingElement.name;
15 |     const parts: string[] = [];
16 | 
17 |     // Traverse the member expression to collect all parts
18 |     let current: t.JSXMemberExpression | t.JSXIdentifier = memberExpr;
19 |     while (t.isJSXMemberExpression(current)) {
20 |       parts.unshift(current.property.name);
21 |       current = current.object;
22 |     }
23 | 
24 |     // Add the base identifier
25 |     if (t.isJSXIdentifier(current)) {
26 |       parts.unshift(current.name);
27 |     }
28 | 
29 |     return parts.join(".");
30 |   }
31 |   return null;
32 | }
33 | 
34 | export function getNestedJsxElements(nodePath: NodePath<t.JSXElement>) {
35 |   const nestedElements: t.JSXElement[] = [];
36 | 
37 |   nodePath.traverse({
38 |     JSXElement(path) {
39 |       if (path.node !== nodePath.node) {
40 |         nestedElements.push(path.node);
41 |       }
42 |     },
43 |   });
44 | 
45 |   const arrayOfElements = nestedElements.map((element, index) => {
46 |     // Create a function that takes children as param and returns the JSX element
47 |     const param = t.identifier("children");
48 | 
49 |     // Replace the original children with the param
50 |     const clonedElement = t.cloneNode(element);
51 |     clonedElement.children = [t.jsxExpressionContainer(param)];
52 | 
53 |     return t.arrowFunctionExpression(
54 |       [t.objectPattern([t.objectProperty(param, param, false, true)])],
55 |       clonedElement,
56 |     );
57 |   });
58 |   const result = t.arrayExpression(arrayOfElements);
59 |   return result;
60 | }
61 | 
```

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

```typescript
 1 | const STEP_WAIT_INTERVAL = 250;
 2 | const MAX_WAIT_INTERVAL = 2000;
 3 | 
 4 | export function exitGracefully(elapsedMs = 0) {
 5 |   // Check if there are any pending operations
 6 |   const hasPendingOperations = checkForPendingOperations();
 7 | 
 8 |   if (hasPendingOperations && elapsedMs < MAX_WAIT_INTERVAL) {
 9 |     // Wait a bit longer if there are pending operations
10 |     setTimeout(
11 |       () => exitGracefully(elapsedMs + STEP_WAIT_INTERVAL),
12 |       STEP_WAIT_INTERVAL,
13 |     );
14 |   } else {
15 |     // Exit immediately if no pending operations
16 |     process.exit(0);
17 |   }
18 | }
19 | 
20 | function checkForPendingOperations(): boolean {
21 |   // Check for active handles and requests using internal Node.js methods
22 |   const activeHandles = (process as any)._getActiveHandles?.() || [];
23 |   const activeRequests = (process as any)._getActiveRequests?.() || [];
24 | 
25 |   // Filter out standard handles that are always present
26 |   const nonStandardHandles = activeHandles.filter((handle: any) => {
27 |     // Skip standard handles like process.stdin, process.stdout, etc.
28 |     if (
29 |       handle === process.stdin ||
30 |       handle === process.stdout ||
31 |       handle === process.stderr
32 |     ) {
33 |       return false;
34 |     }
35 |     // Skip timers that are part of the normal process
36 |     if (
37 |       handle &&
38 |       typeof handle === "object" &&
39 |       "hasRef" in handle &&
40 |       !handle.hasRef()
41 |     ) {
42 |       return false;
43 |     }
44 |     return true;
45 |   });
46 | 
47 |   // Check if there are any file watchers or other async operations
48 |   const hasFileWatchers = nonStandardHandles.some(
49 |     (handle: any) => handle && typeof handle === "object" && "close" in handle,
50 |   );
51 | 
52 |   // Check for pending promises or async operations
53 |   const hasPendingPromises = activeRequests.length > 0;
54 | 
55 |   return nonStandardHandles.length > 0 || hasFileWatchers || hasPendingPromises;
56 | }
57 | 
```

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

```typescript
 1 | import { openrouter } from "@openrouter/ai-sdk-provider";
 2 | 
 3 | export const providerDetails: Record<
 4 |   string,
 5 |   {
 6 |     name: string; // Display name (e.g., "Groq", "Google")
 7 |     apiKeyEnvVar?: string; // Environment variable name (e.g., "GROQ_API_KEY")
 8 |     apiKeyConfigKey?: string; // Config key if applicable (e.g., "llm.groqApiKey")
 9 |     getKeyLink: string; // Link to get API key
10 |     docsLink: string; // Link to API docs for troubleshooting
11 |   }
12 | > = {
13 |   groq: {
14 |     name: "Groq",
15 |     apiKeyEnvVar: "GROQ_API_KEY",
16 |     apiKeyConfigKey: "llm.groqApiKey",
17 |     getKeyLink: "https://groq.com",
18 |     docsLink: "https://console.groq.com/docs/errors",
19 |   },
20 |   google: {
21 |     name: "Google",
22 |     apiKeyEnvVar: "GOOGLE_API_KEY",
23 |     apiKeyConfigKey: "llm.googleApiKey",
24 |     getKeyLink: "https://ai.google.dev/",
25 |     docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting",
26 |   },
27 |   openrouter: {
28 |     name: "OpenRouter",
29 |     apiKeyEnvVar: "OPENROUTER_API_KEY",
30 |     apiKeyConfigKey: "llm.openrouterApiKey",
31 |     getKeyLink: "https://openrouter.ai",
32 |     docsLink: "https://openrouter.ai/docs",
33 |   },
34 |   ollama: {
35 |     name: "Ollama",
36 |     apiKeyEnvVar: undefined, // Ollama doesn't require an API key
37 |     apiKeyConfigKey: undefined, // Ollama doesn't require an API key
38 |     getKeyLink: "https://ollama.com/download",
39 |     docsLink: "https://github.com/ollama/ollama/tree/main/docs",
40 |   },
41 |   mistral: {
42 |     name: "Mistral",
43 |     apiKeyEnvVar: "MISTRAL_API_KEY",
44 |     apiKeyConfigKey: "llm.mistralApiKey",
45 |     getKeyLink: "https://console.mistral.ai",
46 |     docsLink: "https://docs.mistral.ai",
47 |   },
48 |   "lingo.dev": {
49 |     name: "Lingo.dev",
50 |     apiKeyEnvVar: "LINGODOTDEV_API_KEY",
51 |     apiKeyConfigKey: "auth.apiKey",
52 |     getKeyLink: "https://lingo.dev",
53 |     docsLink: "https://lingo.dev/docs",
54 |   },
55 | };
56 | 
```

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

```typescript
 1 | import _ from "lodash";
 2 | import { ILoader } from "./_types";
 3 | import { createLoader } from "./_utils";
 4 | import { minimatch } from "minimatch";
 5 | 
 6 | export default function createInjectLocaleLoader(
 7 |   injectLocaleKeys?: string[],
 8 | ): ILoader<Record<string, any>, Record<string, any>> {
 9 |   return createLoader({
10 |     async pull(locale, data) {
11 |       if (!injectLocaleKeys) {
12 |         return data;
13 |       }
14 |       const omitKeys = _getKeysWithLocales(data, injectLocaleKeys, locale);
15 |       const result = _.omit(data, omitKeys);
16 |       return result;
17 |     },
18 |     async push(locale, data, originalInput, originalLocale) {
19 |       if (!injectLocaleKeys || !originalInput) {
20 |         return data;
21 |       }
22 | 
23 |       const localeKeys = _getKeysWithLocales(
24 |         originalInput,
25 |         injectLocaleKeys,
26 |         originalLocale,
27 |       );
28 | 
29 |       localeKeys.forEach((key) => {
30 |         _.set(data, key, locale);
31 |       });
32 | 
33 |       return data;
34 |     },
35 |   });
36 | }
37 | 
38 | function _getKeysWithLocales(
39 |   data: Record<string, any>,
40 |   injectLocaleKeys: string[],
41 |   locale: string,
42 | ) {
43 |   const allKeys = _getAllKeys(data);
44 |   return allKeys.filter((key) => {
45 |     return (
46 |       injectLocaleKeys.some((pattern) => minimatch(key, pattern)) &&
47 |       _.get(data, key) === locale
48 |     );
49 |   });
50 | }
51 | 
52 | // Helper to get all deep keys in lodash path style (e.g., 'a.b.c')
53 | function _getAllKeys(obj: Record<string, any>, prefix = ""): string[] {
54 |   let keys: string[] = [];
55 |   for (const key in obj) {
56 |     if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
57 |     const path = prefix ? `${prefix}.${key}` : key;
58 |     if (
59 |       typeof obj[key] === "object" &&
60 |       obj[key] !== null &&
61 |       !Array.isArray(obj[key])
62 |     ) {
63 |       keys = keys.concat(_getAllKeys(obj[key], path));
64 |     } else {
65 |       keys.push(path);
66 |     }
67 |   }
68 |   return keys;
69 | }
70 | 
```

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

```typescript
 1 | import { LingoProvider as LingoClientProvider } from "../client";
 2 | import { loadDictionaryFromRequest, loadLocaleFromCookies } from "./utils";
 3 | 
 4 | /**
 5 |  * The props for the `LingoProvider` component.
 6 |  */
 7 | export type LingoProviderProps = {
 8 |   /**
 9 |    * A callback function that loads the dictionary for the current locale.
10 |    *
11 |    * @param locale - The locale code to load the dictionary for.
12 |    *
13 |    * @returns The dictionary object containing localized content.
14 |    */
15 |   loadDictionary: (locale: string | null) => Promise<any>;
16 |   /**
17 |    * The child components containing localizable content.
18 |    */
19 |   children: React.ReactNode;
20 | };
21 | 
22 | /**
23 |  * A context provider that loads the dictionary for the current locale and makes localized content available to its descendants.
24 |  *
25 |  * This component:
26 |  *
27 |  * - Should be placed at the top of the component tree
28 |  * - Should be used in server-side rendering scenarios with React Server Components (RSC)
29 |  *
30 |  * @template D - The type of the dictionary object containing localized content.
31 |  *
32 |  * @example Use in a Next.js (App Router) application
33 |  * ```tsx file="app/layout.tsx"
34 |  * import { LingoProvider, loadDictionary } from "lingo.dev/react/rsc";
35 |  *
36 |  * export default function RootLayout({
37 |  *   children,
38 |  * }: Readonly<{
39 |  *   children: React.ReactNode;
40 |  * }>) {
41 |  *   return (
42 |  *     <LingoProvider loadDictionary={(locale) => loadDictionary(locale)}>
43 |  *       <html lang="en">
44 |  *        <body>
45 |  *           {children}
46 |  *         </body>
47 |  *       </html>
48 |  *     </LingoProvider>
49 |  *   );
50 |  * }
51 |  * ```
52 |  */
53 | export async function LingoProvider(props: LingoProviderProps) {
54 |   const dictionary = await loadDictionaryFromRequest(props.loadDictionary);
55 | 
56 |   return (
57 |     <LingoClientProvider dictionary={dictionary}>
58 |       {props.children}
59 |     </LingoClientProvider>
60 |   );
61 | }
62 | 
```

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

```typescript
 1 | import { Command } from "interactive-commander";
 2 | import chalk from "chalk";
 3 | import dedent from "dedent";
 4 | import _ from "lodash";
 5 | import {
 6 |   SETTINGS_KEYS,
 7 |   loadSystemSettings,
 8 |   saveSettings,
 9 | } from "../../utils/settings";
10 | 
11 | export default new Command()
12 |   .name("unset")
13 |   .description("Remove a CLI setting from ~/.lingodotdevrc")
14 |   .addHelpText("afterAll", `\nAvailable keys:\n  ${SETTINGS_KEYS.join("\n  ")}`)
15 |   .argument(
16 |     "<key>",
17 |     "Configuration key to remove (must match one of the available keys listed below)",
18 |   )
19 |   .helpOption("-h, --help", "Show help")
20 |   .action(async (key: string) => {
21 |     // Validate key first (defensive; choices() should already restrict but keep for safety).
22 |     if (!SETTINGS_KEYS.includes(key)) {
23 |       console.error(
24 |         dedent`
25 |           ${chalk.red("✖")} Unknown configuration key: ${chalk.bold(key)}
26 |           Run ${chalk.dim(
27 |             "lingo.dev config unset --help",
28 |           )} to see available keys.
29 |         `,
30 |       );
31 |       process.exitCode = 1;
32 |       return;
33 |     }
34 | 
35 |     // Load existing settings.
36 |     const settings = loadSystemSettings();
37 |     const currentValue = _.get(settings, key);
38 | 
39 |     if (!_.trim(String(currentValue || ""))) {
40 |       console.log(`${chalk.cyan("ℹ")} ${chalk.bold(key)} is not set.`);
41 |       return;
42 |     } else {
43 |       const updated: any = _.cloneDeep(settings);
44 |       _.unset(updated, key);
45 |       try {
46 |         saveSettings(updated as any);
47 |         console.log(
48 |           `${chalk.green("✔")} Removed configuration key ${chalk.bold(key)}`,
49 |         );
50 |       } catch (err) {
51 |         console.error(
52 |           chalk.red(
53 |             `✖ Failed to save configuration: ${chalk.dim(
54 |               err instanceof Error ? err.message : String(err),
55 |             )}`,
56 |           ),
57 |         );
58 |         process.exitCode = 1;
59 |       }
60 |     }
61 |   });
62 | 
```

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

```typescript
 1 | export function formatPlutilStyle(
 2 |   jsonData: any,
 3 |   existingJson?: string,
 4 | ): string {
 5 |   // Detect indentation from existing JSON if provided
 6 |   const indent = existingJson ? detectIndentation(existingJson) : "  ";
 7 | 
 8 |   function format(data: any, level = 0): string {
 9 |     const currentIndent = indent.repeat(level);
10 |     const nextIndent = indent.repeat(level + 1);
11 | 
12 |     if (typeof data !== "object" || data === null) {
13 |       return JSON.stringify(data);
14 |     }
15 | 
16 |     if (Array.isArray(data)) {
17 |       if (data.length === 0) return "[]";
18 |       const items = data.map(
19 |         (item) => `${nextIndent}${format(item, level + 1)}`,
20 |       );
21 |       return `[\n${items.join(",\n")}\n${currentIndent}]`;
22 |     }
23 | 
24 |     const keys = Object.keys(data);
25 |     if (keys.length === 0) {
26 |       return `{\n\n${currentIndent}}`; // Empty object with proper indentation
27 |     }
28 | 
29 |     // Sort keys to ensure whitespace keys come first
30 |     const sortedKeys = keys.sort((a, b) => {
31 |       // If both keys are whitespace or both are non-whitespace, maintain stable order
32 |       const aIsWhitespace = /^\s*$/.test(a);
33 |       const bIsWhitespace = /^\s*$/.test(b);
34 | 
35 |       if (aIsWhitespace && !bIsWhitespace) return -1;
36 |       if (!aIsWhitespace && bIsWhitespace) return 1;
37 |       return a.localeCompare(b, undefined, { numeric: true });
38 |     });
39 | 
40 |     const items = sortedKeys.map((key) => {
41 |       const value = data[key];
42 |       return `${nextIndent}${JSON.stringify(key)} : ${format(
43 |         value,
44 |         level + 1,
45 |       )}`;
46 |     });
47 | 
48 |     return `{\n${items.join(",\n")}\n${currentIndent}}`;
49 |   }
50 | 
51 |   const result = format(jsonData);
52 |   return result;
53 | }
54 | 
55 | function detectIndentation(jsonStr: string): string {
56 |   // Find the first indented line
57 |   const match = jsonStr.match(/\n(\s+)/);
58 |   return match ? match[1] : "    "; // fallback to 4 spaces if no indentation found
59 | }
60 | 
```

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

```yaml
 1 | name: "Lingo.dev"
 2 | 
 3 | on:
 4 |   workflow_dispatch:
 5 |     inputs:
 6 |       version:
 7 |         description: "Lingo.dev CLI version"
 8 |         default: "latest"
 9 |         required: false
10 |       pull-request:
11 |         description: "Create a pull request with the changes"
12 |         type: boolean
13 |         default: false
14 |         required: false
15 |       commit-message:
16 |         description: "Commit message"
17 |         default: "feat: update translations via @LingoDotDev"
18 |         required: false
19 |       pull-request-title:
20 |         description: "Pull request title"
21 |         default: "feat: update translations via @LingoDotDev"
22 |         required: false
23 |       working-directory:
24 |         description: "Working directory"
25 |         default: "."
26 |         required: false
27 |       process-own-commits:
28 |         description: "Process commits made by this action"
29 |         type: boolean
30 |         default: false
31 |         required: false
32 |       parallel:
33 |         description: "Run in parallel mode"
34 |         type: boolean
35 |         default: false
36 |         required: false
37 | 
38 | jobs:
39 |   lingodotdev:
40 |     runs-on: ubuntu-latest
41 |     permissions:
42 |       contents: write
43 |       pull-requests: write
44 |     steps:
45 |       - name: Checkout
46 |         uses: actions/checkout@v4
47 | 
48 |       - name: Use Node.js
49 |         uses: actions/setup-node@v2
50 |         with:
51 |           node-version: "20"
52 | 
53 |       - name: Lingo.dev
54 |         uses: ./
55 |         with:
56 |           api-key: ${{ secrets.LINGODOTDEV_API_KEY }}
57 |           version: ${{ inputs.version }}
58 |           pull-request: ${{ inputs['pull-request'] }}
59 |           commit-message: ${{ inputs['commit-message'] }}
60 |           pull-request-title: ${{ inputs['pull-request-title'] }}
61 |           working-directory: ${{ inputs['working-directory'] }}
62 |           process-own-commits: ${{ inputs['process-own-commits'] }}
63 |           parallel: ${{ inputs.parallel }}
64 |         env:
65 |           GH_TOKEN: ${{ github.token }}
66 | 
```

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

```typescript
 1 | import { createCodeMutation } from "./_base";
 2 | import { ModuleId } from "./_const";
 3 | import { getModuleExecutionMode, getOrCreateImport } from "./utils";
 4 | import { findInvokations } from "./utils/invokations";
 5 | import * as t from "@babel/types";
 6 | import { getDictionaryPath } from "./_utils";
 7 | import { createLocaleImportMap } from "./utils/create-locale-import-map";
 8 | 
 9 | export const reactRouterDictionaryLoaderMutation = createCodeMutation(
10 |   (payload) => {
11 |     const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
12 |     if (mode === "server") {
13 |       return payload;
14 |     }
15 | 
16 |     const invokations = findInvokations(payload.ast, {
17 |       moduleName: ModuleId.ReactRouter,
18 |       functionName: "loadDictionary",
19 |     });
20 | 
21 |     const allLocales = Array.from(
22 |       new Set([payload.params.sourceLocale, ...payload.params.targetLocales]),
23 |     );
24 | 
25 |     for (const invokation of invokations) {
26 |       const internalDictionaryLoader = getOrCreateImport(payload.ast, {
27 |         moduleName: ModuleId.ReactRouter,
28 |         exportedName: "loadDictionary_internal",
29 |       });
30 | 
31 |       // Replace the function identifier with internal version
32 |       if (t.isIdentifier(invokation.callee)) {
33 |         invokation.callee.name = internalDictionaryLoader.importedName;
34 |       }
35 | 
36 |       const dictionaryPath = getDictionaryPath({
37 |         sourceRoot: payload.params.sourceRoot,
38 |         lingoDir: payload.params.lingoDir,
39 |         relativeFilePath: payload.relativeFilePath,
40 |       });
41 | 
42 |       // Create locale import map object
43 |       const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);
44 | 
45 |       // Add the locale import map as the second argument
46 |       invokation.arguments.push(localeImportMap);
47 |       // console.log("invokation modified", JSON.stringify(invokation, null, 2));
48 |     }
49 | 
50 |     // console.log("dictionary-loader", generate(payload.ast).code);
51 | 
52 |     return payload;
53 |   },
54 | );
55 | 
```

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

```typescript
 1 | import { describe, it, expect, vi, beforeEach } from "vitest";
 2 | import { createPayload, createOutput, defaultParams } from "./_base";
 3 | import { jsxAttributeScopesExportMutation } from "./jsx-attribute-scopes-export";
 4 | 
 5 | vi.mock("./lib/lcp", () => {
 6 |   const instance = {
 7 |     resetScope: vi.fn().mockReturnThis(),
 8 |     setScopeType: vi.fn().mockReturnThis(),
 9 |     setScopeHash: vi.fn().mockReturnThis(),
10 |     setScopeContext: vi.fn().mockReturnThis(),
11 |     setScopeSkip: vi.fn().mockReturnThis(),
12 |     setScopeOverrides: vi.fn().mockReturnThis(),
13 |     setScopeContent: vi.fn().mockReturnThis(),
14 |     save: vi.fn(),
15 |   };
16 |   const getInstance = vi.fn(() => instance);
17 |   return {
18 |     LCP: {
19 |       getInstance,
20 |     },
21 |     __test__: { instance, getInstance },
22 |   };
23 | });
24 | describe("jsxAttributeScopesExportMutation", () => {
25 |   beforeEach(() => {
26 |     // dynamic import avoids ESM mock timing issues
27 |     return import("./lib/lcp").then((lcpMod) => {
28 |       (lcpMod.LCP.getInstance as any).mockClear();
29 |     });
30 |   });
31 | 
32 |   it("collects attribute scopes and saves to LCP", async () => {
33 |     const code = `
34 | export default function X() {
35 |   return <div data-jsx-attribute-scope="title:scope-1" title="Hello"/>;
36 | }`.trim();
37 |     const input = createPayload({
38 |       code,
39 |       params: defaultParams,
40 |       relativeFilePath: "src/App.tsx",
41 |     } as any);
42 |     const out = jsxAttributeScopesExportMutation(input);
43 |     // Not asserting output code as mutation does not change AST; assert side effects
44 |     const lcpMod: any = await import("./lib/lcp");
45 |     const inst = lcpMod.__test__.instance;
46 |     expect(lcpMod.LCP.getInstance).toHaveBeenCalled();
47 |     expect(inst.setScopeType).toHaveBeenCalledWith(
48 |       "src/App.tsx",
49 |       "scope-1",
50 |       "attribute",
51 |     );
52 |     expect(inst.setScopeContent).toHaveBeenCalledWith(
53 |       "src/App.tsx",
54 |       "scope-1",
55 |       "Hello",
56 |     );
57 |     expect(inst.save).toHaveBeenCalled();
58 |   });
59 | });
60 | 
```

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

```yaml
 1 | name: Check PR
 2 | 
 3 | on:
 4 |   workflow_dispatch:
 5 |   pull_request:
 6 |     types:
 7 |       - opened
 8 |       - edited
 9 |       - synchronize
10 |     branches:
11 |       - main
12 | 
13 | jobs:
14 |   check:
15 |     runs-on: ubuntu-latest
16 |     permissions:
17 |       contents: read
18 |     steps:
19 |       - name: Checkout
20 |         uses: actions/checkout@v4
21 |         with:
22 |           ref: ${{github.event.pull_request.head.sha}}
23 |           fetch-depth: 0
24 | 
25 |       - name: Check for [skip i18n]
26 |         run: |
27 |           COMMIT_MESSAGE=$(git log -1 --pretty=%B)
28 |           if echo "$COMMIT_MESSAGE" | grep -iq '\[skip i18n\]'; then
29 |             echo "Skipping i18n checks due to [skip i18n] in commit message."
30 |             exit 0
31 |           fi
32 | 
33 |       - name: Use Node.js
34 |         uses: actions/setup-node@v2
35 |         with:
36 |           node-version: 20.12.2
37 | 
38 |       - name: Install pnpm
39 |         uses: pnpm/action-setup@v4
40 |         id: pnpm-install
41 |         with:
42 |           version: 9.12.3
43 |           run_install: false
44 | 
45 |       - name: Configure pnpm cache
46 |         id: pnpm-cache
47 |         run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
48 |       - uses: actions/cache@v3
49 |         with:
50 |           path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
51 |           key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
52 |           restore-keys: |
53 |             ${{ runner.os }}-pnpm-store-
54 | 
55 |       - name: Install deps
56 |         run: pnpm install
57 | 
58 |       - name: Setup
59 |         run: |
60 |           pnpm turbo telemetry disable
61 | 
62 |       - name: Configure Turbo cache
63 |         uses: dtinth/setup-github-actions-caching-for-turbo@v1
64 | 
65 |       - name: Check formatting
66 |         run: pnpm format:check
67 | 
68 |       - name: Build
69 |         run: pnpm turbo build --force
70 | 
71 |       - name: Test
72 |         run: pnpm turbo test --force
73 | 
74 |       - name: Require changeset to be present in PR
75 |         if: github.event.pull_request.user.login != 'dependabot[bot]'
76 |         run: pnpm changeset status --since origin/main
77 | 
```

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

```typescript
 1 | import _ from "lodash";
 2 | import _isUrl from "is-url";
 3 | import { isValid, parseISO } from "date-fns";
 4 | 
 5 | import { ILoader } from "./_types";
 6 | import { createLoader } from "./_utils";
 7 | 
 8 | export default function createUnlocalizableLoader(
 9 |   returnUnlocalizedKeys: boolean = false,
10 | ): ILoader<Record<string, any>, Record<string, any>> {
11 |   return createLoader({
12 |     async pull(locale, input) {
13 |       const unlocalizableKeys = _getUnlocalizableKeys(input);
14 | 
15 |       const result = _.omitBy(input, (_, key) =>
16 |         unlocalizableKeys.includes(key),
17 |       );
18 | 
19 |       if (returnUnlocalizedKeys) {
20 |         result.unlocalizable = _.omitBy(
21 |           input,
22 |           (_, key) => !unlocalizableKeys.includes(key),
23 |         );
24 |       }
25 | 
26 |       return result;
27 |     },
28 |     async push(locale, data, originalInput) {
29 |       const unlocalizableKeys = _getUnlocalizableKeys(originalInput);
30 | 
31 |       const result = _.merge(
32 |         {},
33 |         data,
34 |         _.omitBy(originalInput, (_, key) => !unlocalizableKeys.includes(key)),
35 |       );
36 | 
37 |       return result;
38 |     },
39 |   });
40 | }
41 | 
42 | function _isSystemId(v: string) {
43 |   return /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)[A-Za-z0-9]{22}$/.test(v);
44 | }
45 | 
46 | function _isIsoDate(v: string) {
47 |   return isValid(parseISO(v));
48 | }
49 | 
50 | function _getUnlocalizableKeys(input?: Record<string, any> | null) {
51 |   const rules = {
52 |     isEmpty: (v: any) => _.isEmpty(v),
53 |     isNumber: (v: any) => typeof v === "number" || /^[0-9]+$/.test(v),
54 |     isBoolean: (v: any) => _.isBoolean(v),
55 |     isIsoDate: (v: any) => _.isString(v) && _isIsoDate(v),
56 |     isSystemId: (v: any) => _.isString(v) && _isSystemId(v),
57 |     isUrl: (v: any) => _.isString(v) && _isUrl(v),
58 |   };
59 | 
60 |   if (!input) {
61 |     return [];
62 |   }
63 | 
64 |   return Object.entries(input)
65 |     .filter(([key, value]) => {
66 |       for (const [ruleName, rule] of Object.entries(rules)) {
67 |         if (rule(value)) {
68 |           return true;
69 |         }
70 |       }
71 |       return false;
72 |     })
73 |     .map(([key, _]) => key);
74 | }
75 | 
```
Page 3/20FirstPrevNextLast