├── .github
├── ISSUE_TEMPLATE
│ ├── 01_bug_report.yml
│ ├── 02_feature_request.yml
│ └── config.yml
├── PULL_REQUEST_TEMPLATE.md
├── codecov.yml
├── verdaccio
│ ├── .yarnrc.yml
│ └── config.yaml
└── workflows
│ ├── docs-suite.yml
│ ├── lint-pr-title.yml
│ ├── main-suite.yml
│ ├── next-sync.yml
│ ├── release-docs.yml
│ ├── release-test.yml
│ ├── release.yml
│ └── size-limit.yml
├── .gitignore
├── .husky
└── pre-commit
├── .prettierignore
├── .prettierrc.json
├── .yarn
├── plugins
│ └── @yarnpkg
│ │ └── plugin-workspace-tools.cjs
└── releases
│ └── yarn-3.4.1.cjs
├── .yarnrc.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── eslint.config.mjs
├── examples
├── create-react-app
│ ├── .babelrc
│ ├── .env
│ ├── .gitignore
│ ├── README.md
│ ├── lingui.config.js
│ ├── package.json
│ ├── public
│ │ └── index.html
│ ├── src
│ │ ├── App.css
│ │ ├── App.test.tsx
│ │ ├── App.tsx
│ │ ├── i18n.ts
│ │ ├── index.css
│ │ ├── index.tsx
│ │ ├── locales
│ │ │ ├── cs.po
│ │ │ └── en.po
│ │ ├── logo.svg
│ │ ├── react-app-env.d.ts
│ │ ├── serviceWorker.ts
│ │ └── setupTests.ts
│ ├── tsconfig.json
│ └── yarn.lock
├── js
│ ├── .gitignore
│ ├── README.md
│ ├── babel.config.js
│ ├── lingui.config.js
│ ├── package.json
│ ├── src
│ │ ├── ids.js
│ │ ├── locale
│ │ │ ├── cs
│ │ │ │ ├── messages.js
│ │ │ │ └── messages.po
│ │ │ └── en
│ │ │ │ ├── messages.js
│ │ │ │ └── messages.po
│ │ ├── messages.js
│ │ └── test.js
│ └── yarn.lock
├── nextjs-babel
│ ├── .babelrc
│ ├── .gitignore
│ ├── README.md
│ ├── lingui.config.js
│ ├── next-env.d.ts
│ ├── next.config.js
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ └── vercel.svg
│ ├── src
│ │ ├── components
│ │ │ ├── Layout.module.css
│ │ │ ├── Layout.tsx
│ │ │ └── PluralExample.tsx
│ │ ├── i18n.ts
│ │ ├── locales
│ │ │ ├── cs.po
│ │ │ ├── en.po
│ │ │ └── pseudo.po
│ │ ├── pages
│ │ │ ├── _app.tsx
│ │ │ ├── api
│ │ │ │ └── hello.ts
│ │ │ ├── examples.tsx
│ │ │ ├── index.module.css
│ │ │ └── index.tsx
│ │ └── styles.css
│ ├── tsconfig.json
│ └── yarn.lock
├── nextjs-swc
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── .prettierrc.js
│ ├── README.md
│ ├── lingui.config.js
│ ├── next-env.d.ts
│ ├── next.config.ts
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ └── vercel.svg
│ ├── src
│ │ ├── app
│ │ │ └── [lang]
│ │ │ │ ├── app-router-demo
│ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ ├── appRouterI18n.ts
│ │ ├── components
│ │ │ ├── AboutText.tsx
│ │ │ ├── Developers.tsx
│ │ │ ├── HomePage.tsx
│ │ │ ├── LinguiClientProvider.tsx
│ │ │ └── Switcher.tsx
│ │ ├── initLingui.tsx
│ │ ├── locales
│ │ │ ├── en.po
│ │ │ ├── es.po
│ │ │ ├── pseudo.po
│ │ │ └── sr.po
│ │ ├── middleware.ts
│ │ ├── pages
│ │ │ ├── [lang]
│ │ │ │ └── pages-router-demo
│ │ │ │ │ └── index.tsx
│ │ │ └── _app.tsx
│ │ ├── pagesRouterI18n.ts
│ │ └── styles
│ │ │ ├── Index.module.css
│ │ │ └── globals.css
│ ├── tsconfig.json
│ └── yarn.lock
├── react-native
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc
│ ├── .yarnrc.yml
│ ├── App.tsx
│ ├── README.md
│ ├── app.json
│ ├── assets
│ │ ├── adaptive-icon.png
│ │ ├── favicon.png
│ │ ├── icon.png
│ │ └── splash.png
│ ├── babel.config.js
│ ├── lingui.config.js
│ ├── metro.config.js
│ ├── package.json
│ ├── src
│ │ ├── Components.tsx
│ │ ├── MainScreen.tsx
│ │ ├── PaddedButton.tsx
│ │ ├── locales
│ │ │ ├── cs
│ │ │ │ └── messages.po
│ │ │ └── en
│ │ │ │ └── messages.po
│ │ └── po-types.d.ts
│ ├── tsconfig.json
│ └── yarn.lock
├── remix-vite-babel
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── app
│ │ ├── entry.client.tsx
│ │ ├── entry.server.tsx
│ │ ├── locales
│ │ │ ├── en.po
│ │ │ └── fr.po
│ │ ├── modules
│ │ │ └── lingui
│ │ │ │ ├── config.ts
│ │ │ │ ├── lingui.server.ts
│ │ │ │ ├── lingui.tsx
│ │ │ │ ├── remix.server.ts
│ │ │ │ └── utils.ts
│ │ ├── root.tsx
│ │ └── routes
│ │ │ └── _index.tsx
│ ├── lingui.config.ts
│ ├── package.json
│ ├── tsconfig.json
│ ├── vite.config.ts
│ └── yarn.lock
├── rspack
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── demo.gif
│ ├── index.html
│ ├── lingui.config.ts
│ ├── package.json
│ ├── rspack.config.js
│ ├── src
│ │ ├── Inbox.tsx
│ │ ├── LocaleSwitcher.tsx
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── index.css
│ │ ├── locales.ts
│ │ ├── locales
│ │ │ ├── en
│ │ │ │ ├── messages.d.ts
│ │ │ │ ├── messages.po
│ │ │ │ └── messages.ts
│ │ │ └── fr
│ │ │ │ ├── messages.d.ts
│ │ │ │ ├── messages.po
│ │ │ │ └── messages.ts
│ │ ├── main.tsx
│ │ └── react-env.d.ts
│ ├── tsconfig.json
│ └── yarn.lock
├── tanstack-start
│ ├── .gitignore
│ ├── .prettierignore
│ ├── README.md
│ ├── app.config.ts
│ ├── lingui.config.ts
│ ├── package.json
│ ├── postcss.config.mjs
│ ├── public
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── favicon.png
│ │ └── site.webmanifest
│ ├── src
│ │ ├── api.ts
│ │ ├── client.tsx
│ │ ├── components
│ │ │ ├── DefaultCatchBoundary.tsx
│ │ │ ├── NotFound.tsx
│ │ │ ├── PostError.tsx
│ │ │ └── UserError.tsx
│ │ ├── functions
│ │ │ └── deferred.ts
│ │ ├── global-middleware.ts
│ │ ├── locales
│ │ │ ├── en
│ │ │ │ └── messages.po
│ │ │ └── fr
│ │ │ │ └── messages.po
│ │ ├── modules
│ │ │ └── lingui
│ │ │ │ ├── i18n.server.ts
│ │ │ │ └── i18n.ts
│ │ ├── routeTree.gen.ts
│ │ ├── router.tsx
│ │ ├── routes
│ │ │ ├── __root.tsx
│ │ │ ├── _pathlessLayout.tsx
│ │ │ ├── _pathlessLayout
│ │ │ │ ├── _nested-layout.tsx
│ │ │ │ └── _nested-layout
│ │ │ │ │ ├── route-a.tsx
│ │ │ │ │ └── route-b.tsx
│ │ │ ├── api
│ │ │ │ ├── users.$id.ts
│ │ │ │ └── users.ts
│ │ │ ├── deferred.tsx
│ │ │ ├── index.tsx
│ │ │ ├── posts.$postId.tsx
│ │ │ ├── posts.index.tsx
│ │ │ ├── posts.route.tsx
│ │ │ ├── posts_.$postId.deep.tsx
│ │ │ ├── redirect.tsx
│ │ │ ├── users.$userId.tsx
│ │ │ ├── users.index.tsx
│ │ │ └── users.route.tsx
│ │ ├── ssr.tsx
│ │ ├── styles
│ │ │ └── app.css
│ │ └── utils
│ │ │ ├── loggingMiddleware.tsx
│ │ │ ├── posts.tsx
│ │ │ ├── seo.ts
│ │ │ └── users.tsx
│ ├── tailwind.config.mjs
│ ├── tsconfig.json
│ └── yarn.lock
├── vite-project-react-babel
│ ├── .gitignore
│ ├── index.html
│ ├── lingui.config.ts
│ ├── package.json
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── App.css
│ │ ├── App.tsx
│ │ ├── assets
│ │ │ ├── lingui-logo.svg
│ │ │ └── react.svg
│ │ ├── i18n.ts
│ │ ├── index.css
│ │ ├── locales
│ │ │ ├── en.po
│ │ │ └── pl.po
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ ├── vite.config.ts
│ └── yarn.lock
└── vite-project-react-swc
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── lingui.config.ts
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ │ ├── lingui-logo.svg
│ │ └── react.svg
│ ├── i18n.ts
│ ├── index.css
│ ├── locales
│ │ ├── en.po
│ │ └── pl.po
│ ├── main.tsx
│ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ ├── vite.config.ts
│ └── yarn.lock
├── jest.config.js
├── lerna.json
├── package.json
├── packages
├── babel-plugin-extract-messages
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── build.config.ts
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ └── index.ts.snap
│ │ ├── fixtures
│ │ │ ├── js-call-expression.js
│ │ │ ├── js-message-descriptor.js
│ │ │ ├── js-with-macros.js
│ │ │ ├── jsx-with-macros.js
│ │ │ ├── jsx-without-macros.js
│ │ │ ├── jsx-without-trans.js
│ │ │ ├── lingui.config.js
│ │ │ └── without-lingui.js
│ │ └── index.ts
│ └── tsconfig.json
├── babel-plugin-lingui-macro
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── ast.ts
│ │ ├── constants.ts
│ │ ├── icu.test.ts
│ │ ├── icu.ts
│ │ ├── index.ts
│ │ ├── macro.ts
│ │ ├── macroJs.ts
│ │ ├── macroJsAst.test.ts
│ │ ├── macroJsAst.ts
│ │ ├── macroJsx.test.ts
│ │ ├── macroJsx.ts
│ │ ├── messageDescriptorUtils.ts
│ │ ├── utils.ts
│ │ └── utils
│ │ │ └── cleanJSXElementLiteralChild.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ ├── js-defineMessage.test.ts.snap
│ │ │ ├── js-plural.test.ts.snap
│ │ │ ├── js-select.test.ts.snap
│ │ │ ├── js-selectOrdinal.test.ts.snap
│ │ │ ├── js-t.test.ts.snap
│ │ │ ├── js-useLingui.test.ts.snap
│ │ │ ├── jsx-plural.test.ts.snap
│ │ │ ├── jsx-select.test.ts.snap
│ │ │ ├── jsx-selectOrdinal.test.ts.snap
│ │ │ └── jsx-trans.test.ts.snap
│ │ ├── fixtures
│ │ │ ├── js-t-continuation-character.expected.js
│ │ │ ├── js-t-continuation-character.js
│ │ │ ├── js-t-var
│ │ │ │ ├── js-t-var.expected.js
│ │ │ │ └── js-t-var.js
│ │ │ ├── jsx-keep-forced-newlines.expected.js
│ │ │ ├── jsx-keep-forced-newlines.js
│ │ │ ├── jsx-plural-select-nested.expected.js
│ │ │ └── jsx-plural-select-nested.js
│ │ ├── index.ts
│ │ ├── js-defineMessage.test.ts
│ │ ├── js-plural.test.ts
│ │ ├── js-select.test.ts
│ │ ├── js-selectOrdinal.test.ts
│ │ ├── js-t.test.ts
│ │ ├── js-useLingui.test.ts
│ │ ├── jsx-plural.test.ts
│ │ ├── jsx-select.test.ts
│ │ ├── jsx-selectOrdinal.test.ts
│ │ ├── jsx-trans.test.ts
│ │ ├── lingui.config.js
│ │ └── macroTester.ts
│ └── tsconfig.json
├── cli
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── api.ts
│ ├── package.json
│ ├── src
│ │ ├── api
│ │ │ ├── __snapshots__
│ │ │ │ ├── catalog.test.ts.snap
│ │ │ │ └── compile.test.ts.snap
│ │ │ ├── catalog.test.ts
│ │ │ ├── catalog.ts
│ │ │ ├── catalog
│ │ │ │ ├── __snapshots__
│ │ │ │ │ └── getCatalogs.test.ts.snap
│ │ │ │ ├── extractFromFiles.ts
│ │ │ │ ├── getCatalogDependentFiles.test.ts
│ │ │ │ ├── getCatalogDependentFiles.ts
│ │ │ │ ├── getCatalogs.test.ts
│ │ │ │ ├── getCatalogs.ts
│ │ │ │ ├── getFallbackListForLocale.test.ts
│ │ │ │ ├── getFallbackListForLocale.ts
│ │ │ │ ├── getTranslationsForCatalog.test.ts
│ │ │ │ ├── getTranslationsForCatalog.ts
│ │ │ │ ├── mergeCatalog.test.ts
│ │ │ │ └── mergeCatalog.ts
│ │ │ ├── compile.test.ts
│ │ │ ├── compile.ts
│ │ │ ├── extractors
│ │ │ │ ├── babel.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── typescript.ts
│ │ │ ├── fixtures
│ │ │ │ ├── .linguirc
│ │ │ │ ├── collect-inline-sourcemaps
│ │ │ │ │ └── componentB.jsx
│ │ │ │ ├── collect-invalid
│ │ │ │ │ ├── invalid.js
│ │ │ │ │ └── valid.js
│ │ │ │ ├── collect-syntax-flow
│ │ │ │ │ ├── flow-syntax.js
│ │ │ │ │ └── ts-syntax.ts
│ │ │ │ ├── collect-typescript-jsx
│ │ │ │ │ ├── jsx-in-js.js
│ │ │ │ │ ├── jsx-syntax.jsx
│ │ │ │ │ ├── macro.tsx
│ │ │ │ │ ├── tsx-experimental-decorators.tsx
│ │ │ │ │ └── tsx-syntax.tsx
│ │ │ │ ├── collect
│ │ │ │ │ ├── $componentE
│ │ │ │ │ │ └── index.js
│ │ │ │ │ ├── (componentC)
│ │ │ │ │ │ └── index.js
│ │ │ │ │ ├── [componentD]
│ │ │ │ │ │ └── index.js
│ │ │ │ │ ├── componentA
│ │ │ │ │ │ ├── componentA.js
│ │ │ │ │ │ └── index.js
│ │ │ │ │ └── componentB.js
│ │ │ │ ├── duplicate-id.js
│ │ │ │ ├── locales
│ │ │ │ │ └── existing
│ │ │ │ │ │ ├── cs.po
│ │ │ │ │ │ └── en.po
│ │ │ │ ├── messages.po
│ │ │ │ ├── pot-template
│ │ │ │ │ ├── messages.pot
│ │ │ │ │ └── pl.po
│ │ │ │ └── readAll
│ │ │ │ │ ├── cs
│ │ │ │ │ └── messages.po
│ │ │ │ │ └── en
│ │ │ │ │ └── messages.po
│ │ │ ├── formats
│ │ │ │ ├── formatterWrapper.test.ts
│ │ │ │ ├── formatterWrapper.ts
│ │ │ │ └── index.ts
│ │ │ ├── help.ts
│ │ │ ├── index.ts
│ │ │ ├── messages.test.ts
│ │ │ ├── messages.ts
│ │ │ ├── pseudoLocalize.test.ts
│ │ │ ├── pseudoLocalize.ts
│ │ │ ├── rethrownError.ts
│ │ │ ├── stats.test.ts
│ │ │ ├── stats.ts
│ │ │ ├── types.ts
│ │ │ ├── utils.test.ts
│ │ │ └── utils.ts
│ │ ├── extract-experimental
│ │ │ ├── bundleSource.ts
│ │ │ ├── constants.ts
│ │ │ ├── getEntryPoints.ts
│ │ │ ├── getExperimentalCatalogs.ts
│ │ │ ├── linguiEsbuildPlugin.ts
│ │ │ ├── resolveCatalogPath.ts
│ │ │ ├── resolveTemplatePath.test.ts
│ │ │ ├── resolveTemplatePath.ts
│ │ │ └── writeCatalogs.ts
│ │ ├── index.ts
│ │ ├── lingui-compile.ts
│ │ ├── lingui-extract-experimental.ts
│ │ ├── lingui-extract-template.ts
│ │ ├── lingui-extract.ts
│ │ ├── lingui.ts
│ │ ├── services
│ │ │ └── translationIO.ts
│ │ ├── test
│ │ │ ├── __snapshots__
│ │ │ │ └── compile.test.ts.snap
│ │ │ └── compile.test.ts
│ │ └── tests.ts
│ ├── test
│ │ ├── .gitignore
│ │ ├── extract-partial-consistency
│ │ │ ├── existing
│ │ │ │ └── en.po
│ │ │ ├── expected
│ │ │ │ └── en.po
│ │ │ └── fixtures
│ │ │ │ ├── file-a.ts
│ │ │ │ └── file-b.tsx
│ │ ├── extract-po-format
│ │ │ ├── expected
│ │ │ │ ├── en.po
│ │ │ │ └── pl.po
│ │ │ └── fixtures
│ │ │ │ ├── file-a.ts
│ │ │ │ ├── file-b.tsx
│ │ │ │ └── placeholders.ts
│ │ ├── extract-template-po-format
│ │ │ ├── expected
│ │ │ │ └── messages.pot
│ │ │ └── fixtures
│ │ │ │ ├── file-a.ts
│ │ │ │ └── file-b.tsx
│ │ ├── extractor-experimental-clean
│ │ │ ├── existing
│ │ │ │ ├── about.page.en.po
│ │ │ │ ├── about.page.pl.po
│ │ │ │ ├── index.page.en.po
│ │ │ │ └── index.page.pl.po
│ │ │ ├── expected
│ │ │ │ ├── about.page.en.po
│ │ │ │ ├── about.page.pl.po
│ │ │ │ ├── index.page.en.po
│ │ │ │ └── index.page.pl.po
│ │ │ ├── fixtures
│ │ │ │ ├── components
│ │ │ │ │ └── header.ts
│ │ │ │ └── pages
│ │ │ │ │ ├── about.page.ts
│ │ │ │ │ └── index.page.ts
│ │ │ └── package.json
│ │ ├── extractor-experimental-template
│ │ │ ├── expected
│ │ │ │ ├── about.page.en.js
│ │ │ │ ├── about.page.messages.pot
│ │ │ │ ├── about.page.pl.js
│ │ │ │ ├── index.page.en.js
│ │ │ │ ├── index.page.messages.pot
│ │ │ │ └── index.page.pl.js
│ │ │ ├── fixtures
│ │ │ │ ├── components
│ │ │ │ │ ├── aliased-module.ts
│ │ │ │ │ └── header.ts
│ │ │ │ └── pages
│ │ │ │ │ ├── about.page.tsx
│ │ │ │ │ └── index.page.ts
│ │ │ ├── package.json
│ │ │ └── tsconfig.json
│ │ ├── extractor-experimental
│ │ │ ├── existing
│ │ │ │ ├── about.page.en.po
│ │ │ │ ├── about.page.pl.po
│ │ │ │ ├── index.page.en.po
│ │ │ │ └── index.page.pl.po
│ │ │ ├── expected
│ │ │ │ ├── about.page.en.js
│ │ │ │ ├── about.page.en.po
│ │ │ │ ├── about.page.pl.js
│ │ │ │ ├── about.page.pl.po
│ │ │ │ ├── index.page.en.js
│ │ │ │ ├── index.page.en.po
│ │ │ │ ├── index.page.pl.js
│ │ │ │ └── index.page.pl.po
│ │ │ ├── fixtures
│ │ │ │ ├── components
│ │ │ │ │ └── header.ts
│ │ │ │ ├── constants
│ │ │ │ │ ├── green.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── red.ts
│ │ │ │ └── pages
│ │ │ │ │ ├── about.page.ts
│ │ │ │ │ └── index.page.ts
│ │ │ └── package.json
│ │ └── index.test.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── conf
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── __typetests__
│ │ ├── index.test-d.tsx
│ │ └── tsconfig.json
│ ├── package.json
│ ├── src
│ │ ├── __snapshots__
│ │ │ └── index.test.ts.snap
│ │ ├── defineConfig.ts
│ │ ├── fixtures
│ │ │ └── valid
│ │ │ │ ├── .linguirc
│ │ │ │ ├── custom.config.js
│ │ │ │ └── custom.config.ts
│ │ ├── getConfig.ts
│ │ ├── index.test.ts
│ │ ├── index.ts
│ │ ├── makeConfig.ts
│ │ ├── migrations
│ │ │ ├── normalizeRuntimeConfigModule.test.ts
│ │ │ ├── normalizeRuntimeConfigModule.ts
│ │ │ └── setCldrParentLocales.ts
│ │ ├── types.ts
│ │ └── utils
│ │ │ ├── pathJoinPosix.ts
│ │ │ ├── replaceRootDir.test.ts
│ │ │ └── replaceRootDir.ts
│ └── tsconfig.json
├── core
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── __typetests__
│ │ ├── index.test-d.tsx
│ │ └── tsconfig.json
│ ├── macro
│ │ ├── __typetests__
│ │ │ ├── index.test-d.tsx
│ │ │ └── tsconfig.json
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ └── index.test.ts
│ ├── package.json
│ ├── src
│ │ ├── essentials.test.ts
│ │ ├── essentials.ts
│ │ ├── eventEmitter.test.ts
│ │ ├── eventEmitter.ts
│ │ ├── formats.test.ts
│ │ ├── formats.ts
│ │ ├── i18n.test.ts
│ │ ├── i18n.ts
│ │ ├── index.ts
│ │ ├── interpolate.test.ts
│ │ └── interpolate.ts
│ └── tsconfig.json
├── detect-locale
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ └── src
│ │ ├── detectors
│ │ ├── __snapshots__
│ │ │ └── fromUrl.test.ts.snap
│ │ ├── fromCookie.test.ts
│ │ ├── fromCookie.ts
│ │ ├── fromHtmlTag.test.ts
│ │ ├── fromHtmlTag.ts
│ │ ├── fromNavigator.test.ts
│ │ ├── fromNavigator.ts
│ │ ├── fromPath.test.ts
│ │ ├── fromPath.ts
│ │ ├── fromStorage.test.ts
│ │ ├── fromStorage.ts
│ │ ├── fromSubdomain.test.ts
│ │ ├── fromSubdomain.ts
│ │ ├── fromUrl.test.ts
│ │ └── fromUrl.ts
│ │ ├── index.test.ts
│ │ ├── index.ts
│ │ └── utils
│ │ ├── cookie-getter.test.ts
│ │ ├── cookie-getter.ts
│ │ ├── query-string.test.ts
│ │ └── query-string.ts
├── extractor-vue
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ └── src
│ │ ├── __snapshots__
│ │ └── extractor.test.ts.snap
│ │ ├── extractor.test.ts
│ │ ├── fixtures
│ │ ├── functional.vue
│ │ └── test.vue
│ │ ├── index.ts
│ │ └── vue-extractor.ts
├── format-csv
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── __typetests__
│ │ ├── index.test-d.ts
│ │ └── tsconfig.json
│ ├── package.json
│ └── src
│ │ ├── __snapshots__
│ │ └── csv.test.ts.snap
│ │ ├── csv.test.ts
│ │ ├── csv.ts
│ │ └── fixtures
│ │ └── messages.csv
├── format-json
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── __typetests__
│ │ ├── index.test-d.ts
│ │ └── tsconfig.json
│ ├── package.json
│ └── src
│ │ ├── __snapshots__
│ │ └── json.test.ts.snap
│ │ ├── fixtures
│ │ └── messages.json
│ │ ├── json.test.ts
│ │ └── json.ts
├── format-po-gettext
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── __typetests__
│ │ ├── index.test-d.ts
│ │ └── tsconfig.json
│ ├── package.json
│ └── src
│ │ ├── __snapshots__
│ │ └── po-gettext.test.ts.snap
│ │ ├── fixtures
│ │ ├── messages_plural-4-letter.po
│ │ └── messages_plural.po
│ │ ├── plural-samples.test.ts
│ │ ├── plural-samples.ts
│ │ ├── po-gettext.test.ts
│ │ └── po-gettext.ts
├── format-po
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── __typetests__
│ │ ├── index.test-d.ts
│ │ └── tsconfig.json
│ ├── package.json
│ └── src
│ │ ├── __snapshots__
│ │ ├── po.test.ts.snap
│ │ └── utils.test.ts.snap
│ │ ├── fixtures
│ │ └── messages.po
│ │ ├── po.test.ts
│ │ ├── po.ts
│ │ ├── utils.test.ts
│ │ └── utils.ts
├── jest-mocks
│ ├── index.test.ts
│ ├── index.ts
│ └── package.json
├── loader
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── webpackLoader.ts
│ └── test
│ │ ├── __snapshots__
│ │ └── loader.test.ts.snap
│ │ ├── compiler.ts
│ │ ├── entrypoint.js
│ │ ├── fail-on-compile-errors
│ │ ├── entrypoint.js
│ │ ├── lingui.config.js
│ │ └── locale
│ │ │ └── en.po
│ │ ├── fail-on-missing-pseudo
│ │ ├── entrypoint.js
│ │ ├── lingui.config.js
│ │ └── locale
│ │ │ ├── en.po
│ │ │ └── pseudo.po
│ │ ├── fail-on-missing
│ │ ├── entrypoint.js
│ │ ├── lingui.config.js
│ │ └── locale
│ │ │ └── en.po
│ │ ├── json-format
│ │ ├── entrypoint.js
│ │ ├── lingui.config.ts
│ │ └── locale
│ │ │ └── en.json
│ │ ├── loader.test.ts
│ │ ├── not-known-catalog
│ │ ├── .linguirc
│ │ ├── entrypoint.js
│ │ └── locale
│ │ │ └── en.po
│ │ ├── po-format
│ │ ├── .linguirc
│ │ ├── entrypoint.js
│ │ └── locale
│ │ │ ├── en.po
│ │ │ └── messages.pot
│ │ └── relative-catalog-path
│ │ ├── .linguirc
│ │ ├── entrypoint.js
│ │ └── locale
│ │ ├── en.po
│ │ └── messages.pot
├── macro
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── index.d.ts
│ ├── index.js
│ ├── package.json
│ └── tsconfig.json
├── message-utils
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── build.config.ts
│ ├── compileMessage.js
│ ├── generateMessageId.js
│ ├── package.json
│ ├── src
│ │ ├── compileMessage.test.ts
│ │ ├── compileMessage.ts
│ │ ├── generateMessageId.test.ts
│ │ └── generateMessageId.ts
│ └── tsconfig.json
├── metro-transformer
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── expo
│ │ │ └── index.ts
│ │ ├── metroTransformer.ts
│ │ ├── react-native
│ │ │ └── index.ts
│ │ └── types.ts
│ └── test
│ │ ├── __fixtures__
│ │ └── test-project
│ │ │ ├── lingui.config.js
│ │ │ └── locales
│ │ │ ├── cs
│ │ │ └── messages.po
│ │ │ └── en
│ │ │ └── messages.po
│ │ └── metroTransformer.test.ts
├── react
│ ├── .eslintrc
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── build.config.ts
│ ├── macro
│ │ ├── __typetests__
│ │ │ ├── index.test-d.tsx
│ │ │ └── tsconfig.json
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ └── index.test.ts
│ ├── package.json
│ ├── src
│ │ ├── I18nProvider.test.tsx
│ │ ├── I18nProvider.tsx
│ │ ├── Trans.test.tsx
│ │ ├── Trans.tsx
│ │ ├── TransNoContext.tsx
│ │ ├── TransRsc.tsx
│ │ ├── format.test.tsx
│ │ ├── format.ts
│ │ ├── index-rsc.ts
│ │ ├── index.ts
│ │ └── server.ts
│ └── tsconfig.json
├── remote-loader
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── browserCompiler.ts
│ │ ├── index.ts
│ │ └── minimalParser.ts
│ └── test
│ │ └── index.test.ts
└── vite-plugin
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ └── index.ts
│ ├── test
│ ├── __snapshots__
│ │ └── index.ts.snap
│ ├── default-vite.config.ts
│ ├── fail-on-compile-errors
│ │ ├── entrypoint.js
│ │ ├── failOnCompileErrorFalse.vite.config.ts
│ │ ├── lingui.config.js
│ │ ├── locale
│ │ │ └── en.po
│ │ └── vite.config.ts
│ ├── fail-on-missing-pseudo
│ │ ├── entrypoint.js
│ │ ├── lingui.config.js
│ │ ├── locale
│ │ │ ├── en.po
│ │ │ └── pseudo.po
│ │ └── vite.config.ts
│ ├── fail-on-missing
│ │ ├── entrypoint.js
│ │ ├── lingui.config.js
│ │ ├── locale
│ │ │ └── en.po
│ │ └── vite.config.ts
│ ├── index.ts
│ ├── json-format
│ │ ├── entrypoint.js
│ │ ├── lingui.config.ts
│ │ ├── locale
│ │ │ └── en.json
│ │ └── vite.config.ts
│ ├── macro-usage
│ │ ├── .linguirc
│ │ ├── entrypoint.js
│ │ ├── locale
│ │ │ └── en.po
│ │ └── vite.config.ts
│ ├── no-macro-error
│ │ ├── .linguirc
│ │ ├── entrypoint.js
│ │ ├── locale
│ │ │ └── en.po
│ │ └── vite.config.ts
│ └── po-format
│ │ ├── entrypoint.js
│ │ ├── lingui.config.js
│ │ ├── locale
│ │ └── en.po
│ │ └── vite.config.ts
│ └── tsconfig.json
├── scripts
├── jest
│ ├── env.js
│ ├── setupTimezone.js
│ └── stripAnsiSerializer.js
└── verdaccio-release.ts
├── test
├── cli-version
│ ├── index.js
│ └── package.json
├── node-api-esm
│ ├── index.js
│ └── package.json
├── node-api
│ ├── index.js
│ └── package.json
└── typescript-nodenext-resolution
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
├── tsconfig.json
├── tstyche.config.json
├── vercel.json
├── website
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── .remarkrc.mjs
├── babel.config.js
├── blog
│ ├── 2023-04-26-announcing-lingui-4.0
│ │ ├── index.md
│ │ └── social-card.png
│ ├── 2023-12-12-4k-stars
│ │ ├── index.md
│ │ └── social-card.png
│ ├── 2024-11-20-metro-transformer
│ │ ├── index.md
│ │ └── social-card.png
│ ├── 2024-11-28-announcing-lingui-5.0
│ │ ├── index.md
│ │ └── social-card.png
│ └── authors.yml
├── docs
│ ├── community.md
│ ├── examples.md
│ ├── guides
│ │ ├── custom-extractor.md
│ │ ├── custom-formatter.md
│ │ ├── dynamic-loading-catalogs.md
│ │ ├── explicit-vs-generated-ids.md
│ │ ├── lazy-translations.md
│ │ ├── message-extraction.md
│ │ ├── message-format.md
│ │ ├── monorepo.md
│ │ ├── plurals.md
│ │ ├── pseudolocalization.md
│ │ └── testing.md
│ ├── installation.mdx
│ ├── introduction.md
│ ├── misc
│ │ ├── i18next.md
│ │ ├── react-intl.md
│ │ ├── resources.md
│ │ ├── showroom.md
│ │ └── tooling.md
│ ├── ref
│ │ ├── catalog-formats.md
│ │ ├── cli.md
│ │ ├── conf.md
│ │ ├── core.md
│ │ ├── eslint-plugin.md
│ │ ├── extractor-vue.md
│ │ ├── loader.md
│ │ ├── locale-detector.md
│ │ ├── macro.mdx
│ │ ├── metro-transformer.mdx
│ │ ├── react.md
│ │ ├── swc-plugin.md
│ │ └── vite-plugin.md
│ ├── releases
│ │ ├── migration-3.md
│ │ ├── migration-4.md
│ │ └── migration-5.md
│ ├── tools
│ │ ├── crowdin.md
│ │ ├── introduction.md
│ │ └── translation-io.md
│ └── tutorials
│ │ ├── javascript.md
│ │ ├── react-native.md
│ │ ├── react-rsc.md
│ │ └── react.md
├── docusaurus.config.ts
├── eslint.config.mjs
├── linkcheck-ignore.txt
├── package.json
├── sidebars.ts
├── src
│ ├── components
│ │ ├── Button.tsx
│ │ ├── Code.tsx
│ │ ├── Features.module.scss
│ │ ├── Features.tsx
│ │ ├── Header.module.scss
│ │ ├── Header.tsx
│ │ ├── PartnerBanner.module.scss
│ │ ├── PartnerBanner.tsx
│ │ ├── Users.module.scss
│ │ ├── Users.tsx
│ │ └── Workflow.tsx
│ ├── css
│ │ └── custom.scss
│ ├── definitions.d.ts
│ ├── pages
│ │ └── index.tsx
│ └── theme
│ │ └── Footer
│ │ └── index.js
├── static
│ ├── .nojekyll
│ └── img
│ │ ├── docs
│ │ ├── Crowdin__js-lingui-vcs.png
│ │ ├── dynamic-loading-catalogs-1.png
│ │ ├── dynamic-loading-catalogs-2.png
│ │ ├── extractor-deps-scheme.svg
│ │ ├── extractor-glob-scheme.svg
│ │ ├── lingui-workflow.svg
│ │ ├── rn-component-nesting.png
│ │ ├── translation-lingui-plural-forms.png
│ │ ├── with-collaboration-tool.svg
│ │ └── without-collaboration-tool.svg
│ │ ├── favicon.ico
│ │ ├── features
│ │ ├── ai-ready.png
│ │ ├── all-platforms.svg
│ │ ├── clean-and-readable.png
│ │ ├── fledged.svg
│ │ ├── pattern-left-big.svg
│ │ ├── pattern-right-big.svg
│ │ ├── rich-text.svg
│ │ ├── time.svg
│ │ ├── tooling.png
│ │ ├── universal.svg
│ │ └── verified.svg
│ │ ├── header
│ │ ├── left-bg.svg
│ │ └── right-bg.svg
│ │ ├── lingui-logo.svg
│ │ ├── logo-small.svg
│ │ ├── og-image-examples.png
│ │ ├── og-image.png
│ │ └── users
│ │ ├── ansible.png
│ │ ├── bluesky.png
│ │ ├── brave.png
│ │ ├── documenso.png
│ │ ├── fider.png
│ │ ├── flood.svg
│ │ ├── graysky.png
│ │ ├── linkerd.png
│ │ ├── metamask.png
│ │ ├── remirror.png
│ │ ├── twenty.png
│ │ └── zipkin.png
├── tools
│ └── algolia
│ │ └── config.json
├── tsconfig.json
└── yarn.lock
└── yarn.lock
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: View documentation
4 | url: https://lingui.dev
5 | about: Check the official docs for answers to common questions
6 | - name: Chat on Discord
7 | url: https://discord.gg/gFWwAYnMtA
8 | about: Join the Lingui community on Discord
9 | - name: Ask AI
10 | url: https://gurubase.io/g/lingui-js
11 | about: Ask Lingui JS Guru - AI powered Q&A assistant
12 |
--------------------------------------------------------------------------------
/.github/codecov.yml:
--------------------------------------------------------------------------------
1 | # https://docs.codecov.com/docs/codecovyml-reference
2 |
3 | codecov:
4 | notify:
5 | require_ci_to_pass: yes
6 |
7 | coverage:
8 | precision: 2
9 | round: down
10 | range: "65...100"
11 |
12 | status:
13 | project:
14 | default:
15 | target: auto
16 | threshold: 2%
17 | patch:
18 | default:
19 | target: 70%
20 |
--------------------------------------------------------------------------------
/.github/verdaccio/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | npmScopes:
2 | lingui:
3 | npmRegistryServer: http://0.0.0.0:4873/
4 | npmPublishRegistry: http://0.0.0.0:4873/
5 |
6 | unsafeHttpWhitelist:
7 | - 0.0.0.0
8 |
--------------------------------------------------------------------------------
/.github/verdaccio/config.yaml:
--------------------------------------------------------------------------------
1 | listen: 0.0.0.0:4873
2 | auth:
3 | auth-memory:
4 | users:
5 | foo:
6 | name: test
7 | password: test
8 | store:
9 | memory:
10 | limit: 1000
11 | uplinks:
12 | npmjs:
13 | url: https://registry.npmjs.org/
14 | packages:
15 | '@*/*':
16 | access: $all
17 | publish: $all
18 | '**':
19 | access: $all
20 | publish: $all
21 | middlewares:
22 | audit:
23 | enabled: true
24 | log:
25 | - {type: stdout, format: pretty, level: trace}
26 |
--------------------------------------------------------------------------------
/.github/workflows/docs-suite.yml:
--------------------------------------------------------------------------------
1 | name: docs-suite
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - '*'
7 | paths:
8 | - website/**
9 |
10 | jobs:
11 | validate:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | - name: Setup node
18 | uses: actions/setup-node@v4
19 | with:
20 | node-version: 'lts/*'
21 |
22 | - name: Install dependencies
23 | working-directory: website
24 | run: yarn install
25 |
26 | - name: Build
27 | working-directory: website
28 | run: yarn build
29 |
30 | - name: Lint
31 | working-directory: website
32 | run: yarn lint
33 |
34 | - name: Check Formatting
35 | working-directory: website
36 | run: yarn checkFormat
37 |
--------------------------------------------------------------------------------
/.github/workflows/lint-pr-title.yml:
--------------------------------------------------------------------------------
1 | name: lint-pr-title
2 |
3 | on:
4 | pull_request_target:
5 | types:
6 | - opened
7 | - reopened
8 | - edited
9 | - synchronize
10 |
11 | jobs:
12 | main:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: amannn/action-semantic-pull-request@v5
17 | env:
18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 |
--------------------------------------------------------------------------------
/.github/workflows/next-sync.yml:
--------------------------------------------------------------------------------
1 | name: next-sync
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | next-sync:
10 | runs-on: ubuntu-latest
11 | name: Syncing branches
12 |
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v4
16 |
17 | - name: Set up Node
18 | uses: actions/setup-node@v4
19 | with:
20 | node-version: 'lts/*'
21 |
22 | - name: Opening pull request
23 | id: pull
24 | uses: tretuna/sync-branches@1.4.0
25 | with:
26 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
27 | FROM_BRANCH: "main"
28 | TO_BRANCH: "next"
29 | PULL_REQUEST_TITLE: "chore: sync main to next"
30 |
--------------------------------------------------------------------------------
/.github/workflows/size-limit.yml:
--------------------------------------------------------------------------------
1 | name: Size Testing
2 |
3 | on:
4 | pull_request_target:
5 | types:
6 | - opened
7 | - synchronize
8 | - reopened
9 |
10 | jobs:
11 | size:
12 | runs-on: ubuntu-latest
13 | env:
14 | CI_JOB_NUMBER: 1
15 |
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - uses: andresz1/size-limit-action@v1.8.0
20 | with:
21 | build_script: release:build
22 | github_token: ${{ secrets.GITHUB_TOKEN }}
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .yalc/
3 | yalc.lock
4 | dist
5 |
6 | npm-debug.log
7 | yarn-error.log
8 |
9 | coverage/
10 | results/
11 | junit.xml
12 |
13 | .DS_Store
14 | .vscode
15 | .idea
16 | *.iml
17 |
18 | .pnp.*
19 | .yarn/*
20 | !.yarn/patches
21 | !.yarn/plugins
22 | !.yarn/releases
23 | !.yarn/sdks
24 | !.yarn/versions
25 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/.next/*
2 | **/dist/*
3 | **/test/fixtures/**
4 | **/test/**/actual.js
5 | **/test/**/actual/**
6 | **/test/**/expected.js
7 | **/locale/*
8 | **/fixtures/*
9 | **/expected/*
10 | coverage/
11 | website/
12 | .github
13 | examples
14 | /.nx/workspace-data
15 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false
3 | }
4 |
--------------------------------------------------------------------------------
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
3 | plugins:
4 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
5 | spec: "@yarnpkg/plugin-workspace-tools"
6 |
7 | yarnPath: .yarn/releases/yarn-3.4.1.cjs
8 |
9 | unsafeHttpWhitelist:
10 | - 0.0.0.0
11 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: 16,
8 | },
9 | modules: "commonjs",
10 | },
11 | ],
12 | "@babel/preset-typescript",
13 | "@babel/preset-react",
14 | ],
15 | }
16 |
--------------------------------------------------------------------------------
/examples/create-react-app/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "next/babel"
4 | ],
5 | "plugins": ["@lingui/babel-plugin-lingui-macro"]
6 | }
7 |
--------------------------------------------------------------------------------
/examples/create-react-app/.env:
--------------------------------------------------------------------------------
1 | SKIP_PREFLIGHT_CHECK=true
--------------------------------------------------------------------------------
/examples/create-react-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | .pnp.*
26 | .yarn/*
27 | !.yarn/patches
28 | !.yarn/plugins
29 | !.yarn/releases
30 | !.yarn/sdks
31 | !.yarn/versions
32 |
--------------------------------------------------------------------------------
/examples/create-react-app/lingui.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@lingui/conf').LinguiConfig} */
2 | module.exports = {
3 | locales: ["en", "cs"],
4 | sourceLocale: "en",
5 | catalogs: [
6 | {
7 | path: "/src/locales/{locale}",
8 | include: [""],
9 | exclude: ["**/node_modules/**"],
10 | },
11 | ],
12 | format: "po",
13 | }
14 |
--------------------------------------------------------------------------------
/examples/create-react-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 | React App
12 |
13 |
14 | You need to enable JavaScript to run this app.
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/examples/create-react-app/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 10vmin;
7 | pointer-events: none;
8 | }
9 |
10 | .App-header {
11 | background-color: #282c34;
12 | min-height: 100vh;
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | justify-content: center;
17 | font-size: calc(10px + 2vmin);
18 | color: white;
19 | }
20 |
21 |
22 | .lang-container {
23 | display: flex;
24 | }
25 |
26 | .lang-container button {
27 | margin: 1rem;
28 | background: rgb(164, 13, 13);
29 | color: white;
30 | border-radius: 1rem;
31 | box-shadow: none;
32 | border: 0;
33 | padding: 1rem;
34 | text-transform: uppercase;
35 | cursor: pointer;
36 | }
37 |
--------------------------------------------------------------------------------
/examples/create-react-app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/examples/create-react-app/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/examples/create-react-app/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/examples/create-react-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/examples/js/.gitignore:
--------------------------------------------------------------------------------
1 | src/locale/_build/
2 | src/locale/*/*.js
3 |
4 | .pnp.*
5 | .yarn/*
6 | !.yarn/patches
7 | !.yarn/plugins
8 | !.yarn/releases
9 | !.yarn/sdks
10 | !.yarn/versions
11 |
--------------------------------------------------------------------------------
/examples/js/README.md:
--------------------------------------------------------------------------------
1 | # Using LinguiJS in VanillaJS projects
2 |
3 | Prepare the example by installing dependencies and compiling message catalogs:
4 |
5 | ```sh
6 | yarn install
7 | yarn lingui compile
8 | ```
9 |
10 | Now, either run full test suit:
11 |
12 | ```sh
13 | yarn test
14 | ```
15 |
16 | Or each file individually (you need to have `babel-cli` installed globally):
17 |
18 | ```sh
19 | babel-node src/messages.js
20 | ```
21 |
--------------------------------------------------------------------------------
/examples/js/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@babel/env"],
3 | plugins: ["@lingui/babel-plugin-lingui-macro"],
4 | }
5 |
--------------------------------------------------------------------------------
/examples/js/lingui.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@lingui/conf').LinguiConfig} */
2 | module.exports = {
3 | locales: ["en", "cs"],
4 | format: "po",
5 | catalogs: [
6 | {
7 | path: "./src/locale/{locale}/messages",
8 | include: ["./src"],
9 | },
10 | ],
11 | sourceLocale: "en",
12 | }
13 |
--------------------------------------------------------------------------------
/examples/js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vanilla-js",
3 | "version": "1.0.0",
4 | "main": "src/index.js",
5 | "license": "MIT",
6 | "author": {
7 | "name": "Tomáš Ehrlich",
8 | "email": "tomas.ehrlich@gmail.com"
9 | },
10 | "scripts": {
11 | "test": "lingui compile && jest src",
12 | "extract": "lingui extract --clean"
13 | },
14 | "dependencies": {
15 | "@lingui/core": "^5.0.0-next.3"
16 | },
17 | "devDependencies": {
18 | "@babel/core": "^7.20.12",
19 | "@babel/preset-env": "^7.20.2",
20 | "@lingui/babel-plugin-lingui-macro": "^5.0.0-next.3",
21 | "@lingui/cli": "^5.0.0-next.3",
22 | "jest": "^29.5.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/js/src/locale/cs/messages.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"static\":\"Ukázka @lingui/core\",\"zziTz4\":\"Ukázka @lingui/core\",\"lazy\":[\"Chcete pokračovat? \",[\"yes\"],\"/\",[\"no\"]],\"+GYOc0\":[\"Chcete pokračovat? \",[\"yes\"],\"/\",[\"no\"]],\"variables\":[\"Ahoj \",[\"name\"]],\"OVaF9k\":[\"Ahoj \",[\"name\"]],\"common.no\":\"Ne\",\"1UzENP\":\"Ne\",\"plural\":[[\"value\",\"plural\",{\"one\":[\"#\",\" láhev\"],\"few\":[\"#\",\" láhve\"],\"other\":[\"#\",\" láhví\"]}],\" visí na stěně\"],\"KE/K99\":[[\"value\",\"plural\",{\"one\":[\"#\",\" láhev\"],\"few\":[\"#\",\" láhve\"],\"other\":[\"#\",\" láhví\"]}],\" visí na stěně\"],\"common.yes\":\"Ano\",\"l75CjT\":\"Ano\"}")};
--------------------------------------------------------------------------------
/examples/js/src/locale/en/messages.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"static\":\"@lingui/core example\",\"zziTz4\":\"@lingui/core example\",\"lazy\":[\"Do you want to proceed? \",[\"yes\"],\"/\",[\"no\"]],\"+GYOc0\":[\"Do you want to proceed? \",[\"yes\"],\"/\",[\"no\"]],\"variables\":[\"Hello \",[\"name\"]],\"OVaF9k\":[\"Hello \",[\"name\"]],\"common.no\":\"No\",\"1UzENP\":\"No\",\"plural\":[\"There are \",[\"value\",\"plural\",{\"one\":[\"#\",\" bottle\"],\"other\":[\"#\",\" bottles\"]}],\" hanging on the wall\"],\"KE/K99\":[\"There are \",[\"value\",\"plural\",{\"one\":[\"#\",\" bottle\"],\"other\":[\"#\",\" bottles\"]}],\" hanging on the wall\"],\"common.yes\":\"Yes\",\"l75CjT\":\"Yes\"}")};
--------------------------------------------------------------------------------
/examples/nextjs-babel/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "next/babel"
4 | ],
5 | "plugins": ["@lingui/babel-plugin-lingui-macro"]
6 | }
7 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # LinguiJS
16 | locale/*/*.js
17 |
18 | # production
19 | /build
20 |
21 | # misc
22 | .DS_Store
23 | *.pem
24 |
25 | # debug
26 | npm-debug.log*
27 | yarn-debug.log*
28 | yarn-error.log*
29 |
30 | # local env files
31 | .env.local
32 | .env.development.local
33 | .env.test.local
34 | .env.production.local
35 |
36 | # vercel
37 | .vercel
38 |
39 | .pnp.*
40 | .yarn/*
41 | !.yarn/patches
42 | !.yarn/plugins
43 | !.yarn/releases
44 | !.yarn/sdks
45 | !.yarn/versions
46 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/lingui.config.js:
--------------------------------------------------------------------------------
1 | const nextConfig = require("./next.config")
2 |
3 | /** @type {import('@lingui/conf').LinguiConfig} */
4 | module.exports = {
5 | locales: nextConfig.i18n.locales,
6 | pseudoLocale: "pseudo",
7 | sourceLocale: nextConfig.i18n.defaultLocale,
8 | fallbackLocales: {
9 | default: "en",
10 | },
11 | catalogs: [
12 | {
13 | path: "src/locales/{locale}",
14 | include: ["src/"],
15 | },
16 | ],
17 | }
18 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | module.exports = {
3 | i18n: {
4 | // These are all the locales you want to support in
5 | // your application
6 | locales: ["en", "cs", "pseudo"],
7 | defaultLocale: "en",
8 | },
9 | }
10 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-js-babel",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "extract": "lingui extract",
7 | "dev": "next dev",
8 | "build": "yarn extract && next build",
9 | "start": "next start"
10 | },
11 | "dependencies": {
12 | "@lingui/core": "^5.0.0-next.2",
13 | "@lingui/react": "^5.0.0-next.2",
14 | "classnames": "^2.3.1",
15 | "next": "13.2.4",
16 | "react": "18.2.0",
17 | "react-dom": "18.2.0"
18 | },
19 | "devDependencies": {
20 | "@lingui/babel-plugin-lingui-macro": "^5.0.0-next.2",
21 | "@lingui/cli": "^5.0.0-next.2",
22 | "@lingui/loader": "^5.0.0-next.2",
23 | "@types/react": "^18.0.28",
24 | "typescript": "^4.9.5",
25 | "webpack": "^5.76.2"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/nextjs-babel/public/favicon.ico
--------------------------------------------------------------------------------
/examples/nextjs-babel/src/components/Layout.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | min-height: 100vh;
3 | max-width: 960px;
4 | width: 100%;
5 | padding: 0 0.5rem;
6 | margin: 0 auto;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: center;
10 | align-items: center;
11 | }
12 |
13 | .main {
14 | flex: 1;
15 | }
16 |
17 | .footer {
18 | width: 100%;
19 | height: 100px;
20 | border-top: 1px solid #eaeaea;
21 | display: flex;
22 | justify-content: center;
23 | align-items: center;
24 | }
25 |
26 | .footer img {
27 | margin-left: 0.5rem;
28 | }
29 |
30 | .footer a {
31 | display: flex;
32 | justify-content: center;
33 | align-items: center;
34 | }
35 |
36 | .logo {
37 | height: 1em;
38 | }
39 |
40 | .link {
41 | border: none;
42 | background: none;
43 | cursor: pointer;
44 | font-size: inherit;
45 | }
46 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/src/components/PluralExample.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 |
3 | export function PluralExample({ initialValue = 1, render }) {
4 | const [value, setValue] = React.useState(initialValue)
5 |
6 | return (
7 |
8 |
{render({ value })}
9 |
10 | setValue(e.target.value as any)}
14 | />
15 |
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import { I18nProvider } from "@lingui/react"
2 | import { i18n } from "@lingui/core"
3 |
4 | import "../styles.css"
5 | import { useLinguiInit } from "../i18n"
6 | import { AppProps } from "next/app"
7 |
8 | export default function MyApp({ Component, pageProps }: AppProps) {
9 | useLinguiInit(pageProps.translation)
10 |
11 | return (
12 | <>
13 |
14 |
15 |
16 | >
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/src/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default (req, res) => {
4 | res.statusCode = 200
5 | res.json({ name: 'John Doe' })
6 | }
7 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/src/styles.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
--------------------------------------------------------------------------------
/examples/nextjs-babel/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "ESNext",
5 | "lib": [
6 | "dom",
7 | "dom.iterable",
8 | "esnext"
9 | ],
10 | "allowJs": true,
11 | "skipLibCheck": true,
12 | "strict": false,
13 | "forceConsistentCasingInFileNames": true,
14 | "noEmit": true,
15 | "esModuleInterop": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "jsx": "preserve",
21 | "incremental": true
22 | },
23 | "include": [
24 | "next-env.d.ts",
25 | "**/*.ts",
26 | "**/*.tsx"
27 | ],
28 | "exclude": [
29 | "node_modules"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
36 | # lingui js
37 | /src/translations/**/*.js
38 |
39 | .pnp.*
40 | .yarn/*
41 | !.yarn/patches
42 | !.yarn/plugins
43 | !.yarn/releases
44 | !.yarn/sdks
45 | !.yarn/versions
46 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: false,
3 | singleQuote: true,
4 | trailingComma: 'none'
5 | // endOfLine: "lf"
6 | }
7 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/lingui.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@lingui/conf').LinguiConfig} */
2 | module.exports = {
3 | locales: ['en', 'sr', 'es', 'pseudo'],
4 | pseudoLocale: 'pseudo',
5 | sourceLocale: 'en',
6 | fallbackLocales: {
7 | default: 'en'
8 | },
9 | catalogs: [
10 | {
11 | path: 'src/locales/{locale}',
12 | include: ['src/']
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 |
5 | // NOTE: This file should not be edited
6 | // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
7 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/next.config.ts:
--------------------------------------------------------------------------------
1 | import type { NextConfig } from 'next'
2 |
3 | const nextConfig: NextConfig = {
4 | experimental: {
5 | swcPlugins: [['@lingui/swc-plugin', {}]],
6 | turbo: {
7 | rules: {
8 | '*.po': {
9 | loaders: ['@lingui/loader'],
10 | as: '*.js'
11 | }
12 | }
13 | }
14 | },
15 | webpack: (config) => {
16 | config.module.rules.push({
17 | test: /\.po$/,
18 | use: {
19 | loader: "@lingui/loader",
20 | },
21 | });
22 |
23 | return config;
24 | },
25 | }
26 |
27 | export default nextConfig
28 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/nextjs-swc/public/favicon.ico
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/app/[lang]/app-router-demo/page.tsx:
--------------------------------------------------------------------------------
1 | import { HomePage } from '../../../components/HomePage'
2 | import {initLingui, PageLangParam} from '../../../initLingui'
3 |
4 | export default async function Page(props: PageLangParam) {
5 | const lang = (await props.params).lang
6 | initLingui(lang)
7 | return
8 | }
9 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/app/[lang]/page.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 |
3 | export default function Index() {
4 | return (
5 | <>
6 | This is the homepage of the demo app. This page is not localized. You can
7 | go to the App router demo or the{' '}
8 | Pages router demo.
9 | >
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/components/AboutText.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from '@lingui/react/macro'
2 |
3 | export function AboutText() {
4 | return (
5 |
6 |
7 | Next.js is an open-source React front-end development web framework that
8 | enables functionality such as server-side rendering and generating
9 | static websites for React based web applications. It is a
10 | production-ready framework that allows developers to quickly create
11 | static and dynamic JAMstack websites and is used widely by many large
12 | companies.
13 |
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/components/Developers.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 | // this is a client component because it uses the `useState` hook
3 |
4 | import { useState } from 'react'
5 | import { Trans, Plural } from '@lingui/react/macro'
6 |
7 | export default function Developers() {
8 | const [selected, setSelected] = useState('1')
9 | return (
10 |
11 |
12 | Plural Test: How many developers?
13 |
14 |
15 |
setSelected(evt.target.value)}
18 | >
19 | 1
20 | 2
21 |
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/components/LinguiClientProvider.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { I18nProvider } from '@lingui/react'
4 | import { type Messages, setupI18n } from '@lingui/core'
5 | import { useState } from 'react'
6 |
7 | type Props = {
8 | children: React.ReactNode
9 | initialLocale: string
10 | initialMessages: Messages
11 | }
12 |
13 | export function LinguiClientProvider({
14 | children,
15 | initialLocale,
16 | initialMessages
17 | }: Props) {
18 | const [i18n] = useState(() => {
19 | return setupI18n({
20 | locale: initialLocale,
21 | messages: { [initialLocale]: initialMessages }
22 | })
23 | })
24 | return {children}
25 | }
26 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/initLingui.tsx:
--------------------------------------------------------------------------------
1 | import { getI18nInstance } from './appRouterI18n'
2 | import { setI18n } from '@lingui/react/server'
3 |
4 | export type PageLangParam = {
5 | params: Promise<{ lang: string }>
6 | }
7 |
8 | export function initLingui(lang: string) {
9 | const i18n = getI18nInstance(lang)
10 | setI18n(i18n)
11 | return i18n
12 | }
13 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/pages/[lang]/pages-router-demo/index.tsx:
--------------------------------------------------------------------------------
1 | import { GetStaticProps } from 'next'
2 | import { loadCatalog } from '../../../pagesRouterI18n'
3 | import { HomePage } from '../../../components/HomePage'
4 |
5 | import linguiConfig from '../../../../lingui.config'
6 | import type { GetStaticPaths } from 'next'
7 |
8 | export const getStaticPaths = (async () => {
9 | const paths = linguiConfig.locales.map((lang) => ({ params: { lang } }))
10 |
11 | return {
12 | paths,
13 | fallback: false
14 | }
15 | }) satisfies GetStaticPaths
16 |
17 | export const getStaticProps: GetStaticProps = async (ctx) => {
18 | const locale = ctx.params?.lang
19 | const translation = await loadCatalog(
20 | typeof locale === 'string' ? locale : 'en'
21 | )
22 |
23 | return {
24 | props: {
25 | translation
26 | }
27 | }
28 | }
29 |
30 | export default HomePage
31 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import { i18n } from '@lingui/core'
2 | import { I18nProvider } from '@lingui/react'
3 | import '../styles/globals.css'
4 | import type { AppProps } from 'next/app'
5 | import { useLinguiInit } from '../pagesRouterI18n'
6 |
7 | function MyApp({ Component, pageProps }: AppProps) {
8 | useLinguiInit(pageProps.translation)
9 |
10 | return (
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | export default MyApp
18 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/styles/Index.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | min-height: 100vh;
3 | padding: 0 0.5rem;
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .main {
11 | padding: 5rem 0;
12 | flex: 1;
13 | display: flex;
14 | flex-direction: column;
15 | justify-content: center;
16 | align-items: center;
17 | }
18 |
19 | .title a {
20 | color: #0070f3;
21 | text-decoration: none;
22 | }
23 |
24 | .title a:hover,
25 | .title a:focus,
26 | .title a:active {
27 | text-decoration: underline;
28 | }
29 |
30 | .title {
31 | margin-bottom: 0;
32 | margin-top: 2rem;
33 | line-height: 1.15;
34 | font-size: 4rem;
35 | }
36 |
37 | .title,
38 | .description {
39 | text-align: center;
40 | }
41 |
42 | .description {
43 | /* line-height: 1.5; */
44 | /* font-size: 1.5rem; */
45 | max-width: 600px;
46 | text-align: left;
47 | }
48 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
--------------------------------------------------------------------------------
/examples/nextjs-swc/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2017",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "strict": true,
12 | "noUncheckedIndexedAccess": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "noEmit": true,
15 | "esModuleInterop": true,
16 | "module": "esnext",
17 | "moduleResolution": "Bundler",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | // "downlevelIteration": true,
21 | "jsx": "preserve",
22 | "incremental": true,
23 | "plugins": [
24 | {
25 | "name": "next"
26 | }
27 | ]
28 | },
29 | "include": [
30 | "next-env.d.ts",
31 | "src/**/*.ts",
32 | "src/**/*.tsx",
33 | ".next/types/**/*.ts"
34 | ],
35 | "exclude": [
36 | "node_modules"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/examples/react-native/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ["@react-native-community"],
4 | };
5 |
--------------------------------------------------------------------------------
/examples/react-native/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # Temporary files created by Metro to check the health of the file watcher
17 | .metro-health-check*
18 |
19 | # js translation files should be generated as part of build process
20 | #src/locales/**/*.js
21 |
22 | .yarn/*
23 | !.yarn/patches
24 | !.yarn/plugins
25 | !.yarn/releases
26 | !.yarn/sdks
27 | !.yarn/versions
28 |
--------------------------------------------------------------------------------
/examples/react-native/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": false,
3 | "trailingComma": "all",
4 | "tabWidth": 2,
5 | "bracketSpacing": true,
6 | "printWidth": 90
7 | }
8 |
--------------------------------------------------------------------------------
/examples/react-native/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
--------------------------------------------------------------------------------
/examples/react-native/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "js-lingui-demo",
4 | "description": "This a simple demo app for lingui.js",
5 | "slug": "js-lingui-demo",
6 | "version": "2.0.1",
7 | "orientation": "portrait",
8 | "icon": "./assets/icon.png",
9 | "userInterfaceStyle": "light",
10 | "newArchEnabled": true,
11 | "splash": {
12 | "image": "./assets/splash.png",
13 | "resizeMode": "contain",
14 | "backgroundColor": "#ffffff"
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "android": {
23 | "adaptiveIcon": {
24 | "foregroundImage": "./assets/adaptive-icon.png",
25 | "backgroundColor": "#ffffff"
26 | }
27 | },
28 | "web": {
29 | "favicon": "./assets/favicon.png",
30 | "bundler": "metro"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/examples/react-native/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/react-native/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/examples/react-native/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/react-native/assets/favicon.png
--------------------------------------------------------------------------------
/examples/react-native/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/react-native/assets/icon.png
--------------------------------------------------------------------------------
/examples/react-native/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/react-native/assets/splash.png
--------------------------------------------------------------------------------
/examples/react-native/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(false);
3 | return {
4 | plugins: ["@lingui/babel-plugin-lingui-macro"],
5 | presets: ["babel-preset-expo"],
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/examples/react-native/lingui.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@lingui/conf').LinguiConfig} */
2 | module.exports = {
3 | locales: ["en", "cs"],
4 | sourceLocale: "en",
5 | catalogs: [
6 | {
7 | path: "src/locales/{locale}/messages",
8 | include: ["src"],
9 | },
10 | ],
11 | format: "po",
12 | };
13 |
--------------------------------------------------------------------------------
/examples/react-native/metro.config.js:
--------------------------------------------------------------------------------
1 | // Learn more https://docs.expo.io/guides/customizing-metro
2 | const { getDefaultConfig } = require("expo/metro-config");
3 |
4 | const config = getDefaultConfig(__dirname);
5 | const { transformer, resolver } = config;
6 |
7 | config.transformer = {
8 | ...transformer,
9 | babelTransformerPath: require.resolve("@lingui/metro-transformer/expo"),
10 | };
11 | config.resolver = {
12 | ...resolver,
13 | sourceExts: [...resolver.sourceExts, "po", "pot"],
14 | };
15 |
16 | module.exports = config;
17 |
--------------------------------------------------------------------------------
/examples/react-native/src/Components.tsx:
--------------------------------------------------------------------------------
1 | import { TextProps, Text } from "react-native";
2 |
3 | export const Heading = (props: Omit) => {
4 | return (
5 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/examples/react-native/src/PaddedButton.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Button as RNButton,
3 | StyleSheet,
4 | View,
5 | Platform,
6 | ButtonProps,
7 | } from "react-native";
8 | import React from "react";
9 |
10 | export const Button = (props: ButtonProps) => (
11 |
12 |
13 |
14 | );
15 |
16 | const styles = StyleSheet.create({
17 | margin: {
18 | ...Platform.select({
19 | android: {
20 | margin: 10,
21 | },
22 | }),
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/examples/react-native/src/po-types.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.po" {
2 | import type { Messages } from "@lingui/core";
3 | export const messages: Messages;
4 | }
5 |
--------------------------------------------------------------------------------
/examples/react-native/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "strict": true
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/remix-vite-babel/.gitignore:
--------------------------------------------------------------------------------
1 | .yarn
2 | node_modules
3 |
4 | /.cache
5 | /build
6 | .env
7 |
--------------------------------------------------------------------------------
/examples/remix-vite-babel/app/modules/lingui/config.ts:
--------------------------------------------------------------------------------
1 | import type { LinguiConfig } from "@lingui/conf";
2 |
3 | const config: LinguiConfig = {
4 | fallbackLocales: {
5 | default: "en",
6 | },
7 | locales: ["en", "fr"],
8 | catalogs: [
9 | {
10 | path: "/app/locales/{locale}",
11 | include: ["app"],
12 | },
13 | ],
14 | };
15 |
16 | export default config;
17 |
--------------------------------------------------------------------------------
/examples/remix-vite-babel/app/modules/lingui/lingui.server.ts:
--------------------------------------------------------------------------------
1 | import config from "./config";
2 | import { RemixLingui } from "./remix.server";
3 | import { createCookie } from "@remix-run/node";
4 |
5 | export const localeCookie = createCookie("lng", {
6 | path: "/",
7 | sameSite: "lax",
8 | secure: process.env.NODE_ENV === "production",
9 | httpOnly: true,
10 | });
11 |
12 | export const linguiServer = new RemixLingui({
13 | detection: {
14 | supportedLanguages: config.locales,
15 | fallbackLanguage:
16 | (!!config.fallbackLocales && config.fallbackLocales?.default) || "en",
17 | cookie: localeCookie,
18 | },
19 | });
20 |
--------------------------------------------------------------------------------
/examples/remix-vite-babel/lingui.config.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/export
2 | export * from "./app/modules/lingui/config";
3 |
--------------------------------------------------------------------------------
/examples/remix-vite-babel/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { lingui } from "@lingui/vite-plugin";
2 | import { vitePlugin as remix } from "@remix-run/dev";
3 | import { installGlobals } from "@remix-run/node";
4 | import { defineConfig } from "vite";
5 | import macrosPlugin from "vite-plugin-babel-macros";
6 | import tsconfigPaths from "vite-tsconfig-paths";
7 |
8 | installGlobals();
9 |
10 | export default defineConfig({
11 | plugins: [
12 | remix(),
13 | macrosPlugin(),
14 | lingui(),
15 | tsconfigPaths()
16 | ],
17 | });
18 |
--------------------------------------------------------------------------------
/examples/rspack/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/rspack/demo.gif
--------------------------------------------------------------------------------
/examples/rspack/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Rspack + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/rspack/lingui.config.ts:
--------------------------------------------------------------------------------
1 | import { LinguiConfig } from '@lingui/conf'
2 |
3 | const config: Partial = {
4 | locales: ["en", "fr"],
5 | sourceLocale: "en",
6 | catalogs: [{
7 | path: "src/locales/{locale}/messages",
8 | include: ["src"]
9 | }],
10 | format: "po"
11 | };
12 |
13 | export default config;
--------------------------------------------------------------------------------
/examples/rspack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rspack-react-ts-starter",
3 | "private": true,
4 | "version": "1.0.0",
5 | "scripts": {
6 | "dev": "rspack serve",
7 | "build": "rspack build",
8 | "extract": "lingui extract",
9 | "compile": "lingui compile --typescript"
10 | },
11 | "dependencies": {
12 | "@lingui/react": "^4.7.2",
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@lingui/cli": "^4.7.2",
18 | "@lingui/macro": "^4.7.2",
19 | "@lingui/swc-plugin": "^4.0.7",
20 | "@rspack/cli": "^0.6.2",
21 | "@rspack/core": "^0.6.2",
22 | "@types/react": "^18.2.79",
23 | "@types/react-dom": "18.2.1",
24 | "typescript": "^5.0.4"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/rspack/src/LocaleSwitcher.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useLingui } from '@lingui/react';
3 | import Locale from './locales';
4 |
5 | function LocaleSwitcher() {
6 | const { i18n } = useLingui();
7 |
8 | const handleLocaleChange = (newLocale: Locale) => {
9 | i18n.activate(newLocale);
10 | };
11 |
12 | return (
13 |
14 | handleLocaleChange(Locale.ENGLISH)}>English
15 | handleLocaleChange(Locale.FRENCH)}>Français
16 | {/* Add more buttons for other supported locales */}
17 |
18 | );
19 | }
20 |
21 | export default LocaleSwitcher;
22 |
--------------------------------------------------------------------------------
/examples/rspack/src/locales.ts:
--------------------------------------------------------------------------------
1 | enum Locale {
2 | ENGLISH = 'en',
3 | FRENCH = 'fr',
4 | }
5 |
6 | export default Locale;
7 |
--------------------------------------------------------------------------------
/examples/rspack/src/locales/en/messages.d.ts:
--------------------------------------------------------------------------------
1 | import { Messages } from '@lingui/core';
2 | declare const messages: Messages;
3 | export { messages };
4 |
--------------------------------------------------------------------------------
/examples/rspack/src/locales/en/messages.ts:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/export const messages=JSON.parse("{\"iHvPFN\":[[\"messagesCount\",\"plural\",{\"one\":[\"There's \",\"#\",\" message in your inbox.\"],\"other\":[\"There are \",\"#\",\" messages in your inbox.\"]}]],\"ItXLVU\":[\"Last login on \",[\"0\"],\".\"],\"8bWV5m\":\"Message Inbox\",\"f8BUjV\":\"See all <0>unread messages 0>or <1>mark them1> as read.\"}");
--------------------------------------------------------------------------------
/examples/rspack/src/locales/fr/messages.d.ts:
--------------------------------------------------------------------------------
1 | import { Messages } from '@lingui/core';
2 | declare const messages: Messages;
3 | export { messages };
4 |
--------------------------------------------------------------------------------
/examples/rspack/src/locales/fr/messages.ts:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/export const messages=JSON.parse("{\"iHvPFN\":[[\"messagesCount\",\"plural\",{\"one\":[\"Il y a \",\"#\",\" message dans boîte de réception.\"],\"other\":[\"Il y a \",\"#\",\" messages dans votre boîte de réception.\"]}]],\"ItXLVU\":[\"Last login on \",[\"0\"],\".\"],\"8bWV5m\":\"Boîte de réception de messages.\",\"f8BUjV\":\"Voir tous <0>les messages non lus 0>ou <1>les marquer1> comme lus.\"}");
--------------------------------------------------------------------------------
/examples/rspack/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createRoot } from "react-dom/client";
3 |
4 | import { i18n } from "@lingui/core";
5 | import { I18nProvider } from "@lingui/react";
6 | import { messages as enMessages } from "./locales/en/messages";
7 | import { messages as frMessages } from "./locales/fr/messages";
8 |
9 | import Inbox from "./Inbox";
10 |
11 | i18n.load({
12 | "en": enMessages,
13 | "fr": frMessages,
14 | });
15 |
16 | i18n.activate("en");
17 |
18 | const App = () => (
19 |
20 |
21 |
22 | );
23 |
24 | const container = document.getElementById('root');
25 | const root = createRoot(container!);
26 | root.render(
27 |
28 |
29 |
30 | )
31 |
--------------------------------------------------------------------------------
/examples/rspack/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES6",
4 | "lib": [
5 | "DOM",
6 | "DOM.Iterable",
7 | "ESNext"
8 | ],
9 | "module": "ESNext",
10 | "skipLibCheck": true,
11 | "moduleResolution": "bundler",
12 | "allowImportingTsExtensions": true,
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "noEmit": true,
16 | "jsx": "react-jsx",
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "noFallthroughCasesInSwitch": true,
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
--------------------------------------------------------------------------------
/examples/tanstack-start/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .yarn
3 |
4 | .DS_Store
5 | .cache
6 | .env
7 | .vercel
8 | .output
9 | .vinxi
10 |
11 | /build/
12 | /api/
13 | /server/build
14 | /public/build
15 | .vinxi
16 | # Sentry Config File
17 | .env.sentry-build-plugin
18 | /test-results/
19 | /playwright-report/
20 | /blob-report/
21 | /playwright/.cache/
22 |
--------------------------------------------------------------------------------
/examples/tanstack-start/.prettierignore:
--------------------------------------------------------------------------------
1 | **/build
2 | **/public
3 | pnpm-lock.yaml
4 | routeTree.gen.ts
--------------------------------------------------------------------------------
/examples/tanstack-start/README.md:
--------------------------------------------------------------------------------
1 | # Example project using Tanstack Start + Vite + Babel with LinguiJS Plugin
2 |
3 | This is a [Tanstack Start](https://tanstack.com/start/latest) project that demonstrates i18n support with Lingui.
4 |
5 | ## Development
6 |
7 | From your terminal:
8 |
9 | ```sh
10 | yarn install
11 | yarn dev
12 | ```
13 |
14 | This starts your app in development mode, rebuilding assets on file changes.
15 |
--------------------------------------------------------------------------------
/examples/tanstack-start/app.config.ts:
--------------------------------------------------------------------------------
1 | import { lingui } from "@lingui/vite-plugin"
2 | import { defineConfig } from "@tanstack/react-start/config"
3 | import tsConfigPaths from "vite-tsconfig-paths"
4 |
5 | export default defineConfig({
6 | tsr: {
7 | appDirectory: "src",
8 | },
9 | react: {
10 | babel: {
11 | plugins: ["@lingui/babel-plugin-lingui-macro"],
12 | },
13 | },
14 | vite: {
15 | plugins: [
16 | lingui(),
17 | tsConfigPaths({
18 | projects: ["./tsconfig.json"],
19 | }),
20 | ],
21 | },
22 | })
23 |
--------------------------------------------------------------------------------
/examples/tanstack-start/lingui.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | catalogs: [
5 | {
6 | include: ["src"],
7 | path: "/src/locales/{locale}/messages",
8 | },
9 | ],
10 | locales: ["fr", "en"],
11 | sourceLocale: "en",
12 | })
13 |
--------------------------------------------------------------------------------
/examples/tanstack-start/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/examples/tanstack-start/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/tanstack-start/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/examples/tanstack-start/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/tanstack-start/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/examples/tanstack-start/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/tanstack-start/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/examples/tanstack-start/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/tanstack-start/public/favicon-16x16.png
--------------------------------------------------------------------------------
/examples/tanstack-start/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/tanstack-start/public/favicon-32x32.png
--------------------------------------------------------------------------------
/examples/tanstack-start/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/tanstack-start/public/favicon.ico
--------------------------------------------------------------------------------
/examples/tanstack-start/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/examples/tanstack-start/public/favicon.png
--------------------------------------------------------------------------------
/examples/tanstack-start/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/api.ts:
--------------------------------------------------------------------------------
1 | import {
2 | createStartAPIHandler,
3 | defaultAPIFileRouteHandler,
4 | } from "@tanstack/react-start/api"
5 | import {
6 | defaultLocale,
7 | dynamicActivate,
8 | isLocaleValid,
9 | } from "./modules/lingui/i18n"
10 |
11 | export default createStartAPIHandler(async (ctx) => {
12 | // Define the locale based on the Accept-Language header
13 | const headerLocale = ctx.request.headers.get("Accept-Language") ?? ""
14 | await dynamicActivate(
15 | isLocaleValid(headerLocale) ? headerLocale : defaultLocale
16 | )
17 |
18 | return defaultAPIFileRouteHandler(ctx)
19 | })
20 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/client.tsx:
--------------------------------------------------------------------------------
1 | ///
2 | import { i18n } from "@lingui/core"
3 | import { hydrateRoot } from "react-dom/client"
4 | import { StartClient } from "@tanstack/react-start"
5 | import { dynamicActivate } from "./modules/lingui/i18n"
6 |
7 | import { createRouter } from "./router"
8 |
9 | // The lang should be set by the server
10 | dynamicActivate(document.documentElement.lang)
11 |
12 | const router = createRouter({ i18n })
13 |
14 | hydrateRoot(document, )
15 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/components/PostError.tsx:
--------------------------------------------------------------------------------
1 | import { ErrorComponent, ErrorComponentProps } from "@tanstack/react-router"
2 |
3 | export function PostErrorComponent({ error }: ErrorComponentProps) {
4 | return
5 | }
6 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/components/UserError.tsx:
--------------------------------------------------------------------------------
1 | import { ErrorComponent, ErrorComponentProps } from "@tanstack/react-router"
2 |
3 | export function UserErrorComponent({ error }: ErrorComponentProps) {
4 | return
5 | }
6 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/functions/deferred.ts:
--------------------------------------------------------------------------------
1 | import { createServerFn } from "@tanstack/react-start"
2 |
3 | export const personServerFn = createServerFn({ method: "GET" })
4 | .validator((d: string) => d)
5 | .handler(({ data: name }) => {
6 | return { name, randomNumber: Math.floor(Math.random() * 100) }
7 | })
8 |
9 | export const slowServerFn = createServerFn({ method: "GET" })
10 | .validator((d: string) => d)
11 | .handler(async ({ data: name }) => {
12 | await new Promise((r) => setTimeout(r, 1000))
13 | return { name, randomNumber: Math.floor(Math.random() * 100) }
14 | })
15 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/global-middleware.ts:
--------------------------------------------------------------------------------
1 | import { registerGlobalMiddleware } from "@tanstack/react-start"
2 | import { logMiddleware } from "./utils/loggingMiddleware"
3 |
4 | registerGlobalMiddleware({
5 | middleware: [logMiddleware],
6 | })
7 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/modules/lingui/i18n.ts:
--------------------------------------------------------------------------------
1 | import { i18n } from "@lingui/core"
2 |
3 | export const locales = {
4 | en: "English",
5 | fr: "French",
6 | }
7 |
8 | export const isLocaleValid = (locale: string) =>
9 | Object.keys(locales).includes(locale)
10 |
11 | export const defaultLocale = "en"
12 |
13 | /**
14 | * We do a dynamic import of just the catalog that we need
15 | * @param locale any locale string
16 | */
17 | export async function dynamicActivate(locale: string) {
18 | const { messages } = await import(`../../locales/${locale}/messages.po`)
19 | i18n.load(locale, messages)
20 | i18n.activate(locale)
21 | }
22 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/_pathlessLayout.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import { Outlet, createFileRoute } from "@tanstack/react-router"
3 |
4 | export const Route = createFileRoute("/_pathlessLayout")({
5 | component: LayoutComponent,
6 | })
7 |
8 | function LayoutComponent() {
9 | return (
10 |
11 |
12 | I'm a layout
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/_pathlessLayout/_nested-layout/route-a.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import { createFileRoute } from "@tanstack/react-router"
3 |
4 | export const Route = createFileRoute("/_pathlessLayout/_nested-layout/route-a")(
5 | {
6 | component: LayoutAComponent,
7 | }
8 | )
9 |
10 | function LayoutAComponent() {
11 | return (
12 |
13 | I'm A!
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/_pathlessLayout/_nested-layout/route-b.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import { createFileRoute } from "@tanstack/react-router"
3 |
4 | export const Route = createFileRoute("/_pathlessLayout/_nested-layout/route-b")(
5 | {
6 | component: LayoutBComponent,
7 | }
8 | )
9 |
10 | function LayoutBComponent() {
11 | return (
12 |
13 | I'm B!
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/api/users.$id.ts:
--------------------------------------------------------------------------------
1 | import { json } from "@tanstack/react-start"
2 | import { createAPIFileRoute } from "@tanstack/react-start/api"
3 | import axios from "redaxios"
4 | import type { User } from "../../utils/users"
5 | import { i18n } from "@lingui/core"
6 |
7 | export const APIRoute = createAPIFileRoute("/api/users/$id")({
8 | GET: async ({ request, params }) => {
9 | console.info(`Fetching users by id=${params.id}... @`, request.url)
10 | try {
11 | const res = await axios.get(
12 | "https://jsonplaceholder.typicode.com/users/" + params.id
13 | )
14 |
15 | return json({
16 | id: res.data.id,
17 | name: res.data.name,
18 | email: res.data.email,
19 | })
20 | } catch (e) {
21 | console.error(e)
22 | return json({ error: i18n._("User not found") }, { status: 404 })
23 | }
24 | },
25 | })
26 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/api/users.ts:
--------------------------------------------------------------------------------
1 | import { json } from "@tanstack/react-start"
2 | import { createAPIFileRoute } from "@tanstack/react-start/api"
3 | import axios from "redaxios"
4 | import type { User } from "../../utils/users"
5 |
6 | export const APIRoute = createAPIFileRoute("/api/users")({
7 | GET: async ({ request }) => {
8 | console.info("Fetching users... @", request.url)
9 | const res = await axios.get>(
10 | "https://jsonplaceholder.typicode.com/users"
11 | )
12 |
13 | const list = res.data.slice(0, 10)
14 |
15 | return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email })))
16 | },
17 | })
18 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/index.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import { createFileRoute } from "@tanstack/react-router"
3 |
4 | export const Route = createFileRoute("/")({
5 | component: Home,
6 | })
7 |
8 | function Home() {
9 | return (
10 |
11 |
12 | Welcome Home!!!
13 |
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/posts.index.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import { createFileRoute } from "@tanstack/react-router"
3 |
4 | export const Route = createFileRoute("/posts/")({
5 | component: PostsIndexComponent,
6 | })
7 |
8 | function PostsIndexComponent() {
9 | return (
10 |
11 | Select a post.
12 |
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/redirect.tsx:
--------------------------------------------------------------------------------
1 | import { createFileRoute, redirect } from "@tanstack/react-router"
2 |
3 | export const Route = createFileRoute("/redirect")({
4 | beforeLoad: async () => {
5 | throw redirect({
6 | to: "/posts",
7 | })
8 | },
9 | })
10 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/routes/users.index.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import { createFileRoute } from "@tanstack/react-router"
3 |
4 | export const Route = createFileRoute("/users/")({
5 | component: UsersIndexComponent,
6 | })
7 |
8 | function UsersIndexComponent() {
9 | return (
10 |
11 | Select a user.
12 |
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/ssr.tsx:
--------------------------------------------------------------------------------
1 | ///
2 | import { i18n } from "@lingui/core"
3 | import {
4 | createStartHandler,
5 | defaultStreamHandler,
6 | defineEventHandler,
7 | } from "@tanstack/react-start/server"
8 | import { getRouterManifest } from "@tanstack/react-start/router-manifest"
9 |
10 | import { createRouter } from "./router"
11 | import { setupLocaleFromRequest } from "./modules/lingui/i18n.server"
12 |
13 | export default defineEventHandler(async (event) => {
14 | await setupLocaleFromRequest()
15 |
16 | return createStartHandler({
17 | createRouter: () => {
18 | return createRouter({ i18n })
19 | },
20 | getRouterManifest,
21 | })(defaultStreamHandler)(event)
22 | })
23 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/styles/app.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | html {
7 | color-scheme: light dark;
8 | }
9 |
10 | * {
11 | @apply border-gray-200 dark:border-gray-800;
12 | }
13 |
14 | html,
15 | body {
16 | @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200;
17 | }
18 |
19 | .using-mouse * {
20 | outline: none !important;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/tanstack-start/src/utils/users.tsx:
--------------------------------------------------------------------------------
1 | export type User = {
2 | id: number
3 | name: string
4 | email: string
5 | }
6 |
7 | export const DEPLOY_URL = "http://localhost:3000"
8 |
--------------------------------------------------------------------------------
/examples/tanstack-start/tailwind.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ['./src/**/*.{js,jsx,ts,tsx}'],
4 | }
5 |
--------------------------------------------------------------------------------
/examples/tanstack-start/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["**/*.ts", "**/*.tsx"],
3 | "compilerOptions": {
4 | "strict": true,
5 | "esModuleInterop": true,
6 | "jsx": "react-jsx",
7 | "module": "ESNext",
8 | "moduleResolution": "Bundler",
9 | "lib": ["DOM", "DOM.Iterable", "ES2022"],
10 | "isolatedModules": true,
11 | "resolveJsonModule": true,
12 | "skipLibCheck": true,
13 | "target": "ES2022",
14 | "allowJs": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "baseUrl": ".",
17 | "paths": {
18 | "~/*": ["./src/*"]
19 | },
20 | "noEmit": true
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 |
27 | .pnp.*
28 | .yarn/*
29 | !.yarn/patches
30 | !.yarn/plugins
31 | !.yarn/releases
32 | !.yarn/sdks
33 | !.yarn/versions
34 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/lingui.config.ts:
--------------------------------------------------------------------------------
1 | import type { LinguiConfig } from "@lingui/conf"
2 |
3 | const config: LinguiConfig = {
4 | locales: ["en", "pl"],
5 | catalogs: [
6 | {
7 | path: "src/locales/{locale}",
8 | include: ["src"],
9 | },
10 | ],
11 | }
12 |
13 | export default config
14 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-project",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "messages:extract": "lingui extract",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@lingui/core": "^5.0.0-next.3",
14 | "@lingui/react": "^5.0.0-next.3",
15 | "react": "^18.2.0",
16 | "react-dom": "^18.2.0"
17 | },
18 | "devDependencies": {
19 | "@lingui/babel-plugin-lingui-macro": "5.0.0-next.3",
20 | "@lingui/cli": "^5.0.0-next.3",
21 | "@lingui/vite-plugin": "^5.0.0-next.3",
22 | "@types/react": "^18.0.28",
23 | "@types/react-dom": "^18.0.11",
24 | "@vitejs/plugin-react": "^4.3.2",
25 | "typescript": "^4.9.3",
26 | "vite": "^5.4.9"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import { i18n } from "@lingui/core"
2 |
3 | /**
4 | * Load messages for requested locale and activate it.
5 | * This function isn't part of the LinguiJS library because there are
6 | * many ways how to load messages — from REST API, from file, from cache, etc.
7 | */
8 | export async function loadCatalog(locale: string) {
9 | const catalog = await import(`./locales/${locale}.po`)
10 | i18n.loadAndActivate({ locale, messages: catalog.messages })
11 | }
12 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/examples/vite-project-react-babel/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite"
2 | import react from "@vitejs/plugin-react"
3 | import { lingui } from "@lingui/vite-plugin"
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [
8 | react({
9 | babel: {
10 | plugins: ["@lingui/babel-plugin-lingui-macro"],
11 | },
12 | }),
13 | lingui(),
14 | ],
15 | })
16 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 |
27 | .pnp.*
28 | .yarn/*
29 | !.yarn/patches
30 | !.yarn/plugins
31 | !.yarn/releases
32 | !.yarn/sdks
33 | !.yarn/versions
34 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/lingui.config.ts:
--------------------------------------------------------------------------------
1 | import type { LinguiConfig } from "@lingui/conf"
2 |
3 | const config: LinguiConfig = {
4 | locales: ["en", "pl"],
5 | catalogs: [
6 | {
7 | path: "src/locales/{locale}",
8 | include: ["src"],
9 | },
10 | ],
11 | }
12 |
13 | export default config
14 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-project-react-swc",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "lingui:extract": "lingui extract",
10 | "preview": "vite preview"
11 | },
12 | "resolutions": {
13 | "@swc/core": "1.5.7"
14 | },
15 | "dependencies": {
16 | "@lingui/core": "^5.0.0-next.3",
17 | "@lingui/react": "^5.0.0-next.3",
18 | "react": "^18.2.0",
19 | "react-dom": "^18.2.0"
20 | },
21 | "devDependencies": {
22 | "@lingui/cli": "^5.0.0-next.3",
23 | "@lingui/swc-plugin": "5.0.0-next.2",
24 | "@lingui/vite-plugin": "^5.0.0-next.3",
25 | "@types/react": "^18.0.28",
26 | "@types/react-dom": "^18.0.11",
27 | "@vitejs/plugin-react-swc": "3.7.0",
28 | "typescript": "^4.9.3",
29 | "vite": "5.4.9"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import { i18n } from "@lingui/core"
2 |
3 | /**
4 | * Load messages for requested locale and activate it.
5 | * This function isn't part of the LinguiJS library because there are
6 | * many ways how to load messages — from REST API, from file, from cache, etc.
7 | */
8 | export async function loadCatalog(locale: string) {
9 | const { messages } = await import(`./locales/${locale}.po`)
10 | i18n.loadAndActivate({ locale, messages })
11 | }
12 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import ReactDOM from "react-dom/client"
3 | import App from "./App"
4 | import "./index.css"
5 | import { loadCatalog } from "./i18n"
6 |
7 | // load initial language, you can detect here a user language with your preferred method
8 | await loadCatalog("en")
9 |
10 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
11 |
12 |
13 |
14 | )
15 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/examples/vite-project-react-swc/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite"
2 | import react from "@vitejs/plugin-react-swc"
3 | import { lingui } from "@lingui/vite-plugin"
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [
8 | react({
9 | plugins: [["@lingui/swc-plugin", {}]],
10 | }),
11 | lingui(),
12 | ],
13 | })
14 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "5.3.2",
3 | "packages": ["packages/*"],
4 | "npmClient": "yarn",
5 | "command": {
6 | "version": {
7 | "message": "chore(release): published %s [skip ci]",
8 | "ignoreChanges": [
9 | "**/CHANGELOG.md",
10 | "**/examples/*",
11 | "**/node_modules/**",
12 | "**/package.json",
13 | "**/website/**",
14 | "**/*.md",
15 | "test/**"
16 | ]
17 | },
18 | "publish": {
19 | "allowBranch": ["main", "next"],
20 | "ignoreChanges": [
21 | "**/CHANGELOG.md",
22 | "**/examples/*",
23 | "**/node_modules/**",
24 | "**/package.json",
25 | "**/website/**",
26 | "**/*.md",
27 | "test/**"
28 | ]
29 | }
30 | },
31 | "$schema": "node_modules/lerna/schemas/lerna-schema.json"
32 | }
33 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/build.config.ts:
--------------------------------------------------------------------------------
1 | import { defineBuildConfig } from "unbuild"
2 |
3 | export default defineBuildConfig({
4 | externals: ["@babel/core", "@babel/types", "@babel/traverse"],
5 | })
6 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/test/fixtures/js-call-expression.js:
--------------------------------------------------------------------------------
1 | const msg = i18n._("Message")
2 |
3 | const withDescription = i18n._("Description", {}, { comment: "description" })
4 |
5 | const withId = i18n._("ID", {}, { message: "Message with id" })
6 |
7 | const withValues = i18n._("Values {param}", { param: param })
8 |
9 | const withContext = i18n._("Some id", {}, { context: "Context1" })
10 |
11 | // from message descriptor
12 | i18n._({
13 | id: "my.id",
14 | message: "My Id Message",
15 | comment: "My comment",
16 | })
17 |
18 | // support alias
19 | i18n.t("Aliased Message")
20 |
21 | // from message descriptor
22 | i18n.t({
23 | id: "my.id",
24 | message: "My Id Message",
25 | comment: "My comment",
26 | })
27 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/test/fixtures/js-message-descriptor.js:
--------------------------------------------------------------------------------
1 | const msg = /*i18n*/ { id: "Message" }
2 |
3 | const withDescription = /*i18n*/ { id: "Description", comment: "description" }
4 |
5 | const withId = /*i18n*/ { id: "ID", message: "Message with id" }
6 |
7 | const withValues = /*i18n*/ {
8 | id: "Values {param} {0} {name} {value}",
9 | values: {
10 | param: param,
11 | 0: user.getName(),
12 | ["name"]: "foo",
13 | // prettier-ignore
14 | value: user
15 | ? user.name
16 | : null,
17 | },
18 | }
19 | /**
20 | * With values passed as variable
21 | */
22 | const values = {}
23 | const withValues2 = /*i18n*/ { id: "Values {param} {0}", values }
24 |
25 | const withContext = /*i18n*/ { id: "Some id", context: "Context1" }
26 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/test/fixtures/jsx-with-macros.js:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import { t, plural } from "@lingui/core/macro"
3 | ;Hi, my name is {name}
4 | ;Some message
5 | ;Some other message
6 | ;Some message
7 | ;
8 | ;
14 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/test/fixtures/jsx-without-macros.js:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react"
2 |
3 | ;
4 |
5 | ;
6 | ;
7 | ;
8 | ;
9 | ;
10 | ;
11 | ;
12 |
13 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/test/fixtures/jsx-without-trans.js:
--------------------------------------------------------------------------------
1 | import { Plural } from "@lingui/react/macro"
2 | ;
3 | ;
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/test/fixtures/lingui.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locales: ["en", "cs"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/test/fixtures/without-lingui.js:
--------------------------------------------------------------------------------
1 | import { Select } from "awesome-form-lib"
2 | import { Trans } from "awesome-animation-lib"
3 |
4 | ;
5 | Displaced element
6 |
7 | ; {}} />
8 |
--------------------------------------------------------------------------------
/packages/babel-plugin-extract-messages/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "strictNullChecks": false,
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/src/ast.ts:
--------------------------------------------------------------------------------
1 | export * from "./icu"
2 | export * from "./messageDescriptorUtils"
3 | export { JsMacroName } from "./constants"
4 |
5 | export {
6 | isChoiceMethod,
7 | isLinguiIdentifier,
8 | isI18nMethod,
9 | isDefineMessage,
10 | tokenizeExpression,
11 | tokenizeChoiceComponent,
12 | tokenizeTemplateLiteral,
13 | tokenizeNode,
14 | processDescriptor,
15 | createMacroJsContext,
16 | type MacroJsContext,
17 | tokenizeArg,
18 | isArgDecorator,
19 | } from "./macroJsAst"
20 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const EXTRACT_MARK = "i18n"
2 |
3 | export enum MsgDescriptorPropKey {
4 | id = "id",
5 | message = "message",
6 | comment = "comment",
7 | values = "values",
8 | components = "components",
9 | context = "context",
10 | }
11 |
12 | export enum JsMacroName {
13 | t = "t",
14 | plural = "plural",
15 | select = "select",
16 | selectOrdinal = "selectOrdinal",
17 | msg = "msg",
18 | defineMessage = "defineMessage",
19 | arg = "arg",
20 | useLingui = "useLingui",
21 | ph = "ph",
22 | }
23 |
24 | export enum JsxMacroName {
25 | Trans = "Trans",
26 | Plural = "Plural",
27 | Select = "Select",
28 | SelectOrdinal = "SelectOrdinal",
29 | }
30 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/src/utils.ts:
--------------------------------------------------------------------------------
1 | export const makeCounter =
2 | (index = 0) =>
3 | () =>
4 | index++
5 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/__snapshots__/js-selectOrdinal.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`#1 1`] = `
4 | import { t, selectOrdinal } from "@lingui/core/macro";
5 | t\`This is my \${selectOrdinal(count, {
6 | one: "#st",
7 | two: \`#nd\`,
8 | other: "#rd",
9 | })} cat\`;
10 |
11 | ↓ ↓ ↓ ↓ ↓ ↓
12 |
13 | import { i18n as _i18n } from "@lingui/core";
14 | _i18n._(
15 | /*i18n*/
16 | {
17 | id: "dJXd3T",
18 | message:
19 | "This is my {count, selectordinal, one {#st} two {#nd} other {#rd}} cat",
20 | values: {
21 | count: count,
22 | },
23 | }
24 | );
25 |
26 | `;
27 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/fixtures/js-t-continuation-character.expected.js:
--------------------------------------------------------------------------------
1 | import { i18n as _i18n } from "@lingui/core"
2 | _i18n._(
3 | /*i18n*/
4 | {
5 | id: "LBYoFK",
6 | message: "Multiline with continuation",
7 | }
8 | )
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/fixtures/js-t-continuation-character.js:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | t`Multiline\
4 | with continuation`
5 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/fixtures/js-t-var/js-t-var.expected.js:
--------------------------------------------------------------------------------
1 | import { i18n as _i18n } from "@lingui/core"
2 | function scoped(foo) {
3 | if (foo) {
4 | const bar = 50
5 | _i18n._(
6 | /*i18n*/
7 | {
8 | id: "EvVtyn",
9 | message: "This is bar {bar}",
10 | values: {
11 | bar: bar,
12 | },
13 | }
14 | )
15 | } else {
16 | const bar = 10
17 | _i18n._(
18 | /*i18n*/
19 | {
20 | id: "e6QGtZ",
21 | message: "This is a different bar {bar}",
22 | values: {
23 | bar: bar,
24 | },
25 | }
26 | )
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/fixtures/js-t-var/js-t-var.js:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | function scoped(foo) {
4 | if (foo) {
5 | const bar = 50
6 | t`This is bar ${bar}`
7 | } else {
8 | const bar = 10
9 | t`This is a different bar ${bar}`
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/fixtures/jsx-keep-forced-newlines.expected.js:
--------------------------------------------------------------------------------
1 | import { Trans as _Trans } from "@lingui/react"
2 | ;<_Trans
3 | {
4 | /*i18n*/
5 | ...{
6 | id: "9xE5pD",
7 | message: "Keep multiple\nforced\nnewlines!",
8 | }
9 | }
10 | />
11 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/fixtures/jsx-keep-forced-newlines.js:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | ;
3 | Keep multiple{"\n"}
4 | forced{"\n"}
5 | newlines!
6 |
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/js-selectOrdinal.test.ts:
--------------------------------------------------------------------------------
1 | import { macroTester } from "./macroTester"
2 | describe.skip("", () => {})
3 |
4 | macroTester({
5 | cases: [
6 | {
7 | code: `
8 | import { t, selectOrdinal } from '@lingui/core/macro'
9 | t\`This is my \${selectOrdinal(count, {
10 | one: "#st",
11 | "two": \`#nd\`,
12 | other: ("#rd")
13 | })} cat\`
14 | `,
15 | },
16 | ],
17 | })
18 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/test/lingui.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locales: ["en"],
3 | }
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-lingui-macro/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "strictNullChecks": false,
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/cli/.gitignore:
--------------------------------------------------------------------------------
1 | locale/
2 |
--------------------------------------------------------------------------------
/packages/cli/api.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/api"
2 |
--------------------------------------------------------------------------------
/packages/cli/src/api/catalog/getFallbackListForLocale.ts:
--------------------------------------------------------------------------------
1 | import { FallbackLocales } from "@lingui/conf"
2 |
3 | export function getFallbackListForLocale(
4 | fallbackLocales: FallbackLocales,
5 | locale: string
6 | ): string[] {
7 | const fL: string[] = []
8 |
9 | if (fallbackLocales?.[locale]) {
10 | const mapping = fallbackLocales?.[locale]
11 | Array.isArray(mapping) ? fL.push(...mapping) : fL.push(mapping)
12 | }
13 |
14 | if (fallbackLocales?.default && locale !== fallbackLocales?.default) {
15 | fL.push(fallbackLocales?.default)
16 | }
17 |
18 | return fL
19 | }
20 |
--------------------------------------------------------------------------------
/packages/cli/src/api/extractors/typescript.ts:
--------------------------------------------------------------------------------
1 | import { ExtractorType } from "@lingui/conf"
2 |
3 | const extractor: ExtractorType = {
4 | match(filename) {
5 | throw new Error(
6 | "Typescript extractor was removed. " +
7 | "Lingui CLI can parse typescript out of the box. " +
8 | "Please remove it from your lingui.config.js"
9 | )
10 | },
11 |
12 | extract(): Promise | void {},
13 | }
14 |
15 | export default extractor
16 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/.linguirc:
--------------------------------------------------------------------------------
1 | {
2 | "locales": ["en", "cs"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-inline-sourcemaps/componentB.jsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | ;Some message
3 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQuanN4Iiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5wdXQudHN4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFJckMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxZQUFZLEVBQUUsS0FBSyxDQUFDLENBQUEifQ==
4 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-invalid/invalid.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const syntax-error
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-invalid/valid.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._("Component B")
2 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-syntax-flow/flow-syntax.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | function truthy(a: ?string, b: ?string): boolean %checks {
3 | return a != null && b != null;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-syntax-flow/ts-syntax.ts:
--------------------------------------------------------------------------------
1 | function foo(bar?: string): string {
2 | return bar;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-typescript-jsx/jsx-in-js.js:
--------------------------------------------------------------------------------
1 | // jsx syntax in files without explicit jsx extension
2 | const jsx = Hello!
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-typescript-jsx/jsx-syntax.jsx:
--------------------------------------------------------------------------------
1 | // check parsing different syntax proposals
2 |
3 | const jsx = Hello!
4 |
5 | @Decorator()
6 | export class TestDecorator {
7 | @Decorator()
8 | prop
9 |
10 | @Decorator()
11 | method() {}
12 | }
13 |
14 | export
15 | @Decorator()
16 | class TestDecoratorAfterExport {}
17 |
18 | class A {
19 | // classProperties
20 | b = 1
21 |
22 | // classPrivateProperties
23 | #b = 1
24 | }
25 |
26 | // dynamicImport
27 | import("./guy").then(a)
28 |
29 | // exportNamespaceFrom
30 | export * as ns from "mod"
31 |
32 | // nullishCoalescingOperator
33 | const a = a ?? b
34 |
35 | // objectRestSpread
36 | const b = { b, ...c }
37 |
38 | // optionalChaining
39 | const c = a?.b
40 |
41 | // topLevelAwait
42 | await promise
43 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-typescript-jsx/macro.tsx:
--------------------------------------------------------------------------------
1 | import { t, defineMessage, plural } from "@lingui/core/macro"
2 | import { Trans } from "@lingui/react/macro"
3 |
4 | // JS Macro usages
5 | const msg = t`Message`
6 |
7 | const withDescription = defineMessage({
8 | message: "Description",
9 | comment: "description",
10 | })
11 |
12 | const withTId = t({
13 | id: "ID Some",
14 | message: "Message with id some",
15 | })
16 |
17 | // JSX Macro usages
18 | ;Hi, my name is {name}
19 | ;Some message
20 | ;
21 | ;
27 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-experimental-decorators.tsx:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | @Decorator()
4 | export class TestDecorator {
5 | // supports typescript legacy decorator on parameters
6 | constructor(@Decorator() param) {}
7 |
8 | @Decorator()
9 | prop
10 |
11 | @Decorator()
12 | method() {}
13 | }
14 |
15 | t`Message`
16 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-syntax.tsx:
--------------------------------------------------------------------------------
1 | const jsx = Hello!
2 |
3 | // Typescript syntax
4 | function foo(bar: string): string {
5 | return bar
6 | }
7 |
8 | const test1: string = ""
9 |
10 | // check parsing different syntax proposals
11 | @Decorator()
12 | export class TestDecorator {
13 | @Decorator()
14 | prop
15 |
16 | @Decorator()
17 | method() {}
18 | }
19 |
20 | // optional chaining
21 | const test = foo?.bar?.baz
22 |
23 | class A {
24 | // classProperties
25 | b = 1
26 |
27 | // classPrivateProperties
28 | #b = 1
29 | }
30 |
31 | // dynamicImport
32 | import("./guy").then(a)
33 |
34 | // exportNamespaceFrom
35 | export * as ns from "mod"
36 |
37 | // nullishCoalescingOperator
38 | const a = a ?? b
39 |
40 | // objectRestSpread
41 | const b = { b, ...c }
42 |
43 | // optionalChaining
44 | const c = a?.b
45 |
46 | // topLevelAwait
47 | await promise
48 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect/$componentE/index.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._("Component E")
2 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect/(componentC)/index.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._("Component C")
2 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect/[componentD]/index.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._("Component D")
2 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect/componentA/componentA.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._("Component A");
2 | /*i18n*/ i18n._("Hello World", {}, {comment: "Comment A"});
3 | /*i18n*/ i18n._("Hello World", {}, {comment: "Comment A again"});
4 | /*i18n*/ i18n._('custom.id', {}, { message: 'Message with id' });
5 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect/componentA/index.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._("Hello World", {}, {comment: "Hello comment"})
2 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/collect/componentB.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._("Component B")
2 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/duplicate-id.js:
--------------------------------------------------------------------------------
1 | /*i18n*/ i18n._('custom.id', {}, { message: 'Message with id' });
2 | /*i18n*/ i18n._('custom.id', {}, { message: 'Diffrent message' });
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/locales/existing/cs.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Ahoj Brno"
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/locales/existing/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Ahoj Brno"
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/pot-template/messages.pot:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr ""
3 |
4 | msgid "Test String"
5 | msgstr ""
6 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/pot-template/pl.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Cześć świat"
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/readAll/cs/messages.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Ahoj Brno"
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/fixtures/readAll/en/messages.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
--------------------------------------------------------------------------------
/packages/cli/src/api/index.ts:
--------------------------------------------------------------------------------
1 | export { getFormat } from "./formats"
2 | export { getCatalogForFile, getCatalogs } from "./catalog/getCatalogs"
3 |
4 | export { createCompiledCatalog } from "./compile"
5 |
6 | export {
7 | default as extractor,
8 | extractFromFileWithBabel,
9 | } from "./extractors/babel"
10 | export { getCatalogDependentFiles } from "./catalog/getCatalogDependentFiles"
11 | export {
12 | createMissingErrorMessage,
13 | createCompilationErrorMessage,
14 | } from "./messages"
15 | export * from "./types"
16 |
--------------------------------------------------------------------------------
/packages/cli/src/api/rethrownError.ts:
--------------------------------------------------------------------------------
1 | export class RethrownError extends Error {
2 | public message: string
3 |
4 | constructor(message: string, originalError: Error) {
5 | super()
6 |
7 | this.message = message + " " + originalError.message
8 | this.stack = `Error: ${message} \nOriginal: ` + originalError.stack
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/cli/src/api/types.ts:
--------------------------------------------------------------------------------
1 | import type { CatalogType } from "@lingui/conf"
2 | export type {
3 | MessageOrigin,
4 | ExtractedMessageType,
5 | MessageType,
6 | ExtractedCatalogType,
7 | CatalogType,
8 | } from "@lingui/conf"
9 |
10 | export type AllCatalogsType = {
11 | [locale: string]: CatalogType
12 | }
13 |
--------------------------------------------------------------------------------
/packages/cli/src/extract-experimental/constants.ts:
--------------------------------------------------------------------------------
1 | export const ENTRY_NAME_PH = "{entryName}"
2 | export const DEFAULT_TEMPLATE_NAME = "messages"
3 |
--------------------------------------------------------------------------------
/packages/cli/src/extract-experimental/getEntryPoints.ts:
--------------------------------------------------------------------------------
1 | import { globSync } from "glob"
2 |
3 | export function getEntryPoints(entries: string[]) {
4 | return globSync(entries, { mark: true })
5 | }
6 |
--------------------------------------------------------------------------------
/packages/cli/src/extract-experimental/resolveCatalogPath.ts:
--------------------------------------------------------------------------------
1 | import nodepath from "path"
2 | import { replacePlaceholders } from "../api/utils"
3 |
4 | export function resolveCatalogPath(
5 | configOutput: string,
6 | entryPath: string,
7 | rootDir: string,
8 | locale: string,
9 | extension: string
10 | ) {
11 | const entryName = getEntryName(entryPath)
12 | const entryDir = nodepath.relative(rootDir, nodepath.dirname(entryPath))
13 |
14 | return nodepath.normalize(
15 | replacePlaceholders(configOutput, {
16 | entryName,
17 | entryDir,
18 | locale,
19 | }) + extension
20 | )
21 | }
22 |
23 | export function getEntryName(entryPath: string) {
24 | const parsedPath = nodepath.parse(entryPath)
25 | return parsedPath.name.replace(parsedPath.ext, "")
26 | }
27 |
--------------------------------------------------------------------------------
/packages/cli/src/extract-experimental/resolveTemplatePath.ts:
--------------------------------------------------------------------------------
1 | import { resolveCatalogPath, getEntryName } from "./resolveCatalogPath"
2 | import { DEFAULT_TEMPLATE_NAME, ENTRY_NAME_PH } from "./constants"
3 |
4 | export function resolveTemplatePath(
5 | entryPoint: string,
6 | output: string,
7 | rootDir: string,
8 | catalogExtension: string
9 | ) {
10 | let templateName: string
11 |
12 | if (output.includes(ENTRY_NAME_PH)) {
13 | templateName = DEFAULT_TEMPLATE_NAME
14 | } else {
15 | templateName = getEntryName(entryPoint)
16 | }
17 |
18 | return resolveCatalogPath(
19 | output,
20 | entryPoint,
21 | rootDir,
22 | templateName,
23 | catalogExtension
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/packages/cli/src/index.ts:
--------------------------------------------------------------------------------
1 | export { defineConfig } from "@lingui/conf"
2 |
--------------------------------------------------------------------------------
/packages/cli/src/lingui.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { program } from "commander"
4 | import { readFileSync } from "node:fs"
5 | import path from "node:path"
6 |
7 | const packageJson = JSON.parse(
8 | readFileSync(path.resolve(__dirname, "../package.json"), "utf8")
9 | )
10 |
11 | program
12 | .version(packageJson.version)
13 | .command("extract [files...]", "Extracts messages from source files")
14 | .command(
15 | "extract-experimental",
16 | "Extracts messages from source files traversing dependency tree"
17 | )
18 | .command(
19 | "extract-template",
20 | "Extracts messages from source files to a .pot template"
21 | )
22 | .command("compile", "Compile message catalogs")
23 | .parse(process.argv)
24 |
--------------------------------------------------------------------------------
/packages/cli/test/.gitignore:
--------------------------------------------------------------------------------
1 | actual/
2 |
--------------------------------------------------------------------------------
/packages/cli/test/extract-partial-consistency/fixtures/file-a.ts:
--------------------------------------------------------------------------------
1 | import { i18n } from "@lingui/core"
2 | import { defineMessage, t } from "@lingui/macro"
3 |
4 | const msg = t`Hello world`
5 |
6 | const msg2 = t({
7 | message: "Hello world",
8 | context: "custom context",
9 | })
10 |
11 | const msg3 = null /* original translation commented to mark message obsolete *//*t({
12 | message: "This message has custom id",
13 | id: "custom.id",
14 | })*/
15 |
16 | const msgDescriptor = defineMessage({
17 | message: "Message in descriptor",
18 | })
19 |
20 | i18n._(msgDescriptor)
21 |
22 | i18n._("addToCart")
23 | i18n._({id: "addToCart", message: "Add To Cart with change ignored"})
--------------------------------------------------------------------------------
/packages/cli/test/extract-partial-consistency/fixtures/file-b.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/macro"
2 | import React from "react"
3 |
4 | export function MyComponent() {
5 | return (
6 | Hello this is JSX Translation
7 | )
8 | }
9 |
10 | export function MyComponent2() {
11 | return Hello this is JSX Translation
12 | }
13 |
14 | export function MyComponent3() {
15 | return This JSX element has custom id
16 | }
17 |
--------------------------------------------------------------------------------
/packages/cli/test/extract-po-format/fixtures/file-a.ts:
--------------------------------------------------------------------------------
1 | import { defineMessage, t } from "@lingui/core/macro"
2 | import { i18n } from "@lingui/core"
3 |
4 | const msg = t`Hello world`
5 |
6 | const msg2 = t({
7 | message: "Hello world",
8 | context: "custom context",
9 | })
10 |
11 | const msg3 = t({
12 | message: "This message has custom id",
13 | id: "custom.id",
14 | })
15 |
16 | const msgDescriptor = defineMessage({
17 | message: "Message in descriptor",
18 | })
19 |
20 | i18n._(msgDescriptor)
21 |
22 | i18n._("addToCart")
23 | i18n._({id: "addToCart", message: "Add To Cart"})
24 |
--------------------------------------------------------------------------------
/packages/cli/test/extract-po-format/fixtures/file-b.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import React from "react"
3 |
4 | export function MyComponent() {
5 | return (
6 | Hello this is JSX Translation
7 | )
8 | }
9 |
10 | export function MyComponent2() {
11 | return Hello this is JSX Translation
12 | }
13 |
14 | export function MyComponent3() {
15 | return This JSX element has custom id
16 | }
17 |
--------------------------------------------------------------------------------
/packages/cli/test/extract-po-format/fixtures/placeholders.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | t`Hello ${user.name}`
4 | t`Hello ${author.name}`
5 | t`Hello ${moderator.name}`
6 |
7 | t`Hello ${userName} ${user.name} ${
8 | // prettier-ignore
9 | user
10 | ? user.name
11 | : null
12 | }`
13 |
--------------------------------------------------------------------------------
/packages/cli/test/extract-template-po-format/fixtures/file-a.ts:
--------------------------------------------------------------------------------
1 | import { defineMessage, t } from "@lingui/core/macro"
2 | import { i18n } from "@lingui/core"
3 |
4 | const msg = t`Hello world`
5 |
6 | const msg2 = t({
7 | message: "Hello world",
8 | context: "custom context",
9 | })
10 |
11 | const msg3 = t({
12 | message: "This message has custom id",
13 | id: "custom.id",
14 | })
15 |
16 | const msgDescriptor = defineMessage({
17 | message: "Message in descriptor",
18 | })
19 |
20 | i18n._(msgDescriptor)
21 |
--------------------------------------------------------------------------------
/packages/cli/test/extract-template-po-format/fixtures/file-b.tsx:
--------------------------------------------------------------------------------
1 | import { Trans } from "@lingui/react/macro"
2 | import React from "react"
3 |
4 | export function MyComponent() {
5 | return (
6 | Hello this is JSX Translation
7 | )
8 | }
9 |
10 | export function MyComponent2() {
11 | return Hello this is JSX Translation
12 | }
13 |
14 | export function MyComponent3() {
15 | return This JSX element has custom id
16 | }
17 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/existing/about.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 |
10 | #. js-lingui-id: LGGfGX
11 | #: fixtures/components/header.ts:3
12 | msgid "header message"
13 | msgstr "header message"
14 |
15 | #. js-lingui-id: u5PTM8
16 | #: fixtures/pages/about.page.ts:4
17 | msgid "about page message"
18 | msgstr "about page message"
19 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/existing/about.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 |
10 | #. js-lingui-id: LGGfGX
11 | #: fixtures/components/header.ts:3
12 | msgid "header message"
13 | msgstr "translation: header message"
14 |
15 | msgid "this should be marked as obsolete"
16 | msgstr ""
17 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/existing/index.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 |
10 | #. js-lingui-id: D+XV65
11 | #: fixtures/pages/index.page.ts:3
12 | msgid "index page message"
13 | msgstr "index page message"
14 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/existing/index.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 |
10 | #. js-lingui-id: D+XV65
11 | #: fixtures/pages/index.page.ts:3
12 | msgid "index page message"
13 | msgstr ""
14 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/expected/about.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/about.page.ts:4
17 | msgid "about page message"
18 | msgstr "about page message"
19 |
20 | #: fixtures/components/header.ts:3
21 | msgid "header message"
22 | msgstr "header message"
23 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/expected/about.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/about.page.ts:4
17 | msgid "about page message"
18 | msgstr ""
19 |
20 | #: fixtures/components/header.ts:3
21 | msgid "header message"
22 | msgstr "translation: header message"
23 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/expected/index.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/index.page.ts:3
17 | msgid "index page message"
18 | msgstr "index page message"
19 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/expected/index.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/index.page.ts:3
17 | msgid "index page message"
18 | msgstr ""
19 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/fixtures/components/header.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | export const msg = t`header message`
4 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/fixtures/pages/about.page.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 | import { msg as headerMsg } from "../components/header"
3 |
4 | const msg = t`about page message`
5 |
6 | console.log(msg, headerMsg)
7 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/fixtures/pages/index.page.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | const msg = t`index page message`
4 | console.log(msg)
5 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-clean/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "extractor-experimental-clean",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "@lingui/core": "*"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/expected/about.page.en.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"1TzdHc\":[\"aliased module message\"],\"LGGfGX\":[\"header message\"],\"8Pj7KC\":[\"JSX: about page message\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/expected/about.page.messages.pot:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 |
9 | #: fixtures/pages/about.page.tsx:16
10 | msgid "about page message"
11 | msgstr ""
12 |
13 | #: fixtures/components/aliased-module.ts:3
14 | msgid "aliased module message"
15 | msgstr ""
16 |
17 | #: fixtures/components/header.ts:3
18 | msgid "header message"
19 | msgstr ""
20 |
21 | #: fixtures/pages/about.page.tsx:19
22 | msgid "JSX: about page message"
23 | msgstr ""
24 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/expected/about.page.pl.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"1TzdHc\":[\"aliased module message\"],\"LGGfGX\":[\"header message\"],\"8Pj7KC\":[\"JSX: about page message\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/expected/index.page.en.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"D+XV65\":[\"index page message\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/expected/index.page.messages.pot:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 |
9 | #: fixtures/pages/index.page.ts:3
10 | msgid "index page message"
11 | msgstr ""
12 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/expected/index.page.pl.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"D+XV65\":[\"index page message\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/fixtures/components/aliased-module.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | export const msg = t`aliased module message`
4 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/fixtures/components/header.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | export const msg = t`header message`
4 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/fixtures/pages/about.page.tsx:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 | import { Trans } from "@lingui/react/macro"
3 | import { msg as headerMsg } from "../components/header"
4 |
5 | // this import should be externalized
6 | // because it's defined in package.json as deps
7 | import { bla } from "some-package"
8 | // resource imports should be externalized
9 | import styles from "./styles.css"
10 | // resource imports with query params should be externalized
11 | import styles2 from "./styles.css?inline"
12 |
13 | // should respect tsconfig path aliases
14 | import { msg as msg2 } from "@alias"
15 |
16 | const msg = t`about page message`
17 |
18 | export default function Page() {
19 | return JSX: about page message
20 | }
21 |
22 | console.log(msg, headerMsg, bla, styles, styles2, msg2)
23 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/fixtures/pages/index.page.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | const msg = t`index page message`
4 | console.log(msg)
5 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "extractor-experimental-template",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "@lingui/core": "*",
7 | "@lingui/react": "*",
8 | "some-package": "*"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental-template/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "baseUrl": "./",
6 | "paths": {
7 | "@alias": [
8 | "./fixtures/components/aliased-module.ts"
9 | ]
10 | }
11 | },
12 | "exclude": [
13 | "node_modules"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/existing/about.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 |
10 | #. js-lingui-id: LGGfGX
11 | #: fixtures/components/header.ts:3
12 | msgid "header message"
13 | msgstr "header message"
14 |
15 | #. js-lingui-id: u5PTM8
16 | #: fixtures/pages/about.page.ts:4
17 | msgid "about page message"
18 | msgstr "about page message"
19 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/existing/about.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 |
10 | #. js-lingui-id: LGGfGX
11 | #: fixtures/components/header.ts:3
12 | msgid "header message"
13 | msgstr "translation: header message"
14 |
15 | msgid "this should be marked as obsolete"
16 | msgstr ""
17 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/existing/index.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 |
10 | #. js-lingui-id: D+XV65
11 | #: fixtures/pages/index.page.ts:3
12 | msgid "index page message"
13 | msgstr "index page message"
14 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/existing/index.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 |
10 | #. js-lingui-id: D+XV65
11 | #: fixtures/pages/index.page.ts:3
12 | msgid "index page message"
13 | msgstr ""
14 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/about.page.en.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"VmkjGB\":[\"Green\"],\"LGGfGX\":[\"header message\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/about.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/about.page.ts:5
17 | msgid "about page message"
18 | msgstr "about page message"
19 |
20 | #: fixtures/constants/green.ts:3
21 | msgid "Green"
22 | msgstr "Green"
23 |
24 | #: fixtures/components/header.ts:3
25 | msgid "header message"
26 | msgstr "header message"
27 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/about.page.pl.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"u5PTM8\":[\"about page message\"],\"VmkjGB\":[\"Green\"],\"LGGfGX\":[\"translation: header message\"],\"nPi9F1\":[\"this should be marked as obsolete\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/about.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/about.page.ts:5
17 | msgid "about page message"
18 | msgstr ""
19 |
20 | #: fixtures/constants/green.ts:3
21 | msgid "Green"
22 | msgstr ""
23 |
24 | #: fixtures/components/header.ts:3
25 | msgid "header message"
26 | msgstr "translation: header message"
27 |
28 | #~ msgid "this should be marked as obsolete"
29 | #~ msgstr ""
30 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/index.page.en.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"D+XV65\":[\"index page message\"],\"wRTiSD\":[\"Red\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/index.page.en.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/index.page.ts:4
17 | msgid "index page message"
18 | msgstr "index page message"
19 |
20 | #: fixtures/constants/red.ts:3
21 | msgid "Red"
22 | msgstr "Red"
23 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/index.page.pl.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable*/module.exports={messages:JSON.parse("{\"D+XV65\":[\"index page message\"],\"wRTiSD\":[\"Red\"]}")};
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/expected/index.page.pl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-03-15 10:00+0000\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: pl\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: fixtures/pages/index.page.ts:4
17 | msgid "index page message"
18 | msgstr ""
19 |
20 | #: fixtures/constants/red.ts:3
21 | msgid "Red"
22 | msgstr ""
23 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/fixtures/components/header.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | export const msg = t`header message`
4 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/fixtures/constants/green.ts:
--------------------------------------------------------------------------------
1 | import { msg } from "@lingui/core/macro"
2 |
3 | export const GREEN = msg`Green`
4 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/fixtures/constants/index.ts:
--------------------------------------------------------------------------------
1 | // test tree-shaking from barrel files
2 | export * from "./red"
3 | export * from "./green"
4 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/fixtures/constants/red.ts:
--------------------------------------------------------------------------------
1 | import { msg } from "@lingui/core/macro"
2 |
3 | export const RED = msg`Red`
4 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/fixtures/pages/about.page.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 | import { msg as headerMsg } from "../components/header"
3 | import { GREEN } from "../constants"
4 |
5 | const msg = t`about page message`
6 |
7 | console.log(msg, headerMsg)
8 | console.log(GREEN)
9 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/fixtures/pages/index.page.ts:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 | import { RED } from "../constants"
3 |
4 | const msg: string = t`index page message`
5 | console.log(msg)
6 | console.log(RED)
7 |
8 | function test(input: string): void {
9 | console.log("Should support TS type annotation syntax")
10 | }
11 |
--------------------------------------------------------------------------------
/packages/cli/test/extractor-experimental/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "extractor-experimental",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "@lingui/core": "*"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/cli/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "strictNullChecks": false,
6 | "declaration": true,
7 | "paths": {},
8 | "noEmit": false,
9 | "outDir": "./dist",
10 | "rootDir": "./src",
11 | "skipLibCheck": true,
12 | "module": "NodeNext",
13 | },
14 | "include": ["./src"],
15 | "exclude": [
16 | "**/test/**",
17 | "src/tests.ts",
18 | "**/*.test.ts",
19 | "dist",
20 | "**/fixtures/**"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/packages/cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "strictNullChecks": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/conf/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "skipLibCheck": true
4 | },
5 | "paths": {}
6 | }
7 |
--------------------------------------------------------------------------------
/packages/conf/src/defineConfig.ts:
--------------------------------------------------------------------------------
1 | import { LinguiConfig } from "./types"
2 |
3 | /**
4 | * Type helper for lingui.config.ts, returns {@link LinguiConfig} object
5 | */
6 | export function defineConfig(config: LinguiConfig): LinguiConfig {
7 | return config
8 | }
9 |
--------------------------------------------------------------------------------
/packages/conf/src/fixtures/valid/.linguirc:
--------------------------------------------------------------------------------
1 | {
2 | "rootDir": ".",
3 | "locales": ["en-gb"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/conf/src/fixtures/valid/custom.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locales: ["cs", "sk"],
3 | }
4 |
--------------------------------------------------------------------------------
/packages/conf/src/fixtures/valid/custom.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | locales: ["pl"],
3 | }
4 |
--------------------------------------------------------------------------------
/packages/conf/src/index.ts:
--------------------------------------------------------------------------------
1 | export { makeConfig } from "./makeConfig"
2 | export { defineConfig } from "./defineConfig"
3 | export { getConfig } from "./getConfig"
4 | export * from "./types"
5 |
--------------------------------------------------------------------------------
/packages/conf/src/utils/pathJoinPosix.ts:
--------------------------------------------------------------------------------
1 | import path from "path"
2 |
3 | // Enforce posix path delimiters internally
4 | export const pathJoinPosix = (...values: string[]) =>
5 | path
6 | // normalize double slashes
7 | .join(...values)
8 | // convert platform specific path.sep to posix
9 | .split(path.sep)
10 | .join("/")
11 |
--------------------------------------------------------------------------------
/packages/conf/src/utils/replaceRootDir.test.ts:
--------------------------------------------------------------------------------
1 | import { replaceRootDir } from "./replaceRootDir"
2 |
3 | it("should replace ", () => {
4 | const config = replaceRootDir(
5 | {
6 | compileNamespace: "cjs",
7 | catalogs: [
8 | {
9 | path: "/",
10 | include: ["/src"],
11 | exclude: ["/ignored"],
12 | },
13 | ],
14 | },
15 | "/Root"
16 | )
17 |
18 | expect(config).toMatchObject({
19 | compileNamespace: "cjs",
20 | catalogs: [
21 | {
22 | path: "/",
23 | include: ["/Root/src"],
24 | exclude: ["/Root/ignored"],
25 | },
26 | ],
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/packages/conf/src/utils/replaceRootDir.ts:
--------------------------------------------------------------------------------
1 | import { LinguiConfig } from "../types"
2 |
3 | export function replaceRootDir>(
4 | config: T,
5 | rootDir: string
6 | ): T {
7 | return (function replaceDeep(value: any, rootDir: string): any {
8 | const replace = (s: string) => s.replace("", rootDir)
9 |
10 | if (value == null) {
11 | return value
12 | } else if (typeof value === "string") {
13 | return replace(value)
14 | } else if (Array.isArray(value)) {
15 | return value.map((item) => replaceDeep(item, rootDir))
16 | } else if (typeof value === "object") {
17 | Object.keys(value).forEach((key) => {
18 | const newKey = replaceDeep(key, rootDir)
19 | value[newKey] = replaceDeep(value[key], rootDir)
20 | if (key !== newKey) delete value[key]
21 | })
22 | }
23 |
24 | return value
25 | })(config, rootDir) as T
26 | }
27 |
--------------------------------------------------------------------------------
/packages/conf/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "ES2019",
5 | "sourceMap": true,
6 | "noEmit": false,
7 | "declaration": true,
8 | "outDir": "./build",
9 | "esModuleInterop": true,
10 | "resolveJsonModule": true,
11 | "skipLibCheck": true,
12 | "strict": true,
13 | "strictNullChecks": false
14 | },
15 | "files": [
16 | "./src/index.ts"
17 | ],
18 | "exclude": [
19 | "build",
20 | "node_modules"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/packages/core/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react",
4 | "esModuleInterop": true,
5 | "skipLibCheck": true
6 | },
7 | "paths": {}
8 | }
9 |
--------------------------------------------------------------------------------
/packages/core/macro/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "esModuleInterop": true,
4 | "skipLibCheck": true
5 | },
6 | "paths": {}
7 | }
8 |
--------------------------------------------------------------------------------
/packages/core/macro/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("@lingui/babel-plugin-lingui-macro/macro")
2 |
--------------------------------------------------------------------------------
/packages/core/macro/index.test.ts:
--------------------------------------------------------------------------------
1 | import macro from "@lingui/core/macro"
2 |
3 | describe("react-macro", () => {
4 | it("Should re-export Macro", () => {
5 | expect((macro as any).isBabelMacro).toBeTruthy()
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/packages/core/src/essentials.test.ts:
--------------------------------------------------------------------------------
1 | import { isString, isFunction } from "./essentials"
2 |
3 | describe("isString", function () {
4 | it("should check string", function () {
5 | expect(isString("Hello")).toBeTruthy()
6 | expect(isString(42)).toBeFalsy()
7 | expect(isString([42])).toBeFalsy()
8 | })
9 | })
10 |
11 | describe("isFunction", function () {
12 | it("should check function", function () {
13 | expect(isFunction(function () {})).toBeTruthy()
14 | expect(isFunction(() => {})).toBeTruthy()
15 | expect(isFunction("Nope")).toBeFalsy()
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/packages/core/src/essentials.ts:
--------------------------------------------------------------------------------
1 | export const isString = (s: unknown): s is string => typeof s === "string"
2 | // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
3 | export const isFunction = (f: unknown): f is Function => typeof f === "function"
4 |
--------------------------------------------------------------------------------
/packages/core/src/formats.test.ts:
--------------------------------------------------------------------------------
1 | import { number } from "./formats"
2 |
3 | describe("@lingui/core/formats", () => {
4 | describe("number", () => {
5 | it("should pass format options", () => {
6 | expect(number(["en"], 1000, { style: "currency", currency: "EUR" })).toBe(
7 | "€1,000.00"
8 | )
9 |
10 | expect(number(["en"], 1000, { maximumSignificantDigits: 3 })).toBe(
11 | "1,000"
12 | )
13 | })
14 |
15 | it("should respect passed locale(s)", () => {
16 | expect(number(["pl"], 1000, { style: "currency", currency: "EUR" })).toBe(
17 | "1000,00 €"
18 | )
19 |
20 | expect(
21 | number(["pl", "en-US"], 1000, { style: "currency", currency: "EUR" })
22 | ).toBe("1000,00 €")
23 | expect(
24 | number(["en-US", "pl"], 1000, { style: "currency", currency: "EUR" })
25 | ).toBe("€1,000.00")
26 | })
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/packages/core/src/index.ts:
--------------------------------------------------------------------------------
1 | export { setupI18n, I18n } from "./i18n"
2 |
3 | export type {
4 | AllMessages,
5 | MessageDescriptor,
6 | Messages,
7 | AllLocaleData,
8 | LocaleData,
9 | Locale,
10 | Locales,
11 | MessageOptions,
12 | } from "./i18n"
13 |
14 | // Default i18n object
15 | import { setupI18n } from "./i18n"
16 | export const i18n = setupI18n()
17 |
18 | import * as formats from "./formats"
19 | export { formats }
20 |
--------------------------------------------------------------------------------
/packages/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "noUncheckedIndexedAccess": true,
6 | "isolatedModules": true,
7 | "forceConsistentCasingInFileNames": true,
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/__snapshots__/fromUrl.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`fromUrl throws an error if parameter is not passed 1`] = `fromUrl parameter is required`;
4 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromCookie.test.ts:
--------------------------------------------------------------------------------
1 | import { fromCookie } from ".."
2 |
3 | describe("fromCookie detector", () => {
4 | it("should return a correct value from the cookie stored", () => {
5 | Object.defineProperty(window.document, "cookie", {
6 | writable: true,
7 | value: "CONSENT=YES+ES.es+V11; SEARCH_SAMESITE=CgQI3JAB",
8 | })
9 | expect(fromCookie("CONSENT")).toEqual("YES+ES.es+V11")
10 | expect(fromCookie("SEARCH_SAMESITE")).toEqual("CgQI3JAB")
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromCookie.ts:
--------------------------------------------------------------------------------
1 | import { LocaleString } from ".."
2 | import { getCookie } from "../utils/cookie-getter"
3 |
4 | export default function detectFromCookie(key: string): LocaleString {
5 | return getCookie(key)
6 | }
7 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromHtmlTag.test.ts:
--------------------------------------------------------------------------------
1 | import { fromHtmlTag } from ".."
2 | import { JSDOM } from "jsdom"
3 |
4 | describe("htmlTag detector", () => {
5 | it("should find a locale from a standard html5", () => {
6 | const dom = new JSDOM(
7 | `Hello world `
8 | )
9 | expect(fromHtmlTag("lang", dom.window.document)).toEqual("es")
10 | })
11 |
12 | it("should find a locale from a xml lang attribute", () => {
13 | const dom = new JSDOM(
14 | `Hello world`
15 | )
16 | expect(fromHtmlTag("xml:lang", dom.window.document)).toEqual("en")
17 | })
18 | })
19 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromHtmlTag.ts:
--------------------------------------------------------------------------------
1 | import { LocaleString } from ".."
2 |
3 | export default function detectHtmlTag(
4 | htmlTagIdentifier: string,
5 | document: Partial = globalThis.document
6 | ): LocaleString {
7 | if (htmlTagIdentifier) {
8 | return document.documentElement.getAttribute(htmlTagIdentifier)
9 | }
10 |
11 | return null
12 | }
13 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromNavigator.test.ts:
--------------------------------------------------------------------------------
1 | import { fromNavigator } from ".."
2 |
3 | describe("fromNavigator", () => {
4 | it("parses correctly navigator.language", () => {
5 | const mock: Partial = {
6 | language: "en_EN",
7 | }
8 | const locale = fromNavigator(mock)
9 | expect(locale).toEqual("en_EN")
10 | })
11 |
12 | it("on IE_11 navigator.language doesnt exist, goes to the fallback", () => {
13 | const mock: Partial = {
14 | userLanguage: "es_ES",
15 | }
16 | const locale = fromNavigator(mock)
17 | expect(locale).toEqual("es_ES")
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromNavigator.ts:
--------------------------------------------------------------------------------
1 | import { LocaleString } from ".."
2 |
3 | type IE11NavigatorLanguage = {
4 | userLanguage?: string
5 | }
6 |
7 | export default function detectFromNavigator(
8 | navigator: Partial = globalThis.navigator
9 | ): LocaleString {
10 | const result: LocaleString = navigator.language || navigator.userLanguage
11 | return result
12 | }
13 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromPath.test.ts:
--------------------------------------------------------------------------------
1 | import { fromPath } from "../"
2 |
3 | describe("fromPath detector", () => {
4 | it("should find a locale on the first index", () => {
5 | const mockedLocation: Partial = {
6 | pathname: "/fr/some/route",
7 | }
8 |
9 | expect(fromPath(0, mockedLocation)).toEqual("fr")
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromPath.ts:
--------------------------------------------------------------------------------
1 | import { LocaleString } from "../"
2 |
3 | export default function detectFromPath(
4 | localePathIndex: number,
5 | location: Partial = globalThis.location
6 | ): LocaleString {
7 | const locale: RegExpMatchArray = location.pathname.match(/\/([a-zA-Z-]*)/g)
8 | if (Array.isArray(locale)) {
9 | return locale[localePathIndex].replace("/", "")
10 | }
11 |
12 | return null
13 | }
14 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromStorage.test.ts:
--------------------------------------------------------------------------------
1 | import { fromStorage } from ".."
2 |
3 | describe("fromStorage detector", () => {
4 | it("should return a correct value from the local storage stored", () => {
5 | localStorage.setItem("lang", "es_ES")
6 | expect(fromStorage("lang")).toEqual("es_ES")
7 | localStorage.setItem("lang", null)
8 | expect(fromStorage("lang")).toEqual("null")
9 | })
10 |
11 | it("should return a correct value from the session storage if opts passed", () => {
12 | sessionStorage.setItem("lang", "en_EN")
13 | expect(fromStorage("lang", { useSessionStorage: true })).toEqual("en_EN")
14 | sessionStorage.setItem("lang", null)
15 | expect(fromStorage("lang", { useSessionStorage: true })).toEqual("null")
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromStorage.ts:
--------------------------------------------------------------------------------
1 | import { LocaleString } from ".."
2 |
3 | export default function detectFromStorage(
4 | key: string,
5 | options: { useSessionStorage: boolean } = { useSessionStorage: false }
6 | ): LocaleString {
7 | if (options.useSessionStorage) {
8 | return globalThis.sessionStorage.getItem(key)
9 | }
10 |
11 | return globalThis.localStorage.getItem(key)
12 | }
13 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromSubdomain.test.ts:
--------------------------------------------------------------------------------
1 | import { fromSubdomain } from "../"
2 |
3 | describe("fromSubdomain detector", () => {
4 | it("should find a locale on the first index", () => {
5 | const mockedLocation: Partial = {
6 | href: "https://es.url.com/some_path",
7 | }
8 |
9 | expect(fromSubdomain(0, mockedLocation)).toEqual("es")
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromSubdomain.ts:
--------------------------------------------------------------------------------
1 | import { LocaleString } from "../"
2 |
3 | export default function detectFromSubdomain(
4 | localeSubdomainIndex: number,
5 | location: Partial = globalThis.location
6 | ): LocaleString {
7 | const locale: RegExpMatchArray = location.href.match(
8 | /(?:http[s]*:\/\/)*(.*?)\.(?=[^/]*\..{2,5})/gi
9 | )
10 | if (Array.isArray(locale)) {
11 | return locale[localeSubdomainIndex]
12 | .replace("http://", "")
13 | .replace("https://", "")
14 | .replace(".", "")
15 | }
16 |
17 | return null
18 | }
19 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/detectors/fromUrl.ts:
--------------------------------------------------------------------------------
1 | import { parse } from "../utils/query-string"
2 | import { LocaleString } from ".."
3 |
4 | export default function detectFromUrl(
5 | parameter: string,
6 | location: Partial = globalThis.location
7 | ): LocaleString {
8 | if (!parameter) throw new Error("fromUrl parameter is required")
9 |
10 | const result: LocaleString = parse(location.search)[parameter] || null
11 | return result
12 | }
13 |
--------------------------------------------------------------------------------
/packages/detect-locale/src/utils/cookie-getter.test.ts:
--------------------------------------------------------------------------------
1 | import { getCookie } from "./cookie-getter"
2 |
3 | describe("getCookie", () => {
4 | it("should return a correct value from the cookie stored", () => {
5 | Object.defineProperty(window.document, "cookie", {
6 | writable: true,
7 | value: "CONSENT=YES+ES.es+V11; SEARCH_SAMESITE=CgQI3JAB",
8 | })
9 | expect(getCookie("CONSENT")).toEqual("YES+ES.es+V11")
10 | expect(getCookie("SEARCH_SAMESITE")).toEqual("CgQI3JAB")
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/packages/extractor-vue/src/fixtures/functional.vue:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/packages/extractor-vue/src/index.ts:
--------------------------------------------------------------------------------
1 | export { vueExtractor } from "./vue-extractor"
2 |
--------------------------------------------------------------------------------
/packages/format-csv/__typetests__/index.test-d.ts:
--------------------------------------------------------------------------------
1 | import { CatalogFormatter } from "@lingui/conf"
2 | import { formatter } from "@lingui/format-csv"
3 | import { expect } from "tstyche"
4 |
5 | expect(formatter()).type.toBeAssignableTo()
6 |
--------------------------------------------------------------------------------
/packages/format-csv/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "skipLibCheck": true,
7 | "esModuleInterop": true
8 | },
9 | "paths": {}
10 | }
11 |
--------------------------------------------------------------------------------
/packages/format-csv/src/fixtures/messages.csv:
--------------------------------------------------------------------------------
1 | static,Static message
2 | stringWithUnpairedDoubleQuote,"Camecho 9"" LCD Monitor HD TFT Color Screen, 2 Video Input/HDMI/VGA, Support Car Backup"
3 | veryLongString,"One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover it and seemed ready to slide off any moment. His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked. ""What's happened to me?"" he thought. It wasn't a dream. His room, a proper human"
--------------------------------------------------------------------------------
/packages/format-json/__typetests__/index.test-d.ts:
--------------------------------------------------------------------------------
1 | import { CatalogFormatter } from "@lingui/conf"
2 | import { formatter } from "@lingui/format-json"
3 | import { expect } from "tstyche"
4 |
5 | expect(formatter()).type.toBeAssignableTo()
6 | expect(
7 | formatter({ lineNumbers: true, origins: true })
8 | ).type.toBeAssignableTo()
9 |
--------------------------------------------------------------------------------
/packages/format-json/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "skipLibCheck": true,
7 | "esModuleInterop": true
8 | },
9 | "paths": {}
10 | }
11 |
--------------------------------------------------------------------------------
/packages/format-json/src/fixtures/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "static": "Static message",
3 | "veryLongString": "One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover it and seemed ready to slide off any moment. His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked. \"What's happened to me?\" he thought. It wasn't a dream. His room, a proper human"
4 | }
5 |
--------------------------------------------------------------------------------
/packages/format-po-gettext/__typetests__/index.test-d.ts:
--------------------------------------------------------------------------------
1 | import { CatalogFormatter } from "@lingui/conf"
2 | import { formatter } from "@lingui/format-po-gettext"
3 | import { expect } from "tstyche"
4 |
5 | expect(formatter()).type.toBeAssignableTo()
6 | expect(
7 | formatter({
8 | lineNumbers: true,
9 | origins: true,
10 | printLinguiId: true,
11 | disableSelectWarning: true,
12 | })
13 | ).type.toBeAssignableTo()
14 |
--------------------------------------------------------------------------------
/packages/format-po-gettext/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "skipLibCheck": true,
7 | "esModuleInterop": true
8 | },
9 | "paths": {}
10 | }
11 |
--------------------------------------------------------------------------------
/packages/format-po/__typetests__/index.test-d.ts:
--------------------------------------------------------------------------------
1 | import { CatalogFormatter } from "@lingui/conf"
2 | import { formatter } from "@lingui/format-po"
3 | import { expect } from "tstyche"
4 |
5 | expect(formatter()).type.toBeAssignableTo()
6 | expect(
7 | formatter({
8 | lineNumbers: true,
9 | origins: true,
10 | printLinguiId: true,
11 | })
12 | ).type.toBeAssignableTo()
13 |
--------------------------------------------------------------------------------
/packages/format-po/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "skipLibCheck": true,
7 | "esModuleInterop": true
8 | },
9 | "paths": {}
10 | }
11 |
--------------------------------------------------------------------------------
/packages/format-po/src/__snapshots__/utils.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`normalizePlaceholderValue Should normalize whitespaces 1`] = `user ? user.name : null`;
4 |
5 | exports[`normalizePlaceholderValue Should normalize whitespaces 2`] = `userName`;
6 |
--------------------------------------------------------------------------------
/packages/format-po/src/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { normalizePlaceholderValue } from "./utils"
2 |
3 | describe("normalizePlaceholderValue", () => {
4 | it.each([
5 | `user
6 | ? user.name
7 | : null`,
8 | "userName",
9 | ])("Should normalize whitespaces", (input) => {
10 | expect(normalizePlaceholderValue(input)).toMatchSnapshot()
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/packages/format-po/src/utils.ts:
--------------------------------------------------------------------------------
1 | export function normalizePlaceholderValue(text: string) {
2 | return text.replace(/\n/g, " ").replace(/\s{2,}/g, " ")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/jest-mocks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@lingui/jest-mocks",
4 | "version": "3.0.3",
5 | "description": "Mocks for Jest",
6 | "main": "index.js",
7 | "author": {
8 | "name": "Tomáš Ehrlich",
9 | "email": "tomas.ehrlich@gmail.com"
10 | },
11 | "license": "MIT",
12 | "keywords": [
13 | "jest",
14 | "testing",
15 | "mock"
16 | ],
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/lingui/js-lingui.git"
20 | },
21 | "bugs": {
22 | "url": "https://github.com/lingui/js-lingui/issues"
23 | },
24 | "engines": {
25 | "node": ">=20.0.0"
26 | },
27 | "files": [
28 | "LICENSE",
29 | "README.md",
30 | "index.js"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/packages/loader/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default } from "./webpackLoader"
2 |
--------------------------------------------------------------------------------
/packages/loader/test/__snapshots__/loader.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`lingui-loader should compile catalog in json format 1`] = `
4 | {
5 | key: [
6 | Message,
7 | ],
8 | key2: [
9 | Hello ,
10 | [
11 | name,
12 | ],
13 | ],
14 | }
15 | `;
16 |
17 | exports[`lingui-loader should compile catalog in po format 1`] = `
18 | {
19 | ED2Xk0: [
20 | String from template,
21 | ],
22 | mVmaLu: [
23 | My name is ,
24 | [
25 | name,
26 | ],
27 | ],
28 | mY42CM: [
29 | Hello World,
30 | ],
31 | }
32 | `;
33 |
34 | exports[`lingui-loader should compile catalog with relative path with no warnings 1`] = `
35 | {
36 | ED2Xk0: [
37 | String from template,
38 | ],
39 | mVmaLu: [
40 | My name is ,
41 | [
42 | name,
43 | ],
44 | ],
45 | mY42CM: [
46 | Hello World,
47 | ],
48 | }
49 | `;
50 |
--------------------------------------------------------------------------------
/packages/loader/test/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return import("./locale/en/messages.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-compile-errors/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return await import("./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-compile-errors/lingui.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | locales: ["en"],
5 | catalogs: [
6 | {
7 | path: "/locale/{locale}",
8 | },
9 | ],
10 | format: "po",
11 | })
12 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-compile-errors/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World {var"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name"
6 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-missing-pseudo/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return await import("./locale/pseudo.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-missing-pseudo/lingui.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | locales: ["pseudo"],
5 | pseudoLocale: "pseudo",
6 | catalogs: [
7 | {
8 | path: "/locale/{locale}",
9 | },
10 | ],
11 | format: "po",
12 | })
13 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-missing-pseudo/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr ""
6 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-missing-pseudo/locale/pseudo.po:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/packages/loader/test/fail-on-missing-pseudo/locale/pseudo.po
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-missing/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return await import("./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-missing/lingui.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | locales: ["en"],
5 | catalogs: [
6 | {
7 | path: "/locale/{locale}",
8 | },
9 | ],
10 | format: "po",
11 | })
12 |
--------------------------------------------------------------------------------
/packages/loader/test/fail-on-missing/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr ""
6 |
--------------------------------------------------------------------------------
/packages/loader/test/json-format/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return (await import("@lingui/loader!./locale/en.json")).default
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/json-format/lingui.config.ts:
--------------------------------------------------------------------------------
1 | import { formatter } from "@lingui/format-json"
2 |
3 | export default {
4 | locales: ["en"],
5 | catalogs: [
6 | {
7 | path: "/locale/{locale}",
8 | },
9 | ],
10 | fallbackLocales: {
11 | default: "en",
12 | },
13 | format: formatter({ style: "minimal" }),
14 | }
15 |
--------------------------------------------------------------------------------
/packages/loader/test/json-format/locale/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "key": "Message",
3 | "key2": "Hello {name}"
4 | }
5 |
--------------------------------------------------------------------------------
/packages/loader/test/not-known-catalog/.linguirc:
--------------------------------------------------------------------------------
1 | {
2 | "locales": ["en"],
3 | "catalogs": [{
4 | "path": "./other-path/{locale}"
5 | }],
6 | "fallbackLocales": {
7 | "default": "en"
8 | },
9 | "format": "po"
10 | }
11 |
--------------------------------------------------------------------------------
/packages/loader/test/not-known-catalog/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return import("@lingui/loader!./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/not-known-catalog/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name}"
6 |
--------------------------------------------------------------------------------
/packages/loader/test/po-format/.linguirc:
--------------------------------------------------------------------------------
1 | {
2 | "locales": ["en"],
3 | "catalogs": [{
4 | "path": "/locale/{locale}"
5 | }],
6 | "fallbackLocales": {
7 | "default": "en"
8 | },
9 | "format": "po"
10 | }
11 |
--------------------------------------------------------------------------------
/packages/loader/test/po-format/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return import("@lingui/loader!./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/po-format/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name}"
6 |
--------------------------------------------------------------------------------
/packages/loader/test/po-format/locale/messages.pot:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr ""
3 |
4 | msgid "My name is {name}"
5 | msgstr ""
6 |
7 | msgid "String from template"
8 | msgstr ""
9 |
--------------------------------------------------------------------------------
/packages/loader/test/relative-catalog-path/.linguirc:
--------------------------------------------------------------------------------
1 | {
2 | "locales": ["en"],
3 | "catalogs": [{
4 | "path": "./locale/{locale}"
5 | }],
6 | "fallbackLocales": {
7 | "default": "en"
8 | },
9 | "format": "po"
10 | }
11 |
--------------------------------------------------------------------------------
/packages/loader/test/relative-catalog-path/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return import("@lingui/loader!./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/loader/test/relative-catalog-path/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name}"
6 |
--------------------------------------------------------------------------------
/packages/loader/test/relative-catalog-path/locale/messages.pot:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr ""
3 |
4 | msgid "My name is {name}"
5 | msgstr ""
6 |
7 | msgid "String from template"
8 | msgstr ""
9 |
--------------------------------------------------------------------------------
/packages/macro/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("@lingui/babel-plugin-lingui-macro/macro")
2 |
--------------------------------------------------------------------------------
/packages/macro/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "lib": [
5 | "ES2019.Array"
6 | ],
7 | "strict": true,
8 | "strictNullChecks": false
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/message-utils/README.md:
--------------------------------------------------------------------------------
1 | [![License][badge-license]][license]
2 | [![Version][badge-version]][package]
3 | [![Downloads][badge-downloads]][package]
4 |
5 | # @lingui/message-utils
6 |
7 | > Internal package. You probably don't need to use it directly.
8 |
9 | `@lingui/message-utils` is part of [LinguiJS][linguijs]. See the [documentation][documentation] for all information, tutorials and examples.
10 |
11 | ## License
12 |
13 | [MIT][license]
14 |
15 | [license]: https://github.com/lingui/js-lingui/blob/main/LICENSE
16 | [linguijs]: https://github.com/lingui/js-lingui
17 | [documentation]: https://lingui.dev
18 | [package]: https://www.npmjs.com/package/@lingui/message-utils
19 | [badge-downloads]: https://img.shields.io/npm/dw/@lingui/message-utils.svg
20 | [badge-version]: https://img.shields.io/npm/v/@lingui/message-utils.svg
21 | [badge-license]: https://img.shields.io/npm/l/@lingui/message-utils.svg
22 |
--------------------------------------------------------------------------------
/packages/message-utils/build.config.ts:
--------------------------------------------------------------------------------
1 | import { defineBuildConfig } from "unbuild"
2 |
3 | export default defineBuildConfig({
4 | // we want to inline @messageformat/date-skeleton package, because it's
5 | // esm only and will not work properly from ours cjs packages.
6 | // need to delete this as well as inlining after switching to the ESM
7 | failOnWarn: false,
8 | })
9 |
--------------------------------------------------------------------------------
/packages/message-utils/compileMessage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this file is a workaround for older runtimes
3 | * such as React Native or Jest 27 which is not
4 | * support package.json exports field
5 | **/
6 | module.exports = require("./dist/compileMessage.cjs")
7 |
--------------------------------------------------------------------------------
/packages/message-utils/generateMessageId.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this file is a workaround for older runtimes
3 | * such as React Native or Jest 27 which is not
4 | * support package.json exports field
5 | **/
6 | module.exports = require("./dist/generateMessageId.cjs")
7 |
--------------------------------------------------------------------------------
/packages/message-utils/src/generateMessageId.ts:
--------------------------------------------------------------------------------
1 | import { sha256 } from "js-sha256"
2 |
3 | const UNIT_SEPARATOR = "\u001F"
4 |
5 | export function generateMessageId(msg: string, context = "") {
6 | return hexToBase64(sha256(msg + UNIT_SEPARATOR + (context || ""))).slice(0, 6)
7 | }
8 |
9 | function hexToBase64(hexStr: string) {
10 | let base64 = ""
11 | for (let i = 0; i < hexStr.length; i++) {
12 | base64 += !((i - 1) & 1)
13 | ? String.fromCharCode(parseInt(hexStr.substring(i - 1, i + 1), 16))
14 | : ""
15 | }
16 | return btoa(base64)
17 | }
18 |
--------------------------------------------------------------------------------
/packages/message-utils/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "lib": [
5 | "ES2019.Array"
6 | ],
7 | "strict": true,
8 | "strictNullChecks": false
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/metro-transformer/src/expo/index.ts:
--------------------------------------------------------------------------------
1 | import { createLinguiMetroTransformer } from "../metroTransformer"
2 |
3 | // @ts-expect-error typings are not published
4 | import expoTransformer from "@expo/metro-config/babel-transformer"
5 |
6 | export const transform = createLinguiMetroTransformer(expoTransformer)
7 |
--------------------------------------------------------------------------------
/packages/metro-transformer/src/react-native/index.ts:
--------------------------------------------------------------------------------
1 | import { createLinguiMetroTransformer } from "../metroTransformer"
2 |
3 | // @ts-expect-error typings are not published
4 | import reactNativeTransformer from "@react-native/metro-babel-transformer"
5 |
6 | export const transform = createLinguiMetroTransformer(reactNativeTransformer)
7 |
--------------------------------------------------------------------------------
/packages/metro-transformer/src/types.ts:
--------------------------------------------------------------------------------
1 | // taken and redacted (removed unnecessary parts) from
2 | // https://github.com/facebook/metro/blob/main/packages/metro-babel-transformer/types/index.d.ts
3 |
4 | export type BabelTransformerArgs = {
5 | readonly filename: string
6 | readonly options: unknown // a more precise type would be BabelTransformerOptions, but we don't care about its shape
7 | readonly plugins?: unknown
8 | readonly src: string
9 | }
10 |
11 | export type BabelTransformer = {
12 | transform: (args: BabelTransformerArgs) => Promise<{
13 | ast: unknown
14 | metadata: unknown
15 | }>
16 | getCacheKey?: () => string
17 | }
18 |
--------------------------------------------------------------------------------
/packages/metro-transformer/test/__fixtures__/test-project/lingui.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locales: ["en", "cs"],
3 | sourceLocale: "en",
4 | catalogs: [
5 | {
6 | path: "locales/{locale}/messages",
7 | include: ["src"],
8 | },
9 | ],
10 | fallbackLocales: {
11 | cs: "en",
12 | },
13 | format: "po",
14 | }
15 |
--------------------------------------------------------------------------------
/packages/metro-transformer/test/__fixtures__/test-project/locales/cs/messages.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-04-27 00:37+0200\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=UTF-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: cs\n"
9 | "Project-Id-Version: linguidemo\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: 2023-04-28 17:32\n"
12 | "Last-Translator: \n"
13 | "Language-Team: Czech\n"
14 | "Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n"
15 | "X-Crowdin-Project: linguidemo\n"
16 | "X-Crowdin-Project-ID: 573605\n"
17 | "X-Crowdin-Language: cs\n"
18 | "X-Crowdin-File: messages.po\n"
19 | "X-Crowdin-File-ID: 25\n"
20 |
21 | #: src/MainScreen.tsx:76
22 | msgid "Add a message to your inbox"
23 | msgstr "Přidat zprávu do doručené pošty"
24 |
25 | #: src/MainScreen.tsx:23
26 | msgid "Cancel"
27 | msgstr ""
28 |
--------------------------------------------------------------------------------
/packages/metro-transformer/test/__fixtures__/test-project/locales/en/messages.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "POT-Creation-Date: 2023-04-27 00:37+0200\n"
4 | "MIME-Version: 1.0\n"
5 | "Content-Type: text/plain; charset=utf-8\n"
6 | "Content-Transfer-Encoding: 8bit\n"
7 | "X-Generator: @lingui/cli\n"
8 | "Language: en\n"
9 | "Project-Id-Version: \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "PO-Revision-Date: \n"
12 | "Last-Translator: \n"
13 | "Language-Team: \n"
14 | "Plural-Forms: \n"
15 |
16 | #: src/MainScreen.tsx:76
17 | msgid "Add a message to your inbox"
18 | msgstr "Add a message to your inbox"
19 |
20 | #: src/MainScreen.tsx:23
21 | msgid "Cancel"
22 | msgstr "Cancel"
23 |
--------------------------------------------------------------------------------
/packages/react/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["../../.eslintrc", "plugin:react/recommended", "plugin:react-hooks/recommended"],
3 | "settings": {
4 | "react": {
5 | "version": "detect" // "detect" automatically picks the version of React that is installed
6 | }
7 | },
8 | "rules": {
9 | "react/prop-types": "off",
10 | "react/display-name": "off"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/react/build.config.ts:
--------------------------------------------------------------------------------
1 | import { defineBuildConfig } from "unbuild"
2 |
3 | export default defineBuildConfig({
4 | rollup: {
5 | output: {
6 | banner: (chunk: any) => {
7 | if (chunk.name === "index") {
8 | return `'use client';`
9 | }
10 | },
11 | },
12 | },
13 | })
14 |
--------------------------------------------------------------------------------
/packages/react/macro/__typetests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react",
4 | "esModuleInterop": true,
5 | "skipLibCheck": true
6 | },
7 | "paths": {}
8 | }
9 |
--------------------------------------------------------------------------------
/packages/react/macro/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("@lingui/babel-plugin-lingui-macro/macro")
2 |
--------------------------------------------------------------------------------
/packages/react/macro/index.test.ts:
--------------------------------------------------------------------------------
1 | import macro from "@lingui/react/macro"
2 |
3 | describe("react-macro", () => {
4 | it("Should re-export Macro", () => {
5 | expect((macro as any).isBabelMacro).toBeTruthy()
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/packages/react/src/Trans.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 |
3 | import { useLinguiInternal } from "./I18nProvider"
4 | import { TransNoContext, type TransProps } from "./TransNoContext"
5 |
6 | export function Trans(props: TransProps): React.ReactElement | null {
7 | let errMessage = undefined
8 | if (process.env.NODE_ENV !== "production") {
9 | errMessage = `Trans component was rendered without I18nProvider.
10 | Attempted to render message: ${props.message} id: ${props.id}. Make sure this component is rendered inside a I18nProvider.`
11 | }
12 | const lingui = useLinguiInternal(errMessage)
13 | return React.createElement(TransNoContext, { ...props, lingui })
14 | }
15 |
--------------------------------------------------------------------------------
/packages/react/src/TransRsc.tsx:
--------------------------------------------------------------------------------
1 | import { TransProps, TransNoContext } from "./TransNoContext"
2 | import React from "react"
3 | import { getI18n } from "./server"
4 |
5 | export function TransRsc(
6 | props: TransProps
7 | ): React.ReactElement | null {
8 | const ctx = getI18n()
9 | if (!ctx) {
10 | throw new Error(
11 | "You tried to use `Trans` in Server Component, but i18n instance for RSC hasn't been setup.\nMake sure to call `setI18n` in the root of your page."
12 | )
13 | }
14 | return
15 | }
16 |
--------------------------------------------------------------------------------
/packages/react/src/index-rsc.ts:
--------------------------------------------------------------------------------
1 | export type {
2 | TransProps,
3 | TransRenderProps,
4 | TransRenderCallbackOrComponent,
5 | } from "./TransNoContext"
6 |
7 | import type { I18nContext } from "./I18nProvider"
8 | import { getI18n } from "./server"
9 |
10 | export { TransRsc as Trans } from "./TransRsc"
11 |
12 | export function useLingui(): I18nContext {
13 | const ctx = getI18n()
14 | if (!ctx) {
15 | throw new Error(
16 | "You tried to use `useLingui` in a Server Component, but i18n instance for RSC hasn't been setup.\nMake sure to call `setI18n` in the root of your page."
17 | )
18 | }
19 |
20 | return ctx
21 | }
22 |
--------------------------------------------------------------------------------
/packages/react/src/index.ts:
--------------------------------------------------------------------------------
1 | export { I18nProvider, useLingui, LinguiContext } from "./I18nProvider"
2 |
3 | export type { I18nProviderProps, I18nContext } from "./I18nProvider"
4 |
5 | export { Trans } from "./Trans"
6 |
7 | export type {
8 | TransProps,
9 | TransRenderProps,
10 | TransRenderCallbackOrComponent,
11 | } from "./TransNoContext"
12 |
--------------------------------------------------------------------------------
/packages/react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "noUncheckedIndexedAccess": true,
6 | "isolatedModules": true,
7 | "forceConsistentCasingInFileNames": true,
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/remote-loader/src/browserCompiler.ts:
--------------------------------------------------------------------------------
1 | import { compileMessage } from "@lingui/message-utils/compileMessage"
2 |
3 | export function createBrowserCompiledCatalog(messages: Record) {
4 | return Object.keys(messages).reduce((obj, key: string) => {
5 | const value = messages[key]
6 |
7 | const translation = value || key
8 |
9 | obj[key] = compileMessage(translation)
10 | return obj
11 | }, {})
12 | }
13 |
--------------------------------------------------------------------------------
/packages/remote-loader/src/minimalParser.ts:
--------------------------------------------------------------------------------
1 | const deserialize = (minimalCatalog: Record) => {
2 | const result: Record = {}
3 | for (const key in minimalCatalog) {
4 | result[key] = {
5 | translation: minimalCatalog[key],
6 | obsolete: false,
7 | message: null,
8 | origin: [],
9 | }
10 | }
11 | return result
12 | }
13 |
14 | const PARSERS = {
15 | minimal: (content: Record | T) => {
16 | return deserialize(content as Record)
17 | },
18 | }
19 |
20 | export default PARSERS
21 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/__snapshots__/index.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`vite-plugin should not report error when macro correctly used 1`] = `Ola`;
4 |
5 | exports[`vite-plugin should return compiled catalog 1`] = `
6 | {
7 | mVmaLu: [
8 | My name is ,
9 | [
10 | name,
11 | ],
12 | ],
13 | mY42CM: [
14 | Hello World,
15 | ],
16 | }
17 | `;
18 |
19 | exports[`vite-plugin should return compiled catalog json 1`] = `
20 | {
21 | key: [
22 | Message,
23 | ],
24 | key2: [
25 | Hello ,
26 | [
27 | name,
28 | ],
29 | ],
30 | }
31 | `;
32 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/default-vite.config.ts:
--------------------------------------------------------------------------------
1 | import { UserConfig } from "vite"
2 | import { lingui, LinguiPluginOpts } from "../src/index"
3 | import path from "path"
4 |
5 | export function createDefaultViteConfig(
6 | dirname: string,
7 | pluginConfig: LinguiPluginOpts = {}
8 | ): UserConfig {
9 | return {
10 | build: {
11 | lib: {
12 | entry: path.resolve(dirname, "entrypoint.js"),
13 | fileName: "bundle",
14 | formats: ["cjs"],
15 | },
16 | },
17 |
18 | plugins: [
19 | lingui({
20 | cwd: dirname,
21 | ...pluginConfig,
22 | }),
23 | ],
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-compile-errors/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return await import("./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-compile-errors/failOnCompileErrorFalse.vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 |
3 | export default createDefaultViteConfig(__dirname, { failOnCompileError: false })
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-compile-errors/lingui.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | locales: ["en"],
5 | catalogs: [
6 | {
7 | path: "/locale/{locale}",
8 | },
9 | ],
10 | format: "po",
11 | })
12 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-compile-errors/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World {var"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name"
6 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-compile-errors/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 |
3 | export default createDefaultViteConfig(__dirname, { failOnCompileError: true })
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing-pseudo/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return await import("./locale/pseudo.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing-pseudo/lingui.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | locales: ["pseudo"],
5 | pseudoLocale: "pseudo",
6 | catalogs: [
7 | {
8 | path: "/locale/{locale}",
9 | },
10 | ],
11 | format: "po",
12 | })
13 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing-pseudo/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr ""
6 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing-pseudo/locale/pseudo.po:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/packages/vite-plugin/test/fail-on-missing-pseudo/locale/pseudo.po
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing-pseudo/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 |
3 | export default createDefaultViteConfig(__dirname, { failOnMissing: true })
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return await import("./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing/lingui.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | locales: ["en"],
5 | catalogs: [
6 | {
7 | path: "/locale/{locale}",
8 | },
9 | ],
10 | format: "po",
11 | })
12 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr ""
6 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/fail-on-missing/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 |
3 | export default createDefaultViteConfig(__dirname, { failOnMissing: true })
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/json-format/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return await import("./locale/en.json?lingui")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/json-format/lingui.config.ts:
--------------------------------------------------------------------------------
1 | import { formatter } from "@lingui/format-json"
2 |
3 | export default {
4 | locales: ["en"],
5 | catalogs: [
6 | {
7 | path: "/locale/{locale}",
8 | },
9 | ],
10 | fallbackLocales: {
11 | default: "en",
12 | },
13 | format: formatter({ style: "minimal" }),
14 | }
15 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/json-format/locale/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "key": "Message",
3 | "key2": "Hello {name}"
4 | }
5 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/json-format/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 |
3 | export default createDefaultViteConfig(__dirname)
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/macro-usage/.linguirc:
--------------------------------------------------------------------------------
1 | {
2 | "locales": ["en"],
3 | "catalogs": [{
4 | "path": "/locale/{locale}"
5 | }],
6 | "fallbackLocales": {
7 | "default": "en"
8 | },
9 | "format": "po"
10 | }
11 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/macro-usage/entrypoint.js:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 | import { i18n } from "@lingui/core"
3 |
4 | export async function load() {
5 | i18n.loadAndActivate({
6 | locale: "en",
7 | messages: {},
8 | })
9 | return t`Ola`
10 | }
11 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/macro-usage/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name}"
6 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/macro-usage/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 | import { UserConfig } from "vite"
3 | import macrosPlugin from "vite-plugin-babel-macros"
4 |
5 | const config: UserConfig = {
6 | ...createDefaultViteConfig(__dirname),
7 | }
8 |
9 | config.plugins.push(macrosPlugin())
10 |
11 | export default config
12 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/no-macro-error/.linguirc:
--------------------------------------------------------------------------------
1 | {
2 | "locales": ["en"],
3 | "catalogs": [{
4 | "path": "/locale/{locale}"
5 | }],
6 | "fallbackLocales": {
7 | "default": "en"
8 | },
9 | "format": "po"
10 | }
11 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/no-macro-error/entrypoint.js:
--------------------------------------------------------------------------------
1 | import { t } from "@lingui/core/macro"
2 |
3 | export async function load() {
4 | return t`Ola`
5 | }
6 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/no-macro-error/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name}"
6 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/no-macro-error/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 |
3 | export default createDefaultViteConfig(__dirname)
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/po-format/entrypoint.js:
--------------------------------------------------------------------------------
1 | export async function load() {
2 | return import("./locale/en.po")
3 | }
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/po-format/lingui.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "@lingui/cli"
2 |
3 | export default defineConfig({
4 | locales: ["en"],
5 | catalogs: [
6 | {
7 | path: "/locale/{locale}",
8 | },
9 | ],
10 | fallbackLocales: {
11 | default: "en",
12 | },
13 | format: "po",
14 | })
15 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/po-format/locale/en.po:
--------------------------------------------------------------------------------
1 | msgid "Hello World"
2 | msgstr "Hello World"
3 |
4 | msgid "My name is {name}"
5 | msgstr "My name is {name}"
6 |
--------------------------------------------------------------------------------
/packages/vite-plugin/test/po-format/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { createDefaultViteConfig } from "../default-vite.config"
2 |
3 | export default createDefaultViteConfig(__dirname)
4 |
--------------------------------------------------------------------------------
/packages/vite-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "ES2019",
5 | "sourceMap": true,
6 | "noEmit": false,
7 | "declaration": true,
8 | "outDir": "./build",
9 | "esModuleInterop": true,
10 | "resolveJsonModule": true,
11 | "types": []
12 | },
13 | "include": [
14 | "src"
15 | ],
16 | "exclude": [
17 | "node_modules"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/scripts/jest/env.js:
--------------------------------------------------------------------------------
1 | // avoid snapshot of cli output mismatching because
2 | // of different ways to run test
3 | process.env.npm_config_user_agent = "yarn"
4 |
--------------------------------------------------------------------------------
/scripts/jest/setupTimezone.js:
--------------------------------------------------------------------------------
1 | module.exports = async () => {
2 | process.env.TZ = "UTC"
3 | }
4 |
--------------------------------------------------------------------------------
/scripts/jest/stripAnsiSerializer.js:
--------------------------------------------------------------------------------
1 | const stripAnsi = require("strip-ansi")
2 |
3 | module.exports = {
4 | test: (val) => typeof val === "string",
5 | print: (val) => stripAnsi(val),
6 | }
7 |
--------------------------------------------------------------------------------
/test/cli-version/index.js:
--------------------------------------------------------------------------------
1 | import { execa } from "execa"
2 | import assert from "node:assert"
3 |
4 | const { stdout } = await execa("lingui", ["--version"])
5 | assert.match(stdout, /^\d\.\d+\.\d+/)
6 |
--------------------------------------------------------------------------------
/test/cli-version/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cli-version",
3 | "version": "1.0.0",
4 | "private": true,
5 | "type": "module",
6 | "scripts": {
7 | "test:e2e": "node index.js"
8 | },
9 | "dependencies": {
10 | "@lingui/cli": "workspace:*",
11 | "@lingui/core": "workspace:*",
12 | "execa": "^7.1.1"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/node-api-esm/index.js:
--------------------------------------------------------------------------------
1 | import assert from "node:assert"
2 |
3 | assert(await import("@lingui/cli/api"))
4 |
5 | assert(await import("@lingui/cli/api/extractors/typescript"))
6 | assert(await import("@lingui/cli/api/extractors/babel"))
7 |
8 | assert(await import("@lingui/core"))
9 | assert(await import("@lingui/react/server"))
10 |
--------------------------------------------------------------------------------
/test/node-api-esm/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-api-esm",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "test:e2e": "node index.js"
8 | },
9 | "dependencies": {
10 | "@lingui/cli": "workspace:*",
11 | "@lingui/core": "workspace:*"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/test/node-api/index.js:
--------------------------------------------------------------------------------
1 | const assert = require("assert")
2 | assert(require.resolve("@lingui/cli/api"))
3 | assert(require.resolve("@lingui/cli/api/extractors/typescript"))
4 | assert(require.resolve("@lingui/cli/api/extractors/babel"))
5 |
6 | assert(require.resolve("@lingui/core"))
7 |
--------------------------------------------------------------------------------
/test/node-api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-api",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "test:e2e": "node index.js"
7 | },
8 | "dependencies": {
9 | "@lingui/cli": "workspace:*",
10 | "@lingui/core": "workspace:*"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/test/typescript-nodenext-resolution/index.ts:
--------------------------------------------------------------------------------
1 | // Check support typescript's NodeNext moduleResolution with dual `@lingui` packages
2 | // https://github.com/microsoft/TypeScript/issues/50466
3 |
4 | import { i18n } from "@lingui/core"
5 | import { Trans } from "@lingui/react"
6 | import { t as t1 } from "@lingui/macro"
7 | import { t } from "@lingui/core/macro"
8 | import { Trans as TransMacro } from "@lingui/react/macro"
9 |
10 | console.log(i18n)
11 | console.log(Trans)
12 | console.log(t1, t, TransMacro)
13 |
--------------------------------------------------------------------------------
/test/typescript-nodenext-resolution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typescript-nodenext-resolution",
3 | "private": true,
4 | "version": "1.0.0",
5 | "scripts": {
6 | "test:e2e": "tsc -p tsconfig.json"
7 | },
8 | "dependencies": {
9 | "@lingui/core": "workspace:*",
10 | "@lingui/macro": "workspace:*",
11 | "@lingui/react": "workspace:*"
12 | },
13 | "devDependencies": {
14 | "typescript": "4.9.5"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/test/typescript-nodenext-resolution/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "NodeNext",
5 | "moduleResolution": "NodeNext",
6 | "noEmit": true,
7 | "strict": true,
8 | "types": []
9 | },
10 | "files": [
11 | "index.ts"
12 | ],
13 | "exclude": [
14 | "node_modules"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/tstyche.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://tstyche.org/schemas/config.json",
3 | "testFileMatch": [
4 | "packages/**/__typetests__/*.test-d.*"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/website/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 |
8 | [*.{js,jsx,mjs,ts,tsx,css,md}]
9 | indent_style = space
10 | indent_size = 2
11 | max_line_length = 160
12 |
13 | [*.{yml,yaml}]
14 | indent_style = space
15 | indent_size = 2
16 |
17 | [*.{bat,cmd,ps1}]
18 | end_of_line = crlf
19 |
--------------------------------------------------------------------------------
/website/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
3 | *.editorconfig text eol=lf
4 | *.html text eol=lf
5 | *.md text eol=lf
6 | *.py text eol=lf
7 | *.sh text eol=lf
8 | *.txt text eol=lf
9 | *.yml text eol=lf
10 | *.json text eol=lf
11 |
12 | *.gitignore text=auto
13 | *.gitattributes text=auto
14 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | build/
3 | build-local/
4 |
5 | .docusaurus/
6 | .idea/
7 |
8 | .cache-loader
9 | .DS_Store
10 | .env.local
11 | .env.development.local
12 | .env.test.local
13 | .env.production.local
14 |
15 | npm-debug.log*
16 | yarn-debug.log*
17 | yarn-error.log*
18 |
19 | .pnp.*
20 | .yarn/*
21 | !.yarn/patches
22 | !.yarn/plugins
23 | !.yarn/releases
24 | !.yarn/sdks
25 | !.yarn/versions
26 |
--------------------------------------------------------------------------------
/website/.prettierignore:
--------------------------------------------------------------------------------
1 | .docusaurus/
2 | .github/
3 | .idea/
4 | build/
5 | node_modules/
6 |
--------------------------------------------------------------------------------
/website/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": false,
7 | "trailingComma": "es5"
8 | }
9 |
--------------------------------------------------------------------------------
/website/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve("@docusaurus/core/lib/babel/preset")],
3 | };
4 |
--------------------------------------------------------------------------------
/website/blog/2023-04-26-announcing-lingui-4.0/social-card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/blog/2023-04-26-announcing-lingui-4.0/social-card.png
--------------------------------------------------------------------------------
/website/blog/2023-12-12-4k-stars/social-card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/blog/2023-12-12-4k-stars/social-card.png
--------------------------------------------------------------------------------
/website/blog/2024-11-20-metro-transformer/social-card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/blog/2024-11-20-metro-transformer/social-card.png
--------------------------------------------------------------------------------
/website/blog/2024-11-28-announcing-lingui-5.0/social-card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/blog/2024-11-28-announcing-lingui-5.0/social-card.png
--------------------------------------------------------------------------------
/website/blog/authors.yml:
--------------------------------------------------------------------------------
1 | andrii-bodnar:
2 | name: Andrii Bodnar
3 | title: Engineering Manager
4 | page: true
5 | image_url: https://github.com/andrii-bodnar.png
6 | socials:
7 | x: AndriiBodnar1
8 | github: andrii-bodnar
9 | vonovak:
10 | name: Vojtech Novak
11 | title: Software Engineer
12 | page: true
13 | image_url: https://github.com/vonovak.png
14 | socials:
15 | x: vonovak
16 | github: vonovak
17 |
--------------------------------------------------------------------------------
/website/docs/guides/monorepo.md:
--------------------------------------------------------------------------------
1 | # Monorepo
2 |
3 | If you're using lingui within a monorepo you need:
4 |
5 | - 1x `babel.config.js` within root
6 | - 1x `lingui.config.js` within root
7 | - And **n**-times `lingui.config.js` per package which extends/overrides from root
8 |
--------------------------------------------------------------------------------
/website/linkcheck-ignore.txt:
--------------------------------------------------------------------------------
1 | http://localhost:\d{4}
2 | https://.*.algolia.net
3 |
--------------------------------------------------------------------------------
/website/src/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Link from "@docusaurus/Link";
3 |
4 | type ButtonProps = {
5 | href: string;
6 | children: string;
7 | isOutline?: boolean;
8 | };
9 |
10 | const Button = (props: ButtonProps): React.ReactElement => {
11 | return (
12 |
16 | {props.children}
17 |
18 | );
19 | };
20 |
21 | export default Button;
22 |
--------------------------------------------------------------------------------
/website/src/components/PartnerBanner.module.scss:
--------------------------------------------------------------------------------
1 | .Partner {
2 | margin-top: 3rem;
3 | margin-bottom: 6rem;
4 | position: relative;
5 | z-index: 1000;
6 |
7 | a {
8 | text-decoration: none;
9 | color: var(--p-color);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/website/src/components/Workflow.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Button from "./Button";
3 | import { useBaseUrlUtils } from "@docusaurus/useBaseUrl";
4 |
5 | const Workflow = (): React.ReactElement => {
6 | const { withBaseUrl } = useBaseUrlUtils();
7 |
8 | return (
9 |
10 |
11 |
Workflow
12 |
13 |
14 |
15 |
16 | Read More
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default Workflow;
24 |
--------------------------------------------------------------------------------
/website/src/definitions.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.module.scss";
2 | declare module "@docusaurus/*";
3 |
--------------------------------------------------------------------------------
/website/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Layout from "@theme/Layout";
3 | import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
4 | import Features from "../components/Features";
5 | import Header from "../components/Header";
6 | import Users from "../components/Users";
7 | import Code from "../components/Code";
8 | import PartnerBanner from "../components/PartnerBanner";
9 | import Workflow from "../components/Workflow";
10 |
11 | function Home() {
12 | const { siteConfig } = useDocusaurusContext();
13 |
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 | }
27 |
28 | export default Home;
29 |
--------------------------------------------------------------------------------
/website/src/theme/Footer/index.js:
--------------------------------------------------------------------------------
1 | import OriginalFooter from "@theme-original/Footer";
2 | import React from "react";
3 |
4 | export default function Footer(props) {
5 | return (
6 | <>
7 |
8 | >
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/website/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/.nojekyll
--------------------------------------------------------------------------------
/website/static/img/docs/Crowdin__js-lingui-vcs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/docs/Crowdin__js-lingui-vcs.png
--------------------------------------------------------------------------------
/website/static/img/docs/dynamic-loading-catalogs-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/docs/dynamic-loading-catalogs-1.png
--------------------------------------------------------------------------------
/website/static/img/docs/dynamic-loading-catalogs-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/docs/dynamic-loading-catalogs-2.png
--------------------------------------------------------------------------------
/website/static/img/docs/rn-component-nesting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/docs/rn-component-nesting.png
--------------------------------------------------------------------------------
/website/static/img/docs/translation-lingui-plural-forms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/docs/translation-lingui-plural-forms.png
--------------------------------------------------------------------------------
/website/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/favicon.ico
--------------------------------------------------------------------------------
/website/static/img/features/ai-ready.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/features/ai-ready.png
--------------------------------------------------------------------------------
/website/static/img/features/clean-and-readable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/features/clean-and-readable.png
--------------------------------------------------------------------------------
/website/static/img/features/tooling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/features/tooling.png
--------------------------------------------------------------------------------
/website/static/img/og-image-examples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/og-image-examples.png
--------------------------------------------------------------------------------
/website/static/img/og-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/og-image.png
--------------------------------------------------------------------------------
/website/static/img/users/ansible.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/ansible.png
--------------------------------------------------------------------------------
/website/static/img/users/bluesky.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/bluesky.png
--------------------------------------------------------------------------------
/website/static/img/users/brave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/brave.png
--------------------------------------------------------------------------------
/website/static/img/users/documenso.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/documenso.png
--------------------------------------------------------------------------------
/website/static/img/users/fider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/fider.png
--------------------------------------------------------------------------------
/website/static/img/users/graysky.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/graysky.png
--------------------------------------------------------------------------------
/website/static/img/users/linkerd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/linkerd.png
--------------------------------------------------------------------------------
/website/static/img/users/metamask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/metamask.png
--------------------------------------------------------------------------------
/website/static/img/users/remirror.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/remirror.png
--------------------------------------------------------------------------------
/website/static/img/users/twenty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/twenty.png
--------------------------------------------------------------------------------
/website/static/img/users/zipkin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingui/js-lingui/37f40ec18928b357c07a228947b2bf071e92449e/website/static/img/users/zipkin.png
--------------------------------------------------------------------------------
/website/tools/algolia/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "index_name": "lingui",
3 | "start_urls": ["https://lingui.dev/"],
4 | "sitemap_urls": ["https://lingui.dev/sitemap.xml"],
5 | "stop_urls": [],
6 | "strip_chars": "#",
7 | "selectors": {
8 | "lvl0": {
9 | "selector": "(//nav[contains(@class, 'navbar')]//div[contains(@class, 'navbar__items')]//a[contains(@class, 'navbar__link--active')]/text())",
10 | "type": "xpath",
11 | "global": true,
12 | "default_value": "Lingui"
13 | },
14 | "lvl1": "article h1",
15 | "lvl2": "article h2",
16 | "lvl3": "article h3",
17 | "lvl4": "article h4",
18 | "lvl5": "article h5",
19 | "text": "article p, article li"
20 | },
21 | "custom_settings": {
22 | "attributesForFaceting": ["language", "version", "type", "docusaurus_tag"]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/docusaurus/tsconfig.json",
3 | "include": ["src/"],
4 | "compilerOptions": {
5 | "jsx": "react",
6 | "plugins": [{ "name": "typescript-plugin-css-modules" }],
7 | "moduleResolution": "node"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------