This is page 1 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.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
--------------------------------------------------------------------------------
/integrations/directus/.gitignore:
--------------------------------------------------------------------------------
```
.directus
```
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
```
engine-strict=true
```
--------------------------------------------------------------------------------
/demo/react-router-app/.dockerignore:
--------------------------------------------------------------------------------
```
.react-router
build
node_modules
README.md
```
--------------------------------------------------------------------------------
/demo/react-router-app/.gitignore:
--------------------------------------------------------------------------------
```
.DS_Store
/node_modules/
# React Router
/.react-router/
/build/
```
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
```
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
```
--------------------------------------------------------------------------------
/demo/adonisjs/.env.example:
--------------------------------------------------------------------------------
```
TZ=UTC
PORT=3333
HOST=localhost
LOG_LEVEL=info
APP_KEY=
NODE_ENV=development
SESSION_DRIVER=cookie
```
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
```
pnpm-lock.yaml
.changeset/
packages/cli/demo/
build/
dist/
.react-router/
.turbo/
.next/
CLAUDE.md
```
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
```
{
"trailingComma": "all",
"singleQuote": false,
"semi": true,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false
}
```
--------------------------------------------------------------------------------
/demo/vite-project/.gitignore:
--------------------------------------------------------------------------------
```
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
```
--------------------------------------------------------------------------------
/demo/adonisjs/.gitignore:
--------------------------------------------------------------------------------
```
# Dependencies and AdonisJS build
node_modules
build
tmp
# Secrets
.env
.env.local
.env.production.local
.env.development.local
# Frontend assets compiled code
public/assets
# Build tools specific
npm-debug.log
yarn-error.log
# Editors specific
.fleet
.idea
.vscode
# Platform specific
.DS_Store
```
--------------------------------------------------------------------------------
/demo/adonisjs/.editorconfig:
--------------------------------------------------------------------------------
```
# http://editorconfig.org
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.json]
insert_final_newline = unset
[**.min.js]
indent_style = unset
insert_final_newline = unset
[MakeFile]
indent_style = space
[*.md]
trim_trailing_whitespace = false
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# Dependencies
node_modules
.pnp
.pnp.js
# Local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Testing
coverage
.idea
# Turbo
.turbo
# Vercel
.vercel
# Build Outputs
.next/
out/
build
dist
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Misc
.DS_Store
*.pem
i18n.cache
```
--------------------------------------------------------------------------------
/demo/next-app/.gitignore:
--------------------------------------------------------------------------------
```
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
```
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
```markdown
packages/cli/README.md
```
--------------------------------------------------------------------------------
/legacy/cli/readme.md:
--------------------------------------------------------------------------------
```markdown
Replexica is now [Lingo.dev](https://npmjs.com/package/lingo.dev)
```
--------------------------------------------------------------------------------
/legacy/sdk/README.md:
--------------------------------------------------------------------------------
```markdown
Replexica is now [Lingo.dev](https://npmjs.com/package/lingo.dev)
```
--------------------------------------------------------------------------------
/packages/react/README.md:
--------------------------------------------------------------------------------
```markdown
# Lingo.dev Compiler React
Set of components to implement Lingo.dev Compiler in modern React frameworks.
Please refer to [Lingo.dev Compiler documentation](https://lingo.dev/en/compiler/).
```
--------------------------------------------------------------------------------
/packages/sdk/README.md:
--------------------------------------------------------------------------------
```markdown
# Lingo.dev SDK
Official SDK for Lingo.dev.
### Installation
```bash
npm i lingo.dev
```
### Usage
```
import {} from 'lingo.dev/sdk';
```
### Documentation
[Documentation](https://lingo.dev/go/docs)
```
--------------------------------------------------------------------------------
/packages/spec/README.md:
--------------------------------------------------------------------------------
```markdown
# Lingo.dev Spec
A utility package for Lingo.dev.
### Installation
```bash
npm i lingo.dev
```
### Usage
```
import {} from 'lingo.dev/spec';
```
### Documentation
[Documentation](https://lingo.dev/go/docs)
```
--------------------------------------------------------------------------------
/packages/compiler/README.md:
--------------------------------------------------------------------------------
```markdown
# Lingo.dev Compiler
**Lingo.dev Compiler** is a free, open-source compiler middleware, that makes React apps multilingual at build time without requiring any changes to the existing React components.
Documentation: https://lingo.dev/compiler
```
--------------------------------------------------------------------------------
/demo/vite-project/README.md:
--------------------------------------------------------------------------------
```markdown
# Compiler demo: Vite + React + TypeScript
This template provides a minimal setup to get [React](https://react.dev/) and [Lingo.dev Compiler](https://lingo.dev/compiler) working in [Vite](https://vite.dev/).
Documentation: https://lingo.dev/compiler/frameworks/vite
```
--------------------------------------------------------------------------------
/demo/react-router-app/README.md:
--------------------------------------------------------------------------------
```markdown
# Compiler demo: React Router / Remix
A modern, production-ready template for building full-stack React applications using [React Router](https://reactrouter.com/) and and [Lingo.dev Compiler](https://lingo.dev/compiler) implementation.
Documentation: https://lingo.dev/compiler/frameworks/react-router
```
--------------------------------------------------------------------------------
/demo/next-app/README.md:
--------------------------------------------------------------------------------
```markdown
# Compiler demo: Next.js with App Router
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app) and [Lingo.dev Compiler](https://lingo.dev/compiler) implementation.
Documentation: https://lingo.dev/compiler/frameworks/nextjs
```
--------------------------------------------------------------------------------
/.changeset/README.md:
--------------------------------------------------------------------------------
```markdown
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
```
--------------------------------------------------------------------------------
/demo/adonisjs/README.md:
--------------------------------------------------------------------------------
```markdown
# Lingo.dev Compiler with AdonisJS
## Introduction
This example demonstrates how to set up [Lingo.dev Compiler](https://lingo.dev/en/compiler/) with [AdonisJS](https://adonisjs.com/).
## Running this example
To run this example:
1. Set the `LINGODOTDEV_API_KEY` environment variable:
```bash
export LINGODOTDEV_API_KEY="<your_api_key>"
```
To get an API key, sign up for a free account at [lingo.dev](https://lingo.dev).
2. Navigate into this example's directory:
```bash
cd demo/adonisjs
```
3. Install the dependencies:
```bash
pnpm install
```
4. Run the development server:
```bash
pnpm run dev
```
5. Navigate to <http://localhost:3333>.
## Changed files
These are the files that were changed to get **Lingo.dev Compiler** up and running:
- [inertia/pages/home.tsx](./inertia/pages/home.tsx)
- [vite.config.ts](./vite.config.ts)
You can use these files as a reference when setting up the compiler in your own project.
```
--------------------------------------------------------------------------------
/scripts/docs/README.md:
--------------------------------------------------------------------------------
```markdown
# scripts/docs
## Introduction
This directory contains scripts for generating documentation from the Lingo.dev source code.
## generate-cli-docs
This script generates reference documentation for **Lingo.dev CLI**.
### Usage
```bash
pnpm --filter docs run generate-cli-docs [output_directory]
```
### How it works
1. Loads the CLI program from the `cli` package.
2. Walks through top-level commands and their subcommands.
3. Generates an `.mdx` file for each top-level command with structured reference content.
### Notes
- When running inside a GitHub Action, this script comments on the PR with the Markdown content.
- When running outside of a GitHub action, the script writes one `.mdx` file per top-level command to the provided directory.
## generate-config-docs
This script generates reference documentation for the `i18n.json` file.
### Usage
```bash
pnpm --filter docs run generate-config-docs [output_file_path]
```
### How it works
1. Converts the Zod schema into a JSON Schema.
2. Walks through all properties on the schema.
3. Generates a Markdown file with the complete property reference.
```
--------------------------------------------------------------------------------
/integrations/directus/README.md:
--------------------------------------------------------------------------------
```markdown
# Lingo.dev Integration for Directus
This is the official Lingo.dev integration for [Directus](https://directus.io), a headless CMS, enabling automated AI-powered localization within your Directus workflow.
## Overview
This integration adds a Lingo.dev operation to Directus CMS that allows you to automatically translate content across 80+ languages using Lingo.dev's AI localization engine.
## Configuration
1. Install Lingo.dev Extension in your Directus project
2. Create a new Flow in Directus with Lingo.dev Extension
3. Run the Flow to localize content
## 1. Set up Lingo.dev Extension
This section is based on the [Directus documentation for installing extensions via the npm registry](https://docs.directus.io/extensions/installing-extensions.html#installing-via-the-npm-registry).
### Modify `docker-compose.yml`
Open the `docker-compose.yml` file of your project and replace the `image` option with a `build` section:
- remove the `image` option:
```yaml
image: directus/directus:11.x.y
```
- add the `build` section:
```yaml
build:
context: ./
```
This allows you to build a customized Docker Image with the added extensions.
### Create a `Dockerfile`
At the root of your project, create a `Dockerfile` if one doesn't already exist and add the following:
```Dockerfile
FROM directus/directus:11.x.y
USER root
RUN corepack enable
USER node
RUN pnpm install @replexica/integration-directus
```
### Build the Docker Image
Build your Docker image:
```bash
docker compose build
```
### Start the Docker Container
Start your Docker container:
```bash
docker compose up
```
On startup, Directus will automatically load any extension installed in the previous steps.
## 2. Create a New Flow
1. Navigate to the Flows section in Directus CMS.
2. Create a new Flow

3. Select a Manual trigger, check collections to apply to, and Save.

4. Add Confirmation dialog with Target Languages and Save.

5. Click '+' to add a new operation and select Lingo.dev Integration for Directus.

6. Configure the operation with the required parameters.

7. Save the Flow.
## 3. Run the Flow
Go to Content and run the Flow on the collection to localize your content.

## Results
The Flow will automatically translate the content in the selected collection.

## Lingo.dev Extension Inputs
The integration provides a Directus operation that accepts the following parameters:
- `item_id`: The ID of the item to translate
- `collection`: The collection containing the content
- `translation_table`: The table storing translations
- `language_table`: The table containing supported languages
- `replexica_api_key`: Your Lingo.dev API key
- `source_language`: Source language code (defaults to 'en-US')
- `target_languages`: Array of target language codes (example: ['fr-FR', 'de-DE'])
## Development
To run the integration locally:
```bash
# Clone the repo
git clone https://github.com/lingodotdev/lingo.dev
# Install dependencies
cd integrations/directus
pnpm install
# Run dev server
pnpm dev
# Build
pnpm build
# Run tests
pnpm test
```
The integration can be tested using the included Docker setup:
```bash
docker-compose up
```
This will start Directus at [http://localhost:8055](http://localhost:8055).
## License
[Apache-2.0](./LICENSE)
## More Information
- [Lingo.dev Documentation](https://lingo.dev)
- [Directus Extensions Guide](https://docs.directus.io/extensions/operations)
- [GitHub Repository](https://github.com/lingodotdev/lingo.dev)
## Support
For questions and support:
- [Lingo.dev Discord](https://lingo.dev/go/discord)
- Email: <[email protected]>
```
--------------------------------------------------------------------------------
/packages/locales/README.md:
--------------------------------------------------------------------------------
```markdown
# @lingo.dev/locales
A JavaScript package that helps developers work with locale codes (like "en-US" or "zh-Hans-CN") and get country/language names in different languages.
## Features
- **Locale Parsing**: Break apart locale strings into language, script, and region components
- **Validation**: Check if locale codes are properly formatted and use real ISO codes
- **Name Resolution**: Get localized names for countries, languages, and scripts in 200+ languages
- **Small Bundle Size**: Core package is ~12KB with on-demand data loading
- **Full TypeScript Support**: Complete type definitions included
## Installation
```bash
npm install @lingo.dev/locales
```
## Usage
### Locale Parsing
```typescript
import {
parseLocale,
getLanguageCode,
getScriptCode,
getRegionCode,
} from "@lingo.dev/locales";
// Parse complete locale
parseLocale("en-US"); // { language: "en", region: "US" }
parseLocale("zh-Hans-CN"); // { language: "zh", script: "Hans", region: "CN" }
parseLocale("sr-Cyrl-RS"); // { language: "sr", script: "Cyrl", region: "RS" }
// Extract individual components
getLanguageCode("en-US"); // "en"
getScriptCode("zh-Hans-CN"); // "Hans"
getRegionCode("en-US"); // "US"
```
### Validation
```typescript
import {
isValidLocale,
isValidLanguageCode,
isValidScriptCode,
isValidRegionCode,
} from "@lingo.dev/locales";
// Validate complete locales
isValidLocale("en-US"); // true
isValidLocale("en-FAKE"); // false
isValidLocale("xyz-US"); // false
// Validate individual components
isValidLanguageCode("en"); // true
isValidLanguageCode("xyz"); // false
isValidScriptCode("Hans"); // true
isValidScriptCode("Fake"); // false
isValidRegionCode("US"); // true
isValidRegionCode("ZZ"); // false
```
### Name Resolution (Async)
```typescript
import {
getCountryName,
getLanguageName,
getScriptName,
} from "@lingo.dev/locales";
// Get country names in different languages
await getCountryName("US"); // "United States"
await getCountryName("US", "es"); // "Estados Unidos"
await getCountryName("CN", "fr"); // "Chine"
// Get language names in different languages
await getLanguageName("en"); // "English"
await getLanguageName("en", "es"); // "inglés"
await getLanguageName("zh", "fr"); // "chinois"
// Get script names in different languages
await getScriptName("Hans"); // "Simplified Han"
await getScriptName("Hans", "es"); // "han simplificado"
await getScriptName("Latn", "zh"); // "拉丁文"
```
## API Reference
### Parsing Functions
#### `parseLocale(locale: string): LocaleComponents`
Breaks apart a locale string into its components.
**Parameters:**
- `locale` (string): The locale string to parse
**Returns:** `LocaleComponents` object with `language`, `script`, and `region` properties
**Examples:**
```typescript
parseLocale("en-US"); // { language: "en", region: "US" }
parseLocale("zh-Hans-CN"); // { language: "zh", script: "Hans", region: "CN" }
parseLocale("es"); // { language: "es" }
```
#### `getLanguageCode(locale: string): string`
Extracts just the language part from a locale string.
#### `getScriptCode(locale: string): string | null`
Extracts the script part from a locale string.
#### `getRegionCode(locale: string): string | null`
Extracts the region/country part from a locale string.
### Validation Functions
#### `isValidLocale(locale: string): boolean`
Checks if a locale string is properly formatted and uses real codes.
#### `isValidLanguageCode(code: string): boolean`
Checks if a language code is valid (ISO 639-1).
#### `isValidScriptCode(code: string): boolean`
Checks if a script code is valid (ISO 15924).
#### `isValidRegionCode(code: string): boolean`
Checks if a region code is valid (ISO 3166-1 alpha-2 or UN M.49).
### Name Resolution Functions
#### `getCountryName(countryCode: string, displayLanguage = "en"): Promise<string>`
Gets a country name in the specified language.
**Parameters:**
- `countryCode` (string): The country code (e.g., "US", "CN")
- `displayLanguage` (string, optional): The language to display the name in (default: "en")
**Returns:** Promise<string> - The localized country name
#### `getLanguageName(languageCode: string, displayLanguage = "en"): Promise<string>`
Gets a language name in the specified language.
#### `getScriptName(scriptCode: string, displayLanguage = "en"): Promise<string>`
Gets a script name in the specified language.
## Supported Formats
The package supports both hyphen (`-`) and underscore (`_`) delimiters:
- `en-US` or `en_US` → `{ language: "en", region: "US" }`
- `zh-Hans-CN` or `zh_Hans_CN` → `{ language: "zh", script: "Hans", region: "CN" }`
## Data Sources
- **Locale parsing**: Uses regex-based parsing with ISO standard validation
- **Name resolution**: Uses Unicode CLDR (Common Locale Data Repository) data
- **Validation**: Uses official ISO 639-1, ISO 15924, and ISO 3166-1 standards
## Performance
- **Bundle size**: Core package is ~12KB (ESM) / ~14KB (CJS)
- **Runtime data**: Loaded on-demand from GitHub raw URLs
- **Caching**: In-memory cache to avoid repeated network requests
- **Fallback**: Graceful degradation to English when language data is unavailable
## Error Handling
All functions include comprehensive error handling:
```typescript
try {
parseLocale("invalid");
} catch (error) {
console.log(error.message); // "Invalid locale format: invalid"
}
try {
await getCountryName("XX");
} catch (error) {
console.log(error.message); // "Country code "XX" not found"
}
```
## TypeScript Support
Full TypeScript support with comprehensive type definitions:
```typescript
interface LocaleComponents {
language: string;
script?: string;
region?: string;
}
type LocaleDelimiter = "-" | "_";
interface ParseResult {
components: LocaleComponents;
delimiter: LocaleDelimiter | null;
isValid: boolean;
error?: string;
}
```
## License
Apache 2.0
```
--------------------------------------------------------------------------------
/packages/cli/README.md:
--------------------------------------------------------------------------------
```markdown
<p align="center">
<a href="https://lingo.dev">
<img src="https://raw.githubusercontent.com/lingodotdev/lingo.dev/main/content/banner.compiler.png" width="100%" alt="Lingo.dev" />
</a>
</p>
<p align="center">
<strong>⚡ Lingo.dev - open-source, AI-powered i18n toolkit for instant localization with LLMs.</strong>
</p>
<br />
<p align="center">
<a href="https://lingo.dev/compiler">Lingo.dev Compiler</a> •
<a href="https://lingo.dev/cli">Lingo.dev CLI</a> •
<a href="https://lingo.dev/ci">Lingo.dev CI/CD</a> •
<a href="https://lingo.dev/sdk">Lingo.dev SDK</a>
</p>
<p align="center">
<a href="https://github.com/lingodotdev/lingo.dev/actions/workflows/release.yml">
<img src="https://github.com/lingodotdev/lingo.dev/actions/workflows/release.yml/badge.svg" alt="Release" />
</a>
<a href="https://github.com/lingodotdev/lingo.dev/blob/main/LICENSE.md">
<img src="https://img.shields.io/github/license/lingodotdev/lingo.dev" alt="License" />
</a>
<a href="https://github.com/lingodotdev/lingo.dev/commits/main">
<img src="https://img.shields.io/github/last-commit/lingodotdev/lingo.dev" alt="Last Commit" />
</a>
<a href="https://lingo.dev/en">
<img src="https://img.shields.io/badge/Product%20Hunt-%231%20DevTool%20of%20the%20Month-orange?logo=producthunt&style=flat-square" alt="Product Hunt #1 DevTool of the Month" />
</a>
<a href="https://lingo.dev/en">
<img src="https://img.shields.io/badge/Product%20Hunt-%231%20Product%20of%20the%20Week-orange?logo=producthunt&style=flat-square" alt="Product Hunt #1 DevTool of the Week" />
</a>
<a href="https://lingo.dev/en">
<img src="https://img.shields.io/badge/Product%20Hunt-%232%20Product%20of%20the%20Day-orange?logo=producthunt&style=flat-square" alt="Product Hunt #2 Product of the Day" />
</a>
<a href="https://lingo.dev/en">
<img src="https://img.shields.io/badge/GitHub-Trending-blue?logo=github&style=flat-square" alt="Github trending" />
</a>
</p>
---
## Meet the Compiler 🆕
**Lingo.dev Compiler** is a free, open-source compiler middleware, designed to make any React app multilingual at build time without requiring any changes to the existing React components.
Install once:
```bash
npm install lingo.dev
```
Enable in your build config:
```js
import lingoCompiler from "lingo.dev/compiler";
const existingNextConfig = {};
export default lingoCompiler.next({
sourceLocale: "en",
targetLocales: ["es", "fr"],
})(existingNextConfig);
```
Run `next build` and watch Spanish and French bundles pop out ✨
[Read the docs →](https://lingo.dev/compiler) for the full guide, and [Join our Discord](https://lingo.dev/go/discord) to get help with your setup.
---
### What's inside this repo?
| Tool | TL;DR | Docs |
| ------------ | ------------------------------------------------------------------------------ | --------------------------------------- |
| **Compiler** | Build-time React localization | [/compiler](https://lingo.dev/compiler) |
| **CLI** | One-command localization for web and mobile apps, JSON, YAML, markdown, + more | [/cli](https://lingo.dev/cli) |
| **CI/CD** | Auto-commit translations on every push + create pull requests if needed | [/ci](https://lingo.dev/ci) |
| **SDK** | Realtime translation for user-generated content | [/sdk](https://lingo.dev/sdk) |
Below are the quick hits for each 👇
---
### ⚡️ Lingo.dev CLI
Translate code & content straight from your terminal.
```bash
npx lingo.dev@latest run
```
It fingerprints every string, caches results, and only re-translates what changed.
[Follow the docs →](https://lingo.dev/cli) to learn how to set it up.
---
### 🔄 Lingo.dev CI/CD
Ship perfect translations automatically.
```yaml
# .github/workflows/i18n.yml
name: Lingo.dev i18n
on: [push]
jobs:
i18n:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: lingodotdev/lingo.dev@main
with:
api-key: ${{ secrets.LINGODOTDEV_API_KEY }}
```
Keeps your repo green and your product multilingual without the manual steps.
[Read the docs →](https://lingo.dev/ci)
---
### 🧩 Lingo.dev SDK
Instant per-request translation for dynamic content.
```ts
import { LingoDotDevEngine } from "lingo.dev/sdk";
const lingoDotDev = new LingoDotDevEngine({
apiKey: "your-api-key-here",
});
const content = {
greeting: "Hello",
farewell: "Goodbye",
message: "Welcome to our platform",
};
const translated = await lingoDotDev.localizeObject(content, {
sourceLocale: "en",
targetLocale: "es",
});
// Returns: { greeting: "Hola", farewell: "Adiós", message: "Bienvenido a nuestra plataforma" }
```
Perfect for chat, user comments, and other real-time flows.
[Read the docs →](https://lingo.dev/sdk)
---
## 🤝 Community
We're community-driven and love contributions!
- Got an idea? [Open an issue](https://github.com/lingodotdev/lingo.dev/issues)
- Want to fix something? [Send a PR](https://github.com/lingodotdev/lingo.dev/pulls)
- Need help? [Join our Discord](https://lingo.dev/go/discord)
## ⭐ Star History
If you like what we're doing, give us a ⭐ and help us reach 4,000 stars! 🌟
[](https://www.star-history.com/#lingodotdev/lingo.dev&Date)
## 🌐 Readme in other languages
[English](https://github.com/lingodotdev/lingo.dev) • [中文](/readme/zh-Hans.md) • [日本語](/readme/ja.md) • [한국어](/readme/ko.md) • [Español](/readme/es.md) • [Français](/readme/fr.md) • [Русский](/readme/ru.md) • [Українська](/readme/uk-UA.md) • [Deutsch](/readme/de.md) • [Italiano](/readme/it.md) • [العربية](/readme/ar.md) • [עברית](/readme/he.md) • [हिन्दी](/readme/hi.md) • [বাংলা](/readme/bn.md) • [فارسی](/readme/fa.md)
Don't see your language? Add it to [`i18n.json`](./i18n.json) and open a PR!
```
--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------
```markdown
# Extremely important instructions for Claude
## FYI
- We're in a pnpm + turbo monorepo
## Tools
- Must use `pnpm` as package manager
## Testing
- When you add tests - make sure they pass
```
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
```markdown
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[email protected].
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
```
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
```markdown
# CONTRIBUTING.md
Thank you for contributing to Lingo.dev! We're an exciting open source project and we love having you contribute!
Here are some resources and guidance to help you get started:
1. [Getting Started](#getting-started)
2. [Issues](#issues)
3. [Pull Requests](#pull-requests)
4. [Release Process](#release-process)
## Getting Started
Here's how to get the project running locally:
### Prerequisites
- **Node.js**: Make sure you have Node.js version 18 or higher installed.
- **pnpm**: You can install using this command `npm install -g pnpm` or by following [this guide](https://pnpm.io/installation)
- **AI API Key**:
Currently, Groq, Google, and Mistral are supported.
- **GROQ API Key**: You can get one by signing up at [Groq](https://console.groq.com/)
- **GOOGLE API Key**: You can get one in the [Google AI Studio](https://aistudio.google.com/apikey)
- **MISTRAL API Key**: You can get one by signing up at [Mistral AI](https://console.mistral.ai)
### Setup
To set up the project, clone the repository and install the dependencies:
```bash
git clone https://github.com/lingodotdev/lingo.dev
cd lingo.dev
pnpm install
```
Next, configure an AI API key. You can use either a Lingo.dev API key or one of the supported LLM model providers.
Please refer to our docs on how to set this up: https://lingo.dev/en/cli/quick-start#step-2-authentication
_Note:_ When loading LLM API keys (both Lingo.dev and other LLM model providers like Groq or Mistral), the Lingo.dev Compiler checks the following sources in order of priority:
1. Environment variables (via `process.env`)
2. Environment files (`.env`, `.env.local`, `.env.development`)
3. Lingo.dev configuration
Next, you can run the project using the following commands:
```bash
# start the build process
pnpm turbo build
# in terminal window 1 - watch for CLI code changes
cd packages/cli
pnpm run dev
# in terminal window 2 - test the CLI
cd packages/cli
pnpm lingo.dev --help # this command will use the current CLI code + demo config from ./packages/cli/i18n.json
```
Feel free to ask questions on our [Discord server](https://lingo.dev/go/discord)!
## Adding a New LLM Provider
Want to add support for a new LLM provider to Lingo.dev? Here's a checklist to help you get started:
1. **Add Your Dependency**
- Install the relevant SDK/package for your provider in the necessary `package.json` (usually `cli` and/or `compiler`). Lingo.dev uses the [AI SDK](https://ai-sdk.dev) and its [providers](https://ai-sdk.dev/providers/ai-sdk-providers), so check first to make sure the AI SDK supports your provider.
2. **Update the Config Schema**
- Edit [`packages/spec/src/config.ts`](./packages/spec/src/config.ts) and update the list of allowed provider `id` values to include your new provider.
3. **Provider Details**
- Add your provider to [`packages/compiler/src/lib/lcp/api/provider-details.ts`](./packages/compiler/src/lib/lcp/api/provider-details.ts) with name, env var, config key, API docs, and signup link.
4. **API Key Handling**
- Update [`packages/compiler/src/utils/llm-api-key.ts`](./packages/compiler/src/utils/llm-api-key.ts) to add functions for getting the API key from environment/config.
5. **CLI and Compiler Logic**
- Update the CLI (e.g., [`packages/cli/src/cli/localizer/explicit.ts`](./packages/cli/src/cli/localizer/explicit.ts), [`packages/cli/src/cli/processor/index.ts`](./packages/cli/src/cli/processor/index.ts)) to support your provider.
- Update the compiler's translation logic to instantiate your provider's client (see [`packages/compiler/src/lib/lcp/api/index.ts`](./packages/compiler/src/lib/lcp/api/index.ts)).
6. **Error Handling**
- Ensure user-facing error messages are updated to mention your provider where relevant (API key checks, troubleshooting, etc).
7. **Test and Document**
- Add or update tests to cover your provider.
- Update documentation and this contributing guide as needed.
**Tip:**
Look at how existing providers like "groq", "google", and "mistral" are implemented for reference. Consistency helps us maintain quality and predictability!
## Issues
If you find a bug, please create an Issue and we'll triage it.
- Please search [existing Issues](https://github.com/lingodotdev/lingo.dev/issues) before creating a new one
- Please include a clear description of the problem along with steps to reproduce it. Exact steps with screenshots and URLs really help here
- Before starting work on an issue, please comment on it and wait for it to be assigned to you. This prevents multiple people from working on the same issue simultaneously
- Let's discuss implementation details in the issue comments or Discord before starting work, to ensure alignment between contributors and the Lingo.dev team
## Pull Requests
We love your Pull Requests! However, we maintain extremely high standards for code quality and design. We are looking for elegant, 12/10, beautiful code and deeply weighted system design decisions.
### Our Standards
- **Surgical PRs**: Pull requests must be surgical and extremely single-purposed. One clear objective per PR.
- **Elegant Code**: We expect beautifully crafted, elegant code that demonstrates mastery of the language and patterns.
- **Deep Design Thinking**: System design decisions must be deeply considered and well-reasoned.
- **Comprehensive Testing**: Must include tests that surgically test both positive and negative paths of the code.
- **Uncompromising Quality**: We prefer fewer, higher-quality contributions over numerous mediocre ones.
A couple of things to keep in mind before you submit:
### Before you open a pull request
- GitHub Issue
- Make sure the fix or feature is sufficiently documented and discussed in advance in an existing [GitHub Issue](https://github.com/lingodotdev/lingo.dev/issues)
- If there are no related issues, **we strongly suggest you [create a new Issue](https://github.com/lingodotdev/lingo.dev/issues/new)** and discuss your feature or proposal with the Lingo.dev team
- If there is a Discord thread already, please summarize it in a GitHub Issue. This helps to keep everyone in the loop, including open-source contributors and Lingo.dev team members not part of the original conversation. It also serves as documentation for future decisions.
- README update
- If applicable, please add a section with the CLI commands introduced in your PR (what their purpose is and how to use them)
- It is not necessary to update the README file for every change, oftentimes a comprehensive description in the Issue or PR description is enough
- Tests
- Your changes should include unit tests for the main code paths, to make sure nothing breaks
- Changeset
- Add a [changeset](https://github.com/changesets/changesets) for your feature or fix (run `pnpm new` from the repo root)
- PR checks
- Make sure all checks pass
- You can run the checks locally in repo root:
```sh
pnpm install --frozen-lockfile
pnpm format:check
pnpm turbo build --force
pnpm turbo test --force
pnpm changeset status --since origin/main
```
...or let GitHub run it in the PR for you.
### Opening a pull request
- GitHub Issue
- Make sure to link your PR to the existing Issue(s)
- We may not be able to accept new features without existing Issues
- This does not apply to smaller fixes with sufficient description in the PR
- Existing PRs
- Make sure someone else hasn't already created a PR fixing the same issue.
- PR title
- The title should be [a valid Conventional Commit title](https://github.com/amannn/action-semantic-pull-request?tab=readme-ov-file#action-semantic-pull-request)
- Should start with `feat:`, `fix:`, `chore:`, etc.
- PR description
- Should contain sufficient description of your PR (unless the linked Issue already does)
- _💡 Tip:_ Oftentimes less is more. Try to write in your own words; real humans are reviewing your PR.
- Demo video
- For larger features we would really appreciate a quick screen recording showing it in action
- It helps make the review process faster
- You can use [open-source Cap](https://github.com/CapSoftware/Cap), [QuickTime on Mac](https://support.apple.com/guide/quicktime-player/record-your-screen-qtp97b08e666/mac), or any other software you prefer
### Review Process
- We will always try to accept the first viable PR that resolves the Issue
- Please discuss implementation approach beforehand to avoid having PRs rejected
- Please actively discuss with the Lingo.dev team in the PR and related Issue(s)
#### Automated Code Review
We use Claude Code to provide automated code reviews on all pull requests. This helps ensure:
- Code quality and maintainability
- Security best practices
- Performance considerations
- Proper test coverage
- Documentation completeness
The automated review will post comments on your PR with suggestions and feedback. While these are helpful guidelines, human reviewers will make the final decisions. If Claude Code identifies critical security issues, please address them promptly.
---
Thank you!
```
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
```markdown
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2024 Lingo.dev
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
--------------------------------------------------------------------------------
/packages/react/src/test/setup.ts:
--------------------------------------------------------------------------------
```typescript
```
--------------------------------------------------------------------------------
/packages/cli/demo/yaml-root-key/es/example.yml:
--------------------------------------------------------------------------------
```yaml
es: {}
```
--------------------------------------------------------------------------------
/readme/en.md:
--------------------------------------------------------------------------------
```markdown
../packages/cli/README.md
```
--------------------------------------------------------------------------------
/packages/react/src/react-router/index.ts:
--------------------------------------------------------------------------------
```typescript
export * from "./loader";
```
--------------------------------------------------------------------------------
/legacy/sdk/index.d.ts:
--------------------------------------------------------------------------------
```typescript
export * from "lingo.dev/sdk";
```
--------------------------------------------------------------------------------
/demo/vite-project/src/vite-env.d.ts:
--------------------------------------------------------------------------------
```typescript
/// <reference types="vite/client" />
```
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
```javascript
export default { extends: ["@commitlint/config-conventional"] };
```
--------------------------------------------------------------------------------
/demo/adonisjs/eslint.config.js:
--------------------------------------------------------------------------------
```javascript
import { configApp } from '@adonisjs/eslint-config'
export default configApp()
```
--------------------------------------------------------------------------------
/demo/adonisjs/inertia/css/app.css:
--------------------------------------------------------------------------------
```css
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
width: 100%;
}
```
--------------------------------------------------------------------------------
/packages/spec/src/index.ts:
--------------------------------------------------------------------------------
```typescript
export * from "./locales";
export * from "./formats";
export * from "./config";
```
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
```json
{
"recommendations": ["esbenp.prettier-vscode", "bradlc.vscode-tailwindcss"]
}
```
--------------------------------------------------------------------------------
/demo/next-app/postcss.config.mjs:
--------------------------------------------------------------------------------
```
const config = {
plugins: ["@tailwindcss/postcss"],
};
export default config;
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/md5.ts:
--------------------------------------------------------------------------------
```typescript
import { MD5 } from "object-hash";
export function md5(input: any) {
return MD5(input);
}
```
--------------------------------------------------------------------------------
/packages/cli/bin/cli.mjs:
--------------------------------------------------------------------------------
```
#!/usr/bin/env node
import CLI from "../build/cli.mjs";
await CLI.parseAsync(process.argv);
```
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
```yaml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
```
--------------------------------------------------------------------------------
/packages/cli/src/sdk/index.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_sdk";
export * from "@lingo.dev/_sdk";
```
--------------------------------------------------------------------------------
/demo/vite-project/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
```
--------------------------------------------------------------------------------
/packages/cli/src/spec/index.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_spec";
export * from "@lingo.dev/_spec";
```
--------------------------------------------------------------------------------
/packages/cli/types/xliff.d.ts:
--------------------------------------------------------------------------------
```typescript
declare module "xliff" {
export function xliff2js(data: string): any;
export function js2xliff(data: any): string;
}
```
--------------------------------------------------------------------------------
/packages/cli/src/react/index.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_react";
export * from "@lingo.dev/_react";
```
--------------------------------------------------------------------------------
/packages/cli/types/vtt.d.ts:
--------------------------------------------------------------------------------
```typescript
declare module "node-webvtt" {
export function parse(data: string): any;
export function compile(data: any): string;
}
```
--------------------------------------------------------------------------------
/packages/cli/src/locale-codes/index.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_locales";
export * from "@lingo.dev/_locales";
```
--------------------------------------------------------------------------------
/packages/react/src/core/index.ts:
--------------------------------------------------------------------------------
```typescript
export * from "./component";
export * from "./const";
export * from "./attribute-component";
export * from "./get-dictionary";
```
--------------------------------------------------------------------------------
/demo/next-app/public/vercel.svg:
--------------------------------------------------------------------------------
```
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
```
--------------------------------------------------------------------------------
/integrations/directus/tsconfig.test.json:
--------------------------------------------------------------------------------
```json
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.tsx"],
"compilerOptions": {
"noEmit": true
}
}
```
--------------------------------------------------------------------------------
/packages/cli/tsconfig.test.json:
--------------------------------------------------------------------------------
```json
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.tsx"],
"compilerOptions": {
"noEmit": true
}
}
```
--------------------------------------------------------------------------------
/packages/sdk/tsconfig.test.json:
--------------------------------------------------------------------------------
```json
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.tsx"],
"compilerOptions": {
"noEmit": true
}
}
```
--------------------------------------------------------------------------------
/packages/spec/tsconfig.test.json:
--------------------------------------------------------------------------------
```json
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.tsx"],
"compilerOptions": {
"noEmit": true
}
}
```
--------------------------------------------------------------------------------
/packages/cli/src/react/rsc.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_react/rsc";
export * from "@lingo.dev/_react/rsc";
```
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
```yaml
packages:
- "./packages/*"
- "./demo/*"
- "./integrations/*"
- "./legacy/*"
- "./action"
- "./php/*"
- "./scripts/*"
```
--------------------------------------------------------------------------------
/demo/next-app/src/components/index.ts:
--------------------------------------------------------------------------------
```typescript
export { HeroTitle } from "./hero-title";
export { HeroSubtitle } from "./hero-subtitle";
export { HeroActions } from "./hero-actions";
```
--------------------------------------------------------------------------------
/packages/cli/src/react/client.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_react/client";
export * from "@lingo.dev/_react/client";
```
--------------------------------------------------------------------------------
/packages/cli/src/compiler/index.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_compiler";
export { default } from "@lingo.dev/_compiler";
```
--------------------------------------------------------------------------------
/packages/compiler/src/jsx-attribute.ts:
--------------------------------------------------------------------------------
```typescript
import { createCodeMutation } from "./_base";
export const jsxAttributeMutation = createCodeMutation((payload) => {
return payload;
});
```
--------------------------------------------------------------------------------
/integrations/directus/src/index.spec.ts:
--------------------------------------------------------------------------------
```typescript
import { describe, it, expect } from "vitest";
describe("Test suite", () => {
it("should pass", () => {
expect(1).toBe(1);
});
});
```
--------------------------------------------------------------------------------
/packages/spec/src/index.spec.ts:
--------------------------------------------------------------------------------
```typescript
import { describe, it, expect } from "vitest";
describe("Test suite", () => {
it("should pass", () => {
expect(1).toBe(1);
});
});
```
--------------------------------------------------------------------------------
/packages/cli/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
setupFiles: ["./tests/mock-storage.ts"],
},
});
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/index.spec.ts:
--------------------------------------------------------------------------------
```typescript
import { describe, it, expect } from "vitest";
describe("lingo.dev", () => {
it("should work", () => {
expect(true).toBe(true);
});
});
```
--------------------------------------------------------------------------------
/packages/react/src/rsc/index.ts:
--------------------------------------------------------------------------------
```typescript
export * from "./loader";
export * from "./component";
export * from "./provider";
export * from "./utils";
export * from "./attribute-component";
```
--------------------------------------------------------------------------------
/packages/cli/src/react/react-router.ts:
--------------------------------------------------------------------------------
```typescript
// Re-export everything but with type checking
export type * from "@lingo.dev/_react/react-router";
export * from "@lingo.dev/_react/react-router";
```
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll": "always"
}
}
```
--------------------------------------------------------------------------------
/integrations/directus/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
FROM directus/directus:11
USER root
RUN npm install -g pnpm@latest
USER node
# Install the integration
RUN pnpm install @replexica/integration-directus
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/constants.ts:
--------------------------------------------------------------------------------
```typescript
export const colors = {
orange: "#ff6600",
green: "#6ae300",
blue: "#0090ff",
yellow: "#ffcc00",
grey: "#808080",
red: "#ff0000",
white: "#ffffff",
};
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/po/_types.ts:
--------------------------------------------------------------------------------
```typescript
export type PoTranslationEntry = {
id: string;
value: string;
pluralValue?: string;
context?: string;
metadata?: Record<string, string>;
flags?: string[];
};
```
--------------------------------------------------------------------------------
/demo/next-app/src/components/hero-title.tsx:
--------------------------------------------------------------------------------
```typescript
export function HeroTitle() {
return (
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold text-gray-900 mb-6 leading-tight">
Lingo.dev
</h1>
);
}
```
--------------------------------------------------------------------------------
/demo/vite-project/src/components/test.tsx:
--------------------------------------------------------------------------------
```typescript
export const TestComponent = () => {
return (
<div>
<h1>Testing Component</h1>
<p>This is a component intended for testing purposes.</p>
</div>
);
};
```
--------------------------------------------------------------------------------
/packages/compiler/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "jsdom",
globals: true,
include: ["./src/**/*.spec.ts*"],
},
});
```
--------------------------------------------------------------------------------
/demo/react-router-app/app/routes.ts:
--------------------------------------------------------------------------------
```typescript
import { type RouteConfig, index, route } from "@react-router/dev/routes";
export default [
index("routes/home.tsx"),
route("test", "./routes/test.tsx"),
] satisfies RouteConfig;
```
--------------------------------------------------------------------------------
/demo/adonisjs/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"extends": "@adonisjs/tsconfig/tsconfig.app.json",
"compilerOptions": {
"rootDir": "./",
"outDir": "./build"
},
"exclude": ["./inertia/**/*", "node_modules", "build"]
}
```
--------------------------------------------------------------------------------
/demo/react-router-app/react-router.config.ts:
--------------------------------------------------------------------------------
```typescript
import type { Config } from "@react-router/dev/config";
export default {
// Config options...
// Server-side render by default, to enable SPA mode set this to `false`
ssr: true,
} satisfies Config;
```
--------------------------------------------------------------------------------
/packages/react/src/client/index.ts:
--------------------------------------------------------------------------------
```typescript
export * from "./loader";
export * from "./context";
export * from "./provider";
export * from "./component";
export * from "./locale-switcher";
export * from "./attribute-component";
export * from "./locale";
```
--------------------------------------------------------------------------------
/packages/cli/demo/txt/en/example.txt:
--------------------------------------------------------------------------------
```
This is the first line of text content
This is the second line with different content
This line contains special characters: !@#$%^&*()
This is line five after an empty line above
Thank you for choosing our service
```
--------------------------------------------------------------------------------
/demo/adonisjs/inertia/pages/errors/not_found.tsx:
--------------------------------------------------------------------------------
```typescript
export default function NotFound() {
return (
<>
<div className="container">
<div className="title">Page not found</div>
<span>This page does not exist.</span>
</div>
</>
)
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/inertia/pages/errors/server_error.tsx:
--------------------------------------------------------------------------------
```typescript
export default function ServerError(props: { error: any }) {
return (
<>
<div className="container">
<div className="title">Server Error</div>
<span>{props.error.message}</span>
</div>
</>
)
}
```
--------------------------------------------------------------------------------
/packages/react/src/core/const.ts:
--------------------------------------------------------------------------------
```typescript
/**
* The name of the cookie that stores the current locale.
*/
export const LOCALE_COOKIE_NAME = "lingo-locale";
/**
* The name of the header that stores the current locale.
*/
export const LOCALE_HEADER_NAME = "x-lingo-locale";
```
--------------------------------------------------------------------------------
/packages/cli/demo/csv/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"csv": {
"include": [
"./example.csv"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/inertia/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"extends": "@adonisjs/tsconfig/tsconfig.client.json",
"compilerOptions": {
"baseUrl": ".",
"module": "ESNext",
"jsx": "react-jsx",
"paths": {
"~/*": ["./*"]
}
},
"include": ["./**/*.ts", "./**/*.tsx"]
}
```
--------------------------------------------------------------------------------
/packages/compiler/src/utils/module-params.ts:
--------------------------------------------------------------------------------
```typescript
export function parseParametrizedModuleId(rawId: string) {
const moduleUri = new URL(rawId, "module://");
return {
id: moduleUri.pathname.replace(/^\//, ""),
params: Object.fromEntries(moduleUri.searchParams.entries()),
};
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/vue-json/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"vue-json": {
"include": [
"./example.vue"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/txt/es/example.txt:
--------------------------------------------------------------------------------
```
Esta es la primera línea de contenido de texto
Esta es la segunda línea con contenido diferente
Esta línea contiene caracteres especiales: !@#$%^&*()
Esta es la línea cinco después de una línea vacía arriba
Gracias por elegir nuestro servicio
```
--------------------------------------------------------------------------------
/packages/cli/demo/po/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"po": {
"include": [
"./[locale]/example.po"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/ejs/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"ejs": {
"include": [
"./[locale]/example.ejs"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/php/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"php": {
"include": [
"./[locale]/example.php"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/srt/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"srt": {
"include": [
"./[locale]/example.srt"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/txt/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"txt": {
"include": [
"./[locale]/example.txt"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/vtt/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"vtt": {
"include": [
"./[locale]/example.vtt"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/xml/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"xml": {
"include": [
"./[locale]/example.xml"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
```markdown
### What
[//]: # "Brief description of the new feature / a bug. Expected vs actual, if relevant."
### Why
[//]: # "Explain why this is needed"
### How
[//]: # "Solution proposals, ideas, etc. Overview of how the feature could be implemented"
```
--------------------------------------------------------------------------------
/packages/cli/demo/html/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"html": {
"include": [
"./[locale]/example.html"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/android/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"android": {
"include": [
"./[locale]/example.xml"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/flutter/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"flutter": {
"include": [
"./[locale]/example.arb"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/markdown/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"markdown": {
"include": [
"./[locale]/example.md"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/xliff/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"xliff": {
"include": [
"./[locale]/example.xliff"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/json-dictionary/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"json-dictionary": {
"include": [
"./example.json"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/jsonc/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"jsonc": {
"include": [
"./[locale]/example.jsonc"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/markdoc/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"markdoc": {
"include": [
"./[locale]/example.markdoc"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/xcode-xcstrings/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"xcode-xcstrings": {
"include": [
"./example.xcstrings"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/yaml-root-key/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"yaml-root-key": {
"include": [
"./[locale]/example.yml"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/xcode-xcstrings-v2/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"xcode-xcstrings-v2": {
"include": [
"./example.xcstrings"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/properties/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"properties": {
"include": [
"./[locale]/example.properties"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/xcode-strings/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"xcode-strings": {
"include": [
"./[locale]/example.strings"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/xcode-stringsdict/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"xcode-stringsdict": {
"include": [
"./[locale]/example.stringsdict"
]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/react/src/client/context.ts:
--------------------------------------------------------------------------------
```typescript
"use client";
import { createContext, useContext } from "react";
export type LingoContextType = {
dictionary: any;
};
export const LingoContext = createContext<LingoContextType>({
dictionary: {},
});
export function useLingo() {
return useContext(LingoContext);
}
```
--------------------------------------------------------------------------------
/packages/react/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
export default defineConfig({
test: {
environment: "jsdom",
globals: true,
setupFiles: ["./src/test/setup.ts"],
include: ["./src/**/*.spec.ts*"],
},
plugins: [react()],
});
```
--------------------------------------------------------------------------------
/packages/cli/demo/yaml/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"yaml": {
"include": [
"./[locale]/example.yml"
],
"lockedKeys": ["locked_key_1"]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/json/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"json": {
"include": [
"./[locale]/example.json"
],
"lockedKeys": ["locked_key_1"]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/json5/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"json5": {
"include": [
"./[locale]/example.json5"
],
"lockedKeys": ["locked_key_1"]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/compiler/src/_const.ts:
--------------------------------------------------------------------------------
```typescript
export const ModuleId = {
ReactClient: ["lingo.dev/react/client", "lingo.dev/react-client"],
ReactRSC: ["lingo.dev/react/rsc", "lingo.dev/react-rsc"],
ReactRouter: ["lingo.dev/react/react-router", "lingo.dev/react-router"],
};
export const LCP_DICTIONARY_FILE_NAME = "dictionary.js";
```
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
```json
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "lingodotdev/lingo.dev" }],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch"
}
```
--------------------------------------------------------------------------------
/demo/react-router-app/app/app.css:
--------------------------------------------------------------------------------
```css
@import "tailwindcss";
@theme {
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
html,
body {
@apply bg-white dark:bg-gray-950;
@media (prefers-color-scheme: dark) {
color-scheme: dark;
}
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/passthrough.ts:
--------------------------------------------------------------------------------
```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createPassThroughLoader(
state: any,
): ILoader<void, string> {
return createLoader({
pull: async () => state.data,
push: async (locale, data) => {
state.data = data;
},
});
}
```
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
```json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["typecheck", "^build"]
},
"typecheck": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["^build"]
},
"deploy": {
"dependsOn": ["build", "test", "^deploy"]
}
}
}
```
--------------------------------------------------------------------------------
/packages/sdk/tsup.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "tsup";
export default defineConfig({
clean: true,
target: "esnext",
entry: ["src/index.ts"],
outDir: "build",
format: ["cjs", "esm"],
dts: true,
cjsInterop: true,
splitting: true,
outExtension: (ctx) => ({
js: ctx.format === "cjs" ? ".cjs" : ".mjs",
}),
});
```
--------------------------------------------------------------------------------
/packages/locales/tsup.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "tsup";
export default defineConfig({
clean: true,
target: "esnext",
entry: ["src/index.ts"],
outDir: "build",
format: ["cjs", "esm"],
dts: true,
cjsInterop: true,
splitting: false,
outExtension: (ctx) => ({
js: ctx.format === "cjs" ? ".cjs" : ".mjs",
}),
});
```
--------------------------------------------------------------------------------
/demo/react-router-app/app/routes/home.tsx:
--------------------------------------------------------------------------------
```typescript
import type { Route } from "./+types/home";
import { Welcome } from "../welcome/welcome";
export function meta({}: Route.MetaArgs) {
return [
{ title: "New React Router App" },
{ name: "description", content: "Welcome to React Router!" },
];
}
export default function Home() {
return <Welcome />;
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/properties/en/example.properties:
--------------------------------------------------------------------------------
```
app.title=MyApp
app.description=A simple demo application
user.greeting=Hello, world!
user.farewell=Thanks for using MyApp
error.message=Something went wrong
error.notFound=Page not found
database.host=localhost
database.port=5432
notification.success=Changes saved!
notification.warning=Please check your input
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/mdx2/_utils.ts:
--------------------------------------------------------------------------------
```typescript
import { Root, RootContent } from "mdast";
export function traverseMdast(
ast: Root | RootContent,
visitor: (node: Root | RootContent) => void,
) {
visitor(ast);
if ("children" in ast && Array.isArray(ast.children)) {
for (const child of ast.children) {
traverseMdast(child, visitor);
}
}
}
```
--------------------------------------------------------------------------------
/packages/compiler/src/i18n-directive.ts:
--------------------------------------------------------------------------------
```typescript
import { createCodeMutation } from "./_base";
import { hasI18nDirective } from "./utils";
const i18nDirectiveMutation = createCodeMutation((payload) => {
if (!payload.params.useDirective || hasI18nDirective(payload.ast)) {
return payload;
} else {
return null;
}
});
export default i18nDirectiveMutation;
```
--------------------------------------------------------------------------------
/demo/adonisjs/start/routes.ts:
--------------------------------------------------------------------------------
```typescript
/*
|--------------------------------------------------------------------------
| Routes file
|--------------------------------------------------------------------------
|
| The routes file is used for defining the HTTP routes.
|
*/
import router from '@adonisjs/core/services/router'
router.on('/').renderInertia('home')
```
--------------------------------------------------------------------------------
/packages/cli/demo/mdx/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"mdx": {
"include": [
"./[locale]/example.mdx"
],
"lockedKeys": ["locked_key_1"],
"lockedPatterns": ["pattern_1"]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/legacy/sdk/index.js:
--------------------------------------------------------------------------------
```javascript
console.warn(
"\x1b[33m%s\x1b[0m",
`
⚠️ WARNING: NEW PACKAGE AVAILABLE ⚠️
=======================================
This SDK version is deprecated.
Please use lingo.dev instead:
npm install lingo.dev
Visit https://lingo.dev for more information.
=======================================
`,
);
export * from "lingo.dev/sdk";
```
--------------------------------------------------------------------------------
/packages/cli/demo/run_i18n.sh:
--------------------------------------------------------------------------------
```bash
#!/usr/bin/env bash
set -euo pipefail
pnpm install
pnpm --filter lingo.dev run build
root_dir=$(git rev-parse --show-toplevel)
cli="$root_dir/packages/cli/bin/cli.mjs"
demo_root="$root_dir/packages/cli/demo"
for demo in "$demo_root"/*/; do
printf '\n%s\n' "${demo%/}"
(
cd "$demo"
node "$cli" i18n "$@"
)
done
```
--------------------------------------------------------------------------------
/packages/cli/demo/typescript/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"es"
]
},
"buckets": {
"typescript": {
"include": [
"./[locale]/example.ts"
],
"lockedKeys": ["locked_key_1"],
"ignoredKeys": ["ignored_key_1"]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/properties/es/example.properties:
--------------------------------------------------------------------------------
```
app.title=MyApp
app.description=Una aplicación de demostración simple
user.greeting=¡Hola, mundo!
user.farewell=Gracias por usar MyApp
error.message=Algo salió mal
error.notFound=Página no encontrada
database.host=localhost
database.port=5432
notification.success=¡Cambios guardados!
notification.warning=Por favor, revisa tu entrada
```
--------------------------------------------------------------------------------
/packages/compiler/src/utils/env.ts:
--------------------------------------------------------------------------------
```typescript
import fs from "fs";
/**
* Checks if the compiler is running in CI or Docker environment.
* Returns true if either:
* - CI environment variable is set
* - /.dockerenv file exists (indicating Docker environment)
*/
export function isRunningInCIOrDocker(): boolean {
return Boolean(process.env.CI) || fs.existsSync("/.dockerenv");
}
```
--------------------------------------------------------------------------------
/demo/next-app/next.config.ts:
--------------------------------------------------------------------------------
```typescript
import type { NextConfig } from "next";
import lingoCompiler from "lingo.dev/compiler";
const nextConfig: NextConfig = {
/* config options here */
};
export default lingoCompiler.next({
sourceLocale: "en",
targetLocales: ["es", "ja", "fr", "ru", "de", "zh", "ar", "ko"],
models: "lingo.dev",
useDirective: true,
})(nextConfig);
```
--------------------------------------------------------------------------------
/integrations/directus/tsup.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "tsup";
export default defineConfig({
clean: true,
target: "esnext",
entry: ["src/api.ts", "src/app.ts"],
outDir: "build",
format: ["cjs", "esm"],
cjsInterop: true,
splitting: true,
external: ["@replexica/sdk"],
outExtension: (ctx) => ({
js: ctx.format === "cjs" ? ".cjs" : ".mjs",
}),
});
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/xcode-strings/types.ts:
--------------------------------------------------------------------------------
```typescript
export enum TokenType {
COMMENT_SINGLE = "COMMENT_SINGLE",
COMMENT_MULTI = "COMMENT_MULTI",
STRING = "STRING",
EQUALS = "EQUALS",
SEMICOLON = "SEMICOLON",
EOF = "EOF",
}
export interface Token {
type: TokenType;
value: string;
line: number;
column: number;
}
export interface Position {
line: number;
column: number;
}
```
--------------------------------------------------------------------------------
/packages/compiler/tsup.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "tsup";
export default defineConfig({
clean: true,
target: "esnext",
entry: ["src/index.ts", "src/lingo-turbopack-loader.ts"],
outDir: "build",
format: ["cjs", "esm"],
dts: true,
cjsInterop: true,
splitting: true,
outExtension: (ctx) => ({
js: ctx.format === "cjs" ? ".cjs" : ".mjs",
}),
});
```
--------------------------------------------------------------------------------
/packages/cli/demo/yaml-root-key/en/example.yml:
--------------------------------------------------------------------------------
```yaml
es:
navigation:
home: "Inicio"
about: "Sobre nosotros"
contact: "Contacto"
services: "Servicios"
forms:
title: "Formulario de contacto"
name_label: "Su nombre"
email_label: "Dirección de correo electrónico"
message_label: "Mensaje"
submit_button: "Enviar mensaje"
success_message: "¡Gracias por su mensaje!"
```
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
```json
{
"name": "lingodotdev/lingo.dev",
"description": "Lingo.dev Monorepo",
"type": "project",
"license": "MIT",
"repositories": [
{
"type": "path",
"url": "php/sdk",
"options": {
"symlink": false
}
}
],
"require": {
"lingodotdev/sdk": "*"
},
"minimum-stability": "dev",
"prefer-stable": true
}
```
--------------------------------------------------------------------------------
/demo/next-app/src/components/hero-subtitle.tsx:
--------------------------------------------------------------------------------
```typescript
"use server";
"use i18n";
export async function HeroSubtitle() {
return (
<p className="text-lg sm:text-xl text-gray-600 mb-10 max-w-xl mx-auto leading-relaxed">
Localize your React app in every language in minutes.
<br />
Scale to millions from day one
<sup title="supports many popular frameworks">*</sup>.
</p>
);
}
```
--------------------------------------------------------------------------------
/.github/workflows/pr-lint.yml:
--------------------------------------------------------------------------------
```yaml
name: Lint PR
on:
pull_request:
types:
- opened
- edited
- synchronize
jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
--------------------------------------------------------------------------------
/demo/vite-project/index.html:
--------------------------------------------------------------------------------
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
```
--------------------------------------------------------------------------------
/packages/cli/demo/csv/example.csv:
--------------------------------------------------------------------------------
```
KEY,en,es
welcome_message,Welcome to our application,Bienvenido a nuestra aplicación
button_save,Save,Guardar
error_invalid_email,Please enter a valid email address,"Por favor, introduce una dirección de correo electrónico válida"
product_name,Premium Widget,Widget Premium
empty_row_key,,
whitespace_only, ,
new_feature,This is a new feature,Esta es una nueva función
```
--------------------------------------------------------------------------------
/demo/next-app/src/app/globals.css:
--------------------------------------------------------------------------------
```css
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
```
--------------------------------------------------------------------------------
/packages/compiler/src/lib/lcp/api/provider-details.spec.ts:
--------------------------------------------------------------------------------
```typescript
import { describe, it, expect } from "vitest";
import { providerDetails } from "./provider-details";
describe("provider-details", () => {
it("should provide data for all supported providers", () => {
expect(Object.keys(providerDetails)).toEqual([
"groq",
"google",
"openrouter",
"ollama",
"mistral",
"lingo.dev",
]);
});
});
```
--------------------------------------------------------------------------------
/demo/next-app/public/window.svg:
--------------------------------------------------------------------------------
```
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
```
--------------------------------------------------------------------------------
/scripts/docs/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
exclude: ["node_modules", "build"],
coverage: {
reporter: ["text", "html", "lcov"],
exclude: ["node_modules/", "build/", "**/*.d.ts", "**/*.config.*"],
},
},
});
```
--------------------------------------------------------------------------------
/demo/next-app/public/file.svg:
--------------------------------------------------------------------------------
```
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
```
--------------------------------------------------------------------------------
/demo/next-app/eslint.config.mjs:
--------------------------------------------------------------------------------
```
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];
export default eslintConfig;
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/mdx2/_types.ts:
--------------------------------------------------------------------------------
```typescript
export interface RawMdx {
frontmatter: Record<string, any>;
content: string;
}
export interface PlaceholderedMdx extends RawMdx {
codePlaceholders: Record<string, string>;
}
export interface SectionedMdx {
frontmatter: Record<string, any>;
sections: Record<string, string>;
}
export type LocalizableMdxDocument = {
meta: Record<string, any>;
content: Record<string, string>;
};
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/config/index.ts:
--------------------------------------------------------------------------------
```typescript
import { Command } from "interactive-commander";
import setCmd from "./set";
import unsetCmd from "./unset";
import getCmd from "./get";
export default new Command()
.command("config")
.description(
"Manage CLI settings (authentication, API keys) stored in ~/.lingodotdevrc",
)
.helpOption("-h, --help", "Show help")
.addCommand(setCmd)
.addCommand(unsetCmd)
.addCommand(getCmd);
```
--------------------------------------------------------------------------------
/packages/compiler/src/utils/rc.ts:
--------------------------------------------------------------------------------
```typescript
import os from "os";
import path from "path";
import fs from "fs";
import Ini from "ini";
export function getRc() {
const settingsFile = ".lingodotdevrc";
const homedir = os.homedir();
const settingsFilePath = path.join(homedir, settingsFile);
const content = fs.existsSync(settingsFilePath)
? fs.readFileSync(settingsFilePath, "utf-8")
: "";
const data = Ini.parse(content);
return data;
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/config/static.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from '@adonisjs/static'
/**
* Configuration options to tweak the static files middleware.
* The complete set of options are documented on the
* official documentation website.
*
* https://docs.adonisjs.com/guides/static-assets
*/
const staticServerConfig = defineConfig({
enabled: true,
etag: true,
lastModified: true,
dotFiles: 'ignore',
})
export default staticServerConfig
```
--------------------------------------------------------------------------------
/demo/next-app/src/app/page.tsx:
--------------------------------------------------------------------------------
```typescript
/*
"use client";
"use server";
"use i18n";
*/
import { HeroTitle, HeroSubtitle, HeroActions } from "../components";
export default function Home() {
return (
<div className="min-h-screen bg-white flex items-center justify-center px-4 sm:px-6 lg:px-8">
<div className="max-w-2xl mx-auto text-center">
<HeroTitle />
<HeroSubtitle />
<HeroActions />
</div>
</div>
);
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/run/_const.ts:
--------------------------------------------------------------------------------
```typescript
import chalk from "chalk";
import { ListrDefaultRendererLogLevels } from "listr2";
import { colors } from "../../constants";
export const commonTaskRendererOptions = {
color: {
[ListrDefaultRendererLogLevels.COMPLETED]: (msg?: string) =>
msg ? chalk.hex(colors.green)(msg) : chalk.hex(colors.green)(""),
},
icon: {
[ListrDefaultRendererLogLevels.COMPLETED]: chalk.hex(colors.green)("✓"),
},
};
```
--------------------------------------------------------------------------------
/packages/spec/tsup.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "tsup";
import buildJsonSchema from "./src/json-schema";
export default defineConfig({
clean: true,
target: "esnext",
entry: ["src/index.ts"],
outDir: "build",
format: ["cjs", "esm"],
dts: true,
cjsInterop: true,
splitting: true,
outExtension: (ctx) => ({
js: ctx.format === "cjs" ? ".cjs" : ".mjs",
}),
onSuccess: async () => {
buildJsonSchema();
},
});
```
--------------------------------------------------------------------------------
/i18n.json:
--------------------------------------------------------------------------------
```json
{
"version": "1.10",
"locale": {
"source": "en",
"targets": [
"ru",
"he",
"fr",
"es",
"de",
"zh-Hans",
"ko",
"ja",
"it",
"ar",
"hi",
"pt-BR",
"uk-UA",
"bn",
"fa",
"pl",
"tr"
]
},
"buckets": {
"mdx": {
"include": ["readme/[locale].md"]
}
},
"$schema": "https://lingo.dev/schema/i18n.json"
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/localizer/index.ts:
--------------------------------------------------------------------------------
```typescript
import { I18nConfig } from "@lingo.dev/_spec";
import createLingoDotDevLocalizer from "./lingodotdev";
import createExplicitLocalizer from "./explicit";
import { ILocalizer } from "./_types";
export default function createLocalizer(
provider: I18nConfig["provider"],
apiKey?: string,
): ILocalizer {
if (!provider) {
return createLingoDotDevLocalizer(apiKey);
} else {
return createExplicitLocalizer(provider);
}
}
```
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
FROM node:20.12.2-alpine
# Run the Node.js / TypeScript application
ENTRYPOINT ["sh", "-c", "npx lingo.dev@latest ci \
--api-key \"$LINGODOTDEV_API_KEY\" \
--pull-request \"$LINGODOTDEV_PULL_REQUEST\" \
--commit-message \"$LINGODOTDEV_COMMIT_MESSAGE\" \
--pull-request-title \"$LINGODOTDEV_PULL_REQUEST_TITLE\" \
--working-directory \"$LINGODOTDEV_WORKING_DIRECTORY\" \
--process-own-commits \"$LINGODOTDEV_PROCESS_OWN_COMMITS\""]
```
--------------------------------------------------------------------------------
/demo/vite-project/src/main.tsx:
--------------------------------------------------------------------------------
```typescript
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";
// Compiler: add import
import { LingoProviderWrapper, loadDictionary } from "lingo.dev/react/client";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<LingoProviderWrapper loadDictionary={(locale) => loadDictionary(locale)}>
<App />
</LingoProviderWrapper>
</StrictMode>,
);
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/run/_utils.ts:
--------------------------------------------------------------------------------
```typescript
import { CmdRunContext } from "./_types";
/**
* Determines the authentication ID for tracking purposes
*/
export async function determineAuthId(
ctx: CmdRunContext,
): Promise<string | null> {
const isByokMode = !!ctx.config?.provider;
if (isByokMode) {
return null;
} else {
try {
const authStatus = await ctx.localizer?.checkAuth();
return authStatus?.username || null;
} catch {
return null;
}
}
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/config/cors.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from '@adonisjs/cors'
/**
* Configuration options to tweak the CORS policy. The following
* options are documented on the official documentation website.
*
* https://docs.adonisjs.com/guides/security/cors
*/
const corsConfig = defineConfig({
enabled: true,
origin: [],
methods: ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'],
headers: true,
exposeHeaders: [],
credentials: true,
maxAge: 90,
})
export default corsConfig
```
--------------------------------------------------------------------------------
/integrations/directus/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"rootDir": "src",
"outDir": "build"
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["src/**/*.spec.ts", "src/**/*.spec.tsx"]
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/processor/_base.ts:
--------------------------------------------------------------------------------
```typescript
export type LocalizerInput = {
sourceLocale: string;
sourceData: Record<string, any>;
processableData: Record<string, any>;
targetLocale: string;
targetData: Record<string, any>;
};
export type LocalizerProgressFn = (
progress: number,
sourceChunk: Record<string, string>,
processedChunk: Record<string, string>,
) => void;
export type LocalizerFn = (
input: LocalizerInput,
onProgress: LocalizerProgressFn,
) => Promise<Record<string, any>>;
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/ci/platforms/index.ts:
--------------------------------------------------------------------------------
```typescript
import { BitbucketPlatformKit } from "./bitbucket";
import { GitHubPlatformKit } from "./github";
import { GitlabPlatformKit } from "./gitlab";
export const getPlatformKit = () => {
if (process.env.BITBUCKET_PIPELINE_UUID) {
return new BitbucketPlatformKit();
}
if (process.env.GITHUB_ACTION) {
return new GitHubPlatformKit();
}
if (process.env.GITLAB_CI) {
return new GitlabPlatformKit();
}
throw new Error("This platform is not supported");
};
```
--------------------------------------------------------------------------------
/packages/locales/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"rootDir": "src",
"outDir": "build",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"allowUnreachableCode": true
},
"include": ["src/**/*.ts"],
"exclude": ["src/**/*.spec.ts"]
}
```
--------------------------------------------------------------------------------
/packages/compiler/src/utils/create-locale-import-map.ts:
--------------------------------------------------------------------------------
```typescript
import * as t from "@babel/types";
export function createLocaleImportMap(
allLocales: string[],
dictionaryPath: string,
): t.ObjectExpression {
return t.objectExpression(
allLocales.map((locale) =>
t.objectProperty(
t.stringLiteral(locale),
t.arrowFunctionExpression(
[],
t.callExpression(t.identifier("import"), [
t.stringLiteral(`${dictionaryPath}?locale=${locale}`),
]),
),
),
),
);
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/json5.ts:
--------------------------------------------------------------------------------
```typescript
import JSON5 from "json5";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createJson5Loader(): ILoader<
string,
Record<string, any>
> {
return createLoader({
pull: async (locale, input) => {
const json5String = input || "{}";
return JSON5.parse(json5String);
},
push: async (locale, data) => {
const serializedData = JSON5.stringify(data, null, 2);
return serializedData;
},
});
}
```
--------------------------------------------------------------------------------
/packages/spec/src/json-schema.ts:
--------------------------------------------------------------------------------
```typescript
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { zodToJsonSchema } from "zod-to-json-schema";
import { LATEST_CONFIG_DEFINITION } from "./config";
export default function buildJsonSchema() {
const configSchema = zodToJsonSchema(LATEST_CONFIG_DEFINITION.schema);
const currentDir = path.dirname(fileURLToPath(import.meta.url));
fs.writeFileSync(
`${currentDir}/../build/i18n.schema.json`,
JSON.stringify(configSchema, null, 2),
);
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/plutil-json-loader.ts:
--------------------------------------------------------------------------------
```typescript
import { formatPlutilStyle } from "../utils/plutil-formatter";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createPlutilJsonTextLoader(): ILoader<string, string> {
return createLoader({
async pull(locale, data) {
return data;
},
async push(locale, data, originalInput) {
const jsonData = JSON.parse(data);
const result = formatPlutilStyle(jsonData, originalInput || "");
return result;
},
});
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/config/hash.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig, drivers } from '@adonisjs/core/hash'
const hashConfig = defineConfig({
default: 'scrypt',
list: {
scrypt: drivers.scrypt({
cost: 16384,
blockSize: 8,
parallelization: 1,
maxMemory: 33554432,
}),
},
})
export default hashConfig
/**
* Inferring types for the list of hashers you have configured
* in your application.
*/
declare module '@adonisjs/core/types' {
export interface HashersList extends InferHashers<typeof hashConfig> {}
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/root-key.ts:
--------------------------------------------------------------------------------
```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createRootKeyLoader(
replaceAll = false,
): ILoader<Record<string, any>, Record<string, any>> {
return createLoader({
async pull(locale, input) {
const result = input[locale];
return result;
},
async push(locale, data, originalInput) {
const result = {
...(replaceAll ? {} : originalInput),
[locale]: data,
};
return result;
},
});
}
```
--------------------------------------------------------------------------------
/integrations/directus/docker-compose.yml:
--------------------------------------------------------------------------------
```yaml
version: "3"
services:
directus:
build:
context: ./
ports:
- 8055:8055
volumes:
- ./.directus/database:/directus/database
- ./.directus/uploads:/directus/uploads
- ./:/directus/extensions/lingo.dev-directus-extension
environment:
SECRET: "replace-with-secure-random-value"
ADMIN_EMAIL: "[email protected]"
ADMIN_PASSWORD: "d1r3ctu5"
DB_CLIENT: "sqlite3"
DB_FILENAME: "/directus/database/data.db"
WEBSOCKETS_ENABLED: "true"
```
--------------------------------------------------------------------------------
/packages/compiler/src/jsx-root-flag.ts:
--------------------------------------------------------------------------------
```typescript
import traverse from "@babel/traverse";
import { createCodeMutation } from "./_base";
import { getJsxRoots } from "./utils";
import * as t from "@babel/types";
const jsxRootFlagMutation = createCodeMutation((payload) => {
const jsxRoots = getJsxRoots(payload.ast);
for (const jsxElementPath of jsxRoots) {
jsxElementPath.node.openingElement.attributes.push(
t.jsxAttribute(t.jsxIdentifier("data-jsx-root"), null),
);
}
return {
...payload,
};
});
export default jsxRootFlagMutation;
```
--------------------------------------------------------------------------------
/demo/react-router-app/vite.config.ts:
--------------------------------------------------------------------------------
```typescript
import { reactRouter } from "@react-router/dev/vite";
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
// Compiler: import
import lingoCompiler from "lingo.dev/compiler";
export default defineConfig(({ isSsrBuild }) =>
lingoCompiler.vite({
sourceRoot: "app",
targetLocales: ["es", "fr", "de"],
useDirective: false,
models: "lingo.dev",
})({
plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
}),
);
```
--------------------------------------------------------------------------------
/packages/spec/src/formats.ts:
--------------------------------------------------------------------------------
```typescript
import Z from "zod";
export const bucketTypes = [
"android",
"csv",
"ejs",
"flutter",
"html",
"json",
"json5",
"jsonc",
"markdown",
"markdoc",
"mdx",
"xcode-strings",
"xcode-stringsdict",
"xcode-xcstrings",
"xcode-xcstrings-v2",
"yaml",
"yaml-root-key",
"properties",
"po",
"xliff",
"xml",
"srt",
"dato",
"compiler",
"vtt",
"php",
"po",
"vue-json",
"typescript",
"txt",
"json-dictionary",
] as const;
export const bucketTypeSchema = Z.enum(bucketTypes);
```
--------------------------------------------------------------------------------
/demo/vite-project/vite.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
// Compiler: add import
import lingoCompiler from "lingo.dev/compiler";
const viteConfig = {
plugins: [react()],
};
// https://vite.dev/config/
export default defineConfig(() =>
// Compiler: add lingoCompiler.vite
lingoCompiler.vite({
sourceRoot: "src",
targetLocales: ["es", "fr", "ru", "de", "ja", "zh", "ar", "ko"],
models: "lingo.dev",
})(viteConfig),
);
// export default defineConfig({
// plugins: [react()],
// })
```
--------------------------------------------------------------------------------
/packages/cli/demo/typescript/en/example.ts:
--------------------------------------------------------------------------------
```typescript
const messages = {
navigation: {
home: "Home",
about: "About Us",
contact: "Contact Us",
services: "Our Services"
},
forms: {
title: "Contact Form",
nameLabel: "Your Name",
emailLabel: "Email Address",
messageLabel: "Your Message",
submitButton: "Send Message",
successMessage: "Thank you for your message!",
locked_key_1: "This value is locked and should not be changed",
ignored_key_1: "This value is ignored and should not be processed"
},
};
export default messages;
```
--------------------------------------------------------------------------------
/scripts/docs/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"rootDir": "src",
"outDir": "build",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"allowUnreachableCode": true,
"types": ["node"]
},
"include": ["src/**/*.ts", "src/**/*.tsx", "vitest.config.ts"],
"exclude": ["build/**/*"]
}
```
--------------------------------------------------------------------------------
/packages/compiler/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"rootDir": "src",
"outDir": "build",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"allowUnreachableCode": true
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["src/**/*.spec.ts", "src/**/*.spec.tsx"]
}
```
--------------------------------------------------------------------------------
/packages/sdk/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"rootDir": "src",
"outDir": "build",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"allowUnreachableCode": true
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["src/**/*.spec.ts", "src/**/*.spec.tsx"]
}
```
--------------------------------------------------------------------------------
/packages/spec/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"rootDir": "src",
"outDir": "build",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"allowUnreachableCode": true
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["src/**/*.spec.ts", "src/**/*.spec.tsx"]
}
```
--------------------------------------------------------------------------------
/packages/compiler/src/utils/hash.ts:
--------------------------------------------------------------------------------
```typescript
import { NodePath } from "@babel/traverse";
import * as t from "@babel/types";
import { MD5 } from "object-hash";
export function getJsxElementHash(nodePath: NodePath<t.Node>) {
if (!nodePath.node) {
return "";
}
const content = (nodePath.node as any).children
.map((child: any) => child.value)
.join("");
const result = MD5(content);
return result;
}
export function getJsxAttributeValueHash(attributeValue: string) {
if (!attributeValue) {
return "";
}
const result = MD5(attributeValue);
return result;
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/show/index.ts:
--------------------------------------------------------------------------------
```typescript
import { Command } from "interactive-commander";
import _ from "lodash";
import configCmd from "./config";
import localeCmd from "./locale";
import filesCmd from "./files";
import lockedKeysCmd from "./locked-keys";
import ignoredKeysCmd from "./ignored-keys";
export default new Command()
.command("show")
.description("Display configuration, locales, and file paths")
.helpOption("-h, --help", "Show help")
.addCommand(configCmd)
.addCommand(localeCmd)
.addCommand(filesCmd)
.addCommand(lockedKeysCmd)
.addCommand(ignoredKeysCmd);
```
--------------------------------------------------------------------------------
/packages/cli/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"rootDir": "src",
"outDir": "build",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"allowUnreachableCode": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "types"],
"exclude": ["src/**/*.spec.ts", "src/**/*.spec.tsx"]
}
```
--------------------------------------------------------------------------------
/packages/locales/CHANGELOG.md:
--------------------------------------------------------------------------------
```markdown
# @lingo.dev/\_locales
## 0.1.0
### Minor Changes
- [#1124](https://github.com/lingodotdev/lingo.dev/pull/1124) [`40fa69d`](https://github.com/lingodotdev/lingo.dev/commit/40fa69d9525a18c5861b6cce33262968c511ce5a) Thanks [@leen-neel](https://github.com/leen-neel)! - Implemented locales package from #1080
- Added new `@lingo.dev/_locales` package for locale management
- Includes locale name parsing and validation utilities
- Provides integration helpers for various frameworks
- Supports locale code normalization and fallback handling
```
--------------------------------------------------------------------------------
/packages/cli/demo/yaml/es/example.yml:
--------------------------------------------------------------------------------
```yaml
title: "MyApp"
description: "¡Hola, mundo!"
welcome_message: "Bienvenido a MyApp"
user_profile:
display_name: "Juan Pérez"
bio: "Desarrollador de software"
navigation_items:
- "Inicio"
- "Acerca de"
- "Contacto"
product:
name: "MyWidget"
tagline: "El mejor widget de todos"
features:
- "Fácil de usar"
- "Rápido y confiable"
settings:
max_users: 100
enabled: true
timeout: 30.5
complex_structure:
level_one:
level_two:
message: "Texto anidado profundo"
locked_key_1: "This value is locked and should not be changed"
```
--------------------------------------------------------------------------------
/packages/cli/demo/typescript/es/example.ts:
--------------------------------------------------------------------------------
```typescript
const messages = {
navigation: {
home: "Inicio",
about: "Sobre nosotros",
contact: "Contacto",
services: "Nuestros servicios",
},
forms: {
title: "Formulario de contacto",
nameLabel: "Tu nombre",
emailLabel: "Dirección de correo electrónico",
messageLabel: "Tu mensaje",
submitButton: "Enviar mensaje",
successMessage: "¡Gracias por tu mensaje!",
locked_key_1: "This value is locked and should not be changed",
ignored_key_1: "This value is ignored and should not be processed",
},
};
export default messages;
```
--------------------------------------------------------------------------------
/packages/locales/src/index.ts:
--------------------------------------------------------------------------------
```typescript
// Export types
export type { LocaleComponents, LocaleDelimiter, ParseResult } from "./types";
// Export constants
export { LOCALE_REGEX } from "./constants";
// Export parsing functions
export {
parseLocale,
parseLocaleWithDetails,
getLanguageCode,
getScriptCode,
getRegionCode,
} from "./parser";
// Export validation functions
export {
isValidLocale,
isValidLanguageCode,
isValidScriptCode,
isValidRegionCode,
} from "./validation";
// Export async name resolution functions
export { getCountryName, getLanguageName, getScriptName } from "./names";
```
--------------------------------------------------------------------------------
/packages/compiler/src/jsx-scope-flag.ts:
--------------------------------------------------------------------------------
```typescript
import { createCodeMutation } from "./_base";
import * as t from "@babel/types";
import { getAstKey } from "./utils/ast-key";
import { getJsxScopes } from "./utils/jsx-scope";
const jsxScopeFlagMutation = createCodeMutation((payload) => {
const jsxScopes = getJsxScopes(payload.ast);
for (const jsxScope of jsxScopes) {
jsxScope.node.openingElement.attributes.push(
t.jsxAttribute(
t.jsxIdentifier("data-jsx-scope"),
t.stringLiteral(getAstKey(jsxScope)),
),
);
}
return {
...payload,
};
});
export default jsxScopeFlagMutation;
```
--------------------------------------------------------------------------------
/packages/react/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"rootDir": "src",
"outDir": "build",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"jsxImportSource": "react",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"types": ["vitest/globals", "@testing-library/react"],
"allowUnreachableCode": true
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": []
}
```
--------------------------------------------------------------------------------
/demo/react-router-app/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"include": [
"**/*",
"**/.server/**/*",
"**/.client/**/*",
".react-router/types/**/*"
],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": ["node", "vite/client"],
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"rootDirs": [".", "./.react-router/types"],
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true
}
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/yaml/en/example.yml:
--------------------------------------------------------------------------------
```yaml
title: "MyApp"
description: Hello, world!
welcome_message: 'Welcome to MyApp'
user_profile:
display_name: "John Doe"
bio: Software developer
navigation_items:
- "Home"
- "About"
- "Contact"
product:
name: "MyWidget"
tagline: The best widget ever
features:
- "Easy to use"
- "Fast and reliable"
settings:
max_users: 100
enabled: true
timeout: 30.5
complex_structure:
level_one:
level_two:
message: "Deep nested text"
locked_key_1: "This value is locked and should not be changed"
ignored_key_1: "This value is ignored and should not appear in target locales"
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/exp-backoff.ts:
--------------------------------------------------------------------------------
```typescript
export function withExponentialBackoff<T, Args extends any[]>(
fn: (...args: Args) => Promise<T>,
maxAttempts: number = 3,
baseDelay: number = 1000,
): (...args: Args) => Promise<T> {
return async (...args: Args): Promise<T> => {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fn(...args);
} catch (error) {
if (attempt === maxAttempts - 1) throw error;
const delay = baseDelay * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
throw new Error("Unreachable code");
};
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/app/middleware/container_bindings_middleware.ts:
--------------------------------------------------------------------------------
```typescript
import { Logger } from '@adonisjs/core/logger'
import { HttpContext } from '@adonisjs/core/http'
import { NextFn } from '@adonisjs/core/types/http'
/**
* The container bindings middleware binds classes to their request
* specific value using the container resolver.
*
* - We bind "HttpContext" class to the "ctx" object
* - And bind "Logger" class to the "ctx.logger" object
*/
export default class ContainerBindingsMiddleware {
handle(ctx: HttpContext, next: NextFn) {
ctx.containerResolver.bindValue(HttpContext, ctx)
ctx.containerResolver.bindValue(Logger, ctx.logger)
return next()
}
}
```
--------------------------------------------------------------------------------
/demo/next-app/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "next-app",
"version": "0.2.78",
"private": true,
"scripts": {
"dev": "next dev",
"build": "NODE_ENV=production next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"lingo.dev": "workspace:*",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.3.1"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4",
"eslint": "^9",
"eslint-config-next": "15.3.1",
"@eslint/eslintrc": "^3"
}
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/config/vite.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from '@adonisjs/vite'
const viteBackendConfig = defineConfig({
/**
* The output of vite will be written inside this
* directory. The path should be relative from
* the application root.
*/
buildDirectory: 'public/assets',
/**
* The path to the manifest file generated by the
* "vite build" command.
*/
manifestFile: 'public/assets/.vite/manifest.json',
/**
* Feel free to change the value of the "assetsUrl" to
* point to a CDN in production.
*/
assetsUrl: '/assets',
scriptAttributes: {
defer: true,
},
})
export default viteBackendConfig
```
--------------------------------------------------------------------------------
/legacy/sdk/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "@replexica/sdk",
"version": "0.7.11",
"description": "[DEPRECATED] Replexica SDK (now Lingo.dev) - Please use lingo.dev instead",
"private": false,
"type": "module",
"sideEffects": false,
"types": "index.d.ts",
"module": "index.js",
"main": "index.js",
"files": [
"index.js",
"index.d.ts"
],
"keywords": [],
"author": "",
"license": "Apache-2.0",
"dependencies": {
"lingo.dev": "*"
},
"deprecated": "Replexica is now Lingo.dev! Please use our new SDK package by running: npm install lingo.dev. Visit https://lingo.dev for the latest features and documentation."
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/utils/fs.ts:
--------------------------------------------------------------------------------
```typescript
import * as fs from "fs";
import * as path from "path";
export function tryReadFile(
filePath: string,
defaultValue: string | null = null,
): string | null {
try {
const content = fs.readFileSync(filePath, "utf-8");
return content;
} catch (error) {
return defaultValue;
}
}
export function writeFile(filePath: string, content: string) {
// create dirs
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(filePath, content);
}
export function checkIfFileExists(filePath: string) {
return fs.existsSync(filePath);
}
```
--------------------------------------------------------------------------------
/demo/vite-project/tsconfig.node.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/inertia/app/ssr.tsx:
--------------------------------------------------------------------------------
```typescript
import ReactDOMServer from 'react-dom/server'
import { createInertiaApp } from '@inertiajs/react'
import { LingoProviderWrapper, loadDictionary } from 'lingo.dev/react/client'
export default function render(page: any) {
return createInertiaApp({
page,
render: ReactDOMServer.renderToString,
resolve: (name) => {
const pages = import.meta.glob('../pages/**/*.tsx', { eager: true })
return pages[`../pages/${name}.tsx`]
},
setup: ({ App, props }) => (
<LingoProviderWrapper loadDictionary={(locale) => loadDictionary(locale)}>
<App {...props} />
</LingoProviderWrapper>
),
})
}
```
--------------------------------------------------------------------------------
/packages/compiler/src/_utils.ts:
--------------------------------------------------------------------------------
```typescript
import path from "path";
import { LCP_DICTIONARY_FILE_NAME } from "./_const";
export type GetDictionaryPathParams = {
sourceRoot: string;
lingoDir: string;
relativeFilePath: string;
};
export const getDictionaryPath = (params: GetDictionaryPathParams) => {
const toFile = path.resolve(
params.sourceRoot,
params.lingoDir,
LCP_DICTIONARY_FILE_NAME,
);
const fromDir = path.dirname(
path.resolve(params.sourceRoot, params.relativeFilePath),
);
const relativePath = path.relative(fromDir, toFile);
const normalizedPath = relativePath.split(path.sep).join(path.posix.sep);
return `./${normalizedPath}`;
};
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/mdx2/localizable-document.ts:
--------------------------------------------------------------------------------
```typescript
import { ILoader } from "../_types";
import { createLoader } from "../_utils";
import { LocalizableMdxDocument, SectionedMdx } from "./_types";
export default function createLocalizableMdxDocumentLoader(): ILoader<
SectionedMdx,
LocalizableMdxDocument
> {
return createLoader({
async pull(_locale, input) {
return {
meta: input.frontmatter,
content: input.sections,
};
},
async push(_locale, data, originalInput, _originalLocale, pullInput) {
const result: SectionedMdx = {
frontmatter: data.meta || {},
sections: data.content || {},
};
return result;
},
});
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/json.ts:
--------------------------------------------------------------------------------
```typescript
import { jsonrepair } from "jsonrepair";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createJsonLoader(): ILoader<
string,
Record<string, any>
> {
return createLoader({
pull: async (locale, input) => {
const jsonString = input || "{}";
let result: Record<string, any>;
try {
result = JSON.parse(jsonString);
} catch (error) {
result = JSON.parse(jsonrepair(jsonString));
}
return result;
},
push: async (locale, data) => {
const serializedData = JSON.stringify(data, null, 2);
return serializedData;
},
});
}
```
--------------------------------------------------------------------------------
/packages/react/src/client/attribute-component.tsx:
--------------------------------------------------------------------------------
```typescript
"use client";
import {
LingoAttributeComponent as LingoCoreAttributeComponent,
LingoAttributeComponentProps as LingoCoreAttributeComponentProps,
} from "../core";
import { useLingo } from "./context";
export type LingoAttributeComponentProps = Omit<
LingoCoreAttributeComponentProps,
"$dictionary"
>;
export function LingoAttributeComponent(props: LingoAttributeComponentProps) {
const { $attrAs, $attributes, $fileKey, ...rest } = props;
const lingo = useLingo();
return (
<LingoCoreAttributeComponent
$dictionary={lingo.dictionary}
$as={$attrAs}
$attributes={$attributes}
$fileKey={$fileKey}
{...rest}
/>
);
}
```
--------------------------------------------------------------------------------
/demo/next-app/src/components/hero-actions.tsx:
--------------------------------------------------------------------------------
```typescript
"use client";
export function HeroActions() {
return (
<div className="flex flex-row gap-4 justify-center items-center">
<button className="px-8 py-3 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
Get Started
</button>
<button className="px-8 py-3 bg-white hover:bg-gray-50 text-gray-700 font-medium rounded-lg border border-gray-300 hover:border-gray-400 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
Learn More
</button>
</div>
);
}
```
--------------------------------------------------------------------------------
/demo/next-app/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"../react-router-app/app/welcome/lingo-dot-dev.tsx"
],
"exclude": ["node_modules"]
}
```
--------------------------------------------------------------------------------
/packages/react/src/core/attribute-component.tsx:
--------------------------------------------------------------------------------
```typescript
import { createElement } from "react";
import _ from "lodash";
import React from "react";
export type LingoAttributeComponentProps = {
$as: string;
$attributes: Record<string, string>;
$fileKey: string;
[key: string]: any;
};
export const LingoAttributeComponent = React.forwardRef(
(props: Omit<LingoAttributeComponentProps, "ref">, ref: React.Ref<any>) => {
const { $as, $attributes, $fileKey, $dictionary, ...rest } = props;
const localizedAttributes = _.mapValues($attributes, (v, k) => {
return $dictionary?.files?.[$fileKey]?.entries?.[v] ?? k;
});
return createElement($as, {
...rest,
...localizedAttributes,
ref,
});
},
);
```
--------------------------------------------------------------------------------
/packages/cli/demo/xml/es/example.xml:
--------------------------------------------------------------------------------
```
<root><title>¡Hola, mundo!</title><description><summary>Aplicación de demostración simple</summary><details>Contenido de ejemplo básico</details></description><image src="photo.jpg" alt="Foto de ejemplo" title="Haz clic para ver"/><link href="example.com" label="Haz clic aquí">Más información</link><button type="submit" value="Enviar" placeholder="Introduce texto">Enviar</button><section><article><paragraph><sentence>Contenido anidado</sentence></paragraph></article></section><meta name="description" content="Metadatos de la aplicación de demostración"/><message><greeting>¡Hola!</greeting><body>Bienvenido a la aplicación</body><signature>Gracias, Equipo de MyApp</signature></message></root>
```
--------------------------------------------------------------------------------
/demo/vite-project/tsconfig.app.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/json/es/example.json:
--------------------------------------------------------------------------------
```json
{
"title": "¡Hola, mundo!",
"description": "Una aplicación de demostración simple",
"version": "1.0.0",
"support_email": "[email protected]",
"homepage": "https://lingo.dev",
"deprecated": null,
"empty": "",
"emoji": "🚀",
"author": {
"name": "Juan Pérez"
},
"contributors": [
{
"name": "Alicia"
},
{
"name": "Roberto"
}
],
"messages": ["Bienvenido a Mi aplicación", "¡Hola, mundo!"],
"config": {
"theme": {
"primary": "Tema Azul"
}
},
"mixed_array": [
"Contenido mixto aquí",
42,
true,
{
"nested_message": "Texto anidado"
}
],
"locked_key_1": "This value is locked and should not be changed"
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/_types.ts:
--------------------------------------------------------------------------------
```typescript
export interface ILoaderDefinition<I, O, C> {
init?(): Promise<C>;
pull(
locale: string,
input: I,
initCtx: C,
originalLocale: string,
originalInput: I,
): Promise<O>;
push(
locale: string,
data: O,
originalInput: I | null,
originalLocale: string,
pullInput: I | null,
pullOutput: O | null,
): Promise<I>;
pullHints?(originalInput: I): Promise<O | undefined>;
}
export interface ILoader<I, O, C = void> extends ILoaderDefinition<I, O, C> {
setDefaultLocale(locale: string): this;
init(): Promise<C>;
pull(locale: string, input: I): Promise<O>;
push(locale: string, data: O): Promise<I>;
pullHints(originalInput: I): Promise<O | undefined>;
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/locked-keys.ts:
--------------------------------------------------------------------------------
```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
import _ from "lodash";
import { matchesKeyPattern } from "../utils/key-matching";
export default function createLockedKeysLoader(
lockedKeys: string[],
): ILoader<Record<string, any>, Record<string, any>> {
return createLoader({
pull: async (locale, data) => {
return _.pickBy(
data,
(value, key) => !matchesKeyPattern(key, lockedKeys),
);
},
push: async (locale, data, originalInput) => {
const lockedSubObject = _.chain(originalInput)
.pickBy((value, key) => matchesKeyPattern(key, lockedKeys))
.value();
return _.merge({}, data, lockedSubObject);
},
});
}
```
--------------------------------------------------------------------------------
/demo/adonisjs/config/inertia.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from '@adonisjs/inertia'
import type { InferSharedProps } from '@adonisjs/inertia/types'
const inertiaConfig = defineConfig({
/**
* Path to the Edge view that will be used as the root view for Inertia responses
*/
rootView: 'inertia_layout',
/**
* Data that should be shared with all rendered pages
*/
sharedData: {
// user: (ctx) => ctx.inertia.always(() => ctx.auth.user),
},
/**
* Options for the server-side rendering
*/
ssr: {
enabled: true,
entrypoint: 'inertia/app/ssr.tsx',
},
})
export default inertiaConfig
declare module '@adonisjs/inertia/types' {
export interface SharedProps extends InferSharedProps<typeof inertiaConfig> {}
}
```
--------------------------------------------------------------------------------
/packages/locales/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "@lingo.dev/_locales",
"version": "0.1.0",
"description": "Lingo.dev locales",
"private": false,
"publishConfig": {
"access": "public"
},
"type": "module",
"sideEffects": false,
"main": "build/index.cjs",
"module": "build/index.mjs",
"types": "build/index.d.ts",
"files": [
"build",
"localenames-data"
],
"scripts": {
"dev": "tsup --watch",
"build": "pnpm typecheck && tsup",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
"keywords": [],
"author": "",
"license": "Apache-2.0",
"devDependencies": {
"@types/node": "^22.13.5",
"tsup": "^8.3.5",
"typescript": "^5.8.3",
"vitest": "^3.2.4"
}
}
```
--------------------------------------------------------------------------------
/packages/cli/troubleshooting.md:
--------------------------------------------------------------------------------
```markdown
## Troubleshooting
### Error: Dynamic require of "module_name" is not supported
If you encounter this error when running the cli, it typically means that a dependency is trying to dynamically `require()` a Node.js built-in module or another dependency in a way that's incompatible with the ESM bundle format (`.mjs`).
The solution is to identify the problematic dependency mentioned in the error stack trace and exclude it from the bundle by adding it to the `external` array in `tsup.config.ts`.
For example, we encountered this issue with the `debug` package (a dependency of `@babel/traverse`) trying to dynamically require `"tty"`. We resolved it by adding `@babel/*` to the `external` array in `tsup.config.ts`.
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/sync.ts:
--------------------------------------------------------------------------------
```typescript
import _ from "lodash";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createSyncLoader(): ILoader<
Record<string, string>,
Record<string, string>
> {
return createLoader({
async pull(locale, input, initCtx, originalLocale, originalInput) {
if (!originalInput) {
return input;
}
return _.chain(originalInput)
.mapValues((value, key) => input[key])
.value() as Record<string, string>;
},
async push(locale, data, originalInput) {
if (!originalInput) {
return data;
}
return _.chain(originalInput || {})
.mapValues((value, key) => data[key])
.value();
},
});
}
```
--------------------------------------------------------------------------------
/legacy/cli/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "replexica",
"version": "0.71.0",
"description": "[DEPRECATED] Replexica CLI (now Lingo.dev) - Please use lingo.dev instead",
"private": false,
"type": "module",
"sideEffects": false,
"types": "build/index.d.ts",
"module": "build/index.mjs",
"main": "build/index.cjs",
"bin": {
"replexica": "./bin/cli.mjs"
},
"files": [
"bin",
"build"
],
"scripts": {
"replexica": "./bin/cli.mjs"
},
"keywords": [],
"author": "",
"license": "Apache-2.0",
"dependencies": {
"lingo.dev": "*"
},
"deprecated": "Replexica is now Lingo.dev! Please use our new CLI package by running: npx lingo.dev@latest. Visit https://lingo.dev for the latest features and documentation."
}
```
--------------------------------------------------------------------------------
/packages/cli/tsup.config.ts:
--------------------------------------------------------------------------------
```typescript
import { defineConfig } from "tsup";
export default defineConfig({
clean: true,
entry: {
cli: "src/cli/index.ts",
sdk: "src/sdk/index.ts",
spec: "src/spec/index.ts",
react: "src/react/index.ts",
"react/client": "src/react/client.ts",
"react/rsc": "src/react/rsc.ts",
"react/react-router": "src/react/react-router.ts",
compiler: "src/compiler/index.ts",
"locale-codes": "src/locale-codes/index.ts",
},
outDir: "build",
format: ["cjs", "esm"],
dts: true,
cjsInterop: true,
splitting: true,
bundle: true,
sourcemap: true,
external: ["readline/promises", "@babel/traverse", "node-machine-id"],
outExtension: (ctx) => ({
js: ctx.format === "cjs" ? ".cjs" : ".mjs",
}),
});
```
--------------------------------------------------------------------------------
/demo/vite-project/eslint.config.js:
--------------------------------------------------------------------------------
```javascript
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
},
);
```
--------------------------------------------------------------------------------
/packages/cli/demo/json/en/example.json:
--------------------------------------------------------------------------------
```json
{
"title": "Hello, world!",
"description": "A simple demo app",
"version": "1.0.0",
"support_email": "[email protected]",
"homepage": "https://lingo.dev",
"deprecated": null,
"empty": "",
"emoji": "🚀",
"author": {
"name": "John Doe"
},
"contributors": [
{ "name": "Alice" },
{ "name": "Bob" }
],
"messages": [
"Welcome to MyApp",
"Hello, world!"
],
"config": {
"theme": {
"primary": "Blue theme"
}
},
"mixed_array": [
"Mixed content here",
42,
true,
{
"nested_message": "Nested text"
}
],
"locked_key_1": "This value is locked and should not be changed",
"ignored_key_1": "This value is ignored and should not appear in target locales"
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/txt.ts:
--------------------------------------------------------------------------------
```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createTxtLoader(): ILoader<
string,
Record<string, string>
> {
return createLoader({
async pull(locale, input) {
const result: Record<string, string> = {};
if (input !== undefined && input !== null && input !== "") {
const lines = input.split("\n");
lines.forEach((line, index) => {
result[String(index + 1)] = line;
});
}
return result;
},
async push(locale, payload) {
const sortedEntries = Object.entries(payload).sort(
([a], [b]) => parseInt(a) - parseInt(b),
);
return sortedEntries.map(([_, value]) => value).join("\n");
},
});
}
```
--------------------------------------------------------------------------------
/demo/next-app/src/app/test/page.tsx:
--------------------------------------------------------------------------------
```typescript
import Link from "next/link";
export default function Test() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<Link href="/" className="text-primary underline">
Navigate home
</Link>
<div className="flex flex-col justify-center items-center gap-4 w-100">
<h1 className="text-4xl">Testing this thing now</h1>
<p>
Hello, this is a non-interactive test. Please do not try to interact
with it.
</p>
</div>
</main>
</div>
);
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/php/en/example.php:
--------------------------------------------------------------------------------
```php
<?php
return [
'Hello, world!',
'Welcome to MyApp',
"It's \"simple\" with a backslash \\ and newline\nAll text here",
'welcome_message' => 'Welcome!',
'error_text' => 'Something went wrong',
'navigation' => [
'home' => 'Home',
'about' => 'About',
'contact' => 'Contact',
],
'forms' => [
'login' => [
'username_label' => 'Username',
'password_label' => 'Password',
'submit_button' => 'Sign In',
],
],
'mixed_content' => [
'title' => 'Settings',
'count' => 42,
'enabled' => true,
'nothing_here' => null,
'description' => 'App settings and preferences',
],
];
```
--------------------------------------------------------------------------------
/demo/vite-project/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "vite-project",
"private": true,
"version": "0.0.3",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@vitejs/plugin-react": "^4.4.1",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@vitejs/plugin-react-swc": "^3.9.0",
"eslint": "^9.25.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"lingo.dev": "workspace:*",
"typescript": "~5.8.3",
"typescript-eslint": "^8.30.1",
"vite": "^6.3.5"
}
}
```
--------------------------------------------------------------------------------
/scripts/docs/src/json-schema/types.ts:
--------------------------------------------------------------------------------
```typescript
export type PropertyInfo = {
name: string;
fullPath: string;
type: string;
required: boolean;
description?: string;
defaultValue?: unknown;
allowedValues?: unknown[];
allowedKeys?: string[];
children?: PropertyInfo[];
};
export type JSONSchemaObject = {
type?: string | string[];
properties?: Record<string, unknown>;
required?: string[];
items?: unknown;
anyOf?: unknown[];
$ref?: string;
description?: string;
markdownDescription?: string;
default?: unknown;
enum?: unknown[];
propertyNames?: {
enum?: string[];
};
additionalProperties?: unknown;
definitions?: Record<string, unknown>;
};
export type SchemaParsingOptions = {
customOrder?: string[];
parentPath?: string;
rootSchema?: unknown;
};
```
--------------------------------------------------------------------------------
/demo/react-router-app/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
FROM node:20-alpine AS development-dependencies-env
COPY . /app
WORKDIR /app
RUN npm ci
FROM node:20-alpine AS production-dependencies-env
COPY ./package.json package-lock.json /app/
WORKDIR /app
RUN npm ci --omit=dev
FROM node:20-alpine AS build-env
COPY . /app/
COPY --from=development-dependencies-env /app/node_modules /app/node_modules
WORKDIR /app
RUN npm run build
FROM node:20-alpine
COPY ./package.json package-lock.json /app/
COPY --from=production-dependencies-env /app/node_modules /app/node_modules
COPY --from=build-env /app/build /app/build
WORKDIR /app
# Create non-root user, set ownership, switch to user before running the app
RUN adduser -D nodeuser && \
chown -R nodeuser:nodeuser /app
USER nodeuser
CMD ["npm", "run", "start"]
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/ignored-keys.ts:
--------------------------------------------------------------------------------
```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
import _ from "lodash";
import { matchesKeyPattern } from "../utils/key-matching";
export default function createIgnoredKeysLoader(
ignoredKeys: string[],
): ILoader<Record<string, any>, Record<string, any>> {
return createLoader({
pull: async (locale, data) => {
const result = _.omitBy(data, (value, key) =>
matchesKeyPattern(key, ignoredKeys),
);
return result;
},
push: async (locale, data, originalInput, originalLocale, pullInput) => {
// Remove ignored keys from the data being pushed
const result = _.omitBy(data, (value, key) =>
matchesKeyPattern(key, ignoredKeys),
);
return result;
},
});
}
```
--------------------------------------------------------------------------------
/demo/next-app/src/lingo/meta.json:
--------------------------------------------------------------------------------
```json
{
"version": 0.1,
"files": {
"components/hero-subtitle.tsx": {
"scopes": {
"0/declaration/body/0/argument": {
"type": "element",
"hash": "75cc719ebad12413e5fa788174d4d4ec",
"context": "",
"skip": false,
"overrides": {},
"content": "Localize your React app in every language in minutes.<element:br></element:br> Scale to millions from day one<element:sup>*</element:sup>."
},
"0/declaration/body/0/argument/3-title": {
"type": "attribute",
"hash": "ce9b34049534ad201aef501f2a224a9d",
"context": "",
"skip": false,
"overrides": {},
"content": "supports many popular frameworks"
}
}
}
}
}
```
--------------------------------------------------------------------------------
/scripts/docs/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "docs",
"private": true,
"type": "module",
"scripts": {
"generate-cli-docs": "tsx ./src/generate-cli-docs.ts",
"generate-config-docs": "tsx ./src/generate-config-docs.ts",
"test": "vitest run",
"test:watch": "vitest",
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage"
},
"devDependencies": {
"@lingo.dev/_spec": "workspace:*",
"@octokit/rest": "^20.1.2",
"@types/mdast": "^4.0.4",
"@types/node": "^24.0.10",
"@vitest/ui": "^3.2.4",
"commander": "^12.0.0",
"remark-stringify": "^11.0.0",
"tsx": "^4.7.1",
"typescript": "^5.8.3",
"unified": "^11.0.4",
"vitest": "^3.2.4"
},
"dependencies": {
"zod": "^3.25.76",
"zod-to-json-schema": "^3.24.5"
}
}
```
--------------------------------------------------------------------------------
/packages/react/src/rsc/component.spec.tsx:
--------------------------------------------------------------------------------
```typescript
import { describe, it, expect, vi } from "vitest";
import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { LingoHtmlComponent } from "./component";
vi.mock("./utils", () => {
return {
loadLocaleFromCookies: vi.fn(async () => "nl"),
loadDictionaryFromRequest: vi.fn(),
};
});
describe("rsc/component", () => {
describe("LingoHtmlComponent", () => {
it("sets lang and data-lingodotdev-compiler from cookies-derived locale", async () => {
const element = await LingoHtmlComponent({});
const markup = renderToStaticMarkup(element);
expect(markup).toContain("<html");
expect(markup).toContain('lang="nl"');
expect(markup).toContain('data-lingodotdev-compiler="nl"');
});
});
});
```
--------------------------------------------------------------------------------
/packages/cli/demo/json-dictionary/example.json:
--------------------------------------------------------------------------------
```json
{
"navigation": {
"en": "Home",
"es": "Inicio"
},
"buttons": {
"submit": {
"en": "Submit",
"es": "Enviar"
},
"cancel": {
"en": "Cancel",
"es": "Cancelar"
}
},
"messages": {
"welcome": {
"en": "Welcome to our application",
"es": "Bienvenido a nuestra aplicación"
},
"error": {
"en": "An error occurred",
"es": "Ha ocurrido un error"
}
},
"forms": {
"login": {
"title": {
"en": "Login",
"es": "Iniciar sesión"
},
"fields": {
"username": {
"en": "Username",
"es": "Nombre de usuario"
},
"password": {
"en": "Password",
"es": "Contraseña"
}
}
}
}
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/json-sorting.ts:
--------------------------------------------------------------------------------
```typescript
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createJsonSortingLoader(): ILoader<
Record<string, any>,
Record<string, any>
> {
return createLoader({
async pull(locale, input) {
return input;
},
async push(locale, data, originalInput) {
return sortObjectDeep(data);
},
});
}
function sortObjectDeep(obj: any): any {
if (Array.isArray(obj)) {
return obj.map(sortObjectDeep);
}
if (obj !== null && typeof obj === "object") {
return Object.keys(obj)
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
.reduce((result: any, key) => {
result[key] = sortObjectDeep(obj[key]);
return result;
}, {});
}
return obj;
}
```
--------------------------------------------------------------------------------
/packages/react/src/rsc/attribute-component.tsx:
--------------------------------------------------------------------------------
```typescript
import {
LingoAttributeComponent as LingoCoreAttributeComponent,
LingoAttributeComponentProps as LingoCoreAttributeComponentProps,
} from "../core";
import { loadDictionaryFromRequest } from "./utils";
export type LingoAttributeComponentProps = Omit<
LingoCoreAttributeComponentProps,
"$dictionary"
>;
export async function LingoAttributeComponent(
props: LingoAttributeComponentProps,
) {
const {
$attrAs,
$attributes,
$fileKey,
$entryKey,
$loadDictionary,
...rest
} = props;
const dictionary = await loadDictionaryFromRequest($loadDictionary);
return (
<LingoCoreAttributeComponent
$dictionary={dictionary}
$as={$attrAs}
$attributes={$attributes}
$fileKey={$fileKey}
{...rest}
/>
);
}
```
--------------------------------------------------------------------------------
/demo/react-router-app/app/routes/test.tsx:
--------------------------------------------------------------------------------
```typescript
import type { Route } from "./+types/home";
import { Link } from "react-router";
export function meta({}: Route.MetaArgs) {
return [
{ title: "New React Router App" },
{ name: "description", content: "Welcome to React Router!" },
];
}
export default function Test() {
return (
<main className="flex items-center justify-center pt-16 pb-4">
<div className="flex-1 flex flex-col items-center gap-4 min-h-0">
<Link to="/" className="text-blue-500 hover:underline">
Go back home
</Link>
<h1 className="text-2xl font-bold">This is a test page</h1>
<p>Welcome to non-interactive testing page.</p>
<p>Please do not try to interact with this page for your own safety.</p>
</div>
</main>
);
}
```
--------------------------------------------------------------------------------
/packages/cli/demo/xml/en/example.xml:
--------------------------------------------------------------------------------
```
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>Hello, world!</title>
<description>
<summary>Simple demo app</summary>
<details>Basic example content</details>
</description>
<image src="photo.jpg" alt="Example photo" title="Click to view"/>
<link href="example.com" label="Click here">Learn more</link>
<button type="submit" value="Submit" placeholder="Enter text">Submit</button>
<section>
<article>
<paragraph>
<sentence>Nested content</sentence>
</paragraph>
</article>
</section>
<meta name="description" content="Demo app metadata"/>
<message>
<greeting>Hello there!</greeting>
<body>Welcome to the app</body>
<signature>Thanks, MyApp Team</signature>
</message>
</root>
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/cmd/ci/flows/_base.ts:
--------------------------------------------------------------------------------
```typescript
import { Ora } from "ora";
import { PlatformKit } from "../platforms/_base";
export type IIntegrationFlowOptions = {
parallel?: boolean;
force?: boolean;
};
export interface IIntegrationFlow {
preRun?(): Promise<boolean>;
run(options: IIntegrationFlowOptions): Promise<boolean>;
postRun?(): Promise<void>;
}
export abstract class IntegrationFlow implements IIntegrationFlow {
protected i18nBranchName?: string;
constructor(
protected ora: Ora,
protected platformKit: PlatformKit,
) {}
abstract run(options: IIntegrationFlowOptions): Promise<boolean>;
}
export const gitConfig = {
userName: "Lingo.dev",
userEmail: "[email protected]",
};
export function escapeShellArg(arg: string): string {
return `'${arg.replace(/'/g, "'\\''")}'`;
}
```
--------------------------------------------------------------------------------
/packages/locales/src/types.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Represents the components of a locale string
*/
export interface LocaleComponents {
/** The language code (e.g., "en", "zh", "es") */
language: string;
/** The script code (e.g., "Hans", "Hant", "Cyrl") - optional */
script?: string;
/** The region/country code (e.g., "US", "CN", "RS") - optional */
region?: string;
}
/**
* Locale delimiter types
*/
export type LocaleDelimiter = "-" | "_";
/**
* Validation result for locale parsing
*/
export interface ParseResult {
/** The parsed locale components */
components: LocaleComponents;
/** The delimiter used in the original string */
delimiter: LocaleDelimiter | null;
/** Whether the locale string was valid */
isValid: boolean;
/** Error message if parsing failed */
error?: string;
}
```
--------------------------------------------------------------------------------
/packages/react/src/client/component.spec.tsx:
--------------------------------------------------------------------------------
```typescript
import { describe, it, expect } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import React from "react";
import { LingoHtmlComponent } from "./component";
import { LingoContext } from "./context";
describe("client/component", () => {
describe("LingoHtmlComponent", () => {
it("sets lang and data-lingodotdev-compiler from context dictionary locale", () => {
const dictionary = { locale: "ja" } as any;
const markup = renderToStaticMarkup(
<LingoContext.Provider value={{ dictionary }}>
<LingoHtmlComponent />
</LingoContext.Provider>,
);
expect(markup).toContain("<html");
expect(markup).toContain('lang="ja"');
expect(markup).toContain('data-lingodotdev-compiler="ja"');
});
});
});
```
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
```json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach to CLI",
"processId": "${command:PickProcess}",
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node",
"sourceMaps": true,
"outFiles": ["${workspaceFolder}/packages/cli/build/**/*.mjs"],
"resolveSourceMapLocations": [
"${workspaceFolder}/packages/cli/build/**/*.mjs",
"!**/node_modules/**"
],
"remoteRoot": "${workspaceFolder}/packages/cli",
"localRoot": "${workspaceFolder}/packages/cli",
"port": 9229
}
]
}
```
--------------------------------------------------------------------------------
/packages/spec/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "@lingo.dev/_spec",
"version": "0.41.1",
"description": "Lingo.dev open specification",
"private": false,
"publishConfig": {
"access": "public"
},
"type": "module",
"sideEffects": false,
"types": "build/index.d.ts",
"module": "build/index.mjs",
"main": "build/index.cjs",
"files": [
"build"
],
"scripts": {
"dev": "tsup --watch",
"build": "pnpm typecheck && tsup",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
"keywords": [],
"author": "",
"license": "Apache-2.0",
"dependencies": {
"zod": "^3.25.76",
"zod-to-json-schema": "^3.24.5"
},
"devDependencies": {
"@types/node": "^22.13.5",
"tsup": "^8.3.5",
"typescript": "^5.8.3",
"vitest": "^3.1.2"
}
}
```
--------------------------------------------------------------------------------
/packages/cli/src/cli/loaders/flutter.ts:
--------------------------------------------------------------------------------
```typescript
import _ from "lodash";
import { ILoader } from "./_types";
import { createLoader } from "./_utils";
export default function createFlutterLoader(): ILoader<
Record<string, any>,
Record<string, any>
> {
return createLoader({
async pull(locale, input) {
// skip all metadata (keys starting with @)
const result = _.pickBy(input, (value, key) => !_isMetadataKey(key));
return result;
},
async push(locale, data, originalInput) {
// find all metadata keys in originalInput
const metadata = _.pickBy(originalInput, (value, key) =>
_isMetadataKey(key),
);
const result = _.merge({}, metadata, { "@@locale": locale }, data);
return result;
},
});
}
function _isMetadataKey(key: string) {
return key.startsWith("@");
}
```