#
tokens: 46260/50000 5/626 files (page 12/16)
lines: off (toggle) GitHub
raw markdown copy
This is page 12 of 16. Use http://codebase.md/lingodotdev/lingo.dev?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

--------------------------------------------------------------------------------
/demo/next-app/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
# next-app

## 0.2.81

### Patch Changes

- Updated dependencies [[`68fb3ea`](https://github.com/lingodotdev/lingo.dev/commit/68fb3ea64fc0191ecee66403432e0c8efabab2b9)]:
  - [email protected]

## 0.2.80

### Patch Changes

- Updated dependencies [[`e70385b`](https://github.com/lingodotdev/lingo.dev/commit/e70385bd1ac676bf5bd31b212d8510e6b7ebf793)]:
  - [email protected]

## 0.2.79

### Patch Changes

- Updated dependencies [[`f7215c1`](https://github.com/lingodotdev/lingo.dev/commit/f7215c1e435378aac8fc953765335cd478cbf507)]:
  - [email protected]

## 0.2.78

### Patch Changes

- Updated dependencies [[`898bd36`](https://github.com/lingodotdev/lingo.dev/commit/898bd36cc2e444641560d2ad2b28065a57072183)]:
  - [email protected]

## 0.2.77

### Patch Changes

- Updated dependencies [[`060680c`](https://github.com/lingodotdev/lingo.dev/commit/060680cd13c05dd77dd9d5447c064d948bd21cb0), [`f102356`](https://github.com/lingodotdev/lingo.dev/commit/f102356e1ea12c800399ac11f074c42708c304b1), [`a956e53`](https://github.com/lingodotdev/lingo.dev/commit/a956e537d0d45565c3243dd0c5ba4eec8bed69c6), [`3fd38c2`](https://github.com/lingodotdev/lingo.dev/commit/3fd38c2d38e4b22dcd824c865fe31abbc56bc862)]:
  - [email protected]

## 0.2.76

### Patch Changes

- Updated dependencies [[`03671f7`](https://github.com/lingodotdev/lingo.dev/commit/03671f7cb252d6bee3debce2f4a4eb989dc0050b)]:
  - [email protected]

## 0.2.75

### Patch Changes

- Updated dependencies [[`4f5ffe6`](https://github.com/lingodotdev/lingo.dev/commit/4f5ffe62189949bb26a6c7825cb72c217aefa32f)]:
  - [email protected]

## 0.2.74

### Patch Changes

- Updated dependencies [[`be8de32`](https://github.com/lingodotdev/lingo.dev/commit/be8de3280bb5dc5f409fc7680c0e5ff6a53e2fe5)]:
  - [email protected]

## 0.2.73

### Patch Changes

- Updated dependencies [[`79c4c00`](https://github.com/lingodotdev/lingo.dev/commit/79c4c00108b9c102cf53e1c090b286070a43e3d5)]:
  - [email protected]

## 0.2.72

### Patch Changes

- Updated dependencies [[`b45347c`](https://github.com/lingodotdev/lingo.dev/commit/b45347c38572ee371b2bc494261b7e3e90c4aed1)]:
  - [email protected]

## 0.2.71

### Patch Changes

- Updated dependencies [[`74d8efe`](https://github.com/lingodotdev/lingo.dev/commit/74d8efef8d4789f9baa5b7837e053c2571df0308)]:
  - [email protected]

## 0.2.70

### Patch Changes

- Updated dependencies [[`3d3c3d7`](https://github.com/lingodotdev/lingo.dev/commit/3d3c3d783a61443da50a5d182391db33a0d29c84)]:
  - [email protected]

## 0.2.69

### Patch Changes

- Updated dependencies [[`38139c8`](https://github.com/lingodotdev/lingo.dev/commit/38139c81a85001739cece60873c0c6ad711327a4)]:
  - [email protected]

## 0.2.68

### Patch Changes

- Updated dependencies [[`3413dad`](https://github.com/lingodotdev/lingo.dev/commit/3413dad22af688a6d26649c4f25e18304b3caee6)]:
  - [email protected]

## 0.2.67

### Patch Changes

- Updated dependencies [[`26d2ec1`](https://github.com/lingodotdev/lingo.dev/commit/26d2ec155c5868a5bdce1027cd76a5a2d4f8f2b1)]:
  - [email protected]

## 0.2.66

### Patch Changes

- Updated dependencies [[`82f5e7c`](https://github.com/lingodotdev/lingo.dev/commit/82f5e7cdde9a2a15b4c2a7fcb8c67ed64eab596b), [`e858174`](https://github.com/lingodotdev/lingo.dev/commit/e858174fd5165e0ea3e3f25fa1fc3edb292bc58f)]:
  - [email protected]

## 0.2.65

### Patch Changes

- Updated dependencies [[`f3d4987`](https://github.com/lingodotdev/lingo.dev/commit/f3d4987ddc393c28d488f030c087f3e99a667975), [`a933b81`](https://github.com/lingodotdev/lingo.dev/commit/a933b8102763e0481f088c847da53e0eee3f0617)]:
  - [email protected]

## 0.2.64

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.63

### Patch Changes

- Updated dependencies [[`dd0663f`](https://github.com/lingodotdev/lingo.dev/commit/dd0663fdcdd0ff4fd5748386758a8c20f9e52a4b)]:
  - [email protected]

## 0.2.62

### Patch Changes

- Updated dependencies [[`762396b`](https://github.com/lingodotdev/lingo.dev/commit/762396bb37110dbe3e4e000edb27892b318aa3ef)]:
  - [email protected]

## 0.2.61

### Patch Changes

- Updated dependencies [[`468a59b`](https://github.com/lingodotdev/lingo.dev/commit/468a59b89736c72253b1f32abbf30a950e5434ec)]:
  - [email protected]

## 0.2.60

### Patch Changes

- Updated dependencies [[`bbc71b9`](https://github.com/lingodotdev/lingo.dev/commit/bbc71b9948ccc289c9669d8b0c276c9596f6a5e7)]:
  - [email protected]

## 0.2.59

### Patch Changes

- Updated dependencies [[`0e6d605`](https://github.com/lingodotdev/lingo.dev/commit/0e6d605a9ad6835bef26c40895760c652a69b7a2)]:
  - [email protected]

## 0.2.58

### Patch Changes

- Updated dependencies [[`03138da`](https://github.com/lingodotdev/lingo.dev/commit/03138dac37e869e2e99702ffd3c76532f1c58aa6), [`9557fe5`](https://github.com/lingodotdev/lingo.dev/commit/9557fe572d3e4a1a4d8c1e35417fe3b7531c3d52)]:
  - [email protected]

## 0.2.57

### Patch Changes

- Updated dependencies [[`64225d0`](https://github.com/lingodotdev/lingo.dev/commit/64225d073999d599ba86f65fee8e08e3e5f2800b)]:
  - [email protected]

## 0.2.56

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.55

### Patch Changes

- Updated dependencies [[`88b7e31`](https://github.com/lingodotdev/lingo.dev/commit/88b7e3132c77d0a1e823de4ee6ef5a96a3098b97)]:
  - [email protected]

## 0.2.54

### Patch Changes

- Updated dependencies [[`d9294c0`](https://github.com/lingodotdev/lingo.dev/commit/d9294c0bbb993454ad3654f77dd48d82211e0465)]:
  - [email protected]

## 0.2.53

### Patch Changes

- Updated dependencies [[`100b141`](https://github.com/lingodotdev/lingo.dev/commit/100b141d2143e33b603830475ba55089dc421e3d)]:
  - [email protected]

## 0.2.52

### Patch Changes

- Updated dependencies [[`8741a20`](https://github.com/lingodotdev/lingo.dev/commit/8741a20dcaa3983131a1919f875dd2c264cb29fb)]:
  - [email protected]

## 0.2.51

### Patch Changes

- Updated dependencies [[`bd3f69d`](https://github.com/lingodotdev/lingo.dev/commit/bd3f69dde76814146f775bc87241fa2fad012ab0)]:
  - [email protected]

## 0.2.50

### Patch Changes

- Updated dependencies [[`6c174c3`](https://github.com/lingodotdev/lingo.dev/commit/6c174c38f3cf28c2af24ead18503658c3c641026)]:
  - [email protected]

## 0.2.49

### Patch Changes

- Updated dependencies [[`3a642f3`](https://github.com/lingodotdev/lingo.dev/commit/3a642f33c04378706a8382aa0fde36e747fd6af5)]:
  - [email protected]

## 0.2.48

### Patch Changes

- Updated dependencies [[`bc7b08e`](https://github.com/lingodotdev/lingo.dev/commit/bc7b08ef1245d1af0c68813cb18193d4f14bc7e0)]:
  - [email protected]

## 0.2.47

### Patch Changes

- Updated dependencies [[`b6071e4`](https://github.com/lingodotdev/lingo.dev/commit/b6071e4f19dd1823f4f2ce54ba5495538a94d4fd)]:
  - [email protected]

## 0.2.46

### Patch Changes

- Updated dependencies [[`e898c1e`](https://github.com/lingodotdev/lingo.dev/commit/e898c1eeb34e4dd3e74df26465802b520018acf9)]:
  - [email protected]

## 0.2.45

### Patch Changes

- Updated dependencies [[`410825c`](https://github.com/lingodotdev/lingo.dev/commit/410825c8bf0029d8ee458514d6f203a7397c8f22)]:
  - [email protected]

## 0.2.44

### Patch Changes

- Updated dependencies [[`555384d`](https://github.com/lingodotdev/lingo.dev/commit/555384dacf79167e1bb8b9e6871e153fea763471)]:
  - [email protected]

## 0.2.43

### Patch Changes

- Updated dependencies [[`c0486ca`](https://github.com/lingodotdev/lingo.dev/commit/c0486ca9b0451ea75d070e199f502507ba418e5e)]:
  - [email protected]

## 0.2.42

### Patch Changes

- Updated dependencies [[`99aae2d`](https://github.com/lingodotdev/lingo.dev/commit/99aae2d09a26060c810913f740893a4a5874d9d4)]:
  - [email protected]

## 0.2.41

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.40

### Patch Changes

- Updated dependencies [[`6af91a0`](https://github.com/lingodotdev/lingo.dev/commit/6af91a083d16f85051fb49a4034789abe784017e)]:
  - [email protected]

## 0.2.39

### Patch Changes

- Updated dependencies [[`1ff847b`](https://github.com/lingodotdev/lingo.dev/commit/1ff847b9273a3082178553e70c22524f5831ad36), [`55e9e68`](https://github.com/lingodotdev/lingo.dev/commit/55e9e687a3d0efa84b808818a848a276b1a42015), [`b9e2551`](https://github.com/lingodotdev/lingo.dev/commit/b9e2551f349e33542212f941b3407e8517b5fb27)]:
  - [email protected]

## 0.2.38

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.37

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.36

### Patch Changes

- Updated dependencies [[`20a3737`](https://github.com/lingodotdev/lingo.dev/commit/20a3737ddb50b2a97699e57e03ea353b8912b78f)]:
  - [email protected]

## 0.2.35

### Patch Changes

- Updated dependencies [[`afbb978`](https://github.com/lingodotdev/lingo.dev/commit/afbb978fec83d574f2c43b7d68457e435fca9b57)]:
  - [email protected]

## 0.2.34

### Patch Changes

- Updated dependencies [[`1f1e33f`](https://github.com/lingodotdev/lingo.dev/commit/1f1e33fe4d0767c2f026214a505a2aa9f3785996), [`9266fd0`](https://github.com/lingodotdev/lingo.dev/commit/9266fd0bcddf4b07ca51d2609af92a9473106f9d)]:
  - [email protected]

## 0.2.33

### Patch Changes

- Updated dependencies [[`6baa1a7`](https://github.com/lingodotdev/lingo.dev/commit/6baa1a7e88dbfac3783d1d49695595077fd8d209)]:
  - [email protected]

## 0.2.32

### Patch Changes

- Updated dependencies [[`925997d`](https://github.com/lingodotdev/lingo.dev/commit/925997d75a1edbb4211a3be8db2b186cb139327e)]:
  - [email protected]

## 0.2.31

### Patch Changes

- Updated dependencies [[`cb2aa0f`](https://github.com/lingodotdev/lingo.dev/commit/cb2aa0f505d6b7dbc435b526e8a6f62265d1f453)]:
  - [email protected]

## 0.2.30

### Patch Changes

- Updated dependencies [[`bfcb424`](https://github.com/lingodotdev/lingo.dev/commit/bfcb424eb4479d0d3b767e062d30f02c5bcaeb14)]:
  - [email protected]

## 0.2.29

### Patch Changes

- Updated dependencies [[`2b297ba`](https://github.com/lingodotdev/lingo.dev/commit/2b297babe76f9799c5154d9421fecd1ebbe1bb72)]:
  - [email protected]

## 0.2.28

### Patch Changes

- Updated dependencies [[`30faa6d`](https://github.com/lingodotdev/lingo.dev/commit/30faa6d10e851a38ced86ae403b3a1fd48440bca)]:
  - [email protected]

## 0.2.27

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.26

### Patch Changes

- Updated dependencies [[`4e9e368`](https://github.com/lingodotdev/lingo.dev/commit/4e9e36830ee4277ef9d65eee9ee92380a95a622c)]:
  - [email protected]

## 0.2.25

### Patch Changes

- Updated dependencies [[`65701e5`](https://github.com/lingodotdev/lingo.dev/commit/65701e5b9694e811587ef600227251a1ff1384a0), [`4e55355`](https://github.com/lingodotdev/lingo.dev/commit/4e5535535029743b7a0edc4fdab3d4ee71374035)]:
  - [email protected]

## 0.2.24

### Patch Changes

- Updated dependencies [[`f644123`](https://github.com/lingodotdev/lingo.dev/commit/f644123ddf6a6254790d08af50141e4dd78c3677)]:
  - [email protected]

## 0.2.23

### Patch Changes

- Updated dependencies [[`29cf6a7`](https://github.com/lingodotdev/lingo.dev/commit/29cf6a7359707e0e341c11942d1ce6dedf7e66e5)]:
  - [email protected]

## 0.2.22

### Patch Changes

- Updated dependencies [[`b249484`](https://github.com/lingodotdev/lingo.dev/commit/b249484d6f0060e29cd5b50b3d8ce68b857ccad5)]:
  - [email protected]

## 0.2.21

### Patch Changes

- Updated dependencies [[`f7debef`](https://github.com/lingodotdev/lingo.dev/commit/f7debef9f004e670bb1f6a45ae17067a72a6e53f)]:
  - [email protected]

## 0.2.20

### Patch Changes

- Updated dependencies [[`da6f0c8`](https://github.com/lingodotdev/lingo.dev/commit/da6f0c85e69687615df943323d261078742ba3f2)]:
  - [email protected]

## 0.2.19

### Patch Changes

- Updated dependencies [[`8b306bc`](https://github.com/lingodotdev/lingo.dev/commit/8b306bcd0a3231ffd8bde283414b6d069b7a5b99), [`013fca0`](https://github.com/lingodotdev/lingo.dev/commit/013fca0f4252103ee3009fe3cdcfce2a87c80058)]:
  - [email protected]

## 0.2.18

### Patch Changes

- Updated dependencies [[`84fd214`](https://github.com/lingodotdev/lingo.dev/commit/84fd214a21766e7683c5d645fcb8c4c0162eb0b6), [`0fc6385`](https://github.com/lingodotdev/lingo.dev/commit/0fc63856c6f49ac68a220b6e2f1c4f060e7ce78e), [`cac5429`](https://github.com/lingodotdev/lingo.dev/commit/cac54296d512d436dc3861441d5d1a3f1076792b)]:
  - [email protected]

## 0.2.17

### Patch Changes

- Updated dependencies [[`ce0e5cd`](https://github.com/lingodotdev/lingo.dev/commit/ce0e5cd6d1ec17f5c593d394ceb63a28666df924)]:
  - [email protected]

## 0.2.16

### Patch Changes

- Updated dependencies [[`ce8c75c`](https://github.com/lingodotdev/lingo.dev/commit/ce8c75c7fc1a2124d3e18444bc356c4dfce26434)]:
  - [email protected]

## 0.2.15

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.14

### Patch Changes

- Updated dependencies [[`d80285a`](https://github.com/lingodotdev/lingo.dev/commit/d80285a9b12bd85425564cb00e558812fd0aee40)]:
  - [email protected]

## 0.2.13

### Patch Changes

- Updated dependencies [[`81eff21`](https://github.com/lingodotdev/lingo.dev/commit/81eff2104a4401b1c1b6cdf4dcc7ca75b7411ba4)]:
  - [email protected]

## 0.2.12

### Patch Changes

- Updated dependencies [[`b39b04a`](https://github.com/lingodotdev/lingo.dev/commit/b39b04ad83d3c8001008c3cefe309d8e762b2adc), [`4e5983d`](https://github.com/lingodotdev/lingo.dev/commit/4e5983d7e59ebf9eb529c4b7c1c87689432ac873)]:
  - [email protected]

## 0.2.11

### Patch Changes

- Updated dependencies [[`1a3cbc1`](https://github.com/lingodotdev/lingo.dev/commit/1a3cbc1751c64e5617e91812506b3c061475f16a)]:
  - [email protected]

## 0.2.10

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.9

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.8

### Patch Changes

- [`8e97256`](https://github.com/lingodotdev/lingo.dev/commit/8e97256ca4e78dd09a967539ca9dec359bd558ef) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - fix dictionary merging

- Updated dependencies []:
  - [email protected]

## 0.2.7

### Patch Changes

- [#925](https://github.com/lingodotdev/lingo.dev/pull/925) [`215af19`](https://github.com/lingodotdev/lingo.dev/commit/215af1944667cce66e9c5966f4fb627186687b74) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - improved compiler concurrency, caching, added lingo.dev engine to the compiler, and updated demo apps

- Updated dependencies [[`1b9b113`](https://github.com/lingodotdev/lingo.dev/commit/1b9b11301978e8caa2555832d027ff93216aa6e1), [`0329a9c`](https://github.com/lingodotdev/lingo.dev/commit/0329a9cdb5e5a63fcecab4efcd7cce22f155a0e9)]:
  - [email protected]

## 0.2.6

### Patch Changes

- Updated dependencies [[`3b6574f`](https://github.com/lingodotdev/lingo.dev/commit/3b6574f0499f3f4d3c48f66ba2b828d2c1c0ceb0), [`6b4b9e6`](https://github.com/lingodotdev/lingo.dev/commit/6b4b9e6cc9a0cb5da8a4df9e9ebda474bf2a18ed), [`6b4b9e6`](https://github.com/lingodotdev/lingo.dev/commit/6b4b9e6cc9a0cb5da8a4df9e9ebda474bf2a18ed)]:
  - [email protected]

## 0.2.5

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.4

### Patch Changes

- Updated dependencies [[`2dd8170`](https://github.com/lingodotdev/lingo.dev/commit/2dd8170ff0101268f2253c9248409d184da5f75c)]:
  - [email protected]

## 0.2.3

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.2.2

### Patch Changes

- Updated dependencies [[`cc232eb`](https://github.com/lingodotdev/lingo.dev/commit/cc232eb72d0e54b3571bbb70e88cdad24ba6372a)]:
  - [email protected]

## 0.2.1

### Patch Changes

- Updated dependencies [[`fead8e0`](https://github.com/lingodotdev/lingo.dev/commit/fead8e08dc2b2869a093cb25a04f6e0aa78cf6b7)]:
  - [email protected]

## 0.2.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.

### Patch Changes

- Updated dependencies [[`a5da697`](https://github.com/lingodotdev/lingo.dev/commit/a5da697f7efd46de31d17b202d06eb5f655ed9b9), [`10a0139`](https://github.com/lingodotdev/lingo.dev/commit/10a0139edc9ffbc1c52ac2226f6b0f345cc19878)]:
  - [email protected]

## 0.1.23

### Patch Changes

- Updated dependencies [[`3bd4045`](https://github.com/lingodotdev/lingo.dev/commit/3bd40450cbb5c8aabce61d7f1f3ab9c7293323d9)]:
  - [email protected]

## 0.1.22

### Patch Changes

- Updated dependencies [[`f140f82`](https://github.com/lingodotdev/lingo.dev/commit/f140f820d00b15f99214a7eece1a9c7f0d098e90)]:
  - [email protected]

## 0.1.21

### Patch Changes

- Updated dependencies [[`145fb74`](https://github.com/lingodotdev/lingo.dev/commit/145fb74c09b42c8810f351be5a641b1366881ae1), [`0c45acc`](https://github.com/lingodotdev/lingo.dev/commit/0c45accfc45e63f597758c47033bc58d2f6059b5)]:
  - [email protected]

## 0.1.20

### Patch Changes

- Updated dependencies [[`511a2ec`](https://github.com/lingodotdev/lingo.dev/commit/511a2ecd68a9c5e2800035d5c6a6b5b31b2dc80f)]:
  - [email protected]

## 0.1.19

### Patch Changes

- Updated dependencies [[`7191444`](https://github.com/lingodotdev/lingo.dev/commit/7191444f67864ea5b5a91a9be759b2445bf186d3)]:
  - [email protected]

## 0.1.18

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.17

### Patch Changes

- Updated dependencies [[`af011b1`](https://github.com/lingodotdev/lingo.dev/commit/af011b18fe96f15287609278f4d4d2b343b6c2cc)]:
  - [email protected]

## 0.1.16

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.15

### Patch Changes

- Updated dependencies [[`3750c9c`](https://github.com/lingodotdev/lingo.dev/commit/3750c9ca25a78280b04e4a2b2e6641dd21f9f3b0)]:
  - [email protected]

## 0.1.14

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.13

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.12

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.11

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.10

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.9

### Patch Changes

- Updated dependencies [[`cb7d5e2`](https://github.com/lingodotdev/lingo.dev/commit/cb7d5e213282c00af658159472183a763f84ca3d)]:
  - [email protected]

## 0.1.8

### Patch Changes

- Updated dependencies [[`5d27455`](https://github.com/lingodotdev/lingo.dev/commit/5d2745545044cbaddb099f7920c96fe198879ba3)]:
  - [email protected]

## 0.1.7

### Patch Changes

- Updated dependencies [[`b67a331`](https://github.com/lingodotdev/lingo.dev/commit/b67a33141253fa755b5531e52cd690bf5824d4b6)]:
  - [email protected]

## 0.1.6

### Patch Changes

- Updated dependencies []:
  - [email protected]

## 0.1.5

### Patch Changes

- Updated dependencies [[`f42cff8`](https://github.com/lingodotdev/lingo.dev/commit/f42cff8355b1ff7bba1445bd04d11ee4672903c2)]:
  - [email protected]

## 0.1.4

### Patch Changes

- Updated dependencies [[`920e3f5`](https://github.com/lingodotdev/lingo.dev/commit/920e3f5c3ca1fd51b0919db13a4787cfd616de54)]:
  - [email protected]

## 0.1.3

### Patch Changes

- Updated dependencies [[`cdb59dd`](https://github.com/lingodotdev/lingo.dev/commit/cdb59dddcd14da1ba3181a33c4c119af877cb4f3)]:
  - [email protected]

## 0.1.2

### Patch Changes

- Updated dependencies [[`caef325`](https://github.com/lingodotdev/lingo.dev/commit/caef3253bc99fa7bf7a0b40e5604c3590dcb4958)]:
  - [email protected]

## 0.1.1

### Patch Changes

- Updated dependencies [[`e980e84`](https://github.com/lingodotdev/lingo.dev/commit/e980e84178439ad70417d38b425acf9148cfc4b6)]:
  - [email protected]

```

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

```typescript
import Z from "zod";
import { LocaleCode, localeCodeSchema } from "@lingo.dev/_spec";
import { createId } from "@paralleldrive/cuid2";

const engineParamsSchema = Z.object({
  apiKey: Z.string(),
  apiUrl: Z.string().url().default("https://engine.lingo.dev"),
  batchSize: Z.number().int().gt(0).lte(250).default(25),
  idealBatchItemSize: Z.number().int().gt(0).lte(2500).default(250),
}).passthrough();

const payloadSchema = Z.record(Z.string(), Z.any());
const referenceSchema = Z.record(localeCodeSchema, payloadSchema);
const hintsSchema = Z.record(Z.string(), Z.array(Z.string()));

const localizationParamsSchema = Z.object({
  sourceLocale: Z.union([localeCodeSchema, Z.null()]),
  targetLocale: localeCodeSchema,
  fast: Z.boolean().optional(),
  reference: referenceSchema.optional(),
  hints: hintsSchema.optional(),
});

/**
 * LingoDotDevEngine class for interacting with the LingoDotDev API
 * A powerful localization engine that supports various content types including
 * plain text, objects, chat sequences, and HTML documents.
 */
export class LingoDotDevEngine {
  protected config: Z.infer<typeof engineParamsSchema>;

  /**
   * Create a new LingoDotDevEngine instance
   * @param config - Configuration options for the Engine
   */
  constructor(config: Partial<Z.infer<typeof engineParamsSchema>>) {
    this.config = engineParamsSchema.parse(config);
  }

  /**
   * Localize content using the Lingo.dev API
   * @param payload - The content to be localized
   * @param params - Localization parameters including source/target locales and fast mode option
   * @param progressCallback - Optional callback function to report progress (0-100)
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns Localized content
   * @internal
   */
  async _localizeRaw(
    payload: Z.infer<typeof payloadSchema>,
    params: Z.infer<typeof localizationParamsSchema>,
    progressCallback?: (
      progress: number,
      sourceChunk: Record<string, string>,
      processedChunk: Record<string, string>,
    ) => void,
    signal?: AbortSignal,
  ): Promise<Record<string, string>> {
    const finalPayload = payloadSchema.parse(payload);
    const finalParams = localizationParamsSchema.parse(params);

    const chunkedPayload = this.extractPayloadChunks(finalPayload);
    const processedPayloadChunks: Record<string, string>[] = [];

    const workflowId = createId();
    for (let i = 0; i < chunkedPayload.length; i++) {
      const chunk = chunkedPayload[i];
      const percentageCompleted = Math.round(
        ((i + 1) / chunkedPayload.length) * 100,
      );

      const processedPayloadChunk = await this.localizeChunk(
        finalParams.sourceLocale,
        finalParams.targetLocale,
        { data: chunk, reference: params.reference, hints: params.hints },
        workflowId,
        params.fast || false,
        signal,
      );

      if (progressCallback) {
        progressCallback(percentageCompleted, chunk, processedPayloadChunk);
      }

      processedPayloadChunks.push(processedPayloadChunk);
    }

    return Object.assign({}, ...processedPayloadChunks);
  }

  /**
   * Localize a single chunk of content
   * @param sourceLocale - Source locale
   * @param targetLocale - Target locale
   * @param payload - Payload containing the chunk to be localized
   * @param workflowId - Workflow ID for tracking
   * @param fast - Whether to use fast mode
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns Localized chunk
   */
  private async localizeChunk(
    sourceLocale: string | null,
    targetLocale: string,
    payload: {
      data: Z.infer<typeof payloadSchema>;
      reference?: Z.infer<typeof referenceSchema>;
      hints?: Z.infer<typeof hintsSchema>;
    },
    workflowId: string,
    fast: boolean,
    signal?: AbortSignal,
  ): Promise<Record<string, string>> {
    const res = await fetch(`${this.config.apiUrl}/i18n`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json; charset=utf-8",
        Authorization: `Bearer ${this.config.apiKey}`,
      },
      body: JSON.stringify(
        {
          params: { workflowId, fast },
          locale: {
            source: sourceLocale,
            target: targetLocale,
          },
          data: payload.data,
          reference: payload.reference,
          hints: payload.hints,
        },
        null,
        2,
      ),
      signal,
    });

    if (!res.ok) {
      if (res.status >= 500 && res.status < 600) {
        const errorText = await res.text();
        throw new Error(
          `Server error (${res.status}): ${res.statusText}. ${errorText}. This may be due to temporary service issues.`,
        );
      } else if (res.status === 400) {
        throw new Error(`Invalid request: ${res.statusText}`);
      } else {
        const errorText = await res.text();
        throw new Error(errorText);
      }
    }

    const jsonResponse = await res.json();

    // when streaming the error is returned in the response body
    if (!jsonResponse.data && jsonResponse.error) {
      throw new Error(jsonResponse.error);
    }

    return jsonResponse.data || {};
  }

  /**
   * Extract payload chunks based on the ideal chunk size
   * @param payload - The payload to be chunked
   * @returns An array of payload chunks
   */
  private extractPayloadChunks(
    payload: Record<string, string>,
  ): Record<string, string>[] {
    const result: Record<string, string>[] = [];
    let currentChunk: Record<string, string> = {};
    let currentChunkItemCount = 0;

    const payloadEntries = Object.entries(payload);
    for (let i = 0; i < payloadEntries.length; i++) {
      const [key, value] = payloadEntries[i];
      currentChunk[key] = value;
      currentChunkItemCount++;

      const currentChunkSize = this.countWordsInRecord(currentChunk);
      if (
        currentChunkSize > this.config.idealBatchItemSize ||
        currentChunkItemCount >= this.config.batchSize ||
        i === payloadEntries.length - 1
      ) {
        result.push(currentChunk);
        currentChunk = {};
        currentChunkItemCount = 0;
      }
    }

    return result;
  }

  /**
   * Count words in a record or array
   * @param payload - The payload to count words in
   * @returns The total number of words
   */
  private countWordsInRecord(
    payload: any | Record<string, any> | Array<any>,
  ): number {
    if (Array.isArray(payload)) {
      return payload.reduce(
        (acc, item) => acc + this.countWordsInRecord(item),
        0,
      );
    } else if (typeof payload === "object" && payload !== null) {
      return Object.values(payload).reduce(
        (acc: number, item) => acc + this.countWordsInRecord(item),
        0,
      );
    } else if (typeof payload === "string") {
      return payload.trim().split(/\s+/).filter(Boolean).length;
    } else {
      return 0;
    }
  }

  /**
   * Localize a typical JavaScript object
   * @param obj - The object to be localized (strings will be extracted and translated)
   * @param params - Localization parameters:
   *   - sourceLocale: The source language code (e.g., 'en')
   *   - targetLocale: The target language code (e.g., 'es')
   *   - fast: Optional boolean to enable fast mode (faster but potentially lower quality)
   * @param progressCallback - Optional callback function to report progress (0-100)
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns A new object with the same structure but localized string values
   */
  async localizeObject(
    obj: Record<string, any>,
    params: Z.infer<typeof localizationParamsSchema>,
    progressCallback?: (
      progress: number,
      sourceChunk: Record<string, string>,
      processedChunk: Record<string, string>,
    ) => void,
    signal?: AbortSignal,
  ): Promise<Record<string, any>> {
    return this._localizeRaw(obj, params, progressCallback, signal);
  }

  /**
   * Localize a single text string
   * @param text - The text string to be localized
   * @param params - Localization parameters:
   *   - sourceLocale: The source language code (e.g., 'en')
   *   - targetLocale: The target language code (e.g., 'es')
   *   - fast: Optional boolean to enable fast mode (faster for bigger batches)
   * @param progressCallback - Optional callback function to report progress (0-100)
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns The localized text string
   */
  async localizeText(
    text: string,
    params: Z.infer<typeof localizationParamsSchema>,
    progressCallback?: (progress: number) => void,
    signal?: AbortSignal,
  ): Promise<string> {
    const response = await this._localizeRaw(
      { text },
      params,
      progressCallback,
      signal,
    );
    return response.text || "";
  }

  /**
   * Localize a text string to multiple target locales
   * @param text - The text string to be localized
   * @param params - Localization parameters:
   *   - sourceLocale: The source language code (e.g., 'en')
   *   - targetLocales: An array of target language codes (e.g., ['es', 'fr'])
   *   - fast: Optional boolean to enable fast mode (for bigger batches)
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns An array of localized text strings
   */
  async batchLocalizeText(
    text: string,
    params: {
      sourceLocale: LocaleCode;
      targetLocales: LocaleCode[];
      fast?: boolean;
    },
    signal?: AbortSignal,
  ) {
    const responses = await Promise.all(
      params.targetLocales.map((targetLocale) =>
        this.localizeText(
          text,
          {
            sourceLocale: params.sourceLocale,
            targetLocale,
            fast: params.fast,
          },
          undefined,
          signal,
        ),
      ),
    );

    return responses;
  }

  /**
   * Localize an array of strings
   * @param strings - An array of strings to be localized
   * @param params - Localization parameters:
   *   - sourceLocale: The source language code (e.g., 'en')
   *   - targetLocale: The target language code (e.g., 'es')
   *   - fast: Optional boolean to enable fast mode (faster for bigger batches)
   * @returns An array of localized strings in the same order
   */
  async localizeStringArray(
    strings: string[],
    params: Z.infer<typeof localizationParamsSchema>,
  ): Promise<string[]> {
    const mapped = strings.reduce(
      (acc, str, i) => {
        acc[`item_${i}`] = str;
        return acc;
      },
      {} as Record<string, string>,
    );

    const result = await this.localizeObject(mapped, params);
    return Object.values(result);
  }

  /**
   * Localize a chat sequence while preserving speaker names
   * @param chat - Array of chat messages, each with 'name' and 'text' properties
   * @param params - Localization parameters:
   *   - sourceLocale: The source language code (e.g., 'en')
   *   - targetLocale: The target language code (e.g., 'es')
   *   - fast: Optional boolean to enable fast mode (faster but potentially lower quality)
   * @param progressCallback - Optional callback function to report progress (0-100)
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns Array of localized chat messages with preserved structure
   */
  async localizeChat(
    chat: Array<{ name: string; text: string }>,
    params: Z.infer<typeof localizationParamsSchema>,
    progressCallback?: (progress: number) => void,
    signal?: AbortSignal,
  ): Promise<Array<{ name: string; text: string }>> {
    const localized = await this._localizeRaw(
      { chat },
      params,
      progressCallback,
      signal,
    );

    return Object.entries(localized).map(([key, value]) => ({
      name: chat[parseInt(key.split("_")[1])].name,
      text: value,
    }));
  }

  /**
   * Localize an HTML document while preserving structure and formatting
   * Handles both text content and localizable attributes (alt, title, placeholder, meta content)
   * @param html - The HTML document string to be localized
   * @param params - Localization parameters:
   *   - sourceLocale: The source language code (e.g., 'en')
   *   - targetLocale: The target language code (e.g., 'es')
   *   - fast: Optional boolean to enable fast mode (faster but potentially lower quality)
   * @param progressCallback - Optional callback function to report progress (0-100)
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns The localized HTML document as a string, with updated lang attribute
   */
  async localizeHtml(
    html: string,
    params: Z.infer<typeof localizationParamsSchema>,
    progressCallback?: (progress: number) => void,
    signal?: AbortSignal,
  ): Promise<string> {
    const jsdomPackage = await import("jsdom");
    const { JSDOM } = jsdomPackage;
    const dom = new JSDOM(html);
    const document = dom.window.document;

    const LOCALIZABLE_ATTRIBUTES: Record<string, string[]> = {
      meta: ["content"],
      img: ["alt"],
      input: ["placeholder"],
      a: ["title"],
    };
    const UNLOCALIZABLE_TAGS = ["script", "style"];

    const extractedContent: Record<string, string> = {};

    const getPath = (node: Node, attribute?: string): string => {
      const indices: number[] = [];
      let current = node as ChildNode;
      let rootParent = "";

      while (current) {
        const parent = current.parentElement as Element;
        if (!parent) break;

        if (parent === document.documentElement) {
          rootParent = current.nodeName.toLowerCase();
          break;
        }

        const siblings = Array.from(parent.childNodes).filter(
          (n) =>
            n.nodeType === 1 || (n.nodeType === 3 && n.textContent?.trim()),
        );
        const index = siblings.indexOf(current);
        if (index !== -1) {
          indices.unshift(index);
        }
        current = parent;
      }

      const basePath = rootParent
        ? `${rootParent}/${indices.join("/")}`
        : indices.join("/");
      return attribute ? `${basePath}#${attribute}` : basePath;
    };

    const processNode = (node: Node) => {
      let parent = node.parentElement;
      while (parent) {
        if (UNLOCALIZABLE_TAGS.includes(parent.tagName.toLowerCase())) {
          return;
        }
        parent = parent.parentElement;
      }

      if (node.nodeType === 3) {
        const text = node.textContent?.trim() || "";
        if (text) {
          extractedContent[getPath(node)] = text;
        }
      } else if (node.nodeType === 1) {
        const element = node as Element;
        const tagName = element.tagName.toLowerCase();

        const attributes = LOCALIZABLE_ATTRIBUTES[tagName] || [];
        attributes.forEach((attr) => {
          const value = element.getAttribute(attr);
          if (value) {
            extractedContent[getPath(element, attr)] = value;
          }
        });

        Array.from(element.childNodes)
          .filter(
            (n) =>
              n.nodeType === 1 || (n.nodeType === 3 && n.textContent?.trim()),
          )
          .forEach(processNode);
      }
    };

    Array.from(document.head.childNodes)
      .filter(
        (n) => n.nodeType === 1 || (n.nodeType === 3 && n.textContent?.trim()),
      )
      .forEach(processNode);
    Array.from(document.body.childNodes)
      .filter(
        (n) => n.nodeType === 1 || (n.nodeType === 3 && n.textContent?.trim()),
      )
      .forEach(processNode);

    const localizedContent = await this._localizeRaw(
      extractedContent,
      params,
      progressCallback,
      signal,
    );

    // Update the DOM with localized content
    document.documentElement.setAttribute("lang", params.targetLocale);

    Object.entries(localizedContent).forEach(([path, value]) => {
      const [nodePath, attribute] = path.split("#");
      const [rootTag, ...indices] = nodePath.split("/");

      let parent: Element = rootTag === "head" ? document.head : document.body;
      let current: Node | null = parent;

      for (const index of indices) {
        const siblings = Array.from(parent.childNodes).filter(
          (n) =>
            n.nodeType === 1 || (n.nodeType === 3 && n.textContent?.trim()),
        );
        current = siblings[parseInt(index)] || null;
        if (current?.nodeType === 1) {
          parent = current as Element;
        }
      }

      if (current) {
        if (attribute) {
          (current as Element).setAttribute(attribute, value);
        } else {
          current.textContent = value;
        }
      }
    });

    return dom.serialize();
  }

  /**
   * Detect the language of a given text
   * @param text - The text to analyze
   * @param signal - Optional AbortSignal to cancel the operation
   * @returns Promise resolving to a locale code (e.g., 'en', 'es', 'fr')
   */
  async recognizeLocale(
    text: string,
    signal?: AbortSignal,
  ): Promise<LocaleCode> {
    const response = await fetch(`${this.config.apiUrl}/recognize`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json; charset=utf-8",
        Authorization: `Bearer ${this.config.apiKey}`,
      },
      body: JSON.stringify({ text }),
      signal,
    });

    if (!response.ok) {
      if (response.status >= 500 && response.status < 600) {
        throw new Error(
          `Server error (${response.status}): ${response.statusText}. This may be due to temporary service issues.`,
        );
      }
      throw new Error(`Error recognizing locale: ${response.statusText}`);
    }

    const jsonResponse = await response.json();
    return jsonResponse.locale;
  }

  async whoami(
    signal?: AbortSignal,
  ): Promise<{ email: string; id: string } | null> {
    try {
      const res = await fetch(`${this.config.apiUrl}/whoami`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${this.config.apiKey}`,
          ContentType: "application/json",
        },
        signal,
      });

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

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

      if (res.status >= 500 && res.status < 600) {
        throw new Error(
          `Server error (${res.status}): ${res.statusText}. This may be due to temporary service issues.`,
        );
      }

      return null;
    } catch (error) {
      if (error instanceof Error && error.message.includes("Server error")) {
        throw error;
      }
      return null;
    }
  }
}

/**
 * @deprecated Use LingoDotDevEngine instead. This class is maintained for backwards compatibility.
 */
export class ReplexicaEngine extends LingoDotDevEngine {
  private static hasWarnedDeprecation = false;

  constructor(config: Partial<Z.infer<typeof engineParamsSchema>>) {
    super(config);
    if (!ReplexicaEngine.hasWarnedDeprecation) {
      console.warn(
        "ReplexicaEngine is deprecated and will be removed in a future release. " +
          "Please use LingoDotDevEngine instead. " +
          "See https://lingo.dev/cli for more information.",
      );
      ReplexicaEngine.hasWarnedDeprecation = true;
    }
  }
}

/**
 * @deprecated Use LingoDotDevEngine instead. This class is maintained for backwards compatibility.
 */
export class LingoEngine extends LingoDotDevEngine {
  private static hasWarnedDeprecation = false;

  constructor(config: Partial<Z.infer<typeof engineParamsSchema>>) {
    super(config);
    if (!LingoEngine.hasWarnedDeprecation) {
      console.warn(
        "LingoEngine is deprecated and will be removed in a future release. " +
          "Please use LingoDotDevEngine instead. " +
          "See https://lingo.dev/cli for more information.",
      );
      LingoEngine.hasWarnedDeprecation = true;
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/sdk/CHANGELOG.md:
--------------------------------------------------------------------------------

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

## 0.12.6

### Patch Changes

- [#1230](https://github.com/lingodotdev/lingo.dev/pull/1230) [`b45347c`](https://github.com/lingodotdev/lingo.dev/commit/b45347c38572ee371b2bc494261b7e3e90c4aed1) Thanks [@vrcprl](https://github.com/vrcprl)! - add an xcode-xcstrings-v2 bucket type that supports cldr pluralization rules

- Updated dependencies [[`b45347c`](https://github.com/lingodotdev/lingo.dev/commit/b45347c38572ee371b2bc494261b7e3e90c4aed1)]:
  - @lingo.dev/[email protected]

## 0.12.5

### Patch Changes

- Updated dependencies [[`82f5e7c`](https://github.com/lingodotdev/lingo.dev/commit/82f5e7cdde9a2a15b4c2a7fcb8c67ed64eab596b), [`e858174`](https://github.com/lingodotdev/lingo.dev/commit/e858174fd5165e0ea3e3f25fa1fc3edb292bc58f)]:
  - @lingo.dev/[email protected]

## 0.12.4

### Patch Changes

- Updated dependencies [[`1fa218c`](https://github.com/lingodotdev/lingo.dev/commit/1fa218c13bf90df6d175fb18264f59c1a10b967c)]:
  - @lingo.dev/[email protected]

## 0.12.3

### Patch Changes

- Updated dependencies [[`bbc71b9`](https://github.com/lingodotdev/lingo.dev/commit/bbc71b9948ccc289c9669d8b0c276c9596f6a5e7)]:
  - @lingo.dev/[email protected]

## 0.12.2

### Patch Changes

- Updated dependencies [[`6579d70`](https://github.com/lingodotdev/lingo.dev/commit/6579d70bc670c2fdc06c09842d931b07e134151c)]:
  - @lingo.dev/[email protected]

## 0.12.1

### Patch Changes

- Updated dependencies [[`a35032e`](https://github.com/lingodotdev/lingo.dev/commit/a35032e7e7a188d1f5e774576352068124526e24)]:
  - @lingo.dev/[email protected]

## 0.12.0

### Minor Changes

- [#1066](https://github.com/lingodotdev/lingo.dev/pull/1066) [`6af91a0`](https://github.com/lingodotdev/lingo.dev/commit/6af91a083d16f85051fb49a4034789abe784017e) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add hints support

### Patch Changes

- Updated dependencies [[`6af91a0`](https://github.com/lingodotdev/lingo.dev/commit/6af91a083d16f85051fb49a4034789abe784017e)]:
  - @lingo.dev/[email protected]

## 0.11.0

### Minor Changes

- [#1049](https://github.com/lingodotdev/lingo.dev/pull/1049) [`85dfc10`](https://github.com/lingodotdev/lingo.dev/commit/85dfc10961b116e31b2bb478f42013756ca49974) Thanks [@VAIBHAVSING](https://github.com/VAIBHAVSING)! - Added new methods to the SDK:

  1. `localizeStringArray`: Localizes an array of strings while maintaining their order.

  Also added comprehensive tests for these methods using Vitest.

## 0.10.2

### Patch Changes

- Updated dependencies [[`afbb978`](https://github.com/lingodotdev/lingo.dev/commit/afbb978fec83d574f2c43b7d68457e435fca9b57)]:
  - @lingo.dev/[email protected]

## 0.10.1

### Patch Changes

- [#1023](https://github.com/lingodotdev/lingo.dev/pull/1023) [`9266fd0`](https://github.com/lingodotdev/lingo.dev/commit/9266fd0bcddf4b07ca51d2609af92a9473106f9d) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Update Zod dependency to version 3.25.76

- Updated dependencies [[`9266fd0`](https://github.com/lingodotdev/lingo.dev/commit/9266fd0bcddf4b07ca51d2609af92a9473106f9d)]:
  - @lingo.dev/[email protected]

## 0.10.0

### Minor Changes

- [#998](https://github.com/lingodotdev/lingo.dev/pull/998) [`cb2aa0f`](https://github.com/lingodotdev/lingo.dev/commit/cb2aa0f505d6b7dbc435b526e8a6f62265d1f453) Thanks [@VAIBHAVSING](https://github.com/VAIBHAVSING)! - Added support for AbortController to all public SDK methods, enabling consumers to cancel long-running operations using the standard AbortController API. Refactored internal methods to propagate AbortSignal and check for abortion between batch chunks. Updated fetch calls to use AbortSignal for network request cancellation.

## 0.9.6

### Patch Changes

- Updated dependencies [[`acd5356`](https://github.com/lingodotdev/lingo.dev/commit/acd5356b68d2261576240c173fea790864c3c31d)]:
  - @lingo.dev/[email protected]

## 0.9.5

### Patch Changes

- Updated dependencies [[`f644123`](https://github.com/lingodotdev/lingo.dev/commit/f644123ddf6a6254790d08af50141e4dd78c3677)]:
  - @lingo.dev/[email protected]

## 0.9.4

### Patch Changes

- Updated dependencies [[`84fd214`](https://github.com/lingodotdev/lingo.dev/commit/84fd214a21766e7683c5d645fcb8c4c0162eb0b6)]:
  - @lingo.dev/[email protected]

## 0.9.3

### Patch Changes

- Updated dependencies [[`ce8c75c`](https://github.com/lingodotdev/lingo.dev/commit/ce8c75c7fc1a2124d3e18444bc356c4dfce26434)]:
  - @lingo.dev/[email protected]

## 0.9.2

### Patch Changes

- [#937](https://github.com/lingodotdev/lingo.dev/pull/937) [`4e5983d`](https://github.com/lingodotdev/lingo.dev/commit/4e5983d7e59ebf9eb529c4b7c1c87689432ac873) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Update documentation URLs from docs.lingo.dev to lingo.dev/cli and lingo.dev/compiler

## 0.9.1

### Patch Changes

- Updated dependencies [[`1b9b113`](https://github.com/lingodotdev/lingo.dev/commit/1b9b11301978e8caa2555832d027ff93216aa6e1), [`0329a9c`](https://github.com/lingodotdev/lingo.dev/commit/0329a9cdb5e5a63fcecab4efcd7cce22f155a0e9)]:
  - @lingo.dev/[email protected]

## 0.9.0

### Minor Changes

- [#915](https://github.com/lingodotdev/lingo.dev/pull/915) [`6b4b9e6`](https://github.com/lingodotdev/lingo.dev/commit/6b4b9e6cc9a0cb5da8a4df9e9ebda474bf2a18ed) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - feat: enhance 5xx error handling with Cloudflare status integration

- [#915](https://github.com/lingodotdev/lingo.dev/pull/915) [`6b4b9e6`](https://github.com/lingodotdev/lingo.dev/commit/6b4b9e6cc9a0cb5da8a4df9e9ebda474bf2a18ed) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - feat: enhance 5xx error handling with Cloudflare status integration

## 0.8.1

### Patch Changes

- Updated dependencies [[`a5da697`](https://github.com/lingodotdev/lingo.dev/commit/a5da697f7efd46de31d17b202d06eb5f655ed9b9)]:
  - @lingo.dev/[email protected]

## 0.8.0

### Minor Changes

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

### Patch Changes

- Updated dependencies [[`e980e84`](https://github.com/lingodotdev/lingo.dev/commit/e980e84178439ad70417d38b425acf9148cfc4b6)]:
  - @lingo.dev/[email protected]

## 0.7.43

### Patch Changes

- Updated dependencies [[`0272fbf`](https://github.com/lingodotdev/lingo.dev/commit/0272fbf8847240ed9453130237d5843b918f869f)]:
  - @lingo.dev/[email protected]

## 0.7.42

### Patch Changes

- [#782](https://github.com/lingodotdev/lingo.dev/pull/782) [`d913c20`](https://github.com/lingodotdev/lingo.dev/commit/d913c20fdf0086741c8b50fd4ddfb38eae304a24) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - parallel processing

- Updated dependencies [[`d913c20`](https://github.com/lingodotdev/lingo.dev/commit/d913c20fdf0086741c8b50fd4ddfb38eae304a24)]:
  - @lingo.dev/[email protected]

## 0.7.41

### Patch Changes

- Updated dependencies [[`3f2aba9`](https://github.com/lingodotdev/lingo.dev/commit/3f2aba9c1d5834faf89a26194f1f3d9f9b878d40)]:
  - @lingo.dev/[email protected]

## 0.7.40

### Patch Changes

- Updated dependencies [[`9aa7004`](https://github.com/lingodotdev/lingo.dev/commit/9aa700491446865dc131b80419f681132b888652)]:
  - @lingo.dev/[email protected]

## 0.7.39

### Patch Changes

- Updated dependencies [[`5170449`](https://github.com/lingodotdev/lingo.dev/commit/517044905dfc682d6a5fa95b0605b8715e2b72c7)]:
  - @lingo.dev/[email protected]

## 0.7.38

### Patch Changes

- Updated dependencies [[`c5ccf81`](https://github.com/lingodotdev/lingo.dev/commit/c5ccf81e9c2bd27bae332306da2a41e41bbeb87d)]:
  - @lingo.dev/[email protected]

## 0.7.37

### Patch Changes

- [#649](https://github.com/lingodotdev/lingo.dev/pull/649) [`409018d`](https://github.com/lingodotdev/lingo.dev/commit/409018de74614a1fd99363c6749b0e4be9e1a278) Thanks [@mathio](https://github.com/mathio)! - refactor dependencies

- Updated dependencies [[`409018d`](https://github.com/lingodotdev/lingo.dev/commit/409018de74614a1fd99363c6749b0e4be9e1a278)]:
  - @lingo.dev/[email protected]

## 0.7.36

### Patch Changes

- [#647](https://github.com/lingodotdev/lingo.dev/pull/647) [`235b6d9`](https://github.com/lingodotdev/lingo.dev/commit/235b6d914c5f542ee5f1a8a88085cfd9dea5409e) Thanks [@mathio](https://github.com/mathio)! - update vitest

- Updated dependencies [[`235b6d9`](https://github.com/lingodotdev/lingo.dev/commit/235b6d914c5f542ee5f1a8a88085cfd9dea5409e)]:
  - @lingo.dev/[email protected]

## 0.7.35

### Patch Changes

- [#645](https://github.com/lingodotdev/lingo.dev/pull/645) [`d824b10`](https://github.com/lingodotdev/lingo.dev/commit/d824b106631f45fc428cf01f733aab4842b4fa81) Thanks [@mathio](https://github.com/mathio)! - update dependencies

- Updated dependencies [[`d824b10`](https://github.com/lingodotdev/lingo.dev/commit/d824b106631f45fc428cf01f733aab4842b4fa81)]:
  - @lingo.dev/[email protected]

## 0.7.34

### Patch Changes

- Updated dependencies [[`82efe61`](https://github.com/lingodotdev/lingo.dev/commit/82efe6176db12cc7c5bbeb84f38bc3261f9eec4f), [`82efe61`](https://github.com/lingodotdev/lingo.dev/commit/82efe6176db12cc7c5bbeb84f38bc3261f9eec4f)]:
  - @lingo.dev/[email protected]

## 0.7.33

### Patch Changes

- Updated dependencies [[`58f3959`](https://github.com/lingodotdev/lingo.dev/commit/58f39599b3b765ad807e725b4089a5e9b11a01b2)]:
  - @lingo.dev/[email protected]

## 0.7.32

### Patch Changes

- Updated dependencies [[`fe922a4`](https://github.com/lingodotdev/lingo.dev/commit/fe922a469c2d5dac23a909a4fb67a6efd56d80d6)]:
  - @lingo.dev/[email protected]

## 0.7.31

### Patch Changes

- Updated dependencies [[`2495afd`](https://github.com/lingodotdev/lingo.dev/commit/2495afd69e23700f96e19e5bbf74e393b29c2033), [`516a79c`](https://github.com/lingodotdev/lingo.dev/commit/516a79c75501c5960ae944379f38591806ca43e2), [`2cc6114`](https://github.com/lingodotdev/lingo.dev/commit/2cc61140fccc69ab73d40c7802a2d0e018889475)]:
  - @lingo.dev/[email protected]

## 0.7.30

### Patch Changes

- Updated dependencies [[`1dbbfd2`](https://github.com/lingodotdev/lingo.dev/commit/1dbbfd2ed9f5a7e0479dc83f700fb68ee5347a18)]:
  - @lingo.dev/[email protected]

## 0.7.29

### Patch Changes

- [#596](https://github.com/lingodotdev/lingo.dev/pull/596) [`61b487e`](https://github.com/lingodotdev/lingo.dev/commit/61b487e1e059328a32c3cdf673255d9d2cd480d9) Thanks [@vrcprl](https://github.com/vrcprl)! - add new locale

- Updated dependencies [[`61b487e`](https://github.com/lingodotdev/lingo.dev/commit/61b487e1e059328a32c3cdf673255d9d2cd480d9)]:
  - @lingo.dev/[email protected]

## 0.7.28

### Patch Changes

- Updated dependencies [[`743d93e`](https://github.com/lingodotdev/lingo.dev/commit/743d93e554841bbd96d23682d8aec63cb4eb3ec8)]:
  - @lingo.dev/[email protected]

## 0.7.27

### Patch Changes

- [#574](https://github.com/lingodotdev/lingo.dev/pull/574) [`dde7fbe`](https://github.com/lingodotdev/lingo.dev/commit/dde7fbe57fc9b1d3ce28e192b778921099354dad) Thanks [@mathio](https://github.com/mathio)! - handle errors from i18n when streaming

## 0.7.26

### Patch Changes

- [#553](https://github.com/lingodotdev/lingo.dev/pull/553) [`95023f2`](https://github.com/lingodotdev/lingo.dev/commit/95023f2c8da3958e8582628a22bf40674f8d2317) Thanks [@vrcprl](https://github.com/vrcprl)! - Add new locales

- Updated dependencies [[`95023f2`](https://github.com/lingodotdev/lingo.dev/commit/95023f2c8da3958e8582628a22bf40674f8d2317)]:
  - @lingo.dev/[email protected]

## 0.7.25

### Patch Changes

- Updated dependencies [[`9089b08`](https://github.com/lingodotdev/lingo.dev/commit/9089b085b968ff3195866e377ecf3016aa06f959)]:
  - @lingo.dev/[email protected]

## 0.7.24

### Patch Changes

- Updated dependencies [[`0b48be1`](https://github.com/lingodotdev/lingo.dev/commit/0b48be197e88dac581cc4f257789a04b43acf932)]:
  - @lingo.dev/[email protected]

## 0.7.23

### Patch Changes

- [#537](https://github.com/lingodotdev/lingo.dev/pull/537) [`7597b99`](https://github.com/lingodotdev/lingo.dev/commit/7597b99c4869f63a42e6de3c4ed25424498d15ae) Thanks [@mathio](https://github.com/mathio)! - automatic source locale detection

## 0.7.22

### Patch Changes

- Updated dependencies [[`bafa755`](https://github.com/lingodotdev/lingo.dev/commit/bafa755d9681e93741462eb7bcf9b85073d20fd7)]:
  - @lingo.dev/[email protected]

## 0.7.21

### Patch Changes

- Updated dependencies [[`444a731`](https://github.com/lingodotdev/lingo.dev/commit/444a7319a1351e22e5666504169023b4c8a29d5f)]:
  - @lingo.dev/[email protected]

## 0.7.20

### Patch Changes

- [#515](https://github.com/lingodotdev/lingo.dev/pull/515) [`fd99a6c`](https://github.com/lingodotdev/lingo.dev/commit/fd99a6ca18ee21774ba5c2b7ce72d1712e374675) Thanks [@mathio](https://github.com/mathio)! - add typesVersions for support of older `moduleResolution`

## 0.7.19

### Patch Changes

- Updated dependencies [[`ec2902e`](https://github.com/lingodotdev/lingo.dev/commit/ec2902e5dc31fd79cc3b6fbf478ed1f3c4df0345)]:
  - @lingo.dev/[email protected]

## 0.7.18

### Patch Changes

- Updated dependencies [[`beb0541`](https://github.com/lingodotdev/lingo.dev/commit/beb05411ee459461e05801a763b1fa28d288e04e)]:
  - @lingo.dev/[email protected]

## 0.7.17

### Patch Changes

- [#493](https://github.com/lingodotdev/lingo.dev/pull/493) [`81527a4`](https://github.com/lingodotdev/lingo.dev/commit/81527a457ad8ef7fe735232caacdf2cc575e5b20) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - fix payload references

## 0.7.16

### Patch Changes

- Updated dependencies [[`a096300`](https://github.com/lingodotdev/lingo.dev/commit/a0963008ea2a8bbc910b0eaeb20f4e3b3cd641a7)]:
  - @lingo.dev/[email protected]

## 0.7.15

### Patch Changes

- [#473](https://github.com/lingodotdev/lingo.dev/pull/473) [`3a99763`](https://github.com/lingodotdev/lingo.dev/commit/3a99763087512ba82955303d6f0567e813f4fa05) Thanks [@vrcprl](https://github.com/vrcprl)! - add new locales

- Updated dependencies [[`3a99763`](https://github.com/lingodotdev/lingo.dev/commit/3a99763087512ba82955303d6f0567e813f4fa05)]:
  - @lingo.dev/[email protected]

## 0.7.14

### Patch Changes

- [#463](https://github.com/lingodotdev/lingo.dev/pull/463) [`f249d8f`](https://github.com/lingodotdev/lingo.dev/commit/f249d8f69d04f0ce40fd94e500e7b829b7ba1ed4) Thanks [@vrcprl](https://github.com/vrcprl)! - set utf-8 encoding explicitly

## 0.7.13

### Patch Changes

- [`dc8bfc7`](https://github.com/lingodotdev/lingo.dev/commit/dc8bfc7ddc38ade768b8aa11c56669db7eb446e6) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - publish deps

- Updated dependencies [[`dc8bfc7`](https://github.com/lingodotdev/lingo.dev/commit/dc8bfc7ddc38ade768b8aa11c56669db7eb446e6)]:
  - @lingo.dev/[email protected]

## 0.7.12

### Patch Changes

- [`6281dbd`](https://github.com/lingodotdev/lingo.dev/commit/6281dbd96bd5cfe54f194a6a1d055c8255a250de) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - fix sdk/spec exported types

- Updated dependencies [[`6281dbd`](https://github.com/lingodotdev/lingo.dev/commit/6281dbd96bd5cfe54f194a6a1d055c8255a250de)]:
  - @lingo.dev/[email protected]

## 0.7.11

### Patch Changes

- [#419](https://github.com/lingodotdev/lingo.dev/pull/419) [`a45feb1`](https://github.com/lingodotdev/lingo.dev/commit/a45feb1d747f8fa32c42c1726953a04c174e754a) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Replexica is now Lingo.dev! 🎉

- Updated dependencies [[`a45feb1`](https://github.com/lingodotdev/lingo.dev/commit/a45feb1d747f8fa32c42c1726953a04c174e754a)]:
  - @lingo.dev/[email protected]

## 0.7.10

### Patch Changes

- Updated dependencies [[`003344f`](https://github.com/lingodotdev/lingo.dev/commit/003344ffcca98a391a298707f18476971c4d4c2b)]:
  - @replexica/[email protected]

## 0.7.9

### Patch Changes

- Updated dependencies [[`a2ada16`](https://github.com/lingodotdev/lingo.dev/commit/a2ada16ecf4cd559d3486f0e4756d58808194f7e)]:
  - @replexica/[email protected]

## 0.7.8

### Patch Changes

- Updated dependencies [[`e6521b8`](https://github.com/lingodotdev/lingo.dev/commit/e6521b86637c254c011aba89a3558802c04ab3ca)]:
  - @replexica/[email protected]

## 0.7.7

### Patch Changes

- Updated dependencies [[`cff3c4e`](https://github.com/lingodotdev/lingo.dev/commit/cff3c4eb1a40f82a9c4c095e49cfd9fce053b048)]:
  - @replexica/[email protected]

## 0.7.6

### Patch Changes

- Updated dependencies [[`58d7b35`](https://github.com/lingodotdev/lingo.dev/commit/58d7b3567e51cc3ef0fad0288c13451381b95a98)]:
  - @replexica/[email protected]

## 0.7.5

### Patch Changes

- Updated dependencies [[`9cf5299`](https://github.com/lingodotdev/lingo.dev/commit/9cf5299f7efbef70fd83f95177eac49b4d8f8007), [`3ab5de6`](https://github.com/lingodotdev/lingo.dev/commit/3ab5de66d8a913297b46095c2e73823124cc8c5b)]:
  - @replexica/[email protected]

## 0.7.4

### Patch Changes

- Updated dependencies [[`1556977`](https://github.com/lingodotdev/lingo.dev/commit/1556977332a6f949100283bfa8c9a9ff5e74b156)]:
  - @replexica/[email protected]

## 0.7.3

### Patch Changes

- [`cbef8f3`](https://github.com/lingodotdev/lingo.dev/commit/cbef8f3cafdc955d61053ce885d98e425acb668d) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - moved jsdom import into the html handler function

## 0.7.2

### Patch Changes

- Updated dependencies [[`5cb3c93`](https://github.com/lingodotdev/lingo.dev/commit/5cb3c930fff6e30cff5cc2266b794f75a0db646d)]:
  - @replexica/[email protected]

## 0.7.1

### Patch Changes

- [`db819a4`](https://github.com/lingodotdev/lingo.dev/commit/db819a42412ceb67fedbe729b7d018952686d60b) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - reduce default batch size to avoid hitting rate limits

- [`2c5cbcf`](https://github.com/lingodotdev/lingo.dev/commit/2c5cbcfbf6feb28440255cdea0818c8cefa61d91) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - filter out non extistent keys

## 0.7.0

### Minor Changes

- [`c42dc2d`](https://github.com/lingodotdev/lingo.dev/commit/c42dc2d5b4efe95e804b5a7e7f6d354cf8622dc7) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add `batchLocalizeText` to sdk

## 0.6.0

### Minor Changes

- [`a71a88e`](https://github.com/lingodotdev/lingo.dev/commit/a71a88e5c8bd6601b0838c381433a87763142801) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - fast mode

### Patch Changes

- [`f0a77ad`](https://github.com/lingodotdev/lingo.dev/commit/f0a77ad774a01c30e7e9bc5a0253638176332fd2) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - updated default batch size limits in the SDK

## 0.5.0

### Minor Changes

- [`ebf44cb`](https://github.com/lingodotdev/lingo.dev/commit/ebf44cbb462516abfe660c295c04627796c5a3a7) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - implement recognize locale

- [`42d0a5a`](https://github.com/lingodotdev/lingo.dev/commit/42d0a5a7a53e296192a31e8f1d67c126793ea280) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - added .localizeHtml implementation to SDK

### Patch Changes

- Updated dependencies [[`a6b22a3`](https://github.com/lingodotdev/lingo.dev/commit/a6b22a3237f574455d8119f914d82b0b247b4151)]:
  - @replexica/[email protected]

## 0.4.3

### Patch Changes

- Updated dependencies [[`091ee35`](https://github.com/lingodotdev/lingo.dev/commit/091ee353081795bf8f61c7d41483bc309c7b62ef)]:
  - @replexica/[email protected]

## 0.4.2

### Patch Changes

- Updated dependencies [[`5e282d7`](https://github.com/lingodotdev/lingo.dev/commit/5e282d7ffa5ca9494aa7046a090bb7c327085a86)]:
  - @replexica/[email protected]

## 0.4.1

### Patch Changes

- Updated dependencies [[`0071cd6`](https://github.com/lingodotdev/lingo.dev/commit/0071cd66b1c868ad3898fc368390a628c5a67767)]:
  - @replexica/[email protected]

## 0.4.0

### Minor Changes

- [#264](https://github.com/lingodotdev/lingo.dev/pull/264) [`cdef5b7`](https://github.com/lingodotdev/lingo.dev/commit/cdef5b7bfbee4670c6de62cf4b4f3e0315748e25) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - added format specific methods to `@replexica/sdk`

## 0.3.4

### Patch Changes

- Updated dependencies [[`2859938`](https://github.com/lingodotdev/lingo.dev/commit/28599388a91bf80cea3813bb4b8999bb4df302c9)]:
  - @replexica/[email protected]

## 0.3.3

### Patch Changes

- Updated dependencies [[`ca9e20e`](https://github.com/lingodotdev/lingo.dev/commit/ca9e20eef9047e20d39ccf9dff74d2f6069d4676), [`2aedf3b`](https://github.com/lingodotdev/lingo.dev/commit/2aedf3bec2d9dffc7b43fc10dea0cab5742d44af), [`626082a`](https://github.com/lingodotdev/lingo.dev/commit/626082a64b88fb3b589acd950afeafe417ce5ddc)]:
  - @replexica/[email protected]

## 0.3.2

### Patch Changes

- Updated dependencies [[`1601f70`](https://github.com/lingodotdev/lingo.dev/commit/1601f708bdf0ff1786d3bf9b19265ac5b567f740)]:
  - @replexica/[email protected]

## 0.3.1

### Patch Changes

- Updated dependencies [[`bc5a28c`](https://github.com/lingodotdev/lingo.dev/commit/bc5a28c3c98b619872924b5f913229ac01387524)]:
  - @replexica/[email protected]

## 0.3.0

### Minor Changes

- [#165](https://github.com/lingodotdev/lingo.dev/pull/165) [`5c2ca37`](https://github.com/lingodotdev/lingo.dev/commit/5c2ca37114663eaeb529a027e33949ef3839549b) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Update locale code resolution logic

### Patch Changes

- Updated dependencies [[`5c2ca37`](https://github.com/lingodotdev/lingo.dev/commit/5c2ca37114663eaeb529a027e33949ef3839549b)]:
  - @replexica/[email protected]

## 0.2.1

### Patch Changes

- Updated dependencies [[`6870fc7`](https://github.com/lingodotdev/lingo.dev/commit/6870fc758dae9d1adb641576befbd8cda61cd5ea)]:
  - @replexica/[email protected]

## 0.2.0

### Minor Changes

- [`d6e6d5c`](https://github.com/lingodotdev/lingo.dev/commit/d6e6d5c24b266de3769e95545f74632e7d75c697) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Add support for multisource localization to the CLI

### Patch Changes

- Updated dependencies [[`d6e6d5c`](https://github.com/lingodotdev/lingo.dev/commit/d6e6d5c24b266de3769e95545f74632e7d75c697)]:
  - @replexica/[email protected]

## 0.1.1

### Patch Changes

- Updated dependencies [[`73c9250`](https://github.com/lingodotdev/lingo.dev/commit/73c925084989ccea120cae1617ec87776c88e83e)]:
  - @replexica/[email protected]

## 0.1.0

### Minor Changes

- [#142](https://github.com/lingodotdev/lingo.dev/pull/142) [`d9b0e51`](https://github.com/lingodotdev/lingo.dev/commit/d9b0e512196329cc781a4d33346f8ca0f3a81e7e) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Extract API calling into SDK package

```

--------------------------------------------------------------------------------
/packages/spec/CHANGELOG.md:
--------------------------------------------------------------------------------

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

## 0.41.1

### Patch Changes

- [#1230](https://github.com/lingodotdev/lingo.dev/pull/1230) [`b45347c`](https://github.com/lingodotdev/lingo.dev/commit/b45347c38572ee371b2bc494261b7e3e90c4aed1) Thanks [@vrcprl](https://github.com/vrcprl)! - add an xcode-xcstrings-v2 bucket type that supports cldr pluralization rules

## 0.41.0

### Minor Changes

- [#1186](https://github.com/lingodotdev/lingo.dev/pull/1186) [`82f5e7c`](https://github.com/lingodotdev/lingo.dev/commit/82f5e7cdde9a2a15b4c2a7fcb8c67ed64eab596b) Thanks [@davidturnbull](https://github.com/davidturnbull)! - Add Markdoc support

### Patch Changes

- [#1215](https://github.com/lingodotdev/lingo.dev/pull/1215) [`e858174`](https://github.com/lingodotdev/lingo.dev/commit/e858174fd5165e0ea3e3f25fa1fc3edb292bc58f) Thanks [@vrcprl](https://github.com/vrcprl)! - add provider settings

## 0.40.4

### Patch Changes

- [#1201](https://github.com/lingodotdev/lingo.dev/pull/1201) [`1fa218c`](https://github.com/lingodotdev/lingo.dev/commit/1fa218c13bf90df6d175fb18264f59c1a10b967c) Thanks [@vrcprl](https://github.com/vrcprl)! - add new languages Malayalam (India), Armenian (Armenia), Macedonian (Macedonia)

## 0.40.3

### Patch Changes

- [#1192](https://github.com/lingodotdev/lingo.dev/pull/1192) [`bbc71b9`](https://github.com/lingodotdev/lingo.dev/commit/bbc71b9948ccc289c9669d8b0c276c9596f6a5e7) Thanks [@vrcprl](https://github.com/vrcprl)! - Add biome support

## 0.40.2

### Patch Changes

- [#1171](https://github.com/lingodotdev/lingo.dev/pull/1171) [`6579d70`](https://github.com/lingodotdev/lingo.dev/commit/6579d70bc670c2fdc06c09842d931b07e134151c) Thanks [@vrcprl](https://github.com/vrcprl)! - add el-CY en-IE fr-LU locales

## 0.40.1

### Patch Changes

- [#1016](https://github.com/lingodotdev/lingo.dev/pull/1016) [`a35032e`](https://github.com/lingodotdev/lingo.dev/commit/a35032e7e7a188d1f5e774576352068124526e24) Thanks [@davidturnbull](https://github.com/davidturnbull)! - feat: add automated config documentation generator for i18n.json schema

## 0.40.0

### Minor Changes

- [#1066](https://github.com/lingodotdev/lingo.dev/pull/1066) [`6af91a0`](https://github.com/lingodotdev/lingo.dev/commit/6af91a083d16f85051fb49a4034789abe784017e) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add hints support for xcode and jsonc buckets

## 0.39.3

### Patch Changes

- [#1031](https://github.com/lingodotdev/lingo.dev/pull/1031) [`afbb978`](https://github.com/lingodotdev/lingo.dev/commit/afbb978fec83d574f2c43b7d68457e435fca9b57) Thanks [@mathio](https://github.com/mathio)! - add json-dictionary loader support

## 0.39.2

### Patch Changes

- [#1023](https://github.com/lingodotdev/lingo.dev/pull/1023) [`9266fd0`](https://github.com/lingodotdev/lingo.dev/commit/9266fd0bcddf4b07ca51d2609af92a9473106f9d) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Update Zod dependency to version 3.25.76

## 0.39.1

### Patch Changes

- [#995](https://github.com/lingodotdev/lingo.dev/pull/995) [`acd5356`](https://github.com/lingodotdev/lingo.dev/commit/acd5356b68d2261576240c173fea790864c3c31d) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Add Icelandic (is) locale support with is-IS regional variant

## 0.39.0

### Minor Changes

- [#981](https://github.com/lingodotdev/lingo.dev/pull/981) [`f644123`](https://github.com/lingodotdev/lingo.dev/commit/f644123ddf6a6254790d08af50141e4dd78c3677) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Add support for plain TXT files to enable translation of fastlane App Store metadata and other plain text content

## 0.38.0

### Minor Changes

- [#958](https://github.com/lingodotdev/lingo.dev/pull/958) [`84fd214`](https://github.com/lingodotdev/lingo.dev/commit/84fd214a21766e7683c5d645fcb8c4c0162eb0b6) Thanks [@chrissiwaffler](https://github.com/chrissiwaffler)! - feat: add Mistral AI as a supported LLM provider

  - Added Mistral AI provider support across the entire lingo.dev ecosystem
  - Users can now use Mistral models for localization by setting MISTRAL_API_KEY
  - Supports all Mistral models available through the @ai-sdk/mistral package
  - Configuration via environment variable or user-wide config: `npx lingo.dev@latest config set llm.mistralApiKey <key>`

## 0.37.0

### Minor Changes

- [#956](https://github.com/lingodotdev/lingo.dev/pull/956) [`ce8c75c`](https://github.com/lingodotdev/lingo.dev/commit/ce8c75c7fc1a2124d3e18444bc356c4dfce26434) Thanks [@VAIBHAVSING](https://github.com/VAIBHAVSING)! - feat: add EJS (Embedded JavaScript) templating engine support

  - Added EJS loader to support parsing and translating EJS template files
  - EJS loader extracts translatable text while preserving EJS tags and expressions
  - Updated spec package to include "ejs" in supported bucket types
  - Added comprehensive test suite covering various EJS scenarios including conditionals, loops, includes, and mixed content
  - Automatically installed EJS dependency (@types/ejs) for TypeScript support

## 0.36.0

### Minor Changes

- [#913](https://github.com/lingodotdev/lingo.dev/pull/913) [`1b9b113`](https://github.com/lingodotdev/lingo.dev/commit/1b9b11301978e8caa2555832d027ff93216aa6e1) Thanks [@The-Best-Codes](https://github.com/The-Best-Codes)! - Add support for Ollama as a CLI and Compiler provider.

### Patch Changes

- [#922](https://github.com/lingodotdev/lingo.dev/pull/922) [`0329a9c`](https://github.com/lingodotdev/lingo.dev/commit/0329a9cdb5e5a63fcecab4efcd7cce22f155a0e9) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add openrouter ais support for compiler

## 0.35.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.34.0

### Minor Changes

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

## 0.33.3

### Patch Changes

- [#805](https://github.com/lingodotdev/lingo.dev/pull/805) [`0272fbf`](https://github.com/lingodotdev/lingo.dev/commit/0272fbf8847240ed9453130237d5843b918f869f) Thanks [@Vicentesan](https://github.com/Vicentesan)! - Introduce the gregorian language (ka-GE)

## 0.33.2

### Patch Changes

- [#782](https://github.com/lingodotdev/lingo.dev/pull/782) [`d913c20`](https://github.com/lingodotdev/lingo.dev/commit/d913c20fdf0086741c8b50fd4ddfb38eae304a24) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - parallel processing

## 0.33.1

### Patch Changes

- [#778](https://github.com/lingodotdev/lingo.dev/pull/778) [`3f2aba9`](https://github.com/lingodotdev/lingo.dev/commit/3f2aba9c1d5834faf89a26194f1f3d9f9b878d40) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add ignoredKeys

## 0.33.0

### Minor Changes

- [#759](https://github.com/lingodotdev/lingo.dev/pull/759) [`9aa7004`](https://github.com/lingodotdev/lingo.dev/commit/9aa700491446865dc131b80419f681132b888652) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Enhance TypeScript loader to support nested fields and arrays

## 0.32.0

### Minor Changes

- [#757](https://github.com/lingodotdev/lingo.dev/pull/757) [`5170449`](https://github.com/lingodotdev/lingo.dev/commit/517044905dfc682d6a5fa95b0605b8715e2b72c7) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Add TypeScript loader for .ts files that extracts string literals from default exports

## 0.31.0

### Minor Changes

- [#700](https://github.com/lingodotdev/lingo.dev/pull/700) [`c5ccf81`](https://github.com/lingodotdev/lingo.dev/commit/c5ccf81e9c2bd27bae332306da2a41e41bbeb87d) Thanks [@devin-ai-integration](https://github.com/apps/devin-ai-integration)! - Add support for locked patterns in MDX loader

  This change adds support for preserving specific patterns in MDX files during translation, including:

  - !params syntax for parameter documentation
  - !! parameter_name headings
  - !type declarations
  - !required flags
  - !values lists

  The implementation adds a new config version 1.7 with a "lockedPatterns" field that accepts an array of regex patterns to be preserved during translation.

## 0.30.3

### Patch Changes

- [#649](https://github.com/lingodotdev/lingo.dev/pull/649) [`409018d`](https://github.com/lingodotdev/lingo.dev/commit/409018de74614a1fd99363c6749b0e4be9e1a278) Thanks [@mathio](https://github.com/mathio)! - refactor dependencies

## 0.30.2

### Patch Changes

- [#647](https://github.com/lingodotdev/lingo.dev/pull/647) [`235b6d9`](https://github.com/lingodotdev/lingo.dev/commit/235b6d914c5f542ee5f1a8a88085cfd9dea5409e) Thanks [@mathio](https://github.com/mathio)! - update vitest

## 0.30.1

### Patch Changes

- [#645](https://github.com/lingodotdev/lingo.dev/pull/645) [`d824b10`](https://github.com/lingodotdev/lingo.dev/commit/d824b106631f45fc428cf01f733aab4842b4fa81) Thanks [@mathio](https://github.com/mathio)! - update dependencies

## 0.30.0

### Minor Changes

- [#631](https://github.com/lingodotdev/lingo.dev/pull/631) [`82efe61`](https://github.com/lingodotdev/lingo.dev/commit/82efe6176db12cc7c5bbeb84f38bc3261f9eec4f) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - double formatting for mdx

- [#631](https://github.com/lingodotdev/lingo.dev/pull/631) [`82efe61`](https://github.com/lingodotdev/lingo.dev/commit/82efe6176db12cc7c5bbeb84f38bc3261f9eec4f) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - advanced mdx support (shout out to @ZYJLiu!)

## 0.29.0

### Minor Changes

- [#629](https://github.com/lingodotdev/lingo.dev/pull/629) [`58f3959`](https://github.com/lingodotdev/lingo.dev/commit/58f39599b3b765ad807e725b4089a5e9b11a01b2) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - advanced mdx support (shout out to @ZYJLiu!)

## 0.28.0

### Minor Changes

- [#627](https://github.com/lingodotdev/lingo.dev/pull/627) [`fe922a4`](https://github.com/lingodotdev/lingo.dev/commit/fe922a469c2d5dac23a909a4fb67a6efd56d80d6) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add support for json/yaml key locking

## 0.27.0

### Minor Changes

- [#614](https://github.com/lingodotdev/lingo.dev/pull/614) [`2495afd`](https://github.com/lingodotdev/lingo.dev/commit/2495afd69e23700f96e19e5bbf74e393b29c2033) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add basic translators

### Patch Changes

- [#616](https://github.com/lingodotdev/lingo.dev/pull/616) [`516a79c`](https://github.com/lingodotdev/lingo.dev/commit/516a79c75501c5960ae944379f38591806ca43e2) Thanks [@mathio](https://github.com/mathio)! - po files --frozen flag

- [`2cc6114`](https://github.com/lingodotdev/lingo.dev/commit/2cc61140fccc69ab73d40c7802a2d0e018889475) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add Welsh language support

## 0.26.6

### Patch Changes

- [#605](https://github.com/lingodotdev/lingo.dev/pull/605) [`1dbbfd2`](https://github.com/lingodotdev/lingo.dev/commit/1dbbfd2ed9f5a7e0479dc83f700fb68ee5347a18) Thanks [@mathio](https://github.com/mathio)! - inject locale

## 0.26.5

### Patch Changes

- [#596](https://github.com/lingodotdev/lingo.dev/pull/596) [`61b487e`](https://github.com/lingodotdev/lingo.dev/commit/61b487e1e059328a32c3cdf673255d9d2cd480d9) Thanks [@vrcprl](https://github.com/vrcprl)! - add new locale

## 0.26.4

### Patch Changes

- [#584](https://github.com/lingodotdev/lingo.dev/pull/584) [`743d93e`](https://github.com/lingodotdev/lingo.dev/commit/743d93e554841bbd96d23682d8aec63cb4eb3ec8) Thanks [@khalatevarun](https://github.com/khalatevarun)! - Add unit test for utility function in locales.ts

## 0.26.3

### Patch Changes

- [#553](https://github.com/lingodotdev/lingo.dev/pull/553) [`95023f2`](https://github.com/lingodotdev/lingo.dev/commit/95023f2c8da3958e8582628a22bf40674f8d2317) Thanks [@vrcprl](https://github.com/vrcprl)! - Add new locales

## 0.26.2

### Patch Changes

- [#546](https://github.com/lingodotdev/lingo.dev/pull/546) [`9089b08`](https://github.com/lingodotdev/lingo.dev/commit/9089b085b968ff3195866e377ecf3016aa06f959) Thanks [@mathio](https://github.com/mathio)! - add helper method to spec

## 0.26.1

### Patch Changes

- [`0b48be1`](https://github.com/lingodotdev/lingo.dev/commit/0b48be197e88dac581cc4f257789a04b43acf932) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add Kinyarwanda and Kiswahili

## 0.26.0

### Minor Changes

- [#530](https://github.com/lingodotdev/lingo.dev/pull/530) [`bafa755`](https://github.com/lingodotdev/lingo.dev/commit/bafa755d9681e93741462eb7bcf9b85073d20fd7) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Add Kazakh (Kazakhstan) locale (localization engine passed the benchmarks!)

## 0.25.3

### Patch Changes

- [#518](https://github.com/lingodotdev/lingo.dev/pull/518) [`444a731`](https://github.com/lingodotdev/lingo.dev/commit/444a7319a1351e22e5666504169023b4c8a29d5f) Thanks [@mathio](https://github.com/mathio)! - support JSON messages in <i18n> block of .vue files

## 0.25.2

### Patch Changes

- [#498](https://github.com/lingodotdev/lingo.dev/pull/498) [`ec2902e`](https://github.com/lingodotdev/lingo.dev/commit/ec2902e5dc31fd79cc3b6fbf478ed1f3c4df0345) Thanks [@mathio](https://github.com/mathio)! - build json schema for config

## 0.25.1

### Patch Changes

- [#496](https://github.com/lingodotdev/lingo.dev/pull/496) [`beb0541`](https://github.com/lingodotdev/lingo.dev/commit/beb05411ee459461e05801a763b1fa28d288e04e) Thanks [@mathio](https://github.com/mathio)! - po files

## 0.25.0

### Minor Changes

- [#485](https://github.com/lingodotdev/lingo.dev/pull/485) [`a096300`](https://github.com/lingodotdev/lingo.dev/commit/a0963008ea2a8bbc910b0eaeb20f4e3b3cd641a7) Thanks [@mathio](https://github.com/mathio)! - add support for php buckets

## 0.24.4

### Patch Changes

- [#473](https://github.com/lingodotdev/lingo.dev/pull/473) [`3a99763`](https://github.com/lingodotdev/lingo.dev/commit/3a99763087512ba82955303d6f0567e813f4fa05) Thanks [@vrcprl](https://github.com/vrcprl)! - add new locales

## 0.24.3

### Patch Changes

- [`dc8bfc7`](https://github.com/lingodotdev/lingo.dev/commit/dc8bfc7ddc38ade768b8aa11c56669db7eb446e6) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - publish deps

## 0.24.2

### Patch Changes

- [`6281dbd`](https://github.com/lingodotdev/lingo.dev/commit/6281dbd96bd5cfe54f194a6a1d055c8255a250de) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - fix sdk/spec exported types

## 0.24.1

### Patch Changes

- [#419](https://github.com/lingodotdev/lingo.dev/pull/419) [`a45feb1`](https://github.com/lingodotdev/lingo.dev/commit/a45feb1d747f8fa32c42c1726953a04c174e754a) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Replexica is now Lingo.dev! 🎉

## 0.24.0

### Minor Changes

- [`003344f`](https://github.com/lingodotdev/lingo.dev/commit/003344ffcca98a391a298707f18476971c4d4c2b) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add locale delimiter override

## 0.23.0

### Minor Changes

- [#390](https://github.com/lingodotdev/lingo.dev/pull/390) [`a2ada16`](https://github.com/lingodotdev/lingo.dev/commit/a2ada16ecf4cd559d3486f0e4756d58808194f7e) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add explicit regional flag support

## 0.22.1

### Patch Changes

- [#371](https://github.com/lingodotdev/lingo.dev/pull/371) [`e6521b8`](https://github.com/lingodotdev/lingo.dev/commit/e6521b86637c254c011aba89a3558802c04ab3ca) Thanks [@mathio](https://github.com/mathio)! - support underscore in locale code

## 0.22.0

### Minor Changes

- [#356](https://github.com/lingodotdev/lingo.dev/pull/356) [`cff3c4e`](https://github.com/lingodotdev/lingo.dev/commit/cff3c4eb1a40f82a9c4c095e49cfd9fce053b048) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add dato support

## 0.21.1

### Patch Changes

- [`58d7b35`](https://github.com/lingodotdev/lingo.dev/commit/58d7b3567e51cc3ef0fad0288c13451381b95a98) Thanks [@vrcprl](https://github.com/vrcprl)! - Added Telugu (India) locale

## 0.21.0

### Minor Changes

- [#327](https://github.com/lingodotdev/lingo.dev/pull/327) [`3ab5de6`](https://github.com/lingodotdev/lingo.dev/commit/3ab5de66d8a913297b46095c2e73823124cc8c5b) Thanks [@partik03](https://github.com/partik03)! - added support for xliff loader

### Patch Changes

- [`9cf5299`](https://github.com/lingodotdev/lingo.dev/commit/9cf5299f7efbef70fd83f95177eac49b4d8f8007) Thanks [@vrcprl](https://github.com/vrcprl)! - Add Tagalog

## 0.20.0

### Minor Changes

- [`1556977`](https://github.com/lingodotdev/lingo.dev/commit/1556977332a6f949100283bfa8c9a9ff5e74b156) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add new locales

## 0.19.0

### Minor Changes

- [`5cb3c93`](https://github.com/lingodotdev/lingo.dev/commit/5cb3c930fff6e30cff5cc2266b794f75a0db646d) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - added Latin / Cyrilic modifiers for Serbian

## 0.18.0

### Minor Changes

- [#300](https://github.com/lingodotdev/lingo.dev/pull/300) [`a6b22a3`](https://github.com/lingodotdev/lingo.dev/commit/a6b22a3237f574455d8119f914d82b0b247b4151) Thanks [@partik03](https://github.com/partik03)! - implemented srt file loader and added support for srt file format in spec

## 0.17.0

### Minor Changes

- [#275](https://github.com/lingodotdev/lingo.dev/pull/275) [`091ee35`](https://github.com/lingodotdev/lingo.dev/commit/091ee353081795bf8f61c7d41483bc309c7b62ef) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add support for `.po` format

## 0.16.0

### Minor Changes

- [#268](https://github.com/lingodotdev/lingo.dev/pull/268) [`5e282d7`](https://github.com/lingodotdev/lingo.dev/commit/5e282d7ffa5ca9494aa7046a090bb7c327085a86) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - composable loaders

## 0.15.0

### Minor Changes

- [`0071cd6`](https://github.com/lingodotdev/lingo.dev/commit/0071cd66b1c868ad3898fc368390a628c5a67767) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add csv format support

## 0.14.1

### Patch Changes

- [`2859938`](https://github.com/lingodotdev/lingo.dev/commit/28599388a91bf80cea3813bb4b8999bb4df302c9) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add missing locales

## 0.14.0

### Minor Changes

- [`ca9e20e`](https://github.com/lingodotdev/lingo.dev/commit/ca9e20eef9047e20d39ccf9dff74d2f6069d4676) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - .strings support

- [`2aedf3b`](https://github.com/lingodotdev/lingo.dev/commit/2aedf3bec2d9dffc7b43fc10dea0cab5742d44af) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - added support for .stringsdict

- [`626082a`](https://github.com/lingodotdev/lingo.dev/commit/626082a64b88fb3b589acd950afeafe417ce5ddc) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - added Flutter .arb support

## 0.13.0

### Minor Changes

- [#181](https://github.com/lingodotdev/lingo.dev/pull/181) [`1601f70`](https://github.com/lingodotdev/lingo.dev/commit/1601f708bdf0ff1786d3bf9b19265ac5b567f740) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Added support for .properties file

## 0.12.1

### Patch Changes

- [`bc5a28c`](https://github.com/lingodotdev/lingo.dev/commit/bc5a28c3c98b619872924b5f913229ac01387524) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Fix spec imports

## 0.12.0

### Minor Changes

- [#165](https://github.com/lingodotdev/lingo.dev/pull/165) [`5c2ca37`](https://github.com/lingodotdev/lingo.dev/commit/5c2ca37114663eaeb529a027e33949ef3839549b) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Update locale code resolution logic

## 0.11.0

### Minor Changes

- [`6870fc7`](https://github.com/lingodotdev/lingo.dev/commit/6870fc758dae9d1adb641576befbd8cda61cd5ea) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Fix version number bumping in 1.2 config autoupgrade

## 0.10.0

### Minor Changes

- [`d6e6d5c`](https://github.com/lingodotdev/lingo.dev/commit/d6e6d5c24b266de3769e95545f74632e7d75c697) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Add support for multisource localization to the CLI

## 0.9.0

### Minor Changes

- [#158](https://github.com/lingodotdev/lingo.dev/pull/158) [`73c9250`](https://github.com/lingodotdev/lingo.dev/commit/73c925084989ccea120cae1617ec87776c88e83e) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Configuration spec v1.1: Improved bucket config structure, to support exclusion patterns

## 0.8.0

### Minor Changes

- [`8c8e7dd`](https://github.com/lingodotdev/lingo.dev/commit/8c8e7dd4d35669d484240d643427612ecdaf73eb) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Added new locales

## 0.7.0

### Minor Changes

- [`c0be1a2`](https://github.com/lingodotdev/lingo.dev/commit/c0be1a29e3069ef2c8bdc4e4f52d2fb17abdb1f5) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Replaced `replexica config` with `replexica show config`. Added `replexica show locale sources` and `replexica show locale targets`.

## 0.6.0

### Minor Changes

- [`10252ce`](https://github.com/lingodotdev/lingo.dev/commit/10252ceaa2685cc23f4dbeb6ac985cc2148853e2) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Add android support

## 0.5.1

### Patch Changes

- [`088de18`](https://github.com/lingodotdev/lingo.dev/commit/088de18a53f45fa8df5833fe81ed96a2ed231299) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Fix @replexica/config reference

## 0.5.0

### Minor Changes

- [#99](https://github.com/lingodotdev/lingo.dev/pull/99) [`4e94058`](https://github.com/lingodotdev/lingo.dev/commit/4e940582ea8ebe5a058b76fb33420729f7bfdcef) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - Added support for i18n lockfiles to improve AI localization performance.

## 0.4.1

### Patch Changes

- [#94](https://github.com/lingodotdev/lingo.dev/pull/94) [`abab45c`](https://github.com/lingodotdev/lingo.dev/commit/abab45cc91675f507499bf84350b080cd647c464) Thanks [@vrcprl](https://github.com/vrcprl)! - Locales mapping (ex. en -> en-US)

## 0.4.0

### Minor Changes

- [#87](https://github.com/lingodotdev/lingo.dev/pull/87) [`07657c6`](https://github.com/lingodotdev/lingo.dev/commit/07657c611306797d605718e13ce6b2c920a5a94e) Thanks [@vrcprl](https://github.com/vrcprl)! - added new core locales : ja de pt it ru uk hi zh ko tr ar and source locales yue pl sk th

## 0.3.0

### Minor Changes

- [`830d4a4`](https://github.com/lingodotdev/lingo.dev/commit/830d4a441c4d1177c9356756a9e9afc170a386d6) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - add support for shyriiwook language

## 0.2.0

### Minor Changes

- [#76](https://github.com/lingodotdev/lingo.dev/pull/76) [`69d487c`](https://github.com/lingodotdev/lingo.dev/commit/69d487c0b4c8e22f9c86867ebf6cc55ea2875dbf) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - enable french, catalan in source/target mode, and czech in source-only mode

## 0.1.0

### Minor Changes

- [#73](https://github.com/lingodotdev/lingo.dev/pull/73) [`94ab265`](https://github.com/lingodotdev/lingo.dev/commit/94ab26551577b5dfab629ffee3c82e59b56ce25d) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - intro a `@replexica/spec` package containing common definitions, constants, schemas, and types

- [#75](https://github.com/lingodotdev/lingo.dev/pull/75) [`b11b48e`](https://github.com/lingodotdev/lingo.dev/commit/b11b48e7c3ab05dd8de0ddcfe5cb4589786abbf9) Thanks [@maxprilutskiy](https://github.com/maxprilutskiy)! - framework-agnostic i18n support

```

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

```typescript
import {
  bucketTypeSchema,
  I18nConfig,
  localeCodeSchema,
  resolveOverriddenLocale,
} from "@lingo.dev/_spec";
import { Command } from "interactive-commander";
import Z from "zod";
import _ from "lodash";
import * as path from "path";
import { getConfig } from "../utils/config";
import { getSettings } from "../utils/settings";
import { CLIError } from "../utils/errors";
import Ora from "ora";
import createBucketLoader from "../loaders";
import { createAuthenticator } from "../utils/auth";
import { getBuckets } from "../utils/buckets";
import chalk from "chalk";
import Table from "cli-table3";
import { createDeltaProcessor } from "../utils/delta";
import trackEvent from "../utils/observability";
import { minimatch } from "minimatch";
import { exitGracefully } from "../utils/exit-gracefully";

// Define types for our language stats
interface LanguageStats {
  complete: number;
  missing: number;
  updated: number;
  words: number;
}

export default new Command()
  .command("status")
  .description("Show the status of the localization process")
  .helpOption("-h, --help", "Show help")
  .option(
    "--locale <locale>",
    "Limit the report to specific target locales from i18n.json. Repeat the flag to include multiple locales. Defaults to all configured target locales",
    (val: string, prev: string[]) => (prev ? [...prev, val] : [val]),
  )
  .option(
    "--bucket <bucket>",
    "Limit the report to specific bucket types defined in i18n.json (e.g., json, yaml, android). Repeat the flag to include multiple bucket types. Defaults to all buckets",
    (val: string, prev: string[]) => (prev ? [...prev, val] : [val]),
  )
  .option(
    "--file [files...]",
    "Filter the status report to only include files whose paths contain these substrings. Example: 'components' to match any file path containing 'components'",
  )
  .option(
    "--force",
    "Force all keys to be counted as needing translation, bypassing change detection. Shows word estimates for a complete retranslation regardless of current translation status",
  )
  .option(
    "--verbose",
    "Print detailed output showing missing and updated key counts with example key names for each file and locale",
  )
  .option(
    "--api-key <api-key>",
    "Override the API key from settings or environment variables for this run",
  )
  .action(async function (options) {
    const ora = Ora();
    const flags = parseFlags(options);
    let authId: string | null = null;

    try {
      ora.start("Loading configuration...");
      const i18nConfig = getConfig();
      const settings = getSettings(flags.apiKey);
      ora.succeed("Configuration loaded");

      // Try to authenticate, but continue even if not authenticated
      try {
        ora.start("Checking authentication status...");
        const auth = await tryAuthenticate(settings);
        if (auth) {
          authId = auth.id;
          ora.succeed(`Authenticated as ${auth.email}`);
        } else {
          ora.info(
            "Not authenticated. Continuing without authentication. (Run `lingo.dev login` to authenticate)",
          );
        }
      } catch (error) {
        ora.info("Authentication failed. Continuing without authentication.");
      }

      ora.start("Validating localization configuration...");
      validateParams(i18nConfig, flags);
      ora.succeed("Localization configuration is valid");

      // Track event with or without authentication
      trackEvent(authId || "status", "cmd.status.start", {
        i18nConfig,
        flags,
      });

      let buckets = getBuckets(i18nConfig!);
      if (flags.bucket?.length) {
        buckets = buckets.filter((bucket: any) =>
          flags.bucket!.includes(bucket.type),
        );
      }
      ora.succeed("Buckets retrieved");

      if (flags.file?.length) {
        buckets = buckets
          .map((bucket: any) => {
            const paths = bucket.paths.filter((path: any) =>
              flags.file!.find(
                (file) =>
                  path.pathPattern?.includes(file) ||
                  path.pathPattern?.match(file) ||
                  minimatch(path.pathPattern, file),
              ),
            );
            return { ...bucket, paths };
          })
          .filter((bucket: any) => bucket.paths.length > 0);
        if (buckets.length === 0) {
          ora.fail(
            "No buckets found. All buckets were filtered out by --file option.",
          );
          process.exit(1);
        } else {
          ora.info(`\x1b[36mProcessing only filtered buckets:\x1b[0m`);
          buckets.map((bucket: any) => {
            ora.info(`  ${bucket.type}:`);
            bucket.paths.forEach((path: any) => {
              ora.info(`    - ${path.pathPattern}`);
            });
          });
        }
      }

      const targetLocales = flags.locale?.length
        ? flags.locale
        : i18nConfig!.locale.targets;

      // Global stats
      let totalSourceKeyCount = 0;
      let uniqueKeysToTranslate = 0;
      let totalExistingTranslations = 0;
      const totalWordCount = new Map<string, number>(); // Words per language
      const languageStats: Record<string, LanguageStats> = {};

      // Initialize per-language stats
      for (const locale of targetLocales) {
        languageStats[locale] = {
          complete: 0,
          missing: 0,
          updated: 0,
          words: 0,
        };
        totalWordCount.set(locale, 0);
      }

      // Per-file stats
      const fileStats: Record<
        string,
        {
          path: string;
          sourceKeys: number;
          wordCount: number;
          languageStats: Record<
            string,
            {
              complete: number;
              missing: number;
              updated: number;
              words: number;
            }
          >;
        }
      > = {};

      // Process each bucket
      for (const bucket of buckets) {
        try {
          console.log();
          ora.info(`Analyzing bucket: ${bucket.type}`);

          for (const bucketPath of bucket.paths) {
            const bucketOra = Ora({ indent: 2 }).info(
              `Analyzing path: ${bucketPath.pathPattern}`,
            );

            const sourceLocale = resolveOverriddenLocale(
              i18nConfig!.locale.source,
              bucketPath.delimiter,
            );
            const bucketLoader = createBucketLoader(
              bucket.type,
              bucketPath.pathPattern,
              {
                defaultLocale: sourceLocale,
                injectLocale: bucket.injectLocale,
                formatter: i18nConfig!.formatter,
              },
              bucket.lockedKeys,
              bucket.lockedPatterns,
              bucket.ignoredKeys,
            );

            bucketLoader.setDefaultLocale(sourceLocale);
            await bucketLoader.init();

            // Initialize file stats
            const filePath = bucketPath.pathPattern;
            if (!fileStats[filePath]) {
              fileStats[filePath] = {
                path: filePath,
                sourceKeys: 0,
                wordCount: 0,
                languageStats: {},
              };

              for (const locale of targetLocales) {
                fileStats[filePath].languageStats[locale] = {
                  complete: 0,
                  missing: 0,
                  updated: 0,
                  words: 0,
                };
              }
            }

            // Get source data and count source keys
            const sourceData = await bucketLoader.pull(sourceLocale);
            const sourceKeys = Object.keys(sourceData);
            fileStats[filePath].sourceKeys = sourceKeys.length;
            totalSourceKeyCount += sourceKeys.length;

            // Calculate source word count
            let sourceWordCount = 0;
            for (const key of sourceKeys) {
              const value = sourceData[key];
              if (typeof value === "string") {
                const words = value.trim().split(/\s+/).length;
                sourceWordCount += words;
              }
            }
            fileStats[filePath].wordCount = sourceWordCount;

            // Process each target locale
            for (const _targetLocale of targetLocales) {
              const targetLocale = resolveOverriddenLocale(
                _targetLocale,
                bucketPath.delimiter,
              );
              bucketOra.start(
                `[${sourceLocale} -> ${targetLocale}] Analyzing translation status...`,
              );

              let targetData = {};
              let fileExists = true;

              try {
                targetData = await bucketLoader.pull(targetLocale);
              } catch (error) {
                fileExists = false;
                bucketOra.info(
                  `[${sourceLocale} -> ${targetLocale}] Target file not found, assuming all keys need translation.`,
                );
              }

              if (!fileExists) {
                // All keys are missing for this locale
                fileStats[filePath].languageStats[_targetLocale].missing =
                  sourceKeys.length;
                fileStats[filePath].languageStats[_targetLocale].words =
                  sourceWordCount;
                languageStats[_targetLocale].missing += sourceKeys.length;
                languageStats[_targetLocale].words += sourceWordCount;
                totalWordCount.set(
                  _targetLocale,
                  (totalWordCount.get(_targetLocale) || 0) + sourceWordCount,
                );

                bucketOra.succeed(
                  `[${sourceLocale} -> ${targetLocale}] ${chalk.red(
                    `0% complete`,
                  )} (0/${sourceKeys.length} keys) - file not found`,
                );
                continue;
              }

              // Calculate delta for existing file
              const deltaProcessor = createDeltaProcessor(
                bucketPath.pathPattern,
              );
              const checksums = await deltaProcessor.loadChecksums();
              const delta = await deltaProcessor.calculateDelta({
                sourceData,
                targetData,
                checksums,
              });

              const missingKeys = delta.added;
              const updatedKeys = delta.updated;
              const completeKeys = sourceKeys.filter(
                (key) =>
                  !missingKeys.includes(key) && !updatedKeys.includes(key),
              );

              // Count words that need translation
              let wordsToTranslate = 0;
              const keysToProcess = flags.force
                ? sourceKeys
                : [...missingKeys, ...updatedKeys];

              for (const key of keysToProcess) {
                const value = sourceData[String(key)];
                if (typeof value === "string") {
                  const words = value.trim().split(/\s+/).length;
                  wordsToTranslate += words;
                }
              }

              // Update file stats
              fileStats[filePath].languageStats[_targetLocale].missing =
                missingKeys.length;
              fileStats[filePath].languageStats[_targetLocale].updated =
                updatedKeys.length;
              fileStats[filePath].languageStats[_targetLocale].complete =
                completeKeys.length;
              fileStats[filePath].languageStats[_targetLocale].words =
                wordsToTranslate;

              // Update global stats
              languageStats[_targetLocale].missing += missingKeys.length;
              languageStats[_targetLocale].updated += updatedKeys.length;
              languageStats[_targetLocale].complete += completeKeys.length;
              languageStats[_targetLocale].words += wordsToTranslate;
              totalWordCount.set(
                _targetLocale,
                (totalWordCount.get(_targetLocale) || 0) + wordsToTranslate,
              );

              // Display progress
              const totalKeysInFile = sourceKeys.length;
              const completionPercent = (
                (completeKeys.length / totalKeysInFile) *
                100
              ).toFixed(1);

              if (missingKeys.length === 0 && updatedKeys.length === 0) {
                bucketOra.succeed(
                  `[${sourceLocale} -> ${targetLocale}] ${chalk.green(
                    `100% complete`,
                  )} (${completeKeys.length}/${totalKeysInFile} keys)`,
                );
              } else {
                const message = `[${sourceLocale} -> ${targetLocale}] ${
                  parseFloat(completionPercent) > 50
                    ? chalk.yellow(`${completionPercent}% complete`)
                    : chalk.red(`${completionPercent}% complete`)
                } (${completeKeys.length}/${totalKeysInFile} keys)`;

                bucketOra.succeed(message);

                if (flags.verbose) {
                  if (missingKeys.length > 0) {
                    console.log(
                      `    ${chalk.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`,
                    );
                    console.log(
                      `    ${chalk.red(`Missing:`)} ${
                        missingKeys.length
                      } keys, ~${wordsToTranslate} words`,
                    );
                    console.log(
                      `    ${chalk.dim(
                        `Example missing: ${missingKeys
                          .slice(0, 2)
                          .join(", ")}${missingKeys.length > 2 ? "..." : ""}`,
                      )}`,
                    );
                  }
                  if (updatedKeys.length > 0) {
                    console.log(
                      `    ${chalk.yellow(`Updated:`)} ${
                        updatedKeys.length
                      } keys that changed in source`,
                    );
                  }
                }
              }
            }
          }
        } catch (error: any) {
          ora.fail(`Failed to analyze bucket ${bucket.type}: ${error.message}`);
        }
      }

      // Calculate unique keys needing translation and keys fully translated
      // Count unique keys that need translation
      const totalKeysNeedingTranslation = Object.values(languageStats).reduce(
        (sum, stats) => {
          return sum + stats.missing + stats.updated;
        },
        0,
      );

      // Calculate keys that are completely translated
      const totalCompletedKeys =
        totalSourceKeyCount -
        totalKeysNeedingTranslation / targetLocales.length;

      // Summary output
      console.log();
      ora.succeed(chalk.green(`Localization status completed.`));

      // Create a visually impactful main header
      console.log(chalk.bold.cyan(`\n╔════════════════════════════════════╗`));
      console.log(chalk.bold.cyan(`║   LOCALIZATION STATUS REPORT       ║`));
      console.log(chalk.bold.cyan(`╚════════════════════════════════════╝`));

      // Source content overview
      console.log(chalk.bold(`\n📝 SOURCE CONTENT:`));
      console.log(
        `• Source language: ${chalk.green(i18nConfig!.locale.source)}`,
      );
      console.log(
        `• Source keys: ${chalk.yellow(
          totalSourceKeyCount.toString(),
        )} keys across all files`,
      );

      // Create a language-by-language breakdown table
      console.log(chalk.bold(`\n🌐 LANGUAGE BY LANGUAGE BREAKDOWN:`));

      // Create a new table instance with cli-table3
      const table = new Table({
        head: [
          "Language",
          "Status",
          "Complete",
          "Missing",
          "Updated",
          "Total Keys",
          "Words to Translate",
        ],
        style: {
          head: ["white"], // White color for headers
          border: [], // No color for borders
        },
        colWidths: [12, 20, 18, 12, 12, 12, 15], // Explicit column widths, making Status column wider
      });

      // Data rows
      let totalWordsToTranslate = 0;
      for (const locale of targetLocales) {
        const stats = languageStats[locale];
        const percentComplete = (
          (stats.complete / totalSourceKeyCount) *
          100
        ).toFixed(1);
        const totalNeeded = stats.missing + stats.updated;

        // Determine status text and color
        let statusText;
        let statusColor;
        if (stats.missing === totalSourceKeyCount) {
          statusText = "🔴 Not started";
          statusColor = chalk.red;
        } else if (stats.missing === 0 && stats.updated === 0) {
          statusText = "✅ Complete";
          statusColor = chalk.green;
        } else if (parseFloat(percentComplete) > 80) {
          statusText = "🟡 Almost done";
          statusColor = chalk.yellow;
        } else if (parseFloat(percentComplete) > 0) {
          statusText = "🟠 In progress";
          statusColor = chalk.yellow;
        } else {
          statusText = "🔴 Not started";
          statusColor = chalk.red;
        }

        // Create row data
        const words = totalWordCount.get(locale) || 0;
        totalWordsToTranslate += words;

        // Add row to the table
        table.push([
          locale,
          statusColor(statusText),
          `${stats.complete}/${totalSourceKeyCount} (${percentComplete}%)`,
          stats.missing > 0 ? chalk.red(stats.missing.toString()) : "0",
          stats.updated > 0 ? chalk.yellow(stats.updated.toString()) : "0",
          totalNeeded > 0 ? chalk.magenta(totalNeeded.toString()) : "0",
          words > 0 ? `~${words.toLocaleString()}` : "0",
        ]);
      }

      // Display the table
      console.log(table.toString());

      // Total usage summary
      console.log(chalk.bold(`\n📊 USAGE ESTIMATE:`));
      console.log(
        `• WORDS TO BE CONSUMED: ~${chalk.yellow.bold(
          totalWordsToTranslate.toLocaleString(),
        )} words across all languages`,
      );
      console.log(
        `  (Words are counted from source language for keys that need translation in target languages)`,
      );

      // Breakdown by language if we have multiple languages
      if (targetLocales.length > 1) {
        console.log(`• Per-language breakdown:`);
        for (const locale of targetLocales) {
          const words = totalWordCount.get(locale) || 0;
          const percent = ((words / totalWordsToTranslate) * 100).toFixed(1);
          console.log(
            `  - ${locale}: ~${words.toLocaleString()} words (${percent}% of total)`,
          );
        }
      }

      // Detailed stats if flags.confirm is specified
      if (flags.confirm && Object.keys(fileStats).length > 0) {
        console.log(chalk.bold(`\n📑 BREAKDOWN BY FILE:`));

        Object.entries(fileStats)
          .sort((a, b) => b[1].wordCount - a[1].wordCount) // Sort by word count
          .forEach(([path, stats]) => {
            // Skip files with no source keys
            if (stats.sourceKeys === 0) return;

            console.log(chalk.bold(`\n• ${path}:`));
            console.log(
              `  ${
                stats.sourceKeys
              } source keys, ~${stats.wordCount.toLocaleString()} source words`,
            );

            // Create file detail table
            const fileTable = new Table({
              head: ["Language", "Status", "Details"],
              style: {
                head: ["white"],
                border: [],
              },
              colWidths: [12, 20, 50], // Explicit column widths for file detail table
            });

            for (const locale of targetLocales) {
              const langStats = stats.languageStats[locale];
              const complete = langStats.complete;
              const total = stats.sourceKeys;
              const completion = ((complete / total) * 100).toFixed(1);

              let status = "✅ Complete";
              let statusColor = chalk.green;

              if (langStats.missing === total) {
                status = "❌ Not started";
                statusColor = chalk.red;
              } else if (langStats.missing > 0 || langStats.updated > 0) {
                status = `⚠️ ${completion}% complete`;
                statusColor = chalk.yellow;
              }

              // Show counts only if there's something missing or updated
              let details = "";
              if (langStats.missing > 0 || langStats.updated > 0) {
                const parts = [];
                if (langStats.missing > 0)
                  parts.push(`${langStats.missing} missing`);
                if (langStats.updated > 0)
                  parts.push(`${langStats.updated} changed`);
                details = `${parts.join(", ")}, ~${langStats.words} words`;
              } else {
                details = "All keys translated";
              }

              fileTable.push([locale, statusColor(status), details]);
            }

            console.log(fileTable.toString());
          });
      }

      // Find fully translated and missing languages
      const completeLanguages = targetLocales.filter(
        (locale) =>
          languageStats[locale].missing === 0 &&
          languageStats[locale].updated === 0,
      );

      const missingLanguages = targetLocales.filter(
        (locale) => languageStats[locale].complete === 0,
      );

      // Add optimization tips
      console.log(chalk.bold.green(`\n💡 OPTIMIZATION TIPS:`));

      if (missingLanguages.length > 0) {
        console.log(
          `• ${chalk.yellow(missingLanguages.join(", "))} ${
            missingLanguages.length === 1 ? "has" : "have"
          } no translations yet`,
        );
      }

      if (completeLanguages.length > 0) {
        console.log(
          `• ${chalk.green(completeLanguages.join(", "))} ${
            completeLanguages.length === 1 ? "is" : "are"
          } completely translated`,
        );
      }

      // Other tips
      if (targetLocales.length > 1) {
        console.log(`• Translating one language at a time reduces complexity`);
        console.log(
          `• Try 'lingo.dev@latest i18n --locale ${targetLocales[0]}' to process just one language`,
        );
      }

      // Track successful completion
      trackEvent(authId || "status", "cmd.status.success", {
        i18nConfig,
        flags,
        totalSourceKeyCount,
        languageStats,
        totalWordsToTranslate,
        authenticated: !!authId,
      });
      exitGracefully();
    } catch (error: any) {
      ora.fail(error.message);
      trackEvent(authId || "status", "cmd.status.error", {
        flags,
        error: error.message,
        authenticated: !!authId,
      });
      process.exit(1);
    }
  });

function parseFlags(options: any) {
  return Z.object({
    locale: Z.array(localeCodeSchema).optional(),
    bucket: Z.array(bucketTypeSchema).optional(),
    force: Z.boolean().optional(),
    confirm: Z.boolean().optional(),
    verbose: Z.boolean().optional(),
    file: Z.array(Z.string()).optional(),
    apiKey: Z.string().optional(),
  }).parse(options);
}

async function tryAuthenticate(settings: ReturnType<typeof getSettings>) {
  if (!settings.auth.apiKey) {
    return null;
  }

  try {
    const authenticator = createAuthenticator({
      apiKey: settings.auth.apiKey,
      apiUrl: settings.auth.apiUrl,
    });
    const user = await authenticator.whoami();
    return user;
  } catch (error) {
    return null;
  }
}

function validateParams(
  i18nConfig: I18nConfig | null,
  flags: ReturnType<typeof parseFlags>,
) {
  if (!i18nConfig) {
    throw new CLIError({
      message:
        "i18n.json not found. Please run `lingo.dev init` to initialize the project.",
      docUrl: "i18nNotFound",
    });
  } else if (!i18nConfig.buckets || !Object.keys(i18nConfig.buckets).length) {
    throw new CLIError({
      message:
        "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
      docUrl: "bucketNotFound",
    });
  } else if (
    flags.locale?.some((locale) => !i18nConfig.locale.targets.includes(locale))
  ) {
    throw new CLIError({
      message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
      docUrl: "localeTargetNotFound",
    });
  } else if (
    flags.bucket?.some(
      (bucket) =>
        !i18nConfig.buckets[bucket as keyof typeof i18nConfig.buckets],
    )
  ) {
    throw new CLIError({
      message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
      docUrl: "bucketNotFound",
    });
  }
}

```
Page 12/16FirstPrevNextLast