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

# Directory Structure

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

# Files

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

```typescript
import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
import * as fs from "fs";
import * as path from "path";
import dedent from "dedent";

vi.mock("fs", async (importOriginal) => {
  const mod = await importOriginal<typeof import("fs")>();
  return {
    ...mod,
    existsSync: vi.fn(() => false),
    mkdirSync: vi.fn(),
    writeFileSync: vi.fn(),
    readFileSync: vi.fn(() => "{}"),
    statSync: vi.fn(() => ({ mtimeMs: Date.now() - 10_000 }) as any),
    rmdirSync: vi.fn(),
    utimesSync: vi.fn(),
  } as any;
});

// import after mocks
import { LCP } from "./index";

describe("LCP", () => {
  beforeEach(() => {
    (fs.existsSync as any).mockReset().mockReturnValue(false);
    (fs.mkdirSync as any).mockReset();
    (fs.writeFileSync as any).mockReset();
    (fs.readFileSync as any).mockReset().mockReturnValue("{}");
    (fs.statSync as any)
      .mockReset()
      .mockReturnValue({ mtimeMs: Date.now() - 10_000 });
    (fs.rmdirSync as any).mockReset();
    (fs.utimesSync as any).mockReset();
  });

  describe("ensureFile", () => {
    it("creates meta.json and throws an error", () => {
      (fs.existsSync as any).mockReturnValueOnce(false);
      expect(() => {
        LCP.ensureFile({ sourceRoot: "src", lingoDir: "lingo" });
      }).toThrow(/Lingo.dev Compiler detected missing meta.json file/);
      expect(fs.mkdirSync).toHaveBeenCalled();
      expect(fs.writeFileSync).toHaveBeenCalled();
    });

    it("does not create meta.json if it already exists", () => {
      (fs.existsSync as any).mockReturnValue(true);
      LCP.ensureFile({ sourceRoot: "src", lingoDir: "lingo" });
      expect(fs.mkdirSync).not.toHaveBeenCalled();
      expect(fs.writeFileSync).not.toHaveBeenCalled();
    });
  });

  describe("getInstance", () => {
    it("returns parsed schema when file exists", () => {
      (fs.existsSync as any).mockReturnValue(true);
      (fs.readFileSync as any).mockReturnValue('{"version":42, "files": {}}');
      const lcp = LCP.getInstance({ sourceRoot: "src", lingoDir: "lingo" });
      expect(lcp.data.version).toBe(42);
    });

    it("returns new instance when file does not exist", () => {
      (fs.existsSync as any).mockReturnValue(false);
      const lcp = LCP.getInstance({ sourceRoot: "src", lingoDir: "lingo" });
      expect(lcp.data.version).toBe(0.1);
    });
  });

  describe("ready", () => {
    it("resolves immediately when meta.json is older than threshold", async () => {
      (fs.existsSync as any).mockReturnValue(true);
      (fs.statSync as any).mockReturnValue({ mtimeMs: Date.now() - 10_000 });
      await LCP.ready({ sourceRoot: "src", lingoDir: "lingo", isDev: false });
      expect(fs.statSync).toHaveBeenCalled();
    });
  });

  describe("setScope* chain", () => {
    it("modifies internal data and save writes only on change", () => {
      const lcp = LCP.getInstance({ sourceRoot: "src", lingoDir: "lingo" });
      (fs.existsSync as any).mockReturnValue(false);
      lcp
        .resetScope("file.tsx", "scope-1")
        .setScopeType("file.tsx", "scope-1", "element")
        .setScopeContext("file.tsx", "scope-1", "ctx")
        .setScopeHash("file.tsx", "scope-1", "hash")
        .setScopeSkip("file.tsx", "scope-1", false)
        .setScopeOverrides("file.tsx", "scope-1", { es: "x" })
        .setScopeContent("file.tsx", "scope-1", "Hello");

      // first save writes
      lcp.save();
      expect(fs.writeFileSync).toHaveBeenCalledTimes(1);

      // mimic that file exists and content matches -> no write
      (fs.existsSync as any).mockReturnValue(true);
      (fs.readFileSync as any).mockReturnValueOnce(
        (fs.writeFileSync as any).mock.calls[0][1],
      );
      lcp.save();
      expect(fs.writeFileSync).toHaveBeenCalledTimes(1);
    });
  });
});

```

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

```
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Basic translatable strings -->
    <string name="app_name">MyApp</string>
    <string name="welcome_message">Hello, world!</string>
    <string name="button_text">Get Started</string>

    <!-- Non-translatable configuration strings (will not appear in target locales) -->
    <string name="api_endpoint" translatable="false">https://api.example.com</string>
    <string name="debug_key" translatable="false">DEBUG_MODE_ENABLED</string>

    <!-- Translatable string arrays -->
    <string-array name="color_names">
        <item>Red</item>
        <item>Green</item>
        <item>Blue!</item>
    </string-array>

    <!-- Non-translatable server URLs (will not appear in target locales) -->
    <string-array name="server_urls" translatable="false">
        <item>https://prod.example.com</item>
        <item>https://staging.example.com</item>
        <item>https://dev.example.com</item>
    </string-array>

    <!-- Translatable plurals -->
    <plurals name="notification_count">
        <item quantity="one">%d new message</item>
        <item quantity="other">%d new messages</item>
    </plurals>

    <!-- Non-translatable plurals (will not appear in target locales) -->
    <plurals name="cache_size" translatable="false">
        <item quantity="one">%d byte</item>
        <item quantity="other">%d bytes</item>
    </plurals>

    <!-- Translatable booleans -->
    <bool name="show_tutorial">true</bool>
    <bool name="enable_animations">false</bool>

    <!-- Non-translatable debug flags (will not appear in target locales) -->
    <bool name="is_debug_build" translatable="false">false</bool>
    <bool name="enable_logging" translatable="false">true</bool>

    <!-- Translatable integers -->
    <integer name="max_retry_attempts">3</integer>
    <integer name="default_timeout">30</integer>

    <!-- Non-translatable version numbers (will not appear in target locales) -->
    <integer name="build_version" translatable="false">43</integer>
    <integer name="api_version" translatable="false">1</integer>

    <!-- Special character handling -->
    <string name="html_snippet">&lt;b&gt;Bold&lt;/b&gt;</string>

    <string name="apostrophe_example">Don\'t forget!</string>

    <string name="cdata_example"><![CDATA[Users can only see your comment after they’ve signed up. <u>Learn more.</u>]]></string>

    <!-- Array with whitespace preservation -->
    <string-array name="mixed_items">
        <item>  Item with spaces  </item>
        <item>    </item>
    </string-array>

    <!-- Non-translatable test resources (will not appear in target locales) -->
    <string-array name="non_localised_array" translatable="false">
        <item>Ignored</item>
    </string-array>

    <plurals name="non_localised_plural" translatable="false">
        <item quantity="one">Ignored</item>
        <item quantity="other">Ignored</item>
    </plurals>

    <!-- Colors - will not be translated (copied as-is to target locales) -->
    <color name="primary_color">#FF6200EE</color>
    <color name="secondary_color">#FF03DAC5</color>

    <!-- Dimensions - will not be translated (copied as-is to target locales) -->
    <dimen name="text_size">16sp</dimen>
    <dimen name="margin">8dp</dimen>

    <!-- Integer arrays - will not be translated (copied as-is to target locales) -->
    <integer-array name="numbers">
        <item>1</item>
        <item>2</item>
        <item>3</item>
    </integer-array>

    <!-- Typed arrays - will not be translated (copied as-is to target locales) -->
    <array name="icons">
        <item>@drawable/icon1</item>
        <item>@drawable/icon2</item>
    </array>

    <!-- Resource IDs - will not be translated (copied as-is to target locales) -->
    <item type="id" name="button_ok" />

</resources>
```

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

```typescript
import { Command } from "interactive-commander";
import createOra from "ora";
import { getSettings } from "../../utils/settings";
import { createAuthenticator } from "../../utils/auth";
import { IIntegrationFlow } from "./flows/_base";
import { PullRequestFlow } from "./flows/pull-request";
import { InBranchFlow } from "./flows/in-branch";
import { getPlatformKit } from "./platforms";

interface CIOptions {
  parallel?: boolean;
  apiKey?: string;
  debug?: boolean;
  pullRequest?: boolean;
  commitMessage?: string;
  pullRequestTitle?: string;
  workingDirectory?: string;
  processOwnCommits?: boolean;
}

export default new Command()
  .command("ci")
  .description("Run localization pipeline in CI/CD environment")
  .helpOption("-h, --help", "Show help")
  .option(
    "--parallel [boolean]",
    "Process translations concurrently for faster execution. Defaults to false",
    parseBooleanArg,
  )
  .option(
    "--api-key <key>",
    "Override API key from settings or environment variables",
  )
  .option(
    "--pull-request [boolean]",
    "Create or update translations on a dedicated branch and manage pull requests automatically. When false, commits directly to current branch. Defaults to false",
    parseBooleanArg,
  )
  .option(
    "--commit-message <message>",
    "Commit message for localization changes. Defaults to 'feat: update translations via @lingodotdev'",
  )
  .option(
    "--pull-request-title <title>",
    "Title for the pull request when using --pull-request mode. Defaults to 'feat: update translations via @lingodotdev'",
  )
  .option(
    "--working-directory <dir>",
    "Directory to run localization from (useful for monorepos where localization files are in a subdirectory)",
  )
  .option(
    "--process-own-commits [boolean]",
    "Allow processing commits made by this CI user (bypasses infinite loop prevention)",
    parseBooleanArg,
  )
  .action(async (options: CIOptions) => {
    const settings = getSettings(options.apiKey);

    console.log(options);

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

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

    if (!auth) {
      console.error("Not authenticated");
      return;
    }

    const env = {
      LINGODOTDEV_API_KEY: settings.auth.apiKey,
      LINGODOTDEV_PULL_REQUEST: options.pullRequest?.toString() || "false",
      ...(options.commitMessage && {
        LINGODOTDEV_COMMIT_MESSAGE: options.commitMessage,
      }),
      ...(options.pullRequestTitle && {
        LINGODOTDEV_PULL_REQUEST_TITLE: options.pullRequestTitle,
      }),
      ...(options.workingDirectory && {
        LINGODOTDEV_WORKING_DIRECTORY: options.workingDirectory,
      }),
      ...(options.processOwnCommits && {
        LINGODOTDEV_PROCESS_OWN_COMMITS: options.processOwnCommits.toString(),
      }),
    };

    process.env = { ...process.env, ...env };

    const ora = createOra();
    const platformKit = getPlatformKit();
    const { isPullRequestMode } = platformKit.config;

    ora.info(`Pull request mode: ${isPullRequestMode ? "on" : "off"}`);

    const flow: IIntegrationFlow = isPullRequestMode
      ? new PullRequestFlow(ora, platformKit)
      : new InBranchFlow(ora, platformKit);

    const canRun = await flow.preRun?.();
    if (canRun === false) {
      return;
    }

    const hasChanges = await flow.run({
      parallel: options.parallel,
    });
    if (!hasChanges) {
      return;
    }

    await flow.postRun?.();
  });

function parseBooleanArg(val: string | boolean | undefined): boolean {
  if (val === true) return true;
  if (typeof val === "string") {
    return val.toLowerCase() === "true";
  }
  return false;
}

```

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

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

/**
 * Gets a map of all JSX attributes from a JSX element
 *
 * @param nodePath The JSX element node path
 * @returns A record mapping attribute names to their values
 */
export function getJsxAttributesMap(
  nodePath: NodePath<t.JSXElement>,
): Record<string, any> {
  const attributes = nodePath.node.openingElement.attributes;

  return _.reduce(
    attributes,
    (result, attr) => {
      if (attr.type !== "JSXAttribute" || attr.name.type !== "JSXIdentifier") {
        return result;
      }

      const name = attr.name.name;
      const value = extractAttributeValue(attr);

      return { ...result, [name]: value };
    },
    {} as Record<string, any>,
  );
}

/**
 * Gets the value of a JSX attribute from a JSX element
 *
 * @param nodePath The JSX element node path
 * @param attributeName The name of the attribute to get
 * @returns The attribute value or undefined if not found
 */
export function getJsxAttributeValue(
  nodePath: NodePath<t.JSXElement>,
  attributeName: string,
) {
  const attributes = nodePath.node.openingElement.attributes;
  const attribute = _.find(
    attributes,
    (attr): attr is t.JSXAttribute =>
      attr.type === "JSXAttribute" &&
      attr.name.type === "JSXIdentifier" &&
      attr.name.name === attributeName,
  );

  if (!attribute) {
    return undefined;
  }

  return extractAttributeValue(attribute);
}

/**
 * Sets the value of a JSX attribute on a JSX element
 *
 * @param nodePath The JSX element node path
 * @param attributeName The name of the attribute to set
 * @param value The value to set (string, number, boolean, expression, or null for boolean attributes)
 */
export function setJsxAttributeValue(
  nodePath: NodePath<t.JSXElement>,
  attributeName: string,
  value: any,
) {
  const attributes = nodePath.node.openingElement.attributes;
  const attributeIndex = _.findIndex(
    attributes,
    (attr) =>
      attr.type === "JSXAttribute" &&
      attr.name.type === "JSXIdentifier" &&
      attr.name.name === attributeName,
  );

  const jsxValue = createAttributeValue(value);
  const jsxAttribute = t.jsxAttribute(t.jsxIdentifier(attributeName), jsxValue);

  if (attributeIndex >= 0) {
    attributes[attributeIndex] = jsxAttribute;
  } else {
    attributes.push(jsxAttribute);
  }
}

/**
 * Extracts the value from a JSX attribute
 */
function extractAttributeValue(attribute: t.JSXAttribute) {
  if (!attribute.value) {
    return true; // Boolean attribute
  }

  if (attribute.value.type === "StringLiteral") {
    return attribute.value.value;
  }

  if (attribute.value.type === "JSXExpressionContainer") {
    const expression = attribute.value.expression;

    if (expression.type === "BooleanLiteral") {
      return expression.value;
    }

    if (expression.type === "NumericLiteral") {
      return expression.value;
    }

    if (expression.type === "StringLiteral") {
      return expression.value;
    }
  }
  // We could return the raw expression for other types
  return null;
}

/**
 * Creates an appropriate JSX attribute value based on the input value
 */
function createAttributeValue(
  value: any,
): t.StringLiteral | t.JSXExpressionContainer | null {
  if (value === null || value === undefined) {
    return null;
  }

  if (typeof value === "string") {
    return t.stringLiteral(value);
  }

  if (typeof value === "boolean") {
    return t.jsxExpressionContainer(t.booleanLiteral(value));
  }

  if (typeof value === "number") {
    return t.jsxExpressionContainer(t.numericLiteral(value));
  }

  if (t.isExpression(value)) {
    return t.jsxExpressionContainer(value);
  }

  // For complex objects/arrays, convert to expression
  return t.jsxExpressionContainer(t.stringLiteral(JSON.stringify(value)));
}

```

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

```typescript
import { createCodeMutation } from "./_base";
import {
  getJsxAttributeValue,
  getModuleExecutionMode,
  getOrCreateImport,
} from "./utils";
import * as t from "@babel/types";
import _ from "lodash";
import { ModuleId } from "./_const";
import { getJsxElementName, getNestedJsxElements } from "./utils/jsx-element";
import { getJsxVariables } from "./utils/jsx-variables";
import { getJsxFunctions } from "./utils/jsx-functions";
import { getJsxExpressions } from "./utils/jsx-expressions";
import { collectJsxScopes, getJsxScopeAttribute } from "./utils/jsx-scope";
import { setJsxAttributeValue } from "./utils/jsx-attribute";

export const lingoJsxScopeInjectMutation = createCodeMutation((payload) => {
  const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
  const jsxScopes = collectJsxScopes(payload.ast);

  for (const jsxScope of jsxScopes) {
    const skip = getJsxAttributeValue(jsxScope, "data-lingo-skip");
    if (skip) {
      continue;
    }
    // Import LingoComponent based on the module execution mode
    const packagePath =
      mode === "client" ? ModuleId.ReactClient : ModuleId.ReactRSC;
    const lingoComponentImport = getOrCreateImport(payload.ast, {
      moduleName: packagePath,
      exportedName: "LingoComponent",
    });

    // Get the original JSX element name
    const originalJsxElementName = getJsxElementName(jsxScope);
    if (!originalJsxElementName) {
      continue;
    }

    // Create new JSXElement with original attributes
    const newNode = t.jsxElement(
      t.jsxOpeningElement(
        t.jsxIdentifier(lingoComponentImport.importedName),
        jsxScope.node.openingElement.attributes.slice(), // original attributes
        true, // selfClosing
      ),
      null, // no closing element
      [], // no children
      true, // selfClosing
    );

    // Create a NodePath wrapper for the new node to use setJsxAttributeValue
    const newNodePath = {
      node: newNode,
    } as any;

    // Add $as prop
    const as = /^[A-Z]/.test(originalJsxElementName)
      ? t.identifier(originalJsxElementName)
      : originalJsxElementName;
    setJsxAttributeValue(newNodePath, "$as", as);

    // Add $fileKey prop
    setJsxAttributeValue(newNodePath, "$fileKey", payload.relativeFilePath);

    // Add $entryKey prop
    setJsxAttributeValue(
      newNodePath,
      "$entryKey",
      getJsxScopeAttribute(jsxScope)!,
    );

    // Extract $variables from original JSX scope before lingo component was inserted
    const $variables = getJsxVariables(jsxScope);
    if ($variables.properties.length > 0) {
      setJsxAttributeValue(newNodePath, "$variables", $variables);
    }

    // Extract nested JSX elements
    const $elements = getNestedJsxElements(jsxScope);
    if ($elements.elements.length > 0) {
      setJsxAttributeValue(newNodePath, "$elements", $elements);
    }

    // Extract nested functions
    const $functions = getJsxFunctions(jsxScope);
    if ($functions.properties.length > 0) {
      setJsxAttributeValue(newNodePath, "$functions", $functions);
    }

    // Extract expressions
    const $expressions = getJsxExpressions(jsxScope);
    if ($expressions.elements.length > 0) {
      setJsxAttributeValue(newNodePath, "$expressions", $expressions);
    }

    if (mode === "server") {
      // Add $loadDictionary prop
      const loadDictionaryImport = getOrCreateImport(payload.ast, {
        exportedName: "loadDictionary",
        moduleName: ModuleId.ReactRSC,
      });
      setJsxAttributeValue(
        newNodePath,
        "$loadDictionary",
        t.arrowFunctionExpression(
          [t.identifier("locale")],
          t.callExpression(t.identifier(loadDictionaryImport.importedName), [
            t.identifier("locale"),
          ]),
        ),
      );
    }

    jsxScope.replaceWith(newNode);
  }

  return payload;
});

```

--------------------------------------------------------------------------------
/packages/react/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
# @lingo.dev/\_react

## 0.5.0

### Minor Changes

- [#1134](https://github.com/lingodotdev/lingo.dev/pull/1134) [`3a642f3`](https://github.com/lingodotdev/lingo.dev/commit/3a642f33c04378706a8382aa0fde36e747fd6af5) Thanks [@mathio](https://github.com/mathio)! - useLingoLocale, setLingoLocale

## 0.4.3

### Patch Changes

- [#1119](https://github.com/lingodotdev/lingo.dev/pull/1119) [`e898c1e`](https://github.com/lingodotdev/lingo.dev/commit/e898c1eeb34e4dd3e74df26465802b520018acf9) Thanks [@mathio](https://github.com/mathio)! - compiler fallback to source locale

## 0.4.2

### Patch Changes

- [#1054](https://github.com/lingodotdev/lingo.dev/pull/1054) [`2d67369`](https://github.com/lingodotdev/lingo.dev/commit/2d673697b9cf4d91de2f48444581f8b3fd894cd6) Thanks [@davidturnbull](https://github.com/davidturnbull)! - Fix loadLocaleFromCookies to return default locale instead of null when no cookie is found

## 0.4.1

### Patch Changes

- [#1011](https://github.com/lingodotdev/lingo.dev/pull/1011) [`bfcb424`](https://github.com/lingodotdev/lingo.dev/commit/bfcb424eb4479d0d3b767e062d30f02c5bcaeb14) Thanks [@mathio](https://github.com/mathio)! - replace elements with dot in name

## 0.4.0

### Minor Changes

- [`95c23cc`](https://github.com/lingodotdev/lingo.dev/commit/95c23ccbafd335939832dbdd0f995ebcb23082fd) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add className support to language switcher component

## 0.3.0

### Minor Changes

- [#897](https://github.com/lingodotdev/lingo.dev/pull/897) [`a5da697`](https://github.com/lingodotdev/lingo.dev/commit/a5da697f7efd46de31d17b202d06eb5f655ed9b9) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Add support for other providers in the compiler and implement Google AI as a provider.

## 0.2.4

### Patch Changes

- [#887](https://github.com/lingodotdev/lingo.dev/pull/887) [`511a2ec`](https://github.com/lingodotdev/lingo.dev/commit/511a2ecd68a9c5e2800035d5c6a6b5b31b2dc80f) Thanks [@mathio](https://github.com/mathio)! - handle when lingo dir is deleted

## 0.2.3

### Patch Changes

- [#883](https://github.com/lingodotdev/lingo.dev/pull/883) [`7191444`](https://github.com/lingodotdev/lingo.dev/commit/7191444f67864ea5b5a91a9be759b2445bf186d3) Thanks [@mathio](https://github.com/mathio)! - client-side loading state

## 0.2.2

### Patch Changes

- [#867](https://github.com/lingodotdev/lingo.dev/pull/867) [`a7bf553`](https://github.com/lingodotdev/lingo.dev/commit/a7bf5538b5b72e41f90371f6211378aac7d5f800) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Fix template substitution destructive shift() bug that caused rendering failures when translations have different element counts between locales

- [#868](https://github.com/lingodotdev/lingo.dev/pull/868) [`562e667`](https://github.com/lingodotdev/lingo.dev/commit/562e667471abb51d7dd193217eefb8e8b3f8a686) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - show dictionary error

## 0.2.1

### Patch Changes

- [`1f9db11`](https://github.com/lingodotdev/lingo.dev/commit/1f9db11a53d8c75ce0e83517b73d43544d0f0fd2) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add console log to lingoproviderwrapper

## 0.2.0

### Minor Changes

- [#838](https://github.com/lingodotdev/lingo.dev/pull/838) [`e75e615`](https://github.com/lingodotdev/lingo.dev/commit/e75e615ab17e279deb5a505dbda682fdfc7ead62) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - switch from tsup to unbuild

## 0.1.1

### Patch Changes

- [`caef325`](https://github.com/lingodotdev/lingo.dev/commit/caef3253bc99fa7bf7a0b40e5604c3590dcb4958) Thanks [@mathio](https://github.com/mathio)! - release fix

## 0.1.0

### Minor Changes

- [`e980e84`](https://github.com/lingodotdev/lingo.dev/commit/e980e84178439ad70417d38b425acf9148cfc4b6) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - added the compiler

```

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

```typescript
import { XMLParser, XMLBuilder } from "fast-xml-parser";
import _ from "lodash";

// Generic tag names used in XML output
const TAG_OBJECT = "object";
const TAG_ARRAY = "array";
const TAG_VALUE = "value";

/**
 * Converts a JavaScript value to a generic XML node structure understood by fast-xml-parser.
 */
function _toGenericNode(value: any, key?: string): Record<string, any> {
  if (_.isArray(value)) {
    const children = _.map(value, (item) => _toGenericNode(item));
    return {
      [TAG_ARRAY]: {
        ...(key ? { key } : {}),
        ..._groupChildren(children),
      },
    };
  }

  if (_.isPlainObject(value)) {
    const children = _.map(Object.entries(value), ([k, v]) =>
      _toGenericNode(v, k),
    );
    return {
      [TAG_OBJECT]: {
        ...(key ? { key } : {}),
        ..._groupChildren(children),
      },
    };
  }

  return {
    [TAG_VALUE]: {
      ...(key ? { key } : {}),
      "#text": value ?? "",
    },
  };
}

/**
 * Groups a list of nodes by their tag name so that fast-xml-parser outputs arrays even for single elements.
 */
function _groupChildren(nodes: Record<string, any>[]): Record<string, any> {
  return _(nodes)
    .groupBy((node) => Object.keys(node)[0])
    .mapValues((arr) => _.map(arr, (n) => n[Object.keys(n)[0]]))
    .value();
}

/**
 * Recursively converts a generic XML node back to a JavaScript value.
 */
function _fromGenericNode(tag: string, data: any): any {
  if (tag === TAG_VALUE) {
    // <value>123</value> without attributes is parsed as a primitive (number | string)
    // whereas <value key="id">123</value> is parsed as an object with a "#text" field.
    // Support both shapes.
    if (_.isPlainObject(data)) {
      return _.get(data, "#text", "");
    }
    return data ?? "";
  }

  if (tag === TAG_ARRAY) {
    const result: any[] = [];
    _.forEach([TAG_VALUE, TAG_OBJECT, TAG_ARRAY], (childTag) => {
      const childNodes = _.castArray(_.get(data, childTag, []));
      _.forEach(childNodes, (child) => {
        result.push(_fromGenericNode(childTag, child));
      });
    });
    return result;
  }

  // TAG_OBJECT
  const obj: Record<string, any> = {};
  _.forEach([TAG_VALUE, TAG_OBJECT, TAG_ARRAY], (childTag) => {
    const childNodes = _.castArray(_.get(data, childTag, []));
    _.forEach(childNodes, (child) => {
      const key = _.get(child, "key", "");
      obj[key] = _fromGenericNode(childTag, child);
    });
  });
  return obj;
}

export function obj2xml<T>(obj: T): string {
  const rootNode = _toGenericNode(obj)[TAG_OBJECT];
  const builder = new XMLBuilder({
    ignoreAttributes: false,
    attributeNamePrefix: "",
    format: true,
    suppressEmptyNode: true,
  });
  return builder.build({ [TAG_OBJECT]: rootNode });
}

export function xml2obj<T = any>(xml: string): T {
  const parser = new XMLParser({
    ignoreAttributes: false,
    attributeNamePrefix: "",
    parseTagValue: true,
    parseAttributeValue: false,
    processEntities: true,
    isArray: (name) => [TAG_VALUE, TAG_ARRAY, TAG_OBJECT].includes(name),
  });
  const parsed = parser.parse(xml);

  // The parser keeps the XML declaration (<?xml version="1.0"?>) under the
  // pseudo-tag "?xml". Skip it so that we always start the conversion at the
  // first real node (i.e. <object>, <array> or <value>).
  const withoutDeclaration = _.omit(parsed, "?xml");

  const rootTag = Object.keys(withoutDeclaration)[0];

  // fast-xml-parser treats every <object>, <array> and <value> element as an array
  // because we configured the `isArray` option above. This means even the root
  // element comes wrapped in an array. Unwrap it so that the recursive
  // conversion logic receives the actual node object instead of an array –
  // otherwise no children will be found and we would return an empty result.
  const rootNode = _.castArray(withoutDeclaration[rootTag])[0];

  return _fromGenericNode(rootTag, rootNode);
}

```

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

```typescript
import chalk from "chalk";
import figlet from "figlet";
import { vice } from "gradient-string";
import readline from "readline";
import { colors } from "../constants";

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

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

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

export async function renderHero() {
  console.log(
    `⚡️ ${chalk.hex(colors.green)(
      "Lingo.dev",
    )} - open-source, AI-powered i18n CLI for web & mobile localization.`,
  );
  console.log("");

  const label1 = "📚 Docs:";
  const label2 = "⭐ Star the repo:";
  const label3 = "🎮 Join Discord:";
  const maxLabelWidth = 17; // Approximate visual width accounting for emoji

  console.log(
    `${chalk.hex(colors.blue)(label1.padEnd(maxLabelWidth + 1))} ${chalk.hex(
      colors.blue,
    )("https://lingo.dev/go/docs")}`,
  ); // Docs emoji seems narrower
  console.log(
    `${chalk.hex(colors.blue)(label2.padEnd(maxLabelWidth))} ${chalk.hex(
      colors.blue,
    )("https://lingo.dev/go/gh")}`,
  );
  console.log(
    `${chalk.hex(colors.blue)(label3.padEnd(maxLabelWidth + 1))} ${chalk.hex(
      colors.blue,
    )("https://lingo.dev/go/discord")}`,
  );
}

export async function waitForUserPrompt(message: string): Promise<void> {
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  return new Promise((resolve) => {
    rl.question(chalk.dim(`[${message}]\n`), () => {
      rl.close();
      resolve();
    });
  });
}

export async function pauseIfDebug(debug: boolean) {
  if (debug) {
    await waitForUserPrompt("Press Enter to continue...");
  }
}

export async function renderSummary(results: Map<any, any>) {
  console.log(chalk.hex(colors.green)("[Done]"));

  const skippedResults = Array.from(results.values()).filter(
    (r) => r.status === "skipped",
  );
  const succeededResults = Array.from(results.values()).filter(
    (r) => r.status === "success",
  );
  const failedResults = Array.from(results.values()).filter(
    (r) => r.status === "error",
  );

  console.log(
    `• ${chalk.hex(colors.yellow)(skippedResults.length)} from cache`,
  );
  console.log(
    `• ${chalk.hex(colors.yellow)(succeededResults.length)} processed`,
  );
  console.log(`• ${chalk.hex(colors.yellow)(failedResults.length)} failed`);

  // Show processed files
  if (succeededResults.length > 0) {
    console.log(chalk.hex(colors.green)("\n[Processed Files]"));
    for (const result of succeededResults) {
      const displayPath =
        result.pathPattern?.replace("[locale]", result.targetLocale) ||
        "unknown";
      console.log(
        `  ✓ ${chalk.dim(displayPath)} ${chalk.hex(colors.yellow)(`(${result.sourceLocale} → ${result.targetLocale})`)}`,
      );
    }
  }

  // Show cached files
  if (skippedResults.length > 0) {
    console.log(chalk.hex(colors.blue)("\n[Cached Files]"));
    for (const result of skippedResults) {
      const displayPath =
        result.pathPattern?.replace("[locale]", result.targetLocale) ||
        "unknown";
      console.log(
        `  ⚡ ${chalk.dim(displayPath)} ${chalk.hex(colors.yellow)(`(${result.sourceLocale} → ${result.targetLocale})`)}`,
      );
    }
  }

  // Show failed files
  if (failedResults.length > 0) {
    console.log(chalk.hex(colors.orange)("\n[Failed Files]"));
    for (const result of failedResults) {
      const displayPath =
        result.pathPattern?.replace("[locale]", result.targetLocale) ||
        "unknown";
      console.log(
        `  ❌ ${chalk.dim(displayPath)} ${chalk.hex(colors.yellow)(`(${result.sourceLocale} → ${result.targetLocale})`)}`,
      );
      console.log(
        `     ${chalk.hex(colors.white)(String(result.error?.message || "Unknown error"))}`,
      );
    }
  }
}

```

--------------------------------------------------------------------------------
/scripts/docs/src/generate-config-docs.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node

import { LATEST_CONFIG_DEFINITION } from "@lingo.dev/_spec/src/config";
import type { Root } from "mdast";
import { mkdirSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import remarkStringify from "remark-stringify";
import { unified } from "unified";
import { zodToJsonSchema } from "zod-to-json-schema";
import { renderMarkdown } from "./json-schema/markdown-renderer";
import { parseSchema } from "./json-schema/parser";
import type { JSONSchemaObject } from "./json-schema/types";
import { createOrUpdateGitHubComment, formatMarkdown } from "./utils";

const ROOT_PROPERTY_ORDER = ["$schema", "version", "locale", "buckets"];

function generateMarkdown(schema: unknown): string {
  if (!schema || typeof schema !== "object") {
    throw new Error("Invalid schema provided");
  }

  // Ensure the `version` property reflects the latest schema version in docs
  const schemaObj = schema as JSONSchemaObject;
  const rootRef = schemaObj.$ref as string | undefined;
  const rootName: string = rootRef
    ? (rootRef.split("/").pop() ?? "I18nConfig")
    : "I18nConfig";

  let rootSchema: unknown;
  if (
    rootRef &&
    schemaObj.definitions &&
    typeof schemaObj.definitions === "object"
  ) {
    const definitions = schemaObj.definitions as Record<string, unknown>;
    rootSchema = definitions[rootName];
  } else {
    rootSchema = schema;
  }

  if (rootSchema && typeof rootSchema === "object") {
    const rootSchemaObj = rootSchema as JSONSchemaObject;
    if (
      rootSchemaObj.properties &&
      typeof rootSchemaObj.properties === "object"
    ) {
      const properties = rootSchemaObj.properties as Record<string, unknown>;
      if (properties.version && typeof properties.version === "object") {
        (properties.version as Record<string, unknown>).default =
          LATEST_CONFIG_DEFINITION.defaultValue.version;
      }
    }
  }

  const properties = parseSchema(schema, { customOrder: ROOT_PROPERTY_ORDER });
  return renderMarkdown(properties);
}

async function main() {
  const commentMarker = "<!-- generate-config-docs -->";
  const isGitHubAction = Boolean(process.env.GITHUB_ACTIONS);

  const outputArg = process.argv[2];

  const schema = zodToJsonSchema(LATEST_CONFIG_DEFINITION.schema, {
    name: "I18nConfig",
    markdownDescription: true,
  });

  console.log("🔄 Generating i18n.json reference docs...");
  const markdown = generateMarkdown(schema);
  const formattedMarkdown = await formatMarkdown(markdown);

  if (isGitHubAction) {
    const mdast: Root = {
      type: "root",
      children: [
        { type: "html", value: commentMarker },
        {
          type: "paragraph",
          children: [
            {
              type: "text",
              value:
                "Your PR affects the Lingo.dev i18n.json configuration schema and may affect the auto-generated reference documentation. Please review the output below to ensure that the changes are correct.",
            },
          ],
        },
        { type: "html", value: "<details>" },
        {
          type: "html",
          value: "<summary>i18n.json reference docs</summary>",
        },
        { type: "code", lang: "markdown", value: formattedMarkdown },
        { type: "html", value: "</details>" },
      ],
    };
    const body = unified()
      .use([[remarkStringify, { fence: "~" }]])
      .stringify(mdast)
      .toString();
    await createOrUpdateGitHubComment({
      commentMarker,
      body,
    });
    return;
  }

  if (!outputArg) {
    throw new Error(
      "Output file path is required. Usage: generate-config-docs <output-path>",
    );
  }

  const outputFilePath = resolve(process.cwd(), outputArg);
  console.log(`💾 Saving to ${outputFilePath}...`);
  mkdirSync(dirname(outputFilePath), { recursive: true });
  writeFileSync(outputFilePath, formattedMarkdown);
  console.log(`✅ Saved to ${outputFilePath}`);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

```

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

```typescript
import { execSync } from "child_process";
import bbLib from "bitbucket";
import Z from "zod";
import { PlatformKit } from "./_base";

const { Bitbucket } = bbLib;

interface BitbucketConfig {
  baseBranchName: string;
  repositoryOwner: string;
  repositoryName: string;
  bbToken?: string;
}

export class BitbucketPlatformKit extends PlatformKit<BitbucketConfig> {
  private _bb?: ReturnType<typeof Bitbucket>;

  private get bb() {
    if (!this._bb) {
      this._bb = new Bitbucket({
        auth: { token: this.platformConfig.bbToken || "" },
      });
    }
    return this._bb;
  }

  async branchExists({ branch }: { branch: string }) {
    return await this.bb.repositories
      .getBranch({
        workspace: this.platformConfig.repositoryOwner,
        repo_slug: this.platformConfig.repositoryName,
        name: branch,
      })
      .then((r) => r.data)
      .then((v) => !!v)
      .catch((r) => (r.status === 404 ? false : Promise.reject(r)));
  }

  async getOpenPullRequestNumber({ branch }: { branch: string }) {
    return await this.bb.repositories
      .listPullRequests({
        workspace: this.platformConfig.repositoryOwner,
        repo_slug: this.platformConfig.repositoryName,
        state: "OPEN",
      })
      .then(({ data: { values } }) => {
        // TODO: we might need to handle pagination in future
        // bitbucket API does not support filtering pull requests
        // https://developer.atlassian.com/cloud/bitbucket/rest/api-group-pullrequests/#api-repositories-workspace-repo-slug-pullrequests-get
        return values?.find(
          ({ source, destination }) =>
            source?.branch?.name === branch &&
            destination?.branch?.name === this.platformConfig.baseBranchName,
        );
      })
      .then((pr) => pr?.id);
  }

  async closePullRequest({ pullRequestNumber }: { pullRequestNumber: number }) {
    await this.bb.repositories.declinePullRequest({
      workspace: this.platformConfig.repositoryOwner,
      repo_slug: this.platformConfig.repositoryName,
      pull_request_id: pullRequestNumber,
    });
  }

  async createPullRequest({
    title,
    body,
    head,
  }: {
    title: string;
    body?: string;
    head: string;
  }) {
    return await this.bb.repositories
      .createPullRequest({
        workspace: this.platformConfig.repositoryOwner,
        repo_slug: this.platformConfig.repositoryName,
        _body: {
          title,
          description: body,
          source: { branch: { name: head } },
          destination: { branch: { name: this.platformConfig.baseBranchName } },
        } as any,
      })
      .then(({ data }) => data.id ?? 0);
  }

  async commentOnPullRequest({
    pullRequestNumber,
    body,
  }: {
    pullRequestNumber: number;
    body: string;
  }) {
    await this.bb.repositories.createPullRequestComment({
      workspace: this.platformConfig.repositoryOwner,
      repo_slug: this.platformConfig.repositoryName,
      pull_request_id: pullRequestNumber,
      _body: {
        content: {
          raw: body,
        },
      } as any,
    });
  }

  async gitConfig() {
    execSync("git config --unset http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy", {
      stdio: "inherit",
    });
    execSync(
      "git config http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy http://host.docker.internal:29418/",
      {
        stdio: "inherit",
      },
    );
  }

  get platformConfig() {
    const env = Z.object({
      BITBUCKET_BRANCH: Z.string(),
      BITBUCKET_REPO_FULL_NAME: Z.string(),
      BB_TOKEN: Z.string().optional(),
    }).parse(process.env);

    const [repositoryOwner, repositoryName] =
      env.BITBUCKET_REPO_FULL_NAME.split("/");

    return {
      baseBranchName: env.BITBUCKET_BRANCH,
      repositoryOwner,
      repositoryName,
      bbToken: env.BB_TOKEN,
    };
  }

  buildPullRequestUrl(pullRequestNumber: number) {
    const { repositoryOwner, repositoryName } = this.platformConfig;
    return `https://bitbucket.org/${repositoryOwner}/${repositoryName}/pull-requests/${pullRequestNumber}`;
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/ci/flows/in-branch.ts:
--------------------------------------------------------------------------------

```typescript
import { execSync } from "child_process";
import path from "path";
import {
  gitConfig,
  IntegrationFlow,
  escapeShellArg,
  IIntegrationFlowOptions,
} from "./_base";
import i18nCmd from "../../i18n";
import runCmd from "../../run";

export class InBranchFlow extends IntegrationFlow {
  async preRun() {
    this.ora.start("Configuring git");
    const canContinue = this.configureGit();
    this.ora.succeed("Git configured");

    return canContinue;
  }

  async run(options: IIntegrationFlowOptions) {
    this.ora.start("Running Lingo.dev");
    await this.runLingoDotDev(options.parallel);
    this.ora.succeed("Done running Lingo.dev");

    execSync(`rm -f i18n.cache`, { stdio: "inherit" }); // do not commit cache file if it exists

    this.ora.start("Checking for changes");
    const hasChanges = this.checkCommitableChanges();
    this.ora.succeed(hasChanges ? "Changes detected" : "No changes detected");

    if (hasChanges) {
      this.ora.start("Committing changes");
      execSync(`git add .`, { stdio: "inherit" });
      execSync(`git status --porcelain`, { stdio: "inherit" });
      execSync(
        `git commit -m ${escapeShellArg(
          this.platformKit.config.commitMessage,
        )} --no-verify`,
        {
          stdio: "inherit",
        },
      );
      this.ora.succeed("Changes committed");

      this.ora.start("Pushing changes to remote");
      const currentBranch =
        this.i18nBranchName ?? this.platformKit.platformConfig.baseBranchName;
      execSync(
        `git push origin ${currentBranch} ${options.force ? "--force" : ""}`,
        {
          stdio: "inherit",
        },
      );
      this.ora.succeed("Changes pushed to remote");
    }

    return hasChanges;
  }

  protected checkCommitableChanges() {
    return (
      execSync('git status --porcelain || echo "has_changes"', {
        encoding: "utf8",
      }).length > 0
    );
  }

  private async runLingoDotDev(isParallel?: boolean) {
    try {
      if (!isParallel) {
        await i18nCmd
          .exitOverride()
          .parseAsync(["--api-key", this.platformKit.config.replexicaApiKey], {
            from: "user",
          });
      } else {
        await runCmd
          .exitOverride()
          .parseAsync(["--api-key", this.platformKit.config.replexicaApiKey], {
            from: "user",
          });
      }
    } catch (err: any) {
      if (err.code === "commander.helpDisplayed") return;
      throw err;
    }
  }

  private configureGit() {
    const { processOwnCommits } = this.platformKit.config;
    const { baseBranchName } = this.platformKit.platformConfig;

    this.ora.info(`Current working directory:`);
    execSync(`pwd`, { stdio: "inherit" });
    execSync(`ls -la`, { stdio: "inherit" });

    execSync(`git config --global safe.directory ${process.cwd()}`);

    execSync(`git config user.name "${gitConfig.userName}"`);
    execSync(`git config user.email "${gitConfig.userEmail}"`);

    // perform platform-specific configuration before fetching or pushing to the remote
    this.platformKit?.gitConfig();

    execSync(`git fetch origin ${baseBranchName}`, { stdio: "inherit" });
    execSync(`git checkout ${baseBranchName} --`, { stdio: "inherit" });

    if (!processOwnCommits) {
      const currentAuthor = `${gitConfig.userName} <${gitConfig.userEmail}>`;
      const authorOfLastCommit = execSync(
        `git log -1 --pretty=format:'%an <%ae>'`,
      ).toString();
      if (authorOfLastCommit === currentAuthor) {
        this.ora.warn(
          `The last commit was already made by ${currentAuthor}, so this run will be skipped, as running again would have no effect. See docs: https://lingo.dev/ci`,
        );
        return false;
      }
    }

    const workingDir = path.resolve(
      process.cwd(),
      this.platformKit.config.workingDir,
    );
    if (workingDir !== process.cwd()) {
      this.ora.info(
        `Changing to working directory: ${this.platformKit.config.workingDir}`,
      );
      process.chdir(workingDir);
    }

    return true;
  }
}

```

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

```typescript
import { I18nConfig } from "@lingo.dev/_spec";
import chalk from "chalk";
import dedent from "dedent";
import { LocalizerFn } from "./_base";
import { createLingoLocalizer } from "./lingo";
import { createBasicTranslator } from "./basic";
import { createOpenAI } from "@ai-sdk/openai";
import { colors } from "../constants";
import { createAnthropic } from "@ai-sdk/anthropic";
import { createGoogleGenerativeAI } from "@ai-sdk/google";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { createMistral } from "@ai-sdk/mistral";
import { createOllama } from "ollama-ai-provider";

export default function createProcessor(
  provider: I18nConfig["provider"],
  params: { apiKey?: string; apiUrl: string },
): LocalizerFn {
  if (!provider) {
    const result = createLingoLocalizer(params);
    return result;
  } else {
    const model = getPureModelProvider(provider);
    const settings = provider.settings || {};
    const result = createBasicTranslator(model, provider.prompt, settings);
    return result;
  }
}

function getPureModelProvider(provider: I18nConfig["provider"]) {
  const createMissingKeyErrorMessage = (
    providerId: string,
    envVar?: string,
  ) => dedent`
  You're trying to use raw ${chalk.dim(providerId)} API for translation. ${
    envVar
      ? `However, ${chalk.dim(envVar)} environment variable is not set.`
      : "However, that provider is unavailable."
  }

  To fix this issue:
  1. ${
    envVar
      ? `Set ${chalk.dim(envVar)} in your environment variables`
      : "Set the environment variable for your provider (if required)"
  }, or
  2. Remove the ${chalk.italic(
    "provider",
  )} node from your i18n.json configuration to switch to ${chalk.hex(
    colors.green,
  )("Lingo.dev")}

  ${chalk.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
`;

  const createUnsupportedProviderErrorMessage = (providerId?: string) =>
    dedent`
  You're trying to use unsupported provider: ${chalk.dim(providerId)}.

  To fix this issue:
  1. Switch to one of the supported providers, or
  2. Remove the ${chalk.italic(
    "provider",
  )} node from your i18n.json configuration to switch to ${chalk.hex(
    colors.green,
  )("Lingo.dev")}

  ${chalk.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
  `;

  switch (provider?.id) {
    case "openai": {
      if (!process.env.OPENAI_API_KEY) {
        throw new Error(
          createMissingKeyErrorMessage("OpenAI", "OPENAI_API_KEY"),
        );
      }
      return createOpenAI({
        apiKey: process.env.OPENAI_API_KEY,
        baseURL: provider.baseUrl,
      })(provider.model);
    }
    case "anthropic": {
      if (!process.env.ANTHROPIC_API_KEY) {
        throw new Error(
          createMissingKeyErrorMessage("Anthropic", "ANTHROPIC_API_KEY"),
        );
      }
      return createAnthropic({
        apiKey: process.env.ANTHROPIC_API_KEY,
      })(provider.model);
    }
    case "google": {
      if (!process.env.GOOGLE_API_KEY) {
        throw new Error(
          createMissingKeyErrorMessage("Google", "GOOGLE_API_KEY"),
        );
      }
      return createGoogleGenerativeAI({
        apiKey: process.env.GOOGLE_API_KEY,
      })(provider.model);
    }
    case "openrouter": {
      if (!process.env.OPENROUTER_API_KEY) {
        throw new Error(
          createMissingKeyErrorMessage("OpenRouter", "OPENROUTER_API_KEY"),
        );
      }
      return createOpenRouter({
        apiKey: process.env.OPENROUTER_API_KEY,
        baseURL: provider.baseUrl,
      })(provider.model);
    }
    case "ollama": {
      // No API key check needed for Ollama
      return createOllama()(provider.model);
    }
    case "mistral": {
      if (!process.env.MISTRAL_API_KEY) {
        throw new Error(
          createMissingKeyErrorMessage("Mistral", "MISTRAL_API_KEY"),
        );
      }
      return createMistral({
        apiKey: process.env.MISTRAL_API_KEY,
        baseURL: provider.baseUrl,
      })(provider.model);
    }
    default: {
      throw new Error(createUnsupportedProviderErrorMessage(provider?.id));
    }
  }
}

```

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

```typescript
import { describe, it, expect } from "vitest";
import { createPayload, createOutput } from "../_base";
import * as t from "@babel/types";
import {
  getJsxRoots,
  isGoodJsxText,
  getOrCreateImport,
  hasI18nDirective,
  hasClientDirective,
  hasServerDirective,
  getModuleExecutionMode,
} from "./index";

function parse(code: string) {
  return createPayload({ code, params: {} as any, relativeFilePath: "x.tsx" })
    .ast as unknown as t.Node;
}

describe("getOrCreateImport", () => {
  it("inserts import when missing and reuses existing import when present", () => {
    const ast = parse(`export const X = 1;`);
    const res1 = getOrCreateImport(ast, {
      exportedName: "Fragment",
      moduleName: ["react"],
    });
    expect(res1.importedName).toBe("Fragment");
    const code1 = createOutput({
      code: "",
      ast,
      params: {} as any,
      relativeFilePath: "x.tsx",
    }).code;
    expect(code1).toMatch(/import\s*\{\s*Fragment\s*\}\s*from\s*["']react["']/);

    // Call again should reuse the same import and not duplicate
    const res2 = getOrCreateImport(ast, {
      exportedName: "Fragment",
      moduleName: ["react"],
    });
    expect(res2.importedName).toBe("Fragment");
    const code2 = createOutput({
      code: "",
      ast,
      params: {} as any,
      relativeFilePath: "x.tsx",
    }).code;
    const matches =
      code2.match(/import\s*\{\s*Fragment\s*\}\s*from\s*["']react["']/g) || [];
    expect(matches.length).toBe(1);
  });
});

describe("getJsxRoots", () => {
  it("returns only top-level JSX roots", () => {
    const ast = parse(`const X = () => (<div><span>Hello</span></div>);`);
    const roots = getJsxRoots(ast);
    expect(roots.length).toBe(1);
  });
});

describe("isGoodJsxText", () => {
  it("detects non-empty JSXText", () => {
    const payload = createPayload({
      code: `const X = () => (<div> Hello </div>);`,
      params: {} as any,
      relativeFilePath: "x.tsx",
    });
    let textPath: any;
    // locate JSXText
    require("@babel/traverse").default(payload.ast, {
      JSXText(p: any) {
        if (!textPath) textPath = p;
      },
    });
    expect(isGoodJsxText(textPath)).toBe(true);
  });
});

describe("hasI18nDirective", () => {
  it("returns true when file has use i18n directive", () => {
    const ast = parse(`"use i18n"; export const X = 1;`);
    expect(hasI18nDirective(ast)).toBe(true);
  });

  it("returns false when file does not have use i18n directive", () => {
    const ast = parse(`export const X = 1;`);
    expect(hasI18nDirective(ast)).toBe(false);
  });
});

describe("hasClientDirective", () => {
  it("returns true when file has use client directive", () => {
    const ast = parse(`"use client"; export const X = 1;`);
    expect(hasClientDirective(ast)).toBe(true);
  });

  it("returns false when file does not have use client directive", () => {
    expect(hasClientDirective(parse(`const X = 1;`))).toBe(false);
    expect(hasClientDirective(parse(`"use server"; const X=1;`))).toBe(false);
  });
});

describe("hasServerDirective", () => {
  it("returns true when file has use server directive", () => {
    const ast = parse(`"use server"; export const X = 1;`);
    expect(hasServerDirective(ast)).toBe(true);
  });

  it("returns false when file does not have use server directive", () => {
    expect(hasServerDirective(parse(`const X = 1;`))).toBe(false);
    expect(hasServerDirective(parse(`"use client"; const X=1;`))).toBe(false);
  });
});

describe("getModuleExecutionMode", () => {
  it("returns server by default when RSC enabled and no client directive", () => {
    const ast = parse(`export const X = 1;`);
    expect(getModuleExecutionMode(ast, true)).toBe("server");
  });

  it("returns client when use client directive present", () => {
    const ast = parse(`"use client"; export const X = 1;`);
    expect(getModuleExecutionMode(ast, true)).toBe("client");
  });

  it("returns client when RSC disabled", () => {
    const ast = parse(`export const X = 1;`);
    expect(getModuleExecutionMode(ast, false)).toBe("client");
  });
});

```

--------------------------------------------------------------------------------
/demo/vite-project/src/assets/react.svg:
--------------------------------------------------------------------------------

```
<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="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/json5.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, expect, it } from "vitest";
import createJson5Loader from "./json5";

describe("json5 loader", () => {
  it("pull should parse valid JSON5 format", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    const json5Input = `{
      // Comments are allowed in JSON5
      hello: "Hello",
      'single-quotes': 'work too',
      unquoted: 'keys work',
      trailing: 'comma is ok',
    }`;

    const result = await loader.pull("en", json5Input);
    expect(result).toEqual({
      hello: "Hello",
      "single-quotes": "work too",
      unquoted: "keys work",
      trailing: "comma is ok",
    });
  });

  it("pull should parse regular JSON as fallback", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    const jsonInput = '{"hello": "Hello", "world": "World"}';

    const result = await loader.pull("en", jsonInput);
    expect(result).toEqual({
      hello: "Hello",
      world: "World",
    });
  });

  it("pull should handle empty input", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    const result = await loader.pull("en", "");
    expect(result).toEqual({});
  });

  it("pull should handle null/undefined input", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    const result = await loader.pull("en", null as any);
    expect(result).toEqual({});
  });

  it("pull should handle JSON5 with multiline strings", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    const json5Input = `{
      multiline: "This is a \\
long string that \\
spans multiple lines"
    }`;

    const result = await loader.pull("en", json5Input);
    expect(result).toEqual({
      multiline: "This is a long string that spans multiple lines",
    });
  });

  it("pull should handle JSON5 with hexadecimal numbers", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    const json5Input = `{
      hex: 0xdecaf,
      positive: +123,
      negative: -456
    }`;

    const result = await loader.pull("en", json5Input);
    expect(result).toEqual({
      hex: 0xdecaf,
      positive: 123,
      negative: -456,
    });
  });

  it("pull should throw error for invalid JSON5", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    const invalidInput = `{
      hello: "Hello"
      world: "World" // missing comma
      invalid: syntax
    }`;

    await expect(loader.pull("en", invalidInput)).rejects.toThrow();
  });

  it("push should serialize data to JSON5 format", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    // Need to call pull first to initialize the loader state
    await loader.pull("en", "{}");

    const data = {
      hello: "Hello",
      world: "World",
      nested: {
        key: "value",
      },
    };

    const result = await loader.push("en", data);
    const expectedOutput = `{
  hello: 'Hello',
  world: 'World',
  nested: {
    key: 'value',
  },
}`;

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

  it("push should handle empty object", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    // Need to call pull first to initialize the loader state
    await loader.pull("en", "{}");

    const result = await loader.push("en", {});
    expect(result).toBe("{}");
  });

  it("push should handle complex nested data", async () => {
    const loader = createJson5Loader();
    loader.setDefaultLocale("en");
    // Need to call pull first to initialize the loader state
    await loader.pull("en", "{}");

    const data = {
      strings: ["hello", "world"],
      numbers: [1, 2, 3],
      nested: {
        deep: {
          key: "value",
        },
      },
    };

    const result = await loader.push("en", data);

    // Parse the result back to verify it's valid JSON5
    const JSON5 = await import("json5");
    const parsed = JSON5.default.parse(result);
    expect(parsed).toEqual(data);
  });
});

```

--------------------------------------------------------------------------------
/packages/locales/src/names/loader.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Data loader for locale names
 * Fetches CLDR data directly from GitHub raw URLs
 */

// Base URL for CLDR data from GitHub
const CLDR_BASE_URL =
  process.env.CLDR_BASE_URL ||
  "https://raw.githubusercontent.com/unicode-org/cldr-json/main/cldr-json/cldr-localenames-full/main";

interface NameData {
  [key: string]: string;
}

// Cache for loaded data to avoid repeated fetches
const cache = new Map<string, NameData>();

/**
 * Loads country/territory names for a specific display language
 */
export async function loadTerritoryNames(
  displayLanguage: string,
): Promise<NameData> {
  const cacheKey = `territories-${displayLanguage}`;

  if (cache.has(cacheKey)) {
    return cache.get(cacheKey)!;
  }

  try {
    // Fetch from GitHub raw URL
    const response = await fetch(
      `${CLDR_BASE_URL}/${displayLanguage}/territories.json`,
    );

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();
    const territories =
      data?.main?.[displayLanguage]?.localeDisplayNames?.territories || {};
    cache.set(cacheKey, territories);
    return territories;
  } catch (error) {
    // Fallback to English if the requested language is not available
    if (displayLanguage !== "en") {
      console.warn(
        `Failed to load territory names for ${displayLanguage}, falling back to English`,
      );
      return loadTerritoryNames("en");
    }
    throw new Error(
      `Failed to load territory names for ${displayLanguage}: ${error}`,
    );
  }
}

/**
 * Loads language names for a specific display language
 */
export async function loadLanguageNames(
  displayLanguage: string,
): Promise<NameData> {
  const cacheKey = `languages-${displayLanguage}`;

  if (cache.has(cacheKey)) {
    return cache.get(cacheKey)!;
  }

  try {
    // Fetch from GitHub raw URL
    const response = await fetch(
      `${CLDR_BASE_URL}/${displayLanguage}/languages.json`,
    );

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();
    const languages =
      data?.main?.[displayLanguage]?.localeDisplayNames?.languages || {};
    cache.set(cacheKey, languages);
    return languages;
  } catch (error) {
    // Fallback to English if the requested language is not available
    if (displayLanguage !== "en") {
      console.warn(
        `Failed to load language names for ${displayLanguage}, falling back to English`,
      );
      return loadLanguageNames("en");
    }
    throw new Error(
      `Failed to load language names for ${displayLanguage}: ${error}`,
    );
  }
}

/**
 * Loads script names for a specific display language
 */
export async function loadScriptNames(
  displayLanguage: string,
): Promise<NameData> {
  const cacheKey = `scripts-${displayLanguage}`;

  if (cache.has(cacheKey)) {
    return cache.get(cacheKey)!;
  }

  try {
    // Fetch from GitHub raw URL
    const response = await fetch(
      `${CLDR_BASE_URL}/${displayLanguage}/scripts.json`,
    );

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();
    const scripts =
      data?.main?.[displayLanguage]?.localeDisplayNames?.scripts || {};

    // Use longer form for Han scripts to match GitHub issue examples
    const enhancedScripts = { ...scripts };

    // Check for alternative Han script names
    if (scripts["Hans-alt-stand-alone"]) {
      enhancedScripts.Hans = scripts["Hans-alt-stand-alone"];
    }
    if (scripts["Hant-alt-stand-alone"]) {
      enhancedScripts.Hant = scripts["Hant-alt-stand-alone"];
    }

    cache.set(cacheKey, enhancedScripts);
    return enhancedScripts;
  } catch (error) {
    // Fallback to English if the requested language is not available
    if (displayLanguage !== "en") {
      console.warn(
        `Failed to load script names for ${displayLanguage}, falling back to English`,
      );
      return loadScriptNames("en");
    }
    throw new Error(
      `Failed to load script names for ${displayLanguage}: ${error}`,
    );
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/find-locale-paths.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { glob } from "glob";
import findLocaleFiles from "./find-locale-paths";

vi.mock("glob", () => ({
  glob: {
    sync: vi.fn(),
  },
}));

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

  it("should find json locale files", () => {
    vi.mocked(glob.sync).mockReturnValue([
      // valid locales
      "src/i18n/en.json",
      "src/i18n/fr.json",
      "src/i18n/en-US.json",
      "src/translations/es.json",

      // not a valid locale
      "src/xx.json",
      "src/settings.json",
    ]);

    const result = findLocaleFiles("json");

    expect(result).toEqual({
      patterns: ["src/i18n/[locale].json", "src/translations/[locale].json"],
      defaultPatterns: ["i18n/[locale].json"],
    });
  });

  it("should find yaml locale files", () => {
    vi.mocked(glob.sync).mockReturnValue([
      "locales/en.yml",
      "locales/fr.yml",
      "translations/es.yml",
    ]);

    const result = findLocaleFiles("yaml");

    expect(result).toEqual({
      patterns: ["locales/[locale].yml", "translations/[locale].yml"],
      defaultPatterns: ["i18n/[locale].yml"],
    });
  });

  it("should find flutter arb locale files", () => {
    vi.mocked(glob.sync).mockReturnValue([
      "lib/l10n/en.arb",
      "lib/l10n/es.arb",
      "lib/translations/fr.arb",
    ]);

    const result = findLocaleFiles("flutter");

    expect(result).toEqual({
      patterns: ["lib/l10n/[locale].arb", "lib/translations/[locale].arb"],
      defaultPatterns: ["i18n/[locale].arb"],
    });
  });

  it("should find locale files in nested directories", () => {
    vi.mocked(glob.sync).mockReturnValue([
      // valid locales
      "src/locales/en/messages.json",
      "src/locales/fr/messages.json",
      "src/i18n/es/strings.json",
      "src/translations/es.json",
      "src/aa/translations/en.json",
      "src/aa/bb/foobar/cc/translations/es/values.json",
      "src/aa/en.json",
      "src/aa/translations/bb/en.json",
      "foo/en-US/en-US.json",
      "foo/en-US/en-US/messages.json",
      "bar/es/baz/es.json",
      "bar/es/es.json",

      // not a valid locale
      "src/xx/settings.json",
      "src/xx.json",
    ]);

    const result = findLocaleFiles("json");

    expect(result).toEqual({
      patterns: [
        "src/locales/[locale]/messages.json",
        "src/i18n/[locale]/strings.json",
        "src/translations/[locale].json",
        "src/aa/translations/[locale].json",
        "src/aa/bb/foobar/cc/translations/[locale]/values.json",
        "src/aa/[locale].json",
        "src/aa/translations/bb/[locale].json",
        "foo/[locale]/[locale].json",
        "foo/[locale]/[locale]/messages.json",
        "bar/[locale]/baz/[locale].json",
        "bar/[locale]/[locale].json",
      ],
      defaultPatterns: ["i18n/[locale].json"],
    });
  });

  it("should return no patterns when no files found", () => {
    vi.mocked(glob.sync).mockReturnValue([]);

    const result = findLocaleFiles("json");

    expect(result).toEqual({
      patterns: [],
      defaultPatterns: ["i18n/[locale].json"],
    });
  });

  it("should find xcode-xcstrings locale files", () => {
    vi.mocked(glob.sync).mockReturnValue([
      "ios/MyApp/Localizable.xcstrings",
      "ios/MyApp/Onboarding/Localizable.xcstrings",
      "ios/MyApp/Onboarding/fr.xcstrings",
      "ios/MyApp/xx/Localizable.xcstrings",
    ]);

    const result = findLocaleFiles("xcode-xcstrings");

    expect(result).toEqual({
      patterns: [
        "ios/MyApp/Localizable.xcstrings",
        "ios/MyApp/Onboarding/Localizable.xcstrings",
        "ios/MyApp/xx/Localizable.xcstrings",
      ],
      defaultPatterns: ["Localizable.xcstrings"],
    });
  });

  it("should return no patterns for xcode-xcstrings when no files found", () => {
    vi.mocked(glob.sync).mockReturnValue([]);

    const result = findLocaleFiles("xcode-xcstrings");

    expect(result).toEqual({
      patterns: [],
      defaultPatterns: ["Localizable.xcstrings"],
    });
  });

  it("should return null unsupported bucket type", () => {
    expect(findLocaleFiles("invalid")).toBeNull();
  });
});

```

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

```typescript
import chalk from "chalk";
import { Listr } from "listr2";
import { colors } from "../../constants";
import { CmdRunContext, flagsSchema } from "./_types";
import { commonTaskRendererOptions } from "./_const";
import { getConfig } from "../../utils/config";
import createLocalizer from "../../localizer";

export default async function setup(input: CmdRunContext) {
  console.log(chalk.hex(colors.orange)("[Setup]"));

  return new Listr<CmdRunContext>(
    [
      {
        title: "Setting up the environment",
        task: async (ctx, task) => {
          // setup gitignore, etc here
          task.title = `Environment setup completed`;
        },
      },
      {
        title: "Loading i18n configuration",
        task: async (ctx, task) => {
          ctx.config = getConfig(true);

          if (!ctx.config) {
            throw new Error(
              "i18n.json not found. Please run `lingo.dev init` to initialize the project.",
            );
          } else if (
            !ctx.config.buckets ||
            !Object.keys(ctx.config.buckets).length
          ) {
            throw new Error(
              "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
            );
          } else if (
            ctx.flags.bucket?.some(
              (bucket) =>
                !ctx.config?.buckets[bucket as keyof typeof ctx.config.buckets],
            )
          ) {
            throw new Error(
              `One or more specified buckets do not exist in i18n.json. Please add them to the list first and try again.`,
            );
          }
          task.title = `Loaded i18n configuration`;
        },
      },
      {
        title: "Selecting localization provider",
        task: async (ctx, task) => {
          ctx.localizer = createLocalizer(
            ctx.config?.provider,
            ctx.flags.apiKey,
          );
          if (!ctx.localizer) {
            throw new Error(
              "Could not create localization provider. Please check your i18n.json configuration.",
            );
          }
          task.title =
            ctx.localizer.id === "Lingo.dev"
              ? `Using ${chalk.hex(colors.green)(ctx.localizer.id)} provider`
              : `Using raw ${chalk.hex(colors.yellow)(ctx.localizer.id)} API`;
        },
      },
      {
        title: "Checking authentication",
        enabled: (ctx) => ctx.localizer?.id === "Lingo.dev",
        task: async (ctx, task) => {
          const authStatus = await ctx.localizer!.checkAuth();
          if (!authStatus.authenticated) {
            throw new Error(authStatus.error || "Authentication failed");
          }
          task.title = `Authenticated as ${chalk.hex(colors.yellow)(
            authStatus.username,
          )}`;
        },
      },
      {
        title: "Validating configuration",
        enabled: (ctx) => ctx.localizer?.id !== "Lingo.dev",
        task: async (ctx, task) => {
          const validationStatus = await ctx.localizer!.validateSettings!();
          if (!validationStatus.valid) {
            throw new Error(
              validationStatus.error || "Configuration validation failed",
            );
          }
          task.title = `Configuration validated`;
        },
      },
      {
        title: "Initializing localization provider",
        async task(ctx, task) {
          const isLingoDotDev = ctx.localizer!.id === "Lingo.dev";

          const subTasks = isLingoDotDev
            ? [
                "Brand voice enabled",
                "Translation memory connected",
                "Glossary enabled",
                "Quality assurance enabled",
              ].map((title) => ({ title, task: () => {} }))
            : [
                "Skipping brand voice",
                "Skipping glossary",
                "Skipping translation memory",
                "Skipping quality assurance",
              ].map((title) => ({ title, task: () => {}, skip: true }));

          return task.newListr(subTasks, {
            concurrent: true,
            rendererOptions: { collapseSubtasks: false },
          });
        },
      },
    ],
    {
      rendererOptions: commonTaskRendererOptions,
    },
  ).run(input);
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/xcode-xcstrings-lock-compatibility.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import { MD5 } from "object-hash";

/**
 * Test suite for xcode-xcstrings pluralization lock file format.
 *
 * With the ICU loader approach, lock files contain checksums of ICU MessageFormat objects.
 * This is a NEW format for pluralization (not backward compatible with non-plural keys).
 *
 * Example lock file format:
 * item_count: <checksum of ICU object>
 *
 * vs old format (would have been):
 * item_count/zero: <checksum>
 * item_count/one: <checksum>
 * item_count/other: <checksum>
 */
describe("xcode-xcstrings ICU lock file format", () => {
  it("should compute checksums on ICU format objects", async () => {
    // This is what xcstrings-icu loader produces
    const sourceData = {
      welcome_message: "Hello!",
      item_count: {
        icu: "{count, plural, =0 {No items} one {# item} other {# items}}",
        _meta: {
          variables: {
            count: {
              format: "%d",
              role: "plural",
            },
          },
        },
      },
    };

    // Compute checksums on this format (what goes into lock file)
    const checksums: Record<string, string> = {};
    for (const [key, value] of Object.entries(sourceData)) {
      checksums[key] = MD5(value);
    }

    // Verify we have ICU object keys in checksums
    expect(checksums).toHaveProperty("item_count");
    expect(checksums).toHaveProperty("welcome_message");

    // No flattened keys
    expect(checksums).not.toHaveProperty("item_count/zero");
    expect(checksums).not.toHaveProperty("item_count/one");
    expect(checksums).not.toHaveProperty("item_count/other");
  });

  it("should have consistent ICU object structure for checksums", () => {
    const icuObject = {
      icu: "{count, plural, one {1 item} other {# items}}",
      _meta: {
        variables: {
          count: {
            format: "%d",
            role: "plural",
          },
        },
      },
    };

    const checksum1 = MD5(icuObject);
    const checksum2 = MD5(icuObject);

    // Checksums should be deterministic
    expect(checksum1).toBe(checksum2);
    expect(typeof checksum1).toBe("string");
    expect(checksum1.length).toBeGreaterThan(0);
  });

  it("should change checksum when ICU string changes", () => {
    const icuObject1 = {
      icu: "{count, plural, one {1 item} other {# items}}",
      _meta: { variables: { count: { format: "%d", role: "plural" } } },
    };

    const icuObject2 = {
      icu: "{count, plural, one {1 elemento} other {# elementos}}", // Spanish translation
      _meta: { variables: { count: { format: "%d", role: "plural" } } },
    };

    const checksum1 = MD5(icuObject1);
    const checksum2 = MD5(icuObject2);

    // Different ICU strings should produce different checksums
    expect(checksum1).not.toBe(checksum2);
  });

  it("should preserve ICU objects (not flatten them)", () => {
    // ICU objects should NOT be flattened into item_count/one, item_count/other
    // They should remain as single objects

    const icuObject = {
      icu: "{count, plural, =0 {No items} one {# item} other {# items}}",
      [Symbol.for("@lingo.dev/icu-plural-object")]: true,
    };

    // Verify it's recognized as ICU object
    expect(icuObject).toHaveProperty("icu");
    expect(icuObject.icu).toContain("plural");

    // Should have symbol marker
    expect(Symbol.for("@lingo.dev/icu-plural-object") in icuObject).toBe(true);
  });

  it("should handle mixed content (plurals and regular strings)", () => {
    const sourceData = {
      simple_string: "Hello!",
      plural_key: {
        icu: "{count, plural, one {1 item} other {# items}}",
        _meta: { variables: { count: { format: "%d", role: "plural" } } },
      },
      another_string: "Welcome!",
    };

    const checksums: Record<string, string> = {};
    for (const [key, value] of Object.entries(sourceData)) {
      checksums[key] = MD5(value);
    }

    // All keys should have checksums
    expect(Object.keys(checksums).sort()).toEqual([
      "another_string",
      "plural_key",
      "simple_string",
    ]);

    // Each should have unique checksum
    const uniqueChecksums = new Set(Object.values(checksums));
    expect(uniqueChecksums.size).toBe(3);
  });
});

```

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

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

export class Tokenizer {
  private input: string;
  private pos: number;
  private line: number;
  private column: number;

  constructor(input: string) {
    this.input = input;
    this.pos = 0;
    this.line = 1;
    this.column = 1;
  }

  tokenize(): Token[] {
    const tokens: Token[] = [];

    while (this.pos < this.input.length) {
      const char = this.current();

      // Skip whitespace
      if (this.isWhitespace(char)) {
        this.advance();
        continue;
      }

      // Handle comments
      if (char === "/" && this.peek() === "/") {
        tokens.push(this.scanSingleLineComment());
        continue;
      }

      if (char === "/" && this.peek() === "*") {
        tokens.push(this.scanMultiLineComment());
        continue;
      }

      // Handle strings
      if (char === '"') {
        tokens.push(this.scanString());
        continue;
      }

      // Handle operators
      if (char === "=") {
        tokens.push(this.makeToken(TokenType.EQUALS, "="));
        this.advance();
        continue;
      }

      if (char === ";") {
        tokens.push(this.makeToken(TokenType.SEMICOLON, ";"));
        this.advance();
        continue;
      }

      // Unexpected character - skip it
      // (More forgiving than throwing error)
      this.advance();
    }

    tokens.push(this.makeToken(TokenType.EOF, ""));
    return tokens;
  }

  private scanString(): Token {
    const start = this.getPosition();
    let value = "";

    this.advance(); // Skip opening "

    while (this.pos < this.input.length) {
      const char = this.current();

      if (char === "\\") {
        // Escape sequence - preserve both \ and next char
        this.advance();
        if (this.pos < this.input.length) {
          const nextChar = this.current();
          value += "\\" + nextChar;
          this.advance();
        }
        continue;
      }

      if (char === '"') {
        // End of string
        this.advance(); // Skip closing "
        return {
          type: TokenType.STRING,
          value,
          ...start,
        };
      }

      // Regular character (including actual newlines)
      value += char;
      this.advance();
    }

    // Unterminated string - return what we have
    return {
      type: TokenType.STRING,
      value,
      ...start,
    };
  }

  private scanSingleLineComment(): Token {
    const start = this.getPosition();
    let value = "";

    this.advance(); // Skip first '/'
    this.advance(); // Skip second '/'

    while (this.pos < this.input.length && this.current() !== "\n") {
      value += this.current();
      this.advance();
    }

    return {
      type: TokenType.COMMENT_SINGLE,
      value,
      ...start,
    };
  }

  private scanMultiLineComment(): Token {
    const start = this.getPosition();
    let value = "";

    this.advance(); // Skip '/'
    this.advance(); // Skip '*'

    while (this.pos < this.input.length) {
      if (this.current() === "*" && this.peek() === "/") {
        this.advance(); // Skip '*'
        this.advance(); // Skip '/'
        return {
          type: TokenType.COMMENT_MULTI,
          value,
          ...start,
        };
      }

      value += this.current();
      this.advance();
    }

    // Unterminated comment - return what we have
    return {
      type: TokenType.COMMENT_MULTI,
      value,
      ...start,
    };
  }

  private current(): string {
    return this.input[this.pos];
  }

  private peek(): string | null {
    if (this.pos + 1 < this.input.length) {
      return this.input[this.pos + 1];
    }
    return null;
  }

  private advance(): void {
    if (this.pos < this.input.length) {
      if (this.current() === "\n") {
        this.line++;
        this.column = 1;
      } else {
        this.column++;
      }
      this.pos++;
    }
  }

  private isWhitespace(char: string): boolean {
    return char === " " || char === "\t" || char === "\n" || char === "\r";
  }

  private getPosition(): Position {
    return {
      line: this.line,
      column: this.column,
    };
  }

  private makeToken(type: TokenType, value: string): Token {
    return {
      type,
      value,
      ...this.getPosition(),
    };
  }
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/json-dictionary.ts:
--------------------------------------------------------------------------------

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

const TOP_LEVEL_KEY = "--content--";

export default function createJsonDictionaryLoader(): ILoader<
  Record<string, any>,
  Record<string, any>
> {
  return createLoader({
    pull: async (locale, input) => {
      const result = extractTranslatables(input, locale);

      // if locale keys are on top level, only single string is extracted and returned under special key
      if (typeof result === "string") {
        return { [TOP_LEVEL_KEY]: result };
      }

      return result;
    },
    push: async (locale, data, originalInput, originalLocale) => {
      if (!originalInput) {
        throw new Error("Error while parsing json-dictionary bucket");
      }
      const input = _.cloneDeep(originalInput);

      // if content is under special key, locale keys are on top level
      if (
        Object.keys(data).length === 1 &&
        Object.keys(data)[0] === TOP_LEVEL_KEY
      ) {
        setNestedLocale(
          { [TOP_LEVEL_KEY]: input },
          [TOP_LEVEL_KEY],
          locale,
          data[TOP_LEVEL_KEY],
          originalLocale,
        );
        return input;
      }

      // set the translation under the target locale key, use value from data (which is now a string)
      function walk(obj: any, dataNode: any, path: string[] = []) {
        if (Array.isArray(obj) && Array.isArray(dataNode)) {
          obj.forEach((item, idx) =>
            walk(item, dataNode[idx], [...path, String(idx)]),
          );
        } else if (
          obj &&
          typeof obj === "object" &&
          dataNode &&
          typeof dataNode === "object" &&
          !Array.isArray(dataNode)
        ) {
          for (const key of Object.keys(obj)) {
            if (dataNode.hasOwnProperty(key)) {
              walk(obj[key], dataNode[key], [...path, key]);
            }
          }
        } else if (
          obj &&
          typeof obj === "object" &&
          !Array.isArray(obj) &&
          typeof dataNode === "string"
        ) {
          // dataNode is the new string for the target locale
          setNestedLocale(input, path, locale, dataNode, originalLocale);
        }
      }
      walk(input, data);

      return input;
    },
  });
}

// extract all keys that match locale from object
function extractTranslatables(obj: any, locale: string): any {
  if (Array.isArray(obj)) {
    return obj.map((item) => extractTranslatables(item, locale));
  } else if (isTranslatableObject(obj, locale)) {
    return obj[locale];
  } else if (obj && typeof obj === "object") {
    const result: any = {};
    for (const key of Object.keys(obj)) {
      const value = extractTranslatables(obj[key], locale);
      if (
        (typeof value === "object" &&
          value !== null &&
          Object.keys(value).length > 0) ||
        (Array.isArray(value) && value.length > 0) ||
        (typeof value === "string" && value.length > 0)
      ) {
        result[key] = value;
      }
    }
    return result;
  }
  return undefined;
}

function isTranslatableObject(obj: any, locale: string): boolean {
  return (
    obj &&
    typeof obj === "object" &&
    !Array.isArray(obj) &&
    Object.prototype.hasOwnProperty.call(obj, locale)
  );
}

function setNestedLocale(
  obj: any,
  path: string[],
  locale: string,
  value: string,
  originalLocale: string,
) {
  let curr = obj;
  for (let i = 0; i < path.length - 1; i++) {
    const key = path[i];
    if (!(key in curr)) curr[key] = {};
    curr = curr[key];
  }
  const last = path[path.length - 1];
  if (curr[last] && typeof curr[last] === "object") {
    curr[last][locale] = value;
    // Reorder keys: source locale first, then others alphabetically
    if (originalLocale && curr[last][originalLocale]) {
      const entries = Object.entries(curr[last]);
      const first = entries.filter(([k]) => k === originalLocale);
      const rest = entries
        .filter(([k]) => k !== originalLocale)
        .sort(([a], [b]) => a.localeCompare(b));
      const ordered = [...first, ...rest];
      const reordered: Record<string, string> = {};
      for (const [k, v] of ordered) {
        reordered[k] = v as string;
      }
      curr[last] = reordered;
    }
  }
}

```

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

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

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

describe("jsxAttributeFlagMutation", () => {
  it("should add data-jsx-attribute-scope to elements with title attribute", () => {
    const input = `
function Component() {
  return <div>
    <a href="https://example.com" title="Visit Example">Example link</a>
  </div>;
}
`.trim();

    const expected = `
function Component() {
  return <div>
    <a href="https://example.com" title="Visit Example" data-jsx-attribute-scope={["title:0/body/0/argument/1-title"]}>Example link</a>
  </div>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should add data-jsx-attribute-scope to elements with aria-label attribute", () => {
    const input = `
function Component() {
  return <div>
    <button aria-label="Close dialog">×</button>
  </div>;
}
`.trim();

    const expected = `
function Component() {
  return <div>
    <button aria-label="Close dialog" data-jsx-attribute-scope={["aria-label:0/body/0/argument/1-aria-label"]}>×</button>
  </div>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle multiple localizable attributes on the same element", () => {
    const input = `
function Component() {
  return <div>
    <input placeholder="Enter name" aria-label="Name field" title="Your full name" />
  </div>;
}
`.trim();

    const expected = `
function Component() {
  return <div>
    <input placeholder="Enter name" aria-label="Name field" title="Your full name" data-jsx-attribute-scope={["placeholder:0/body/0/argument/1-placeholder", "aria-label:0/body/0/argument/1-aria-label", "title:0/body/0/argument/1-title"]} />
  </div>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle nested elements with localizable attributes", () => {
    const input = `
function Component() {
  return <div>
    <div>
      <a href="/" title="Home page">Home</a>
      <span aria-description="Navigation menu">Menu</span>
    </div>
    <img src="/logo.png" alt="Company logo" />
  </div>;
}
`.trim();

    const expected = `
function Component() {
  return <div>
    <div>
      <a href="/" title="Home page" data-jsx-attribute-scope={["title:0/body/0/argument/1/1-title"]}>Home</a>
      <span aria-description="Navigation menu" data-jsx-attribute-scope={["aria-description:0/body/0/argument/1/3-aria-description"]}>Menu</span>
    </div>
    <img src="/logo.png" alt="Company logo" data-jsx-attribute-scope={["alt:0/body/0/argument/3-alt"]} />
  </div>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should ignore elements without localizable attributes", () => {
    const input = `
function Component() {
  return <div>
    <span className="regular">No attributes to localize</span>
    <button onClick={() => {}}>Click me</button>
  </div>;
}
`.trim();

    const expected = `
function Component() {
  return <div>
    <span className="regular">No attributes to localize</span>
    <button onClick={() => {}}>Click me</button>
  </div>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should not ignore component elements (uppercase names)", () => {
    const input = `
function Component() {
  return <div>
    <CustomComponent title="This should be ignored" />
    <span title="This should be flagged">Text</span>
  </div>;
}
`.trim();

    const expected = `
function Component() {
  return <div>
    <CustomComponent title="This should be ignored" data-jsx-attribute-scope={["title:0/body/0/argument/1-title"]} />
    <span title="This should be flagged" data-jsx-attribute-scope={["title:0/body/0/argument/3-title"]}>Text</span>
  </div>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });
});

```

--------------------------------------------------------------------------------
/packages/compiler/src/utils/jsx-attribute.spec.ts:
--------------------------------------------------------------------------------

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

describe("JSX Attribute Value Utils", () => {
  function parseJSX(code: string): t.File {
    return parse(code, {
      sourceType: "module",
      plugins: ["jsx", "typescript"],
    });
  }

  function generateCode(ast: t.Node): string {
    return generate(ast).code;
  }

  function getJSXElementPath(code: string): NodePath<t.JSXElement> {
    const ast = parseJSX(code);
    let elementPath: NodePath<t.JSXElement> | null = null;

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

    if (!elementPath) {
      throw new Error("No JSX element found in the code");
    }

    return elementPath;
  }

  describe("getJsxAttributeValue", () => {
    it("should return undefined for non-existent attribute", () => {
      const path = getJSXElementPath("<div className='test'></div>");
      const value = getJsxAttributeValue(path, "id");
      expect(value).toBeUndefined();
    });

    it("should return string value for string attribute", () => {
      const path = getJSXElementPath("<div className='test'></div>");
      const value = getJsxAttributeValue(path, "className");
      expect(value).toBe("test");
    });

    it("should return boolean value for boolean attribute", () => {
      const path = getJSXElementPath("<div disabled></div>");
      const value = getJsxAttributeValue(path, "disabled");
      expect(value).toBe(true);
    });

    it("should return number value for numeric attribute", () => {
      const path = getJSXElementPath("<div tabIndex={5}></div>");
      const value = getJsxAttributeValue(path, "tabIndex");
      expect(value).toBe(5);
    });
  });

  describe("setJsxAttributeValue", () => {
    it("should add a new string attribute", () => {
      const path = getJSXElementPath("<div></div>");
      setJsxAttributeValue(path, "className", "test");

      const code = generateCode(path.node);

      expect(code).toBe('<div className="test"></div>');
    });

    it("should update an existing attribute", () => {
      const path = getJSXElementPath("<div className='old'></div>");
      setJsxAttributeValue(path, "className", "new");

      const code = generateCode(path.node);

      expect(code).toBe('<div className="new"></div>');
    });

    it("should add a boolean attribute", () => {
      const path = getJSXElementPath("<div></div>");
      setJsxAttributeValue(path, "disabled", true);

      const code = generateCode(path.node);

      expect(code).toBe("<div disabled={true}></div>");
    });

    it("should add a boolean attribute with null for presence-only", () => {
      const path = getJSXElementPath("<div></div>");
      setJsxAttributeValue(path, "disabled", null);

      const code = generateCode(path.node);

      expect(code).toBe("<div disabled></div>");
    });

    it("should handle numeric attributes", () => {
      const path = getJSXElementPath("<div></div>");
      setJsxAttributeValue(path, "tabIndex", 5);

      const code = generateCode(path.node);

      expect(code).toBe("<div tabIndex={5}></div>");
    });
  });

  describe("getAttributesMap", () => {
    it("should return an empty object for elements with no attributes", () => {
      const path = getJSXElementPath("<div></div>");
      const attrs = getJsxAttributesMap(path);
      expect(attrs).toEqual({});
    });

    it("should return all attributes as a map", () => {
      const path = getJSXElementPath(
        "<div className='test' id='main' disabled tabIndex={5}></div>",
      );
      const attrs = getJsxAttributesMap(path);

      expect(attrs).toEqual({
        className: "test",
        id: "main",
        disabled: true,
        tabIndex: 5,
      });
    });

    it("should return null for complex expressions", () => {
      const path = getJSXElementPath(
        "<div data-value={{complex: 'object'}}></div>",
      );
      const attrs = getJsxAttributesMap(path);

      expect(attrs).toHaveProperty("data-value");
      expect(attrs["data-value"]).toBeNull();
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/react/src/react-router/loader.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, expect, it, vi } from "vitest";
import { LOCALE_COOKIE_NAME } from "../core";
import { loadDictionary_internal } from "./loader";

describe("loadDictionary_internal", () => {
  function createMockRequest(cookieHeader?: string): Request {
    const headers = new Headers();
    if (cookieHeader) {
      headers.set("Cookie", cookieHeader);
    }
    return new Request("http://localhost", { headers });
  }

  const mockDictionaryLoader = {
    en: vi.fn().mockResolvedValue({ default: { hello: "Hello" } }),
    es: vi.fn().mockResolvedValue({ default: { hello: "Hola" } }),
    fr: vi.fn().mockResolvedValue({ default: { hello: "Bonjour" } }),
  };

  it("should return first dictionary when no Cookie header is present", async () => {
    const request = createMockRequest();
    const result = await loadDictionary_internal(request, mockDictionaryLoader);

    expect(mockDictionaryLoader.en).toHaveBeenCalled();
    expect(result).toEqual({ hello: "Hello" });
  });

  it("should return  first dictionary when Cookie header exists but no lingo-locale cookie", async () => {
    const request = createMockRequest("session=abc123; other-cookie=value");
    const result = await loadDictionary_internal(request, mockDictionaryLoader);

    expect(mockDictionaryLoader.en).toHaveBeenCalled();
    expect(result).toEqual({ hello: "Hello" });
  });

  it("should parse locale from lingo-locale cookie", async () => {
    const request = createMockRequest(`${LOCALE_COOKIE_NAME}=es`);
    const result = await loadDictionary_internal(request, mockDictionaryLoader);

    expect(mockDictionaryLoader.es).toHaveBeenCalled();
    expect(result).toEqual({ hello: "Hola" });
  });

  it("should handle lingo-locale cookie with other cookies", async () => {
    const request = createMockRequest(
      `session=abc; ${LOCALE_COOKIE_NAME}=fr; other=value`,
    );
    const result = await loadDictionary_internal(request, mockDictionaryLoader);

    expect(mockDictionaryLoader.fr).toHaveBeenCalled();
    expect(result).toEqual({ hello: "Bonjour" });
  });

  it("should handle lingo-locale cookie with spaces", async () => {
    const request = createMockRequest(
      `session=abc; ${LOCALE_COOKIE_NAME}=es ; other=value`,
    );
    const result = await loadDictionary_internal(request, mockDictionaryLoader);

    expect(mockDictionaryLoader.es).toHaveBeenCalled();
    expect(result).toEqual({ hello: "Hola" });
  });

  it("should use explicit locale string when provided", async () => {
    const result = await loadDictionary_internal("fr", mockDictionaryLoader);

    expect(mockDictionaryLoader.fr).toHaveBeenCalled();
    expect(result).toEqual({ hello: "Bonjour" });
  });

  it("should return first dictionary when locale is not available in dictionary loaders", async () => {
    const request = createMockRequest(`${LOCALE_COOKIE_NAME}=de`);
    const result = await loadDictionary_internal(request, mockDictionaryLoader);

    expect(result).toEqual({ hello: "Hello" });
  });

  it("should return first dictionary when explicit locale is not available", async () => {
    const result = await loadDictionary_internal("de", mockDictionaryLoader);

    expect(result).toEqual({ hello: "Hello" });
  });

  it("should handle malformed cookie values gracefully", async () => {
    const request = createMockRequest(`${LOCALE_COOKIE_NAME}=`);
    const result = await loadDictionary_internal(request, mockDictionaryLoader);

    expect(result).toEqual({ hello: "Hello" });
  });

  it("should handle cookie with equals sign in value", async () => {
    const request = createMockRequest(`${LOCALE_COOKIE_NAME}=en=US`);
    const mockLoader = {
      "en=US": vi.fn().mockResolvedValue({ default: { hello: "Hello US" } }),
    };
    const result = await loadDictionary_internal(request, mockLoader);

    expect(mockLoader["en=US"]).toHaveBeenCalled();
    expect(result).toEqual({ hello: "Hello US" });
  });

  it("should handle empty string locale", async () => {
    const result = await loadDictionary_internal("", mockDictionaryLoader);

    expect(result).toEqual({ hello: "Hello" });
  });

  it("should extract default export from loader result", async () => {
    const customLoader = {
      custom: vi.fn().mockResolvedValue({
        default: { test: "value" },
        other: { ignored: "data" },
      }),
    };
    const result = await loadDictionary_internal("custom", customLoader);

    expect(result).toEqual({ test: "value" });
  });
});

```

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

```typescript
import _ from "lodash";
import { ILoader } from "../_types";
import { composeLoaders, createLoader } from "../_utils";
import { isICUPluralObject } from "../xcode-xcstrings-icu";

export type VariableLoaderParams = {
  type: "ieee" | "python";
};

export default function createVariableLoader(
  params: VariableLoaderParams,
): ILoader<Record<string, any>, Record<string, string>> {
  return composeLoaders(variableExtractLoader(params), variableContentLoader());
}

type VariableExtractionPayload = {
  variables: string[];
  value: string | any; // Can be string or ICU object
};

function variableExtractLoader(
  params: VariableLoaderParams,
): ILoader<Record<string, any>, Record<string, VariableExtractionPayload>> {
  const specifierPattern = getFormatSpecifierPattern(params.type);
  return createLoader({
    pull: async (locale, input, initXtx, originalLocale, originalInput) => {
      const result: Record<string, VariableExtractionPayload> = {};
      const inputValues = _.omitBy(input, _.isEmpty);
      for (const [key, value] of Object.entries(inputValues)) {
        const originalValue = originalInput[key];

        // Handle ICU objects: strip metadata before sending to backend
        if (isICUPluralObject(originalValue)) {
          // ICU objects have metadata, but backend only needs the ICU string
          // Strip _meta and pass through only the ICU string
          const icuValue = isICUPluralObject(value)
            ? { icu: value.icu }
            : value;

          result[key] = {
            value: icuValue,
            variables: [], // Metadata stored separately, not in variables
          };
          continue;
        }

        // Handle regular strings
        const matches = originalValue.match(specifierPattern) || [];
        result[key] = result[key] || {
          value,
          variables: [],
        };
        for (let i = 0; i < matches.length; i++) {
          const match = matches[i];
          const currentValue = result[key].value;
          const newValue = currentValue?.replace(match, `{variable:${i}}`);

          result[key].value = newValue;
          result[key].variables[i] = match;
        }
      }
      return result;
    },
    push: async (
      locale,
      data,
      originalInput,
      originalDefaultLocale,
      pullInput,
      pullOutput,
    ) => {
      const result: Record<string, any> = {};
      for (const [key, valueObj] of Object.entries(data)) {
        result[key] = valueObj.value;

        // Restore metadata for ICU objects
        const resultValue = result[key];
        if (isICUPluralObject(resultValue)) {
          const originalValue = originalInput?.[key];
          if (isICUPluralObject(originalValue) && originalValue._meta) {
            // Restore the _meta and type marker from original input
            (resultValue as any)._meta = originalValue._meta;
            (resultValue as any)[Symbol.for("@lingo.dev/icu-plural-object")] =
              true;
          }
        }

        // Restore variables for regular strings
        for (let i = 0; i < valueObj.variables.length; i++) {
          const variable = valueObj.variables[i];
          const currentValue = result[key];
          if (typeof currentValue === "string") {
            const newValue = currentValue?.replace(`{variable:${i}}`, variable);
            result[key] = newValue;
          }
        }
      }
      return result;
    },
  });
}

function variableContentLoader(): ILoader<
  Record<string, VariableExtractionPayload>,
  Record<string, string>
> {
  return createLoader({
    pull: async (locale, input) => {
      const result = _.mapValues(input, (payload) => payload.value);
      return result;
    },
    push: async (locale, data, originalInput, defaultLocale, pullInput) => {
      const result: Record<string, VariableExtractionPayload> = _.cloneDeep(
        originalInput || {},
      );
      for (const [key, originalValueObj] of Object.entries(result)) {
        result[key] = {
          ...originalValueObj,
          value: data[key],
        };
      }
      return result;
    },
  });
}

function getFormatSpecifierPattern(type: VariableLoaderParams["type"]): RegExp {
  switch (type) {
    case "ieee":
      return /%(?:\d+\$)?[+-]?(?:[ 0]|'.)?-?\d*(?:\.\d+)?(?:[hljztL]|ll|hh)?[@diuoxXfFeEgGaAcspn%]/g;
    case "python":
      return /%\([^)]+\)[diouxXeEfFgGcrs%]/g;
    default:
      throw new Error(`Unsupported variable format type: ${type}`);
  }
}

```

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

```typescript
"use client";

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

/**
 * The props for the `LingoProvider` component.
 */
export type LingoProviderProps<D> = {
  /**
   * The dictionary object that contains localized content.
   */
  dictionary: D;
  /**
   * The child components containing localizable content.
   */
  children: React.ReactNode;
};

/**
 * A context provider that makes localized content from a preloaded dictionary available to its descendants.
 *
 * This component:
 *
 * - Should be placed at the top of the component tree
 * - Should be used in client-side applications that preload data from the server (e.g., React Router apps)
 *
 * @template D - The type of the dictionary object.
 * @throws {Error} When no dictionary is provided.
 *
 * @example Use in a React Router application
 * ```tsx
 * import { LingoProvider } from "lingo.dev/react/client";
 * import { loadDictionary } from "lingo.dev/react/react-router";
 * import {
 *   Links,
 *   Meta,
 *   Outlet,
 *   Scripts,
 *   ScrollRestoration,
 *   useLoaderData,
 *   type LoaderFunctionArgs,
 * } from "react-router";
 * import "./app.css";
 *
 * export const loader = async ({ request }: LoaderFunctionArgs) => {
 *   return {
 *     lingoDictionary: await loadDictionary(request),
 *   };
 * };
 *
 * export function Layout({ children }: { children: React.ReactNode }) {
 *   const { lingoDictionary } = useLoaderData<typeof loader>();
 *
 *   return (
 *     <LingoProvider dictionary={lingoDictionary}>
 *       <html lang="en">
 *         <head>
 *           <meta charSet="utf-8" />
 *           <meta name="viewport" content="width=device-width, initial-scale=1" />
 *           <Meta />
 *           <Links />
 *         </head>
 *         <body>
 *           {children}
 *           <ScrollRestoration />
 *           <Scripts />
 *         </body>
 *       </html>
 *     </LingoProvider>
 *   );
 * }
 *
 * export default function App() {
 *   return <Outlet />;
 * }
 * ```
 */
export function LingoProvider<D>(props: LingoProviderProps<D>) {
  // TODO: handle case when no dictionary is provided - throw suspense? return null / other fallback?
  if (!props.dictionary) {
    throw new Error("LingoProvider: dictionary is not provided.");
  }

  return (
    <LingoContext.Provider
      value={{ dictionary: props.dictionary }}
      children={props.children}
    />
  );
}

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

/**
 * A context provider that loads the dictionary for the current locale and makes localized content available to its descendants.
 *
 * This component:
 *
 * - Should be placed at the top of the component tree
 * - Should be used in purely client-side rendered applications (e.g., Vite-based apps)
 *
 * @template D - The type of the dictionary object containing localized content.
 *
 * @example Use in a Vite application
 * ```tsx file="src/main.tsx"
 * import { LingoProviderWrapper, loadDictionary } from "lingo.dev/react/client";
 * import { StrictMode } from 'react'
 * import { createRoot } from 'react-dom/client'
 * import './index.css'
 * import App from './App.tsx'
 *
 * createRoot(document.getElementById('root')!).render(
 *   <StrictMode>
 *     <LingoProviderWrapper loadDictionary={(locale) => loadDictionary(locale)}>
 *       <App />
 *     </LingoProviderWrapper>
 *   </StrictMode>,
 * );
 * ```
 */
export function LingoProviderWrapper<D>(props: LingoProviderWrapperProps<D>) {
  const [dictionary, setDictionary] = useState<D | null>(null);

  // for client-side rendered apps, the dictionary is also loaded on the client
  useEffect(() => {
    (async () => {
      try {
        const locale = getLocaleFromCookies();
        console.log(
          `[Lingo.dev] Loading dictionary file for locale ${locale}...`,
        );
        const localeDictionary = await props.loadDictionary(locale);
        setDictionary(localeDictionary);
      } catch (error) {
        console.log("[Lingo.dev] Failed to load dictionary:", error);
      }
    })();
  }, []);

  // TODO: handle case when the dictionary is loading (throw suspense?)
  if (!dictionary) {
    return null;
  }

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

```

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

```typescript
import { Link } from "react-router";
import logoDark from "./logo-dark.svg";
import logoLight from "./logo-light.svg";
import { LingoDotDev } from "./lingo-dot-dev";

export function Welcome() {
  return (
    <main className="flex items-center justify-center pt-16 pb-4">
      <div className="flex-1 flex flex-col items-center gap-16 min-h-0">
        <header className="flex items-center gap-9">
          <a href="https://lingo.dev/">
            <LingoDotDev height={38} />
          </a>
          <span className="text-4xl">💚</span>
          <div className="p-4">
            <a href="https://reactrouter.com/">
              <img
                src={logoLight}
                alt="React Router"
                className="block w-full dark:hidden h-[38px]"
              />
              <img
                src={logoDark}
                alt="React Router"
                className="hidden w-full dark:block h-[38px]"
              />
            </a>
          </div>
        </header>
        <Link to="/test" className="text-blue-500 hover:underline">
          Open test page
        </Link>
        <p className="text-gray-700 dark:text-gray-200 text-center max-w-[500px]">
          Welcome to your new React Router application! This starter template
          includes everything you need to get started with React Router and
          Lingo.dev for internationalization.
        </p>
        <div className="max-w-[300px] w-full space-y-6 px-4">
          <nav className="rounded-3xl border border-gray-200 p-6 dark:border-gray-700 space-y-4">
            <p className="leading-6 text-gray-700 dark:text-gray-200 text-center">
              What&apos;s next?
            </p>
            <ul>
              {resources.map(({ href, text, icon }) => (
                <li key={href}>
                  <a
                    className="group flex items-center gap-3 self-stretch p-3 leading-normal text-blue-700 hover:underline dark:text-blue-500"
                    href={href}
                    target="_blank"
                    rel="noreferrer"
                  >
                    {icon}
                    {text}
                  </a>
                </li>
              ))}
            </ul>
          </nav>
        </div>
      </div>
    </main>
  );
}

const resources = [
  {
    href: "https://reactrouter.com/docs",
    text: "React Router Docs",
    icon: (
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="24"
        height="20"
        viewBox="0 0 20 20"
        fill="none"
        className="stroke-gray-600 group-hover:stroke-current dark:stroke-gray-300"
      >
        <path
          d="M9.99981 10.0751V9.99992M17.4688 17.4688C15.889 19.0485 11.2645 16.9853 7.13958 12.8604C3.01467 8.73546 0.951405 4.11091 2.53116 2.53116C4.11091 0.951405 8.73546 3.01467 12.8604 7.13958C16.9853 11.2645 19.0485 15.889 17.4688 17.4688ZM2.53132 17.4688C0.951566 15.8891 3.01483 11.2645 7.13974 7.13963C11.2647 3.01471 15.8892 0.951453 17.469 2.53121C19.0487 4.11096 16.9854 8.73551 12.8605 12.8604C8.73562 16.9853 4.11107 19.0486 2.53132 17.4688Z"
          strokeWidth="1.5"
          strokeLinecap="round"
        />
      </svg>
    ),
  },
  {
    href: "https://rmx.as/discord",
    text: "Join Discord",
    icon: (
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="24"
        height="20"
        viewBox="0 0 24 20"
        fill="none"
        className="stroke-gray-600 group-hover:stroke-current dark:stroke-gray-300"
      >
        <path
          d="M15.0686 1.25995L14.5477 1.17423L14.2913 1.63578C14.1754 1.84439 14.0545 2.08275 13.9422 2.31963C12.6461 2.16488 11.3406 2.16505 10.0445 2.32014C9.92822 2.08178 9.80478 1.84975 9.67412 1.62413L9.41449 1.17584L8.90333 1.25995C7.33547 1.51794 5.80717 1.99419 4.37748 2.66939L4.19 2.75793L4.07461 2.93019C1.23864 7.16437 0.46302 11.3053 0.838165 15.3924L0.868838 15.7266L1.13844 15.9264C2.81818 17.1714 4.68053 18.1233 6.68582 18.719L7.18892 18.8684L7.50166 18.4469C7.96179 17.8268 8.36504 17.1824 8.709 16.4944L8.71099 16.4904C10.8645 17.0471 13.128 17.0485 15.2821 16.4947C15.6261 17.1826 16.0293 17.8269 16.4892 18.4469L16.805 18.8725L17.3116 18.717C19.3056 18.105 21.1876 17.1751 22.8559 15.9238L23.1224 15.724L23.1528 15.3923C23.5873 10.6524 22.3579 6.53306 19.8947 2.90714L19.7759 2.73227L19.5833 2.64518C18.1437 1.99439 16.6386 1.51826 15.0686 1.25995ZM16.6074 10.7755L16.6074 10.7756C16.5934 11.6409 16.0212 12.1444 15.4783 12.1444C14.9297 12.1444 14.3493 11.6173 14.3493 10.7877C14.3493 9.94885 14.9378 9.41192 15.4783 9.41192C16.0471 9.41192 16.6209 9.93851 16.6074 10.7755ZM8.49373 12.1444C7.94513 12.1444 7.36471 11.6173 7.36471 10.7877C7.36471 9.94885 7.95323 9.41192 8.49373 9.41192C9.06038 9.41192 9.63892 9.93712 9.6417 10.7815C9.62517 11.6239 9.05462 12.1444 8.49373 12.1444Z"
          strokeWidth="1.5"
        />
      </svg>
    ),
  },
];

```

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

```typescript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import * as path from "path";

// ESM mocks for internal modules used by _loader-utils
vi.mock("./utils/module-params", () => {
  return {
    parseParametrizedModuleId: vi.fn((rawId: string) => {
      const url = new URL(rawId, "module://");
      return {
        id: url.pathname.replace(/^\//, ""),
        params: Object.fromEntries(url.searchParams.entries()),
      };
    }),
  };
});

vi.mock("./lib/lcp", () => {
  return {
    LCP: {
      ready: vi.fn(async () => undefined),
      getInstance: vi.fn(() => ({ data: { version: 0.1 } })),
    },
  };
});

vi.mock("./lib/lcp/server", () => {
  return {
    LCPServer: {
      loadDictionaries: vi.fn(async () => ({})),
    },
  };
});

// Import under test AFTER mocks
import { loadDictionary, transformComponent } from "./_loader-utils";
import { defaultParams } from "./_base";

describe("loadDictionary", () => {
  beforeEach(async () => {
    const lcpMod = await import("./lib/lcp");
    (lcpMod.LCP.ready as any).mockClear();
    (lcpMod.LCP.getInstance as any).mockClear();
    const serverMod = await import("./lib/lcp/server");
    (serverMod.LCPServer.loadDictionaries as any).mockClear();
  });

  it("returns null when path is not a dictionary file", async () => {
    const result = await loadDictionary({
      resourcePath: "/project/src/lingo/not-dictionary.tsx",
      resourceQuery: "",
      params: {},
      sourceRoot: "src",
      lingoDir: "lingo",
      isDev: false,
    });
    expect(result).toBeNull();
    const lcpMod = await import("./lib/lcp");
    expect(lcpMod.LCP.ready).not.toHaveBeenCalled();
  });

  it("returns null when locale param is missing", async () => {
    // Override parser to drop locale
    const parseMod = await import("./utils/module-params");
    (parseMod.parseParametrizedModuleId as any).mockImplementation(
      (rawId: string) => ({ id: rawId, params: {} }),
    );

    const result = await loadDictionary({
      resourcePath: "/project/src/lingo/dictionary.js",
      resourceQuery: "",
      params: {},
      sourceRoot: "src",
      lingoDir: "lingo",
      isDev: false,
    });
    expect(result).toBeNull();
    const lcpMod = await import("./lib/lcp");
    expect(lcpMod.LCP.ready).not.toHaveBeenCalled();
  });

  it("loads dictionary for provided locale and passes params to server", async () => {
    // Restore default module param parser
    const parseMod = await import("./utils/module-params");
    (parseMod.parseParametrizedModuleId as any).mockImplementation(
      (rawId: string) => {
        const url = new URL(rawId, "module://");
        return {
          id: url.pathname.replace(/^\//, ""),
          params: Object.fromEntries(url.searchParams.entries()),
        };
      },
    );

    const DICT = { version: 0.1, locale: "es", files: {} };
    const serverMod = await import("./lib/lcp/server");
    (serverMod.LCPServer.loadDictionaries as any).mockResolvedValueOnce({
      es: DICT,
    });

    const result = await loadDictionary({
      resourcePath: "/project/src/lingo/dictionary.js",
      resourceQuery: "?locale=es",
      params: { sourceLocale: "en", targetLocales: ["es"], foo: "bar" },
      sourceRoot: "src",
      lingoDir: "lingo",
      isDev: true,
    });

    expect(result).toEqual(DICT);
    const lcpMod = await import("./lib/lcp");
    expect(lcpMod.LCP.ready).toHaveBeenCalledWith({
      sourceRoot: "src",
      lingoDir: "lingo",
      isDev: true,
    });
    expect(lcpMod.LCP.getInstance).toHaveBeenCalledWith({
      sourceRoot: "src",
      lingoDir: "lingo",
      isDev: true,
    });
    expect(serverMod.LCPServer.loadDictionaries).toHaveBeenCalledWith({
      sourceLocale: "en",
      targetLocales: ["es"],
      foo: "bar",
      lcp: { version: 0.1 },
    });
  });

  it("throws when dictionary for locale is missing", async () => {
    const serverMod = await import("./lib/lcp/server");
    (serverMod.LCPServer.loadDictionaries as any).mockResolvedValueOnce({});
    await expect(
      loadDictionary({
        resourcePath: "/project/src/lingo/dictionary.js",
        resourceQuery: "?locale=fr",
        params: { sourceLocale: "en", targetLocales: ["fr"] },
        sourceRoot: "src",
        lingoDir: "lingo",
        isDev: false,
      }),
    ).rejects.toThrow('Dictionary for locale "fr" could not be generated.');
  });
});

describe("transformComponent", () => {
  it("returns the same code when nothing to transform and normalizes relativeFilePath", () => {
    const code = "export const X = 1;";
    const result = transformComponent({
      code,
      params: defaultParams,
      resourcePath: path.join("/project", "src", "deep", "file.tsx"),
      sourceRoot: "src",
    });
    expect(result.code).toContain("export const X = 1;");
    // sanity: should return a code+map object
    expect(result.map).toBeDefined();
  });
});

```

--------------------------------------------------------------------------------
/packages/compiler/src/jsx-attribute-scope-inject.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from "vitest";
import { lingoJsxAttributeScopeInjectMutation } from "./jsx-attribute-scope-inject";
import { createPayload, createOutput, defaultParams } from "./_base";
import * as parser from "@babel/parser";
import generate from "@babel/generator";

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

// Helper function to normalize code for comparison
function normalizeCode(code: string) {
  const ast = parser.parse(code, {
    sourceType: "module",
    plugins: ["jsx", "typescript"],
  });
  return generate(ast).code;
}

describe("lingoJsxAttributeScopeInjectMutation", () => {
  describe("attribute scopes", () => {
    it("should handle JSX elements with attribute scopes", () => {
      const input = `
    function Component() {
    return <div>
    <button data-jsx-attribute-scope={["aria-label:0/path/1", "title:0/path/2"]} className="btn">Click me</button>
    </div>;
    }
    `.trim();

      const expected = `
    import { LingoAttributeComponent } from "lingo.dev/react/client";
    function Component() {
    return <div>
    <LingoAttributeComponent 
      data-jsx-attribute-scope={["aria-label:0/path/1", "title:0/path/2"]} 
      className="btn" 
      $attrAs="button" 
      $fileKey="test" 
      $attributes={{
        "aria-label": "0/path/1",
        "title": "0/path/2"
      }}
    >Click me</LingoAttributeComponent>
    </div>;
    }
    `.trim();

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

    it("should handle JSX elements with attribute scopes in server components", () => {
      const input = `
    function Component() {
      return <div>
        <a data-jsx-attribute-scope={["title:0/path/1", "aria-label:0/path/2"]} className="link">Visit website</a>
      </div>;
    }
    `.trim();

      const expected = `
    import { LingoAttributeComponent, loadDictionary } from "lingo.dev/react/rsc";
    function Component() {
      return <div>
        <LingoAttributeComponent
          data-jsx-attribute-scope={["title:0/path/1", "aria-label:0/path/2"]}
          className="link"
          $attrAs="a"
          $fileKey="test"
          $attributes={{
            "title": "0/path/1",
            "aria-label": "0/path/2"
          }}
          $loadDictionary={locale => loadDictionary(locale)}
        >Visit website</LingoAttributeComponent>
      </div>;
    }
    `.trim();

      const result = runMutation(input, true);
      expect(normalizeCode(result)).toBe(normalizeCode(expected));
    });

    it("should handle JSX elements with both attribute scopes and JSX children", () => {
      const input = `
    function Component() {
      return <div>
        <a data-jsx-attribute-scope={["title:0/path/1", "aria-label:0/path/2"]} className="link">
          <span>Click here</span> to visit
        </a>
      </div>;
    }
    `.trim();

      const expected = `
    import { LingoAttributeComponent } from "lingo.dev/react/client";
    function Component() {
      return <div>
        <LingoAttributeComponent
          data-jsx-attribute-scope={["title:0/path/1", "aria-label:0/path/2"]}
          className="link"
          $attrAs="a"
          $fileKey="test"
          $attributes={{
            "title": "0/path/1",
            "aria-label": "0/path/2"
          }}
        >
          <span>Click here</span> to visit
        </LingoAttributeComponent>
      </div>;
    }
    `.trim();

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

    it("should handle JSX elements with attribute scopes and variables", () => {
      const input = `
    function Component({ url, accessibilityLabel }) {
      return <div>
        <a data-jsx-attribute-scope={["title:0/path/1", "aria-label:0/path/2"]} className="link">
          Visit {url}
        </a>
      </div>;
    }
    `.trim();

      const expected = `
    import { LingoAttributeComponent } from "lingo.dev/react/client";
    function Component({ url, accessibilityLabel }) {
      return <div>
        <LingoAttributeComponent
          data-jsx-attribute-scope={["title:0/path/1", "aria-label:0/path/2"]}
          className="link"
          $attrAs="a"
          $fileKey="test"
          $attributes={{
            "title": "0/path/1",
            "aria-label": "0/path/2"
          }}
        >
          Visit {url}
        </LingoAttributeComponent>
      </div>;
    }
    `.trim();

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

```

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

```typescript
import chalk from "chalk";
import { Listr } from "listr2";
import { minimatch } from "minimatch";

import { colors } from "../../constants";
import { resolveOverriddenLocale } from "@lingo.dev/_spec";
import { getBuckets } from "../../utils/buckets";
import { commonTaskRendererOptions } from "./_const";
import { CmdRunContext } from "./_types";

export default async function plan(
  input: CmdRunContext,
): Promise<CmdRunContext> {
  console.log(chalk.hex(colors.orange)("[Planning]"));

  let buckets = getBuckets(input.config!);
  if (input.flags.bucket) {
    buckets = buckets.filter((b) => input.flags.bucket!.includes(b.type));
  }

  const _sourceLocale = input.flags.sourceLocale || input.config!.locale.source;
  if (!_sourceLocale) {
    throw new Error(
      `No source locale provided. Use --source-locale to specify the source locale or add it to i18n.json (locale.source)`,
    );
  }
  const _targetLocales =
    input.flags.targetLocale || input.config!.locale.targets;
  if (!_targetLocales.length) {
    throw new Error(
      `No target locales provided. Use --target-locale to specify the target locales or add them to i18n.json (locale.targets)`,
    );
  }

  return new Listr<CmdRunContext>(
    [
      {
        title: "Locating content buckets",
        task: async (ctx, task) => {
          const bucketCount = buckets.length;
          const bucketFilter = input.flags.bucket
            ? ` ${chalk.dim(
                `(filtered by: ${chalk.hex(colors.yellow)(
                  input.flags.bucket!.join(", "),
                )})`,
              )}`
            : "";
          task.title = `Found ${chalk.hex(colors.yellow)(
            bucketCount.toString(),
          )} bucket(s)${bucketFilter}`;
        },
      },
      {
        title: "Detecting locales",
        task: async (ctx, task) => {
          task.title = `Found ${chalk.hex(colors.yellow)(
            _targetLocales.length.toString(),
          )} target locale(s)`;
        },
      },
      {
        title: "Locating localizable files",
        task: async (ctx, task) => {
          const patterns: string[] = [];

          for (const bucket of buckets) {
            for (const bucketPath of bucket.paths) {
              if (input.flags.file) {
                if (
                  !input.flags.file.some(
                    (f) =>
                      bucketPath.pathPattern.includes(f) ||
                      minimatch(bucketPath.pathPattern, f),
                  )
                ) {
                  continue;
                }
              }

              patterns.push(bucketPath.pathPattern);
            }
          }

          const fileFilter = input.flags.file
            ? ` ${chalk.dim(
                `(filtered by: ${chalk.hex(colors.yellow)(
                  input.flags.file.join(", "),
                )})`,
              )}`
            : "";
          task.title = `Found ${chalk.hex(colors.yellow)(
            patterns.length.toString(),
          )} path pattern(s)${fileFilter}`;
        },
      },
      {
        title: "Computing translation tasks",
        task: async (ctx, task) => {
          for (const bucket of buckets) {
            for (const bucketPath of bucket.paths) {
              if (input.flags.file) {
                if (
                  !input.flags.file.some(
                    (f) =>
                      bucketPath.pathPattern.includes(f) ||
                      minimatch(bucketPath.pathPattern, f),
                  )
                ) {
                  continue;
                }
              }

              const sourceLocale = resolveOverriddenLocale(
                _sourceLocale,
                bucketPath.delimiter,
              );

              for (const _targetLocale of _targetLocales) {
                const targetLocale = resolveOverriddenLocale(
                  _targetLocale,
                  bucketPath.delimiter,
                );

                // Skip if source and target are identical (shouldn't happen but guard)
                if (sourceLocale === targetLocale) continue;

                ctx.tasks.push({
                  sourceLocale,
                  targetLocale,
                  bucketType: bucket.type,
                  bucketPathPattern: bucketPath.pathPattern,
                  injectLocale: bucket.injectLocale || [],
                  lockedKeys: bucket.lockedKeys || [],
                  lockedPatterns: bucket.lockedPatterns || [],
                  ignoredKeys: bucket.ignoredKeys || [],
                  onlyKeys: input.flags.key || [],
                  formatter: input.config!.formatter,
                });
              }
            }
          }

          task.title = `Prepared ${chalk.hex(colors.green)(
            ctx.tasks.length.toString(),
          )} translation task(s)`;
        },
      },
    ],
    {
      rendererOptions: commonTaskRendererOptions,
    },
  ).run(input);
}

```

--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/buckets.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi } from "vitest";
import { getBuckets } from "./buckets";
import { glob, Path } from "glob";

vi.mock("glob", () => ({
  glob: {
    sync: vi.fn(),
  },
}));

describe("getBuckets", () => {
  const makeI18nConfig = (include: any[]) => ({
    $schema: "https://lingo.dev/schema/i18n.json",
    version: 0,
    locale: {
      source: "en",
      targets: ["fr", "es"],
    },
    buckets: {
      json: {
        include,
      },
    },
  });

  it("should return correct buckets", () => {
    mockGlobSync(["src/i18n/en.json"], ["src/translations/en/messages.json"]);

    const i18nConfig = makeI18nConfig([
      "src/i18n/[locale].json",
      "src/translations/[locale]/messages.json",
    ]);
    const buckets = getBuckets(i18nConfig);
    expect(buckets).toEqual([
      {
        type: "json",
        paths: [
          { pathPattern: "src/i18n/[locale].json", delimiter: null },
          {
            pathPattern: "src/translations/[locale]/messages.json",
            delimiter: null,
          },
        ],
      },
    ]);
  });

  it("should return correct buckets for paths with asterisk", () => {
    mockGlobSync(
      [
        "src/translations/landing.en.json",
        "src/translations/app.en.json",
        "src/translations/email.en.json",
      ],
      [
        "src/locale/landing/messages.en.json",
        "src/locale/app/data.en.json",
        "src/locale/email/custom.en.json",
      ],
      [
        "src/i18n/landing/en.messages.json",
        "src/i18n/app/en.data.json",
        "src/i18n/email/en.custom.json",
      ],
      [
        "src/i18n/data-landing-en-strings/en.messages.json",
        "src/i18n/data-app-en-strings/en.data.json",
        "src/i18n/data-email-en-strings/en.custom.json",
      ],
    );

    const i18nConfig = makeI18nConfig([
      "src/translations/*.[locale].json",
      "src/locale/*/*.[locale].json",
      "src/i18n/*/[locale].*.json",
      "src/i18n/data-*-[locale]-*/[locale].*.json",
    ]);
    const buckets = getBuckets(i18nConfig);
    expect(buckets).toEqual([
      {
        type: "json",
        paths: [
          {
            pathPattern: "src/translations/landing.[locale].json",
            delimiter: null,
          },
          {
            pathPattern: "src/translations/app.[locale].json",
            delimiter: null,
          },
          {
            pathPattern: "src/translations/email.[locale].json",
            delimiter: null,
          },
          {
            pathPattern: "src/locale/landing/messages.[locale].json",
            delimiter: null,
          },
          { pathPattern: "src/locale/app/data.[locale].json", delimiter: null },
          {
            pathPattern: "src/locale/email/custom.[locale].json",
            delimiter: null,
          },
          {
            pathPattern: "src/i18n/landing/[locale].messages.json",
            delimiter: null,
          },
          { pathPattern: "src/i18n/app/[locale].data.json", delimiter: null },
          {
            pathPattern: "src/i18n/email/[locale].custom.json",
            delimiter: null,
          },
          {
            pathPattern:
              "src/i18n/data-landing-[locale]-strings/[locale].messages.json",
            delimiter: null,
          },
          {
            pathPattern:
              "src/i18n/data-app-[locale]-strings/[locale].data.json",
            delimiter: null,
          },
          {
            pathPattern:
              "src/i18n/data-email-[locale]-strings/[locale].custom.json",
            delimiter: null,
          },
        ],
      },
    ]);
  });

  it("should return correct bucket with delimiter", () => {
    mockGlobSync(["src/i18n/en.json"]);
    const i18nConfig = makeI18nConfig([
      { path: "src/i18n/[locale].json", delimiter: "-" },
    ]);
    const buckets = getBuckets(i18nConfig);
    expect(buckets).toEqual([
      {
        type: "json",
        paths: [{ pathPattern: "src/i18n/[locale].json", delimiter: "-" }],
      },
    ]);
  });

  it("should return bucket with multiple locale placeholders", () => {
    mockGlobSync(
      ["src/i18n/en/en.json"],
      ["src/en/translations/en/messages.json"],
    );
    const i18nConfig = makeI18nConfig([
      "src/i18n/[locale]/[locale].json",
      "src/[locale]/translations/[locale]/messages.json",
    ]);
    const buckets = getBuckets(i18nConfig);
    expect(buckets).toEqual([
      {
        type: "json",
        paths: [
          { pathPattern: "src/i18n/[locale]/[locale].json", delimiter: null },
          {
            pathPattern: "src/[locale]/translations/[locale]/messages.json",
            delimiter: null,
          },
        ],
      },
    ]);
  });
});

function mockGlobSync(...args: string[][]) {
  args.forEach((files) => {
    vi.mocked(glob.sync).mockReturnValueOnce(
      files.map(
        (file) => ({ isFile: () => true, fullpath: () => file }) as Path,
      ),
    );
  });
}

```

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

```typescript
import { describe, expect, it } from "vitest";
import createXcodeStringsLoader from "./xcode-strings";

describe("xcode-strings loader", () => {
  it("should parse single-line entries", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `"hello" = "Hello";
"world" = "World";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      hello: "Hello",
      world: "World",
    });
  });

  it("should parse multi-line string values", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `"greeting" = "Hello";
"multiline" = "This is line one
This is line two
This is line three";
"another" = "Another value";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      greeting: "Hello",
      multiline: "This is line one\nThis is line two\nThis is line three",
      another: "Another value",
    });
  });

  it("should handle multi-line string with placeholders", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `"add_new_reference_share_text" = "Hi!
Could you stop by quickly and tell us what you thought of our experience together? Your words will be super important to boost my profile on Worldpackers!
[url]
";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      add_new_reference_share_text:
        "Hi!\nCould you stop by quickly and tell us what you thought of our experience together? Your words will be super important to boost my profile on Worldpackers!\n[url]\n",
    });
  });

  it("should skip comments", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `// This is a comment
"hello" = "Hello";
// Another comment
"world" = "World";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      hello: "Hello",
      world: "World",
    });
  });

  it("should skip empty lines", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `"hello" = "Hello";

"world" = "World";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      hello: "Hello",
      world: "World",
    });
  });

  it("should handle escaped characters in single-line values", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `"escaped_quote" = "He said \\"Hello\\"";
"escaped_newline" = "Line 1\\nLine 2";
"escaped_backslash" = "Path: C:\\\\Users";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      escaped_quote: 'He said "Hello"',
      escaped_newline: "Line 1\nLine 2",
      escaped_backslash: "Path: C:\\Users",
    });
  });

  it("should handle empty values", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `"empty" = "";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      empty: "",
    });
  });

  it("push should convert object to .strings format", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    // Need to call pull first to initialize the loader state
    await loader.pull("en", "");

    const payload = {
      hello: "Hello",
      world: "World",
    };

    const result = await loader.push("en", payload);
    expect(result).toBe(`"hello" = "Hello";
"world" = "World";`);
  });

  it("push should escape special characters", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    // Need to call pull first to initialize the loader state
    await loader.pull("en", "");

    const payload = {
      escaped_quote: 'He said "Hello"',
      escaped_newline: "Line 1\nLine 2",
      escaped_backslash: "Path: C:\\Users",
    };

    const result = await loader.push("en", payload);
    expect(result).toBe(
      `"escaped_quote" = "He said \\"Hello\\"";
"escaped_newline" = "Line 1\\nLine 2";
"escaped_backslash" = "Path: C:\\\\Users";`,
    );
  });

  it("push should handle multi-line values by escaping newlines", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    // Need to call pull first to initialize the loader state
    await loader.pull("en", "");

    const payload = {
      multiline: "This is line one\nThis is line two\nThis is line three",
    };

    const result = await loader.push("en", payload);
    expect(result).toBe(
      `"multiline" = "This is line one\\nThis is line two\\nThis is line three";`,
    );
  });

  it("should handle mixed single-line and multi-line entries", async () => {
    const loader = createXcodeStringsLoader();
    loader.setDefaultLocale("en");
    const input = `"single1" = "Value 1";
"multi" = "Line 1
Line 2";
"single2" = "Value 2";`;

    const result = await loader.pull("en", input);
    expect(result).toEqual({
      single1: "Value 1",
      multi: "Line 1\nLine 2",
      single2: "Value 2",
    });
  });
});

```

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

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

// Helper function to run mutation and get result
function runMutation(code: string) {
  const input = createPayload({ code, params: defaultParams, fileKey: "test" });
  const mutated = jsxFragmentMutation(input);
  if (!mutated) return code; // Return original code if no changes made
  return createOutput(mutated).code;
}

describe("jsxFragmentMutation", () => {
  it("should transform empty fragment shorthand to explicit Fragment", () => {
    const input = `
function Component() {
  return <></>;
}
`.trim();

    const expected = `
import { Fragment } from "react";
function Component() {
  return <Fragment></Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should transform fragment shorthand with content to explicit Fragment", () => {
    const input = `
function Component() {
  return <>Hello world</>;
}
`.trim();

    const expected = `
import { Fragment } from "react";
function Component() {
  return <Fragment>Hello world</Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should transform nested fragment shorthand", () => {
    const input = `
function Component() {
  return <>
    <div>Outer content</div>
    <>Inner fragment</>
  </>;
}
`.trim();

    const expected = `
import { Fragment } from "react";
function Component() {
  return <Fragment>
    <div>Outer content</div>
    <Fragment>Inner fragment</Fragment>
  </Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle existing Fragment import", () => {
    const input = `
import { Fragment } from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import { Fragment } from "react";
function Component() {
  return <Fragment></Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle renamed Fragment import", () => {
    const input = `
import { Fragment as ReactFragment } from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import { Fragment as ReactFragment } from "react";
function Component() {
  return <ReactFragment></ReactFragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle type-only React import and add Fragment import", () => {
    const input = `
import type React from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import type React from "react";
import { Fragment } from "react";
function Component() {
  return <Fragment></Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should return null (no changes) when no fragments found", () => {
    const input = `
function Component() {
  return <div>No fragments here</div>;
}
`.trim();

    const result = runMutation(input);
    expect(result).toBe(input);
  });

  it("should handle default import React and use React.Fragment", () => {
    const input = `
import React from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import React from "react";
function Component() {
  return <React.Fragment></React.Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle import * as React and use React.Fragment", () => {
    const input = `
import * as React from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import * as React from "react";
function Component() {
  return <React.Fragment></React.Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle mixed default and named imports", () => {
    const input = `
import React, { useState } from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import React, { useState } from "react";
function Component() {
  return <React.Fragment></React.Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle separate namespace and named imports", () => {
    const input = `
import * as React from "react";
import { Fragment } from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import * as React from "react";
import { Fragment } from "react";
function Component() {
  return <Fragment></Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });

  it("should handle import * as SomeOtherName from react", () => {
    const input = `
import * as SomeOtherName from "react";

function Component() {
  return <></>;
}
`.trim();

    const expected = `
import * as SomeOtherName from "react";
function Component() {
  return <SomeOtherName.Fragment></SomeOtherName.Fragment>;
}
`.trim();
    const result = runMutation(input);
    expect(result).toBe(expected);
  });
});

```

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

```typescript
import * as chokidar from "chokidar";
import chalk from "chalk";
import { minimatch } from "minimatch";
import { colors } from "../../constants";
import { CmdRunContext } from "./_types";
import plan from "./plan";
import execute from "./execute";
import { renderSummary } from "../../utils/ui";
import { getBuckets } from "../../utils/buckets";

interface WatchState {
  isRunning: boolean;
  pendingChanges: Set<string>;
  debounceTimer?: NodeJS.Timeout;
}

export default async function watch(ctx: CmdRunContext) {
  const debounceDelay = ctx.flags.debounce || 5000; // Use configured debounce or 5s default

  console.log(chalk.hex(colors.orange)("[Watch Mode]"));
  console.log(
    `👀 Watching for changes... (Press ${chalk.yellow("Ctrl+C")} to stop)`,
  );
  console.log(chalk.dim(`   Debounce delay: ${debounceDelay}ms`));
  console.log("");

  const state: WatchState = {
    isRunning: false,
    pendingChanges: new Set(),
  };

  // Get all source file patterns to watch
  const watchPatterns = await getWatchPatterns(ctx);

  if (watchPatterns.length === 0) {
    console.log(chalk.yellow("⚠️  No source files found to watch"));
    return;
  }

  console.log(chalk.dim(`Watching ${watchPatterns.length} file pattern(s):`));
  watchPatterns.forEach((pattern) => {
    console.log(chalk.dim(`  • ${pattern}`));
  });
  console.log("");

  // Initialize file watcher
  const watcher = chokidar.watch(watchPatterns, {
    ignoreInitial: true,
    persistent: true,
    awaitWriteFinish: {
      stabilityThreshold: 500,
      pollInterval: 100,
    },
  });

  // Handle file changes
  watcher.on("change", (path) => {
    handleFileChange(path, state, ctx);
  });

  watcher.on("add", (path) => {
    handleFileChange(path, state, ctx);
  });

  watcher.on("unlink", (path) => {
    handleFileChange(path, state, ctx);
  });

  watcher.on("error", (error) => {
    console.error(
      chalk.red(
        `Watch error: ${error instanceof Error ? error.message : String(error)}`,
      ),
    );
  });

  // Handle graceful shutdown
  process.on("SIGINT", () => {
    console.log(chalk.yellow("\n\n🛑 Stopping watch mode..."));
    watcher.close();
    process.exit(0);
  });

  // Keep the process running
  await new Promise(() => {}); // Never resolves, keeps process alive
}

async function getWatchPatterns(ctx: CmdRunContext): Promise<string[]> {
  if (!ctx.config) return [];

  const buckets = getBuckets(ctx.config);
  const patterns: string[] = [];

  for (const bucket of buckets) {
    // Skip if specific buckets are filtered
    if (ctx.flags.bucket && !ctx.flags.bucket.includes(bucket.type)) {
      continue;
    }

    for (const bucketPath of bucket.paths) {
      // Skip if specific files are filtered
      if (ctx.flags.file) {
        if (
          !ctx.flags.file.some(
            (f) =>
              bucketPath.pathPattern.includes(f) ||
              minimatch(bucketPath.pathPattern, f),
          )
        ) {
          continue;
        }
      }

      // Get the source locale pattern (replace [locale] with source locale)
      const sourceLocale = ctx.flags.sourceLocale || ctx.config.locale.source;
      const sourcePattern = bucketPath.pathPattern.replace(
        "[locale]",
        sourceLocale,
      );

      patterns.push(sourcePattern);
    }
  }

  return patterns;
}

function handleFileChange(
  filePath: string,
  state: WatchState,
  ctx: CmdRunContext,
) {
  const debounceDelay = ctx.flags.debounce || 5000; // Use configured debounce or 5s default

  state.pendingChanges.add(filePath);

  console.log(chalk.dim(`📝 File changed: ${filePath}`));

  // Clear existing debounce timer
  if (state.debounceTimer) {
    clearTimeout(state.debounceTimer);
  }

  // Set new debounce timer
  state.debounceTimer = setTimeout(async () => {
    if (state.isRunning) {
      console.log(
        chalk.yellow("⏳ Translation already in progress, skipping..."),
      );
      return;
    }

    await triggerRetranslation(state, ctx);
  }, debounceDelay);
}

async function triggerRetranslation(state: WatchState, ctx: CmdRunContext) {
  if (state.isRunning) return;

  state.isRunning = true;

  try {
    const changedFiles = Array.from(state.pendingChanges);
    state.pendingChanges.clear();

    console.log(chalk.hex(colors.green)("\n🔄 Triggering retranslation..."));
    console.log(chalk.dim(`Changed files: ${changedFiles.join(", ")}`));
    console.log("");

    // Create a new context for this run (preserve original flags but reset tasks/results)
    const runCtx: CmdRunContext = {
      ...ctx,
      tasks: [],
      results: new Map(),
    };

    // Re-run the translation pipeline
    await plan(runCtx);

    if (runCtx.tasks.length === 0) {
      console.log(chalk.dim("✨ No translation tasks needed"));
    } else {
      await execute(runCtx);
      await renderSummary(runCtx.results);
    }

    console.log(chalk.hex(colors.green)("✅ Retranslation completed"));
    console.log(chalk.dim("👀 Continuing to watch for changes...\n"));
  } catch (error: any) {
    console.error(chalk.red(`❌ Retranslation failed: ${error.message}`));
    console.log(chalk.dim("👀 Continuing to watch for changes...\n"));
  } finally {
    state.isRunning = false;
  }
}

```
Page 5/16FirstPrevNextLast