[
  {
    "path": ".cleandir.sh",
    "content": "echo Cleaning up project directory...\nrm -rf node_modules dist build coverage src/**/*.d.ts src/**/*.js src/**/*.js.map src/**/*.metadata.json"
  },
  {
    "path": ".editorconfig",
    "content": "# Editor configuration, see http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\nmax_line_length = off\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintignore",
    "content": "node_modules\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"ignorePatterns\": [\"**/*\"],\n  \"plugins\": [\"@nx\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\", \"*.tsx\", \"*.js\", \"*.jsx\"],\n      \"rules\": {\n        \"@nx/enforce-module-boundaries\": [\n          \"error\",\n          {\n            \"enforceBuildableLibDependency\": true,\n            \"allow\": [],\n            \"depConstraints\": [\n              {\n                \"sourceTag\": \"*\",\n                \"onlyDependOnLibsWithTags\": [\"*\"]\n              }\n            ]\n          }\n        ]\n      }\n    },\n    {\n      \"files\": [\"*.ts\", \"*.tsx\"],\n      \"extends\": [\"plugin:@nx/typescript\"],\n      \"rules\": {}\n    },\n    {\n      \"files\": [\"*.js\", \"*.jsx\"],\n      \"extends\": [\"plugin:@nx/javascript\"],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "custom: [\"https://www.paypal.com/paypalme2/sergeyromanchuk/10USD\"]\n"
  },
  {
    "path": ".github/workflows/static.yml",
    "content": "# Simple workflow for deploying static content to GitHub Pages\nname: Deploy static content to Pages\n\non:\n  # Runs on pushes targeting the default branch\n  push:\n    branches: [\"master\"]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# Allow one concurrent deployment\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: true\n\njobs:\n  # Single deploy job since we're just deploying\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [22.13.x]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Pages\n        uses: actions/configure-pages@v5\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n      - run: npm ci\n      - run: npm run test\n      - run: npm run build\n      - run: npm run prepare:demo\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: './dist/angular-i18next-demo/browser'\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".gitignore",
    "content": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n# compiled output\ndist\n/tmp\n/out-tsc\n\n# dependencies\nnode_modules\n\n# IDEs and editors\n/.idea\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# IDE - VSCode\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\n# misc\n/.sass-cache\n/connect.lock\n/coverage\n/libpeerconnection.log\nnpm-debug.log\nyarn-error.log\ntestem.log\n/typings\n\n# System Files\n.DS_Store\nThumbs.db\n\n.angular\n\n.nx\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Add files here to ignore them from prettier formatting\n\n/dist\n/coverage\n\n/.nx/cache\n.angular\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"angular.ng-template\",\n    \"nrwl.angular-console\",\n    \"esbenp.prettier-vscode\",\n    \"firsttris.vscode-jest-runner\",\n    \"dbaeumer.vscode-eslint\",\n    \"github.vscode-github-actions\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"configurations\": [\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"Jest: current file\",\n      //\"env\": { \"NODE_ENV\": \"test\" },\n      \"program\": \"${workspaceFolder}/node_modules/.bin/jest\",\n      \"args\": [\"${fileBasenameNoExtension}\", \"--config\", \"jest.config.ts\"],\n      \"console\": \"integratedTerminal\",\n      \"windows\": {\n        \"program\": \"${workspaceFolder}/node_modules/jest/bin/jest\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "// Place your settings in this file to overwrite default and user settings.\n{\n  \"search.exclude\": {\n    \"coverage\": true,\n    \"dist\": true,\n    \"build\": true\n  },\n  \"typescript.tsdk\": \"node_modules\\\\typescript\\\\lib\"\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# [10.3.0](https://github.com/Romanchuk/angular-i18next/compare/v10.3.0-0...v10.3.0) (2021-06-15)\n\n\n\n# [10.3.0-0](https://github.com/Romanchuk/angular-i18next/compare/v10.2.0...v10.3.0-0) (2021-06-15)\n\n\n\n# [10.2.0](https://github.com/Romanchuk/angular-i18next/compare/v10.2.0-0...v10.2.0) (2021-05-12)\n\n\n\n# [10.2.0-0](https://github.com/Romanchuk/angular-i18next/compare/v10.1.0...v10.2.0-0) (2021-05-12)\n\n\n### Features\n\n* i18next v20+ support ([0327a7c](https://github.com/Romanchuk/angular-i18next/commit/0327a7c9f35140f0c8e098d9d1528b6e7303a8d0))\n\n\n\n# [10.1.0](https://github.com/Romanchuk/angular-i18next/compare/v10.1.0-0...v10.1.0) (2021-03-01)\n\n\n\n# [10.1.0-0](https://github.com/Romanchuk/angular-i18next/compare/v10.0.1...v10.1.0-0) (2021-03-01)\n\n\n### Bug Fixes\n\n* **I18NextEagerPipe:** ensure changing PipeOptions returns correct translated value a not cached one with different PipeOptions but same key ([4a6d375](https://github.com/Romanchuk/angular-i18next/commit/4a6d375181dda41399c58f7644b97d3755acf84f))\n\n\n\n## [10.0.1](https://github.com/Romanchuk/angular-i18next/compare/v10.0.1-beta...v10.0.1) (2020-12-21)\n\n\n\n## [10.0.1-beta](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0...v10.0.1-beta) (2020-12-21)\n\n\n\n# [10.0.0](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0-2...v10.0.0) (2020-07-06)\n\n\n\n# [10.0.0-2](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0-1...v10.0.0-2) (2020-07-06)\n\n\n\n# [10.0.0-1](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0-0...v10.0.0-1) (2020-07-06)\n\n\n\n# [10.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v9.0.1...v10.0.0-0) (2020-07-06)\n\n\n\n## [9.0.1](https://github.com/Romanchuk/angular-i18next/compare/v9.0.0...v9.0.1) (2020-02-25)\n\n\n### Bug Fixes\n\n* pass translate options ([4cfe42c](https://github.com/Romanchuk/angular-i18next/commit/4cfe42c))\n\n\n\n# [9.0.0](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta.3...v9.0.0) (2020-02-20)\n\n\n\n# [8.1.0-beta.3](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta.2...v8.1.0-beta.3) (2020-02-20)\n\n\n\n# [8.1.0-beta.2](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta.1...v8.1.0-beta.2) (2020-02-20)\n\n\n\n# [8.1.0-beta.1](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta...v8.1.0-beta.1) (2020-02-20)\n\n\n### Features\n\n* improved typings ([214e35d](https://github.com/Romanchuk/angular-i18next/commit/214e35d))\n\n\n\n# [8.1.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v7.2.0-beta...v8.1.0-beta) (2020-02-20)\n\n\n\n## [8.0.1](https://github.com/Romanchuk/angular-i18next/compare/v8.0.1-beta.0...v8.0.1) (2020-02-18)\n\n\n\n## [8.0.1-beta.0](https://github.com/Romanchuk/angular-i18next/compare/v8.0.1-beta...v8.0.1-beta.0) (2020-02-18)\n\n\n\n## [8.0.1-beta](https://github.com/Romanchuk/angular-i18next/compare/v8.0.0...v8.0.1-beta) (2020-02-18)\n\n\n\n# [8.0.0](https://github.com/Romanchuk/angular-i18next/compare/v8.0.0-beta.1...v8.0.0) (2020-02-14)\n\n\n\n# [8.0.0-beta.1](https://github.com/Romanchuk/angular-i18next/compare/v8.0.0-beta...v8.0.0-beta.1) (2020-02-13)\n\n\n\n# [8.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v7.2.0-beta...v8.0.0-beta) (2020-02-13)\n\n\n\n# [7.2.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v7.0.0...v7.2.0-beta) (2020-01-28)\n\n\n### Bug Fixes\n\n* I18NextEagerPipe ([8dbefe1](https://github.com/Romanchuk/angular-i18next/commit/8dbefe1))\n\n\n\n# [7.0.0](https://github.com/Romanchuk/angular-i18next/compare/v6.1.0...v7.0.0) (2019-06-05)\n\n\n\n# [6.1.0](https://github.com/Romanchuk/angular-i18next/compare/v6.1.0-beta...v6.1.0) (2019-05-27)\n\n\n\n# [6.1.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v6.0.1...v6.1.0-beta) (2019-05-25)\n\n\n\n## [6.0.1](https://github.com/Romanchuk/angular-i18next/compare/v6.0.0...v6.0.1) (2019-03-11)\n\n\n\n# [6.0.0](https://github.com/Romanchuk/angular-i18next/compare/v6.0.0-beta.0...v6.0.0) (2019-02-10)\n\n\n\n# [6.0.0-beta.0](https://github.com/Romanchuk/angular-i18next/compare/v6.0.0-beta...v6.0.0-beta.0) (2019-02-10)\n\n\n\n# [6.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v5.0.6...v6.0.0-beta) (2019-02-10)\n\n\n\n## [5.0.6](https://github.com/Romanchuk/angular-i18next/compare/v5.0.5...v5.0.6) (2018-12-03)\n\n\n\n## [5.0.5](https://github.com/Romanchuk/angular-i18next/compare/v5.0.4...v5.0.5) (2018-12-03)\n\n\n\n## [5.0.4](https://github.com/Romanchuk/angular-i18next/compare/v5.0.3...v5.0.4) (2018-12-03)\n\n\n\n## [5.0.3](https://github.com/Romanchuk/angular-i18next/compare/v5.0.2...v5.0.3) (2018-12-03)\n\n\n\n## [5.0.2](https://github.com/Romanchuk/angular-i18next/compare/v5.0.1...v5.0.2) (2018-12-03)\n\n\n### Bug Fixes\n\n* package.json ([54a8c37](https://github.com/Romanchuk/angular-i18next/commit/54a8c37))\n\n\n\n## [5.0.1](https://github.com/Romanchuk/angular-i18next/compare/v5.0.0...v5.0.1) (2018-11-28)\n\n\n\n# [5.0.0](https://github.com/Romanchuk/angular-i18next/compare/v5.0.0-beta2...v5.0.0) (2018-11-28)\n\n\n\n# [5.0.0-beta2](https://github.com/Romanchuk/angular-i18next/compare/v5.0.0-beta...v5.0.0-beta2) (2018-11-28)\n\n\n\n# [5.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v4.0.0...v5.0.0-beta) (2018-11-28)\n\n\n### Bug Fixes\n\n* docs ([220a0b8](https://github.com/Romanchuk/angular-i18next/commit/220a0b8))\n\n\n\n<a name=\"4.0.0\"></a>\n# [4.0.0](https://github.com/Romanchuk/angular-i18next/compare/v4.0.0-beta...v4.0.0) (2018-06-25)\n\nIn v4 passed through most of i18next api methods\n\n1. Update angular to v6+\n2. Update rxjs to v6.2.0+\n\n\n<a name=\"4.0.0-beta\"></a>\n# [4.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v3.4.2...v4.0.0-beta) (2018-06-11)\n\n\n\n<a name=\"3.4.2\"></a>\n## [3.4.2](https://github.com/Romanchuk/angular-i18next/compare/v3.4.1...v3.4.2) (2018-05-05)\n\n\n\n<a name=\"3.4.1\"></a>\n## [3.4.1](https://github.com/Romanchuk/angular-i18next/compare/v3.4.0...v3.4.1) (2018-04-29)\n\n- default formater fixes\n\n\n<a name=\"3.4.0\"></a>\n# [3.4.0](https://github.com/Romanchuk/angular-i18next/compare/v3.3.0...v3.4.0) (2018-04-29)\n\n- i18next v11 support \n- fix: [format pipe](https://github.com/Romanchuk/angular-i18next/issues/15)\n\n\n<a name=\"3.3.0\"></a>\n# [3.3.0](https://github.com/Romanchuk/angular-i18next/compare/v3.3.0-beta.2...v3.3.0) (2018-03-12)\n\n- added umd bundle\n- comments cleanup\n- updated dev dependencies\n\n<a name=\"3.3.0-beta.2\"></a>\n# [3.3.0-beta.2](https://github.com/Romanchuk/angular-i18next/compare/v3.3.0-beta.1...v3.3.0-beta.2) (2018-03-12)\n\n\n\n<a name=\"3.3.0-beta.1\"></a>\n# [3.3.0-beta.1](https://github.com/Romanchuk/angular-i18next/compare/v3.2.0...v3.3.0-beta.1) (2018-02-04)\n\n\n\n<a name=\"3.2.0\"></a>\n# [3.2.0](https://github.com/Romanchuk/angular-i18next/compare/v3.1.1...v3.2.0) (2018-01-17)\n\n### Bug Fixes\n* [aot build failed](Romanchuk/angular-i18next#10)\n\n### Breaking changes\n\nRemoved parameter 'localizeTitle' from forRoot method.\nYou need to manually resolve Title as I18NextTitle for same behavior.\n\n\n<a name=\"3.1.1\"></a>\n## [3.1.1](https://github.com/Romanchuk/angular-i18next/compare/v3.1.0...v3.1.1) (2018-01-01)\n\n\n### Bug Fixes\n\n* bug namespace fallback ([a16b067](https://github.com/Romanchuk/angular-i18next/commit/a16b067))\n* conventional-github-releaser run ([df3bb84](https://github.com/Romanchuk/angular-i18next/commit/df3bb84))\n\n\n\n<a name=\"3.1.0\"></a>\n# [3.1.0](https://github.com/Romanchuk/angular-i18next/compare/v3.0.0...v3.1.0) (2017-12-22)\n\nIt is possible to pass array of namespaces (or scopes). [Key would fallback](https://www.i18next.com/api.html#t) to next namespace in array if the previous failed to resolve.\n\n`[feature.validators:key, validators:key]`\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: ['feature.validators', 'validators']\n}\n```\n\n<a name=\"3.0.0\"></a>\n# [3.0.0](https://github.com/Romanchuk/angular-i18next/compare/v3.0.0-alpha.2...v3.0.0) (2017-12-15)\n\n\n\n<a name=\"3.0.0-alpha.2\"></a>\n# [3.0.0-alpha.2](https://github.com/Romanchuk/angular-i18next/compare/v3.0.0-alpha...v3.0.0-alpha.2) (2017-12-05)\n\n\n\n<a name=\"3.0.0-alpha\"></a>\n# [3.0.0-alpha](https://github.com/Romanchuk/angular-i18next/compare/v2.0.0...v3.0.0-alpha) (2017-11-27)\n\n\n\n<a name=\"2.0.0\"></a>\n# [2.0.0](https://github.com/Romanchuk/angular-i18next/compare/v2.0.0-beta2...v2.0.0) (2017-11-14)\n\n\n\n<a name=\"2.0.0-beta2\"></a>\n# [2.0.0-beta2](https://github.com/Romanchuk/angular-i18next/compare/v2.0.0-beta...v2.0.0-beta2) (2017-11-05)\n\n\n\n<a name=\"2.0.0-beta\"></a>\n# [2.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v1.1.0...v2.0.0-beta) (2017-11-05)\n\n\n\n<a name=\"1.1.0\"></a>\n# [1.1.0](https://github.com/Romanchuk/angular-i18next/compare/v1.0.2...v1.1.0) (2017-11-04)\n\n\n\n<a name=\"1.0.2\"></a>\n## [1.0.2](https://github.com/Romanchuk/angular-i18next/compare/v1.0.1...v1.0.2) (2017-09-22)\n\n\n\n<a name=\"1.0.1\"></a>\n## [1.0.1](https://github.com/Romanchuk/angular-i18next/compare/v1.0.0...v1.0.1) (2017-09-21)\n\n\n\n<a name=\"1.0.0\"></a>\n# [1.0.0](https://github.com/Romanchuk/angular-i18next/compare/v0.2.4...v1.0.0) (2017-09-21)\n\n\n\n<a name=\"0.2.4\"></a>\n## [0.2.4](https://github.com/Romanchuk/angular-i18next/compare/v0.2.3...v0.2.4) (2017-06-29)\n\n\n\n<a name=\"0.2.3\"></a>\n## [0.2.3](https://github.com/Romanchuk/angular-i18next/compare/v0.2.2...v0.2.3) (2017-06-29)\n\n\n\n<a name=\"0.2.2\"></a>\n## [0.2.2](https://github.com/Romanchuk/angular-i18next/compare/v0.2.1...v0.2.2) (2017-06-29)\n\n\n### Bug Fixes\n\n* **I18NextService:** context-safe calls of i18next methods ([455a07d](https://github.com/Romanchuk/angular-i18next/commit/455a07d))\n\n\n\n<a name=\"0.2.1\"></a>\n## [0.2.1](https://github.com/Romanchuk/angular-i18next/compare/v0.2.0...v0.2.1) (2017-06-29)\n\n\n### Bug Fixes\n\n* **package:** return back required exports ([fb7ead6](https://github.com/Romanchuk/angular-i18next/commit/fb7ead6))\n\n\n\n<a name=\"0.2.0\"></a>\n# [0.2.0](https://github.com/Romanchuk/angular-i18next/compare/0.1.0...0.2.0) (2017-06-28)\n\n\n### Features\n\n* **package:** AOT support added ([fc1f66d](https://github.com/Romanchuk/angular-i18next/commit/fc1f66d))\n\n\n\n"
  },
  {
    "path": "FUNDING.yml",
    "content": "github: Romanchuk\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Sergey Romanchuk\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "[![npm version](https://badge.fury.io/js/angular-i18next.svg)](https://badge.fury.io/js/angular-i18next)\n[![Downloads](http://img.shields.io/npm/dm/angular-i18next.svg)](https://npmjs.org/package/angular-i18next)\n[![Build Status](https://github.com/romanchuk/angular-i18next/actions/workflows/static.yml/badge.svg)](https://github.com/Romanchuk/angular-i18next/actions/workflows/static.yml)\n[![Coverage Status](https://coveralls.io/repos/github/Romanchuk/angular-i18next/badge.svg?branch=master)](https://coveralls.io/github/Romanchuk/angular-i18next?branch=master)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n[![paypal](https://img.shields.io/badge/say_thanks-%2410-green)](https://www.paypal.com/paypalme2/sergeyromanchuk/10USD)\n[![GitHub stars](https://img.shields.io/github/stars/romanchuk/angular-i18next?label=Please%20star%20repo%21&style=social)](https://github.com/romanchuk/angular-i18next)\n\n# angular-i18next\n\nBest [i18next](http://i18next.com/) integration with [angular](https://angular.io/)\n\n[Live DEMO](https://angular-i18next.onrender.com)\n\n- [Features](#features)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Cookbook](#cookbook)\n- [In-project testing](#in-project-testing)\n- [Demo](#demo)\n- [Articles](#articles)\n- [Support project](#cheers)\n- [DEPRECATED DOCS](./README_DEPRECATED.md)\n\n# Features\n\n- Native i18next [options](https://www.i18next.com/configuration-options.html)\n- Promise initialization\n- [i18next plugin](https://www.i18next.com/plugins-and-utils.html#plugins) support\n- Events support\n- Namespaces lazy load\n- i18next native [format](https://www.i18next.com/api.html#format) support\n- document.title localization\n- Error handling strategies\n- i18next namespaces and scopes (prefixes) for angular modules and components\n- AOT support\n- SSR support\n- Providers for unit testing\n- Angular Package Format support\n- Zoneless compatible\n\n# Cheers\n\nStar this project\n\nHey dude! Help me out for a couple of :beers:!\n\nПоддержи проект - угости автора кружечкой пива!\n\n[![paypal](https://img.shields.io/badge/paypal-%2410-green)](https://www.paypal.com/paypalme2/sergeyromanchuk/10USD)\n\n## Available Submodules (optional)\n\n- **`angular-i18next/ssr`**: Adds Server Side Rendering support.\n- **`angular-i18next/forms`**: Provides localization for `@angular/forms`.\n- **`angular-i18next/testing`**: Offers features for testing.\n\n# Installation\n\n**1.** Install package\n\n   ```bash\n    npm install i18next angular-i18next\n  ```\n\n**2.** Initialize i18next before angular application and provide\n\nAngular would not load until i18next initialize event fired\n\n```typescript\nimport { I18NEXT_SERVICE } from 'angular-i18next';\n\nexport function i18nAppInit() {\n  return () {\n    const i18next = inject(I18NEXT_SERVICE);\n    return i18next.init();\n  }\n}\n```\n\n```typescript\n  providers: [\n    provideAppInitializer(i18nAppInit()),\n    provideI18Next(\n      withCustomErrorHandlingStrategy(StrictErrorHandlingStrategy)\n    )\n  ] \n```\n\n# Usage\n\n## Pipes\n\nUse \"i18next\" pipe to translate key:\n\n```html\n  <div>{{ 'test' | i18next }}</div>\n```\n\nPassing [\"t options\"](https://www.i18next.com/api.html#t):\n\n```html\n    <div>{{ 'test' | i18next: { count: 5, nsSeparator: '#' } }}</div>\n```\n\nRemember to import the Pipe into the Component:\n\n```typescript\n  @Component({\n    // ...\n    imports: [I18NextPipe],\n  })\n  export class SomeExampleComponent {}\n```\n\nTrigger native i18next [format method](https://www.i18next.com/formatting.html) by using I18NextFormatPipe or I18NextPipe with option 'format':\n\n`{{ 'any_key' | i18next | i18nextFormat }}`\n\n`{{ 'any_key' | i18next: { format: 'cap' } }}`\n\n`{{ 'any_key' | i18nextCap }}`\n\n**Note:** Using \"i18nextCap\" you will get the same result as  `i18next: { format: 'cap' }`\n\n**REMEMBER** that format will not work until you set \"interpolation.format\" function in i18next options.\n\n`angular-i81next` has static method `static interpolationFormat(customFormat: Function = null): Function` that can be used as default interpolation format function (it provides 'upper', 'cap' and 'lower' formatters). You also can pass your custom function to be called after library formatters:\n\n```typescript\nimport { defaultInterpolationFormat, interpolationFormat } from \"angular-i18next\";\n\n\nconst i18nextOptions = {\n  supportedLngs: ['en', 'ru'],\n  ns: [\n    'translation',\n    'validation',\n    'error',\n  ],\n  interpolation: {\n    format: interpolationFormat((value, format, lng) => {\n      // extend interpolation format\n      if(value instanceof Date)\n        return moment(value).format(format);\n      return value;\n    });\n    // format: interpolationFormat(defaultInterpolationFormat)\n  }\n};\n\n```\n\n**i18nextEager pipe**\n\nThis is the impure analog of *i18next pipe* that is subscribed to language change, it will change string right away to choosen language (without reloading page).\n\n**Warning!**: Use i18nextEager only in combine with [OnPush change detection strategy](https://netbasal.com/a-comprehensive-guide-to-angular-onpush-change-detection-strategy-5bac493074a4), or else (default change detection) each pipe will retrigger more than one time (cause of performance issues).\n\nSubscribing to event observables:\n\n```typescript\nthis.i18NextService.events.languageChanged.subscribe(lang => {\n  // do something\n})\n```\n\nAdd a provider to module/component if you want to prefix child i18next keys:\n\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: 'feature' // set 'feature:' prefix \n}\n```\n\n```typescript\n{\n  provide: I18NEXT_SCOPE,\n  useValue: 'person' // set 'person.' prefix \n}\n```\n\nSince v3.1.0+ it is possible to pass array of namespaces (or scopes). [Key would fallback](https://www.i18next.com/api.html#t) to next namespace in array if the previous failed to resolve.\n\n`[feature_validators:key, validators:key]`\n\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: ['feature_validators', 'validators']\n}\n```\n\n_NOTE:* **Do NOT** use default (or custom) i18next delimiters in namespace names.\n\n### Document title\n\nIf you want to turn on document title localization resolve Title as `I18NextTitle` imported from 'angular-i18next':\n\n```typescript\n  providers: [provideI18Next(withTitle())]\n```\n\nRoutes example:\n\n```typescript\nconst appRoutes: Routes = [\n  { \n    path: 'error',\n    component: AppErrorComponent,\n    data: { title: 'error:error_occured' }\n  },\n  { \n    path: 'denied',\n    component: AccessDeniedComponent,\n    data: { title: 'error:access_denied' }\n  }\n];\n```\n\nWays to use I18NextService in your code:\n> **Warning:** Injection of **I18NextService** is possible, but it would not consider I18NEXT_NAMESPACE and I18NEXT_SCOPE providers. There are 2 possible reasons to inject **I18NextService**: initialization and subscription to its events. In all other cases inject **I18NextPipe**.\n\n1) **Recommended way:** Inject via **I18NEXT_SERVICE** token. By default it will inject instance of **I18NextService**.\n\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService) \n```\n\n2) Legacy way: Inject via type\n\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              private i18NextService: I18NextService) \n```\n\n### Error handling\n\nError handling is now configurable:\n\n  1) By default i18next promise will use NativeErrorHandlingStrategy. I18Next would be always resolve successfully. Error could be get from 'then' handler parameter.\n  2) Set StrictErrorHandlingStrategy to reject load promises (init, languageChange, loadNamespaces) on first load fail (this was default in v2 but changed to fit [native i18next behavior](https://github.com/Romanchuk/angular-i18next/issues/9):\n\n```typescript\n  providers: [\n    provideI18Next(\n      withCustomErrorHandlingStrategy(StrictErrorHandlingStrategy)\n    )\n  ]    \n```\n\n### Lazy loading\n\nUse `i18NextNamespacesGuard` in your routes to to load i18next namespace.\n\nNote: It is not necessary to register lazy loading namespaces in global i18next options.\n\n```\n{\n    path: 'rich_form',\n    loadComponent: () => RichFormComponent,\n    providers: [\n      {\n          provide: I18NEXT_NAMESPACE, // namespace to start in component\n          useValue: 'feature.rich_form',\n      },\n    ],\n    canActivate: [i18NextNamespacesGuard('feature.rich_form')]\n }\n```\n\nUse I18NextService.loadNamespaces() method to load namespaces in code.\n\n# Cookbook\n\n### i18next plugin support\n\n```typescript\nimport { I18NextModule, ITranslationService, I18NEXT_SERVICE } from 'angular-i18next';\n//  import Backend from 'i18next-xhr-backend'; //for i18next < 20.0.0\nimport HttpApi from 'i18next-http-backend';\nimport LanguageDetector from 'i18next-browser-languagedetector';\n\n...\n\ni18next.use(HttpApi)\n       .use(LanguageDetector)\n       .init(i18nextOptions)\n```\n\n### Server side rendereng (SSR)\n\n1. Provide for server:\n\n```typescript\nimport { provideI18Next, withTitle } from 'angular-i18next';\nimport { withSSR } from 'angular-i18next/ssr';\n\nconst serverConfig: ApplicationConfig = {\n  providers: [\n    provideServerRendering(),\n    provideServerRouting(serverRoutes),\n    provideI18Next(withTitle(), withSSR()),\n  ],\n};\n\nexport const config = mergeApplicationConfig(appConfig, serverConfig);\n```\n\n2. Configure i18next in `server.ts` ([Example](./apps/angular-i18next-demo/src/server.ts)):\n\n### Auto error message for `@angular/forms`\n\nUse `i18nextValidationMessage` directive with formControlName\n\n```typescript\nimport { I18NextValidationMessageDirective } from 'angular-i18next/forms'\n\n@Component({\n  imports: [I18NextValidationMessageDirective]\n})\n\n<input i18nextValidationMessage class=\"form-control\" type=\"text\" formControlName=\"lastName\"/>\n```\n\nThere is priority order for validation messages:\n\n1. namespace + `control_specific` with form hierarchy\n2. namespace +  Common validation key(like `required`)\n3. `control_specific` with form hierarchy\n4. Common validation key like `required`\n\nAlso you can interpolate `control.error` values. For example: For validator `Validators.min(1)`\n\n```json\n\"min\": \"Minimal {{min}}. Actual: {{actual}}.\"\n```\n\n`en.validation.json`\n\n```json\n{\n    \"required\": \"Field is required.\",\n    \"pattern\": \"$t(validation:_fill) valid value.\",\n    \"_fill\": \"Please fill in\",\n    \"control_specific\": {\n        \"technicalContact\": {\n            \"firstName\": {\n                \"required\": \"$t(validation:_fill) technical specialist's first name.\"\n            },\n            \"lastName\": {\n                \"required\": \"$t(validation:_fill) technical specialist's last name.\"\n            },\n            \"middleName\": {\n                \"required\": \"$t(validation:_fill) technical specialist's patronymic.\"\n            }\n        }\n    }\n}\n```\n\n### Testing\n\n```typescript\n  import { withSSR } from 'angular-i18next/testing';\n\n  TestBed.configureTestingModule({\n      imports: [ProjectComponent],\n      providers: [\n        provideI18NextMockAppInitializer(),\n        provideI18Next(withMock())\n      ]\n  });\n```\n\n# What to do if... ?\n\n## New angular version released, but angular-i18next is not released YET\n\nAngular releases mostly don't break angular-i18next, but we cannot tell ahead that current version of `angular-i18next` will work correctly with latest angular version.\n\nYou can override an angular-i18next `peerDependencies` in your `package.json` on your **own risk**:\n\n```json\n\"overrides\": {\n  \"angular-i18next\": {\n    \"@angular/common\": \"*\",\n    \"@angular/core\": \"*\",\n    \"@angular/platform-browser\": \"*\"\n  }\n}\n```\n\n# In-project testing\n\nYou might want to unit-test project components that are using i18next pipes\n\nExample tests setup:\n[libs/angular-i18next/src/tests/projectTests](https://github.com/Romanchuk/angular-i18next/tree/master/libs/angular-i18next/src/tests/projectTests)\n\n# Demo\n\n[Live DEMO](https://angular-i18next.onrender.com)\nDemo app source code available here: <https://github.com/Romanchuk/angular-i18next-demo>\n\n# Articles\n\n- [Angular L10n with I18next](https://phrase.com/blog/posts/angular-l10n-with-i18next/)\n- [Best Libraries for Angular I18n](https://phrase.com/blog/posts/best-libraries-for-angular-i18n/)\n"
  },
  {
    "path": "README_DEPRECATED.md",
    "content": "[![npm version](https://badge.fury.io/js/angular-i18next.svg)](https://badge.fury.io/js/angular-i18next)\n[![Downloads](http://img.shields.io/npm/dm/angular-i18next.svg)](https://npmjs.org/package/angular-i18next)\n[![Build Status](https://travis-ci.com/Romanchuk/angular-i18next.svg?branch=master)](https://travis-ci.com/Romanchuk/angular-i18next)\n[![Coverage Status](https://coveralls.io/repos/github/Romanchuk/angular-i18next/badge.svg?branch=master)](https://coveralls.io/github/Romanchuk/angular-i18next?branch=master)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n[![paypal](https://img.shields.io/badge/say_thanks-%2410-green)](https://www.paypal.com/paypalme2/sergeyromanchuk/10USD)\n[![GitHub stars](https://img.shields.io/github/stars/romanchuk/angular-i18next?label=Please%20star%20repo%21&style=social)](https://github.com/romanchuk/angular-i18next)\n\n# angular-i18next\n[i18next](http://i18next.com/) v8.4+ integration with [angular](https://angular.io/) v2.0+\n\n[Live DEMO](https://romanchuk.github.io/angular-i18next/)\n\n - [Features](#features)\n - [Installation](#installation)\n - [Usage](#usage)\n - [Cookbook](#cookbook)\n - [Deep integration](#deep-integration)\n - [In-project testing](#in-project-testing)\n - [Demo](#demo)\n - [Articles](#articles)\n - [Support project](#support-on-beerpay)\n \n\n# Features\n\n- Native i18next [options](https://www.i18next.com/configuration-options.html)\n- Promise initialization\n- [i18next plugin](https://www.i18next.com/plugins-and-utils.html#plugins) support \n- Events support\n- Namespaces lazy load\n- i18next native [format](https://www.i18next.com/api.html#format) support\n- document.title localization\n- Error handling strategies\n- i18next namespaces and scopes (prefixes) for angular modules and components\n- AOT support\n- [Angular Package Format](https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs/preview) support\n\n[Related packages](#deep-integration) also has implementations for:\n- Reactive forms validators localization\n- Http error message localizer\n\n# Cheers!\nHey dude! Help me out for a couple of :beers:!\n\nПоддержи проект - угости автора кружечкой пива!\n\n[![paypal](https://img.shields.io/badge/paypal-%2410-green)](https://www.paypal.com/paypalme2/sergeyromanchuk/10USD)\n\n\n# Installation\n\n**1.** Install package\n\n   ```\n    npm install i18next --save\n    npm install angular-i18next --save\n  ```\n\n**2.** Import I18NextModule to AppModule\n\n```typescript\n\nimport { I18NextModule } from 'angular-i18next';\n\n@NgModule({\n  bootstrap: [ AppComponent ],\n  declarations: [   \n    AppComponent\n  ],\n  import: [\n    I18NextModule.forRoot()\n  ]\n})\nexport class AppModule {}\n\n```\n**3.** Import I18NextModule.forRoot() to AppModule and setup provider with \"init\" method (use native [options](https://www.i18next.com/overview/configuration-options)). Angular would not load until i18next initialize event fired\n> **Warning:**: options in example valid for i18next v20 (Always check latest API options of i18next)\n\n```typescript\nexport function appInit(i18next: ITranslationService) {\n    return () => i18next.init({\n        supportedLngs: ['en', 'ru'],\n        fallbackLng: 'en',\n        debug: true,\n        returnEmptyString: false,\n        ns: [\n          'translation',\n          'validation',\n          'error'          \n        ],\n      });\n}\n\nexport function localeIdFactory(i18next: ITranslationService)  {\n    return i18next.language;\n}\n\nexport const I18N_PROVIDERS = [\n{\n    provide: APP_INITIALIZER,\n    useFactory: appInit,\n    deps: [I18NEXT_SERVICE],\n    multi: true\n},\n{\n    provide: LOCALE_ID,\n    deps: [I18NEXT_SERVICE],\n    useFactory: localeIdFactory\n}];\n```\n\n```typescript\n@NgModule({\n    imports: [\n        ...\n        I18NextModule.forRoot()\n    ],\n    providers: [\n        ...\n        I18N_PROVIDERS, \n    ],\n    bootstrap: [AppComponent]\n})\nexport class AppModule {\n}\n```\n\n# Usage\n\n### Pipes\n\nUse \"i18next\" pipe to translate key:\n\n    <div>{{ 'test' | i18next }}</div>\n\nPassing [\"t options\"](https://www.i18next.com/api.html#t):\n\n    <div>{{ 'test' | i18next: { count: 5, nsSeparator: '#' } }}</div>\n\n\nTrigger native i18next [format method](https://www.i18next.com/formatting.html) by using I18NextFormatPipe or I18NextPipe with option 'format':\n\n`{{ 'any_key' | i18next | i18nextFormat }}`\n\n`{{ 'any_key' | i18next: { format: 'cap' } }}`\n\n`{{ 'any_key' | i18nextCap }}`\n\n**Note:** Using \"i18nextCap\" you will get the same result as  `i18next: { format: 'cap' }`\n\n**REMEMBER** that format will not work until you set \"interpolation.format\" function in i18next options.\n\nI18NextModule has static method `static interpolationFormat(customFormat: Function = null): Function` that can be used as default interpolation format function (it provides 'upper', 'cap' and 'lower' formatters). You also can pass your custom function to be called after I18NextModule formatters:\n\n```typescript\nconst i18nextOptions = {\n  supportedLngs: ['en', 'ru'],\n  ns: [\n    'translation',\n    'validation',\n    'error',\n  ],\n  interpolation: {\n    format: I18NextModule.interpolationFormat((value, format, lng) => {\n      if(value instanceof Date)\n        return moment(value).format(format);\n      return value;\n    });\n    // format: I18NextModule.interpolationFormat()\n  }\n};\n\n```\n\n**i18nextEager pipe**\n\nThis is the impure analog of *i18next pipe* that is subscribed to language change, it will change string right away to choosen language (without reloading page).\n\n**Warning!**: Use i18nextEager only in combine with [OnPush change detection strategy](https://netbasal.com/a-comprehensive-guide-to-angular-onpush-change-detection-strategy-5bac493074a4), or else (default change detection) each pipe will retrigger more than one time (cause of performance issues).\n\nSubscribing to event observables:\n```typescript\nthis.i18NextService.events.languageChanged.subscribe(lang => {\n  // do something\n})\n```\n\nAdd a provider to module/component if you want to prefix child i18next keys:\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: 'feature' // set 'feature:' prefix \n}\n```\n```typescript\n{\n  provide: I18NEXT_SCOPE,\n  useValue: 'person' // set 'person.' prefix \n}\n```\nSince v3.1.0+ it is possible to pass array of namespaces (or scopes). [Key would fallback](https://www.i18next.com/api.html#t) to next namespace in array if the previous failed to resolve.\n\n`[feature_validators:key, validators:key]`\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: ['feature_validators', 'validators']\n}\n```\n_NOTE:_ **Do NOT** use default (or custom) i18next delimiters in namespace names.\n\n### Document title\nIf you want to turn on document title localization resolve Title as `I18NextTitle` imported from 'angular-i18next':\n\n```typescript\n{\n  provide: Title,\n  useClass: I18NextTitle\n}\n```\n\nAlso you can implement your own Title service with specific behavior. Inject `I18NextPipe` (or `I18NextService`) to service/component:\n```typescript\nimport { Injectable, Inject } from '@angular/core';\nimport { Title, DOCUMENT } from '@angular/platform-browser';\nimport { I18NextPipe } from 'angular-i18next';\n\n@Injectable()\nexport class I18NextTitle extends Title {\n   constructor(private i18nextPipe: I18NextPipe, @Inject(DOCUMENT) doc) {\n    super(doc);\n   }\n\n   setTitle(value: string) {\n    return super.setTitle(this.translate(value));\n   }\n\n   private translate(text: string) {\n     return this.i18nextPipe.transform(text, { format: 'cap'});\n   }\n}\n\n```\n\nWays to use I18NextService in your code:\n> **Warning:** Injection of **I18NextService** is possible, but it would not consider I18NEXT_NAMESPACE and I18NEXT_SCOPE providers. There are 2 possible reasons to inject **I18NextService**: initialization and subscription to its events. In all other cases inject **I18NextPipe**.\n1) **Recommended way:** Inject via **I18NEXT_SERVICE** token. By default it will inject instance of **I18NextService**.\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService) \n```\n\n2) Legacy way: Inject via type\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              private i18NextService: I18NextService) \n```\n\n### Error handling\n\nError handling is now configurable:\n  1) By default i18next promise will use NativeErrorHandlingStrategy. I18Next would be always resolve succesfully. Error could be get from 'then' handler parameter.\n  2) Set StrictErrorHandlingStrategy to reject load promises (init, languageChange, loadNamespaces) on first load fail (this was default in v2 but changed to fit [native i18next behavior](https://github.com/Romanchuk/angular-i18next/issues/9):\n\n    `I18NextModule.forRoot({ errorHandlingStrategy: StrictErrorHandlingStrategy })`\n\n    \n\n### Lazy loading\n\nUse I18NEXT_NAMESPACE_RESOLVER in your routes to to load i18next namespace.\n\nNote: It is not neccesary to register lazy loading namespaces in global i18next options.\n\n```\n{\n    path: 'rich_form',\n    loadChildren: 'app/features/rich_form_feature/RichFormFeatureModule#RichFormFeatureModule',\n    data: {\n      i18nextNamespaces: ['feature.rich_form']\n    },\n    resolve: {\n      i18next: I18NEXT_NAMESPACE_RESOLVER\n    }\n },\n\n```\nUse I18NextService.loadNamespaces() method to load namespaces in code.\n\n\n# Cookbook\n\n### i18next plugin support\n\n```typescript\nimport { I18NextModule, ITranslationService, I18NEXT_SERVICE } from 'angular-i18next';\n//  import Backend from 'i18next-xhr-backend'; //for i18next < 20.0.0\nimport HttpApi from 'i18next-http-backend';\nimport LanguageDetector from 'i18next-browser-languagedetector';\n\n...\n\ni18next.use(HttpApi)\n       .use(LanguageDetector)\n       .init(i18nextOptions)\n```\n\n\n\n\n### Initialize i18next before angular application\nAngular would not load until i18next initialize event fired\n```typescript\nexport function appInit(i18next: ITranslationService) {\n    return () => i18next.init();\n}\n\nexport function localeIdFactory(i18next: ITranslationService)  {\n    return i18next.language;\n}\n\nexport const I18N_PROVIDERS = [\n{\n    provide: APP_INITIALIZER,\n    useFactory: appInit,\n    deps: [I18NEXT_SERVICE],\n    multi: true\n},\n{\n    provide: LOCALE_ID,\n    deps: [I18NEXT_SERVICE],\n    useFactory: localeIdFactory\n}];\n```\n\n\n\n### Document title update on language or route change\n\n\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService) {\n      // page title subscription\n      // https://toddmotto.com/dynamic-page-titles-angular-2-router-events#final-code\n      this.router.events\n        .filter(event => event instanceof NavigationEnd)\n        .map(() => this.router.routerState.root)\n        .map(route => {\n          while (route.firstChild) route = route.firstChild;\n          return route;\n        })\n        .filter(route => route.outlet === 'primary')\n        .mergeMap(route => route.data)\n        .subscribe((event) => this.updatePageTitle(event['title']));\n  }\n\n  ngOnInit() {\n    this.i18NextService.events.languageChanged.subscribe(lang => {\n      let root = this.router.routerState.root;\n      if (root != null && root.firstChild != null) {\n        let data: any = root.firstChild.data;\n        this.updatePageTitle(data && data.value && data.value.title);\n      }\n    });\n  }\n\n  updatePageTitle(title: string): void {\n    let newTitle = title || 'application_title';\n    this.title.setTitle(newTitle);\n  }\n}\n```\nRoutes example:\n```typescript\nconst appRoutes: Routes = [\n  { \n    path: 'error',\n    component: AppErrorComponent,\n    data: { title: 'error:error_occured' }\n  },\n  { \n    path: 'denied',\n    component: AccessDeniedComponent,\n    data: { title: 'error:access_denied' }\n  }\n];\n```\n\n# What to do if... ?\n\n## New angular version released, but angular-i18next is not released YET!!!\n\nAngular releases mostly don't break angular-i18next, but we cannot tell ahead that current version of `angular-i18next` will work correctly with latest angular version.\n\nYou can override an angular-i18next `peerDependencies` in your `package.json` on your **own risk**:\n\n```json\n\"overrides\": {\n  \"angular-i18next\": {\n    \"@angular/common\": \"*\",\n    \"@angular/core\": \"*\",\n    \"@angular/platform-browser\": \"*\"\n  }\n}\n```\n\n# Deep integration\n\nList of packages to integrate angular and i18next more deeply:\n\n- [angular-validation-message](https://github.com/Romanchuk/angular-validation-message) - angular [reactive form validators](https://angular.io/guide/reactive-forms#step-2-making-a-field-required) integration (and [angular-validation-message-i18next ](https://github.com/Romanchuk/angular-validation-message-i18next) is i18next bridge to it). It gives you possibility to localize form validators and it automatically puts localized validator error message to markup (if there is one).\n- [angular-i18next-error-interceptor](https://github.com/LCGroupIT/angular-i18next-error-interceptor) - allows you to set default errot messages for non-200 http status responses. So if the back-end didn't specify { message: 'some error' } in a response (sort of contract with our backend) interceptor will check response status code and will fill { message: 'Server is not available. Please try again.' }. Also package includes pipe where you can pass HttpErrorResponse and it will return error message whenever it's back-end message or our localized message.\n\n# In-project testing\n\nYou might want to unit-test project components that are using i18next pipes\n\nExample tests setup:\n[libs/angular-i18next/src/tests/projectTests](https://github.com/Romanchuk/angular-i18next/tree/master/libs/angular-i18next/src/tests/projectTests)\n\n# Demo\n\n[Live DEMO](https://romanchuk.github.io/angular-i18next-demo/)\nDemo app source code available here: https://github.com/Romanchuk/angular-i18next-demo\n\n\n# Articles\n- [Angular L10n with I18next](https://phrase.com/blog/posts/angular-l10n-with-i18next/)\n- [Best Libraries for Angular I18n](https://phrase.com/blog/posts/best-libraries-for-angular-i18n/)\n\n"
  },
  {
    "path": "apps/angular-i18next-demo/.browserslistrc",
    "content": "# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.\n# For additional information regarding the format and rule options, please see:\n# https://github.com/browserslist/browserslist#queries\n\n# For the full list of supported browsers by the Angular framework, please see:\n# https://angular.io/guide/browser-support\n\n# You can see what browsers were selected by your queries by running:\n#   npx browserslist\n\nlast 1 Chrome version\nlast 1 Firefox version\nlast 2 Edge major versions\nlast 2 Safari major versions\nlast 2 iOS major versions\nFirefox ESR\n"
  },
  {
    "path": "apps/angular-i18next-demo/.eslintrc.json",
    "content": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\"],\n      \"extends\": [\n        \"plugin:@nx/angular\",\n        \"plugin:@angular-eslint/template/process-inline-templates\"\n      ],\n      \"rules\": {}\n    },\n    {\n      \"files\": [\"*.html\"],\n      \"extends\": [\"plugin:@nx/angular-template\"],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/jest.config.ts",
    "content": "/* eslint-disable */\nexport default {\n  displayName: 'angular-i18next-demo',\n  preset: '../../jest.preset.js',\n  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],\n  globals: {},\n  coverageDirectory: '../../coverage/apps/angular-i18next-demo',\n  transform: {\n    '^.+\\\\.(ts|mjs|js|html)$': [\n      'jest-preset-angular',\n      {\n        tsconfig: '<rootDir>/tsconfig.spec.json',\n        stringifyContentPathRegex: '\\\\.(html|svg)$',\n      },\n    ],\n  },\n  transformIgnorePatterns: ['node_modules/(?!.*\\\\.mjs$)'],\n  snapshotSerializers: [\n    'jest-preset-angular/build/serializers/no-ng-attributes',\n    'jest-preset-angular/build/serializers/ng-snapshot',\n    'jest-preset-angular/build/serializers/html-comment',\n  ],\n};\n"
  },
  {
    "path": "apps/angular-i18next-demo/project.json",
    "content": "{\n  \"name\": \"angular-i18next-demo\",\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"sourceRoot\": \"apps/angular-i18next-demo/src\",\n  \"prefix\": \"angular-i18next\",\n  \"tags\": [],\n  \"targets\": {\n    \"build\": {\n      \"executor\": \"@nx/angular:application\",\n      \"outputs\": [\"{options.outputPath}\"],\n      \"options\": {\n        \"browser\": \"apps/angular-i18next-demo/src/main.ts\",\n        \"outputPath\": \"dist/angular-i18next-demo\",\n        \"index\": \"apps/angular-i18next-demo/src/index.html\",\n        \"tsConfig\": \"apps/angular-i18next-demo/tsconfig.app.json\",\n        \"assets\": [\n          \"apps/angular-i18next-demo/src/assets/favicon.png\",\n          \"apps/angular-i18next-demo/src/assets\",\n          \"apps/angular-i18next-demo/src/locales\"\n        ],\n        \"styles\": [\"apps/angular-i18next-demo/src/styles.css\"],\n        \"scripts\": [],\n        \"server\": \"apps/angular-i18next-demo/src/main.server.ts\",\n        \"ssr\": {\n          \"entry\": \"apps/angular-i18next-demo/src/server.ts\"\n        },\n        \"outputMode\": \"server\"\n      },\n      \"configurations\": {\n        \"production\": {\n          \"budgets\": [\n            {\n              \"type\": \"initial\",\n              \"maximumWarning\": \"500kb\",\n              \"maximumError\": \"1mb\"\n            },\n            {\n              \"type\": \"anyComponentStyle\",\n              \"maximumWarning\": \"2kb\",\n              \"maximumError\": \"4kb\"\n            }\n          ],\n          \"fileReplacements\": [\n            {\n              \"replace\": \"apps/angular-i18next-demo/src/environments/environment.ts\",\n              \"with\": \"apps/angular-i18next-demo/src/environments/environment.prod.ts\"\n            }\n          ],\n          \"outputHashing\": \"all\"\n        },\n        \"development\": {\n          \"optimization\": false,\n          \"extractLicenses\": false,\n          \"sourceMap\": true,\n          \"namedChunks\": true\n        }\n      },\n      \"defaultConfiguration\": \"production\"\n    },\n    \"serve\": {\n      \"executor\": \"@nx/angular:dev-server\",\n      \"configurations\": {\n        \"production\": {\n          \"buildTarget\": \"angular-i18next-demo:build:production\"\n        },\n        \"development\": {\n          \"buildTarget\": \"angular-i18next-demo:build:development\"\n        }\n      },\n      \"defaultConfiguration\": \"development\"\n    },\n    \"extract-i18n\": {\n      \"executor\": \"@angular-devkit/build-angular:extract-i18n\",\n      \"options\": {\n        \"buildTarget\": \"angular-i18next-demo:build\"\n      }\n    },\n    \"lint\": {\n      \"executor\": \"@nx/eslint:lint\",\n      \"options\": {\n        \"lintFilePatterns\": [\n          \"apps/angular-i18next-demo/**/*.ts\",\n          \"apps/angular-i18next-demo/**/*.html\"\n        ]\n      }\n    },\n    \"test\": {\n      \"executor\": \"@nx/jest:jest\",\n      \"outputs\": [\"{workspaceRoot}/coverage/apps/angular-i18next-demo\"],\n      \"options\": {\n        \"jestConfig\": \"apps/angular-i18next-demo/jest.config.ts\",\n        \"passWithNoTests\": true\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/app.component.css",
    "content": ""
  },
  {
    "path": "apps/angular-i18next-demo/src/app/app.component.html",
    "content": "<div class=\"app-wrapper\">\n  @if (loading) {\n  <div class=\"app-loader\">\n      <div class=\"loader-pusher\">\n          <div class=\"spinner\">\n              <div class=\"spinner-tail\"></div>\n          </div>\n      </div>\n  </div>\n  }\n  <app-header></app-header>\n  <main>\n      <div class=\"app-body\">\n          <div class=\"container\">\n              <hr />\n              <p class=\"lead\">{{ 'intro' | i18next }}</p>\n              <hr />\n              <router-outlet></router-outlet>\n          </div>\n      </div>\n  </main>\n  <app-footer></app-footer>\n</div>\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/app.component.ts",
    "content": "\nimport { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';\nimport { Title } from '@angular/platform-browser';\nimport {\n  Event as RouterEvent, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router,\n  RouterOutlet\n} from '@angular/router';\nimport { I18NEXT_SERVICE, I18NextPipe, ITranslationService } from 'angular-i18next';\nimport { filter, map, mergeMap, tap } from 'rxjs/operators';\nimport { AppHeaderComponent } from \"./structure/app-header.component\";\nimport { AppFooterComponent } from \"./structure/app-footer.component\";\n\n\n@Component({\n  selector: 'app',\n  encapsulation: ViewEncapsulation.None,\n  templateUrl: './app.component.html',\n  standalone: true,\n  imports: [I18NextPipe, AppHeaderComponent, AppFooterComponent, RouterOutlet],\n})\nexport class AppComponent implements OnInit  {\n\n  loading = true;\n  start = 0;\n\n  get title() {\n    return this._title.getTitle();\n  }\n\n  constructor(private router: Router,\n              private _title: Title,\n              @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService) {\n\n\n      // spinner/loader subscription\n      router.events\n        .subscribe((event: RouterEvent) => {\n            this.navigationInterceptor(event);\n        });\n      // page title subscription\n      // https://toddmotto.com/dynamic-page-titles-angular-2-router-events#final-code\n      this.router.events\n        .pipe(\n            filter(event => event instanceof NavigationEnd),\n            map(() => this.router.routerState.root),\n            map(route => {\n              while (route.firstChild) route = route.firstChild;\n              return route;\n            }),\n            filter(route => route.outlet === 'primary'),\n            mergeMap(route => route.data)\n        )\n        .subscribe((event) => this.updatePageTitle(event['title']));\n  }\n\n  ngOnInit() {\n    this.i18NextService.events.languageChanged.subscribe(() => {\n      const root = this.router.routerState.root;\n      if (root != null && root.firstChild != null) {\n        const data = root.firstChild.data;\n        data\n          .pipe(\n            tap((data) => {\n              this.updatePageTitle(data && data['value'] && data['value'].title);\n            })\n          )\n          .subscribe();\n\n      }\n    });\n  }\n\n  // http://stackoverflow.com/questions/37069609/show-loading-screen-when-navigating-between-routes-in-angular-2\n  navigationInterceptor(event: RouterEvent): void {\n        if (event instanceof NavigationStart) {\n            this.loading = true;\n        }\n        if (event instanceof NavigationEnd\n            || event instanceof NavigationCancel\n            || event instanceof NavigationError) {\n            this.loading = false;\n        }\n    }\n\n    updatePageTitle(title: string): void {\n      const newTitle = title || 'application_title';\n      console.log('Setting page title:', newTitle);\n      this._title.setTitle(newTitle);\n      console.log('Setting page title end:', newTitle);\n    }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/app.config.server.ts",
    "content": "import { ApplicationConfig, mergeApplicationConfig } from '@angular/core';\nimport { provideServerRendering, withRoutes } from '@angular/ssr';\nimport { provideI18Next, withTitle } from 'angular-i18next';\nimport { withSSR } from 'angular-i18next/ssr';\nimport { appConfig } from './app.config';\nimport { serverRoutes } from './app.routes.server';\n\nconst serverConfig: ApplicationConfig = {\n  providers: [\n    provideServerRendering(withRoutes(serverRoutes)),\n    provideI18Next(withTitle(), withSSR()),\n  ],\n};\n\nexport const config = mergeApplicationConfig(appConfig, serverConfig);\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/app.config.ts",
    "content": "import { isPlatformBrowser } from '@angular/common';\nimport {\n  ApplicationConfig,\n  importProvidersFrom,\n  inject,\n  PLATFORM_ID,\n  provideAppInitializer,\n  provideZonelessChangeDetection,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n  BrowserModule,\n  provideClientHydration,\n  withEventReplay,\n} from '@angular/platform-browser';\nimport { I18NEXT_SERVICE, I18NextLoadResult, provideI18Next, withTitle } from 'angular-i18next';\nimport HttpApi from 'i18next-http-backend';\nimport LanguageDetector from 'i18next-browser-languagedetector';\nimport i18nextOptions from './i18next.options';\nimport { provideRouter } from '@angular/router';\nimport { appRoutes } from './app.routes';\n\nexport function appInit() {\n  return () => {\n    const i18next = inject(I18NEXT_SERVICE);\n    const platformId = inject(PLATFORM_ID);\n\n    if (!isPlatformBrowser(platformId)) {\n      return Promise.resolve();\n    }\n    const promise: Promise<I18NextLoadResult> = i18next\n      .use(HttpApi)\n      .use(LanguageDetector)\n      .init(i18nextOptions);\n    return promise;\n  };\n}\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideClientHydration(withEventReplay()),\n    provideZonelessChangeDetection(),\n    provideRouter(appRoutes),\n    importProvidersFrom(BrowserModule, FormsModule),\n    provideAppInitializer(appInit()),\n    provideI18Next(withTitle()),\n  ],\n};\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/app.routes.server.ts",
    "content": "import { RenderMode, ServerRoute } from '@angular/ssr';\n\nexport const serverRoutes: ServerRoute[] = [\n  {\n    path: '**',\n    renderMode: RenderMode.Server,\n  },\n];\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/app.routes.ts",
    "content": "import { Routes } from \"@angular/router\";\nimport { I18NEXT_NAMESPACE, i18NextNamespacesGuard } from \"angular-i18next\";\nimport { AccessDeniedComponent } from \"./content/access-denied/access-denied.component\";\nimport { SimpleDemoComponent } from \"./content/simple-demo.component\";\nimport { RichFormComponent } from \"./features/rich_form_feature/rich-form.component\";\n\nexport const appRoutes: Routes = [\n  { path: '', component: SimpleDemoComponent },\n  {\n    path: 'rich_form',\n    loadComponent: () => RichFormComponent,\n    data: {\n      title: 'feature.rich_form:title'\n    },\n    providers: [\n      {\n          provide: I18NEXT_NAMESPACE,\n          useValue: 'feature.rich_form',\n      },\n    ],\n    canActivate: [i18NextNamespacesGuard('feature.rich_form')]\n },\n  { path: 'denied', component: AccessDeniedComponent, data: { title: 'error:access_denied' }}\n];\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/content/access-denied/access-denied.component.html",
    "content": "<div class=\"main-header\">\n    <h2>{{ 'error:access_denied' | i18next: { case: 'cap' } }}</h2>\n</div>\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/content/access-denied/access-denied.component.ts",
    "content": "\nimport { Component } from '@angular/core';\nimport { I18NextPipe } from \"angular-i18next\";\n\n@Component({\n  selector: 'access-denied',\n  templateUrl: './access-denied.component.html',\n  standalone: true,\n  imports: [I18NextPipe]\n})\nexport class AccessDeniedComponent {\n\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/content/simple-demo.component.html",
    "content": "﻿<div class=\"container\">\n    <br/>\n    <h1>{{ 'simple_demo' | i18nextCap }}</h1>\n    <br/>\n    <hr/>\n    <div class=\"row\">\n        <h4>\n            {{ 'parametrized_string_title' | i18nextCap }}\n        </h4>\n        <div class=\"input-group\">\n            <div class=\"form-inline\">\n                <div class=\"form-group\">\n                    <span>{{ 'parametrized_string' | i18next: { value: value, str: str } }}</span>\n                </div>\n                <div class=\"form-group mx-sm-3\">\n                    <input name=\"number\" type=\"number\" class=\"form-control\" [(ngModel)]=\"value\">\n                </div>\n                <div class=\"form-group mx-sm-3\">\n                    <input name=\"str\" type=\"text\" class=\"form-control\" [(ngModel)]=\"str\">\n                </div>\n            </div>\n        </div>\n    </div>\n    <br/>\n    <hr/>\n    <div class=\"row\">\n        <h4>\n            {{ 'case_demo_title' | i18nextCap }}\n        </h4>\n        <div class=\"form-inline\">\n            <table class=\"table table-hover\">\n                <thead>\n                    <tr>\n                        <th>original</th>\n                        <th>capitalize</th>\n                        <th>lowercase</th>\n                        <th>uppercase</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr>\n                        <td>{{ 'case_demo' | i18next }}</td>\n                        <td>{{ 'case_demo' | i18next: { format: 'capitalize' } }}</td>\n                        <td>{{ 'case_demo' | i18next: { format: 'lowercase' } }}</td>\n                        <td>{{ 'case_demo' | i18next | i18nextFormat: 'uppercase' }}</td>\n                    </tr>\n                </tbody>\n            </table>\n        </div>\n    </div>\n</div>"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/content/simple-demo.component.ts",
    "content": "﻿\nimport { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { I18NextCapPipe, I18NextFormatPipe, I18NextPipe } from \"angular-i18next\";\n\n@Component({\n  selector: 'simple-demo',\n  encapsulation: ViewEncapsulation.None,\n  templateUrl: './simple-demo.component.html',\n  standalone: true,\n  imports: [I18NextCapPipe, I18NextPipe, I18NextFormatPipe, FormsModule]\n})\nexport class SimpleDemoComponent {\n  value = 15;\n  str = 'Hello';\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/features/rich_form_feature/rich-form.component.html",
    "content": "﻿<div>\n    <div class=\"main-header\">\n        <h1>{{ 'title' | i18next: { case: 'cap' } }}</h1>\n    </div>\n    <br/>\n    <form #requestHtmlForm class=\"form-default\" name=\"requestHtmlForm\" [formGroup]=\"form\" (ngSubmit)=\"onSubmit($event)\">\n\n        <div class=\"row\">\n            <div class=\"col-6\">\n                <div class=\"form-group\">\n                    <label class=\"control-label control-label-sm text-muted\">{{ 'email' | i18nextCap }}</label>\n                    <input i18nextValidationMessage name=\"email\" type=\"email\" class=\"form-control\" formControlName=\"email\" />\n                </div>\n            </div>\n            <div class=\"col-6\">\n                <div class=\"form-group\">\n                    <label class=\"control-label control-label-sm text-muted\">{{ 'count' | i18nextCap }}</label>\n                    <input  i18nextValidationMessage name=\"count\" type=\"number\" class=\"form-control\" formControlName=\"count\" />\n                </div>\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <div>{{ 'technical_contact' | i18nextEager }}</div>\n        </div>\n\n        <div formGroupName=\"technicalContact\">\n\n            <div class=\"row\">\n                <div class=\"col-6\">\n                    <div class=\"form-group\">\n                        <label class=\"control-label control-label-sm text-muted\">{{ 'person.last_name' | i18next: { format: 'cap' } }}</label>\n                        <input i18nextValidationMessage class=\"form-control\" type=\"text\" formControlName=\"lastName\"/>\n                    </div>\n                </div>\n                <div class=\"col-6\">\n                    <div class=\"form-group\">\n                        <label class=\"control-label control-label-sm text-muted\">{{ 'person.first_name' | i18next: { format: 'cap' } }}</label>\n                        <input i18nextValidationMessage class=\"form-control\" type=\"text\" formControlName=\"firstName\">\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"row\">\n                <div class=\"col-6\">\n                    <div class=\"form-group\">\n                        <label class=\"control-label control-label-sm text-muted\">{{ 'person.middle_name' | i18next: { format: 'cap' } }}</label>\n                        <input i18nextValidationMessage class=\"form-control\" type=\"text\" formControlName=\"middleName\">\n                    </div>\n                </div>\n                <div class=\"col-6\">\n                </div>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-4\">\n                <div class=\"form-group\">\n                    <button type=\"submit\" class=\"btn btn-primary btn-block\">{{ 'buttons.send' | i18nextCap }}</button>\n                </div>\n            </div>\n        </div>\n    </form>\n</div>\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/features/rich_form_feature/rich-form.component.ts",
    "content": "﻿\nimport { Component, ViewEncapsulation } from '@angular/core';\nimport { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';\nimport { I18NextCapPipe, I18NextEagerPipe, I18NextPipe } from \"angular-i18next\";\nimport { I18NextValidationMessageDirective } from 'angular-i18next/forms';\nimport { ValidationDirtyChecker } from '../../../lib/validation/services/ValidationDirtyChecker';\nimport { RichFormModel } from './rich-form.model';\n\n@Component({\n  selector: 'rich-form',\n  encapsulation: ViewEncapsulation.None,\n  templateUrl: './rich-form.component.html',\n  standalone: true,\n  imports: [I18NextCapPipe, I18NextPipe, I18NextEagerPipe, ReactiveFormsModule, I18NextValidationMessageDirective],\n  providers: [ValidationDirtyChecker]\n})\nexport class RichFormComponent {\n\n  form: FormGroup;\n  model: RichFormModel = new RichFormModel();\n\n  constructor(private fb: FormBuilder, private readonly validationDirtyChecker: ValidationDirtyChecker) {\n    this.form = this.fb.group({\n      'count': [this.model.count, [Validators.min(1), Validators.max(3)]],\n      'email': [this.model.email, [Validators.email]],\n      'technicalContact': this.fb.group({\n        'firstName': [this.model.technicalContact.firstName, [Validators.required]],\n        'lastName': [this.model.technicalContact.lastName, [Validators.required]],\n        'middleName': [this.model.technicalContact.middleName, [Validators.required]],\n      })\n    });\n  }\n\n\n  onSubmit(e: Event) {\n    if (!this.form.valid) {\n        this.validationDirtyChecker.markControlsDirty(this.form);\n         return;\n    }\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/features/rich_form_feature/rich-form.model.ts",
    "content": "export class Contact {\n    lastName: string | undefined;\n    firstName: string | undefined;\n    middleName: string | undefined;\n}\n\nexport class RichFormModel {\n    email: string | undefined;\n    count = 0;\n    technicalContact: Contact = new Contact();\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/i18next.options.ts",
    "content": "import { defaultInterpolationFormat, interpolationFormat } from \"angular-i18next\";\nimport type * as i18n from 'i18next';\nimport type { HttpBackendOptions } from \"i18next-http-backend\";\n\nexport const i18nextOptions: i18n.InitOptions & { backend: HttpBackendOptions} = {\n  supportedLngs:['en', 'ru'],\n  fallbackLng: 'en',\n  debug: true,\n  returnEmptyString: false,\n  ns: [\n    'translation',\n    'validation',\n    'error'\n  ],\n  interpolation: {\n    format: interpolationFormat(defaultInterpolationFormat)\n  },\n  //backend plugin options\n  backend: {\n    loadPath: 'locales/{{lng}}.{{ns}}.json',\n  },\n  // lang detection plugin options\n  detection: {\n    // order and from where user language should be detected\n    order: ['cookie', 'header'],\n\n    // keys or params to lookup language from\n    lookupCookie: 'lang',\n   // lookupHeader: 'accept-language',\n    // cache user language on\n    caches: ['cookie'],\n\n    // optional expire and domain for set cookie\n    cookieMinutes: 10080, // 7 days\n  }\n};\n\nexport default i18nextOptions;\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/app-error.component.html",
    "content": "<div class=\"error-page\">\n    <div class=\"viewport\">\n        <div class=\"page-404\">\n            <div class=\"cols\">\n                <div class=\"col\">\n                    <div class=\"error-code\">{{ 'error:oops' | i18next }}</div>\n                </div>\n                <div class=\"col\">\n                    <div class=\"error-description\">{{ 'error:error_occured_onload' | i18next }}</div>\n                    <ul>\n                        <li>\n                            <p>{{ 'error:contact_administrator_or_try_to_clear_browser_chache_and_restart_application' | i18next }}</p>\n                            <button class=\"btn btn-success btn-block\" (click)=\"reload()\">{{ 'error:restart' | i18next }}</button>\n                            <div class=\"popover-wrapper\">\n                                @if (showed) {\n                                  <div>\n                                    <svg class=\"icon\" (click)=\"close()\">\n                                        <use xmlns:xlink=\"http://www.w3.org/1999/xlink\" xlink:href=\"assets/images/icons.svg#cross\"></use>\n                                    </svg>\n                                    <div class=\"popover-header\">{{ 'error:cookies.how_to' | i18next }}</div>\n                                    <div class=\"popover-body\">{{ 'error:cookies.clear_chrome' | i18next }}</div>\n                                 </div>\n                                }\n\n                                <svg class=\"icon icon-question-circle-black\" placement=\"right\" (click)=\"toggle()\">\n                                    <use xmlns:xlink=\"http://www.w3.org/1999/xlink\" xlink:href=\"assets/images/icons.svg#question-circle-black\"></use>\n                                </svg>\n                            </div>\n                        </li>\n                        <li>\n                            <p>{{ 'error:need_help_write_to_us' | i18next }}</p>\n                            <a class=\"link text-sm\" href=\"#\">\n                                {{ 'error:write' | i18next }}\n                                <svg class=\"icon icon_link-arrow\">\n                                    <use xlink:href=\"assets/images/icons.svg#link-arrow\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"></use>\n                                </svg>\n                            </a>\n                        </li>\n                    </ul>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/app-error.component.ts",
    "content": "\nimport { Component, ViewEncapsulation } from '@angular/core';\nimport { I18NextPipe } from 'angular-i18next';\n\n@Component({\n  selector: 'app-error',\n  encapsulation: ViewEncapsulation.None,\n  templateUrl: './app-error.component.html',\n  standalone: true,\n  imports: [I18NextPipe]\n})\nexport class AppErrorComponent {\n  public showed = false;\n  public toggle(){\n    this.showed = !this.showed;\n  }\n  public close(){\n    this.showed = false;\n  }\n  public reload(){\n    document.location.href = document.location.protocol + '//' + document.location.host;\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/app-footer.component.html",
    "content": "﻿<footer>\n    <nav class=\"fixed-bottom navbar navbar-expand-lg navbar-light\" style=\"background-color: #f2f2f2;\">\n        <div><a href=\"https://angular.io\" target=\"_blank\">angular</a> v.{{angularVersion}} / <a href=\"https://www.i18next.com\" target=\"_blank\">i18next</a> v.{{i18nextVersion}}</div>\n\n\n        <iframe src=\"https://ghbtns.com/github-btn.html?user=romanchuk&repo=angular-i18next&type=star&count=true\" frameborder=\"0\" scrolling=\"0\" width=\"170px\" height=\"20px\"></iframe>\n    </nav>\n</footer>"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/app-footer.component.ts",
    "content": "﻿\nimport { Component, VERSION, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'app-footer',\n  encapsulation: ViewEncapsulation.None,\n  templateUrl: './app-footer.component.html',\n  standalone: true\n})\nexport class AppFooterComponent {\n  angularVersion = '0.0.0';\n  i18nextVersion = '0.0.0';\n  constructor(){\n    this.angularVersion = VERSION.full;\n    this.i18nextVersion = '24.2.1';\n  }\n\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/app-header.component.html",
    "content": "﻿<header>\n    <nav class=\"navbar navbar-expand-lg navbar-dark\" style=\"background-color: #f2f2f2;\">\n        <div class=\"collapse navbar-collapse\" id=\"navbarSupportedContent\">\n            <a class=\"navbar-brand\" href=\"#\">\n                <img src=\"assets/logo.svg\" width=\"80\" height=\"40\" class=\"d-inline-block align-top\" alt=\"\" />\n            </a>\n            <b>{{ 'application_title' | i18next }}</b>\n            <ul class=\"nav nav-pills\">\n                <li class=\"nav-item\">\n                    <a class=\"nav-link\" routerLink=\"/\">{{ 'simple_demo' | i18nextCap }}</a>\n                </li>\n                <li class=\"nav-item\">\n                    <a class=\"nav-link\" routerLink=\"/rich_form\">{{ 'rich_form_title' | i18nextCap }}</a>\n                </li>\n            </ul>\n        </div>\n        <header-language></header-language>\n    </nav>\n</header>\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/app-header.component.ts",
    "content": "﻿import { Component, ViewEncapsulation } from '@angular/core';\nimport { I18NextCapPipe, I18NextPipe } from 'angular-i18next';\nimport { HeaderLanguageComponent } from \"./header-controls/header.language.component\";\nimport { RouterLink } from '@angular/router';\n\n@Component({\n  selector: 'app-header',\n  encapsulation: ViewEncapsulation.None,\n  templateUrl: './app-header.component.html',\n  standalone: true,\n  imports: [I18NextPipe, I18NextCapPipe, HeaderLanguageComponent, RouterLink],\n})\nexport class AppHeaderComponent {}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/header-controls/header.language.component.html",
    "content": "<div>\n  @for (lang of languages; track lang) {\n    @if (currentLanguage() !== lang) {\n      <a  href=\"javascript:void(0)\" class=\"link lang-item {{lang}}\" (click)=\"changeLanguage(lang)\">{{ '_languages.' + lang | i18nextCap }}</a>\n    } @else {\n      <span class=\"current lang-item {{lang}}\">{{ '_languages.' + lang | i18nextCap }}</span>\n    }\n  }\n</div>\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/app/structure/header-controls/header.language.component.ts",
    "content": "\nimport { Component, Inject, ViewEncapsulation, OnInit, signal } from '@angular/core';\nimport { I18NEXT_SERVICE, I18NextCapPipe, ITranslationService } from 'angular-i18next';\n\n@Component({\n  selector: 'header-language',\n  encapsulation: ViewEncapsulation.None,\n  templateUrl: './header.language.component.html',\n  standalone: true,\n  imports: [I18NextCapPipe]\n})\nexport class HeaderLanguageComponent implements OnInit {\n\n  currentLanguage = signal('ru');\n  languages: string[] = ['ru', 'en'];\n\n  constructor(\n    @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService\n  )\n  {}\n\n  ngOnInit() {\n    this.i18NextService.events.initialized.subscribe((e) => {\n      if (e) {\n        this.updateState(this.i18NextService.language);\n      }\n    });\n  }\n\n  changeLanguage(lang: string){\n    if (lang !== this.i18NextService.language) {\n      this.i18NextService.changeLanguage(lang).then(() => {\n        this.updateState(lang);\n        document.location.reload();\n      });\n    }\n  }\n\n  private updateState(lang: string) {\n    this.currentLanguage.set(lang);\n  }\n\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/assets/.gitkeep",
    "content": ""
  },
  {
    "path": "apps/angular-i18next-demo/src/assets/ng-validation.css",
    "content": "\ninput.ng-dirty.ng-invalid,\ntextarea.ng-dirty.ng-invalid,\n.form-control.ng-dirty.ng-invalid,\n.ng-dirty.ng-invalid:focus\n{\n    background-color: #FDEDED;\n    border-color: #D22630;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n}\n\n/* s7 ui kit fix */\n.form-group .error-container {\n  display: block;\n}\n\n.error-container {\n\tcolor: #D22630;\n\tpadding-top: 2px;\n}\n\n\n/* end fix */\n\ncheckbox.ng-invalid .custom-control-indicator,\nmultiplecheckbox.ng-invalid.ng-dirty .custom-control-indicator,\nflatpickr.ng-invalid.ng-dirty .form-control, \ndatepicker.ng-invalid.ng-dirty .select2-container .select2-selection,\nradio-button.ng-dirty.ng-invalid .custom-control-indicator,\ndiv.ng-invalid.ng-dirty.form-group-valid .custom-control-indicator,\ndiv.ng-invalid.ng-dirty.form-group-valid .select2-container .select2-selection {\n    border-color: #D22630;\n    background-color: #FDEDED;\n}\n\nradio-button + radio-button,\ncheckbox + checkbox {\n  margin-left: 15px;\n}\n\n\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/environments/environment.prod.ts",
    "content": "export const environment = {\n  production: true\n};\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/environments/environment.ts",
    "content": "// This file can be replaced during build by using the `fileReplacements` array.\n// `ng build` replaces `environment.ts` with `environment.prod.ts`.\n// The list of file replacements can be found in `angular.json`.\n\nexport const environment = {\n  production: false\n};\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/index.html",
    "content": "<!DOCTYPE html>\n<html>\n\n  <head>\n      <meta charset=\"utf-8\">\n      <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\">\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n      <meta name=\"description\" content=\"DEMO angular-i18next\">\n\n      <title>\n          DEMO angular-i18next\n      </title>\n      <link rel=\"icon\" type=\"image/ico\" href=\"assets/favicon.png\" />\n      <!-- base url -->\n      <base href=\"/\">\n\n      <script src=\"https://code.jquery.com/jquery-3.2.1.slim.min.js\" integrity=\"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN\" crossorigin=\"anonymous\"></script>\n      <script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js\" integrity=\"sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh\" crossorigin=\"anonymous\"></script>\n      <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js\" integrity=\"sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ\" crossorigin=\"anonymous\"></script>\n\n      <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css\" integrity=\"sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb\" crossorigin=\"anonymous\">\n\n  </head>\n\n  <body>\n\n      <app>\n          <style type=\"text/css\">\n              * {\n                  outline: 0!important\n              }\n\n              .app-loader {\n                  display: table;\n                  height: 100vh;\n                  width: 100%\n              }\n\n              .app-loader .loader-pusher {\n                  display: table-cell;\n                  text-align: center;\n                  vertical-align: middle\n              }\n\n              .app-loader .loader-pusher .spinner {\n                  background: url('assets/logo.svg') no-repeat 50% 50% #f2f2f2;\n                  background-size: 80%;\n                  border-radius: 50%;\n                  display: inline-block;\n                  height: 80px;\n                  position: relative;\n                  width: 80px;\n                  line-height: 80px;\n                  text-align: center;\n                  color: #fff;\n              }\n\n              .app-loader .loader-pusher .spinner .spinner-tail {\n                  -webkit-animation: spinner .86s linear infinite;\n                  animation: spinner .86s linear infinite;\n                  background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzgiIGhlaWdodD0iMzgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IHgxPSI4LjA0MiUiIHkxPSIwJSIgeDI9IjY1LjY4MiUiIHkyPSIyMy44NjUlIiBpZD0iYSI+PHN0b3Agc3RvcC1jb2xvcj0iI2JlYmViZSIgc3RvcC1vcGFjaXR5PSIwIiBvZmZzZXQ9IjAlIi8+PHN0b3Agc3RvcC1jb2xvcj0iI2JlYmViZSIgc3RvcC1vcGFjaXR5PSIuNjMxIiBvZmZzZXQ9IjYzLjE0NiUiLz48c3RvcCBzdG9wLWNvbG9yPSIjYmViZWJlIiBvZmZzZXQ9IjEwMCUiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxIDEpIiBmaWxsPSJub25lIj48cGF0aCBkPSJNMzYgMThjMC05Ljk0LTguMDYtMTgtMTgtMTgiIHN0cm9rZT0idXJsKCNhKSIgc3Ryb2tlLXdpZHRoPSIyIi8+PGNpcmNsZSBmaWxsPSIjYmViZWJlIiBjeD0iMzYiIGN5PSIxOCIgcj0iMSIvPjwvZz48L3N2Zz4=) 0 0/cover no-repeat;\n                  bottom: -10px;\n                  left: -10px;\n                  position: absolute;\n                  right: -10px;\n                  top: -10px;\n              }\n\n              @-webkit-keyframes spinner {\n                  0% {\n                      -webkit-transform: rotate(0);\n                      transform: rotate(0)\n                  }\n                  100% {\n                      -webkit-transform: rotate(360deg);\n                      transform: rotate(360deg)\n                  }\n              }\n\n              @keyframes spinner {\n                  0% {\n                      -webkit-transform: rotate(0);\n                      transform: rotate(0)\n                  }\n                  100% {\n                      -webkit-transform: rotate(360deg);\n                      transform: rotate(360deg)\n                  }\n              }\n          </style>\n          <div class=\"app-loader\">\n              <div class=\"loader-pusher\">\n                  <div class=\"spinner\">\n                      <div class=\"spinner-tail\"></div>\n                  </div>\n              </div>\n          </div>\n      </app>\n  </body>\n\n</html>\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/lib/validation/services/ValidationDirtyChecker.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { FormArray, FormGroup } from '@angular/forms';\n\n@Injectable()\nexport class ValidationDirtyChecker {\n  markControlsDirty(group: FormGroup | FormArray) {\n    const controls = group.controls;\n    for (const ck in controls) {\n      // eslint-disable-next-line no-prototype-builtins\n      if (controls.hasOwnProperty(ck)) {\n        const c = (<any>controls)[ck];\n        c.markAsDirty({ onlySelf: true });\n        if (c instanceof FormGroup || c instanceof FormArray)\n          this.markControlsDirty(c);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/lib/validation/validators/ArrayValidators.js",
    "content": "var ArrayValidators = (function () {\n    function ArrayValidators() {\n    }\n    ArrayValidators.minLength = function (minLength, ignoreNullAndUndefined) {\n        if (ignoreNullAndUndefined === void 0) { ignoreNullAndUndefined = false; }\n        return function (control) {\n            if (control) {\n                var isArray = control.value instanceof Array;\n                if (!isArray)\n                    throw new Error('Control value must be array!');\n                var val = control.value;\n                var isValid = false;\n                if (!ignoreNullAndUndefined)\n                    isValid = val.length >= minLength;\n                else\n                    isValid = val.filter(function (v) { return v != null; }).length >= minLength;\n                if (isValid)\n                    return null;\n                return { 'arrayMinLength': minLength };\n            }\n        };\n    };\n    ArrayValidators.maxLength = function (maxLength, ignoreNullAndUndefined) {\n        if (ignoreNullAndUndefined === void 0) { ignoreNullAndUndefined = false; }\n        return function (control) {\n            if (control) {\n                var isArray = control.value instanceof Array;\n                if (!isArray)\n                    throw new Error('Control value must be array!');\n                var val = control.value;\n                var isValid = false;\n                if (!ignoreNullAndUndefined)\n                    isValid = val.length <= maxLength;\n                else\n                    isValid = val.filter(function (v) { return v != null; }).length <= maxLength;\n                if (isValid)\n                    return null;\n                return { 'arrayMaxLength': maxLength };\n            }\n        };\n    };\n    ArrayValidators.eqLength = function (length, ignoreNullAndUndefined) {\n        if (ignoreNullAndUndefined === void 0) { ignoreNullAndUndefined = false; }\n        return function (control) {\n            if (control) {\n                var isArray = control.value instanceof Array;\n                if (!isArray)\n                    throw new Error('Control value must be array!');\n                var val = control.value;\n                var isValid = false;\n                if (!ignoreNullAndUndefined)\n                    isValid = val.length === length;\n                else\n                    isValid = val.filter(function (v) { return v != null; }).length === length;\n                if (isValid)\n                    return null;\n                return { 'arrayMaxLength': length };\n            }\n        };\n    };\n    return ArrayValidators;\n}());\nexport { ArrayValidators };\n//# sourceMappingURL=ArrayValidators.js.map"
  },
  {
    "path": "apps/angular-i18next-demo/src/lib/validation/validators/ArrayValidators.ts",
    "content": "import { OnChanges, SimpleChanges, Component, Directive, forwardRef } from '@angular/core';\nimport { Validator, AsyncValidatorFn, ValidatorFn, FormControl, FormGroup, FormArray, AbstractControl, NG_VALIDATORS } from '@angular/forms';\n\nexport class ArrayValidators {\n  static minLength(minLength: Number, ignoreNullAndUndefined: Boolean = false): ValidatorFn {\n    return (control: FormControl) => {\n      if (control) {\n        let isArray = control.value instanceof Array;\n        if (!isArray)\n          throw new Error('Control value must be array!');\n        let val: Array<any> = control.value;\n        let isValid: Boolean = false;\n        if (!ignoreNullAndUndefined)\n          isValid = val.length >= minLength;\n        else\n          isValid = val.filter(v => v != null).length >= minLength;\n        if (isValid)\n          return null;\n        return { 'arrayMinLength': minLength };\n      }\n    };\n  }\n  static maxLength(maxLength: Number, ignoreNullAndUndefined: Boolean = false): ValidatorFn {\n    return (control: FormControl) => {\n      if (control) {\n        let isArray = control.value instanceof Array;\n        if (!isArray)\n          throw new Error('Control value must be array!');\n        let val: Array<any> = control.value;\n        let isValid: Boolean = false;\n        if (!ignoreNullAndUndefined)\n          isValid = val.length <= maxLength;\n        else\n          isValid = val.filter(v => v != null).length <= maxLength;\n        if (isValid)\n          return null;\n        return { 'arrayMaxLength': maxLength };\n      }\n    };\n  }\n\n  static eqLength(length: Number, ignoreNullAndUndefined: Boolean = false): ValidatorFn {\n    return (control: FormControl) => {\n      if (control) {\n        let isArray = control.value instanceof Array;\n        if (!isArray)\n          throw new Error('Control value must be array!');\n        let val: Array<any> = control.value;\n        let isValid: Boolean = false;\n        if (!ignoreNullAndUndefined)\n          isValid = val.length === length;\n        else\n          isValid = val.filter(v => v != null).length === length;\n        if (isValid)\n          return null;\n        return { 'arrayMaxLength': length };\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/lib/validation/validators/ConditionalValidator.js",
    "content": "import 'rxjs/add/operator/distinctUntilChanged'; // fn distinctUntilChanged\nvar ConditionalValidator = (function () {\n    function ConditionalValidator() {\n    }\n    /**\n    *  Валидатор, который применяет валидатор при некотором заданом условии.\n    * @param {ConditionalFunc} conditional Условие для применения валидатора\n    * @param {ValidatorFn} validator Валидатор, который будет применен\n    * @param {Boolean} trackParentOnly Подписка только на изменение значения родителя (По-умолчанию подписка на root)\n    */\n    ConditionalValidator.set = function (conditional, validator, trackParentOnly) {\n        if (trackParentOnly === void 0) { trackParentOnly = null; }\n        var revalidateSub;\n        return function (control) {\n            if (control && control.parent) {\n                if (!revalidateSub) {\n                    revalidateOnChanges(control, trackParentOnly);\n                    revalidateSub = true;\n                }\n                if (conditional(control.root)) {\n                    return validator(control);\n                }\n            }\n            return null;\n        };\n    };\n    /* Не реализован */\n    ConditionalValidator.setAsync = function (conditional, validator) {\n        throw new Error('Not implemented'); // todo: implement\n    };\n    ConditionalValidator.equivalent = function (controlKey, expectedValue) {\n        return function (rootGroup) {\n            var control = rootGroup.get(controlKey);\n            if (!control)\n                return expectedValue === undefined;\n            return expectedValue === control.value;\n        };\n    };\n    return ConditionalValidator;\n}());\nexport { ConditionalValidator };\nfunction revalidateOnChanges(control, trackParentOnly) {\n    if (trackParentOnly === void 0) { trackParentOnly = null; }\n    var parentControl = trackParentOnly ? control.parent : control.root;\n    parentControl.valueChanges\n        .distinctUntilChanged(function (a, b) {\n        // These will always be plain objects coming from the form, do a simple comparison\n        if (a && !b || !a && b) {\n            return false;\n        }\n        else if (a && b && Object.keys(a).length !== Object.keys(b).length) {\n            return false;\n        }\n        else if (a && b) {\n            for (var i in a) {\n                if (a[i] !== b[i]) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    })\n        .subscribe(function () {\n        control.updateValueAndValidity({ onlySelf: true, emitEvent: false });\n    });\n}\n//# sourceMappingURL=ConditionalValidator.js.map"
  },
  {
    "path": "apps/angular-i18next-demo/src/lib/validation/validators/ConditionalValidator.ts",
    "content": "import { Validator, AsyncValidatorFn, ValidatorFn, FormControl, FormGroup, FormArray, AbstractControl } from '@angular/forms';\nimport { distinctUntilChanged } from 'rxjs/operators';\n\n// todo: доработать ConditionalValidator, чтобы он работал в связке с асинхронным валидатором (сейчас валится)\n\n/* usage\n\nthis.formBuilder.group({\n    vehicleType: ['', Validators.required],\n    licencePlate: [\n        '',\n        ConditionalValidator.apply(\n            group => group.controls.vehicleType.value === 'car',\n            Validators.compose([\n                Validators.required,\n                Validators.minLength(6)\n            ])\n        ),\n    ]\n});\n\n\nthis.formBuilder.group({\n    country: ['', Validators.required],\n    vehicleType: ['', Validators.required],\n    licencePlate: [\n        '',\n        Validators.compose([\n            ConditionalValidator.apply(\n                group => group.controls.vehicleType.value === 'car',\n                Validators.required\n            ),\n            ConditionalValidator.apply(\n                group => group.controls.country.value === 'sweden',\n                Validators.minLength(6)\n            ),\n        ])\n    ]\n});\n\n*/\n\n\ninterface ConditionalFunc {\n  (rootGroup: FormGroup | FormArray): Boolean;\n}\n\n\nexport class ConditionalValidator {\n  /**\n  *  Валидатор, который применяет валидатор при некотором заданом условии.\n  * @param {ConditionalFunc} conditional Условие для применения валидатора\n  * @param {ValidatorFn} validator Валидатор, который будет применен\n  * @param {Boolean} trackParentOnly Подписка только на изменение значения родителя (По-умолчанию подписка на root)\n  */\n  static set(conditional: ConditionalFunc, validator: ValidatorFn, trackParentOnly: Boolean = null): ValidatorFn {\n    let revalidateSub: Boolean;\n    return (control: FormControl) => {\n      if (control && control.parent) {\n        if (!revalidateSub) {\n          revalidateOnChanges(control, trackParentOnly);\n          revalidateSub = true;\n        }\n        if (conditional(<FormGroup|FormArray>control.root)) {\n          return validator(control);\n        }\n      }\n      return null;\n    };\n  }\n\n  /* Не реализован */\n  static setAsync(conditional: Function, validator: AsyncValidatorFn): AsyncValidatorFn {\n    throw new Error('Not implemented'); // todo: implement\n  }\n\n  static equivalent(controlKey: string, expectedValue: any): ConditionalFunc {\n    return (rootGroup: FormGroup|FormArray) => {\n      let control = rootGroup.get(controlKey);\n      if (!control)\n        return expectedValue === undefined;\n      return expectedValue === control.value;\n    }\n  }\n}\n\nfunction revalidateOnChanges(control: AbstractControl, trackParentOnly: Boolean = null): void {\n  let parentControl = trackParentOnly ? control.parent : control.root;\n  parentControl.valueChanges\n    .pipe(\n        distinctUntilChanged((a, b) => {\n          // These will always be plain objects coming from the form, do a simple comparison\n          if (a && !b || !a && b) {\n            return false;\n          } else if (a && b && Object.keys(a).length !== Object.keys(b).length) {\n            return false;\n          } else if (a && b) {\n            for (let i in a) {\n              if (a[i] !== b[i]) {\n                return false;\n              }\n            }\n          }\n          return true;\n        })\n    )\n    .subscribe(() => {\n      control.updateValueAndValidity({ onlySelf: true, emitEvent: false });\n    });\n}\n\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/en.error.json",
    "content": "{\n  \"oops\": \"Oops!\",\n  \"error_occured\": \"Error has occured\",\n  \"error_occured_onload\": \"$t(error:error_occured)\",\n  \"access_denied\": \"Access is denied\",\n  \"reload\": \"Reload\",\n  \"restart\": \"Restart\",\n  \"contact_administrator_or_try_to_clear_browser_chache_and_restart_application\": \"Contact your administrator or clear browser cache and restart page.\",\n  \"need_help_write_to_us\": \"Need help? Contact us.\",\n  \"write\": \"Contact\",\n  \"cookies\": {\n    \"how_to\": \"How to clear browser cache and cookies\",\n    \"chrome_clear\": \"Если у вас Google Chrome, то:<ol><li>Запустите Chrome.</li><li>Нажмите на значок&nbsp;<img src=\\\"//storage.googleapis.com/support-kms-prod/5C6FB52C8BBB2C12DC89B5F42F16B9B5E9CF\\\" width=\\\"18\\\" height=\\\"18\\\" alt=\\\"Настройка и управление Google Chrome\\\" title=\\\"Настройка и управление Google Chrome\\\"> на панели инструментов.</li><li>В меню <strong>Дополнительные инструменты</strong> нажмите <strong>Удаление данных о просмотренных страницах</strong>.</li><li>В окне \\\"Очистить историю\\\" выберите пункты <strong>Файлы cookie, а также другие данные сайтов и плагинов</strong> и <strong>Изображения и другие файлы, сохраненные в кеше</strong>.</li><li>В раскрывающемся меню в верхней части страницы выберите период, данные за который нужно удалить. Выберите вариант <strong>за все время</strong>, если вы хотите удалить все сведения.</li><li>Нажмите кнопку <strong>Очистить историю</strong>.</li></ol>\"\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/en.feature.rich_form.json",
    "content": "{\n    \"title\": \"Rich form with validation\",\n    \"technical_contact\": \"technical contact\",\n    \"count\": \"count\",\n    \"person\": {\n        \"first_name\": \"first name\",\n        \"last_name\": \"last name\",\n        \"middle_name\": \"middle name\"\n    }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/en.translation.json",
    "content": "﻿{\n    \"application_title\": \"Demo: angular-i18next\",\n    \"intro\": \"This application is demonstrating itegration of i18next library with angular. You can switch language in the navbar.\",\n    \"simple_demo\": \"Simple demo\",\n    \"rich_form_title\": \"Rich form with validation\",\n    \"parametrized_string_title\": \"parametrized string demo\",\n    \"case_demo_title\": \"i18next pipe 'format' option demo\",\n    \"case_demo\": \"rise and shine, Mr.Freeman\",\n    \"parametrized_string\": \"I am parametrized sting with a value: {{value}} and a string: '{{str}}'\",\n    \"email\": \"email\",\n    \"_languages\": {\n        \"ru\": \"Русский\",\n        \"en\": \"English\"\n    },\n    \"buttons\": {\n        \"send\": \"send\"\n    }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/en.validation.json",
    "content": "﻿{\n    \"required\": \"Field is required.\",\n    \"error\": \"Error occured.\",\n    \"min\": \"Minimum value is {{min}}. Was {{actual}}.\",\n    \"max\": \"Maximum value is {{max}}. Was {{actual}}.\",\n    \"email\": \"$t(validation:_fill) valid e-mail.\",\n    \"pattern\": \"$t(validation:_fill) valid value.\",\n    \"maxlength\": \"Maximum length {{requiredLength}}.\",\n\n    \"_fill\": \"Please fill in\",\n    \"control_specific\": {\n        \"technicalContact\": {\n            \"firstName\": {\n                \"required\": \"$t(validation:_fill) technical specialist's first name.\"\n            },\n            \"lastName\": {\n                \"required\": \"$t(validation:_fill) technical specialist's last name.\"\n            },\n            \"middleName\": {\n                \"required\": \"$t(validation:_fill) technical specialist's patronymic.\"\n            }\n        }\n    }\n}"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/ru.error.json",
    "content": "{\n  \"oops\": \"Упс!\",\n  \"error_occured\": \"произошла ошибка\",\n  \"error_occured_onload\": \"При загрузке приложения $t(error:error_occured)\",\n  \"access_denied\": \"Недостаточно прав\",\n  \"reload\": \"Перезагрузить\",\n  \"restart\": \"Перезапустить\",\n  \"contact_administrator_or_try_to_clear_browser_chache_and_restart_application\": \"Обратитесь к администратору либо попробуйте очистить кэш и перезапустить приложение\",\n  \"need_help_write_to_us\": \"Нужна помощь? Пишите нам.\",\n  \"write\": \"Написать\",\n  \"cookies\": {\n    \"how_to\": \"Как очистить кэш и удалить файлы cookie\",\n    \"chrome_clear\": \"Если у вас Google Chrome, то:<ol><li>Запустите Chrome.</li><li>Нажмите на значок&nbsp;<img src=\\\"//storage.googleapis.com/support-kms-prod/5C6FB52C8BBB2C12DC89B5F42F16B9B5E9CF\\\" width=\\\"18\\\" height=\\\"18\\\" alt=\\\"Настройка и управление Google Chrome\\\" title=\\\"Настройка и управление Google Chrome\\\"> на панели инструментов.</li><li>В меню <strong>Дополнительные инструменты</strong> нажмите <strong>Удаление данных о просмотренных страницах</strong>.</li><li>В окне \\\"Очистить историю\\\" выберите пункты <strong>Файлы cookie, а также другие данные сайтов и плагинов</strong> и <strong>Изображения и другие файлы, сохраненные в кеше</strong>.</li><li>В раскрывающемся меню в верхней части страницы выберите период, данные за который нужно удалить. Выберите вариант <strong>за все время</strong>, если вы хотите удалить все сведения.</li><li>Нажмите кнопку <strong>Очистить историю</strong>.</li></ol>\"\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/ru.feature.rich_form.json",
    "content": "{\n    \"title\": \"Форма с валидацией\",\n    \"technical_contact\": \"технический специалист\",\n    \"count\": \"кол-во\",\n    \"person\": {\n        \"first_name\": \"имя\",\n        \"last_name\": \"фамилия\",\n        \"middle_name\": \"отчество\"\n    }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/ru.translation.json",
    "content": "﻿{\n    \"application_title\": \"Демо: angular-i18next\",\n    \"intro\": \"Данное приложение демонстрирует интеграцию библиотеки i18next с angular. Вы можете сменить язык в шапке.\",\n    \"simple_demo\": \"простое демо\",\n    \"rich_form_title\": \"Форма с валидацией\",\n    \"parametrized_string_title\": \"демонстрация параметризованной строки\",\n    \"case_demo_title\": \"демонстрация опции 'format'\",\n    \"case_demo\": \"проснись и пой, мистер Фримэн\",\n    \"parametrized_string\": \"Я параметризованная строка значением: {{value}} и строкой: '{{str}}'\",\n    \"email\": \"email адрес\",\n    \"_languages\": {\n        \"ru\": \"Русский\",\n        \"en\": \"English\"\n    },\n    \"buttons\": {\n        \"send\": \"отправить\"\n    }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/locales/ru.validation.json",
    "content": "﻿{\n    \"required\": \"Заполните это поле.\",\n    \"error\": \"Возникла ошибка.\",\n    \"minValue\": \"Минимальное значение.\",\n    \"maxValue\": \"Максимальное значение.\",\n    \"min\": \"Минимальное значение: {{min}}. Текущее: {{actual}}.\",\n    \"max\": \"Максимальное значение: {{max}}. Текущее: {{actual}}.\",\n    \"email\": \"Введите валидный email.\",\n    \"pattern\": \"Введите валидное значение.\",\n    \"maxlength\": \"Максимальная длина {{requiredLength}}.\",\n\n    \"control_specific\": {\n        \"technicalContact\": {\n            \"firstName\": {\n                \"required\": \"Заполните имя технического специалиста.\",\n                \"pattern\": \"Имя технического специалиста содержит недопустимые символы.\"\n            },\n            \"lastName\": {\n                \"required\": \"Заполните фамилию технического специалиста.\",\n                \"pattern\": \"Фамилия технического специалиста содержит недопустимые символы.\"\n            },\n            \"middleName\": {\n                \"required\": \"Заполните отчество технического специалиста.\",\n                \"pattern\": \"Отчество технического специалиста содержит недопустимые символы.\"\n            }\n        }\n    }\n}"
  },
  {
    "path": "apps/angular-i18next-demo/src/main.server.ts",
    "content": "import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\nimport { config } from './app/app.config.server';\n\n\nconst bootstrap = (context: BootstrapContext) => bootstrapApplication(AppComponent, config, context);\nexport default bootstrap;\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/main.ts",
    "content": "import { enableProdMode } from '@angular/core';\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\nimport { appConfig } from './app/app.config';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n  enableProdMode();\n}\n\nfunction bootstrap() {\n  bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));\n}\n\nif (document.readyState === 'complete') {\n  bootstrap();\n} else {\n  document.addEventListener('DOMContentLoaded', bootstrap);\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/server.ts",
    "content": "import {\n  AngularNodeAppEngine,\n  createNodeRequestHandler,\n  isMainModule,\n  writeResponseToNodeResponse,\n} from '@angular/ssr/node';\nimport type { NextFunction, Request, Response } from 'express';\nimport express from 'express';\nimport i18next from 'i18next';\nimport ChainedBackend, { ChainedBackendOptions } from 'i18next-chained-backend';\nimport * as i18nextHttpMiddleware from 'i18next-http-middleware';\nimport resourcesToBackend from \"i18next-resources-to-backend\";\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport i18nextOptions from './app/i18next.options';\n\n\nconst serverDistFolder = dirname(fileURLToPath(import.meta.url));\nconst browserDistFolder = resolve(serverDistFolder, '../browser');\n\nconst app = express();\nconst angularApp = new AngularNodeAppEngine();\n\nawait i18next\n    .use(ChainedBackend)\n    .use(i18nextHttpMiddleware.LanguageDetector)\n    .init<ChainedBackendOptions>({\n      ...i18nextOptions,\n      backend: {\n        backends: [\n          resourcesToBackend((lng, ns, clb) => {\n            import(`./locales/${lng}.${ns}.json`)\n                  .then((resources) => clb(null, resources))\n                  .catch((r)=> clb(r,null))\n          })\n        ],\n        backendOptions: [{\n          loadPath: '/locales/{{lng}}.{{ns}}.json'\n        }]\n      }\n  });\n\nconst i18nextHandler = i18nextHttpMiddleware.handle(i18next) as any;\napp.use(i18nextHandler);\n/**\n * Example Express Rest API endpoints can be defined here.\n * Uncomment and define endpoints as necessary.\n *\n * Example:\n * ```ts\n * app.get('/api/**', (req, res) => {\n *   // Handle API request\n * });\n * ```\n */\n\n/**\n * Serve static files from /browser\n */\napp.use(\n  express.static(browserDistFolder, {\n    maxAge: '1y',\n    index: false,\n    redirect: false,\n  }),\n);\n\n/**\n * Handle all other requests by rendering the Angular application.\n */\napp.use('/**', (req: Request & i18nextHttpMiddleware.I18NextRequest, res: Response, next: NextFunction) => {\n  angularApp\n    .handle(req, {\n      i18n: req.i18n,\n    })\n    .then((response) =>\n      response ? writeResponseToNodeResponse(response, res) : next(),\n    )\n    .catch(next);\n});\n\n/**\n * Start the server if this module is the main entry point.\n * The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.\n */\nif (isMainModule(import.meta.url) || process.env['PM2'] === 'true') {\n  const port = process.env['PORT'] || 4000;\n  const server = app.listen(port, () => {\n    process.send?.('ready');\n    console.log(`Node Express server listening on http://localhost:${port}`);\n  });\n\n  // Graceful shutdown\n  process.on('SIGINT', () => {\n      const cleanUp = () => {\n        // Clean up other resources like DB connections\n      }\n\n      console.log('Closing server...')\n\n      server.close(() => {\n        console.log('Server closed !!! ')\n\n        cleanUp()\n        process.exit()\n      })\n\n      // Force close server after 5secs\n      setTimeout((e: any) => {\n        console.log('Forcing server close !!!', e)\n\n        cleanUp()\n        process.exit(1)\n      }, 5000)\n    })\n  }\n\n/**\n * The request handler used by the Angular CLI (dev-server and during build).\n */\nexport const reqHandler = createNodeRequestHandler(app);\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/styles.css",
    "content": "/* You can add global styles to this file, and also import other style files */\n\ninput.ng-dirty.ng-invalid,\ntextarea.ng-dirty.ng-invalid,\n.form-control.ng-dirty.ng-invalid,\n.ng-dirty.ng-invalid:focus\n{\n    background-color: #FDEDED;\n    border-color: #D22630;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n}\n\n/* s7 ui kit fix */\n.form-group .error-container {\n  display: block;\n}\n\n.error-container {\n\tcolor: #D22630;\n\tpadding-top: 2px;\n}\n\n\n/* end fix */\n\ncheckbox.ng-invalid .custom-control-indicator,\nmultiplecheckbox.ng-invalid.ng-dirty .custom-control-indicator,\nflatpickr.ng-invalid.ng-dirty .form-control,\ndatepicker.ng-invalid.ng-dirty .select2-container .select2-selection,\nradio-button.ng-dirty.ng-invalid .custom-control-indicator,\ndiv.ng-invalid.ng-dirty.form-group-valid .custom-control-indicator,\ndiv.ng-invalid.ng-dirty.form-group-valid .select2-container .select2-selection {\n    border-color: #D22630;\n    background-color: #FDEDED;\n}\n\nradio-button + radio-button,\ncheckbox + checkbox {\n  margin-left: 15px;\n}\n\n\n"
  },
  {
    "path": "apps/angular-i18next-demo/src/test-setup.ts",
    "content": "import { setupZonelessTestEnv } from 'jest-preset-angular/setup-env/zoneless';\n\nsetupZonelessTestEnv();\n"
  },
  {
    "path": "apps/angular-i18next-demo/tsconfig.app.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"types\": [\"node\"]\n  },\n  \"files\": [\n    \"src/main.ts\",\n    \"src/main.server.ts\",\n    \"src/server.ts\"\n  ],\n  \"include\": [\"src/**/*.d.ts\"],\n  \"exclude\": [\"**/*.test.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/tsconfig.editor.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"**/*.ts\"],\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsconfig.app.json\"\n    },\n    {\n      \"path\": \"./tsconfig.spec.json\"\n    },\n    {\n      \"path\": \"./tsconfig.editor.json\"\n    }\n  ],\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"noImplicitOverride\": true,\n    \"noPropertyAccessFromIndexSignature\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"angularCompilerOptions\": {\n    \"enableI18nLegacyMessageIdFormat\": false,\n    \"strictInjectionParameters\": true,\n    \"strictInputAccessModifiers\": true,\n    \"strictTemplates\": true\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/tsconfig.server.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"./tsconfig.app.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../out-tsc/server\",\n    \"target\": \"es2019\",\n    \"types\": [\n      \"node\"\n    ],\n    \"allowSyntheticDefaultImports\": true,\n  },\n  \"files\": [\n    \"src/main.server.ts\",\n    \"server.ts\"\n  ],\n  \"angularCompilerOptions\": {\n    \"entryModule\": \"./src/app/app.server.module#AppServerModule\"\n  }\n}\n"
  },
  {
    "path": "apps/angular-i18next-demo/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n    \"types\": [\"jest\", \"node\"],\n    \"allowSyntheticDefaultImports\": true, // Typing support for this case\n    \"esModuleInterop\": true,\n  },\n  \"files\": [\"src/test-setup.ts\"],\n  \"include\": [\"jest.config.ts\", \"**/*.test.ts\", \"**/*.spec.ts\", \"**/*.d.ts\"]\n}\n"
  },
  {
    "path": "decorate-angular-cli.js",
    "content": "/**\n * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching\n * and faster execution of tasks.\n *\n * It does this by:\n *\n * - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command.\n * - Symlinking the ng to nx command, so all commands run through the Nx CLI\n * - Updating the package.json postinstall script to give you control over this script\n *\n * The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it.\n * Every command you run should work the same when using the Nx CLI, except faster.\n *\n * Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case,\n * will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked.\n * The Nx CLI simply does some optimizations before invoking the Angular CLI.\n *\n * To opt out of this patch:\n * - Replace occurrences of nx with ng in your package.json\n * - Remove the script from your postinstall script in your package.json\n * - Delete and reinstall your node_modules\n */\n\nconst fs = require('fs');\nconst os = require('os');\nconst cp = require('child_process');\nconst isWindows = os.platform() === 'win32';\nlet output;\ntry {\n  output = require('@nx/workspace').output;\n} catch (e) {\n  console.warn(\n    'Angular CLI could not be decorated to enable computation caching. Please ensure @nx/workspace is installed.'\n  );\n  process.exit(0);\n}\n\n/**\n * Symlink of ng to nx, so you can keep using `ng build/test/lint` and still\n * invoke the Nx CLI and get the benefits of computation caching.\n */\nfunction symlinkNgCLItoNxCLI() {\n  try {\n    const ngPath = './node_modules/.bin/ng';\n    const nxPath = './node_modules/.bin/nx';\n    if (isWindows) {\n      /**\n       * This is the most reliable way to create symlink-like behavior on Windows.\n       * Such that it works in all shells and works with npx.\n       */\n      ['', '.cmd', '.ps1'].forEach((ext) => {\n        if (fs.existsSync(nxPath + ext))\n          fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext));\n      });\n    } else {\n      // If unix-based, symlink\n      cp.execSync(`ln -sf ./nx ${ngPath}`);\n    }\n  } catch (e) {\n    output.error({\n      title:\n        'Unable to create a symlink from the Angular CLI to the Nx CLI:' +\n        e.message,\n    });\n    throw e;\n  }\n}\n\ntry {\n  symlinkNgCLItoNxCLI();\n  require('@nrwl/cli/lib/decorate-cli').decorateCli();\n  output.log({\n    title: 'Angular CLI has been decorated to enable computation caching.',\n  });\n} catch (e) {\n  output.error({\n    title: 'Decoration of the Angular CLI did not complete successfully',\n  });\n}\n"
  },
  {
    "path": "ecosystem.config.js",
    "content": "const { cwd } = require(\"process\");\n\nmodule.exports = {\n  apps: [\n    {\n      name: 'angular-i18next-demo',\n      script: 'server.mjs',\n      cwd: './dist/angular-i18next-demo/server',\n      max_memory_restart: '100M',\n      env: {\n        PM2: true,\n        NODE_ENV: \"development\"\n      },\n      env_production: {\n        PM2: true,\n        NODE_ENV: \"production\",\n      }\n    },\n  ],\n};\n"
  },
  {
    "path": "jest.config.ts",
    "content": "\nexport default {\n  projects: ['./libs/**/jest.config.ts'],\n};\n"
  },
  {
    "path": "jest.preset.js",
    "content": "const nxPreset = require('@nx/jest/preset').default;\n\nmodule.exports = {\n  ...nxPreset,\n  /* TODO: Update to latest Jest snapshotFormat\n   * By default Nx has kept the older style of Jest Snapshot formats\n   * to prevent breaking of any existing tests with snapshots.\n   * It's recommend you update to the latest format.\n   * You can do this by removing snapshotFormat property\n   * and running tests with --update-snapshot flag.\n   * Example: \"nx affected --targets=test --update-snapshot\"\n   * More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format\n   */\n  snapshotFormat: { escapeString: true, printBasicPrototype: true },\n};\n"
  },
  {
    "path": "libs/angular-i18next/.eslintrc.json",
    "content": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"]\n}\n"
  },
  {
    "path": "libs/angular-i18next/CHANGELOG.md",
    "content": "# [21.0.0-3](https://github.com/Romanchuk/angular-i18next/compare/v20.0.1...v21.0.0-3) (2026-01-23)\n\n\n### Bug Fixes\n\n* build ([4f8d746](https://github.com/Romanchuk/angular-i18next/commit/4f8d746e88401bc339250af3383097f6837823cb))\n* jest test setup ([253a5eb](https://github.com/Romanchuk/angular-i18next/commit/253a5eb47f55428e81ec43c0c48fff2de3036205))\n* units ([2a46eda](https://github.com/Romanchuk/angular-i18next/commit/2a46eda0df9e117357965e7499573a88992fef5b))\n\n\n\n# [21.0.0-2](https://github.com/Romanchuk/angular-i18next/compare/v20.0.1...v21.0.0-2) (2026-01-23)\n\n\n### Bug Fixes\n\n* build ([4f8d746](https://github.com/Romanchuk/angular-i18next/commit/4f8d746e88401bc339250af3383097f6837823cb))\n* jest test setup ([253a5eb](https://github.com/Romanchuk/angular-i18next/commit/253a5eb47f55428e81ec43c0c48fff2de3036205))\n* units ([2a46eda](https://github.com/Romanchuk/angular-i18next/commit/2a46eda0df9e117357965e7499573a88992fef5b))\n\n\n\n# [21.0.0-1](https://github.com/Romanchuk/angular-i18next/compare/v20.0.1...v21.0.0-1) (2026-01-23)\n\n\n### Bug Fixes\n\n* build ([4f8d746](https://github.com/Romanchuk/angular-i18next/commit/4f8d746e88401bc339250af3383097f6837823cb))\n* jest test setup ([253a5eb](https://github.com/Romanchuk/angular-i18next/commit/253a5eb47f55428e81ec43c0c48fff2de3036205))\n* units ([2a46eda](https://github.com/Romanchuk/angular-i18next/commit/2a46eda0df9e117357965e7499573a88992fef5b))\n\n\n\n## [20.0.1](https://github.com/Romanchuk/angular-i18next/compare/v20.0.1-0...v20.0.1) (2025-11-14)\n\n\n\n## [20.0.1-0](https://github.com/Romanchuk/angular-i18next/compare/v20.0.0...v20.0.1-0) (2025-11-14)\n\n\n### Bug Fixes\n\n* i18next typings ([9dabeb9](https://github.com/Romanchuk/angular-i18next/commit/9dabeb9ab832413bb488151eb6f74bd65c9a48e8))\n\n\n\n# [20.0.0](https://github.com/Romanchuk/angular-i18next/compare/v19.1.1...v20.0.0) (2025-08-22)\n\n\n### Features\n\n* **up version i18next 25:** up version i18next 25 ([4a8d23a](https://github.com/Romanchuk/angular-i18next/commit/4a8d23a016ca4daa5bf06255b24ec10faa004948))\n\n\n### BREAKING CHANGES\n\n* **up version i18next 25:** up version i18next 25\n\n\n\n## [19.1.1](https://github.com/Romanchuk/angular-i18next/compare/v19.1.1-0...v19.1.1) (2025-08-22)\n\n\n\n## [19.1.1-0](https://github.com/Romanchuk/angular-i18next/compare/v19.1.0...v19.1.1-0) (2025-06-22)\n\n\n### Bug Fixes\n\n* ci ([f5c5339](https://github.com/Romanchuk/angular-i18next/commit/f5c5339598c340c2e7f973f90f06dd73c85c621b))\n* ci ([563993b](https://github.com/Romanchuk/angular-i18next/commit/563993b507873903a6caf4374508686d8b1b5fd0))\n* ci ([443db4e](https://github.com/Romanchuk/angular-i18next/commit/443db4e748522519bd1057947651e724187b1392))\n* prepare demo ([a80d2bc](https://github.com/Romanchuk/angular-i18next/commit/a80d2bc19cfed95c5c5a7c4cf40a560f720353af))\n* tsconfig.spec ([cea853b](https://github.com/Romanchuk/angular-i18next/commit/cea853bdab70b7199f05896a43deed9c26e26088))\n\n\n\n# [19.1.0](https://github.com/Romanchuk/angular-i18next/compare/v19.0.1...v19.1.0) (2025-03-03)\n\n\n### Bug Fixes\n\n* browser build and serve ([d9b73f2](https://github.com/Romanchuk/angular-i18next/commit/d9b73f20b82f5ba1d0692c40787e47032f30367e))\n* build ([300e975](https://github.com/Romanchuk/angular-i18next/commit/300e975a1c6072e0564c5fff50e4bf1ddb7f4751))\n* build ([ed46b54](https://github.com/Romanchuk/angular-i18next/commit/ed46b542564070d462b8d5b3c0b92b1e4a04ac55))\n* forms ([3781a6b](https://github.com/Romanchuk/angular-i18next/commit/3781a6b7786b4666a77402cefec13860dacc4b05))\n* new provide ([f17a4f8](https://github.com/Romanchuk/angular-i18next/commit/f17a4f863b422c667d76457bc4c996760a3c1ca0))\n* specs ([5e12691](https://github.com/Romanchuk/angular-i18next/commit/5e12691a4dc091f251d0e254f36d8fa568a22158))\n* ssr ([822b4d1](https://github.com/Romanchuk/angular-i18next/commit/822b4d1950acdadc2a5dabcbdd3a9983d9b15acd))\n* tests ([7bba2bc](https://github.com/Romanchuk/angular-i18next/commit/7bba2bc353eab68a867c8bef62e7da28b9557f58))\n\n\n\n# [19.1.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v19.0.1...v19.1.0-beta) (2025-03-01)\n\n\n### Bug Fixes\n\n* browser build and serve ([d9b73f2](https://github.com/Romanchuk/angular-i18next/commit/d9b73f20b82f5ba1d0692c40787e47032f30367e))\n* build ([300e975](https://github.com/Romanchuk/angular-i18next/commit/300e975a1c6072e0564c5fff50e4bf1ddb7f4751))\n* build ([ed46b54](https://github.com/Romanchuk/angular-i18next/commit/ed46b542564070d462b8d5b3c0b92b1e4a04ac55))\n* forms ([3781a6b](https://github.com/Romanchuk/angular-i18next/commit/3781a6b7786b4666a77402cefec13860dacc4b05))\n* new provide ([f17a4f8](https://github.com/Romanchuk/angular-i18next/commit/f17a4f863b422c667d76457bc4c996760a3c1ca0))\n* specs ([5e12691](https://github.com/Romanchuk/angular-i18next/commit/5e12691a4dc091f251d0e254f36d8fa568a22158))\n* ssr ([822b4d1](https://github.com/Romanchuk/angular-i18next/commit/822b4d1950acdadc2a5dabcbdd3a9983d9b15acd))\n* tests ([7bba2bc](https://github.com/Romanchuk/angular-i18next/commit/7bba2bc353eab68a867c8bef62e7da28b9557f58))\n\n\n\n## [19.0.1](https://github.com/Romanchuk/angular-i18next/compare/v19.0.0...v19.0.1) (2025-01-11)\n\n\n\n# [19.0.0](https://github.com/Romanchuk/angular-i18next/compare/v19.0.0-0...v19.0.0) (2025-01-11)\n\n\n### Bug Fixes\n\n* app ([b634439](https://github.com/Romanchuk/angular-i18next/commit/b63443967f5da8bb470c09871562d431a2af2cf3))\n\n\n\n# [19.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v18.0.0...v19.0.0-0) (2025-01-11)\n\n\n### Bug Fixes\n\n* pages ([27d6e56](https://github.com/Romanchuk/angular-i18next/commit/27d6e5644d9c9d50d88fc7ab7bdc3d23f94285ef))\n* tests ([29abe20](https://github.com/Romanchuk/angular-i18next/commit/29abe20a002ec9912af0388abf4a3f5eb0a97d90))\n\n\n\n# [18.0.0](https://github.com/Romanchuk/angular-i18next/compare/v18.0.0-0...v18.0.0) (2024-06-03)\n\n\n\n# [18.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v17.0.2...v18.0.0-0) (2024-06-03)\n\n\n\n## [17.0.2](https://github.com/Romanchuk/angular-i18next/compare/v17.0.1...v17.0.2) (2024-06-03)\n\n\n### Bug Fixes\n\n* tests ([50c5f38](https://github.com/Romanchuk/angular-i18next/commit/50c5f38b122755d1a33fa0db0a59f7be201f26d3))\n\n\n\n## [17.0.1](https://github.com/Romanchuk/angular-i18next/compare/v17.0.0...v17.0.1) (2023-12-07)\n\n\n### Bug Fixes\n\n* nx and jest setup ([0e6a61d](https://github.com/Romanchuk/angular-i18next/commit/0e6a61dd882f103b40bce38577fd7e7bcf44309a))\n\n\n\n# [17.0.0](https://github.com/Romanchuk/angular-i18next/compare/v17.0.0-1...v17.0.0) (2023-12-01)\n\n\n\n# [17.0.0-1](https://github.com/Romanchuk/angular-i18next/compare/v17.0.0-0...v17.0.0-1) (2023-11-28)\n\n\n\n# [17.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v16.0.0...v17.0.0-0) (2023-11-27)\n\n\n\n# [16.0.0](https://github.com/Romanchuk/angular-i18next/compare/v16.0.0-0...v16.0.0) (2023-06-09)\n\n\n\n# [16.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v15.0.5...v16.0.0-0) (2023-06-09)\n\n\n### Bug Fixes\n\n* package.json ([4f3d909](https://github.com/Romanchuk/angular-i18next/commit/4f3d909321651faa4f6406cf300582ce8a8001ce))\n* test ([991dbca](https://github.com/Romanchuk/angular-i18next/commit/991dbca3c5ad9807b4884727065effe456f56b61))\n* test script ([b075485](https://github.com/Romanchuk/angular-i18next/commit/b0754858d865a5e4aaa80ac18fb264d276f26787))\n\n\n\n## [15.0.5](https://github.com/Romanchuk/angular-i18next/compare/v15.0.4...v15.0.5) (2023-01-24)\n\n\n### Bug Fixes\n\n* [#101](https://github.com/Romanchuk/angular-i18next/issues/101) ([e7d095a](https://github.com/Romanchuk/angular-i18next/commit/e7d095a2336b663f95e08ddadbe65de6cf8b191c))\n\n\n\n## [15.0.4](https://github.com/Romanchuk/angular-i18next/compare/v15.0.3...v15.0.4) (2023-01-16)\n\n\n\n## [15.0.3](https://github.com/Romanchuk/angular-i18next/compare/v15.0.1...v15.0.3) (2023-01-16)\n\n\n\n## [15.0.2](https://github.com/Romanchuk/angular-i18next/compare/v15.0.1...v15.0.2) (2023-01-16)\n\n\n\n## [15.0.1](https://github.com/Romanchuk/angular-i18next/compare/v15.0.0...v15.0.1) (2023-01-16)\n\n\n### Bug Fixes\n\n* [#97](https://github.com/Romanchuk/angular-i18next/issues/97) \"strictNullChecks\": true ([92d8205](https://github.com/Romanchuk/angular-i18next/commit/92d8205003908cb89587a99268983184fa4d6316))\n* t signature ([029478a](https://github.com/Romanchuk/angular-i18next/commit/029478a5582afe626d892b8e1ee59c7d08e544f5))\n\n\n\n# [15.0.0](https://github.com/Romanchuk/angular-i18next/compare/v15.0.0-1...v15.0.0) (2023-01-16)\n\n\n\n# [15.0.0-1](https://github.com/Romanchuk/angular-i18next/compare/v15.0.0-0...v15.0.0-1) (2023-01-16)\n\n\n\n# [15.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v14.2.0...v15.0.0-0) (2022-12-22)\n\n\n### Bug Fixes\n\n* pages deploy ([df17d58](https://github.com/Romanchuk/angular-i18next/commit/df17d58fcfd3a18c9862064d43e33e799effb84e))\n\n\n\n# [14.2.0](https://github.com/Romanchuk/angular-i18next/compare/v14.2.0-1...v14.2.0) (2022-11-22)\n\n\n\n# [14.2.0-1](https://github.com/Romanchuk/angular-i18next/compare/v14.2.0-0...v14.2.0-1) (2022-11-21)\n\n\n### Bug Fixes\n\n* factory type ([7a0c62c](https://github.com/Romanchuk/angular-i18next/commit/7a0c62cac779149c9b26b8cbd502538457d7159e))\n* missed import ([e793bc5](https://github.com/Romanchuk/angular-i18next/commit/e793bc511227f887d677bd2f45f3b2b173977a8e))\n* specs default import ([532dd94](https://github.com/Romanchuk/angular-i18next/commit/532dd94bc23f57f0e3e0256a3534f0c48381f12f))\n\n\n\n# [14.2.0-0](https://github.com/Romanchuk/angular-i18next/compare/v14.1.0...v14.2.0-0) (2022-11-17)\n\n\n### Bug Fixes\n\n* i18next instance ([93e48b6](https://github.com/Romanchuk/angular-i18next/commit/93e48b646c486d9e157447a704d88925e05957c6))\n* jest default import ([cea6677](https://github.com/Romanchuk/angular-i18next/commit/cea66776dd6af912dfdfff500f14bbe8e17c81e7))\n* link to global i18next ([4439d3a](https://github.com/Romanchuk/angular-i18next/commit/4439d3a19ef3d2bec7fcb296b8f3eaebbd1af6a8))\n* tests ([78bc41e](https://github.com/Romanchuk/angular-i18next/commit/78bc41e3a4eca2b63f28513120f0ef9863d2a21a))\n\n\n\n# [14.1.0](https://github.com/Romanchuk/angular-i18next/compare/v14.0.5-6...v14.1.0) (2022-11-09)\n\n\n### Bug Fixes\n\n* messages ([1cbebea](https://github.com/Romanchuk/angular-i18next/commit/1cbebea76d188057070442d6ffbd62bbf44ccf09))\n* setup ([86de471](https://github.com/Romanchuk/angular-i18next/commit/86de471f898068274355d87f1c084ce76bb72b91))\n\n\n\n## [14.0.5-6](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.5-6) (2022-11-07)\n\n\n### Bug Fixes\n\n* async funcs ([25e2c24](https://github.com/Romanchuk/angular-i18next/commit/25e2c24ba8c0cce1d4b235d1449fb554937b6fe4))\n* build ([aafe356](https://github.com/Romanchuk/angular-i18next/commit/aafe356437287a4a2e30668a726c18e5a118cc04))\n* cpy ([2a2460e](https://github.com/Romanchuk/angular-i18next/commit/2a2460e8e53f5a18185bf979318e0be77019f82e))\n* Fixes i18next format call with options undefined ([ccfc6e1](https://github.com/Romanchuk/angular-i18next/commit/ccfc6e1583fcb4a5a8b591ac0e3e8cf95ce675eb))\n* package ([9b03de0](https://github.com/Romanchuk/angular-i18next/commit/9b03de01029432a679b84f0b535c8c0986a2ce49))\n* test run ([cc2ca1c](https://github.com/Romanchuk/angular-i18next/commit/cc2ca1c6dbef4fe1126de9ffb7c73f0dc2be9062))\n* tests ([0b868fc](https://github.com/Romanchuk/angular-i18next/commit/0b868fc25b9c7ff4902308425e066835d117596d))\n\n\n\n## [14.0.5-3](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.5-3) (2022-07-05)\n\n\n### Bug Fixes\n\n* package ([9b03de0](https://github.com/Romanchuk/angular-i18next/commit/9b03de01029432a679b84f0b535c8c0986a2ce49))\n\n\n\n## [14.0.5-2](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.5-2) (2022-07-05)\n\n\n### Bug Fixes\n\n* package ([9b03de0](https://github.com/Romanchuk/angular-i18next/commit/9b03de01029432a679b84f0b535c8c0986a2ce49))\n\n\n\n## [14.0.5-1](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.5-1) (2022-07-05)\n\n\n### Bug Fixes\n\n* package ([9b03de0](https://github.com/Romanchuk/angular-i18next/commit/9b03de01029432a679b84f0b535c8c0986a2ce49))\n\n\n\n## [14.0.5-0](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.5-0) (2022-07-05)\n\n\n### Bug Fixes\n\n* package ([9b03de0](https://github.com/Romanchuk/angular-i18next/commit/9b03de01029432a679b84f0b535c8c0986a2ce49))\n\n\n\n## [14.0.4-0](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.4-0) (2022-07-05)\n\n\n### Bug Fixes\n\n* package ([9b03de0](https://github.com/Romanchuk/angular-i18next/commit/9b03de01029432a679b84f0b535c8c0986a2ce49))\n\n\n\n## [14.0.3](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.3) (2022-07-05)\n\n\n### Bug Fixes\n\n* package ([9b03de0](https://github.com/Romanchuk/angular-i18next/commit/9b03de01029432a679b84f0b535c8c0986a2ce49))\n\n\n\n## [14.0.2](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.2) (2022-07-05)\n\n\n\n## [14.0.1](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0...v14.0.1) (2022-07-05)\n\n\n\n# [14.0.0](https://github.com/Romanchuk/angular-i18next/compare/v14.0.0-0...v14.0.0) (2022-07-04)\n\n\n\n# [14.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v11.0.0...v14.0.0-0) (2022-06-14)\n\n\n### Bug Fixes\n\n* [#81](https://github.com/Romanchuk/angular-i18next/issues/81) ([820a9e8](https://github.com/Romanchuk/angular-i18next/commit/820a9e8ab0d1b3f0c4757c4f7096dce4e1f844ed))\n\n\n\n# [11.0.0](https://github.com/Romanchuk/angular-i18next/compare/v11.0.0-0...v11.0.0) (2022-01-28)\n\n\n\n# [11.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v10.3.0...v11.0.0-0) (2022-01-04)\n\n\n### Bug Fixes\n\n* np dist ([670004f](https://github.com/Romanchuk/angular-i18next/commit/670004f2b1c41e0de88708767563b960bd88a3e6))\n\n\n\n# [10.3.0](https://github.com/Romanchuk/angular-i18next/compare/v10.3.0-0...v10.3.0) (2021-06-15)\n\n\n\n# [10.3.0-0](https://github.com/Romanchuk/angular-i18next/compare/v10.2.0...v10.3.0-0) (2021-06-15)\n\n\n\n# [10.2.0](https://github.com/Romanchuk/angular-i18next/compare/v10.2.0-0...v10.2.0) (2021-05-12)\n\n\n\n# [10.2.0-0](https://github.com/Romanchuk/angular-i18next/compare/v10.1.0...v10.2.0-0) (2021-05-12)\n\n\n### Features\n\n* i18next v20+ support ([0327a7c](https://github.com/Romanchuk/angular-i18next/commit/0327a7c9f35140f0c8e098d9d1528b6e7303a8d0))\n\n\n\n# [10.1.0](https://github.com/Romanchuk/angular-i18next/compare/v10.1.0-0...v10.1.0) (2021-03-01)\n\n\n\n# [10.1.0-0](https://github.com/Romanchuk/angular-i18next/compare/v10.0.1...v10.1.0-0) (2021-03-01)\n\n\n### Bug Fixes\n\n* **I18NextEagerPipe:** ensure changing PipeOptions returns correct translated value a not cached one with different PipeOptions but same key ([4a6d375](https://github.com/Romanchuk/angular-i18next/commit/4a6d375181dda41399c58f7644b97d3755acf84f))\n\n\n\n## [10.0.1](https://github.com/Romanchuk/angular-i18next/compare/v10.0.1-beta...v10.0.1) (2020-12-21)\n\n\n\n## [10.0.1-beta](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0...v10.0.1-beta) (2020-12-21)\n\n\n\n# [10.0.0](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0-2...v10.0.0) (2020-07-06)\n\n\n\n# [10.0.0-2](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0-1...v10.0.0-2) (2020-07-06)\n\n\n\n# [10.0.0-1](https://github.com/Romanchuk/angular-i18next/compare/v10.0.0-0...v10.0.0-1) (2020-07-06)\n\n\n\n# [10.0.0-0](https://github.com/Romanchuk/angular-i18next/compare/v9.0.1...v10.0.0-0) (2020-07-06)\n\n\n\n## [9.0.1](https://github.com/Romanchuk/angular-i18next/compare/v9.0.0...v9.0.1) (2020-02-25)\n\n\n### Bug Fixes\n\n* pass translate options ([4cfe42c](https://github.com/Romanchuk/angular-i18next/commit/4cfe42c))\n\n\n\n# [9.0.0](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta.3...v9.0.0) (2020-02-20)\n\n\n\n# [8.1.0-beta.3](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta.2...v8.1.0-beta.3) (2020-02-20)\n\n\n\n# [8.1.0-beta.2](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta.1...v8.1.0-beta.2) (2020-02-20)\n\n\n\n# [8.1.0-beta.1](https://github.com/Romanchuk/angular-i18next/compare/v8.1.0-beta...v8.1.0-beta.1) (2020-02-20)\n\n\n### Features\n\n* improved typings ([214e35d](https://github.com/Romanchuk/angular-i18next/commit/214e35d))\n\n\n\n# [8.1.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v7.2.0-beta...v8.1.0-beta) (2020-02-20)\n\n\n\n## [8.0.1](https://github.com/Romanchuk/angular-i18next/compare/v8.0.1-beta.0...v8.0.1) (2020-02-18)\n\n\n\n## [8.0.1-beta.0](https://github.com/Romanchuk/angular-i18next/compare/v8.0.1-beta...v8.0.1-beta.0) (2020-02-18)\n\n\n\n## [8.0.1-beta](https://github.com/Romanchuk/angular-i18next/compare/v8.0.0...v8.0.1-beta) (2020-02-18)\n\n\n\n# [8.0.0](https://github.com/Romanchuk/angular-i18next/compare/v8.0.0-beta.1...v8.0.0) (2020-02-14)\n\n\n\n# [8.0.0-beta.1](https://github.com/Romanchuk/angular-i18next/compare/v8.0.0-beta...v8.0.0-beta.1) (2020-02-13)\n\n\n\n# [8.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v7.2.0-beta...v8.0.0-beta) (2020-02-13)\n\n\n\n# [7.2.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v7.0.0...v7.2.0-beta) (2020-01-28)\n\n\n### Bug Fixes\n\n* I18NextEagerPipe ([8dbefe1](https://github.com/Romanchuk/angular-i18next/commit/8dbefe1))\n\n\n\n# [7.0.0](https://github.com/Romanchuk/angular-i18next/compare/v6.1.0...v7.0.0) (2019-06-05)\n\n\n\n# [6.1.0](https://github.com/Romanchuk/angular-i18next/compare/v6.1.0-beta...v6.1.0) (2019-05-27)\n\n\n\n# [6.1.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v6.0.1...v6.1.0-beta) (2019-05-25)\n\n\n\n## [6.0.1](https://github.com/Romanchuk/angular-i18next/compare/v6.0.0...v6.0.1) (2019-03-11)\n\n\n\n# [6.0.0](https://github.com/Romanchuk/angular-i18next/compare/v6.0.0-beta.0...v6.0.0) (2019-02-10)\n\n\n\n# [6.0.0-beta.0](https://github.com/Romanchuk/angular-i18next/compare/v6.0.0-beta...v6.0.0-beta.0) (2019-02-10)\n\n\n\n# [6.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v5.0.6...v6.0.0-beta) (2019-02-10)\n\n\n\n## [5.0.6](https://github.com/Romanchuk/angular-i18next/compare/v5.0.5...v5.0.6) (2018-12-03)\n\n\n\n## [5.0.5](https://github.com/Romanchuk/angular-i18next/compare/v5.0.4...v5.0.5) (2018-12-03)\n\n\n\n## [5.0.4](https://github.com/Romanchuk/angular-i18next/compare/v5.0.3...v5.0.4) (2018-12-03)\n\n\n\n## [5.0.3](https://github.com/Romanchuk/angular-i18next/compare/v5.0.2...v5.0.3) (2018-12-03)\n\n\n\n## [5.0.2](https://github.com/Romanchuk/angular-i18next/compare/v5.0.1...v5.0.2) (2018-12-03)\n\n\n### Bug Fixes\n\n* package.json ([54a8c37](https://github.com/Romanchuk/angular-i18next/commit/54a8c37))\n\n\n\n## [5.0.1](https://github.com/Romanchuk/angular-i18next/compare/v5.0.0...v5.0.1) (2018-11-28)\n\n\n\n# [5.0.0](https://github.com/Romanchuk/angular-i18next/compare/v5.0.0-beta2...v5.0.0) (2018-11-28)\n\n\n\n# [5.0.0-beta2](https://github.com/Romanchuk/angular-i18next/compare/v5.0.0-beta...v5.0.0-beta2) (2018-11-28)\n\n\n\n# [5.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v4.0.0...v5.0.0-beta) (2018-11-28)\n\n\n### Bug Fixes\n\n* docs ([220a0b8](https://github.com/Romanchuk/angular-i18next/commit/220a0b8))\n\n\n\n<a name=\"4.0.0\"></a>\n# [4.0.0](https://github.com/Romanchuk/angular-i18next/compare/v4.0.0-beta...v4.0.0) (2018-06-25)\n\nIn v4 passed through most of i18next api methods\n\n1. Update angular to v6+\n2. Update rxjs to v6.2.0+\n\n\n<a name=\"4.0.0-beta\"></a>\n# [4.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v3.4.2...v4.0.0-beta) (2018-06-11)\n\n\n\n<a name=\"3.4.2\"></a>\n## [3.4.2](https://github.com/Romanchuk/angular-i18next/compare/v3.4.1...v3.4.2) (2018-05-05)\n\n\n\n<a name=\"3.4.1\"></a>\n## [3.4.1](https://github.com/Romanchuk/angular-i18next/compare/v3.4.0...v3.4.1) (2018-04-29)\n\n- default formater fixes\n\n\n<a name=\"3.4.0\"></a>\n# [3.4.0](https://github.com/Romanchuk/angular-i18next/compare/v3.3.0...v3.4.0) (2018-04-29)\n\n- i18next v11 support \n- fix: [format pipe](https://github.com/Romanchuk/angular-i18next/issues/15)\n\n\n<a name=\"3.3.0\"></a>\n# [3.3.0](https://github.com/Romanchuk/angular-i18next/compare/v3.3.0-beta.2...v3.3.0) (2018-03-12)\n\n- added umd bundle\n- comments cleanup\n- updated dev dependencies\n\n<a name=\"3.3.0-beta.2\"></a>\n# [3.3.0-beta.2](https://github.com/Romanchuk/angular-i18next/compare/v3.3.0-beta.1...v3.3.0-beta.2) (2018-03-12)\n\n\n\n<a name=\"3.3.0-beta.1\"></a>\n# [3.3.0-beta.1](https://github.com/Romanchuk/angular-i18next/compare/v3.2.0...v3.3.0-beta.1) (2018-02-04)\n\n\n\n<a name=\"3.2.0\"></a>\n# [3.2.0](https://github.com/Romanchuk/angular-i18next/compare/v3.1.1...v3.2.0) (2018-01-17)\n\n### Bug Fixes\n* [aot build failed](Romanchuk/angular-i18next#10)\n\n### Breaking changes\n\nRemoved parameter 'localizeTitle' from forRoot method.\nYou need to manually resolve Title as I18NextTitle for same behavior.\n\n\n<a name=\"3.1.1\"></a>\n## [3.1.1](https://github.com/Romanchuk/angular-i18next/compare/v3.1.0...v3.1.1) (2018-01-01)\n\n\n### Bug Fixes\n\n* bug namespace fallback ([a16b067](https://github.com/Romanchuk/angular-i18next/commit/a16b067))\n* conventional-github-releaser run ([df3bb84](https://github.com/Romanchuk/angular-i18next/commit/df3bb84))\n\n\n\n<a name=\"3.1.0\"></a>\n# [3.1.0](https://github.com/Romanchuk/angular-i18next/compare/v3.0.0...v3.1.0) (2017-12-22)\n\nIt is possible to pass array of namespaces (or scopes). [Key would fallback](https://www.i18next.com/api.html#t) to next namespace in array if the previous failed to resolve.\n\n`[feature.validators:key, validators:key]`\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: ['feature.validators', 'validators']\n}\n```\n\n<a name=\"3.0.0\"></a>\n# [3.0.0](https://github.com/Romanchuk/angular-i18next/compare/v3.0.0-alpha.2...v3.0.0) (2017-12-15)\n\n\n\n<a name=\"3.0.0-alpha.2\"></a>\n# [3.0.0-alpha.2](https://github.com/Romanchuk/angular-i18next/compare/v3.0.0-alpha...v3.0.0-alpha.2) (2017-12-05)\n\n\n\n<a name=\"3.0.0-alpha\"></a>\n# [3.0.0-alpha](https://github.com/Romanchuk/angular-i18next/compare/v2.0.0...v3.0.0-alpha) (2017-11-27)\n\n\n\n<a name=\"2.0.0\"></a>\n# [2.0.0](https://github.com/Romanchuk/angular-i18next/compare/v2.0.0-beta2...v2.0.0) (2017-11-14)\n\n\n\n<a name=\"2.0.0-beta2\"></a>\n# [2.0.0-beta2](https://github.com/Romanchuk/angular-i18next/compare/v2.0.0-beta...v2.0.0-beta2) (2017-11-05)\n\n\n\n<a name=\"2.0.0-beta\"></a>\n# [2.0.0-beta](https://github.com/Romanchuk/angular-i18next/compare/v1.1.0...v2.0.0-beta) (2017-11-05)\n\n\n\n<a name=\"1.1.0\"></a>\n# [1.1.0](https://github.com/Romanchuk/angular-i18next/compare/v1.0.2...v1.1.0) (2017-11-04)\n\n\n\n<a name=\"1.0.2\"></a>\n## [1.0.2](https://github.com/Romanchuk/angular-i18next/compare/v1.0.1...v1.0.2) (2017-09-22)\n\n\n\n<a name=\"1.0.1\"></a>\n## [1.0.1](https://github.com/Romanchuk/angular-i18next/compare/v1.0.0...v1.0.1) (2017-09-21)\n\n\n\n<a name=\"1.0.0\"></a>\n# [1.0.0](https://github.com/Romanchuk/angular-i18next/compare/v0.2.4...v1.0.0) (2017-09-21)\n\n\n\n<a name=\"0.2.4\"></a>\n## [0.2.4](https://github.com/Romanchuk/angular-i18next/compare/v0.2.3...v0.2.4) (2017-06-29)\n\n\n\n<a name=\"0.2.3\"></a>\n## [0.2.3](https://github.com/Romanchuk/angular-i18next/compare/v0.2.2...v0.2.3) (2017-06-29)\n\n\n\n<a name=\"0.2.2\"></a>\n## [0.2.2](https://github.com/Romanchuk/angular-i18next/compare/v0.2.1...v0.2.2) (2017-06-29)\n\n\n### Bug Fixes\n\n* **I18NextService:** context-safe calls of i18next methods ([455a07d](https://github.com/Romanchuk/angular-i18next/commit/455a07d))\n\n\n\n<a name=\"0.2.1\"></a>\n## [0.2.1](https://github.com/Romanchuk/angular-i18next/compare/v0.2.0...v0.2.1) (2017-06-29)\n\n\n### Bug Fixes\n\n* **package:** return back required exports ([fb7ead6](https://github.com/Romanchuk/angular-i18next/commit/fb7ead6))\n\n\n\n<a name=\"0.2.0\"></a>\n# [0.2.0](https://github.com/Romanchuk/angular-i18next/compare/0.1.0...0.2.0) (2017-06-28)\n\n\n### Features\n\n* **package:** AOT support added ([fc1f66d](https://github.com/Romanchuk/angular-i18next/commit/fc1f66d))\n\n\n\n"
  },
  {
    "path": "libs/angular-i18next/README.md",
    "content": "[![npm version](https://badge.fury.io/js/angular-i18next.svg)](https://badge.fury.io/js/angular-i18next)\n[![Downloads](http://img.shields.io/npm/dm/angular-i18next.svg)](https://npmjs.org/package/angular-i18next)\n[![Build Status](https://travis-ci.com/Romanchuk/angular-i18next.svg?branch=master)](https://travis-ci.com/Romanchuk/angular-i18next)\n[![Coverage Status](https://coveralls.io/repos/github/Romanchuk/angular-i18next/badge.svg?branch=master)](https://coveralls.io/github/Romanchuk/angular-i18next?branch=master)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n[![Dependency Status](https://david-dm.org/Romanchuk/angular-i18next.svg)](https://david-dm.org/Romanchuk/angular-i18next)\n[![devDependency Status](https://david-dm.org/Romanchuk/angular-i18next/dev-status.svg)](https://david-dm.org/Romanchuk/angular-i18next?type=dev)\n[![paypal](https://img.shields.io/badge/say_thanks-%2410-green)](https://www.paypal.com/paypalme2/sergeyromanchuk/10USD)\n[![GitHub stars](https://img.shields.io/github/stars/romanchuk/angular-i18next?label=Please%20star%20repo%21&style=social)](https://github.com/romanchuk/angular-i18next)\n\n# angular-i18next\n[i18next](http://i18next.com/) v8.4+ integration with [angular](https://angular.io/) v2.0+\n\n[Live DEMO](https://romanchuk.github.io/angular-i18next-demo/)\n\n - [Features](#features)\n - [Installation](#installation)\n - [Usage](#usage)\n - [Cookbook](#cookbook)\n - [Deep integration](#deep-integration)\n - [In-project testing](#in-project-testing)\n - [Demo](#demo)\n - [Articles](#articles)\n - [Support project](#support-on-beerpay)\n \n\n# Features\n\n- Native i18next [options](https://www.i18next.com/configuration-options.html)\n- Promise initialization\n- [i18next plugin](https://www.i18next.com/plugins-and-utils.html#plugins) support \n- Events support\n- Namespaces lazy load\n- i18next native [format](https://www.i18next.com/api.html#format) support\n- document.title localization\n- Error handling strategies\n- i18next namespaces and scopes (prefixes) for angular modules and components\n- AOT support\n- [Angular Package Format](https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs/preview) support\n\n[Related packages](#deep-integration) also has implementations for:\n- Reactive forms validators localization\n- Http error message localizer\n\n# Cheers!\nHey dude! Help me out for a couple of :beers:!\n\nПоддержи проект - угости автора кружечкой пива!\n\n[![paypal](https://img.shields.io/badge/paypal-%2410-green)](https://www.paypal.com/paypalme2/sergeyromanchuk/10USD)\n\n\n# Installation\n\n**1.** Install package\n\n   ```\n    npm install i18next --save\n    npm install angular-i18next --save\n  ```\n\n**2.** Import I18NextModule to AppModule\n\n```typescript\n\nimport { I18NextModule } from 'angular-i18next';\n\n@NgModule({\n  bootstrap: [ AppComponent ],\n  declarations: [   \n    AppComponent\n  ],\n  import: [\n    I18NextModule.forRoot()\n  ]\n})\nexport class AppModule {}\n\n```\n**3.** Import I18NextModule.forRoot() to AppModule and setup provider with \"init\" method (use native [options](https://www.i18next.com/configuration-options.html)). Angular would not load until i18next initialize event fired\n```typescript\nexport function appInit(i18next: ITranslationService) {\n    return () => i18next.init({\n        whitelist: ['en', 'ru'],\n        fallbackLng: 'en',\n        debug: true,\n        returnEmptyString: false,\n        ns: [\n          'translation',\n          'validation',\n          'error'          \n        ],\n      });\n}\n\nexport function localeIdFactory(i18next: ITranslationService)  {\n    return i18next.language;\n}\n\nexport const I18N_PROVIDERS = [\n{\n    provide: APP_INITIALIZER,\n    useFactory: appInit,\n    deps: [I18NEXT_SERVICE],\n    multi: true\n},\n{\n    provide: LOCALE_ID,\n    deps: [I18NEXT_SERVICE],\n    useFactory: localeIdFactory\n}];\n```\n\n```typescript\n@NgModule({\n    imports: [\n        ...\n        I18NextModule.forRoot()\n    ],\n    providers: [\n        ...\n        I18N_PROVIDERS, \n    ],\n    bootstrap: [AppComponent]\n})\nexport class AppModule {\n}\n```\n\n# Usage\n\n### Pipes\n\nUse \"i18next\" pipe to translate key:\n\n    <div>{{ 'test' | i18next }}</div>\n\nPassing [\"t options\"](https://www.i18next.com/api.html#t):\n\n    <div>{{ 'test' | i18next: { count: 5, nsSeparator: '#' } }}</div>\n\n\nTrigger native i18next [format method](https://www.i18next.com/formatting.html) by using I18NextFormatPipe or I18NextPipe with option 'format':\n\n`{{ 'any_key' | i18next | i18nextFormat }}`\n\n`{{ 'any_key' | i18next: { format: 'cap' } }}`\n\n`{{ 'any_key' | i18nextCap }}`\n\n**Note:** Using \"i18nextCap\" you will get the same result as  `i18next: { format: 'cap' }`\n\n**REMEMBER** that format will not work until you set \"interpolation.format\" function in i18next options.\n\nI18NextModule has static method `static interpolationFormat(customFormat: Function = null): Function` that can be used as default interpolation format function (it provides 'upper', 'cap' and 'lower' formatters). You also can pass your custom function to be called after I18NextModule formatters:\n\n```typescript\nconst i18nextOptions = {\n  whitelist: ['en', 'ru'],\n  ns: [\n    'translation',\n    'validation',\n    'error',\n  ],\n  interpolation: {\n    format: I18NextModule.interpolationFormat((value, format, lng) => {\n      if(value instanceof Date)\n        return moment(value).format(format);\n      return value;\n    });\n    // format: I18NextModule.interpolationFormat()\n  }\n};\n\n```\n\n**i18nextEager pipe**\n\nThis is the impure analog of *i18next pipe* that is subscribed to language change, it will change string right away to choosen language (without reloading page).\n\n**Warning!**: Use i18nextEager only in combine with [OnPush change detection strategy](https://netbasal.com/a-comprehensive-guide-to-angular-onpush-change-detection-strategy-5bac493074a4), or else (default change detection) each pipe will retrigger more than one time (cause of performance issues).\n\nSubscribing to event observables:\n```typescript\nthis.i18NextService.events.languageChanged.subscribe(lang => {\n  // do something\n})\n```\n\nAdd a provider to module/component if you want to prefix child i18next keys:\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: 'feature' // set 'feature:' prefix \n}\n```\n```typescript\n{\n  provide: I18NEXT_SCOPE,\n  useValue: 'person' // set 'person.' prefix \n}\n```\nSince v3.1.0+ it is possible to pass array of namespaces (or scopes). [Key would fallback](https://www.i18next.com/api.html#t) to next namespace in array if the previous failed to resolve.\n\n`[feature_validators:key, validators:key]`\n```typescript\n{\n  provide: I18NEXT_NAMESPACE,\n  useValue: ['feature_validators', 'validators']\n}\n```\n_NOTE:_ **Do NOT** use default (or custom) i18next delimiters in namespace names.\n\n### Document title\nIf you want to turn on document title localization resolve Title as `I18NextTitle` imported from 'angular-i18next':\n\n```typescript\n{\n  provide: Title,\n  useClass: I18NextTitle\n}\n```\n\nAlso you can implement your own Title service with specific behavior. Inject `I18NextPipe` (or `I18NextService`) to service/component:\n```typescript\nimport { Injectable, Inject } from '@angular/core';\nimport { Title, DOCUMENT } from '@angular/platform-browser';\nimport { I18NextPipe } from 'angular-i18next';\n\n@Injectable()\nexport class I18NextTitle extends Title {\n   constructor(private i18nextPipe: I18NextPipe, @Inject(DOCUMENT) doc) {\n    super(doc);\n   }\n\n   setTitle(value: string) {\n    return super.setTitle(this.translate(value));\n   }\n\n   private translate(text: string) {\n     return this.i18nextPipe.transform(text, { format: 'cap'});\n   }\n}\n\n```\n\nWays to use I18NextService in your code:\n> **Warning:** Injection of **I18NextService** is possible, but it would not consider I18NEXT_NAMESPACE and I18NEXT_SCOPE providers. There are 2 possible reasons to inject **I18NextService**: initialization and subscription to its events. In all other cases inject **I18NextPipe**.\n1) **Recommended way:** Inject via **I18NEXT_SERVICE** token. By default it will inject instance of **I18NextService**.\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService) \n```\n\n2) Legacy way: Inject via type\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              private i18NextService: I18NextService) \n```\n\n### Error handling\n\nError handling is now configurable:\n  1) By default i18next promise will use NativeErrorHandlingStrategy. I18Next would be always resolve succesfully. Error could be get from 'then' handler parameter.\n  2) Set StrictErrorHandlingStrategy to reject load promises (init, languageChange, loadNamespaces) on first load fail (this was default in v2 but changed to fit [native i18next behavior](https://github.com/Romanchuk/angular-i18next/issues/9):\n\n    `I18NextModule.forRoot({ errorHandlingStrategy: StrictErrorHandlingStrategy })`\n\n    \n\n### Lazy loading\n\nUse I18NEXT_NAMESPACE_RESOLVER in your routes to to load i18next namespace.\n\nNote: It is not neccesary to register lazy loading namespaces in global i18next options.\n\n```\n{\n    path: 'rich_form',\n    loadChildren: 'app/features/rich_form_feature/RichFormFeatureModule#RichFormFeatureModule',\n    data: {\n      i18nextNamespaces: ['feature.rich_form']\n    },\n    resolve: {\n      i18next: I18NEXT_NAMESPACE_RESOLVER\n    }\n },\n\n```\nUse I18NextService.loadNamespaces() method to load namespaces in code.\n\n\n# Cookbook\n\n### i18next plugin support\n\n```typescript\nimport { I18NextModule, ITranslationService, I18NEXT_SERVICE } from 'angular-i18next';\n//  import Backend from 'i18next-xhr-backend'; //for i18next < 20.0.0\nimport HttpApi from 'i18next-http-backend';\nimport LanguageDetector from 'i18next-browser-languagedetector';\n\n...\n\ni18next.use(HttpApi)\n       .use(LanguageDetector)\n       .init(i18nextOptions)\n```\n\n\n\n\n### Initialize i18next before angular application\nAngular would not load until i18next initialize event fired\n```typescript\nexport function appInit(i18next: ITranslationService) {\n    return () => i18next.init();\n}\n\nexport function localeIdFactory(i18next: ITranslationService)  {\n    return i18next.language;\n}\n\nexport const I18N_PROVIDERS = [\n{\n    provide: APP_INITIALIZER,\n    useFactory: appInit,\n    deps: [I18NEXT_SERVICE],\n    multi: true\n},\n{\n    provide: LOCALE_ID,\n    deps: [I18NEXT_SERVICE],\n    useFactory: localeIdFactory\n}];\n```\n\n\n\n### Document title update on language or route change\n\n\n```typescript\nexport class AppComponent implements OnInit  {\n  constructor(private router: Router,\n              private title: Title,\n              @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService) {\n      // page title subscription\n      // https://toddmotto.com/dynamic-page-titles-angular-2-router-events#final-code\n      this.router.events\n        .filter(event => event instanceof NavigationEnd)\n        .map(() => this.router.routerState.root)\n        .map(route => {\n          while (route.firstChild) route = route.firstChild;\n          return route;\n        })\n        .filter(route => route.outlet === 'primary')\n        .mergeMap(route => route.data)\n        .subscribe((event) => this.updatePageTitle(event['title']));\n  }\n\n  ngOnInit() {\n    this.i18NextService.events.languageChanged.subscribe(lang => {\n      let root = this.router.routerState.root;\n      if (root != null && root.firstChild != null) {\n        let data: any = root.firstChild.data;\n        this.updatePageTitle(data && data.value && data.value.title);\n      }\n    });\n  }\n\n  updatePageTitle(title: string): void {\n    let newTitle = title || 'application_title';\n    this.title.setTitle(newTitle);\n  }\n}\n```\nRoutes example:\n```typescript\nconst appRoutes: Routes = [\n  { \n    path: 'error',\n    component: AppErrorComponent,\n    data: { title: 'error:error_occured' }\n  },\n  { \n    path: 'denied',\n    component: AccessDeniedComponent,\n    data: { title: 'error:access_denied' }\n  }\n];\n```\n\n# New angular version released, but angular-i18next is not released YET!!!\n\nAngular releases mostly don't break angular-i18next, but we cannot tell ahead that current version of `angular-i18next` will work correctly with latest angular version.\n\nYou can override an angular-i18next `peerDependencies` in your `package.json` on your **own risk**:\n\n```json\n\"overrides\": {\n  \"angular-i18next\": {\n    \"@angular/common\": \"*\",\n    \"@angular/core\": \"*\",\n    \"@angular/platform-browser\": \"*\"\n  }\n}\n```\n\n# Deep integration\n\nList of packages to integrate angular and i18next more deeply:\n\n- [angular-validation-message](https://github.com/Romanchuk/angular-validation-message) - angular [reactive form validators](https://angular.io/guide/reactive-forms#step-2-making-a-field-required) integration (and [angular-validation-message-i18next ](https://github.com/Romanchuk/angular-validation-message-i18next) is i18next bridge to it). It gives you possibility to localize form validators and it automatically puts localized validator error message to markup (if there is one).\n- [angular-i18next-error-interceptor](https://github.com/LCGroupIT/angular-i18next-error-interceptor) - allows you to set default errot messages for non-200 http status responses. So if the back-end didn't specify { message: 'some error' } in a response (sort of contract with our backend) interceptor will check response status code and will fill { message: 'Server is not available. Please try again.' }. Also package includes pipe where you can pass HttpErrorResponse and it will return error message whenever it's back-end message or our localized message.\n\n# In-project testing\n\nYou might want to unit-test project components that are using i18next pipes\n\nExample tests setup:\n[/tests/projectTests/projectTests.spec.ts](https://github.com/Romanchuk/angular-i18next/blob/master/tests/projectTests/projectTests.spec.ts)\n\n# Demo\n\n[Live DEMO](https://romanchuk.github.io/angular-i18next-demo/)\nDemo app source code available here: https://github.com/Romanchuk/angular-i18next-demo\n\n\n# Articles\n- [Angular L10n with I18next](https://phrase.com/blog/posts/angular-l10n-with-i18next/)\n- [Best Libraries for Angular I18n](https://phrase.com/blog/posts/best-libraries-for-angular-i18n/)\n\n"
  },
  {
    "path": "libs/angular-i18next/forms/ng-package.json",
    "content": "{}\n"
  },
  {
    "path": "libs/angular-i18next/forms/src/components/validation-message.component.ts",
    "content": "import { Component, ViewEncapsulation, computed, effect, inject, input, signal } from \"@angular/core\";\nimport { AbstractControl, NgControl } from \"@angular/forms\";\nimport { I18NEXT_NAMESPACE, I18NextCapPipe } from \"angular-i18next\";\nimport { ValidationMessage } from \"../models\";\nimport { combineLatest, startWith, Subscription, tap } from \"rxjs\";\n\n@Component({\n  selector: 'i18next-validation-message',\n  template: `\n    <div class=\"error-container\">{{ i18nextKey() | i18nextCap: firstMessage().params }}</div>\n    <i class=\"error-icon\"></i>\n  `,\n  styles: [`\n    .i18next-validation-message {\n      display: none;\n      width: 100%;\n      position: relative;\n    }\n    .i18next-validation-message.standalone,\n    .ng-dirty.ng-invalid + .i18next-validation-message {\n      display: block;\n    }\n  `],\n  encapsulation: ViewEncapsulation.None,\n  standalone: true,\n  imports: [I18NextCapPipe],\n  host: {\n    'class': 'i18next-validation-message'\n  }\n})\nexport class I18NextValidationMessageComponent {\n  private readonly i18nextNamespace = inject<string | string[]>(I18NEXT_NAMESPACE);\n  private readonly validationString = 'validation';\n  private readonly manualSettedFor = signal<NgControl | null>(null);\n  private readonly messages = signal<ValidationMessage[]>([]);\n  private controlChangesSub: Subscription | null = null;\n\n  for = input<NgControl | null>(null);\n\n  setFor(control: NgControl) {\n    this.manualSettedFor.set(control);\n  }\n\n  constructor() {\n    effect(() => {\n        this.controlChangesSub?.unsubscribe();\n        this.messages.set([]);\n        const control = this.control();\n        if (!control?.valueChanges) {\n          return;\n        }\n        control.statusChanges?.pipe(tap((s) => console.log(s))).subscribe();\n        this.controlChangesSub = combineLatest([control.valueChanges, control.statusChanges]).pipe(\n          startWith([control.value, control.status]),\n          tap(() => {\n             this.messages.set(this.getErrorMessages(control))\n          })\n        ).subscribe();\n    });\n  }\n\n  protected readonly control = computed(() => this.for() ?? this.manualSettedFor());\n\n  protected readonly firstMessage = computed(() =>\n    this.messages()[0] ?? new ValidationMessage()\n  );\n\n  protected readonly controlPath = computed(() =>\n    this.control()?.path?.join('.') ?? ''\n  );\n\n  protected readonly i18nextKey = computed(() => {\n    if (!this.firstMessage().key) return '';\n\n    const specificKey = [\n      this.validationString,\n      ['control_specific', this.controlPath(), this.firstMessage().key].join('.')\n    ].join(':');\n\n    const commonKey = [this.validationString, this.firstMessage().key].join(':');\n    const i18nextKeys: string[] = [];\n\n    if (this.i18nextNamespace && this.i18nextNamespace !== this.validationString) {\n      i18nextKeys.push([this.i18nextNamespace, specificKey].join('.'));\n      i18nextKeys.push([this.i18nextNamespace, commonKey].join('.'));\n    }\n\n    i18nextKeys.push(specificKey);\n    i18nextKeys.push(commonKey);\n\n    return i18nextKeys;\n  });\n\n  private getErrorMessages(control: NgControl) {\n    const errors = control.errors;\n    if (!errors) return [];\n\n    return Object.entries(errors ?? {}).map(([key, value]) => {\n      let params = null;\n      if (value instanceof Object) {\n        params = value;\n      } else if (value !== true) {\n        params = { [key]: value };\n      }\n      return new ValidationMessage(key, params);\n    });\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/forms/src/directives/validation-message.directive.ts",
    "content": "import { AfterViewInit, ComponentRef, Directive, inject, OnDestroy, ViewContainerRef } from \"@angular/core\";\nimport { FormControlName, NgControl } from \"@angular/forms\";\nimport { I18NextValidationMessageComponent } from \"../components/validation-message.component\";\n\n@Directive({\n  selector: '[formControlName][i18nextValidationMessage],[formGroupName][i18nextValidationMessage],[formArrayName][i18nextValidationMessage]',\n  standalone: true\n})\nexport class I18NextValidationMessageDirective implements AfterViewInit, OnDestroy {\n  private readonly viewContainer = inject(ViewContainerRef);\n  private readonly formControlName = inject(FormControlName, { optional: true });\n\n  private validationMessageComponent: ComponentRef<I18NextValidationMessageComponent> | null = null;\n\n  ngAfterViewInit(): void {\n    this.detach();\n    this.validationMessageComponent = this.viewContainer.createComponent(I18NextValidationMessageComponent);\n\n    const control: NgControl = this.formControlName!;\n    this.validationMessageComponent.instance.setFor(control);\n    this.validationMessageComponent.changeDetectorRef.detectChanges();\n  }\n\n  ngOnDestroy(): void {\n    this.detach();\n  }\n\n  private detach(): void {\n    if (this.validationMessageComponent?.changeDetectorRef) {\n      this.validationMessageComponent.changeDetectorRef.detach();\n      this.validationMessageComponent = null;\n    }\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/forms/src/models.ts",
    "content": "/**\n * Represents a validation message with translation key and parameters\n */\nexport interface ValidationMessageParams {\n  [key: string]: unknown;\n}\n\nexport class ValidationMessage {\n  constructor(\n    public readonly key = '',\n    public readonly params?: ValidationMessageParams\n  ) {}\n}\n"
  },
  {
    "path": "libs/angular-i18next/forms/src/public_api.ts",
    "content": "export { ValidationMessage, ValidationMessageParams } from './models';\nexport { I18NextValidationMessageComponent } from './components/validation-message.component';\nexport { I18NextValidationMessageDirective } from './directives/validation-message.directive';\n"
  },
  {
    "path": "libs/angular-i18next/jest.config.ts",
    "content": "/* eslint-disable */\nexport default {\n  displayName: 'angular-i18next',\n  preset: '../../jest.preset.js',\n  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],\n  globals: {},\n  coverageDirectory: '../../libs/angular-i18next/coverage',\n  transform: {\n    '^.+\\\\.(ts|mjs|js|html)$': [\n      'jest-preset-angular',\n      {\n        tsconfig: '<rootDir>/tsconfig.spec.json',\n        stringifyContentPathRegex: '\\\\.(html|svg)$',\n      },\n    ],\n  },\n  transformIgnorePatterns: ['node_modules/(?!.*\\\\.mjs$)'],\n  snapshotSerializers: [\n    'jest-preset-angular/build/serializers/no-ng-attributes',\n    'jest-preset-angular/build/serializers/ng-snapshot',\n    'jest-preset-angular/build/serializers/html-comment',\n  ],\n  useESM: true,\n};\n"
  },
  {
    "path": "libs/angular-i18next/ng-package.json",
    "content": "{\n  \"$schema\": \"../../node_modules/ng-packagr/ng-package.schema.json\",\n  \"assets\": [\n    \"CHANGELOG.md\",\n    \"postinstall.js\"\n  ],\n  \"lib\": {\n    \"entryFile\": \"src/index.ts\"\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/package.json",
    "content": "{\n  \"name\": \"angular-i18next\",\n  \"version\": \"21.0.0-3\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"np\": {\n    \"contents\": \"./dist\"\n  },\n  \"author\": {\n    \"name\": \"Sergey Romanchuk\"\n  },\n  \"homepage\": \"https://github.com/Romanchuk/angular-i18next#readme\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Romanchuk/angular-i18next.git\"\n  },\n  \"engines\": {\n    \"node\": \">=22.0.0\"\n  },\n  \"license\": \"MIT\",\n  \"description\": \"i18next module for Angular\",\n  \"keywords\": [\n    \"i18n\",\n    \"i18next\",\n    \"angular\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/Romanchuk/angular-i18next/issues\"\n  },\n  \"maintainers\": [\n    {\n      \"email\": \"rezety@gmail.com\",\n      \"name\": \"Sergey Romanchuk\"\n    }\n  ],\n  \"scripts\": {\n    \"clean\": \"npm run clean:build && npm run clean:tests\",\n    \"clean:build\": \"npx rimraf dist\",\n    \"clean:tests\": \"npx rimraf coverage && npx rimraf tests/**/*.+{js,js.map,d.ts,metadata.json}\",\n    \"copy:assets\": \"npx cpy CHANGELOG.md dist\",\n    \"conventional-changelog\": \"npx conventional-changelog\",\n    \"changelog\": \"npm run conventional-changelog -- -p angular -i CHANGELOG.md -s\",\n    \"changelog:add\": \"git add --force CHANGELOG.md package.json\",\n    \"changelog:commit\": \"git commit -m \\\"Updated CHANGELOG.md\\\"\",\n    \"version\": \"npx conventional-changelog -p angular -i CHANGELOG.md -s -r && npx nx run angular-i18next:build && npm run copy:assets && npm run changelog:add && npm run changelog:commit\",\n    \"release\": \"npx np\",\n    \"test\": \"npx nx run angular-i18next:test\"\n  },\n  \"dependencies\": {\n    \"tslib\": \"^2.8.1\"\n  },\n  \"peerDependencies\": {\n    \"@angular/common\": \"^21.1.1\",\n    \"@angular/core\": \"^21.1.1\",\n    \"@angular/platform-browser\": \"^21.1.1\",\n    \"i18next\": \"^25.4.0\",\n    \"rxjs\": \"^7.8.2\"\n  },\n  \"optionalDependencies\": {\n    \"@angular/ssr\": \"^21.1.1\",\n    \"@angular/platform-server\": \"^21.1.1\"\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/postinstall.js",
    "content": "var BANNER = '\\u001B[96mThank you for using angular-i18next (https://github.com/Romanchuk/angular-i18next). Please star the repo!\\u001B[0m\\n\\n' +\n             '\\u001B[96mThe project needs your help! Please consider supporting of angular-i18next \\u001B[0m\\n' +\n             '\\u001B[96m>\\u001B[94m Say thanks via donation: https://www.paypal.com/paypalme2/sergeyromanchuk/10USD \\u001B[0m\\n';\n\nconsole.log(BANNER);\n"
  },
  {
    "path": "libs/angular-i18next/project.json",
    "content": "{\n  \"name\": \"angular-i18next\",\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"sourceRoot\": \"libs/angular-i18next/src\",\n  \"targets\": {\n    \"build\": {\n      \"dependsOn\": [\"clean\"],\n      \"executor\": \"@nx/angular:package\",\n      \"options\": {\n        \"project\": \"libs/angular-i18next/ng-package.json\",\n        \"tsConfig\": \"libs/angular-i18next/tsconfig.lib.json\"\n      }\n    },\n    \"test\": {\n      \"executor\": \"@nx/jest:jest\",\n      \"outputs\": [\"{workspaceRoot}/coverage/libs/angular-i18next\"],\n      \"options\": {\n        \"jestConfig\": \"libs/angular-i18next/jest.config.ts\",\n        \"passWithNoTests\": true\n      }\n    },\n    \"lint\": {\n      \"executor\": \"@nx/eslint:lint\",\n      \"options\": {\n        \"lintFilePatterns\": [\n          \"libs/angular-i18next/src/**/*.ts\",\n          \"libs/angular-i18next/src/**/*.html\"\n        ]\n      }\n    }\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/.eslintrc.json",
    "content": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"]\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/index.ts",
    "content": "export * from './lib/index';\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/I18NextErrorHandlingStrategies.ts",
    "content": "import { I18NextLoadResult } from './I18NextLoadResult';\nimport * as i18n from 'i18next';\n\nexport interface I18NextErrorHandlingStrategy {\n  handle(\n    resolve: (thenableOrResult?: any) => void,\n    reject: (error: any) => void\n  ): i18n.Callback;\n}\n\nexport class NativeErrorHandlingStrategy\n  implements I18NextErrorHandlingStrategy\n{\n  handle(\n    resolve: (thenableOrResult?: I18NextLoadResult) => void,\n    reject: (error: any) => void\n  ) {\n    return (err: any, t?: Function) => {\n      let result: I18NextLoadResult = {\n        err: err,\n        t: t,\n      };\n      resolve(result);\n    };\n  }\n}\n\nexport class StrictErrorHandlingStrategy\n  implements I18NextErrorHandlingStrategy\n{\n  handle(\n    resolve: (thenableOrResult?: I18NextLoadResult) => void,\n    reject: (error: any) => void\n  ) {\n    return (err: any, t?: any) => {\n      let result: I18NextLoadResult = {\n        err: err,\n        t: t,\n      };\n      if (!err) {\n        resolve(result);\n        return;\n      }\n      reject(err);\n    };\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/I18NextEvents.ts",
    "content": "import { BehaviorSubject, Subject } from 'rxjs';\n\nimport {\n  ITranslationEvents,\n  MissingKeyEvent,\n  ResourceEvent,\n} from './services/translation.events';\nimport * as i18n from 'i18next';\n\nexport class I18NextEvents implements ITranslationEvents {\n  initialized = new BehaviorSubject<i18n.InitOptions | undefined>(undefined);\n  loaded = new BehaviorSubject(false);\n  failedLoading = new Subject();\n  missingKey = new Subject<MissingKeyEvent>();\n  added = new Subject<ResourceEvent>();\n  removed = new Subject<ResourceEvent>();\n  languageChanged = new BehaviorSubject<string | null>(null);\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/I18NextLoadResult.ts",
    "content": "export interface I18NextLoadResult {\n  err: any;\n  t?: Function;\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/I18NextModuleParams.ts",
    "content": "import { Type } from '@angular/core';\nimport { I18NextErrorHandlingStrategy } from './I18NextErrorHandlingStrategies';\n\nexport interface I18NextModuleParams {\n  errorHandlingStrategy?: Type<I18NextErrorHandlingStrategy>;\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/index.ts",
    "content": "export * from './I18NextErrorHandlingStrategies';\nexport * from './I18NextEvents';\nexport * from './I18NextLoadResult';\nexport * from './I18NextModuleParams';\nexport * from './interpolation';\nexport * from './models';\nexport * from './module';\nexport * from './namespaces.guard';\nexport * from './pipes/i18next-cap.pipe';\nexport * from './pipes/i18next-eager.pipe';\nexport * from './pipes/i18next-format.pipe';\nexport * from './pipes/i18next.pipe';\nexport * from './provider';\nexport * from './provider.utils';\nexport * from './services/i18next-title';\nexport * from './services/i18next.service';\nexport * from './services/translation.events';\nexport * from './services/translation.service';\nexport * from './tokens';\n\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/interpolation.ts",
    "content": "import type { FormatFunction, InterpolationOptions } from \"i18next\";\n\nexport function defaultInterpolationFormat(\n    value: any,\n    format?: string,\n    lng?: string\n  ): string {\n    if (!value) return value;\n    switch (format) {\n      case 'upper':\n      case 'uppercase':\n        return value.toUpperCase();\n      case 'lower':\n      case 'lowercase':\n        return value.toLowerCase();\n      case 'cap':\n      case 'capitalize':\n        return value.charAt(0).toUpperCase() + value.slice(1);\n      case null:\n      case undefined:\n      case 'none':\n      default:\n        return value;\n    }\n  }\n\n  export function interpolationFormat(customFormat: Function | null = null): FormatFunction {\n    function formatDelegate(value: any,\n                            format?: string,\n                            lng?: string,\n                            options?: InterpolationOptions & { [key: string]: any }\n    ): string {\n      let formatedValue: string = defaultInterpolationFormat(\n        value,\n        format,\n        lng\n      );\n      if (customFormat === null) return formatedValue;\n      return customFormat(formatedValue, format, lng);\n    }\n    return formatDelegate;\n  }"
  },
  {
    "path": "libs/angular-i18next/src/lib/models.ts",
    "content": "import type * as i18n from 'i18next';\n\nexport type FormatPipeOptions = { format?: string; lng?: string; case?: string; [key: string]: any };\nexport type PrependPipeOptions = {\n  prependScope?: boolean;\n  prependNamespace?: boolean;\n};\n\n\nexport type PipeOptions = i18n.TOptions &\n  FormatPipeOptions &\n  PrependPipeOptions;\n\nexport type NamespaceResolver = (\n  activatedRouteSnapshot: any,\n  routerStateSnapshot?: any\n) => Promise<void>\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/module.ts",
    "content": "import { NgModule, ModuleWithProviders } from \"@angular/core\";\nimport { FormatFunction, InterpolationOptions } from \"i18next\";\nimport { I18NEXT_NAMESPACE, I18NEXT_SCOPE, I18NEXT_INSTANCE, I18NEXT_SERVICE, I18NEXT_ERROR_HANDLING_STRATEGY, I18NEXT_NAMESPACE_RESOLVER } from \"./tokens\";\nimport { I18NextCapPipe } from \"./pipes/i18next-cap.pipe\";\nimport { I18NextEagerPipe } from \"./pipes/i18next-eager.pipe\";\nimport { I18NextErrorHandlingStrategy, NativeErrorHandlingStrategy } from \"./I18NextErrorHandlingStrategies\";\nimport { I18NextFormatPipe } from \"./pipes/i18next-format.pipe\";\nimport { I18NextModuleParams } from \"./I18NextModuleParams\";\nimport { I18NextPipe } from \"./pipes/i18next.pipe\";\nimport { I18NextService } from \"./services/i18next.service\";\nimport { I18NextTitle } from \"./services/i18next-title\";\nimport { defaultInterpolationFormat } from \"./interpolation\";\nimport * as i18n from 'i18next';\nimport { i18nextNamespaceResolverFactory } from \"./namespace.resolver\";\n\nconst i18nextGlobal: i18n.i18n = i18n.default;\n\n/**\n * @deprecated Use provideI18Next() instead. This module-based approach will be removed in a future version.\n * Example:\n * ```typescript\n * // Instead of\n * imports: [I18NextModule.forRoot()]\n *\n * // Use\n * providers: [provideI18Next()]\n * ```\n */\n@NgModule({\n  imports: [I18NextPipe, I18NextEagerPipe, I18NextCapPipe, I18NextFormatPipe],\n  exports: [I18NextPipe, I18NextEagerPipe, I18NextCapPipe, I18NextFormatPipe],\n  providers: [\n    {\n      provide: I18NEXT_NAMESPACE,\n      useValue: '',\n    },\n    {\n      provide: I18NEXT_SCOPE,\n      useValue: '',\n    },\n    I18NextTitle,\n    I18NextFormatPipe\n  ],\n})\nexport class I18NextModule {\n  /**\n   * @deprecated Use provideI18Next() instead. This module-based approach will be removed in a future version.\n   * Example:\n   * ```typescript\n   * // Instead of\n   * imports: [I18NextModule.forRoot()]\n   *\n   * // Use\n   * providers: [provideI18Next()]\n   * ```\n   */\n  static forRoot(\n    params: I18NextModuleParams = {}\n  ): ModuleWithProviders<I18NextModule> {\n    return {\n      ngModule: I18NextModule,\n      providers: [{\n        provide: I18NEXT_INSTANCE,\n        useValue: i18nextGlobal,\n      },\n        {\n          provide: I18NEXT_SERVICE,\n          useFactory: (errHandle: I18NextErrorHandlingStrategy, i18nextInstance: i18n.i18n) => new I18NextService(errHandle, i18nextInstance),\n          deps: [\n            I18NEXT_ERROR_HANDLING_STRATEGY,\n            I18NEXT_INSTANCE\n          ]\n        },\n        {\n          provide: I18NEXT_ERROR_HANDLING_STRATEGY,\n          useClass: params.errorHandlingStrategy || NativeErrorHandlingStrategy,\n        },\n        I18NextService,\n        I18NextPipe,\n        I18NextEagerPipe,\n        I18NextCapPipe,\n        I18NextFormatPipe,\n        I18NextTitle,\n        {\n          provide: I18NEXT_NAMESPACE_RESOLVER,\n          useFactory: i18nextNamespaceResolverFactory,\n          deps: [I18NEXT_SERVICE],\n        },\n      ],\n    };\n  }\n\n  static interpolationFormat(customFormat: Function | null = null): FormatFunction {\n    function formatDelegate(value: any,\n                            format?: string,\n                            lng?: string,\n                            options?: InterpolationOptions & { [key: string]: any }\n    ): string {\n      let formatedValue: string = defaultInterpolationFormat(\n        value,\n        format,\n        lng\n      );\n      if (customFormat === null) return formatedValue;\n      return customFormat(formatedValue, format, lng);\n    }\n    return formatDelegate;\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/namespace.resolver.ts",
    "content": "import { inject } from \"@angular/core\";\nimport { I18NEXT_SERVICE } from \"./tokens\";\nimport { ITranslationService } from \"./services/translation.service\";\nimport { NamespaceResolver } from \"./models\";\n\nexport function resolver(\n  activatedRouteSnapshot: any,\n  routerStateSnapshot: any\n): NamespaceResolver {\n  const i18next: ITranslationService = inject(I18NEXT_SERVICE);\n  let namespaces: string[] = activatedRouteSnapshot.data?.i18nextNamespaces ?? [];\n  // @ts-ignore\n  return i18next.loadNamespaces(namespaces.filter((n) => n));\n}\n\nexport function i18nextNamespaceResolverFactory() {\n  return resolver;\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/namespaces.guard.ts",
    "content": "import { inject } from \"@angular/core\";\nimport { I18NEXT_SERVICE } from \"./tokens\";\n\n/**\n * This function can trigger the loading of I18Next namespaces and block route activation to ensure namespaces are loaded before navigation continues.\n *\n * @param i18nextNamespaces I18Next namespaces to load\n * @returns A functional guard that will load the I18Next Namespaces, and continue navigation when loaded.\n */\nexport const i18NextNamespacesGuard =\n  (...i18nextNamespaces: string[]) =>\n  () =>\n    inject(I18NEXT_SERVICE)\n      .loadNamespaces(i18nextNamespaces.filter(Boolean))\n      .then(() => true)\n      .catch(() => false);\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/pipes/i18next-cap.pipe.ts",
    "content": "import { Inject, Injectable, Pipe, PipeTransform } from '@angular/core';\nimport {\n  I18NEXT_NAMESPACE,\n  I18NEXT_SCOPE,\n  I18NEXT_SERVICE,\n} from '../tokens';\nimport { I18NextPipe } from './i18next.pipe';\nimport { ITranslationService } from '../services/translation.service';\nimport { PipeOptions } from '../models';\n\n@Injectable()\n@Pipe({\n  name: 'i18nextCap',\n  standalone: true\n})\nexport class I18NextCapPipe extends I18NextPipe implements PipeTransform {\n  constructor(\n    @Inject(I18NEXT_SERVICE) translateI18Next: ITranslationService,\n    @Inject(I18NEXT_NAMESPACE) ns: string | string[],\n    @Inject(I18NEXT_SCOPE) scope: string | string[]\n  ) {\n    super(translateI18Next, ns, scope);\n  }\n\n  public override transform(key: string | string[], options?: PipeOptions): string {\n    options = options || {};\n    options.format = 'cap';\n    return super.transform(key, options);\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/pipes/i18next-eager.pipe.ts",
    "content": "import {\n  ChangeDetectorRef,\n  Inject,\n  Pipe,\n  PipeTransform\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { PipeOptions } from '../models';\nimport { ITranslationService } from '../services/translation.service';\nimport {\n  I18NEXT_NAMESPACE,\n  I18NEXT_SCOPE,\n  I18NEXT_SERVICE,\n} from '../tokens';\nimport { I18NextPipe } from './i18next.pipe';\n\n@Pipe({\n  name: 'i18nextEager',\n  pure: false,\n  standalone: true,\n})\nexport class I18NextEagerPipe\n  extends I18NextPipe\n  implements PipeTransform\n{\n  private lastKey: string | undefined;\n  private lastOptions: PipeOptions | undefined;\n  private lastValue: string = '';\n\n  constructor(\n    @Inject(I18NEXT_SERVICE) protected override translateI18Next: ITranslationService,\n    @Inject(I18NEXT_NAMESPACE) protected override ns: string | string[],\n    @Inject(I18NEXT_SCOPE) protected override scope: string | string[],\n    private cd: ChangeDetectorRef\n  ) {\n    super(translateI18Next, ns, scope);\n    translateI18Next.events.languageChanged\n      .pipe(takeUntilDestroyed())\n      .subscribe(() => {\n          this.cd.markForCheck();\n      });\n  }\n  private hasKeyChanged(key: string | string[]): boolean {\n    return !this.lastKey || this.lastKey !== key;\n  }\n\n  private hasOptionsChanged(options?: PipeOptions): boolean {\n    return this.lastOptions !== options;\n  }\n\n  public override transform(key: string | string[], options?: PipeOptions): string {\n    const newKey = this.translateI18Next.language + '|' + JSON.stringify(key);\n\n    if (this.hasKeyChanged(newKey) || this.hasOptionsChanged(options)) {\n      this.lastKey = newKey;\n      this.lastOptions = options;\n      this.lastValue = super.transform(key, options);\n    }\n    return this.lastValue;\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/pipes/i18next-format.pipe.ts",
    "content": "import { Inject, Injectable, Pipe, PipeTransform } from '@angular/core';\nimport { FormatPipeOptions } from '../models';\nimport { ITranslationService } from '../services/translation.service';\nimport { I18NEXT_SERVICE } from '../tokens';\n\n@Injectable()\n@Pipe({\n  name: 'i18nextFormat',\n  standalone: true\n})\nexport class I18NextFormatPipe implements PipeTransform {\n  constructor(\n    @Inject(I18NEXT_SERVICE) private translateI18Next: ITranslationService\n  ) {}\n\n  public transform(value: any, options: FormatPipeOptions | string): string {\n    let opts: FormatPipeOptions =\n      typeof options === 'string' ? { format: options } : options;\n    return this.translateI18Next.format(value, opts.format, opts.lng);\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/pipes/i18next.pipe.ts",
    "content": "import { Inject, Injectable, Pipe, PipeTransform } from '@angular/core';\nimport { PipeOptions } from '../models';\nimport { ITranslationService } from '../services/translation.service';\nimport {\n  I18NEXT_NAMESPACE,\n  I18NEXT_SCOPE,\n  I18NEXT_SERVICE\n} from '../tokens';\n\n@Injectable()\n@Pipe({\n  name: 'i18next',\n  standalone: true\n})\nexport class I18NextPipe implements PipeTransform {\n  constructor(\n    @Inject(I18NEXT_SERVICE) protected translateI18Next: ITranslationService,\n    @Inject(I18NEXT_NAMESPACE) protected ns: string | string[],\n    @Inject(I18NEXT_SCOPE) protected scope: string | string[]\n  ) {}\n\n  public transform(key: string | string[], options?: PipeOptions): string {\n    options = this.prepareOptions(options);\n\n    let i18nOpts = this.translateI18Next.options;\n    if (options.prependScope === undefined || options.prependScope === true) {\n      if (this.scope) {\n        key = this.prependScope(\n          key,\n          this.scope,\n          i18nOpts.keySeparator,\n          i18nOpts.nsSeparator\n        );\n      }\n    }\n    if (\n      options.prependNamespace === undefined ||\n      options.prependNamespace === true\n    ) {\n      if (this.ns) {\n        key = this.prependNamespace(key, this.ns, i18nOpts.nsSeparator);\n      }\n    }\n\n    let result = this.translateI18Next.t(key, options);\n\n    if (options.format) {\n      if (result) {\n        result = this.translateI18Next.format(\n          result,\n          options.format,\n          this.translateI18Next.language\n        );\n      }\n    }\n    return result ?? '';\n  }\n\n  private prependScope(\n    key: string | string[],\n    scope: string | string[],\n    keySeparator: string | false | undefined,\n    nsSeparator: string | false | undefined\n  ): string[] {\n    const nsSep = nsSeparator || '';\n    const keySep = keySeparator || '';\n    if (typeof key === 'string') {\n      key = [key];\n    }\n    if (typeof scope === 'string') {\n      scope = [scope];\n    }\n    let keysWithScope = [];\n    for (let i = 0; i < key.length; i++) {\n      const k = key[i];\n      if (!this.keyContainsNsSeparator(k, nsSep)) {\n        // Do not set scope, if key contains a namespace\n        keysWithScope.push(\n          ...scope.map((sc) => this.joinStrings(keySep, sc, k))\n        );\n      }\n      keysWithScope.push(k);\n    }\n    return keysWithScope;\n  }\n\n  private prependNamespace(\n    key: string | string[],\n    ns: string | string[],\n    nsSeparator: string | false | undefined\n  ): string[] {\n    const nsSep = nsSeparator || '';\n    if (typeof key === 'string') {\n      key = [key];\n    }\n    if (typeof ns === 'string') {\n      ns = [ns];\n    }\n    let keysWithNamespace = [];\n    for (let i = 0; i < key.length; i++) {\n      const k = key[i];\n      if (!this.keyContainsNsSeparator(k, nsSep)) {\n        // Do not set namespace, if key contains a namespace\n        keysWithNamespace.push(...ns.map((n) => this.joinStrings(nsSep, n, k)));\n      }\n      keysWithNamespace.push(k);\n    }\n    return keysWithNamespace;\n  }\n\n  private joinStrings(separator: string, ...str: string[]) {\n    return [...str].join(separator);\n  }\n\n  private keyContainsNsSeparator(key: string, nsSeparator: string) {\n    return key.indexOf(nsSeparator) !== -1;\n  }\n\n  private prepareOptions(options?: PipeOptions): PipeOptions {\n    options = options || {};\n    if (options.context != null) options.context = options.context.toString();\n    return options;\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/provider.ts",
    "content": "import {\n  ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID,\n  EnvironmentProviders,\n  inject,\n  LOCALE_ID,\n  makeEnvironmentProviders,\n  Provider,\n  Type\n} from '@angular/core';\nimport { Title } from '@angular/platform-browser';\nimport * as i18n from 'i18next';\nimport {\n  I18NextErrorHandlingStrategy,\n  NativeErrorHandlingStrategy,\n} from './I18NextErrorHandlingStrategies';\nimport { I18NextCapPipe } from './pipes/i18next-cap.pipe';\nimport { I18NextEagerPipe } from './pipes/i18next-eager.pipe';\nimport { I18NextFormatPipe } from './pipes/i18next-format.pipe';\nimport { I18NextPipe } from './pipes/i18next.pipe';\nimport { I18NextFeature, I18NextFeatureKind, makeI18NextFeature } from './provider.utils';\nimport { I18NextTitle } from './services/i18next-title';\nimport { I18NextService } from './services/i18next.service';\nimport {\n  I18NEXT_ERROR_HANDLING_STRATEGY,\n  I18NEXT_INSTANCE,\n  I18NEXT_NAMESPACE,\n  I18NEXT_SCOPE,\n  I18NEXT_SERVICE\n} from './tokens';\n\nconst i18nextGlobal: i18n.i18n = i18n.default;\n\nexport function localeIdFactory() {\n  const i18next = inject(I18NEXT_SERVICE);\n  return i18next.language ?? DEFAULT_LOCALE_ID;\n}\n\n  /**\n   * Provides the necessary dependencies for using i18next with Angular.\n   *\n   * @param features An array of features to enable. See {@link I18NextFeature} for available features.\n   * @returns An array of providers that can be added to the root providers.\n   *\n   * @example\n   * import { provideI18Next } from '@angular-i18next/core';\n   *\n   *   providers: [\n   *     provideI18Next(),\n   *   ],\n   *\n   */\nexport function provideI18Next(\n  ...features: I18NextFeature<I18NextFeatureKind>[]\n): EnvironmentProviders {\n  const providers: Provider[] = [\n    {\n      provide: I18NEXT_INSTANCE,\n      useValue: i18nextGlobal,\n    },\n    {\n      provide: I18NEXT_SERVICE,\n      useFactory: (\n        errHandle: I18NextErrorHandlingStrategy,\n        i18nextInstance: i18n.i18n,\n      ) => new I18NextService(errHandle, i18nextInstance),\n      deps: [I18NEXT_ERROR_HANDLING_STRATEGY, I18NEXT_INSTANCE],\n    },\n    {\n      provide: I18NEXT_NAMESPACE,\n      useValue: '',\n    },\n    {\n      provide: I18NEXT_SCOPE,\n      useValue: '',\n    },\n    {\n      provide: I18NEXT_ERROR_HANDLING_STRATEGY,\n      useClass: NativeErrorHandlingStrategy,\n    },\n    {\n      provide: LOCALE_ID,\n      useFactory: localeIdFactory,\n    },\n    I18NextService,\n    I18NextPipe,\n    I18NextEagerPipe,\n    I18NextCapPipe,\n    I18NextFormatPipe,\n  ];\n\n  for (const feature of features) {\n    providers.push(...feature.ɵproviders);\n  }\n\n  return makeEnvironmentProviders(providers);\n}\n\n/**\n * Configures a custom error handling strategy for i18next.\n *\n * @param errorHandlingStrategy - A class implementing the I18NextErrorHandlingStrategy interface.\n * @returns An I18NextFeature for the specified custom error handling strategy.\n *\n * This feature allows the integration of a custom error handling mechanism\n * into the i18next setup, replacing the default error handling strategy.\n *\n *  * Example:\n * ```typescript\n *    providers: [\n *       provideI18Next(withCustomErrorHandlingStrategy(StrictErrorHandlingStrategy)())\n *    ]\n * ```\n */\nexport function withCustomErrorHandlingStrategy(\n  errorHandlingStrategy: Type<I18NextErrorHandlingStrategy>,\n): I18NextFeature<I18NextFeatureKind.CustomErrorHandlingStrategy> {\n  return makeI18NextFeature(I18NextFeatureKind.CustomErrorHandlingStrategy, [\n    {\n      provide: I18NEXT_ERROR_HANDLING_STRATEGY,\n      useClass: errorHandlingStrategy,\n    },\n  ]);\n}\n\n/**\n * Provides I18NextTitle service for document title translation support.\n *\n * @returns An I18NextFeature that configures the I18NextTitle service\n *\n * Example:\n * ```typescript\n * providers: [\n *   provideI18Next(withTitle())\n * ]\n * ```\n */\nexport function withTitle(): I18NextFeature<I18NextFeatureKind.Title> {\n  return makeI18NextFeature(I18NextFeatureKind.Title, [\n    {\n        provide: Title,\n        useClass: I18NextTitle\n    }\n  ]);\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/provider.utils.ts",
    "content": "import { Provider } from \"@angular/core\";\n\n/**\n * A feature for use when configuring `provideI18Next`.\n *\n * @publicApi\n */\nexport interface I18NextFeature<KindT extends I18NextFeatureKind> {\n  ɵkind: KindT;\n  ɵproviders: Provider[];\n}\n\nexport function makeI18NextFeature<KindT extends I18NextFeatureKind>(\n  kind: KindT,\n  providers: Provider[],\n): I18NextFeature<KindT> {\n  return {\n    ɵkind: kind,\n    ɵproviders: providers,\n  };\n}\n\n/**\n * Identifies a particular kind of `HttpFeature`.\n *\n * @publicApi\n */\nexport enum I18NextFeatureKind {\n  CustomErrorHandlingStrategy,\n  Mock,\n  Title,\n  AppInitialize,\n  SSR,\n  Forms\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/services/i18next-title.ts",
    "content": "import { DOCUMENT } from '@angular/common';\nimport { Inject, Injectable } from '@angular/core';\nimport { Title } from '@angular/platform-browser';\nimport { I18NextPipe } from '../pipes/i18next.pipe';\n\n@Injectable()\nexport class I18NextTitle extends Title {\n  constructor(private i18nextPipe: I18NextPipe, @Inject(DOCUMENT) doc: any) {\n    super(doc);\n  }\n\n  override setTitle(value: string) {\n    return super.setTitle(this.translate(value));\n  }\n\n  private translate(text: string) {\n    return this.i18nextPipe.transform(text, { format: 'cap' });\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/services/i18next.service.ts",
    "content": "import { Inject, Injectable, Optional } from '@angular/core';\nimport * as i18n from 'i18next';\nimport { I18NextErrorHandlingStrategy } from '../I18NextErrorHandlingStrategies';\nimport { I18NextEvents } from '../I18NextEvents';\nimport { I18NextLoadResult } from '../I18NextLoadResult';\nimport { I18NEXT_ERROR_HANDLING_STRATEGY, I18NEXT_INSTANCE } from '../tokens';\nimport { ITranslationEvents } from './translation.events';\nimport { ITranslationOptions, ITranslationService } from './translation.service';\nimport type { InitOptions, Module, Modules, Namespace, Newable, NewableModule, ResourceStore, Services, TFunction, TFunctionReturn } from 'i18next';\n\n\nconst i18nextGlobal: i18n.i18n = i18n.default;\n\n@Injectable()\nexport class I18NextService implements ITranslationService {\n\n  private readonly i18next: i18n.i18n;\n\n  events: ITranslationEvents = new I18NextEvents();\n\n  get language() {\n    return this.i18next.language;\n  }\n  get languages() {\n    return this.i18next.languages;\n  }\n\n  get options() {\n    return this.i18next.options;\n  }\n\n  get modules(): Modules {\n    return this.i18next.modules;\n  }\n  get services(): Services {\n    return this.i18next.services;\n  }\n  get store(): ResourceStore {\n    return this.i18next.store;\n  }\n\n  get resolvedLanguage() {\n    return this.i18next.resolvedLanguage;\n  }\n\n  get isInitialized() {\n    return this.i18next.isInitialized;\n  }\n\n  constructor(\n    @Inject(I18NEXT_ERROR_HANDLING_STRATEGY)\n    private errorHandlingStrategy: I18NextErrorHandlingStrategy,\n    @Optional() @Inject(I18NEXT_INSTANCE) i18nextInstance?: i18n.i18n\n  ) {\n    this.i18next = i18nextInstance ?? i18nextGlobal;\n  }\n\n  t(key: string | string[], options?: ITranslationOptions | undefined): TFunctionReturn<Namespace, string | string[], ITranslationOptions>;\n  t(key: string | string[] | (string | TemplateStringsArray)[], defaultValue: string, options?: ITranslationOptions | undefined): TFunctionReturn<Namespace, string | string[], ITranslationOptions>;\n  t(key: unknown, defaultValueOrOptions?: unknown, options?: unknown): TFunctionReturn<Namespace, unknown, ITranslationOptions> {\n    const hasDefault = !!defaultValueOrOptions && typeof defaultValueOrOptions === 'string';\n\n    this.i18next.t.bind(this.i18next);\n    if (hasDefault) {\n      return this.i18next.t(key as (string | string[]), defaultValueOrOptions as string, options as ITranslationOptions);\n    } else {\n      return this.i18next.t(key as (string | string[]), defaultValueOrOptions as ITranslationOptions);\n    }\n  }\n\n  public use<T extends Module>(\n    module:\n    T | NewableModule<T> | Newable<T>\n  ): ITranslationService {\n    this.i18next.use.call(this.i18next, module);\n    return this;\n  }\n\n  init(options: InitOptions): Promise<I18NextLoadResult> {\n    this.subscribeEvents();\n\n    return new Promise<I18NextLoadResult>((resolve, reject) => {\n      this.i18next.init.call(\n        this.i18next,\n        Object.assign({}, options ?? {}),\n        this.errorHandlingStrategy.handle(resolve, reject)\n      );\n    });\n  }\n\n  public format(value: any, format?: string, lng?: string): string {\n    return this.i18next.format.call(this.i18next, value, format, lng, {});\n  }\n\n  public exists(key: string | string[], options: any) {\n    return this.i18next.exists.call(this.i18next, key, options);\n  }\n\n  getFixedT(lng: string | readonly string[], ns?: string | readonly string[], keyPrefix?: string): TFunction;\n  getFixedT(lng: null, ns: string | readonly string[] | null, keyPrefix?: string): TFunction;\n  getFixedT(lng: any, ns?: any, keyPrefix?: any): TFunction {\n    return this.i18next.getFixedT.call(this.i18next, lng, ns, keyPrefix);\n  }\n\n  public setDefaultNamespace(ns: string) {\n    this.i18next.setDefaultNamespace.call(this.i18next, ns);\n  }\n\n  public dir(lng?: string) {\n    return this.i18next.dir.call(this.i18next, lng);\n  }\n\n  public changeLanguage(lng: string): Promise<TFunction> {\n    return new Promise<TFunction>(\n      (\n        resolve: (thenableOrResult: TFunction | PromiseLike<TFunction>) => void,\n        reject: (error: any) => void\n      ) => {\n        return this.i18next.changeLanguage.call(\n          this.i18next,\n          lng,\n          this.errorHandlingStrategy.handle(resolve, reject)\n        );\n      }\n    );\n  }\n\n  public loadNamespaces(namespaces: string | string[]): Promise<any> {\n    return new Promise<I18NextLoadResult>(\n      (\n        resolve: (thenableOrResult: I18NextLoadResult | PromiseLike<I18NextLoadResult>) => void,\n        reject: (error: any) => void\n      ) => {\n        this.i18next.loadNamespaces.call(\n          this.i18next,\n          namespaces,\n          this.errorHandlingStrategy.handle(resolve, reject)\n        );\n      }\n    );\n  }\n\n  public loadLanguages(lngs: string | string[]) {\n    return new Promise<void>(\n      (\n        resolve: (thenableOrResult: void | PromiseLike<void>) => void,\n        reject: (error: any) => void\n      ) => {\n        this.i18next.loadLanguages.call(\n          this.i18next,\n          lngs,\n          this.errorHandlingStrategy.handle(resolve, reject)\n        );\n      }\n    );\n  }\n\n  //#region resource handling\n\n  public loadResources(callback?: (err: any) => void): void {\n    this.i18next.loadResources.call(this.i18next, callback);\n  }\n  public getDataByLanguage(lng: string) {\n    return this.i18next.getDataByLanguage.call(this.i18next, lng);\n  }\n\n  public async reloadResources(...params: any) {\n    await this.i18next.reloadResources.apply(this.i18next, params);\n  }\n\n  public getResource(lng: string, ns: string, key: string, options: any) {\n    return this.i18next.getResource.call(this.i18next, lng, ns, key, options);\n  }\n\n  public addResource(lng: string, ns: string, key: string, value: any, options: any): i18n.i18n {\n    return this.i18next.addResource.call(this.i18next, lng, ns, key, value, options);\n  }\n\n  public addResources(lng: string, ns: string, resources: any): i18n.i18n {\n    return this.i18next.addResources.call(this.i18next, lng, ns, resources);\n  }\n\n  public addResourceBundle(lng: string, ns: string, resources: any, deep: any, overwrite: any): i18n.i18n {\n    return this.i18next.addResourceBundle.call(\n      this.i18next,\n      lng,\n      ns,\n      resources,\n      deep,\n      overwrite\n    );\n  }\n\n  public hasResourceBundle(lng: string, ns: string) {\n    return this.i18next.hasResourceBundle.call(this.i18next, lng, ns);\n  }\n\n  public getResourceBundle(lng: string, ns: string) {\n    return this.i18next.getResourceBundle.call(this.i18next, lng, ns);\n  }\n\n  public removeResourceBundle(lng: string, ns: string): i18n.i18n {\n    return this.i18next.removeResourceBundle.call(this.i18next, lng, ns);\n  }\n\n  //#endregion\n\n  private subscribeEvents() {\n    this.i18next.on.call(this.i18next, 'initialized', (options: InitOptions) => {\n      this.events.initialized.next(options);\n    });\n    this.i18next.on.call(this.i18next, 'loaded', (loaded: boolean) =>\n      this.events.loaded.next(loaded)\n    );\n    this.i18next.on.call(this.i18next, 'failedLoading', (lng: string, ns: string, msg: string) =>\n      this.events.failedLoading.next({ lng, ns, msg })\n    );\n    this.i18next.on.call(this.i18next, 'languageChanged', (lng: string) => {\n      this.events.languageChanged.next(lng);\n    });\n    this.i18next.on.call(this.i18next, 'missingKey', (lngs: string, namespace: string, key: string, res: any) =>\n      this.events.missingKey.next({ lngs, namespace, key, res })\n    );\n    this.i18next.on.call(this.i18next, 'added', (lng: string, ns: string) =>\n      this.events.added.next({ lng, ns })\n    );\n    this.i18next.on.call(this.i18next, 'removed', (lng: string, ns: string) =>\n      this.events.removed.next({ lng, ns })\n    );\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/services/translation.events.ts",
    "content": "import { BehaviorSubject, Subject } from 'rxjs';\nimport * as i18n from 'i18next';\n\nexport type ResourceEvent = { lng: any; ns: any };\nexport type MissingKeyEvent = { lngs: any; namespace: any; key: any; res: any };\n\nexport interface ITranslationEvents {\n  initialized: BehaviorSubject<i18n.InitOptions | undefined>;\n  loaded: BehaviorSubject<boolean>;\n  failedLoading: Subject<any>;\n  missingKey: Subject<MissingKeyEvent>;\n  added: Subject<ResourceEvent>;\n  removed: Subject<ResourceEvent>;\n  languageChanged: BehaviorSubject<string | null>;\n}\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/services/translation.service.ts",
    "content": "import * as i18n from 'i18next';\nimport { I18NextLoadResult } from '../I18NextLoadResult';\nimport { ITranslationEvents } from './translation.events';\nimport type { Callback, ExistsFunction, FormatFunction, InitOptions, Module, Modules, Namespace, Newable, NewableModule, ResourceStore, Services, TFunction, TOptions } from 'i18next';\n\ntype Modify<T, R> = Omit<T, keyof R> & R;\n\nexport type ITranslationOptions = TOptions;\n\nexport type ITranslationService = Modify<Partial<i18n.i18n>, {\n\n  events: ITranslationEvents;\n\n  language: string;\n  languages: readonly string[];\n  options: InitOptions;\n  modules: Modules;\n  services: Services;\n  store: ResourceStore;\n  resolvedLanguage: string | undefined;\n\n  use<T extends Module>(\n    module:\n    T | NewableModule<T> | Newable<T>\n  ): ITranslationService;\n\n  init(options: InitOptions): Promise<I18NextLoadResult>;\n\n  t<Options extends ITranslationOptions>(\n    key: string | string[],\n    options?: Options,\n  ): i18n.TFunctionReturn<Namespace, string | string[], Options>;\n  t<Options extends ITranslationOptions>(\n    key: string | string[],\n    defaultValue: string,\n    options?: Options\n  ): i18n.TFunctionReturn<Namespace, string | string[], Options>;\n\n  format: FormatFunction;\n\n  exists: ExistsFunction;\n\n  getFixedT(\n    lng: string | readonly string[],\n    ns?: string | readonly string[],\n    keyPrefix?: string,\n  ): TFunction;\n  getFixedT(lng: null, ns: string | readonly string[] | null, keyPrefix?: string): TFunction;\n\n  setDefaultNamespace(ns: string): void;\n\n  dir(lng: string): string;\n\n  changeLanguage(lng: string): Promise<any>;\n\n  loadNamespaces(namespaces: string[]): Promise<any>;\n  loadLanguages(lngs: string | readonly string[], callback?: Callback): Promise<void>;\n\n  loadResources(callback?: (err: any) => void): void;\n\n  getDataByLanguage(lng: string): {\n    [key: string]: {\n        [key: string]: string;\n    };\n} | undefined;\n\n  reloadResources(\n    lngs?: string | readonly string[],\n    ns?: string | readonly string[],\n    callback?: () => void,\n  ): Promise<void>;\n  reloadResources(lngs: null, ns: string | readonly string[], callback?: () => void): Promise<void>;\n\n  getResource(\n    lng: string,\n    ns: string,\n    key: string,\n    options?: Pick<i18n.InitOptions, 'keySeparator' | 'ignoreJSONStructure'>,\n  ): any;\n  addResource(\n    lng: string,\n    ns: string,\n    key: string,\n    value: string,\n    options?: { keySeparator?: string; silent?: boolean },\n  ): i18n.i18n;\n  addResources(lng: string, ns: string, resources: any): i18n.i18n;\n  addResourceBundle(\n    lng: string,\n    ns: string,\n    resources: any,\n    deep?: boolean,\n    overwrite?: boolean,\n  ): i18n.i18n;\n  hasResourceBundle(lng: string, ns: string): boolean;\n  getResourceBundle(lng: string, ns: string): any;\n  removeResourceBundle(lng: string, ns: string): i18n.i18n;\n\n}>;\n"
  },
  {
    "path": "libs/angular-i18next/src/lib/tokens.ts",
    "content": "import * as i18n from 'i18next'\nimport { InjectionToken } from '@angular/core';\nimport { I18NextErrorHandlingStrategy } from './I18NextErrorHandlingStrategies';\nimport { ITranslationService } from './services/translation.service';\nimport { NamespaceResolver } from './models';\n\nexport const I18NEXT_SCOPE = new InjectionToken<string | string[]>(\n  'I18NEXT_SCOPE'\n);\nexport const I18NEXT_NAMESPACE = new InjectionToken<string | string[]>(\n  'I18NEXT_NAMESPACE'\n);\nexport const I18NEXT_SERVICE = new InjectionToken<ITranslationService>(\n  'I18NEXT_SERVICE'\n);\nexport const I18NEXT_NAMESPACE_RESOLVER = new InjectionToken<NamespaceResolver>(\n  'I18NEXT_NAMESPACE_RESOLVER'\n);\nexport const I18NEXT_ERROR_HANDLING_STRATEGY =\n  new InjectionToken<I18NextErrorHandlingStrategy>(\n    'I18NEXT_ERROR_HANDLING_STRATEGY'\n  );\n\nexport const I18NEXT_INSTANCE = new InjectionToken<i18n.i18n>('I18NEXT_INSTANCE');\n"
  },
  {
    "path": "libs/angular-i18next/src/test-setup.ts",
    "content": "import { setupZonelessTestEnv } from 'jest-preset-angular/setup-env/zoneless';\nimport { TestBed } from \"@angular/core/testing\";\nimport { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';\n\n\nsetupZonelessTestEnv();\nTestBed.initTestEnvironment(BrowserTestingModule, platformBrowserTesting());\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/module/module.spec.ts",
    "content": "import { TestBed } from '@angular/core/testing';\nimport {\n  defaultInterpolationFormat,\n  I18NEXT_NAMESPACE,\n  I18NEXT_NAMESPACE_RESOLVER,\n  I18NEXT_SCOPE,\n  I18NEXT_SERVICE,\n  I18NextCapPipe,\n  I18NextFormatPipe,\n  I18NextModule,\n  I18NextPipe,\n  I18NextService,\n  I18NextTitle,\n} from '../../lib/index';\n\ndescribe('I18NextModule', () => {\n  const DEFAULT_NAMESPACE = '';\n  const DEFAULT_SCOPE = '';\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      imports: [I18NextModule.forRoot()],\n    });\n  });\n\n  it('should provide tokens with default values', () =>  {\n    let tokenNs = TestBed.inject(I18NEXT_NAMESPACE);\n    expect(tokenNs).toEqual(DEFAULT_NAMESPACE);\n    let tokenScope = TestBed.inject(I18NEXT_SCOPE);\n    expect(tokenScope).toEqual(DEFAULT_SCOPE);\n  });\n\n  it('should provide I18NextService', () => {\n    let i18nextService = TestBed.inject(I18NEXT_SERVICE);\n    expect(i18nextService).not.toBeNull();\n    let i18nextService2 = TestBed.inject(I18NextService);\n    expect(i18nextService2).not.toBeNull();\n  });\n\n  it('should provide pipes',  () =>  {\n    let i18nextPipe = TestBed.inject(I18NextPipe);\n    expect(i18nextPipe).not.toBeNull();\n    let i18nextCapPipe = TestBed.inject(I18NextCapPipe);\n    expect(i18nextCapPipe).not.toBeNull();\n    let i18nextFormatPipe = TestBed.inject(I18NextFormatPipe);\n    expect(i18nextFormatPipe).not.toBeNull();\n  });\n\n  it('should provide title',  () => {\n    let title: I18NextTitle = TestBed.inject(I18NextTitle);\n    expect(title).toBeTruthy();\n    expect(title instanceof I18NextTitle).toBeTruthy();\n  });\n\n  it('should have default formatters',  () =>  {\n    const capitalizedTest = defaultInterpolationFormat('test', 'cap');\n    const capitalized2Test = defaultInterpolationFormat('test', 'capitalize');\n    expect(capitalizedTest).toEqual('Test');\n    expect(capitalizedTest).toEqual(capitalized2Test);\n\n    const uppercaseTest = defaultInterpolationFormat('test', 'upper');\n    const uppercase2Test = defaultInterpolationFormat('test', 'uppercase');\n    expect(uppercaseTest).toEqual('TEST');\n    expect(uppercaseTest).toEqual(uppercase2Test);\n\n    let lowercaseTest = defaultInterpolationFormat('TEST', 'lower');\n    let lowercase2Test = defaultInterpolationFormat('TEST', 'lowercase');\n    expect(lowercaseTest).toEqual('test');\n    expect(lowercaseTest).toEqual(lowercase2Test);\n\n    let noFormat = defaultInterpolationFormat('test', undefined);\n    let noFormat2 = defaultInterpolationFormat('test', 'none');\n    expect(noFormat).toEqual('test');\n    expect(noFormat).toEqual(noFormat2);\n  });\n\n  it('should support interpolation custom formatters', () =>  {\n    const valueParam = 'test';\n    const formatParam = 'cap';\n    const lngParam = 'en';\n    let customFormat = function (value: any, format: any, lng: any) {\n      expect(value).toEqual('Test');\n      expect(format).toEqual(formatParam);\n      expect(lng).toEqual(lngParam);\n\n      return `$${value}$`;\n    };\n    let formatFunc = I18NextModule.interpolationFormat(customFormat);\n    let result = formatFunc(valueParam, formatParam, lngParam);\n    expect(result).toBe('$Test$');\n  });\n\n  it('should provide resolver', (done) => {\n    let resolver =  TestBed.inject(I18NEXT_NAMESPACE_RESOLVER);\n    expect(resolver).toBeTruthy();\n\n    TestBed.runInInjectionContext(() => {\n      resolver({\n        data: {\n          i18nextNamespaces: [],\n        },\n      }).then(() => {\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/pipes/I18NextEagerPipe.spec.ts",
    "content": "import { ApplicationInitStatus, ChangeDetectorRef } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport { I18NextEagerPipe, I18NextModule, I18NEXT_NAMESPACE, I18NEXT_SCOPE, I18NEXT_SERVICE, ITranslationService, PipeOptions } from '../../lib';\nimport { MOCK_I18N_PROVIDERS } from '../setup';\n\n\ndescribe('I18NextEagerPipe', () => {\n  let pipe: I18NextEagerPipe,\n    service: ITranslationService,\n    markForCheckSpy: jest.SpyInstance<any, unknown[]>;\n\n  beforeEach(async () => {\n      TestBed.configureTestingModule({\n        providers: [...MOCK_I18N_PROVIDERS,\n          { provide: ChangeDetectorRef, useValue: { detectChanges: () => { }, markForCheck: () => { } } }, {\n            provide: I18NEXT_SCOPE,\n            useValue: 'scope'\n          },\n          {\n            provide: I18NEXT_NAMESPACE,\n            useValue: 'ns'\n          }],\n      });\n\n      // until https://github.com/angular/angular/issues/24218 is fixed\n      await TestBed.inject(ApplicationInitStatus).donePromise;\n\n      service = TestBed.inject(I18NEXT_SERVICE);\n      pipe = TestBed.inject(I18NextEagerPipe);\n      const changeDetector = TestBed.inject(ChangeDetectorRef);\n\n      // So, I am spying directly on the prototype.\n      markForCheckSpy = jest.spyOn(changeDetector, 'markForCheck');\n  });\n\n  it('should create the pipe', () => {\n    expect(pipe).toBeTruthy();\n  });\n\n  describe('when called with key and options', () => {\n    let result: string;\n    let myOptions: PipeOptions;\n\n    beforeEach(() => {\n      myOptions = { defaultValue: 'value1' };\n\n      result = pipe.transform('myKey', myOptions);\n    });\n\n    it('should call the translate service', () => {\n      expect(service.t).toHaveBeenCalledWith(\n        ['ns:scope.myKey', 'scope.myKey', 'ns:myKey', 'myKey'],\n        myOptions\n      );\n    });\n\n    it('should return the correct result', () => {\n      expect(result).toBe('ns:scope.myKey');\n    });\n\n    describe('when the language changes', () => {\n      beforeEach(() => {\n        service.events.languageChanged.next('es');\n        service.language = 'es';\n      });\n\n      it('should mark for check so it triggers the pipe transform', () => {\n        expect(markForCheckSpy).toHaveBeenCalled();\n      });\n\n      describe('when the pipe gets triggered by change detection', () => {\n        beforeEach(() => {\n          jest.clearAllMocks();\n          result = pipe.transform('myKey', myOptions);\n        });\n\n        it('should call the translate service', () => {\n          expect(service.t).toHaveBeenCalledWith(\n            ['ns:scope.myKey', 'scope.myKey', 'ns:myKey', 'myKey'],\n            { defaultValue: 'value1' }\n          );\n        });\n\n        it('should return the new result', () => {\n          expect(result).toBe('ns:scope.myKey');\n        });\n      });\n    });\n\n    describe('when called with same key and options', () => {\n      beforeEach(() => {\n        jest.clearAllMocks();\n        result = pipe.transform('myKey', myOptions);\n      });\n\n      it('should not call the translate service', () => {\n        expect(service.t).not.toHaveBeenCalled();\n      });\n\n      it('should return the previously cached result', () => {\n        expect(result).toBe('ns:scope.myKey');\n      });\n    });\n\n    describe('when called with same key but different options', () => {\n      beforeEach(() => {\n        jest.clearAllMocks();\n        result = pipe.transform('myKey', { defaultValue: 'value2' });\n      });\n\n      it('should call the translate service', () => {\n        expect(service.t).toHaveBeenCalledWith(\n          ['ns:scope.myKey', 'scope.myKey', 'ns:myKey', 'myKey'],\n          { defaultValue: 'value2' }\n        );\n      });\n\n      it('should return the new result', () => {\n        expect(result).toBe('ns:scope.myKey');\n      });\n    });\n\n    describe('when called with different key but same options', () => {\n      beforeEach(() => {\n        jest.clearAllMocks();\n        result = pipe.transform('myKey2', myOptions);\n      });\n\n      it('should call the translate service', () => {\n        expect(service.t).toHaveBeenCalledWith(\n          ['ns:scope.myKey2', 'scope.myKey2', 'ns:myKey2', 'myKey2'],\n          { defaultValue: 'value1' }\n        );\n      });\n\n      it('should return the new result', () => {\n        expect(result).toBe('ns:scope.myKey2');\n      });\n    });\n  });\n\n  describe('when called with only with key', () => {\n    let result: string;\n\n    beforeEach(() => {\n      result = pipe.transform('myKey');\n    });\n\n    it('should call the translate service', () => {\n      expect(service.t).toHaveBeenCalledWith(\n        ['ns:scope.myKey', 'scope.myKey', 'ns:myKey', 'myKey'],\n        {}\n      );\n    });\n\n    it('should return the correct result', () => {\n      expect(result).toBe('ns:scope.myKey');\n    });\n\n    describe('when called with same key', () => {\n      beforeEach(() => {\n        jest.clearAllMocks();\n        result = pipe.transform('myKey');\n      });\n\n      it('should not call the translate service', () => {\n        expect(service.t).not.toHaveBeenCalled();\n      });\n\n      it('should return the previously cached result', () => {\n        expect(result).toBe('ns:scope.myKey');\n      });\n    });\n\n    describe('when called with different key', () => {\n      beforeEach(() => {\n        jest.clearAllMocks();\n        result = pipe.transform('myKey2');\n      });\n\n      it('should call the translate service', () => {\n        expect(service.t).toHaveBeenCalledWith(\n          ['ns:scope.myKey2', 'scope.myKey2', 'ns:myKey2', 'myKey2'],\n          {}\n        );\n      });\n\n      it('should return the new result', () => {\n        expect(result).toBe('ns:scope.myKey2');\n      });\n    });\n  });\n});\n\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/pipes/I18NextPipe.spec.ts",
    "content": "import { ApplicationInitStatus } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport { I18NextCapPipe, I18NextModule, I18NextPipe, I18NEXT_NAMESPACE, I18NEXT_SCOPE, I18NEXT_SERVICE, ITranslationService } from '../../lib';\nimport { MOCK_I18N_PROVIDERS } from '../setup';\n\n\ndescribe('I18NextPipe tests', function () {\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      imports: [I18NextPipe],\n      providers: [...MOCK_I18N_PROVIDERS],\n    });\n\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('transform', async () => {\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const key = 'test';\n    const transResult = pipe.transform(key);\n    expect(transResult).toEqual(key);\n  });\n\n  it('format options', async () => {\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const capPipe = TestBed.inject(I18NextCapPipe);\n    const key = 'test';\n    const pipeResult = pipe.transform(key, { format: 'cap' });\n    const capPipeResult = capPipe.transform(key);\n    expect(pipeResult).toEqual(capPipeResult);\n    const keyCap = key.charAt(0).toUpperCase() + key.slice(1);\n    expect(pipeResult).toEqual(keyCap);\n  });\n\n\n  it('namespace prefix', async () => {\n    const namespace = 'error';\n    TestBed.overrideProvider(I18NEXT_NAMESPACE, {\n      useValue: namespace\n    });\n\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    await TestBed.compileComponents();\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const service = TestBed.inject(I18NEXT_SERVICE)\n    const key = 'test';\n\n    const transResult = pipe.transform(key);\n    expect(transResult).toEqual(buildKeyWithNs(service, namespace, key));\n    // for array key\n    const arrayKey = ['test_1', 'test_2'];\n    const arrResult = pipe.transform(arrayKey);\n    expect(arrResult).toEqual(buildKeyWithNs(service, namespace, arrayKey[0]));\n  });\n\n\n\n  it('ignore namespace param if key already contains it', async () => {\n    const namespace = 'error';\n    TestBed.overrideProvider(I18NEXT_NAMESPACE, {\n      useValue: namespace\n    });\n\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const realns = 'realns';\n    const service = TestBed.inject(I18NEXT_SERVICE);\n    const key = [realns, 'test'].join(service.options.keySeparator || '.');\n    const transResult = pipe.transform(key);\n    expect(transResult).toEqual(buildKeyWithNs(service, namespace, key));\n  });\n\n\n\n  it('scope prefix', async () => {\n    const scope = 'scope';\n    TestBed.overrideProvider(I18NEXT_SCOPE, {\n      useValue: scope\n    });\n\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const service = TestBed.inject(I18NEXT_SERVICE);\n    const key = 'test';\n    // for primitive key\n    const transResult = pipe.transform(key);\n    expect(transResult).toEqual([scope, key].join(service.options.keySeparator || '.'));\n    // for array key\n    const arrayKey = ['test_1', 'test_2'];\n    const arrResult = pipe.transform(arrayKey);\n    expect(arrResult).toEqual([scope, arrayKey[0]].join(service.options.keySeparator || '.'));\n  });\n\n  it('ns and scope prefix', async () => {\n    const scope = 'scope';\n    const ns = 'ns';\n    TestBed.overrideProvider(I18NEXT_SCOPE, {\n      useValue: scope\n    });\n    TestBed.overrideProvider(I18NEXT_NAMESPACE, {\n      useValue: ns\n    });\n\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const service = TestBed.inject(I18NEXT_SERVICE);\n    const key = 'test';\n    const transResult = pipe.transform(key);\n    expect(transResult).toEqual(buildKeyWithNs(service, ns, [scope, key].join(service.options.keySeparator || '.')));\n  });\n\n  it('ns and scope prefix (arrays)', async () => {\n    const scope = ['scope1', 'scope2'];\n    const ns = ['ns1', 'ns2'];\n    TestBed.overrideProvider(I18NEXT_SCOPE, {\n      useValue: scope\n    });\n    TestBed.overrideProvider(I18NEXT_NAMESPACE, {\n      useValue: ns\n    });\n\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const service = TestBed.inject(I18NEXT_SERVICE);\n    const key = 'test';\n    const transResult = pipe.transform(key);\n    expect(transResult).toEqual(buildKeyWithNs(service, ns[0], [scope[0], key].join(service.options.keySeparator || '.')));\n  });\n\n  it('ns and scope no prefix (prependScope = false and prependNamespace = false)', async () => {\n    const scope = 'scope';\n    const ns = 'ns';\n    TestBed.overrideProvider(I18NEXT_SCOPE, {\n      useValue: scope\n    });\n    TestBed.overrideProvider(I18NEXT_NAMESPACE, {\n      useValue: ns\n    });\n\n    // until https://github.com/angular/angular/issues/24218 is fixed\n    await TestBed.inject(ApplicationInitStatus).donePromise;\n\n    const pipe = TestBed.inject(I18NextPipe);\n    const service = TestBed.inject(I18NEXT_SERVICE);\n    const key = 'test';\n    const transResult = pipe.transform(key, {\n      prependScope: false,\n      prependNamespace: false,\n    });\n    expect(transResult).toEqual(key);\n  });\n\n});\n\nfunction buildKeyWithNs(service: ITranslationService, ns: string, key: string): string {\n  return `${ns}${service.options.nsSeparator}${key}`;\n}\n\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/projectTests/project.component.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { I18NextPipe } from '../../lib';\n\n@Component({\n  selector: 'project-component',\n  encapsulation: ViewEncapsulation.None,\n  template: '<div>{{ \"privet\" | i18next }}</div>',\n  standalone: true,\n  imports: [I18NextPipe]\n})\nexport class ProjectComponent {}\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/projectTests/projectTests.spec.ts",
    "content": "import { TestBed } from \"@angular/core/testing\";\nimport { MOCK_I18N_PROVIDERS } from \"../setup\";\nimport { ProjectComponent } from './project.component';\n\ndescribe('Project component tests', function () {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      imports: [ProjectComponent],\n      providers: [MOCK_I18N_PROVIDERS],\n    });\n  });\n\n  it('should test project component', function () {\n    let pc = TestBed.createComponent(ProjectComponent);\n    expect(pc).toBeDefined();\n    pc.detectChanges();\n  });\n});\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/provider/provider.spec.ts",
    "content": "import { ChangeDetectorRef, inject, provideAppInitializer } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport { Title } from '@angular/platform-browser';\nimport { MockI18NextService, withMock } from '../../../testing/src/public_api';\nimport {\n  I18NEXT_ERROR_HANDLING_STRATEGY,\n  I18NEXT_INSTANCE,\n  I18NEXT_NAMESPACE,\n  I18NEXT_SCOPE,\n  I18NEXT_SERVICE,\n  I18NextCapPipe,\n  I18NextEagerPipe,\n  I18NextFormatPipe,\n  I18NextLoadResult,\n  I18NextPipe,\n  I18NextService,\n  I18NextTitle,\n  interpolationFormat,\n  NativeErrorHandlingStrategy,\n  provideI18Next,\n  withCustomErrorHandlingStrategy,\n  withTitle\n} from '../../lib/index';\n\ndescribe('I18Next Provider', () => {\n  describe('provideI18Next', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [\n          ChangeDetectorRef,\n          provideAppInitializer(() => {\n            const i18next = inject(I18NEXT_SERVICE);\n            let promise: Promise<I18NextLoadResult> = i18next.init({\n              lng: 'en',\n              interpolation: {\n                format: interpolationFormat(),\n              },\n            });\n            return promise;\n          }),\n          provideI18Next(),\n        ],\n      });\n    });\n\n    it('should provide default tokens', () => {\n      const namespace = TestBed.inject(I18NEXT_NAMESPACE);\n      const scope = TestBed.inject(I18NEXT_SCOPE);\n\n      expect(namespace).toBe('');\n      expect(scope).toBe('');\n    });\n\n    it('should provide i18next instance', () => {\n      const instance = TestBed.inject(I18NEXT_INSTANCE);\n      expect(instance).toBeTruthy();\n    });\n\n    it('should provide I18NextService with NativeErrorHandlingStrategy', () => {\n      const service = TestBed.inject(I18NEXT_SERVICE);\n      const strategy = TestBed.inject(I18NEXT_ERROR_HANDLING_STRATEGY);\n\n      expect(service).toBeInstanceOf(I18NextService);\n      expect(strategy).toBeInstanceOf(NativeErrorHandlingStrategy);\n    });\n\n    it('should provide all required pipes', () => {\n      const i18nextPipe = TestBed.inject(I18NextPipe);\n      const eagerPipe = TestBed.inject(I18NextEagerPipe);\n      const capPipe = TestBed.inject(I18NextCapPipe);\n      const formatPipe = TestBed.inject(I18NextFormatPipe);\n\n      expect(i18nextPipe).toBeInstanceOf(I18NextPipe);\n      expect(eagerPipe).toBeInstanceOf(I18NextEagerPipe);\n      expect(capPipe).toBeInstanceOf(I18NextCapPipe);\n      expect(formatPipe).toBeInstanceOf(I18NextFormatPipe);\n    });\n  });\n\n  describe('withMock feature', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideI18Next(withMock())],\n      });\n    });\n\n    it('should provide MockI18NextService', () => {\n      const service = TestBed.inject(I18NEXT_SERVICE);\n      expect(service).toBeInstanceOf(MockI18NextService);\n    });\n  });\n\n  describe('withTitle feature', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideI18Next(withTitle())],\n      });\n    });\n\n    it('should provide I18NextTitle service', () => {\n      const title = TestBed.inject(Title);\n      expect(title).toBeInstanceOf(I18NextTitle);\n    });\n  });\n\n  describe('withCustomErrorHandlingStrategy feature', () => {\n      class CustomErrorStrategy extends NativeErrorHandlingStrategy {}\n\n      beforeEach(() => {\n        TestBed.configureTestingModule({\n          providers: [\n            provideI18Next(withCustomErrorHandlingStrategy(CustomErrorStrategy)),\n          ],\n        });\n      });\n\n      it('should use the custom error handling strategy', () => {\n        const strategy = TestBed.inject(I18NEXT_ERROR_HANDLING_STRATEGY);\n        expect(strategy).toBeInstanceOf(CustomErrorStrategy);\n      });\n    });\n});\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/service/I18NextService.spec.ts",
    "content": "import { TestBed } from '@angular/core/testing';\nimport {\n  I18NextModule, I18NEXT_SERVICE,\n  ITranslationService\n} from '../../lib';\n\nconst i18nextOptions: i18n.InitOptions = {\n  lng: 'cimode',\n  supportedLngs: ['cimode', 'en', 'ru'],\n  appendNamespaceToCIMode: true\n};\nimport * as i18n from 'i18next';\n\n\n// Be descriptive with titles here. The describe and it titles combined read like a sentence.\ndescribe('I18nService', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      imports: [I18NextModule.forRoot()]\n    });\n  });\n\n  it('should trigger initialize event', (done) => {\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    service.events.initialized.subscribe((isInited) => {\n      if (isInited) done();\n    });\n    service.init(i18nextOptions);\n  });\n\n\n  it('should init', (done) => {\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    service.init(i18nextOptions).then(() => {\n      expect(service.options).toBeTruthy();\n      done();\n    });\n  });\n\n\n  it('should load namespace', (done) => {\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    service.init(i18nextOptions).then(()=> {\n      service.loadNamespaces(['somens']).then(() => {\n        done();\n      });\n    });\n  });\n\n\n  it('should translate', (done) => {\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    const key = 'test';\n    service.init(i18nextOptions).then(()=> {\n        const serviceResult = service.t(key);\n        expect(serviceResult).toEqual(`${service.options.defaultNS}${service.options.nsSeparator}test`);\n        const serviceResult2 = service.t([key, key + '2']);\n        expect(serviceResult2).toEqual(`${service.options.defaultNS}${service.options.nsSeparator}test2`);\n        done();\n    })\n  });\n\n\n  it('should dir', () => {\n    const lng = 'ru';\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    expect(<any>service.dir(lng)).toEqual('ltr');\n    expect(<any>service.dir(lng)).toEqual(service.dir(lng));\n  });\n\n\n  it('should able to pass custom params (no typechecking errors)', () => {\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    service.t('some.string', {\n      hello: 'there',\n    });\n  });\n\n  it('should be able to return different types while setting returnObjects: true (no typechecking errors)', () => {\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    service.t('some.string') as string;\n    service.t('some.string', {\n      returnObjects: true\n    }) as string[];\n  });\n\n  /*\n  // does not work because language=cimode ignores default value\n  // setting language to anything other than 'cimode' breaks the rest of the tests\n\n  xit('should translate with default value', (done) => {\n    const service: ITranslationService = TestBed.inject(I18NEXT_SERVICE);\n    let title: Title = TestBed.inject(Title);\n    let i18nextPipe: I18NextPipe = TestBed.inject(I18NextPipe);\n    const key = 'test2';\n    const defaultValue = 'test3';\n    service.events.initialized.subscribe((value) => {\n      if (value) {\n        // service\n        const serviceResult = service.t(key, defaultValue);\n        expect(serviceResult).toEqual(defaultValue);\n        // pipes\n        const pipeResult = i18nextPipe.transform(key, { defaultValue });\n        expect(pipeResult).toEqual(defaultValue);\n        done();\n      }\n    });\n  });\n  */\n});\n\n"
  },
  {
    "path": "libs/angular-i18next/src/tests/setup.ts",
    "content": "import { provideI18NextMockAppInitializer, withMock } from '../../testing/src/public_api';\nimport {\n  provideI18Next,\n\n} from '../lib';\n\nexport const MOCK_I18N_PROVIDERS = [\n  provideI18NextMockAppInitializer(),\n  provideI18Next(withMock()),\n];\n"
  },
  {
    "path": "libs/angular-i18next/ssr/ng-package.json",
    "content": "{}\n"
  },
  {
    "path": "libs/angular-i18next/ssr/src/provider.ssr.ts",
    "content": "import { REQUEST_CONTEXT } from '@angular/core';\nimport { I18NEXT_INSTANCE, I18NextFeature, I18NextFeatureKind, makeI18NextFeature } from 'angular-i18next';\n\n\n/**\n * Feature for use when configuring `provideI18Next` to enable SSR.\n *\n * @description\n * This feature expects the Express request object to be injected as\n * `REQUEST` and will extract the `i18n` object from it.\n *\n * @publicApi\n */\nexport function withSSR(): I18NextFeature<I18NextFeatureKind.SSR> {\n  return makeI18NextFeature(I18NextFeatureKind.SSR, [\n    {\n      provide: I18NEXT_INSTANCE,\n      useFactory: (reqCtx: any) => {\n        return reqCtx?.i18n;\n      },\n      deps: [REQUEST_CONTEXT],\n    },\n  ]);\n}\n"
  },
  {
    "path": "libs/angular-i18next/ssr/src/public_api.ts",
    "content": "export * from './provider.ssr';\n"
  },
  {
    "path": "libs/angular-i18next/testing/ng-package.json",
    "content": "{}\n"
  },
  {
    "path": "libs/angular-i18next/testing/src/mock.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { jest } from '@jest/globals';\nimport { defaultInterpolationFormat, I18NextEvents, I18NextLoadResult, ITranslationEvents, ITranslationService } from 'angular-i18next';\nimport type { Callback, FormatFunction, i18n, InterpolationOptions, TFunction, Modules, Services, ResourceStore } from 'i18next';\nimport * as i18next from 'i18next';\n\n\n@Injectable()\nexport class MockI18NextService implements ITranslationService {\n\n  private i18next: i18n;\n\n  get isInitialized() {\n    return this.i18next.isInitialized;\n  }\n\n  get modules(): Modules {\n    return this.i18next.modules;\n  }\n  get services(): Services {\n    return this.i18next.services;\n  }\n  get store(): ResourceStore {\n    return this.i18next.store;\n  }\n\n  get resolvedLanguage() {\n    return this.i18next.resolvedLanguage;\n  }\n\n  constructor(\n  ) {\n    this.i18next = i18next.default;\n  }\n\n  t = jest.fn((key: string | string[],\n    optionsOrDefault?: string | i18next.TOptions,\n    options?: i18next.TOptions): i18next.TFunctionReturn<i18next.Namespace, string | string[], (i18next.TOptions & { defaultValue: string; })> => {\n    if (key instanceof Array) {\n      return key.length > 0 ? key[0] : '';\n    }\n    return key;\n})\n\n  format: FormatFunction = jest.fn((\n    value: any,\n    format?: string,\n    lng?: string,\n    options?: InterpolationOptions & { [key: string]: any },\n  ) => defaultInterpolationFormat(value, format, lng));\n\n  getFixedT(lng: string | readonly string[], ns?: string | readonly string[], keyPrefix?: string): TFunction;\n  getFixedT(lng: null, ns: string | readonly string[] | null, keyPrefix?: string): TFunction;\n  getFixedT(lng: any, ns?: any, keyPrefix?: any): import(\"i18next\").TFunction {\n    throw new Error('Method not implemented.');\n  }\n  loadLanguages(lngs: string | readonly string[], callback?: Callback): Promise<void> {\n    throw new Error('Method not implemented.');\n  }\n  loadResources(callback?: (err: any) => void): void {\n    throw new Error('Method not implemented.');\n  }\n  getDataByLanguage(lng: string): { translation: { [key: string]: string; }; } | undefined {\n    throw new Error('Method not implemented.');\n  }\n  reloadResources(lngs?: string | readonly string[], ns?: string | readonly string[], callback?: () => void): Promise<void>;\n  reloadResources(lngs: null, ns: string | readonly string[], callback?: () => void): Promise<void>;\n  reloadResources(lngs?: any, ns?: any, callback?: any): Promise<void> {\n    throw new Error('Method not implemented.');\n  }\n  addResource(lng: string, ns: string, key: string, value: string, options?: { keySeparator?: string | undefined; silent?: boolean | undefined; }): i18n {\n    throw new Error('Method not implemented.');\n  }\n  addResources(lng: string, ns: string, resources: any): i18n {\n    throw new Error('Method not implemented.');\n  }\n  addResourceBundle(lng: string, ns: string, resources: any, deep?: boolean, overwrite?: boolean): i18n {\n    throw new Error('Method not implemented.');\n  }\n  removeResourceBundle(lng: string, ns: string): i18n {\n    throw new Error('Method not implemented.');\n  }\n  events: ITranslationEvents = new I18NextEvents();\n  language: string = '';\n  languages: string[] = [];\n\n  get options(): any {\n    return {\n      keySeparator: '.',\n      nsSeparator: ':',\n    };\n  }\n\n  public use(plugin: any): ITranslationService {\n    return this;\n  }\n\n  public init(options?: any): Promise<I18NextLoadResult> {\n    options = options || {};\n    return new Promise<any>(\n      (\n        resolve: (thenableOrResult?: any) => void,\n        reject: (error: any) => void\n      ) => {\n        resolve(null);\n      }\n    );\n  }\n\n\n  public changeLanguage(lng: string): Promise<any> {\n    return new Promise<any>(\n      (\n        resolve: (thenableOrResult?: any) => void,\n        reject: (error: any) => void\n      ) => {\n        this.language = lng;\n        resolve(this.language);\n      }\n    );\n  }\n\n  public loadNamespaces(namespaces: string[]): Promise<any> {\n    return new Promise<any>(\n      (\n        resolve: (thenableOrResult?: any) => void,\n        reject: (error: any) => void\n      ) => {\n        resolve();\n      }\n    );\n  }\n\n  exists(key: any, options: any) {\n    return true;\n  }\n\n  setDefaultNamespace(ns: string) {}\n\n  dir(lng: string) {\n    return 'ltr';\n  }\n\n  getResource(lng: any, ns: any, key: any, options: any) {\n    return null;\n  }\n\n  hasResourceBundle(lng: any, ns: any) {\n    return true;\n  }\n\n  getResourceBundle(lng: any, ns: any) {\n    return null;\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/testing/src/provider.ts",
    "content": "import { inject, provideAppInitializer } from '@angular/core';\nimport { I18NEXT_SERVICE, I18NextFeature, I18NextFeatureKind, I18NextLoadResult, interpolationFormat, makeI18NextFeature } from 'angular-i18next';\nimport { MockI18NextService } from './mock.service';\n\n/**\n * Initializes i18next with mock settings for testing\n */\nexport function mockAppInit() {\n  const i18next = inject(I18NEXT_SERVICE);\n  let promise: Promise<I18NextLoadResult> = i18next.init({\n    lng: 'cimode',\n    interpolation: {\n      format: interpolationFormat(),\n    },\n  });\n  return promise;\n}\n\nexport const provideI18NextMockAppInitializer = () =>\n  provideAppInitializer(mockAppInit);\n\n/**\n * Provides a mock implementation of I18NEXT_SERVICE for testing purposes.\n * Also initializes i18next with mock settings.\n *\n * @returns An I18NextFeature that configures the service to use MockI18NextService\n *\n * Example:\n * ```typescript\n * providers: [\n *   provideI18Next(withMock())\n * ]\n * ```\n */\nexport function withMock(): I18NextFeature<I18NextFeatureKind.Mock> {\n  return makeI18NextFeature(I18NextFeatureKind.Mock, [\n    {\n      provide: I18NEXT_SERVICE,\n      useClass: MockI18NextService,\n    },\n  ]);\n}\n"
  },
  {
    "path": "libs/angular-i18next/testing/src/public_api.ts",
    "content": "export * from './mock.service';\nexport * from './provider';\n"
  },
  {
    "path": "libs/angular-i18next/tsconfig.json",
    "content": "\n{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"es2022\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"noImplicitOverride\": true,\n    \"noPropertyAccessFromIndexSignature\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsconfig.lib.json\"\n    },\n    {\n      \"path\": \"./tsconfig.spec.json\"\n    }\n  ],\n  \"angularCompilerOptions\": {\n    \"enableI18nLegacyMessageIdFormat\": false,\n    \"strictInjectionParameters\": true,\n    \"strictInputAccessModifiers\": true,\n    \"strictTemplates\": true,\n    \"compilationMode\": \"partial\"\n  }\n}\n"
  },
  {
    "path": "libs/angular-i18next/tsconfig.lib.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../dist/out-tsc\",\n    \"declaration\": true,\n    \"declarationMap\": false,\n    \"types\": []\n  },\n  \"exclude\": [\n    \"src/**/*.spec.ts\",\n    \"src/test-setup.ts\",\n    \"jest.config.ts\",\n    \"src/**/*.test.ts\"\n  ],\n  \"include\": [\"src/**/*.ts\"]\n}\n"
  },
  {
    "path": "libs/angular-i18next/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../dist/out-tsc\",\n    \"module\": \"preserve\",\n    \"target\": \"es2016\",\n    \"types\": [\"jest\", \"node\"],\n    \"allowSyntheticDefaultImports\": false,\n    \"esModuleInterop\": true,\n    \"isolatedModules\": true\n  },\n  \"files\": [\"src/test-setup.ts\"],\n  \"include\": [\n    \"jest.config.ts\",\n    \"src/**/*.test.ts\",\n    \"src/**/*.spec.ts\",\n    \"src/**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "migrations.json",
    "content": "{\n  \"migrations\": [\n    {\n      \"version\": \"22.0.0-beta.1\",\n      \"description\": \"Updates release version config based on the breaking changes in Nx v22\",\n      \"implementation\": \"./src/migrations/update-22-0-0/release-version-config-changes\",\n      \"package\": \"nx\",\n      \"name\": \"22-0-0-release-version-config-changes\"\n    },\n    {\n      \"version\": \"22.0.0-beta.2\",\n      \"description\": \"Consolidates releaseTag* options into nested releaseTag object structure\",\n      \"implementation\": \"./src/migrations/update-22-0-0/consolidate-release-tag-config\",\n      \"package\": \"nx\",\n      \"name\": \"22-0-0-consolidate-release-tag-config\"\n    },\n    {\n      \"cli\": \"nx\",\n      \"version\": \"22.1.0-beta.5\",\n      \"description\": \"Updates the nx wrapper.\",\n      \"implementation\": \"./src/migrations/update-22-1-0/update-nx-wrapper\",\n      \"package\": \"nx\",\n      \"name\": \"22-1-0-update-nx-wrapper\"\n    },\n    {\n      \"version\": \"21.5.0-beta.2\",\n      \"description\": \"Migrate the legacy 'development' custom condition to a workspace-unique custom condition name.\",\n      \"factory\": \"./src/migrations/update-21-5-0/migrate-development-custom-condition\",\n      \"package\": \"@nx/js\",\n      \"name\": \"migrate-development-custom-condition\"\n    },\n    {\n      \"version\": \"22.0.0-beta.0\",\n      \"description\": \"Remove the deprecated `external` and `externalBuildTargets` options from the `@nx/js:swc` and `@nx/js:tsc` executors.\",\n      \"factory\": \"./src/migrations/update-22-0-0/remove-external-options-from-js-executors\",\n      \"package\": \"@nx/js\",\n      \"name\": \"remove-external-options-from-js-executors\"\n    },\n    {\n      \"version\": \"22.1.0-rc.1\",\n      \"description\": \"Removes redundant TypeScript project references from project's tsconfig.json files when runtime tsconfig files (e.g., tsconfig.lib.json, tsconfig.app.json) exist.\",\n      \"factory\": \"./src/migrations/update-22-1-0/remove-redundant-ts-project-references\",\n      \"package\": \"@nx/js\",\n      \"name\": \"remove-redundant-ts-project-references\"\n    },\n    {\n      \"version\": \"22.2.0-beta.2\",\n      \"description\": \"Convert jest.config.ts files from ESM to CJS syntax (export default -> module.exports, import -> require) for projects using CommonJS resolution to ensure correct loading under Node.js type-stripping.\",\n      \"implementation\": \"./src/migrations/update-22-2-0/convert-jest-config-to-cjs\",\n      \"package\": \"@nx/jest\",\n      \"name\": \"convert-jest-config-to-cjs\"\n    },\n    {\n      \"version\": \"22.3.2-beta.0\",\n      \"requires\": { \"jest\": \">=30.0.0\" },\n      \"description\": \"Replace removed matcher aliases in Jest v30 with their corresponding matcher\",\n      \"implementation\": \"./src/migrations/update-21-3-0/replace-removed-matcher-aliases\",\n      \"package\": \"@nx/jest\",\n      \"name\": \"replace-removed-matcher-aliases-v22-3\"\n    }\n  ]\n}\n"
  },
  {
    "path": "nx.json",
    "content": "{\n  \"affected\": {\n    \"defaultBase\": \"master\"\n  },\n  \"targetDependencies\": {\n    \"build\": [\n      {\n        \"target\": \"build\",\n        \"projects\": \"dependencies\"\n      }\n    ]\n  },\n  \"cli\": {\n    \"packageManager\": \"npm\"\n  },\n  \"generators\": {\n    \"@nx/angular:application\": {\n      \"style\": \"css\",\n      \"linter\": \"eslint\",\n      \"unitTestRunner\": \"jest\",\n      \"e2eTestRunner\": \"cypress\"\n    },\n    \"@nx/angular:library\": {\n      \"linter\": \"eslint\",\n      \"unitTestRunner\": \"jest\"\n    },\n    \"@nx/angular:component\": {\n      \"style\": \"css\"\n    },\n    \"@nx/angular\": {\n      \"application\": {\n        \"linter\": \"eslint\"\n      },\n      \"library\": {\n        \"linter\": \"eslint\"\n      },\n      \"storybook-configuration\": {\n        \"linter\": \"eslint\"\n      }\n    }\n  },\n  \"defaultProject\": \"angular-i18next\",\n  \"$schema\": \"./node_modules/nx/schemas/nx-schema.json\",\n  \"targetDefaults\": {\n    \"lint\": {\n      \"inputs\": [\"default\", \"{workspaceRoot}/.eslintrc.json\"],\n      \"cache\": true\n    },\n    \"build\": {\n      \"cache\": true,\n      \"inputs\": [\"production\", \"^production\"]\n    },\n    \"e2e\": {\n      \"cache\": true\n    },\n    \"@nx/jest:jest\": {\n      \"cache\": true,\n      \"inputs\": [\"default\", \"^default\", \"{workspaceRoot}/jest.preset.js\"],\n      \"options\": {\n        \"passWithNoTests\": true\n      },\n      \"configurations\": {\n        \"ci\": {\n          \"ci\": true,\n          \"codeCoverage\": true\n        }\n      }\n    },\n    \"test\": {\n      \"cache\": true\n    }\n  },\n  \"namedInputs\": {\n    \"default\": [\"{projectRoot}/**/*\", \"sharedGlobals\"],\n    \"sharedGlobals\": [],\n    \"production\": [\"default\"]\n  },\n  \"neverConnectToCloud\": true\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"angular-i18next-rep\",\n  \"version\": \"0.0.1\",\n  \"author\": {\n    \"name\": \"Sergey Romanchuk\"\n  },\n  \"homepage\": \"https://github.com/Romanchuk/angular-i18next#readme\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Romanchuk/angular-i18next.git\"\n  },\n  \"license\": \"MIT\",\n  \"description\": \"i18next module for Angular\",\n  \"keywords\": [\n    \"i18n\",\n    \"i18next\",\n    \"angular\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/Romanchuk/angular-i18next/issues\"\n  },\n  \"engines\": {\n    \"node\": \">=22.13.0\"\n  },\n  \"maintainers\": [\n    {\n      \"email\": \"rezety@gmail.com\",\n      \"name\": \"Sergey Romanchuk\"\n    }\n  ],\n  \"scripts\": {\n    \"start\": \"npx nx run angular-i18next-demo:serve:development\",\n    \"test\": \"npx nx test angular-i18next\",\n    \"lint\": \"npx nx workspace-lint && ng lint\",\n    \"affected:apps\": \"npx nx affected:apps\",\n    \"affected:libs\": \"npx nx affected:libs\",\n    \"affected:build\": \"npx nx affected:build\",\n    \"affected:e2e\": \"npx nx affected:e2e\",\n    \"affected:test\": \"npx nx affected:test\",\n    \"affected:lint\": \"npx nx affected:lint\",\n    \"affected:dep-graph\": \"npx nx affected:dep-graph\",\n    \"affected\": \"npx nx affected\",\n    \"build\": \"npx nx run angular-i18next-demo:build\",\n    \"prepare:demo\": \"npx cpy --cwd=dist/angular-i18next-demo/browser --rename=index.html ./index.csr.html ./\",\n    \"format\": \"npx nx format:write\",\n    \"format:write\": \"npx nx format:write\",\n    \"format:check\": \"npx nx format:check\",\n    \"update\": \"npx nx migrate latest\",\n    \"release\": \"npx nx run angular-i18next:release\",\n    \"pm2:prod\": \"npx pm2-runtime start ecosystem.config.js --env production\"\n  },\n  \"devDependencies\": {\n    \"@angular-devkit/build-angular\": \"21.1.1\",\n    \"@angular-devkit/core\": \"21.1.1\",\n    \"@angular-devkit/schematics\": \"21.1.1\",\n    \"@angular-eslint/eslint-plugin\": \"21.1.0\",\n    \"@angular-eslint/eslint-plugin-template\": \"21.1.0\",\n    \"@angular-eslint/template-parser\": \"21.1.0\",\n    \"@angular/cli\": \"21.1.1\",\n    \"@angular/compiler-cli\": \"21.1.1\",\n    \"@angular/language-service\": \"21.1.1\",\n    \"@angular/platform-browser\": \"21.1.1\",\n    \"@angular/platform-browser-dynamic\": \"21.1.1\",\n    \"@angular/platform-server\": \"21.1.1\",\n    \"@nx/angular\": \"22.4.0\",\n    \"@nx/eslint\": \"22.4.0\",\n    \"@nx/eslint-plugin\": \"22.4.0\",\n    \"@nx/jest\": \"22.4.0\",\n    \"@nx/js\": \"22.4.0\",\n    \"@nx/workspace\": \"22.4.0\",\n    \"@schematics/angular\": \"21.1.1\",\n    \"@swc-node/register\": \"~1.11.1\",\n    \"@swc/core\": \"~1.13.4\",\n    \"@swc/helpers\": \"~0.5.11\",\n    \"@types/express\": \"4.17.14\",\n    \"@types/jest\": \"^29.5.14\",\n    \"@types/node\": \"20.9.1\",\n    \"@typescript-eslint/eslint-plugin\": \"7.11.0\",\n    \"@typescript-eslint/parser\": \"7.11.0\",\n    \"@typescript-eslint/utils\": \"^7.16.0\",\n    \"browser-sync\": \"^3.0.3\",\n    \"conventional-changelog-cli\": \"^2.1.1\",\n    \"conventional-github-releaser\": \"^3.1.5\",\n    \"coveralls\": \"^3.1.0\",\n    \"cpy-cli\": \"^4.1.0\",\n    \"cross-env\": \"~7.0.3\",\n    \"cz-conventional-changelog\": \"^2.1.0\",\n    \"es6-shim\": \"0.35.4\",\n    \"eslint\": \"8.57.0\",\n    \"eslint-config-prettier\": \"10.0.0\",\n    \"i18next\": \"24.2.2\",\n    \"jest\": \"~30.2.0\",\n    \"jest-environment-jsdom\": \"~30.2.0\",\n    \"jest-preset-angular\": \"16.0.0\",\n    \"keyv\": \"^4.5.1\",\n    \"ng-packagr\": \"21.1.0\",\n    \"np\": \"11.0.1\",\n    \"nx\": \"22.4.0\",\n    \"pm2\": \"5.4.3\",\n    \"prettier\": \"3.1.0\",\n    \"replace\": \"^1.2.0\",\n    \"require-dir\": \"^1.2.0\",\n    \"rimraf\": \"3.0.0\",\n    \"ts-jest\": \"29.4.1\",\n    \"ts-node\": \"10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"~5.89.0\",\n    \"jest-util\": \"30.0.5\"\n  },\n  \"dependencies\": {\n    \"@angular/common\": \"21.1.1\",\n    \"@angular/compiler\": \"21.1.1\",\n    \"@angular/core\": \"21.1.1\",\n    \"@angular/forms\": \"21.1.1\",\n    \"@angular/platform-browser\": \"21.1.1\",\n    \"@angular/platform-browser-dynamic\": \"21.1.1\",\n    \"@angular/platform-server\": \"21.1.1\",\n    \"@angular/router\": \"21.1.1\",\n    \"@angular/ssr\": \"21.1.1\",\n    \"express\": \"~4.18.2\",\n    \"i18next\": \"25.4.0\",\n    \"i18next-browser-languagedetector\": \"~8.0.4\",\n    \"i18next-chained-backend\": \"~4.6.2\",\n    \"i18next-http-backend\": \"~2.4.1\",\n    \"i18next-http-middleware\": \"~3.7.1\",\n    \"i18next-resources-to-backend\": \"~1.2.0\",\n    \"rxjs\": \"~7.8.2\",\n    \"tslib\": \"~2.6.2\"\n  },\n  \"optionalDependencies\": {\n    \"@nx/nx-linux-x64-gnu\": \"20.3.1\"\n  }\n}\n"
  },
  {
    "path": "tools/tsconfig.tools.json",
    "content": "{\n  \"extends\": \"../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../dist/out-tsc/tools\",\n    \"rootDir\": \".\",\n    \"module\": \"commonjs\",\n    \"target\": \"es5\",\n    \"types\": [\"node\"],\n    \"importHelpers\": false\n  },\n  \"include\": [\"**/*.ts\"]\n}\n"
  },
  {
    "path": "tsconfig.base.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"rootDir\": \".\",\n    \"sourceMap\": true,\n    \"declaration\": false,\n    \"moduleResolution\": \"bundler\",\n    \"alwaysStrict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"downlevelIteration\": true,\n    \"experimentalDecorators\": true,\n    \"noImplicitOverride\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitThis\": true,\n    \"importHelpers\": true,\n    \"strictFunctionTypes\": true,\n    \"strictBindCallApply\": true,\n    \"strictNullChecks\": true,\n    \"target\": \"ES2022\",\n    \"module\": \"ES2022\",\n    \"lib\": [\"ES2022\", \"dom\"],\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"skipDefaultLibCheck\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"angular-i18next\": [\"libs/angular-i18next/src/index.ts\"],\n      \"angular-i18next/forms\": [\"libs/angular-i18next/forms/src/public_api.ts\"],\n      \"angular-i18next/ssr\": [\"libs/angular-i18next/ssr/src/public_api.ts\"],\n      \"angular-i18next/testing\": [\n        \"libs/angular-i18next/testing/src/public_api.ts\"\n      ],\n    }\n  },\n  \"exclude\": [\"node_modules\", \"tmp\"]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"extends\": \"./tsconfig.base.json\"\n}\n"
  }
]