Repository: the-hideout/tarkov-dev Branch: main Commit: 5a9fd0cf37f2 Files: 399 Total size: 2.3 MB Directory structure: gitextract_ffd8hvvc/ ├── .devcontainer/ │ ├── Dockerfile │ ├── devcontainer.json │ └── docker-compose.yml ├── .github/ │ ├── CODEOWNERS │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug.yml │ │ ├── config.yml │ │ └── feature-request.yml │ ├── dependabot.yml │ ├── exclude.txt │ ├── new-pr-comment.md │ ├── pull_request_template.md │ └── workflows/ │ ├── branch-deploy.yml │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── combine-prs.yml │ ├── deploy.yml │ ├── new-pr.yml │ └── unlock-on-merge.yml ├── .gitignore ├── .husky/ │ └── pre-commit ├── .node-version ├── .nvmrc ├── .prettierignore ├── .stylelintignore ├── .vscode/ │ ├── launch.json │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── additional.d.ts ├── dependabot.yml ├── i18next-parser.config.mjs ├── package.json ├── prettier.config.mjs ├── public/ │ ├── browserconfig.xml │ ├── data/ │ │ └── .gitignore │ ├── index.html │ ├── robots.txt │ └── site.webmanifest ├── rsbuild.config.ts ├── rstest.config.ts ├── rstest.setup.ts ├── scripts/ │ ├── build-redirects.mjs │ ├── build-sitemap.mjs │ ├── critical.mjs │ ├── custom-loader.mjs │ ├── generate-thumbnails.mjs │ ├── generate_api-users_thumbs_macOS.sh │ ├── generate_items_thumbs.mjs │ ├── generate_items_thumbs_macOS.sh │ ├── generate_known_icons_macOS.sh │ ├── get-contributors.mjs │ ├── get-supported-languages.mjs │ ├── test-redirects.mjs │ └── update-props.mjs ├── src/ │ ├── App.css │ ├── App.jsx │ ├── __tests__/ │ │ ├── App.test.jsx │ │ ├── test-utils.js │ │ └── tsconfig.json │ ├── components/ │ │ ├── Debug.jsx │ │ ├── FilterIcon.jsx │ │ ├── FleaMarketLoadingIcon.jsx │ │ ├── Graph.jsx │ │ ├── GraphLabel.jsx │ │ ├── SEO.jsx │ │ ├── Symbol.jsx │ │ ├── Time.jsx │ │ ├── api-metrics-graph/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── barter-tooltip/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── barters-table/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── boss-list/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── canvas-grid/ │ │ │ └── index.jsx │ │ ├── center-cell/ │ │ │ └── index.jsx │ │ ├── cheeki-breeki-effect/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── contained-items-list/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── contributors/ │ │ │ └── index.jsx │ │ ├── cost-items-cell/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── countdown/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── crafts-table/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── data-table/ │ │ │ ├── Arrow.tsx │ │ │ ├── TableHead.tsx │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── em-item-tag/ │ │ │ └── index.jsx │ │ ├── filter/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── flea-price-cell/ │ │ │ └── index.jsx │ │ ├── footer/ │ │ │ ├── index.css │ │ │ └── index.tsx │ │ ├── item-cost/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── item-grid/ │ │ │ ├── Item.jsx │ │ │ ├── ItemIcon.jsx │ │ │ ├── ItemTooltip.jsx │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── item-icon-list/ │ │ │ └── index.jsx │ │ ├── item-image/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── item-name-cell/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── item-search/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── items-for-hideout/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── items-summary-table/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── loading/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── loading-small/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── loyalty-level-icon/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── menu/ │ │ │ ├── CategoryMenu.jsx │ │ │ ├── MenuItem.jsx │ │ │ ├── alert-config.js │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ ├── menu-data.js │ │ │ └── useMenuOverflow.js │ │ ├── open-collective-button/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── patreon-button/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── points/ │ │ │ ├── Circle.jsx │ │ │ ├── Diamond.jsx │ │ │ ├── Plus.jsx │ │ │ ├── Square.jsx │ │ │ ├── TriangleDown.jsx │ │ │ ├── TriangleUp.jsx │ │ │ └── index.jsx │ │ ├── preset-selector/ │ │ │ └── index.jsx │ │ ├── price-graph/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── property-list/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── quest-items-cell/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── quest-table/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── remote-control-id/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── reward-cell/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── reward-image/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── scroll-to-top/ │ │ │ └── index.jsx │ │ ├── server-status/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── small-item-table/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── station-skill-trader-setting/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── supporter/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── supporters-list/ │ │ │ └── index.jsx │ │ ├── trader-image/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── trader-price-cell/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── trader-reset-time/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── ukraine-button/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ └── value-cell/ │ │ ├── index.css │ │ └── index.jsx │ ├── data/ │ │ ├── api-users.json │ │ ├── bosses.json │ │ ├── category-pages.json │ │ ├── game-modes.json │ │ ├── item-grids.json │ │ ├── maps.json │ │ ├── maps_static.json │ │ ├── patreons.json │ │ └── wipe-details.json │ ├── features/ │ │ ├── barters/ │ │ │ ├── do-fetch-barters.mjs │ │ │ └── index.js │ │ ├── crafts/ │ │ │ ├── do-fetch-crafts.mjs │ │ │ └── index.js │ │ ├── hideout/ │ │ │ ├── do-fetch-hideout.mjs │ │ │ └── index.js │ │ ├── items/ │ │ │ ├── do-fetch-items.mjs │ │ │ └── index.js │ │ ├── maps/ │ │ │ ├── do-fetch-maps.mjs │ │ │ └── index.js │ │ ├── quests/ │ │ │ ├── do-fetch-quests.mjs │ │ │ └── index.js │ │ ├── settings/ │ │ │ └── settingsSlice.mjs │ │ ├── sockets/ │ │ │ └── socketsSlice.js │ │ ├── status/ │ │ │ ├── do-fetch-status.mjs │ │ │ └── index.mjs │ │ └── traders/ │ │ ├── do-fetch-traders.mjs │ │ └── index.js │ ├── hooks/ │ │ ├── useDate.jsx │ │ ├── useKeyPress.jsx │ │ ├── useObserver.jsx │ │ ├── useRepositoryContributors.js │ │ └── useStateWithLocalStorage.jsx │ ├── i18n.js │ ├── index.jsx │ ├── modules/ │ │ ├── api-query.mjs │ │ ├── api-request.mjs │ │ ├── best-price.js │ │ ├── camelcase-to-dashes.js │ │ ├── capitalize-first.js │ │ ├── dogtags.js │ │ ├── flea-market-fee.mjs │ │ ├── format-ammo.mjs │ │ ├── format-category-name.js │ │ ├── format-cost-items.js │ │ ├── format-duration.js │ │ ├── format-price.js │ │ ├── graphql-request.mjs │ │ ├── item-can-contain.js │ │ ├── item-search.js │ │ ├── lang-helpers.js │ │ ├── leaflet-control-coordinates.js │ │ ├── leaflet-control-groupedlayer.js │ │ ├── leaflet-control-map-search.js │ │ ├── leaflet-control-map-settings.js │ │ ├── leaflet-control-raid-info.js │ │ ├── leaflet-control-remote.js │ │ ├── make-id.js │ │ ├── mui-theme.mjs │ │ ├── player-stats.mjs │ │ ├── polyfills.js │ │ ├── property-format.js │ │ ├── queue-browser-task.js │ │ ├── remote-websocket.mjs │ │ ├── task-elements.css │ │ ├── task-elements.mjs │ │ ├── window-focus-handler.mjs │ │ └── wipe-length.js │ ├── pages/ │ │ ├── about/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── achievements/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── ammo/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── api-docs/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── api-users/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── barters/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── bitcoin-farm-calculator/ │ │ │ ├── data.js │ │ │ ├── graph.jsx │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ ├── profit-info.jsx │ │ │ └── profitable-graph.jsx │ │ ├── boss/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── bosses/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── control/ │ │ │ ├── Connect.jsx │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── converter/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── crafts/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── error-page/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── hideout/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── item/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── item-tracker/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── items/ │ │ │ ├── armors/ │ │ │ │ └── index.jsx │ │ │ ├── backpacks/ │ │ │ │ └── index.jsx │ │ │ ├── barter-items/ │ │ │ │ └── index.jsx │ │ │ ├── bsg-category/ │ │ │ │ └── index.jsx │ │ │ ├── containers/ │ │ │ │ └── index.jsx │ │ │ ├── glasses/ │ │ │ │ └── index.jsx │ │ │ ├── grenades/ │ │ │ │ └── index.jsx │ │ │ ├── guns/ │ │ │ │ └── index.jsx │ │ │ ├── handbook-category/ │ │ │ │ └── index.jsx │ │ │ ├── headsets/ │ │ │ │ └── index.jsx │ │ │ ├── helmets/ │ │ │ │ └── index.jsx │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ ├── keys/ │ │ │ │ └── index.jsx │ │ │ ├── mods/ │ │ │ │ └── index.jsx │ │ │ ├── pistol-grips/ │ │ │ │ └── index.jsx │ │ │ ├── provisions/ │ │ │ │ └── index.jsx │ │ │ ├── rigs/ │ │ │ │ └── index.jsx │ │ │ └── suppressors/ │ │ │ └── index.jsx │ │ ├── loot-tiers/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── map/ │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ └── map-images.mjs │ │ ├── maps/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── moobot/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── nightbot/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── other-tools/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── player/ │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ └── player-forward.jsx │ │ ├── players/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── prestige/ │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ └── list.jsx │ │ ├── quest/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── quests/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── settings/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── start/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── stash-bot/ │ │ │ ├── index.css │ │ │ └── index.js │ │ ├── stream-elements/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── tarkov-monitor/ │ │ │ ├── index.css │ │ │ └── index.js │ │ ├── trader/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── traders/ │ │ │ ├── index.css │ │ │ └── index.jsx │ │ └── wipe-length/ │ │ ├── index.css │ │ └── index.jsx │ ├── serviceWorker.js │ ├── setupTests.js │ ├── store.js │ ├── styles/ │ │ ├── mapRemote.css │ │ ├── mapSearch.css │ │ ├── mapSettings.css │ │ └── singleEntity.css │ └── translations/ │ ├── de/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── en/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── es/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── fr/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── it/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── ja/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── pl/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── pt/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── remove_equal_key_value.py │ ├── ru/ │ │ ├── bosses.json │ │ ├── maps.json │ │ ├── properties.json │ │ └── translation.json │ ├── sync_key_value.py │ └── zh/ │ ├── bosses.json │ ├── maps.json │ ├── properties.json │ └── translation.json ├── stylelint.config.mjs ├── tsconfig.json ├── workers-site/ │ ├── .cargo-ok │ ├── .gitignore │ ├── index-template.js │ └── package.json └── wrangler.toml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .devcontainer/Dockerfile ================================================ FROM node:20 EXPOSE 3000 ENV APP_ROOT /tarkov-dev RUN mkdir -p $APP_ROOT WORKDIR $APP_ROOT CMD ["/bin/bash", "-c", "npm install && npm start && while :; do sleep 1; done"] ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "name": "Tarkov-Dev Local Dev", "dockerComposeFile": "docker-compose.yml", "service": "dev", "workspaceFolder": "/tarkov-dev", "features": { "ghcr.io/devcontainers/features/github-cli:1": { "installDirectlyFromGitHubRelease": true, "version": "latest" }, "ghcr.io/devcontainers/features/node:1": { "version": "24.11.1", // Defaults to 'lts' "nvmVersion": "latest", // Default value "installYarnUsingApt": false }, "common": { "username": "automatic", "uid": "automatic", "gid": "automatic", "installZsh": true, "configureZshAsDefaultShell": true, "installOhMyZsh": true, "upgradePackages": true, "nonFreePackages": false } }, "customizations": { // jetbrains devcontainer compatability for zsh "jetbrains": { "settings": { "org.jetbrains.plugins.terminal:app:TerminalOptionsProvider.myShellPath": "/bin/zsh" } }, "vscode": { "settings": { "terminal.integrated.defaultProfile.linux": "zsh", "terminal.integrated.profiles.linux": { "bash": { "path": "bash", "icon": "terminal-bash" }, "zsh": { "path": "zsh", "icon": "terminal-bash" } } } }, "extensions": [ // adds to @recommended exentions to install into devcontainer "jasonnutter.search-node-modules", "eamodio.gitlens", "dbaeumer.vscode-eslint" ] } } ================================================ FILE: .devcontainer/docker-compose.yml ================================================ services: dev: build: context: .. dockerfile: ./.devcontainer/Dockerfile volumes: - ..:/tarkov-dev ports: - "3000:3000" ================================================ FILE: .github/CODEOWNERS ================================================ # Default reviewers for all files in the repo * @the-hideout/reviewers ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms open_collective: tarkov-dev ================================================ FILE: .github/ISSUE_TEMPLATE/bug.yml ================================================ name: Bug Report description: File a bug/issue report labels: ["bug"] body: - type: markdown attributes: value: | # Bug Report 🐛 Thanks for taking the time to fill out this bug report! Please answer each question below to your best ability. It is okay to leave questions blank if you have to! - type: textarea id: description attributes: label: Describe the Issue description: Please describe the bug/issue in detail placeholder: Something is wrong with X when going to page Y validations: required: true - type: textarea id: expected attributes: label: Expected Behavior description: A clear and concise description of what you expected to happen placeholder: I expected X to happen when going to page Y validations: required: true - type: textarea id: reproduce attributes: label: To Reproduce description: If you know how to reproduce the issue, please provided detailed steps below placeholder: Go to page Y and click on button Z. Look at the console and see error XYZ validations: required: true - type: dropdown id: client attributes: label: Client description: What type of client are you using to reproduce this error? options: - Desktop - Mobile - Other validations: required: true - type: dropdown id: browser attributes: label: Browser description: What type of web browser are you using to reproduce this error? options: - Chrome - Brave - Firefox - Opera - Safari - Edge - Chromium - Other validations: required: true - type: textarea id: logs attributes: label: Relevant Console Log Output description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. render: console - type: textarea id: extra attributes: label: Extra Information description: Any extra information, links to issues, screenshots, etc ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: true ================================================ FILE: .github/ISSUE_TEMPLATE/feature-request.yml ================================================ name: Feature Request description: Suggest a new feature or enhancement labels: ["enhancement"] body: - type: markdown attributes: value: | # Feature Request 🏆 Thanks for taking the time to fill out this feature request! Please answer each question below to your best ability. It is okay to leave questions blank if you have to! - type: textarea id: description attributes: label: Describe the Feature Request description: Please describe the feature request in detail placeholder: I would like feature XYZ because ABC ================================================ FILE: .github/dependabot.yml ================================================ # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates --- version: 2 updates: - package-ecosystem: github-actions directory: "/" groups: github-actions: patterns: - "*" schedule: interval: monthly - package-ecosystem: npm directory: "/" groups: npm-dependencies: patterns: - "*" schedule: interval: monthly cooldown: default-days: 90 ignore: - dependency-name: "i18next" update-types: ["version-update:semver-major"] - dependency-name: "react" update-types: ["version-update:semver-major"] - dependency-name: "react-i18next" update-types: ["version-update:semver-minor"] - dependency-name: "react-router" update-types: ["version-update:semver-major"] - dependency-name: "react-router-dom" update-types: ["version-update:semver-major"] - dependency-name: "eslint" update-types: ["version-update:semver-major"] ================================================ FILE: .github/exclude.txt ================================================ # custom exclude file for the GrantBirki/json-yaml-validate@vX.X.X Actions workflow .devcontainer/devcontainer.json ================================================ FILE: .github/new-pr-comment.md ================================================ ### 👋 Thanks for opening a pull request! If you are new, please check out the trimmed down summary of our deployment process below: 1. 👀 Observe the CI jobs and tests to ensure they are passing 1. ✔️ Obtain an approval/review on this pull request 1. 🚀 Deploy your pull request to the **development** environment with `.deploy to development` 1. 🚀 Deploy your pull request to the **production** environment with `.deploy` > If anything goes wrong, rollback with `.deploy main` 1. 🎉 Merge! > Note: If you have a larger change and want to block deployments, you can run `.lock --reason ` to lock all other deployments (remove with `.unlock`) You can view the branch deploy [usage guide](https://github.com/github/branch-deploy/blob/main/docs/usage.md) for additional information ================================================ FILE: .github/pull_request_template.md ================================================ # [title here] ## Description 🗒️ ## Examples 📸 ## Related Issues 🔗 ---
Expand for Help - Have questions about the review or deployment process? View our [contributing docs](https://github.com/the-hideout/tarkov-dev/blob/main/CONTRIBUTING.md) - Need additional help and want to chat in real time? Join our [community Discord](https://discord.gg/WwTvNe356u) > By submitting this pull request, you agree to our [code of conduct](https://github.com/the-hideout/tarkov-dev/blob/main/CODE_OF_CONDUCT.md)
================================================ FILE: .github/workflows/branch-deploy.yml ================================================ name: branch-deploy on: issue_comment: types: [ created ] # Permissions needed for reacting and adding comments for IssueOps commands permissions: pull-requests: write deployments: write contents: write checks: read statuses: read jobs: deploy: environment: secrets if: ${{ github.event.issue.pull_request }} # only run on pull request comments runs-on: ubuntu-latest steps: - uses: github/branch-deploy@v11 id: branch-deploy with: admins: the-hideout/core-contributors admins_pat: ${{ secrets.BRANCH_DEPLOY_ADMINS_PAT }} environment_targets: production,development environment_urls: production|https://tarkov.dev,development|disabled sticky_locks: "true" - name: checkout if: ${{ steps.branch-deploy.outputs.continue == 'true' }} uses: actions/checkout@v6 with: ref: ${{ steps.branch-deploy.outputs.sha }} - uses: actions/setup-node@v6.4.0 if: ${{ steps.branch-deploy.outputs.continue == 'true' }} with: node-version-file: .node-version cache: 'npm' - name: install dependencies if: ${{ steps.branch-deploy.outputs.continue == 'true' }} run: npm ci - name: env setup if: ${{ steps.branch-deploy.outputs.continue == 'true' }} env: PUBLIC_URL: '' run: | touch .env echo PUBLIC_URL=$PUBLIC_URL >> .env - name: build if: ${{ steps.branch-deploy.outputs.continue == 'true' }} run: npm run build env: GITHUB_TOKEN: ${{ secrets.HIDEOUT_BOT_TOKEN }} # deploy to the dev env and also save the stdout to a file - name: deploy - dev id: dev-deploy if: ${{ steps.branch-deploy.outputs.continue == 'true' && steps.branch-deploy.outputs.noop != 'true' && steps.branch-deploy.outputs.environment == 'development' }} uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # pin@v3.15.0 with: apiToken: ${{ secrets.CF_API_TOKEN }} accountId: ${{ secrets.CF_ACCOUNT_ID }} wranglerVersion: '2.13.0' command: pages publish build/ --project-name=tarkov-dev --branch=preview # fetch the dev url from stdout and save add it to the deploy message - name: add development url to deploy message if: ${{ steps.branch-deploy.outputs.continue == 'true' && steps.branch-deploy.outputs.noop != 'true' && steps.branch-deploy.outputs.environment == 'development' }} env: DEPLOYMENT_URL: ${{ steps.dev-deploy.outputs.deployment-url }} CMD_OUTPUT: ${{ steps.dev-deploy.outputs.command-output }} run: | echo "for debugging (cmd output): ${CMD_OUTPUT}" echo "" echo "DEPLOY_MESSAGE=${DEPLOYMENT_URL}" >> $GITHUB_ENV echo "DEPLOY_MESSAGE=${DEPLOYMENT_URL}" - name: deploy - prod id: prod-deploy if: ${{ steps.branch-deploy.outputs.continue == 'true' && steps.branch-deploy.outputs.noop != 'true' && steps.branch-deploy.outputs.environment == 'production' }} uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # pin@v3.15.0 with: apiToken: ${{ secrets.CF_API_TOKEN }} accountId: ${{ secrets.CF_ACCOUNT_ID }} wranglerVersion: '2.13.0' command: pages publish build/ --project-name=tarkov-dev --branch=main ================================================ FILE: .github/workflows/ci.yml ================================================ name: ci on: push: branches: - main pull_request: branches: [ main ] permissions: contents: read pull-requests: write jobs: test: runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v6 # check to ensure all JSON files are valid in the repository - name: json-yaml-validate uses: GrantBirki/json-yaml-validate@v4.0.0 with: comment: "true" exclude_file: .github/exclude.txt - uses: actions/setup-node@v6.4.0 with: node-version-file: .node-version cache: 'npm' - name: install dependencies run: npm ci - name: env setup env: PUBLIC_URL: '' run: | touch .env echo PUBLIC_URL=$PUBLIC_URL >> .env - name: Get files needed run: npm run prebuild env: GITHUB_TOKEN: ${{ secrets.HIDEOUT_BOT_TOKEN }} - name: test run: npm run test ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ name: CodeQL on: push: branches: [ main ] schedule: - cron: '29 10 * * 4' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'javascript' ] steps: - name: checkout uses: actions/checkout@v6 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # pin@v2 with: languages: ${{ matrix.language }} - name: Autobuild uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # pin@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # pin@v2 ================================================ FILE: .github/workflows/combine-prs.yml ================================================ name: Combine PRs on: schedule: - cron: "0 1 * * 3" # Wednesday at 01:00 workflow_dispatch: jobs: combine-prs: uses: the-hideout/reusable-workflows/.github/workflows/combine-prs.yml@main secrets: COMBINE_PRS_APP_ID: ${{ secrets.COMBINE_PRS_APP_ID }} COMBINE_PRS_PRIVATE_KEY: ${{ secrets.COMBINE_PRS_PRIVATE_KEY }} fallback: ${{ secrets.GITHUB_TOKEN }} # fall back to the default token if the app token is not available ================================================ FILE: .github/workflows/deploy.yml ================================================ name: deploy on: push: branches: - main permissions: contents: read jobs: deploy: if: github.event_name == 'push' environment: production runs-on: ubuntu-latest steps: - name: deployment check uses: github/branch-deploy@v11 id: deployment-check with: merge_deploy_mode: "true" # tells the Action to use the merge commit workflow strategy environment: production - name: checkout if: ${{ steps.deployment-check.outputs.continue == 'true' }} uses: actions/checkout@v6 with: ref: ${{ steps.deployment-check.outputs.sha }} # check to ensure all JSON files are valid in the repository - name: json-yaml-validate if: ${{ steps.deployment-check.outputs.continue == 'true' }} uses: GrantBirki/json-yaml-validate@v4.0.0 - uses: actions/setup-node@v6.4.0 if: ${{ steps.deployment-check.outputs.continue == 'true' }} with: node-version-file: .node-version cache: 'npm' - name: install dependencies if: ${{ steps.deployment-check.outputs.continue == 'true' }} run: npm ci - name: env setup if: ${{ steps.deployment-check.outputs.continue == 'true' }} env: PUBLIC_URL: '' run: | touch .env echo PUBLIC_URL=$PUBLIC_URL >> .env - name: build if: ${{ steps.deployment-check.outputs.continue == 'true' }} run: npm run build env: GITHUB_TOKEN: ${{ secrets.HIDEOUT_BOT_TOKEN }} PUBLIC_URL: '' - name: test if: ${{ steps.deployment-check.outputs.continue == 'true' }} run: npm run test - name: deploy if: ${{ steps.deployment-check.outputs.continue == 'true' }} uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # pin@v3.15.0 with: apiToken: ${{ secrets.CF_API_TOKEN }} accountId: ${{ secrets.CF_ACCOUNT_ID }} wranglerVersion: '2.13.0' command: pages publish build/ --project-name=tarkov-dev --branch=main # Uncomment to enable Sentry releases via CI # - name: Create Sentry release # uses: getsentry/action-release@744e4b262278339b79fb39c8922efcae71e98e39 # pin@v1.1.6 # env: # SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} # SENTRY_ORG: tarkov-dev # SENTRY_PROJECT: tarkovdev # with: # environment: production # sourcemaps: ./build/static/ # Always run this step on push to main - name: CDN Purge # if: ${{ steps.deployment-check.outputs.continue == 'true' }} uses: jakejarvis/cloudflare-purge-action@eee6dba0236093358f25bb1581bd615dc8b3d8e3 # pin@v0.3.0 env: CLOUDFLARE_ZONE: ${{ secrets.CLOUDFLARE_ZONE }} CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_PURGE_TOKEN }} PURGE_URLS: '["https://tarkov.dev/data/item-grids.min.json", "https://tarkov.dev/data/item-props.min.json"]' ================================================ FILE: .github/workflows/new-pr.yml ================================================ name: New Pull Request on: pull_request: branches: - main permissions: pull-requests: write jobs: comment: if: github.event_name == 'pull_request' && github.event.action == 'opened' runs-on: ubuntu-latest steps: # Comment on new PR requests with deployment instructions - uses: actions/checkout@v6 - name: comment uses: GrantBirki/comment@v2.1.1 continue-on-error: true with: file: .github/new-pr-comment.md ================================================ FILE: .github/workflows/unlock-on-merge.yml ================================================ name: Unlock On Merge on: pull_request: types: [closed] permissions: contents: write jobs: unlock-on-merge: runs-on: ubuntu-latest if: github.event.pull_request.merged == true steps: - name: unlock on merge uses: github/branch-deploy@v11 id: unlock-on-merge with: unlock_on_merge_mode: "true" # <-- indicates that this is the "Unlock on Merge Mode" workflow environment_targets: production,development ================================================ FILE: .gitignore ================================================ # Created by https://www.toptal.com/developers/gitignore/api/node,macos,react,windows,jetbrains,visualstudiocode # Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,react,windows,jetbrains,visualstudiocode ### JetBrains ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # AWS User-specific .idea/**/aws.xml # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. # .idea/artifacts # .idea/compiler.xml # .idea/jarRepositories.xml # .idea/modules.xml # .idea/*.iml # .idea/modules # *.iml # *.ipr # CMake cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # SonarLint plugin .idea/sonarlint/ # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser ### JetBrains Patch ### # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 # *.iml # modules.xml # .idea/misc.xml # *.ipr # Sonarlint plugin # https://plugins.jetbrains.com/plugin/7973-sonarlint .idea/**/sonarlint/ # SonarQube Plugin # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin .idea/**/sonarIssues.xml # Markdown Navigator plugin # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced .idea/**/markdown-navigator.xml .idea/**/markdown-navigator-enh.xml .idea/**/markdown-navigator/ # Cache file creation bug # See https://youtrack.jetbrains.com/issue/JBR-2257 .idea/$CACHE_FILE$ # CodeStream plugin # https://plugins.jetbrains.com/plugin/12206-codestream .idea/codestream.xml # Azure Toolkit for IntelliJ plugin # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij .idea/**/azureSettings.xml ### macOS ### # General .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ### macOS Patch ### # iCloud generated files *.icloud ### Node ### # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* .pnpm-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Snowpack dependency directory (https://snowpack.dev/) web_modules/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional stylelint cache .stylelintcache # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ .rts2_cache_es/ .rts2_cache_umd/ # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variable files .env .env.development.local .env.test.local .env.production.local .env.local # parcel-bundler cache (https://parceljs.org/) .cache .parcel-cache # Next.js build output .next out # Nuxt.js build / generate output .nuxt dist # Gatsby files .cache/ # Comment in the public line in if your project uses Gatsby and not Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist # vuepress v2.x temp and cache directory .temp # Docusaurus cache and generated files .docusaurus # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # TernJS port file .tern-port # Stores VSCode versions used for testing VSCode extensions .vscode-test # yarn v2 .yarn/cache .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz .pnp.* ### Node Patch ### # Serverless Webpack directories .webpack/ # Optional stylelint cache # SvelteKit build / generate output .svelte-kit ### react ### .DS_* **/*.backup.* **/*.back.* node_modules *.sublime* psd thumb sketch ### VisualStudioCode ### .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json !.vscode/*.code-snippets # Local History for Visual Studio Code .history/ # Built Visual Studio Code Extensions *.vsix ### VisualStudioCode Patch ### # Ignore all local history of files .history .ionide ### Windows ### # Windows thumbnail cache files Thumbs.db Thumbs.db:encryptable ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file [Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msix *.msm *.msp # Windows shortcuts *.lnk # End of https://www.toptal.com/developers/gitignore/api/node,macos,react,windows,jetbrains,visualstudiocode build/ public/maps/*_thumb.jpg src/data/contributors.json src/data/supported-languages.json # Cache src/data/barters_cached.json src/data/bosses_cached.json src/data/bosses_locale.json src/data/crafts_cached.json src/data/hideout_cached.json src/data/items_cached.json src/data/items_locale.json src/data/maps_cached.json src/data/maps_locale.json src/data/meta_cached.json src/data/quests_cached.json src/data/quests_locale.json src/data/traders_cached.json src/data/traders_locale.json src/data/project-contributors.json # Sitemap public/sitemap*.xml public/sitemap*.xml.gz # Workers workers-site/index.js ================================================ FILE: .husky/pre-commit ================================================ npx lint-staged ================================================ FILE: .node-version ================================================ 24.11.1 ================================================ FILE: .nvmrc ================================================ 24.11.1 ================================================ FILE: .prettierignore ================================================ # Ignore artifacts: build dist # Ignore all HTML files: **/*.html ================================================ FILE: .stylelintignore ================================================ # Ignore artifacts: build dist # Ignore all HTML files: **/*.html ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "type": "chrome", "request": "launch", "name": "Launch Chrome against localhost", "url": "http://localhost:3000", "webRoot": "${workspaceFolder}" } ] } ================================================ FILE: .vscode/settings.json ================================================ { "cSpell.words": [ "Tarkov" ] } ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at our community Discord server. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: CONTRIBUTING.md ================================================ # How to Contribute to tarkov-dev 💻 > This contributing guide is specfic to the [tarkov-dev](https://github.com/the-hideout/tarkov-dev) repo but many of its practices are shared with other repos in [the-hideout](https://github.com/the-hideout) ## Reporting a Bug 🐛 - Do not open up a GitHub issue if the bug is a security vulnerability, and instead to refer to our [security policy](SECURITY.md) - Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/the-hideout/tarkov-dev/issues) - If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/the-hideout/tarkov-dev/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring (if possible) ## Opening a Pull Request 🌟 If you have a fix for a bug or a feature request, follow the flow below to propose your change > If you are new to creating pull requests from a repository fork, check out this [guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) ### Pull Request - TL;DR If you don't want to read the detailed section below (you should), here is a TL;DR for our PR process: 1. Open a PR with changes 2. A team member will run CI, review, and deploy (first to dev, then prod) 3. If all looks good, we merge the PR ## Pull Request - Detailed 1. Fork the [tarkov-dev](https://github.com/the-hideout/tarkov-dev) repo 2. Clone your forked repo 3. Make your changes and ensure they work locally 4. Push your changes to your forked repo 5. Open a pull request on GitHub with the `tarkov-dev` repo and the `main` branch as the target 6. Ensure your pull request has a meaningful title, description, and links to any related issues Hooray! You have opened a PR with your changes. Now a member from [the-hideout/reviewers](https://github.com/orgs/the-hideout/teams/reviewers) will step in and follow the process below: 1. A [the-hideout/reviewers](https://github.com/orgs/the-hideout/teams/reviewers) member will review your PR 2. They will run the GitHub Actions CI suite on your PR 3. If CI is passing, they will comment `.deploy to development` to ship your changes to our development environment 4. At this point, the reviewer will review the changes live in development. You should also test your changes as well in this environment to ensure they are working as expected 5. If all looks good, the reviewer will run `.deploy` to ship your changes to our production environment 6. If nothing goes wrong, the reviewer will merge the PR 7. 🎉 ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 Oskar Risberg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # tarkov.dev 💻 [![deploy](https://github.com/the-hideout/tarkov-dev/actions/workflows/deploy.yml/badge.svg)](https://github.com/the-hideout/tarkov-dev/actions/workflows/deploy.yml) [![ci](https://github.com/the-hideout/tarkov-dev/actions/workflows/ci.yml/badge.svg)](https://github.com/the-hideout/tarkov-dev/actions/workflows/ci.yml) [![CodeQL](https://github.com/the-hideout/tarkov-dev/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/the-hideout/tarkov-dev/actions/workflows/codeql-analysis.yml) ![contributors](https://img.shields.io/github/contributors-anon/the-hideout/tarkov-dev) [![Discord](https://img.shields.io/discord/956236955815907388?color=7388DA&label=Discord)](https://discord.gg/WwTvNe356u) ![react](https://img.shields.io/badge/lib-react-blue) ![JS](https://img.shields.io/badge/language-JS-blue) ![stars](https://img.shields.io/github/stars/the-hideout/tarkov-dev?style=social) This is the source code for the official [tarkov.dev](https://tarkov.dev) website. View Escape from Tarkov information about items, barters, trades, flea market prices, quests, maps, hideout profits, and so much more! ![homepage](docs/assets/homepage.png) ## Local Development 🔨 To build and test the site locally just follow the steps below: 0. Install Node.js ```bash # use nvm to install the correct version of Node.js nvm use ``` 1. Install dependencies: ```bash npm install ``` 1. Copy .env.example to .env (no values need to be changed) 1. Start development server: ```bash npm start ``` 1. Access the site: [localhost:3000](http://localhost:3000/) 🎉 > Note: You can update data with: `npm run prebuild` ## VS Code Dev Container 1. Open VS Code command palette: ``` cmd + shift + p / ctrl + shift + p ``` 2. Start the dev container: ``` > Dev Containers: open folder in container... ``` 3. Select local path to tarkov-dev repo 4. After the container builds and starts it will auto run `npm install && npm start` 5. Access the site: [localhost:3000](http://localhost:3000/) 🎉 ## History 📚 This project ([tarkov-dev](https://github.com/the-hideout/tarkov-dev)) is a fork of [tarkov-tools.com](https://github.com/kokarn/tarkov-tools). The original creator [@kokarn](https://github.com/kokarn) decided to shut the site down. In the spirit of open source, a group of developers came together to revive the site in order to continue providing a great website for the Tarkov community and an API to power further development for creators. This project is now 100% open source (see infrastructure section below) and developer first. Our GitHub Organization ([the-hideout](https://github.com/the-hideout)) contains all the repos which power the API, this website, the community Discord bot, server infrastructure, and much more! We are passionate about open source and love pull requests to improve our ecosystem for all. ## We ❤️ Pull Requests We love pull requests and contributors looking to improve this project! Anything from simple spelling errors, icon updates, fixes for small css bugs or just posting issues to keep track of what needs to be done is greatly appreciated. ## Deployment 🚀 Deploying your changes to production is easy! Just do the following: 1. Open a pull request with your changes 1. Make sure CI is passing (a core member of [the-hideout](https://github.com/orgs/the-hideout/teams/core-contributors) will run CI for you) 1. A core member of [the-hideout](https://github.com/orgs/the-hideout/teams/core-contributors) will run `.deploy to development` to deploy your changes to the development environment for final validation 1. A review will be recieved from a [reviewer](https://github.com/orgs/the-hideout/teams/reviewers) if all looks good 1. A core member of [the-hideout](https://github.com/orgs/the-hideout/teams/core-contributors) will run `.deploy` on your pull request to branch deploy your changes to production 1. If everything goes okay, your PR will be merged and your changes will be auto-deployed to production! ✨ ## Updating Languages 🌐 There are two _ways_ to update languages on the site: - Updating the core translations (most common) - Updating the language that the GraphQL API uses (least common) ### Language Translations Rather than go into detail here, we have opened a great guide in a GitHub issue for how you can provide translation contributions to tarkov.dev! > Check out the guide [here](https://github.com/the-hideout/tarkov-dev/issues/175) ### GraphQL API Language Support To update the supported languages used by the site with the **GraphQL API**, you will need to edit the following file: [`supported-languages.json`](https://github.com/the-hideout/tarkov-dev/blob/main/src/data/supported-languages.json) > See this [pull request](https://github.com/the-hideout/tarkov-dev/pull/123) for additional context ## Other Parts of the Ecosystem 🌎 - [Stash](https://github.com/the-hideout/stash) - The official tarkov.dev Discord bot - [Tarkov API](https://github.com/the-hideout/tarkov-api) - The GraphQL API that powers everything - [Tarkov Data](https://github.com/TarkovTracker/tarkovdata/) - Open source structured data for Escape from Tarkov - [Tarkov Image Generator](https://github.com/the-hideout/tarkov-image-generator) - Tool to generate images from the local icon cache - [Tarkov Data Manager](https://github.com/the-hideout/tarkov-data-manager) - Data manager that core contributors to the project can use to update items in the database. It also contains cron jobs that sync database information to our Cloudflare workers for the GraphQL API - [Cache](https://github.com/the-hideout/cache) - A bespoke caching service to cache frequent GraphQL API queries - [Status](https://github.com/the-hideout/status) - The official status page for tarkov.dev, api.tarkov.dev, and much more ## Infrastructure 🧱 To learn more about the infrastructure, components, and open source pieces of this project, check out our [infrastructure documentation](https://github.com/the-hideout/.github/blob/main/profile/docs/infrastructure.md#opensource-notice-) ## Contributors 🧑‍🤝‍🧑 Thank you to all of our awesome contributors! ❤️ ================================================ FILE: SECURITY.md ================================================ # Security Policy 🔒 ## Supported Versions The `main` branch of this repo is considered active and supported for all security concerns ## Reporting a Vulnerability If you discover a security vulnerability, please reach out in our [community Discord](https://discord.gg/WwTvNe356u) to report it. ================================================ FILE: additional.d.ts ================================================ declare const __COMMIT_HASH__: string; declare const __BRANCH_NAME__: string; declare module "*.svg" { export const ReactComponent: React.FunctionComponent>; const content: string; export default content; } declare module "*.svg?react" { const ReactComponent: React.FunctionComponent>; export default ReactComponent; } ================================================ FILE: dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "monthly" ignore: - dependency-name: "i18next" update-types: ["version-update:semver-major"] - dependency-name: "react" update-types: ["version-update:semver-major"] - dependency-name: "react-i18next" update-types: ["version-update:semver-minor"] - dependency-name: "react-router" update-types: ["version-update:semver-major"] - dependency-name: "react-router-dom" update-types: ["version-update:semver-major"] ================================================ FILE: i18next-parser.config.mjs ================================================ // i18next-parser.config.mjs const config = { contextSeparator: "_", // Key separator used in your translation keys createOldCatalogs: true, // Save the \_old files defaultNamespace: "translation", // Default namespace used in your i18next config defaultValue: (locale, namespace, key, value) => (value ? value : key), // Default value to give to keys with no value // You may also specify a function accepting the locale, namespace, key, and value as arguments indentation: 4, // Indentation of the catalog files keepRemoved: false, // Keep keys from the catalog that are no longer in code keySeparator: false, // Key separator used in your translation keys // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance. // see below for more details lexers: { hbs: ["HandlebarsLexer"], handlebars: ["HandlebarsLexer"], htm: ["HTMLLexer"], html: ["HTMLLexer"], mjs: ["JavascriptLexer"], js: ["JsxLexer"], // if you're writing jsx inside .mjs files, change this to JsxLexer ts: ["JavascriptLexer"], jsx: ["JsxLexer"], tsx: ["JsxLexer"], default: ["JavascriptLexer"], }, lineEnding: "auto", // Control the line ending. See options at https://github.com/ryanve/eol locales: ["de", "en", "fr", "it", "ja", "pl", "pt", "ru", "zh"], // An array of the locales in your applications namespaceSeparator: false, // Namespace separator used in your translation keys // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance. //output: 'public/translations/$LOCALE/$NAMESPACE.json', output: "src/translations/$LOCALE/$NAMESPACE.json", // Supports $LOCALE and $NAMESPACE injection // Supports JSON (.json) and YAML (.yml) file formats // Where to write the locale files relative to process.cwd() pluralSeparator: "_", // Plural separator used in your translation keys // If you want to use plain english keys, separators such as `_` might conflict. You might want to set `pluralSeparator` to a different string that does not occur in your keys. input: ["src/App.js", "src/pages/**/*.{js,jsx}", "src/components/**/*.{js,jsx}"], // An array of globs that describe where to look for source files // relative to the location of the configuration file sort: false, // Whether or not to sort the catalog. Can also be a [compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#parameters) verbose: false, // Display info about the parsing including some stats failOnWarnings: false, // Exit with an exit code of 1 on warnings failOnUpdate: false, // Exit with an exit code of 1 when translations are updated (for CI purpose) customValueTemplate: null, // If you wish to customize the value output the value as an object, you can set your own format. // ${defaultValue} is the default value you set in your translation function. // Any other custom property will be automatically extracted. // // Example: // { // message: "${defaultValue}", // description: "${maxLength}", // t('my-key', {maxLength: 150}) // } resetDefaultValueLocale: null, // The locale to compare with default values to determine whether a default value has been changed. // If this is set and a default value differs from a translation in the specified locale, all entries // for that key across locales are reset to the default value, and existing translations are moved to // the `_old` file. i18nextOptions: null, // If you wish to customize options in internally used i18next instance, you can define an object with any // configuration property supported by i18next (https://www.i18next.com/overview/configuration-options). // { compatibilityJSON: 'v3' } can be used to generate v3 compatible plurals. yamlOptions: null, // If you wish to customize options for yaml output, you can define an object here. // Configuration options are here (https://github.com/nodeca/js-yaml#dump-object---options-). // Example: // { // lineWidth: -1, // } }; export default config; ================================================ FILE: package.json ================================================ { "name": "tarkov.dev", "version": "0.0.0", "private": true, "type": "module", "imports": { "#src/*": "./src/*", "#scripts/*": "./scripts/*", "#public/*": "./public/*" }, "exports": "./index.js", "engines": { "node": ">=20" }, "scripts": { "analyze": "source-map-explorer 'build/static/js/*.js'", "prestart": "npm run prebuild", "start": "rsbuild start --open", "build": "rsbuild build", "test": "rstest", "prettier": "prettier --write \"src/**/*.{js,jsx,mjs,ts,tsx,json,css,scss,md}\"", "prebuild": "node scripts/update-props.mjs && node scripts/get-supported-languages.mjs && node scripts/get-contributors.mjs && node scripts/build-sitemap.mjs && node scripts/generate-thumbnails.mjs", "postbuild": "node scripts/build-redirects.mjs && node scripts/critical.mjs", "stage": "npx rimraf build && npm run build && npm run preview", "preview": "npx serve build -l 3001 -s", "critical": "node scripts/critical.mjs", "lint": "eslint src", "prepare": "husky" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@rsbuild/core": "^1.7.3", "@rsbuild/plugin-react": "^1.4.5", "@rsbuild/plugin-svgr": "^1.3.0", "@rstest/core": "^0.9.0", "@types/react-table": "^7.7.20", "eslint": "^8.57.1", "eslint-config-prettier": "^10.1.8", "eslint-config-react-app": "^7.0.1", "husky": "^9.1.7", "lint-staged": "^16.3.2", "prettier": "^3.8.1", "sharp": "^0.34.5", "stylelint": "^17.4.0", "stylelint-config-standard": "^40.0.0", "typescript": "^5.9.3" }, "dependencies": { "@emotion/styled": "^11.14.1", "@marsidev/react-turnstile": "^1.4.2", "@mdi/js": "^7.4.47", "@mdi/react": "^1.6.1", "@mui/lab": "^7.0.0-beta.17", "@mui/material": "^7.3.9", "@mui/x-tree-view": "^8.27.2", "@reduxjs/toolkit": "^2.11.0", "@tanstack/react-query": "^5.90.21", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "clsx": "^2.1.1", "critical": "^7.2.0", "dayjs": "^1.11.19", "dotenv": "^17.3.1", "fast-deep-equal": "^3.1.3", "framer-motion": "^12.35.0", "fuse.js": "^7.1.0", "i18next": "^23.16.8", "i18next-browser-languagedetector": "^8.2.1", "i18next-http-backend": "^3.0.5", "intersection-observer": "^0.12.2", "jsonpath-plus": "^10.4.0", "leaflet": "^1.9.4", "leaflet-fullscreen": "^1.0.2", "lodash.debounce": "^4.0.8", "lz-string": "^1.5.0", "react": "^18.3.1", "react-cookie-consent": "^10.0.1", "react-countdown": "^2.3.6", "react-dom": "^18.3.1", "react-error-boundary": "^6.1.1", "react-helmet": "^6.1.0", "react-hotkeys-hook": "^5.2.4", "react-i18next": "^15.4.1", "react-intersection-observer": "^10.0.3", "react-redux": "^9.2.0", "react-router-dom": "^6.30.3", "react-router-hash-link": "^2.4.3", "react-select": "^5.10.2", "react-simple-image-viewer": "1.2.2", "react-spinners": "^0.17.0", "react-syntax-highlighter": "^16.1.1", "react-table": "^7.8.0", "react-zoom-pan-pinch": "^3.7.0", "resize-observer-polyfill": "^1.5.1", "source-map-explorer": "^2.5.3", "victory": "^37.3.6" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest", "prettier" ], "ignorePatterns": [ "*.html", "public/**/*.html", "build/**/*.html" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "lint-staged": { "*.css": [ "stylelint --fix", "prettier --write --ignore-unknown" ], "*.{js,jsx,mjs,ts,tsx}": [ "eslint --fix", "prettier --write --ignore-unknown" ] } } ================================================ FILE: prettier.config.mjs ================================================ /** * @see https://prettier.io/docs/configuration * @type {import("prettier").Config} */ const config = { printWidth: 120, singleQuote: false, trailingComma: "all", tabWidth: 4, quoteProps: "consistent", }; export default config; ================================================ FILE: public/browserconfig.xml ================================================ #2d2d2f ================================================ FILE: public/data/.gitignore ================================================ * !.gitignore ================================================ FILE: public/index.html ================================================ Tarkov.dev
================================================ FILE: public/robots.txt ================================================ User-agent: * Allow: / Sitemap: https://tarkov.dev/sitemap_index.xml ================================================ FILE: public/site.webmanifest ================================================ { "name": "Tarkov.dev", "short_name": "Tarkov.dev", "icons": [ { "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" } ], "theme_color": "#2d2d2f", "background_color": "#2d2d2f", "start_url": "https://tarkov.dev", "display": "standalone" } ================================================ FILE: rsbuild.config.ts ================================================ import { defineConfig } from "@rsbuild/core"; import { pluginReact } from "@rsbuild/plugin-react"; import { pluginSvgr } from "@rsbuild/plugin-svgr"; import { execSync } from "node:child_process"; const commitHash = execSync("git rev-parse --short HEAD").toString().trim(); export default defineConfig({ plugins: [pluginReact(), pluginSvgr({ mixedImport: true })], server: { base: process.env.PUBLIC_URL, }, source: { define: { "process.env.RSTEST": process.env.RSTEST, "__COMMIT_HASH__": JSON.stringify(commitHash), }, }, html: { template: "./public/index.html", }, output: { distPath: { root: "build", }, }, }); ================================================ FILE: rstest.config.ts ================================================ import { defineConfig } from "@rstest/core"; import rsbuildConfig from "./rsbuild.config"; export default defineConfig({ ...rsbuildConfig, testEnvironment: "jsdom", globals: true, setupFiles: ["./rstest.setup.ts"], }); ================================================ FILE: rstest.setup.ts ================================================ import "dotenv/config"; import "@testing-library/jest-dom"; import { resetIntersectionMocking, setupIntersectionMocking } from "react-intersection-observer/test-utils"; import { afterEach, beforeEach, rstest } from "@rstest/core"; beforeEach(() => { setupIntersectionMocking(rstest.fn); }); afterEach(() => { resetIntersectionMocking(); }); ================================================ FILE: scripts/build-redirects.mjs ================================================ import fs from "fs"; import path from "path"; import url from "url"; (async () => { let redirects; try { redirects = await fetch("https://manager.tarkov.dev/data/redirects.json").then((response) => response.json()); } catch (redirectsError) { console.error(redirectsError); process.exit(1); } const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); let indexTemplate = fs.readFileSync(path.join(__dirname, "..", "workers-site", "index-template.js"), "utf8"); indexTemplate = indexTemplate.replace("REDIRECTS_DATA", JSON.stringify(redirects, null, 4)); console.time("Write new data"); fs.writeFileSync(path.join(__dirname, "..", "workers-site", "index.js"), indexTemplate); console.timeEnd("Write new data"); })(); ================================================ FILE: scripts/build-sitemap.mjs ================================================ import { writeFileSync } from "fs"; import path from "path"; import { fileURLToPath } from "url"; import { createGzip } from "zlib"; import { pipeline } from "stream"; import { createReadStream, createWriteStream, unlink } from "fs"; import maps from "../src/data/maps.json" with { type: "json" }; import categoryPages from "../src/data/category-pages.json" with { type: "json" }; import { caliberArrayWithSplit } from "../src/modules/format-ammo.mjs"; //import apiRequest from "../src/modules/api-request.mjs"; const standardPaths = [ "", "/ammo", "/barters", "/hideout-profit", "/loot-tier", "/trader/prapor", "/trader/therapist", "/trader/skier", "/trader/fence", "/trader/peacekeeper", "/trader/mechanic", "/trader/ragman", "/trader/jaeger", "/trader/lightkeeper", "/wipe-length", "/bitcoin-farm-calculator", ]; const standardPathsWeekly = [ "/about", "/api", "/api-users", "/control", "/items", "/maps", "/moobot", "/nightbot", "/settings", "/streamelements", "/traders", "/bosses", "/tasks", "/hideout", ]; const languages = ["de", "en", "fr", "it", "ja", "pl", "pt", "ru"]; const addPath = (sitemap, url, change = "hourly") => { for (const lang in languages) { sitemap = `${sitemap} `; if (Object.hasOwnProperty.call(languages, lang)) { const loclang = languages[lang]; if (loclang === "en") { sitemap = `${sitemap} https://tarkov.dev${url}`; } else { sitemap = `${sitemap} https://tarkov.dev${url}?lng=${loclang}`; } for (const lang in languages) { if (Object.hasOwnProperty.call(languages, lang)) { const hreflang = languages[lang]; if (hreflang === "en") { sitemap = `${sitemap} `; } else { sitemap = `${sitemap} `; } } } } sitemap = `${sitemap} ${change} `; } return sitemap; }; const apiRequest = (path) => { return fetch(`https://json.tarkov.dev/${path}`, { cache: "no-cache", headers: { Accept: "application/json", }, }).then((response) => { if (!response.ok) { return Promise.reject(new Error(`${response.status} ${response.statusText}`)); } return response.json().then((json) => json.data); }); }; async function build_sitemap() { let sitemap = ` `; for (const path of standardPaths) { sitemap = addPath(sitemap, path); } for (const path of standardPathsWeekly) { sitemap = addPath(sitemap, path, "weekly"); } for (const mapsGroup of maps) { for (const map of mapsGroup.maps) { sitemap = addPath(sitemap, `/map/${map.key}`, "weekly"); } } const itemResponse = await apiRequest("regular/items"); const itemCategories = Object.values(itemResponse.itemCategories); for (const itemCategory of itemCategories) { sitemap = addPath(sitemap, `/items/${itemCategory.normalizedName}`); } const itemHandbookCategories = Object.values(itemResponse.handbookCategories); for (const itemCategory of itemHandbookCategories) { sitemap = addPath(sitemap, `/items/handbook/${itemCategory.normalizedName}`); } for (const categoryPage of categoryPages) { sitemap = addPath(sitemap, `/items/${categoryPage.key}`); } const mapsResponse = await apiRequest("regular/maps"); const allBosses = Object.values(mapsResponse.mobs); for (const boss of allBosses) { sitemap = addPath(sitemap, `/boss/${boss.normalizedName}`); } const tasksResponse = await apiRequest("regular/tasks"); const allTasks = Object.values(tasksResponse.tasks); for (const task of allTasks) { sitemap = addPath(sitemap, `/task/${task.normalizedName}`, "weekly"); } const ammoTypes = caliberArrayWithSplit(); for (const ammoType of ammoTypes) { sitemap = addPath(sitemap, `/ammo/${ammoType.replace(/ /g, "%20")}`); } sitemap = `${sitemap} `; const __dirname = fileURLToPath(new URL(".", import.meta.url)); writeFileSync(path.join(__dirname, "..", "public", "sitemap.xml"), sitemap); } async function build_sitemap_items() { let sitemap = ` `; const itemsResponse = await apiRequest("regular/items"); const allItems = Object.values(itemsResponse.items); for (const item of allItems) { sitemap = addPath(sitemap, `/item/${item.normalizedName}`); } sitemap = `${sitemap} `; const __dirname = fileURLToPath(new URL(".", import.meta.url)); writeFileSync(path.join(__dirname, "..", "public", "sitemap_items.xml"), sitemap); const gzip = createGzip(); const source = createReadStream(path.join(__dirname, "..", "public", "sitemap_items.xml")); const destination = createWriteStream(path.join(__dirname, "..", "public", "sitemap_items.xml.gz")); pipeline(source, gzip, destination, (err) => { if (err) { console.error("An error occurred:", err); process.exitCode = 1; } unlink(path.join(__dirname, "..", "public", "sitemap_items.xml"), (err) => { if (err) { throw err; } console.log("successfully deleted sitemap_items.xml"); }); }); } async function build_sitemap_index() { let sitemap = ` https://tarkov.dev/sitemap.xml https://tarkov.dev/sitemap_items.xml.gz `; const __dirname = fileURLToPath(new URL(".", import.meta.url)); writeFileSync(path.join(__dirname, "..", "public", "sitemap_index.xml"), sitemap); } (async () => { try { console.time("build-sitemap"); await build_sitemap(); await build_sitemap_items(); await build_sitemap_index(); console.timeEnd("build-sitemap"); } catch (error) { console.error(error); console.log("trying to use pre-built sitemap (offline mode?)"); } })(); ================================================ FILE: scripts/critical.mjs ================================================ import * as critical from "critical"; critical.generate( { base: "build/", src: "./index.html", inline: true, css: ["build/static/css/*.css"], target: "index.html", }, (err, output) => { if (err) { console.error(err); } else if (output) { console.log("Generated critical CSS"); } }, ); ================================================ FILE: scripts/custom-loader.mjs ================================================ import { URL } from "url"; import { readFile } from "fs/promises"; /** * This function forces .mjs files to be loades as ES modules * so the default export is a string containing the CSS stylesheet. */ export async function load(url, context, defaultLoad) { if (context.format !== "commonjs") { return defaultLoad(url, context, defaultLoad); } const forceConvert = [ "do-fetch-items.mjs", "do-fetch-barters.mjs", "do-fetch-crafts.mjs", "do-fetch-hideout.mjs", "do-fetch-maps.mjs", "do-fetch-meta.mjs", "do-fetch-traders.mjs", "do-fetch-quests.mjs", "do-fetch-bosses.mjs", "flea-market-fee.mjs", "camelcase-to-dashes.mjs", "graphql-request.mjs", "api-query.mjs", ]; for (const fileName of forceConvert) { if (url.endsWith(fileName)) { const content = await readFile(new URL(url)); return { format: "module", source: content, shortCircuit: true, }; } } return defaultLoad(url, context, defaultLoad); } ================================================ FILE: scripts/generate-thumbnails.mjs ================================================ import fs from "fs/promises"; import sharp from "sharp"; (async () => { console.time("Generating thumbnails"); // Max height from css ".map-wrapper img" const maxHeight = 200; const mapsPath = "./public/maps/"; const files = await fs.readdir(mapsPath); for (const fileName of files) { if (!fileName.endsWith(".jpg")) { continue; } if (fileName.endsWith("_thumb.jpg")) { continue; } const thumbName = fileName.replace(".jpg", "_thumb.jpg"); console.log(`Generating ${thumbName}`); const image = sharp(mapsPath + fileName) .resize(null, maxHeight) .jpeg({ mozjpeg: true, quality: 90 }); await image.toFile(mapsPath + thumbName); } /*const mapGroups = JSON.parse(await fs.readFile('./src/data/maps.json')); for (const group of mapGroups) { for (const map of group.maps) { if (map.projection !== 'interactive') continue; let path = map.tilePath || map.svgPath || `https://assets.tarkov.dev/maps/${group.normalizedName}/{z}/{x}/{y}.png`; path = path.replace(/{[xyz]}/g, '0'); const thumbName = `${group.normalizedName}_thumb.jpg`; try { const imageRequest = await fetch(path); console.log(`Generating ${thumbName}`); const image = sharp(await imageRequest.arrayBuffer()).trim('#00000000').resize(null, maxHeight).jpeg({mozjpeg: true, quality: 90}); await image.toFile(mapsPath+thumbName); if (map.altMaps) { for (const altKey of map.altMaps) { await image.toFile(mapsPath+`${altKey}_thumb.jpg`); } } } catch (error) { console.error(error) console.log(`Asset for ${thumbName} unavailable`) } } }*/ console.timeEnd("Generating thumbnails"); })(); ================================================ FILE: scripts/generate_api-users_thumbs_macOS.sh ================================================ #!/bin/bash # Max height from css ".api-users-page-wrapper img" HEIGHT=150 cd ../public/images/api-users/ # Remove old thumbs rm *_thumb.jpg rm *_thumb.png for IMAGE in ./*.jpg ./*.png; do ORIG_HEIGHT=$(sips -g pixelHeight "$IMAGE" | grep -o '[0-9]*$') # New name for the thumb ORIGINAL=$(basename "$IMAGE") EXTENSION="${ORIGINAL##*.}" FILENAME="${ORIGINAL%.*}" NEW_FILENAME="./${FILENAME}_thumb.${EXTENSION}" if [[ $ORIG_HEIGHT -le $HEIGHT ]] then #copy the original cp "$IMAGE" "$NEW_FILENAME" else #resizing to max height sips --resampleHeight $HEIGHT "$IMAGE" --out "$NEW_FILENAME" fi done ================================================ FILE: scripts/generate_items_thumbs.mjs ================================================ import fs from "fs"; import path from "path"; import sharp from "sharp"; import { exit } from "process"; //import apiRequest from "../src/modules/api-request.mjs"; import categoryPages from "../src/data/category-pages.json" with { type: "json" }; const ignoredCategories = [ "headsets", "helmets", "glasses", "armors", "rigs", "backpacks", "guns", // 'mods', "pistol-grips", "suppressors", "grenades", "containers", "barter-items", "keys", "provisions", ]; const apiRequest = (path) => { return fetch(`https://json.tarkov.dev/${path}`, { cache: "no-cache", headers: { Accept: "application/json", }, }).then((response) => { if (!response.ok) { return Promise.reject(new Error(`${response.status} ${response.statusText}`)); } return response.json().then((json) => json.data); }); }; function shuffle(array) { let currentIndex = array.length; let randomIndex; // While there remain elements to shuffle. while (currentIndex > 0) { // Pick a remaining element. randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; // And swap it with the current element. [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]]; } return array; } (async () => { try { console.time("Generating thumbnails"); const maxWidth = 256; const maxHeight = 144; const mapsPath = "./public/images/items/"; const allItems = await apiRequest("regular/items"); for (const categoryPage of categoryPages) { if (ignoredCategories.includes(categoryPage.key)) { continue; } const originalImg = await sharp(mapsPath + categoryPage.key + "-table.png"); const metadata = await originalImg.metadata(); const scale = metadata.width / maxWidth; const cropHeight = Math.ceil(scale * maxHeight); const itemWidth = metadata.width / 2; const itemHeight = cropHeight / 2; const croppedImage = originalImg.extract({ left: 0, top: 0, width: metadata.width, height: cropHeight }); // const croppedImage = await sharp({ // create: { // width: metadata.width, // height: cropHeight, // channels: 4, // background: { r: 45, g: 45, b: 47, alpha: 1.0 } // } // }).png(); const items = Object.values(allItems.items).filter((i) => i.types.includes(categoryPage.type)); shuffle(items); const itemResize = { width: itemWidth, height: itemHeight, fit: sharp.fit.contain, background: { r: 255, g: 255, b: 255, alpha: 0.0 }, }; const itemRotate = 0; //7 + Math.random()*4-2; const tlImageFetch = await fetch(items[0].image512pxLink); const tlImageBuffer = await tlImageFetch.buffer(); const tlImage = await sharp(tlImageBuffer).resize(itemResize).rotate(-itemRotate).toBuffer(); const trImageFetch = await fetch(items[1].image512pxLink); const trImageBuffer = await trImageFetch.buffer(); const trImage = await sharp(trImageBuffer).resize(itemResize).rotate(itemRotate).toBuffer(); const blImageFetch = await fetch(items[2].image512pxLink); const blImageBuffer = await blImageFetch.buffer(); const blImage = await sharp(blImageBuffer).resize(itemResize).rotate(itemRotate).toBuffer(); const brImageFetch = await fetch(items[3].image512pxLink); const brImageBuffer = await brImageFetch.buffer(); const brImage = await sharp(brImageBuffer).resize(itemResize).rotate(-itemRotate).toBuffer(); const cImageFetch = await fetch(items[4].image512pxLink); const cImageBuffer = await cImageFetch.buffer(); const cImage = await sharp(cImageBuffer).resize(itemResize).toBuffer(); const composedImage = await croppedImage .blur(6) .composite([ { input: tlImage, gravity: "northwest", blend: "over" }, { input: trImage, gravity: "northeast", blend: "over" }, { input: blImage, gravity: "southwest", blend: "over" }, { input: brImage, gravity: "southeast", blend: "over" }, { input: cImage, gravity: "centre", blend: "over" }, ]) .toBuffer(); const finalImage = await sharp(composedImage) .resize(maxWidth, maxHeight) .jpeg({ mozjpeg: true, quality: 100 }); // const finalImage = await sharp(composedImage).jpeg({mozjpeg: true, quality: 90}); await finalImage.toFile(mapsPath + categoryPage.key + "-table_thumb.jpg"); console.log(`Generated thumbnail for ${categoryPage.key}`); // return; } console.timeEnd("Generating thumbnails"); } catch (error) { console.error(error); console.log("error generating thumbnail (offline mode?)"); } })(); ================================================ FILE: scripts/generate_items_thumbs_macOS.sh ================================================ #!/bin/bash # Max height and width HEIGHT=144 WIDTH=256 cd ../public/images/items/ # Remove old thumbs rm *_thumb.jpg rm *_thumb.png for IMAGE in ./*.png do ORIG_HEIGHT=$(sips -g pixelHeight "$IMAGE" | grep -o '[0-9]*$') ORIG_WIDTH=$(sips -g pixelWidth "$IMAGE" | grep -o '[0-9]*$') # New name for the thumb ORIGINAL=$(basename "$IMAGE") EXTENSION="${ORIGINAL##*.}" FILENAME="${ORIGINAL%.*}" NEW_FILENAME="./${FILENAME}_thumb.jpg" # Resizing to max height sips -s format jpeg -s formatOptions 70 --resampleWidth $WIDTH "$IMAGE" --out "$NEW_FILENAME" # Leave here as a reminder: # Without cropOffset it crops at center, but with 0 0 it also crops at center. # But if you try to offset from center with something like this: #RESIZED_HEIGHT=$(sips -g pixelHeight "$NEW_FILENAME" | grep -o '[0-9]*$') #CROP_OFFSET_Y=$(($HEIGHT - $RESIZED_HEIGHT)) # it now crops from top-left... # So a true crop from top-left is impossible, you always need to lose at least one pixel... sips --cropOffset 1 0 --cropToHeightWidth $HEIGHT $WIDTH "$NEW_FILENAME" --out "$NEW_FILENAME" done ================================================ FILE: scripts/generate_known_icons_macOS.sh ================================================ #!/bin/bash # Max height and width HEIGHT=64 WIDTH=64 CWD="$(pwd)" cd ../public/images/traders/ # Remove old icons rm *-icon.jpg for IMAGE in ./*portrait.png do ORIG_HEIGHT=$(sips -g pixelHeight "$IMAGE" | grep -o '[0-9]*$') ORIG_WIDTH=$(sips -g pixelWidth "$IMAGE" | grep -o '[0-9]*$') # New name for the icon ORIGINAL=$(basename "$IMAGE") EXTENSION="${ORIGINAL##*.}" FILENAME="${ORIGINAL%.*}" FILENAME="${FILENAME//-portrait/}" NEW_FILENAME="./$FILENAME-icon.jpg" # Resizing to max height sips -s format jpeg -s formatOptions 100 --resampleWidth $WIDTH "$IMAGE" --out "$NEW_FILENAME" done cd $CWD cd ../public/images/bosses/ # Remove old icons rm *-icon.jpg for IMAGE in ./*portrait.png do ORIG_HEIGHT=$(sips -g pixelHeight "$IMAGE" | grep -o '[0-9]*$') ORIG_WIDTH=$(sips -g pixelWidth "$IMAGE" | grep -o '[0-9]*$') # New name for the icon ORIGINAL=$(basename "$IMAGE") EXTENSION="${ORIGINAL##*.}" FILENAME="${ORIGINAL%.*}" FILENAME="${FILENAME//-portrait/}" NEW_FILENAME="./$FILENAME-icon.jpg" # Resizing to max height sips -s format jpeg -s formatOptions 100 --resampleWidth $WIDTH "$IMAGE" --out "$NEW_FILENAME" done ================================================ FILE: scripts/get-contributors.mjs ================================================ import fs from "fs"; import path from "path"; import url from "url"; const repositories = [ "the-hideout/tarkov-dev", "the-hideout/stash", "the-hideout/tarkov-api", "the-hideout/cloudflare", "the-hideout/tarkov-data-manager", "the-hideout/cache", "the-hideout/status", "the-hideout/tarkov-dev-image-generator", "the-hideout/tarkov-dev-svg-maps", ]; // If a GitHub token is provided, use it to increase the rate limit const token = process.env.GITHUB_TOKEN; const headers = {}; if (token) { headers.authorization = `token ${token}`; console.log("Using provided GitHub token to increase rate limit"); } else { console.log("No GitHub token provided, rate limit may be reached"); console.warn("To increase the rate limit, provide a GitHub token via the GITHUB_TOKEN environment variable"); } async function getContributors(repository) { console.time(`get contributors to ${repository}`); let responseJson = []; let contributors = []; try { const response = await fetch(`https://api.github.com/repos/${repository}/contributors`, { headers, signal: AbortSignal.timeout(5000), }); if (!response.ok) { console.error(`Error! status: ${response.status} message: ${response.statusText}`); } else { responseJson = await response.json(); } for (const contributor of responseJson) { if (contributor.type !== "User") { continue; } contributors.push({ login: contributor.login, html_url: contributor.html_url, avatar_url: contributor.avatar_url, contributions: contributor.contributions, }); } } catch (responseError) { console.error(`Error: ${responseError.message}`); } console.timeEnd(`get contributors to ${repository}`); return contributors; } (async () => { console.log("Loading contributors"); let allContributors = []; const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const contributorsPath = path.join(__dirname, "..", "src", "data", "contributors.json"); try { let allRepContributors = []; for (const repository of repositories) { const contributosArr = await getContributors(repository); if (!contributosArr) { console.log(`Error fetching contributors of ${repository}`); continue; } allRepContributors.push(...contributosArr); } // Calculate total contributions by user const totalRepContributors = allRepContributors.reduce((acc, { login, contributions }) => { if (!acc[login]) { acc[login] = 0; } acc[login] += contributions; return acc; }, {}); // Add total contributions field to each object allContributors = Object.entries(totalRepContributors) .map(([login, totalContributions]) => { const { html_url, avatar_url } = allRepContributors.find((contributor) => contributor.login === login); return { login, html_url, avatar_url, totalContributions, }; }) .sort((a, b) => { let compare = b.totalContributions - a.totalContributions; if (compare !== 0) { return compare; } return a.login.localeCompare(b.login); }); } catch (error) { // If we're running in CI and a failure occurs, use fallback data for contributors if (process.env.CI === "true") { console.log(`error in CI: ${error}`); } else { console.log(`error fetching contributors: ${error}`); } } if (allContributors.length === 0) { console.log("using fallback contributors.json (offline mode?)"); try { const existing = JSON.parse(fs.readFileSync(contributorsPath, "utf-8")); if (Array.isArray(existing) && existing.length > 0) { allContributors = existing; } } catch (readError) { console.warn(`Unable to read existing contributors.json fallback: ${readError}`); } if (allContributors.length === 0) { allContributors = [ { login: "hideout-bot", html_url: "https://github.com/hideout-bot", avatar_url: "https://avatars.githubusercontent.com/u/121582168?v=4", totalContributions: 9000, }, ]; } } else { console.log(`Total contributors: ${allContributors.length}`); console.time("Write new data"); const stringifyed = JSON.stringify(allContributors, null, 4); fs.writeFileSync(contributorsPath, stringifyed); console.timeEnd("Write new data"); } })(); ================================================ FILE: scripts/get-supported-languages.mjs ================================================ import fs from "fs"; import apiRequest from "../src/modules/api-request.mjs"; try { const endpoints = await apiRequest("endpoints"); const allLangs = endpoints.languages; fs.writeFileSync("./src/data/supported-languages.json", JSON.stringify(allLangs, null, 4)); } catch (error) { if (process.env.CI) { throw error; } else { console.log(error); console.log("attempting to get supported languages (offline mode?)"); } } ================================================ FILE: scripts/test-redirects.mjs ================================================ import fs from "fs"; import path from "path"; import url from "url"; import redirects from "../workers-site/redirects.json"; (async () => { let liveNames = []; try { const response = await fetch("https://json.tarkov.dev/regular/items", { method: "POST", cache: "no-store", headers: { "Content-Type": "application/json", "Accept": "application/json", }, body: JSON.stringify({ query: `{ itemsByType(type: any){ normalizedName } }`, }), }).then((response) => response.json()); liveNames = Object.values(response.data.items).map((item) => item.normalizedName); } catch (loadError) { console.error(loadError); return false; } const keys = Object.keys(redirects); for (const key of keys) { const itemName = key.replace("/item/", ""); if (!liveNames.includes(itemName)) { continue; } console.log(`${key} `); Reflect.deleteProperty(redirects, key); } const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); fs.writeFileSync(path.join(__dirname, "..", "workers-site", "redirects.json"), JSON.stringify(redirects, null, 4)); })(); ================================================ FILE: scripts/update-props.mjs ================================================ import fs from "fs"; import path from "path"; import url from "url"; const files = [ //'item-props', "item-grids", //'globals', //'item_presets', ]; for (const file of files) { const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const props = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "src", "data", `${file}.json`))); fs.writeFileSync(path.join(__dirname, "..", "public", "data", `${file}.min.json`), JSON.stringify(props)); } ================================================ FILE: src/App.css ================================================ @import url("./styles/singleEntity.css"); @import url("./styles/mapSearch.css"); /* Variables start */ :root { --color-black: #000; --color-black-light: #1b1919; --color-white: #fff; --color-gunmetal: #383945; --color-gunmetal-dark: #2d2d2f; --color-gold-one: #c7c5b3; --color-gold-two: #9a8866; --color-blue-light: #0292c0; --color-gray: #424242; --color-gray-light: #636363; --color-green: #00a700; --color-green-light: #6a9a66; --color-orange: #ca8a00; --color-red: #cd1e2f; --color-red-light: #9a6666; --color-purple: #8c6edf; --color-yellow: #ffe084; --color-yellow-light: #e0dfd6; } .desc-line-break { margin-top: 2rem; margin-bottom: 2rem; width: 50%; } body { background-color: var(--color-gunmetal-dark); background-image: url("images/background-1.png"); color: var(--color-gold-one); margin: 0; padding: 0; height: 100%; font-family: "bender", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", "Arial", sans-serif; font-style: normal; font-weight: 400; font-size: 16px; word-spacing: 1px; text-size-adjust: 100%; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; } code { font-family: "source-code-pro", "Menlo", "Monaco", "Consolas", "Courier New", monospace; } body * { box-sizing: border-box; } iframe { border: 0; height: 100%; width: 100%; } input, select, button { border-radius: 0; font-family: inherit; } button, input[type="submit"] { background-color: var(--color-gold-two); border: 0; color: var(--color-black); height: 40px; padding: 0; } input[type="text"], input[type="number"] { padding: 12px; max-height: 40px; border: 2px solid var(--color-gold-two); background-color: var(--color-gunmetal-dark); color: var(--color-gold-one); } input[type="text"]:focus, input[type="number"]:focus { outline: none; border: 2px solid var(--color-gold-one); } input[type="text"].number { width: 80px; } input[name="session-id"] { padding-left: 20px; } select { padding: 10px; margin-bottom: 2vh; } a { color: var(--color-gold-two); text-decoration: none; } a:hover { text-decoration: underline; text-underline-offset: 2px; } cite { display: block; font-size: 14px; } .display-wrapper { height: var(--display-height); min-height: 80vh; margin: 0 10px; position: relative; } .page-wrapper { margin: 0 10px; max-width: 1200px; /* min-height: 80vh; */ } .updated-label { color: var(--color-gold-one); font-size: 10px; left: 4px; position: absolute; top: 2px; } .time-wrapper { background-color: rgb(from var(--color-black) r g b / 0.5); padding: 10px 20px; position: absolute; right: -10px; top: 0; z-index: 1005; text-align: right; } .time-wrapper a { color: inherit; } .time-wrapper div { font-family: "source-code-pro", "Menlo", "Monaco", "Consolas", "Courier New", monospace; } .map-image-wrapper { height: var(--display-height); width: 98vw; display: flex; align-items: center; justify-content: center; } .map-image { max-height: 100%; max-width: 100%; object-fit: contain; } .icon-with-text { vertical-align: middle; margin-right: 8px; margin-left: 8px; } .icon-with-text-hidden { visibility: hidden; } .center-title { text-align: center; } .screen-link { margin-left: 8px; margin-right: 8px; display: flex; flex-direction: column; align-items: center; } .screen-link-icon { vertical-align: middle; margin-right: 8px; } .price-wrapper { color: var(--color-gold-one); font-size: 14px; } .price-wrapper-tool { color: var(--color-blue-light); font-size: 14px; } .page-headline-wrapper { display: flex; align-items: center; max-width: 1200px; margin: auto; white-space: nowrap; } .page-headline-wrapper h1 { flex-grow: 1; text-align: center; white-space: initial; display: inline-flex; } .wiki-link-wrapper { font-size: larger; } .hr-muted { margin-top: 2rem; border-bottom: 1px solid var(--color-gold-two); width: 80%; opacity: 0.4; } .hr-muted-full { margin-top: 2rem; border-bottom: 1px solid var(--color-gold-two); width: 100%; opacity: 0.4; } /* Global reuseable styles, specific to the Tarkov.Dev style */ .information-section { background: rgb(from var(--color-black) r g b / 0.1); border: 1px solid rgb(from var(--color-white) r g b/ 0.1); border-radius: 0 20px 0 20px; margin-bottom: 50px; overflow: hidden; } .information-section.has-table { border-radius: 0 20px 0 0; } .information-section h2 { display: flex; align-items: center; font-size: 24px; margin: 0; padding: 15px 20px; color: var(--color-gold-one); background: rgb(from var(--color-black) r g b / 0.3); border-bottom: 1px solid rgb(from var(--color-white) r g b / 0.1); } .information-section h2 svg { width: 1.6rem !important; height: auto !important; margin: 0 12px 0 0; } .information-section .content { padding: 20px; } .information-section .content p { margin: 0; } .filter-wrapper.open { z-index: 2; } .level-locked { color: var(--color-red); } @media screen and (width >= 800px) { .control-wrapper { display: none; } .page-headline-wrapper h1 { flex-grow: 1; text-align: left; } } @media screen and (width >= 1280px) { .page-wrapper { margin: 0 auto; } } @media screen and (width >= 1920px) { .page-wrapper { margin: 0 auto; max-width: 1600px; } } ================================================ FILE: src/App.jsx ================================================ /* eslint-disable no-restricted-globals */ import React, { useEffect, useCallback, useRef, Suspense } from "react"; import { Routes, Route, useNavigate, Navigate } from "react-router-dom"; import { Helmet } from "react-helmet"; import { useDispatch, useSelector } from "react-redux"; import CookieConsent from "react-cookie-consent"; import { ErrorBoundary } from "react-error-boundary"; import { ThemeProvider } from "@mui/material/styles"; import "./App.css"; import theme from "./modules/mui-theme.mjs"; import i18n from "./i18n.js"; import loadPolyfills from "./modules/polyfills.js"; import RemoteControlId from "./components/remote-control-id/index.jsx"; import { fetchTarkovTrackerProgress, setPlayerPosition } from "./features/settings/settingsSlice.mjs"; import { setConnectionStatus, enableConnection } from "./features/sockets/socketsSlice.js"; import useStateWithLocalStorage from "./hooks/useStateWithLocalStorage.jsx"; import makeID from "./modules/make-id.js"; import WindowFocusHandler from "./modules/window-focus-handler.mjs"; import RemoteWebSocket from "./modules/remote-websocket.mjs"; import Loading from "./components/loading/index.jsx"; import supportedLanguages from "./data/supported-languages.json"; import Menu from "./components/menu/index.jsx"; import Footer from "./components/footer/index.tsx"; const Map = React.lazy(() => import("./pages/map/index.jsx")); const ErrorPage = React.lazy(() => import("./pages/error-page/index.jsx")); const Debug = React.lazy(() => import("./components/Debug.jsx")); const Ammo = React.lazy(() => import("./pages/ammo/index.jsx")); const Control = React.lazy(() => import("./pages/control/index.jsx")); const LootTiers = React.lazy(() => import("./pages/loot-tiers/index.jsx")); const Barters = React.lazy(() => import("./pages/barters/index.jsx")); const Maps = React.lazy(() => import("./pages/maps/index.jsx")); const Crafts = React.lazy(() => import("./pages/crafts/index.jsx")); const Item = React.lazy(() => import("./pages/item/index.jsx")); const Start = React.lazy(() => import("./pages/start/index.jsx")); const Settings = React.lazy(() => import("./pages/settings/index.jsx")); const Nightbot = React.lazy(() => import("./pages/nightbot/index.jsx")); const StreamElements = React.lazy(() => import("./pages/stream-elements/index.jsx")); const ApiUsers = React.lazy(() => import("./pages/api-users/index.jsx")); const Moobot = React.lazy(() => import("./pages/moobot/index.jsx")); const Items = React.lazy(() => import("./pages/items/index.jsx")); const Armors = React.lazy(() => import("./pages/items/armors/index.jsx")); const Backpacks = React.lazy(() => import("./pages/items/backpacks/index.jsx")); const BarterItems = React.lazy(() => import("./pages/items/barter-items/index.jsx")); const Containers = React.lazy(() => import("./pages/items/containers/index.jsx")); const Glasses = React.lazy(() => import("./pages/items/glasses/index.jsx")); const Grenades = React.lazy(() => import("./pages/items/grenades/index.jsx")); const Guns = React.lazy(() => import("./pages/items/guns/index.jsx")); const Headsets = React.lazy(() => import("./pages/items/headsets/index.jsx")); const Helmets = React.lazy(() => import("./pages/items/helmets/index.jsx")); const Keys = React.lazy(() => import("./pages/items/keys/index.jsx")); const Mods = React.lazy(() => import("./pages/items/mods/index.jsx")); const PistolGrips = React.lazy(() => import("./pages/items/pistol-grips/index.jsx")); const Provisions = React.lazy(() => import("./pages/items/provisions/index.jsx")); const Rigs = React.lazy(() => import("./pages/items/rigs/index.jsx")); const Suppressors = React.lazy(() => import("./pages/items/suppressors/index.jsx")); const BsgCategory = React.lazy(() => import("./pages/items/bsg-category/index.jsx")); const HandbookCategory = React.lazy(() => import("./pages/items/handbook-category/index.jsx")); const BitcoinFarmCalculator = React.lazy(() => import("./pages/bitcoin-farm-calculator/index.jsx")); const Quests = React.lazy(() => import("./pages/quests/index.jsx")); const Quest = React.lazy(() => import("./pages/quest/index.jsx")); const Prestiges = React.lazy(() => import("./pages/prestige/list.jsx")); const Prestige = React.lazy(() => import("./pages/prestige/index.jsx")); const Bosses = React.lazy(() => import("./pages/bosses/index.jsx")); const Boss = React.lazy(() => import("./pages/boss/index.jsx")); const Traders = React.lazy(() => import("./pages/traders/index.jsx")); const Trader = React.lazy(() => import("./pages/trader/index.jsx")); const ItemTracker = React.lazy(() => import("./pages/item-tracker/index.jsx")); const Hideout = React.lazy(() => import("./pages/hideout/index.jsx")); const WipeLength = React.lazy(() => import("./pages/wipe-length/index.jsx")); const Achievements = React.lazy(() => import("./pages/achievements/index.jsx")); const Players = React.lazy(() => import("./pages/players/index.jsx")); const Player = React.lazy(() => import("./pages/player/index.jsx")); const PlayerForward = React.lazy(() => import("./pages/player/player-forward.jsx")); const Converter = React.lazy(() => import("./pages/converter/index.jsx")); const About = React.lazy(() => import("./pages/about/index.jsx")); const OtherTools = React.lazy(() => import("./pages/other-tools/index.jsx")); const TarkovMonitorPage = React.lazy(() => import("./pages/tarkov-monitor/index.js")); const StashBotPage = React.lazy(() => import("./pages/stash-bot/index.js")); const APIDocs = React.lazy(() => import("./pages/api-docs/index.jsx")); let socket = false; let socketMonitorInterval = false; loadPolyfills(); function Fallback({ error, resetErrorBoundary }) { let loadingChunkErrorMessage = ""; if (error.message.toLowerCase().includes("loading") && error.message.toLowerCase().includes("chunk")) { loadingChunkErrorMessage = (
This error is often caused by caching issues and can usually be resolved by{" "} .
); } return (

Something went wrong.

{error.message}
{error.stack}
{`${window.location}`}
{loadingChunkErrorMessage} You can{" "} {" "} or report the issue by joining our{" "} Discord {" "} server and copy/paste the above error and some details in{" "} #🐞bugs-issues {" "} channel.
); } function App() { const connectToId = new URLSearchParams(window.location.search).get("connection"); if (connectToId) { localStorage.setItem("sessionId", JSON.stringify(connectToId)); } const [sessionID] = useStateWithLocalStorage("sessionId", makeID(4)); const socketEnabled = useSelector((state) => state.sockets.enabled); const controlId = useSelector((state) => state.sockets.controlId); let navigate = useNavigate(); const dispatch = useDispatch(); const retrievedTarkovTrackerToken = useRef(false); const tarkovTrackerProgressInterval = useRef(false); const tarkovTrackerUpdatePending = useRef(false); const tabHasFocus = useRef(true); if (connectToId) { dispatch(enableConnection()); } const useTarkovTracker = useSelector((state) => state.settings[state.settings.gameMode].useTarkovTracker); const progressStatus = useSelector((state) => { return state.settings.progressStatus; }); const tarkovTrackerAPIKey = useSelector((state) => state.settings[state.settings.gameMode].tarkovTrackerAPIKey); const updateTarkovTrackerData = useCallback(() => { tarkovTrackerUpdatePending.current = false; retrievedTarkovTrackerToken.current = tarkovTrackerAPIKey; dispatch(fetchTarkovTrackerProgress(tarkovTrackerAPIKey)); }, [dispatch, tarkovTrackerAPIKey]); const scheduleTarkovTrackerUpdate = useCallback(() => { clearInterval(tarkovTrackerProgressInterval.current); tarkovTrackerProgressInterval.current = setInterval( () => { if (!tabHasFocus.current) { // window doesn't have focus, so postpone the update until it does tarkovTrackerUpdatePending.current = true; return; } updateTarkovTrackerData(); }, 1000 * 60 * 5, ); }, [updateTarkovTrackerData]); // monitor window focus for Tarkov Tracker updates useEffect(() => { const handleFocus = () => { tabHasFocus.current = true; if (!tarkovTrackerUpdatePending.current) { return; } scheduleTarkovTrackerUpdate(); updateTarkovTrackerData(); }; const handleBlur = () => { tabHasFocus.current = false; }; window.addEventListener("focus", handleFocus); window.addEventListener("blur", handleBlur); // Clean up return () => { window.removeEventListener("focus", handleFocus); window.removeEventListener("blur", handleBlur); }; }, [scheduleTarkovTrackerUpdate, updateTarkovTrackerData]); useEffect(() => { if (!tarkovTrackerProgressInterval.current && useTarkovTracker) { scheduleTarkovTrackerUpdate(); } if ( useTarkovTracker && progressStatus !== "loading" && retrievedTarkovTrackerToken.current !== tarkovTrackerAPIKey ) { updateTarkovTrackerData(); } if (tarkovTrackerProgressInterval.current && !useTarkovTracker) { clearInterval(tarkovTrackerProgressInterval.current); tarkovTrackerProgressInterval.current = false; } return () => { clearInterval(tarkovTrackerProgressInterval.current); tarkovTrackerProgressInterval.current = false; }; }, [progressStatus, scheduleTarkovTrackerUpdate, updateTarkovTrackerData, tarkovTrackerAPIKey, useTarkovTracker]); useEffect(() => { const connect = function connect() { dispatch(setConnectionStatus("connecting")); clearInterval(socketMonitorInterval); socket = new RemoteWebSocket(sessionID); socket.addEventListener("message", (rawMessage) => { const message = JSON.parse(rawMessage.data); if (message.type !== "command") { return; } if (message.data.type === "playerPosition") { dispatch(setPlayerPosition(message.data)); return; } navigate(`/${message.data.type}/${message.data.value}`); }); socket.addEventListener("open", () => { console.log("Connected to socket server"); //console.log(socket); dispatch(setConnectionStatus("connected")); }); socket.addEventListener("close", () => { console.log("Disconnected from socket server"); dispatch(setConnectionStatus("idle")); }); socketMonitorInterval = setInterval(() => { if (socket.readyState === 3 && socketEnabled) { console.log("Trying to re-connect to socket server"); connect(); } }, 5000); }; if (socket === false && socketEnabled) { connect(); } return () => { // socket.close(); // clearInterval(socketMonitorInterval); }; }, [socketEnabled, sessionID, navigate, dispatch]); const send = useCallback( (messageData) => { if (socket.readyState !== 1) { // Wait a bit if we're not connected setTimeout(() => { socket.send( JSON.stringify({ sessionID: controlId, ...messageData, }), ); }, 500); return true; } socket.send( JSON.stringify({ sessionID: controlId, ...messageData, }), ); }, [controlId], ); const hideRemoteControlId = useSelector((state) => state.settings.hideRemoteControl); const remoteControlSessionElement = hideRemoteControlId ? null : ( } key="suspense-connection-wrapper"> dispatch(enableConnection())} /> ); const alternateLangs = supportedLanguages.filter((lang) => lang !== i18n.language); return (
{alternateLangs.map((lang) => ( ))} {i18n.t("cookie-consent")} } key="suspense-start-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-ammo-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-ammo-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-maps-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-map-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-loot-tier-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-barters-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-items-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> , remoteControlSessionElement]} /> } key="suspense-helmets-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-glasses-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-armors-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-backpacks-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-rigs-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-suppressors-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-guns-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-mods-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-pistol-grips-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-barter-items-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-containers-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-grenades-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-headsets-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-keys-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-provisions-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-items-category-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-items-category-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-item-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-bosses-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-boss-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-traders-wrapper"> , remoteControlSessionElement, ]} /> , remoteControlSessionElement]} /> } key="suspense-trader-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-hideout-profit-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-item-tracker-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-debug-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-about-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-api-docs-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-nightbot-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-streamelements-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-moobot-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-api-users-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-hideout-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-wipe-length-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-bitcoin-farm-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-settings-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-control-wrapper"> , ]} /> } key="suspense-tasks-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-task-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-tasks-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-task-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-achievements-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-players-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-player-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-player-forward-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-converter-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-other-tools-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-tarkov-monitor-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-stash-wrapper"> , remoteControlSessionElement, ]} /> } key="suspense-errorpage-wrapper"> , remoteControlSessionElement, ]} />
); } export default App; ================================================ FILE: src/__tests__/App.test.jsx ================================================ import { expect, it } from "@rstest/core"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { waitFor, screen } from "@testing-library/react"; import React from "react"; import { mockAllIsIntersecting } from "react-intersection-observer/test-utils"; import App from "#src/App.jsx"; import { renderWithProviders } from "#src/__tests__/test-utils.js"; const queryClient = new QueryClient(); it("renders without crashing", async () => { mockAllIsIntersecting(true); renderWithProviders( , ); await waitFor(() => { expect(screen.getByRole("navigation")).toHaveClass("navigation"); }); }); ================================================ FILE: src/__tests__/test-utils.js ================================================ // https://redux.js.org/usage/writing-tests#components import React from "react"; import { render } from "@testing-library/react"; import { Provider } from "react-redux"; import { BrowserRouter as Router } from "react-router-dom"; import defaultStore from "#src/store"; export function renderWithProviders( ui, { preloadedState = {}, // Automatically create a store instance if no store was passed in store = defaultStore, ...renderOptions } = {}, ) { function Wrapper({ children }) { return ( {children} ); } return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) }; } ================================================ FILE: src/__tests__/tsconfig.json ================================================ { "compilerOptions": { "types": ["@testing-library/jest-dom", "@rstest/core/globals"] }, "extends": "../../tsconfig.json", "include": ["./"] } ================================================ FILE: src/components/Debug.jsx ================================================ import { useState } from "react"; function Debug() { const [itemId, setItemId] = useState("5eff09cd30a7dc22fd1ddfed"); return (
setItemId(e.target.value)} />
Nothing here
); } export default Debug; ================================================ FILE: src/components/FilterIcon.jsx ================================================ import { Component } from "react"; class FilterIcon extends Component { render() { return ( ); } } export default FilterIcon; ================================================ FILE: src/components/FleaMarketLoadingIcon.jsx ================================================ import { useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiTimerSand } from "@mdi/js"; import { Tooltip } from "@mui/material"; function FleaMarketLoadingIcon({ size = 1, tooltip }) { const { t } = useTranslation(); if (!tooltip) { tooltip = t("Flea market prices loading"); } return ( ); } export default FleaMarketLoadingIcon; ================================================ FILE: src/components/Graph.jsx ================================================ import { useCallback, useMemo } from "react"; import { VictoryChart, VictoryScatter, VictoryTheme, VictoryLegend, VictoryLine, VictoryLabel, VictoryAxis, // VictoryContainer, // VictoryTooltip, // VictoryVoronoiContainer, VictoryContainer, } from "victory"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; import Symbol from "./Symbol.jsx"; // import GraphLabel from './GraphLabel'; const MAX_DAMAGE = 170; const MAX_PENETRATION = 70; const styles = { classLabel: { fontSize: 3, fill: "#ddd", strokeWidth: 1, }, xaxis: { tickLabels: { fontSize: 5, }, grid: { stroke: "#555", }, axisLabel: { fontSize: 4, padding: 5, fill: "#ccc", }, }, yaxis: { tickLabels: { fill: "#fff", fontSize: 4, }, grid: { stroke: "#555", }, axisLabel: { fontSize: 4, padding: 5, fill: "#ccc", }, ticks: { size: 0, }, }, scatter: { labels: { fontSize: 2.5, fill: "#ccc", }, }, legend: { border: { stroke: "black", fill: "#2d2d2f", width: 37, }, labels: { fill: "#ccc", fontSize: 3, cursor: "pointer", }, title: { fill: "#ccc", fontSize: 4, padding: 2, }, }, annotionLine: { data: { stroke: "#888", strokeWidth: 0.5, strokeDasharray: 1, }, labels: { angle: -90, fill: "#ccc", fontSize: 3, }, }, }; const LegendLabel = (props) => { const { selectedDatumName, datum } = props; const style = useMemo(() => { let style = props.style; if (selectedDatumName.includes(datum.name)) { style = { ...props.style, textDecoration: "underline", fill: "#fff", }; } return style; }, [selectedDatumName, datum.name, props.style]); return ; }; export const getMarkerLine = (xMax, xTarget, label) => { if (xMax < xTarget + 1) { return null; } return ( } x={() => xTarget} /> ); }; // const getArmorLabel = (tier, yMax, xMax) => { // if(tier * 10 > yMax){ // return null; // } // return // }; const xTickValues = [ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, ]; const yTickValues = [10, 20, 30, 40, 50, 60, 70]; const chartAnimate = { duration: 500 }; const chartPadding = { top: 10, bottom: 20, right: 50, left: 10 }; // Use provided max domains if passed, otherwise fallback to defaults // Note: evaluated inside component to access props const Graph = (props) => { const { xMax, listState } = props; const navigate = useNavigate(); const handleLabelClick = useCallback( (event, data) => { navigate(`/item/${data.datum.id.toString()}`); }, [navigate], ); const { t } = useTranslation(); const chartMinDomain = { y: props.yMin ?? 0, x: props.xMin ?? 0 }; const markerLines = useMemo(() => { return [ getMarkerLine(xMax, 85, t("PMC & Scav Thorax HP")), getMarkerLine(xMax, 145, t("Reshala Thorax HP")), getMarkerLine(xMax, 160, t("Raider Thorax HP")), getMarkerLine(xMax, 180, t("Shturman Thorax HP")), getMarkerLine(xMax, 200, t("Cultist Priest Thorax HP")), getMarkerLine(xMax, 220, t("Cultist Warrior Thorax HP")), // getArmorLabel(1, yMax, xMax), // getArmorLabel(2, yMax, xMax), // getArmorLabel(3, yMax, xMax), // getArmorLabel(4, yMax, xMax), // getArmorLabel(5, yMax, xMax), // getArmorLabel(6, yMax, xMax), ].filter(Boolean); }, [xMax, t]); const scatterData = useMemo(() => { return listState.map((ls) => { return { x: ls.displayDamage, y: ls.displayPenetration, label: ls.chartName, symbol: ls.symbol, id: ls.id, }; }); }, [listState]); const chartMaxDomain = { y: props.yMax ?? MAX_PENETRATION, x: props.xMax ?? MAX_DAMAGE }; return ( } > } label={t("Damage")} tickValues={xTickValues} style={styles.xaxis} /> (tick === 70 ? "" : t("Class {{tier}}", { tier: tick / 10 }))} tickLabelComponent={} label={t("Penetration")} tickValues={yTickValues} style={styles.yaxis} /> } _animate={chartAnimate} events={[ { target: "labels", eventHandlers: { onClick: handleLabelClick, }, }, ]} style={styles.scatter} // labelComponent={} labelComponent={} size={1} activeSize={5} data={scatterData} /> {/* } style={styles.scatter} labelComponent={} // labelComponent={} // />} labels={({ datum }) => { return datum.name; }} size={1} activeSize={5} data={props.listState} x="damage" y="penetration" /> */} } title={t("Filter by caliber")} labelComponent={} events={[ { target: "labels", eventHandlers: { onClick: props.handleLegendClick, }, }, ]} gutter={10} orientation="vertical" style={styles.legend} x={312} y={9} /> {markerLines} ); }; export default Graph; ================================================ FILE: src/components/GraphLabel.jsx ================================================ import React from "react"; import { VictoryLabel, VictoryTooltip } from "victory"; class GraphLabel extends React.Component { static defaultEvents = VictoryTooltip.defaultEvents; render() { return ( ); } } export default GraphLabel; ================================================ FILE: src/components/SEO.jsx ================================================ import React from "react"; import { Helmet } from "react-helmet"; export default function SEO({ title, description, url, image, type = "article", card = "summary" }) { let urlPath = url ? url : window.location.href; return ( {/* Standard metadata tags */} {title} {/* End standard metadata tags */} {/* OpenGraph / Facebook tags */} {/* End Facebook tags */} {/* Twitter tags */} {/* End Twitter tags */} ); } ================================================ FILE: src/components/Symbol.jsx ================================================ import { Component } from "react"; import { Navigate } from "react-router-dom"; import * as shapes from "./points/index.jsx"; const SIZE = 2; class Symbol extends Component { constructor() { super(); this.state = { redirect: false, }; this.handleOnClick = () => { if (this.props.link === false) { return true; } this.setState({ redirect: true, }); }; } render() { if (this.state.redirect) { return ; } const { x, y, datum } = this.props; const PointComponent = shapes[datum.symbol.type]; return ( ); } } export default Symbol; ================================================ FILE: src/components/Time.jsx ================================================ import dayjs from "dayjs"; import dayjsUtc from "dayjs/plugin/utc"; import { useTranslation } from "react-i18next"; import useDate from "../hooks/useDate.jsx"; /* Huge thanks to Adam Burgess https://github.com/adamburgess/tarkov-time as most of the code is his. Thanks a bunch! */ dayjs.extend(dayjsUtc); // 1 second real time = 7 seconds tarkov time const tarkovRatio = 7; export function hrs(num) { return 1000 * 60 * 60 * num; } export function realTimeToTarkovTime(time, left) { // tarkov time moves at 7 seconds per second. // surprisingly, 00:00:00 does not equal unix 0... but it equals unix 10,800,000. // Which is 3 hours. What's also +3? Yep, Russia. UTC+3. // therefore, to convert real time to tarkov time, // tarkov time = (real time * 7 % 24 hr) + 3 hour const oneDay = hrs(24); const russia = hrs(3); const offset = russia + (left ? 0 : hrs(12)); const tarkovTime = new Date((offset + time.getTime() * tarkovRatio) % oneDay); return tarkovTime; } export function timeUntilRelative(until, left, date) { const tarkovTime = realTimeToTarkovTime(date, left); if (until < tarkovTime.getTime()) { until += hrs(24); } const diffTarkov = until - tarkovTime.getTime(); const diffRT = diffTarkov / tarkovRatio; return diffRT; } export function formattedTarkovTime(left = true) { const time = new Date(); const tarkovTime = realTimeToTarkovTime(time, left); return dayjs.utc(tarkovTime).format("HH:mm:ss"); } export function formatFuture(ms) { const time = dayjs.utc(ms); const hour = time.hour(); const min = time.minute(); const sec = time.second(); let text = ""; if (hour !== 0) { text = hour + "hr"; } text += min + "min"; if (hour === 0 && min === 0) { text = sec + "s"; } return text; } function MapDetails(props) { const { t } = useTranslation(); const overlayItem = [
{t("Duration")}: {props.duration}
,
{t("Players")}: {props.players}
, ]; if (props.author) { overlayItem.push(
{t("By")} :{" "} {props.author}
, ); } return overlayItem; } function Time(props) { const time = useDate(new Date(), 50); if (props?.normalizedName === "factory") { return (
15:28:00
03:28:00
); } if (props?.normalizedName === "the-lab") { return (
); } const tarkovTime1 = realTimeToTarkovTime(time, true); const tarkovTime2 = realTimeToTarkovTime(time); return (
{dayjs.utc(tarkovTime1).format("HH:mm:ss")}
{dayjs.utc(tarkovTime2).format("HH:mm:ss")}
); } export default Time; ================================================ FILE: src/components/api-metrics-graph/index.css ================================================ .api-metrics-wrapper { height: 300px; margin-bottom: 100px; } ================================================ FILE: src/components/api-metrics-graph/index.jsx ================================================ import { useQuery } from "@tanstack/react-query"; import { VictoryChart, VictoryLine, VictoryTheme, VictoryVoronoiContainer } from "victory"; import { useTranslation } from "react-i18next"; import "./index.css"; const API_METRICS_ENDPOINT = "https://status.tarkov.dev/api/status-page/heartbeat/api"; const fetchApiData = async () => { const res = await fetch(API_METRICS_ENDPOINT); return res.json(); }; function ApiMetricsGraph({ graph }) { const { t } = useTranslation(); const { status, data } = useQuery({ queryKey: `api-metrics`, queryFn: fetchApiData, refetchOnMount: false, refetchOnWindowFocus: false, }); let height = VictoryTheme.material.height; if (window.innerWidth < 760) { height = 1280; } if (status === "error") { return "⚠️ Error Fetching API Metrics"; } if (status !== "success") { return null; } if (status === "success" && data.heartbeatList["1"] === 0) { return `⚠️ ${t("No data")}`; } let max = 0; data.heartbeatList["1"].map((heartbeat) => { if (heartbeat.ping > max) { max = heartbeat.ping; } return true; }); // Loop through each heartbeat and add the latency to a total that is rounded let total = 0; for (const heartbeat of data.heartbeatList["1"]) { total += heartbeat.ping; } const average = Math.round(total / data.heartbeatList["1"].length); // If the graph param was used, return the graph and the latency average as a div if (graph === true) { return (

{t("Current Average Latency")}: {average}ms

{t("API Latency in milliseconds")}:

`${datum.y}`} />} > { return { x: new Date(heartbeat.time), y: heartbeat.ping, }; })} />
); } // If the graph param was not provided, return the latency average as a div else { return `${average}ms`; } } export default ApiMetricsGraph; ================================================ FILE: src/components/barter-tooltip/index.css ================================================ .barter-tooltip-wrapper { display: flex; flex-wrap: wrap; } .barter-tooltip-details-wrapper > div { line-height: 20px; } .barter-tooltip-wrapper h3 { text-align: center; width: 100%; } .barter-required-item-image img { width: 48px; height: 48px; } .barter-tooltip-wrapper .reward-image-wrapper img { height: 48px; width: 48px; } .barter-tooltip-item-wrapper { align-items: center; display: flex; position: relative; width: 100%; padding: 5px 0px; } .barter-tooltip-details-wrapper a { font-size: 16px; } .barter-tooltip-details-wrapper .price-wrapper { white-space: nowrap; } .barter-tooltip-icon { border: 0; position: relative; top: 2px; width: 14px; margin-right: 3px; } .barter-required-item-image { margin-right: 10px; } ================================================ FILE: src/components/barter-tooltip/index.jsx ================================================ import { useTranslation } from "react-i18next"; import { useMemo } from "react"; import { useSelector } from "react-redux"; import { Link } from "react-router-dom"; import { Icon } from "@mdi/react"; import { mdiCached, mdiProgressWrench } from "@mdi/js"; import ItemImage from "../item-image/index.jsx"; import formatPrice from "../../modules/format-price.js"; import { isAnyDogtag, getDogTagCost } from "../../modules/dogtags.js"; import { getCheapestPrice } from "../../modules/format-cost-items.js"; import { getDurationDisplay } from "../../modules/format-duration.js"; import useHideoutData from "../../features/hideout/index.js"; import useTraderData from "../../features/traders/index.js"; import "./index.css"; function BarterTooltip({ barter, showTitle = true, title, allowAllSources = false, crafts, barters, useBarterIngredients, useCraftIngredients, }) { const settings = useSelector((state) => state.settings[state.settings.gameMode]); const { t } = useTranslation(); const { data: hideout } = useHideoutData(); const { data: traders } = useTraderData(); if (barters && typeof useBarterIngredients === "undefined") { useBarterIngredients = true; } if (crafts && typeof useCraftIngredients === "undefined") { useCraftIngredients = true; } const requirements = useMemo(() => { if (!barter) { return false; } const items = barter.requiredItems; if (!items) { // Should never happen return false; } return items.map((req) => { const cheapestPrice = getCheapestPrice(req.item, { barters: useBarterIngredients ? barters : false, crafts: useCraftIngredients ? crafts : false, settings, allowAllSources, useBarterIngredients, useCraftIngredients, }); return { ...req, cheapestPrice, }; }); }, [barter, settings, allowAllSources, barters, crafts, useBarterIngredients, useCraftIngredients]); const totalCost = useMemo(() => { if (!requirements) { return 0; } return requirements.reduce((total, req) => { if (req.attributes.some((att) => att.type === "tool")) { return total; } total += req.cheapestPrice.pricePerUnit * req.count; return total; }, 0); }, [requirements]); if (!barter) { return t("No barters found for this item"); } if (!barter.trader && !barter.station) { // Should never happen return "Missing trader for this barter"; } if (!requirements) { // Should never happen return "Missing requirements for this barter"; } let titleElement = ""; if (showTitle) { const source = barter.trader ? traders.find((t) => t.id === barter.trader.id) : hideout.find((s) => s.id === barter.station.id); const sourceLevelText = barter.trader ? `${source.name} ${t("LL{{level}}", { level: barter.level })}` : `${source.name} ${barter.level}`; const tipTitle = barter.trader ? t("Barter at {{trader}}", { trader: sourceLevelText }) : t("Craft at {{station}}", { station: sourceLevelText }); titleElement = (

{tipTitle}

); if (title) { titleElement =

{title}

; } } return (
{titleElement} {requirements.map((requiredItem) => { let itemName = requiredItem.item.name; let price = requiredItem.cheapestPrice.pricePerUnit; let sourceName = requiredItem.cheapestPrice.vendor?.normalizedName || requiredItem.cheapestPrice.craft?.station.normalizedName; if (isAnyDogtag(requiredItem.item.id)) { const dogtagCost = getDogTagCost(requiredItem, settings); itemName = dogtagCost.name; price = dogtagCost.price; sourceName = dogtagCost.sourceNormalizedName; } let sourceImage = ( {t("Barter")} ); if (requiredItem.cheapestPrice.type === "craft") { const station = hideout.find((s) => s.id === requiredItem.cheapestPrice.craft.station.id); const craftInfo = t("Craft at {{stationName}} {{stationLevel}}", { stationName: station.name, stationLevel: requiredItem.cheapestPrice.craft.level, }); sourceImage = ( {craftInfo} ); } return (
{itemName}
{sourceImage} {requiredItem.cheapestPrice.barter && ( {t("Barter")} )} {requiredItem.count} X {formatPrice(price)} ={" "} {formatPrice(requiredItem.count * price)}
); })} {barter.rewardItems[0].count > 1 && barter.trader && (
{t("Provides {{count}} for {{totalCost}}", { count: barter.rewardItems[0].count, totalCost: formatPrice(totalCost), })}
)} {barter.station && (
{t("Crafts {{count}} in {{duration}} for {{totalCost}}", { count: barter.rewardItems[0].count, duration: getDurationDisplay(barter.duration * 1000), totalCost: formatPrice(totalCost), })}
)}
); } export default BarterTooltip; ================================================ FILE: src/components/barters-table/index.css ================================================ /* CSS Placeholder */ ================================================ FILE: src/components/barters-table/index.jsx ================================================ import { useMemo, useState } from "react"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import DataTable from "../data-table/index.jsx"; import useBartersData from "../../features/barters/index.js"; import useCraftsData from "../../features/crafts/index.js"; import useItemsData, { useHandbookData } from "../../features/items/index.js"; import { selectAllTraders } from "../../features/settings/settingsSlice.mjs"; import ValueCell from "../value-cell/index.jsx"; import CostItemsCell from "../cost-items-cell/index.jsx"; import RewardCell from "../reward-cell/index.jsx"; import FleaMarketLoadingIcon from "../FleaMarketLoadingIcon.jsx"; import { formatCostItems, getCheapestCashPrice, getCheapestBarter } from "../../modules/format-cost-items.js"; import { isAnyDogtag, isBothDogtags } from "../../modules/dogtags.js"; import fleaMarketFee from "../../modules/flea-market-fee.mjs"; import "./index.css"; function BartersTable({ selectedTrader, nameFilter, itemFilter, showAll, useBarterIngredients, useCraftIngredients }) { const { t } = useTranslation(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const { hasJaeger, removeDogtags, completedQuests } = useMemo(() => { return { hasJaeger: settings.jaeger !== 0, removeDogtags: settings.hideDogtagBarters, completedQuests: settings.completedQuests, }; }, [settings]); const traders = useSelector(selectAllTraders); const [skippedBySettings, setSkippedBySettings] = useState(false); const { data: barters } = useBartersData(); const { data: crafts } = useCraftsData(); const { data: items } = useItemsData(); const { data: handbook } = useHandbookData(); const columns = useMemo( () => [ { Header: t("Reward"), id: "reward", accessor: "reward", Cell: ({ value }) => { return ; }, }, { Header: t("Cost"), id: "costItems", accessor: "costItems", sortType: (a, b, columnId, desc) => { if ( a.values.costItems[0].id === "5d235b4d86f7742e017bc88a" && a.values.costItems[0].id === "5d235b4d86f7742e017bc88a" ) { const aGPCost = a.values.costItems[0].price || 0; const bGPCost = b.values.costItems[0].price || 0; return aGPCost - bGPCost; } const aCost = a.values.cost || 0; const bCost = b.values.cost || 0; return aCost - bCost; }, Cell: ({ value }) => { return ( ); }, }, { Header: t("Cost ₽"), id: "cost", accessor: "cost", Cell: (props) => { if (props.row.original.cached) { return (
); } return ; }, }, { Header: t("Estimated savings"), id: "savings", accessor: (d) => Number(d.savings), sortType: (a, b, columnId, desc) => { const aSave = a.values.savings || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bSave = b.values.savings || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aSave - bSave; }, Cell: (props) => { if (props.row.original.cached) { return (
); } return ( ); }, }, { Header: t("InstaProfit"), id: "instaProfit", accessor: "instaProfit", sortType: (a, b, columnId, desc) => { const aProf = a.values.instaProfit || 0; const bProf = b.values.instaProfit || 0; if (aProf === bProf) { const aSave = a.values.savings || 0; const bSave = b.values.savings || 0; return aSave - bSave; } return aProf - bProf; }, Cell: (props) => { if (props.row.original.cached) { return (
); } return (
{props.row.original.instaProfitSource.vendor.normalizedName !== "unknown" ? props.row.original.instaProfitSource.vendor.name : ""}
); }, }, ], [t, showAll, useBarterIngredients, useCraftIngredients, barters, crafts], ); const data = useMemo(() => { let addedTraders = []; setSkippedBySettings(false); return barters .filter((barter) => { return !!barter.rewardItems[0]; }) .filter((barter) => { if (!itemFilter) { return true; } for (const requiredItem of barter.requiredItems) { if (requiredItem === null) { continue; } if (requiredItem.item.id === itemFilter) { return true; } if (isBothDogtags(itemFilter) && isAnyDogtag(requiredItem.item.id)) { return true; } if (isBothDogtags(requiredItem.item.id) && isAnyDogtag(itemFilter)) { return true; } } for (const rewardItem of barter.rewardItems) { if (rewardItem.item.id === itemFilter) { return true; } if (!rewardItem.item.containsItems) { continue; } for (const contained of rewardItem.item.containsItems) { if (!contained) { continue; } if (contained.item.id === itemFilter) { return true; } } } return false; }) .filter((barter) => { let traderNormalizedName = barter.trader.normalizedName; let level = barter.level; if ( !nameFilter && selectedTrader && selectedTrader !== "all" && selectedTrader !== traderNormalizedName ) { return false; } if (!showAll && level > traders[traderNormalizedName]) { setSkippedBySettings(true); return false; } if (!showAll && barter.taskUnlock && settings.useTarkovTracker) { if (!completedQuests.some((taskId) => taskId === barter.taskUnlock.id)) { setSkippedBySettings(true); return false; } } if (removeDogtags) { for (const requiredItem of barter.requiredItems) { if (requiredItem === null) { continue; } if (requiredItem.item.normalizedName.includes("dogtag")) { setSkippedBySettings(true); return false; } } } return true; }) .filter((barter) => { if (!nameFilter || nameFilter.length <= 0) { return true; } const findString = nameFilter.toLowerCase().replace(/\s/g, ""); for (const requiredItem of barter.requiredItems) { if (requiredItem === null) { continue; } if (requiredItem.item.name.toLowerCase().replace(/\s/g, "").includes(findString)) { return true; } } for (const rewardItem of barter.rewardItems) { if (rewardItem.item.name.toLowerCase().replace(/\s/g, "").includes(findString)) { return true; } } return false; }) .filter((barter) => { if (selectedTrader !== "all") { return true; } if (selectedTrader === "all") { return true; } if (addedTraders.includes(barter.reward.source)) { return false; } addedTraders.push(barter.reward.source); return true; }) .map((barterRow) => { let cost = 0; const costItems = formatCostItems(barterRow.requiredItems, { settings, barters: useBarterIngredients ? barters : false, crafts: useCraftIngredients ? crafts : false, allowAllSources: showAll, useBarterIngredients, useCraftIngredients, }); costItems.forEach((costItem) => (cost += costItem.pricePerUnit * costItem.count)); const barterRewardItem = barterRow.rewardItems[0].item; let barterRewardContainedItem; if (barterRewardItem.bsgCategoryId === "543be5cb4bdc2deb348b4568") { // "ammo-container" barterRewardContainedItem = items.find((i) => i.id === barterRewardItem.containsItems[0]?.item.id); if (barterRewardContainedItem?.types.includes("noFlea")) { barterRewardContainedItem = null; } } const whatWeSell = barterRewardContainedItem ? barterRewardContainedItem : barterRewardItem; const howManyWeSell = barterRewardContainedItem ? barterRewardItem.containsItems[0].count : barterRow.rewardItems[0].count; const bestSellTo = whatWeSell.sellFor.reduce( (previousSellFor, currentSellFor) => { if ( currentSellFor.vendor.normalizedName === "flea-market" && (handbook.fleaMarket.foundInRaidRequired || !handbook.fleaMarket.enabled) ) { return previousSellFor; } if (currentSellFor.vendor.normalizedName === "jaeger" && !hasJaeger) { return previousSellFor; } if (previousSellFor.priceRUB > currentSellFor.priceRUB) { return previousSellFor; } return currentSellFor; }, { vendor: { name: t("N/A"), normalizedName: "unknown", }, priceRUB: 0, }, ); if (cost === 0 && costItems.length === 1 && costItems[0].id === "5d235b4d86f7742e017bc88a") { // "gp-coin" cost = bestSellTo.priceRUB * howManyWeSell; const GPCoinPrice = cost / costItems[0].count; costItems[0].price = GPCoinPrice; costItems[0].priceRUB = GPCoinPrice; costItems[0].pricePerUnit = GPCoinPrice; } let fleaFee = 0; if (bestSellTo.vendor.normalizedName === "flea-market") { fleaFee = fleaMarketFee(barterRewardItem.basePrice, bestSellTo.priceRUB, { count: howManyWeSell }); } const tradeData = { costItems: costItems, cost: cost, instaProfit: bestSellTo.priceRUB * howManyWeSell - cost - fleaFee, instaProfitSource: bestSellTo, instaProfitDetails: [ { name: bestSellTo.vendor.name, value: bestSellTo.priceRUB * howManyWeSell, }, ], reward: { item: barterRewardItem, count: barterRow.rewardItems[0].count, source: `${barterRow.trader.name} ${t("LL{{level}}", { level: barterRow.level })}`, sellTo: bestSellTo.vendor.name, sellToNormalized: bestSellTo.vendor.normalizedName, sellValue: bestSellTo.priceRUB * howManyWeSell, taskUnlock: barterRow.taskUnlock, isFIR: false, }, cached: barterRow.cached || barterRewardItem.cached, }; if (fleaFee) { tradeData.instaProfitDetails.push({ name: t("Flea Fee"), value: fleaFee * -1, }); } tradeData.instaProfitDetails.push({ name: t("Barter cost"), value: cost * -1, }); if (barterRewardItem.priceCustom) { tradeData.reward.sellValue = barterRewardItem.priceCustom; tradeData.reward.sellType = "custom"; } if (barterRewardContainedItem) { // "ammo-container" tradeData.reward.sellNote = t("Unpacked"); } tradeData.savingsParts = []; const cheapestPrice = getCheapestCashPrice(barterRewardItem, settings, showAll); const cheapestBarter = getCheapestBarter(barterRewardItem, { barters, crafts: useCraftIngredients ? crafts : false, settings, useBarterIngredients, useCraftIngredients, allowAllSources: showAll, }); if (cheapestPrice.type === "cash-sell") { //this item cannot be purchased for cash if (cheapestBarter) { if (cheapestBarter.priceRUB !== cost) { tradeData.savingsParts.push({ name: `${cheapestBarter.vendor.name} ${t("LL{{level}}", { level: cheapestBarter.vendor.minTraderLevel })} ${t("Barter")}`, value: cheapestBarter.priceRUB, }); } tradeData.savings = cheapestBarter.priceRUB - cost; } } else if (cheapestPrice.type !== "none") { // savings based on cheapest cash price let sellerName = cheapestPrice.vendor.name; if (cheapestPrice.vendor.minTraderLevel) { sellerName += ` ${t("LL{{level}}", { level: cheapestPrice.vendor.minTraderLevel })}`; } tradeData.savingsParts.push({ name: sellerName, value: cheapestPrice.priceRUB, }); tradeData.savings = cheapestPrice.priceRUB - Math.round(cost / howManyWeSell); } if (tradeData.savingsParts.length > 0) { tradeData.savingsParts.push({ name: t("Barter cost"), value: Math.round(cost / howManyWeSell) * -1, }); } if (tradeData.reward.sellValue === 0) { tradeData.instaProfitDetails.splice(0, 1); } return tradeData; }) .filter(Boolean) .sort((itemA, itemB) => { return itemB.savings - itemA.savings; }); }, [ nameFilter, selectedTrader, barters, crafts, items, handbook, itemFilter, traders, completedQuests, hasJaeger, t, removeDogtags, showAll, settings, useBarterIngredients, useCraftIngredients, ]); let extraRow = false; if (data.length <= 0) { extraRow = t("No barters available for selected filters"); } if (data.length <= 0 && skippedBySettings) { extraRow = ( <> {t("No barters available for selected filters but some were hidden by ")} {t("your settings")} ); } if (data.length > 0 && skippedBySettings) { extraRow = ( <> {t("Some barters hidden by ")} {t("your settings")} ); } return ( ); } export default BartersTable; ================================================ FILE: src/components/boss-list/index.css ================================================ .boss-icon { height: 24px; width: 24px; margin-right: 10px; } ================================================ FILE: src/components/boss-list/index.jsx ================================================ import { Link } from "react-router-dom"; import MenuItem from "../menu/MenuItem.jsx"; import LoadingSmall from "../loading-small/index.jsx"; import { useBossesData } from "../../features/maps/index.js"; import "./index.css"; // BossPageList component for the main boss page export function BossPageList() { // Fetch bosses const { data: bosses } = useBossesData(); // If no maps have been returned yet, return 'loading' if (!bosses || bosses.length === 0) { return ; } // Return the home page boss React component return ( <> {bosses .filter((boss) => boss.maps.length > 0) .sort((a, b) => a.name.localeCompare(b.name)) .map((boss) => { // Format the boss name for links var key = boss.normalizedName; return (

{boss.name}

{boss.name} ); })} ); } // BossListNav component for homepage nav bar export function BossListNav(onClick) { // Fetch bosses const { data: bosses } = useBossesData(); // If no maps have been returned yet, return 'loading' if (!bosses || bosses.length === 0) { return null; } // Return the home page nav boss React component return ( <>
    {bosses .map((boss) => boss) .sort((a, b) => a.name.localeCompare(b.name)) .map((boss) => { // Format the boss name for links var key = boss.normalizedName; return ( ); })}
); } // BossList component for homepage function BossList() { // Fetch bosses const { data: bosses } = useBossesData(); // If no maps have been returned yet, return 'loading' if (!bosses || bosses.length === 0) { return ; } // Return the home page boss React component return ( <> {bosses .filter((boss) => boss.maps.length > 0) .sort((a, b) => a.name.localeCompare(b.name)) .map((boss) => { // Format the boss name for links var key = boss.normalizedName; return (
  • {boss.name} { if (!e.target.src.includes("icon.jpg")) { return; } // if we don't have an icon, use the portrait image e.target.src = boss.imagePortraitLink; }} /> {boss.name}
  • ); })} ); } export default BossList; ================================================ FILE: src/components/canvas-grid/index.jsx ================================================ import { useRef, useEffect } from "react"; function CanvasGrid(props) { const canvas = useRef(null); let boxes = []; boxes = boxes .concat( props.grid?.map((pocket) => { const returnData = { startX: pocket.col * 20 + pocket.col * 2, startY: pocket.row * 20 + pocket.row * 2, horizontal: pocket.width, vertical: pocket.height, }; return returnData; }), ) .filter(Boolean); // initialize the canvas context useEffect(() => { const canvasEle = canvas.current; if (!canvasEle) { return; } canvasEle.width = canvasEle.clientWidth; canvasEle.height = canvasEle.clientHeight; const ctx = canvasEle.getContext("2d"); boxes.map((info) => drawPocket(info, ctx)); }); if (!props.height || !props.width) { return null; } if (!boxes) { return null; } const drawPocket = (info, ctx) => { let { startX, startY, horizontal, vertical } = info; const height = 20; const width = 20; ctx.beginPath(); ctx.fillStyle = "var(--color-black)"; // outer border color ctx.fillRect(startX, startY, horizontal * 20 + 2, vertical * 20 + 2); startX = startX + 1; startY = startY + 1; for (let i = 0; i < horizontal * vertical; i = i + 1) { const x = startX + (i % horizontal) * 20; const y = startY + Math.floor(i / horizontal) * 20; drawSquare( { x: x, y: y, width: width, height: height, fillStyle: "#181818", // inner border color }, ctx, ); drawSquare( { x: x + 1, y: y + 1, width: width - 2, height: height - 2, fillStyle: "#121212", // inner background color }, ctx, ); // ctx.fillStyle = '#ffffff'; // ctx.font = '10px serif'; // ctx.fillText(i, x + 8, y + 15); } }; const drawSquare = (info, ctx) => { ctx.beginPath(); ctx.fillStyle = info.fillStyle; ctx.fillRect(info.x, info.y, info.width, info.height); }; return ; } export default CanvasGrid; ================================================ FILE: src/components/center-cell/index.jsx ================================================ const CenterCell = ({ children, className, nowrap = false, value }) => { return (
    {children || value}
    ); }; export default CenterCell; ================================================ FILE: src/components/cheeki-breeki-effect/index.css ================================================ .cheeki-breeki { display: flex; } .cheeki-breeki-button { padding: .2rem; border-radius: 4px; } ================================================ FILE: src/components/cheeki-breeki-effect/index.jsx ================================================ import { motion } from "framer-motion"; import "./index.css"; function CheekiBreekiEffect() { return (
    {"killa"} {"killa"} {"killa"} {"killa"} {"killa"}
    ); } export default CheekiBreekiEffect; ================================================ FILE: src/components/contained-items-list/index.css ================================================ .contained-item-title-wrapper, .contained-item-link-wrapper { display: inline-block; margin-right: 5px; } .contained-item-link { white-space: nowrap; } ================================================ FILE: src/components/contained-items-list/index.jsx ================================================ import { useMemo } from "react"; import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import useItemsData, { useHandbookData } from "../../features/items/index.js"; import "./index.css"; const ContainedItemsList = ({ item, showRestrictedType }) => { const { data: handbook, status: handbookStatus } = useHandbookData(); const { data: items } = useItemsData(); const { t } = useTranslation(); //const containers = item.properties?.slots || item.properties?.grids; const containers = item.properties?.grids; const holdItems = useMemo(() => { if (!items) { return []; } if (showRestrictedType) { const restrictedItems = new Set(); item.properties?.grids?.forEach((grid) => { for (const id of grid.filters.excludedItems) { restrictedItems.add(id); } }); return [...restrictedItems] .map((id) => { const rItem = items.find((testItem) => testItem.id === id); if (!rItem) { return false; } if (rItem.types.includes(showRestrictedType)) { return rItem; } return false; }) .filter(Boolean) .sort((a, b) => { return a.name.localeCompare(b.name); }); } else { if ( !containers || (containers.length === 1 && containers[0].filters.allowedCategories.length === 1 && containers[0].filters.allowedCategories[0] === "54009119af1c881c07000029") ) { return []; } let sorted = items.filter((linkedItem) => { for (const slot of containers) { // const included = slot.filters.allowedItems.includes(linkedItem.id) || linkedItem.categoryIds.some(catId => slot.filters.allowedCategories.includes(catId)); // const excluded = slot.filters.excludedItems.includes(linkedItem.id) || linkedItem.categoryIds.some(catId => slot.filters.excludedCategories.includes(catId)); const included = slot.filters.allowedItems.includes(linkedItem.id); const excluded = linkedItem.categoryIds.some((catId) => slot.filters.excludedCategories.includes(catId), ); if (included && !excluded) { return true; } } return false; }); if (handbookStatus !== "idle") { handbook.itemCategories.forEach((category) => { for (const slot of containers) { if (slot.filters.allowedCategories.includes(category.id)) { sorted.push(category); } } }); } return sorted .reduce((allItems, current) => { if (!allItems.some((item) => item.id === current.id)) { allItems.push(current); } return allItems; }, []) .sort((a, b) => { return a.name.localeCompare(b.name); }); } }, [items, handbook, handbookStatus, containers, item, showRestrictedType]); //console.log(item.name, item.showRestricted, sortedItems) let itemsText = t("Can hold:"); if (showRestrictedType) { itemsText = t("Can't hold:"); } if (holdItems.length === 0) { return null; } if (holdItems.length === 1 && holdItems[0].id === "54009119af1c881c07000029") { return null; } return (
    {itemsText} {holdItems.map((linked, index) => { if (linked.id === "54009119af1c881c07000029") { // Special case for items that can contain all items return null; } const isCategory = linked.parent ? "s" : ""; return ( {linked.name} {holdItems.length > index + 1 ? "," : ""} ); })}
    ); }; export default ContainedItemsList; ================================================ FILE: src/components/contributors/index.jsx ================================================ import { AvatarGroup, Avatar, createTheme, ThemeProvider } from "@mui/material"; import contributorJson from "../../data/contributors.json"; // inputs // size: number (pixels) of the size of the avatar // quality: number (pixels) of the quality of the avatar // stack: boolean (true/false) to stack the avatars function Contributors(props) { var quality; if (!props.quality) { quality = props.size; } else { quality = props.quality; } const contributorData = props.data && props.data.length > 0 ? props.data : contributorJson; const avatarTheme = createTheme({ components: { // Name of the component MuiAvatar: { styleOverrides: { // Name of the slot root: { // Some CSS width: props.size, height: props.size, display: "inline-block", verticalAlign: "middle", border: 1, borderStyle: "solid", marginRight: 2, }, }, }, }, }); if (props.stack === true) { return ( {contributorData.map((contributor) => ( ))} ); } else { return ( <> {contributorData.map((contributor) => ( ))} ); } } export default Contributors; ================================================ FILE: src/components/cost-items-cell/index.css ================================================ .cost-item-wrapper { align-items: center; display: flex; position: relative; width: 100%; } .cost-image-wrapper img { width: 32px; height: 32px; } .cost-item-wrapper.disabled img { filter: grayscale(100%); } .cost-item-wrapper.disabled::after { background-color: rgb(from var(--color-black) r g b / 0.3); inset: 0 0 0 0; content: ' '; position: absolute; } .cost-item-count-wrapper { color: var(--color-gold-one); } .cost-image-wrapper { font-size: 0; margin-right: 10px; } .cost-item-text-wrapper { flex-grow: 1; white-space: nowrap; } ================================================ FILE: src/components/cost-items-cell/index.jsx ================================================ import { Link } from "react-router-dom"; import { useDispatch } from "react-redux"; import ItemCost from "../item-cost/index.jsx"; import ItemImage from "../item-image/index.jsx"; import "./index.css"; import { toggleItem as toggleCraftItem } from "../../features/crafts/index.js"; import { toggleItem as toggleBarterItem } from "../../features/barters/index.js"; function CostItemsCell({ costItems, craftId, barterId, allowAllSources = false, crafts, barters, useCraftIngredients, useBarterIngredients, }) { const dispatch = useDispatch(); return (
    {costItems.map((costItem, itemIndex) => { return (
    { // Don't allow to toggle/disable tools if (costItem.isTool === true) { return true; } // Don't hook A's if (event.target.nodeName === "A") { return true; } if (event.target.nodeName === "path") { return true; } if (event.target.classList.contains("no-click")) { return true; } dispatch( toggleCraftItem({ itemId: costItem.id, }), ); dispatch( toggleBarterItem({ itemId: costItem.id, }), ); }} >
    {costItem.name}
    ); })}
    ); } export default CostItemsCell; ================================================ FILE: src/components/countdown/index.css ================================================ /* CSS Placeholder */ ================================================ FILE: src/components/countdown/index.jsx ================================================ import Countdown from "react-countdown"; import "./index.css"; const renderer = ({ days, hours, minutes, seconds, completed }) => { if (completed) { // Render a completed state return null; } else { // Render a countdown return ( {days} days {hours} hours {minutes} minutes {seconds} seconds to wipe ); } }; function WipeCountdown() { return ; } export default WipeCountdown; ================================================ FILE: src/components/crafts-table/index.css ================================================ .duration-wrapper, .finish-wrapper { color: var(--color-gray-light); font-size: 14px; } .finish-wrapper { cursor: pointer; } ================================================ FILE: src/components/crafts-table/index.jsx ================================================ import { useMemo, useState, useCallback } from "react"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import DataTable from "../data-table/index.jsx"; import fleaMarketFee from "../../modules/flea-market-fee.mjs"; import useCraftsData from "../../features/crafts/index.js"; import useBartersData from "../../features/barters/index.js"; import useHideoutData from "../../features/hideout/index.js"; import ValueCell from "../value-cell/index.jsx"; import CostItemsCell from "../cost-items-cell/index.jsx"; import formatCostItems from "../../modules/format-cost-items.js"; import { selectAllStations, selectAllSkills } from "../../features/settings/settingsSlice.mjs"; import CenterCell from "../center-cell/index.jsx"; import "./index.css"; import RewardCell from "../reward-cell/index.jsx"; import { getDurationDisplay } from "../../modules/format-duration.js"; import bestPrice from "../../modules/best-price.js"; import { useHandbookData } from "../../features/items/index.js"; import FleaMarketLoadingIcon from "../FleaMarketLoadingIcon.jsx"; function CraftTable({ selectedStation, freeFuel, nameFilter, itemFilter, showAll, averagePrices, useBarterIngredients, useCraftIngredients, }) { const { t } = useTranslation(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const stations = useSelector(selectAllStations); const skills = useSelector(selectAllSkills); const [skippedBySettings, setSkippedBySettings] = useState(false); const [sortState, setSortState] = useState([{ id: "profit", desc: true }]); const { data: crafts } = useCraftsData(); const { data: barters } = useBartersData(); const { data: handbook } = useHandbookData(); const { data: hideout } = useHideoutData(); const { fleaUnlocked, hasJaeger, completedQuests } = useMemo(() => { return { fleaUnlocked: handbook.fleaMarket.enabled && settings.playerLevel >= handbook.fleaMarket.minPlayerLevel, hasJaeger: settings.jaeger !== 0, completedQuests: settings.completedQuests, }; }, [settings, handbook]); const availableOnFlea = useCallback( (item) => { return ( showAll || (handbook.fleaMarket.enabled && settings.playerLevel >= Math.max(handbook.fleaMarket.minPlayerLevel, item.minLevelForFlea)) ); }, [settings, handbook], ); const data = useMemo(() => { let addedStations = {}; setSkippedBySettings(false); return crafts .filter((craftRow) => { if (!craftRow.rewardItems[0]) { console.log("Invalid craft", craftRow); return false; } return true; }) .filter((craftRow) => { if (!itemFilter) { return true; } for (const requiredItem of craftRow.requiredItems) { if (requiredItem === null) { continue; } if (requiredItem.item.id === itemFilter) { return true; } } for (const rewardItem of craftRow.rewardItems) { if (rewardItem.item.id === itemFilter) { return true; } } return false; }) .filter((craftRow) => { if (!nameFilter?.length) { return true; } const findString = nameFilter.toLowerCase().replace(/\s/g, ""); for (const requiredItem of craftRow.requiredItems) { if (requiredItem === null) { continue; } if (requiredItem.item.name.toLowerCase().replace(/\s/g, "").includes(findString)) { return true; } } for (const rewardItem of craftRow.rewardItems) { if (rewardItem.item.name.toLowerCase().replace(/\s/g, "").includes(findString)) { return true; } } return false; }) .map((craftRow) => { let totalCost = 0; const station = hideout.find((s) => s.id === craftRow.station.id); if (!station) { return false; } const stationNormalized = station.normalizedName; const level = craftRow.level; if ( !nameFilter && selectedStation && selectedStation !== "top" && selectedStation !== "banned" && selectedStation !== stationNormalized ) { return false; } if ( (selectedStation === "top" || selectedStation === "banned") && stationNormalized === "bitcoin-farm" ) { return false; } if (selectedStation === "banned") { if (!craftRow.rewardItems[0].item.types.includes("noFlea")) { return false; } } if (!showAll && level > stations[stationNormalized]) { //setSkippedByLevel(true); setSkippedBySettings(true); return false; } if (!showAll && craftRow.taskUnlock && settings.useTarkovTracker) { if (!completedQuests.some((taskId) => taskId === craftRow.taskUnlock.id)) { setSkippedBySettings(true); return false; } } const costItems = formatCostItems(craftRow.requiredItems, { settings, barters: useBarterIngredients ? barters : false, crafts: useCraftIngredients ? crafts : false, freeFuel, allowAllSources: showAll, useBarterIngredients, useCraftIngredients, }); const craftDuration = Math.floor( craftRow.duration - (craftRow.duration * (skills.crafting * 0.75)) / 100, ); var costItemsWithoutTools = costItems.filter((costItem) => costItem.isTool === false); costItemsWithoutTools.forEach((costItem) => (totalCost += costItem.pricePerUnit * costItem.count)); const craftRewardItem = craftRow.rewardItems[0].item; const bestSellTo = craftRewardItem.sellFor.reduce( (previousSellFor, currentSellFor) => { if (currentSellFor.vendor.normalizedName === "flea-market") { return previousSellFor; } if (currentSellFor.vendor.normalizedName === "jaeger" && !hasJaeger) { return previousSellFor; } if (previousSellFor.priceRUB > currentSellFor.priceRUB) { return previousSellFor; } return currentSellFor; }, { vendor: { name: t("N/A"), normalizedName: "unknown", }, priceRUB: 0, }, ); const tradeData = { costItems: costItems, cost: totalCost, craftTime: craftDuration, reward: { item: craftRewardItem, source: `${station.name} (${t("Level")} ${level})`, count: craftRow.rewardItems[0].count, sellTo: bestSellTo.vendor.name, sellToNormalized: bestSellTo.vendor.normalizedName, sellValue: bestSellTo.priceRUB, taskUnlock: craftRow.taskUnlock, isFIR: true, }, cached: craftRow.cached || craftRewardItem.cached, stationId: craftRow.station.id, }; let fleaFeeSingle = 0; let fleaFeeTotal = 0; let fleaPriceToUse = craftRewardItem[averagePrices === true ? "avg24hPrice" : "lastLowPrice"]; if (fleaPriceToUse === 0) { fleaPriceToUse = craftRewardItem.lastLowPrice; } if ( !tradeData.cached && !craftRewardItem.types.includes("noFlea") && availableOnFlea(craftRewardItem) ) { const bestFleaPrice = bestPrice( craftRewardItem, handbook?.fleaMarket?.sellOfferFeeRate, handbook?.fleaMarket?.sellRequirementFeeRate, fleaPriceToUse, ); if ( !craftRow.rewardItems[0].priceCustom && (fleaPriceToUse === 0 || bestFleaPrice.bestPrice < fleaPriceToUse) ) { fleaPriceToUse = bestFleaPrice.bestPrice; fleaFeeSingle = bestFleaPrice.bestPriceFee; } else { fleaFeeSingle = fleaMarketFee(craftRewardItem.basePrice, fleaPriceToUse); } fleaFeeTotal = fleaMarketFee(craftRewardItem.basePrice, fleaPriceToUse, { count: craftRow.rewardItems[0].count, }); if (fleaPriceToUse - fleaFeeSingle > tradeData.reward.sellValue) { tradeData.reward.sellValue = fleaPriceToUse; tradeData.reward.sellTo = t("Flea Market"); } else { fleaFeeSingle = 0; fleaFeeTotal = 0; } } else if (craftRewardItem.types.includes("noFlea")) { tradeData.reward.sellNote = t("Flea banned"); } if (craftRewardItem.priceCustom) { tradeData.reward.sellValue = craftRewardItem.priceCustom; tradeData.reward.sellType = "custom"; } tradeData.profitParts = [ { name: t("Sell price"), value: tradeData.reward.sellValue * craftRow.rewardItems[0].count, }, ]; if (totalCost) { tradeData.profitParts.push({ name: t("Cost"), value: totalCost * -1, }); } if (fleaFeeTotal) { tradeData.profitParts.push({ name: t("Flea Market fee"), value: fleaFeeTotal * -1, }); } tradeData.fleaThroughput = Math.floor( (tradeData.reward.sellValue * craftRow.rewardItems[0].count) / (craftDuration / 3600), ); tradeData.profit = tradeData.reward.sellValue * craftRow.rewardItems[0].count - totalCost - fleaFeeTotal; if (tradeData.profit === Infinity) { tradeData.profit = 0; } tradeData.profitPerHour = Math.floor(tradeData.profit / (craftDuration / 3600)); return tradeData; }) .filter(Boolean) .sort((itemA, itemB) => { let sortField = "profit"; let desc = true; const columnSwap = { costItems: "cost", reward: "profit", }; if (sortState.length > 0) { sortField = sortState[0].id; //desc = sortState[0].desc; } if (columnSwap[sortField]) { sortField = columnSwap[sortField]; } if (sortField === "craftTime" || sortField === "cost") { desc = false; } if (!desc) { return itemA[sortField] - itemB[sortField]; } return itemB[sortField] - itemA[sortField]; }) .filter((craft) => { // This is done after profit sorting if (selectedStation !== "top") { return true; } if (!craft.cost && !craft.profit && !craft.profitPerHour) { return false; } if (!addedStations[craft.stationId]) { addedStations[craft.stationId] = 0; } if (addedStations[craft.stationId] >= 2) { return false; } addedStations[craft.stationId]++; return true; }); }, [ nameFilter, selectedStation, freeFuel, crafts, barters, hideout, completedQuests, hasJaeger, itemFilter, stations, skills, t, showAll, averagePrices, handbook, settings, sortState, useCraftIngredients, useBarterIngredients, availableOnFlea, ]); const columns = useMemo( () => [ { Header: t("Reward"), id: "reward", accessor: "reward", sortType: (a, b, columnId, desc) => { const aName = a.values.reward.item.name; const bName = b.values.reward.item.name; return aName.localeCompare(bName); }, Cell: ({ value }) => { return ; }, }, { Header: t("Cost"), id: "costItems", accessor: "costItems", sortType: (a, b, columnId, desc) => { let aCostItems = a.original.cost || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); let bCostItems = b.original.cost || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); if (selectedStation === "banned") { aCostItems = a.original.cost / a.original.reward.count || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); bCostItems = b.original.cost / b.original.reward.count || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); } return aCostItems - bCostItems; }, Cell: ({ value }) => { return ( ); }, }, { Header: t("Duration") + "\n" + t("Finishes"), id: "craftTime", accessor: "craftTime", sortType: "basic", Cell: ({ value }) => { return (
    {getDurationDisplay(value * 1000)}
    { e.target.innerText = getLocalFinishes(value, t); }} > {getLocalFinishes(value, t)}
    ); }, }, { Header: t("Cost ₽"), id: "cost", accessor: (d) => Number(d.cost), sortType: (a, b, columnId, desc) => { let aCostItems = a.original.cost || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); let bCostItems = b.original.cost || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); if (selectedStation === "banned") { aCostItems = a.original.cost / a.original.reward.count || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); bCostItems = b.original.cost / b.original.reward.count || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); } return aCostItems - bCostItems; }, Cell: (props) => { if (props.row.original.cached) { return (
    ); } return ; }, }, ...(fleaUnlocked ? [ { Header: t("Flea throughput/h"), id: "fleaThroughput", accessor: "fleaThroughput", sortType: "basic", Cell: (props) => { if (props.row.original.cached) { return (
    ); } return ; }, }, ] : []), { Header: t("Estimated profit"), id: "profit", accessor: "profit", sortType: "basic", Cell: (props) => { if (props.row.original.cached) { return (
    ); } return ( ); }, }, { Header: t("Estimated profit/h"), id: "profitPerHour", accessor: "profitPerHour", sortType: "basic", Cell: (props) => { if (props.row.original.cached) { return (
    ); } return ; }, }, ], [t, fleaUnlocked, selectedStation, showAll, crafts, barters, useCraftIngredients, useBarterIngredients], ); let extraRow = false; if (data.length <= 0) { extraRow = t("No crafts available for selected filters"); } if (data.length <= 0 && skippedBySettings) { extraRow = ( <> {t("No crafts available for selected filters but some were hidden by ")} {t("your settings")} ); } if (data.length > 0 && skippedBySettings) { extraRow = ( <> {t("Some crafts hidden by ")} {t("your settings")} ); } return ( { setSortState(newSortState); }} /> ); } function getLocalFinishes(time, t) { const finishes = t("{{val, datetime}}", { val: Date.now() + time * 1000, formatParams: { val: { weekday: "short", hour: "numeric", minute: "numeric", second: "numeric" }, }, }); return finishes; } export default CraftTable; ================================================ FILE: src/components/data-table/Arrow.tsx ================================================ import clsx from "clsx"; function ArrowIcon({ className, direction = "down", }: { className?: string; direction?: "up" | "down" | "left" | "right"; }) { return ( ); } export default ArrowIcon; ================================================ FILE: src/components/data-table/TableHead.tsx ================================================ import clsx from "clsx"; import { TableHeaderProps } from "react-table"; import "./index.css"; import ArrowIcon from "#src/components/data-table/Arrow.jsx"; export default function TableHead({ itemKey, headProps, children, align = "center", isSorted, isSortedDesc, }: { itemKey: string; children: React.ReactNode; align: "left" | "center" | "right"; isSorted?: boolean; isSortedDesc?: boolean; headProps: TableHeaderProps; }) { return ( {children} ); } ================================================ FILE: src/components/data-table/index.css ================================================ .data-table, .data-table-filters-wrapper { border: 0; border-collapse: collapse; max-width: 1200px; margin: 0 auto; width: 100%; } .data-table-filters-wrapper { display: flex; justify-content: center; margin: 20px auto; width: 100%; } .data-table thead, .data-table tfoot { background: rgb(from var(--color-black) r g b / 0.4); position: sticky; top: 0; } .data-table thead { z-index: 1; } .data-table tbody tr { height: 69px; } .data-table thead tr:first-child { border-top: 4px solid var(--color-black-light); } .data-table tbody tr.last-row { height: 1px; } .data-table th { padding: 10px 5px 10px; } th:first-child, td.data-cell:first-child { border-left: 4px solid var(--color-black-light); } th:last-child, td.data-cell:last-child { border-right: 4px solid var(--color-black-light); } .data-cell, .data-table tfoot th { padding: 5px 15px; border-top: 4px solid var(--color-black-light); border-bottom: 4px solid var(--color-black-light); } .data-table .center-content { text-align: center; } .data-table .nowrap-content { white-space: nowrap; } .data-table .table-image { max-width: 64px; max-height: 64px; } .data-table .table-image + span { margin-left: 10px; } .data-table tr td { background-color: var(--color-gunmetal-dark); } .data-table tbody tr.expanded td { background-color: var(--color-gunmetal-dark); } .arrow-icon { fill: var(--color-gold-one); height: 10px; width: 10px; transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out; } .arrow-icon--up { transform: rotate(180deg); } .arrow-icon--down { transform: rotate(0deg); } .arrow-icon--left { transform: rotate(90deg); } .arrow-icon--right { transform: rotate(-90deg); } .header-sort-icon__icon.header-sort-icon__icon--visible { opacity: 1; } .header-sort-icon__icon.header-sort-icon__icon--hidden { opacity: 0; } .data-table .header-sort-icon-container { height: 10px; transition: height 0.2s ease-in-out; } .data-table .header-sort-icon-container--h-0 { height: 0px; } .data-table .header-sort-icon-container--ml-6 { margin-left: 6px; } .data-table .header-sort-icon-container--block { display: block; } div.no-data-info { display: flex; justify-content: center; } .table-wrapper { max-width: 100%; overflow-x: scroll; } .cost-wrapper { padding: 5px 0; } .table-extra-row { text-align: center; } .data-table { .table-head--left { text-align: left; padding-left: 15px; } .table-head--right { text-align: right; } .table-head--center { padding-top: 20px; } } @media screen and (width >= 800px) { .table-wrapper { overflow-x: initial; } } ================================================ FILE: src/components/data-table/index.jsx ================================================ import { useEffect } from "react"; import { useTable, useSortBy, useExpanded, usePagination } from "react-table/index.js"; import { useInView } from "react-intersection-observer"; import useStateWithLocalStorage from "#src/hooks/useStateWithLocalStorage.jsx"; import formatPrice from "#src/modules/format-price.js"; import TableHead from "#src/components/data-table/TableHead.tsx"; import "./index.css"; function DataTable({ className, columns, sumColumns, data, extraRow, sortBy, sortByDesc, disableSortBy, autoResetSortBy, maxItems, nameFilter, autoScroll, onSort, headConfig = {}, }) { // Use the state and functions returned from useTable to build your UI // const [data, setData] = React.useState([]) const storageKey = columns .map(({ Header, id }) => { if (typeof id === "string") { return id; } if (!Header || typeof Header !== "string") { return ""; } return Header.toLowerCase() .replace(/\s/, "-") .replace(/[^a-zа-я-]/g, ""); }) .join(","); const [initialSortBy, storageSetSortBy] = useStateWithLocalStorage(storageKey, [ { id: sortBy, desc: sortByDesc, }, ]); const { ref, inView } = useInView({ threshold: 0, }); const { setSortBy, getTableProps, getTableBodyProps, headerGroups, page, rows, prepareRow, setPageSize, state: { sortBy: sortByState } = {}, state, } = useTable( { columns, data, initialState: { pageSize: maxItems || 10, sortBy: initialSortBy, }, autoResetSortBy: autoResetSortBy, disableSortBy, }, useSortBy, useExpanded, usePagination, ); useEffect(() => { storageSetSortBy(sortByState); if (typeof onSort === "function") { onSort(sortByState); } }, [storageSetSortBy, sortByState, onSort]); useEffect(() => { if (nameFilter && (sortByState[0]?.id === "name" || sortByState[0]?.id === undefined)) { setSortBy([]); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [nameFilter]); useEffect(() => { if (autoScroll && inView && data.length > state.pageSize) { setPageSize(state.pageSize + 50); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [inView, autoScroll]); const getRows = () => { let rowContainer = rows; if (maxItems) { rowContainer = page; } return rowContainer.map((row, i) => { prepareRow(row); const tableProps = { ...row.getRowProps() }; tableProps.className = `${row.depth >= 1 ? "expanded" : ""}`; delete tableProps.key; return ( {row.cells.map((cell, i) => { const cellProps = { ...cell.getCellProps() }; const cellKey = cellProps.key; delete cellProps.key; return ( {cell.render("Cell")} ); })} ); }); }; // Render the UI for your table return (
    {headerGroups.map((headerGroup) => ( { if (propName !== "key") { props[propName] = headerGroup.getHeaderGroupProps()[propName]; } return props; }, {})} > {headerGroup.headers.map((column) => { const { key, ...restProps } = column.getHeaderProps( column.getSortByToggleProps({ title: undefined }), ); const headAlign = headConfig?.align?.find((h) => h.id === column.id)?.align || "center"; return ( {column.render("Header")} ); })} ))} {getRows()} {extraRow && ( )} {sumColumns && rows.length > 1 && ( {columns.map((col, colIndex) => ( ))} )}
    {extraRow}
    {col.summable ? formatPrice( rows .map((row) => { const val = row.cells[colIndex].value; const count = row.original?.count ? row.original.count : 1; if (isNaN(val)) { return false; } return val * count; }) .filter(Boolean) .reduce( (previousValue, currentValue) => previousValue + currentValue, 0, ), ) : ""}
    ); } export default DataTable; ================================================ FILE: src/components/em-item-tag/index.jsx ================================================ import { Link } from "react-router-dom"; function EmItemTag({ children }) { // console.log(props); const itemName = children[0].toLowerCase().replace(/ /g, "-"); // ({node, ...props}) => return {children}; } export default EmItemTag; ================================================ FILE: src/components/filter/index.css ================================================ .filter-wrapper { left: 0; line-height: 24px; margin: 0 auto; max-width: 1200px; overflow: hidden; padding: 0; position: fixed; right: 0; top: 0; transform-origin: top; transform: scaleY(0); transition: transform 0.26s ease; z-index: 2; } .filter-wrapper.full-width { max-width: 100%; } .filter-content-wrapper { background-color: var(--color-gunmetal-dark); display: flex; flex-grow: 1; flex-wrap: wrap; justify-content: space-between; padding: 30px 10px; position: relative; gap: 10px; } .filter-wrapper-center .filter-content-wrapper { justify-content: center; gap: 20px; } .filter-wrapper.open { box-shadow: 0px 5px 15px 5px rgb(from var(--color-black) r g b / 0.7); overflow: visible; transform: scaleY(1); } .filter-item { display: flex; align-items: center; } .filter-toggle-icon-wrapper { bottom: 20px; position: fixed; right: 20px; width: 6vh; z-index: 1; } .filter-toggle-icon-wrapper svg { margin: 5px; } .single-filter-wrapper { display: flex; align-items: center; } .single-filter-wrapper-wide { width: 400px; } .basic-multi-select { min-width: 110px; color: var(--color-gunmetal-dark); } .single-filter-wrapper-wide .basic-multi-select { flex-grow: 1; } .filter-input-wrapper { display: flex; align-items: center; } .filter-dropdown-wrapper { display: flex; align-items: center; } .filter-dropdown-select { min-width: 70px; } .filter-slider-wrapper { display: flex; justify-content: space-between; align-items: center; } .filter-input { padding: 4px; margin-left: 10px; margin-right: 10px; } .filter-slider-wrapper .MuiSlider-root { margin-left: 20px; } .button-group-wrapper { border: 1px solid var(--color-black-light); display: flex; flex-wrap: wrap; justify-content: space-between; width: 100%; } .button-group-button { border-radius: 0; background-color: var(--color-gunmetal-dark); color: var(--color-gold-one); height: 40px; width: 40px; outline: none; } .button-group-text-button { padding: 0 10px; width: auto; } .button-group-button img { max-height: 100%; opacity: 0.6; } .button-group-button:hover, .button-group-button.selected { background-color: var(--color-black-light); cursor: pointer; } .button-group-button:hover img, .button-group-button.selected img { opacity: 1; } .button-group-button:first-child { border-top-left-radius: 4px; border-bottom-left-radius: 4px; } .button-group-button:last-child { border-top-right-radius: 4px; border-bottom-right-radius: 4px; } @media screen and (width >= 800px) { .button-group-wrapper { margin-right: 10px; gap: 10px; width: auto; } .filter-content-wrapper { background: none; justify-content: flex-end; padding: 20px 0px; } .filter-toggle-icon-wrapper { display: none; } .filter-wrapper { transform: scaleY(1); overflow: initial; position: relative; } } ================================================ FILE: src/components/filter/index.jsx ================================================ import { useState, useRef, useEffect } from "react"; import { useTranslation } from "react-i18next"; import Select from "react-select"; import { Slider, Switch, Tooltip } from "@mui/material"; import "./index.css"; import { Fab } from "@mui/material"; import { mdiTune } from "@mdi/js"; import { Icon } from "@mdi/react"; import { t } from "i18next"; const ConditionalWrapper = ({ condition, wrapper, children }) => { return condition ? wrapper(children) : children; }; function ButtonGroupFilterButton({ tooltipContent, onClick, content, selected, type = "image" }) { return ( ); } function ButtonGroupFilter({ children }) { return
    {children}
    ; } function SliderFilter({ label, value, defaultValue, min, max, marks, onChange, style = {}, size = "medium", track = "normal", step = 1, valueLabelDisplay = "auto", }) { if (!!marks && !Array.isArray(marks)) { marks = Object.keys(marks).map((val) => { return { label: String(marks[val]), value: parseInt(val), }; }); } return (
    {label}
    ); } function RangeFilter({ label, defaultValue, value, min, max, marks, onChange, track = "normal", style = {}, size = "medium", step = 1, valueLabelDisplay, }) { if (!!marks && !Array.isArray(marks)) { marks = Object.keys(marks).map((val) => { return { label: String(marks[val]), value: parseInt(val), }; }); } return (
    {label}
    ); } function ToggleFilter({ label, onChange, checked, tooltipContent, disabled }) { return ( { return ( {children} ); }} > ); } const selectFilterStyle = { multiValueLabel: (provided) => ({ ...provided, color: "var(--color-yellow-light)", padding: "0.1rem", }), menu: (provided) => ({ ...provided, backgroundColor: "var(--color-gunmetal-dark)", border: "2px solid var(--color-gold-two)", borderRadius: 0, }), control: (provided) => ({ ...provided, backgroundColor: "var(--color-gunmetal-dark)", border: "2px solid var(--color-gold-two)", borderRadius: 0, }), menuList: (provided) => ({ ...provided, color: "var(--color-yellow-light)", borderRadius: 0, }), option: (provided) => ({ ...provided, "color": "var(--color-white)", "backgroundColor": "var(--color-gunmetal-dark)", "borderRadius": 0, "&:hover": { backgroundColor: "var(--color-gold-two)", color: "var(--color-gunmetal-dark)", fontweight: 700, }, }), singleValue: (provided) => ({ ...provided, color: "var(--color-gold-one)", }), multiValue: (provided) => ({ ...provided, backgroundColor: "#5F553B", color: "var(--color-white)", }), }; function SelectFilter({ placeholder, defaultValue, value, options, onChange, isMulti = false, label, tooltip, tooltipDisabled, onMenuOpen, onMenuClose, wide, parentRef, }) { if (tooltipDisabled) { tooltip = undefined; } return ( { return ( {children} ); }} > { return ( ); }} > ); } function Filter({ center, children, fullWidth }) { const [showFilter, setShowFilter] = useState(false); const toggleButton = useRef(); useEffect(() => { if (!toggleButton.current) { return; } const intersectionObserver = new IntersectionObserver((entries) => { if (!toggleButton.current) { return; } if (!entries[0].isIntersecting && showFilter) { setShowFilter(false); } }); intersectionObserver.observe(toggleButton.current); return () => intersectionObserver.disconnect(); }, [showFilter]); return [
    setShowFilter(!showFilter)} ref={toggleButton} > setShowFilter(!showFilter)} >
    ,
    {/*
    {`Prices updated: ${new Date().toLocaleDateString()}`}
    */} {children}
    , ]; } export { Filter, ToggleFilter, SelectFilter, InputFilter, SliderFilter, ButtonGroupFilter, ButtonGroupFilterButton, RangeFilter, SelectItemFilter, }; ================================================ FILE: src/components/flea-price-cell/index.jsx ================================================ import { Icon } from "@mdi/react"; import { mdiCloseOctagon, mdiHelpRhombus, mdiTimerSand } from "@mdi/js"; import { useTranslation } from "react-i18next"; import { Tooltip } from "@mui/material"; import ValueCell from "../value-cell/index.jsx"; const FleaPriceCell = function (props) { const { t } = useTranslation(); if (props.row.original.types.includes("noFlea")) { return ( } /> ); } let noFleaTip = t("Not scanned on the Flea Market"); let noFleaIcon = mdiHelpRhombus; if (props.row.original.cached) { noFleaTip = t("Flea market prices loading"); noFleaIcon = mdiTimerSand; } return ( } /> ); }; export default FleaPriceCell; ================================================ FILE: src/components/footer/index.css ================================================ .footer-wrapper { background-color: var(--color-black); display: flex; flex-flow: wrap; gap: 30px; justify-content: center; margin-top: 50px; padding: 40px 10px 50px 10px; } .footer-wrapper svg { height: 20px; width: 20px; position: relative; top: 5px; } .footer-section-wrapper { width: 100%; } .copyright-wrapper { font-size: 12px; text-align: center; width: 100%; } @media screen and (width >= 800px) { .footer-section-wrapper { width: 20%; } } .discord { display: block; width: 320px; height: 70px; transition: all 0.5s ease-in-out; } .discord:hover { width: 320px; height: 250px; } ================================================ FILE: src/components/footer/index.tsx ================================================ import { Trans, useTranslation } from "react-i18next"; import { Link, useLocation } from "react-router-dom"; import { ReactComponent as DiscordIcon } from "#src/images/Discord.svg"; import { ReactComponent as GithubIcon } from "#src/images/Github.svg"; import { ReactComponent as XIcon } from "#src/images/X.svg"; import Contributors from "#src/components/contributors/index.jsx"; import OpenCollectiveButton from "#src/components/open-collective-button/index.jsx"; import UkraineButton from "#src/components/ukraine-button/index.jsx"; import "./index.css"; function Footer() { const { t } = useTranslation(); const location = useLocation(); if (location.pathname.startsWith("/map/")) { return ""; } return (

    {t("Tarkov.dev")}

    {/* prettier-ignore */}

    The whole platform is open source and focused around developers. All code is available on GitHub.

    {/* prettier-ignore */}

    If you wanna have a chat, ask questions or request features, we have a Discord server.

    {/* prettier-ignore */}

    Follow us on X for all the latest updates.

    {t("About")} tarkov.dev

    {t("Contributors")}

    {t("Massive thanks to all the people who help build and maintain this project!")}

    {t("Made with ❤️ by:")}

    {t("Supporters")}

    {/* prettier-ignore */}

    We encourage everyone who can to donate to support the people of Ukraine using the button below.

    {/* prettier-ignore */}

    If you'd also like to support this project, you can make a donation and/or become a backer on Open Collective.

    {t("Item Data")}

    {t("Fresh EFT data courtesy of")}{" "} Tarkov-Changes

    {t("Additional data courtesy of")}{" "} SPT

    {t("Map Icons")}

    {t("Map marker icons by")}{" "} {t("The Official Escape From Tarkov Wiki")}

    {t("Resources")}

    {t("Tarkov.dev API")}

    Tarkov Monitor

    {t("{{bot}} integration", { bot: "Moobot" })}

    {t("{{bot}} integration", { bot: "Nightbot" })}

    {t("{{bot}} integration", { bot: "StreamElements" })}

    {t("Stash Discord Bot")}

    {t("External resources")}

    TarkovTracker.org

    RatScanner

    {t( "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.", )}
    {t( "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.", )}
    {t("version")} {": "} {} {__COMMIT_HASH__}
    ); } export default Footer; ================================================ FILE: src/components/item-cost/index.css ================================================ .hidden { display: none; } .item-cost-custom-price { background-color: var(--color-gunmetal-dark); border: var(--color-gold-two) 2px solid; color: var(--color-gold-one); padding: 4px; width: 5em; } .item-cost-cash-sell { color: #c89898; } .item-cost-muted-green { color: var(--color-green-light); } .item-cost-muted-red { color: var(--color-red-light); } .item-cost-barter-icon { border: 0; position: relative; top: 2px; width: 14px; margin-right: 3px; } .craft-barter-icon { vertical-align: middle; margin-right: 3px; } ================================================ FILE: src/components/item-cost/index.jsx ================================================ import { useMemo, useState, useEffect } from "react"; import { Tooltip } from "@mui/material"; import { useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiTimerSand, mdiCloseBox, mdiCheckboxMarked, mdiProgressWrench } from "@mdi/js"; import BarterTooltip from "../barter-tooltip/index.jsx"; import formatPrice from "../../modules/format-price.js"; import { setCustomSellValue } from "../../features/items/index.js"; import "./index.css"; const ConditionalWrapper = ({ condition, wrapper, children }) => { return condition ? wrapper(children) : children; }; function ItemCost({ itemId, count, price = 0, vendor = { name: "N/A", normalizedName: "unknown" }, priceType = "cash", priceDetails, isTool, allowAllSources = false, crafts, barters, useBarterIngredients, useCraftIngredients, }) { const dispatch = useDispatch(); const { t } = useTranslation(); const [customPrice, setCustomPrice] = useState(price); const [editingCustomPrice, setEditingCustomPrice] = useState(false); useEffect(() => { setCustomPrice(price); }, [price, setCustomPrice]); if (barters && typeof useBarterIngredients === "undefined") { useBarterIngredients = true; } if (crafts && typeof useCraftIngredients === "undefined") { useCraftIngredients = true; } let { displayPrice, tooltip, displayImage } = useMemo(() => { let displayPrice = ""; let tooltip = false; let displayImage = ""; if (vendor.normalizedName !== "unknown") { displayImage = ( {vendor.name} ); } if (priceType === "cached") { displayPrice = count; displayImage = ; tooltip = t("Flea market prices loading"); } else if (isTool) { displayPrice = `${count} x ${formatPrice(price)} = ${formatPrice(count * price)}`; } else { displayPrice = ( {count} x { setEditingCustomPrice(true); }} > {formatPrice(price)} {priceType === "custom" ? "*" : ""} { let sanitized = e.target.value.replaceAll(/[^0-9]/g, ""); if (sanitized) { sanitized = parseInt(sanitized); } setCustomPrice(sanitized); }} /> { dispatch( setCustomSellValue({ itemId: itemId, price: customPrice, }), ); setEditingCustomPrice(false); }} /> { dispatch( setCustomSellValue({ itemId: itemId, price: false, }), ); setEditingCustomPrice(false); }} /> {` = ${formatPrice(count * price)}`} ); } return { displayPrice: displayPrice, tooltip: tooltip, displayImage: displayImage }; }, [ dispatch, t, vendor, priceType, itemId, count, price, isTool, customPrice, setCustomPrice, editingCustomPrice, setEditingCustomPrice, ]); if (priceType === "barter") { displayImage = ( {t("Barter")} ); tooltip = ( ); } else if (priceType === "craft") { displayImage = ; tooltip = ( ); } else if (priceType === "cash-sell" && !isTool && price !== 0) { displayPrice = {displayPrice}; tooltip = t("This item can only be sold to trader"); } return ( { return ( {children} ); }} >
    {displayImage} {displayPrice}
    ); } export default ItemCost; ================================================ FILE: src/components/item-grid/Item.jsx ================================================ import { Link } from "react-router-dom"; import ItemTooltip from "./ItemTooltip.jsx"; import ItemIcon from "./ItemIcon.jsx"; // const sizesNotToRotate = [ // '3x2', // '4x2', // '4x1', // '5x1', // '5x2', // '5x3', // '6x1', // '7x1', // ]; // const sizesToAlwaysRotate = ['2x3']; function Item(props) { let imgSrc = props.src; //const gridSize = `${props.width}x${props.height}`; // // if (props.width > props.height && !sizesNotToRotate.includes(gridSize)) { // imgSrc = `//images.weserv.nl/?url=${encodeURIComponent(imgSrc)}&ro=-90`; // } else if (sizesToAlwaysRotate.includes(gridSize)) { // imgSrc = `//images.weserv.nl/?url=${encodeURIComponent(imgSrc)}&ro=-90`; // } return ( {props.name} ); } export default Item; ================================================ FILE: src/components/item-grid/ItemIcon.jsx ================================================ function ItemIcon(props) { let sellTo = props.sellTo; let sellToNormalized = props.sellToNormalized; let count = props.count; let sell; if (sellToNormalized) { sell = ( {sellTo} ); } else { sell = count; } return {sell}; } export default ItemIcon; ================================================ FILE: src/components/item-grid/ItemTooltip.jsx ================================================ import { useTranslation } from "react-i18next"; import formatPrice from "../../modules/format-price.js"; function ItemTooltip(props) { const { t } = useTranslation(); if (!props.pricePerSlot) { return false; } return (
    {props.name}
    {t("Value")}: {formatPrice(props.pricePerSlot * props.slots)}
    {t("Per slot")}: {formatPrice(props.pricePerSlot)}
    {t("Sell to")}: {props.sellTo}
    ); } export default ItemTooltip; ================================================ FILE: src/components/item-grid/index.css ================================================ .item-group-wrapper { border: 1px solid var(--color-black-light); background-color: var(--color-gunmetal-dark); display: flex; flex-wrap: wrap; margin-bottom: 10px; padding: 10px 0; width: 100%; --grid-base: 48px; } .item-group-wrapper .text-label { flex-grow: 1; font-size: 10px; position: absolute; top: 0; } .item-group-wrapper.filter-wrapper button { border: 0; background-color: rgb(239 239 239); padding: 10px; } .item-group-title { align-items: center; display: flex; flex-flow: wrap; justify-content: space-around; padding: 10px; text-align: center; width: 100%; } .item-group-wrapper.big { font-size: 40px; } .item-group-subtitle-wrapper { align-items: center; display: flex; flex-flow: column nowrap; font-size: 14px; } .item-group-subtitle-wrapper .note { color: var(--color-gray-light); } .item-group-items { display: grid; grid-auto-rows: var(--grid-base); grid-template-columns: repeat(auto-fill, minmax(var(--grid-base), 1fr)); gap: 1px; margin: auto; width: 90vw; } .sell-to-icon { background-color: rgb(from var(--color-black) r g b / 0.8); border-top-left-radius: 3px; bottom: 1px; color: var(--color-gold-one); font-size: 14px; height: 24px; line-height: 24px; position: absolute; right: 1px; text-align: center; width: 24px; } .sell-to-icon img { height: 24px; width: 24px; } .grid-item { position: relative; } .grid-item-tooltip { background-color: rgb(from var(--color-black) r g b / 0.8); color: #fff; font-size: 12px; opacity: 0; padding: 5px 10px; pointer-events: none; position: absolute; right: 90%; text-align: right; top: 50%; transform: translateY(-50%); transition: all 0.15s ease; white-space: nowrap; z-index: 1; } .grid-item:hover .grid-item-tooltip { right: 100%; opacity: 1; } .grid-item img { height: 100%; width: 100%; } .grid-item-tooltip-title { font-weight: bold; } .grid-item.grid-item-1x1 { height: var(--grid-base); width: var(--grid-base); } .grid-item.grid-item-2x1 { height: calc(2 * var(--grid-base)); width: var(--grid-base); grid-row-end: span 2; } .grid-item.grid-item-1x2, .grid-item.grid-item-1x3, .grid-item.grid-item-3x1, .grid-item.grid-item-6x2 { height: calc(2 * var(--grid-base)); width: var(--grid-base); grid-row-end: span 2; } .grid-item.grid-item-4x1, .grid-item.grid-item-5x1, .grid-item.grid-item-6x1, .grid-item.grid-item-7x1 { height: var(--grid-base); width: calc(3 * var(--grid-base)); grid-column-end: span 3; } .grid-item.grid-item-2x2, .grid-item.grid-item-3x3, .grid-item.grid-item-3x4, .grid-item.grid-item-4x3, .grid-item.grid-item-4x4, .grid-item.grid-item-4x5, .grid-item.grid-item-5x5, .grid-item.grid-item-4x8 { height: calc(2 * var(--grid-base)); width: calc(2 * var(--grid-base)); grid-row-end: span 2; grid-column-end: span 2; } .grid-item.grid-item-2x3, .grid-item.grid-item-3x2, .grid-item.grid-item-5x2, .grid-item.grid-item-5x3 { height: calc(2 * var(--grid-base)); width: calc(3 * var(--grid-base)); grid-row-end: span 2; grid-column-end: span 3; } .grid-item.grid-item-4x2 { height: calc(2 * var(--grid-base)); width: calc(4 * var(--grid-base)); grid-row-end: span 2; grid-column-end: span 4; } @media screen and (width >= 1920px) { .item-group-wrapper { --grid-base: 64px; } } @media screen and (width >= 800px) { .item-group-title { width: 10vw; } .item-group-wrapper { flex-wrap: nowrap; } .item-group-wrapper .text-label { bottom: -4px; right: 30px; top: auto; } .barter-class-wrapper { width: 100%; } .item-group-subtitle-wrapper { width: 100%; } .item-group-subtitle-wrapper > div { flex-grow: 1; } } ================================================ FILE: src/components/item-grid/index.jsx ================================================ import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import ItemImage from "../item-image/index.jsx"; import ItemTooltip from "./ItemTooltip.jsx"; import ItemIcon from "./ItemIcon.jsx"; import formatPrice from "../../modules/format-price.js"; import "./index.css"; const getSubtitle = (text, minPrice, maxPrice, t) => { if (minPrice || maxPrice) { return (
    {formatPrice(maxPrice)}
    {"⇩"}
    {formatPrice(minPrice)}
    {t("per slot")}
    ); } return
    {text}
    ; }; function ItemGrid(props) { const { t } = useTranslation(); let minPrice = false; let maxPrice = false; for (const item of props.items) { if (!minPrice || item.pricePerSlot < minPrice) { minPrice = item.pricePerSlot; } if (!maxPrice || item.pricePerSlot > maxPrice) { maxPrice = item.pricePerSlot; } } minPrice = Math.ceil(minPrice / 250) * 250; maxPrice = Math.ceil(maxPrice / 250) * 250; let className = "item-group-wrapper"; if (props.name.length <= 2) { className = `${className} big`; } return (
    {props.name}
    {getSubtitle(props.subtitle, minPrice, maxPrice, t)} {props.extraTitleProps}
    {props.items.map((item) => ( ))}
    ); } export default ItemGrid; ================================================ FILE: src/components/item-icon-list/index.jsx ================================================ import { mdiAccountGroup, mdiAmmunition, mdiHammerWrench, mdiFinance, mdiCached, mdiProgressWrench, mdiMap, mdiViewGrid, mdiTshirtCrew, mdiBagPersonal, mdiPliers, mdiArchive, mdiRacingHelmet, mdiSunglasses, mdiGasCylinder, mdiPistol, mdiHeadset, mdiKeyVariant, mdiMagazineRifle, mdiHandPointingLeft, mdiFoodForkDrink, mdiTshirtCrewOutline, mdiBottleWine, } from "@mdi/js"; const map = { mdiAccountGroup, mdiAmmunition, mdiHammerWrench, mdiFinance, mdiCached, mdiProgressWrench, mdiMap, mdiViewGrid, mdiTshirtCrew, mdiBagPersonal, mdiPliers, mdiArchive, mdiRacingHelmet, mdiSunglasses, mdiGasCylinder, mdiPistol, mdiHeadset, mdiKeyVariant, mdiMagazineRifle, mdiHandPointingLeft, mdiFoodForkDrink, mdiTshirtCrewOutline, mdiBottleWine, }; function ItemIconList(key) { return map[key]; } export default ItemIconList; ================================================ FILE: src/components/item-image/index.css ================================================ .item-image-mask { background: linear-gradient(to left, var(--color-gold-two) 20%, var(--color-gold-one) 40%, var(--color-gold-one) 60%, var(--color-gold-two) 80%); background-size: 200% auto; width: 200px; height: 200px; opacity: 0.9; animation: shine 1s linear infinite; } @keyframes shine { to { background-position: -200% center; } } @keyframes shine { to { background-position: -200% center; } } .react-simple-image-viewer__modal-content img { max-width: 100% !important; max-height: 100% !important; } .item-image-fir { max-width: 16px; max-height: 16px; } .item-image-count { background-color: rgb(from var(--color-black) r g b / 0.8); border-top-left-radius: 3px; color: var(--color-gold-one); font-size: 14px; height: 18px; line-height: 20px; padding: 0 5px; text-align: center; } ================================================ FILE: src/components/item-image/index.jsx ================================================ import React, { useState, useEffect, useRef, useMemo, useCallback } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { Link, useNavigate } from "react-router-dom"; import ImageViewer from "react-simple-image-viewer"; import { useTranslation } from "react-i18next"; import { Tooltip } from "@mui/material"; import ResizeObserver from "resize-observer-polyfill"; import "./index.css"; const colors = { black: { r: 0, g: 0, b: 0, alpha: 77 / 255 }, blue: { r: 28, g: 65, b: 86, alpha: 77 / 255 }, default: { r: 127, g: 127, b: 127, alpha: 77 / 255 }, green: { r: 21, g: 45, b: 0, alpha: 77 / 255 }, grey: { r: 29, g: 29, b: 29, alpha: 77 / 255 }, orange: { r: 60, g: 25, b: 0, alpha: 77 / 255 }, red: { r: 109, g: 36, b: 24, alpha: 77 / 255 }, violet: { r: 76, g: 42, b: 85, alpha: 77 / 255 }, yellow: { r: 104, g: 102, b: 40, alpha: 77 / 255 }, }; function ItemImage({ item, backgroundScale = 1, imageField = "baseImageLink", nonFunctionalOverlay = false, imageViewer = false, children = "", attributes = [], count, isFIR = false, isTool = false, nonFunctional = false, linkToItem = false, fullNameTooltip = false, trader, station, className, style, imageLink, }) { const { t } = useTranslation(); const navigate = useNavigate(); const refContainer = useRef(); /*const [containerDimensions, setDimensions] = useState({ width: 0, height: 0 }); useEffect(() => { if (!refContainer.current) { return; } const resizeObserver = new ResizeObserver(() => { setDimensions({ width: refContainer.current.offsetWidth, height: refContainer.current.offsetHeight, }); }); resizeObserver.observe(refContainer.current); return () => resizeObserver.disconnect(); }, []);*/ const refImage = useRef(); const [imageDimensions, setImageDimensions] = useState({ width: 0, height: 0, }); const [imageNaturalDimensons, setNaturalImageDimensions] = useState({ width: 1, height: 1, }); const [customImageLoaded, setCustomImageLoaded] = useState(false); const [customImageLoadFailed, setCustomImageLoadFailed] = useState(false); useEffect(() => { if (!refImage.current) { return; } const resizeObserver = new ResizeObserver(() => { if (!refImage.current) { return; } setNaturalImageDimensions({ width: refImage.current.naturalWidth, height: refImage.current.naturalHeight, }); if ( refImage.current.width === imageDimensions.width && refImage.current.height === imageDimensions.height ) { return; } setImageDimensions({ width: refImage.current.width, height: refImage.current.height, }); }); const intersectionObserver = new IntersectionObserver((entries) => { if (!refImage.current) { return; } if (entries[0].isIntersecting) { resizeObserver.observe(refImage.current); intersectionObserver.disconnect(); } }); intersectionObserver.observe(refImage.current); return () => { intersectionObserver.disconnect(); resizeObserver.disconnect(); }; }, [imageDimensions]); const itemSize = useMemo(() => { const size = { width: 1, height: 1, }; if (item?.width) { size.width = item.width; size.height = item.height; } if (!imageLink) { return size; } if (imageNaturalDimensons.width === 0) { return size; } if (customImageLoadFailed) { return size; } const w = imageNaturalDimensons.width / 8; const h = imageNaturalDimensons.height / 8; size.width = (w - 1) / 63; size.height = (h - 1) / 63; return size; }, [item, imageLink, customImageLoadFailed, imageNaturalDimensons]); const testImageElement = useMemo(() => { if (!imageLink) { return ""; } return ( { setCustomImageLoaded(true); }} onError={(error) => { setCustomImageLoadFailed(true); }} /> ); }, [imageLink]); const imageUrl = useMemo(() => { if (!imageLink || customImageLoadFailed || !customImageLoaded) { return item[imageField]; } return imageLink; }, [item, imageField, imageLink, customImageLoadFailed, customImageLoaded]); const maxImageSize = useMemo(() => { const max = { width: itemSize.width * 63 + 1, height: itemSize.height * 63 + 1, }; if (imageField === "iconLink") { max.width = 64; max.height = 64; } if (imageField === "image8xLink") { max.width *= 8; max.height *= 8; } if (imageField === "image512pxLink") { max.width = 512; max.height = 512; } return max; }, [itemSize, imageField]); const imageScale = useMemo(() => { const w = imageDimensions.width || itemSize.width * 63 + 1; return w / (itemSize.width * 63 + 1); }, [imageDimensions, itemSize]); const loadingImage = useMemo(() => { if (!item.types?.includes("loading")) { return <>; } const loadingStyle = { WebkitMask: `url(${imageUrl}) center/cover`, mask: `url(${imageUrl}) center/cover`, }; return
    ; }, [item, imageUrl]); const [isViewerOpen, setIsViewerOpen] = useState(false); const openImageViewer = useCallback(() => { if (!imageViewer) { return; } setIsViewerOpen(true); }, [imageViewer]); const closeImageViewer = () => { setIsViewerOpen(false); }; const viewerBackgroundStyle = { backgroundColor: "rgba(0,0,0,.9)", zIndex: 20, maxWidth: "100%", maxHeight: "100%", }; /*const placeholderImage = useMemo(() => { if (!imageLink || mainImageLoaded) { return ''; } const imageStyle = {}; if (item.types?.includes('loading')) { imageStyle.display = 'none'; } if (imageViewer) { imageStyle.cursor = 'zoom-in'; } imageStyle.maxWidth = maxImageSize.width; imageStyle.maxHeight = maxImageSize.height; const img = {item.name}; if (linkToItem && !item.types.includes('quest')) { return {img} ; } return img; }, [imageLink, mainImageLoaded, item, imageField, maxImageSize, linkToItem, imageViewer, openImageViewer]);*/ const loadingIcon = useMemo(() => { if (!imageLink || customImageLoaded || customImageLoadFailed) { return ""; } const elementStyle = { position: "absolute", top: "0px", left: "0px", display: "flex", flexDirection: "column", alignItems: "flex-end", maxWidth: `${32}px`, maxHeight: `${32}px`, }; const imageStyle = { maxWidth: `${32}px`, maxHeight: `${32}px`, }; return (
    {t("Loading...")}
    ); }, [imageLink, customImageLoaded, customImageLoadFailed, t]); const imageElement = useMemo(() => { const imageStyle = {}; if (item.types?.includes("loading")) { imageStyle.display = "none"; } if (imageViewer) { imageStyle.cursor = "zoom-in"; } if (imageLink) { imageStyle.maxWidth = maxImageSize.width; imageStyle.maxHeight = maxImageSize.height; } //console.log(dimensions); const img = ( {item.name} ); if (linkToItem && !item.types.includes("quest")) { return {img}; } return img; }, [item, refImage, imageUrl, openImageViewer, imageViewer, linkToItem, maxImageSize, imageLink]); const textSize = useMemo(() => { return Math.min(12 * imageScale, 16); }, [imageScale]); const { colorString, gridPercentX, gridPercentY } = useMemo(() => { const color = colors[item.backgroundColor]; return { colorString: `${color.r}, ${color.g}, ${color.b}, ${color.alpha}`, gridPercentX: (1 / itemSize.width) * 100, gridPercentY: (1 / itemSize.height) * 100, }; }, [item, itemSize]); const nonFunctionalElement = useMemo(() => { if (!nonFunctionalOverlay || !item.types.includes("gun") || !item.properties?.defaultPreset) { return <>; } const nonFunctionalStyle = { position: "absolute", boxSizing: "border-box", top: `${1 * backgroundScale}px`, left: `${1 * backgroundScale}px`, height: `calc(100% - ${2 * backgroundScale}px)`, width: `calc(100% - ${2 * backgroundScale}px)`, fallbacks: [ { width: `-webkit-calc(100% - ${2 * backgroundScale}px)` }, { width: `-moz-calc(100% - ${2 * backgroundScale}px)` }, { height: `-webkit-calc(100% - ${2 * backgroundScale}px)` }, { height: `-moz-calc(100% - ${2 * backgroundScale}px)` }, ], backgroundColor: "#4400004f", }; if (imageViewer) { nonFunctionalStyle.cursor = "zoom-in"; } return
    ; }, [item, nonFunctionalOverlay, backgroundScale, openImageViewer, imageViewer]); const toolOverride = useMemo(() => { return isTool || attributes?.some((att) => att.name === "tool"); }, [attributes, isTool]); const borderColor = useMemo(() => { let color = "rgb(73, 81, 84)"; if (toolOverride) { color = "#0292c0"; } if (item.types.includes("gun")) { if (nonFunctional) { color = "#c00802"; } } return color; }, [item, toolOverride, nonFunctional]); const backgroundStyle = useMemo(() => { if (imageField === "iconLink") { const iconStyle = { position: "relative", maxHeight: `${imageDimensions.height || 64}px`, maxWidth: `${imageDimensions.width || 64}px`, }; if (toolOverride || nonFunctional) { iconStyle.outline = `1px solid ${borderColor}`; iconStyle.outlineOffset = `-1px`; } return iconStyle; } let sizeFactor = 1; if (imageField === "image512pxLink") { sizeFactor = 512 / (itemSize.width * 63 + 1); if (itemSize.height > itemSize.width) { sizeFactor = 512 / (itemSize.height * 63 + 1); } } if (imageField === "image8xLink") { sizeFactor = 8; } let width = imageDimensions.width || (itemSize.width * 63 + 1) * sizeFactor; let height = imageDimensions.height || (itemSize.height * 63 + 1) * sizeFactor; const gridSvg = () => ( ); const backgroundStyle = { backgroundImage: `url('data:image/svg+xml,${encodeURIComponent(renderToStaticMarkup(gridSvg()))}')`, backgroundSize: `${gridPercentX}% ${gridPercentY}%`, position: "relative", outline: `${1 * backgroundScale}px solid ${borderColor}`, outlineOffset: `-${1 * backgroundScale}px`, maxHeight: `${height}px`, maxWidth: `${width}px`, }; return backgroundStyle; }, [ backgroundScale, borderColor, colorString, imageField, gridPercentX, gridPercentY, itemSize, imageDimensions, toolOverride, nonFunctional, ]); const imageTextStyle = useMemo(() => { if (imageField === "iconLink" || item.types.includes("loading")) { return { display: "none" }; } const style = { position: "absolute", top: `${Math.min(backgroundScale + imageScale, 4)}px`, right: `${Math.min(backgroundScale + 1.5 * imageScale, 7)}px`, cursor: "default", color: "#a4aeb4", fontWeight: "bold", textShadow: "1px 1px 0 var(--color-black), -1px -1px 0 var(--color-black), 1px -1px 0 var(--color-black), -1px 1px 0 var(--color-black)", fontSize: `${textSize}px`, textAlign: "right", }; if (linkToItem) { style.cursor = "pointer"; } return style; }, [imageField, imageScale, textSize, backgroundScale, item, linkToItem]); const imageTextClick = useMemo(() => { if (!linkToItem) { return () => {}; } return () => { navigate(`/item/${item.normalizedName}`); }; }, [item, linkToItem, navigate]); const imageText = useMemo(() => { let element = (
    {item.shortName}
    ); if (fullNameTooltip && imageTextStyle.dispolay !== "none") { element = ( {element} ); } return element; }, [fullNameTooltip, imageTextClick, imageTextStyle, item]); const itemExtraStyle = { position: "absolute", bottom: `${backgroundScale}px`, right: `${backgroundScale}px`, display: "flex", flexDirection: "column", alignItems: "flex-end", }; const traderElementStyle = useMemo(() => { let scale = 24; if (item.width > 1 && item.height > 1) { scale = 48; } return { position: "absolute", bottom: `${backgroundScale}px`, left: `${backgroundScale}px`, display: "flex", flexDirection: "column", alignItems: "flex-end", maxWidth: `${scale * imageScale}px`, maxHeight: `${scale * imageScale}px`, }; }, [backgroundScale, imageScale, item]); const traderImageStyle = useMemo(() => { let scale = 24; if (item.width > 1 && item.height > 1) { scale = 48; } return { maxWidth: `${scale * imageScale}px`, maxHeight: `${scale * imageScale}px`, }; }, [imageScale, item]); return (
    {loadingImage} {/*placeholderImage*/} {imageElement} {nonFunctionalElement} {imageText}
    {isFIR && ( )} {count && ( {trader ? t("LL{{level}}", { level: count }) : count} )}
    {trader && (
    {trader.name}
    )} {station && (
    {station.name}
    )} {loadingIcon} {testImageElement} {children} {isViewerOpen && ( )}
    ); } export default ItemImage; ================================================ FILE: src/components/item-name-cell/index.css ================================================ .small-item-table-description-wrapper { align-items: center; display: flex; } .small-item-table-image-wrapper { margin-right: 10px; } .small-item-table-image-wrapper img { width: 32px; height: 32px; } .small-item-table-name-wrapper cite { display: none; } .item-fir { position: absolute; bottom: 0; right: 0; margin-bottom: 4px; max-width: 10px; max-height: 10px; } @media screen and (width >= 800px) { .small-item-table-image-wrapper img { width: 64px; height: 64px; } .small-item-table-name-wrapper cite { display: block; } .item-fir { max-width: 16px; max-height: 16px; } } ================================================ FILE: src/components/item-name-cell/index.jsx ================================================ import { Link } from "react-router-dom"; import ContainedItemsList from "../contained-items-list/index.jsx"; import "./index.css"; function ItemNameCell(props) { let { item, showContainedItems, showRestrictedType } = props; if (!item) { item = props.row.original; } let firImage = ""; if (item.foundInRaid) { firImage = ( ); } return (
    {item.name} {firImage}
    {item.name} {item.count > 1 ? ` x ${item.count}` : ""} {showRestrictedType && ( )} {showContainedItems && (item.properties?.grids || item.properties?.slots) && ( )}
    ); } export default ItemNameCell; ================================================ FILE: src/components/item-search/index.css ================================================ .item-search { position: relative; margin-bottom: 10px; } .item-search input[type='text'] { font-size: 20px; padding: 12px 10px; width: 100%; max-height: 50px; } .item-list-wrapper { background-color: var(--color-black-light); position: absolute; top: 56px; width: 100%; z-index: 1; } .search-result-wrapper { align-items: center; display: flex; padding: 5px 10px; } .search-result-wrapper.active { background-color: #fff; } .search-result-wrapper img { margin-right: 10px; max-width: 32px; } .search-tip-wrapper { display: none; pointer-events: none; padding: 6px 10px; margin: 8px; } @media screen and (width >= 800px) { .search-tip-wrapper { border: 2px solid var(--color-gold-two); display: inline-flex; } } .search-type-selector { display: inline-flex; margin: 5px; } .search-extras-wrapper { display: block; position: absolute; right: 0px; top: 0px; z-index: 20; } .item-search-item-image { vertical-align: middle; } .item-search-separator { margin-left: 5px; margin-right: 5px; } img.item-search-price { max-width: 16px; max-height: 16px; vertical-align: middle; } .item-search-result-parts-wrapper { z-index: 1; } ================================================ FILE: src/components/item-search/index.jsx ================================================ import { useMemo, useState, useCallback, useEffect, useRef } from "react"; import { Link, useNavigate, useLocation } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { useHotkeys } from "react-hotkeys-hook"; import debounce from "lodash.debounce"; import { Tooltip } from "@mui/material"; import useKeyPress from "../../hooks/useKeyPress.jsx"; import itemSearch from "../../modules/item-search.js"; import { SelectFilter } from "../filter/index.jsx"; import formatPrice from "../../modules/format-price.js"; import "./index.css"; import useItemsData from "../../features/items/index.js"; import useQuestsData from "../../features/quests/index.js"; function ItemSearch({ defaultValue, onChange, placeholder, autoFocus, showDropdown, defaultSearch = "item", showSearchTypeSelector = true, }) { const { data: items } = useItemsData(); const { data: tasks } = useQuestsData(); const { t } = useTranslation(); const [nameFilter, setNameFilter] = useState(defaultValue || ""); const [searchFor, setSearchFor] = useState(defaultSearch || "item"); const searchTypeSelectRef = useRef(); const [cursor, setCursor] = useState(0); const [isFocused, setIsFocused] = useState(false); const downPress = useKeyPress("ArrowDown"); const upPress = useKeyPress("ArrowUp"); const enterPress = useKeyPress("Enter"); let navigate = useNavigate(); let location = useLocation(); const inputRef = useRef(null); const placeholderText = useMemo(() => { if (placeholder) { return placeholder; } // t('Search item...') // t('Search task...') return t(`Search ${searchFor}...`); }, [placeholder, searchFor, t]); const selectPlaceholder = useMemo(() => { if (searchFor === "task") { return t("Tasks"); } return t("Items"); }, [t, searchFor]); useHotkeys("ctrl+q", () => { if (inputRef?.current.scrollIntoView) { inputRef.current.scrollIntoView({ behavior: "smooth", block: "start", }); } inputRef?.current.focus(); }); const debouncedOnChange = useRef( debounce((newValue) => { onChange(newValue); }, 300), ).current; const handleNameFilterChange = useCallback( (e) => { setNameFilter(e.target.value.toLowerCase()); if (onChange) { debouncedOnChange(e.target.value.toLowerCase()); } }, [setNameFilter, debouncedOnChange, onChange], ); const handleSearchTypeChange = useCallback( (e) => { setSearchFor(e.value.toLowerCase()); inputRef?.current.focus(); }, [setSearchFor], ); useEffect(() => { if (downPress) { setCursor((prevState) => Math.min(prevState + 1, 9)); } }, [downPress]); useEffect(() => { if (upPress) { setCursor((prevState) => (prevState > 0 ? prevState - 1 : prevState)); } }, [upPress]); if (autoFocus && window?.matchMedia && window.matchMedia("(max-width: 600px)").matches) { autoFocus = false; } const data = useMemo(() => { if (!nameFilter || !showDropdown) { return []; } let returnData; if (searchFor === "task") { returnData = tasks .filter((task) => { if (nameFilter.length === 0) { return true; } return task.name.toLowerCase().includes(nameFilter.toLowerCase()) || task.id === nameFilter; }) .map((task) => { return { ...task, itemLink: `/task/${task.normalizedName}`, displayName: task.name, }; }); } else { returnData = items .map((itemData) => { const formattedItem = { id: itemData.id, name: itemData.name, shortName: itemData.shortName, normalizedName: itemData.normalizedName, avg24hPrice: itemData.avg24hPrice, lastLowPrice: itemData.lastLowPrice, iconLink: itemData.iconLink || `${process.env.PUBLIC_URL}/images/unknown-item-icon.jpg`, instaProfit: 0, itemLink: `/item/${itemData.normalizedName}`, types: itemData.types, buyFor: itemData.buyFor, sellFor: itemData.sellFor, width: itemData.width, height: itemData.height, }; const buyOnFleaPrice = itemData.buyFor.find( (buyPrice) => buyPrice.vendor.normalizedName === "flea-market", ); if (buyOnFleaPrice) { formattedItem.instaProfit = itemData.sellForTradersBest.priceRUB - buyOnFleaPrice.price; } return formattedItem; }) .filter((item) => { return !item.types.includes("disabled"); }); if (nameFilter.length > 0) { returnData = itemSearch(returnData, nameFilter); } returnData.forEach((formattedItem) => { formattedItem.displayName = [ {`${formattedItem.name}`}, {formattedItem.name}, ]; const sellOnFleaPrice = formattedItem.sellFor.find( (buyPrice) => buyPrice.vendor.normalizedName === "flea-market", ); if (sellOnFleaPrice) { let toolTip = [
    {t("Sell to Flea")}
    ]; if (formattedItem.width > 1 || formattedItem.height > 1) { toolTip.push(
    {`\n ${t("Per slot")}: ${formatPrice(Math.round(sellOnFleaPrice.priceRUB / (formattedItem.width * formattedItem.height)))}`}
    , ); } formattedItem.displayName.push( | {sellOnFleaPrice.vendor.name} {formatPrice(sellOnFleaPrice.priceRUB)} , ); } const sellToTrader = formattedItem.sellFor.reduce((best, buyPrice) => { if (buyPrice.vendor.normalizedName === "flea-market") { return best; } if (!best) { return buyPrice; } if (buyPrice.priceRUB > best.priceRUB) { return buyPrice; } return best; }, undefined); if (sellToTrader) { let toolTip = [
    {sellToTrader.vendor.name}
    ]; if (formattedItem.width > 1 || formattedItem.height > 1) { toolTip.push(
    {`\n ${t("Per slot")}: ${formatPrice(Math.round(sellToTrader.priceRUB / (formattedItem.width * formattedItem.height)))}`}
    , ); } formattedItem.displayName.push( | {sellToTrader.vendor} {formatPrice(sellToTrader.priceRUB)} , ); } formattedItem.displayName = ( {formattedItem.displayName} ); }); } return returnData; }, [searchFor, nameFilter, showDropdown, items, tasks, t]); useEffect(() => { if (enterPress && data[cursor]) { navigate(data[cursor].itemLink); } }, [cursor, enterPress, data, navigate]); useEffect(() => { setCursor(0); if (!location.search) { setNameFilter(""); } }, [location]); return (
    setIsFocused(true)} onBlur={() => setIsFocused(false)} ref={inputRef} />
    {!isFocused &&
    ctrl+q
    } {showSearchTypeSelector && (
    { setIsFocused(true); }} className="search-type-selector" placeholder={selectPlaceholder} parentRef={searchTypeSelectRef} options={[ { label: t("Items"), value: "item", selected: searchFor !== "task", }, { label: t("Tasks"), value: "task", selected: searchFor === "task", }, ]} />
    )}
    {showDropdown && (
    {data.map((item, index) => { if (index >= 10) { return null; } return ( {item.displayName} ); })}
    )}
    ); } export default ItemSearch; ================================================ FILE: src/components/items-for-hideout/index.css ================================================ .hideout-item-list thead { background: rgb( from var(--color-black) r g b / 0.4); position: sticky; top: 0; } .hideout-item-list th { padding: 20px 0; } .hideout-item-list { border-collapse: collapse; width: 100%; } .hideout-item-list-row { border-left: 4px solid var(--color-black-light); border-right: 4px solid var(--color-black-light); } .hideout-item-list-column { background-color: var(--color-gunmetal-dark); border-top: 4px solid var(--color-black-light); border-bottom: 4px solid var(--color-black-light); padding: 5px 15px; } .hideout-item-list-column:first-child { width: 70%; } .hideout-name-wrapper { align-items: center; display: flex; } .hideout-item-wrapper { align-items: center; display: flex; justify-content: flex-start; } .hideout-item-image-wrapper { font-size: 0; margin-right: 10px; } .hideout-item-image-wrapper img { width: 32px; height: 32px; } .hideout-item-list-extra-row { height: 69px; text-align: center; } .amount-wrapper { color: var(--color-gray-light); font-size: 14px; } .hideout-item-list thead tr:first-child { border-top: 4px solid var(--color-black-light); } ================================================ FILE: src/components/items-for-hideout/index.jsx ================================================ import { useMemo } from "react"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import useHideoutData from "../../features/hideout/index.js"; import useItemsData from "../../features/items/index.js"; import "./index.css"; function ItemsForHideout(props) { const { itemFilter, showAll } = props; const { t } = useTranslation(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const { data: hideout } = useHideoutData(); const { data: items } = useItemsData(); // Data manipulation section const data = useMemo(() => { return hideout.reduce((acc, curr) => { curr.levels.map((level) => { return acc.push( ...level.itemRequirements .filter((c) => { if (!c) { return false; } return c.item.id === itemFilter; }) .map((c) => { return { ...c, moduleName: curr.name, normalizedName: curr.normalizedName, imageLink: curr.imageLink, level: level.level, }; }), ); }); return acc; }, []); }, [hideout, itemFilter]); // Visual rendering section // if (data.length <= 0) { // return
    // {t('None')} //
    // } const unbuilt = useMemo(() => { return data.filter((module) => settings[module.normalizedName] < module.level); }, [data, settings]); let extraRow = false; if (data.length <= 0) { extraRow = t("No hideout modules requires this item"); } else if (unbuilt.length !== data.length && !showAll) { extraRow = ( <> {t("No unbuilt hideout modules for selected filters but some were hidden by ")} {t("your settings")} ); } let displayList = showAll ? data : unbuilt; return (
    {extraRow && ( )} {displayList .map((hideoutModule, k) => { const item = items.find((i) => i.id === hideoutModule.item.id); if (!item) { return false; } return ( ); }) .filter(Boolean)}
    {t("Hideout Module")} {t("Item")}
    {extraRow}
    {hideoutModule.moduleName}
    {hideoutModule.moduleName}
    {t("Level")} {hideoutModule.level}
    {item.name}
    {item.name}
    {t("Amount")}: {hideoutModule.quantity}
    ); } export default ItemsForHideout; ================================================ FILE: src/components/items-summary-table/index.css ================================================ .trader-unlock-wrapper { color: var(--color-gray); } .trader-station-level-unmet { color: var(--color-red); } ================================================ FILE: src/components/items-summary-table/index.jsx ================================================ import { useMemo } from "react"; import { useSelector } from "react-redux"; import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Tooltip } from "@mui/material"; import { Icon } from "@mdi/react"; import { mdiCloseOctagon, mdiHelpRhombus, mdiCached, mdiClipboardList, mdiTimerSand, mdiCloseCircle, mdiCheckCircle, } from "@mdi/js"; import DataTable from "../data-table/index.jsx"; import ItemNameCell from "../item-name-cell/index.jsx"; import ValueCell from "../value-cell/index.jsx"; import BarterTooltip from "../barter-tooltip/index.jsx"; import formatPrice from "../../modules/format-price.js"; import { getCheapestPrice } from "../../modules/format-cost-items.js"; import useItemsData, { useHandbookData } from "../../features/items/index.js"; import useBartersData from "../../features/barters/index.js"; import useCraftsData from "../../features/crafts/index.js"; import useTradersData from "../../features/traders/index.js"; import useHideoutData from "../../features/hideout/index.js"; import FleaMarketLoadingIcon from "../FleaMarketLoadingIcon.jsx"; import "./index.css"; const ConditionalWrapper = ({ condition, wrapper, children }) => { return condition ? wrapper(children) : children; }; function ItemsSummaryTable({ includeItems, includeTraders, includeStations }) { const { t } = useTranslation(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const { data: items } = useItemsData(); const { data: barters } = useBartersData(); const { data: crafts } = useCraftsData(); const { data: traders } = useTradersData(); const { data: stations } = useHideoutData(); const { data: handbook } = useHandbookData(); const data = useMemo(() => { const requiredItems = items .filter((item) => includeItems.some((it) => it.id === item.id)) .map((item) => { const includeItem = includeItems.find((includeItem) => includeItem.id === item.id); const foundInRaid = includeItem.attributes?.some( (att) => att.name === "foundInRaid" && att.value === "true", ); const formattedItem = { ...item, quantity: includeItem.quantity, foundInRaid, attribtues: includeItem.attributes, itemLink: `/item/${item.normalizedName}`, barters: barters.filter((barter) => barter.rewardItems[0].item.id === item.id), }; formattedItem.cheapestObtainInfo = getCheapestPrice(formattedItem, { barters, crafts, settings, useBarterIngredients: false, useCraftIngredients: false, }); formattedItem.cheapestPrice = formattedItem.cheapestObtainInfo.pricePerUnit; if (formattedItem.id === "5449016a4bdc2d6f028b456f") { formattedItem.cheapestPrice = 1; formattedItem.cheapestObtainInfo.price = 1; formattedItem.cheapestObtainInfo.priceRUB = 1; formattedItem.cheapestObtainInfo.pricePerUnit = 1; } formattedItem.totalPrice = formattedItem.cheapestObtainInfo.pricePerUnit * formattedItem.quantity; return formattedItem; }); for (const req of includeTraders) { const trader = traders.find((t) => t.id === req.trader.id); if (!trader) { continue; } requiredItems.push({ ...trader, quantity: req.level, itemLink: `/trader/${trader.normalizedName}`, iconLink: `images/traders/${trader.normalizedName}-icon.jpg`, types: [], barters: [], buyOnFleaPrice: 0, cheapestPrice: 0, requiredTraderLevel: trader.levels.find((l) => l.level === req.level), totalPrice: 0, levelMet: settings[trader.normalizedName] >= req.level, }); } for (const req of includeStations) { const station = stations.find((s) => s.id === req.station.id); requiredItems.push({ ...station, quantity: req.level, //itemLink: `#`, iconLink: station.imageLink, types: [], barters: [], buyOnFleaPrice: 0, cheapestPrice: 0, requiredStationLevel: station.levels.find((l) => l.level === req.level), totalPrice: 0, levelMet: settings[station.normalizedName] >= req.level, }); } return requiredItems; }, [items, includeItems, includeTraders, includeStations, settings, barters, crafts, traders, stations]); let displayColumns = useMemo(() => { const useColumns = [ { Header: t("Item"), id: "name", accessor: "name", Cell: (props) => { return ; }, }, { Header: t("Amount"), id: "quantity", accessor: "quantity", Cell: (props) => { let quantity = props.value.toLocaleString(); let tipContent = []; const priceContent = []; let addedClasses = ""; if (props.row.original.requiredTraderLevel) { const trader = props.row.original; priceContent.push( , ); if (!props.row.original.levelMet) { addedClasses = " trader-station-level-unmet"; } tipContent.push(
    {t("Player level: {{playerLevel}}", { playerLevel: trader.requiredTraderLevel.requiredPlayerLevel, })}
    , ); tipContent.push(
    {t("Reputation: {{reputation}}", { reputation: trader.requiredTraderLevel.requiredReputation, })}
    , ); tipContent.push(
    {t("Commerce: {{commerce}}", { commerce: formatPrice( trader.requiredTraderLevel.requiredCommerce, trader.currency.normalizedName, ), })}
    , ); } else if (props.row.original.requiredStationLevel) { if (!props.row.original.levelMet) { addedClasses = " trader-station-level-unmet"; } } return ( 0} wrapper={(children) => { return ( {children} ); }} >
    {quantity}
    ); }, }, { Header: t("Cheapest Price"), id: "cheapestPrice", accessor: "cheapestPrice", sortType: (a, b, columnId, desc) => { const aCheap = a.values.cheapestPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bCheap = b.values.cheapestPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aCheap - bCheap; }, Cell: (props) => { let tipContent = ""; const priceContent = []; const cheapestObtainInfo = props.row.original.cheapestObtainInfo; if (cheapestObtainInfo && cheapestObtainInfo.type !== "none") { let priceSource = ""; const displayedPrice = []; let taskIcon = ""; let barterIcon = ""; if (!cheapestObtainInfo.barter && !cheapestObtainInfo.craft) { if (props.row.original.id === "5449016a4bdc2d6f028b456f") { priceSource = ""; } else if (cheapestObtainInfo.vendor.normalizedName === "flea-market") { priceSource = cheapestObtainInfo.vendor.name; } else { let sellTo = ""; let loyalty = ` ${t("LL{{level}}", { level: cheapestObtainInfo.vendor.minTraderLevel })}`; if (cheapestObtainInfo.type === "cash-sell") { sellTo = `${t("Sell to")} `; loyalty = ""; } priceSource = `${sellTo}${cheapestObtainInfo.vendor.name}${loyalty}`; } if (cheapestObtainInfo.vendor?.taskUnlock) { taskIcon = ( ); tipContent = (
    {t("Task: {{taskName}}", { taskName: cheapestObtainInfo.vendor.taskUnlock.name, })}
    ); } } else if (cheapestObtainInfo.barter) { priceSource = `${cheapestObtainInfo.barter.trader.name} ${t("LL{{level}}", { level: cheapestObtainInfo.barter.level })}`; barterIcon = ( ); let barterTipTitle = ""; if (cheapestObtainInfo.barter.taskUnlock) { taskIcon = ( ); barterTipTitle = ( {t("Task: {{taskName}}", { taskName: cheapestObtainInfo.barter.taskUnlock.name, })} ); } tipContent = ( ); } else if (cheapestObtainInfo.craft) { const craft = cheapestObtainInfo.craft; const station = stations.find((s) => s.id === craft.station.id); priceSource = `${station.name} ${craft.level}`; let barterTipTitle = ""; if (craft.taskUnlock) { taskIcon = ( ); barterTipTitle = ( {t("Task: {{taskName}}", { taskName: craft.taskUnlock.name })} ); } tipContent = ( ); } displayedPrice.push(priceSource); displayedPrice.push(barterIcon); displayedPrice.push(taskIcon); priceContent.push(
    {formatPrice(props.value)}
    ); priceContent.push(
    {displayedPrice}
    , ); } else if (props.row.original.requiredTraderLevel) { priceContent.push("-"); } else if (props.row.original.requiredStationLevel) { priceContent.push("-"); } else if (props.row.original.foundInRaid) { priceContent.push(t("Found In Raid")); } else { tipContent = []; if (props.row.original.types.includes("noFlea")) { priceContent.push( , ); tipContent.push(
    {t("This item can't be sold on the Flea Market")}
    , ); } else if ( !( handbook.fleaMarket.enabled && settings.playerLevel >= Math.max(props.row.original.minLevelForFlea, handbook.fleaMarket.minPlayerLevel) ) ) { priceContent.push( , ); tipContent.push(
    {t("Flea Market not available")}
    ); } else { let tipText = t("Not scanned on the Flea Market"); let icon = mdiHelpRhombus; if (props.row.original.cached) { tipText = t("Flea market prices loading"); icon = mdiTimerSand; } priceContent.push( , ); tipContent.push(
    {tipText}
    ); } tipContent.push(
    {t("No trader offers available")}
    ); } return ( { return ( {children} ); }} >
    {priceContent}
    ); }, }, { Header: t("Cost"), id: "totalPrice", accessor: "totalPrice", Cell: (props) => { if (!props.value && props.row.original.cached) { return (
    ); } return ; }, }, ]; return useColumns; }, [t, items, barters, crafts, stations, settings, handbook]); const extraRow = ( <> {t("Cost")}:{" "} {formatPrice( data.reduce((previousValue, currentValue) => { return previousValue + currentValue.totalPrice; }, 0), )} ); return ( ); } export default ItemsSummaryTable; ================================================ FILE: src/components/loading/index.css ================================================ .loader-wrapper { display: flex; align-items: center; justify-content: space-around; height: 100vh; margin: 50px auto; } ================================================ FILE: src/components/loading/index.jsx ================================================ import { ScaleLoader } from "react-spinners"; import "./index.css"; function Loading() { return (
    ); } export default Loading; ================================================ FILE: src/components/loading-small/index.css ================================================ .loading-wipe { background: linear-gradient(to left, var(--color-gold-one) 20%, var(--color-gold-two) 40%, var(--color-gold-two) 60%, var(--color-gold-one) 80%); background-size: 200% auto; color: var(--color-black); background-clip: text; -webkit-text-fill-color: transparent; animation: shine 1s linear infinite; } @keyframes shine { to { background-position: -200% center; } } @keyframes shine { to { background-position: -200% center; } } ================================================ FILE: src/components/loading-small/index.jsx ================================================ import { useTranslation } from "react-i18next"; import "./index.css"; function LoadingSmall() { const { t } = useTranslation(); return
    {t("Loading...")}
    ; } export default LoadingSmall; ================================================ FILE: src/components/loyalty-level-icon/index.css ================================================ .loyalty-level-parent { filter: drop-shadow(2px 3px 1px rgb( from var(--color-black) r g b / 0.5)); left: 2px; position: absolute; top: 2px; width: 20px; } .loyalty-level-wrapper { background-color: var(--color-white); clip-path: polygon(100% 0, 100% 70%, 70% 100%, 0 100%, 0 0); color: var(--color-black); font-weight: 700; text-align: center; } ================================================ FILE: src/components/loyalty-level-icon/index.jsx ================================================ import "./index.css"; function loyaltyLevelIcon({ loyaltyLevel }) { let loyaltyLevelString = loyaltyLevel; if (loyaltyLevel < 4) { loyaltyLevelString = new Array(loyaltyLevel).fill("I").join(""); } return (
    {loyaltyLevelString}
    ); } export default loyaltyLevelIcon; ================================================ FILE: src/components/menu/CategoryMenu.jsx ================================================ import { useState, useRef } from "react"; import { Link } from "react-router-dom"; import { motion, AnimatePresence } from "framer-motion"; import { Icon } from "@mdi/react"; import { mdiChevronDown } from "@mdi/js"; const CategoryMenu = ({ title, items, to }) => { const [isOpen, setIsOpen] = useState(false); const timeoutRef = useRef(null); const handleMouseEnter = () => { if (timeoutRef.current) clearTimeout(timeoutRef.current); setIsOpen(true); }; const handleMouseLeave = () => { timeoutRef.current = setTimeout(() => { setIsOpen(false); }, 150); }; const renderItems = (itemsToRender) => { return itemsToRender.map((item, index) => { if (item.items?.length) { const isLongSection = item.items.length > 10; return (
  • {item.text}
      {renderItems(item.items)}
  • ); } return (
  • setIsOpen(false)}> {item.icon && ( )} {item.text}
  • ); }); }; const isMegaMenu = items.some((item) => item.items?.length > 10); return (
    {to ? ( {title} ) : ( {title} )}
    {isOpen && ( {renderItems(items)} )}
    ); }; export default CategoryMenu; ================================================ FILE: src/components/menu/MenuItem.jsx ================================================ import { mdiEarthBox } from "@mdi/js"; import { Icon } from "@mdi/react"; import { useState, useEffect } from "react"; import { Link, useNavigate, useMatch } from "react-router-dom"; function MenuItem(props) { const routeMatch = useMatch("/ammo/:currentAmmo"); let currentAmmo = ""; let ammoTypes = []; if (routeMatch) { currentAmmo = decodeURIComponent(routeMatch.params.currentAmmo); ammoTypes = currentAmmo.split(","); } const [checked, setChecked] = useState(ammoTypes.includes(props.displayText)); const navigate = useNavigate(); const handleChange = (event) => { setChecked(event.currentTarget.checked); if (!event.currentTarget.checked) { ammoTypes.splice(ammoTypes.indexOf(event.currentTarget.value), 1); } else { ammoTypes.push(event.currentTarget.value); ammoTypes.sort(); } navigate(`${props.prefix}/${ammoTypes.filter(Boolean).join(",")}`); }; useEffect(() => { if (currentAmmo) { setChecked(currentAmmo.split(",").includes(props.displayText)); } else { setChecked(false); } }, [currentAmmo, props.displayText]); const handleClick = (event) => { if (props.onClick) { props.onClick(); } }; const getCheckbox = () => { if (!props.checkbox) { return false; } return ; }; const getIcon = () => { if (props.icon) { return ; } else if (props.padding) { return ; } }; return (
  • {getCheckbox()} {getIcon()} {props.displayText}
  • ); } export default MenuItem; ================================================ FILE: src/components/menu/alert-config.js ================================================ const alertConfig = { // set this bool if the site alert should be enabled or not alertEnabled: false, // if alert should show on page load even if the user has closed it alwaysShow: false, // valid alert colors alertColors: { error: "#cd1e2f", info: "#0292c0", success: "#00a700", warning: "#ca8a00", }, // set this variable to the severity of the alert banner alertLevel: "info", // The text to display in the alert banner //text: '🌟 Flea market scanners are currently being leveled, and data for the {{patchVersion}} patch should be appearing soon! 🌟 If you enjoy using tarkov.dev, please consider donating to help keep it running. All donations go directly towards server costs and operational expenses. This banner will only be up for a week. Thank you! ❤️', //text: '🌟 Flea market scanners have been leveled, and flea market prices are being updated for patch {{patchVersion}}! 🌟 If you enjoy using tarkov.dev, please consider donating to help keep it running. All donations go directly towards server costs and operational expenses. This banner will only be up for a week. Thank you! ❤️', //text: 'We want to keep Tarkov.dev and its API free for all and without ads, but we\'ve been struggling with increased expenses. If you enjoy using tarkov.dev, please consider donating to help keep it running. All donations go directly towards server costs and operational expenses. Thank you! ❤️', text: "🌟 We now have some PVP flea price data in addition to the regular PVE flea prices.", textVariables: { patchVersion: "0.16.9" }, linkEnabled: false, linkText: "Donate", link: "https://opencollective.com/tarkov-dev", // when a banner with a specific key is hidden, it never shows for that user again // (unless they clear their browser cache) // use a different key to force new banners to display again bannerKey: "alertBanner-0.16.9-pvp-prices", }; export default alertConfig; ================================================ FILE: src/components/menu/index.css ================================================ :root { --nav-height: 64px; --glass-bg: rgb(18 18 18 / 0.85); --glass-border: rgb(210 175 120 / 0.15); --accent-gold: #d2af78; --accent-gold-hover: #e6c58c; --text-main: #f0f0f0; --text-muted: #a0a0a0; --bg-dark: #0a0a0a; } .navigation { position: sticky; top: 0; z-index: 1000; background: var(--glass-bg); backdrop-filter: blur(12px); border-bottom: 1px solid var(--glass-border); height: var(--nav-height); width: 100%; display: flex; align-items: center; transition: all 0.3s ease; } .nav-content { max-width: 1440px; margin: 0 auto; width: 100%; padding: 0 20px; display: flex; justify-content: space-between; align-items: center; } .nav-left { display: flex; align-items: center; gap: 30px; flex: 1; min-width: 0; transition: gap 0.3s ease; } @media (width <= 1100px) { .nav-left { gap: 15px; } } .branding { display: flex; align-items: center; text-decoration: none; } .logo { height: 32px; width: auto; max-width: 100%; object-fit: contain; transition: transform 0.2s ease; display: block; } .branding:hover .logo { transform: scale(1.02); } .desktop-menu { display: flex; list-style: none; margin: 0; padding: 0; gap: 15px; flex: 1; align-items: center; min-width: 0; } .ghost-menu { position: absolute !important; visibility: hidden !important; pointer-events: none !important; height: 0 !important; overflow: hidden !important; z-index: -1000 !important; opacity: 0 !important; /* Ensure it takes up vertical space for measurement if needed, but here we just need width */ white-space: nowrap !important; } .category-menu-wrapper { position: relative; padding: 10px 0; } .category-trigger { display: flex; align-items: center; gap: 6px; color: var(--text-main); cursor: pointer; font-size: 14px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; padding: 6px 10px; border-radius: 4px; transition: all 0.2s ease; } .category-trigger:hover { background: rgb(255 255 255 / 0.05); color: var(--accent-gold); } .category-link { text-decoration: none; color: inherit; } .chevron { transition: transform 0.2s ease; color: var(--text-muted); } .chevron.rotated { transform: rotate(180deg); color: var(--accent-gold); } .category-dropdown { position: absolute; top: calc(100% - 5px); left: 0; background: #111; border: 1px solid var(--glass-border); border-radius: 6px; box-shadow: 0 10px 30px rgb(0 0 0 / 0.5); min-width: 220px; max-height: calc(100vh - var(--nav-height) - 20px); overflow-y: auto; padding: 10px 0; list-style: none; z-index: 1001; scrollbar-width: thin; scrollbar-color: var(--accent-gold) transparent; } .category-dropdown::-webkit-scrollbar { width: 4px; } .category-dropdown::-webkit-scrollbar-track { background: transparent; } .category-dropdown::-webkit-scrollbar-thumb { background-color: var(--accent-gold); border-radius: 20px; } .category-dropdown.mega-menu { min-width: 320px; display: flex; flex-direction: column; gap: 0; padding: 10px 0; left: 0; transform: none; } /* Dropdown list items */ .category-dropdown li { margin: 0; padding: 0; } .category-dropdown a { display: flex; align-items: center; padding: 8px 20px; color: var(--text-muted); text-decoration: none; font-size: 14px; transition: all 0.2s ease; } /* Nested categories */ .nested-category { padding: 5px 0; margin-bottom: 5px; flex: 1 1 100%; } .nested-title { display: block; padding: 12px 20px 8px 20px; font-size: 11px; color: var(--accent-gold); text-transform: uppercase; letter-spacing: 0.12em; font-weight: 800; border-bottom: 1px solid rgb(210 175 120 / 0.1); margin-bottom: 4px; background: rgb(210 175 120 / 0.03); } .nested-items { list-style: none; padding: 0; } /* Right side content */ .nav-right { display: flex; align-items: center; gap: 15px; flex-shrink: 0; } .nav-icon-link { color: var(--text-muted); display: flex; align-items: center; padding: 8px; border-radius: 50%; transition: all 0.2s ease; } .nav-icon-link:hover { color: var(--accent-gold); background: rgb(255 255 255 / 0.05); } .mobile-menu-toggle { display: none !important; color: var(--text-main) !important; } /* Mobile Drawer & Backdrop */ .mobile-drawer-backdrop { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgb(0 0 0 / 0.6); backdrop-filter: blur(4px); z-index: 1999; } .mobile-menu-drawer { background: #0f0f0f !important; border-left: 1px solid var(--glass-border); position: fixed; top: 0; right: 0; width: 70vw; height: 100vh; z-index: 2000; display: flex; flex-direction: column; box-shadow: -10px 0 30px rgb(0 0 0 / 0.5); padding: 0 !important; } .mobile-drawer-header { display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; border-bottom: 1px solid var(--glass-border); background: rgb(0 0 0 / 0.3); flex-shrink: 0; } .mobile-drawer-content { flex: 1; overflow-y: auto; padding: 20px; -webkit-overflow-scrolling: touch; } .mobile-drawer-title { color: var(--accent-gold); font-weight: 800; text-transform: uppercase; letter-spacing: 0.1em; } .mobile-close-button { background: rgb(255 255 255 / 0.05) !important; border: 1px solid rgb(210 175 120 / 0.2) !important; } .mobile-close-button:hover { background: rgb(210 175 120 / 0.1) !important; } .mobile-menu-list { padding: 20px; list-style: none; margin: 0; } .mobile-category { margin-bottom: 30px; list-style: none; } .mobile-category-title { color: var(--accent-gold); font-size: 18px; font-weight: 800; text-transform: uppercase; margin-bottom: 15px; border-bottom: 1px solid rgb(210 175 120 / 0.2); padding-bottom: 5px; } .mobile-category-items { list-style: none; padding-left: 0; } .mobile-nested-section { margin: 15px 0 20px 0; background: transparent; border-radius: 0; padding: 0; } .mobile-nested-title { color: var(--text-muted); font-size: 12px; text-transform: uppercase; font-weight: 700; margin-bottom: 10px; padding-left: 5px; } .mobile-nested-items { list-style: none; padding: 0; display: grid; grid-template-columns: 1fr; gap: 8px; } .mobile-nested-items a { display: block; padding: 12px 15px; color: var(--text-main); text-decoration: none; font-size: 16px; background: rgb(255 255 255 / 0.03); border-radius: 4px; } .mobile-category-items > li > a { display: block; padding: 12px 15px; color: var(--text-main); text-decoration: none; font-size: 16px; background: rgb(255 255 255 / 0.03); margin-bottom: 8px; border-radius: 4px; } .category-dropdown a:hover { background: rgb(210 175 120 / 0.1); color: var(--accent-gold); padding-left: 24px; } .item-icon { transition: transform 0.2s ease; } .category-dropdown a:hover .item-icon { transform: scale(1.1); opacity: 1 !important; } /* Responsive */ @media (width <= 640px) { .desktop-menu { display: none; } .mobile-menu-toggle { display: inline-flex !important; } .nav-content { padding: 0 15px; } } /* Branding & Toggle */ .branding-section { display: flex; align-items: center; gap: 10px; } .game-mode-toggle { cursor: pointer; padding: 2px 8px; border-radius: 4px; font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; user-select: none; transition: all 0.2s ease; border: 1px solid transparent; } .game-mode-toggle.regular { background: rgb(46 125 50 / 0.2); color: #81c784; border-color: rgb(46 125 50 / 0.3); } .game-mode-toggle.regular:hover { background: rgb(46 125 50 / 0.3); border-color: #81c784; } .game-mode-toggle.pve { background: rgb(2 136 209 / 0.2); color: #4fc3f7; border-color: rgb(2 136 209 / 0.3); } .game-mode-toggle.pve:hover { background: rgb(2 136 209 / 0.3); border-color: #4fc3f7; } @media (width >= 641px) { .mobile-menu-drawer { display: none !important; } } /* Ultra-Narrow Support */ @media (width <= 500px) { .game-mode-toggle { font-size: 9px; padding: 2px 6px; } } @media (width <= 400px) { .nav-content { padding: 0 10px; } .nav-right { gap: 6px; } .nav-left { gap: 8px; } .branding-section { gap: 6px; } } @media (width <= 320px) { .logo { height: 20px; } .nav-content { padding: 0 4px; } .branding { min-width: 0; overflow: hidden; } .branding-section { gap: 4px; } .nav-right { gap: 4px; } } @media (width < 180px) { .game-mode-toggle { display: none !important; } } ================================================ FILE: src/components/menu/index.jsx ================================================ import { useMemo, useState, useRef } from "react"; import { useSelector, useDispatch } from "react-redux"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiCogOutline, mdiRemote, mdiClose, mdiMenu } from "@mdi/js"; import { motion, AnimatePresence } from "framer-motion"; import { Box, Alert, IconButton, Collapse, LinearProgress } from "@mui/material"; import { caliberArrayWithSplit } from "../../modules/format-ammo.mjs"; import categoryPages from "../../data/category-pages.json"; import { useBossesData } from "../../features/maps/index.js"; import { mapIcons, useMapImagesSortedArray } from "../../features/maps/index.js"; import { setGameMode } from "../../features/settings/settingsSlice.mjs"; import alertConfig from "./alert-config.js"; import useTradersData from "../../features/traders/index.js"; import CategoryMenu from "./CategoryMenu.jsx"; import { getMenuData } from "./menu-data.js"; import useMenuOverflow from "./useMenuOverflow.js"; import "./index.css"; const alertColor = alertConfig.alertColors[alertConfig.alertLevel]; const ammoTypes = caliberArrayWithSplit(); const Menu = () => { const { t } = useTranslation(); const dispatch = useDispatch(); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [alertsClosed, setAlertsClosed] = useStateWithLocalStorage("alertBannersClosed", []); const [alertStateOpen, setAlertStateOpen] = useState( alertConfig.alwaysShow || !alertsClosed.includes(alertConfig.bannerKey), ); const gameMode = useSelector((state) => state.settings.gameMode); const loadingData = useSelector((state) => state.settings.loadingData); const otherGameMode = useMemo(() => { return gameMode === "regular" ? "pve" : "regular"; }, [gameMode]); const gameModeTranslated = useMemo(() => { return t(`game_mode_${gameMode}`); }, [gameMode, t]); const uniqueMaps = useMapImagesSortedArray(); const processedMaps = useMemo(() => { // Deduplicate by id, prioritizing interactive projection const deduplicated = uniqueMaps.reduce((acc, map) => { const existing = acc[map.id]; if (!existing || map.projection === "interactive") { acc[map.id] = map; } return acc; }, {}); const maps = Object.values(deduplicated); for (const map of maps) { if (mapIcons[map.normalizedName]) { map.icon = mapIcons[map.normalizedName]; } else { map.menuPadding = true; } } return maps; }, [uniqueMaps]); const { data: bosses } = useBossesData(); const { data: allTraders } = useTradersData(); const traders = useMemo(() => { return allTraders.filter((t) => t.barters?.length > 0); }, [allTraders]); const menuData = useMemo( () => getMenuData(t, { traders, bosses, uniqueMaps: processedMaps, categoryPages, }), [t, traders, bosses, processedMaps], ); const desktopMenuRef = useRef(null); const measuringRef = useRef(null); const { visibleCount } = useMenuOverflow(desktopMenuRef, measuringRef, menuData); const visibleItems = useMemo(() => { return menuData.slice(0, visibleCount); }, [menuData, visibleCount]); const overflowItems = useMemo(() => { return menuData.slice(visibleCount); }, [menuData, visibleCount]); return ( <> {/* Ghost menu for stable measurement - hidden via CSS */}
      {menuData.map((category) => ( ))}
    {alertConfig?.alertEnabled === true && ( { if (!alertsClosed.includes(alertConfig.bannerKey)) { setAlertsClosed([...alertsClosed, alertConfig.bannerKey]); } setAlertStateOpen(false); }} > } > {t(alertConfig.text, alertConfig.textVariables)} {alertConfig.linkEnabled === true && ( <> {" - "} {t(alertConfig.linkText)} )} )} ); }; export default Menu; ================================================ FILE: src/components/menu/menu-data.js ================================================ export const CATEGORIES = { MAPS: "Maps", DATABASE: "Database", CALCULATORS: "Calculators", PROGRESSION: "Progression", COMMUNITY: "Community", }; export const getMenuData = (t, { traders, bosses, uniqueMaps, categoryPages }) => [ { id: "maps", text: t("Maps"), to: "/maps/", items: uniqueMaps.map((map) => ({ text: map.name, to: `/map/${map.key}`, icon: map.icon, padding: map.menuPadding, })), }, { id: "items", text: t("Items"), to: "/items/", items: [ { text: t("Gear"), items: categoryPages .filter((cp) => ["headsets", "helmets", "glasses", "armors", "rigs", "backpacks"].includes(cp.key)) .map((cp) => ({ text: t(cp.displayText), to: `/items/${cp.key}`, })), }, { text: t("Weaponry"), items: [ { text: t("Ammo"), to: "/ammo/" }, ...categoryPages .filter((cp) => ["guns", "mods", "pistol-grips", "suppressors"].includes(cp.key)) .map((cp) => ({ text: t(cp.displayText), to: `/items/${cp.key}`, })), ], }, { text: t("Equipment & Tools"), items: categoryPages .filter((cp) => ["grenades", "containers", "barter-items", "keys", "provisions"].includes(cp.key)) .map((cp) => ({ text: t(cp.displayText), to: `/items/${cp.key}`, })), }, ], }, { id: "traders", text: t("Traders"), to: "/traders", items: traders.map((trader) => ({ text: trader.name, to: `/trader/${trader.normalizedName}`, })), }, { id: "bosses", text: t("Bosses"), to: "/bosses/", items: bosses .filter((boss) => boss.maps.length > 0) .sort((a, b) => a.name.localeCompare(b.name)) .map((boss) => ({ text: boss.name, to: `/boss/${boss.normalizedName}`, })), }, { id: "calculators", text: t("Calculators"), items: [ { text: t("Barter profit"), to: "/barters/" }, { text: t("Hideout profit"), to: "/hideout-profit/" }, { text: t("Hideout build costs"), to: "/hideout" }, { text: t("Bitcoin Farm Profit"), to: "/bitcoin-farm-calculator" }, { text: t("Currency Converter"), to: "/converter" }, ], }, { id: "progression", text: t("Progression"), items: [ { text: t("Tasks"), to: "/tasks" }, { text: t("Loot tiers"), to: "/loot-tier/" }, { text: t("Wipe length"), to: "/wipe-length" }, { text: t("Achievements"), to: "/achievements" }, { text: t("Prestige"), to: "/prestige" }, { text: t("Players"), to: "/players" }, ], }, { id: "community", text: t("Community"), items: [ { text: t("TarkovMonitor"), to: "/tarkov-monitor" }, { text: t("Stash Discord Bot"), to: "/stash-discord-bot" }, { text: t("API"), to: "/api/" }, ], }, ]; ================================================ FILE: src/components/menu/useMenuOverflow.js ================================================ import { useState, useEffect } from "react"; /** * A hook to determine how many menu items can fit in a container. * @param {React.RefObject} containerRef The ref of the container that restricts the width. * @param {React.RefObject} measuringRef The ref of a "ghost" element containing all items for measurement. * @param {Array} items The list of menu items. */ const useMenuOverflow = (containerRef, measuringRef, items) => { const [visibleCount, setVisibleCount] = useState(items.length); useEffect(() => { if (!containerRef.current || !measuringRef.current) return; const measure = () => { if (!containerRef.current || !measuringRef.current) return; const containerWidth = containerRef.current.offsetWidth; // Get all immediate kids of the ghost/measuring element const children = Array.from(measuringRef.current.children); if (children.length === 0) return; // Estimate "More" menu width // This button is only rendered in the real menu, but we need to reserve space for it const MORE_BUTTON_WIDTH = 100; const GAP = 15; // Matches .desktop-menu gap let currentWidth = 0; let count = 0; for (let i = 0; i < items.length; i++) { const child = children[i]; if (!child) break; const childWidth = child.getBoundingClientRect().width; const isLast = i === items.length - 1; const neededWidth = currentWidth + childWidth + (count > 0 ? GAP : 0); // If it's not the last item, we need to ensure there's space for the "More" button const buffer = isLast ? 0 : MORE_BUTTON_WIDTH + GAP; if (neededWidth + buffer > containerWidth) { break; } currentWidth = neededWidth; count++; } setVisibleCount((prev) => (prev !== count ? count : prev)); }; if (typeof ResizeObserver === "undefined") { measure(); return; } const observer = new ResizeObserver(() => { window.requestAnimationFrame(measure); }); observer.observe(containerRef.current); // Initial measure measure(); return () => observer.disconnect(); }, [containerRef, measuringRef, items]); return { visibleCount }; }; export default useMenuOverflow; ================================================ FILE: src/components/open-collective-button/index.css ================================================ .oc-button { border-radius: 5px !important; color: white !important; font-size: 16px !important; font-family: 'bender', -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', sans-serif !important; font-weight: bold !important; padding: 5px 15px !important; background: rgb(78 180 102) !important; text-shadow: 0 1px 4px black; } ================================================ FILE: src/components/open-collective-button/index.jsx ================================================ import { useTranslation } from "react-i18next"; import { Button } from "@mui/material"; import "./index.css"; function OpenCollectiveButton({ large = false, linkStyle }) { const { t } = useTranslation(); return ( ); } export default OpenCollectiveButton; ================================================ FILE: src/components/patreon-button/index.css ================================================ .become-supporter-wrapper { text-align: center; } .become-supporter-wrapper.only-large { display: none; } .become-supporter-wrapper a { color: #fff; font-size: 0.875rem; font-family: 'America', 'GT America', 'Lato', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; background-color: rgb(255 66 77); border-radius: 20px; padding: 10px 40px; text-align: center; display: inline-block; } .become-supporter-wrapper a.alternate-style { padding: 5px 20px; margin-right: 20px; border-radius: 0; } .become-supporter-wrapper svg { margin-right: 0; } ================================================ FILE: src/components/patreon-button/index.jsx ================================================ import { useTranslation } from "react-i18next"; import "./index.css"; function PatreonButton({ onlyLarge, linkStyle, wrapperStyle, text, children }) { const { t } = useTranslation(); return (

    {children ? children : t("Become a patron")}

    ); } export default PatreonButton; ================================================ FILE: src/components/points/Circle.jsx ================================================ import { Component } from "react"; class Circle extends Component { render() { return ( ); } } export default Circle; ================================================ FILE: src/components/points/Diamond.jsx ================================================ import { Component } from "react"; class TriangleUp extends Component { render() { return ( ); } } export default TriangleUp; ================================================ FILE: src/components/points/Plus.jsx ================================================ import { Component } from "react"; class Plus extends Component { render() { return ( ); } } export default Plus; ================================================ FILE: src/components/points/Square.jsx ================================================ import { Component } from "react"; class Square extends Component { render() { return ( ); } } export default Square; ================================================ FILE: src/components/points/TriangleDown.jsx ================================================ import { Component } from "react"; class TriangleUp extends Component { render() { return ( ); } } export default TriangleUp; ================================================ FILE: src/components/points/TriangleUp.jsx ================================================ import { Component } from "react"; class TriangleUp extends Component { render() { return ( ); } } export default TriangleUp; ================================================ FILE: src/components/points/index.jsx ================================================ export { default as Square } from "./Square.jsx"; export { default as Circle } from "./Circle.jsx"; export { default as TriangleUp } from "./TriangleUp.jsx"; export { default as TriangleDown } from "./TriangleDown.jsx"; export { default as Diamond } from "./Diamond.jsx"; export { default as Plus } from "./Plus.jsx"; ================================================ FILE: src/components/preset-selector/index.jsx ================================================ import React, { useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import useItemsData from "../../features/items/index.js"; import { SelectItemFilter } from "../filter/index.jsx"; export function PresetSelector({ item, alt = "" }) { const navigate = useNavigate(); // Use the primary items API query to fetch all items const { data: allItems } = useItemsData(); const [selected, setSelected] = useState(item); const baseId = useMemo(() => { setSelected(item); if (item.types.includes("preset")) { return item.properties.baseItem.id; } return item.id; }, [item]); const selectedValue = useMemo(() => { return { label: selected.shortName, value: selected.normalizedName || "loading", }; }, [selected]); const items = useMemo(() => { return allItems .filter((testItem) => baseId && (testItem.id === baseId || testItem.properties?.baseItem?.id === baseId)) .sort((a, b) => { if (a.types.includes("gun")) { return -1; } if (b.types.includes("gun")) { return 1; } const baseItem = allItems.find((i) => i.id === baseId); if (baseItem?.properties?.defaultPreset?.id === a.id) { return -1; } if (baseItem?.properties?.defaultPreset?.id === b.id) { return 1; } return a.shortName.localeCompare(b.shortName); }); }, [allItems, baseId]); if (items.length < 2) { return alt; } return (
    { if (!event) { return true; } navigate(`/item/${event.value}`); }} valueField={"normalizedName"} />
    ); } ================================================ FILE: src/components/price-graph/index.css ================================================ .price-history-wrapper { height: 300px; } ================================================ FILE: src/components/price-graph/index.jsx ================================================ import { useMemo, useState, useEffect, useRef } from "react"; import { useSelector } from "react-redux"; import { VictoryChart, VictoryLine, VictoryTheme, VictoryAxis, // VictoryTooltip, VictoryVoronoiContainer, } from "victory"; import { useTranslation } from "react-i18next"; import { Slider } from "@mui/material"; import formatPrice from "../../modules/format-price.js"; import apiRequest from "../..//modules/api-request.mjs"; // import { getRelativeTimeAndUnit } from '../../modules/format-duration.js'; import "./index.css"; function PriceGraph({ item, itemId, days }) { if (item && !itemId) { itemId = item.id; // if this is a default preset, use the base item's price data if (item.properties?.baseItem?.properties?.defaultPreset?.id === item.id) { itemId = item.properties.baseItem.id; } } if (!days) { days = 7; } const [filterRange, setFilterRange] = useState([0, 0]); const [data, setPriceData] = useState(); const { t } = useTranslation(); const gameMode = useSelector((state) => state.settings.gameMode); const loadedItemId = useRef(); useEffect(() => { if (loadedItemId.current !== itemId) { setPriceData([]); } apiRequest(`${gameMode}/prices/${itemId}`) .then((priceData) => { loadedItemId.current = itemId; setPriceData(priceData); return priceData; }) .catch((error) => { console.log(`Error retrieving item prices`, error); setPriceData([]); }); }, [itemId, gameMode]); const daysData = useMemo(() => { if (!data) { return []; } const cutoffTimestamp = new Date().setDate(new Date().getDate() - days); return data.filter((scan) => scan.timestamp >= cutoffTimestamp); }, [data, days]); const { dayTicks, tickLabels } = useMemo(() => { const returnValues = { dayTicks: [], tickLabels: {}, }; returnValues.dayTicks = daysData.reduce((all, current) => { const newTimestamp = new Date(Number(current.timestamp)).setHours(0, 0, 0, 0); if (!all.some((currentTs) => currentTs === newTimestamp)) { all.push(newTimestamp); const dateTime = new Date(newTimestamp); returnValues.tickLabels[newTimestamp] = `${dateTime.toLocaleString(navigator.language, { weekday: "long" })}\n${dateTime.toLocaleString(navigator.language, { year: "numeric", month: "numeric", day: "numeric" })}`; } return all; }, []); if (daysData.length > 0) { const firstTick = returnValues.dayTicks[0]; returnValues.tickLabels[firstTick] = undefined; returnValues.dayTicks[0] = Number(daysData[0].timestamp); returnValues.tickLabels[returnValues.dayTicks[0]] = ""; } if (daysData.length > 1) { const lastTick = Number(daysData[daysData.length - 1].timestamp); returnValues.dayTicks.push(lastTick); returnValues.tickLabels[lastTick] = ""; } return returnValues; }, [daysData]); const { filteredData, filteredMax, filteredMin, filteredAvgDown, filteredMinDown } = useMemo(() => { const returnValues = { filteredData: [], filteredMax: 0, filteredMin: 0, filteredAvgDown: false, filteredMinDown: false, }; if (daysData.length > 0) { const min = filterRange[0] ? filterRange[0] : Number(daysData[0].timestamp); const max = filterRange[1] ? filterRange[1] : Number(daysData[daysData.length - 1].timestamp); returnValues.filteredData = daysData.filter( (p) => Number(p.timestamp) >= min && Number(p.timestamp) <= max, ); } else { returnValues.filteredData = daysData; } returnValues.filteredMax = returnValues.filteredData.reduce((currMax, price) => { return Math.max(currMax, price.price); }, 0); returnValues.filteredMin = returnValues.filteredData.reduce((curMin, p) => { if (p.priceMin < curMin) { return p.priceMin; } return curMin; }, Number.MAX_SAFE_INTEGER); if (returnValues.filteredMin === Number.MAX_SAFE_INTEGER) { returnValues.filteredMin = 0; } if (returnValues.filteredData.length > 1) { returnValues.filteredAvgDown = returnValues.filteredData[0].price > returnValues.filteredData[returnValues.filteredData.length - 1].price; returnValues.filteredMinDown = returnValues.filteredData[0].priceMin > returnValues.filteredData[returnValues.filteredData.length - 1].priceMin; } return returnValues; }, [daysData, filterRange]); let height = VictoryTheme.material.height; if (window.innerWidth < 760) { height = 1280; } if (!data) { return null; } if (daysData.length < 2) { return t("No data"); } return (
    { let timeLabel = ""; const thirtyDaysAgo = new Date(); thirtyDaysAgo.setDate(new Date().getDate() - 30); if (new Date(datum.x) >= thirtyDaysAgo) { timeLabel = `\n${new Date(datum.x).toLocaleTimeString(navigator.language, { hour: "2-digit", minute: "2-digit", hour12: false })}`; } return `${formatPrice(datum.y)}${timeLabel}\n${new Date(datum.x).toLocaleDateString(navigator.language, { dateStyle: "short" })}`; }} /> } > { // let relativeTime = getRelativeTimeAndUnit(timestamp); // // return t('{{val, relativetime}}', { val: relativeTime[0], range: relativeTime[1] }) return tickLabels[timestamp]; }} tickValues={dayTicks} fixLabelOverlap={true} /> { return { x: new Date(Number(pricePoint.timestamp)), y: pricePoint.price, }; })} /> { return { x: new Date(Number(pricePoint.timestamp)), y: pricePoint.priceMin, }; })} />
    { allMarks.push({ label: "", value: current }); return allMarks; }, [])} onChange={(event, value) => { setFilterRange(value); }} valueLabelDisplay="auto" valueLabelFormat={(timestamp) => new Date(timestamp ?? 0).toLocaleString(navigator.language, { hour: "2-digit", minute: "2-digit", hour12: false, year: "numeric", month: "numeric", day: "numeric", }) } />
    ); } export default PriceGraph; ================================================ FILE: src/components/property-list/index.css ================================================ .property-list { display: flex; flex-flow: wrap; gap: 5px; margin-top: 20px; margin-bottom: 20px; } .property-wrapper { display: flex; align-items: flex-start; flex: 1 auto; flex-direction: column; flex-basis: calc(50% - 2.5px); padding: 10px 20px; background-color: var(--color-gunmetal-dark); border: 1px solid var(--color-black-light); } .property-wrapper.large { min-width: 100%; max-width: none; } .property-wrapper.health { max-width: 160px; } .property-key-wrapper { cursor: default; display: inline-block; color: var(--color-gray-light); font-size: 18px; margin-bottom: 5px; font-weight: 600; } .property-wrapper .item { white-space: normal; } .property-wrapper .item p { margin: 0; } @media screen and (width >= 800px) { .property-wrapper { /* flex-basis: 10%; */ white-space: nowrap; } } ================================================ FILE: src/components/property-list/index.jsx ================================================ import { useMemo } from "react"; import propertyFormatter from "../../modules/property-format.js"; import { useTranslation } from "react-i18next"; import { Tooltip } from "@mui/material"; import "./index.css"; const skipProps = ["grid", "ConflictingItems", "__typename", "slots", "presets", "armorSlots"]; const ConditionalWrapper = ({ condition, wrapper, children }) => { return condition ? wrapper(children) : children; }; function PropertyList({ properties, id }) { const { t } = useTranslation(); const data = useMemo( () => Object.entries(properties ?? {}) .filter(([property, value]) => { return !skipProps.includes(property); }) .map(([property, value]) => { return propertyFormatter(property, value, id); }) .filter(([property, value]) => value.value !== undefined && value.value !== null) .filter(([property, value]) => value.value?.length !== 0) .sort((a, b) => { let aVal = a[0]; let bVal = b[0]; if (typeof a[1].order !== "undefined" && typeof b[1].order !== "undefined") { aVal = String(a[1].order); bVal = String(b[1].order); } else if (a[1].label && b[1].label) { aVal = a[1].label; bVal = b[1].label; } if (typeof aVal === "object") { aVal = a[0]; } if (typeof bVal === "object") { bVal = b[0]; } return aVal.localeCompare(bVal); }), [properties, id], ); if (data.length === 0) { return ""; } return (
    {data.map(([property, value, index]) => { return (
    = 40 ? "large" : ""} ${property}`} key={property ?? `property-${index}`} >
    (
    {children}
    )} > {value.label ? value.label : t(property)}
    {value.value}
    ); })}
    ); } export default PropertyList; ================================================ FILE: src/components/quest-items-cell/index.css ================================================ .quest-item-wrapper { display: flex; align-items: center; justify-content: center; } .quest-image-wrapper { margin-right: 10px; } .quest-image-wrapper img { width: 32px; height: 32px; } .amount-wrapper, .found-in-raid-wrapper, .reward-type-wrapper { color: var(--color-gray); font-size: 14px; } .found-in-raid-wrapper.find-in-raid { color: var(--color-red); } ================================================ FILE: src/components/quest-items-cell/index.jsx ================================================ import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import ItemImage from "../item-image/index.jsx"; import "./index.css"; const rewardMap = { finishRewards: "On Task Completion", startRewards: "On Task Start", }; function QuestItemsCell({ questItems }) { const { t } = useTranslation(); return questItems.map((questItem, index) => { return (
    {questItem.item.name}
    {t("Amount")} : {questItem.count.toLocaleString()} {questItem.alternates ? ` (${t("has alternates")})` : ""}
    { // t('On Task Completion') // t('On Task Start') t(rewardMap[questItem.rewardType]) }
    ); }); } export default QuestItemsCell; ================================================ FILE: src/components/quest-table/index.css ================================================ .quest-name-wrapper { display: flex; align-items: center; } .quest-giver-image { margin-right: 10px; max-width: 64px; max-height: 64px; } .quest-item-wrapper { display: flex; align-items: start; justify-content: left; } .quest-image-wrapper { margin-right: 10px; } .quest-image-wrapper img { width: 48px; height: 48px; } .amount-wrapper, .found-in-raid-wrapper { color: var(--color-gray); font-size: 14px; } .found-in-raid-wrapper.find-in-raid { color: var(--color-red); } .quest-link-wrapper { align-items: center; display: flex; } .quest-link-wrapper a { display: flex; } @keyframes endgame-pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); /* Slightly larger at the midpoint */ } 100% { transform: scale(1); /* Returns to original size */ } } .endgame-filtered-icon { animation: endgame-pulse 2s infinite cubic-bezier(0.4, 0, 0.6, 1); } ================================================ FILE: src/components/quest-table/index.jsx ================================================ import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import { useSelector } from "react-redux"; import { Icon } from "@mdi/react"; import { mdiClipboardCheck, mdiClipboardRemove, mdiBriefcase, mdiLighthouse } from "@mdi/js"; import { Tooltip } from "@mui/material"; import DataTable from "../data-table/index.jsx"; import QuestItemsCell from "../quest-items-cell/index.jsx"; import CenterCell from "../center-cell/index.jsx"; import useQuestsData from "../../features/quests/index.js"; import useItemsData from "../../features/items/index.js"; import useTradersData from "../../features/traders/index.js"; import TraderImage from "../trader-image/index.jsx"; import "./index.css"; export function getRequiredQuestItems(quest, itemFilter = false) { const requiredItems = []; const addItem = (item, count = 1, foundInRaid = false, alternates = false) => { if (itemFilter && item.id !== itemFilter) { return; } let req = requiredItems.find((reqItem) => reqItem.item.id === item.id); if (!req) { req = { item: item, count: 0, foundInRaid: foundInRaid, alternates: alternates, }; requiredItems.push(req); } req.count += count; }; quest.objectives.forEach((objectiveData) => { if (objectiveData.items && objectiveData.type !== "findItem" && objectiveData.items.length < 1000) { const alternates = objectiveData.items.length > 1; for (const objItem of objectiveData.items) { addItem(objItem, objectiveData.count || 1, objectiveData.foundInRaid, alternates); } } if (objectiveData.markerItem?.id) { addItem(objectiveData.markerItem); } objectiveData.containsAll?.forEach((part) => { addItem(part); }); if (objectiveData.usingWeapon?.length === 1) { objectiveData.usingWeapon?.forEach((item) => { addItem(item); }); } if (objectiveData.usingWeaponMods?.length === 1) { objectiveData.usingWeaponMods[0].forEach((item) => { addItem(item); }); } else if (objectiveData.usingWeaponMods?.length) { let requiredCount = {}; objectiveData.usingWeaponMods?.forEach((modSet) => { modSet.forEach((item) => { if (!requiredCount[item.id]) { requiredCount[item.id] = 0; } requiredCount[item.id]++; }); }); for (const id of Object.keys(requiredCount)) { if (requiredCount[id] === objectiveData.usingWeaponMods.length) { addItem(objectiveData.usingWeaponMods[0].find((mod) => mod.id === id)); } } } if (objectiveData.wearing?.length === 1) { objectiveData.wearing?.forEach((outfit) => { outfit.forEach((item) => { addItem(item); }); }); } else if (objectiveData.wearing?.length) { let requiredCount = {}; objectiveData.wearing?.forEach((outfit) => { outfit.forEach((item) => { if (!requiredCount[item.id]) { requiredCount[item.id] = 0; } requiredCount[item.id]++; }); }); for (const id of Object.keys(requiredCount)) { if (requiredCount[id] === objectiveData.wearing.length) { addItem(objectiveData.wearing[0].find((item) => item.id === id)); } } } }); quest.neededKeys?.forEach((taskKey) => { taskKey.keys.forEach((key) => { addItem(key); }); }); return requiredItems; } const rewardTypes = ["startRewards", "finishRewards"]; export function getRewardQuestItems(quest, itemFilter = false) { const rewardItems = []; const addItem = (item, count = 1, rewardType) => { if (itemFilter) { let passed = item.id === itemFilter; if (!passed && item.containsItems) { for (const contained of item.containsItems) { if (contained.item.id === itemFilter) { passed = true; break; } } } if (!passed) { return; } } let rew = rewardItems.find((rewItem) => rewItem.item.id === item.id); if (!rew) { rew = { item: item, count: 0, rewardType: rewardType, }; rewardItems.push(rew); } rew.count += count; }; rewardTypes.forEach((rewardType) => { quest[rewardType].items.forEach((contained) => { if (!contained) { return; } addItem(contained.item, contained.count, rewardType); }); }); return rewardItems; } function QuestTable({ giverFilter, nameFilter, requiredItemFilter, rewardItemFilter, hideBorders, hideCompleted, hideLocked, hideNonKappa, hideNonLK, questRequirements, minimumLevel, minimumTraderLevel, requiredItems, rewardItems, reputationRewards, requiredForEndGame, }) { const { t } = useTranslation(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const { data: items } = useItemsData(); const { data: traders } = useTradersData(); const { data: quests } = useQuestsData(); const allQuestData = useMemo(() => { return quests .map((rawQuest) => { const questData = { ...rawQuest, requiredItems: [], rewardItems: [], }; if (reputationRewards) { questData.totalRepReward = rawQuest.finishRewards.traderStanding?.reduce((total, current) => { total += current.standing; return Math.round(total * 100) / 100; }, 0); } if (requiredItemFilter || requiredItems) { questData.requiredItems = getRequiredQuestItems(rawQuest, requiredItemFilter) .map((req) => { return { ...req, item: items.find((i) => i.id === req.item.id), }; }) .filter((req) => req.item); if (requiredItemFilter && questData.requiredItems.length === 0) { return false; } } if (rewardItemFilter || rewardItems) { questData.rewardItems = getRewardQuestItems(rawQuest, rewardItemFilter) .map((rew) => { const foundItem = items.find((i) => i.id === rew.item.id); if (!foundItem) { return false; } const contained = rew.item.containsItems; const mapped = { ...rew, item: { ...foundItem, containsItems: contained, }, }; return mapped; }) .filter(Boolean); if (rewardItemFilter && questData.rewardItems.length === 0) { return false; } } if (giverFilter && giverFilter !== "all") { if (questData.trader.normalizedName !== giverFilter) { return false; } } if (nameFilter && !questData.name.toLowerCase().includes(nameFilter.toLowerCase())) { return false; } return questData; }) .filter(Boolean); }, [ quests, items, giverFilter, nameFilter, requiredItemFilter, rewardItemFilter, requiredItems, rewardItems, reputationRewards, ]); const shownQuests = useMemo(() => { return allQuestData .filter((quest) => { if (!hideCompleted && !hideLocked) { return true; } let completedPassed = true; if (hideCompleted) { completedPassed = !settings.completedQuests.includes(quest.id) && !settings.failedQuests.includes(quest.id); } let lockedPassed = true; if (hideLocked) { lockedPassed = quest.active; if (!hideCompleted && !quest.active) { lockedPassed = settings.completedQuests.includes(quest.id) || settings.failedQuests.includes(quest.id); } if (settings.playerLevel < quest.minPlayerLevel) { lockedPassed = false; } } return completedPassed && lockedPassed; }) .filter((quest) => { if (!hideNonKappa) { return true; } return quest.kappaRequired; }) .filter((quest) => { if (!hideNonLK) { return true; } return quest.lightkeeperRequired; }); }, [settings, allQuestData, hideCompleted, hideLocked, hideNonKappa, hideNonLK]); const columns = useMemo(() => { const useColumns = [ { Header: t("Task"), id: "name", accessor: "name", Cell: (props) => { const questData = props.row.original; let completedIcon = ""; if (settings.completedQuests.includes(questData.id)) { completedIcon = ; } return (
    {questData.name} {questData.factionName !== "Any" ? ` (${questData.factionName})` : ""} {completedIcon}
    ); }, }, ]; if (requiredItems) { useColumns.push({ Header: t("Required items"), id: "requiredItems", accessor: (quest) => { return quest.requiredItems[0]?.item.name; }, Cell: (props) => { const questData = props.row.original; return ; }, position: requiredItems, }); } if (rewardItems) { useColumns.push({ Header: t("Reward items"), id: "rewardItems", accessor: (quest) => { return quest.rewardItems[0]?.item.name; }, Cell: (props) => { const questData = props.row.original; return ; }, position: rewardItems, }); } if (questRequirements) { useColumns.push({ Header: t("Required tasks"), id: "questRequirements", accessor: (questData) => { return quests.find((quest) => quest.id === questData.taskRequirements[0]?.task.id)?.name; }, Cell: (props) => { const questData = props.row.original; return questData.taskRequirements.map((req) => { if (!req) { return null; } const reqQuest = quests.find((quest) => quest.id === req.task.id); if (!reqQuest) { return null; } let completedIcon = ""; if (req.status.includes("complete") && settings.completedQuests.includes(req.task.id)) { completedIcon = ; } if ( completedIcon === "" && req.status.includes("failed") && settings.failedQuests.includes(req.task.id) ) { completedIcon = ; } if ( completedIcon === "" && req.status.length === 1 && req.status[0] === "active" && (settings.completedQuests.includes(req.task.id) || settings.failedQuests.includes(req.task.id)) ) { completedIcon = ; } return (
    {reqQuest.name} {reqQuest.factionName !== "Any" ? ` (${reqQuest.factionName})` : ""} {`: ${ // t('loading') // t('active') // t('succeeded') // t('complete') // t('failed') req.status.map((status) => t(status)).join(", ") }`} {completedIcon}
    ); }); }, position: questRequirements, }); } if (minimumLevel) { useColumns.push({ Header: t("Minimum level"), id: "minimumLevel", accessor: "minPlayerLevel", sortType: (a, b, columnId, desc) => { let minA = a.original.minPlayerLevel; let minB = b.original.minPlayerLevel; if (minA === 0) { minA = desc ? -1 : 100; } if (minB === 0) { minB = desc ? -1 : 100; } return minA - minB; }, Cell: (props) => { if (!props.value) { return ""; } return ( ); }, position: minimumLevel, }); } if (minimumTraderLevel) { useColumns.push({ Header: t("Minimum trader level"), id: "minimumTraderLevel", accessor: (questData) => { return questData.traderRequirements.filter((req) => req.requirementType === "level")[0]?.value; }, Cell: (props) => { return ( req.requirementType === "level") .map((req) => req.value) .join(", ")} /> ); }, position: minimumTraderLevel, }); } if (reputationRewards) { useColumns.push({ Header: t("Reputation rewards"), id: "reputationRewards", accessor: "totalRepReward", sortType: (a, b, columnId, desc) => { return a.original.totalRepReward - b.original.totalRepReward; }, Cell: (props) => { return ( {props.row.original.finishRewards.traderStanding.map((reward) => { const trader = traders.find((t) => t.id === reward.trader.id); if (!trader) { return ""; } return ( ); })} ); }, position: reputationRewards, }); } if (requiredForEndGame) { useColumns.push({ Header: t("Endgame"), id: "requiredForEndGame", accessor: "kappaRequired", sortType: (a, b, columnId, desc) => { let aValue = 0; let bValue = 0; if (a.original.kappaRequired) { aValue += 1; } if (b.original.kappaRequired) { bValue += 1; } if (a.original.lightkeeperRequired) { aValue += 2; } if (b.original.lightkeeperRequired) { bValue += 2; } return aValue - bValue; }, Cell: (props) => { const endgameGoals = []; if (props.row.original.kappaRequired) { endgameGoals.push( , ); } if (props.row.original.lightkeeperRequired) { endgameGoals.push( , ); } return {endgameGoals}; }, position: requiredForEndGame, }); } const claimedPositions = []; for (let i = 1; i < useColumns.length; i++) { const column = useColumns[i]; if (Number.isInteger(column.position)) { let position = parseInt(column.position); if (position < 1) { position = 1; } if (position >= useColumns.length) { position = useColumns.length - 1; } if (position !== i && !claimedPositions.includes(position)) { //console.log(`Moving ${column.Header} from ${i} to ${position}`); claimedPositions.push(position); useColumns.splice(i, 1); useColumns.splice(position, 0, column); i = 1; } else if (position !== i && claimedPositions.includes(position)) { //console.warn(`Warning: ${column.Header} wants position ${position}, but that position has already been claimed by ${useColumns[position].Header}`); } } } return useColumns; }, [ t, settings, quests, traders, questRequirements, minimumLevel, minimumTraderLevel, requiredItems, rewardItems, reputationRewards, requiredForEndGame, hideNonKappa, hideNonLK, ]); let extraRow = false; if (allQuestData.length <= 0) { extraRow = t("No quests found"); } else if (allQuestData.length !== shownQuests.length) { extraRow = t("Some tasks hidden by filter settings"); } return ( ); } export default QuestTable; ================================================ FILE: src/components/remote-control-id/index.css ================================================ .id-wrapper { background-color: rgb(from var(--color-black) r g b / 0.5); bottom: 0; color: #fff; display: none; font-family: 'bender', -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', sans-serif; font-size: 16px; line-height: 20px; padding: 10px 40px; position: fixed; z-index: 405; } .id-wrapper-left { left: 0; } .id-wrapper-right { right: 0; } .session-question { /* background-color: black; */ border-radius: 50%; font-size: 16px; font-weight: bold; height: 30px; line-height: 30px; position: absolute; right: 0px; text-align: center; top: 0px; width: 30px; } .session-popup { display: none; position: absolute; bottom: 0; width: 30vw; background-color: rgb(from var(--color-black) r g b / 0.8); padding: 15px; font-size: 16px; } .id-wrapper-left .session-popup { left: 0; } .id-wrapper-right .session-popup { right: 0; } .session-question:hover .session-popup { display: block; } .session-switch-side { position: absolute; right: 0; bottom: 0; font-size: 16px; font-weight: bold; height: 30px; width: 30px; line-height: 30px; text-align: center; background-color: transparent; border: none; cursor: pointer; text-decoration: none; color: var(--color-white); } .session-switch-side:hover, .session-switch-side:focus, .session-switch-side:active { text-decoration: none; } .id-wrapper svg { fill: var(--color-gold-one); height: 35px; margin-right: 1vh; width: 35px; } .session-id { display: inline-block; line-height: 23px; position: relative; top: -6px; } .update-label { font-size: 10px; text-align: center; color: var(--color-white); } @media screen and (width >= 800px) { .id-wrapper { display: block; } } ================================================ FILE: src/components/remote-control-id/index.jsx ================================================ import { useState, useCallback, useMemo } from "react"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import { Badge, LinearProgress } from "@mui/material"; import "./index.css"; const Sides = { Left: "Left", Right: "Right", }; function ID(props) { const [side, setSide] = useState(Sides.Left); const [copied, setCopied] = useState(false); const { t } = useTranslation(); const socketStatus = useSelector((state) => state.sockets.status); const progressStyle = useMemo(() => { if (socketStatus !== "connecting") { return { display: "none" }; } return {}; }, [socketStatus]); const sessionText = useMemo(() => { if (socketStatus === "idle") { return t("Click to connect"); } if (socketStatus === "connected") { return props.sessionID; } return t("Connecting..."); }, [socketStatus, t]); const handleCopyClick = useCallback(async () => { if (socketStatus !== "connected") { return; } try { await navigator.clipboard.writeText(props.sessionID); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch (err) { console.error("Copy failed", err); } }, [socketStatus]); let sideClass; let sideButtonContent; let otherSide; if (side === Sides.Left) { sideClass = "id-wrapper-left"; sideButtonContent = ">>"; otherSide = Sides.Right; } else { sideClass = "id-wrapper-right"; sideButtonContent = "<<"; otherSide = Sides.Left; } const handleSwitchSideClick = useCallback(() => { setSide(otherSide); }, [setSide, otherSide]); return (
    {t("ID for remote control")} ?
    {t("Go to Tarkov.dev with another browser and enter this ID to control this page from there")}
    {sessionText}
    ); } export default ID; ================================================ FILE: src/components/reward-cell/index.css ================================================ .hidden { display: none; } .reward-wrapper { align-items: center; display: flex; } .reward-info-wrapper { flex-grow: 1; display: flex; flex-wrap: wrap; } .reward-info-wrapper > div { width: 100%; } .reward-info-wrapper div:first-child { white-space: nowrap; } .reward-info-source { font-size: 14px; } .reward-custom-price { background-color: var(--color-gunmetal-dark); border: var(--color-gold-two) 2px solid; color: var(--color-gold-two); padding: 4px; width: 5em; } .reward-muted-green { color: var(--color-green-light); } .reward-muted-red { color: var(--color-red-light); } @media screen and (width >= 800px) { .reward-info-wrapper div:first-child { white-space: initial; } } ================================================ FILE: src/components/reward-cell/index.jsx ================================================ import { useMemo, useState, useEffect } from "react"; import { useDispatch } from "react-redux"; import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Tooltip } from "@mui/material"; import { Icon } from "@mdi/react"; import { mdiCloseBox, mdiCheckboxMarked, mdiClipboardList } from "@mdi/js"; import ItemImage from "../item-image/index.jsx"; import formatPrice from "../../modules/format-price.js"; import { setCustomSellValue } from "../../features/items/index.js"; import "./index.css"; function RewardCell({ item, count, source, sellValue, sellTo, sellNote = false, valueTooltip, sellType, taskUnlock, isFIR, }) { const dispatch = useDispatch(); const { t } = useTranslation(); //console.log(item, sellTo); const [customPrice, setCustomPrice] = useState(sellValue); const [editingCustomPrice, setEditingCustomPrice] = useState(false); useEffect(() => { setCustomPrice(sellValue); }, [sellValue, setCustomPrice]); const taskTooltip = useMemo(() => { if (!taskUnlock) { return ""; } const tooltipContent = ( {t("Task: {{taskName}}", { taskName: taskUnlock.name })} ); return ( ); }, [taskUnlock, t]); const displayValue = useMemo(() => { let shownPrice = t("N/A"); let shownSellTo = ""; if (sellValue) { shownPrice = formatPrice(sellValue); shownSellTo = ` @ ${sellTo}`; } return ( { setEditingCustomPrice(true); }} > {shownPrice} {sellType === "custom" ? "*" : ""} { let sanitized = e.target.value.replaceAll(/[^0-9]/g, ""); if (sanitized) { sanitized = parseInt(sanitized); } setCustomPrice(sanitized); }} /> { dispatch( setCustomSellValue({ itemId: item.id, price: customPrice, }), ); setEditingCustomPrice(false); }} /> { dispatch( setCustomSellValue({ itemId: item.id, price: false, }), ); setEditingCustomPrice(false); }} /> {shownSellTo} ); }, [ dispatch, item, sellValue, sellType, sellTo, customPrice, setCustomPrice, editingCustomPrice, setEditingCustomPrice, t, ]); if (sellNote) { sellNote = ({sellNote}); } if (!valueTooltip) { valueTooltip = t("Sell value"); } return (
    {item.name}
    {source} {taskTooltip}
    {displayValue} {sellNote}
    ); } export default RewardCell; ================================================ FILE: src/components/reward-image/index.css ================================================ .reward-image-wrapper { position: relative; margin-right: 10px; font-size: 0; } .reward-image-extra-wrapper { position: absolute; bottom: 1px; right: 1px; display: flex; flex-direction: column; align-items: flex-end; } .reward-image-fir { max-width: 16px; max-height: 16px; } .reward-image-count { background-color: rgb(from var(--color-black) r g b / 0.8); border-top-left-radius: 3px; color: var(--color-gold-one); font-size: 14px; height: 18px; line-height: 20px; padding: 0 5px; text-align: center; } .reward-image-img { max-width: 64px; max-height: 64px; } .reward-image-img-tool { outline: 1px solid var(--color-blue-light); outline-offset: -1px; } .reward-image-img-nonfunctional { outline: 1px solid var(--color-red); outline-offset: -1px; } @media screen and (width >= 800px) { .reward-image-wrapper { margin-right: 10px; } } ================================================ FILE: src/components/reward-image/index.jsx ================================================ import "./index.css"; function RewardImage({ count, iconLink, height = "64", width = "64", isTool = false, nonFunctional = false, isFIR = false, }) { let imageClass = "reward-image-img"; if (isTool) { imageClass = "reward-image-img-tool"; } else if (nonFunctional) { imageClass = "reward-image-img-nonfunctional"; } return (
    {isFIR && ( )} {count && {count}}
    ); } export default RewardImage; ================================================ FILE: src/components/scroll-to-top/index.jsx ================================================ import { useEffect } from "react"; import { useLocation } from "react-router-dom"; export default function ScrollToTop() { const { pathname } = useLocation(); useEffect(() => { window.scrollTo(0, 0); }, [pathname]); return null; } ================================================ FILE: src/components/server-status/index.css ================================================ .server-status-wrapper { text-align: center; } .server-status-wrapper a { color: var(--color-gold-one); } .status-indicator { border-radius: 50%; display: inline-block; height: 10px; margin-left: 10px; width: 10px; } .status-0 { background-color: var(--color-green); } .status-1 { background-color: var(--color-blue-light); } .status-2 { background-color: var(--color-orange); } .status-3 { background-color: var(--color-red); } ================================================ FILE: src/components/server-status/index.jsx ================================================ import { useTranslation } from "react-i18next"; // import ApiMetricsGraph from '../../components/api-metrics-graph/index.js'; import { Tooltip } from "@mui/material"; import useStatusData from "../../features/status/index.mjs"; import "./index.css"; function ServerStatus() { const { status, data } = useStatusData(); const { t } = useTranslation(); if (status !== "succeeded" || !data) { return null; } if (status === "succeeded" && data.messages.length === 0) { //return t('No data'); } if (data.messages[0]?.content && !data.messages[0]?.solveTime) { return (
    {t(`Tarkov server status`)} ); } return (
    {t(`Tarkov server status`)}
    {data.generalStatus.message}
    {/*

    {t('API Latency')}{': '}

    */}
    ); } export default ServerStatus; ================================================ FILE: src/components/small-item-table/index.css ================================================ .small-data-table td.data-cell { padding: 10px; } .small-data-table.no-borders td.data-cell:first-child { border-left: 0; } .small-data-table.no-borders td.data-cell:last-child { border-right: 0; } .small-data-table .trader-icon { max-width: 40px; } .small-data-table .trader-price-content { align-items: center; display: flex; gap: 15px; } ================================================ FILE: src/components/small-item-table/index.jsx ================================================ import { useMemo, useCallback } from "react"; import { useSelector } from "react-redux"; import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiCloseOctagon, mdiHelpRhombus, mdiCached, mdiClipboardList, mdiTimerSand } from "@mdi/js"; import { Tooltip } from "@mui/material"; import ValueCell from "../value-cell/index.jsx"; import TraderPriceCell from "../trader-price-cell/index.jsx"; import CenterCell from "../center-cell/index.jsx"; import ItemNameCell from "../item-name-cell/index.jsx"; import FleaPriceCell from "../flea-price-cell/index.jsx"; import BarterTooltip from "../barter-tooltip/index.jsx"; import DataTable from "../data-table/index.jsx"; import LoadingSmall from "../loading-small/index.jsx"; import ArrowIcon from "../../components/data-table/Arrow.jsx"; import formatPrice from "../../modules/format-price.js"; import itemSearch from "../../modules/item-search.js"; import { getCheapestBarter, getCheapestCraft, getBarterCost } from "../../modules/format-cost-items.js"; import { formatCaliber } from "../../modules/format-ammo.mjs"; import itemCanContain from "../../modules/item-can-contain.js"; import useBartersData from "../../features/barters/index.js"; import useCraftsData from "../../features/crafts/index.js"; import useItemsData, { useHandbookData } from "../../features/items/index.js"; import useHideoutData from "../../features/hideout/index.js"; import { selectAllSkills } from "../../features/settings/settingsSlice.mjs"; import CanvasGrid from "../canvas-grid/index.jsx"; import "./index.css"; function getItemCountPrice(item) { if (item.count < 2) { return ""; } return (
    {formatPrice(item.sellForTradersBest.priceRUB)} x {item.count}
    ); } function TraderSellCell(datum, showSlotValue = false) { const { t } = useTranslation(); if (!datum.row.original.sellForTradersBest) { return (
    ); } const sellForTradersBest = datum.row.original.sellForTradersBest; const count = datum.row.original.count; const priceRUB = sellForTradersBest.priceRUB; const price = sellForTradersBest.price; const slots = datum.row.original.slots; let slotValue = ""; if (showSlotValue && slots > 1) { slotValue = (
    {formatPrice(Math.round(priceRUB / slots))}
    ); } return [
    {sellForTradersBest.vendor.name} {sellForTradersBest.currency !== "RUB" ? (
    {formatPrice(price * count, sellForTradersBest.currency)}
    ) : (
    {formatPrice(priceRUB * count)}
    )} {getItemCountPrice(datum.row.original)} {slotValue}
    , ]; } function shuffleArray(array, randomSeeds) { if (!Array.isArray(randomSeeds)) { randomSeeds = []; } for (let i = randomSeeds.length; i < array.length; i++) { randomSeeds.push(Math.random()); } for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(randomSeeds[i] * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } const getArmorZoneString = (armorZones) => { return armorZones ?.map((zoneName) => { if (zoneName === zoneName.toUpperCase()) { return zoneName.charAt(0).toUpperCase().concat(zoneName.substr(1).toLowerCase()); } return zoneName; }) .filter(Boolean) .sort() .join(" · "); }; const getGuns = (items, targetItem) => { let parentItems = []; const currentParentItems = items.filter((item) => itemCanContain(item, targetItem, "slots")); for (const parentItem of currentParentItems) { if (parentItem.types.includes("gun")) { parentItems.push(parentItem); continue; } parentItems = parentItems.concat(getGuns(items, parentItem)); } return parentItems.reduce((parents, current) => { if (!parents.some((item) => item.id === current.id)) { parents.push(current); } return parents; }, []); }; const getAttachmentPoints = (items, targetItem) => { return items .filter((parentItem) => itemCanContain(parentItem, targetItem, "slots")) .map((item) => { return { ...item, fitsTo: getGuns(items, item), }; }); }; const ConditionalWrapper = ({ condition, wrapper, children }) => { return condition ? wrapper(children) : children; }; function SmallItemTable(props) { let { // common maxItems, nameFilter, defaultRandom, typeFilter, containedInFilter, armorSlotFilter, sortBy, sortByDesc, // columns instaProfit, traderPrice, traderOffer, traderFilter, loyaltyLevelFilter, traderValue, traderBuybackFilter, caliberFilter, traderBuyback, fleaPrice, grid, gridSlots, innerSize, slotRatio, pricePerSlot, barterPrice, fleaValue, hideBorders, autoScroll = true, armorClass, armorZones, maxDurability, effectiveDurability, repairability, stats, typeLimit, excludeTypeFilter, minPropertyFilter, maxPropertyFilter, maxPrice, bsgCategoryFilter, handbookCategoryFilter, showContainedItems, weight, slotsPerWeight, showNetPPS, showAllSources = false, cheapestPrice, sumColumns, idFilter, useClassEffectiveDurability, excludeArmor, requireArmor, minSlots, has3Slot, has4Slot, caliber, damage, penetrationPower, armorDamage, fragChance, blindnessProtection, useAllProjectileDamage, hydration, energy, hydrationCost, energyCost, totalEnergyCost, provisionValue, soundSuppression, blocksHeadset, showAttachments, includeBlockingHeadset = true, ergonomics, ergoCost, recoilModifier, showAttachTo, attachesToItemFilter, showSlotValue, showPresets, showRestrictedType, attachmentMap, showGunDefaultPresetImages, useBarterIngredients, useCraftIngredients, minPenetration, maxPenetration, minDamage, distance, softArmorFilter, plateArmorFilter, customFilter, } = props; const { t } = useTranslation(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const skills = useSelector(selectAllSkills); const { data: handbook } = useHandbookData(); const { materialDestructibilityMap, materialRepairabilityMap } = useMemo(() => { const destruct = {}; const repair = {}; if (!handbook?.armorMaterials) { return { materialDestructibilityMap: destruct, materialRepairabilityMap: repair }; } handbook.armorMaterials.forEach((armor) => { destruct[armor.id] = armor.destructibility; repair[armor.id] = 100 - Math.round(((armor.minRepairDegradation + armor.maxRepairDegradation) / 2) * 100); }); return { materialDestructibilityMap: destruct, materialRepairabilityMap: repair }; }, [handbook]); const availableOnFlea = useCallback( (item) => { return ( handbook.fleaMarket.enabled && settings.playerLevel >= Math.max(item.minLevelForFlea, handbook.fleaMarket.minPlayerLevel) ); }, [settings, handbook], ); // Create a constant of all data returned const { data: items, status: itemsStatus } = useItemsData(); const itemCount = items ? items.length : 0; const randomSeeds = useMemo(() => { const seeds = []; if (!defaultRandom) { return seeds; } for (let i = seeds.length; i < itemCount; i++) { seeds.push(Math.random()); } return seeds; }, [itemCount, defaultRandom]); const { data: barters } = useBartersData(); const { data: crafts } = useCraftsData(); const { data: hideout } = useHideoutData(); const containedItems = useMemo(() => { if (!containedInFilter) { return {}; } const filterItems = {}; containedInFilter.forEach((ci) => { if (!ci) { return; } filterItems[ci.item.id] = ci.count; }); return filterItems; }, [containedInFilter]); const data = useMemo(() => { const formatItem = (itemData) => { const formattedItem = { id: itemData.id, name: itemData.name, shortName: itemData.shortName, normalizedName: itemData.normalizedName, avg24hPrice: itemData.avg24hPrice, lastLowPrice: itemData.lastLowPrice, iconLink: itemData.iconLink || `${process.env.PUBLIC_URL}/images/unknown-item-icon.jpg`, instaProfit: 0, itemLink: `/item/${itemData.normalizedName}`, types: itemData.types, buyFor: itemData.buyFor.filter((buyFor) => { if ( !showAllSources && buyFor.vendor.normalizedName === "flea-market" && !availableOnFlea(itemData) ) { return false; } if (!showAllSources && settings[buyFor.vendor.normalizedName] < buyFor.vendor.minTraderLevel) { return false; } if ( !showAllSources && settings.useTarkovTracker && buyFor.vendor.taskUnlock && !settings.completedQuests.includes(buyFor.vendor.taskUnlock.id) ) { return false; } if ( buyFor.vendor.normalizedName === "flea-market" && traderValue && traderBuyback && (itemData.types.includes("preset") || itemData.lastOfferCount < 2) ) { return false; } return true; }), sellFor: itemData.sellFor, buyOnFleaPrice: itemData.buyFor.find( (buyPrice) => buyPrice.vendor.normalizedName === "flea-market" && (showAllSources || availableOnFlea(itemData)), ), barters: barters.filter((barter) => { if (!barter.rewardItems[0]) { return false; } return barter.rewardItems[0].item.id === itemData.id; }), grid: itemData.grid, ratio: (itemData.properties.capacity / (itemData.width * itemData.height)).toFixed(2), size: itemData.properties.capacity, slots: itemData.width * itemData.height, armorClass: itemData.properties.class, armorZone: getArmorZoneString(itemData.properties.zones || itemData.properties.headZones), maxDurability: itemData.properties.durability, effectiveDurability: Math.floor( itemData.properties?.durability / materialDestructibilityMap[itemData.properties?.material?.id], ), repairability: materialRepairabilityMap[itemData.properties?.material?.id], stats: `${Math.round((itemData.properties.speedPenalty || 0) * 100)}% / ${Math.round((itemData.properties.turnPenalty || 0) * 100)}% / ${itemData.properties.ergoPenalty || 0}`, weight: itemData.weight, properties: itemData.properties, categories: itemData.categories, categoryIds: itemData.categoryIds, width: itemData.width, height: itemData.height, cached: itemData.cached, pricePerSlot: 0, minLevelForFlea: itemData.minLevelForFlea, }; formattedItem.sellForTradersBest = itemData.sellFor.reduce((best, sellFor) => { if (sellFor.vendor.normalizedName === "flea-market") { return best; } if (traderBuybackFilter && traderFilter !== sellFor.vendor.normalizedName) { return best; } if (!showAllSources && !settings.jaeger && sellFor.vendor.normalizedName === "jaeger") { return best; } if (!best || best.priceRUB < sellFor.priceRUB) { return sellFor; } return best; }, undefined); if (!showAllSources && !availableOnFlea(formattedItem)) { formattedItem.buyOnFleaPrice = 0; } if (formattedItem.buyOnFleaPrice && formattedItem.buyOnFleaPrice.price > 0) { formattedItem.instaProfit = formattedItem.sellForTradersBest?.priceRUB - formattedItem.buyOnFleaPrice.price; } if (formattedItem.barters.length > 0) { formattedItem.cheapestBarter = getCheapestBarter(itemData, { barters: formattedItem.barters, settings, allowAllSources: showAllSources, useBarterIngredients, useCraftIngredients, }); } formattedItem.cheapestObtainPrice = Number.MAX_SAFE_INTEGER; formattedItem.cheapestObtainInfo = null; if (formattedItem.cheapestBarter && (availableOnFlea(formattedItem) || showAllSources)) { //console.log(formattedItem.cheapestBarter.barter, settings[formattedItem.cheapestBarter.barter.trader.normalizedName]); //if (!showAllSources && settings[buyFor.vendor.normalizedName] < buyFor.vendor.minTraderLevel) formattedItem.cheapestObtainPrice = formattedItem.cheapestBarter.pricePerUnit; formattedItem.cheapestObtainInfo = formattedItem.cheapestBarter; } for (const buyFor of formattedItem.buyFor) { if (buyFor.priceRUB && buyFor.priceRUB < formattedItem.cheapestObtainPrice) { formattedItem.cheapestObtainPrice = buyFor.priceRUB; formattedItem.cheapestObtainInfo = buyFor; } } if ( !formattedItem.cheapestObtainInfo && (availableOnFlea(formattedItem) || showAllSources) && !traderBuybackFilter ) { const cheapestCraft = getCheapestCraft(itemData, { crafts, settings, allowAllSources: showAllSources, useBarterIngredients, useCraftIngredients, }); if (cheapestCraft) { formattedItem.cheapestObtainInfo = cheapestCraft; formattedItem.cheapestObtainPrice = Math.round(cheapestCraft.price / cheapestCraft.count); } } if (formattedItem.cheapestObtainInfo === null) { formattedItem.cheapestObtainPrice = 0; } if (traderBuybackFilter && formattedItem.cheapestObtainPrice) { const thisTraderSell = formattedItem.sellFor.find( (sellFor) => sellFor.vendor.normalizedName === traderFilter, ); if (thisTraderSell) { formattedItem.buyback = thisTraderSell.priceRUB / formattedItem.cheapestObtainPrice; } } if (formattedItem.cheapestObtainPrice) { formattedItem.pricePerSlot = showNetPPS ? Math.floor(formattedItem.cheapestObtainPrice / (itemData.properties.capacity - itemData.slots)) : formattedItem.cheapestObtainPrice / itemData.properties.capacity; } formattedItem.count = containedItems[itemData.id] || 1; if (armorSlotFilter && armorZones) { formattedItem.armorZone = getArmorZoneString( armorSlotFilter.reduce((zones, slot) => { if (slot.allowedPlates.some((plate) => plate.id === formattedItem.id)) { zones.push(...slot.zones); } return zones; }, []), ); } return formattedItem; }; let returnData = items .filter((item) => { return !item.types.includes("disabled"); }) .filter((item) => { if (!typeFilter) { return true; } if (typeFilter === "gun") { if (item.types.includes("gun")) { if (!item.properties?.defaultPreset) { return true; } return false; } if (!item.types.includes("preset")) { return false; } const baseItem = items.find((i) => i.id === item.properties.baseItem.id); if (!baseItem?.types.includes("gun")) { return false; } if (baseItem.properties.defaultPreset?.id !== item.id) { return false; } return true; } let typeFilterList = typeFilter; if (typeFilter && !Array.isArray(typeFilter)) { typeFilterList = [typeFilterList]; } return item.types.some((itemType) => typeFilterList.includes(itemType)); }) .filter((item) => { if (!typeLimit) { return true; } let typeLimitList = typeLimit; if (typeLimit && !Array.isArray(typeLimit)) { typeLimitList = [typeLimitList]; } return typeLimitList.every((itemType) => item.types.includes(itemType)); }) .filter((item) => { if (!excludeTypeFilter) { return true; } let excludeTypeFilterList = excludeTypeFilter; if (excludeTypeFilter && !Array.isArray(excludeTypeFilter)) { excludeTypeFilterList = [excludeTypeFilterList]; } return !item.types.some((itemType) => excludeTypeFilterList.includes(itemType)); }) .filter((item) => { if (!minPropertyFilter) { return true; } if (item.properties[minPropertyFilter.property] < minPropertyFilter.value) { return false; } return true; }) .filter((item) => { if (!maxPropertyFilter) { return true; } if (item.properties[maxPropertyFilter.property] > maxPropertyFilter.value) { return false; } return true; }) .filter((item) => { if (!bsgCategoryFilter) { return true; } let categoriesFilter = bsgCategoryFilter; if (!Array.isArray(categoriesFilter)) { categoriesFilter = [categoriesFilter]; } return item.categories.some((category) => categoriesFilter.includes(category.id)); }) .filter((item) => { if (!handbookCategoryFilter) { return true; } let categoriesFilter = handbookCategoryFilter; if (!Array.isArray(categoriesFilter)) { categoriesFilter = [categoriesFilter]; } return item.handbookCategories.some((category) => categoriesFilter.includes(category.id)); }) .filter((item) => { if (!containedInFilter) { return true; } return containedItems[item.id]; }) .filter((item) => { if (!armorSlotFilter) { return true; } return armorSlotFilter.some((slot) => slot.allowedPlates.some((plate) => plate.id === item.id)); }) .filter((item) => { if (includeBlockingHeadset) { return true; } return !item.properties.blocksHeadset; }) .filter((item) => { if (typeof minPenetration === "undefined" && typeof maxPenetration === "undefined") { return true; } const min = minPenetration || 0; let max = typeof maxPenetration === "undefined" ? Number.MAX_SAFE_INTEGER : maxPenetration; if (max === 60) { max = Number.MAX_SAFE_INTEGER; } const pen = item.properties?.penetrationPower; if (typeof pen === "undefined") { return false; } return pen >= min && pen <= max; }) .filter((item) => { if (typeof minDamage === "undefined" || typeof item.properties?.damage === "undefined") { return true; } return item.properties.damage >= minDamage; }) .map((itemData) => { return formatItem(itemData); }) .filter((item) => { if (!maxPrice) { return true; } if (item.cheapestObtainPrice > maxPrice) { return false; } return true; }) .filter((item) => { if (typeof customFilter !== "function") { return true; } return customFilter(item); }); if (traderFilter) { returnData = returnData.filter((item) => { item.buyFor = item.buyFor.filter((buy) => buy.vendor.normalizedName === traderFilter); item.sellFor = item.sellFor?.filter((sell) => sell.vendor.normalizedName === traderFilter); if (item.buyOnFleaPrice) { item.instaProfit = item.sellForTradersBest?.priceRUB - item.buyOnFleaPrice.price; } else if (traderBuybackFilter && item.cheapestObtainPrice) { item.instaProfit = item.sellForTradersBest?.priceRUB - item.cheapestObtainPrice; } if (traderBuybackFilter) { return true; } if (item.buyFor.length === 0) { return false; } if (!loyaltyLevelFilter) { return true; } return item.buyFor.some((buy) => buy.requirements.some((req) => req.type === "loyaltyLevel" && req.value === loyaltyLevelFilter), ); }); } if (traderBuybackFilter) { returnData = returnData .filter((item) => item.instaProfit !== 0) .filter((item) => item.cheapestObtainPrice > 0) .filter((item) => item.sellForTradersBest && item.sellForTradersBest.priceRUB > 500) .sort((a, b) => { return b.buyback - a.buyback; }); } if (traderOffer) { for (const barter of barters) { if (traderFilter && barter.trader.normalizedName !== traderFilter) { continue; } if (loyaltyLevelFilter && barter.level !== loyaltyLevelFilter) { continue; } const barterCost = getBarterCost(barter, { barters, crafts, settings, allowAllSources: showAllSources, useBarterIngredients, useCraftIngredients, }); const barterItem = items.find((i) => i.id === barter.rewardItems[0].item.id); returnData.push({ ...formatItem(barterItem), barter, barterCost, }); } returnData = returnData.sort((a, b) => a.name.localeCompare(b.name)); } if (nameFilter) { returnData = itemSearch(returnData, nameFilter); } if (defaultRandom && !nameFilter) { shuffleArray(returnData, randomSeeds); } if (idFilter) { const idArray = Array.isArray(idFilter) ? idFilter : [idFilter]; returnData = returnData.filter((item) => idArray.includes(item.id)); } if (excludeArmor) { returnData = returnData.filter((item) => !item.properties.class); } if (requireArmor) { returnData = returnData.filter((item) => item.properties.class); } if (minSlots) { returnData = returnData.filter((item) => item.properties.capacity >= minSlots); } if (has3Slot) { returnData = returnData.filter((item) => item.properties?.grids?.some((grid) => grid.width >= 3 || grid.height >= 3), ); } if (has4Slot) { returnData = returnData.filter((item) => item.properties?.grids?.some((grid) => grid.width * grid.height >= 4), ); } if (softArmorFilter) { returnData = returnData.filter((item) => item.properties?.armorSlots?.some( (slot) => slot.durability && slot.class >= softArmorFilter[0] && slot.class <= softArmorFilter[1], ), ); } if (plateArmorFilter && (plateArmorFilter[0] !== 0 || plateArmorFilter[1] !== 6)) { returnData = returnData.filter((item) => item.properties?.armorSlots?.some((slot) => { if (!slot.allowedPlates && plateArmorFilter[1] === 0) { return true; } if (!slot.allowedPlates) { return false; } const plateArmorClass = slot.allowedPlates?.reduce((highestClass, current) => { const plate = items.find((i) => i.id === current.id); if (plate?.properties.class > highestClass) { return plate.properties.class; } return highestClass; }, 0); return plateArmorClass >= plateArmorFilter[0] && plateArmorClass <= plateArmorFilter[1]; }), ); } if (caliberFilter) { let filterArray = []; if (!Array.isArray(caliberFilter)) { filterArray.push(caliberFilter); } else { filterArray.push(...caliberFilter); } returnData = returnData .filter((item) => { if (caliberFilter.length < 1) { return true; } let caliber = formatCaliber(item.properties.caliber, item.properties.ammoType); if (!caliber) { return false; } return caliberFilter.includes(caliber); }) .sort((a, b) => { const caliberA = formatCaliber(a.properties.caliber, a.properties.ammoType); const caliberB = formatCaliber(b.properties.caliber, b.properties.ammoType); if (caliberA === caliberB) { const damageA = a.properties.damage; const damageB = b.properties.damage; if (damageA === damageB) { return a.name.localeCompare(b.name); } return damageA - damageB; } return caliberA.localeCompare(caliberB); }); } if (showAttachments) { returnData.forEach((item) => { item.subRows = items .filter((linkedItem) => { if (!item.properties?.slots) { return false; } for (const slot of item.properties.slots) { const included = slot.filters.allowedItems.includes(linkedItem.id) || linkedItem.categoryIds.some((catId) => slot.filters.allowedCategories.includes(catId)); const excluded = slot.filters.excludedItems.includes(linkedItem.id) || linkedItem.categoryIds.some((catId) => slot.filters.excludedCategories.includes(catId)); if (included && !excluded) { return true; } } return false; }) .map((item) => formatItem(item)); }); } if (showPresets) { returnData.forEach((item) => { item.subRows = items .filter((linkedItem) => { if (!linkedItem.types.includes("preset")) { return false; } return ( linkedItem.properties.baseItem.id === item.properties?.baseItem?.id && linkedItem.id !== item.id ); }) .sort((a, b) => { return b.name.localeCompare(a.name); }) .map((item) => formatItem(item)); }); returnData.sort((a, b) => { return a.name.localeCompare(b.name); }); } if (attachmentMap) { returnData.forEach((item) => { item.subRows = items .filter((attachmentItem) => { return attachmentMap[item.id]?.includes(attachmentItem.id); }) .map((item) => formatItem(item)); }); } if (showGunDefaultPresetImages) { returnData.forEach((item) => { if (!item.types.includes("gun")) { return; } const preset = items.find((it) => it.id === item.properties?.defaultPreset?.id); if (preset) { item.iconLink = preset.iconLink; } }); } if (showAttachTo || attachesToItemFilter) { returnData.forEach((item) => { item.fitsTo = getGuns(items, item); }); } if (attachesToItemFilter) { returnData = returnData.filter((item) => { for (const baseItem of item.fitsTo) { if (baseItem.id === attachesToItemFilter.id) { return true; } } return false; }); } if (showAttachTo) { returnData.forEach((formattedItem) => { formattedItem.subRows = getAttachmentPoints(items, formattedItem) .filter((item) => { if (!attachesToItemFilter) { return true; } for (const subRow of item.fitsTo) { if (subRow.id === attachesToItemFilter.id) { return true; } } return false; }) .map((parentItem) => formatItem(parentItem)); }); } if (energy || hydration || hydrationCost || energyCost || provisionValue) { returnData.forEach((item) => { const hyd = item.properties.hydration; if (hyd) { let change = item.properties.hydration * Math.min(skills.metabolism * 0.01, 0.5); if (change < 0) { change *= -1; } item.metabolismHydration = Math.round(item.properties.hydration + change); } const eng = item.properties.energy; if (eng) { let change = item.properties.energy * Math.min(skills.metabolism * 0.01, 0.5); if (change < 0) { change *= -1; } item.metabolismEnergy = Math.round(item.properties.energy + change); } }); } return returnData; }, [ nameFilter, containedInFilter, containedItems, caliberFilter, defaultRandom, randomSeeds, items, typeFilter, traderFilter, loyaltyLevelFilter, traderBuybackFilter, barters, crafts, excludeTypeFilter, typeLimit, minPropertyFilter, maxPropertyFilter, maxPrice, bsgCategoryFilter, handbookCategoryFilter, showNetPPS, materialDestructibilityMap, materialRepairabilityMap, settings, showAllSources, idFilter, excludeArmor, requireArmor, minSlots, has3Slot, has4Slot, showAttachments, includeBlockingHeadset, showAttachTo, attachesToItemFilter, showPresets, attachmentMap, showGunDefaultPresetImages, useBarterIngredients, useCraftIngredients, minPenetration, maxPenetration, minDamage, traderValue, traderBuyback, traderOffer, armorSlotFilter, armorZones, softArmorFilter, plateArmorFilter, customFilter, hydration, energy, hydrationCost, energyCost, provisionValue, skills, ]); const lowHydrationCost = useMemo(() => { if (!totalEnergyCost && !provisionValue) { return 0; } let lowHyd = Number.MAX_SAFE_INTEGER; data.forEach((item) => { if (item.properties.hydration > 0) { if (item.cheapestObtainPrice) { const hydrationCost = item.cheapestObtainPrice / item.metabolismHydration; if (hydrationCost < lowHyd) { lowHyd = hydrationCost; } } } }); if (lowHyd === Number.MAX_SAFE_INTEGER) { lowHyd = 0; } return lowHyd; }, [data, totalEnergyCost, provisionValue]); const lowEnergyCost = useMemo(() => { if (!totalEnergyCost && !provisionValue) { return 0; } let lowEng = Number.MAX_SAFE_INTEGER; data.forEach((item) => { if (item.properties.energy > 0) { if (item.cheapestObtainPrice) { let energyCost = item.cheapestObtainPrice / item.metabolismEnergy; if (item.metabolismHydration < 0 && totalEnergyCost) { const totalHydrationCost = item.metabolismHydration * -1 * lowHydrationCost; const hydrationCostPerEnergy = totalHydrationCost / item.metabolismEnergy; energyCost = energyCost + hydrationCostPerEnergy; } if (energyCost > 0 && energyCost < lowEng) { lowEng = energyCost; } } } }); return lowEng; }, [data, totalEnergyCost, lowHydrationCost, provisionValue]); const columns = useMemo(() => { const useColumns = []; if (showAttachments || showAttachTo || showPresets || attachmentMap) { useColumns.push({ id: "expander", Header: ({ getToggleAllRowsExpandedProps, isAllRowsExpanded }) => // // {isAllRowsExpanded ? 'v' : '>'} // null, Cell: ({ row }) => // Use the row.canExpand and row.getToggleRowExpandedProps prop getter // to build the toggle for expanding a row row.canExpand ? ( ) : null, }); } useColumns.push({ Header: t("Name"), id: "name", accessor: "name", Cell: (props) => { return ( ); }, }); if (fleaValue) { useColumns.push({ Header: t("Sell to Flea"), id: "fleaValue", accessor: (d) => Number(d.lastLowPrice), sortType: (a, b, columnId, desc) => { const aFlea = a.values.fleaValue || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bFlea = b.values.fleaValue || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aFlea - bFlea; }, Cell: (allData) => { if (allData.row.original.types.includes("noFlea")) { return (
    } /> ); } const slots = allData.row.original.slots; let noValueTip = t("Not scanned on the Flea Market"); let noValueIcon = mdiHelpRhombus; if (allData.row.original.cached) { noValueTip = t("Flea market prices loading"); noValueIcon = mdiTimerSand; } return (
    } slots={slots} showSlotValue={showSlotValue} /> ); }, position: fleaValue, }); } if (fleaPrice) { useColumns.push({ Header: t("Buy on Flea"), id: "fleaPrice", accessor: (d) => Number(d.buyOnFleaPrice?.price), sortType: (a, b, columnId, desc) => { const aFlea = a.values.fleaPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bFlea = b.values.fleaPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aFlea - bFlea; }, Cell: FleaPriceCell, position: fleaPrice, }); } if (barterPrice) { useColumns.push({ Header: t("Barter"), id: "barterPrice", accessor: (d) => Number(d.cheapestBarter?.price), sortType: (a, b, columnId, desc) => { const aBart = a.values.barterPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bBart = b.values.barterPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aBart - bBart; }, Cell: (props) => { return ( } arrow >
    {props.value ? formatPrice(props.value) : "-"}
    ); }, position: barterPrice, }); } if (traderValue) { useColumns.push({ Header: t("Sell to Trader"), id: "traderValue", accessor: (d) => Number(d.sellForTradersBest?.priceRUB || 0), Cell: (datum) => TraderSellCell(datum, showSlotValue), summable: true, position: traderValue, }); } if (instaProfit) { useColumns.push({ Header: t("InstaProfit"), id: "instaProfit", accessor: "instaProfit", sortDescFirst: true, sortType: (a, b, columnId, desc) => { const aInsta = a.values.instaProfit || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bInsta = b.values.instaProfit || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aInsta - bInsta; }, Cell: ValueCell, position: instaProfit, }); } if (traderPrice) { useColumns.push({ Header: t("Trader buy"), id: "traderPrice", accessor: (d) => Number(d.buyFor[0]?.priceRUB || 0), Cell: TraderPriceCell, position: traderPrice, }); } if (traderOffer) { useColumns.push({ Header: t("Trader offer"), id: "traderOffer", accessor: (d) => { if (d.barter) { return d.barterCost; } return Number(d.buyFor[0]?.priceRUB || 0); }, Cell: (props) => { if (props.row.original.barter) { const priceSource = `${props.row.original.barter.trader.name} ${t("LL{{level}}", { level: props.row.original.barter.level })}`; const barterIcon = ( ); let barterTipTitle = ""; let taskIcon = ""; if (props.row.original.barter.taskUnlock) { taskIcon = ( ); barterTipTitle = ( {t("Task: {{taskName}}", { taskName: props.row.original.barter.taskUnlock.name })} ); } const tipContent = ( ); const displayedPrice = [priceSource, barterIcon, taskIcon]; const priceContent = []; priceContent.push(
    {formatPrice(props.value * props.row.original.count)}
    , ); priceContent.push(
    {displayedPrice}
    , ); return ( { return ( {children} ); }} >
    {priceContent}
    ); } else { return TraderPriceCell(props); } }, position: traderOffer, }); } if (traderBuyback) { useColumns.push({ Header: t("Buyback ratio"), id: "traderBuyback", accessor: "buyback", sortDescFirst: true, sortType: "basic", Cell: ({ value }) => { return (
    {`${Math.floor((Math.round(value * 100) / 100) * 100)}%`}
    ); }, position: traderBuyback, }); } if (grid) { useColumns.push({ Header: t("Grid"), id: "grid", accessor: "grid", sortType: (a, b, columnId, desc) => { const aSize = a.values.grid.pockets.reduce((totalSize, pocket) => { return (totalSize += pocket.width * pocket.height); }, 0); const bSize = b.values.grid.pockets.reduce((totalSize, pocket) => { return (totalSize += pocket.width * pocket.height); }, 0); return aSize - bSize; }, Cell: ({ value }) => { return ; }, position: grid, }); } if (gridSlots) { useColumns.push({ Header: t("Slots occupied"), id: "gridSlots", accessor: "slots", Cell: CenterCell, position: gridSlots, }); } if (innerSize) { useColumns.push({ Header: t("Slots inside"), id: "innerSize", accessor: "size", Cell: CenterCell, position: innerSize, }); } if (slotRatio) { useColumns.push({ Header: t("Slots ratio"), id: "slotRatio", accessor: "ratio", Cell: CenterCell, position: slotRatio, }); } if (pricePerSlot) { useColumns.push({ Header: t("Price per slot"), id: "pricePerSlot", accessor: "pricePerSlot", sortType: (a, b, columnId, desc) => { const aPPS = a.values.pricePerSlot || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bPPS = b.values.pricePerSlot || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aPPS - bPPS; }, Cell: ValueCell, position: pricePerSlot, }); } if (armorClass) { useColumns.push({ Header: t("Armor class"), id: "armorClass", accessor: "armorClass", sortType: (a, b) => { const aArmor = a.values.armorClass; const bArmor = b.values.armorClass; if (aArmor === bArmor) { if (effectiveDurability) { return a.values.effectiveDurability - b.values.effectiveDurability; } else if (blindnessProtection) { return a.values.blindnessProtection - b.values.blindnessProtection; } else { return a.values.maxDurability - b.values.maxDurability; } } return aArmor - bArmor; }, Cell: CenterCell, position: armorClass, }); } if (armorZones) { useColumns.push({ Header: t("Zones"), id: "armorZone", accessor: "armorZone", Cell: CenterCell, position: armorZones, }); } if (maxDurability) { useColumns.push({ Header: t("Max Durability"), id: "maxDurability", accessor: "maxDurability", Cell: CenterCell, position: maxDurability, }); } if (effectiveDurability) { useColumns.push({ Header: t("Effective Durability"), id: "effectiveDurability", accessor: (item) => { if (useClassEffectiveDurability) { return item.effectiveDurability * (item.armorClass * item.armorClass); } return item.effectiveDurability; }, Cell: CenterCell, position: effectiveDurability, }); } if (repairability) { useColumns.push({ Header: t("Repairability"), id: "repairability", accessor: "repairability", Cell: CenterCell, position: repairability, }); } if (weight) { useColumns.push({ Header: t("Weight (kg)"), id: "weight", accessor: "weight", sortType: (a, b) => { return a.values.weight - b.values.weight; }, Cell: CenterCell, position: weight, }); } if (slotsPerWeight) { useColumns.push({ Header: t("Slots per kg"), id: "slotsPerWeight", accessor: (d) => { const ratio = d.size / d.weight; return ratio.toFixed(2); }, sortType: (a, b) => { return a.values.innerSize / a.values.weight - b.values.innerSize / b.values.weight; }, Cell: CenterCell, position: slotsPerWeight, }); } if (stats) { useColumns.push({ Header: (
    {t("Stats")}
    {t("Mov/Turn/Ergo")}
    ), id: "stats", accessor: "stats", Cell: ({ value }) => { return ; }, position: stats, }); } if (caliber) { useColumns.push({ Header: t("Caliber"), id: "caliber", accessor: (item) => { let caliber = item.properties.caliber; if (!caliber) { return "-"; } caliber = formatCaliber(caliber, item.properties.ammoType); return caliber; }, Cell: CenterCell, position: caliber, }); } if (damage) { useColumns.push({ Header: t("Damage"), id: "damage", accessor: (ammoData) => useAllProjectileDamage ? ammoData.properties.projectileCount * ammoData.properties.damage : ammoData.properties.damage, Cell: CenterCell, position: damage, }); } if (penetrationPower) { useColumns.push({ Header: t("Penetration"), id: "penetrationPower", accessor: (item) => item.properties.penetrationPower, Cell: CenterCell, position: penetrationPower, }); } if (armorDamage) { useColumns.push({ Header: t("Armor damage"), id: "armorDamage", accessor: (item) => item.properties.armorDamage, Cell: CenterCell, position: armorDamage, }); } if (fragChance) { useColumns.push({ Header: t("Fragmentation chance"), id: "fragChance", accessor: (item) => `${Math.floor(item.properties.fragmentationChance * 100)}%`, Cell: CenterCell, position: fragChance, }); } if (blindnessProtection) { useColumns.push({ Header: t("Blindness protection"), id: "blindnessProtection", accessor: (item) => item.properties.blindnessProtection, Cell: ({ value }) => { let valueStr; if (!value) { valueStr = "-"; } else { valueStr = `${value * 100}%`; } return ; }, position: blindnessProtection, sortType: (a, b) => { console.log(a); return (a.values.blindnessProtection ?? 0) - (b.values.blindnessProtection ?? 0); }, }); } if (hydration) { useColumns.push({ Header: t("Hydration"), id: "hydration", accessor: (item) => item.metabolismHydration ?? 0, sortType: (a, b) => { return a.values.hydration - b.values.hydration; }, Cell: CenterCell, position: hydration, }); } if (energy) { useColumns.push({ Header: t("Energy"), id: "energy", accessor: (item) => item.metabolismEnergy ?? 0, Cell: CenterCell, position: energy, }); } if (hydrationCost) { useColumns.push({ Header: t("Hydration Cost"), id: "hydrationCost", accessor: (item) => { if (!item.cheapestObtainPrice) { return 0; } if (!item.metabolismHydration || item.metabolismHydration < 0) { return Number.MAX_SAFE_INTEGER; } return item.cheapestObtainPrice / item.metabolismHydration; }, Cell: ({ value }) => { if (!value) { value = "-"; } else if (value === Number.MAX_SAFE_INTEGER) { value = "∞"; } else { value = formatPrice(value); } return ; }, position: hydrationCost, }); } if (energyCost) { useColumns.push({ Header: t("Energy Cost"), id: "energyCost", accessor: (item) => { if (!item.cheapestObtainPrice) { return 0; } if (!item.metabolismEnergy || item.metabolismEnergy < 0) { return Number.MAX_SAFE_INTEGER; } let hydrationCostPerEnergyUnit = 0; if (item.metabolismHydration && item.metabolismHydration < 0 && totalEnergyCost) { const totalHydrationCost = item.metabolismHydration * -1 * lowHydrationCost; hydrationCostPerEnergyUnit = Math.round(totalHydrationCost / item.metabolismEnergy); } return item.cheapestObtainPrice / item.metabolismEnergy + hydrationCostPerEnergyUnit; }, Cell: ({ value }) => { if (!value) { value = "-"; } else if (value === Number.MAX_SAFE_INTEGER) { value = "∞"; } else { value = formatPrice(value); } return ; }, position: energyCost, }); } if (provisionValue) { useColumns.push({ Header: t("Hydration + Energy Value"), id: "provisionValue", accessor: (item) => { let hydValue = 0; let engValue = 0; if (item.metabolismHydration > 0) { hydValue = item.metabolismHydration * lowHydrationCost; } if (item.metabolismEnergy > 0) { engValue = item.metabolismEnergy * lowEnergyCost; } return hydValue + engValue; }, Cell: ({ value }) => { if (!value) { value = "-"; } else if (value === Number.MAX_SAFE_INTEGER) { value = "∞"; } else { value = formatPrice(value); } return ; }, position: provisionValue, }); } if (soundSuppression) { useColumns.push({ Header: t("Sound suppression"), id: "soundSuppression", // t('Low') // t('None') accessor: (item) => t(item.properties.deafening), Cell: CenterCell, position: soundSuppression, }); } if (blocksHeadset) { useColumns.push({ Header: t("Blocks earpiece"), id: "blocksHeadset", accessor: (item) => (item.properties.blocksHeadset ? t("Yes") : t("No")), Cell: CenterCell, position: blocksHeadset, }); } if (ergonomics) { useColumns.push({ Header: t("Ergonomics"), id: "ergonomics", accessor: (item) => item.properties.ergonomics, sortType: (a, b, columnId, desc) => { const aErgo = a.values.ergonomics; const bErgo = b.values.ergonomics; if (aErgo === bErgo) { if (desc) { return b.values.ergoCost - a.values.ergoCost; } else { return a.values.ergoCost - b.values.ergoCost; } } return aErgo - bErgo; }, Cell: CenterCell, position: ergonomics, }); } if (ergoCost) { useColumns.push({ Header: t("Cost per ergo"), id: "ergoCost", accessor: (item) => { if (item.cheapestObtainPrice) { return item.cheapestObtainPrice / item.properties.ergonomics; } return 0; }, sortType: (a, b, columnId, desc) => { const aErgoCost = a.values.ergoCost || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bErgoCost = b.values.ergoCost || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aErgoCost - bErgoCost; }, Cell: ({ value }) => { if (!value) { value = "-"; } else if (value === Number.MAX_SAFE_INTEGER) { value = "-"; } else { value = formatPrice(value); } return ; }, position: ergoCost, }); } if (recoilModifier) { useColumns.push({ Header: t("Recoil"), id: "recoilModifier", accessor: (item) => item.properties.recoilModifier, sortType: (a, b) => { return b.values.recoilModifier - a.values.recoilModifier; }, Cell: ({ value }) => { if (!value) { value = "-"; } else { value = `${Math.round(value * 100)}%`; } return ; }, position: recoilModifier, }); } if (distance) { useColumns.push({ Header: t("Distance"), id: "distanceModifier", accessor: (item) => item.properties.distanceModifier, sortType: (a, b) => { return b.values.distanceModifier - a.values.distanceModifier; }, Cell: ({ value }) => { if (!value) { value = "-"; } return ; }, position: distance, }); } if (cheapestPrice) { useColumns.push({ Header: t("Cheapest Price"), id: "cheapestPrice", accessor: "cheapestObtainPrice", sortType: (a, b, columnId, desc) => { const aCheap = a.values.cheapestPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); const bCheap = b.values.cheapestPrice || (desc ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER); return aCheap - bCheap; }, Cell: (props) => { let tipContent = ""; const priceContent = []; const cheapestObtainInfo = props.row.original.cheapestObtainInfo; if (cheapestObtainInfo && cheapestObtainInfo.type !== "none") { let priceSource = ""; const displayedPrice = []; let taskIcon = ""; let barterIcon = ""; if (!cheapestObtainInfo.barter && !cheapestObtainInfo.craft) { if (cheapestObtainInfo.vendor.normalizedName === "flea-market") { priceSource = cheapestObtainInfo.vendor.name; } else { priceSource = `${cheapestObtainInfo.vendor.name} ${t("LL{{level}}", { level: cheapestObtainInfo.vendor.minTraderLevel })}`; } if (cheapestObtainInfo.vendor.taskUnlock) { taskIcon = ( ); tipContent = (
    {t("Task: {{taskName}}", { taskName: cheapestObtainInfo.vendor.taskUnlock.name, })}
    ); } } else if (cheapestObtainInfo.barter) { priceSource = `${cheapestObtainInfo.barter.trader.name} ${t("LL{{level}}", { level: cheapestObtainInfo.barter.level })}`; barterIcon = ( ); let barterTipTitle = ""; if (cheapestObtainInfo.barter.taskUnlock) { taskIcon = ( ); barterTipTitle = ( {t("Task: {{taskName}}", { taskName: cheapestObtainInfo.barter.taskUnlock.name, })} ); } tipContent = ( ); } else if (cheapestObtainInfo.craft) { const craft = cheapestObtainInfo.craft; const station = hideout.find((s) => s.id === craft.station.id); priceSource = `${station.name} ${craft.level}`; let barterTipTitle = ""; if (craft.taskUnlock) { taskIcon = ( ); barterTipTitle = ( {t("Task: {{taskName}}", { taskName: craft.taskUnlock.name })} ); } tipContent = ( ); } displayedPrice.push(priceSource); displayedPrice.push(barterIcon); displayedPrice.push(taskIcon); priceContent.push(
    {formatPrice(props.value * props.row.original.count)}
    , ); priceContent.push(
    {displayedPrice}
    , ); } else { tipContent = []; if (props.row.original.types.includes("noFlea")) { priceContent.push( , ); tipContent.push(
    {t("This item can't be sold on the Flea Market")}
    , ); } else if (!availableOnFlea(props.row.original)) { priceContent.push( , ); tipContent.push(
    {t("Flea Market not available")}
    ); } else { let tipText = t("Not scanned on the Flea Market"); let icon = mdiHelpRhombus; if (props.row.original.cached) { tipText = t("Flea market prices loading"); icon = mdiTimerSand; } priceContent.push( , ); tipContent.push(
    {tipText}
    ); } tipContent.push(
    {t("No trader offers available")}
    ); } return ( { return ( {children} ); }} >
    {priceContent}
    ); }, summable: true, position: cheapestPrice, }); } const claimedPositions = []; for (let i = 1; i < useColumns.length; i++) { const column = useColumns[i]; if (Number.isInteger(column.position)) { let position = parseInt(column.position); if (showAttachments || showAttachTo || showPresets || attachmentMap) { position++; } if (position < 1) { position = 1; } if (position >= useColumns.length) { position = useColumns.length - 1; } if (position !== i && !claimedPositions.includes(position)) { //console.log(`Moving ${column.Header} from ${i} to ${position}`); claimedPositions.push(position); useColumns.splice(i, 1); useColumns.splice(position, 0, column); i = 1; } else if (position !== i && claimedPositions.includes(position)) { //console.warn(`Warning: ${column.Header} wants position ${position}, but that position has already been claimed by ${useColumns[position].Header}`); } } } return useColumns; }, [ t, instaProfit, traderPrice, traderOffer, traderValue, traderBuyback, fleaPrice, grid, gridSlots, innerSize, slotRatio, pricePerSlot, barterPrice, fleaValue, armorClass, armorZones, maxDurability, effectiveDurability, repairability, stats, showContainedItems, weight, slotsPerWeight, caliber, damage, penetrationPower, armorDamage, fragChance, cheapestPrice, blindnessProtection, useClassEffectiveDurability, useAllProjectileDamage, hydration, energy, hydrationCost, energyCost, lowHydrationCost, lowEnergyCost, totalEnergyCost, provisionValue, soundSuppression, blocksHeadset, showAttachments, showAttachTo, ergonomics, ergoCost, recoilModifier, showSlotValue, showAllSources, showPresets, showRestrictedType, attachmentMap, settings, items, barters, crafts, hideout, useBarterIngredients, useCraftIngredients, distance, ]); let extraRow = false; // If there are no items returned by the API, we need to add a row to show if (data.length <= 0) { // If the API query has not yet completed if (itemsStatus.status === "pending") { extraRow = ; // If the API query has completed, but no items were found } else { extraRow = t("No items"); } } return ( ); } export default SmallItemTable; ================================================ FILE: src/components/station-skill-trader-setting/index.css ================================================ .station-skill-trader-setting-wrapper { text-align: center; display: flex; } .station-skill-trader-setting-wrapper img { margin-right: 10px; width: 39px; } .station-skill-trader-setting-wrapper .basic-multi-select { width: 122px; } .station-skill-trader-setting-wrapper .select__control { color: var(--color-black-light); background-color: var(--color-gunmetal-dark); border-color: var(--color-gold-two); } .station-skill-trader-setting-wrapper .select__single-value { color: #fff; } ================================================ FILE: src/components/station-skill-trader-setting/index.jsx ================================================ import React from "react"; import Select from "react-select"; import { Tooltip } from "@mui/material"; import "./index.css"; import { useTranslation } from "react-i18next"; import { useDispatch, useSelector } from "react-redux"; import { selectAllStations, selectAllSkills, selectAllTraders, setStationOrTraderLevel, } from "../../features/settings/settingsSlice.mjs"; import capitalizeFirst from "../../modules/capitalize-first.js"; import camelcaseToDashes from "../../modules/camelcase-to-dashes.js"; const getNumericSelect = (min, max) => { let returnOptions = []; for (let i = min; i <= max; i = i + 1) { returnOptions.push({ value: i, label: i.toString(), }); } return returnOptions; }; const getOptionsForStation = (t, stationKey) => { let options = [ { value: 0, label: t("Not built"), }, { value: 1, label: "1", }, { value: 2, label: "2", }, { value: 3, label: "3", }, ]; if (["booze-generator", "christmas-tree", "solar-power"].includes(stationKey)) { options = [...options.slice(0, 2)]; } return options; }; const getOptionsForSkill = (t, skillKey) => { return getNumericSelect(0, 51); }; const getOptionsForTrader = (t, traderKey) => { let options = getNumericSelect(1, 4); if (traderKey === "jaeger" || traderKey === "ref") { options.unshift({ value: 0, label: t("Locked"), }); } if (traderKey === "fence") { options.unshift({ value: 0, label: "0", }); options = [...options.slice(0, 2)]; } return options; }; const StationSkillTraderSetting = React.forwardRef((props, ref) => { const { stateKey, type, isDisabled, label, image } = props; const { t } = useTranslation(); let selector; let options; let imageLink = image; const toolTip = label || t(capitalizeFirst(camelcaseToDashes(stateKey).replace(/-/g, " "))); if (type === "station") { selector = selectAllStations; options = getOptionsForStation(t, stateKey); } else if (type === "skill") { // t('Crafting') // t('Hideout Management') selector = selectAllSkills; options = getOptionsForSkill(t, stateKey); imageLink = `${process.env.PUBLIC_URL}/images/${type}s/${stateKey}-icon.png`; } else if (type === "trader") { selector = selectAllTraders; options = getOptionsForTrader(t, stateKey); imageLink = `${process.env.PUBLIC_URL}/images/${type}s/${stateKey}-icon.jpg`; } const dispatch = useDispatch(); const state = useSelector(selector); const selectedOption = options.find((option) => option.value === state[stateKey]); return (
    {`${stateKey}-icon`} { const parsed = parseInt(event.target.value, 10); if (Number.isFinite(parsed)) { setWipeDaysRemaining(parsed); } }} min={0} />
    )} {/* */}
    , ]; }; export default BitcoinFarmCalculator; ================================================ FILE: src/pages/bitcoin-farm-calculator/profit-info.jsx ================================================ import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; import useItemsData from "../../features/items/index.js"; import useBartersData from "../../features/barters/index.js"; import useCraftsData from "../../features/crafts/index.js"; import { BitcoinItemId, GraphicCardItemId, getAllProduceBitcoinData } from "./data.js"; import DataTable from "../../components/data-table/index.jsx"; import formatPrice from "../../modules/format-price.js"; import CenterCell from "../../components/center-cell/index.jsx"; import { getDurationDisplay } from "../../modules/format-duration.js"; import useHideoutData from "../../features/hideout/index.js"; import { selectAllStations } from "../../features/settings/settingsSlice.mjs"; import { averageWipeLength, currentWipeLength } from "../../modules/wipe-length.js"; import { getCheapestPrice } from "../../modules/format-cost-items.js"; // import ProfitableGraph from './profitable-graph'; const cardSlots = { 1: 10, 2: 25, 3: 50, }; const ProfitInfo = ({ profitForNumCards, showDays = 100, fuelPricePerDay, useBuildCosts, wipeDaysRemaining, gameMode, duration, }) => { const stations = useSelector(selectAllStations); const { data: hideout } = useHideoutData(); const { t } = useTranslation(); const { data: items } = useItemsData(); const { data: barters } = useBartersData(); const { data: crafts } = useCraftsData(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const bitcoinCraftDuration = useMemo(() => { if (!crafts?.length) { return 0; } const btcStation = hideout?.find((s) => s.normalizedName === "bitcoin-farm"); if (!btcStation) { return 0; } for (const craft of crafts) { //console.log(btcStation.id, craft.station.normalizedName, craft); if (craft.station.id !== btcStation.id) { continue; } return craft.duration; } return 0; }, [crafts, hideout]); const bitcoinProductionData = useMemo(() => { return getAllProduceBitcoinData(bitcoinCraftDuration); }, [bitcoinCraftDuration]); const bitcoinItem = useMemo(() => { return items.find((i) => i.id === BitcoinItemId); }, [items]); const graphicCardItem = useMemo(() => { return items.find((i) => i.id === GraphicCardItemId); }, [items]); const solarCost = useMemo(() => { const solar = hideout.find((station) => station.normalizedName === "solar-power"); let buildCost = 0; for (const req of solar.levels[0].itemRequirements) { const item = items.find((i) => i.id === req.item.id); if (!item) { continue; } const foundInRaid = req.attributes?.some((att) => att.name === "foundInRaid" && att.value === "true"); const cheapestObtainInfo = getCheapestPrice( { ...item, foundInRaid }, { barters, crafts, settings, useBarterIngredients: false, useCraftIngredients: false }, ); if (item.id === "5449016a4bdc2d6f028b456f") { cheapestObtainInfo.pricePerUnit = 1; } else if (cheapestObtainInfo.type === "none") { continue; } buildCost += cheapestObtainInfo.pricePerUnit * req.quantity; } return buildCost; }, [hideout, items, barters, crafts, settings]); const farmCosts = useMemo(() => { const farmData = hideout.find((station) => station.normalizedName === "bitcoin-farm"); const farmCosts = {}; for (const level of farmData.levels) { farmCosts[level.level] = 0; for (const req of level.itemRequirements) { const item = items.find((i) => i.id === req.item.id); if (!item) { continue; } const foundInRaid = req.attributes?.some((att) => att.name === "foundInRaid" && att.value === "true"); const cheapestObtainInfo = getCheapestPrice( { ...item, foundInRaid }, { barters, crafts, settings, useBarterIngredients: false, useCraftIngredients: false }, ); if (item.id === "5449016a4bdc2d6f028b456f") { cheapestObtainInfo.pricePerUnit = 1; } else if (cheapestObtainInfo.type === "none") { continue; } farmCosts[level.level] += cheapestObtainInfo.pricePerUnit * req.quantity; } } return farmCosts; }, [hideout, items, barters, crafts, settings]); const daysLeft = useMemo(() => { if (wipeDaysRemaining) { return wipeDaysRemaining; } return averageWipeLength() - currentWipeLength(); }, [wipeDaysRemaining]); const data = useMemo(() => { if (!bitcoinItem || !graphicCardItem) { return []; } const btcSellPrice = bitcoinItem.priceCustom || bitcoinItem.sellFor?.reduce((bestPrice, currentPrice) => { if (bestPrice < currentPrice.priceRUB) { return currentPrice.priceRUB; } return bestPrice; }, 0); const graphicsCardBuyPrice = graphicCardItem.priceCustom || graphicCardItem.buyFor?.reduce((bestPrice, currentPrice) => { if (bestPrice === 0 || bestPrice > currentPrice.priceRUB) { return currentPrice.priceRUB; } return bestPrice; }, 0); return profitForNumCards .map((graphicCardsCount) => { const data = bitcoinProductionData[graphicCardsCount]; if (!data) { return false; } const graphicCardsCost = graphicsCardBuyPrice * graphicCardsCount; const btcRevenuePerDay = data.btcPerDay * btcSellPrice; const btcProfitPerDay = btcRevenuePerDay - fuelPricePerDay; let buildCosts = 0; if (useBuildCosts) { if (stations["solar-power"] === 1) { buildCosts += solarCost; } let farmLevelNeeded = 3; for (let i = Object.values(cardSlots).length; i > 0; i--) { if (cardSlots[i] < graphicCardsCount) { break; } farmLevelNeeded = i; } for (let i = 1; i <= farmLevelNeeded; i++) { buildCosts += farmCosts[i]; } } const totalCosts = graphicCardsCost + buildCosts; let profitableDay; if (btcProfitPerDay > 0) { profitableDay = Math.ceil(totalCosts / btcProfitPerDay); } let remainingProfit; if (profitableDay && daysLeft > profitableDay) { if (daysLeft > 0) { remainingProfit = (daysLeft - profitableDay) * btcProfitPerDay; } } const values = []; for (let day = 0; day <= showDays; day = day + 1) { const fuelCost = fuelPricePerDay * day; const revenue = btcRevenuePerDay * day; const profit = revenue - totalCosts - fuelCost; values.push({ x: day, y: profit, }); } return { ...data, graphicCardsCount, values, profitableDay, graphicCardsCost, btcRevenuePerDay, fuelPricePerDay, btcProfitPerDay, buildCosts, remainingProfit, }; }) .filter(Boolean); }, [ bitcoinItem, graphicCardItem, fuelPricePerDay, profitForNumCards, showDays, solarCost, farmCosts, stations, useBuildCosts, daysLeft, bitcoinProductionData, ]); if (data.length <= 0) { return null; } const columns = [ { Header: t("Num graphic cards"), accessor: "graphicCardsCount", }, { Header: t("Time to produce 1 bitcoin"), accessor: ({ msToProduceBTC }) => getDurationDisplay(msToProduceBTC), Cell: CenterCell, }, { Header: t("BTC/day"), accessor: ({ btcPerDay }) => btcPerDay.toFixed(4), Cell: CenterCell, }, { Header: t("Estimated profit/day"), accessor: ({ btcProfitPerDay }) => formatPrice(btcProfitPerDay), Cell: CenterCell, }, { Header: t("Profitable after days"), accessor: "profitableDay", Cell: CenterCell, }, { Header: t("Total cost of graphic cards"), accessor: ({ graphicCardsCost }) => formatPrice(graphicCardsCost), Cell: CenterCell, }, ]; if (useBuildCosts) { columns.push({ Header: t("Build costs"), accessor: ({ buildCosts }) => formatPrice(buildCosts), Cell: CenterCell, }); columns.push({ Header: t("GPU + build costs"), accessor: (data) => formatPrice(data.graphicCardsCost + data.buildCosts), Cell: CenterCell, }); } if (gameMode !== "pve") { columns.push({ Header: t("Remaining profit"), accessor: ({ remainingProfit }) => formatPrice(remainingProfit), Cell: CenterCell, }); } return ( <> {/* */} ); }; export default ProfitInfo; ================================================ FILE: src/pages/bitcoin-farm-calculator/profitable-graph.jsx ================================================ import { VictoryChart, VictoryTheme, VictoryLine, VictoryAxis } from "victory"; const ProfitableGraph = (props) => { const { data } = props; return ( {data.map(({ graphicCardsCount, values }, index) => ( ))} {data.map(({ profitableDay, graphicCardsCount }) => { return ; })} ); }; export default ProfitableGraph; ================================================ FILE: src/pages/boss/index.css ================================================ /* Please See ./styles/singleEntity.css */ ================================================ FILE: src/pages/boss/index.jsx ================================================ import React, { Suspense, useCallback, useMemo, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { useParams, Link } from "react-router-dom"; import ImageViewer from "react-simple-image-viewer"; import { Icon } from "@mdi/react"; import { mdiBrain, mdiDiamondStone, mdiDice5, mdiHeart, mdiMapLegend, mdiAccountGroup, mdiInvoiceTextClockOutline, } from "@mdi/js"; import SEO from "../../components/SEO.jsx"; import CenterCell from "../../components/center-cell/index.jsx"; import ErrorPage from "../error-page/index.jsx"; import Loading from "../../components/loading/index.jsx"; import SmallItemTable from "../../components/small-item-table/index.jsx"; import DataTable from "../../components/data-table/index.jsx"; import PropertyList from "../../components/property-list/index.jsx"; import { getRelativeTimeAndUnit } from "../../modules/format-duration.js"; import capitalize from "../../modules/capitalize-first.js"; import { useBossesData } from "../../features/maps/index.js"; import useItemsData from "../../features/items/index.js"; import useMapsData, { useMapImages } from "../../features/maps/index.js"; import i18n from "../../i18n.js"; function BossPage(params) { const { t } = useTranslation(); const { data: bosses } = useBossesData(); const { data: items } = useItemsData(); const { data: maps } = useMapsData(); const allMaps = useMapImages(); const [isViewerOpen, setIsViewerOpen] = useState(false); const openImageViewer = useCallback(() => { setIsViewerOpen(true); }, []); const closeImageViewer = () => { setIsViewerOpen(false); }; const backgroundStyle = { backgroundColor: "rgba(0,0,0,.9)", zIndex: 20, }; // Format the boss table columns for locations const columnsLocations = useMemo(() => { return [ { Header: t("Map"), accessor: "map", Cell: CenterCell, }, { Header: t("Spawn Location"), accessor: "spawnLocations", Cell: CenterCell, }, { Header: t("Chance"), accessor: "chance", Cell: CenterCell, }, ]; }, [t]); // Format the boss table columns const columnsEscorts = useMemo(() => { return [ { Header: t("Map"), accessor: "map", Cell: CenterCell, }, { Header: t("Name"), accessor: "name", Cell: (props) => { if (bosses.some((boss) => boss.normalizedName === props.row.original.normalizedName)) { return ( {props.value} ); } return ; }, }, { Header: t("Count"), accessor: "count", Cell: CenterCell, }, { Header: t("Chance"), accessor: "chance", Cell: CenterCell, }, ]; }, [t, bosses]); const bossNameLower = params.bossName.toLowerCase(); // If no bosses have been returned yet, return 'loading' if (!bosses || bosses.length === 0) { return ; } // Format the boss data //const bossSpawns = formatBossData(maps); // Get the correct individual boss data //var bossSpawnData = bossSpawns.find(boss => boss.normalizedName === bossNameLower); const bossData = bosses.find((boss) => boss.normalizedName === bossNameLower); // If no boss data has been found, return the error page if (!bossData) { return ; } const loot = []; let lootKeys = []; const attachmentMap = {}; const lootValueCutoff = 80000; const getItemSlotValue = (item) => { if (!item) { return 0; } return ( item.sellFor.reduce((best, current) => { if (current.priceRUB > best) { return current.priceRUB; } return best; }, 0) / item.slots ); }; gearLoop: for (const gear of bossData.equipment) { const item = items.find((it) => it.id === gear.item.id); if (!item) { continue; } const itemValue = getItemSlotValue(item); if (item.types.includes("noFlea") || itemValue > lootValueCutoff) { loot.push(gear.item); attachmentMap[item.id] = gear.item.containsItems.map((ci) => ci.item.id); continue; } for (const attach of gear.item.containsItems) { const attachItem = items.find((it) => it.id === attach.item.id); if (!attachItem) { continue; } const attachItemValue = getItemSlotValue(item); if (attachItem.types.includes("noFlea") || attachItemValue > lootValueCutoff) { loot.push(gear.item); attachmentMap[item.id] = gear.item.containsItems.map((ci) => ci.item.id); continue gearLoop; } } } for (const lootItem of bossData.items) { const item = items.find((it) => it.id === lootItem.id); if (!item) { continue; } const itemValue = getItemSlotValue(item); if (item.types.includes("noFlea")) { loot.push(lootItem); continue; } if (itemValue > lootValueCutoff) { if ( item.types.includes("keys") && !item.normalizedName.includes("keycard") && !item.normalizedName.includes("marked") ) { lootKeys.push(lootItem); continue; } loot.push(lootItem); } } loot.sort((a, b) => { const itemA = items.find((it) => it.id === a.id); const itemB = items.find((it) => it.id === b.id); return getItemSlotValue(itemB) - getItemSlotValue(itemA); }); lootKeys.sort((a, b) => { const itemA = items.find((it) => it.id === a.id); const itemB = items.find((it) => it.id === b.id); return getItemSlotValue(itemB) - getItemSlotValue(itemA); }); lootKeys = lootKeys.slice(0, 5); loot.push(...lootKeys); // Get static boss data from json file //var bossJsonData = bossJson.find(boss => boss.normalizedName === bossNameLower); // Format the bossProperties data for the 'stats' section const bossProperties = { usedOnMaps: { value: bossData.maps.reduce((bossMaps, current) => { // Collect a list of all maps without duplicates if (!bossMaps.some((m) => m.normalizedName === current.normalizedName)) { bossMaps.push(current); } return bossMaps; }, []), label: ( {t("Map")} ), order: 2, }, }; // Collect spawn stats for each map var spawnStatsMsg = []; for (const map of bossData.maps) { let displayPercent; // If a specific boss override exists, use that instead of the default from the API const spawnChanceOverride = bossData.spawnChanceOverride?.find( (override) => override.map === map.normalizedName, ); if (spawnChanceOverride) { displayPercent = spawnChanceOverride.chance * 100; } else { let lowerBound = 1; let upperBound = 0; for (const spawn of map.spawns) { lowerBound = lowerBound > spawn.spawnChance ? spawn.spawnChance : lowerBound; upperBound = upperBound < spawn.spawnChance ? spawn.spawnChance : upperBound; } upperBound = Math.round(upperBound * 100); lowerBound = Math.round(lowerBound * 100); displayPercent = `${lowerBound}-${upperBound}`; if (lowerBound === upperBound || upperBound === 100) { displayPercent = upperBound; } } const ele = ( {`${displayPercent}% `} {`(${map.name})`} ); spawnStatsMsg.push(ele); } if (spawnStatsMsg.length > 0) { bossProperties["spawnChance"] = { value: spawnStatsMsg.reduce((prev, curr, currentIndex) => [ prev, , , curr, ]), label: ( {t("Spawn chance")} ), tooltip: t("Chance that the boss spawns on a given map"), order: 3, }; } // Display health stats if (bossData.health) { const totalHealth = bossData.health.reduce((totalHealth, current) => { totalHealth += current.max; return totalHealth; }, 0); bossProperties["bodyPartsHealth"] = { value: bossData.health, label: ( {t("Health")} ({totalHealth}) ), tooltip: t("Total boss health"), order: 4, }; } // Display behavior info if (bossData.behavior) { bossProperties["behavior"] = { // t('Patrol') // t('Rush') // t('Stalker') // t('Hostile and accurate') // t('Patrol and highly armored') // t('Group patrol') // t('Frequent healing and stim injections') // t('Sniper') // t('Batshit insane') value: t(bossData.behavior), label: ( {t("Behavior")} ), tooltip: t("The boss's general AI behavior"), order: 1, }; } // Format the boss table spawnLocation data const spawnLocations = []; for (const map of bossData.maps) { const mapStub = Object.values(allMaps).reduce((found, current) => { if (!found && current.key === `${map.normalizedName}-3d`) { found = current.key; } if (current.key === map.normalizedName) { found = current.key; } return found; }, false); let mapLink = false; if (mapStub) { mapLink = {map.name}; } for (const spawn of map.spawns) { for (const location of spawn.locations) { const chance = map.spawns.length > 1 && location.chance === 1 ? spawn.spawnChance : location.chance; spawnLocations.push({ spawnLocations: location.name, chance: `${parseInt(chance * 100)}%`, map: mapLink || map.name, }); } } } // Format the boss table escorts data const escorts = []; for (const map of bossData.maps) { const mapStub = Object.values(allMaps).reduce((found, current) => { if (!found && current.key === `${map.normalizedName}-3d`) { found = current.key; } if (current.key === map.normalizedName) { found = current.key; } return found; }, false); let mapLink = false; if (mapStub) { mapLink = {map.name}; } for (const escort of map.escorts) { for (const amount of escort.amount) { escorts.push({ map: mapLink || map.name, name: escort.name, normalizedName: escort.normalizedName, chance: `${parseInt(amount.chance * 100)}%`, count: amount.count, }); } } } if (escorts.length === 0) { for (const map of maps) { const mapStub = Object.values(allMaps).reduce((found, current) => { if (!map.id === current.id) { return false; } if (!found && current.key === `${map.normalizedName}-3d`) { found = current.key; } if (current.key === map.normalizedName) { found = current.key; } return found; }, false); let mapLink = false; if (mapStub) { mapLink = {map.name}; } const escortFor = map.bosses.reduce((foundEscorts, b) => { const spawnsWithBoss = b.escorts.some((e) => e.normalizedName === bossData.normalizedName); if (spawnsWithBoss) { foundEscorts.push({ ...b, amount: [{ chance: 1, count: 1 }] }); for (const e of b.escorts) { if (e.normalizedName === bossData.normalizedName) { continue; } foundEscorts.push(e); } } return foundEscorts; }, []); for (const escort of escortFor) { for (const amount of escort.amount) { escorts.push({ map: mapLink || map.name, name: escort.name, normalizedName: escort.normalizedName, chance: `${parseInt(amount.chance * 100)}%`, count: amount.count, }); } } } } let report = ""; if (bossData.reports?.length > 0) { report = (

    {t("Most recent reports")}

      {bossData.reports.map((report, index) => { const reportedMap = Object.values(allMaps).find((m) => m.id === report.map); let relativeTime = getRelativeTimeAndUnit(new Date(parseInt(report.timestamp)).getTime()); return (
    • {reportedMap.name}:{" "} {t("{{val, relativetime}}", { val: relativeTime[0], range: relativeTime[1] })}
    • ); })}
    ); } // Return the main react component for the boss page return [
    {bossData.name} openImageViewer(0)} />
    {t("Boss")}

    {bossData.name}

    {bossData.wikiLink && ( {t("Wiki")} )}
    {i18n.exists(`${bossData.normalizedName}-bio`, { ns: "bosses" }) && (

    {/* prettier-ignore */}

    )} {i18n.exists(`${bossData.normalizedName}-description`, { ns: "bosses" }) && t(`${bossData.normalizedName}-description`, { ns: "bosses" }).length > 0 && (

    {t("Behavior")}

    {/* prettier-ignore */}

    )}
    {report}
    openImageViewer(0)} style={{ backgroundImage: `url(${bossData.imagePosterLink})` }} />
    {isViewerOpen && ( )}

    {t("Special Boss Loot")}

    { prev.push(current.id); return prev; }, [])} attachmentMap={attachmentMap} showGunDefaultPresetImages={true} fleaValue traderValue />
    {spawnStatsMsg.length > 0 && (

    {t("Spawn Locations")}

      {/* prettier-ignore */}
    • Map: The name of the map which the boss can spawn on
    • Spawn Location: The exact location on the given map which the boss can spawn
    • Chance: If the "Spawn Chance" is activated for the map, this is the estimated chance that the boss will spawn at a given location on that map
    )} {escorts.length > 0 && (

    {t("Boss Escorts")}

    )}
    , ]; } function Boss() { const { t } = useTranslation(); // Get the boss name from the url const { bossName } = useParams(); // Capitalize the first letter of the boss name const boss = capitalize(bossName); // Return the main react component for the individual boss page return [ , } key={`suspense-boss-page-${bossName}`}> , ]; } export default Boss; ================================================ FILE: src/pages/bosses/index.css ================================================ .boss-list-wrapper { display: flex; flex-flow: wrap; justify-content: center; } .boss-page-wrapper { min-height: 0; } .boss-list-wrapper img { width: 128px; height: 128px; } .boss-sub-text { margin: 0.75rem; text-align: center; font-size: 16px; font-weight: 400; } ================================================ FILE: src/pages/bosses/index.jsx ================================================ import React, { Suspense } from "react"; import { Icon } from "@mdi/react"; import { Trans, useTranslation } from "react-i18next"; import { mdiSkull } from "@mdi/js"; import SEO from "../../components/SEO.jsx"; import Loading from "../../components/loading/index.jsx"; import { BossPageList } from "../../components/boss-list/index.jsx"; import "./index.css"; function Bosses(props) { const { t } = useTranslation(); return [ ,

    {t("Bosses")}

    {t("Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov")}

    }>

    {t("About Bosses")}

    {/* prettier-ignore */}

    In Escape from Tarkov, there are many bosses that roam the area of besieged Norvinsk.

    Each boss has unique behaviors, characteristics, and tactics. The bosses in Tarkov are feared by players of all levels and will often pose as a greater threat than enemy PMCs in the region.

    However, with high risk comes high reward. Many bosses contain high tier loot items or are required to elimate for quests. Learning the patterns, locations, and distinct attire of a boss is often the best a player can prepare themselves when a fight begins against a boss in Tarkov.

    , ]; } export default Bosses; ================================================ FILE: src/pages/control/Connect.jsx ================================================ /* eslint-disable no-restricted-globals */ import { useState, useRef } from "react"; import { useNavigate } from "react-router-dom"; import { useDispatch, useSelector } from "react-redux"; import { enableConnection, setControlId } from "../../features/sockets/socketsSlice.js"; import { useTranslation } from "react-i18next"; function Connect() { const { t } = useTranslation(); const [connectionText, setConnectionText] = useState(t("Connect")); const controlId = useSelector((state) => state.sockets.controlId); let navigate = useNavigate(); const inputRef = useRef(null); const dispatch = useDispatch(); const handleIDChange = (event) => { const tempConnectID = event.target.value.trim().toUpperCase().substring(0, 4); dispatch(setControlId(tempConnectID)); }; const handleConnectClick = (event) => { if (controlId.length !== 4) { inputRef.current.focus(); return true; } setConnectionText(`${t("Connected to")} ${controlId}`); dispatch(enableConnection()); navigate(`/control/`); }; return (
    ); } export default Connect; ================================================ FILE: src/pages/control/index.css ================================================ .control-wrapper { display: flex; flex-flow: column; padding: 15px; width: 100%; min-height: 100%; position: relative; max-width: 400px; margin: 0 auto; } .control-wrapper span { width: 100%; } .control-wrapper input, .control-wrapper select { height: 40px; width: 100%; } .control-section { display: flex; flex-flow: wrap; } .control-section select { width: 70%; } .control-section .full-width { width: 100%; } .control-section button { margin-left: auto; width: 28%; } .info-wrapper { margin-top: auto; padding: 20px; text-align: center; } .connection-wrapper { bottom: 2vh; display: flex; justify-content: space-between; width: 100%; gap: 30px; } .connection-wrapper input, .connection-wrapper select { height: 40px; text-overflow: ellipsis; text-transform: uppercase; width: calc(50% - 2px); } .connection-wrapper input[type='submit']:active { position: relative; top: 1px; } ================================================ FILE: src/pages/control/index.jsx ================================================ import { useRef, useMemo } from "react"; import Select from "react-select"; import { useSelector } from "react-redux"; import { Trans, useTranslation } from "react-i18next"; import SEO from "../../components/SEO.jsx"; import { caliberArrayWithSplit } from "../../modules/format-ammo.mjs"; import useItemsData from "../../features/items/index.js"; import { useMapImagesSortedArray } from "../../features/maps/index.js"; import Connect from "./Connect.jsx"; import "./index.css"; const ammoTypes = caliberArrayWithSplit(); const selectFilterStyle = { menu: (provided) => ({ ...provided, backgroundColor: "var(--color-gunmetal-dark)", border: "2px solid var(--color-gold-two)", borderRadius: 0, }), control: (provided) => ({ ...provided, backgroundColor: "var(--color-gunmetal-dark)", border: "2px solid var(--color-gold-two)", borderRadius: 0, }), menuList: (provided) => ({ ...provided, color: "var(--color-yellow-light)", borderRadius: 0, }), option: (provided) => ({ ...provided, "color": "var(--color-yellow-light)", "backgroundColor": "var(--color-gunmetal-dark)", "borderRadius": 0, "&:hover": { backgroundColor: "var(--color-gold-two)", color: "var(--color-gunmetal-dark)", fontweight: 700, }, }), singleValue: (provided) => ({ ...provided, color: "var(--color-gold-one)", }), multiValue: (provided) => ({ ...provided, backgroundColor: "var(--color-white)", color: "var(--color-white)", }), }; function Control(props) { const { data: items } = useItemsData(); const uniqueMaps = useMapImagesSortedArray(); const socketConnected = useSelector((state) => state.sockets.connected); const { t } = useTranslation(); const itemList = useMemo(() => { return items .map((item) => { return { label: item.name, value: item.id, }; }) .sort((a, b) => a.label.localeCompare(b.label)); }, [items]); const typeRefs = { ammo: useRef(null), map: useRef(null), lootTier: useRef(null), }; const handleMapChange = () => { handleViewChange("map", typeRefs["map"].current.value); }; const handleAmmoChange = () => { const ammoValues = []; for (const option of typeRefs["ammo"].current.children) { if (!option.selected) { continue; } ammoValues.push(option.value); } ammoValues.sort(); handleViewChange("ammo", ammoValues.join(",")); }; // const handleLootTierChange = () => { // handleViewChange('loot-tier', typeRefs['lootTier'].current.value); // }; const handleViewChange = (view, eventOrValue) => { let value = eventOrValue.target?.value || eventOrValue; if (!props.send) { return false; } props.send({ type: "command", data: { type: view, value: value, }, }); }; const handleSelectChange = (event) => { handleViewChange("item", event.value); }; return [ ,

    {t("Remote Control")}

    {t("View Map")}:
    {t("View caliber")}:
    */}
    {t("Load tarkov.dev in another browser or window to control it from here")}
    {/* prettier-ignore */}

    This page allows you to control the Tarkov.dev website using another browser. The typical use case is to have the Tarkov.dev website open in a browser on a second monitor while you play the game and this page open on your phone or another device so that you can navigate to different pages on the Tarkov.dev website without having to alt+tab out of the game. All you have to do is open the Tarkov.dev website in a browser where you want it to be displayed, click the "Click to connect" button in the lower left*, and then enter the id on this control page on the other device and click the Connect. Once connected, you can use this control page to open specific map or ammo pages in the controlled browser.

    *It appears on the lower left by default but can be toggled to the lower right side of the screen. It can also be hidden by the "Hide remote control" option on the settings page.

    , ]; } export default Control; ================================================ FILE: src/pages/converter/index.css ================================================ .reset-button { padding: 0.2rem; border-radius: 4px; margin-top: 20px; } .currency-input { display: flex; margin-right: 10px; width: 264px; margin-top: 10px; } .currency-input .icon-with-text { margin: 10px; } .error { color: var(--color-red); } ================================================ FILE: src/pages/converter/index.jsx ================================================ import { useEffect, useState } from "react"; import { Icon } from "@mdi/react"; import { mdiCashSync, mdiCurrencyRub, mdiCurrencyUsd, mdiCurrencyEur } from "@mdi/js"; import { useTranslation } from "react-i18next"; import SEO from "../../components/SEO.jsx"; import { InputFilter } from "../../components/filter/index.jsx"; import useItemsData from "../../features/items/index.js"; import itemSearch from "../../modules/item-search.js"; import useKeyPress from "../../hooks/useKeyPress.jsx"; import "./index.css"; function Converter() { const { t } = useTranslation(); const [RUBFilter, setRUBFilter] = useState(); const [USDFilter, setUSDFilter] = useState(); const [EURFilter, setEURFilter] = useState(); const [USDRate, setUSDRate] = useState(143); const [EURRate, setEURRate] = useState(159); const { data: items } = useItemsData(); const enterPress = useKeyPress("Enter"); useEffect(() => { let dollarConversion; const dollarsearch = itemSearch(items, "dollars"); const dollarItem = dollarsearch.find((item) => item.normalizedName === "dollars"); if (dollarItem) { dollarConversion = dollarItem.buyForBest.price; } setUSDRate(dollarConversion); let euroConversion; const euroSearch = itemSearch(items, "euros"); const euroItem = euroSearch.find((item) => item.normalizedName === "euros"); if (euroItem) { euroConversion = euroItem.buyForBest.price; } setEURRate(euroConversion); }, [items, setEURRate, setUSDRate]); useEffect(() => { if (enterPress) { resetInput(); } }, [enterPress]); function exchangeRate() { const exchangeRates = { RUB: { USD: 1 / USDRate, EUR: 1 / EURRate }, USD: { EUR: USDRate / EURRate, RUB: USDRate }, EUR: { USD: EURRate / USDRate, RUB: EURRate }, }; return exchangeRates; } function inputFilter(fromCurrency, amount) { if (fromCurrency === "RUB") { setRUBFilter(amount); convertCurrency(fromCurrency, amount); } else if (fromCurrency === "USD") { setUSDFilter(amount); convertCurrency(fromCurrency, amount); } else if (fromCurrency === "EUR") { setEURFilter(amount); convertCurrency(fromCurrency, amount); } } function convertCurrency(fromCurrency, amount) { if (fromCurrency === "RUB") { let convertedAmount = Math.floor(amount * exchangeRate()[fromCurrency]["USD"]); setUSDFilter(convertedAmount); convertedAmount = Math.floor(amount * exchangeRate()[fromCurrency]["EUR"]); setEURFilter(convertedAmount); } else if (fromCurrency === "USD") { let convertedAmount = Math.floor(amount * exchangeRate()[fromCurrency]["EUR"]); setEURFilter(convertedAmount); convertedAmount = Math.floor(amount * exchangeRate()[fromCurrency]["RUB"]); setRUBFilter(convertedAmount); } else if (fromCurrency === "EUR") { let convertedAmount = Math.floor(amount * exchangeRate()[fromCurrency]["USD"]); setUSDFilter(convertedAmount); convertedAmount = Math.floor(amount * exchangeRate()[fromCurrency]["RUB"]); setRUBFilter(convertedAmount); } } function resetInput() { setRUBFilter(""); setUSDFilter(""); setEURFilter(""); } return [ ,

    {t("Converter")}

    {t("Convert one currency to another")}

    { inputFilter("RUB", event.target.value); }} />
    { inputFilter("USD", event.target.value); }} />
    { inputFilter("EUR", event.target.value); }} />
    , ]; } export default Converter; ================================================ FILE: src/pages/crafts/index.css ================================================ .crafts-headline-wrapper { display: flex; align-items: center; max-width: 1200px; margin: auto; white-space: nowrap; } .crafts-page-title { flex-grow: 1; text-align: center; } .crafts-page-wrapper { min-height: 0; } @media screen and (width >= 800px) { .crafts-page-title { margin: 0; text-align: left; } } ================================================ FILE: src/pages/crafts/index.jsx ================================================ import { useState, useMemo, useCallback, useEffect } from "react"; import { useSearchParams } from "react-router-dom"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiProgressWrench, mdiCancel, mdiCached } from "@mdi/js"; import useHideoutData from "../../features/hideout/index.js"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; import SEO from "../../components/SEO.jsx"; import CraftsTable from "../../components/crafts-table/index.jsx"; import { Filter, InputFilter, ButtonGroupFilter, ButtonGroupFilterButton, ToggleFilter, } from "../../components/filter/index.jsx"; import "./index.css"; function Crafts() { const [searchParams, setSearchParams] = useSearchParams(); const [nameFilter, setNameFilter] = useState(searchParams.get("search") ?? ""); const [freeFuel, setFreeFuel] = useState(false); const [averagePrices, setAveragePrices] = useStateWithLocalStorage("averageCraftingPrices", false); const [selectedStation, setSelectedStation] = useStateWithLocalStorage( "selectedStation", searchParams.get("station") ?? "top", ); useEffect(() => { // set local storage value on initial page load if (!searchParams.get("station")) { return; } setSelectedStation(searchParams.get("station")); }, [searchParams, setSelectedStation]); const [includeBarterIngredients, setIncludeBarterIngredients] = useStateWithLocalStorage( "includeBarterIngredients", true, ); const [includeCraftIngredients, setIncludeCraftIngredients] = useStateWithLocalStorage( "includeCraftIngredients", false, ); const [showAll, setShowAll] = useState(searchParams.get("all") === "true"); const { t } = useTranslation(); const setPathFilters = useCallback( (filtervalues) => { const params = { all: showAll, station: selectedStation, search: nameFilter, }; for (const paramName in filtervalues) { params[paramName] = filtervalues[paramName]; } if (params.all !== "true") { delete params.all; } if (params.station === "top") { delete params.station; } if (params.search === "") { delete params.search; } setSearchParams(params, { replace: true }); }, [setSearchParams, showAll, selectedStation, nameFilter], ); const { data: hideout } = useHideoutData(); const stations = useMemo(() => { return hideout .filter((s) => s.crafts?.length && s.normalizedName !== "bitcoin-farm") .sort((a, b) => { return a.name.localeCompare(b.name); }); }, [hideout]); return [ ,

    {t("Hideout Crafts")}

    { setShowAll(e); setPathFilters({ all: `${e}` }); }} tooltipContent={<>{t("Shows all crafts regardless of your settings")}} /> setAveragePrices(!averagePrices)} tooltipContent={<>{t("Use average prices from the past 24 hours for profit calculations")}} /> {stations.map((station) => { return ( {station.name}} selected={station.normalizedName === selectedStation} content={{station.name}} onClick={() => { setSelectedStation(station.normalizedName); setPathFilters({ station: station.normalizedName }); }} /> ); })} {t("Most profitable craft in each station")}} selected={selectedStation === "top"} content={t("Best")} onClick={() => { setSelectedStation("top"); setPathFilters({ station: "top" }); }} /> {t("Flea Market banned items")}} selected={selectedStation === "banned"} content={} onClick={() => { setSelectedStation("banned"); setPathFilters({ station: "banned" }); }} /> {t("Use barters for item sources")}} selected={includeBarterIngredients} content={} onClick={setIncludeBarterIngredients.bind(undefined, !includeBarterIngredients)} /> {t("Use crafts for item sources")}} selected={includeCraftIngredients} content={} onClick={setIncludeCraftIngredients.bind(undefined, !includeCraftIngredients)} /> setFreeFuel(!freeFuel)} tooltipContent={ <> {t( "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.", )} } /> { setNameFilter(e.target.value); setPathFilters({ search: e.target.value }); }} />
    {/* prettier-ignore */}

    In Escape from Tarkov, crafts allow you create a variety of things. It is accomplished using a variety of hideout modules, including the water collector, workbench, medstation, lavatory, and nutrition unit.

    The "Found in Raid" status will be applied to each item created in the hideout. The entire list of these crafts is shown above. The Crafting skill has an impact on item creation time.

    When an item's icon has a blue border, it will be utilized as an auxiliary tool and, once manufacturing is finished, it will be returned to your stash.

    , ]; } export default Crafts; ================================================ FILE: src/pages/error-page/index.css ================================================ .error-page h1 { text-align: center; } ================================================ FILE: src/pages/error-page/index.jsx ================================================ import { useTranslation } from "react-i18next"; import ItemSearch from "../../components/item-search/index.jsx"; import SEO from "../../components/SEO.jsx"; import "./index.css"; function ErrorPage(props) { const { t } = useTranslation(); return [ ,

    {t("Sorry, that page doesn't exist!")}

    , ]; } export default ErrorPage; ================================================ FILE: src/pages/hideout/index.css ================================================ .hideout-module-wrapper { max-width: 1200px; margin: 0 auto; } .no-hideout-modules-visible { text-align: center; } ================================================ FILE: src/pages/hideout/index.jsx ================================================ import { useMemo } from "react"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiHome } from "@mdi/js"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; import SEO from "../../components/SEO.jsx"; import ItemsSummaryTable from "../../components/items-summary-table/index.jsx"; import { Filter, ButtonGroupFilter, ButtonGroupFilterButton, ToggleFilter } from "../../components/filter/index.jsx"; import useHideoutData from "../../features/hideout/index.js"; import "./index.css"; function Hideout() { const [showBuilt, setShowBuilt] = useStateWithLocalStorage("showBuiltHideoutStations", true); const [showLocked, setShowLocked] = useStateWithLocalStorage("showLockedHideoutStations", true); const [showTraderStationReqs, setShowTraderStationReqs] = useStateWithLocalStorage("showTraderStationReqs", false); const [selectedStation, setSelectedStation] = useStateWithLocalStorage("selectedHideoutStation", "all"); const { t } = useTranslation(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const { data: hideout } = useHideoutData(); const stations = useMemo(() => { return hideout .map((station) => { return { ...station, levels: (showBuilt && showLocked) || !settings.useTarkovTracker ? station.levels : station.levels.filter((lvl) => { if (!showBuilt && lvl.level <= settings[station.normalizedName]) { return false; } for (const req of lvl.stationLevelRequirements) { if (!showLocked && req.level > settings[req.station.normalizedName]) { return false; } } for (const req of lvl.traderRequirements) { if (!showLocked && req.level > settings[req.trader.normalizedName]) { return false; } } return true; }), }; }) .filter((station) => station.levels.length > 0) .sort((a, b) => { return a.name.localeCompare(b.name); }); }, [hideout, settings, showBuilt, showLocked]); const noStationsMessage = useMemo(() => { if (stations.length > 0) { return ""; } return

    {t("No hideout stations match filter settings.")}

    ; }, [stations, t]); return [ ,

    {t("Escape from Tarkov")} {t("Hideout")}

    {stations.map((station) => { return ( {station.name}} selected={station.normalizedName === selectedStation} content={{station.name}} onClick={setSelectedStation.bind(undefined, station.normalizedName)} /> ); })} {t("Show all stations & modules")}} selected={selectedStation === "all"} content={t("All")} onClick={setSelectedStation.bind(undefined, "all")} /> {settings.useTarkovTracker && ( setShowBuilt(!showBuilt)} tooltipContent={<>{t("Show already built stations")}} /> )} {settings.useTarkovTracker && ( setShowLocked(!showLocked)} tooltipContent={<>{t("Show unavailable stations")}} /> )} setShowTraderStationReqs(!showTraderStationReqs)} tooltipContent={<>{t("Show trader and other station level requirements")}} /> {stations.map((hideoutModule) => { /*if (hideoutModule.name === 'Christmas Tree') { return null; }*/ if (selectedStation && selectedStation !== "all" && hideoutModule.normalizedName !== selectedStation) { return null; } return hideoutModule.levels.map((level) => { if (level.itemRequirements.length === 0) { return null; } return (

    {hideoutModule.name} {level.level}

    { return { ...itemRequirement.item, quantity: itemRequirement.quantity, attributes: itemRequirement.attributes, }; })} includeTraders={showTraderStationReqs ? level.traderRequirements : []} includeStations={ showTraderStationReqs ? level.stationLevelRequirements.filter( (req) => req.station.id !== hideoutModule.id, ) : [] } />
    ); }); })} {noStationsMessage}
    , ]; } export default Hideout; ================================================ FILE: src/pages/item/index.css ================================================ .item-page-wrapper { margin: 0 auto 100px auto; max-width: 1200px; padding-top: 10px; position: relative; } .item-page-wrapper h2 { margin-top: 40px; font-size: 24px; } .item-font { font-size: 36px; font-weight: bold; } .item-icon { width: 64px; height: 64px; } .icon-and-link-wrapper { align-items: flex-start; display: none; justify-content: flex-end; flex-grow: 1; right: 0; top: 0; } .icon-and-link-wrapper canvas { margin-right: 10px; } .icon-and-link-wrapper a { display: block; text-align: right; } .information-grid { display: flex; flex-flow: wrap; gap: 10px; } .information-grid h2 { width: 100%; } .item-short-name-wrapper { font-size: x-large; } .filter-content-wrapper.compact { padding-top: 0px; padding-bottom: 0px; } .main-information-grid h1 { align-items: center; display: flex; justify-content: space-between; } .main-information-grid h1 cite { width: 100%; } .main-information-grid h1, .icon-and-link-wrapper { margin: 0 0 10px 0; } .tooltip-calculation { display: flex; } .tooltip-price-wrapper { flex-grow: 1; text-align: right; padding-left: 5px; } .text-information-wrapper { margin-left: auto; } .text-and-image-information-wrapper { align-items: center; display: flex; gap: 10px; } .text-and-image-information-wrapper:first-child { margin-left: 0; flex-basis: 0%; } .text-and-image-information-wrapper img { width: 32px; height: 32px; } .text-and-image-information-wrapper .warning-icon { width: 14px; height: 14px; vertical-align: text-bottom; position: relative; bottom: 2px; margin-right: 5px; } .text-and-image-information-wrapper .price-wrapper { width: 100%; } .text-and-image-information-wrapper.best-profit .price-wrapper, .best-profit { color: var(--color-gold-one); } .best-profit img { outline: var(--color-gold-two) solid 1px; outline-offset: -1px; } .price-wrapper-bright { color: var(--color-gold-one); } .price-wrapper.locked, .best-profit .price-wrapper.locked { color: var(--color-gold-two); } .text-and-image-information-wrapper.price-info-wrapper { align-items: center; display: flex; text-align: left; flex: 1 0 65%; } .source-wrapper { position: relative; } .quest-icon-wrapper { position: absolute; top: -13px; right: -13px; } .quest-icon-wrapper .icon-with-text { margin: 0; } .trader-wrapper { justify-content: space-between; } .item-crafts-headline-wrapper, .item-barters-headline-wrapper, .item-contents-headline-wrapper, .item-hideout-headline-wrapper, .item-quest-headline-wrapper, .item-headline-wrapper-with-controls { margin-top: 20px; margin-bottom: 20px; align-items: center; } .item-crafts-headline-wrapper h2, .item-barters-headline-wrapper h2, .item-contents-headline-wrapper h2, .item-hideout-headline-wrapper h2, .item-quest-headline-wrapper h2, .item-headline-wrapper-with-controls h2 { flex-grow: 1; margin: 0; } h2 div.historical-price-days { float: inline-end; } .historical-price-days .select__control { color: #1b1919; background-color: #2d2c2e; border-color: #9a8866; } .historical-price-days .select__single-value { color: #fff; } @media screen and (width >= 800px) { .item-page-wrapper { padding-top: 20px; } .item-crafts-headline-wrapper, .item-barters-headline-wrapper, .item-contents-headline-wrapper, .item-hideout-headline-wrapper, .item-quest-headline-wrapper, .item-headline-wrapper-with-controls { display: flex; } .icon-and-link-wrapper { display: flex; } .text-and-image-information-wrapper { display: block; } .text-and-image-information-wrapper.price-info-wrapper { flex-basis: auto; flex-grow: 1; } .text-and-image-information-wrapper img { height: 86px; width: 86px; } .text-and-image-information-wrapper .price-wrapper { text-align: center; } .single-line-grid.sell { justify-content: flex-start; } .single-line-grid.buy { justify-content: flex-end; } .icon-and-link-wrapper img { max-height: 200px; } .main-information-grid { display: flex; } .main-information-grid h1 img { display: none; } .main-information-grid h1, .icon-and-link-wrapper { margin: 0 0; } .trader-wrapper { display: flex; } } ================================================ FILE: src/pages/item/index.jsx ================================================ import { useMemo, useState, useEffect, useCallback } from "react"; import { useParams, Link, useNavigate } from "react-router-dom"; import { useSelector, useDispatch } from "react-redux"; import { Tooltip, Badge } from "@mui/material"; import { useTranslation } from "react-i18next"; import Select from "react-select"; import { Icon } from "@mdi/react"; import { mdiClipboardList, mdiTimerSand, mdiCached, mdiProgressWrench } from "@mdi/js"; import SEO from "../../components/SEO.jsx"; import SmallItemTable from "../../components/small-item-table/index.jsx"; import CraftsTable from "../../components/crafts-table/index.jsx"; import BartersTable from "../../components/barters-table/index.jsx"; import QuestTable, { getRequiredQuestItems, getRewardQuestItems } from "../../components/quest-table/index.jsx"; import CanvasGrid from "../../components/canvas-grid/index.jsx"; import ErrorPage from "../error-page/index.jsx"; import LoyaltyLevelIcon from "../../components/loyalty-level-icon/index.jsx"; import PropertyList from "../../components/property-list/index.jsx"; import ItemsForHideout from "../../components/items-for-hideout/index.jsx"; import PriceGraph from "../../components/price-graph/index.jsx"; import ItemSearch from "../../components/item-search/index.jsx"; import { ToggleFilter, ButtonGroupFilter, ButtonGroupFilterButton, RangeFilter, } from "../../components/filter/index.jsx"; import ContainedItemsList from "../../components/contained-items-list/index.jsx"; import LoadingSmall from "../../components/loading-small/index.jsx"; import ItemImage from "../../components/item-image/index.jsx"; import { PresetSelector } from "../../components/preset-selector/index.jsx"; import DataTable from "../../components/data-table/index.jsx"; import CenterCell from "../../components/center-cell/index.jsx"; import warningIcon from "../../images/icon-warning.png"; import useBartersData from "../../features/barters/index.js"; import useHideoutData from "../../features/hideout/index.js"; import useCraftsData from "../../features/crafts/index.js"; import useQuestsData, { usePrestigeData } from "../../features/quests/index.js"; import useItemsData, { useHandbookData } from "../../features/items/index.js"; import useMapsData from "../../features/maps/index.js"; import { toggleHideDogtagBarters } from "../../features/settings/settingsSlice.mjs"; import formatPrice from "../../modules/format-price.js"; import bestPrice from "../../modules/best-price.js"; import { isAnyDogtag } from "../../modules/dogtags.js"; import { getRelativeTimeAndUnit } from "../../modules/format-duration.js"; import fleaMarketFee from "../../modules/flea-market-fee.mjs"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; import { wipeDetails } from "../../modules/wipe-length.js"; import i18n from "../../i18n.js"; import "./index.css"; const ConditionalWrapper = ({ condition, wrapper, children }) => { return condition ? wrapper(children) : children; }; function TraderPrice({ currency, price, priceRUB }) { if (currency !== "RUB") { return (
    {formatPrice(price, currency)}
    ); } return formatPrice(priceRUB); } function Item() { const settings = useSelector((state) => state.settings[state.settings.gameMode]); const gameMode = useSelector((state) => state.settings.gameMode); const navigate = useNavigate(); const { itemName } = useParams(); const { t } = useTranslation(); const dispatch = useDispatch(); const [showAllCrafts, setShowAllCrafts] = useState(false); const [showAllBarters, setShowAllBarters] = useState(false); const [showAllContainedItemSources, setShowAllContainedItemSources] = useState(false); const [showAllHideoutStations, setShowAllHideoutStations] = useState(false); const [hideCompletedQuests, setHideCompletedQuests] = useState(true); const [includeBarterIngredients, setIncludeBarterIngredients] = useStateWithLocalStorage( "includeBarterIngredients", true, ); const [includeCraftIngredients, setIncludeCraftIngredients] = useStateWithLocalStorage( "includeCraftIngredients", false, ); const [showAllCompatiblePlateSources, setShowAllCompatiblePlateSources] = useState(false); const [minArmorClass, setMinArmorClass] = useState(1); const [maxArmorClass, setMaxArmorClass] = useState(6); const handleArmorClassChange = useCallback( ([min, max]) => { setMinArmorClass(min); setMaxArmorClass(max); }, [setMinArmorClass, setMaxArmorClass], ); const [priceDays, setPriceDays] = useStateWithLocalStorage("historicalPriceDays", 7); const loadingData = useMemo(() => { return { id: "loading", name: t("Loading..."), shortName: t("Loading..."), types: ["loading"], iconLink: `${process.env.PUBLIC_URL}/images/unknown-item-icon.jpg`, image512pxLink: `${process.env.PUBLIC_URL}/images/unknown-item-512.webp`, backgroundColor: "default", sellFor: [], buyFor: [], sellForTradersBest: null, }; }, [t]); const priceDaysLabels = useMemo(() => { const labels = [ { label: t("{{count}} days_other", { count: 7 }), value: 7, }, { label: t("{{count}} days_other", { count: 14 }), value: 14, }, { label: t("{{count}} days_other", { count: 30 }), value: 30, }, { label: t("{{count}} months_other", { count: 6 }), value: 183, }, { label: t("{{count}} years_one", { count: 1 }), value: 365, }, { label: t("All"), value: 7300, }, ]; if (gameMode !== "pve") { const wipes = wipeDetails(); const currentWipe = wipes.find((w) => w.ongoing === true); const insertIndex = labels.findIndex((l) => l.value > currentWipe.lengthDays); if (insertIndex > 0) { labels.splice(insertIndex, 0, { label: t("Wipe start"), value: currentWipe.lengthDays, }); } } return labels; }, [t, gameMode]); const { data: items, status: itemsStatus } = useItemsData(); const { data: handbook } = useHandbookData(); const { data: barters } = useBartersData(); const { data: crafts } = useCraftsData(); const { data: hideout } = useHideoutData(); const { data: quests } = useQuestsData(); const { data: prestiges } = usePrestigeData(); const { data: maps } = useMapsData(); const currentItemData = useMemo(() => { let item = items.find((i) => i.normalizedName === itemName); if (!item) { item = items.find((i) => i.id === itemName); } if (!item && (itemsStatus === "idle" || itemsStatus === "loading")) { return loadingData; } if (item) { let extraProps = {}; if (item.types.includes("keys")) { extraProps.usedOnMaps = maps .filter((map) => map.locks.some((l) => l.key.id === item.id)) .sort((a, b) => a.name.localeCompare(b.name)); } if (item.properties.defaultPreset) { extraProps.defaultPreset = items.find((i) => i.id === item.properties.defaultPreset.id); } return { ...item, properties: { ...item.properties, ...extraProps, }, ...bestPrice( item, handbook?.fleaMarket?.sellOfferFeeRate, handbook?.fleaMarket?.sellRequirementFeeRate, ), handbookCategories: item.handbookCategories .map((cat) => { return handbook?.handbookCategories?.find((c) => c.id === cat.id); }) .filter(Boolean), }; } return item; }, [items, itemName, handbook, itemsStatus, loadingData, maps]); const priceIsLocked = useCallback( (item, buyFor) => { let className = ""; if (buyFor.vendor.trader && settings[buyFor.vendor.normalizedName] < buyFor.vendor.minTraderLevel) { className = " locked"; } else if ( buyFor.vendor.normalizedName === "flea-market" && (!handbook.fleaMarket.enabled || settings.playerLevel < Math.max(item.minLevelForFlea, handbook.fleaMarket.minPlayerLevel)) ) { className = " locked"; } return className; }, [settings, handbook], ); const questsRequiringCount = useMemo(() => { if (!currentItemData || currentItemData.id === "loading") { return []; } return quests .map((questData) => { return getRequiredQuestItems(questData, currentItemData.id); }) .filter((required) => required.length > 0).length; }, [currentItemData, quests]); const questsProvidingCount = useMemo(() => { if (!currentItemData || currentItemData.id === "loading") { return []; } return quests .map((questData) => { return getRewardQuestItems(questData, currentItemData.id); }) .filter((reward) => reward.length > 0).length; }, [currentItemData, quests]); const prestigeAwarding = useMemo(() => { if (!currentItemData || currentItemData.id === "loading") { return; } return prestiges.find( (p) => p.rewards?.customization?.some((cust) => cust.items?.some((i) => i.id === currentItemData.id)) || p.rewards?.items.some((i) => i.item.id === currentItemData.id), ); }, [currentItemData, prestiges]); const questsToggle = useMemo(() => { if (settings.completedQuests?.length > 0) { return ( setHideCompletedQuests(!hideCompletedQuests)} tooltipContent={<>{t("Hide tasks you've completed")}} /> ); } return ""; }, [settings, hideCompletedQuests, t]); const dogtagToggle = useMemo(() => { if (!currentItemData || isAnyDogtag(currentItemData.id)) { return ""; } return ( dispatch(toggleHideDogtagBarters(!settings.hideDogtagBarters))} tooltipContent={ <> {t( 'The true "cost" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters', )} } style={{ marginLeft: "3px" }} /> ); }, [currentItemData, dispatch, settings, t]); const softArmorSlots = useMemo(() => { const columns = [ { Header: t("Zone"), id: "zones", accessor: (s) => s.zones.join(", "), }, { Header: t("Class"), id: "class", accessor: "class", Cell: CenterCell, }, { Header: t("Durability"), id: "durability", accessor: "durability", Cell: CenterCell, }, ]; if (!currentItemData?.properties?.armorSlots) { return { data: [], columns }; } const softArmorSlots = currentItemData?.properties?.armorSlots.filter((slot) => slot.durability); return { columns, data: softArmorSlots }; }, [currentItemData, t]); const plateArmorSlots = useMemo(() => { if (!currentItemData?.properties?.armorSlots) { return []; } return currentItemData?.properties?.armorSlots.filter((slot) => slot.allowedPlates); }, [currentItemData]); // if the name we got from the params are the id of the item, redirect // to a nice looking path useEffect(() => { if (currentItemData?.id === itemName) { navigate(`/item/${currentItemData.normalizedName}`); } }, [currentItemData, itemName, navigate]); if (!currentItemData && (itemsStatus === "succeeded" || itemsStatus === "failed")) { return ; } const hasProperties = !!currentItemData.properties; const containsItems = currentItemData?.containsItems?.length > 0; const hasBarters = barters.some((barter) => { let requiredItems = barter.requiredItems.some((contained) => contained?.item.id === currentItemData.id); let rewardItems = barter.rewardItems.some( (contained) => contained?.item.id === currentItemData.id || contained?.item.containsItems.some((ci) => ci?.item.id === currentItemData.id), ); return requiredItems || rewardItems; }); const hasCrafts = crafts.some((craft) => { let requiredItems = craft.requiredItems.some((contained) => contained.item.id === currentItemData.id); let rewardItems = craft.rewardItems.some((contained) => contained.item.id === currentItemData.id); return requiredItems || rewardItems; }); const usedInHideout = hideout?.some((station) => station.levels.some((module) => module.itemRequirements.some((contained) => contained.item.id === currentItemData.id), ), ); const sellForTraders = currentItemData.sellFor.filter((sellFor) => sellFor.vendor.normalizedName !== "flea-market"); currentItemData.fee = fleaMarketFee(currentItemData.basePrice, currentItemData.lastLowPrice); const sellForTradersIsTheBest = currentItemData.sellForTradersBest ? currentItemData.sellForTradersBest.priceRUB > currentItemData.lastLowPrice - currentItemData.fee : false; const useFleaPrice = currentItemData.lastLowPrice <= currentItemData.bestPrice; let fleaSellPriceDisplay = formatPrice(currentItemData.lastLowPrice); let fleaSellIcon = ""; let fleaTooltip; if (!useFleaPrice && currentItemData.bestPrice) { fleaSellPriceDisplay = formatPrice(currentItemData.bestPrice); fleaSellIcon = Warning; fleaTooltip = (
    {t("Best price to sell for")}{" "}
    {formatPrice(currentItemData.bestPrice)}
    {t("Fee")}
    {formatPrice(currentItemData.bestPriceFee)}
    {t("Profit")}{" "}
    {formatPrice(currentItemData.bestPrice - currentItemData.bestPriceFee)}
    {t( `The last observed low price for this item on the Flea Market was {{lastSeenPrice}}. However, due to how fees are calculated, you're better off selling for {{bestPrice}}.`, { lastSeenPrice: formatPrice(currentItemData.lastLowPrice), bestPrice: formatPrice(currentItemData.bestPrice), }, )}
    ); } else if (!currentItemData.lastLowPrice) { fleaSellPriceDisplay = ""; fleaSellIcon = Warning; fleaTooltip = (
    {t("Max price to sell for")}{" "}
    {formatPrice(currentItemData.bestPrice)}
    {t("Fee")}
    {formatPrice(currentItemData.bestPriceFee)}
    {t("Profit")}{" "}
    {formatPrice(currentItemData.bestPrice - currentItemData.bestPriceFee)}
    {t( `This item has not been observed on the Flea Market. The maximum profitable price is {{bestPrice}}, but the item may not sell at that price. The max profitable price is impacted by the intel center and hideout management skill levels in your settings.`, { bestPrice: formatPrice(currentItemData.bestPrice), }, )}
    ); if (currentItemData.cached) { fleaSellIcon = ; fleaTooltip =
    {t("Flea market prices loading")}
    ; } } else { fleaTooltip = (
    {t("Likely sell price")}{" "}
    {useFleaPrice ? formatPrice(currentItemData.lastLowPrice) : formatPrice(currentItemData.bestPrice)}
    {t("Fee")}{" "}
    {useFleaPrice ? formatPrice(currentItemData.fee) : formatPrice(currentItemData.bestPriceFee)}
    {t("Profit")}{" "}
    {useFleaPrice ? formatPrice(currentItemData.lastLowPrice - currentItemData.fee) : formatPrice(currentItemData.bestPrice - currentItemData.bestPriceFee)}
    ); } let showRestrictedType = currentItemData.types.includes("backpack") ? "backpack" : undefined; let dateParsed = Date.parse(currentItemData.updated); let date = new Date(dateParsed); let relativeTime = getRelativeTimeAndUnit(dateParsed); return [ ,

    {!currentItemData.types.includes("loading") ? currentItemData.name : }
    {currentItemData.name}

    {currentItemData.shortName}} /> {currentItemData.wikiLink && ( {t("Wiki")} )} {showRestrictedType && (
    )} {(currentItemData.properties?.grids || currentItemData.properties?.slots) && (
    )}
    {currentItemData.grid && ( )}
    {/* Divider between sections */}
    {currentItemData.sellFor && currentItemData.sellFor.length > 0 && (

    {t("Sell for")}

    {!currentItemData.types.includes("noFlea") && (
    = currentItemData.minLevelForFlea ? "success" : "warning" } title={t("Player level: {{playerLevel}}", { playerLevel: currentItemData.minLevelForFlea || handbook.fleaMarket.minPlayerLevel, })} > Flea market
    {fleaSellIcon} {fleaSellPriceDisplay}
    )} {sellForTraders && sellForTraders.map((sellForTrader) => { const traderNormalizedName = sellForTrader.vendor.normalizedName; const traderIsBest = sellForTradersIsTheBest && traderNormalizedName === currentItemData.sellForTradersBest.vendor.normalizedName; return (
    {sellForTrader.vendor.name}
    (
    {children}
    )} > {formatPrice(sellForTrader.price, sellForTrader.currency)}
    ); })}
    )} {currentItemData.buyFor && currentItemData.buyFor.length > 0 && (

    {t("Buy for")}

    {currentItemData.buyFor.map((buyForSource, index) => { const loyaltyLevel = buyForSource.requirements.find( (requirement) => requirement.type === "loyaltyLevel", )?.value; return (
    {buyForSource.vendor.normalizedName !== "flea-market" && ( )} {buyForSource.vendor.taskUnlock && (
    {t("Task: {{taskName}}", { taskName: buyForSource.vendor.taskUnlock.name, })}
    } arrow >
    )} ( {children} )} > ( = currentItemData.minLevelForFlea ? "success" : "warning" } title={t("Player level: {{playerLevel}}", { playerLevel: currentItemData.minLevelForFlea || handbook.fleaMarket.minPlayerLevel, })} > {children} )} > {buyForSource.vendor.name}
    ); })}
    )}
    {currentItemData.id && currentItemData.id !== "loading" && !currentItemData.types.includes("noFlea") && (

    {t("Flea price history")}{" "}


    {t("Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %", { changeLast48h: currentItemData.changeLast48h, changeLast48Percent: currentItemData.changeLast48hPercent, })}
    {t("Lowest scanned price last 24h: {{low24hPrice}}", { low24hPrice: formatPrice(currentItemData.low24hPrice), })}
    {t("Highest scanned price last 24h: {{high24hPrice}}", { high24hPrice: formatPrice(currentItemData.high24hPrice), })}
    {t("Updated: {{val, relativetime}}", { val: relativeTime[0], range: relativeTime[1], })}
    )}

    {t("Stats")}

    {hasProperties ? ( ) : ( )}
    {softArmorSlots.data.length > 0 && (

    {t("Soft Armor Slots")}

    )} {plateArmorSlots.length > 0 && (

    {t("Compatible Armor Plates")}

    setShowAllCompatiblePlateSources(!showAllCompatiblePlateSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> { handleArmorClassChange(value); }} />
    )} {containsItems && (

    {t("Items contained in {{itemName}}", { itemName: currentItemData.name })}

    setShowAllContainedItemSources(!showAllContainedItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    )} {hasBarters && (

    {t("Barters with {{itemName}}", { itemName: currentItemData.name })}

    setShowAllBarters(!showAllBarters)} tooltipContent={<>{t("Shows all barters regardless of your settings")}} /> {dogtagToggle} {t("Use barters for item sources")}} selected={includeBarterIngredients} content={} onClick={setIncludeBarterIngredients.bind(undefined, !includeBarterIngredients)} /> {t("Use crafts for item sources")}} selected={includeCraftIngredients} content={} onClick={setIncludeCraftIngredients.bind(undefined, !includeCraftIngredients)} />
    )} {hasCrafts && (

    {t("Crafts with {{itemName}}", { itemName: currentItemData.name })}

    setShowAllCrafts(!showAllCrafts)} tooltipContent={<>{t("Shows all crafts regardless of your settings")}} /> {t("Use barters for item sources")}} selected={includeBarterIngredients} content={} onClick={setIncludeBarterIngredients.bind(undefined, !includeBarterIngredients)} /> {t("Use crafts for item sources")}} selected={includeCraftIngredients} content={} onClick={setIncludeCraftIngredients.bind(undefined, !includeCraftIngredients)} />
    )} {usedInHideout && (

    {t("Hideout modules needing {{itemName}}", { itemName: currentItemData.name })}

    setShowAllHideoutStations(!showAllHideoutStations)} tooltipContent={<>{t("Shows all modules regardless of your settings")}} />
    )} {questsRequiringCount > 0 && (

    {t("Quests requiring {{itemName}}", { itemName: currentItemData.name })}

    {questsToggle}
    )} {questsProvidingCount > 0 && (

    {t("Quests rewarding {{itemName}}", { itemName: currentItemData.name })}

    {questsToggle}
    )} {!!prestigeAwarding && (

    {t("Prestige Reward")}

    {prestigeAwarding.name}
    )}
    , ]; } export default Item; ================================================ FILE: src/pages/item-tracker/index.css ================================================ .item-tracker-wrapper { background-color: var(--color-black); height: auto; } ================================================ FILE: src/pages/item-tracker/index.jsx ================================================ import { useMemo, useCallback } from "react"; import { Switch } from "@mui/material"; import { useTranslation } from "react-i18next"; import SEO from "../../components/SEO.jsx"; import ItemGrid from "../../components/item-grid/index.jsx"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; //import quests from '../../data/quests.json'; import useItemsData from "../../features/items/index.js"; import useTradersData from "../../features/traders/index.js"; import useQuestsData from "../../features/quests/index.js"; import "./index.css"; function ItemTracker() { const { data: quests } = useQuestsData(); const [questData, setQuestData] = useStateWithLocalStorage("quests", quests); // const [questData, setQuestData] = useState(quests.data); // const [groupByQuest, setGroupByQuest] = useStateWithLocalStorage('groupByQuest', true); const [onlyFoundInRaid, setOnlyFoundInRaid] = useStateWithLocalStorage("onlyFoundInRaid", true); const { data: items } = useItemsData(); const { data: traders } = useTradersData(); const { t } = useTranslation(); const handleItemClick = useCallback( (item, event) => { event.preventDefault(); const questDataCopy = [...questData]; for (const quest of questDataCopy) { if (quest.questId !== item.questId) { continue; } for (const questItem of quest.items) { if (item.id !== questItem.id) { continue; } questItem.count = questItem.count - 1; break; } break; } setQuestData(questDataCopy); }, [questData, setQuestData], ); const handleDoneClick = useCallback( (questId, event) => { event.preventDefault(); const questDataCopy = [...questData]; for (const quest of questDataCopy) { if (quest.questId !== questId) { continue; } for (const questItem of quest.items) { questItem.count = 0; } break; } setQuestData(questDataCopy); }, [questData, setQuestData], ); const displayQuests = useMemo(() => { return questData .sort((itemA, itemB) => { if (itemA.name && itemB.name) { return itemA.name .replace(/[^a-zA-Z0-9]/g, "") .localeCompare(itemB.name.replace(/[^a-zA-Z0-9]/g, "")); } return 0; }) .map((questData) => { const questItems = []; questData.items.forEach((questItem) => { if (items.length === 0) { return; } const questTemplate = { count: 1, foundInRaid: false, onClick: handleItemClick, questId: questData.questId, }; if (questItem.__typename === "TaskObjectiveBuildItem" && !onlyFoundInRaid) { questItems.push({ ...items.find((item) => item.id === questItem.item.id), ...questTemplate, }); for (const part of questItem.containsAll) { questItems.push({ ...items.find((item) => item.id === part.id), ...questTemplate, }); } return; } if (questItem.__typename === "TaskObjectiveItem" && !(onlyFoundInRaid && !questItem.foundInRaid)) { questItems.push({ ...items.find((item) => item.id === questItem.item.id), count: questItem.count, foundInRaid: questItem.foundInRaid, onClick: handleItemClick, questId: questData.questId, }); return; } if (questItem.__typename === "TaskObjectiveMark" && !onlyFoundInRaid) { questItems.push({ ...items.find((item) => item.id === questItem.markerItem.id), ...questTemplate, }); return; } if (!(onlyFoundInRaid && !questItem.foundInRaid)) { questItems.push({ ...items.find((item) => item.id === questItem.id), count: questItem.count, foundInRaid: questItem.foundInRaid, onClick: handleItemClick, questId: questData.questId, }); } }); if (questItems.length === 0) { return false; } if (traders.length > 0) { let trader = traders.find((trader) => trader.normalizedName === questData.traderId); questData.traderName = trader.name || ""; } return ( {t("Collected")} } /> ); }); }, [onlyFoundInRaid, handleItemClick, questData, handleDoneClick, items, traders, t]); return [ ,

    {t("Escape from Tarkov")} {t("Item Tracker")}

    {/* */}
    {displayQuests}
    , ]; } export default ItemTracker; ================================================ FILE: src/pages/items/armors/index.jsx ================================================ import { useState, useRef } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiTshirtCrew } from "@mdi/js"; import useStateWithLocalStorage from "../../../hooks/useStateWithLocalStorage.jsx"; import SEO from "../../../components/SEO.jsx"; import { Filter, ToggleFilter, InputFilter, RangeFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; const marks = { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, }; function Armors(props) { const [showAllArmorSources, setShowAllArmorSources] = useState(false); const [useClassEffectiveDurability, setUseClassEffectiveDurability] = useStateWithLocalStorage( "useClassEffectiveDurability", false, ); const [includeRigs, setIncludeRigs] = useStateWithLocalStorage("includeRigs", true); const [minArmorClassSoft, setMinArmorClassSoft] = useStateWithLocalStorage("minArmorClassSoft", 0); const [maxArmorClassSoft, setMaxArmorClassSoft] = useStateWithLocalStorage("maxArmorClassSoft", 6); const [minArmorClassPlate, setMinArmorClassPlate] = useStateWithLocalStorage("minArmorClassPlate", 0); const [maxArmorClassPlate, setMaxArmorClassPlate] = useStateWithLocalStorage("maxArmorClassPlate", 6); const [maxPrice, setMaxPrice] = useStateWithLocalStorage("armorMaxPrice", ""); const { t } = useTranslation(); const defaultSoftArmor = useRef([minArmorClassSoft, maxArmorClassSoft]); const defaultPlateArmor = useRef([minArmorClassPlate, maxArmorClassPlate]); const handleSoftArmorClassChange = ([min, max]) => { setMinArmorClassSoft(min); setMaxArmorClassSoft(max); }; const handlePlateArmorClassChange = ([min, max]) => { setMinArmorClassPlate(min); setMaxArmorClassPlate(max); }; const typeFilter = ["armor"]; if (includeRigs) { typeFilter.push("rig"); } return [ ,

    {t("Armors")}

    setShowAllArmorSources(!showAllArmorSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> setUseClassEffectiveDurability(!useClassEffectiveDurability)} checked={useClassEffectiveDurability} /> setIncludeRigs(!includeRigs)} checked={includeRigs} /> setMaxPrice(Number(e.target.value))} placeholder={t("max price")} type="number" /> { handleSoftArmorClassChange(values); }} /> { handlePlateArmorClassChange(values); }} />
    {/* prettier-ignore */}

    {"In the video game Escape from Tarkov, armor vests are worn to lessen bullet damage. Helmets are typically used in addition to them."}

    , ]; } export default Armors; ================================================ FILE: src/pages/items/backpacks/index.jsx ================================================ import { useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiBagPersonal } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; function Backpacks() { const [showAllItemSources, setShowAllItemSources] = useState(false); const [showNetPPS, setShowNetPPS] = useState(false); const { t } = useTranslation(); return [ ,

    {t("Escape from Tarkov")} {t("Backpacks")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> setShowNetPPS(!showNetPPS)} checked={showNetPPS} />
    {/* prettier-ignore */}

    {"Backpacks in the Escape from Tarkov game are various-sized containers for carrying your hard-earned riches."}

    , ]; } export default Backpacks; ================================================ FILE: src/pages/items/barter-items/index.jsx ================================================ import { useCallback, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiPliers } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, InputFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; function BarterItems() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); const { t } = useTranslation(); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); return [ ,

    {t("Escape from Tarkov")} {t("Barter Items")}

    {/* prettier-ignore */}

    {"This table of barter items from Escape from Tarkov will make it simple for you to determine how much each one is worth. It can be challenging to determine which products are valuable enough to take because there are over 150 barter items in the game, and flea market pricing can fluctuate suddenly. You may optimize your loot with the aid of this interactive table."}

    , ]; } export default BarterItems; ================================================ FILE: src/pages/items/bsg-category/index.jsx ================================================ import { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { useParams } from "react-router-dom"; import SEO from "../../../components/SEO.jsx"; import ErrorPage from "../../error-page/index.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; import { useHandbookData } from "../../../features/items/index.js"; function BsgCategory() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [showAllItemSources, setShowAllItemSources] = useState(false); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); let { bsgCategoryName } = useParams(); const { t } = useTranslation(); /*const bsgCategoryData = Object.values(categoryData).find( (category) => category.urlName === bsgCategoryName?.toLowerCase(), );*/ const { data: handbook } = useHandbookData(); const category = handbook.itemCategories.find((cat) => bsgCategoryName === cat.normalizedName); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); if (!category) { return ; } return [ ,

    {t("Escape from Tarkov")} {" - "} {category.name}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    , ]; } export default BsgCategory; ================================================ FILE: src/pages/items/containers/index.jsx ================================================ import { Trans, useTranslation } from "react-i18next"; import { useState } from "react"; import { Icon } from "@mdi/react"; import { mdiArchive } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import { Filter, ToggleFilter } from "../../../components/filter/index.jsx"; function Containers(props) { const [showAllItemSources, setShowAllItemSources] = useState(false); const [showNetPPS, setShowNetPPS] = useState(false); const { t } = useTranslation(); return [ ,

    {t("Escape from Tarkov")} {t("Containers")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> { setShowNetPPS(!showNetPPS); }} checked={showNetPPS} />
    {/* prettier-ignore */}

    {"As their name implies, containers in Escape from Tarkov are items used to hold other things. Some of these items are used to clear up inventory space by acting as storage and taking up less inventory slots however some of them cannot be equipped on the character."}

    , ]; } export default Containers; ================================================ FILE: src/pages/items/glasses/index.jsx ================================================ import { useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiSunglasses } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; function Glasses() { const { t } = useTranslation(); const [showAllItemSources, setShowAllItemSources] = useState(false); return [ ,

    {t("Escape from Tarkov")} {t("Glasses")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    {/* prettier-ignore */}

    {"Eyewear in Escape from Tarkov can be used to decrease the number and quantity of raindrops on the players' screens as well as the length of flashbang effects."}

    , ]; } export default Glasses; ================================================ FILE: src/pages/items/grenades/index.jsx ================================================ import { useCallback, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiGasCylinder } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; function Grenades() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [showAllItemSources, setShowAllItemSources] = useState(false); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); const { t } = useTranslation(); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); return [ ,

    {t("Escape from Tarkov")} {t("Grenades")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    {/* prettier-ignore */}

    {"There are only a handful distinct types of grenades that may be thrown or launched in Escape from Tarkov, and each one has a unique effect: flash, smokes, high explosive, and fragmentation."}
    {"Grenades are situational, but when utilized properly, they can have deadly results. Any advantage from high-tier equipment can be fully negated by a single well-thrown grenade, whether it completely blinds the adversary, kills them instantly, or forces them out of cover and into your gunfire."}
    {"Five factors to think about while using throwable grenades include the fuse time, explosion radius, fragment damage, fragment count, and even the weight of the grenade. With specific uses arising from each component."}

    , ]; } export default Grenades; ================================================ FILE: src/pages/items/guns/index.jsx ================================================ import { useCallback, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiPistol } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; function Guns() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [showAllItemSources, setShowAllItemSources] = useState(false); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); const { t } = useTranslation(); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); return [ ,

    {t("Escape from Tarkov")} {t("Guns")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    {/* prettier-ignore */}

    {"Your main tool for survival is a weapon. Almost all weapons are completely modular, allowing them to be customized for various scenarios. All of the weaponry used in Escape from Tarkov are listed on this page."}

    , ]; } export default Guns; ================================================ FILE: src/pages/items/handbook-category/index.jsx ================================================ import { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { useParams } from "react-router-dom"; import SEO from "../../../components/SEO.jsx"; import ErrorPage from "../../error-page/index.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; import { useHandbookData } from "../../../features/items/index.js"; function HandbookCategory() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [showAllItemSources, setShowAllItemSources] = useState(false); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); let { handbookCategoryName } = useParams(); const { t } = useTranslation(); const { data: handbook } = useHandbookData(); const category = handbook.handbookCategories.find((cat) => handbookCategoryName === cat.normalizedName); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); if (!category) { return ; } let categoryImage = " - "; if (category.imageLink) { categoryImage = ( ); } return [ ,

    {t("Escape from Tarkov")} {categoryImage} {category.name}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    , ]; } export default HandbookCategory; ================================================ FILE: src/pages/items/headsets/index.jsx ================================================ import { useCallback, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiHeadset } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; function Headsets() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); const [showAllItemSources, setShowAllItemSources] = useState(false); const { t } = useTranslation(); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); return [ ,

    {t("Escape from Tarkov")} {t("Headsets")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    {/* prettier-ignore */}

    {"In Escape from Tarkov, headsets magnify low-frequency noises like footsteps while muzzling impulsive stimuli like gunshots. Different audio profiles are offered by the various models."}

    , ]; } export default Headsets; ================================================ FILE: src/pages/items/helmets/index.jsx ================================================ import { useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiRacingHelmet } from "@mdi/js"; import useStateWithLocalStorage from "../../../hooks/useStateWithLocalStorage.jsx"; import SEO from "../../../components/SEO.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import { Filter, ToggleFilter, RangeFilter, InputFilter } from "../../../components/filter/index.jsx"; const marks = { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, }; function Helmets() { const [showAllItemSources, setShowAllItemSources] = useState(false); const [includeBlockingHeadset, setIncludeBlockingHeadset] = useStateWithLocalStorage( "includeBlockingHeadset", true, ); const [minArmorClass, setMinArmorClass] = useStateWithLocalStorage("minHelmetArmorClass", 1); const [maxArmorClass, setMaxArmorClass] = useStateWithLocalStorage("maxHelmetArmorClass", 6); const [maxPrice, setMaxPrice] = useStateWithLocalStorage("helmetMaxPrice", ""); const handleArmorClassChange = ([min, max]) => { setMinArmorClass(min); setMaxArmorClass(max); }; const { t } = useTranslation(); return [ ,

    {t("Helmets")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> setIncludeBlockingHeadset(!includeBlockingHeadset)} checked={includeBlockingHeadset} /> { handleArmorClassChange(values); }} /> setMaxPrice(Number(e.target.value))} placeholder={t("max price")} type="number" />
    {/* prettier-ignore */}

    {"In Escape from Tarkov, headgear serves a variety of functions."}
    {"There are useful objects, vanity items, and safety headgear. Before entering combat, choosing a helmet that will protect different parts of the head becomes crucial."}
    {"The impact that different helmets will have on how much sound they suppress is another crucial factor to take into account. Escape from Tarkov's gameplay heavily relies on sound."}
    {"Modular helmets, which have an assortment of different components, are another aspect of Escape from Tarkov. These helmets may modify the number of segments they protect. Top, Nape, Ears, Eyes, and Jaws are the segments."}

    , ]; } export default Helmets; ================================================ FILE: src/pages/items/index.css ================================================ .items-list-wrapper { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(256px, 1fr)); justify-content: space-between; } .items-page-wrapper { min-height: 0; } .items-list-wrapper a { white-space: nowrap; } .items-list-wrapper img { max-width: 100%; } .items-list-wrapper img:hover { outline: 2px solid var(--color-gold-two); } ================================================ FILE: src/pages/items/index.jsx ================================================ import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiViewGrid } from "@mdi/js"; import SEO from "../../components/SEO.jsx"; import ItemSearch from "../../components/item-search/index.jsx"; import ItemIconList from "../../components/item-icon-list/index.jsx"; import categoryPages from "../../data/category-pages.json"; import "./index.css"; function Items(props) { const { t } = useTranslation(); return [ ,

    {t("Escape from Tarkov")} {t("Items")}

    {categoryPages.map((categoryPage) => (

    {t(categoryPage.displayText)}

    {`${categoryPage.displayText} ))}

    {t( "items-page-description", "This page includes links to pages with information on different item categories, including armor, backpacks, barter items, containers, glasses, grenades, guns, headsets, helmet, keys, gun mods, pistol grips, provisions, rigs, suppressors, and more.", )}

    , ]; } export default Items; ================================================ FILE: src/pages/items/keys/index.jsx ================================================ import { useCallback, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiKeyVariant } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; function Keys() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [showAllItemSources, setShowAllItemSources] = useState(false); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); const { t } = useTranslation(); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); return [ ,

    {t("Escape from Tarkov")} {t("Keys")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    {/* prettier-ignore */}

    {"Maps, keys, key cards, and other useful objects are included in intelligence items. These will help you stay one step ahead of the competition—or at the very least, know where you are in Escape from Tarkov."}
    {"The remaining durability of keys and keycards with a limited number of uses is displayed in the bottom right corner of their icons and on their inspection screens."}

    , ]; } export default Keys; ================================================ FILE: src/pages/items/mods/index.jsx ================================================ import { useCallback, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiMagazineRifle } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; function Mods() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [showAllItemSources, setShowAllItemSources] = useState(false); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); const { t } = useTranslation(); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); return [ ,

    {t("Escape from Tarkov")} {t("Mods")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} />
    {/* prettier-ignore */}

    {"In Escape from Tarkov, the performance and functioning of a weapon are controlled by elaborate mechanisms organized into five categories:"}

    • {"Functional Mods"}
    • {"Muzzle devices (Functional Mods)"}
    • {"Sights (Functional Mods)"}
    • {"Gear Mods"}
    • {"Vital parts"}
    , ]; } export default Mods; ================================================ FILE: src/pages/items/pistol-grips/index.jsx ================================================ import { useMemo, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiHandPointingLeft } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, ToggleFilter, SelectItemFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import useItemsData from "../../../features/items/index.js"; function PistolGrips() { const [showAllItemSources, setShowAllItemSources] = useState(false); const [selectedGun, setSelectedGun] = useState(false); const { data: items } = useItemsData(); const { t } = useTranslation(); const activeGuns = useMemo(() => { return items .filter((item) => item.types.includes("gun")) .sort((a, b) => a.name.localeCompare(b.name)) .map((item) => { let iconLink = item.iconLink; if (item.properties?.defaultPreset) { const preset = items.find((i) => i.id === item.properties.defaultPreset.id); if (preset) { iconLink = preset.iconLink; } } return { ...item, iconLink, }; }); }, [items]); return [ ,

    {t("Pistol Grips")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> { if (!event) { return true; } if (!event.value) { setSelectedGun(undefined); } setSelectedGun(activeGuns.find((activeGun) => activeGun.id === event.value)); }} wide />
    {/* prettier-ignore */}

    {"In Escape from Tarkov a pistol grips and stocks are vital parts of a weapon."}

    {"On this page you can sort them buy ergonomics improvement or their cost and see on which weapon they can be mounted."}

    , ]; } export default PistolGrips; ================================================ FILE: src/pages/items/provisions/index.jsx ================================================ import { useCallback, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiFoodForkDrink } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, InputFilter, ToggleFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import QueueBrowserTask from "../../../modules/queue-browser-task.js"; function Provisions() { const defaultQuery = new URLSearchParams(window.location.search).get("search"); const [nameFilter, setNameFilter] = useState(defaultQuery || ""); const [showAllItemSources, setShowAllItemSources] = useState(false); const [useTotalEnergyCost, setUseTotalEnergyCost] = useState(true); const { t } = useTranslation(); const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); }); } }, [setNameFilter], ); return [ ,

    {t("Escape from Tarkov")} {t("Provisions")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> setUseTotalEnergyCost(!useTotalEnergyCost)} tooltipContent={<>{t("Include the cost of lost hydration in the cost of energy")}} />
    {/* prettier-ignore */}

    {"In Escape from Tarkov, provisions are utilized to replenish energy and hydration."}
    {"Your Metabolism skill level will determine how effective they are."}

    , ]; } export default Provisions; ================================================ FILE: src/pages/items/rigs/index.jsx ================================================ import { useMemo, useState, useRef } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiTshirtCrewOutline } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, ToggleFilter, SliderFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import useStateWithLocalStorage from "../../../hooks/useStateWithLocalStorage.jsx"; import useItemsData from "../../../features/items/index.js"; const marks = { 0: 0, 5: 5, 10: 10, 15: 15, 20: 20, 25: 25, }; function Rigs() { const { data: items } = useItemsData(); const [includeArmoredRigs, setIncludeArmoredRigs] = useStateWithLocalStorage("includeArmoredRigs", true); const [minSlots, setMinSlots] = useStateWithLocalStorage("minSlots", 0); const [has3Slot, setHas3Slot] = useState(false); const [has4Slot, setHas4Slot] = useState(false); const [showNetPPS, setShowNetPPS] = useState(false); const [showAllItemSources, setShowAllItemSources] = useState(false); const { t } = useTranslation(); const displayItems = useMemo(() => items.filter((item) => item.types.includes("rig")), [items]); const maxSlots = useMemo(() => { let max = Math.max(...displayItems.map((displayItem) => displayItem.properties.capacity || 0)); if (max === Infinity) { max = 1; } return max; }, [displayItems]); const minSlotDefault = useRef(minSlots); const handleMinSlotsChange = (e) => { setMinSlots(parseInt(e.target.value)); }; return [ ,

    {t("Rigs")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> setIncludeArmoredRigs(!includeArmoredRigs)} checked={includeArmoredRigs} /> setHas3Slot(!has3Slot)} checked={has3Slot} /> setHas4Slot(!has4Slot)} checked={has4Slot} /> setShowNetPPS(!showNetPPS)} checked={showNetPPS} />
    {/* prettier-ignore */}

    {"When it comes to carrying and storing ammunition and magazines during your excursions in Escape from Tarkov, chest rigs are crucial. Some even provide you with additional security."}

    , ]; } export default Rigs; ================================================ FILE: src/pages/items/suppressors/index.jsx ================================================ import { useMemo, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiBottleWine } from "@mdi/js"; import SEO from "../../../components/SEO.jsx"; import { Filter, ToggleFilter, SelectItemFilter } from "../../../components/filter/index.jsx"; import SmallItemTable from "../../../components/small-item-table/index.jsx"; import useItemsData from "../../../features/items/index.js"; function Suppressors() { const [showAllItemSources, setShowAllItemSources] = useState(false); const [selectedGun, setSelectedGun] = useState(false); const { data: items } = useItemsData(); const { t } = useTranslation(); const activeGuns = useMemo(() => { return items .filter((item) => item.types.includes("gun")) .sort((a, b) => a.name.localeCompare(b.name)) .map((item) => { let iconLink = item.iconLink; if (item.properties?.defaultPreset) { const preset = items.find((i) => i.id === item.properties.defaultPreset.id); if (preset) { iconLink = preset.iconLink; } } return { ...item, iconLink, }; }); }, [items]); return [ ,

    {t("Escape from Tarkov")} {t("Suppressors")}

    setShowAllItemSources(!showAllItemSources)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> { if (!event) { return true; } if (!event.value) { setSelectedGun(undefined); } setSelectedGun(activeGuns.find((activeGun) => activeGun.id === event.value)); }} wide />
    {/* prettier-ignore */}

    {"In Escape from Tarkov, a suppressor is a muzzle device (a functional mod) and can be installed on a weapon to muffle gunshot sound."}

    {"On this page you can sort them buy ergonomics penalty, recoil improvement or their cost and see on which weapon they can be directly mounted."}

    , ]; } export default Suppressors; ================================================ FILE: src/pages/loot-tiers/index.css ================================================ .loot-tier-wrapper { flex-flow: column wrap; display: flex; justify-content: center; align-items: center; } .loot-tier-text { margin: 0.75rem; text-align: center; } .loot-tier-main-wrapper { height: auto; } ================================================ FILE: src/pages/loot-tiers/index.jsx ================================================ import { useState, useCallback, useMemo, useRef } from "react"; import debounce from "lodash.debounce"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import { useHotkeys } from "react-hotkeys-hook"; import { Icon } from "@mdi/react"; import { mdiFinance } from "@mdi/js"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; import SEO from "../../components/SEO.jsx"; import ItemGrid from "../../components/item-grid/index.jsx"; import { Filter, ToggleFilter, SelectFilter, InputFilter } from "../../components/filter/index.jsx"; import QueueBrowserTask from "../../modules/queue-browser-task.js"; import capitalizeFirst from "../../modules/capitalize-first.js"; import itemSearch from "../../modules/item-search.js"; import fleaMarketFee from "../../modules/flea-market-fee.mjs"; import useItemsData, { useHandbookData } from "../../features/items/index.js"; import "./index.css"; const defaultGroupNames = ["S", "A", "B", "C", "D", "E", "F"]; const DEFAULT_MAX_ITEMS = 256; const arrayChunk = (inputArray, chunkLength) => { return inputArray.reduce((resultArray, item, index) => { const chunkIndex = Math.floor(index / chunkLength); if (!resultArray[chunkIndex]) { resultArray[chunkIndex] = []; // start a new chunk } resultArray[chunkIndex].push(item); return resultArray; }, []); }; function LootTier(props) { const settings = useSelector((state) => state.settings[state.settings.gameMode]); const [numberFilter, setNumberFilter] = useState(DEFAULT_MAX_ITEMS); const [minPrice, setMinPrice] = useStateWithLocalStorage("minPrice", 0); const [ignoreFleaSetting, setIgnoreFleaSetting] = useStateWithLocalStorage("ignoreFleaSetting", false); const [includeMarked, setIncludeMarked] = useStateWithLocalStorage("includeMarked", false); const [groupByType, setGroupByType] = useStateWithLocalStorage("groupByType", false); const { t } = useTranslation(); const filterOptions = useMemo(() => { return [ { value: "barter", label: t("Barters"), default: true, }, { value: "keys", label: t("Keys"), default: true, }, // { // value: 'marked', // label: t('Marked'), // default: false, // }, { value: "mods", label: t("Mods"), default: true, }, { value: "provisions", label: t("Provisions"), default: true, }, { value: "wearable", label: t("Wearables"), default: true, }, { value: "gun", label: t("Guns"), default: true, }, ]; }, [t]); const [filters, setFilters] = useStateWithLocalStorage("filters", { name: "", types: filterOptions .map((filter) => { if (filter.default) { return filter.value; } return false; }) .filter(Boolean), }); const inputFilterRef = useRef(); useHotkeys("ctrl+q", () => { if (inputFilterRef?.current.scrollIntoView) { inputFilterRef.current.scrollIntoView({ behavior: "smooth", block: "start", }); } inputFilterRef?.current.focus(); }); const handleFilterChange = (selectedFilters) => { QueueBrowserTask.task(() => { setFilters({ ...filters, types: selectedFilters?.map((selectedValue) => { return selectedValue.value; }) || filterOptions .map((filter) => { if (filter.default) { return filter.value; } return false; }) .filter(Boolean), }); }); }; const { data: items } = useItemsData(); const { data: handbook } = useHandbookData(); const itemData = useMemo(() => { return items .map((item) => { let baseImageLink = item.baseImageLink; let width = item.width; let height = item.height; let slots = item.slots; let itemTypes = item.types; let priceRUB = item.cached ? item.basePrice : item.sellForTradersBest.priceRUB; let sellTo = item.sellForTradersBest.vendor.name; let sellToNormalized = item.sellForTradersBest.vendor.normalizedName; let normalizedName = item.normalizedName; if (item.types.includes("gun")) { // Overrides guns' dimensions using their default height and width. // Fixes a bug where PPS was calculated using just a weapon receiver. if (item.properties.defaultPreset) { // use default preset images for item const preset = items.find((i) => i.id === item.properties.defaultPreset.id); if (preset) { width = preset.width; height = preset.height; slots = width * height; baseImageLink = preset.baseImageLink; priceRUB = preset.cached ? preset.basePrice : preset.sellForTradersBest.priceRUB; sellTo = preset.sellForTradersBest.vendor.name; sellToNormalized = preset.sellForTradersBest.vendor.normalizedName; normalizedName = preset.normalizedName; } } itemTypes = item.types.filter((type) => type !== "wearable"); } // Use flea market if: // 1. User has flea enabled // 2. Ignore setting is on (regardless of user's flea setting) const shouldUseFlea = ignoreFleaSetting || (handbook.fleaMarket.enabled && settings.playerLevel >= Math.max(handbook.fleaMarket.minPlayerLevel, item.minLevelForFlea)); if (shouldUseFlea && !item.types.includes("noFlea")) { const fleaFee = fleaMarketFee(item.basePrice, item.lastLowPrice); const fleaPrice = item.lastLowPrice - fleaFee; if (fleaPrice >= priceRUB) { sellTo = "Flea Market"; sellToNormalized = "flea-market"; priceRUB = fleaPrice; } } return { ...item, sellTo: sellTo, sellToNormalized: sellToNormalized, pricePerSlot: Math.floor(priceRUB / slots), normalizedName, width, height, slots, baseImageLink, types: itemTypes, }; }) .filter((item) => { if (item.types.includes("unLootable")) { return false; } return true; }); }, [settings, items, handbook, ignoreFleaSetting]); const typeFilteredItems = useMemo(() => { const innerTypeFilteredItems = itemData.filter((item) => { if (!includeMarked && item.types.includes("markedOnly")) { return false; } const intersection = item.types.filter((type) => filters.types?.includes(type)); // No categories matching if (intersection.length === 0) { return false; } if (minPrice && item.pricePerSlot < minPrice) { return false; } return true; }); return innerTypeFilteredItems; }, [filters.types, includeMarked, itemData, minPrice]); const filteredItems = useMemo(() => { // const items = typeFilteredItems.filter((item) => { // if ( // filters.name.length > 0 && // item.name.toLowerCase().indexOf(filters.name) === -1 && // item.shortName?.toLowerCase().indexOf(filters.name) === -1 // ) { // return false; // } // return true; // }); let items = typeFilteredItems; if (filters.name.length > 0) { items = itemSearch(typeFilteredItems, filters.name); } items.sort((itemA, itemB) => { const aPPS = itemA.pricePerSlot || Number.MIN_SAFE_INTEGER; const bPPS = itemB.pricePerSlot || Number.MIN_SAFE_INTEGER; return bPPS - aPPS; }); return items; }, [filters.name, typeFilteredItems]); const minPriceHandler = debounce((event) => { console.log("debouncer called"); const newValue = Number(event.target.value); setMinPrice(newValue); if (newValue > 0) { setNumberFilter(99999); } else { setNumberFilter(DEFAULT_MAX_ITEMS); } }, 400); const selectedItems = useMemo(() => { return filteredItems.slice(0, Math.min(filteredItems.length, numberFilter)); }, [filteredItems, numberFilter]); const { groupNames, itemChunks } = useMemo(() => { let innerGroupNames; let innerItemChunks; if (groupByType) { const activeFiltersSet = new Set(); const chunkMap = {}; for (const item of selectedItems) { for (const activeFilter of filters.types) { if (!item.types.includes(activeFilter)) { continue; } const option = filterOptions.find((option) => option.value === activeFilter); activeFiltersSet.add(option.label); if (!chunkMap[activeFilter]) { chunkMap[activeFilter] = []; } chunkMap[activeFilter].push(item); } } innerGroupNames = Array.from(activeFiltersSet); innerItemChunks = Object.values(chunkMap); } else { innerGroupNames = defaultGroupNames; innerItemChunks = arrayChunk(selectedItems, Math.ceil(selectedItems.length / innerGroupNames.length)); } for (let i = 0; i < innerItemChunks.length; i = i + 1) { innerItemChunks[i] = innerItemChunks[i]?.sort((itemA, itemB) => { if (itemA.height > itemB.height) { return -1; } if (itemA.height === itemB.height) { if (itemA.slots > itemB.slots) { return -1; } else if (itemA.slots === itemB.slots) { return 0; } else if (itemA.slots < itemB.slots) { return 1; } } if (itemA.height < itemB.height) { return 1; } return 0; }); } return { groupNames: innerGroupNames, itemChunks: innerItemChunks, }; }, [filterOptions, filters.types, groupByType, selectedItems]); const handleFilterNameChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setFilters({ ...filters, name, }); }); } }, [filters, setFilters], ); return [ ,

    {t("Escape from Tarkov")} {t("Loot tiers")}

    {t("Ranking the most valuable items in the game")}

    setIncludeMarked(!includeMarked)} checked={includeMarked} /> setGroupByType(!groupByType)} checked={groupByType} /> setIgnoreFleaSetting(!ignoreFleaSetting)} tooltipContent={<>{t("Shows all sources of items regardless of your settings")}} /> { return filterOptions.find((defaultFilter) => defaultFilter.value === filter); })} isMulti={true} options={filterOptions} onChange={handleFilterChange} /> {itemChunks.map((items, index) => ( ))}

    {t( "loot-tiers-page-description", "Learn about the different types of loot available in the game, their value, rarity, and what to keep and what to trash.", )}

    , ]; } export default LootTier; ================================================ FILE: src/pages/map/index.css ================================================ :root { /* This is to ensure maps do not clip. Please do not remove */ --display-height: auto; } #leaflet-map { background-color: transparent; } /* Popup styles */ .leaflet-popup-content-wrapper { background-color: rgb(45 45 47); } .leaflet-popup-tip { background-color: rgb(45 45 47); } .leaflet-popup-content-wrapper, .leaflet-popup-content-wrapper a { color: var(--color-gold-one); font-family: "bender", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", "Arial", sans-serif; font-style: normal; /* font-weight: 400; */ } .leaflet-popup-content-wrapper a { color: var(--color-gold-two); } /* leaflet-control-coordinates */ .leaflet-control-coordinates { color: var(--color-black); font-weight: bold; background-color: var(--color-white); background-color: rgb(from var(--color-white) r g b / 0.8); cursor: pointer; } .leaflet-control-coordinates, .leaflet-control-coordinates .uiElement input { border-radius: 5px; } .leaflet-control-coordinates .uiElement { margin: 4px; } .leaflet-control-coordinates .uiElement .labelFirst { margin-right: 4px; } .leaflet-control-coordinates .uiHidden { display: none; } .leaflet-control-coordinates .uiElement.label { color: inherit; font-weight: inherit; font-size: inherit; padding: 0; display: inherit; } /* leaflet-control-groupedlayer */ .leaflet-control-layers-group-name { font-weight: 700; margin-bottom: 0.2em; margin-left: 3px; } .leaflet-control-layers-group { margin-bottom: 0.5em; } .leaflet-control-layers-scrollbar { overflow-y: scroll; padding-right: 10px; } .leaflet-control-layers-group-label { margin-bottom: 2px; } .leaflet-control-layers-group-selector, .leaflet-control-layers-selector { vertical-align: top; } .leaflet-control-layers-group label:not(.leaflet-control-layers-group-label) { text-indent: 15px; } .leaflet-control-layers-group.group-collapsable.collapsed .leaflet-control-layers-group-collapse, .leaflet-control-layers-group.group-collapsable:not(.collapsed) .leaflet-control-layers-group-expand, .leaflet-control-layers-group.group-collapsable.collapsed label:not(.leaflet-control-layers-group-label) { display: none; } .leaflet-control-layers-group-expand-default::before { content: "+"; width: 12px; display: inline-block; text-align: center; } .leaflet-control-layers-group-collapse-default::before { content: "-"; width: 12px; display: inline-block; text-align: center; } /* leaflet-control-groupedlayer */ .control-item-image { height: 14px; position: relative; top: 2px; } /* elevation visability */ .leaflet-layer.off-level > .leaflet-tile-container, div.leaflet-pane.leaflet-overlay-pane > img.off-level, div.leaflet-pane.leaflet-overlay-pane > svg.off-level g.base-layer { opacity: 0.2; } div.leaflet-pane.leaflet-marker-pane > .off-level { opacity: 0.2; z-index: -9999 !important; } .leaflet-container.always-show-snipers div.leaflet-pane.leaflet-marker-pane > .off-level.sniper-spawn { opacity: 1; z-index: initial !important; } div.leaflet-overlay-pane > svg.leaflet-zoom-animated > g > path.off-level { stroke-opacity: 0.2; fill-opacity: 0.02; } .not-shown { display: none; } .btr-stop img { vertical-align: middle; } .extract-name, .btr-stop-name { font-weight: 800; font-size: 18px; font-family: "Arial", "Helvetica", sans-serif; color: var(--color-white); white-space: nowrap; /* text-transform: uppercase; */ vertical-align: top; text-shadow: 0 0 3px var(--color-black); -webkit-text-stroke: 0.5px var(--color-black); } .btr-stop .btr-stop-name { margin-left: 5px; color: var(--color-gold-one); text-shadow: 0 0 3px var(--color-black); -webkit-text-stroke: 0.5px var(--color-black); vertical-align: middle; } .leaflet-container .leaflet-marker-pane .extract-icon img { max-width: 24px !important; max-height: 24px !important; } .leaflet-container .leaflet-marker-pane .btr-stop img { max-width: 16px !important; max-height: 16px !important; } .extract-icon, .btr-stop { display: inline; white-space: nowrap; } .extract-name.pmc { color: var(--color-green); } .extract-name.scav { color: var(--color-orange); } .extract-name.shared { color: var(--color-blue-light); } .extract-name.transit { color: var(--color-red); } .poi-image, img.popup-item { max-width: 24px; max-height: 24px; vertical-align: middle; filter: drop-shadow(0.01em 0.01em white) drop-shadow(-0.01em -0.01em white) drop-shadow(-0.01em 0.01em white) drop-shadow(0.01em -0.01em white); } .poi-link { cursor: pointer; } /* general control styles */ .leaflet-control { background-color: rgb(from var(--color-black) r g b / 0.75); color: var(--color-gold-one); font-family: "bender", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", "Arial", sans-serif; font-style: normal; font-weight: 400; font-size: 16px; } .leaflet-control-layers-separator { border-color: var(--color-gold-two); } .leaflet-control input[type="checkbox"] { /* Add if not using autoprefixer */ appearance: none; /* For iOS < 15 to remove gradient background */ background-color: var(--color-gunmetal-dark); /* Not removed via appearance */ font: inherit; color: currentcolor; width: 1.15em; height: 1.15em; border: 0.15em solid var(--color-gold-two); border-radius: 0.15em; transform: translateY(-0.075em); } .leaflet-control input[type="checkbox"]::before { content: ""; width: 0.65em; height: 0.65em; transform: scale(0); transition: 120ms transform ease-in-out; box-shadow: inset 1em 1em var(--color-gold-one); transform-origin: bottom left; clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); display: grid; place-content: center; margin-left: 2px; margin-top: 2px; } .leaflet-control input[type="checkbox"]:checked::before { transform: scale(1); } .leaflet-control input[type="radio"] { /* Add if not using autoprefixer */ appearance: none; /* For iOS < 15 to remove gradient background */ background-color: var(--color-gunmetal-dark); /* Not removed via appearance */ font: inherit; color: currentcolor; width: 1.15em; height: 1.15em; border: 0.15em solid var(--color-gold-two); border-radius: 0.5em; transform: translateY(-0.075em); } .leaflet-control input[type="radio"]::before { content: ""; width: 0.65em; height: 0.65em; border-radius: 0.5em; transform: scale(0); transition: 120ms transform ease-in-out; box-shadow: inset 1em 1em var(--color-gold-one); display: grid; place-content: center; margin-left: 0.1em; margin-top: 0.1em; } .leaflet-control input[type="radio"]:checked::before { transform: scale(1); } /* settings control */ .leaflet-control-map-settings.leaflet-control { padding: 4px 4px; } .leaflet-control-map-settings { background-color: rgb(from var(--color-black) r g b / 0.75); } .display-wrapper.only-active-quest-markers .inactive-quest-marker { display: none; } /* fullscreen control */ .leaflet-control-fullscreen a { background-color: rgb(from var(--color-black) r g b / 0.75); background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAA0CAYAAACU7CiIAAAAxnpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjabVBRDsMgCP3nFDuC8KjicezaJrvBjj+suLTLXuITeOSh0P5+HfToEFbSpViuOSeHVq3SPLA00E7mpCePpIXG9zpBQxAvwW+M1HL0zzp/DaYhp+ViZM8Q1rtQY4DYj1EMQn+ReLCFUQ0jyBA4DFp8IVcr1y+se7rDxqFOx9xJGddvrsW3ty0+ByI7GMkZYykQ9KOE5gE7M8wbE+pZUWdFjpf0Df/Z0wR9AGIiWbdAFcPEAAABhGlDQ1BJQ0MgcHJvZmlsZQAAeJx9kT1Iw1AUhU/TSkUqBe0g4pChOtlFRRxLFYtgobQVWnUweekfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfE2cFJ0UVKvC8ptIjxwuN9nHfP4b37AKFVY6oZiAOqZhmZZELMF1bF4Ct8GEIYAUQlZuqp7GIOnvV1T91UdzGe5d33Zw0qRZMBPpE4znTDIt4gnt20dM77xBFWkRTic+JJgy5I/Mh12eU3zmWHBZ4ZMXKZeeIIsVjuYbmHWcVQiWeIo4qqUb6Qd1nhvMVZrTVY5578haGitpLlOq0xJLGEFNIQIaOBKmqwEKNdI8VEhs4THv5Rx58ml0yuKhg5FlCHCsnxg//B79mapekpNymUAPpebPtjHAjuAu2mbX8f23b7BPA/A1da119vAXOfpDe7WvQICG8DF9ddTd4DLneAkSddMiRH8tMSSiXg/Yy+qQAM3wIDa+7cOuc4fQByNKvlG+DgEJgoU/a6x7v7e+f2b09nfj92lnKoz48yYwAADXZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wLUV4aXYyIj4KIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgIHhtbG5zOkdJTVA9Imh0dHA6Ly93d3cuZ2ltcC5vcmcveG1wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6NDAyNDAzZGQtMzYxMS00OGRjLWJjMGUtNzQ0NmViYTcxNTc3IgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjE2NTkzNGExLWNhYzAtNGJjNS05Mjc3LTljMDgyZTc3NzA0MSIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmUyMmRkYjhlLWIzZTQtNGRkYy1iN2YxLTRiZDdiNzEyZGVmZCIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09IldpbmRvd3MiCiAgIEdJTVA6VGltZVN0YW1wPSIxNzA1NTkwMjg2MzczMjE5IgogICBHSU1QOlZlcnNpb249IjIuMTAuMzQiCiAgIHRpZmY6T3JpZW50YXRpb249IjEiCiAgIHhtcDpDcmVhdG9yVG9vbD0iR0lNUCAyLjEwIgogICB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0OjAxOjE4VDA5OjA0OjQ2LTA2OjAwIgogICB4bXA6TW9kaWZ5RGF0ZT0iMjAyNDowMToxOFQwOTowNDo0Ni0wNjowMCI+CiAgIDx4bXBNTTpIaXN0b3J5PgogICAgPHJkZjpTZXE+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmQ0MzNjMDAwLTc2MjQtNDcxOS1hNjBhLTBmMDJiZDZiYTZhMyIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iR2ltcCAyLjEwIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyNC0wMS0xOFQwOTowNDo0NiIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz6tAhAHAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH6AESDwQuQlUKHQAAAIdJREFUWMPtl0EOwCAIBNemH+NllZfxNHvxZKixNDWx3TmiBlHAFSCkkjyjmRXPLiIpMg8AtlkR7b1Bb2eRCKdG9D1HZFHMrPRqIrKOdfROr2vP+05vY2cghFCpUqku9/A1x5IBHI1ZRSSHs+5JJvI3McfRheJUZ6qOKtXhrKvZlXlHVKrkB5zEQE3lVsjhWQAAAABJRU5ErkJggg=="); } .leaflet-control-fullscreen a:hover { background-color: rgb(50 50 50 / 0.75); } /* zoom control */ .leaflet-bar a { /* stylelint-disable-line no-descending-specificity */ background-color: transparent; color: var(--color-gold-one); border-bottom-color: rgb(50 50 50); } .leaflet-bar a:hover, .leaflet-bar a:active { background-color: rgb(25 25 25 / 0.75); color: var(--color-gold-one); } .leaflet-bar a.leaflet-disabled { color: var(--color-gold-two); background-color: rgb(50 50 50 / 0.75); } .leaflet-bar a.leaflet-disabled:hover, .leaflet-bar a.leaflet-disabled:active { background-color: rgb(40 40 40 / 0.75); } .leaflet-control-layers-list { font-size: 14px; } /* Raid Info control */ .leaflet-control-raid-info { background-color: rgb(from var(--color-black) r g b / 0.5); line-height: normal; } .leaflet-control-raid-info a { /* stylelint-disable-line no-descending-specificity */ color: var(--color-gold-one); } /* Area labels */ .leaflet-marker-icon.map-area-label { font-family: "bender", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", "Arial", sans-serif; font-weight: 800; font-size: 20px; color: var(--color-gold-one); text-shadow: 0 0 3px var(--color-black); -webkit-text-stroke: 0.5px var(--color-black); text-align: center; } .leaflet-marker-icon.map-area-label .label { position: absolute; /* -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); */ width: 200px; } .leaflet-marker-icon.map-area-label.off-level { display: none; } .leaflet-container .leaflet-marker-pane img.loot-outline { filter: drop-shadow(0.01em 0.01em white) drop-shadow(-0.01em -0.01em white) drop-shadow(-0.01em 0.01em white) drop-shadow(0.01em -0.01em white); } /* active level badge for grouped layer */ .leaflet-left [data-badge]::after { margin-left: 30px; } .leaflet-right [data-badge]::after { margin-right: -14px; right: 100%; } .leaflet-control-container [data-badge]::after { background: #222; border-radius: 30px; color: var(--color-gold-one); content: attr(data-badge); font-size: 14px; font-weight: bold; margin-top: -10px; min-width: 20px; padding: 2px 5px; position: absolute; text-align: center; white-space: nowrap; } .leaflet-control-container [data-badge^="-"]::after, .leaflet-control-container [data-badge="0"]::after, .leaflet-control-container [data-badge=""]::after, .leaflet-control-container [data-badge="undefined"]::after { display: none; } /* remote styles */ .display-wrapper:has(~ .id-wrapper-left) .leaflet-bottom.leaflet-left, .display-wrapper:has(~ .id-wrapper-right) .leaflet-bottom.leaflet-right { margin-bottom: 60px; } .leaflet-pane.leaflet-overlay-pane svg.base-layer { z-index: 1; } .leaflet-pane.leaflet-overlay-pane svg.level-layer { z-index: 2; } .display-wrapper.map-page { margin: 0px; } .leaflet-pane.leaflet-overlay-pane svg .overlay-layer.hidden-layer { display: none; } .leaflet-pane.leaflet-overlay-pane svg.auto-show .overlay-layer.hidden-layer { display: block; } ================================================ FILE: src/pages/map/index.jsx ================================================ import { useEffect, useRef, useMemo, useCallback, useLayoutEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useParams, useSearchParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch"; import ResizeObserver from "resize-observer-polyfill"; import L from "leaflet"; import "leaflet/dist/leaflet.css"; import "leaflet-fullscreen/dist/Leaflet.fullscreen.js"; import "leaflet-fullscreen/dist/leaflet.fullscreen.css"; import "../../modules/leaflet-control-coordinates.js"; import "../../modules/leaflet-control-groupedlayer.js"; import "../../modules/leaflet-control-raid-info.js"; import "../../modules/leaflet-control-map-search.js"; import "../../modules/leaflet-control-map-settings.js"; import "../../styles/mapSettings.css"; import { setPlayerPosition } from "../../features/settings/settingsSlice.mjs"; import { useMapImages } from "../../features/maps/index.js"; import useItemsData, { useHandbookData } from "../../features/items/index.js"; import useQuestsData from "../../features/quests/index.js"; import staticMapMarkers from "../../data/maps_static.json"; import rawMapsData from "../../data/maps.json"; import Time from "../../components/Time.jsx"; import SEO from "../../components/SEO.jsx"; import ErrorPage from "../error-page/index.jsx"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; import "./index.css"; import images from "./map-images.mjs"; const showStaticMarkers = false; const showMarkersBounds = false; const showTestPlayerMarker = false; const showElevation = false; const svgFromGit = false; function getCRS(mapData) { let scaleX = 1; let scaleY = 1; let marginX = 0; let marginY = 0; if (mapData) { if (mapData.transform) { scaleX = mapData.transform[0]; scaleY = mapData.transform[2] * -1; marginX = mapData.transform[1]; marginY = mapData.transform[3]; } } return L.extend({}, L.CRS.Simple, { transformation: new L.Transformation(scaleX, marginX, scaleY, marginY), projection: L.extend({}, L.Projection.LonLat, { project: (latLng) => { return L.Projection.LonLat.project(applyRotation(latLng, mapData.coordinateRotation)); }, unproject: (point) => { return applyRotation(L.Projection.LonLat.unproject(point), mapData.coordinateRotation * -1); }, }), }); } function applyRotation(latLng, rotation) { if (!latLng.lng && !latLng.lat) { return L.latLng(0, 0); } if (!rotation) { return latLng; } const angleInRadians = (rotation * Math.PI) / 180; const cosAngle = Math.cos(angleInRadians); const sinAngle = Math.sin(angleInRadians); const { lng: x, lat: y } = latLng; const rotatedX = x * cosAngle - y * sinAngle; const rotatedY = x * sinAngle + y * cosAngle; return L.latLng(rotatedY, rotatedX); } function pos(position) { return [position.z, position.x]; } function getScaledBounds(bounds, scaleFactor) { // Calculate the center point of the bounds const centerX = (bounds[0][0] + bounds[1][0]) / 2; const centerY = (bounds[0][1] + bounds[1][1]) / 2; // Calculate the new width and height const width = bounds[1][0] - bounds[0][0]; const height = bounds[1][1] - bounds[0][1]; const newWidth = width * scaleFactor; const newHeight = height * scaleFactor; // Update the coordinates of the two points defining the bounds const newBounds = [ [centerY - newHeight / 2, centerX - newWidth / 2], [centerY + newHeight / 2, centerX + newWidth / 2], ]; // console.log("Initial Rectangle:", bounds); // console.log("Scaled Rectangle:", newBounds); // console.log("Center:", L.bounds(bounds).getCenter(true)); return newBounds; } function checkMarkerBounds(position, markerBounds) { if (position.x < markerBounds.TL.x) { markerBounds.TL.x = position.x; } if (position.z > markerBounds.TL.z) { markerBounds.TL.z = position.z; } if (position.x > markerBounds.BR.x) { markerBounds.BR.x = position.x; } if (position.z < markerBounds.BR.z) { markerBounds.BR.z = position.z; } } function getBounds(bounds) { if (!bounds) { return undefined; } return L.latLngBounds([bounds[0][1], bounds[0][0]], [bounds[1][1], bounds[1][0]]); //return [[bounds[0][1], bounds[0][0]], [bounds[1][1], bounds[1][0]]]; } function markerIsOnLayer(marker, layer) { if (!layer?.options?.extents) { return true; } var top = marker.options.top || marker.options.position.y; var bottom = marker.options.bottom || marker.options.position.y; for (const extent of layer.options.extents) { if (top >= extent.height[0] && bottom < extent.height[1]) { let containedType = "partial"; if (bottom >= extent.height[0] && top <= extent.height[1]) { containedType = "full"; } if (extent.bounds) { for (const boundsArray of extent.bounds) { const bounds = getBounds(boundsArray); if (bounds.contains(pos(marker.options.position))) { return containedType; } } } else { return containedType; } } } return false; } function markerIsOnActiveLayer(marker) { if (!marker.options.position) { return true; } const map = marker._map; // check if marker is completely contained by inactive layer const overlays = map.layerControl._layers .map((l) => l.layer) .filter((l) => Boolean(l.options.extents) && l.options.overlay); for (const layer of overlays) { for (const extent of layer.options.extents) { if (markerIsOnLayer(marker, layer) === "full" && !map.hasLayer(layer) && extent.bounds) { return false; } } } // check if marker is on active overlay const activeOverlay = Object.values(map._layers).find((l) => l.options?.extents && l.options?.overlay); if (activeOverlay && markerIsOnLayer(marker, activeOverlay)) { return true; } // check if marker is on base layer const baseLayer = Object.values(map._layers).find((l) => l.options?.extents && !L.options?.overlay); if (!activeOverlay && markerIsOnLayer(marker, baseLayer)) { return true; } return false; } function checkMarkerForActiveLayers(event) { const marker = event.target || event; const outline = marker.options.outline; const onLevel = markerIsOnActiveLayer(marker); if (onLevel) { marker._icon?.classList.remove("off-level"); if (outline) { outline._path?.classList.remove("off-level"); } } else { marker._icon?.classList.add("off-level"); if (outline) { outline._path?.classList.add("off-level"); } } /*if (marker.options.activeQuest === true) { marker._icon.classList.add('active-quest-marker'); marker._icon.classList.remove('inactive-quest-marker'); } else if (marker.options.activeQuest === false) { marker._icon.classList.remove('active-quest-marker'); marker._icon.classList.add('inactive-quest-marker'); }*/ } function mouseHoverOutline(event) { const outline = event.target.options.outline; if (event.originalEvent.type === "mouseover") { outline._path.classList.remove("not-shown"); } else if (!outline._path.classList.contains("force-show")) { outline._path.classList.add("not-shown"); } } function toggleForceOutline(event) { const outline = event.target.options.outline; outline._path.classList.toggle("force-show"); if (outline._path.classList.contains("force-show")) { outline._path.classList.remove("not-shown"); } activateMarkerLayer(event); } function activateMarkerLayer(event) { const marker = event.target || event; if (markerIsOnActiveLayer(marker)) { return; } const activeLayers = Object.values(marker._map._layers).filter((l) => l.options?.extents && l.options?.overlay); for (const layer of activeLayers) { layer.removeFrom(marker._map); } const heightLayers = marker._map.layerControl._layers .filter((l) => l.layer.options.extents && l.layer.options.overlay) .map((l) => l.layer); for (const layer of heightLayers) { if (markerIsOnLayer(marker, layer)) { layer.addTo(marker._map); break; } } } function outlineToPoly(outline) { if (!outline) { return []; } return outline.map((vector) => [vector.z, vector.x]); } function addElevation(item, popup) { if (!showElevation) { return; } const elevationContent = L.DomUtil.create("div", undefined, popup); elevationContent.textContent = `Elevation: ${item.position.y.toFixed(2)}`; if (item.top && item.bottom && item.top !== item.position.y && item.bottom !== item.position.y) { const heightContent = L.DomUtil.create("div", undefined, popup); heightContent.textContent = `Top ${item.top.toFixed(2)}, bottom: ${item.bottom.toFixed(2)}`; } } function Map() { let { currentMap } = useParams(); const [searchParams] = useSearchParams(); const settings = useSelector((state) => state.settings[state.settings.gameMode]); const focusItem = useRef(searchParams.get("q") ? searchParams.get("q").split(",") : []); const { t } = useTranslation(); const dispatch = useDispatch(); const tMaps = useCallback( (string) => { return t(string, { ns: "maps" }); }, [t], ); const [savedMapSettings, setSavedMapSettings] = useStateWithLocalStorage("savedMapSettings", { style: "svg", hiddenGroups: [], hiddenLayers: [], collapsedGroups: [], showOnlyActiveTasks: false, expandMapLegend: false, expandSearch: false, alwaysShowSnipers: true, hiddenTasks: [], }); const mapSettingsRef = useRef(savedMapSettings); const updateSavedMapSettings = useCallback(() => { setSavedMapSettings({ ...mapSettingsRef.current }); }, [setSavedMapSettings]); const markerBoundsRef = useRef({}); const getViewableHeight = () => { const menuHeight = document.querySelector(".navigation")?.offsetHeight || 0; const bannerHeight = document.querySelector(".MuiBox-root")?.offsetHeight || 0; const cookieConsentHeight = document.querySelector(".CookieConsent")?.offsetHeight || 0; let viewableHeight = window.innerHeight - menuHeight - bannerHeight - cookieConsentHeight; if (viewableHeight < 100) { viewableHeight = window.innerHeight; } return viewableHeight; }; useEffect(() => { const viewableHeight = getViewableHeight(); document.documentElement.style.setProperty("--display-height", `${viewableHeight}px`); return function cleanup() { document.documentElement.style.setProperty("--display-height", `auto`); }; }); const playerPosition = useSelector((state) => state.settings.playerPosition); // if playerPosition is set, user already has used TarkovMonitor // so we can hide the TarkovMonitor link in the settings control const playerPositionUsedRef = useRef(!!playerPosition); const ref = useRef(); const mapRef = useRef(null); const [mapHeight, setMapHeight] = useState(500); // stores the maximum size of the map canvas // when the window resizes, update the size of the maximum map canvas useLayoutEffect(() => { function updateSize() { const viewableHeight = getViewableHeight(); setMapHeight(viewableHeight); } window.addEventListener("resize", updateSize); updateSize(); return () => window.removeEventListener("resize", updateSize); }, []); // when the maximum map canvas size changes, update the map container height useEffect(() => { const mapContainer = document.getElementById("leaflet-map"); if (mapContainer) { mapContainer.style.height = `${mapHeight}px`; } }, [mapHeight]); const onMapContainerRefChange = useCallback( (node) => { if (node) { node.style.height = `${mapHeight}px`; } if (mapRef.current) { mapRef.current.invalidateSize({ animate: false }); } }, [mapHeight], ); useEffect(() => { ref?.current?.resetTransform(); }, [currentMap]); const { data: items } = useItemsData(); const { data: quests } = useQuestsData(); const { data: handbook } = useHandbookData(); let allMaps = useMapImages(); const mapData = useMemo(() => { return allMaps[currentMap]; }, [allMaps, currentMap]); // create the leaflet map on first page render useEffect(() => { if (mapRef.current) { return; } const map = L.map("leaflet-map", { zoomSnap: 0.1, scrollWheelZoom: true, wheelPxPerZoomLevel: 120, attributionControl: false, crs: L.CRS.Simple, maxBounds: [ [0, 0], [10, 10], ], minZoom: 1, maxZoom: 1, }); if (playerPositionUsedRef.current) { map._container.classList.add("player-position-shown"); } const layerControl = L.control .groupedLayers(null, null, { position: "topleft", collapsed: !mapSettingsRef.current.expandMapLegend, groupCheckboxes: true, groupsCollapsable: true, exclusiveOptionalGroups: [tMaps("Levels")], }) .addTo(map); layerControl.on("layerToggle", (e) => { const layerState = e.detail; if (!layerState.checked) { mapSettingsRef.current.hiddenLayers.push(layerState.key); } else { mapSettingsRef.current.hiddenLayers = mapSettingsRef.current.hiddenLayers.filter( (key) => key !== layerState.key, ); } updateSavedMapSettings(); }); layerControl.on("groupToggle", (e) => { const groupState = e.detail; for (const groupLayer of layerControl._layers) { if (groupLayer.group?.key !== groupState.key) { continue; } if (!groupState.checked) { mapSettingsRef.current.hiddenLayers.push(groupLayer.key); } else { mapSettingsRef.current.hiddenLayers = mapSettingsRef.current.hiddenLayers.filter( (key) => key !== groupLayer.key, ); } } if (!groupState.checked) { mapSettingsRef.current.hiddenGroups.push(groupState.key); } else { mapSettingsRef.current.hiddenGroups = mapSettingsRef.current.hiddenGroups.filter( (key) => key !== groupState.key, ); } updateSavedMapSettings(); }); layerControl.on("groupCollapseToggle", (e) => { const groupState = e.detail; if (groupState.collapsed) { mapSettingsRef.current.collapsedGroups.push(groupState.key); } else { mapSettingsRef.current.collapsedGroups = mapSettingsRef.current.collapsedGroups.filter( (key) => key !== groupState.key, ); } updateSavedMapSettings(); }); map.on("overlayremove", (e) => { if (e.group?.key !== "Loose Loot") { return; } for (const id in e.layer._layers) { const marker = e.layer._layers[id]; const categories = marker.options.categories; categoryLoop: for (const category of categories) { if (category === e.layer.key) { continue; } for (const groupLayer of layerControl._layers) { if (groupLayer.key !== category) { continue; } if (groupLayer.layer._map) { marker.addTo(map); break categoryLoop; } } } } }); map.layerControl = layerControl; map.addControl( new L.Control.Fullscreen({ title: { false: tMaps("View Fullscreen"), true: tMaps("Exit Fullscreen"), }, }), ); L.control .coordinates({ decimals: 2, labelTemplateLat: "z: {y}", labelTemplateLng: "x: {x}", enableUserInput: false, wrapCoordinate: false, position: "bottomright", customLabelFcn: (latLng, opts) => { return `x: ${latLng.lng.toFixed(2)} z: ${latLng.lat.toFixed(2)}`; }, }) .addTo(map); map.settingsControl = L.control .mapSettings({ hidden: false, position: "bottomright", activeTasksChecked: mapSettingsRef.current.showOnlyActiveTasks, activeTasksLabel: tMaps("Only show markers for active tasks"), expandMapLegendChecked: mapSettingsRef.current.expandMapLegend, expandMapLegendLabel: tMaps("Don't collapse layers control"), expandSearchChecked: mapSettingsRef.current.expandSearch, expandSearchLabel: tMaps("Don't collapse search control"), playerLocationLabel: tMaps("Use TarkovMonitor to show your position"), alwaysShowSnipers: mapSettingsRef.current.alwaysShowSnipers ?? true, alwaysShowSnipersLabel: tMaps("Always show snipers"), collapsed: true, }) .addTo(map); map.settingsControl.on("settingChanged", (e) => { if (e.settingName === "showOnlyActiveTasks") { if (e.settingValue) { map._container.classList.add("only-active-quest-markers"); } else { map._container.classList.remove("only-active-quest-markers"); } } if (e.settingName === "expandMapLegend") { layerControl.setCollapse(!e.settingValue); } if (e.settingName === "expandSearch") { map.searchControl.setCollapse(!e.settingValue); } if (e.settingName === "alwaysShowSnipers") { if (e.settingValue) { map._container.classList.add("always-show-snipers"); } else { map._container.classList.remove("always-show-snipers"); } } mapSettingsRef.current[e.settingName] = e.settingValue; updateSavedMapSettings(); }); if (mapSettingsRef.current.alwaysShowSnipers ?? true) { map._container.classList.add("always-show-snipers"); } map.raidInfoControl = L.control .raidInfo({ position: "topright", durationLabel: t("Duration"), playersLabel: t("Players"), bylabel: t("By"), }) .addTo(map); map.searchControl = L.control .mapSearch({ searchTitle: tMaps("Search"), placeholderText: tMaps("Task, item or container..."), descriptionText: tMaps("Supports multisearch (e.g. 'labs, ledx, bitcoin')"), taskFilterTitle: tMaps("Task Filter"), taskFilterPlaceholderText: tMaps("Task name"), showAllButtonText: tMaps("All"), hideAllButtonText: tMaps("None"), collapsed: !mapSettingsRef.current.expandSearch, hiddenTasks: mapSettingsRef.current.hiddenTasks, }) .addTo(map); map.searchControl.on("hiddenTasksChanged", (e) => { mapSettingsRef.current.hiddenTasks = e.tasks; updateSavedMapSettings(); }); //L.control.scale({position: 'bottomright'}).addTo(map); mapRef.current = map; const mapDiv = document.getElementById("leaflet-map"); const resizeObserver = new ResizeObserver(() => { //map.invalidateSize(); //window.dispatchEvent(new Event('resize')); }); resizeObserver.observe(mapDiv); // Get the map container element const mapContainer = map.getContainer(); // Add a 'wheel' event listener to the map container mapContainer.addEventListener( "wheel", function (event) { // Check if the Ctrl key is pressed if (!event.ctrlKey) { return; } // Prevent default map zooming behavior if desired L.DomEvent.preventDefault(event); L.DomEvent.stopPropagation(event); // Your custom logic for Ctrl + mousewheel goes here const increase = event.wheelDeltaY > 0; const levels = Object.values(layerControl._layers) .filter((l) => l.layer.options.layerType === "level") .map((l) => l.layer); let activeIndex = -1; for (let i = 0; i < levels.length; i++) { const level = levels[i]; if (level._map) { // we've found the active level, so we store the index and remove it from the map activeIndex = i; level.removeFrom(map); break; } } if (activeIndex === -1) { // there was no active index, so we set the active index manually if (increase) { activeIndex = 0; } else { activeIndex = levels.length - 1; } } else if (increase) { activeIndex++; } else { activeIndex--; } if (activeIndex < 0) { // active index went down from the first level, so don't display a level and just show the main map return; } if (activeIndex > levels.length - 1) { // active index went up from the last level, so don't display a level and just show the main map return; } levels[activeIndex].addTo(map); }, { capture: true }, ); }, [t, tMaps, updateSavedMapSettings]); useEffect(() => { if (!mapRef.current?.searchControl) { return; } mapRef.current.searchControl.options.quests = quests; }, [quests]); useEffect(() => { if (!mapRef.current?.settingsControl?.container) { return; } if (settings.useTarkovTracker) { mapRef.current.settingsControl.container.style.display = ""; mapSettingsRef.current.showOnlyActiveTasks = mapRef.current.settingsControl.container.querySelector("#only-active-quest-markers").checked; } else { mapRef.current.settingsControl.container.style.display = "none"; mapSettingsRef.current.showOnlyActiveTasks = false; } updateSavedMapSettings(); }, [settings, updateSavedMapSettings]); const categories = useMemo(() => { return { "extract_pmc": tMaps("PMC"), "extract_shared": tMaps("Shared"), "extract_scav": tMaps("Scav"), "extract_transit": tMaps("Transit"), "spawn_sniper_scav": tMaps("Sniper Scav"), "spawn_pmc": tMaps("PMC"), "spawn_scav": tMaps("Scav"), "spawn_boss": tMaps("Boss"), "quest_item": tMaps("Item"), "quest_objective": tMaps("Objective"), "lock": tMaps("Locks"), "lever": tMaps("Lever"), "stationarygun": tMaps("Stationary Gun"), "switch": tMaps("Switch"), "place-names": tMaps("Place Names"), "btr-stop": tMaps("BTR Stop"), "player-position": tMaps("Player Position"), }; }, [tMaps]); const getLayerOptions = useCallback( (layerKey, groupKey, layerName, imageUrl) => { return { groupKey, layerKey, groupName: tMaps(groupKey), layerName: layerName || categories[layerKey] || layerKey, groupHidden: Boolean(mapSettingsRef.current.hiddenGroups?.includes(groupKey)), layerHidden: Boolean(mapSettingsRef.current.hiddenLayers?.includes(layerKey)), image: (imageUrl ??= images[layerKey] ? `${process.env.PUBLIC_URL}/maps/interactive/${images[layerKey]}.png` : undefined), groupCollapsed: Boolean(mapSettingsRef.current.collapsedGroups?.includes(groupKey)), }; }, [tMaps, categories], ); const addLayer = useCallback( (layer, layerKey, groupKey, layerName, imageUrl) => { /*for (const layerId in layer._layers) { const l = layer._layers[layerId]; l.options.layerKey = layerKey; l.options.groupKey = groupKey; };*/ layer.key = layerKey; const layerOptions = getLayerOptions(layerKey, groupKey, layerName, imageUrl); if (!layerOptions.layerHidden) { layer.addTo(mapRef.current); } mapRef.current.layerControl.addOverlay(layer, layerOptions.layerName, layerOptions); }, [getLayerOptions], ); const getReactLink = (path, contents) => { const a = L.DomUtil.create("a"); a.setAttribute("href", path); a.setAttribute("target", "_blank"); a.append(contents); // a.addEventListener('click', (event) => { // navigate(path); // event.preventDefault(); // }); return a; }; const focusOnPoi = (id) => { for (const marker of Object.values(mapRef.current._layers)) { if (marker.options.id !== id) { continue; } mapRef.current.flyTo(pos(marker.options.position)); marker.fire("click"); return true; } return false; }; const getPoiLinkElement = useCallback((id, imageName) => { const spanEl = L.DomUtil.create("div"); spanEl.classList.add("poi-link"); spanEl.addEventListener("click", () => { focusOnPoi(id); }); const imgEl = L.DomUtil.create("img"); imgEl.setAttribute("src", `${process.env.PUBLIC_URL}/maps/interactive/${imageName}.png`); //imgEl.setAttribute('title', id); imgEl.classList.add("poi-image"); spanEl.append(imgEl); return spanEl; }, []); const positionIsInBounds = (position) => { const bounds = getBounds(mapRef.current.options.baseData.bounds); return bounds.contains(pos(position)); }; const refreshMapSearch = () => { const searchBar = mapRef.current?.searchControl?._container.getElementsByClassName( "maps-search-wrapper-search-bar", )[0]; if (!searchBar) { return; } searchBar.dispatchEvent(new Event("input")); }; // load base layers when map changed useEffect(() => { if (!currentMap || !mapRef.current) { return; } if (mapRef.current.options.id === currentMap) { return; } const interactiveMaps = rawMapsData.reduce((interactive, current) => { const int = current.maps.find((m) => m.projection === "interactive"); if (int) { interactive.push(int); } return interactive; }, []); const mapData = interactiveMaps.find((m) => m.key === currentMap || m.altMaps?.includes(currentMap)); if (!mapData) { return; } const maxZoom = Math.max(7, mapData.maxZoom); const map = mapRef.current; map.options.baseData = mapData; const layerControl = map.layerControl; map.options.maxBounds = getScaledBounds(mapData.bounds, 1.5); map.setMaxBounds(map.options.maxBounds); map.options.minZoom = mapData.minZoom; map.setMinZoom(mapData.minZoom); map.options.maxZoom = maxZoom; map.setMaxZoom(maxZoom); map.options.crs = getCRS(mapData); map.options.id = currentMap; const bounds = getBounds(mapData.bounds); map.eachLayer((layer) => { if (layer.options.type !== "map-layer") { return; } layer.removeFrom(map); }); map.layerControl.updateBadge(); const layerOptions = (map.options.layerOptions = { maxZoom: maxZoom, maxNativeZoom: mapData.maxZoom, extents: [ { height: mapData.heightRange || [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], bounds: [mapData.bounds], }, ], type: "map-layer", layerType: "main", }); let tileLayer = false; const baseLayers = []; const tileSize = mapData.tileSize || 256; if (mapData.tilePath) { tileLayer = L.tileLayer( mapData.tilePath || `https://assets.tarkov.dev/maps/${mapData.normalizedName}/{z}/{x}/{y}.png`, { tileSize, bounds, ...layerOptions, }, ); baseLayers.push(tileLayer); } let svgLayer = false; let svgLoaded = Promise.resolve(); if (mapData.svgPath) { if (svgFromGit) { mapData.svgPath = mapData.svgPath.replace( "https://assets.tarkov.dev/maps/svg", "https://raw.githubusercontent.com/the-hideout/tarkov-dev-svg-maps/refs/heads/main", ); } const svgBounds = mapData.svgBounds ? getBounds(mapData.svgBounds) : bounds; const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgElement.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svgLoaded = fetch(mapData.svgPath) .then((response) => response.text()) .then((svgText) => { svgElement.innerHTML = svgText; svgElement.setAttribute("viewBox", svgElement.children[0].getAttribute("viewBox")); // layer groups are the svg's top-level children that are: (1) g nodes (2) with ids set const layerGroups = [...svgElement.children[0].children].filter( (c) => c.nodeName === "g" && !!c.id, ); // mark the base layer as base-layer // mark other layer groups as overlays // if a layer is marked to keep with base layer, mark it as base layer for (const layerGroup of layerGroups) { if ( layerGroup.id === mapData.svgLayer || layerGroup.dataset["keepWithGroup"] === mapData.svgLayer ) { layerGroup.classList.add("base-layer"); } else { layerGroup.classList.add("hidden-layer", "overlay-layer"); } } }); svgLayer = L.svgOverlay(svgElement, svgBounds, { ...layerOptions, className: "base-layer", layerName: mapData.svgLayer, }); baseLayers.push(svgLayer); } // only add selector if there are multiple if (tileLayer && svgLayer) { layerControl.addBaseLayer(tileLayer, tMaps("Satellite")); layerControl.addBaseLayer(svgLayer, tMaps("Abstract")); layerControl._baseLayersList?.classList.remove("not-shown"); layerControl._separator?.classList.remove("not-shown"); } else { layerControl._baseLayersList?.classList.add("not-shown"); layerControl._separator?.classList.add("not-shown"); } for (const baseLayer of baseLayers) { if (mapData.layers?.length === 0) { // remove added height layers // layerControl.addOverlay(heightLayer, tMaps(layer.name), { groupName: tMaps("Levels") }); const existingLayers = Object.values(layerControl._layers) .filter((l) => l.layer.options.type === "map-layer" && !baseLayers.includes(l.layer)) .map((l) => l.layer); for (const existingLayer of existingLayers) { layerControl.removeLayer(existingLayer); if (map.hasLayer(existingLayer)) { map.removeLayer(existingLayer); selectedLayer = existingLayer.options.name; } } break; } let selectedLayer = ""; baseLayer.on("add", () => { const svgParent = baseLayer._url.nodeName === "svg"; if (tileLayer && svgLayer) { const selectedStyle = svgParent ? "svg" : "tile"; if (mapSettingsRef.current.style !== selectedStyle) { mapSettingsRef.current.style = selectedStyle; updateSavedMapSettings(); } } const existingLayers = Object.values(layerControl._layers) .filter((l) => l.layer.options.type === "map-layer" && !baseLayers.includes(l.layer)) .map((l) => l.layer); for (const existingLayer of existingLayers) { layerControl.removeLayer(existingLayer); if (map.hasLayer(existingLayer)) { map.removeLayer(existingLayer); selectedLayer = existingLayer.options.name; } } if (!mapData.layers) { return; } for (const layer of mapData.layers) { let heightLayer; const layerOptions = { name: layer.name, extents: layer.extents || baseLayer.options?.extents, type: "map-layer", layerType: "level", overlay: Boolean(layer.extents), }; let usedStyle = svgParent ? "svg" : "tile"; if (!layer.svgLayer) { usedStyle = "tile"; } if (!layer.tilePath) { usedStyle = "svg"; } if (!layer.svgLayer && !layer.tilePath) { continue; } if (usedStyle === "svg") { // create dummy layer for leaflet to remove // actual layer display changes are handled in the layer add and remove events const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgElement.setAttribute("xmlns", "http://www.w3.org/2000/svg"); heightLayer = L.svgOverlay(svgElement, bounds, { ...layerOptions, className: "level-layer" }); } else if (usedStyle === "tile") { heightLayer = L.tileLayer(layer.tilePath, { tileSize, bounds, ...layerOptions, }); } heightLayer.on("add", () => { if (layer.extents) { for (const marker of Object.values(map._layers)) { checkMarkerForActiveLayers(marker); } } // if baseLayer._image is set, it's an svg map // since we're adding a height layer, we set base layer to off level if (baseLayer._image && !layer.show) { baseLayer._image.classList.add("off-level"); } else if (baseLayer._container && !layer.show) { baseLayer._container.classList.add("off-level"); } if (baseLayer._image) { // remove the hidden-layer class from the added layer // we wrap it in the svg loading promsise to make sure the svg file has finished loading svgLoaded.finally(() => { if (!baseLayer._image.children[0]?.children) { return; } for (const layerGroup of baseLayer._image.children[0].children) { if (layerGroup.id !== layer.svgLayer) { // hide all layers that weren't just added layerGroup?.classList.add("hidden-layer"); continue; } // un-hide added layer layerGroup?.classList.remove("hidden-layer"); } }); } map.layerControl.updateBadge(tMaps(layer.name)); }); heightLayer.on("remove", () => { /*const heightLayer = Object.values(map._layers).findLast((l) => l.options?.extents); if (!heightLayer) { return; }*/ for (const marker of Object.values(map._layers)) { checkMarkerForActiveLayers(marker); } const layers = Object.values(map._layers).filter((l) => l.options.type === "map-layer"); if (layers.length !== 1) { return; } map.layerControl.updateBadge(); if (baseLayer._image) { baseLayer._image.classList.remove("off-level"); } else if (baseLayer._container) { baseLayer._container.classList.remove("off-level"); } if (baseLayer._image?.children[0]) { // add the hidden-layer class to the removed layer for (const layerGroup of baseLayer._image.children[0].children) { if (layerGroup.id !== layer.svgLayer) { continue; } layerGroup.classList.add("hidden-layer"); break; } } }); const activateLayer = selectedLayer === layer.name || (!selectedLayer && layer.show); if (activateLayer) { heightLayer.addTo(map); } layerControl.addOverlay(heightLayer, tMaps(layer.name), { groupName: tMaps("Levels") }); } }); } let baseLayer = svgLayer ? svgLayer : tileLayer; if (baseLayer === svgLayer && tileLayer && mapSettingsRef.current.style === "tile") { baseLayer = tileLayer; } baseLayer.addTo(map); layerControl.removeGroupFromMap("Landmarks"); markerBoundsRef.current = { TL: { x: Number.MAX_SAFE_INTEGER, z: Number.MIN_SAFE_INTEGER }, BR: { x: Number.MIN_SAFE_INTEGER, z: Number.MAX_SAFE_INTEGER }, }; // Add labels if (mapData.labels?.length > 0) { const labelsGroup = L.layerGroup(); const mainLayerVerticalMidpoint = (layerOptions.extents[0].height[1] - layerOptions.extents[0].height[0]) / 2 + layerOptions.extents[0].height[0]; for (const label of mapData.labels) { let positionY = mainLayerVerticalMidpoint; if (label.position.length > 2) { // if a position is expressly provided, use it positionY = label.position[2]; } else if (typeof label.top !== "undefined" && typeof label.bottom !== "undefined") { // calculate position as midpoint between top and bottom positionY = (label.top - label.bottom) / 2 + label.bottom; } const fontSize = label.size ? label.size : 100; const rotation = label.rotation ? label.rotation : 0; const labelMarker = L.marker(pos({ x: label.position[0], z: label.position[1] }), { icon: L.divIcon({ html: `
    ${tMaps(label.text)}
    `, className: "map-area-label", //layers: baseLayers, }), interactive: false, zIndexOffset: -100000, position: { x: label.position[0], y: positionY, z: label.position[1], }, top: label.top ?? 1000, bottom: label.bottom ?? -1000, group: "place-names", }); labelMarker.position = labelMarker.options.position; labelMarker.on("add", checkMarkerForActiveLayers); labelMarker.addTo(labelsGroup); checkMarkerBounds(label.position, markerBoundsRef.current); } addLayer(labelsGroup, "place-names", "Landmarks"); } // Add static items if (showStaticMarkers) { for (const category in staticMapMarkers[mapData.normalizedName]) { const markerLayer = L.layerGroup(); const items = staticMapMarkers[mapData.normalizedName][category]; for (const item of items) { const itemIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/${category}.png`, iconSize: [24, 24], popupAnchor: [0, -12], //className: layerIncludesMarker(heightLayer, item) ? '' : 'off-level', }); L.marker(pos(item.position), { icon: itemIcon, position: item.position }) .bindPopup(L.popup().setContent(`${item.name}
    Elevation: ${item.position.y}`)) .addTo(markerLayer); checkMarkerBounds(item.position, markerBoundsRef.current); } if (items.length > 0) { var section; if (category.startsWith("extract")) { section = tMaps("Extracts"); } else if (category.startsWith("spawn")) { section = tMaps("Spawns"); } else { section = tMaps("Lootable Items"); } markerLayer.addTo(map); addLayer(markerLayer, category, section); // layerControl.addOverlay(markerLayer, ` ${categories[category] || category}`, section); } } } if (showTestPlayerMarker) { const positionLayer = L.layerGroup(); const rotation = 45; const image = "player-position.png"; const playerIcon = L.divIcon({ //iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/player-position.png`, className: "marker", html: ``, iconSize: [24, 24], iconAnchor: [12, 12], popupAnchor: [0, -12], //className: layerIncludesMarker(heightLayer, item) ? '' : 'off-level', }); const positionMarker = L.marker([0, 0], { icon: playerIcon, position: { x: 0, y: 0, z: 0 } }).addTo( positionLayer, ); const closeButton = L.DomUtil.create("a"); closeButton.innerHTML = tMaps("Clear"); closeButton.addEventListener("click", () => { positionLayer.remove(positionMarker); }); positionMarker.bindPopup(L.popup().setContent(closeButton)); positionLayer.addTo(map); layerControl.addOverlay(positionLayer, tMaps("Player"), tMaps("Misc")); } //map.fitWorld({maxZoom: 0, animate: false}); //map.setView(L.latLngBounds(bounds).getCenter(), 2, {animate: false}); map.fitBounds(L.latLngBounds(bounds)); }, [currentMap, tMaps, updateSavedMapSettings, addLayer]); // load markers from API maps data useEffect(() => { if (!mapData || mapData.projection !== "interactive") { return; } const map = mapRef.current; if (!map.options.baseData) { return; } //console.log('loading api map data', mapData.normalizedName); map.raidInfoControl.options.map = mapData; map.raidInfoControl.refreshMapData(); const layerControl = map.layerControl; const markerBounds = markerBoundsRef.current; // remove old markers const groupIds = ["Extracts", "Hazards", "Lootable Items", "Spawns"]; for (const groupId of groupIds) { layerControl.removeGroupFromMap(groupId); } const layerIds = ["stationarygun", "switch", "btr-stop"]; for (const layerId of layerIds) { map.layerControl.removeLayerFromMap(layerId); } // Add spawns if (mapData.spawns.length > 0) { const spawnLayers = { "pmc": L.layerGroup(), "scav": L.layerGroup(), "sniper_scav": L.layerGroup(), "boss": L.layerGroup(), "cultist-priest": L.layerGroup(), "rogue": L.layerGroup(), "black-div": L.layerGroup(), "af": L.layerGroup(), "bloodhound": L.layerGroup(), }; for (const spawn of mapData.spawns) { if (!positionIsInBounds(spawn.position)) { continue; } let spawnType = ""; let bosses = []; let markerClass; if (spawn.categories.includes("boss")) { bosses = mapData.bosses.filter((boss) => boss.spawnLocations.some((sl) => sl.spawnKey === spawn.zoneName), ); bosses = bosses.reduce((unique, current) => { if (!unique.some((b) => b.normalizedName === current.normalizedName)) { unique.push(current); } return unique; }, []); if (bosses.length === 0) { if (spawn.categories.includes("bot") && spawn.sides.includes("scav")) { spawnType = "scav"; } else { //console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); continue; } } else if ( bosses.length === 1 && (bosses[0].normalizedName === "cultist-priest" || bosses[0].normalizedName === "rogue" || bosses[0].normalizedName === "black-div" || bosses[0].normalizedName === "af" || bosses[0].normalizedName === "bloodhound") ) { spawnType = bosses[0].normalizedName; } else { spawnType = "boss"; } } else if (spawn.categories.includes("player")) { if (spawn.sides.includes("pmc") || spawn.sides.includes("all")) { spawnType = "pmc"; } else { //console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); continue; } } else if (spawn.categories.includes("sniper")) { spawnType = "sniper_scav"; markerClass = "sniper-spawn"; } else if (spawn.sides.includes("scav")) { if (spawn.categories.includes("bot") || spawn.categories.includes("all")) { spawnType = "scav"; } else { //console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); continue; } } else { //console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); continue; } const spawnIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/spawn_${spawnType}.png`, iconSize: [24, 24], popupAnchor: [0, -12], className: markerClass, }); if (spawnType === "pmc") { spawnIcon.iconAnchor = [12, 24]; spawnIcon.popupAnchor = [0, -24]; } const popupContent = L.DomUtil.create("div"); if (spawn.categories.includes("boss") && bosses.length > 0) { const bossList = L.DomUtil.create("div", undefined, popupContent); for (const boss of bosses) { if (!categories[`spawn_${boss.normalizedName}`]) { categories[`spawn_${boss.normalizedName}`] = boss.name; } if (bossList.childNodes.length > 0) { const comma = L.DomUtil.create("span", undefined, bossList); comma.textContent = ", "; } bossList.append( getReactLink( `/boss/${boss.normalizedName}`, `${boss.name} (${Math.round(boss.spawnChance * 100)}%)`, ), ); } } else { const spawnDiv = L.DomUtil.create("div", undefined, popupContent); spawnDiv.textContent = categories[`spawn_${spawnType}`]; } addElevation(spawn, popupContent); const marker = L.marker(pos(spawn.position), { icon: spawnIcon, position: spawn.position, riseOnHover: true, }); if (popupContent.childNodes.length > 0) { marker.bindPopup(L.popup().setContent(popupContent)); } marker.position = spawn.position; marker.on("add", checkMarkerForActiveLayers); marker.on("click", activateMarkerLayer); marker.addTo(spawnLayers[spawnType]); checkMarkerBounds(spawn.position, markerBounds); } for (const key in spawnLayers) { if (Object.keys(spawnLayers[key]._layers).length > 0) { addLayer(spawnLayers[key], `spawn_${key}`, "Spawns"); } } } //add extracts if (mapData.extracts.length > 0) { const extractLayers = { pmc: L.layerGroup(), scav: L.layerGroup(), shared: L.layerGroup(), }; const zIndexOffsets = { pmc: 150, shared: 125, scav: 100, }; for (const extract of mapData.extracts) { const faction = extract.faction ?? "shared"; if (!positionIsInBounds(extract.position)) { //continue; } const colorMap = { scav: "#ff7800", pmc: "#00e599", shared: "#00e4e5", }; const rect = L.polygon(outlineToPoly(extract.outline), { color: colorMap[faction], weight: 1, className: "not-shown", }); const extractIcon = L.divIcon({ className: "extract-icon", html: `${extract.name}`, iconAnchor: [12, 12], }); const extractMarker = L.marker(pos(extract.position), { icon: extractIcon, title: extract.name, zIndexOffset: zIndexOffsets[faction], position: extract.position, top: extract.top, bottom: extract.bottom, outline: rect, id: extract.id, riseOnHover: true, }); extractMarker.on("mouseover", mouseHoverOutline); extractMarker.on("mouseout", mouseHoverOutline); extractMarker.on("click", toggleForceOutline); let popup; if (extract.switches?.length > 0) { popup ??= L.DomUtil.create("div"); const textElement = L.DomUtil.create("div"); textElement.textContent = `${tMaps("Activated by")}:`; popup.appendChild(textElement); for (const sw of extract.switches) { const linkElement = getPoiLinkElement(sw.id, "switch"); const nameElement = L.DomUtil.create("span"); nameElement.innerHTML = `${sw.name}`; linkElement.append(nameElement); popup.appendChild(linkElement); } } if (extract.transferItem) { popup ??= L.DomUtil.create("div"); let itemCount = ""; if (extract.transferItem.count > 1) { itemCount = ` x ${extract.transferItem.count.toLocaleString()}`; } const transferText = L.DomUtil.create("div", undefined, popup); transferText.innerText = `${tMaps("Required item")}:`; const itemName = `${extract.transferItem.item.name}${itemCount}`; const itemImage = L.DomUtil.create("img", "popup-item"); itemImage.setAttribute("src", `${extract.transferItem.item.baseImageLink}`); const itemLink = getReactLink(`/item/${extract.transferItem.item.normalizedName}`, itemImage); itemLink.setAttribute("title", itemName); itemLink.append(itemName); popup.append(itemLink); } if (popup || showElevation) { popup ??= L.DomUtil.create("div"); addElevation(extract, popup); extractMarker.bindPopup(L.popup().setContent(popup)); } extractMarker.on("add", checkMarkerForActiveLayers); L.layerGroup([rect, extractMarker]).addTo(extractLayers[faction]); checkMarkerBounds(extract.position, markerBounds); } if (mapData.transits.length > 0) { extractLayers.transit = L.layerGroup(); for (const transit of mapData.transits) { if (!positionIsInBounds(transit.position)) { //continue; } const rect = L.polygon(outlineToPoly(transit.outline), { color: "#e53500", weight: 1, className: "not-shown", }); const transitIcon = L.divIcon({ className: "extract-icon", html: `${transit.description}`, iconAnchor: [12, 12], }); const transitMarker = L.marker(pos(transit.position), { icon: transitIcon, title: transit.description, zIndexOffset: zIndexOffsets.pmc, position: transit.position, top: transit.top, bottom: transit.bottom, outline: rect, id: transit.id, riseOnHover: true, }); transitMarker.on("mouseover", mouseHoverOutline); transitMarker.on("mouseout", mouseHoverOutline); transitMarker.on("click", toggleForceOutline); if (showElevation) { const popup = L.DomUtil.create("div"); addElevation(transit, popup); transitMarker.bindPopup(L.popup().setContent(popup)); } transitMarker.on("add", checkMarkerForActiveLayers); L.layerGroup([rect, transitMarker]).addTo(extractLayers.transit); checkMarkerBounds(transit.position, markerBounds); } } for (const key in extractLayers) { if (Object.keys(extractLayers[key]._layers).length > 0) { addLayer(extractLayers[key], `extract_${key}`, "Extracts"); } } } //add loot containers if (mapData.lootContainers.length > 0) { const containerLayers = {}; const containerNames = {}; for (const containerPosition of mapData.lootContainers) { if (!positionIsInBounds(containerPosition.position)) { continue; } const containerIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/${images[`container_${containerPosition.lootContainer.normalizedName}`]}.png`, iconSize: [24, 24], popupAnchor: [0, -12], }); const containerMarker = L.marker(pos(containerPosition.position), { icon: containerIcon, title: containerPosition.lootContainer.name, position: containerPosition.position, riseOnHover: true, }); if (!containerLayers[containerPosition.lootContainer.normalizedName]) { containerLayers[containerPosition.lootContainer.normalizedName] = L.layerGroup(); } const popup = L.DomUtil.create("div"); const popupDiv = L.DomUtil.create("div", undefined, popup); popupDiv.textContent = containerPosition.lootContainer.name; addElevation(containerPosition, popup); containerMarker.bindPopup(L.popup().setContent(popup)); containerMarker.on("add", checkMarkerForActiveLayers); containerMarker.on("click", activateMarkerLayer); containerMarker.addTo(containerLayers[containerPosition.lootContainer.normalizedName]); containerNames[containerPosition.lootContainer.normalizedName] = containerPosition.lootContainer.name; } for (const key in containerLayers) { if (Object.keys(containerLayers[key]._layers).length > 0) { addLayer(containerLayers[key], `container_${key}`, "Lootable Items", containerNames[key]); } } } //add switches if (mapData.switches.length > 0) { const switches = L.layerGroup(); for (const sw of mapData.switches) { if (!positionIsInBounds(sw.position)) { continue; } const switchIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/switch.png`, iconSize: [24, 24], popupAnchor: [0, -12], }); const switchMarker = L.marker(pos(sw.position), { icon: switchIcon, position: sw.position, id: sw.id, riseOnHover: true, }); /*const popupLines = [t(sw.id)]; if (sw.previousSwitch) { popupLines.push(`Activated by ${sw.previousSwitch.id}`); } for (const nextSwitch of sw.nextSwitches) { popupLines.push(`${nextSwitch.operation} ${nextSwitch.switch.id}`); } switchMarker.bindPopup(L.popup().setContent(popupLines.join('
    ')));*/ const popup = L.DomUtil.create("div"); const switchNameElement = L.DomUtil.create("div"); switchNameElement.innerHTML = `${sw.name}`; popup.append(switchNameElement); if (sw.activatedBy) { const textElement = L.DomUtil.create("div"); textElement.textContent = `${tMaps("Activated by")}:`; popup.appendChild(textElement); const linkElement = getPoiLinkElement(sw.activatedBy.id, "switch"); const nameElement = L.DomUtil.create("span"); nameElement.innerHTML = `${sw.activatedBy.name}`; linkElement.append(nameElement); popup.appendChild(linkElement); } if (sw.activates.length > 0) { const textElement = L.DomUtil.create("div"); textElement.textContent = `${tMaps("Activates")}:`; popup.append(textElement); } for (const switchOperation of sw.activates) { if (switchOperation.target.__typename === "MapSwitch") { const linkElement = getPoiLinkElement(switchOperation.target.id, "switch"); const nameElement = L.DomUtil.create("span"); nameElement.innerHTML = `${switchOperation.target.name}`; linkElement.append(nameElement); popup.appendChild(linkElement); } else { const extractElement = L.DomUtil.create("div"); const linkElement = getPoiLinkElement( switchOperation.target.id, `extract_${switchOperation.target.faction}`, ); const spanElement = L.DomUtil.create("span"); spanElement.classList.add("extract-name", switchOperation.target.faction); spanElement.textContent = switchOperation.target.name; linkElement.append(spanElement); extractElement.append(linkElement); popup.appendChild(extractElement); } } addElevation(sw, popup); if (popup.childNodes.length > 0) { switchMarker.bindPopup(L.popup().setContent(popup)); } switchMarker.on("add", checkMarkerForActiveLayers); switchMarker.on("click", activateMarkerLayer); switchMarker.addTo(switches); checkMarkerBounds(sw.position, markerBoundsRef.current); } if (Object.keys(switches._layers).length > 0) { addLayer(switches, "switch", "Usable"); } } // add stationary weapons if (mapData.stationaryWeapons.length > 0) { const stationaryWeapons = L.layerGroup(); for (const weaponPosition of mapData.stationaryWeapons) { if (!positionIsInBounds(weaponPosition.position)) { continue; } const weaponIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/stationarygun.png`, iconSize: [24, 24], popupAnchor: [0, -12], }); const weaponMarker = L.marker(pos(weaponPosition.position), { icon: weaponIcon, title: weaponPosition.stationaryWeapon.name, position: weaponPosition.position, riseOnHover: true, }); if (showElevation) { const popup = L.DomUtil.create("div"); addElevation(weaponPosition, popup); weaponMarker.bindPopup(L.popup().setContent(popup)); } weaponMarker.on("add", checkMarkerForActiveLayers); weaponMarker.on("click", activateMarkerLayer); weaponMarker.addTo(stationaryWeapons); } addLayer(stationaryWeapons, "stationarygun", "Usable"); } //add hazards if (mapData.hazards.length > 0 || mapData.artillery?.zones?.length) { const hazardLayers = {}; const hazardNames = {}; for (const hazard of mapData.hazards) { if (!positionIsInBounds(hazard.position)) { continue; } const rect = L.polygon(outlineToPoly(hazard.outline), { color: "#ff0000", weight: 1, className: "not-shown", }); const hazardIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/hazard.png`, iconSize: [24, 24], popupAnchor: [0, -12], }); const hazardMarker = L.marker(pos(hazard.position), { icon: hazardIcon, title: hazard.name, zIndexOffset: -100, position: hazard.position, top: hazard.top, bottom: hazard.bottom, outline: rect, riseOnHover: true, }); const popup = L.DomUtil.create("div"); const hazardText = L.DomUtil.create("div", undefined, popup); hazardText.textContent = hazard.name; addElevation(hazard, popup); hazardMarker.bindPopup(L.popup().setContent(popup)); hazardMarker.on("mouseover", mouseHoverOutline); hazardMarker.on("mouseout", mouseHoverOutline); hazardMarker.on("click", toggleForceOutline); hazardMarker.on("add", checkMarkerForActiveLayers); if (!hazardLayers[hazard.hazardType]) { hazardLayers[hazard.hazardType] = L.layerGroup(); hazardNames[hazard.hazardType] = hazard.name; } L.layerGroup([rect, hazardMarker]).addTo(hazardLayers[hazard.hazardType]); checkMarkerBounds(hazard.position, markerBounds); } if (mapData.artillery?.zones?.length > 0) { for (const hazard of mapData.artillery.zones) { if (!positionIsInBounds(hazard.position)) { continue; } const rect = L.polygon(outlineToPoly(hazard.outline), { color: "#ff0000", weight: 1, className: "not-shown", }); const hazardIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/hazard_mortar.png`, iconSize: [24, 24], popupAnchor: [0, -12], }); const artyName = t("Mortar"); const hazardMarker = L.marker(pos(hazard.position), { icon: hazardIcon, title: artyName, //zIndexOffset: -100, position: hazard.position, top: hazard.top, bottom: hazard.bottom, outline: rect, riseOnHover: true, }); const popup = L.DomUtil.create("div"); const hazardText = L.DomUtil.create("div", undefined, popup); hazardText.textContent = t("Mortar"); addElevation(hazard, popup); hazardMarker.bindPopup(L.popup().setContent(popup)); hazardMarker.on("mouseover", mouseHoverOutline); hazardMarker.on("mouseout", mouseHoverOutline); hazardMarker.on("click", toggleForceOutline); hazardMarker.on("add", checkMarkerForActiveLayers); if (!hazardLayers.mortar) { hazardLayers.mortar = L.layerGroup(); hazardNames.mortar = artyName; } L.layerGroup([rect, hazardMarker]).addTo(hazardLayers.mortar); checkMarkerBounds(hazard.position, markerBounds); } } for (const key in hazardLayers) { if (Object.keys(hazardLayers[key]._layers).length > 0) { addLayer(hazardLayers[key], `hazard_${key}`, "Hazards", hazardNames[key]); } } } // Add btr stops if (mapData.btrStops?.length > 0) { const stopsGroup = L.layerGroup(); for (const btrStop of mapData.btrStops) { const stopIcon = L.divIcon({ className: "btr-stop", html: `${btrStop.name}`, iconAnchor: [8, 8], }); const stopMarker = L.marker(pos(btrStop), { icon: stopIcon, title: `${tMaps("BTR Stop")}: ${btrStop.name}`, //zIndexOffset: zIndexOffsets[faction], position: btrStop, top: btrStop.y, bottom: btrStop.y, riseOnHover: true, }); stopMarker.on("add", checkMarkerForActiveLayers); stopMarker.addTo(stopsGroup); checkMarkerBounds(btrStop, markerBoundsRef.current); } addLayer(stopsGroup, "btr-stop", "Landmarks"); } if (showMarkersBounds) { console.log( `Markers "bounds": [[${markerBounds.BR.x}, ${markerBounds.BR.z}], [${markerBounds.TL.x}, ${markerBounds.TL.z}]] (already rotated, copy/paste to maps.json)`, ); L.rectangle([pos(markerBounds.TL), pos(markerBounds.BR)], { color: "#ff000055", weight: 1 }).addTo(map); const svgBounds = mapData.svgPath && mapData.svgBounds ? getBounds(mapData.svgBounds) : getBounds(mapData.bounds); L.rectangle(svgBounds, { color: "#00ff0055", weight: 1 }).addTo(map); } refreshMapSearch(); // Set default zoom level // map.fitBounds(bounds); // map.fitWorld({maxZoom: Math.max(mapData.maxZoom-3, mapData.minZoom)}); // maxBounds are bigger than the map and the map center is not in 0,0 so we need to move the view to real center // console.log("Center:", L.latLngBounds(bounds).getCenter(true)); //map.setView(L.latLngBounds(bounds).getCenter(true), undefined, {animate: false}); }, [mapData, t, updateSavedMapSettings, addLayer, categories, tMaps, getPoiLinkElement]); // for markers requiring quests useEffect(() => { if (!mapData || mapData.projection !== "interactive") { return; } const map = mapRef.current; if (!map.options.baseData) { return; } //console.log('loading quest markers'); // remove old markers const groupIds = ["Tasks"]; for (const groupId of groupIds) { map.layerControl.removeGroupFromMap(groupId); } //add quest markers const questItems = L.layerGroup(); const questObjectives = L.layerGroup(); const questSet = new Set(); const hiddenTasks = mapSettingsRef.current.hiddenTasks ?? []; const getMarkerClass = (quest, objective) => { const classes = []; if (quest.active && !objective.complete) { classes.push("active-quest-marker"); } else { classes.push("inactive-quest-marker"); } if (hiddenTasks.includes(quest.id)) { classes.push("hidden-task"); } return classes.join(" "); }; for (const quest of quests) { for (const obj of quest.objectives) { if (obj.possibleLocations) { for (const loc of obj.possibleLocations) { if (!loc.map?.id) { continue; } if (loc.map.id !== mapData.id) { continue; } for (const position of loc.positions) { if (!positionIsInBounds(position)) { continue; } questSet.add(quest); const questItemIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/quest_item.png`, iconSize: [24, 24], popupAnchor: [0, -12], className: getMarkerClass(quest, obj), }); const questItemMarker = L.marker(pos(position), { icon: questItemIcon, position: position, title: obj.questItem.name, id: obj.questItem.id, questId: quest.id, riseOnHover: true, }); const popupContent = L.DomUtil.create("div"); const questLink = getReactLink(`/task/${quest.normalizedName}`, quest.name); popupContent.append(questLink); const questItem = L.DomUtil.create("div", "popup-item", popupContent); const questItemImage = L.DomUtil.create("img", "popup-item", questItem); questItemImage.setAttribute("src", `${obj.questItem.baseImageLink}`); questItem.append(`${obj.questItem.name}`); addElevation({ position }, popupContent); questItemMarker.bindPopup(L.popup().setContent(popupContent)); questItemMarker.on("add", checkMarkerForActiveLayers); questItemMarker.on("click", activateMarkerLayer); questItemMarker.addTo(questItems); checkMarkerBounds(position, markerBoundsRef.current); } } } if (obj.zones) { for (const zone of obj.zones) { if (!zone.map?.id || zone.map.id !== mapData.id) { continue; } if (!positionIsInBounds(zone.position)) { continue; } questSet.add(quest); const rect = L.polygon(outlineToPoly(zone.outline), { color: "#e5e200", weight: 1, className: "not-shown", }); const zoneIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/quest_objective.png`, iconSize: [24, 24], popupAnchor: [0, -12], className: getMarkerClass(quest, obj), }); const zoneMarker = L.marker(pos(zone.position), { icon: zoneIcon, title: obj.description, position: zone.position, top: zone.top, bottom: zone.bottom, outline: rect, id: zone.id, questId: quest.id, riseOnHover: true, }); /*zoneMarker.on('click', (e) => { rect._path.classList.toggle('not-shown'); });*/ zoneMarker.on("mouseover", mouseHoverOutline); zoneMarker.on("mouseout", mouseHoverOutline); zoneMarker.on("click", toggleForceOutline); const popupContent = L.DomUtil.create("div"); const questLink = L.DomUtil.create("div", undefined, popupContent); questLink.append(getReactLink(`/task/${quest.normalizedName}`, quest.name)); const objectiveText = L.DomUtil.create("div", undefined, popupContent); objectiveText.textContent = `- ${obj.description}`; addElevation(zone, popupContent); zoneMarker.bindPopup(L.popup().setContent(popupContent)); zoneMarker.on("add", checkMarkerForActiveLayers); L.layerGroup([rect, zoneMarker]).addTo(questObjectives); } } } } if (Object.keys(questItems._layers).length > 0) { addLayer(questItems, "quest_item", "Tasks"); } if (Object.keys(questObjectives._layers).length > 0) { addLayer(questObjectives, "quest_objective", "Tasks"); } for (const id of focusItem.current) { if (focusOnPoi(id)) { focusItem.current = []; break; } } refreshMapSearch(); mapRef.current?.searchControl?.setTasks([...questSet].sort((a, b) => a.name.localeCompare(b.name))); }, [mapData, quests, addLayer]); // for markers requiring game items useEffect(() => { if (!mapData || mapData.projection !== "interactive") { return; } const map = mapRef.current; if (!map.options.baseData) { return; } // remove old markers const groupIds = ["Loose Loot"]; for (const groupId of groupIds) { map.layerControl.removeGroupFromMap(groupId); } const layerIds = ["lock"]; for (const layerId of layerIds) { map.layerControl.removeLayerFromMap(layerId); } //add locks if (mapData.locks.length > 0) { const locks = L.layerGroup(); for (const lock of mapData.locks) { const key = items.find((i) => i.id === lock.key.id); if (!key) { continue; } if (!positionIsInBounds(lock.position)) { continue; } checkMarkerBounds(lock.position, markerBoundsRef.current); const lockIcon = L.icon({ iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/lock.png`, iconSize: [24, 24], popupAnchor: [0, -12], }); var lockTypeText; if (lock.lockType === "door") { lockTypeText = tMaps("Door"); } else if (lock.lockType === "container") { lockTypeText = tMaps("Container"); } else if (lock.lockType === "trunk") { lockTypeText = tMaps("Car Door or Trunk"); } else { lockTypeText = tMaps("Lock"); } const lockMarker = L.marker(pos(lock.position), { icon: lockIcon, position: lock.position, title: `${tMaps("Lock")}: ${key.name}`, id: key.id, riseOnHover: true, }); const popupContent = L.DomUtil.create("div"); const lockTypeNode = L.DomUtil.create("div", undefined, popupContent); lockTypeNode.innerHTML = `${lockTypeText}`; if (lock.needsPower) { const powerNode = L.DomUtil.create("div", undefined, popupContent); powerNode.innerHTML = `${tMaps("Needs power")}`; } const lockImage = L.DomUtil.create("img", "popup-item"); lockImage.setAttribute("src", `${key.baseImageLink}`); const lockLink = getReactLink(`/item/${key.normalizedName}`, lockImage); lockLink.append(`${key.name}`); popupContent.append(lockLink); addElevation(lock, popupContent); lockMarker.bindPopup(L.popup().setContent(popupContent)); lockMarker.on("add", checkMarkerForActiveLayers); lockMarker.on("click", activateMarkerLayer); lockMarker.addTo(locks); } if (Object.keys(locks._layers).length > 0) { addLayer(locks, "lock", "Usable"); } } //add loose loot if (mapData.lootLoose.length > 0) { const looseLootLayers = {}; for (const looseLoot of mapData.lootLoose) { if (!positionIsInBounds(looseLoot.position)) { continue; } const lootItems = items.filter((item) => looseLoot.items.some((lootItem) => item.id === lootItem.id)); if (lootItems.length === 0) { continue; } let iconSize = [24, 24]; let iconUrl = `${process.env.PUBLIC_URL}/maps/interactive/${images.loose_loot}.png`; let markerTitle = t("Loose Loot"); let className = ""; const markerCategories = lootItems.reduce((markerCategories, item) => { const category = handbook.handbookCategories.find((c) => c.id === item.handbookCategories[0]?.id); if (category) { markerCategories.add(category); } return markerCategories; }, new Set()); if (lootItems.length === 1) { const item = lootItems[0]; iconUrl = item.baseImageLink; markerTitle = item.name; className = "loot-outline"; const pixelWidth = item.width * 63 + 1; const pixelHeight = item.height * 63 + 1; if (item.width > item.height) { const scale = 24 / pixelWidth; iconSize = [24, pixelHeight * scale]; } else { const scale = 24 / pixelHeight; iconSize = [pixelWidth * scale, 24]; } } else if (markerCategories.size === 1) { const category = handbook.handbookCategories.find( (c) => c.id === markerCategories.values().next().value.id, ); iconUrl = category.imageLink; markerTitle = category.name; //className = 'loot-outline'; } const lootIcon = new L.Icon({ iconUrl, iconSize, popupAnchor: [0, -12], className, }); const lootMarker = L.marker(pos(looseLoot.position), { icon: lootIcon, title: markerTitle, position: looseLoot.position, items: lootItems.map((item) => item.name), riseOnHover: true, categories: [...markerCategories].map((cat) => cat.normalizedName), }); const popup = L.DomUtil.create("div"); const popupContent = L.DomUtil.create("div", undefined, popup); //L.DomUtil.create('div', undefined, popupContent).textContent = JSON.stringify(looseLoot.position); for (const lootItem of lootItems) { //const lootContent = L.DomUtil.create('div', undefined, popupContent); const lootImage = L.DomUtil.create("img", "popup-item"); lootImage.setAttribute("src", `${lootItem.baseImageLink}`); const lootLink = getReactLink(`/item/${lootItem.normalizedName}`, lootImage); lootLink.setAttribute("title", lootItem.name); if (className) { lootLink.append(`${lootItem.name}`); } popupContent.append(lootLink); const category = handbook.handbookCategories.find( (c) => c.id === lootItem.handbookCategories[0]?.id, ); if (!category) { continue; } markerCategories.add(category.id); if (!looseLootLayers[category.normalizedName]) { looseLootLayers[category.normalizedName] = { layer: L.layerGroup({ category: category.normalizedName }), label: category.name, image: category.imageLink, }; } lootMarker.addTo(looseLootLayers[category.normalizedName].layer); } addElevation(looseLoot, popup); lootMarker.bindPopup(L.popup().setContent(popup)); lootMarker.on("add", checkMarkerForActiveLayers); lootMarker.on("click", activateMarkerLayer); //lootMarker.addTo(looseLootLayers[layerKey].layer); } for (const layerKey in looseLootLayers) { addLayer( looseLootLayers[layerKey].layer, layerKey, "Loose Loot", looseLootLayers[layerKey].label, looseLootLayers[layerKey].image, ); } } for (const id of focusItem.current) { if (focusOnPoi(id)) { focusItem.current = []; break; } } refreshMapSearch(); }, [mapData, items, handbook, addLayer, t, tMaps, getPoiLinkElement]); useEffect(() => { if (!mapData || mapData.projection !== "interactive") { return; } const map = mapRef.current; if (!map?.options.baseData) { return; } //console.log('loading player position marker'); map.layerControl.removeLayerFromMap("player-position"); // Add player position if (playerPosition && (playerPosition.map === mapData.key || playerPosition.map === null)) { map._container.classList.add("player-position-shown"); const positionLayer = L.layerGroup(); let addRotation = mapData.coordinateRotation; if (addRotation === 90 || addRotation === 270) { addRotation += 180; } const rotation = (playerPosition.rotation ?? 0) + addRotation; const image = playerPosition.rotation !== undefined ? "player-position.png" : "player-position-no-rotation.png"; const playerIcon = L.divIcon({ //iconUrl: `${process.env.PUBLIC_URL}/maps/interactive/player-position.png`, className: "marker", html: ``, iconSize: [24, 24], iconAnchor: [12, 12], popupAnchor: [0, -12], //className: layerIncludesMarker(heightLayer, item) ? '' : 'off-level', }); const positionMarker = L.marker(pos(playerPosition.position), { icon: playerIcon, zIndexOffset: 1000, position: playerPosition.position, markerType: "playerPosition", }).addTo(positionLayer); const closeButton = L.DomUtil.create("a"); closeButton.innerHTML = tMaps("Clear"); closeButton.addEventListener("click", () => { dispatch(setPlayerPosition(null)); }); positionMarker.bindPopup(L.popup().setContent(closeButton)); positionMarker.on("add", checkMarkerForActiveLayers); positionMarker.on("click", activateMarkerLayer); positionLayer.addTo(mapRef.current); //layerControl.addOverlay(positionLayer, tMaps('Player'), tMaps('Misc')); addLayer(positionLayer, "player-position", "Landmarks"); activateMarkerLayer({ target: positionMarker }); mapRef.current.panTo(pos(playerPosition.position), { animate: true }); refreshMapSearch(); } }, [mapData, playerPosition, addLayer, dispatch, tMaps]); if (!mapData) { return ; } return [ ,
    {mapData.projection !== "interactive" && [
    , ]; } export default withTranslation()(Settings); ================================================ FILE: src/pages/start/index.css ================================================ .start-wrapper { align-items: stretch; display: flex; height: auto; justify-content: space-between; flex-flow: wrap; max-width: 1200px; } .start-wrapper ul { margin: 0; padding: 0; list-style: none; } .info-text-wrapper { text-align: center; width: 100%; } .main-logo { margin-top: 2.5rem; } .main-h1 { font-size: 1.3rem; } .main-h2 { font-size: 1.1rem; } .main-headers { margin-top: 1rem; margin-bottom: 0; } .start-hero-cta-group { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; margin-top: 1.5rem; } .start-hero-cta { border: 2px solid var(--color-gold-two); border-radius: 999px; font-size: 0.95rem; font-weight: 600; letter-spacing: 0.05em; padding: 0.6rem 1.75rem; text-transform: uppercase; transition: background-color 150ms ease-in-out, color 150ms ease-in-out; } .start-hero-cta.primary { background-color: var(--color-gold-two); color: var(--color-black); } .start-hero-cta.secondary { background-color: transparent; color: var(--color-gold-two); } .start-hero-cta:hover { background-color: var(--color-gold-dark); color: var(--color-black); } .start-wrapper .icon-with-text { margin-left: 0; } .ammo-link-wrapper { display: block; text-align: center; } .start-section-wrapper { background-color: var(--color-gunmetal-dark); border: 4px solid var(--color-black-light); padding: 10px; margin-top: 10px; margin-bottom: 10px; width: 100%; } .start-section-wrapper h2, .start-section-wrapper h3 { /* margin-top: 0; */ text-align: center; text-transform: uppercase; } .traders-list a { align-items: center; } .start-section-wrapper img { max-width: 100%; } .start-section-wrapper li a { display: flex; padding: 5px 0; } .start-section-wrapper .trader-icon { width: 24px; height: 24px; } .traders-list .trader-icon { margin-right: 10px; } .tools-list li a { align-items: center; display: flex; } .load-more-wrapper { margin-top: 1.25rem; margin-bottom: 0.5rem; display: block; text-align: center; } .load-more-button { padding-left: 1rem; padding-right: 1rem; border-radius: 5px; } .load-more-button:hover { background-color: var(--color-gold-two); color: var(--color-white); cursor: pointer; } @media screen and (width >= 1280px) { .start-section-wrapper img { max-width: 256px; } .start-section-wrapper { width: 24%; } .item-section { width: 74%; } } ================================================ FILE: src/pages/start/index.jsx ================================================ import React, { useState, useCallback, useEffect, lazy, Suspense, useMemo } from "react"; import { useSearchParams } from "react-router-dom"; import { Link } from "react-router-dom"; import { HashLink } from "react-router-hash-link"; import { useTranslation } from "react-i18next"; import QueueBrowserTask from "../../modules/queue-browser-task.js"; import categoryPages from "../../data/category-pages.json"; import SEO from "../../components/SEO.jsx"; import ItemIconList from "../../components/item-icon-list/index.jsx"; import LoadingSmall from "../../components/loading-small/index.jsx"; import { mapIcons, useMapImagesSortedArray } from "../../features/maps/index.js"; import useTradersData from "../../features/traders/index.js"; import { Icon } from "@mdi/react"; import { mdiAccountGroup, mdiAmmunition, mdiCalendarClock, mdiBitcoin, mdiHammerWrench, mdiFinance, mdiCached, mdiProgressWrench, mdiMap, mdiViewGrid, mdiHome, mdiSkull, mdiMonitorCellphone, mdiRobot, } from "@mdi/js"; import "./index.css"; // Use Lazy and Suspense to load these components const ServerStatus = lazy(() => import("../../components/server-status/index.jsx")); const SmallItemTable = lazy(() => import("../../components/small-item-table/index.jsx")); const ItemSearch = lazy(() => import("../../components/item-search/index.jsx")); const BossList = lazy(() => import("../../components/boss-list/index.jsx")); function Start() { const [searchParams, setSearchParams] = useSearchParams(); const [nameFilter, setNameFilter] = useState(searchParams.get("search") || ""); const { t } = useTranslation(); const mapImagesSortedArray = useMapImagesSortedArray(); const uniqueMaps = mapImagesSortedArray.reduce((maps, current) => { if (!maps.some((storedMap) => storedMap.normalizedName === current.normalizedName)) { maps.push({ name: current.name, normalizedName: current.normalizedName, description: current.description, }); } return maps; }, []); const { data: allTraders } = useTradersData(); const traders = useMemo(() => { return allTraders.filter((t) => t.barters?.length > 0); }, [allTraders]); useEffect(() => { setNameFilter(searchParams.get("search") || ""); }, [searchParams]); const handleNameFilterChange = useCallback( (value) => { if (typeof window !== "undefined") { // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setSearchParams({ search: value }); }); } }, [setSearchParams], ); const [loadMoreState, setLoadMoreState] = useState(false); const loadMore = (event) => { setLoadMoreState((current) => !current); }; return [ ,
    } key={"item-search"}> }> {!loadMoreState && [
    , ]}
    } key={"server-status"}>

    {t("Tools")}

    • {t("Ammo chart filter")}
    • {t("Traders barter profit")}
    • {t("Hideout crafts profit")}
    • {t("Loot tiers ranking")}
    • {t("Hideout build costs")}
    • {t("Average wipe length")}
    • {t("Bitcoin farm profit")}
    • {t("TarkovMonitor")}
    • {t("Stash Discord Bot")}

    {t("Maps")}

      {uniqueMaps.map((map) => (
    • {map.name}
    • ))}

    {t("Items")}

      {categoryPages.map((categoryPage) => { return (
    • {t(categoryPage.displayText)}
    • ); })}

    {t("Traders")}

      {traders.map((trader) => { return (
    • {`${trader.name} {trader.name}
    • ); })}

    {t("Bosses")}

      }>
    Tarkov.dev

    {t("tarkov.dev is an open source tool kit for Escape from Tarkov.")}

    {t( "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.", )}

    {t("Learn about TarkovMonitor")}
    , ]; } export default Start; ================================================ FILE: src/pages/stash-bot/index.css ================================================ .stash-page table { width: 100%; border-collapse: collapse; } .stash-page thead { text-align: left; border-bottom: 2px solid rgb(255 255 255 / 0.2); } .stash-page th, .stash-page td { padding: 0.75rem 0.5rem; vertical-align: top; } .stash-page tbody tr:nth-child(odd) { background: rgb(255 255 255 / 0.03); } .scroll-table { overflow-x: auto; } .stash-page code { background: rgb(0 0 0 / 0.4); padding: 0.1rem 0.35rem; border-radius: 6px; } .stash-page figure img { width: 100%; max-width: 640px; border-radius: 8px; } ================================================ FILE: src/pages/stash-bot/index.js ================================================ import { Trans, useTranslation } from "react-i18next"; import Contributors from "../../components/contributors/index.jsx"; import SEO from "../../components/SEO.jsx"; import useRepositoryContributors from "../../hooks/useRepositoryContributors.js"; import "../tarkov-monitor/index.css"; import "./index.css"; const INVITE_URL = "https://discord.com/api/oauth2/authorize?client_id=955521336904667227&permissions=309237664832&scope=bot%20applications.commands"; const REPOSITORY_URL = "https://github.com/the-hideout/stash"; const ISSUE_URL = "https://github.com/the-hideout/stash/issues"; const popularCommands = [ { command: "/help", example: "/help or help ", description: "The help command to view all available commands", }, { command: "/about", example: "-", description: "View details about the bot", }, { command: "/ammo", example: "/ammo ammo_type: 5.45x39mm", description: "Get a sorted ammo table for a certain ammo type", }, { command: "/barter", example: "/barter name: ", description: "Check barter details for an item", }, { command: "/boss", example: "-", description: "Get detailed information about a boss", }, { command: "/changes", example: "-", description: "Get the latest game changes from tarkov-changes.com", }, { command: "/craft", example: "/craft name: ", description: "Check crafting details for an item", }, { command: "/gamemode", example: "-", description: "Set the game mode (regular, PVE) for bot responses", }, { command: "/goons", example: "-", description: "Check or report the location of the Goons", }, { command: "/invite", example: "-", description: "Get a Discord invite link for the bot to join it to another server", }, { command: "/issue", example: "/issue message: ", description: "Report an issue with the bot", }, { command: "/item", example: "-", description: "Get price, craft, barter, etc. information about an item", }, { command: "/key", example: "-", description: "Get a key's price and maps it is used on", }, { command: "/map", example: "/map woods", description: "View a map and some general info about it", }, { command: "/patchnotes", example: "-", description: "Get the latest official patchnotes for EFT", }, { command: "/player", example: "-", description: "Get player profile information", }, { command: "/price", example: "/price name: ", description: "Get a detailed output on the price of an item, its price tier, and more!", }, { command: "/progress", example: "-", description: "Manage your customized hideout and trader progress", }, { command: "/quest", example: "-", description: "Get detailed information about a quest", }, { command: "/restock", example: "-", description: "Show or set alerts for trader restock timers", }, { command: "/roulette", example: "-", description: "Play a game of roulette to determine how you play your next raid", }, { command: "/status", example: "-", description: "Get the game/server/website status of Escape from Tarkov", }, { command: "/stim", example: "-", description: "Get information about a in-game stim", }, { command: "/tier", example: "-", description: "Show the criteria for loot tiers", }, { command: "/uptime", example: "-", description: "Get the bot's uptime" }, ]; function StashBotPage() { const { t } = useTranslation(); const { contributors: stashContributors } = useRepositoryContributors("the-hideout/stash"); return [ ,

    {t("Discord companion")}

    {t("Stash Discord Bot")}

    {t( "stash-hero", "Stash pipes the full Tarkov.dev dataset into Discord so your community can check prices, quest progress, hideout timers, and more without leaving chat.", )}

    {t("Item intelligence")}

    • {t("Instant prices with flea, trader, and craft context.")}
    • {t("Craft/barter lookups reuse Tarkov.dev profitability data.")}
    • {t("Toggle PVE or PMC game modes to match your server rules.")}

    {t("Progress tracking")}

    • {t("Quest command lists requirements, turn-ins, and rewards.")}
    • {t( "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.", )}
    • {t("Restock and status alerts keep everyone informed between raids.")}

    {t("Community tools")}

    • {t("Goons tracker for spotting the Rogue Boss trio.")}
    • {t("Roulette mini-game for fun raid modifiers.")}
    • {t("Slash commands, autocomplete, and localized responses.")}

    {t("Frequently used commands")}

    {t("Stash exposes dozens of slash commands. Here are a few that most servers rely on:")}

    {popularCommands.map((command) => ( ))}
    {t("Command")} {t("Example")} {t("Description")}
    {command.command} {command.example} {t(command.description)}

    {t("Support & feedback")}

    {/* prettier-ignore */}

    Stash is maintained by the Tarkov.dev team. Bugs or feature ideas? Open an issue on{" "} GitHub {" "} or chat with the developers inside the{" "} Tarkov.dev Discord . If you are syncing Tarkov.dev and the bot data, include screenshots plus reproduction steps so we can help faster.

    {t( "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.", )}

    {t( "stash-tech-note", "Need developer-focused setup guides or self-hosting instructions? Review the README on GitHub for the latest technical documentation.", )}

    {stashContributors.length > 0 && (

    {t("Contributors")}

    )}
    , ]; } export default StashBotPage; ================================================ FILE: src/pages/stream-elements/index.css ================================================ .stream-elements-page-wrapper { max-width: 900px; } .stream-elements-page-wrapper img { max-width: 100%; height: auto; } .stream-elements-page-wrapper pre { white-space: pre-wrap; } @media screen and (width >= 800px) { .stream-elements-page-wrapper pre { white-space: pre; } } ================================================ FILE: src/pages/stream-elements/index.jsx ================================================ import { useTranslation } from "react-i18next"; import SEO from "../../components/SEO.jsx"; import "./index.css"; function StreamElements() { const { t } = useTranslation(); const botName = "StreamElements"; return [ ,

    {t("Tarkov.dev {{bot}} integration", { bot: botName })}

    {t( "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat", )}

    {t("Instructions")}

    StreamElements step 1

    StreamElements step 2

    • {t("Command: !p or anything you like")}
    • {t("Message:")}
                              {
                                  // eslint-disable-next-line no-template-curly-in-string
                                  "${urlfetch https://streamer.tarkov.dev/webhook/stream-elements?q=${queryencode ${1:}}}"
                              }
                          
    • {t('Press "Activate Command"')}

    StreamElements part 3

    {t("Big thanks to")}{" "} PhreakinPhil {" "} {t("for feedback")}

    , ]; } export default StreamElements; ================================================ FILE: src/pages/tarkov-monitor/index.css ================================================ .tool-detail-page { max-width: 1100px; } .tool-hero { display: flex; flex-wrap: wrap; gap: 2rem; align-items: flex-start; margin-bottom: 2.5rem; } .tool-hero figure, .tool-hero img { margin: 0; max-width: 480px; width: 100%; } .tool-hero figure { text-align: center; } .tool-hero figcaption { margin-top: 0.5rem; font-size: 0.9rem; color: var(--color-text-muted); } .tool-hero img { border-radius: 12px; border: 1px solid rgb(255 255 255 / 0.08); box-shadow: 0 10px 30px rgb(0 0 0 / 0.45); } .eyebrow { text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.8rem; color: var(--color-text-muted); margin-bottom: 0.5rem; } .tool-cta-group { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.5rem; } .tool-cta { padding: 0.75rem 1.5rem; border-radius: 999px; font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; } .tool-cta.primary { background: var(--color-primary, #3e83f8); color: #fff; } .tool-cta.secondary { border: 1px solid rgb(255 255 255 / 0.2); } .tool-card-grid { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); margin-bottom: 2.5rem; } .tool-card-grid article { border: 1px solid rgb(255 255 255 / 0.08); border-radius: 16px; padding: 1.25rem; background: rgb(255 255 255 / 0.03); box-shadow: 0 12px 40px rgb(0 0 0 / 0.25); } .tool-card-grid ul { margin: 0; padding-left: 1.25rem; } .tool-card-grid li + li { margin-top: 0.35rem; } .tool-detail-page figure img { max-width: 100%; border-radius: 8px; } .faq-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } .faq-grid details { border: 1px solid rgb(255 255 255 / 0.08); border-radius: 10px; padding: 1rem; background: rgb(0 0 0 / 0.2); } .faq-grid summary { cursor: pointer; font-weight: 600; margin-bottom: 0.5rem; } .project-contributors-block { border: 1px solid rgb(255 255 255 / 0.08); border-radius: 16px; padding: 1.25rem; margin-bottom: 2.5rem; background: rgb(0 0 0 / 0.3); box-shadow: 0 12px 35px rgb(0 0 0 / 0.3); } .project-contributors-block h2 { margin-top: 0; margin-bottom: 0.75rem; } .project-contributors-block .contributors-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; } .project-contributors-block .contributors-grid a { display: inline-flex; } .project-contributors-block .contributors-grid .MuiAvatar-root { margin-right: 0; } .feature-list ul, #download ol { margin: 0; padding-left: 1.25rem; } .feature-list li + li, #download li + li { margin-top: 0.4rem; } #community-support { margin: 2rem 0; } #community-support .tool-cta { margin-top: 1rem; } @media screen and (width <= 600px) { .tool-cta-group { flex-direction: column; } } ================================================ FILE: src/pages/tarkov-monitor/index.js ================================================ import { Trans, useTranslation } from "react-i18next"; import Contributors from "../../components/contributors/index.jsx"; import SEO from "../../components/SEO.jsx"; import useRepositoryContributors from "../../hooks/useRepositoryContributors.js"; import "./index.css"; const RELEASE_URL = "https://github.com/the-hideout/TarkovMonitor/releases/latest"; const REPOSITORY_URL = "https://github.com/the-hideout/TarkovMonitor"; const DISCORD_URL = "https://discord.gg/XPAsKGHSzH"; function TarkovMonitorPage() { const { t } = useTranslation(); const { contributors: monitorContributors } = useRepositoryContributors("the-hideout/TarkovMonitor"); return [ ,

    {t("Companion app")}

    {t("TarkovMonitor")}

    {/* prettier-ignore */}

    {t( "tarkov-monitor-summary", "TarkovMonitor provides helpful alerts and timers for Escape From Tarkov so you can manage raids without interrupting gameplay.", )}

    {t("Screenshot
    {t("Visual timers, raid state, and integration health in TarkovMonitor.")}

    {t("Main Features")}

    • {t( "tarkov-monitor-feature-audio", "Audio alerts for matchmaking, raid start, runthrough timer, scav cooldown, and air filter notifications.", )}
    • {t( "tarkov-monitor-feature-map", "Automatic map opening on Tarkov.dev based on the location you are joining.", )}
    • {t( "tarkov-monitor-feature-screenshot", "Optional screenshot-activated position display for quick location sharing.", )}
    • {t( "tarkov-monitor-feature-quests", "Automatic quest updates to TarkovTracker whenever completions are detected.", )}
    • {t( "tarkov-monitor-feature-stats", "Local statistics such as flea market income, queue durations, and map play frequency.", )}
    • {t( "tarkov-monitor-feature-timers", "Visible timers for time in raid plus scav cooldowns so you can plan the next run.", )}

    {t("Download")}

    1. {t("tarkov-monitor-download-1", "Grab the latest TarkovMonitor.zip release from GitHub.")}
    2. {t("tarkov-monitor-download-2", "Extract the archive anywhere on your PC.")}
    3. {t("tarkov-monitor-download-3", "Run TarkovMonitor.exe and keep it open while you play.")}

    {t("Community support")}

    {t( "tarkov-monitor-community", "Have questions or want to chat with other users? Join the Discord server for tips, troubleshooting, and feature discussions.", )}

    {t("Join the Discord")}

    {t("Security")}

    {t( "tarkov-monitor-security", "TarkovMonitor is not a cheat. It only reads the Escape From Tarkov log files stored on your PC and never modifies the game or injects code.", )}

    {monitorContributors.length > 0 && (

    {t("Contributors")}

    )}
    , ]; } export default TarkovMonitorPage; ================================================ FILE: src/pages/trader/index.css ================================================ /* Please See ./styles/singleEntity.css */ ================================================ FILE: src/pages/trader/index.jsx ================================================ import { useCallback, useState, useMemo, useEffect } from "react"; import { useParams, useSearchParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; import ImageViewer from "react-simple-image-viewer"; import { Icon } from "@mdi/react"; import { mdiArmFlex, mdiCashSync, mdiChartLine } from "@mdi/js"; import useStateWithLocalStorage from "../../hooks/useStateWithLocalStorage.jsx"; import SEO from "../../components/SEO.jsx"; import { Filter, InputFilter, ButtonGroupFilter, ButtonGroupFilterButton } from "../../components/filter/index.jsx"; import SmallItemTable from "../../components/small-item-table/index.jsx"; import QuestTable from "../../components/quest-table/index.jsx"; import TraderResetTime from "../../components/trader-reset-time/index.jsx"; import ErrorPage from "../error-page/index.jsx"; import Loading from "../../components/loading/index.jsx"; import LoadingSmall from "../../components/loading-small/index.jsx"; import PropertyList from "../../components/property-list/index.jsx"; import formatPrice from "../../modules/format-price.js"; import QueueBrowserTask from "../../modules/queue-browser-task.js"; import useTradersData from "../../features/traders/index.js"; import i18n from "../../i18n.js"; const romanLevels = { 0: "0", 1: "I", 2: "II", 3: "III", 4: "IV", 5: "V", 6: "VI", 7: "VII", 8: "VIII", 9: "IX", 10: "X", }; function Trader() { const { traderName } = useParams(); const [searchParams, setSearchParams] = useSearchParams(); const [nameFilter, setNameFilter] = useState(searchParams.get("search") ?? ""); const [selectedTable, setSelectedTable] = useStateWithLocalStorage( `${traderName.toLowerCase()}SelectedTable`, searchParams.get("tab") ?? "spending", ); useEffect(() => { // set local storage value on initial page load if (!searchParams.get("tab")) { return; } setSelectedTable(searchParams.get("tab")); }, [searchParams, setSelectedTable]); const { t } = useTranslation(); const setPathFilters = useCallback( (filtervalues) => { const params = { search: nameFilter, tab: selectedTable, }; for (const paramName in filtervalues) { params[paramName] = filtervalues[paramName]; } if (params.search === "") { delete params.search; } setSearchParams(params, { replace: true }); }, [setSearchParams, nameFilter, selectedTable], ); const [isViewerOpen, setIsViewerOpen] = useState(false); const openImageViewer = useCallback(() => { setIsViewerOpen(true); }, []); const closeImageViewer = () => { setIsViewerOpen(false); }; const [traderImageExtension, setTraderImageExtension] = useState("jpg"); const backgroundStyle = { backgroundColor: "rgba(0,0,0,.9)", zIndex: 20, }; const handleNameFilterChange = useCallback( (e) => { if (typeof window !== "undefined") { const name = e.target.value.toLowerCase(); // schedule this for the next loop so that the UI // has time to update but we do the filtering as soon as possible QueueBrowserTask.task(() => { setNameFilter(name); setPathFilters({ search: name }); }); } }, [setNameFilter, setPathFilters], ); const handleTableChange = useCallback( (tableName) => { setSelectedTable(String(tableName)); setPathFilters({ tab: tableName }); }, [setSelectedTable, setPathFilters], ); const { data: traders, status } = useTradersData(); const trader = useMemo(() => { return traders.find((tr) => tr.normalizedName === traderName.toLowerCase()); }, [traders, traderName]); const traderImagePath = useMemo(() => { if (!trader) { return ""; } return `${process.env.PUBLIC_URL}/images/traders/${trader.normalizedName}.${traderImageExtension}`; }, [trader, traderImageExtension]); const levelProperties = useMemo(() => { const props = {}; if (!trader) { return props; } if (isNaN(selectedTable)) { return props; } const levelInfo = trader.levels.find((l) => l.level === parseInt(selectedTable)); if (levelInfo.requiredPlayerLevel > 1) { props.requiredPlayerLevel = { value: levelInfo.requiredPlayerLevel, label: ( {t("Player level")} ), }; } props.requiredReputation = { value: levelInfo.requiredReputation, label: ( {t("Reputation")} ), }; if (levelInfo.requiredCommerce > 0) { props.requiredCommerce = { value: formatPrice(levelInfo.requiredCommerce, trader.currency.normalizedName), label: ( {t("Commerce")} ), }; } return props; }, [trader, selectedTable, t]); const buyBackTableEnabled = useMemo(() => { return trader?.levels.some((l) => l.requiredCommerce > 0); }, [trader]); const traderOffersTableEnabled = useMemo(() => { return trader?.barters.length > 0; }, [trader]); if (!trader && (status === "idle" || status === "loading")) { return ; } if (!trader) { return ; } let resetTime = ; if (trader.resetTime && trader.barters.length) { resetTime = ; } else if (trader.resetTime) { resetTime = ""; } return [ ,
    {trader.name} openImageViewer(0)} />
    {t("Trader")}

    {trader.name}

    {t("Wiki")}

    {trader.description}

    openImageViewer(0)} style={{ backgroundImage: `url(${traderImagePath})` }} /> { if (traderImageExtension !== "jpg") { return; } setTraderImageExtension("webp"); }} />
    {isViewerOpen && ( )}

    {resetTime}

    {buyBackTableEnabled ? ( {t("Items with the best cash back prices for leveling")}} selected={selectedTable === "spending"} content={t("Spending")} type="text" onClick={handleTableChange.bind(undefined, "spending")} /> ) : ( "" )} {traderOffersTableEnabled ? ( {trader.levels.map((level) => ( {t("Unlocks at Loyalty Level {{level}}", { level: level.level })} } selected={selectedTable === String(level.level)} content={romanLevels[level.level]} onClick={handleTableChange.bind(undefined, String(level.level))} /> ))} ) : ( "" )} {t("Tasks given by {{traderName}}", { traderName: trader.name })}} selected={selectedTable === "tasks"} content={t("Tasks")} type="text" onClick={handleTableChange.bind(undefined, "tasks")} />
    {selectedTable !== "tasks" && ( )} {selectedTable === "tasks" && ( )}
    , ]; } export default Trader; ================================================ FILE: src/pages/traders/index.css ================================================ .traders-list-wrapper { display: flex; flex-flow: wrap; justify-content: space-between; } .trader-page-wrapper { min-height: 0; } .traders-list-wrapper img { width: 128px; height: 128px; } ================================================ FILE: src/pages/traders/index.jsx ================================================ import { useMemo } from "react"; import { Link } from "react-router-dom"; import { Trans, useTranslation } from "react-i18next"; import { Icon } from "@mdi/react"; import { mdiAccountGroup } from "@mdi/js"; import SEO from "../../components/SEO.jsx"; import TraderResetTime from "../../components/trader-reset-time/index.jsx"; import LoadingSmall from "../../components/loading-small/index.jsx"; import useTradersData from "../../features/traders/index.js"; import i18n from "../../i18n.js"; import "./index.css"; function Traders(props) { const { t } = useTranslation(); const { data: allTraders } = useTradersData(); // filter traders to only those who have barters // we used to check for sell items, but requires all item data // items.some(item => item.buyFor.some(offer => offer.vendor.trader?.id === trader.id)) const traders = useMemo(() => { return allTraders.filter((trader) => trader.barters?.length > 0); }, [allTraders]); return [ ,

    {t("Escape from Tarkov")} {t("Traders")}

    {traders.map((trader) => { let resetTime = ; if (trader.resetTime) { resetTime = ; } return (

    {trader.name}

    {trader.name} {resetTime} ); })}

    {t("About Traders")}

    {/* prettier-ignore */}

    The backbones of trade in the destroyed, besieged Norvinsk. In Escape from Tarkov, each merchant specialized in a particular kind of products, such as medical supplies, weaponry, or military equipment. Although their prices are typically high, you get what you pay for.

    More importantly, you can develop a reputation with each trader through Quests, which will enable you to receive better offers generally and reduce the commission they receive (an additional markup you pay on sales and purchases), among other benefits.

    Additionally, traders provide other services like insurance and repairs (allowing you to recover your gear in case of death during a raid).

    , ]; } export default Traders; ================================================ FILE: src/pages/wipe-length/index.css ================================================ .wipe-length-cell { align-items: center; display: flex; justify-content: center; } .wipe-length-bar-wrapper { /* display: inline-block; */ height: 10px; width: 200px; background-color: var(--color-gold-one); border-radius: 10px; overflow: hidden; margin-right: 10px; } .wipe-length-bar { height: 10px; border-radius: 10px; background-color: var(--color-gold-two); } ================================================ FILE: src/pages/wipe-length/index.jsx ================================================ import React, { useMemo } from "react"; import { useTranslation } from "react-i18next"; import dayjs from "dayjs"; import SEO from "../../components/SEO.jsx"; import DataTable from "../../components/data-table/index.jsx"; import CenterCell from "../../components/center-cell/index.jsx"; import { averageWipeLength, wipeDetails } from "../../modules/wipe-length.js"; import "./index.css"; const lengthDaysAverage = averageWipeLength(); const data = wipeDetails(); const WipeLength = (props) => { const { t } = useTranslation(); const columns = useMemo(() => { return [ { Header: t("Patch"), id: "name", accessor: "name", }, { Header: t("Wipe start"), id: "start", accessor: ({ start }) => { if (start) { return dayjs(start).format("YYYY-MM-DD"); } return ""; }, Cell: CenterCell, }, { Header: t("Wipe end"), id: "end", accessor: ({ end, ongoing }) => { if (ongoing) { return t("Ongoing wipe"); } if (end) { return dayjs(end).format("YYYY-MM-DD"); } return ""; }, Cell: CenterCell, }, { Header: t("Wipe length"), id: "wipeLength", accessor: "lengthDays", Cell: (props) => { const { value } = props; return (
    {t("{{count}} days", { count: value })}
    ); }, }, ]; }, [t]); // const graphData = useMemo(() => { // return data.map(({start, lengthDays}) => { // return { // x: dayjs(start).format('YYYY-MM-DD'), // y: lengthDays // } // }) // }, []); return [ ,

    {t("Escape from Tarkov")} - {t("Wipe Length")}

    {t("Average Wipe Length among last 6 wipes:")}

    {t("{{count}} days", { count: lengthDaysAverage })} 📆

    {}
    , ]; }; export default WipeLength; export function getAverageWipeLength() { return lengthDaysAverage; } export function getWipeData() { return data; } ================================================ FILE: src/serviceWorker.js ================================================ // This optional code is used to register a service worker. // register() is not called by default. // This lets the app load faster on subsequent visits in production, and gives // it offline capabilities. However, it also means that developers (and users) // will only see deployed updates on subsequent visits to a page, after all the // existing tabs open on the page have been closed, since previously cached // resources are updated in the background. // To learn more about the benefits of this model and instructions on how to // opt-in, read https://bit.ly/CRA-PWA const isLocalhost = Boolean( window.location.hostname === "localhost" || // [::1] is the IPv6 localhost address. window.location.hostname === "[::1]" || // 127.0.0.0/8 are considered localhost for IPv4. window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/), ); export function register(config) { if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { // The URL constructor is available in all browsers that support SW. const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to // serve assets; see https://github.com/facebook/create-react-app/issues/2374 return; } window.addEventListener("load", () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { // This is running on localhost. Let's check if a service worker still exists or not. checkValidServiceWorker(swUrl, config); // Add some additional logging to localhost, pointing developers to the // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { console.log( "This web app is being served cache-first by a service " + "worker. To learn more, visit https://bit.ly/CRA-PWA", ); }); } else { // Is not localhost. Just register service worker registerValidSW(swUrl, config); } }); } } function registerValidSW(swUrl, config) { navigator.serviceWorker .register(swUrl) .then((registration) => { registration.onupdatefound = () => { const installingWorker = registration.installing; if (installingWorker == null) { return; } installingWorker.onstatechange = () => { if (installingWorker.state === "installed") { if (navigator.serviceWorker.controller) { // At this point, the updated precached content has been fetched, // but the previous service worker will still serve the older // content until all client tabs are closed. console.log( "New content is available and will be used when all " + "tabs for this page are closed. See https://bit.ly/CRA-PWA.", ); // Execute callback if (config && config.onUpdate) { config.onUpdate(registration); } } else { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. console.log("Content is cached for offline use."); // Execute callback if (config && config.onSuccess) { config.onSuccess(registration); } } } }; }; }) .catch((error) => { console.error("Error during service worker registration:", error); }); } function checkValidServiceWorker(swUrl, config) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl, { headers: { "Service-Worker": "script" }, }) .then((response) => { // Ensure service worker exists, and that we really are getting a JS file. const contentType = response.headers.get("content-type"); if (response.status === 404 || (contentType != null && contentType.indexOf("javascript") === -1)) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then((registration) => { registration.unregister().then(() => { window.location.reload(); }); }); } else { // Service worker found. Proceed as normal. registerValidSW(swUrl, config); } }) .catch(() => { console.log("No internet connection found. App is running in offline mode."); }); } export function unregister() { if ("serviceWorker" in navigator) { navigator.serviceWorker.ready.then((registration) => { registration.unregister(); }); } } ================================================ FILE: src/setupTests.js ================================================ // jest-dom adds custom jest matchers for asserting on DOM nodes. // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import "@testing-library/jest-dom"; ================================================ FILE: src/store.js ================================================ import { configureStore } from "@reduxjs/toolkit"; import { itemsReducer } from "./features/items/index.js"; import { craftsReducer } from "./features/crafts/index.js"; import { bartersReducer } from "./features/barters/index.js"; import { hideoutReducer } from "./features/hideout/index.js"; import { questsReducer } from "./features/quests/index.js"; import { tradersReducer } from "./features/traders/index.js"; import { mapsReducer } from "./features/maps/index.js"; import { statusReducer } from "./features/status/index.mjs"; import socketsReducer from "./features/sockets/socketsSlice.js"; import settingsReducer from "./features/settings/settingsSlice.mjs"; export default configureStore({ reducer: { items: itemsReducer, crafts: craftsReducer, barters: bartersReducer, hideout: hideoutReducer, quests: questsReducer, traders: tradersReducer, maps: mapsReducer, sockets: socketsReducer, settings: settingsReducer, status: statusReducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ immutableCheck: false, serializableCheck: false, }), }); ================================================ FILE: src/styles/mapRemote.css ================================================ .leaflet-control-remote { background-color: rgb(from var(--color-black) r g b / 0.5); color: #fff; font-family: 'bender', -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', sans-serif; font-size: 16px; line-height: 20px; padding: 10px 40px; z-index: 405; } .leaflet-left .leaflet-control-remote .session-switch-side { content: '>>'; } .leaflet-right .leaflet-control-remote .session-switch-side { content: '<<'; } .leaflet-left .leaflet-control-remote .session-question { right: 0px; } .leaflet-right .leaflet-control-remote .session-question { left: 0px; } ================================================ FILE: src/styles/mapSearch.css ================================================ /*** Quest-Search Leaflet Module ***/ .pulse { animation: pulse 0.75s infinite alternate; } .maps-search-wrapper { display: flex; flex-direction: column; } .maps-search-wrapper-search-bar { min-width: 250px; } .maps-search-wrapper-reset-search, .maps-search-wrapper-reset-task-filter { background-color: transparent; color: var(--color-gold-two); border: 0; height: 20px; width: 20px; padding: 0; position: absolute; right: 5px; top: 10px; font-weight: bold; &:hover { cursor: pointer; color: var(--color-gold-one); } } .maps-search-wrapper-reset-task-filter { top: 100px; } .maps-search-wrapper-info { margin: 5px 0px; font-size: 12px; } @keyframes pulse { from { opacity: 0.75; } } .leaflet-control-icon-search-toggle { background-position: 50% 50%; background-repeat: no-repeat; display: block; background-image: url('data:image/svg+xml,Search'); width: 36px; height: 36px; } .leaflet-control-icon-search { box-shadow: 0 1px 5px rgb(0 0 0 / 0.4); background: #fff; border-radius: 5px; } .leaflet-touch .leaflet-control-icon-search-toggle { width: 44px; height: 44px; } .leaflet-control-icon-search-list { border: 0; margin: 0; padding: 0; /* max-height: 447px; */ } .leaflet-control-icon-search .leaflet-control-icon-search-list, .leaflet-control-icon-search-expanded .leaflet-control-icon-search-toggle { display: none; } .leaflet-control-icon-search-expanded .leaflet-control-icon-search-list { display: flex; flex-direction: column; position: relative; /* overflow-y: scroll; */ } .leaflet-control-icon-search-expanded { padding: 6px 10px 6px 6px; color: #333; background: #fff; } .leaflet-control-v-scrollbar { overflow: hidden scroll; padding-right: 5px; } .leaflet-control-icon-search-selector { margin-top: 2px; position: relative; top: 1px; } .leaflet-control-icon-search label { display: block; font-size: 13px; font-size: 1.0833em; } .leaflet-control-v-separator { height: 0; border-top: 1px solid #999; margin: 5px 5px 5px 5px; } .leaflet-touch .leaflet-control-icon-search { box-shadow: none; border: 2px solid rgb(0 0 0 / 0.2); background-clip: padding-box; } .leaflet-control-icon-search-active-quests { display: flex; } .leaflet-control-icon-search a { color: var(--color-gold-two); } .maps-search-wrapper-task-filter-title { font-weight: bold; } .maps-search-task-list { font-size: 14px; overflow-y: scroll; } .maps-search-task-selector { vertical-align: top; } .maps-search-task-list .hide-task { display: none; } .leaflet-marker-pane .hidden-task { display: none; } .maps-search-task-filter-button-container { position: absolute; right: 0px; } .maps-search-task-filter-show-all, .maps-search-task-filter-hide-all { padding: 2px 4px; height: 20px; } .maps-search-task-filter-show-all { margin: 0px 2px; } ================================================ FILE: src/styles/mapSettings.css ================================================ .leaflet-control-map-settings-toggle { background-position: 50% 50%; background-repeat: no-repeat; display: block; background-image: url('data:image/svg+xml,'); width: 36px; height: 36px; } .leaflet-control-map-settings { box-shadow: 0 1px 5px rgb(0 0 0 / 0.4); background: #fff; border-radius: 5px; } .leaflet-touch .leaflet-control-map-settings-toggle { width: 44px; height: 44px; } .leaflet-control-map-settings-expanded { padding: 6px 10px 6px 6px; color: #333; background: #fff; } .leaflet-control-map-settings-list { border: 0; margin: 0; padding: 0; } .leaflet-control-map-settings .leaflet-control-map-settings-list, .leaflet-control-map-settings-expanded .leaflet-control-map-settings-toggle { display: none; } .leaflet-control-map-settings-expanded .leaflet-control-map-settings-list { display: block; position: relative; } .leaflet-control-map-settings-scrollbar { overflow: hidden scroll; padding-right: 5px; } .leaflet-control-map-settings-selector { margin-top: 2px; position: relative; top: 1px; } .leaflet-control-map-settings label { display: block; font-size: 13px; font-size: 1.0833em; } .leaflet-control-map-settings-separator { height: 0; border-top: 1px solid var(--color-gold-two); margin: 5px 5px 5px 5px; } .leaflet-touch .leaflet-control-map-settings { box-shadow: none; border: 2px solid rgb(0 0 0 / 0.2); background-clip: padding-box; } .leaflet-control-map-settings-setting-container { display: flex; } .leaflet-control-map-settings a { color: var(--color-gold-two); } .leaflet-control-map-settings-setting-container label { display: flex; align-items: center; } .leaflet-control-map-settings-player-location-help { background-image: url('../../public/maps/interactive/player-position.png'); background-repeat: no-repeat; background-size: 24px 24px; padding-left: 27px; } .player-position-shown .leaflet-control-map-settings-player-location-help, .player-position-shown .player-location-help-separator { display: none; } ================================================ FILE: src/styles/singleEntity.css ================================================ /* Main page wrapper */ .entity-page-wrapper { margin: 30px auto 100px auto; max-width: 1200px; position: relative; } /* Top Section */ .entity-information-wrapper { display: flex; background-color: rgb(from var(--color-black) r g b / 0.1); border: 1px solid rgb(from var(--color-gold-two) r g b / 0.7); margin-bottom: 30px; box-shadow: 0 0 5px 3px rgb(from var(--color-white) r g b / 0.034); overflow: hidden; min-height: 260px; } .entity-icon-cont { border-left: 1px solid var(--color-gold-two); background: var(--color-gunmetal-dark); display: flex; min-width: 350px; height: inherit; align-items: center; justify-content: center; position: relative; } .entity-icon-and-link-wrapper { position: absolute; left: 0; top: 0; width: 100%; height: 100%; cursor: pointer; background-size: cover; background-position: center center; } .entity-top-content { display: flex; flex-direction: column; flex: 1 auto; max-width: 850px; } .entity-top-content .title-bar { display: flex; align-items: center; background: rgb(from var(--color-black) r g b / 0.4); padding: 10px 20px; border-bottom: 1px solid rgb(from var(--color-white) r g b / 0.2); } .entity-top-content .entity-information-icon { display: none; width: 124px; margin: 20px auto; height: 124px; border: 1px solid rgb(from var(--color-white) r g b / 0.5); } .entity-top-content .entity-information-images { display: none; margin: 20px auto; } .entity-top-content .entity-information-image { max-width: 124px; max-height: 124px; border: 1px solid rgb(from var(--color-white) r g b / 0.5); } .entity-top-content .title-bar h1 { display: inline-block; color: var(--color-gold-two); align-items: center; justify-content: space-between; cursor: default; margin: 0; } .entity-top-content .title-bar .type { opacity: 0.8; text-transform: uppercase; letter-spacing: 1px; margin: auto 12px auto 0; border: 1px solid var(--color-white); display: inline-block; padding: 4px 8px; border-radius: 10px; color: #fff; cursor: default; } .entity-top-content .title-bar .wiki-link-wrapper { margin: auto 0 auto auto; opacity: 0.9; transition-delay: 0.3s; } .entity-top-content .title-bar .wiki-link-wrapper:hover { opacity: 1; transition: all 0.1s; } .entity-top-content .main-content, .information-section .information-content { padding: 20px 20px 0 20px; } .entity-top-content .entity-properties { padding: 0 20px; margin-top: auto; margin-bottom: 0; } .entity-top-content .main-content p.entity-details { margin: 0 0 20px 0; } .entity-top-content .main-content p.entity-details h3 { margin-top: 0; } @media screen and (width <= 960px) { .entity-information-wrapper { min-height: unset; } .entity-icon-cont { display: none; } .entity-top-content .entity-information-icon { display: inline-block; } .entity-top-content .entity-information-images { display: inline-block; } } @media screen and (width <= 600px) { .entity-top-content .title-bar { flex-direction: column; } .entity-top-content .title-bar .type { margin: 0 auto 10px auto; } .entity-top-content .title-bar .wiki-link-wrapper { margin: 10px auto; } } ================================================ FILE: src/translations/de/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Schleichende Schlingel. Kultisten lauern in Gruppen von 3-5 in den Schatten und warten auf einen sich nähernden Spieler. Sie nähern sich lautlos ihren Gegnern an und stechen sie entweder mit normalen Messern, oder im Fall des Priesters, mit einem vergifteten Kultistenmesser. Wenn die Kultisten angeschossen werden, schlagen sie mit Waffen und Granaten zurück. Nachdem sie einen Spieler mit ihrem Messer attackiert haben, können sie sich dazu entscheiden zurück in den Wald zu rennen und sich in den Schatten zu verstecken.", "knight-bio": "", "knight-description": "Der Führer der 'Goons'. Kann auf vielen verschiedenen Karten erscheinen.", "glukhar-bio": "Es gibt keine schlüssigen Informationen über seine vergangenen Aktivitäten, weil all seine Dokumente entweder verloren gegangen sind oder klassifiziert wurden, laut unbestätigten Informationen hatte er den Rang eines belanglosen Offiziers. Er nahm an Kampfeinsätzen teil, kannte die Grundlagen von Taktiken und hat dieses Wissen aktiv verwendet um verschiedene Gebiete zu beanspruchen oder zu verteidigen.
    Alle seiner Anhänger scheinen auch ehemalige Soldaten zu sein. Jedoch ist seine Gruppe jetzt ein tatsächlicher Räubertrupp, welche für Ressourcen und Einfluss in Tarkov kämpfen. Er hat Verbindungen zu Händlern mit der Fähigkeit Waren aus der Norvinsk Region zu exportieren. Diese Händler schicken ihm regelmäßig die letzten funktionierenden Züge für den Gütertransport.", "glukhar-description": "Glukhar und seine vielen Anhänger sind extrem feindlich. Es ist höchst unwahrscheinlich diese in einem offenen Feld zu besiegen. Enge Flure und geschlossene Räume sind zu bevorzugen. Glukhar und seine Anhänger schießen sehr genau und bleiben ständig zusammen. Seine Anhänger folgen ihm überall hin.", "kaban-bio": "Er hatte einst ein kleines legales Geschäft in Tarkov, scheute aber nicht davor zurück, kriminelle Methoden der Geldbeschaffung anzuwenden. Nach der allgemeinen Evakuierung blieb er in der Stadt, und seine Gang ist gewachsen.", "kaban-description": "Seine Größe erlaubt es ihm, verschiedene schwere Maschinengewehre abzufeuern, ohne dass er die Waffe auflegen muss, aber genau das schränkt seine monilität ein und er bleibt daher entweder in Position oder bewegt sich im Kampf langsam von Punkt zu Punkt. Er verfügt über eine große Anzahl gut bewaffneter Wachen, von denen einige ehemalige Militärs sind, die für ihn eine starke Verteidigung organisiert haben. Der Boss hält sich im Bereich der Autowerkstatt in \"Streets of Tarkov\" auf. Das Gelände ist stark verteidigt, die Eingänge sind mit stationären Maschinengewehren und AGS befestigt, die Wege sind vermint, und auf dem Dach der Autowerkstatt stehen Scharfschützen. Kaban verwendet eine speziell angefertigte Vorrichtung zur Aufbewahrung von Maschinengewehrkisten, trägt Schutzwesten unter seiner Kleidung und genießt bei seinen Wachen unbestrittene Autorität. Scavs in der Nähe helfen dem Boss bei der Verteidigung und nehmen für Kaban am Kampf teil.", "killa-bio": "", "killa-description": "Der wahre Giga Chad von Tarkov. Killa verwendet ein leichtes Maschinengewehr oder andere vollautomatische Waffen um seine Gegner zu unterdrücken, während er von Deckung zu Deckung immer näher zu seinem Ziel für einen finalen Sturm schleicht. Während des Angriffs bewegt er sich in einem Zick-Zack Muster, verwendet Rauch und Splittergranaten und unterdrückt seine Gegner mit erbarmungslosem automatischem Feuer. Er folgt seinem Ziel weit, auch aus seiner Patrouillenroute. Also stelle sicher, dass du sehr weit weg rennst, wenn er es auf dich abgesehen hat.", "kollontay-bio": "Er ist ein ehemaliger Offizier des MVD (Innenministerium). Während seines Dienstes in der Strafverfolgung hatte er den Ruf eines niederträchtigen Mannes, dessen Verhalten manchmal von seinen Kollegen gefürchtet wurde. Bei seiner Arbeit griff er oft auf seine bevorzugte Verhörmethode zurück - einen Gummiknüppel, sowie anderen nicht-statutarischen Druck auf jeden, der ihm nicht gefiel. Dank seiner körperlichen Stärke und seines kühnen Temperaments gründete er nach den Ereignissen des TerraGroup-Skandals eine Gang und begann das zu tun, was er selbst vor kurzem noch bekämpfen sollte - Plünderung und Banditentum. Allerdings bot er schon vor dem Konflikt oft Schutz für lokale \"Geschäftsleute\". Zum Beispiel sind seine guten Beziehungen zu Kaban bekannt.", "kollontay-description": "Kollontay hat eine kleine Anzahl von Wachen, bevorzugt es an einer Position zu bleiben und patrouilliert gelegentlich sein Territorium. Wenn er das Gefühl hat, die Oberhand zu haben, wechselt er möglicherweise zu seinem Polizeischlagstock. Er hält sich im Gebiet um das Klimov Einkaufszentrum und die Tarkov Akademie des Innenministeriums auf.", "partisan-bio": "Es gibt wenige zuverlässige Details über seine Vergangenheit, aber es ist bekannt, dass er einst in Afghanistan diente, wo seine radikalen Kriegsmethoden Wurzeln schlugen. Von manchen als 'Partizan' bezeichnet, wurde er berüchtigt für seine Expertise im Legen von Fallen und Minen. Sein Ruf für die Eliminierung von Feinden beruhte oft darauf, sie unvorbereitet zu erwischen und ihre Überheblichkeit gegen sie zu verwenden. Partizans Wissen über Guerillataktiken machte ihn zu einem gefährlichen Gegner, der jeden Ort - ob Wald oder Gebäude - in eine tödliche Falle verwandeln konnte.
    Diejenigen, die lange genug überleben, um seine Methoden zu lernen, könnten sich in seiner Gunst wiederfinden, aber nur wenn sie vorsichtig genug sind, die Fallen rechtzeitig zu erkennen.", "partisan-description": "", "raider-bio": "", "raider-description": "Scav Raider (auch nur als 'Raider' bekannt) sind fortgeschrittene Scavs welche beträchtlich stärker und taktischer sind als die typischen Scavs. Sie besitzen bedeutend gefährlichere Waffen und verwenden stärkere Munition. Zusätzlich können sie besser zielen und erlegen häufig stark ausgerüstete Spieler mit nur ein paar Kugeln (oder man bekommt einfach 'Kopf: Augen'). Scav Raider patrouillieren auch in mehreren Gruppen und können normalerweise anhand ihrer Ausrüstung, einzigartigen Stimmen und generellen Aggression erkannt werden. Scav Raider sind zunächst gegenüber allen anderen Scavs freundlich (auch Spieler Scavs) aber werden zunehmend feindlicher wenn man zu nah an sie heran kommt und ihre verbalen Warnungen ignoriert. Sie werden auch gegenüber allen Scavs feindlich, wenn ein anderer Scav sie verärgert.", "reshala-bio": "", "reshala-description": "Er versucht normalerweise am Ende eines Kampfes und versteckt vor Spielern zu bleiben. Zusätzlich dazu trägt er nie Rüstung. Sei als Spieler Scav vorsichtig, denn wenn du niedriges Scav Karma hast, könnten Reshala und seine Wachen dich ohne Provokation erschießen, wenn du zu nah an Reshala gelangst. Seine Wachen geben manchmal Warnungen an Spieler Scavs mit niedrigem Karma bevor sie feindlich werden.", "rogue-bio": "", "rogue-description": "Die Rogues verteidigen die Kläranlage und ihre Umgebung auf der Karte Leuchtturm. Ihr Hauptverhalten ist das Patrouillieren aber sie nehmen oft defensive Positionen auf Dächern ein und verwenden die stationären Waffen. Sie attackieren alle Spieler die in ihren Bereich eindringen, sind aber leicht nachsichtig gegenüber USEC PMCs und Scavs. Rogues sind aufgrund ihrer vielen Lebenspunkte, extremen Genauigkeit und großer Zielentfernung sehr gefährlich. Rogues rennen auch in ein Versteck und verwenden Medizin wenn sie verletzt wurden.", "sanitar-bio": "Ein ehemaliger Arzt und Wissenschaftler der für TerraGroup gearbeitet hat. Er hat mehrere Projekte im Labor geleitet, einschließlich der Entwicklung einer neuen psychoaktiven Substanz. Der Forschungsbereich erstreckte sich über den Einfluss verschiedener Krankheiten auf den Körper bis hin zur Entwicklung von Neurostimulanzien. Neben dem TerraGroup Labor hatte er sein eigenes Büro im Azure Coast Sanatorium in dem er auch, vor allem in den letzten Wochen vor der vollständigen Evakuation, Forschung betrieb.
    Er ist oft auf Außeneinsätze in gefährlichen Gebieten mit dem Sanitätsdienst gegangen und nach dem Beginn der Arbeit für den Konzern hat er oft afrikanische und andere Büros besucht um Entwicklungen zu überwachen. Deshalb hat er sich den unbestrittene Autorität und Respekt seiner Kollegen verdient.", "sanitar-description": "Wenn er angegriffen wird, kämpft er neben seinen Scavs und Wachen aber trennt sich oft um sich zu heilen oder sich zu injizieren. Er besitzt reichlich Medizin daher ist ein verlängertes Gefächt möglich.", "shturman-bio": "", "shturman-description": "Shturman und seine Anhänger greifen den Spieler über große Distanzen an um das Sägewerk zu beschützen. Sie bevorzugen es ihre Distanz zu halten, da sie nicht für den Nahkampf ausgerüstet sind.", "tagilla-bio": "", "tagilla-description": "Er ist verdammt verrückt und versucht dich mit seinem Hammer niederzuschlagen. Wenn du dich jedoch in einer Position wie zum Beispiel den Dachsparren befindest, zu der er keinen Weg findet, verwendet er seine Zweitwaffe (normalerweise eine Schrotflinte) um dich von weiter weg zu töten. Er ist sofort am Anfang eines Raids aktiv. Er kann Hinterhälte planen, unterdrückendes Feuer verwenden und einbrechen wenn es notwendig ist.", "zryachiy-bio": "Einer der mysteriösesten Figuren in Tarkov. Es ist so gut wie nichts über seine Vergangenheit bekannt, außer dass er Scharfschützen Training besitzt, und dass er häufig in gefährlichen Gebieten im Nahen Osten und Afrika war.
    Lange vor dem Konflikt wurde er Lightkeepers treue rechte Hand und beteiligte sich aktiv daran, Verbindungen zwischen Lightkeeper und allen, die mit ihm interagierten, zu gründen. Er ist dafür bekannt freundlich mit der Rogue Gruppe und den Kapuze tragenden Männern, welche mysteriöse Symbole bei verschiedenen Orten hinmalen, zu sein.
    Zryachiy ist sehr schweigsam, dennoch verstehen ihn die Leute, die regelmäßig mit ihm arbeiten, auch ohne Worte. Es gibt viele Gerüchte über seine Augen, manche meinen, es sein eine angeborene Besonderheit, manche deuten auf gewisse Augentropfen, die es ihm erlauben, seine Sicht im Dunkeln zu verbessern und ihm dadurch als Nebenwirkung weiße Augen gibt. Trotz seines Aussehens scheint es so, als hätte er sich seinen Namen für genau dieses Sehvermögen verdient, was als ehemaligen Scharfschützen keinen wundert.", "zryachiy-description": "Lightkeepers Kultisten Beschützer." } ================================================ FILE: src/translations/de/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Interactive", "Landscape": "Landschaft", "View Fullscreen": "View Fullscreen", "Exit Fullscreen": "Exit Fullscreen", "Satellite": "Satellite", "Abstract": "Abstract", "Levels": "Levels", "1st Floor": "1st Floor", "2nd Floor": "2nd Floor", "3rd Floor": "3rd Floor", "4th Floor": "4th Floor", "5th Floor": "5th Floor", "Underground": "Untergrund", "Garage": "Garage", "Tunnels": "Tunnels", "Bunkers": "Bunkers", "Spawns": "Spawns", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "Sniper Scav", "Boss": "Boss", "Extracts": "Extracts", "Shared": "Shared", "Hazards": "Hazards", "Usable": "Usable", "Locks": "Locks", "Stationary Gun": "Stationary Gun", "Lever": "Lever", "Switch": "Switch", "Door": "Door", "Container": "Container", "Car Door or Trunk": "Car Door or Trunk", "Lock": "Lock", "Activated by": "Activated by", "Activates": "Activates", "Needs power": "Needs power", "Lootable Items": "Lootable Items", "Tasks": "Tasks", "Item": "Item", "Objective": "Objective", "Misc": "Misc", "openworld-name": "Openworld", "openworld-description": "Das ist eine Vorstellung wie die vollständige Karte von Tarkov aussehen könnte. Diese Openworld Karte würde vermutlich alle Standorte von den existierenden Karten in eine einzige riesige Karte zusammenfassen.", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Aufgaben, items, oder Container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Unterstützt Multisuche (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/de/properties.json ================================================ { "ambientVolume": "Ambiente", "caliber": "Kaliber", "damage": "Schaden", "distanceModifier": "Distanz", "distortion": "Verzerrung", "projectileCount": "Projektilanzahl", "penetrationPower": "Durchschlagskraft", "armorDamage": "Rüstungsschaden", "fragmentationChance": "Fragmentations Chance", "ammoType": "Munitionstyp", "class": "Klasse", "material": "Material", "zones": "Zonen", "defaultPreset": "Standard Vorlagen", "durability": "Haltbarkeit", "ergoPenalty": "Ergonomie Strafe", "speedPenalty": "Geschwindigkeits Strafe", "turnPenalty": "Dreh Strafe", "headZones": "Kopfzonen", "capacity": "Kapazität", "grids": "Raster", "energy": "Energie", "hydration": "Wasserhaushalt", "units": "Einheiten", "stimEffects": "Stim Effekte", "blindnessProtection": "Blendschutz", "fuse": "Zünddauer", "maxExplosionDistance": "Max Explosionsdistanz", "fragments": "Fragmente", "deafening": "Ohrenbetäubend", "blocksHeadset": "Blockiert Headsets", "ricochetY": "Abprall Chance", "uses": "Verwendungen", "malfunctionChance": "Defekt Chance", "ergonomics": "Ergonomie", "recoil": "Rückstoß", "loadModifier": "Modifikator laden", "ammoCheckModifier": "Modifikator für Munitionsprüfung", "useTime": "Benutzungsdauer", "cures": "heilt", "hitpoints": "Lebenspunkte", "maxHealPerUse": "Max Leben pro Verwendung", "hpCostLightBleeding": "Hp Kosten leichte Blutung", "hpCostHeavyBleeding": "Hp Kosten schwere Blutung", "painkillerDuration": "Schmerzmittel Dauer", "energyImpact": "Energie Auswirkung", "hydrationImpact": "Wasserhaushalt Auswirkung", "recoilVertical": "Rückstoß vertikal", "recoilHorizontal": "Rückstoß horizontal", "zoomLevels": "Zoom Stufen", "minLimbHealth": "Min Glied Leben", "maxLimbHealth": "Max Glied Leben", "effectiveDistance": "Effektive Distanz", "fireModes": "Schussmodi", "fireRate": "Schussrate", "sightingRange": "Distanzeinstellung", "defaultWidth": "Standard Breite", "defaultHeight": "Standard Höhe", "defaultErgonomics": "Standard Ergonomie", "defaultRecoilVertical": "Standard Rückstoß vertikal", "defaultRecoilHorizontal": "Standard Rückstoß horizontal", "defaultWeight": "Standard Gewicht", "recoilModifier": "Rückstoß Modifikator", "weight": "Gewicht", "baseItem": "Basis Gegenstand", "categories": "Kategorien", "type": "Typ", "convergence": "Konvergenz", "cameraRecoil": "Kamera Rückstoß", "recoilAngle": "Rückstoßwinkel", "recoilDispersion": "Rückstoß Streuung", "usedOnMaps": "Used on Maps" } ================================================ FILE: src/translations/de/translation.json ================================================ { "No data": "Keine Daten vefügbar", "Current Average Latency": "Aktuelle durchschnittliche Latenz", "API Latency in milliseconds": "API Latenz in Millisekunden", "No barters found for this item": "Keine Tauschangebote für diesen Gegenstand gefunden", "LL{{level}}": "LL{{level}}", "Barter at {{trader}}": "Tauschgegenstand bei {{trader}}", "Craft at {{station}}": "Herstellbar bei {{station}}", "Barter": "Tausch", "Craft at {{stationName}} {{stationLevel}}": "Herstellbar bei {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Du erhältst {{count}} für {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Du erhältst {{count}} für {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "{{count}} herstellbar in {{duration}} für {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "{{count}} herstellbar in {{duration}} für {{totalCost}}", "Reward": "Belohnung", "Cost": "Kosten", "Cost ₽": "Kosten ₽", "Estimated savings": "Geschätzte Einsparungen", "InstaProfit": "Sofortgewinn", "N/A": "Nicht verfügbar", "Barter cost": "Tauschkosten", "No barters available for selected filters": "Keine Tauschgegenstände verfügbar für selektierte Filter", "No barters available for selected filters but some were hidden by ": "Keine Tauschgegenstände verfügbar für selektierte Filter aber verborgen bei ", "your settings": "Deine Einstellungen", "Some barters hidden by ": "Einige Tauschgegenstände versteckt bei ", "Can hold:": "Kann enthalten:", "Can't hold:": "Kann nicht enthalten:", "Level": "Level", "Flea Market": "Flohmarkt", "Flea banned": "Nicht auf dem Flohmarkt verfügbar", "Sell price": "Verkaufspreis", "Flea Market fee": "Flohmarktgebühr", "Duration": "Dauer", "Finishes": "Wird fertig gestellt in", "Start now": "Beginne jetzt", "Flea throughput/h": "Flohmarkt Durchsatz", "Estimated profit": "Geschätzter Gewinn", "Estimated profit/h": "Geschätzter Gewinn pro Stunde", "No crafts available for selected filters": "Für die ausgewählten Filter sind keine herstellbaren Gegenstände verfügbar", "No crafts available for selected filters but some were hidden by ": "Keine herstellbaren Gegenstände verfügbar für selektierte Filter aber verborgen bei ", "Some crafts hidden by ": "Einige Tauschgegenstände versteckt bei ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "Alle Optionen bereits ausgewählt", "Clear selection": "Abschnitt löschen", "This item can't be sold on the Flea Market": "Dieser Artikel kann nicht auf dem Flohmarkt verkauft werden", "Not scanned on the Flea Market": "Nicht erkannt auf dem Flohmarkt", "Flea market prices loading": "Flohmarktpreise laden", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>Die gesamte Plattform ist Open Source und auf Entwickler ausgerichtet, der gesamte Quellcode ist verfügbar auf <1><0> GitHub.", "about-discord-p": "<0>Wenn du Fragen hast oder Vorschläge für neue Funktionen hast, oder dich einfach nur unterhalten möchtest, besuch uns gerne auf unseren <1><0> Discord server.", "about-x-p": "<0>Folge uns auf <1><0> X für alle Neuigkeiten.", "About": "Über", "Contributors": "Unterstützer", "Massive thanks to all the people who help build and maintain this project!": "Vielen Dank an alle Menschen, die uns dabei unterstützen das Projekt zu betreiben und die Entwicklung voran zu bringen!", "Made with ❤️ by:": "Mit Liebe ❤️ erstellt von:", "Supporters": "Unterstützung", "about-support-ukraine-p": "<0>Wir unterstützen die Menschen in der Ukraine und würden uns freuen, wenn du die Möglichkeit hast, den Menschen mit einer Spende zu helfen. Nutze dafür bitte den Button.", "about-support-collective-p": "<0>Wenn du dieses Projekt auch unterstützen möchtest, kannst du eine Spende und/oder Unterstützer auf <1>Open Collective geben/werden.", "Item Data": "Gegenstandsinformationen", "Fresh EFT data courtesy of": "Neue EFT-Daten mit freundlicher Genehmigung von", "Additional data courtesy of": "Zusätzliche Daten dank", "Resources": "Ressourcen", "Tarkov.dev API": "Tarkov.dev API", "{{bot}} integration": "{{bot}} Integration", "Discord bot for your Discord": "Discord bot für deinen Discord Server", "External resources": "Externe Ressourcen", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev ist ein Fork von den abgeschalteten tarkov-tools.com | Vielen Dank an kokarn für all seine Arbeit an den Tarkov Tools sowie der dazugehörigen Community.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "Spielinhalte und -materialien sind Marken und Urheberrechte von Battlestate Games und seinen Lizenzgebern. Alle Rechte vorbehalten.", "version": "version", "PMC & Scav Thorax HP": "PMC & Scav Brustkorb HP", "Reshala Thorax HP": "Reshala Brustkorb HP", "Raider Thorax HP": "Raider Brustkorb HP", "Shturman Thorax HP": "Shturman Brustkorb HP", "Cultist Priest Thorax HP": "Cultist Priest Brustkorb HP", "Cultist Warrior Thorax HP": "Cultist Warrior Brustkorb HP", "Damage": "Schaden", "Class {{tier}}": "Klasse {{tier}}", "Penetration": "Durchschlagskraft", "Filter by caliber": "Nach Kaliber filtern", "This item can only be sold to trader": "Dieser Gegenstand kann nur an Händler verkauft werden", "per slot": "pro Slot", "Value": "Wert", "Per slot": "Pro Slot", "Sell to": "Verkaufen an", "Found In Raid": "Im Raid gefunden", "Search item...": "Item suchen...", "Search task...": "Aufgaben suchen...", "Tasks": "Aufgaben", "Items": "Gegenstände", "No hideout modules requires this item": "Keine Unterschlupf Station benötigt diesen Gegenstand", "No unbuilt hideout modules for selected filters but some were hidden by ": "keine ungebauten Unterschlupf Stationen für die selektierten Filter aber versteckt bei ", "Hideout Module": "Unterschlupf Station", "Item": "Gegenstand", "Amount": "Menge", "Player level: {{playerLevel}}": "Spieler Level: {{playerLevel}}", "Reputation: {{reputation}}": "Reputation: {{reputation}}", "Commerce: {{commerce}}": "Handel: {{commerce}}", "Cheapest Price": "Günstigster Preis", "Task: {{taskName}}": "Aufgabe: {{taskName}}", "Flea Market not available": "Flohmarkt nicht verfügbar", "No trader offers available": "Keine Händlerangebote verfügbar", "Loading...": "Lädt...", "Ammo": "Munition", "Maps": "Karten", "More": "Mehr", "Traders": "Händler", "Prapor": "Prapor", "Therapist": "Therapist", "Skier": "Skier", "Peacekeeper": "Peacekeeper", "Mechanic": "Mechanic", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "Bosse", "Barter profit": "Tauschgewinn", "Hideout profit": "Unterschlupf Gewinn", "Loot tiers": "Gegenstand Wertstufen", "Hideout build costs": "Unterschlupf Konstruktionskosten", "Wipe length": "Länge des Wipe", "Bitcoin Farm Profit": "Bitcoinfarm Gewinn", "Achievements": "Erfolge", "API": "API", "Donate": "Spende", "Become a patron": "Werde ein Patron", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "hat Alternativen", "On Task Completion": "Bei Abschluss der Aufgabe", "On Task Start": "Bei Start der Aufgabe", "Task": "Aufgabe", "Required items": "Benötigte Gegenstände", "Reward items": "Belohnungs Gegenstände", "Required tasks": "Benötigte Aufgaben", "loading": "lade", "active": "aktiv", "succeeded": "erfolgreich", "complete": "komplett", "failed": "fehlgeschlagen", "Minimum level": "Minimum Level", "Minimum trader level": "Minimum Händler Level", "Reputation rewards": "Reputationsbelohnung", "Endgame": "Endgame", "Required for Kappa": "Für Kappa benötigt", "Required for Lightkeeper": "Für Lightkeeper benötigt", "Kappa": "Kappa", "Lightkeeper": "Lightkeeper", "No quests found": "Keine Quest gefunden", "Some tasks hidden by filter settings": "Einige Aufgaben durch Filtereinstellungen nicht sichtbar", "open this page in another browser or window and connect using this id": "Öffne die Seite in einem anderen Browser oder Fenster und verbinden dich mit dieser ID", "ID for remote control": "ID für Fernsteuerung", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Gehe auf Tarkov.dev mit einem anderen Browser und füge diese ID ein um diese Seite von dort aus zu steuern.", "Click to connect": "Klicke um zu verbinden", "Sell value": "Verkaufswert", "Tarkov server status": "Tarkov Server Status", "This item can't be sold to traders": "Dieser Gegenstand kann nicht an Händler verkauft werden", "Name": "Name", "Sell to Flea": "Verkaufe auf Flohmarkt", "Buy on Flea": "Kaufe auf Flohmarkt", "Sell to Trader": "Verkaufe an Händler", "Trader buy": "Händlerkauf", "Buyback ratio": "Rückkaufquote", "The percent recovered if you buy this item and sell it to the trader": "Der erholte Prozentsatz, wenn Sie diesen Artikel kaufen und an den Händler verkaufen", "Grid": "Raster", "Slots occupied": "Slots belegt", "Slots inside": "Slots innen", "Slots ratio": "Slots Verhätlnis", "Price per slot": "Preis pro Slot", "Armor class": "Rüstungsklasse", "Zones": "Zonen", "Max Durability": "Maximale Haltbarkeit", "Effective Durability": "Effektive Haltbarkeit", "Repairability": "Reparierbarkeit", "Weight (kg)": "Gewicht in Kilogramm", "Stats": "Statistiken:", "Mov/Turn/Ergo": "Bew./Dreh./Ergo", "Caliber": "Kaliber", "Armor damage": "Rüstungsschaden", "Fragmentation chance": "Chance auf Fraktur", "Blindness protection": "Blendschutz", "Hydration": "Hydration", "Energy": "Energie", "Hydration Cost": "Hydrationskosten", "Energy Cost": "Energiekosten", "Hydration + Energy Value": "Hydration + Energie Werte", "Sound suppression": "Geräuschunterdrückung", "Low": "Niedrig", "None": "Keine", "Blocks earpiece": "Blockiert Headset", "Yes": "Ja", "No": "Nein", "Ergonomics": "Ergonomik", "Cost per ergo": "Kosten pro Ergonomik", "Recoil": "Rückstoß", "Distance": "Distanz", "No items": "Keine Gegenstände", "Not built": "Nicht gebaut", "Locked": "gesperrt", "Crafting": "Herstellung", "Hideout Management": "Unterschlupf Management", "Be the first!": "Sei der Erste!", "Objective": "Objektiv", "No objectives": "keine Objektive", "Players": "Spieler", "By": "Von", "Restock in": "Neue Vorräte in", "Support Ukraine": "Hilfe für die Ukraine", "Cost per unit": "Kosten pro Einheit", "About the tarkov.dev project": "Über das tarkov.dev Projekt", "about-page-description": "Lerne mehr über die Projekte the-hideout und tarkov.dev - eine freie Open Source Community rund um das Escape from Tarkov Ökosystem! Benutze unsere Werkzeuge, spiel das Spiel oder nutze unsere freie API für dein Projekt.", "Open source": "Open source", "Discussions & feedback": "Diskussionen und Feedback", "Support": "Unterstützung", "about-support-more-p": "<0>Du kannst uns ebenfalls unterstützen, indem du Bugs meldest, Featurewünsche, Updates für Karten oder andere nützliche Dinge einreichst, die das Projekt voranbringt.", "about-api-p": "<0>Wir bieten eine 100% freie und öffentlich nutzbare API für all deine Tarkov Projekte - <1>API.", "History": "Geschichte", "about-history-p": "<0>Dieses Projekt ist ein Fork von <1>tarkov-tools.com. Der originale Erschaffer <3>@kokarn entschied die Seite abzuschalten. Mit dem Open Source Gedanken entstand eine Gruppe von Entwicklern mit dem Willen die Seite wiederzubeleben, um für die Tarkov Community eine 100% freie API zu erstellen. Die Entwicklung findet auf Github statt (<5>the-hideout) dort befinden sich alle Repos welche die API betreiben, diese Webseite, der community Discord bot, Dokumentation zur Serverinfrastruktur und vieles mehr! Wir lieben Open Source und freuen uns über deinen Pull Request um unser Projekt zu verbessern.", "Core Contributors": "Kernentwickler", "about-core-contributors-p": "<0>Die Kernentwickler in diesem Projekt sind (in no particular order):", "All Contributors": "Alle Unterstützer", "about-all-contributors-p": "<0>Großes Dankeschön an alle Leute, die an diesem Projekt mitgewirkt haben, um es möglich zu machen! ❤️", "Description": "Beschreibung", "Hidden": "Versteckt", "Player %": "Player %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "Diese Seite enthält Informationen über die Erfolge, die im Spiel freigeschaltet werden können.", "Ammo chart": "Munitionstabelle", "ammo-page-description": "Diese Seite enthält jeden Munitionstyp in Escape from Tarkov. Um die Liste zu filtern, klicke auf das Kaliber.", "ammo-page-p": "<0>Die Wildnis von Tarkov beinhaltet ein vielfältiges Angebot an Munition. Um unterschiedliche Feinde zu bekämpfen, werden unterschiedliche Munitions Typen benötigt.<1>Diese Seite enthält eine Liste über jeden Munitions Typ in Escape from Tarkov. Um die gesamte Liste nach verfügbaren Patronen zu filtern, klicke auf den Namen des Kalibers.", "Total damage": "Kompletter Schaden", "Use total damage of all projectiles in a round": "Totaler Schaden aller Kugeln in einem Magazin", "Ignore settings": "Einstellungen ignorieren", "Shows all sources of items regardless of your settings": "Zeigt Quellen von allen Gegenständen und ignoriert deine Einstellungen", "Use barters for item sources": "Tauschangebote für Item Quellen verwenden", "Use crafts for item sources": "Herstellungen für Item Quellen verwenden", "Ammo Statistics Table": "Munitions Statistik Tabelle", "API Documentation": "API Dokumentation", "api-docs-page-description": "Escape from Tarkov's freie und Community basierte API und seine Dokumentation, lerne mehr darüber über GraphQL auf die API zuzugreifen.", "api-about-p": "<0>Die API basiert auf GraphQL, wir geben unser bestes uns an die Standards zu halten und keine \"breaking Changes\" einzuführen. um zu lernen welche Querys es gibt und wie diese strukturiert sind, besuche die Spielwiese unter dem 'Docs' Tab auf der Rechten Seite. Wenn du bereit bist ein paar Querys auszuprobieren, kannst du das ebenfalls auf der Spielwiese tun. Um etwas über die GraphQL Queries im allgemeinen zu lernen, besuche die GraphQL Foundation.<1><0><0>Tarkov.dev GraphQL Spielwiese<1><0>GraphQL Foundation Ressourcen<1>Wenn du mit deinen Tests auf der Spielwiese fertig bist, lautet der Endpoint: <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Aktuelle API Leistung", "api-performance-p": "<0>Für vollständige API Metriken und Leistung, schaue auf der <1>Status Seite.", "FAQ": "FAQ", "Is it free?": "Ist es kostenlos?", "Is it open source?": "Ist es Open Source?", "api-faq-open-source-p": "Na klar! Den Quellcode findest du in unserem Github Repo: <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "Gibt es eine Limitierung bei der Anzahl der Anfragen?", "api-faq-rate-limit-p": "Gelegentlich werden wir mit viel Traffic belastet, was die Implementierung von Rate Limits erfordert. Preisdaten werden alle 5 Minuten aktualisiert, daher gibt es keinen Grund, schneller abzufragen. Verwende gesunden Menschenverstand und alles wird gut.", "What about caching?": "Wie sieht es mit Caching aus?", "api-faq-caching-p": "Da unsere Daten alle 5 Minuten erneuert werden, cachen wir auch die GraphQL Queries in diesem Zeitraum. Das hilft uns dabei die Last auf unseren Servern zu senken und Antworten im Sekundenbruchteil zu liefern!", "Where is the data from?": "Wo kommen die Daten her?", "We source data from multiple places to build an API as complete as possible. We use data from:": " Wir holen die Daten von mehreren Stellen um die API so komplett wie möglich zu befüllen. Wir nutzen Daten von:", "Our network of scanners": "unserem Netzwerk aus Scannern (Closed Source)", "Examples": "Beispiele", "example": "Beispiel", "Contributed by": "Beigetragen von", "API Users": "API Benutzer", "api-users-page-description": "Diese Seite enthält eine Liste von allen Benutzern der API auf Tarkov.dev und seinen Projekten.", "api-users-p": "<0>Du willst auf dieser Seite aufgelistet werden? Trete dem <1>Discord bei und teile uns mit, was du gemacht hast!", "Barter Profits": "Tauschgewinne", "barters-page-description": "Diese Seite enthält diverse Informationen über Gegenstände welche mit NPCs gehandelt werden können, die Tauschpreise, und den Profit vom Verkauf.", "Shows all barters regardless of your settings": "Zeigt alle Tauschhändler, unnabhängig von deinen Einstellungen", "Hide dogtags": "Verstecke Dogtags", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "Die wahren Kosten von Tauschgegenständen die auf Dogtags basieren sind schwierig zu ermitteln, es macht ggf. Sinn das du diese ausschließt.", "Show all barters": "Zeige alle Täusche", "All": "Alles", "Item filter": "Gegenstandsfilter", "filter on item": "Filter auf Gegenstand", "barters-page-p": "<0>Abgesehen von Fence bietet jeder Händler in Escape from Tarkov Tauschmöglichkeiten an, anstatt einen direkten Kauf zu tätigen.<1>Im Austausch für gewisse billige Gegenstände kann der Spieler diese häufig für wertvollere Objekte handeln, welche dann wiederum verwendet oder für einen Gewinn verkauft werden können. Diese Geschäfte erlauben es Spielern manchmal Ausrüstung und Gegenstände zu bekommen, welche sonst nur bei höheren Händlerleveln gekauft werden können.<3>Stelle sicher, dass du nach jedem Zurücksetzen der Händler deine Lieblingsangebote durchschaust, denn ein Großteil dieser wertvollen Angebote haben strikte Begrenzungen pro Händlerreset und sind häufig ausverkauft.", "Num graphic cards": "Nummer Grafikkarten", "Hours": "Stunden", "Bitcoin Farm Calculator": "Bitcoinfarm Rechner", "bitcoin-farm-calculator-page-description": "Diese Seite beinhaltet ein Kalkulationstool, welches dir dabei hilft die Preise zum aufbauen und betreiben einer Bitcoinfarm zu ermitteln. Basierend auf den vorhandenen GPUs, Stromkosten und Kosten des Bitcoins.", "Graphic cards count": "Anzahl Grafikkarten", "Use fuel cost: {{price}}/day": "Treibstoffkosten: {{price}} pro Tag", "Use station build costs": "Verwende Stationsaufbaukosten", "Purchase cost": "Kosten für Kauf", "Remaining days in wipe:": "Verbleibende Tage im Wipe:", "Time to produce 1 bitcoin": "Zeit um einen Bitcoin herzustellen", "BTC/day": "BTC/Tag", "Estimated profit/day": "Voraussichtlicher Profit pro Tag", "Profitable after days": "Rentabel nach Tagen", "Total cost of graphic cards": "Gesamtkosten der Grafikkarten", "Build costs": "Aufbaukosten", "GPU + build costs": "Grafikkarten + Aufbaukosten", "Remaining profit": "Verbleibender Gewinn", "Map": "Karte", "Spawn Location": "Spawn Ort", "Chance": "Chance", "Count": "Anzahl", "Spawn chance": "Spawn Chance", "Chance that the boss spawns on a given map": "Chance das der Boss auf einer bestimmten Map erscheint", "Health": "Gesundheit", "Total boss health": "Komplette Gesundheit des Bosses", "Patrol": "Wache", "Rush": "Stürmen", "Stalker": "Pirschjäger", "Hostile and accurate": "Feindseligkeit und Genauigkeit", "Patrol and highly armored": "Wachen und gute Rüstung", "Group patrol": "Gruppe von Wachen", "Frequent healing and stim injections": "Verwendet Heilung und Stims", "Sniper": "Scharfschütze", "Batshit insane": "Komplett übertrieben", "Behavior": "Verhalten", "The boss's general AI behavior": "vom Boss angewandetes AI-Verhalten", "Wiki": "Wiki", "Boss Stats": "Boss Werte", "Special Boss Loot": "Spezieller Boss Loot", "Spawn Locations": "Spawn Orte", "boss-spawn-table-description": "<0>Karte: Der Name der Karte auf der der Boss erscheinen kann<1>Spawn Ort: Der exakte Ort auf der Karte, bei dem der Boss erscheinen kann<2>Wahrscheinlichkeit: Wenn die \"Spawn Chance\" auf der Karte aktiviert ist, ist das eine geschätzte Wahrschenlichkeit, dass der Boss an dem bestimmten Ort auf der Karte erscheint", "Boss Escorts": "Boss Begleitung", "This boss does not have any escorts": "Dieser Boss hat keine Begleitung", "boss-page-description": "Diese Seite beinhaltet Informationen zu {{bossName}}, seinen Ort, Loot und Strategien ihn zu besiegen.", "bosses-page-description": "Diese Seite beinhaltet Informationen zu allen Bossen im Spiel, ihre Orte, Loot, Begleitungen und Strategien sie zu besiegen.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Bosse sind gefürchtete und tödliche Feinde in Escape from Tarkov mit einzigartiger Ausrüstung und Verhalten", "About Bosses": "Über die Bosse", "bosses-page-p": "<0>In Escape from Tarkov gibt es viele Bosse, welche die belagerte Norvinsk Region durchstreifen.<1>Jeder Boss hat einzigartige Verhaltensweisen, Eigenschaften und Taktiken. Die Bosse in Tarkov sind von Spielern aller Level gefürchtet und stellen oft eine größere Gefahr als gegnerische PMCs in der Region dar.<2>Jedoch kommt mit großem Risiko auch eine große Belohnung. Viele Bosse besitzen wertvolle Gegenstände oder müssen für eine Aufgabe eliminiert werden. Die Muster, Standorte und besondere Kleidung der Bosse zu lernen ist häufig das meiste was ein Spieler machen kann um sich auf einen Kampf gegen einen Boss vorzubereiten.", "Connect": "Verbinden", "Connected to": "Verbunden zu", "id to control": "ID zum Fernsteuern", "Remote Control": "Fernsteuern", "remote-control-page-description": "Diese Seite enthält alle Werkzeuge um Tarkov.dev aus der Ferne zu steuern.", "View Map": "Karte ansehen", "Go": "Los", "View caliber": "Kaliber anzeigen", "Select...": "Auswählen...", "Load tarkov.dev in another browser or window to control it from here": "Lade tarkov.dev in einem anderen Browser oder Tab um es von hier zu kontrollieren", "Hideout Crafts": "Unterschlupf Fertigungen", "crafts-page-description": "Diese Seite enthält Informationen zu den verschiedenen Dingen die im Unterschlupf hergestellt werden können. Weiterhin gibt es Informationen zu benötigten Materialien und Profite des Verkaufs.", "Shows all crafts regardless of your settings": "Zeigt alles an, ignoriert deine Einstellungen", "Average prices": "Durchschnittspreis", "Use average prices from the past 24 hours for profit calculations": "Nutze Durchschnittspreise der letzten 24 Stunden zur Kalkulation", "Most profitable craft in each station": "Herstellung mit höchstem Gewinn für jede Station", "Best": "Beste", "Flea Market banned items": "Flohmarkt verbotene Gegenstände", "Empty fuel": "Leerer Treibstoff", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "Bestimmt die Treibstoffkosten für Herstellungen die diese benötigen, für den minimalen Verkaufspreis der Händler, wenn die Treibstoffkanister nicht im Raid gefunden wurden.", "crafts-page-p": "<0>Crafts in Escape from Tarkov erlauben es dir eine Vielfalt an Gegenständen herzustellen. Dies wird durch das Benutzen von verschiedenen Unterschlupfmodulen erreicht, wie zum Beispiel dem Wassersammler, der Werkbank, der Erste-Hilfe-Station, der Toilette und der Versorgungsstation.<1>Der \"im Raid gefundener Gegenstand\" Status wird jedem im Unterschlupf hergestellten Gegenstand zugewiesen. Eine vollständige Liste dieser Crafts ist oben angezeigt. Die Fähigkeit Herstellung hat einen Einfluss auf die Dauer des Herstellens.<2>Wenn ein Gegenstand einen blauen Rand hat, wird dieser als Hilfswerkzeug verwendet und, sobald das Herstellen fertig ist, wieder in dein Versteck zurückgelegt.", "Page not found": "Seite nicht gefunden", "error-page-description": "Das ist nicht die Seite, nach der du suchst.", "Sorry, that page doesn't exist!": "Entschuldigung, diese Seite existiert nicht!", "Hideout": "Unterschlupf", "hideout-page-description": "Diese Seite enthält Informationen darüber mit welchen Materialien Unterschlupf Stationen sowie deren Upgrades hergestellt werden können.", "Show all stations & modules": "Zeigt alle Stationen und Module", "Show built": "Zeige bau", "Show already built stations": "Zeige bereits gebaute Stationen", "Show locked": "Zeige gesperrt", "Show unavailable stations": "Zeige nicht verfügbare Stationen", "Show all requirements": "Zeige alle Anforderungen", "Show trader and other station level requirements": "Zeige Händler und andere Stationen Level Anforderungen", "Collected": "Eingesammelt", "Item Tracker": "Gegenstand Tracker", "Only show Found in Raid": "Nur im Raid gefundene anzeigen", "Reset all tracking": "Gesammtes Tracking zurücksetzen", "Hide completed": "Unterschlupf komplett", "Hide tasks you've completed": "Unterschlupf Aufgabe komplett", "Hide dogtag barters": "Verstecke Dogtag Tauschgegenstände", "Best price to sell for": "Bester Preis zum Verkaufen", "Fee": "Gebühr", "Profit": "Gewinn", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "Der letzte günstigste Preis für diesen Gegenstand auf dem Flohmarkt war {{lastSeenPrice}}.\nDurch die zusätzlichen Kosten der Gebühren, solltest du für {{bestPrice}} verkaufen.", "Max price to sell for": "Maximalpreis", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "Dieser Gegenstand wurde nicht auf dem Flohmarkt beobachtet.\nDer beste Preis ist {{bestPrice}}, aber ggf. verkauft sich der Gegenstand nicht für diesen Preis.\nDer profitabelste Preis wird beeinflusst durch das Intelligenzcenter und den Unterschlupf Management Skill in deinen Einstellungen.", "Likely sell price": "geeigneter Verkaufspreis", "item-page-description": "Diese Seite beinhaltet Informationen über Charakteristiken, Anwendungsfälle und Strategien für {{itemName}}.", "Sell for": "Verkaufspreise", "Buy for": "Einkaufspreise", "Flea price history": "Flohmarktpreisentwicklung", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "Veränderungen im Verhältnis zum Vortag: {{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "Niedrigster Preis der letzten 24 Stunden: {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Höchster Preis der letzten 24 Stunden: {{high24hPrice}}", "Updated: {{val, relativetime}}": "Aktualisiert: {{val, relativetime}}", "Items contained in {{itemName}}": "Gegenstände enthalten in {{itemName}}", "Barters with {{itemName}}": "Tauschgegenstand mit {{itemName}}", "Crafts with {{itemName}}": "Herstellbar mit {{itemName}}", "Hideout modules needing {{itemName}}": "Braucht Unterschlupf Station {{itemName}}", "Shows all modules regardless of your settings": "Zeigt alle Module, ignoriert deine Einstellungen", "Quests requiring {{itemName}}": "Quests benötigen {{itemName}}", "Quests rewarding {{itemName}}": "Quests Belohnung {{itemName}}", "Armors": "Rüstungen", "armors-page-description": "Diese Seite enthält eine sortiebare Tabelle aller verfügbaren Rüstungen im Spiel. Inklusive Preis, Reparierbarkeit, Rüstungsklasse und anderen Charakteristiken", "Class effective durability": "Klasseneffektive Haltbarkeit", "Include rigs": "Beziehe Ausrüstung ein", "Max price": "Maximaler Preis", "max price": "maximaler Preis", "armors-page-p": "<0>In Escape from Tarkov werden Rüstungswesten getragen, um den Kugelschaden zu verringern. Zusätzlich werden in der Regel Helme verwendet.", "Backpacks": "Rucksäcke", "backpacks-page-description": "Diese Seite enthält eine sortiebare Tabelle aller verfügbaren Rucksäcke im Spiel. Inklusive Preis, Größe und anderen Charakteristiken", "Net price per slot": "Netto Preis pro Slot", "Show price per additional slot of storage gained from the container": "Zeige Preis basierend auf zusätzlichen Slots, welche durch den Behälter erhalten werden", "backpacks-page-p": "<0>Rucksäcke in Escape from Tarkov gibt es in verschiedenen Größen, um deinen hart verdienten Loot zu transportieren.", "Barter Items": "Tauschgegenstände", "barter-items-page-p": "<0>Diese Tabelle der Tauschgegenstände aus Escape from Tarkov macht es dir einfach, den Wert jedes einzelnen Gegenstands zu bestimmen. Es kann schwierig sein zu entscheiden, welche Gegenstände wertvoll genug sind, da es über 150 Tauschgegenstände im Spiel gibt und die Flohmarktpreise plötzlich schwanken können. Mit Hilfe dieser interaktiven Tabelle kannst du deinen Loot optimieren.", "bsg-category-description": "Finde alles heraus, was du über die {{category}} in Escape from Tarkov wissen musst.", "Containers": "Behälter", "containers-page-p": "<0>Wie der Name schon sagt, sind Behälter in Escape from Tarkov Gegenstände, die zum Aufbewahren anderer Dinge verwendet werden. Einige dieser Gegenstände werden genutzt, um Inventarplatz freizumachen, da sie als Stauraum dienen und weniger Inventarslots belegen. Einige von ihnen können jedoch nicht am Charakter ausgerüstet werden.", "Glasses": "Brillen", "glasses-page-description": "Diese Seite enthält eine sortiebare Tabelle aller verfügbaren Brillen im Spiel. Inklusive Preis, Reparierbarkeit, Rüstungsklasse und anderen Charakteristiken", "glasses-page-p": "<0>Brillen in Escape from Tarkov können verwendet werden, um die Anzahl der Regentropfen auf dem Bildschirm des Spielers sowie die Dauer von Blendgranateneffekten zu verringern.", "Grenades": "Granaten", "grenades-page-description": "Diese Seite enthält eine sortiebare Tabelle aller verfügbaren Granaten im Spiel. Inklusive Preis, Schaden, und anderen Charakteristiken", "grenades-page-p": "<0>In Escape from Tarkov gibt es nur eine Handvoll verschiedener Granatentypen, die geworfen oder abgeschossen werden können, und jeder hat eine einzigartige Wirkung: Blendgranaten, Rauchgranaten, Sprengstoff und Splittergranaten.<1>Granaten sind situationsabhängig, aber bei richtiger Anwendung können sie tödliche Ergebnisse erzielen. Jeder Vorteil durch hochwertige Ausrüstung kann durch eine einzige gut geworfene Granate vollständig zunichte gemacht werden, sei es durch vollständiges Blenden des Gegners, sofortiges Töten oder Heraustreiben aus der Deckung in dein Feuer.<3>Fünf Faktoren, die beim Einsatz von Wurfgranaten zu beachten sind: Zündzeit, Explosionsradius, Splitterschaden, Splitteranzahl und sogar das Gewicht der Granate.", "Guns": "Waffen", "guns-page-description": "Diese Seite enthält eine sortiebare Tabelle aller verfügbaren Waffen im Spiel. Inklusive Preis, Schaden, Genauigkeit und anderen Charakteristiken", "guns-page-p": "<0>Dein wichtigstes Werkzeug zum Überleben ist eine Waffe. Fast alle Waffen sind vollständig modular aufgebaut und können für verschiedene Szenarien angepasst werden. Alle in Escape from Tarkov verwendeten Waffen sind auf dieser Seite aufgelistet.", "Headsets": "Kopfhörer", "headsets-page-description": "Diese Seite enthält eine sortiebare Tabelle aller verfügbaren Kopfhörer im Spiel. Inklusive Preis, Verfügbarkeit und anderen Charakteristiken", "headsets-page-p": "<0>In Escape from Tarkov verstärken Headsets niederfrequente Geräusche wie Schritte, während sie impulsive Reize wie Schüsse dämpfen. Die verschiedenen Modelle bieten unterschiedliche Audioprofile.", "Helmets": "Helme", "helmet-page-description": "Diese Seite enthält eine sortiebare Tabelle aller verfügbaren Helme im Spiel. Inklusive Preis, Reparierbarkeit, Rüstungsklasse und anderen Charakteristiken", "Show blocking headset": "Zeige blockierende Kopfhörer ", "Min armor class": "Minimale Rüstungsklasse", "helmets-page-p": "<0>In Escape from Tarkov erfüllt Kopfbedeckung verschiedene Funktionen.<1>Es gibt nützliche Gegenstände, kosmetische Items und Schutzhelme. Vor dem Kampf ist die Wahl eines Helms, der verschiedene Teile des Kopfes schützt, entscheidend.<3>Wie stark verschiedene Helme Geräusche dämpfen, ist ein weiterer wichtiger Faktor. Das Gameplay von Escape from Tarkov basiert stark auf Sound.<5>Modulare Helme mit verschiedenen Komponenten sind ein weiterer Aspekt von Escape from Tarkov. Diese Helme können die Anzahl der geschützten Segmente verändern. Die Segmente sind: Oberseite, Nacken, Ohren, Augen und Kiefer.", "items-page-description": "Diese Seite enthält Links zu Seiten mit Informationen zu verschiedenen Gegenstandskategorien inklusive: Rüstung, Rucksäcke, Tauschgegenstände, Behälter, Brillen, Granaten, Waffen, Kopfhörer, Helme, Schlüssel, Waffenmodifikationen, Pistolengriffe, Rigs, Schalldämpfern, und mehr.", "Keys": "Schlüssel", "keys-page-description": "Diese Seite enthält eine sortierbare mit Informationen zu verschiedenen Schlüsseln inklusive: Preis, Seltenheit und anderen Charakteristiken", "keys-page-p": "<0>Karten, Schlüssel, Keycards und andere nützliche Objekte gehören zu den Intelligenz-Gegenständen. Diese helfen dir, der Konkurrenz einen Schritt voraus zu sein – oder zumindest zu wissen, wo du dich in Escape from Tarkov befindest.<1>Die verbleibende Haltbarkeit von Schlüsseln und Keycards mit begrenzter Nutzungsanzahl wird in der unteren rechten Ecke ihrer Icons und auf ihren Inspektionsbildschirmen angezeigt.", "Mods": "Modifikationen", "mods-page-description": "Diese Seite enthält eine sortierbare mit Informationen zu verschiedenen Modifikationen inklusive: Preis, Kompatibilität und anderen Charakteristiken", "mods-page-p": "<0>In Escape from Tarkov werden Leistung und Funktion einer Waffe durch komplexe Mechanismen gesteuert, die in fünf Kategorien unterteilt sind:<1><0>Funktionale Mods<1>Mündungsaufsätze (Funktionale Mods)<2>Visiere (Funktionale Mods)<3>Ausrüstungs-Mods<4>Wichtige Teile", "Pistol Grips": "Pistolen Griffe", "pistol-page-description": "Diese Seite enthält eine sortierbare Tabelle mit Informationen zu verschiedenen Pistollengriffen inklusive: Preis, Kompatibilität, Ergonomie und anderen Charakteristiken", "Filter by gun": "Filter nach Waffe", "select a gun": "Wähle eine Waffe", "pistol-grips-page-p": "<0>In Escape from Tarkov sind Pistolengriffe und Schäfte wichtige Teile einer Waffe.<1>Auf dieser Seite kannst du sie nach Ergonomieverbesserung oder Kosten sortieren und sehen, auf welche Waffe sie montiert werden können.", "Provisions": "Nahrung", "provisions-page-description": "Diese Seite enthält eine sortierbare Tabelle mit Informationen zu verschiedenen Pistollengriffen inklusive: Preis, Hydration, Energie und die Flohmarktpreise", "Total energy cost": "Komplette Energiekosten", "Include the cost of lost hydration in the cost of energy": "Beziehe die Kosten von verlorener Hydration in den Energiekosten ein", "provisions-page-p": "<0>In Escape from Tarkov werden Vorräte verwendet, um Energie und Hydration aufzufüllen.<1>Dein Metabolismus-Skilllevel bestimmt, wie effektiv sie sind.", "Rigs": "Ausrüstung", "rigs-page-description": "Diese Seite enthält eine sortierbare Tabelle mit Informationen zu verschiedenen Ausrüstungen inklusive: Preis, Größe, Gewicht und anderen Charakteristiken", "Armored rigs?": "Gepanzerte Ausrüstung", "Min slots": "Min Slots", "3-slot": "3-Slot", "4-slot": "4-Slot", "rigs-page-p": "<0>Wenn es darum geht, Munition und Magazine während deiner Ausflüge in Escape from Tarkov zu tragen und zu verstauen, sind Chest Rigs entscheidend. Einige bieten dir sogar zusätzlichen Schutz.", "Suppressors": "Schalldämpfer", "suppressors-page-description": "Diese Seite enthält eine sortierbare Tabelle mit Informationen zu verschiedenen Schalldämpfern inklusive: Ergonomie, Rückstoß, und günstigster Preis.", "suppressors-page-p": "<0>In Escape from Tarkov ist ein Schalldämpfer ein Mündungsaufsatz (ein funktionaler Mod) und kann auf einer Waffe installiert werden, um das Schussgeräusch zu dämpfen.<1>Auf dieser Seite kannst du sie nach Ergonomie-Malus, Rückstoßverbesserung oder Kosten sortieren und sehen, auf welche Waffe sie direkt montiert werden können.", "Barters": "Tauschwaren", "Marked": "Markiert", "Wearables": "Tragbare Gegenstände", "loot-tiers-page-description": "Lerne über die verschiedenen Lootgegenstände im Spiel, ihren Wert, Seltenheit und was es zu behalten oder entsorgen gibt.", "Ranking the most valuable items in the game": "Ranking der wertvollsten Gegenstände im Spiel", "Include Marked": "Beziehe Makierte ein", "Group by type": "Gruppiere bei Typ", "min value": "Mindestwert", "Only show markers for active tasks": "Nur Markierungen für aktive Aufgaben anzeigen", "Map of {{mapName}}": "Karte von {{mapName}}", "maps-page-description": "Erhalte die aktuellsten Informationen über Karten in Escape from Tarkov, inklusive Ausgängen und Loot Fundorten. Finde heraus wo es die besten Gegenstände gibt.", "maps-page-p": "<0>Es gibt 11 unterschiedliche Standorte auf der Escape from Tarkov Karte, wovon 10 bis jetzt veröffentlicht wurden. Obwohl alle Standorte letztlich verbunden sein werden, sind sie im Moment voneinander getrennt.", "Streets of Tarkov": "Straßen von Tarkov", "Ground Zero": "Ground Zero", "Customs": "Zollgelände", "Factory": "Fabrik", "Interchange": "Autobahnkreuz", "The Lab": "Das Labor", "Lighthouse": "Leuchtturm", "Reserve": "Reserve", "Shoreline": "Küste", "Woods": "Wälder", "Openworld": "Offene Welt", "Tarkov.dev {{bot}} integration": "Tarkov.dev {{bot}} Integration", "bot-page-description": "Diese Seite enthält alle Informationen um {{bot}} mit Tarkov.dev zu verknüpfen.", "You can add command to your moobot to get price check in your twitch chat": "Du kannst Befehle zu deinem moobot hinzufügen um Preisanfragen in deinem Twitch Chat los zu werden.", "Instructions": "Anleitung", "Register at": "Melde dich an unter", "using your twitch account": "mit deinem Twitch Account", "Go to Custom commands": "Gehe zu individuellen Befehlen", "Set what you want the command to be. Common is \"p\" or \"price\"": "Wie soll der Befehl lauten?. Üblich ist \"p\" oder \"preis\"", "Press the \"Create\" button": "Drücke den \"Create\" Knopf", "In response choose URL Fetch - Full (plain) response": "In Antwort wähle URL Fetch - Full (plain) response", "and after insert \"Command arguments\"": "und nach einfügen \"Command arguments\"", "Now press \"Save\" button": "Drücke den \"Save\" Knopf", "Big thanks to": "Vielen Dank an", "for feedback": "für Feedback", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "Du kannst einen Command zu deinem Nightbot hinzufügen um Preise in deinem Twitch / YouTube Chat zu bekommen.", "using your twitch / youtube account": "und benutze dein Twitch / YouTube Account", "Go to dashboard": "Geh zu dem Dashboard", "Click the \"Join Channel\" button": "Klick auf den \"Kanal beitreten\" Knopf", "Make bot - moderator, just type /mod nightbot in your chat": "Erstelle einen Bot - Moderator, tippe nur /mod nightbot in deinen Chat", "Go to custom commands": "Gehe zu benutzerdefinierde commands", "Press the \"Add command\" button": "Drücke den \"Command hinzufügen\" Knopf", "Command: !p or anything you like": "Command: !p oder was auch immer dir gefällt", "Message:": "Nachricht:", "Press \"Submit\"": "Drücke \"Abschicken\"", "Trader Levels": "Händler Levels", "Trader Reputation": "Händler Reputation", "Prerequisite Tasks": "Erforderliche Aufgaben", "Start Requirements": "Zum Start erforderlich", "Attributes": "Attribute", "Contains All": "Beinhaltet alles", "Contains Item in Category": "Beinhaltet Gegenstand in Kategorie", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Hat die {{effectNames, list}} Effekte auf deine {{bodyParts, list(type: disjunction)}} für {{operator}} {{count}} Sekunden", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Hat die {{effectNames, list}} Effekte auf deine {{bodyParts, list(type: disjunction)}} für {{operator}} {{count}} Sekunden", "using extract: {{extractName}}": "verwende Extraktionspunkt: {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extrahiere mit dem Zustand: {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extrahiere {{extractCount}}-mal mit Status: {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x eines von", "Dogtag level": "Dogtag Level", "Max durability": "Max Haltbarkeit", "Min durability": "Min Haltbarkeit", "Kill": "Kill", "Shoot": "Schießen", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "Zwischen den Stunden: {{hourStart}}:00 und {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "Ab einer Distanz von: {{operator}} {{count}} Meter", "From distance: {{operator}} {{count}} meters_other": "Ab einer Distanz von: {{operator}} {{count}} Meter", "While inside: {{zoneList, list(type: disjunction)}}": "Während in: {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Treffen: {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Mit Waffe:", "Using weapon mods:": "Mit Waffenmodifikationen:", "While wearing:": "Dabei tragen:", "Not wearing:": "Nicht tragen:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Während du den/die {{effectNames, list}} Effekt(e) auf deinem {{bodyParts, list(type: disjunction)}} für {{operator}} {{count}} Sekunden hast", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Während du den/die {{effectNames, list}} Effekt(e) auf deinem {{bodyParts, list(type: disjunction)}} für {{operator}} {{count}} Sekunden hast", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "Während du den/die {{effectNames, list}} Effekt(e) auf deinem {{bodyParts, list(type: disjunction)}} hast", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Während dein Ziel den/die {{effectNames, list}} Effekt(e) auf deinem {{bodyParts, list(type: disjunction)}} für {{operator}} {{count}} Sekunden hat", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Während dein Ziel den/die {{effectNames, list}} Effekt(e) auf deinem {{bodyParts, list(type: disjunction)}} für {{operator}} {{count}} Sekunden hat", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "Während dein Ziel den/die {{effectNames, list}} Effekt(e) auf deren {{bodyParts, list(type: disjunction)}} hat", "Obtain level {{level}} {{skillName}} skill": "Erhalte {{level}} {{skillName}} Fähigkeit", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} Reputation", "In area(s): {{areaList, list(type: disjunction)}}": "In Region(en): {{areaList, list(type: disjunction)}}", "Use any of:": "Verwende einen von:", "Reach level {{playerLevel}}": "Erreiche Level {{playerLevel}}", "optional": "optional", "Trader Standing": "Händler Standing", "Skill Level": "Skill-Level", "Trader Offer Unlock": "Händlerangebot freischalten", "Trader Unlock": "Händler freischalten", "Craft Unlock": "Herstellung freischalten", "task-page-description": "Diese Seite enthält Informationen zu Zielen, Belohnungen und Strategien zum erfüllen der Quest: {{questName}}. Erhalte Tipps um dich vernünftig vorzubereiten und meister die Quest.", "TarkovTracker": "TarkovTracker", "Leads to": "Führt zu", "(on failure)": "(bei Fehler)", "Task Details": "Aufgabendetails", "Objectives": "Ziele", "Fail On": "Schlägt fehl bei", "Needed Keys": "Benötigte Schlüssel", "Task Start": "Quest-Start", "Task Completion": "Aufgabenabschluss", "Rewards": "Belohnungen", "Task Failure": "Aufgabe scheitern", "Can be restarted": "Kann neu gestartet werden", "Cannot be restarted": "Kann nicht neu gestartet werden", "Penalties": "Strafen", "tasks-page-description": "Finde alles heraus über Quests in Escape from Tarkov. Lerne mehr über die verfügbaren Quests, wie du diese abschließt und die Belohnungen die du erhältst.", "Hides completed tasks": "Verstecke abgeschlossene Quests", "Hide locked": "Verstecke gesperrte", "Hides locked tasks": "Verstecke gesperrte Quests", "Show all tasks": "Zeige alle Quests", "Name filter": "Name Filter", "filter on task name": "Filter nach Questname", "quests-page-p": "<0>Händler in Escape from Tarkov haben viele Aufgaben, die du abschließen kannst.<1>Im Austausch für das Holen von Gegenständen, Eliminieren von Zielen und dem Durchführen anderer Aktionen, kannst du einen Ruf mit den Händlern erhöhen und wertvolle Gegenstände bekommen", "Settings": "Einstellungen", "settings-page-description": "Diese Seite beinhaltet deine Benutzereinstellungen auf Tarkov.dev.", "Language": "Sprache", "General": "Allgemein", "Has flea": "Flohmarkt freigeschaltet", "Use TarkovTracker": "Benutze TarkovTracker", "TarkovTracker API Token": "TarkovTracker API Token", "API Token": "API Token", "Stations": "Unterschlupf Stationen", "Skills": "Fähigkeiten", "Dogtag Barters": "Dogtag Tauschgegenstände", "Exclude": "Exkludiere", "Minimum dogtag level": "Mindest Dogtag Level", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Mindest Dogtag Level um die Tauschgegenstände entsprechend zu berechnen", "The current estimated average player level is {{avgPlayerLevel}}": "Aktuell beträgt das durchschnittliche Spieler Level {{avgPlayerLevel}}", "Miscellaneous": "Sonstiges", "Hide remote control": "Verstecke Fernsteuerung Hinweis", "start-page-description": "Erhalte alle Informationen für Gegenstände, herstellbare Gegenstände, Tauschgegenstände, Karten, Loot, Unterschlupf Belohnungen, Händlerinformationen, und mehr. Das alles über die 100% freie Tarkov.dev Open Source API! Ein Community basiertes Projekt um dich in deinem Fortschritt in Escape from Tarkov zu unterstützen.", "Load More": "Mehr laden", "Tools": "Werkzeuge", "Ammo chart filter": "Munitionstabellen Filter", "Traders barter profit": "Tauschgegenstände Profit", "Hideout crafts profit": "Unterschlupf Herstellungen Profit", "Loot tiers ranking": "Loot Ranking", "Average wipe length": "Durchschnittliche Wipe-Länge", "Bitcoin farm profit": "Bitcoinfarm Profit", "Invite Discord bot": "Lade unseren Discord bot ein", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.dev ist ein Open Source Werkzeugkoffer für Escape from Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "Er wird in einer aktiven Community von freiwilligen Entwicklern programmiert und gewartet, um dich in deinem Fortschritt in Escape from Tarkov zu unterstützen! Die API ist zu 100% frei und du kannst deine eigenen Tools und Services darum entwickeln.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "Du kannst einen Befehl zu deinem StreamElements Bot hinzufügen um Preisanfragen in deinem Youtube oder Twitch Chat zu beantworten", "Make bot - moderator, just type /mod streamelements in your chat": "Mache deinen Bot zum Moderator, tippe einfach /mod streamelements in deinen Chat", "Press the \"Add new command\" button": "Drücke den \"Add new command\" Knopf", "Press \"Activate Command\"": "Drücke \"Activate Command\"", "Player level": "Spieler Level", "Reputation": "Reputation", "Commerce": "Handel", "Trader {{trader}}": "Händler {{trader}}", "trader-page-description": "Erhalte die letzten Informationen über den Händler {{trader}} in Escape from Tarkov. Lerne welche Items er ab welchem Level verkauft und maximiere deinen Gewinn.", "Items with the best cash back prices for leveling": "Artikel mit den besten Cashback-Preisen für das Leveln", "Spending": "Ausgeben", "Unlocks at Loyalty Level {{level}}": "Wird freigeschaltet ab LL {{level}}", "Tasks given by {{traderName}}": "Quest von {{traderName}}", "traders-page-description": "Finde alles über Händler in Escape from Tarkov heraus. Lerne mehr über die im Spiel vorhandenen Händler und die Items die sie verkaufen.", "About Traders": "Über Händler", "traders-page-p": "<0>Das Rückgrat des Handels im zerstörten und belagerten Norvinsk. In Escape from Tarkov hat sich jeder Verkäufer auf ein gewisses Gebiet an Produkten spezialisiert, wie zum Beispiel medizinische Versorgung, Waffen oder militärische Ausrüstung. Obwohl die Preise normalerweise hoch sind, bekommst du das wofür du zahlst.<1>Wichtiger ist jedoch, dass du mit jedem Händler durch Aufgaben einen Ruf bei diesen entwickeln kannst, was dir dann unter anderem das Erhalten von besseren Angeboten und geringeren Kommissionen ermöglicht (extra Kosten die du für Käufe und Verkäufe bezahlst).<2>Zusätzlich bieten Händler auch andere Dienstleistungen an, wie Versicherung und Repariermöglichkeiten (erlaubt dir das Bergen von deiner Ausrüstung falls du während eines Raids stirbst).", "Patch": "Patch", "Wipe start": "Wipe Start", "Wipe end": "Wipe Ende", "Ongoing wipe": "Wipe im Gange", "{{count}} days_one": "{{count}} Tag", "{{count}} days_other": "{{count}} Tage", "{{count}} months_other": "{{count}} Monate", "{{count}} years_one": "{{count}} Jahr", "Wipe Length": "Wipe Länge", "wipe-length-description": "Erhalte aktuelle Informationen über die durchschnittliche Wipe-Länge in Escape from Tarkov. Finde heraus wie lange diese durchschnittlich dauern und bereite dich auf den nächsten vor", "Average Wipe Length among last 6 wipes:": "Durchschnittliche Wipe-Länge der letzten 6 Monate:", "cookie-consent": "tarkov.dev verwendet Cookies, um deine Erfahrung zu verbessern. Durch die weitere Nutzung dieser Seite stimmst du der Verwendung von Cookies zu. Cookies werden verwendet, um deine Einstellungen und aktivierten Funktionen zu speichern.", "I understand": "Verstanden", "Other Options": "Andere Optionen", "This task {{taskStatus}}": "Diese Aufgabe {{taskStatus}}", "Slots per kg": "Slots pro kg", "Trader Ammo": "Händler Munition", "Only show ammo available from traders on your settings": "Nur Munition anzeigen, die bei Händlern gemäß deinen Einstellungen verfügbar ist", "Reset": "Zurücksetzen", "Convert one currency to another": "Eine Währung in eine andere umrechnen", "Currency Converter": "Währungsrechner", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Neueste Berichte:", "Switch to {{gameMode}} profile": "Zu {{gameMode}}-Profil wechseln", "control-info-p": "<0>Diese Seite ermöglicht es dir, die Tarkov.dev-Website mit einem anderen Browser zu steuern. Der typische Anwendungsfall ist, die Tarkov.dev-Website in einem Browser auf einem zweiten Monitor geöffnet zu haben, während du das Spiel spielst, und diese Seite auf deinem Handy oder einem anderen Gerät geöffnet zu haben, damit du zu verschiedenen Seiten auf der Tarkov.dev-Website navigieren kannst, ohne aus dem Spiel alt+tabben zu müssen. Alles was du tun musst, ist die Tarkov.dev-Website in einem Browser zu öffnen, wo sie angezeigt werden soll, auf den \"Klicke um zu verbinden\"-Button unten links* zu klicken und dann die dort angezeigte ID auf dieser Seite auf dem Steuergerät zu verwenden und auf Verbinden zu klicken. Sobald verbunden, kannst du diese Steuerungsseite verwenden, um bestimmte Karten- oder Munitionsseiten im gesteuerten Browser zu öffnen.<1>*Standardmäßig erscheint es unten links, kann aber auf die untere rechte Seite des Bildschirms umgeschaltet werden. Es kann auch durch die Option \"Fernsteuerung ausblenden\" auf der Einstellungsseite versteckt werden.", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Stash-Discord-Bot", "More Tools": "Weitere Tools", "Companion app": "Begleit-App", "Discord companion": "Discord-Begleiter", "Download latest release": "Neueste Version herunterladen", "View on GitHub": "Auf GitHub ansehen", "Join the community": "Der Community beitreten", "Screenshot of TarkovMonitor showing timers and integrations": "Screenshot von TarkovMonitor mit Timern und Integrationen", "Visual timers, raid state, and integration health in TarkovMonitor.": "Visuelle Timer, Raid-Status und Integrationszustand in TarkovMonitor.", "Main Features": "Hauptfunktionen", "tarkov-monitor-page-description": "Erfahre, wie du TarkovMonitor installierst, mit TarkovTracker verbindest und damit die Karten auf Tarkov.dev steuerst.", "tarkov-monitor-summary": "TarkovMonitor liefert hilfreiche Warnungen und Timer für Escape From Tarkov, damit du Raids verwalten kannst, ohne das Spiel zu unterbrechen.", "tarkov-monitor-feature-audio": "Audio-Warnungen für Matchmaking, Raidstart, Runthrough-Timer, Scav-Abklingzeit und Luftfilter-Benachrichtigungen.", "tarkov-monitor-feature-map": "Automatisches Öffnen der Karte auf Tarkov.dev basierend auf dem Ort, dem du beitrittst.", "tarkov-monitor-feature-screenshot": "Optionale, durch Screenshots ausgelöste Positionsanzeige für schnelles Teilen des Standorts.", "tarkov-monitor-feature-quests": "Automatische Quest-Updates an TarkovTracker, sobald Abschlüsse erkannt werden.", "tarkov-monitor-feature-stats": "Lokale Statistiken wie Flohmarkt-Einnahmen, Wartezeiten und Kartenhäufigkeit.", "tarkov-monitor-feature-timers": "Sichtbare Timer für Raidzeit und Scav-Abklingzeit, damit du den nächsten Lauf planen kannst.", "Download": "Herunterladen", "tarkov-monitor-download-1": "Lade die neueste TarkovMonitor.zip-Version von GitHub herunter.", "tarkov-monitor-download-2": "Entpacke das Archiv irgendwo auf deinem PC.", "tarkov-monitor-download-3": "Starte TarkovMonitor.exe und lasse es geöffnet, während du spielst.", "Community support": "Community-Support", "tarkov-monitor-community": "Fragen oder Lust auf Austausch? Tritt dem Discord-Server für Tipps, Fehlerbehebung und Feature-Diskussionen bei.", "Join the Discord": "Dem Discord beitreten", "Security": "Sicherheit", "tarkov-monitor-security": "TarkovMonitor ist kein Cheat. Es liest nur die Escape-From-Tarkov-Protokolle auf deinem PC und verändert das Spiel nie oder injiziert Code.", "stash-page-description": "Lade den Stash-Discord-Bot ein, entdecke seine Befehle und sieh, wie er deiner Community helfen kann.", "stash-hero": "Stash bringt den gesamten Tarkov.dev-Datensatz in Discord, damit deine Community Preise, Questfortschritt, Hideout-Timer und mehr prüfen kann, ohne den Chat zu verlassen.", "Invite Stash": "Stash einladen", "Report an issue": "Ein Problem melden", "Highlights": "Highlights", "Item intelligence": "Item-Intelligenz", "Instant prices with flea, trader, and craft context.": "Sofortpreise mit Flohmarkt-, Händler- und Crafting-Kontext.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Craft-/Tausch-Abfragen nutzen die Rentabilitätsdaten von Tarkov.dev erneut.", "Toggle PVE or PMC game modes to match your server rules.": "Schalte zwischen PVE- und PMC-Modus, damit die Bot-Antworten zu euren Serverregeln passen.", "Progress tracking": "Fortschrittsverfolgung", "Quest command lists requirements, turn-ins, and rewards.": "Der Quest-Befehl listet Anforderungen, Abgaben und Belohnungen auf.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "Der Progress-Befehl spiegelt die Hideout- und Händler-Upgrades wider, die du auf TarkovTracker gespeichert hast.", "Restock and status alerts keep everyone informed between raids.": "Restock- und Statusalarme halten alle zwischen den Raids auf dem Laufenden.", "Community tools": "Community-Tools", "Goons tracker for spotting the Rogue Boss trio.": "Goons-Tracker zum Aufspüren des Rogue-Boss-Trios.", "Roulette mini-game for fun raid modifiers.": "Roulette-Minispiel für spaßige Raid-Modifikatoren.", "Slash commands, autocomplete, and localized responses.": "Slash-Befehle, Autovervollständigung und lokalisierte Antworten.", "Frequently used commands": "Häufig genutzte Befehle", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash bietet dutzende Slash-Befehle. Hier sind einige, auf die sich die meisten Server verlassen:", "Command": "Befehl", "Example": "Beispiel", "Support & feedback": "Support & Feedback", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "Du brauchst Datenschutz oder Nutzungsbedingungen für das Sicherheitsreview? Sie liegen im Ordner /assets des Repos und werden bei jeder Version aktualisiert.", "stash-tech-note": "Du brauchst technische Guides oder Selfhosting-Anleitungen? Lies das README auf GitHub für die aktuellste Dokumentation.", "card-tarkov-monitor-desc": "Automatisiere TarkovTracker-Fortschritt, erfasse Warteschlangenzeiten und steuere Tarkov.dev-Karten mit einer einzigen Windows-App.", "card-stash-desc": "Slash-Befehle für Preischecks, Quest-Hilfe, Hideout-Fortschritt und Restock-Timer direkt aus Tarkov.dev.", "Read more": "Mehr erfahren", "Invite now": "Jetzt einladen", "other-tools-page-description": "Entdecke Begleit-Apps des Tarkov.dev-Teams, darunter TarkovMonitor und den Stash-Discord-Bot.", "other-tools-body": "<0>Tarkov.dev ist mehr als eine Website. Diese Tools erweitern deine Raids, Streams und Discord-Communitys mit denselben Open-Source-Daten. Schau dir jedes Tool an, um Screenshots, Anleitungen und Supportlinks zu sehen.", "Learn about TarkovMonitor": "Mehr über TarkovMonitor erfahren", "Meet the Stash bot": "Lerne den Stash-Bot kennen", "The help command to view all available commands": "Der Hilfebefehl, um alle verfügbaren Befehle zu sehen", "View details about the bot": "Details über den Bot anzeigen", "Get a sorted ammo table for a certain ammo type": "Eine sortierte Munitionsliste für einen bestimmten Typ abrufen", "Check barter details for an item": "Tauschdetails für ein Item prüfen", "Get detailed information about a boss": "Ausführliche Informationen zu einem Boss erhalten", "Get the latest game changes from tarkov-changes.com": "Die neuesten Spieländerungen von tarkov-changes.com abrufen", "Check crafting details for an item": "Crafting-Details für ein Item prüfen", "Set the game mode (regular, PVE) for bot responses": "Den Spielmodus (regulär, PVE) für Bot-Antworten festlegen", "Check or report the location of the Goons": "Den Standort der Goons prüfen oder melden", "Get a Discord invite link for the bot to join it to another server": "Einen Discord-Einladungslink erhalten, um den Bot einem anderen Server hinzuzufügen", "Report an issue with the bot": "Ein Problem mit dem Bot melden", "Get price, craft, barter, etc. information about an item": "Preis-, Craft- und Tauschinfos zu einem Item abrufen", "Get a key's price and maps it is used on": "Preis eines Schlüssels und passende Karten anzeigen", "View a map and some general info about it": "Eine Karte und allgemeine Infos anzeigen", "Get the latest official patchnotes for EFT": "Die neuesten offiziellen EFT-Patchnotes abrufen", "Get player profile information": "Spielerprofil-Informationen abrufen", "Get a detailed output on the price of an item, its price tier, and more!": "Einen detaillierten Bericht zu Itempreis, Tier und mehr erhalten!", "Manage your customized hideout and trader progress": "Deinen individuellen Hideout- und Händlerfortschritt verwalten", "Get detailed information about a quest": "Detaillierte Informationen zu einer Quest erhalten", "Show or set alerts for trader restock timers": "Alarme für Händler-Restock-Timer anzeigen oder setzen", "Play a game of roulette to determine how you play your next raid": "Roulette spielen, um deinen nächsten Raid festzulegen", "Get the game/server/website status of Escape from Tarkov": "Status von Spiel/Server/Website von Escape from Tarkov abrufen", "Get information about a in-game stim": "Informationen zu einem Ingame-Stim erhalten", "Show the criteria for loot tiers": "Die Kriterien für Loot-Stufen anzeigen", "Get the bot's uptime": "Die Betriebszeit des Bots abrufen", "stash-support": "<0>Stash wird vom Tarkov.dev-Team gepflegt. Bugs oder Ideen? Erstelle ein Issue auf <1>GitHub oder sprich mit den Entwicklern im <2>Tarkov.dev-Discord. Wenn du Tarkov.dev und Bot-Daten synchronisierst, füge Screenshots und Repro-Schritte hinzu.", "Database": "Datenbank", "Calculators": "Rechner", "Progression": "Fortschritt", "Community": "Community", "Prestige":"Prestige", "Gear":"Ausrüstung", "Weaponry":"Waffen", "Equipment & Tools":"Ausrüstung & Werkzeuge", "Game mode":"Spielmodus", "Connecting...": "Verbinde...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max. Siegesserie", "Best ARP": "Best ARP", "Loss Streak": "Niederlagenserie", "Max Loss Streak": "Max. Niederlagenserie", "Mode": "Modus", "Kills": "Kills", "Deaths": "Tode", "Round MVP": "Runden-MVP", "Match MVP": "Match-MVP", "Team Fight": "Teamkampf", "Last Hero": "Letzter Held", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena-Statistiken", "Arena Mode Stats": "Arena-Modus-Statistiken", "K:D": "K:D", "PMC Kills": "PMC-Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "Keine Hideout-Stationen entsprechen den Filtereinstellungen." } ================================================ FILE: src/translations/en/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Sneaky bois. Cultists lurk in the shadows in groups of 3-5 waiting for a player to approach. They silently approach their enemies and stab them using either normal knives or in case of the priests the poisoned Cultist knife. If fired upon the Cultists will return fire using firearms and grenades. After they attack a player with their knife they may choose to run off into the woods again and return to the shadows.", "knight-bio": "", "knight-description": "The leader of 'The Goons'. Can spawn on many different maps.", "glukhar-bio": "There is no reliable information about his past activities because all documents were either lost or classified, but according to unverified information, he had the rank of petty officer. He participated in combat operations. Knew the fundamentals of tactics and actively used this knowledge in claiming or defending various territories.
    All of his crew, too, appear to be former servicemen. Although now his gang is just a de facto bandit group fighting for resources and influence in Tarkov. He has connections to traders capable of exporting goods from the Norvinsk region, which regularly send him the last working trains for cargo transportation.", "glukhar-description": "Glukhar and his many guards are extremely hostile. It's very unlikely to find success while fighting in any open areas. Small hallways and closed rooms are preferable. Glukhar and his guards are very accurate. Glukhar and his guards will stay near each other at all times and his guards will follow him to wherever he goes.", "kaban-bio": "He once had a small legal business in Tarkov, but was not afraid to use criminal methods of money acquisition. After the general evacuation he remained in the city, and his gang has grown. ", "kaban-description": "His size allows him to fire various heavy machine guns without resting the gun, but at the same time Kaban cannot afford to be mobile and therefore either stays in position or moves slowly from point to point during combat. He has a large number of well-armed guards, some of whom are former military men who have organized a strong defense for him. The boss dwells in the area of the car repair shop on \"Streets of Tarkov\". The area is heavily defended, entrances are fortified with stationary machine guns and AGS, the paths are mined, and there are snipers on the roof of the car service center. Kaban uses a custom rig to store machine gun boxes, wears body armor under his clothes, and has unquestionable authority among his guards. Scavs nearby help the boss with defense and will engage in combat for Kaban.", "killa-bio": "", "killa-description": "The true Giga Chad of Tarkov. Killa uses a light machine gun or other automatic weapon to suppress the enemy while lurking from cover to cover getting closer to his target for the final push. During the assault he moves in a zig-zag pattern uses smoke and fragmentation grenades and relentlessly suppresses enemies with automatic fire. He will follow his target large distances out of his patrol route so be sure to run very far to get away from him if he has locked onto you.", "kollontay-bio": "He is a former officer of the MVD (Ministry of Internal Affairs), during his service in law enforcement he had a reputation as a vile man, whose behavior was sometimes feared by his coworkers. During his work, he often resorted to his favorite method of interrogation - a rubber baton, as well as other non-statutory pressure on someone who was not to his liking. Thanks to his physical strength and bold temperament, after the events of the TerraGroup scandal, he formed a gang and began to do what he himself was recently supposed to combat - looting and banditry. However, even before the conflict, he often provided protection to local \"businessmen\". For example, his good relations with Kaban are well-known.", "kollontay-description": "Kollontay has a small number of guards, prefers to stay in one position and occasionally patrols his territory. If he feels he has the upper hand, he may switch to his police baton. He lives in the area around Klimov Shopping Mall and the Tarkov Academy of the Ministry of Internal Affairs.", "partisan-bio": "There are few reliable details about his past, but it's known that he once served in Afghanistan, where his radical methods of warfare took root. Referred to by some as 'Partizan', he became notorious for his expertise in setting traps and mines. His reputation for eliminating enemies often came down to catching them off guard, using their overconfidence against them. Partizan's knowledge of guerrilla tactics made him a dangerous adversary, able to turn any location—whether forest or building—into a deadly trap.
    Those who survive long enough to learn his ways may just find themselves in his good graces, but only if they're careful enough to see the traps before it's too late.", "partisan-description": "", "raider-bio": "", "raider-description": "Scav raiders (also known as just 'raiders') are advanced Scavs that are considerably stronger and more tactical than your typical Scavs. They carry significantly more dangerous weapons and use higher tier ammunition. Additionally they have much better aim and can frequently drop well geared players with only a few bullets (or you just get head-eyes'd). Scav raiders also patrol in multiple groups and can usually be distinguished by their gear unique voicelines and general aggression. Scav Raiders start out friendly to all other Scavs (including player scavs) but they will become hostile if you get to close and ignore their verbal warnings. They will also become hostile to all Scavs if any Scav angers them.", "reshala-bio": "", "reshala-description": "He will normally try to stay at the back of the fight and hidden from the player's view. Additionally he never wears armor. Be careful as a player scav as if you are at lower scav karma levels Reshala or his guards may shoot you without provocation or will shoot you if you come to close to Reshala. His guards are sometimes known to give warnings to player scavs with low karma before becoming hostile.", "rogue-bio": "", "rogue-description": "Rogues defend the water treatment plant and surrounding areas on Lighthouse. Their primary behavior is patrolling but they will often take defensive positions on rooftops and use emplaced weapons. They will target all players who enter their area but are slightly more lenient towards USEC PMCs and Scavs. Rogues are extremely dangerous due to their high health, laserbeam accuracy and high targeting distance. Rogues will also run behind cover and use meds if they are wounded.", "sanitar-bio": "A former doctor and scientist. Worked for TerraGroup. He led several projects in the laboratory, including the development of new psychoactive substances. The area of research extended from the influence of various conditions on the body to developing neurostimulants. Besides the TerraGroup laboratory, he had his own office at the Azure Coast Sanatorium, where he also conducted research, especially during the last weeks before the full evacuation.
    Often went on detached duty to hot zones along with the medical corps, and after starting work for the corporation, he regularly visited African and other offices, supervising developments. He has earned unquestioned authority and respect among colleagues.", "sanitar-description": "When engaged in combat he will fight alongside his fellow scavs and guards but may often break away to heal or inject himself. He has plenty of meds so a prolonged engagement is possible.", "shturman-bio": "", "shturman-description": "Shturman and his followers will engage the player at a long range protecting the sawmill area of the woods. They prefer to keep their distance as they are not suited for close quarters combat.", "tagilla-bio": "", "tagilla-description": "He is batshit insane and will attempt to hammer you down. However if you are in a position that he cannot path-find to such as the rafters he will use his secondary weapon (usually a shotgun) to kill you from a distance. He's active immediately at the start of raid. The boss can set ambushes open suppressive fire and breach if needed.", "zryachiy-bio": "One of Tarkov's most mysterious figures. Virtually nothing is known about his past, except that he has sniper training and is remotely rumored to have been in hot zones in the Middle East and Africa many times.
    Long before the conflict, he became Lightkeeper's loyal lapdog and took an active part in \"establishing\" connections between Lightkeeper and all those with whom he interacted. He is known to be friendly with the Rogue group, as well as with the hooded men who draw mysterious symbols on the locations.
    Zryachiy is very taciturn, though those who work with him usually understand him without words. There are many rumors about his eyes, some say that it is an inborn peculiarity, some point to certain eye drops that allow him to enhance his vision in the dark, giving his eyes this whiteness side effect. Despite the appearance, it seems that he earned his name precisely for his excellent eyesight, which is not surprising for a former military sniper.", "zryachiy-description": "Lightkeeper's cultist guard." } ================================================ FILE: src/translations/en/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Interactive", "Landscape": "Landscape", "View Fullscreen": "View Fullscreen", "Exit Fullscreen": "Exit Fullscreen", "Satellite": "Satellite", "Abstract": "Abstract", "Levels": "Levels", "1st Floor": "1st Floor", "2nd Floor": "2nd Floor", "3rd Floor": "3rd Floor", "4th Floor": "4th Floor", "5th Floor": "5th Floor", "Underground": "Underground", "Garage": "Garage", "Tunnels": "Tunnels", "Bunkers": "Bunkers", "Spawns": "Spawns", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "Sniper Scav", "Boss": "Boss", "Extracts": "Extracts", "Shared": "Shared", "Hazards": "Hazards", "Usable": "Usable", "Locks": "Locks", "Stationary Gun": "Stationary Gun", "Lever": "Lever", "Switch": "Switch", "Door": "Door", "Container": "Container", "Car Door or Trunk": "Car Door or Trunk", "Lock": "Lock", "Activated by": "Activated by", "Activates": "Activates", "Needs power": "Needs power", "Lootable Items": "Lootable Items", "Tasks": "Tasks", "Item": "Item", "Objective": "Objective", "Misc": "Misc", "openworld-name": "Openworld", "openworld-description": "This is an imagination of what the full map of Tarkov could look like. This open world map would likely include all of the key locations from the existing maps combined in a huge single map.", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "Use TarkovMonitor to show your position", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/en/properties.json ================================================ { "ambientVolume": "Ambience", "caliber": "Caliber", "damage": "Damage", "distanceModifier": "Distance", "distortion": "Distortion", "projectileCount": "Projectile count", "penetrationPower": "Penetration power", "armorDamage": "Armor damage", "fragmentationChance": "Fragmentation chance", "ammoType": "Ammo type", "class": "Class", "material": "Material", "zones": "Zones", "defaultPreset": "Default Preset", "durability": "Durability", "ergoPenalty": "Ergo penalty", "speedPenalty": "Speed penalty", "turnPenalty": "Turn penalty", "headZones": "Head zones", "capacity": "Capacity", "grids": "Grids", "energy": "Energy", "hydration": "Hydration", "units": "Units", "stimEffects": "Stim effects", "blindnessProtection": "Blindness protection", "fuse": "Fuse", "maxExplosionDistance": "Max explosion distance", "fragments": "Fragments", "deafening": "Deafening", "blocksHeadset": "Blocks headset", "ricochetY": "Ricochet chance", "uses": "Uses", "malfunctionChance": "Malfunction chance", "ergonomics": "Ergonomics", "recoil": "Recoil", "loadModifier": "Load modifier", "ammoCheckModifier": "Ammo check modifier", "useTime": "Use time", "cures": "Cures", "hitpoints": "Hitpoints", "maxHealPerUse": "Max heal per use", "hpCostLightBleeding": "Hp cost light bleeding", "hpCostHeavyBleeding": "Hp cost heavy bleeding", "painkillerDuration": "Painkiller duration", "energyImpact": "Energy impact", "hydrationImpact": "Hydration impact", "recoilVertical": "Recoil vertical", "recoilHorizontal": "Recoil horizontal", "zoomLevels": "Zoom levels", "minLimbHealth": "Min limb health", "maxLimbHealth": "Max limb health", "effectiveDistance": "Effective distance", "fireModes": "Fire modes", "fireRate": "Fire rate", "sightingRange": "Sighting range", "defaultWidth": "Default width", "defaultHeight": "Default height", "defaultErgonomics": "Default ergonomics", "defaultRecoilVertical": "Default recoil vertical", "defaultRecoilHorizontal": "Default recoil horizontal", "defaultWeight": "Default weight", "recoilModifier": "Recoil modifier", "weight": "Weight", "baseItem": "Base Item", "categories": "Categories", "type": "Type", "convergence": "Convergence", "cameraRecoil": "Camera Recoil", "recoilAngle": "Recoil Angle", "recoilDispersion": "Recoil Dispersion", "usedOnMaps": "Used on Maps" } ================================================ FILE: src/translations/en/translation.json ================================================ { "No data": "No data", "Current Average Latency": "Current Average Latency", "API Latency in milliseconds": "API Latency in milliseconds", "No barters found for this item": "No barters found for this item", "LL{{level}}": "LL{{level}}", "Barter at {{trader}}": "Barter at {{trader}}", "Craft at {{station}}": "Craft at {{station}}", "Barter": "Barter", "Craft at {{stationName}} {{stationLevel}}": "Craft at {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Provides {{count}} for {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Provides {{count}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Reward": "Reward", "Cost": "Cost", "Cost ₽": "Cost ₽", "Estimated savings": "Estimated savings", "InstaProfit": "InstaProfit", "N/A": "N/A", "Barter cost": "Barter cost", "No barters available for selected filters": "No barters available for selected filters", "No barters available for selected filters but some were hidden by ": "No barters available for selected filters but some were hidden by ", "your settings": "your settings", "Some barters hidden by ": "Some barters hidden by ", "Can hold:": "Can hold:", "Can't hold:": "Can't hold:", "Level": "Level", "Flea Market": "Flea Market", "Flea banned": "Flea banned", "Sell price": "Sell price", "Flea Market fee": "Flea Market fee", "Duration": "Duration", "Finishes": "Finishes", "Start now": "Start now", "Flea throughput/h": "Flea throughput/h", "Estimated profit": "Estimated profit", "Estimated profit/h": "Estimated profit/h", "No crafts available for selected filters": "No crafts available for selected filters", "No crafts available for selected filters but some were hidden by ": "No crafts available for selected filters but some were hidden by ", "Some crafts hidden by ": "Some crafts hidden by ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "All options already selected", "Clear selection": "Clear selection", "This item can't be sold on the Flea Market": "This item can't be sold on the Flea Market", "Not scanned on the Flea Market": "Not scanned on the Flea Market", "Flea market prices loading": "Flea market prices loading", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>The whole platform is open source and focused around developers. All code is available on <1><0> GitHub.", "about-discord-p": "<0>If you wanna have a chat, ask questions or request features, we have a <1><0> Discord server.", "about-x-p": "<0>Follow us on <1><0> X for all the latest updates.", "About": "About", "Contributors": "Contributors", "Massive thanks to all the people who help build and maintain this project!": "Massive thanks to all the people who help build and maintain this project!", "Made with ❤️ by:": "Made with ❤️ by:", "Supporters": "Supporters", "about-support-ukraine-p": "<0>We encourage everyone who can to donate to support the people of Ukraine using the button below.", "about-support-collective-p": "<0>If you'd also like to support this project, you can make a donation and/or become a backer on <1>Open Collective.", "Item Data": "Item Data", "Fresh EFT data courtesy of": "Fresh EFT data courtesy of", "Additional data courtesy of": "Additional data courtesy of", "Resources": "Resources", "Tarkov.dev API": "Tarkov.dev API", "{{bot}} integration": "{{bot}} integration", "Discord bot for your Discord": "Discord bot for your Discord", "External resources": "External resources", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.", "version": "version", "PMC & Scav Thorax HP": "PMC & Scav Thorax HP", "Reshala Thorax HP": "Reshala Thorax HP", "Raider Thorax HP": "Raider Thorax HP", "Shturman Thorax HP": "Shturman Thorax HP", "Cultist Priest Thorax HP": "Cultist Priest Thorax HP", "Cultist Warrior Thorax HP": "Cultist Warrior Thorax HP", "Damage": "Damage", "Class {{tier}}": "Class {{tier}}", "Penetration": "Penetration", "Filter by caliber": "Filter by caliber", "This item can only be sold to trader": "This item can only be sold to trader", "per slot": "per slot", "Value": "Value", "Per slot": "Per slot", "Sell to": "Sell to", "Found In Raid": "Found In Raid", "Search item...": "Search item...", "Search task...": "Search task...", "Tasks": "Tasks", "Items": "Items", "No hideout modules requires this item": "No hideout modules requires this item", "No unbuilt hideout modules for selected filters but some were hidden by ": "No unbuilt hideout modules for selected filters but some were hidden by ", "Hideout Module": "Hideout Module", "Item": "Item", "Amount": "Amount", "Player level: {{playerLevel}}": "Player level: {{playerLevel}}", "Reputation: {{reputation}}": "Reputation: {{reputation}}", "Commerce: {{commerce}}": "Commerce: {{commerce}}", "Cheapest Price": "Cheapest Price", "Task: {{taskName}}": "Task: {{taskName}}", "Flea Market not available": "Flea Market not available", "No trader offers available": "No trader offers available", "Loading...": "Loading...", "Ammo": "Ammo", "Maps": "Maps", "More": "More", "Traders": "Traders", "Prapor": "Prapor", "Therapist": "Therapist", "Skier": "Skier", "Peacekeeper": "Peacekeeper", "Mechanic": "Mechanic", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "Bosses", "Barter profit": "Barter profit", "Hideout profit": "Hideout profit", "Loot tiers": "Loot tiers", "Hideout build costs": "Hideout build costs", "Wipe length": "Wipe length", "Bitcoin Farm Profit": "Bitcoin Farm Profit", "Achievements": "Achievements", "API": "API", "Donate": "Donate", "Become a patron": "Become a patron", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "has alternates", "On Task Completion": "On Task Completion", "On Task Start": "On Task Start", "Task": "Task", "Required items": "Required items", "Reward items": "Reward items", "Required tasks": "Required tasks", "loading": "loading", "active": "active", "succeeded": "succeeded", "complete": "complete", "failed": "failed", "Minimum level": "Minimum level", "Minimum trader level": "Minimum trader level", "Reputation rewards": "Reputation rewards", "Endgame": "Endgame", "Required for Kappa": "Required for Kappa", "Required for Lightkeeper": "Required for Lightkeeper", "Kappa": "Kappa", "Lightkeeper": "Lightkeeper", "No quests found": "No quests found", "Some tasks hidden by filter settings": "Some tasks hidden by filter settings", "open this page in another browser or window and connect using this id": "open this page in another browser or window and connect using this id", "ID for remote control": "ID for remote control", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Go to Tarkov.dev with another browser and enter this ID to control this page from there", "Click to connect": "Click to connect", "Sell value": "Sell value", "Tarkov server status": "Tarkov server status", "This item can't be sold to traders": "This item can't be sold to traders", "Name": "Name", "Sell to Flea": "Sell to Flea", "Buy on Flea": "Buy on Flea", "Sell to Trader": "Sell to Trader", "Trader buy": "Trader buy", "Buyback ratio": "Buyback ratio", "The percent recovered if you buy this item and sell it to the trader": "The percent recovered if you buy this item and sell it to the trader", "Grid": "Grid", "Slots occupied": "Slots occupied", "Slots inside": "Slots inside", "Slots ratio": "Slots ratio", "Price per slot": "Price per slot", "Armor class": "Armor class", "Zones": "Zones", "Max Durability": "Max Durability", "Effective Durability": "Effective Durability", "Repairability": "Repairability", "Weight (kg)": "Weight (kg)", "Stats": "Stats", "Mov/Turn/Ergo": "Mov/Turn/Ergo", "Caliber": "Caliber", "Armor damage": "Armor damage", "Fragmentation chance": "Fragmentation chance", "Blindness protection": "Blindness protection", "Hydration": "Hydration", "Energy": "Energy", "Hydration Cost": "Hydration Cost", "Energy Cost": "Energy Cost", "Hydration + Energy Value": "Hydration + Energy Value", "Sound suppression": "Sound suppression", "Low": "Low", "None": "None", "Blocks earpiece": "Blocks earpiece", "Yes": "Yes", "No": "No", "Ergonomics": "Ergonomics", "Cost per ergo": "Cost per ergo", "Recoil": "Recoil", "Distance": "Distance", "No items": "No items", "Not built": "Not built", "Locked": "Locked", "Crafting": "Crafting", "Hideout Management": "Hideout Management", "Be the first!": "Be the first!", "Objective": "Objective", "No objectives": "No objectives", "Players": "Players", "By": "By", "Restock in": "Restock in", "Support Ukraine": "Support Ukraine", "Cost per unit": "Cost per unit", "About the tarkov.dev project": "About the tarkov.dev project", "about-page-description": "Learn more about the-hideout and tarkov.dev. A free, community made, open source Escape from Tarkov ecosystem! Use our tools to help you play the game, or build your own projects with our free API.", "Open source": "Open source", "Discussions & feedback": "Discussions & feedback", "Support": "Support", "about-support-more-p": "<0>You can also help by posting bugs, suggesting or implementing new features, improving maps or anything else you can think of that would improve the site.", "about-api-p": "<0>We offer a 100% free and publically accessible API for all your Tarkov development needs - <1>API.", "History": "History", "about-history-p": "<0>This project is a fork of <1>tarkov-tools.com. The original creator <3>@kokarn decided to shut the site down. In the spirit of open source, a group of developers came together to revive the site in order to continue providing a great website for the Tarkov community and an API to power further development for creators. This project is now 100% open source and developer first. Our GitHub Organization (<5>the-hideout) contains all the repos which power the API, this website, the community Discord bot, server infrastructure, and much more! We are passionate about open source and love pull requests to improve our ecosystem for all.", "Core Contributors": "Core Contributors", "about-core-contributors-p": "<0>The core contributors to this project (in no particular order) are:", "All Contributors": "All Contributors", "about-all-contributors-p": "<0>Massive thank you to all the people that have contributed to this project to make it possible! ❤️", "Description": "Description", "Hidden": "Hidden", "Player %": "Player %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "This page includes information on the achievements that can be earned.", "Ammo chart": "Ammo chart", "ammo-page-description": "This page contains a list of every type of ammo in Escape from Tarkov. To filter the complete list of available cartridges, click the name of a caliber.", "ammo-page-p": "<0>The wilderness of Tarkov includes a diverse range of ammunition. To combat different opponents, different types of ammunition are needed.<1>This page contains a list of every type of ammo in Escape from Tarkov. To filter the complete list of available cartridges, click the name of a caliber.", "Total damage": "Total damage", "Use total damage of all projectiles in a round": "Use total damage of all projectiles in a round", "Ignore settings": "Ignore settings", "Shows all sources of items regardless of your settings": "Shows all sources of items regardless of your settings", "Use barters for item sources": "Use barters for item sources", "Use crafts for item sources": "Use crafts for item sources", "Ammo Statistics Table": "Ammo Statistics Table", "API Documentation": "API Documentation", "api-docs-page-description": "Escape from Tarkov's community made API and its documentation. Learn more about our free and easy to use GraphQL API for EFT.", "api-about-p": "<0>The API is written in GraphQL and we try our hardest to follow spec and not to make breaking changes. To learn about what queries you can make and how the schema is structured, visit the playground and read the documentation by clicking the book icon in the upper left corner. Once you're ready to try some queries, you can also test them out in the playground. To learn about GraphQL queries generally, the GraphQL Foundation has helpful resources.<1><0><0>Tarkov.dev GraphQL playground<1><0>GraphQL Foundation resources<1>Once you're ready to send API queries from outside the playground, the endpoint is: <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Current API Performance", "api-performance-p": "<0>For full API metrics and performance, check out our <1>status page.", "FAQ": "FAQ", "Is it free?": "Is it free?", "Is it open source?": "Is it open source?", "api-faq-open-source-p": "Of course! The source code for the API can be found in its GitHub repo: <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "Is there a rate limit?", "api-faq-rate-limit-p": "We occasionally get hit with a lot of traffic from bad actors that requires implementing rate limits. Price data is updated every 5 minutes, so there's really no need to query faster than that. Use common sense, and you should be fine.", "What about caching?": "What about caching?", "api-faq-caching-p": "Since our data is updated every 5 minutes, we also cache all GraphQL queries for 5 minutes as well. This helps to greatly reduce the load on our servers while making your requests speedy quick!", "Where is the data from?": "Where is the data from?", "We source data from multiple places to build an API as complete as possible. We use data from:": "We source data from multiple places to build an API as complete as possible. We use data from:", "Our network of scanners": "Our network of scanners", "Examples": "Examples", "example": "example", "Contributed by": "Contributed by", "API Users": "API Users", "api-users-page-description": "This page contains a list of all users of public API on Tarkov.dev and their projects.", "api-users-p": "<0>Want to be included on this page? Join the <1>Discord and tell us about what you've made!", "Barter Profits": "Barter Profits", "barters-page-description": "This page includes information on the different items that can be traded with NPC vendors, the barter prices, and the profits that can be made from selling the items.", "Shows all barters regardless of your settings": "Shows all barters regardless of your settings", "Hide dogtags": "Hide dogtags", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters", "Show all barters": "Show all barters", "All": "All", "Item filter": "Item filter", "filter on item": "filter on item", "barters-page-p": "<0>Except for Fence, every trader in Escape from Tarkov offers goods by barter rather than for purchase outright.<1>In exchange for a variety of inexpensive things, the player can frequently trade them for more valuable objects that can be utilized or sold for a profit. These transactions sometimes allow players to obtain gear and items that are usually only purchasable at higher loyalty levels.<3>Be sure to check back after each reset for your favorite offers because the majority of these valued trades have strict limits per trader reset and frequently sell out.", "Num graphic cards": "Num graphic cards", "Hours": "Hours", "Bitcoin Farm Calculator": "Bitcoin Farm Calculator", "bitcoin-farm-calculator-page-description": "This page includes a calculator tool that helps you determine the price of building and maintaining a Bitcoin Farm, based on the number of GPUs, electricity costs, and bitcoin cost.", "Graphic cards count": "Graphic cards count", "Use fuel cost: {{price}}/day": "Use fuel cost: {{price}}/day", "Use station build costs": "Use station build costs", "Purchase cost": "Purchase cost", "Remaining days in wipe:": "Remaining days in wipe:", "Time to produce 1 bitcoin": "Time to produce 1 bitcoin", "BTC/day": "BTC/day", "Estimated profit/day": "Estimated profit/day", "Profitable after days": "Profitable after days", "Total cost of graphic cards": "Total cost of graphic cards", "Build costs": "Build costs", "GPU + build costs": "GPU + build costs", "Remaining profit": "Remaining profit", "Map": "Map", "Spawn Location": "Spawn Location", "Chance": "Chance", "Count": "Count", "Spawn chance": "Spawn chance", "Chance that the boss spawns on a given map": "Chance that the boss spawns on a given map", "Health": "Health", "Total boss health": "Total boss health", "Patrol": "Patrol", "Rush": "Rush", "Stalker": "Stalker", "Hostile and accurate": "Hostile and accurate", "Patrol and highly armored": "Patrol and highly armored", "Group patrol": "Group patrol", "Frequent healing and stim injections": "Frequent healing and stim injections", "Sniper": "Sniper", "Batshit insane": "Batshit insane", "Behavior": "Behavior", "The boss's general AI behavior": "The boss's general AI behavior", "Wiki": "Wiki", "Boss Stats": "Boss Stats", "Special Boss Loot": "Special Boss Loot", "Spawn Locations": "Spawn Locations", "boss-spawn-table-description": "<0>Map: The name of the map which the boss can spawn on<1>Spawn Location: The exact location on the given map which the boss can spawn<2>Chance: If the \"Spawn Chance\" is activated for the map, this is the estimated chance that the boss will spawn at a given location on that map", "Boss Escorts": "Boss Escorts", "This boss does not have any escorts": "This boss does not have any escorts", "boss-page-description": "This page includes information on {{bossName}} location, loot, and strategies for defeating him.", "bosses-page-description": "This page includes information on all the bosses in the game, their location, loot, escort and strategies for defeating them.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov", "About Bosses": "About Bosses", "bosses-page-p": "<0>In Escape from Tarkov, there are many bosses that roam the area of besieged Norvinsk.<1>Each boss has unique behaviours, characteristics, and tactics. The bosses in Tarkov are feared by players of all levels and will often pose as a greater threat than enemy PMCs in the region.<2>However, with high risk comes high reward. Many bosses contain high tier loot items or are required to eliminate for quests. Learning the patterns, locations, and distinct attire of a boss is often the best a player can prepare themselves when a fight begins against a boss in Tarkov.", "Connect": "Connect", "Connected to": "Connected to", "id to control": "id to control", "Remote Control": "Remote Control", "remote-control-page-description": "This page contains all the necessary tools to remote control another instance of Tarkov.dev website.", "View Map": "View Map", "Go": "Go", "View caliber": "View caliber", "Select...": "Select...", "Load tarkov.dev in another browser or window to control it from here": "Load tarkov.dev in another browser or window to control it from here", "Hideout Crafts": "Hideout Crafts", "crafts-page-description": "This page includes information on the different items that can be crafted in the hideout, the materials and resources required, and the profits that can be made from selling the finished products.", "Shows all crafts regardless of your settings": "Shows all crafts regardless of your settings", "Average prices": "Average prices", "Use average prices from the past 24 hours for profit calculations": "Use average prices from the past 24 hours for profit calculations", "Most profitable craft in each station": "Most profitable craft in each station", "Best": "Best", "Flea Market banned items": "Flea Market banned items", "Empty fuel": "Empty fuel", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.", "crafts-page-p": "<0>In Escape from Tarkov, crafts allow you to create a variety of things. It is accomplished using a variety of hideout modules, including the water collector, workbench, medstation, lavatory, and nutrition unit.<1>The \"Found in Raid\" status will be applied to each item created in the hideout. The entire list of these crafts is shown above. The Crafting skill has an impact on item creation time.<2>When an item's icon has a blue border, it will be utilized as an auxiliary tool and, once manufacturing is finished, it will be returned to your stash.", "Page not found": "Page not found", "error-page-description": "This is not the page you are looking for", "Sorry, that page doesn't exist!": "Sorry, that page doesn't exist!", "Hideout": "Hideout", "hideout-page-description": "This page includes information on the different stations and modules that can be built with the materials and resources required to upgrade your hideout.", "Show all stations & modules": "Show all stations & modules", "Show built": "Show built", "Show already built stations": "Show already built stations", "Show locked": "Show locked", "Show unavailable stations": "Show unavailable stations", "Show all requirements": "Show all requirements", "Show trader and other station level requirements": "Show trader and other station level requirements", "Collected": "Collected", "Item Tracker": "Item Tracker", "Only show Found in Raid": "Only show Found in Raid", "Reset all tracking": "Reset all tracking", "Hide completed": "Hide completed", "Hide tasks you've completed": "Hide tasks you've completed", "Hide dogtag barters": "Hide dogtag barters", "Best price to sell for": "Best price to sell for", "Fee": "Fee", "Profit": "Profit", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.", "Max price to sell for": "Max price to sell for", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.", "Likely sell price": "Likely sell price", "item-page-description": "This page includes information on the characteristics, uses, and strategies for {{itemName}}.", "Sell for": "Sell for", "Buy for": "Buy for", "Flea price history": "Flea price history", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "Lowest scanned price last 24h: {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Highest scanned price last 24h: {{high24hPrice}}", "Updated: {{val, relativetime}}": "Updated: {{val, relativetime}}", "Items contained in {{itemName}}": "Items contained in {{itemName}}", "Barters with {{itemName}}": "Barters with {{itemName}}", "Crafts with {{itemName}}": "Crafts with {{itemName}}", "Hideout modules needing {{itemName}}": "Hideout modules needing {{itemName}}", "Shows all modules regardless of your settings": "Shows all modules regardless of your settings", "Quests requiring {{itemName}}": "Quests requiring {{itemName}}", "Quests rewarding {{itemName}}": "Quests rewarding {{itemName}}", "Armors": "Armors", "armors-page-description": "This page includes a sortable table with information on the different types of armor available in the game, including their price, repairability, armor class, and other characteristics.", "Class effective durability": "Class effective durability", "Include rigs": "Include rigs", "Max price": "Max price", "max price": "max price", "armors-page-p": "<0>In the video game Escape from Tarkov, armor vests are worn to lessen bullet damage. Helmets are typically used in addition to them.", "Backpacks": "Backpacks", "backpacks-page-description": "This page includes a sortable table with information on the different types of backpacks available in the game, including their price, size, capacity, and other characteristics.", "Net price per slot": "Net price per slot", "Show price per additional slot of storage gained from the container": "Show price per additional slot of storage gained from the container", "backpacks-page-p": "<0>Backpacks in the Escape from Tarkov game are various-sized containers for carrying your hard-earned riches.", "Barter Items": "Barter Items", "barter-items-page-p": "<0>This table of barter items from Escape from Tarkov will make it simple for you to determine how much each one is worth. It can be challenging to determine which products are valuable enough to take because there are over 150 barter items in the game, and flea market pricing can fluctuate suddenly. You may optimize your loot with the aid of this interactive table.", "bsg-category-description": "Find out everything you need to know about {{category}} in Escape from Tarkov.", "Containers": "Containers", "containers-page-p": "<0>As their name implies, containers in Escape from Tarkov are items used to hold other things. Some of these items are used to clear up inventory space by acting as storage and taking up less inventory slots however some of them cannot be equipped on the character.", "Glasses": "Glasses", "glasses-page-description": "This page includes a sortable table with information on the different types of glasses available in the game, including their price, armor class, and other characteristics.", "glasses-page-p": "<0>Eyewear in Escape from Tarkov can be used to decrease the number and quantity of raindrops on the players' screens as well as the length of flashbang effects.", "Grenades": "Grenades", "grenades-page-description": "This page includes a sortable table with information on the different types of grenades available in the game, including their price, damage, and other characteristics.", "grenades-page-p": "<0>There are only a handful distinct types of grenades that may be thrown or launched in Escape from Tarkov, and each one has a unique effect: flash, smokes, high explosive, and fragmentation.<1>Grenades are situational, but when utilized properly, they can have deadly results. Any advantage from high-tier equipment can be fully negated by a single well-thrown grenade, whether it completely blinds the adversary, kills them instantly, or forces them out of cover and into your gunfire.<3>Five factors to think about while using throwable grenades include the fuse time, explosion radius, fragment damage, fragment count, and even the weight of the grenade. With specific uses arising from each component.", "Guns": "Guns", "guns-page-description": "This page includes a sortable table with information on the different types of guns available in the game, including their price, damage, accuracy, and other characteristics.", "guns-page-p": "<0>Your main tool for survival is a weapon. Almost all weapons are completely modular, allowing them to be customized for various scenarios. All of the weaponry used in Escape from Tarkov are listed on this page.", "Headsets": "Headsets", "headsets-page-description": "This page includes a sortable table with information on the different types of headsets available in the game, including their price, availability, and other characteristics.", "headsets-page-p": "<0>In Escape from Tarkov, headsets magnify low-frequency noises like footsteps while muzzling impulsive stimuli like gunshots. Different audio profiles are offered by the various models.", "Helmets": "Helmets", "helmet-page-description": "This page includes a sortable table with information on the different types of helmets available in the game, including their price, armor class, and other characteristics.", "Show blocking headset": "Show blocking headset", "Min armor class": "Min armor class", "helmets-page-p": "<0>In Escape from Tarkov, headgear serves a variety of functions.<1>There are useful objects, vanity items, and safety headgear. Before entering combat, choosing a helmet that will protect different parts of the head becomes crucial.<3>The impact that different helmets will have on how much sound they suppress is another crucial factor to take into account. Escape from Tarkov's gameplay heavily relies on sound.<5>Modular helmets, which have an assortment of different components, are another aspect of Escape from Tarkov. These helmets may modify the number of segments they protect. Top, Nape, Ears, Eyes, and Jaws are the segments.", "items-page-description": "This page includes links to pages with information on different item categories, including armor, backpacks, barter items, containers, glasses, grenades, guns, headsets, helmets, keys, gun mods, pistol grips, provisions, rigs, suppressors, and more.", "Keys": "Keys", "keys-page-description": "This page includes a sortable table with information on the different types of keys available in the game, including their price, rarity, and other characteristics.", "keys-page-p": "<0>Maps, keys, key cards, and other useful objects are included in intelligence items. These will help you stay one step ahead of the competition—or at the very least, know where you are in Escape from Tarkov.<1>The remaining durability of keys and keycards with a limited number of uses is displayed in the bottom right corner of their icons and on their inspection screens.", "Mods": "Mods", "mods-page-description": "This page includes a sortable table with information on the different types of gun mods available in the game, including their price, compatibility, and other characteristics.", "mods-page-p": "<0>In Escape from Tarkov, the performance and functioning of a weapon are controlled by elaborate mechanisms organized into five categories:<1><0>Functional Mods<1>Muzzle devices (Functional Mods)<2>Sights (Functional Mods)<3>Gear Mods<4>Vital parts", "Pistol Grips": "Pistol Grips", "pistol-page-description": "This page includes a sortable table with information on the different types of pistol grips available in the game, including their price, ergonomics, compatibility, and other characteristics.", "Filter by gun": "Filter by gun", "select a gun": "select a gun", "pistol-grips-page-p": "<0>In Escape from Tarkov a pistol grips and stocks are vital parts of a weapon.<1>On this page you can sort them buy ergonomics improvement or their cost and see on which weapon they can be mounted.", "Provisions": "Provisions", "provisions-page-description": "This page includes a sortable table with information on the different types of provisions available in the game, including their hydration, energy, cheapest price and traders or flea market value.", "Total energy cost": "Total energy cost", "Include the cost of lost hydration in the cost of energy": "Include the cost of lost hydration in the cost of energy", "provisions-page-p": "<0>In Escape from Tarkov, provisions are utilized to replenish energy and hydration.<1>Your Metabolism skill level will determine how effective they are.", "Rigs": "Rigs", "rigs-page-description": "This page includes a sortable table with information on the different types of rigs available in the game, including their price, inside and outside size, weight, compression, and other characteristics.", "Armored rigs?": "Armored rigs?", "Min slots": "Min slots", "3-slot": "3-slot", "4-slot": "4-slot", "rigs-page-p": "<0>When it comes to carrying and storing ammunition and magazines during your excursions in Escape from Tarkov, chest rigs are crucial. Some even provide you with additional security.", "Suppressors": "Suppressors", "suppressors-page-description": "This page includes a sortable table with information on the different types of suppressors available in the game, including their ergonomics, recoil, and cheapest price.", "suppressors-page-p": "<0>In Escape from Tarkov, a suppressor is a muzzle device (a functional mod) and can be installed on a weapon to muffle gunshot sound.<1>On this page you can sort them buy ergonomics penalty, recoil improvement or their cost and see on which weapon they can be directly mounted.", "Barters": "Barters", "Marked": "Marked", "Wearables": "Wearables", "loot-tiers-page-description": "Learn about the different types of loot available in the game, their value, rarity, and what to keep and what to trash.", "Ranking the most valuable items in the game": "Ranking the most valuable items in the game", "Include Marked": "Include Marked", "Group by type": "Group by type", "min value": "min value", "Only show markers for active tasks": "Only show markers for active tasks", "Map of {{mapName}}": "Map of {{mapName}}", "maps-page-description": "Get the latest information on all maps in Escape from Tarkov, including extract points and loot locations. Find out where to find the best gear and resources in the game", "maps-page-p": "<0>There are 11 different locations on the Escape from Tarkov map, of which 10 have been released publicly so far. Although eventually all maps will be connected, they are currently all apart from one another.", "Streets of Tarkov": "Streets of Tarkov", "Ground Zero": "Ground Zero", "Customs": "Customs", "Factory": "Factory", "Interchange": "Interchange", "The Lab": "The Lab", "Lighthouse": "Lighthouse", "Reserve": "Reserve", "Shoreline": "Shoreline", "Woods": "Woods", "Openworld": "Openworld", "Tarkov.dev {{bot}} integration": "Tarkov.dev {{bot}} integration", "bot-page-description": "This page contains everything necessary to integrate {{bot}} with Tarkov.dev.", "You can add command to your moobot to get price check in your twitch chat": "You can add command to your moobot to get price check in your twitch chat", "Instructions": "Instructions", "Register at": "Register at", "using your twitch account": "using your twitch account", "Go to Custom commands": "Go to Custom commands", "Set what you want the command to be. Common is \"p\" or \"price\"": "Set what you want the command to be. Common is \"p\" or \"price\"", "Press the \"Create\" button": "Press the \"Create\" button", "In response choose URL Fetch - Full (plain) response": "In response choose URL Fetch - Full (plain) response", "and after insert \"Command arguments\"": "and after insert \"Command arguments\"", "Now press \"Save\" button": "Now press \"Save\" button", "Big thanks to": "Big thanks to", "for feedback": "for feedback", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "You can add command to your nightbot to get price check in your twitch / youtube channel chat", "using your twitch / youtube account": "using your twitch / youtube account", "Go to dashboard": "Go to dashboard", "Click the \"Join Channel\" button": "Click the \"Join Channel\" button", "Make bot - moderator, just type /mod nightbot in your chat": "Make bot - moderator, just type /mod nightbot in your chat", "Go to custom commands": "Go to custom commands", "Press the \"Add command\" button": "Press the \"Add command\" button", "Command: !p or anything you like": "Command: !p or anything you like", "Message:": "Message:", "Press \"Submit\"": "Press \"Submit\"", "Trader Levels": "Trader Levels", "Trader Reputation": "Trader Reputation", "Prerequisite Tasks": "Prerequisite Tasks", "Start Requirements": "Start Requirements", "Attributes": "Attributes", "Contains All": "Contains All", "Contains Item in Category": "Contains Item in Category", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "using extract: {{extractName}}": "using extract: {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x any of", "Dogtag level": "Dogtag level", "Max durability": "Max durability", "Min durability": "Min durability", "Kill": "Kill", "Shoot": "Shoot", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "During hours: {{hourStart}}:00 to {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "From distance: {{operator}} {{count}} meters", "From distance: {{operator}} {{count}} meters_other": "From distance: {{operator}} {{count}} meters", "While inside: {{zoneList, list(type: disjunction)}}": "While inside: {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Hitting: {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Using weapon:", "Using weapon mods:": "Using weapon mods:", "While wearing:": "While wearing:", "Not wearing:": "Not wearing:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "Obtain level {{level}} {{skillName}} skill", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} reputation", "In area(s): {{areaList, list(type: disjunction)}}": "In area(s): {{areaList, list(type: disjunction)}}", "Use any of:": "Use any of:", "Reach level {{playerLevel}}": "Reach level {{playerLevel}}", "optional": "optional", "Trader Standing": "Trader Standing", "Skill Level": "Skill Level", "Trader Offer Unlock": "Trader Offer Unlock", "Trader Unlock": "Trader Unlock", "Craft Unlock": "Craft Unlock", "task-page-description": "This page includes information on the objectives, rewards, and strategies for completing task {{questName}}. Get tips on how to prepare for and succeed in your mission.", "TarkovTracker": "TarkovTracker", "Leads to": "Leads to", "(on failure)": "(on failure)", "Task Details": "Task Details", "Objectives": "Objectives", "Fail On": "Fail On", "Needed Keys": "Needed Keys", "Task Start": "Task Start", "Task Completion": "Task Completion", "Rewards": "Rewards", "Task Failure": "Task Failure", "Can be restarted": "Can be restarted", "Cannot be restarted": "Cannot be restarted", "Penalties": "Penalties", "tasks-page-description": "Find out everything you need to know about tasks in Escape from Tarkov. Learn about the different types of tasks available in the game, how to complete them, and the rewards you can earn.", "Hides completed tasks": "Hides completed tasks", "Hide locked": "Hide locked", "Hides locked tasks": "Hides locked tasks", "Show all tasks": "Show all tasks", "Name filter": "Name filter", "filter on task name": "filter on task name", "quests-page-p": "<0>Traders in Escape from Tarkov have a number of tasks you can complete.<1>In exchange for retrieving items, eliminating targets, and performing other actions in raid, you can increase your standing with the traders and earn valuable items.", "Settings": "Settings", "settings-page-description": "This page contains user settings on Tarkov.dev.", "Language": "Language", "General": "General", "Has flea": "Has flea", "Use TarkovTracker": "Use TarkovTracker", "TarkovTracker API Token": "TarkovTracker API Token", "API Token": "API Token", "Stations": "Stations", "Skills": "Skills", "Dogtag Barters": "Dogtag Barters", "Exclude": "Exclude", "Minimum dogtag level": "Minimum dogtag level", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Minimum dogtag level to use for calculating the cost of dogtag barter trades", "The current estimated average player level is {{avgPlayerLevel}}": "The current estimated average player level is {{avgPlayerLevel}}", "Miscellaneous": "Miscellaneous", "Hide remote control": "Hide remote control", "start-page-description": "Check out all information for items, crafts, barters, maps, loot tiers, hideout profits, trader details, a free API, and more with tarkov.dev! A free, community made, and open source ecosystem of Escape from Tarkov tools and guides.", "Load More": "Load More", "Tools": "Tools", "Ammo chart filter": "Ammo chart filter", "Traders barter profit": "Traders barter profit", "Hideout crafts profit": "Hideout crafts profit", "Loot tiers ranking": "Loot tiers ranking", "Average wipe length": "Average wipe length", "Bitcoin farm profit": "Bitcoin farm profit", "Invite Discord bot": "Invite Discord bot", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.dev is an open source tool kit for Escape from Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat", "Make bot - moderator, just type /mod streamelements in your chat": "Make bot - moderator, just type /mod streamelements in your chat", "Press the \"Add new command\" button": "Press the \"Add new command\" button", "Press \"Activate Command\"": "Press \"Activate Command\"", "Player level": "Player level", "Reputation": "Reputation", "Commerce": "Commerce", "Trader {{trader}}": "Trader {{trader}}", "trader-page-description": "Get the latest information on the trader {{trader}} in Escape from Tarkov. Learn about the items he sells on certain Loyalty Level and how to maximize your cash-back money to level Loyalty.", "Items with the best cash back prices for leveling": "Items with the best cash back prices for leveling", "Spending": "Spending", "Unlocks at Loyalty Level {{level}}": "Unlocks at Loyalty Level {{level}}", "Tasks given by {{traderName}}": "Tasks given by {{traderName}}", "traders-page-description": "Find out everything you need to know about traders in Escape from Tarkov. Learn about the different traders available in the game, their locations, and the items they sell.", "About Traders": "About Traders", "traders-page-p": "<0>The backbones of trade in the destroyed, besieged Norvinsk. In Escape from Tarkov, each merchant specialized in a particular kind of product, such as medical supplies, weaponry, or military equipment. Although their prices are typically high, you get what you pay for.<1>More importantly, you can develop a reputation with each trader through Quests, which will enable you to receive better offers generally and reduce the commission they receive (an additional markup you pay on sales and purchases), among other benefits.<2>Additionally, traders provide other services like insurance and repairs (allowing you to recover your gear in case of death during a raid).", "Patch": "Patch", "Wipe start": "Wipe start", "Wipe end": "Wipe end", "Ongoing wipe": "Ongoing wipe", "{{count}} days_one": "{{count}} days", "{{count}} days_other": "{{count}} days", "{{count}} months_other": "{{count}} months", "{{count}} years_one": "{{count}} year", "Wipe Length": "Wipe Length", "wipe-length-description": "Get the latest information on the average wipe length in Escape from Tarkov. Find out how long wipes typically last, and prepare for the next wipe.", "Average Wipe Length among last 6 wipes:": "Average Wipe Length among last 6 wipes:", "Trader Ammo": "Trader Ammo", "Only show ammo available from traders on your settings": "Only show ammo available from traders on your settings", "Reset": "Reset", "Convert one currency to another": "Convert one currency to another", "Currency Converter": "Currency Converter", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "control-info-p": "<0>This page allows you to control the Tarkov.dev website using another browser. The typical use case is to have the Tarkov.dev website open in a browser on a second monitor while you play the game and this page open on your phone or another device so that you can navigate to different pages on the Tarkov.dev website without having to alt+tab out of the game. All you have to do is open the Tarkov.dev website in a browser where you want it to be displayed, click the \"Click to connect\" button in the lower left*, and then use the ID shown there on this page on the control device and click the Connect. Once connected, you can use this control page to open specific map or ammo pages in the controlled browser.<1>*It appears on the lower left by default but can be toggled to the lower right side of the screen. It can also be hidden by the \"Hide remote control\" option on the settings page.", "cookie-consent": "tarkov.dev uses cookies to enhance your experience. By continuing to use this site, you agree to the usage of cookies. Cookies are used to remember your settings and features that you enable.", "I understand": "I understand", "Other Options": "Other Options", "This task {{taskStatus}}": "This task {{taskStatus}}", "Slots per kg": "Slots per kg", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Stash Discord Bot", "More Tools": "More Tools", "Companion app": "Companion app", "Discord companion": "Discord companion", "Download latest release": "Download latest release", "View on GitHub": "View on GitHub", "Join the community": "Join the community", "Screenshot of TarkovMonitor showing timers and integrations": "Screenshot of TarkovMonitor showing timers and integrations", "Visual timers, raid state, and integration health in TarkovMonitor.": "Visual timers, raid state, and integration health in TarkovMonitor.", "Main Features": "Main Features", "tarkov-monitor-page-description": "Learn how to install TarkovMonitor, connect it to TarkovTracker, and use it to control Tarkov.dev maps.", "tarkov-monitor-summary": "TarkovMonitor provides helpful alerts and timers for Escape From Tarkov so you can manage raids without interrupting gameplay.", "tarkov-monitor-feature-audio": "Audio alerts for matchmaking, raid start, runthrough timer, scav cooldown, and air filter notifications.", "tarkov-monitor-feature-map": "Automatic map opening on Tarkov.dev based on the location you are joining.", "tarkov-monitor-feature-screenshot": "Optional screenshot-activated position display for quick location sharing.", "tarkov-monitor-feature-quests": "Automatic quest updates to TarkovTracker whenever completions are detected.", "tarkov-monitor-feature-stats": "Local statistics such as flea market income, queue durations, and map play frequency.", "tarkov-monitor-feature-timers": "Visible timers for time in raid plus scav cooldowns so you can plan the next run.", "Download": "Download", "tarkov-monitor-download-1": "Grab the latest TarkovMonitor.zip release from GitHub.", "tarkov-monitor-download-2": "Extract the archive anywhere on your PC.", "tarkov-monitor-download-3": "Run TarkovMonitor.exe and keep it open while you play.", "Community support": "Community support", "tarkov-monitor-community": "Have questions or want to chat with other users? Join the Discord server for tips, troubleshooting, and feature discussions.", "Join the Discord": "Join the Discord", "Security": "Security", "tarkov-monitor-security": "TarkovMonitor is not a cheat. It only reads the Escape From Tarkov log files stored on your PC and never modifies the game or injects code.", "stash-page-description": "Invite the Stash Discord bot, explore its commands, and see how it can help your community.", "stash-hero": "Stash pipes the full Tarkov.dev dataset into Discord so your community can check prices, quest progress, hideout timers, and more without leaving chat.", "Invite Stash": "Invite Stash", "Report an issue": "Report an issue", "Highlights": "Highlights", "Item intelligence": "Item intelligence", "Instant prices with flea, trader, and craft context.": "Instant prices with flea, trader, and craft context.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Craft/barter lookups reuse Tarkov.dev profitability data.", "Toggle PVE or PMC game modes to match your server rules.": "Toggle PVE or PMC game modes to match your server rules.", "Progress tracking": "Progress tracking", "Quest command lists requirements, turn-ins, and rewards.": "Quest command lists requirements, turn-ins, and rewards.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.", "Restock and status alerts keep everyone informed between raids.": "Restock and status alerts keep everyone informed between raids.", "Community tools": "Community tools", "Goons tracker for spotting the Rogue Boss trio.": "Goons tracker for spotting the Rogue Boss trio.", "Roulette mini-game for fun raid modifiers.": "Roulette mini-game for fun raid modifiers.", "Slash commands, autocomplete, and localized responses.": "Slash commands, autocomplete, and localized responses.", "Frequently used commands": "Frequently used commands", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash exposes dozens of slash commands. Here are a few that most servers rely on:", "Command": "Command", "Example": "Example", "Support & feedback": "Support & feedback", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.", "stash-tech-note": "Need developer-focused setup guides or self-hosting instructions? Review the README on GitHub for the latest technical documentation.", "card-tarkov-monitor-desc": "Automate TarkovTracker progress, capture queue timers, and drive Tarkov.dev maps with a single Windows companion app.", "card-stash-desc": "Slash commands for price checks, quest help, hideout progress, and restock timers sourced directly from Tarkov.dev.", "Read more": "Read more", "Invite now": "Invite now", "other-tools-page-description": "Discover companion apps built by the Tarkov.dev team, including TarkovMonitor and the Stash Discord bot.", "other-tools-body": "<0>Tarkov.dev is more than a website. These tools extend your raids, streams, and Discord communities using the same open-source data set. Dive into each tool to see screenshots, setup guides, and support links.", "Learn about TarkovMonitor": "Learn about TarkovMonitor", "Meet the Stash bot": "Meet the Stash bot", "The help command to view all available commands": "The help command to view all available commands", "View details about the bot": "View details about the bot", "Get a sorted ammo table for a certain ammo type": "Get a sorted ammo table for a certain ammo type", "Check barter details for an item": "Check barter details for an item", "Get detailed information about a boss": "Get detailed information about a boss", "Get the latest game changes from tarkov-changes.com": "Get the latest game changes from tarkov-changes.com", "Check crafting details for an item": "Check crafting details for an item", "Set the game mode (regular, PVE) for bot responses": "Set the game mode (regular, PVE) for bot responses", "Check or report the location of the Goons": "Check or report the location of the Goons", "Get a Discord invite link for the bot to join it to another server": "Get a Discord invite link for the bot to join it to another server", "Report an issue with the bot": "Report an issue with the bot", "Get price, craft, barter, etc. information about an item": "Get price, craft, barter, etc. information about an item", "Get a key's price and maps it is used on": "Get a key's price and maps it is used on", "View a map and some general info about it": "View a map and some general info about it", "Get the latest official patchnotes for EFT": "Get the latest official patchnotes for EFT", "Get player profile information": "Get player profile information", "Get a detailed output on the price of an item, its price tier, and more!": "Get a detailed output on the price of an item, its price tier, and more!", "Manage your customized hideout and trader progress": "Manage your customized hideout and trader progress", "Get detailed information about a quest": "Get detailed information about a quest", "Show or set alerts for trader restock timers": "Show or set alerts for trader restock timers", "Play a game of roulette to determine how you play your next raid": "Play a game of roulette to determine how you play your next raid", "Get the game/server/website status of Escape from Tarkov": "Get the game/server/website status of Escape from Tarkov", "Get information about a in-game stim": "Get information about a in-game stim", "Show the criteria for loot tiers": "Show the criteria for loot tiers", "Get the bot's uptime": "Get the bot's uptime", "stash-support": "<0>Stash is maintained by the Tarkov.dev team. Bugs or feature ideas? Open an issue on <1>GitHub or chat with the developers inside the <2>Tarkov.dev Discord. If you are syncing Tarkov.dev and the bot data, include screenshots plus reproduction steps so we can help faster.", "Database": "Database", "Calculators": "Calculators", "Progression": "Progression", "Community": "Community", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/es/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Chicos astutos. Los cultistas acechan en las sombras en grupos de 3 a 5 esperando que se acerque un jugador. Se acercan silenciosamente a sus enemigos y los apuñalan usando cuchillos normales o, en el caso de los sacerdotes, el cuchillo cultista envenenado. Si les disparan, devolverán el fuego con armas de fuego y granadas. Después de atacar a un jugador con su cuchillo, pueden huir al bosque nuevamente y regresar a las sombras", "knight-bio": "", "knight-description": "El líder de 'The Goons'. Puede aparecer en diferentes mapas.", "glukhar-bio": "No hay información fiable sobre sus actividades pasadas porque todos los documentos se perdieron o fueron clasificados, pero según información no verificada, tenía el rango de suboficial. Participó en operaciones de combate. Conocía los fundamentos de las tácticas de combate y las utilizaba para reclamar o defender los territorios.
    Todo su equipo parecen ser ex militares también. Aunque ahora su equipo es solo un grupo de bandidos, luchan por los recursos y ganar influencia en Tarkov. Tiene contactos con comerciantes capaces de exportar mercancías de la región de Norvinsk, que periódicamente le envían los últimos trenes en funcionamiento para el transporte de mercancías.", "glukhar-description": "Glukhar y sus numerosos guardias son extremadamente hostiles. Es muy poco probable que sobrevivas si luchas con ellos en campo abierto. Son preferibles los pasillos pequeños y las habitaciones cerradas. Glukhar y sus guardias son muy precisos. Glukhar y sus guardias permanecerán cerca los unos de los otros en todo momento y sus guardias lo seguirán a donde quiera que vaya.", "kaban-bio": "Una vez tuvo un pequeño negocio legal en Tarkov, pero no temía utilizar métodos delictivos para adquirir dinero. Después de la evacuación general permaneció en la ciudad y su pandilla ha crecido.", "kaban-description": "Su tamaño le permite disparar varias ametralladoras pesadas sin fatigarse, pero al mismo tiempo Kaban no puede permitirse el lujo de ser ágil y por lo tanto permanece en posición o se mueve lentamente de un punto a otro durante el combate. Tiene un gran número de guardias bien armados, algunos de los cuales son ex militares que le han organizado una fuerte defensa. El jefe vive en la zona del taller de reparación de automóviles en la calle Tarkov. La zona está fuertemente defendida, las entradas están fortificadas con ametralladoras estacionarias y AGS, los caminos están minados y hay francotiradores en el techo del centro de servicio de automóviles. Kaban usa una plataforma personalizada para almacenar cajas de ametralladoras, usa un chaleco antibalas debajo de la ropa y tiene una autoridad incuestionable entre sus guardias. Los scavs cercanos ayudan al jefe con la defensa y participarán en el combate por Kaban.", "killa-bio": "", "killa-description": "El verdadero Giga Chad de Tarkov. Killa usa una ametralladora ligera u otra arma automática para inmovilizar al enemigo mientras acecha de refugio en refugio acercándose a su objetivo para el empujón final. Durante el asalto, se mueve en zigzag, utiliza granadas de humo y de fragmentación y suprime implacablemente a los enemigos con fuego automático. Seguirá a su objetivo a grandes distancias incluso fuera de su ruta de patrulla, así que asegúrese de correr muy lejos para alejarse de él si se ha fijado en usted.", "kollontay-bio": "Es un ex oficial del MVD (Ministerio del Interior), durante su servicio en las fuerzas del orden tenía fama de hombre vil, cuyo comportamiento a veces era temido por sus compañeros de trabajo. Durante su trabajo, a menudo recurrió a su método de interrogatorio favorito: un bastón de goma, así como a otras presiones no reglamentarias sobre alguien que no era de su agrado. Gracias a su fuerza física y temperamento audaz, después de los acontecimientos del escándalo TerraGroup, formó una pandilla y comenzó a combatir los saqueos y el pillaje. Sin embargo, incluso antes del conflicto, a menudo brindaba protección a los empresarios locales. Son bien conocidas, por ejemplo, sus buenas relaciones con Kaban.", "kollontay-description": "Kollontay tiene un pequeño número de guardias, prefiere permanecer en una posición y ocasionalmente patrulla su territorio. Si siente que tiene ventaja, puede utilizar su porra policial. Vive en los alrededores del centro comercial Klimov y de la Academia Tarkov del Ministerio del Interior.", "partisan-bio": "There are few reliable details about his past, but it's known that he once served in Afghanistan, where his radical methods of warfare took root. Referred to by some as 'Partizan', he became notorious for his expertise in setting traps and mines. His reputation for eliminating enemies often came down to catching them off guard, using their overconfidence against them. Partizan's knowledge of guerrilla tactics made him a dangerous adversary, able to turn any location—whether forest or building—into a deadly trap.
    Those who survive long enough to learn his ways may just find themselves in his good graces, but only if they're careful enough to see the traps before it's too late.", "partisan-description": "", "raider-bio": "", "raider-description": "Los Scav Raiders (también conocidos simplemente como 'raiders') son Scavs avanzados que son considerablemente más fuertes y tácticos que los Scavs típicos. Llevan armas mucho más peligrosas y utilizan munición de nivel superior. Además, tienen una puntería mucho mejor y con frecuencia pueden derribar a jugadores bien equipados con sólo unas pocas balas (o de un solo tiro en la frente). Los asaltantes scav también patrullan en múltiples grupos y generalmente se les puede distinguir por sus expresiones únicas y su gran hostilidad general. Los Scav Raiders comienzan siendo amigables con todos los demás Scavs (incluidos los scavs de los jugadores), pero se volverán hostiles si te acercas e ignoras sus advertencias verbales. También se volverán hostiles a todos los Scav si alguno de ellos los enfada.", "reshala-bio": "", "reshala-description": "Normalmente intentará permanecer oculto hasta el final del enfrentamiento. Además, nunca usa armadura. Ten cuidado como jugador scav, ya que si estás en los niveles de karma scav más bajos, Reshala o sus guardias pueden dispararte sin provocación o te dispararán si te acercas demasiado a Reshala. A veces, sus guardias lanzan advertencias a los jugadores scavs con karma bajo antes de volverse hostiles.", "rogue-bio": "", "rogue-description": "Los pícaros defienden la planta de tratamiento de agua y las áreas circundantes en Lighthouse. Su rutina principal es patrullar, pero a menudo toman posiciones defensivas en los tejados y utilizan emplazamientos de armas fijas. Priorizarán a todos los jugadores que entren en su área, pero serán un poco más indulgentes con los PMC y Scavs de la USEC. Los pícaros son extremadamente peligrosos debido a su elevada salud, precisión del rayo láser y gran puntería a distancia. Los pícaros también se cubrirán detrás de las coberturas y usarán medicamentos si están heridos.", "sanitar-bio": "Ex médico y científico. Trabajó para TerraGroup. Lideró varios proyectos en el laboratorio, incluido el desarrollo de nuevas sustancias psicoactivas. El campo de investigación abarcó desde la influencia de diversas condiciones en el cuerpo hasta el desarrollo de neuroestimulantes. Además del laboratorio de TerraGroup, tenía su propia oficina en el Sanatorio de la Costa Azul, donde también realizaba investigaciones, especialmente durante las últimas semanas antes de la evacuación total.
    A menudo iba a 'zonas calientes' junto con el cuerpo médico, y después de comenzar a trabajar para la corporación, visitó regularmente las oficinas africanas entre otras, supervisando los desarrollos. Se ha ganado una autoridad incuestionable y el respeto entre sus colegas.", "sanitar-description": "Cuando participa en combate, luchará junto a sus compañeros carroñeros y guardias, pero a menudo puede escaparse para curarse o inyectarse. Tiene muchos medicamentos por lo que capaz de aguantar un enfrentamiento prolongado.", "shturman-bio": "", "shturman-description": "Shturman y sus seguidores se enfrentarán al jugador a larga distancia protegiendo el área del aserradero en el bosque. Prefieren mantener la distancia y evitar así el combate cuerpo a cuerpo.", "tagilla-bio": "", "tagilla-description": "Está completamente loco e intentará derribarte. Sin embargo, si estás en una posición innacesible para él, como las vigas, usará su arma secundaria (generalmente una escopeta) para matarte a distancia. Está activo inmediatamente al comienzo de la incursión. El jefe puede preparar emboscadas, abrir fuego de supresión y asaltar si es necesario.", "zryachiy-bio": "Una de las figuras más misteriosas de Tarkov. Prácticamente no se sabe nada sobre su pasado, excepto que tiene entrenamiento como francotirador y se rumorea que ha estado muchas veces en zonas calientes de Oriente Medio y África.
    Mucho antes del conflicto, se convirtió en el leal perro faldero de Lightkeeper y tomó una parte activa estableciendo conexiones entre Lightkeeper y todos aquellos con quienes interactuaba. Es conocido por ser amigable con el grupo Rogue, así como con los hombres encapuchados que dibujan símbolos misteriosos en los lugares.
    Zryachiy es muy taciturno, aunque quienes trabajan con él generalmente lo entienden sin palabras. Hay muchos rumores sobre sus ojos, algunos dicen que es una peculiaridad innata, otros apuntan a ciertas gotas para los ojos que le permiten mejorar su visión en la oscuridad, dándole a sus ojos ese efecto secundario de blancura. A pesar de su apariencia, parece que se ganó su nombre precisamente por su excelente vista, lo que no sorprende de un ex francotirador militar.", "zryachiy-description": "Guardia cultista de Lightkeeper." } ================================================ FILE: src/translations/es/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Interactivo", "Landscape": "Paisaje", "View Fullscreen": "Ver a pantalla completa", "Exit Fullscreen": "Salir de pantalla completa", "Satellite": "Satélite", "Abstract": "Abstracto", "Levels": "Plantas", "1st Floor": "1a planta", "2nd Floor": "2a planta", "3rd Floor": "3a planta", "4th Floor": "4a planta", "5th Floor": "5a planta", "Underground": "Bajo tierra", "Garage": "Garaje", "Tunnels": "Tuneles", "Bunkers": "Bunkers", "Spawns": "Inicio", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "Francotirador Scav", "Boss": "Boss", "Extracts": "Extracción", "Shared": "Compartido", "Hazards": "Peligros", "Usable": "Usable", "Locks": "Caja fuerte", "Stationary Gun": "Arma fija", "Lever": "Palanca", "Switch": "Interruptor", "Door": "Puerta", "Container": "Caja", "Car Door or Trunk": "Puerta de vehículo o maletero", "Lock": "Cerradura", "Activated by": "Activado por", "Activates": "Se Activa", "Needs power": "Necesita energía", "Lootable Items": "Lootable Items", "Tasks": "Misiones", "Item": "Item", "Objective": "Objetivo", "Misc": "Misc", "openworld-name": "Mundo abierto", "openworld-description": "Esta es una suposición de cómo podría verse el mapa completo de Tarkov. Este mapa de mundo abierto probablemente incluiría todas las ubicaciones clave de los mapas existentes combinadas en un mapa único enorme.", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "Use TarkovMonitor to show your position", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/es/properties.json ================================================ { "ambientVolume": "Volumen ambiental", "caliber": "Calibre", "damage": "Daño", "distanceModifier": "Distancia", "distortion": "Distorsión", "projectileCount": "Número de proyectiles", "penetrationPower": "Poder de penetración", "armorDamage": "Daño a armadura", "fragmentationChance": "Posibilidad de fragmentación", "ammoType": "Tipo de munición", "class": "Clase", "material": "Material", "zones": "Zonas", "defaultPreset": "Preset por defecto", "durability": "Durabilidad", "ergoPenalty": "Penalización ergonomía", "speedPenalty": "Penalización velocidad", "turnPenalty": "Penalización giro", "headZones": "Zona de cabeza", "capacity": "Capacidad", "grids": "Rejillas", "energy": "Energía", "hydration": "Hidratación", "units": "Unidades", "stimEffects": "Efectos estimulante", "blindnessProtection": "Protección ceguera", "fuse": "Detonador", "maxExplosionDistance": "Distancia máxima de explosión", "fragments": "Fragmentos", "deafening": "Ensordecedor", "blocksHeadset": "Bloquea Auriculares", "ricochetY": "Probabilidad de rebote", "uses": "Usos", "malfunctionChance": "Probabilidad de mal funcionamiento", "ergonomics": "Ergonomía", "recoil": "Retroceso", "loadModifier": "Modificador de carga", "ammoCheckModifier": "Modificador de comprobación de munición", "useTime": "Usa tiempo", "cures": "Curas", "hitpoints": "Puntos de impacto", "maxHealPerUse": "Curación máxima por uso", "hpCostLightBleeding": "Hp coste sangrado ligero", "hpCostHeavyBleeding": "Hp coste sangrado abundante", "painkillerDuration": "Duración analgésico", "energyImpact": "Impacto sobre energía", "hydrationImpact": "Impacto sobre hidratación", "recoilVertical": "Retroceso vertical", "recoilHorizontal": "Retroceso horizontal", "zoomLevels": "Niveles de aumento", "minLimbHealth": "Salud mínima extremidad", "maxLimbHealth": "Salud máxima extremidad", "effectiveDistance": "Distancia efectiva", "fireModes": "Modos de disparo", "fireRate": "Cadencia de disparo", "sightingRange": "Distancia de avistamiento", "defaultWidth": "Ancho por defecto", "defaultHeight": "Altura por defecto", "defaultErgonomics": "Ergonomia por defecto", "defaultRecoilVertical": "Retroceso vertical por defecto", "defaultRecoilHorizontal": "Retroceso horizontal por defecto", "defaultWeight": "Peso por defecto", "recoilModifier": "Modificador de retroceso", "weight": "Peso", "baseItem": "Item Base", "categories": "Categorías", "type": "Tipo", "convergence": "Convergencia", "cameraRecoil": "Retroceso de la cámara", "recoilAngle": "Ángulo del retroceso", "recoilDispersion": "Dispersión del retroceso", "usedOnMaps": "Utilizado en los mapas" } ================================================ FILE: src/translations/es/translation.json ================================================ { "No data": "Sin datos", "Current Average Latency": "Latencia media actual", "API Latency in milliseconds": "Latencia API en milisegundos", "No barters found for this item": "No se han encontrado ofertas de trueque para ese objeto", "LL{{level}}": "LL{{level}}", "Barter at {{trader}}": "Intercambiar con {{trader}}", "Craft at {{station}}": "Fabricar en {{station}}", "Barter": "Trueque", "Craft at {{stationName}} {{stationLevel}}": "Fabricar en {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Proporciona {{count}} por {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Proporciona {{count}} por {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "Fabricar {{count}} en {{duration}} por {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "Fabricar {{count}} en {{duration}} por {{totalCost}}", "Reward": "Recompensa", "Cost": "Coste", "Cost ₽": "Coste ₽", "Estimated savings": "Ahorro estimado", "InstaProfit": "InstaProfit", "N/A": "N/A", "Barter cost": "Coste del intercambio", "No barters available for selected filters": "No hay ofertas de trueque para los filtros seleccionados", "No barters available for selected filters but some were hidden by ": "No hay ofertas de trueque para los filtros seleccionados aunque algunos están ocultos ", "your settings": "Tu configuración", "Some barters hidden by ": "Algunas ofertas de trueque están ocultas", "Can hold:": "Can hold:", "Can't hold:": "Can't hold:", "Level": "Nivel", "Flea Market": "Mercado Flea", "Flea banned": "Prohibido en Flea", "Sell price": "Precio de venta", "Flea Market fee": "Tasa mercado Flea", "Duration": "Duración", "Finishes": "Termina en", "Start now": "Empieza ya", "Flea throughput/h": "Flea rendimiento/h", "Estimated profit": "Beneficio estimado", "Estimated profit/h": "Estimación beneficio/h", "No crafts available for selected filters": "No hay objetos fabricables con los filtros actuales", "No crafts available for selected filters but some were hidden by ": "No hay objetos fabricables con los filtros actuales aunque algunos están ocultos ", "Some crafts hidden by ": "Algunos objetos fabricables están ocultos", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "Ya se han seleccionado todas las opciones", "Clear selection": "Borrar selección", "This item can't be sold on the Flea Market": "Este objeto no se puede vender en el mercado Flea", "Not scanned on the Flea Market": "No escaneado en el mercado Flea", "Flea market prices loading": "Cargando precios del mercado Flea", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>Tola la plataforma es de código abierto y está centrada en los desarroladores. Todo el código está disponible en <1><0> GitHub.", "about-discord-p": "<0>Si quieres contactar con nosotros, preguntarnos algo o solicitar alguna característica nueva, tenemos un servidor <1><0> Discord.", "about-x-p": "<0>Síguenos en <1><0> X para estar informado de las últimas actualizaciones.", "About": "Acerca", "Contributors": "Colaboradores", "Massive thanks to all the people who help build and maintain this project!": "¡Muchisimas gracias a todas las personas que ayudan a desarrollar y mantener el proyecto!", "Made with ❤️ by:": "Hecho con ❤️ por:", "Supporters": "Personas que nos apoyan", "about-support-ukraine-p": "<0>Animamos a cualquiera que pueda, a donar para ayudar a la gente de Ucrania usando el boton de debajo.", "about-support-collective-p": "<0> Si deseas apoyar este proyecto, puedes hacer una donación o apoyarnos a través de <1>Open Collective.", "Item Data": "Datos del objeto", "Fresh EFT data courtesy of": "Datos EFT actualizados cortesia de", "Additional data courtesy of": "Datos adicionales cortesia de", "Resources": "Recursos", "Tarkov.dev API": "Tarkov.dev API", "{{bot}} integration": "Integracion {{bot}}", "Discord bot for your Discord": "Bot Discord para tu servidor Discord", "External resources": "Recursos externos", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev es un desarrollo a partir del proyecto original denominado tarkov-tools.com, que dejó de existir | Muchas gracias a kokarn por todo su trabajo construyendo Tarkov Tools y la comunidad alrededor del proyecto.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "El contenido del juego y los materiales del mismo son marcas comerciales registradas cuyos derechos de autor pertenecen a Battlestate Games y los titulares de sus licencias.", "version": "version", "PMC & Scav Thorax HP": "PMC & Scav Torso HP", "Reshala Thorax HP": "Reshala Torso HP", "Raider Thorax HP": "Raider Torso HP", "Shturman Thorax HP": "Shturman Torso HP", "Cultist Priest Thorax HP": "Sacerdote Cultista Torso HP", "Cultist Warrior Thorax HP": "Guerrero Cultista Torso HP", "Damage": "Daño", "Class {{tier}}": "Nivel {{tier}}", "Penetration": "Penetración", "Filter by caliber": "Filtrar por calibre", "This item can only be sold to trader": "Este objeto solo se puede vender a los comerciantes", "per slot": "por casilla", "Value": "Valor", "Per slot": "Por casilla", "Sell to": "Vender a", "Found In Raid": "Encontrado en Raid", "Search item...": "Buscar objeto...", "Search task...": "Buscar misión...", "Tasks": "Misiones", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Items": "Objetos", "No hideout modules requires this item": "Ningún módulo de la guarida requiere este objeto", "No unbuilt hideout modules for selected filters but some were hidden by ": "No hay nigún modulo para la guarida sin fabricar con los filtros actuales aunque algunos están ocultos ", "Hideout Module": "Módulo para la guarida", "Item": "Objeto", "Amount": "Cantidad", "Player level: {{playerLevel}}": "Nivel del jugador: {{playerLevel}}", "Reputation: {{reputation}}": "Reputación: {{reputation}}", "Commerce: {{commerce}}": "Comercio: {{commerce}}", "Cheapest Price": "Precio más bajo", "Task: {{taskName}}": "Misión: {{taskName}}", "Flea Market not available": "Mercado Flea no disponible", "No trader offers available": "No hay intercambios con el comerciante disponibles", "Loading...": "Cargando...", "Ammo": "Munición", "Maps": "Mapas", "More": "Mas", "Traders": "Comerciantes", "Prapor": "Prapor", "Therapist": "Therapist", "Skier": "Skier", "Peacekeeper": "Peacekeeper", "Mechanic": "Mechanic", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "Bosses", "Barter profit": "Beneficio trueque", "Hideout profit": "Beneficio guarida", "Loot tiers": "Niveles de botín", "Hideout build costs": "Costes de construcción de guarida", "Wipe length": "Duración del 'wipe'", "Bitcoin Farm Profit": "Beneficio de la granja de Bitcoin", "Achievements": "Logros", "API": "API", "Donate": "Donar", "Become a patron": "Conviértete en patron", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "tiene suplentes", "On Task Completion": "Cuando se complete una misión", "On Task Start": "Cuando comience una misión", "Task": "Misión", "Required items": "Objetos necesarios", "Reward items": "Objetos de recompensa", "Required tasks": "Misiones necesarias", "loading": "cargando", "active": "activo", "succeeded": "finalizada con éxito", "complete": "completa", "failed": "fallada", "Minimum level": "Nivel mínimo", "Minimum trader level": "Nivel mínimo del comerciante", "Reputation rewards": "Recompensas de reputación", "Endgame": "Endgame", "Required for Kappa": "Necesario para Kappa", "Required for Lightkeeper": "Necesario para Lightkeeper", "No quests found": "No se han encontrado encargos", "Some tasks hidden by filter settings": "Algunas misiones están ocultas por los filtros actuales", "open this page in another browser or window and connect using this id": "abre esta página en otro navegador o ventana y conecta usando esta id", "ID for remote control": "ID para el control remoto", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Ve a Tarkov.dev con otro navegador e introduce esta ID para controlar la página desde allí", "Click to connect": "Haz click para conectar", "Sell value": "Valor de venta", "Tarkov server status": "Estado del servidor de Tarkov", "This item can't be sold to traders": "Este objeto no puede venderse a los comerciantes", "Name": "Nombre", "Sell to Flea": "Vender en el mercado Flea", "Buy on Flea": "Comprar en el mercado Flea", "Sell to Trader": "Vender al Comerciante", "Trader buy": "Comprar al comerciante", "Buyback ratio": "Ratio de recompra", "The percent recovered if you buy this item and sell it to the trader": "Porcetaje recuperado si compras el objeto y se lo vendes al comerciante", "Grid": "Cuadrícula", "Slots occupied": "Espacios ocupados", "Slots inside": "Espacios en el interior", "Slots ratio": "Ratio de espacios", "Price per slot": "Precio por espacio", "Armor class": "Nivel de armadura", "Zones": "Zonas", "Max Durability": "Max Durabilidad", "Effective Durability": "Durabilidad Efectiva", "Repairability": "Reparabilidad", "Weight (kg)": "Peso (kg)", "Stats": "Estadísticas", "Mov/Turn/Ergo": "Mov/Giro/Ergo", "Caliber": "Calibre", "Armor damage": "Daño en armadura", "Fragmentation chance": "Probabilidad de fragmentación", "Blindness protection": "Protección contra ceguera", "Hydration": "Hidratación", "Energy": "Energía", "Hydration Cost": "Coste de Hidratación", "Energy Cost": "Coste de Energía", "Hydration + Energy Value": "Valor de Hidratación + Energía", "Sound suppression": "Supresión del sonido", "Low": "Bajo", "None": "Ninguno", "Blocks earpiece": "Bloquea auriculares", "Yes": "Si", "No": "No", "Ergonomics": "Ergonomía", "Cost per ergo": "Coste por ergo", "Recoil": "Retroceso", "Distance": "Distancia", "No items": "No hay objetos", "Not built": "No construido", "Locked": "Bloqueado", "Crafting": "Fabricando", "Hideout Management": "Gestión de la Guarida", "Be the first!": "Se el primero!", "Objective": "Objetivo", "No objectives": "No hay objetivos", "Players": "Jugadores", "By": "Por", "Restock in": "Reaprovisionamiento en", "Support Ukraine": "Apoyar a Ucrania", "Cost per unit": "Coste por unidad", "About the tarkov.dev project": "Acerca del proyecto tarkov.dev", "about-page-description": "Aprende más acerca de the-hideout y tarkov.dev. Un ecosistema de Escape From Tarkov de codigo abierto hecho por la propia comunidad! Usa nuestras herramientas para ayudarte a jugar, o construye tus propios proyectos con nuestra API gratuita.", "Open source": "Codigo abierto", "Discussions & feedback": "Discusiones & comentarios", "Support": "Soporte", "about-support-more-p": "<0>Puedes ayudarnos informando de bugs, sugiriendo o implementando nuevas funcionalidades, mejorando los mapas o de cualquier otra manera que creas que puede ayudar a nuestro proyecto.", "about-api-p": "<0>Nosotros ofrecemos una API 100% gratuita y públicamente accesible para todos tus desarrollos del sobre el Tarkov - <1>API.", "History": "Historia", "about-history-p": "<0>Este proyecto es una continuación de <1>tarkov-tools.com. El autor original <3>@kokarn decidió desactivar el sitio web. Siguiendo el espíritu del código abierto, un grupo de desarrolladores se reunieron para revivir el proyecto y continuar ofreciendo a la comunidad del Tarkov un gran portal de información y una API para apoyar a futuros desarrolladores.Este proyecto es 100% codigo abierto y está centrado en los desarrolladores. Nuestra organización de GitHub (<5>the-hideout) contiene todos los repositorios que alimentan la API, el sitio web, el bot de la comunidad Discord, la infraestructura del servidor, y mucho más! Somos unos apasionados del codigo abierto y nos encantan los 'pull request' que mejoran nuestro ecosistema para todos.", "Core Contributors": "Principales Colaboradores", "about-core-contributors-p": "<0>Los principales colaboradores del proyecto (sin ningún orden en particular) son:", "All Contributors": "Todos los Colaboradores", "about-all-contributors-p": "<0>Muchísimas gracias a todas las personas que han contribuido para que este proyecto sea posible! ❤️", "Description": "Descripción", "Hidden": "Oculto", "Player %": "Jugador %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "Esta página incluye información de los logros que pueden obtenerse.", "Ammo chart": "Gráfico de munición", "ammo-page-description": "Esta página contiene una lista de todos los tipos de munición de Escape from Tarkov. Para filtrar la lista, haz click en el nombre del calibre.", "ammo-page-p": "<0>La naturaleza de Tarkov incluye numerosos tipos de munición. Para combatir a diferentes tipos de enemigos son necesarios diferentes tipos de munición.<1>Esta página contiene una lista de todos los tipos de munición de Escape from Tarkov. Para filtrar la lista, haz click en el nombre del calibre.", "Total damage": "Daño total", "Use total damage of all projectiles in a round": "Usa el daño total de todos los proyectiles en una partida", "Ignore settings": "Ignorar configuración", "Shows all sources of items regardless of your settings": "Muestra todos los origenes de los objetos independientemente de la configuración", "Use barters for item sources": "Usa ofertas de trueque para los origenes de los objetos", "Use crafts for item sources": "Usa fabricables para los origenes de los objetos", "Ammo Statistics Table": "Tabla de estadísticas de munición", "API Documentation": "Documentación API", "api-docs-page-description": "API creada por la comunidad del Escape from Tarkov's y su documentación. Aprende más acerca de nuestra API GraphQL gratuita y su uso para EFT.", "api-about-p": "<0>La API está escrita en GraphQL y hacemos todo lo posible para seguir las especificaciones y no realizar cambios drásticos. Para aprender que consultas puedes hacer y como está estructurado el esquema, visita nuestro 'playground' y lee la documentación haciendo click en el icono del libro en la esquina superior izquierda. Cuando estés listo para probar algunas consultas, puedes probarlas en el 'playground'. Para aprender sobre las consultas GraphQL en general, la fundación GraphQL tiene algunos recursos útiles.<1><0><0>Tarkov.dev GraphQL playground<1><0>Recursos fundación GraphQL<1>Cuando estés listo para enviar consultas ajenas al 'playground', el punto de servicio de la API es: <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Rendimiento actual de la API", "api-performance-p": "<0>Para un informe completo de métricas y rendimiento de la API, puede consultar la <1>página de estado.", "FAQ": "FAQ", "Is it free?": "¿Es gratuito?", "Is it open source?": "¿Es de código abierto?", "api-faq-open-source-p": "¡Por supuesto! El codigo fuente de la API puede consultarse en su repositorio de GitHub: <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "¿Existe un ratio límite para las peticiones?", "api-faq-rate-limit-p": "Ocasionalmente tenemos picos de tráfico procedente de origenes maliciosos que requieren establecer un límite en el ratio. Los datos sobre los precios se actualizan cada 5 minutos, por tanto no hay necesidad de consultarlos por debajo de ese espacio temporal. Utiliza el sentido común, y todo estará correcto.", "What about caching?": "¿Qué hay acerca de la 'cache'?", "api-faq-caching-p": "Cuando se actualizan los datos cada 5 minutos, también se almacenan en la 'cache' todas las consultas de GraphQL durante ese tiempo. Esto nos ayuda a reducir la carga de nuestros servidores a la vez que procesamos las peticiones ¡lo más rapidamente posible!", "Where is the data from?": "¿De dónde proceden los datos?", "We source data from multiple places to build an API as complete as possible. We use data from:": "Utilizamos datos de multiples orígenes para construir una API lo más completa posible. Nuestras fuentes son:", "Our network of scanners": "Nuestra red de scanners", "Examples": "Ejemplos", "example": "ejemplo", "Contributed by": "Aportado por", "API Users": "Usuarios API", "api-users-page-description": "Esta página contiene una lista de todos los usuarios de la API pública de Tarkov.dev y sus proyectos.", "api-users-p": "<0>¿Quieres que te incluyamos en esta página? Únete a nuestro <1>Discord y cuéntanos que has hecho!", "Barter Profits": "Beneficio de comerciantes", "barters-page-description": "Esta página incluye información de los diferentes objetos que pueden intercambiarse haciendo un trueque con los vendedores NPC, los precios del comerciante, y los beneficios que se pueden obtener con su venta.", "Shows all barters regardless of your settings": "Muestra todos los trueques independientemente de tu configuración", "Hide dogtags": "Oculta dogtags", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "El coste \"cost\" real de los trueques usando 'Dogtags' es dificil de estimar, asi pues quizás quieras ocultarlo", "Show all barters": "Muestra todos los trueques", "All": "Todos", "Item filter": "Filtro por objeto", "filter on item": "Filtrar en objeto", "barters-page-p": "<0>A excepción de Fence, todos los comerciantes de Escape from Tarkov ofrecen productos mediante trueque en lugar de comprarlos directamente.<1>A cambio de una variedad de cosas económicas, el jugador frecuentemente puede intercambiarlas por objetos más valiosos que pueden utilizarse o venderse para obtener ganancias. Estas transacciones a veces permiten a los jugadores obtener equipo y artículos que generalmente solo se pueden comprar con niveles de lealtad más altos.<3>Asegúrate de volver a consultar después de cada reinicio para ver tus ofertas favoritas porque la mayoría de estos valiosos intercambios tienen límites estrictos por reinicio del comerciante o venta repetida.", "Num graphic cards": "Num tarjetas gráficas", "Hours": "Horas", "Bitcoin Farm Calculator": "Calculadora de granja de BitCoin", "bitcoin-farm-calculator-page-description": "Esta página incluye una herramienta para calcular el precio de construir y mantener una granja de BitCoin, basada en el número de las GPUs, el coste de la electricidad y el coste del BitCoin.", "Graphic cards count": "Número de tarjetas gráficas", "Use fuel cost: {{price}}/day": "Usar coste de combustible: {{price}}/día", "Use station build costs": "Usar coste de construcción de la estación", "Purchase cost": "Coste de compra", "Remaining days in wipe:": "Días restantes del 'wipe':", "Time to produce 1 bitcoin": "Tiempo para producir 1 BitCoin", "BTC/day": "BTC/día", "Estimated profit/day": "Beneficio/día estimado", "Profitable after days": "Días para ser rentable", "Total cost of graphic cards": "Coste total de las tarjetas gráficas", "Build costs": "Coste de construcción", "GPU + build costs": "GPU + coste construcción", "Remaining profit": "Ganancia restante", "Map": "Mapa", "Spawn Location": "Punto de aparición", "Chance": "Probabilidad", "Count": "Número", "Spawn chance": "Probabilidad de aparición", "Chance that the boss spawns on a given map": "Probabilidad de aparición del 'Boss' en un mapa dado", "Health": "Salud", "Total boss health": "Salud total del 'Boss'", "Patrol": "Patrulla", "Rush": "Asalto", "Stalker": "Acechador", "Hostile and accurate": "Hostil y preciso", "Patrol and highly armored": "Patrulla y está altamente blindado", "Group patrol": "Patrulla en grupo", "Frequent healing and stim injections": "Inyección de estimulantes y tratamiento médico constante", "Sniper": "Francotirador", "Batshit insane": "Batshit insane", "Behavior": "Comportamiento", "The boss's general AI behavior": "Comportamiento general de la IA del 'Boss'", "Wiki": "Wiki", "Boss Stats": "Estadísticas del 'Boss'", "Special Boss Loot": "Botín especial del 'Boss'", "Spawn Locations": "Puntos de aparición", "boss-spawn-table-description": "<0>Mapa: El nombre del mapa donde el jefe puede aparecer<1>Localización de Aparacición: La localización exacta en el mapa donde el jefe puede aparecer<2>Probabilidad: Si la \"Probabilidad de Aparición\" está activada, esta es la probabilidad estimada de que el jefe aparezca en los localización dada en ese mapa", "Boss Escorts": "Escoltas del Jefe", "This boss does not have any escorts": "Este jefe no tiene ningun escolta", "boss-page-description": "Esta página incluye información de {{bossName}}, su localización, botín, y estrategias para derrotarlo.", "bosses-page-description": "Esta página incluye información de todos los jefes en el juego, sus localizaciones, botines, escoltas, y estrategias para derrotarlos.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Los jefes son enemigos feroces y moratles con equipamento único en Escape from Tarkov", "About Bosses": "Sobre los jefes", "bosses-page-p": "<0>In Escape from Tarkov, there are many bosses that roam the area of besieged Norvinsk.<1>Each boss has unique behaviours, characteristics, and tactics. The bosses in Tarkov are feared by players of all levels and will often pose as a greater threat than enemy PMCs in the region.<2>However, with high risk comes high reward. Many bosses contain high tier loot items or are required to eliminate for quests. Learning the patterns, locations, and distinct attire of a boss is often the best a player can prepare themselves when a fight begins against a boss in Tarkov.", "Connect": "Connect", "Connected to": "Connected to", "id to control": "id to control", "Remote Control": "Remote Control", "remote-control-page-description": "This page contains all the necessary tools to remote control another instance of Tarkov.dev website.", "View Map": "View Map", "Go": "Go", "View caliber": "View caliber", "Select...": "Select...", "Load tarkov.dev in another browser or window to control it from here": "Load tarkov.dev in another browser or window to control it from here", "Hideout Crafts": "Hideout Crafts", "crafts-page-description": "This page includes information on the different items that can be crafted in the hideout, the materials and resources required, and the profits that can be made from selling the finished products.", "Shows all crafts regardless of your settings": "Shows all crafts regardless of your settings", "Average prices": "Average prices", "Use average prices from the past 24 hours for profit calculations": "Use average prices from the past 24 hours for profit calculations", "Most profitable craft in each station": "Most profitable craft in each station", "Best": "Best", "Flea Market banned items": "Flea Market banned items", "Empty fuel": "Empty fuel", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.", "crafts-page-p": "<0>In Escape from Tarkov, crafts allow you to create a variety of things. It is accomplished using a variety of hideout modules, including the water collector, workbench, medstation, lavatory, and nutrition unit.<1>The \"Found in Raid\" status will be applied to each item created in the hideout. The entire list of these crafts is shown above. The Crafting skill has an impact on item creation time.<2>When an item's icon has a blue border, it will be utilized as an auxiliary tool and, once manufacturing is finished, it will be returned to your stash.", "Page not found": "Page not found", "error-page-description": "This is not the page you are looking for", "Sorry, that page doesn't exist!": "Sorry, that page doesn't exist!", "Hideout": "Hideout", "hideout-page-description": "This page includes information on the different stations and modules that can be built with the materials and resources required to upgrade your hideout.", "Show all stations & modules": "Show all stations & modules", "Show built": "Show built", "Show already built stations": "Show already built stations", "Show locked": "Show locked", "Show unavailable stations": "Show unavailable stations", "Show all requirements": "Show all requirements", "Show trader and other station level requirements": "Show trader and other station level requirements", "Collected": "Collected", "Item Tracker": "Item Tracker", "Only show Found in Raid": "Only show Found in Raid", "Reset all tracking": "Reset all tracking", "Hide completed": "Hide completed", "Hide tasks you've completed": "Hide tasks you've completed", "Hide dogtag barters": "Hide dogtag barters", "Best price to sell for": "Best price to sell for", "Fee": "Fee", "Profit": "Profit", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.", "Max price to sell for": "Max price to sell for", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.", "Likely sell price": "Likely sell price", "item-page-description": "This page includes information on the characteristics, uses, and strategies for {{itemName}}.", "Sell for": "Sell for", "Buy for": "Buy for", "Flea price history": "Historial de precios del mercado de pulgas", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "Lowest scanned price last 24h: {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Highest scanned price last 24h: {{high24hPrice}}", "Updated: {{val, relativetime}}": "Updated: {{val, relativetime}}", "Items contained in {{itemName}}": "Items contained in {{itemName}}", "Barters with {{itemName}}": "Barters with {{itemName}}", "Crafts with {{itemName}}": "Crafts with {{itemName}}", "Hideout modules needing {{itemName}}": "Hideout modules needing {{itemName}}", "Shows all modules regardless of your settings": "Shows all modules regardless of your settings", "Quests requiring {{itemName}}": "Quests requiring {{itemName}}", "Quests rewarding {{itemName}}": "Quests rewarding {{itemName}}", "Armors": "Armors", "armors-page-description": "This page includes a sortable table with information on the different types of armor available in the game, including their price, repairability, armor class, and other characteristics.", "Class effective durability": "Class effective durability", "Include rigs": "Include rigs", "Max price": "Max price", "max price": "max price", "armors-page-p": "<0>In the video game Escape from Tarkov, armor vests are worn to lessen bullet damage. Helmets are typically used in addition to them.", "Backpacks": "Backpacks", "backpacks-page-description": "This page includes a sortable table with information on the different types of backpacks available in the game, including their price, size, capacity, and other characteristics.", "Net price per slot": "Net price per slot", "Show price per additional slot of storage gained from the container": "Show price per additional slot of storage gained from the container", "backpacks-page-p": "<0>Backpacks in the Escape from Tarkov game are various-sized containers for carrying your hard-earned riches.", "Barter Items": "Barter Items", "barter-items-page-p": "<0>This table of barter items from Escape from Tarkov will make it simple for you to determine how much each one is worth. It can be challenging to determine which products are valuable enough to take because there are over 150 barter items in the game, and flea market pricing can fluctuate suddenly. You may optimize your loot with the aid of this interactive table.", "bsg-category-description": "Find out everything you need to know about {{category}} in Escape from Tarkov.", "Containers": "Containers", "containers-page-p": "<0>As their name implies, containers in Escape from Tarkov are items used to hold other things. Some of these items are used to clear up inventory space by acting as storage and taking up less inventory slots however some of them cannot be equipped on the character.", "Glasses": "Glasses", "glasses-page-description": "This page includes a sortable table with information on the different types of glasses available in the game, including their price, armor class, and other characteristics.", "glasses-page-p": "<0>Eyewear in Escape from Tarkov can be used to decrease the number and quantity of raindrops on the players' screens as well as the length of flashbang effects.", "Grenades": "Grenades", "grenades-page-description": "This page includes a sortable table with information on the different types of grenades available in the game, including their price, damage, and other characteristics.", "grenades-page-p": "<0>There are only a handful distinct types of grenades that may be thrown or launched in Escape from Tarkov, and each one has a unique effect: flash, smokes, high explosive, and fragmentation.<1>Grenades are situational, but when utilized properly, they can have deadly results. Any advantage from high-tier equipment can be fully negated by a single well-thrown grenade, whether it completely blinds the adversary, kills them instantly, or forces them out of cover and into your gunfire.<3>Five factors to think about while using throwable grenades include the fuse time, explosion radius, fragment damage, fragment count, and even the weight of the grenade. With specific uses arising from each component.", "Guns": "Guns", "guns-page-description": "This page includes a sortable table with information on the different types of guns available in the game, including their price, damage, accuracy, and other characteristics.", "guns-page-p": "<0>Your main tool for survival is a weapon. Almost all weapons are completely modular, allowing them to be customized for various scenarios. All of the weaponry used in Escape from Tarkov are listed on this page.", "Headsets": "Headsets", "headsets-page-description": "This page includes a sortable table with information on the different types of headsets available in the game, including their price, availability, and other characteristics.", "headsets-page-p": "<0>In Escape from Tarkov, headsets magnify low-frequency noises like footsteps while muzzling impulsive stimuli like gunshots. Different audio profiles are offered by the various models.", "Helmets": "Helmets", "helmet-page-description": "This page includes a sortable table with information on the different types of helmets available in the game, including their price, armor class, and other characteristics.", "Show blocking headset": "Show blocking headset", "Min armor class": "Min armor class", "helmets-page-p": "<0>In Escape from Tarkov, headgear serves a variety of functions.<1>There are useful objects, vanity items, and safety headgear. Before entering combat, choosing a helmet that will protect different parts of the head becomes crucial.<3>The impact that different helmets will have on how much sound they suppress is another crucial factor to take into account. Escape from Tarkov's gameplay heavily relies on sound.<5>Modular helmets, which have an assortment of different components, are another aspect of Escape from Tarkov. These helmets may modify the number of segments they protect. Top, Nape, Ears, Eyes, and Jaws are the segments.", "items-page-description": "This page includes links to pages with information on different item categories, including armor, backpacks, barter items, containers, glasses, grenades, guns, headsets, helmets, keys, gun mods, pistol grips, provisions, rigs, suppressors, and more.", "Keys": "Keys", "keys-page-description": "This page includes a sortable table with information on the different types of keys available in the game, including their price, rarity, and other characteristics.", "keys-page-p": "<0>Maps, keys, key cards, and other useful objects are included in intelligence items. These will help you stay one step ahead of the competition—or at the very least, know where you are in Escape from Tarkov.<1>The remaining durability of keys and keycards with a limited number of uses is displayed in the bottom right corner of their icons and on their inspection screens.", "Mods": "Mods", "mods-page-description": "This page includes a sortable table with information on the different types of gun mods available in the game, including their price, compatibility, and other characteristics.", "mods-page-p": "<0>In Escape from Tarkov, the performance and functioning of a weapon are controlled by elaborate mechanisms organized into five categories:<1><0>Functional Mods<1>Muzzle devices (Functional Mods)<2>Sights (Functional Mods)<3>Gear Mods<4>Vital parts", "Pistol Grips": "Pistol Grips", "pistol-page-description": "This page includes a sortable table with information on the different types of pistol grips available in the game, including their price, ergonomics, compatibility, and other characteristics.", "Filter by gun": "Filter by gun", "select a gun": "select a gun", "pistol-grips-page-p": "<0>In Escape from Tarkov a pistol grips and stocks are vital parts of a weapon.<1>On this page you can sort them buy ergonomics improvement or their cost and see on which weapon they can be mounted.", "Provisions": "Provisions", "provisions-page-description": "This page includes a sortable table with information on the different types of provisions available in the game, including their hydration, energy, cheapest price and traders or flea market value.", "Total energy cost": "Total energy cost", "Include the cost of lost hydration in the cost of energy": "Include the cost of lost hydration in the cost of energy", "provisions-page-p": "<0>In Escape from Tarkov, provisions are utilized to replenish energy and hydration.<1>Your Metabolism skill level will determine how effective they are.", "Rigs": "Rigs", "rigs-page-description": "This page includes a sortable table with information on the different types of rigs available in the game, including their price, inside and outside size, weight, compression, and other characteristics.", "Armored rigs?": "Armored rigs?", "Min slots": "Min slots", "3-slot": "3-slot", "4-slot": "4-slot", "rigs-page-p": "<0>When it comes to carrying and storing ammunition and magazines during your excursions in Escape from Tarkov, chest rigs are crucial. Some even provide you with additional security.", "Suppressors": "Suppressors", "suppressors-page-description": "This page includes a sortable table with information on the different types of suppressors available in the game, including their ergonomics, recoil, and cheapest price.", "suppressors-page-p": "<0>In Escape from Tarkov, a suppressor is a muzzle device (a functional mod) and can be installed on a weapon to muffle gunshot sound.<1>On this page you can sort them buy ergonomics penalty, recoil improvement or their cost and see on which weapon they can be directly mounted.", "Barters": "Barters", "Marked": "Marked", "Wearables": "Wearables", "loot-tiers-page-description": "Learn about the different types of loot available in the game, their value, rarity, and what to keep and what to trash.", "Ranking the most valuable items in the game": "Ranking the most valuable items in the game", "Include Marked": "Include Marked", "Group by type": "Group by type", "min value": "min value", "Only show markers for active tasks": "Only show markers for active tasks", "Map of {{mapName}}": "Map of {{mapName}}", "maps-page-description": "Get the latest information on all maps in Escape from Tarkov, including extract points and loot locations. Find out where to find the best gear and resources in the game", "maps-page-p": "<0>There are 11 different locations on the Escape from Tarkov map, of which 10 have been released publicly so far. Although eventually all maps will be connected, they are currently all apart from one another.", "Streets of Tarkov": "Streets of Tarkov", "Ground Zero": "Ground Zero", "Customs": "Customs", "Factory": "Factory", "Interchange": "Interchange", "The Lab": "The Lab", "Lighthouse": "Lighthouse", "Reserve": "Reserve", "Shoreline": "Shoreline", "Woods": "Woods", "Openworld": "Openworld", "Tarkov.dev {{bot}} integration": "Tarkov.dev {{bot}} integration", "bot-page-description": "This page contains everything necessary to integrate {{bot}} with Tarkov.dev.", "You can add command to your moobot to get price check in your twitch chat": "You can add command to your moobot to get price check in your twitch chat", "Instructions": "Instructions", "Register at": "Register at", "using your twitch account": "using your twitch account", "Go to Custom commands": "Go to Custom commands", "Set what you want the command to be. Common is \"p\" or \"price\"": "Set what you want the command to be. Common is \"p\" or \"price\"", "Press the \"Create\" button": "Press the \"Create\" button", "In response choose URL Fetch - Full (plain) response": "In response choose URL Fetch - Full (plain) response", "and after insert \"Command arguments\"": "and after insert \"Command arguments\"", "Now press \"Save\" button": "Now press \"Save\" button", "Big thanks to": "Big thanks to", "for feedback": "for feedback", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "You can add command to your nightbot to get price check in your twitch / youtube channel chat", "using your twitch / youtube account": "using your twitch / youtube account", "Go to dashboard": "Go to dashboard", "Click the \"Join Channel\" button": "Click the \"Join Channel\" button", "Make bot - moderator, just type /mod nightbot in your chat": "Make bot - moderator, just type /mod nightbot in your chat", "Go to custom commands": "Go to custom commands", "Press the \"Add command\" button": "Press the \"Add command\" button", "Command: !p or anything you like": "Command: !p or anything you like", "Message:": "Message:", "Press \"Submit\"": "Press \"Submit\"", "Trader Levels": "Trader Levels", "Trader Reputation": "Trader Reputation", "Prerequisite Tasks": "Prerequisite Tasks", "Start Requirements": "Start Requirements", "Attributes": "Attributes", "Contains All": "Contains All", "Contains Item in Category": "Contains Item in Category", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "using extract: {{extractName}}": "using extract: {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x any of", "Dogtag level": "Dogtag level", "Max durability": "Max durability", "Min durability": "Min durability", "Kill": "Kill", "Shoot": "Shoot", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "During hours: {{hourStart}}:00 to {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "From distance: {{operator}} {{count}} meters", "From distance: {{operator}} {{count}} meters_other": "From distance: {{operator}} {{count}} meters", "While inside: {{zoneList, list(type: disjunction)}}": "While inside: {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Hitting: {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Using weapon:", "Using weapon mods:": "Using weapon mods:", "While wearing:": "While wearing:", "Not wearing:": "Not wearing:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "Obtain level {{level}} {{skillName}} skill", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} reputation", "In area(s): {{areaList, list(type: disjunction)}}": "In area(s): {{areaList, list(type: disjunction)}}", "Use any of:": "Use any of:", "Reach level {{playerLevel}}": "Reach level {{playerLevel}}", "optional": "optional", "Trader Standing": "Trader Standing", "Skill Level": "Skill Level", "Trader Offer Unlock": "Trader Offer Unlock", "Trader Unlock": "Trader Unlock", "Craft Unlock": "Craft Unlock", "task-page-description": "This page includes information on the objectives, rewards, and strategies for completing task {{questName}}. Get tips on how to prepare for and succeed in your mission.", "TarkovTracker": "TarkovTracker", "Leads to": "Leads to", "(on failure)": "(on failure)", "Task Details": "Task Details", "Objectives": "Objectives", "Fail On": "Fail On", "Needed Keys": "Needed Keys", "Task Start": "Task Start", "Task Completion": "Task Completion", "Rewards": "Rewards", "Task Failure": "Task Failure", "Can be restarted": "Can be restarted", "Cannot be restarted": "Cannot be restarted", "Penalties": "Penalties", "tasks-page-description": "Find out everything you need to know about tasks in Escape from Tarkov. Learn about the different types of tasks available in the game, how to complete them, and the rewards you can earn.", "Hides completed tasks": "Hides completed tasks", "Hide locked": "Hide locked", "Hides locked tasks": "Hides locked tasks", "Show all tasks": "Show all tasks", "Name filter": "Name filter", "filter on task name": "filter on task name", "quests-page-p": "<0>Traders in Escape from Tarkov have a number of tasks you can complete.<1>In exchange for retrieving items, eliminating targets, and performing other actions in raid, you can increase your standing with the traders and earn valuable items.", "Settings": "Settings", "settings-page-description": "This page contains user settings on Tarkov.dev.", "Language": "Language", "General": "General", "Has flea": "Has flea", "Use TarkovTracker": "Use TarkovTracker", "TarkovTracker API Token": "TarkovTracker API Token", "API Token": "API Token", "Stations": "Stations", "Skills": "Skills", "Dogtag Barters": "Dogtag Barters", "Exclude": "Exclude", "Minimum dogtag level": "Minimum dogtag level", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Minimum dogtag level to use for calculating the cost of dogtag barter trades", "The current estimated average player level is {{avgPlayerLevel}}": "The current estimated average player level is {{avgPlayerLevel}}", "Miscellaneous": "Miscellaneous", "Hide remote control": "Hide remote control", "start-page-description": "Check out all information for items, crafts, barters, maps, loot tiers, hideout profits, trader details, a free API, and more with tarkov.dev! A free, community made, and open source ecosystem of Escape from Tarkov tools and guides.", "Load More": "Load More", "Tools": "Tools", "Ammo chart filter": "Ammo chart filter", "Traders barter profit": "Traders barter profit", "Hideout crafts profit": "Hideout crafts profit", "Loot tiers ranking": "Loot tiers ranking", "Average wipe length": "Average wipe length", "Bitcoin farm profit": "Bitcoin farm profit", "Invite Discord bot": "Invite Discord bot", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.dev is an open source tool kit for Escape from Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat", "Make bot - moderator, just type /mod streamelements in your chat": "Make bot - moderator, just type /mod streamelements in your chat", "Press the \"Add new command\" button": "Press the \"Add new command\" button", "Press \"Activate Command\"": "Press \"Activate Command\"", "Player level": "Player level", "Reputation": "Reputation", "Commerce": "Commerce", "Trader {{trader}}": "Trader {{trader}}", "trader-page-description": "Get the latest information on the trader {{trader}} in Escape from Tarkov. Learn about the items he sells on certain Loyalty Level and how to maximize your cash-back money to level Loyalty.", "Items with the best cash back prices for leveling": "Items with the best cash back prices for leveling", "Spending": "Spending", "Unlocks at Loyalty Level {{level}}": "Unlocks at Loyalty Level {{level}}", "Tasks given by {{traderName}}": "Tasks given by {{traderName}}", "traders-page-description": "Find out everything you need to know about traders in Escape from Tarkov. Learn about the different traders available in the game, their locations, and the items they sell.", "About Traders": "About Traders", "traders-page-p": "<0>The backbones of trade in the destroyed, besieged Norvinsk. In Escape from Tarkov, each merchant specialized in a particular kind of product, such as medical supplies, weaponry, or military equipment. Although their prices are typically high, you get what you pay for.<1>More importantly, you can develop a reputation with each trader through Quests, which will enable you to receive better offers generally and reduce the commission they receive (an additional markup you pay on sales and purchases), among other benefits.<2>Additionally, traders provide other services like insurance and repairs (allowing you to recover your gear in case of death during a raid).", "Patch": "Patch", "Wipe start": "Wipe start", "Wipe end": "Wipe end", "Ongoing wipe": "Ongoing wipe", "{{count}} days_one": "{{count}} days", "{{count}} days_other": "{{count}} days", "{{count}} months_other": "{{count}} months", "{{count}} years_one": "{{count}} year", "Wipe Length": "Wipe Length", "wipe-length-description": "Get the latest information on the average wipe length in Escape from Tarkov. Find out how long wipes typically last, and prepare for the next wipe.", "Average Wipe Length among last 6 wipes:": "Average Wipe Length among last 6 wipes:", "Trader Ammo": "Trader Ammo", "Only show ammo available from traders on your settings": "Only show ammo available from traders on your settings", "Reset": "Reset", "Convert one currency to another": "Convert one currency to another", "Currency Converter": "Currency Converter", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "control-info-p": "<0>This page allows you to control the Tarkov.dev website using another browser. The typical use case is to have the Tarkov.dev website open in a browser on a second monitor while you play the game and this page open on your phone or another device so that you can navigate to different pages on the Tarkov.dev website without having to alt+tab out of the game. All you have to do is open the Tarkov.dev website in a browser where you want it to be displayed, click the \"Click to connect\" button in the lower left*, and then use the ID shown there on this page on the control device and click the Connect. Once connected, you can use this control page to open specific map or ammo pages in the controlled browser.<1>*It appears on the lower left by default but can be toggled to the lower right side of the screen. It can also be hidden by the \"Hide remote control\" option on the settings page.", "cookie-consent": "tarkov.dev uses cookies to enhance your experience. By continuing to use this site, you agree to the usage of cookies. Cookies are used to remember your settings and features that you enable.", "I understand": "I understand", "Other Options": "Other Options", "This task {{taskStatus}}": "This task {{taskStatus}}", "Slots per kg": "Slots per kg", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Bot de Discord Stash", "More Tools": "Más herramientas", "Companion app": "Aplicación complementaria", "Discord companion": "Complemento de Discord", "Download latest release": "Descargar la última versión", "View on GitHub": "Ver en GitHub", "Join the community": "Únete a la comunidad", "Screenshot of TarkovMonitor showing timers and integrations": "Captura de TarkovMonitor mostrando temporizadores e integraciones", "Visual timers, raid state, and integration health in TarkovMonitor.": "Temporizadores visuales, estado de incursión y salud de las integraciones en TarkovMonitor.", "Main Features": "Funciones principales", "tarkov-monitor-page-description": "Aprende a instalar TarkovMonitor, conectarlo a TarkovTracker y usarlo para controlar los mapas de Tarkov.dev.", "tarkov-monitor-summary": "TarkovMonitor ofrece alertas y temporizadores útiles para Escape From Tarkov para que puedas gestionar las incursiones sin interrumpir la partida.", "tarkov-monitor-feature-audio": "Alertas de audio para emparejamiento, inicio de incursión, temporizador de runthrough, enfriamiento de scav y notificaciones del filtro de aire.", "tarkov-monitor-feature-map": "Apertura automática del mapa en Tarkov.dev según la localización a la que te unes.", "tarkov-monitor-feature-screenshot": "Visualización opcional de la posición activada por capturas para compartir tu ubicación rápidamente.", "tarkov-monitor-feature-quests": "Actualizaciones automáticas de misiones a TarkovTracker cuando se detectan completadas.", "tarkov-monitor-feature-stats": "Estadísticas locales como ingresos del mercadillo, duración de colas y frecuencia de mapas.", "tarkov-monitor-feature-timers": "Temporizadores visibles del tiempo en incursión y el enfriamiento de scav para planificar tu próxima partida.", "Download": "Descargar", "tarkov-monitor-download-1": "Obtén la última versión TarkovMonitor.zip desde GitHub.", "tarkov-monitor-download-2": "Extrae el archivo en cualquier lugar de tu PC.", "tarkov-monitor-download-3": "Ejecuta TarkovMonitor.exe y mantenlo abierto mientras juegas.", "Community support": "Soporte de la comunidad", "tarkov-monitor-community": "¿Preguntas o quieres charlar con otros usuarios? Únete al servidor de Discord para consejos, soporte y hablar de funcionalidades.", "Join the Discord": "Únete al Discord", "Security": "Seguridad", "tarkov-monitor-security": "TarkovMonitor no es un truco. Solo lee los archivos de registro de Escape From Tarkov en tu PC y nunca modifica el juego ni inyecta código.", "stash-page-description": "Invita al bot de Discord Stash, explora sus comandos y descubre cómo puede ayudar a tu comunidad.", "stash-hero": "Stash lleva todo el conjunto de datos de Tarkov.dev a Discord para que tu comunidad consulte precios, progreso de misiones, temporizadores del escondite y más sin salir del chat.", "Invite Stash": "Invitar a Stash", "Report an issue": "Informar de un problema", "Highlights": "Destacados", "Item intelligence": "Inteligencia de objetos", "Instant prices with flea, trader, and craft context.": "Precios al instante con contexto de mercadillo, comerciantes y fabricación.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Las consultas de crafteos e intercambios reutilizan los datos de rentabilidad de Tarkov.dev.", "Toggle PVE or PMC game modes to match your server rules.": "Alterna los modos PVE o PMC para adaptar las respuestas del bot a las reglas de tu servidor.", "Progress tracking": "Seguimiento del progreso", "Quest command lists requirements, turn-ins, and rewards.": "El comando de misiones lista requisitos, entregas y recompensas.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "El comando progress refleja las mejoras de escondite y comerciantes que guardaste en TarkovTracker.", "Restock and status alerts keep everyone informed between raids.": "Las alertas de reabastecimiento y estado mantienen a todos informados entre incursiones.", "Community tools": "Herramientas para la comunidad", "Goons tracker for spotting the Rogue Boss trio.": "Seguimiento de los Goons para ubicar al trío de jefes Renegados.", "Roulette mini-game for fun raid modifiers.": "Minijuego de ruleta para modificadores de incursión divertidos.", "Slash commands, autocomplete, and localized responses.": "Comandos slash, autocompletado y respuestas localizadas.", "Frequently used commands": "Comandos más usados", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash ofrece docenas de comandos slash. Estos son algunos en los que confían la mayoría de servidores:", "Command": "Comando", "Example": "Ejemplo", "Support & feedback": "Soporte y comentarios", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "¿Necesitas la política de privacidad o los términos de servicio para la revisión de seguridad de tu servidor? Están en la carpeta /assets del repositorio y se actualizan con cada versión.", "stash-tech-note": "¿Necesitas guías técnicas o instrucciones para autoalojar? Revisa el README en GitHub para la documentación más reciente.", "card-tarkov-monitor-desc": "Automatiza el progreso de TarkovTracker, captura los tiempos de cola y controla los mapas de Tarkov.dev con una sola app de Windows.", "card-stash-desc": "Comandos slash para consultar precios, misiones, progreso del escondite y temporizadores de reabastecimiento basados directamente en Tarkov.dev.", "Read more": "Leer más", "Invite now": "Invitar ahora", "other-tools-page-description": "Descubre aplicaciones complementarias creadas por el equipo de Tarkov.dev, como TarkovMonitor y el bot de Discord Stash.", "other-tools-body": "<0>Tarkov.dev es más que una web. Estas herramientas amplían tus incursiones, streams y comunidades de Discord usando el mismo conjunto de datos de código abierto. Explora cada herramienta para ver capturas, guías de instalación y enlaces de soporte.", "Learn about TarkovMonitor": "Conoce TarkovMonitor", "Meet the Stash bot": "Conoce al bot Stash", "The help command to view all available commands": "El comando de ayuda para ver todos los comandos disponibles", "View details about the bot": "Ver detalles sobre el bot", "Get a sorted ammo table for a certain ammo type": "Obtener una tabla ordenada de munición para un tipo concreto", "Check barter details for an item": "Consultar detalles de intercambio de un objeto", "Get detailed information about a boss": "Obtener información detallada sobre un jefe", "Get the latest game changes from tarkov-changes.com": "Recibir los últimos cambios del juego desde tarkov-changes.com", "Check crafting details for an item": "Revisar los datos de fabricación de un objeto", "Set the game mode (regular, PVE) for bot responses": "Configurar el modo de juego (regular o PVE) para las respuestas del bot", "Check or report the location of the Goons": "Comprobar o reportar la ubicación de los Goons", "Get a Discord invite link for the bot to join it to another server": "Obtener un enlace de invitación para que el bot se una a otro servidor", "Report an issue with the bot": "Reportar un problema con el bot", "Get price, craft, barter, etc. information about an item": "Obtener información de precio, fabricación, intercambio, etc. de un objeto", "Get a key's price and maps it is used on": "Conocer el precio de una llave y los mapas en los que se usa", "View a map and some general info about it": "Ver un mapa y algunos datos generales", "Get the latest official patchnotes for EFT": "Ver las últimas notas oficiales del parche de EFT", "Get player profile information": "Obtener información del perfil de un jugador", "Get a detailed output on the price of an item, its price tier, and more!": "Recibir un informe detallado del precio de un objeto, su nivel y más", "Manage your customized hideout and trader progress": "Gestionar tu progreso personalizado de escondite y comerciantes", "Get detailed information about a quest": "Obtener información detallada sobre una misión", "Show or set alerts for trader restock timers": "Mostrar o configurar alertas para los temporizadores de reabastecimiento de los comerciantes", "Play a game of roulette to determine how you play your next raid": "Jugar a la ruleta para decidir cómo jugarás la próxima incursión", "Get the game/server/website status of Escape from Tarkov": "Conocer el estado del juego/servidor/sitio web de Escape from Tarkov", "Get information about a in-game stim": "Obtener información sobre un estimulante del juego", "Show the criteria for loot tiers": "Mostrar los criterios de los niveles de botín", "Get the bot's uptime": "Conocer el tiempo de actividad del bot", "stash-support": "<0>Stash es mantenido por el equipo de Tarkov.dev. ¿Errores o ideas? Abre un issue en <1>GitHub o habla con los desarrolladores en el <2>Discord de Tarkov.dev. Si sincronizas Tarkov.dev y los datos del bot, incluye capturas y pasos para reproducirlo.", "Database": "Database", "Calculators": "Calculators", "Progression": "Progression", "Community": "Community", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/fr/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Des cultistes sournois. Les cultistes se cachent dans l'ombre, par groupes de 3 à 5, attendant l'approche d'un joueur. Ils s'approchent silencieusement de leurs ennemis et les poignardent avec des couteaux normaux ou, dans le cas des prêtres, avec le couteau empoisonné du cultiste. En cas de tir, les cultistes ripostent avec des armes à feu et des grenades. Après avoir attaqué un joueur avec leur couteau, ils peuvent choisir de s'enfuir dans les bois et de retourner dans l'ombre.", "knight-bio": "", "knight-description": "Le chef des \"Goons\". Peut apparaître sur de nombreuses cartes.", "glukhar-bio": "Il n'existe aucune information fiable sur ses activités passées, car tous les documents ont été perdus ou classés secrets. Cependant, selon des informations non vérifiées, il avait le grade d'officier. Il a participé à des opérations de combat. Il connaissait les bases de la tactique et a activement utilisé ces connaissances pour revendiquer ou défendre divers territoires.
    Tous les membres de son équipe semblent également être d'anciens militaires. Cependant, son gang n'est plus qu'un groupe de bandits de facto se disputant les ressources et l'influence à Tarkov. Il entretient des relations avec des commerçants capables d'exporter des marchandises de la région de Norvinsk, qui lui envoient régulièrement les derniers trains de marchandises en état de marche.", "glukhar-description": "Glukhar et ses nombreux gardes sont extrêmement hostiles. Il est très peu probable qu'ils réussissent à combattre en zone ouverte. Les couloirs étroits et les pièces fermées sont préférables. Glukhar et ses gardes sont très précis. Ils resteront constamment proches les uns des autres et ses gardes le suivront partout où il ira.", "kaban-bio": "Il possédait autrefois une petite entreprise légale à Tarkov, mais n'hésitait pas à recourir à des méthodes criminelles pour s'enrichir. Après l'évacuation générale, il est resté en ville et son gang s'est agrandi.", "kaban-description": "Sa taille lui permet de tirer avec diverses mitrailleuses lourdes sans poser son arme, mais Kaban ne se laisse pas facilement déplacer et reste donc en position ou se déplace lentement d'un point à l'autre pendant le combat. Il dispose d'une importante garde bien armée, dont certains sont d'anciens militaires qui ont organisé une défense solide pour lui. Le boss réside dans le quartier de l'atelier de réparation automobile, dans les \"Rues de Tarkov\". La zone est fortement défendue : les entrées sont fortifiées par des mitrailleuses fixes et des AGS, les chemins sont minés et des snipers sont postés sur le toit du garage. Kaban utilise un abri sur mesure pour stocker ses caisses de mitrailleuses, porte un gilet pare-balles sous ses vêtements et jouit d'une autorité indiscutable parmi ses gardes. Les scavs à proximité aident le boss à se défendre et combattront pour lui.", "killa-bio": "", "killa-description": "Le véritable Giga Chad de Tarkov. Killa utilise une mitrailleuse légère ou une autre arme automatique pour neutraliser l'ennemi tout en rôdant de couverture en couverture pour se rapprocher de sa cible et mener l'assaut final. Pendant l'assaut, il se déplace en zigzag, utilise des grenades fumigènes et à fragmentation et neutralise sans relâche ses ennemis grâce à des tirs automatiques. Il suit sa cible sur de longues distances, hors de son itinéraire de patrouille ; assurez-vous donc de courir très loin pour vous éloigner de lui s'il vous a verrouillé.", "kollontay-bio": "Ancien officier du MVD (ministère de l'Intérieur), il avait, au cours de son service dans les forces de l'ordre, la réputation d'un homme odieux, dont le comportement était parfois redouté par ses collègues. Dans le cadre de son travail, il recourait souvent à sa méthode d'interrogatoire favorite : la matraque en caoutchouc, ainsi qu'à d'autres pressions non réglementaires sur ceux qui ne lui plaisaient pas. Grâce à sa force physique et à son tempérament audacieux, après le scandale TerraGroup, il a formé un gang et s'est lancé dans ce qu'il était censé combattre lui-même : le pillage et le banditisme. Cependant, même avant le conflit, il offrait souvent sa protection à des \"hommes d'affaires\" locaux. Ses bonnes relations avec Kaban, par exemple, sont bien connues.", "kollontay-description": "Kollontay dispose d'un petit nombre de gardes, préfère rester au même poste et patrouille occasionnellement sur son territoire. S'il estime avoir l'avantage, il peut utiliser sa matraque. Il vit dans le quartier du centre commercial Klimov et de l'Académie Tarkov du ministère de l'Intérieur.", "partisan-bio": "On ne connaît que peu de détails fiables sur son passé, mais on sait qu'il a servi en Afghanistan, où ses méthodes de guerre radicales ont pris racine. Surnommé par certains \"Partisan\", il est devenu célèbre pour son expertise en matière de pose de pièges et de mines. Sa réputation d'éliminer ses ennemis se résumait souvent à les prendre au dépourvu, utilisant leur excès de confiance contre eux. Sa connaissance des tactiques de guérilla faisait de Partizan un adversaire redoutable, capable de transformer n'importe quel endroit, forêt ou bâtiment, en piège mortel.
    Ceux qui survivent assez longtemps pour apprendre ses méthodes pourraient bien se retrouver dans ses bonnes grâces, à condition d'être suffisamment prudents pour repérer les pièges avant qu'il ne soit trop tard.", "partisan-description": "", "raider-bio": "", "raider-description": "Les Scavs pillards (aussi appelés \"raiders\") sont des Scavs avancés, considérablement plus puissants et tactiques que les Scavs classiques. Ils portent des armes bien plus dangereuses et utilisent des munitions de plus haut niveau. De plus, ils visent bien mieux et peuvent souvent abattre des joueurs bien équipés en quelques balles seulement (ou se faire simplement écraser). Les Scavs pillards patrouillent également en plusieurs groupes et se distinguent généralement par leur équipement, leurs répliques uniques et leur agressivité générale. Les Scavs pillards sont initialement amicaux envers tous les autres Scavs (y compris les Scavs joueurs), mais ils deviennent hostiles si vous vous approchez trop près et ignorez leurs avertissements verbaux. Ils deviennent également hostiles envers tous les Scavs si l'un d'eux les met en colère.", "reshala-bio": "", "reshala-description": "Il cherchera généralement à rester en retrait du combat, hors de la vue des joueurs. De plus, il ne porte jamais d'armure. Soyez prudent en tant que joueur Scav : si votre niveau de karma est faible, Reshala ou ses gardes peuvent vous tirer dessus sans provocation, ou vous tirer dessus si vous vous approchez trop près de Reshala. Ses gardes sont parfois connus pour avertir les joueurs Scavs ayant un faible karma avant de devenir hostiles.", "rogue-bio": "", "rogue-description": "Les voleurs défendent la station d'épuration et les environs du Phare. Leur activité principale consiste à patrouiller, mais ils prennent souvent position sur les toits et utilisent des armes stationnées. Ils ciblent tous les joueurs qui pénètrent dans leur zone, mais sont légèrement plus indulgents envers les SMP et les Scavs de l'USEC. Les voleurs sont extrêmement dangereux grâce à leur santé élevée, la précision de leurs rayons laser et leur grande distance de ciblage. Ils se cachent également et utilisent des médicaments s'ils sont blessés.", "sanitar-bio": "Ancien médecin et scientifique, il a travaillé pour TerraGroup. Il a dirigé plusieurs projets en laboratoire, notamment le développement de nouvelles substances psychoactives. Ses recherches s'étendaient de l'influence de diverses pathologies sur l'organisme au développement de neurostimulants. Outre le laboratoire de TerraGroup, il disposait de son propre bureau au Sanatorium de la Côte d'Azur, où il a également mené des recherches, notamment durant les dernières semaines précédant l'évacuation totale. Il était souvent détaché dans les zones sensibles avec le corps médical et, après avoir rejoint l'entreprise, il se rendait régulièrement dans les bureaux africains et étrangers pour superviser les développements. Il a acquis une autorité et un respect incontestés auprès de ses collègues.", "sanitar-description": "En combat, il combat aux côtés de ses camarades scavs et gardes, mais il lui arrive souvent de s'échapper pour se soigner ou se faire des injections. Il dispose de nombreux médicaments, ce qui permet un engagement prolongé.", "shturman-bio": "", "shturman-description": "Shturman et ses partisans attaqueront le joueur à longue distance pour protéger la zone de la scierie dans les bois. Ils préfèrent garder leurs distances, car ils ne sont pas adaptés au combat rapproché.", "tagilla-bio": "", "tagilla-description": "Il est complètement fou et tentera de vous terrasser. Cependant, si vous êtes dans une position où il ne peut pas se repérer, comme les chevrons, il utilisera son arme secondaire (généralement un fusil à pompe) pour vous tuer à distance. Il est actif dès le début du raid. Le boss peut tendre des embuscades, ouvrir des tirs de suppression et ouvrir une brèche si nécessaire.", "zryachiy-bio": "L'un des personnages les plus mystérieux de Tarkov. On ne sait pratiquement rien de son passé, si ce n'est qu'il a suivi une formation de tireur d'élite et qu'il aurait été à plusieurs reprises dans des zones sensibles du Moyen-Orient et d'Afrique. Bien avant le conflit, il était devenu le fidèle compagnon du Gardien de la Lumière et participait activement à l'établissement de liens entre lui et tous ceux qu'il côtoyait. Il est connu pour son amitié avec le groupe des Rogue, ainsi qu'avec les hommes encapuchonnés qui dessinent des symboles mystérieux sur les lieux. Zryachiy est très taciturne, bien que ses collaborateurs le comprennent généralement sans mots. De nombreuses rumeurs circulent au sujet de ses yeux : certains parlent d'une particularité innée, d'autres évoquent des gouttes pour les yeux qui lui permettraient d'améliorer sa vision dans l'obscurité, lui donnant ainsi cet effet secondaire de blancheur. Malgré les apparences, il semble qu'il ait gagné son nom précisément grâce à son excellente vue, ce qui n'est pas surprenant pour un ancien tireur d'élite militaire.", "zryachiy-description": "Garde cultiste du gardien de phare." } ================================================ FILE: src/translations/fr/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Interactive", "Landscape": "Paysage", "View Fullscreen": "Afficher en plein écran", "Exit Fullscreen": "Quitter le plein écran", "Satellite": "Satellite", "Abstract": "Abstrait", "Levels": "Niveaux", "1st Floor": "1er étage", "2nd Floor": "2e étage", "3rd Floor": "3e étage", "4th Floor": "4e étage", "5th Floor": "5e étage", "Underground": "Souterrain", "Garage": "Garage", "Tunnels": "Tunnels", "Bunkers": "Bunkers", "Spawns": "Spawns", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "Sniper Scav", "Boss": "Boss", "Extracts": "Extractions", "Shared": "Commun", "Hazards": "Dangers", "Usable": "Utilisable", "Locks": "Serrures", "Stationary Gun": "Arme stationnaire", "Lever": "Levier", "Switch": "Switch", "Door": "Porte", "Container": "Container", "Car Door or Trunk": "Porte ou coffre de voiture", "Lock": "Coffre-fort", "Activated by": "Activé par", "Activates": "Active", "Needs power": "Besoin d'alimentation", "Lootable Items": "Objets ramassables", "Tasks": "Tâches", "Item": "Objet", "Objective": "Objectif", "Misc": "Divers", "openworld-name": "Monde Ouvert", "openworld-description": "Voici une ébauche de ce à quoi pourrait ressembler la carte complète de Tarkov. Cette carte du monde ouvert regrouperait probablement tous les lieux clés des cartes existantes, réunis en une seule et immense carte.", "transits-name": "Transits", "transits-description": "Ceci est un overlay des transit par dessus la carte officielle montrant les transits de toutes les maps, et lesquels sont à sens unique.", "Transit": "Transit", "Task, item or container...": "Tâche, objet ou container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supporte la recherche multiple (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Afficher uniquement les marqueurs pour les tâches actives", "Don't collapse layers control": "Ne pas réduire le contrôle des calques", "Don't collapse search control": "Ne pas réduire le contrôle de recherche", "Use TarkovMonitor to show your position": "Utilisez TarkovMonitor pour afficher votre position", "Required item": "Article requis", "BTR Stop": "BTR Stop", "Player Position": "Position du joueur", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/fr/properties.json ================================================ { "ambientVolume": "Volume ambiant", "caliber": "Calibre", "damage": "Dommage", "distanceModifier": "Distance", "distortion": "Distortion", "projectileCount": "Nombre de projectiles", "penetrationPower": "Pouvoir de pénétration", "armorDamage": "Dommage d'armure", "fragmentationChance": "Chance de fragmentation", "ammoType": "Type de munition", "class": "Classe", "material": "Matériel", "zones": "Zones", "defaultPreset": "Préréglage par défaut", "durability": "Durabilité", "ergoPenalty": "Pénalité d'ergonomie", "speedPenalty": "Pénalité de vitesse", "turnPenalty": "Pénalité de tour", "headZones": "Zones de tête", "capacity": "Capacité", "grids": "Grilles", "energy": "Energie", "hydration": "Hydratation", "units": "Unités", "stimEffects": "Effets stimulants", "blindnessProtection": "Protection contre la cécité", "fuse": "Fusée", "maxExplosionDistance": "Distance max d'explosion", "fragments": "Fragments", "deafening": "Assourdissant", "blocksHeadset": "Bloque le casque", "ricochetY": "Chance de ricochet", "uses": "Utilisations", "malfunctionChance": "Risque de dysfonctionnement", "ergonomics": "Ergonomie", "recoil": "Recul", "loadModifier": "Modificateur de charge", "ammoCheckModifier": "Modificateur de contrôle de munitions", "useTime": "Temps d'utilisation", "cures": "Remèdes", "hitpoints": "Points de vie", "maxHealPerUse": "Soins max par utilisation", "hpCostLightBleeding": "Coût HP pour saignement léger", "hpCostHeavyBleeding": "Coût HP pour saignement abondant", "painkillerDuration": "Durée de l'antidouleur", "energyImpact": "Impact énergétique", "hydrationImpact": "Impact sur l'hydratation", "recoilVertical": "Recul vertical", "recoilHorizontal": "Recul horizontal", "zoomLevels": "Niveaux de zoom", "minLimbHealth": "Santé min des membres", "maxLimbHealth": "Santé max des membres", "effectiveDistance": "Distance effective", "fireModes": "Modes de tir", "fireRate": "Cadence de tir", "sightingRange": "Portée de visée", "defaultWidth": "Largeur par défaut", "defaultHeight": "Longueur par défaut", "defaultErgonomics": "Ergonomie par défault", "defaultRecoilVertical": "Recul vertical par défaut", "defaultRecoilHorizontal": "Recul horizontal par défaut", "defaultWeight": "Poids par défaut", "recoilModifier": "Modificateur de recul", "weight": "Poids", "baseItem": "Objet de base", "categories": "Catégories", "type": "Type", "convergence": "Convergence", "cameraRecoil": "Caméra de recul", "recoilAngle": "Angle de recul", "recoilDispersion": "Dispersion du recul", "usedOnMaps": "Utilisé sur les cartes" } ================================================ FILE: src/translations/fr/translation.json ================================================ { "No data": "Pas de données", "Current Average Latency": "Latence moyenne actuelle", "API Latency in milliseconds": "Latence de l'API en millisecondes", "No barters found for this item": "Aucun échange trouvé pour cet article", "LL{{level}}": "LL{{level}}", "Barter at {{trader}}": "Échange chez {{trader}}", "Craft at {{station}}": "Fabriquer à {{station}}", "Barter": "Objets d'échange", "Craft at {{stationName}} {{stationLevel}}": "Fabriquer sur {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Fournir {{count}} pour {{totalCost}}", "Provides {{count}} for {{totalCost}}_many": "Fournir {{count}} pour {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Fournir {{count}} pour {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "Fabriquer {{count}} en {{duration}} pour {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_many": "Fabriquer {{count}} en {{duration}} pour {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "Fabriquer {{count}} en {{duration}} pour {{totalCost}}", "Reward": "Récompense", "Cost": "Coût", "Cost ₽": "Coût ₽", "Estimated savings": "Économies estimées", "InstaProfit": "Profit Instantané", "N/A": "N/A", "Barter cost": "Coût d'échange", "No barters available for selected filters": "Pas d'échanges disponibles pour les filtres sélectionnés", "No barters available for selected filters but some were hidden by ": "Pas d'échanges disponibles pour les filtres sélectionnés mais certains sont cachés par ", "your settings": "vos options", "Some barters hidden by ": "Certains échanges cachés par ", "Can hold:": "Peut contenir:", "Can't hold:": "Ne peut pas contenir:", "Level": "Niveau", "Flea Market": "Marché", "Flea banned": "Banni du Marché", "Sell price": "Prix de vente", "Flea Market fee": "Frais du Marché", "Duration": "Durée", "Crafting Duration": "Temps de fabrication", "Finishes": "Se termine", "Start now": "Commence maintenant", "Flea throughput/h": "Flux du Marché/h", "Estimated profit": "Bénéfice estimé", "Estimated profit/h": "Bénéfice estimé/h", "No crafts available for selected filters": "Aucun artisanat disponible pour les filtres sélectionnés", "No crafts available for selected filters but some were hidden by ": "Aucun artisanat disponible pour les filtres sélectionnés, mais certains ont été masqués par ", "Some crafts hidden by ": "Quelques objets d'artisanat cachés par ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "Toutes les options déjà sélectionnées", "Clear selection": "Tout désélectionner", "This item can't be sold on the Flea Market": "Cet article ne peut pas être vendu sur le marché", "Not scanned on the Flea Market": "Non scanné sur le Marché", "Flea market prices loading": "Chargement des tarifs du Marché", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>L'ensemble de la plate-forme est open source et axé sur les développeurs. Tout le code est disponible sur <1><0> GitHub.", "about-discord-p": "<0>Si vous voulez discuter, poser des questions ou demander des fonctionnalités, nous avons un serveur <1><0>Discord.", "about-x-p": "<0>Suivez nous sur <1><0> X pour toutes les dernières mises à jour.", "About": "À propos", "Contributors": "Contributeurs", "Massive thanks to all the people who help build and maintain this project!": "Un merci massif à toutes les personnes qui aident à construire et à maintenir ce projet !", "Made with ❤️ by:": "Fait avec ❤️ par :", "Supporters": "Soutiens", "about-support-ukraine-p": "<0>Nous encourageons tous ceux qui le peuvent à faire un don pour soutenir le peuple ukrainien en utilisant le bouton ci-dessous.", "about-support-collective-p": "<0>Si vous souhaitez vous aussi soutenir ce projet, vous pouvez faire un don et/ou devenir un contributeur sur <1>Open Collective.", "Item Data": "Donnée d'objet", "Fresh EFT data courtesy of": "Données EFT récentes avec l'aimable autorisation de", "Additional data courtesy of": "Données supplémentaires fournies par", "Resources": "Ressources", "Tarkov.dev API": "API de Tarkov.dev", "{{bot}} integration": "Intégration de {{bot}}", "Discord bot for your Discord": "Discord bot pour votre Discord", "External resources": "Ressources externes", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev est un fork du site maintenant fermé tarkov-tools.com | Un grand merci à kokarn pour tout son travail de construction de Tarkov Tools et la communauté qui l’entoure.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "Le contenu et les éléments du jeu sont des marques déposées et des droits d'auteur de Battlestate Games et de ses concédants. Tous les droits sont réservés.", "version": "version", "PMC & Scav Thorax HP": "SMP & Scav Thorax HP", "Reshala Thorax HP": "Reshala Thorax HP", "Raider Thorax HP": "Raider Thorax HP", "Shturman Thorax HP": "Shturman Thorax HP", "Cultist Priest Thorax HP": "Prêtre Cultist Thorax HP", "Cultist Warrior Thorax HP": "Guerrier Cultist Thorax HP", "Damage": "Dommages", "Class {{tier}}": "Classe {{tier}}", "Penetration": "Pénétration", "Filter by caliber": "Filtrer par calibre", "This item can only be sold to trader": "Cet article ne peut être vendu qu’à un marchand", "per slot": "par case", "Value": "Valeur", "Per slot": "Par case", "Sell to": "Vendre à", "Found In Raid": "Trouvé en raid", "Search item...": "Rechercher un article ...", "Search task...": "Rechercher une tâche ...", "Tasks": "Tâches", "Task, item or container...": "Tâche, article ou conteneur ...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supporte la recherche multiple (e.g. 'labs, ledx, bitcoin')", "Items": "Articles", "No hideout modules requires this item": "Aucun module de la planque ne nécessite cet article", "No unbuilt hideout modules for selected filters but some were hidden by ": "Pas de modules de masquage non construit pour les filtres sélectionnés, mais certains ont été masqués par ", "Hideout Module": "Module de la planque", "Item": "Article", "Amount": "Quantité", "Player level: {{playerLevel}}": "Niveau du joueur : {{playerLevel}}", "Reputation: {{reputation}}": "Réputation : {{reputation}}", "Commerce: {{commerce}}": "Commerce : {{commerce}}", "Cheapest Price": "Prix les plus bas", "Task: {{taskName}}": "Tâche : {{taskName}}", "Flea Market not available": "Marché non disponible", "No trader offers available": "Aucune offre de marchand disponible", "Loading...": "Chargement ...", "Ammo": "Munitions", "Maps": "Cartes", "More": "Plus", "Traders": "Marchands", "Prapor": "Prapor", "Therapist": "La Toubib", "Skier": "Skier", "Peacekeeper": "Peacekeeper", "Mechanic": "Le Mécano", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "Boss", "Barter profit": "Profit d'échange", "Hideout profit": "Bénéfice de la planque", "Loot tiers": "Tiers de butin", "Hideout build costs": "Construction planque", "Wipe length": "Durée des wipe", "Bitcoin Farm Profit": "Profit de la Ferme à Bitcoin", "Achievements": "Succès", "API": "API", "Donate": "Dons", "Become a boss": "Devenir mécène", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "a des remplaçants", "On Task Completion": "Sur l'achèvement de la tâche", "On Task Start": "Sur le début de la tâche", "Task": "Tâche", "Required items": "Objets requis", "Reward items": "Récompenser les articles", "Required tasks": "Tâches requises", "loading": "chargement", "active": "active", "succeeded": "réussi", "complete": "complété(e)", "failed": "échoué(e)", "Minimum level": "Niveau minimum", "Minimum trader level": "Niveau de marchand minimum", "Reputation rewards": "Récompenses de réputation", "Endgame": "Endgame", "Required for Kappa": "Requis pour Kappa", "Required for Lightkeeper": "Requis pour Lightkeeper", "No quests found": "Quêtes non trouvées", "Some tasks hidden by filter settings": "Certaines tâches masquées par les paramètres de filtre", "open this page in another browser or window and connect using this id": "ouvrez cette page dans un autre navigateur ou une autre fenêtre et connectez-vous en utilisant cet identifiant", "ID for remote control": "Identifiant pour télécommande", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Allez sur tarkov.dev avec un autre navigateur et entrez cet ID pour contrôler cette page à partir de là", "Click to connect": "Cliquez pour se connecter", "Sell value": "Prix de vente", "Tarkov server status": "Statut du serveur Tarkov", "This item can't be sold to traders": "Cet article ne peut pas être vendu aux marchands", "Name": "Nom", "Sell to Flea": "Prix Marché", "Buy on Flea": "Acheter au Marché", "Sell to Trader": "Prix marchand", "Trader buy": "Marchand acheter", "Buyback ratio": "Taux de rachat", "The percent recovered if you buy this item and sell it to the trader": "Le pourcentage récupéré si vous achetez cet article et le vendez au commerçant", "Grid": "Grille", "Slots occupied": "Emplacements occupés", "Slots inside": "Emplacements intérieur", "Slots ratio": "Ratio des emplacements", "Price per slot": "Prix par emplacement", "Armor class": "Classe d'armure", "Zones": "Zones", "Max Durability": "Durabilité max", "Effective Durability": "Durabilité effective", "Repairability": "Réparabilité", "Weight (kg)": "Poids (kg)", "Stats": "Statistiques", "Mov/Turn/Ergo": "Bouger/Tourner/Ergo", "Caliber": "Calibre", "Armor damage": "Dégâts d'armure", "Fragmentation chance": "Chance de fragmentation", "Blindness protection": "Protection contre la cécité", "Hydration": "Hydratation", "Energy": "Énergie", "Hydration Cost": "Coût d'hydratation", "Energy Cost": "Coût en énergie", "Hydration + Energy Value": "Hydratation + valeur énergétique", "Sound suppression": "Suppression du son", "Low": "Bas", "None": "Aucun", "Blocks earpiece": "Blocs écouteurs", "Yes": "Oui", "No": "Non", "Ergonomics": "Ergonomie", "Cost per ergo": "Coût par ergo", "Recoil": "Recul", "Distance": "Distance", "No items": "Pas d'objets", "Not built": "Non construit", "Locked": "Fermé à clé", "Crafting": "Fabrication", "Hideout Management": "Gestion de la planque", "Be the first!": "Soyez le premier!", "Objective": "Objectif", "No objectives": "Pas d'objectifs", "Players": "Joueurs", "By": "Par", "Restock in": "Réapprovisionné", "Support Ukraine": "Supportez l'Ukraine", "Cost per unit": "Coût par unité", "About the tarkov.dev project": "À propos du projet takov.dev", "about-page-description": "Apprenez-en plus sur the-hideout et tarkov.dev. Un écosystème Escape from Tarkov gratuit, communautaire et open source ! Utilisez nos outils pour jouer au jeu ou créez vos propres projets avec notre API gratuite.", "Open source": "Open source", "Discussions & feedback": "Discussions et retours d'expérience", "Support": "Soutien", "about-support-more-p": "<0>Vous pouvez également aider en remontant des bugs, en suggérant ou en implémentant de nouvelles fonctionnalités, en améliorant les cartes ou tout ce à quoi vous pouvez penser qui pourrait améliorer le site.", "about-api-p": "<0>Nous offrons une API 100 % gratuite et accessible au public pour tous vos besoins de développement Tarkov - <1>API.", "History": "Histoire", "about-history-p": "<0>Ce projet est un fork de <1>tarkov-tools.com. Son créateur original, <3>@kokarn, a décidé de fermer le site. Dans un esprit open source, un groupe de développeurs s'est réuni pour le relancer afin de continuer à offrir un excellent site web à la communauté Tarkov et une API pour alimenter le développement des créateurs. Ce projet est désormais 100% open source et axé sur les développeurs. Notre organisation GitHub (<5>the-hideout) regroupe tous les dépôts qui alimentent l'API, ce site web, le bot Discord communautaire, l'infrastructure serveur et bien plus encore ! Nous sommes passionnés par l'open source et apprécions les pull requests pour améliorer notre écosystème pour tous.", "Core Contributors": "Contributeurs principaux", "about-core-contributors-p": "<0>Les principaux contributeurs à ce projet (sans ordre particulier) sont :", "All Contributors": "Tous les contributeurs", "about-all-contributors-p": "<0>Un grand merci à toutes les personnes qui ont contribué à ce projet pour le rendre possible ! ❤️", "Description": "Description", "Hidden": "Caché", "Player %": "Joueur %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "Cette page comprend des informations sur les réalisations qui peuvent être obtenues.", "Ammo chart": "Munitions", "ammo-page-description": "Cette page contient une liste de tous les types de munitions dans Escape from Tarkov. Pour filtrer la liste complète des cartouches disponibles, cliquez sur le nom d'un calibre.", "ammo-page-p": "<0>Les étendues sauvages de Tarkov regorgent de munitions variées. Pour combattre différents adversaires, différents types de munitions sont nécessaires.<1>Cette page contient la liste de tous les types de munitions d'Escape from Tarkov. Pour filtrer la liste complète des cartouches disponibles, cliquez sur le nom d'un calibre.", "Total damage": "Dégâts totaux", "Use total damage of all projectiles in a round": "Utilisez le total des dégâts de tous les projectiles dans un tour", "Ignore settings": "Ignorer mes paramètres", "Shows all sources of items regardless of your settings": "Affiche toutes les sources d'articles quels que soient vos paramètres", "Use barters for item sources": "Utiliser les trocs pour les sources d'objets", "Use crafts for item sources": "Utilisez l'artisanat pour les sources d'objets.", "Ammo Statistics Table": "Tableau de statistiques des munitions", "API Documentation": "Documentation de l'API", "api-docs-page-description": "L'API communautaire d'Escape from Tarkov et sa documentation. Découvrez notre API GraphQL gratuite et facile à utiliser pour EFT.", "api-about-p": "<0>L'API est écrite en GraphQL et nous nous efforçons de respecter les spécifications et de ne pas apporter de modifications radicales. Pour en savoir plus sur les requêtes possibles et la structure du schéma, visitez le Playground et cliquez sur l'onglet 'Docs' à droite. Une fois prêt à tester des requêtes, vous pouvez également les tester dans le Playground. Pour en savoir plus sur les requêtes GraphQL en général, la Fondation GraphQL propose des ressources utiles.<1><0><0>Tarkov.dev GraphQL playground<1><0>Ressources de la Fondation GraphQL<1>Une fois que vous êtes prêt à envoyer des requêtes API depuis l'extérieur du Playground, le point de terminaison est : <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Performances actuelles de l'API", "api-performance-p": "<0>Pour obtenir des informations complètes sur les mesures et les performances de l'API, consultez notre <1>page d'état.", "FAQ": "FAQ", "Is it free?": "C'est gratuit ?", "Is it open source?": "Est-ce que c'est Open Source ?", "api-faq-open-source-p": "Bien sûr ! Le code source de l'API est disponible dans son dépôt GitHub : <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "Y a-t-il une limite de débit ?", "api-faq-rate-limit-p": "Nous sommes parfois confrontés à un trafic important provenant d'acteurs malveillants, ce qui nécessite la mise en place de limites de débit. Les données tarifaires sont mises à jour toutes les 5 minutes ; il est donc inutile d'effectuer des requêtes plus rapidement. Faites preuve de bon sens et tout devrait bien se passer.", "What about caching?": "Et la mise en cache ?", "api-faq-caching-p": "Comme nos données sont mises à jour toutes les 5 minutes, nous mettons également en cache toutes les requêtes GraphQL pendant 5 minutes. Cela permet de réduire considérablement la charge sur nos serveurs et d'accélérer vos requêtes !", "Where is the data from?": "D'où viennent les données ?", "We source data from multiple places to build an API as complete as possible. We use data from:": "Nous recueillons des données à partir de plusieurs endroits pour créer une API aussi complète que possible. Nous utilisons les données de :", "Our network of scanners": "Notre réseau de scanners", "Examples": "Exemples", "example": "exemple", "Contributed by": "Contribué par", "API Users": "Utilisateurs de l'API", "api-users-page-description": "Cette page contient une liste de tous les utilisateurs de l'API publique sur Tarkov.dev et leurs projets.", "api-users-p": "<0>Vous souhaitez figurer sur cette page ? Rejoignez le Discord et partagez vos créations !", "Barter Profits": "Bénéfices d'échange", "barters-page-description": "Cette page comprend des informations sur les différents objets qui peuvent être échangés avec les vendeurs PNJ, les prix de troc et les bénéfices qui peuvent être réalisés en vendant les objets.", "Shows all barters regardless of your settings": "Affiche tous les échanges, quels que soient vos paramètres", "Hide dogtags": "Cacher les plaques d'identification", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "Le vrai \"coût\" d'échange utilisant des dogtags est difficile à estimer, vous voudrez peut-être exclure les barres de dogtag", "Show all barters": "Afficher tous d'échange", "All": "Tout", "Item filter": "Filtre d'articles", "filter on item": "filtrer sur l'article", "barters-page-p": "<0>À l'exception de Fence, tous les commerçants d'Escape from Tarkov proposent des marchandises par troc plutôt que par achat direct.<1>En échange d'une variété d'objets bon marché, le joueur peut fréquemment les échanger contre des objets plus précieux qui peuvent être utilisés ou vendus pour un profit ou contre de l'équipement de niveau supérieur à des niveaux de fidélité inférieurs.<3>N'oubliez pas de vérifier après la réinitialisation vos transactions préférées, car la majorité de ces échanges de valeur ont des limites strictes par réinitialisation du commerçant et sont fréquemment épuisés.", "Num graphic cards": "Nombre de cartes graphiques", "Hours": "Heures", "Bitcoin Farm Calculator": "Calculateur de ferme Bitcoin", "bitcoin-farm-calculator-page-description": "Cette page comprend un outil de calcul qui vous aide à déterminer le prix de construction et de maintenance d'une ferme Bitcoin, en fonction du nombre de GPU, des coûts d'électricité et du coût du bitcoin.", "Graphic cards count": "Nombre de cartes graphiques", "Use fuel cost: {{price}}/day": "Utiliser le coût du carburant: {{price}}/jour", "Use station build costs": "Utiliser les coûts de construction de la station", "Purchase cost": "Coût d'achat", "Remaining days in wipe:": "Jours restants dans le wipe :", "Time to produce 1 bitcoin": "Il est temps de produire 1 bitcoin", "BTC/day": "BTC/jour", "Estimated profit/day": "Profit estimé/jour", "Profitable after days": "Rentable après quelques jours", "Total cost of graphic cards": "Coût total des cartes graphiques", "Build costs": "Coûts de construction", "GPU + build costs": "GPU + Coût de construction", "Remaining profit": "Bénéfice restant", "Map": "Carte", "Spawn Location": "Point d'apparition", "Chance": "Chance", "Count": "Compter", "Spawn chance": "Taux d'apparition", "Chance that the boss spawns on a given map": "Chance que le boss apparaisse sur une carte donnée", "Health": "Santé", "Total boss health": "Santé totale du boss", "Patrol": "Patrouille", "Rush": "Ruée", "Stalker": "Harceleur", "Hostile and accurate": "Hostile et précis", "Patrol and highly armored": "Patrouille et hautement blindé", "Group patrol": "Patrouille de groupe", "Frequent healing and stim injections": "Injections fréquentes de soin et de stimulant", "Sniper": "Tireur d'élite", "Batshit insane": "Complètement taré", "Behavior": "Comportement", "The boss's general AI behavior": "Le comportement général de l'IA du boss", "Wiki": "Wiki", "Boss Stats": "Statistiques de boss", "Special Boss Loot": "Butin spécial", "Spawn Locations": "Points d'apparition", "boss-spawn-table-description": "<0>Carte : le nom de la carte sur laquelle le boss peut apparaître<1>Emplacement d'apparition : l'emplacement exact sur la carte donnée où le boss peut apparaître<2>Chance : si l'option « Chance d'apparition » est activée pour la carte, il s'agit de la probabilité estimée que le boss apparaisse à un emplacement donné sur cette carte", "Boss Escorts": "Escortes de boss", "This boss does not have any escorts": "Ce boss n'a pas d'escortes", "boss-page-description": "Cette page contient des informations sur l'emplacement de {{bossName}}, le butin et les stratégies pour le vaincre.", "bosses-page-description": "Cette page contient les informations sur tous les boss dans le jeu, leurs emplacements, butins, escortes et les stratégies pour les vaincre.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Les boss sont des ennemis redoutés et mortels dotés d'un équipement et de traits uniques dans Escape from Tarkov", "About Bosses": "À propos des boss", "bosses-page-p": "<0>Dans Escape from Tarkov, de nombreux boss rôdent dans la zone assiégée de Norvinsk.<1>Chaque boss possède des comportements, des caractéristiques et des tactiques uniques. Les boss de Tarkov sont craints par les joueurs de tous niveaux et représentent souvent une menace plus grande que les SMP ennemies de la région.<2>Cependant, un risque élevé implique de grandes récompenses. De nombreux boss contiennent des objets de butin de haut niveau ou doivent être éliminés pour accomplir des quêtes. Apprendre les schémas, les emplacements et les tenues spécifiques d'un boss est souvent la meilleure façon pour un joueur de se préparer avant un combat contre un boss dans Tarkov.", "Connect": "Connecter", "Connected to": "Connecté à", "id to control": "identifiant de contrôle", "Remote Control": "Télécommande", "remote-control-page-description": "Cette page contient tous les outils nécessaires pour contrôler à distance une autre instance du site Web Tarkov.dev.", "View Map": "Afficher la carte", "Go": "Aller", "View caliber": "Voir le calibre", "Select...": "Sélectionner...", "Load tarkov.dev in another browser or window to control it from here": "Chargez tarkov.dev dans un autre navigateur ou une autre fenêtre pour le contrôler à partir d'ici", "Hideout Crafts": "Artisanat de planque", "crafts-page-description": "Cette page comprend des informations sur les différents objets qui peuvent être fabriqués dans la cachette, les matériaux et les ressources nécessaires, ainsi que les bénéfices qui peuvent être réalisés en vendant les produits finis.", "Shows all crafts regardless of your settings": "Montre tous les métiers quels que soient vos paramètres", "Average prices": "Prix moyens", "Use average prices from the past 24 hours for profit calculations": "Utiliser les prix moyens des dernières 24 heures pour les calculs de bénéfices", "Most profitable craft in each station": "Artisanat le plus rentable dans chaque station", "Best": "Meilleur", "Flea Market banned items": "Articles interdits aux Marchés", "Empty fuel": "Carburant vide", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "SDéfinit le coût des bidons de carburant pour les objets artisanaux, les obligeant à respecter le prix de vente minimum des vendeurs lors de l'utilisation de bidons de carburant non-FIR.", "crafts-page-p": "<0>Dans Escape from Tarkov, l'artisanat vous permet de créer une variété d'objets. Cela s'effectue grâce à divers modules de planque, notamment le collecteur d'eau, l'établi, la station médicale, les toilettes et l'unité de nutrition.<1>Le statut 'Trouvé lors d'un raid' sera appliqué à chaque objet créé dans la cachette. La liste complète de ces objets est présentée ci-dessus. La compétence Artisanat a un impact sur le temps de création des objets.<2>Lorsque l'icône d'un objet est bordée de bleu, il sera utilisé comme outil auxiliaire et, une fois la fabrication terminée, il sera remis dans votre réserve.", "Page not found": "Page non trouvée", "error-page-description": "Ce n'est pas la page que vous recherchez", "Sorry, that page doesn't exist!": "Désolé, cette page n'existe pas !", "Hideout": "Planque", "hideout-page-description": "Cette page comprend des informations sur les différentes stations et modules qui peuvent être construits avec les matériaux et les ressources nécessaires pour améliorer votre planque.", "Show all stations & modules": "Afficher toutes les stations & modules", "Show built": "Afficher les constructions", "Show already built stations": "Afficher les stations déjà construites", "Show locked": "Afficher verrouillé", "Show unavailable stations": "Afficher les stations indisponibles", "Show all requirements": "Afficher toutes les exigences", "Show trader and other station level requirements": "Afficher les exigences au niveau du trader et des autres stations", "Collected": "Collecté", "Item Tracker": "Tracker d'article", "Only show Found in Raid": "Afficher uniquement les objets trouvés dans Raid", "Reset all tracking": "Réinitialiser tout le suivi", "Hide completed": "Masquer complète", "Hide tasks you've completed": "Masquer les tâches que vous avez terminées", "Hide dogtag barters": "Cacher les échanges de dogtag", "Best price to sell for": "Le meilleur prix pour vendre", "Fee": "Frais", "Profit": "Profit", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "Le dernier prix bas observé pour cet élément sur le marché était {{lastSeenPrice}}.\nCependant, en raison de la façon dont les frais sont calculés, vous feriez mieux de vendre pour {{bestPrice}}.", "Max price to sell for": "Prix maximum à vendre pour", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "Cet article n'a pas été observé sur le marché.\nLe prix rentable maximum est {{bestPrice}}, mais l'article peut ne pas se vendre à ce prix.\nLe prix rentable maximum est affecté par les niveaux de compétences Intel Center et Hideout Management dans vos paramètres.", "Likely sell price": "Prix de vente probable", "item-page-description": "Cette page comprend des informations sur les caractéristiques, les utilisations et les stratégies pour {itemName}}.", "Sell for": "Vendre pour", "Buy for": "Acheter pour", "Flea price history": "Historique des prix du Marchés", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "Changement par rapport à hier : {{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "Prix scanné le plus bas ces 24h : {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Prix scanné le plus élevé au cours des dernières 24h : {{high24hPrice}}", "Updated: {{val, relativetime}}": "Mise à jour: {{val, relativetime}}", "Items contained in {{itemName}}": "Éléments contenus dans {{itemName}}", "Barters with {{itemName}}": "Echange avec {{itemName}}", "Crafts with {{itemName}}": "Artisanat avec {{itemName}}", "Hideout modules needing {{itemName}}": "Modules de planque nécessitant {{itemName}}", "Shows all modules regardless of your settings": "Montre tous les modules quels que soient vos paramètres", "Quests requiring {{itemName}}": "Quêtes nécessitant {{itemName}}", "Quests rewarding {{itemName}}": "Récompenses de quêtes {{itemName}}", "Armors": "Pare-balles", "armors-page-description": "Cette page comprend un tableau triable avec des informations sur les différents types d’armures disponibles dans le jeu, y compris leur prix, réparabilité, classe d’armure et autres caractéristiques.", "Class effective durability": "Classe de durabilité efficace", "Include rigs": "Inclure les équipements", "Max price": "Prix maximum", "max price": "prix maximum", "armors-page-p": "<0>Dans le jeu vidéo Escape from Tarkov, des gilets de protection sont portés pour réduire les dommages causés par les balles. Des casques sont généralement utilisés en plus.", "Backpacks": "Sacs à dos", "backpacks-page-description": "Cette page comprend une table triable avec des informations sur les différents types de sacs à dos disponibles dans le jeu, y compris leur prix, taille, capacité et d’autres caractéristiques.", "Net price per slot": "Prix net par emplacement", "Show price per additional slot of storage gained from the container": "Afficher le prix par emplacement supplémentaire de stockage obtenu dans le conteneur", "backpacks-page-p": "<0>Les sacs à dos dans le jeu Escape from Tarkov sont des conteneurs de différentes tailles pour transporter vos richesses durement gagnées.", "Barter Items": "Objets", "barter-items-page-p": "<0>Ce tableau des articles de troc d’Escape from Tarkov vous permettra de déterminer facilement la valeur de chacun. Il peut être difficile de déterminer quels produits sont suffisamment précieux pour être pris car il y a plus de 150 articles de troc dans le jeu, et les prix du marché aux puces peuvent fluctuer soudainement. Vous pouvez optimiser votre butin à l’aide de ce tableau interactif.", "bsg-category-description": "Découvrez tout ce que vous devez savoir sur {{category}} dans Escape from Tarkov.", "Containers": "Conteneurs", "containers-page-p": "<0>Comme leur nom l’indique, les conteneurs dans Escape from Tarkov sont des objets utilisés pour contenir d’autres choses. Certains de ces objets sont utilisés pour libérer de l’espace d’inventaire en servant de stockage et en occupant moins d’emplacements d’inventaire, mais certains d’entre eux ne peuvent pas être équipés sur le personnage.", "Glasses": "Protections oculaires", "glasses-page-description": "Cette page comprend une table triable avec des informations sur les différents types de verres disponibles dans le jeu, y compris leur prix, classe d’armure et autres caractéristiques.", "glasses-page-p": "<0>Les lunettes dans Escape from Tarkov peut être utilisé pour diminuer le nombre et la quantité de gouttes de pluie sur les écrans des joueurs ainsi que la durée des effets de flashbang.", "Grenades": "Grenades", "grenades-page-description": "Cette page contient une table triable avec des informations sur les différents types de grenade disponible dans le jeu, incluant leur prix, dégâts et autres caractéristiques.", "grenades-page-p": "<0>Il n'existe que quelques types de grenades distinctes pouvant être lancées dans Escape from Tarkov, chacune possédant un effet unique : flash, fumigène, explosive et fragmentation.<1>Les grenades sont fonction de la situation, mais utilisées correctement, elles peuvent avoir des conséquences mortelles. Tout avantage conféré par un équipement de haut niveau peut être entièrement annulé par une seule grenade bien lancée, qu'elle aveugle complètement l'adversaire, le tue instantanément ou le force à quitter sa couverture et à se retrouver face à vos tirs.<3>Cinq facteurs à prendre en compte lors de l'utilisation de grenades jetables : le temps de détonation, le rayon d'explosion, les dégâts des fragments, le nombre de fragments et même le poids de la grenade. Chaque composant a des utilisations spécifiques.", "Guns": "Armes", "guns-page-description": "Cette page comprend une table triable contenant des informations sur les différents types d'armes disponibles dans le jeu, y compris leur prix, leurs dégâts, leur précision et d'autres caractéristiques.", "guns-page-p": "<0>Votre principal outil de survie est une arme. Presque toutes les armes sont entièrement modulaires, ce qui permet de les personnaliser pour différents scénarios. Toutes les armes utilisées dans Escape from Tarkov sont répertoriées sur cette page.", "Headsets": "Casques électroniques", "headsets-page-description": "Cette page comprend une table triable contenant des informations sur les différents types de casques disponibles dans le jeu, notamment leur prix, leur disponibilité et d'autres caractéristiques.", "headsets-page-p": "<0>Dans Escape from Tarkov, les casques amplifient les bruits de basse fréquence comme les pas tout en atténuant les stimuli impulsifs comme les coups de feu. Différents profils audio sont proposés selon les modèles.", "Helmets": "Casques", "helmet-page-description": "Cette page comprend une table triable contenant des informations sur les différents types de casques disponibles dans le jeu, y compris leur prix, leur classe d'armure et d'autres caractéristiques.", "Show blocking headset": "Afficher le blocage du casque", "Min armor class": "Classe de protection minimale", "helmets-page-p": "<0>Dans Escape from Tarkov, les casques remplissent diverses fonctions.<1>Il existe des objets utiles, des objets décoratifs et des casques de sécurité. Avant de combattre, choisir un casque qui protégera différentes parties de la tête est crucial.<3>L'impact des différents casques sur la réduction du bruit est un autre facteur crucial à prendre en compte. Le gameplay d'Escape from Tarkov repose fortement sur le son.<5>Les casques modulaires, composés de divers composants, constituent un autre aspect d'Escape from Tarkov. Ces casques peuvent modifier le nombre de segments qu'ils protègent : le haut, la nuque, les oreilles, les yeux et la mâchoire.", "items-page-description": "Cette page comprend des liens vers des pages contenant des informations sur différentes catégories d'objets, notamment des armures, des sacs à dos, des objets de troc, des conteneurs, des lunettes, des grenades, des armes à feu, des casques, des casques, des clés, des mods d'armes à feu, des poignées de pistolet, des provisions, des plates-formes, des suppresseurs, et plus encore.", "Keys": "Clés", "keys-page-description": "Cette page comprend une table triable contenant des informations sur les différents types de clés disponibles dans le jeu, y compris leur prix, leur rareté et d'autres caractéristiques.", "keys-page-p": "<0>Les objets de renseignement contiennent des cartes, des clés, des cartes-clés et d'autres objets utiles. Ils vous aideront à garder une longueur d'avance sur vos adversaires, ou du moins à savoir où vous en êtes dans Escape from Tarkov.<1>La durabilité restante des clés et des cartes-clés à usage limité est affichée en bas à droite de leur icône et sur leur écran d'inspection.", "Mods": "Mods", "mods-page-description": "Cette page comprend une table triable contenant des informations sur les différents types de mods d'armes disponibles dans le jeu, y compris leur prix, leur compatibilité et d'autres caractéristiques.", "mods-page-p": "<0>Dans Escape from Tarkov, les performances et le fonctionnement d'une arme sont contrôlés par des mécanismes élaborés organisés en cinq catégories :<1><0>Modifications fonctionnelles<1>Dispositifs de bouche (Modifications fonctionnelles)<2>Viseurs (Modifications fonctionnelles)<3>Modifications d'équipement<4>Pièces vitales", "Pistol Grips": "Poignées pistolet", "pistol-page-description": "Cette page comprend un tableau triable contenant des informations sur les différents types de poignées de pistolet disponibles dans le jeu, y compris leur prix, leur ergonomie, leur compatibilité et d'autres caractéristiques.", "Filter by gun": "Filtrer par armes", "select a gun": "Sélectionnez une arme", "pistol-grips-page-p": "<0>Dans Escape from Tarkov, les poignées et les crosses de pistolet sont des éléments essentiels d'une arme.<1>Sur cette page, vous pouvez les trier, acheter des améliorations ergonomiques ou leur coût et voir sur quelle arme ils peuvent être montés.", "Provisions": "Provisions", "provisions-page-description": "Cette page comprend une table triable avec des informations sur les différents types de provisions disponibles dans le jeu, y compris leur hydratation, leur énergie, leur prix le moins cher et leur valeur chez les commerçants ou au marché aux puces.", "Total energy cost": "Coût énergétique total", "Include the cost of lost hydration in the cost of energy": "Inclure le coût de l'hydratation perdue dans le coût de l'énergie", "provisions-page-p": "<0>Dans Escape from Tarkov, les provisions sont utilisées pour reconstituer l'énergie et l'hydratation.<1>Votre niveau de compétence en métabolisme déterminera leur efficacité.", "Rigs": "Tactiques", "rigs-page-description": "Cette page comprend une table triable contenant des informations sur les différents types de plates-formes disponibles dans le jeu, y compris leur prix, leur taille intérieure et extérieure, leur poids, leur compression et d'autres caractéristiques.", "Armored rigs?": "Plateformes pare-balles ?", "Min slots": "Emplacements minimum", "3-slot": "3-slot", "4-slot": "4-slot", "rigs-page-p": "<0>Pour transporter et stocker munitions et chargeurs lors de vos excursions dans Escape from Tarkov, les gilets tactiques sont essentiels. Certains offrent même une sécurité supplémentaire.", "Suppressors": "Réducteurs de son", "suppressors-page-description": "Cette page comprend un tableau triable contenant des informations sur les différents types de suppresseurs disponibles dans le jeu, y compris leur ergonomie, leur recul et leur prix le moins cher.", "suppressors-page-p": "<0>Dans Escape from Tarkov, un suppresseur est un dispositif de bouche (un mod fonctionnel) et peut être installé sur une arme pour étouffer le bruit des coups de feu.<1>Sur cette page, vous pouvez les trier par prix, pénalité d'ergonomie, amélioration du recul ou leur coût et voir sur quelle arme ils peuvent être directement montés.", "Barters": "Échanges", "Marked": "Marqué", "Wearables": "Portables", "loot-tiers-page-description": "Découvrez les différents types de butin disponibles dans le jeu, leur valeur, leur rareté et ce qu'il faut conserver et ce qu'il faut jeter.", "Ranking the most valuable items in the game": "Classement les objets les plus précieux du jeu", "Include Marked": "Inclure marqué", "Group by type": "Regrouper par type", "min value": "valeur min", "Only show markers for active tasks": "Afficher uniquement les marqueurs pour les tâches actives", "Map of {{mapName}}": "Carte de {{mapName}}", "maps-page-description": "Obtenez les dernières informations sur toutes les cartes d'Escape from Tarkov, y compris les points d'extraction et les emplacements de butin. Découvrez où trouver le meilleur équipement et les meilleures ressources du jeu", "maps-page-p": "<0>La carte Escape from Tarkov compte 11 lieux différents, dont 10 ont déjà été rendus publics. Bien qu'à terme, toutes les cartes soient connectées, elles sont actuellement toutes distinctes les unes des autres.", "Streets of Tarkov": "Rues de Tarkov", "Ground Zero": "Point Zero", "Customs": "Douanes", "Factory": "Usine", "Interchange": "Échangeur", "The Lab": "Le Labo", "Lighthouse": "Phare", "Reserve": "Base militaire", "Shoreline": "Littoral", "Woods": "Bois", "Openworld": "Monde ouvert", "Tarkov.dev {{bot}} integration": "Tarkov.dev {{bot}} intégration", "bot-page-description": "Cette page contient tout ce qui est nécessaire pour intégrer {{bot}} avec Tarkov.dev.", "You can add command to your moobot to get price check in your twitch chat": "Vous pouvez ajouter une commande à votre moobot pour obtenir une vérification des prix dans votre chat Twitch", "Instructions": "Instructions", "Register at": "Inscrivez-vous sur", "using your twitch account": "en utilisant votre compte Twitch", "Go to Custom commands": "Aller aux commandes personnalisées", "Set what you want the command to be. Common is \"p\" or \"price\"": "Définissez ce que vous voulez que la commande soit. Les valeurs les plus courantes sont \"p\" ou \"prix\"", "Press the \"Create\" button": "Appuyez sur le bouton \"Créer\"", "In response choose URL Fetch - Full (plain) response": "En réponse, choisissez URL Fetch - Réponse complète (simple)", "and after insert \"Command arguments\"": "et après insérer \"arguments de commande\"", "Now press \"Save\" button": "Appuyez maintenant sur le bouton \"Enregistrer\"", "Big thanks to": "Un grand merci à", "for feedback": "pour les commentaires", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "Vous pouvez ajouter une commande à votre nightbot pour obtenir une vérification des prix dans votre chat Twitch / Youtube", "using your twitch / youtube account": "en utilisant votre compte Twitch / Youtube", "Go to dashboard": "Aller au tableau de bord", "Click the \"Join Channel\" button": "Cliquez sur le bouton \"Rejoindre la chaîne\"", "Make bot - moderator, just type /mod nightbot in your chat": "Make bot - modérateur, tapez simplement /mod nightbot dans votre chat", "Go to custom commands": "Allez aux commandes personnalisées", "Press the \"Add command\" button": "Appuyer sur le bouton \"Ajouter une commande\"", "Command: !p or anything you like": "Commande: !p ou tout ce que vous voulez", "Message:": "Message :", "Press \"Submit\"": "Appuyez sur \"Soumettre\"", "Trader Levels": "Niveaux de marchand", "Trader Reputation": "Réputation du marchand", "Prerequisite Tasks": "Tâches préalables", "Start Requirements": "Exigences de démarrage", "Attributes": "Les attributs", "Contains All": "Contient tout", "Contains Item in Category": "Contient un élément dans la catégorie", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Applique les effets {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Applique les effets {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Applique les effets {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "using extract: {{extractName}}": "En utilisant l'extraction : {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extraire avec le(s) statut(s) : {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extraire {{extractCount}} fois avec le(s) statut(s) : {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x l'un des", "Dogtag level": "Niveau de dogtag", "Max durability": "Durabilité max", "Min durability": "Durabilité min", "Kill": "Tuer", "Shoot": "Tirer", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "Pendant les heures : {{hourStart}}:00 à {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "À distance : {{operator}} {{count}} mètres", "From distance: {{operator}} {{count}} meters_many": "À distance : {{operator}} {{count}} mètres", "From distance: {{operator}} {{count}} meters_other": "À distance : {{operator}} {{count}} mètres", "While inside: {{zoneList, list(type: disjunction)}}": "À l'intérieur : {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Frapper : {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Utilisation d'arme :", "Using weapon mods:": "Utilisation de mods d'armes :", "While wearing:": "En portant :", "Not wearing:": "Ne pas porter :", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Tout en ayant le(s) effet(s) {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Tout en ayant le(s) effet(s) {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Tout en ayant le(s) effet(s) {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "Tout en ayant le(s) effet(s) {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Tout en ayant le(s) effet(s) {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Tout en ayant le(s) effet(s) {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Tout en ayant le(s) effet(s) {{effectNames, list}} sur vos {{bodyParts, list(type: disjunction)}} pendant {{operator}} {{count}} secondes", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "Alors que la cible a le(s) effet(s) {{effectNames, list}} sur ses {{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "Obtenir la compétence de niveau {{level}} {{skillName}}", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} reputation", "In area(s): {{areaList, list(type: disjunction)}}": "Dans la ou les zones : {{areaList, list(type : disjonction)}}", "Use any of:": "Utilisez l’un des :", "Reach level {{playerLevel}}": "Atteindre le niveau {{playerLevel}}", "optional": "facultatif", "Trader Standing": "Marchand debout", "Skill Level": "Niveau de compétence", "Trader Offer Unlock": "Offre de marchand débloquée", "Trader Unlock": "Marchand débloqué", "Craft Unlock": "Artisanat débloqué", "task-page-description": "Cette page contient des informations sur les objectifs, les récompenses et les stratégies pour accomplir la tâche {{questName}}. Obtenez des conseils pour préparer et réussir votre mission.", "TarkovTracker": "TarkovTracker", "Leads to": "Mène à", "(on failure)": "(en échec)", "Task Details": "Détails de la tâche", "Objectives": "Objectifs", "Fail On": "Fail On", "Needed Keys": "Clés requises", "Task Start": "Début de la tâche", "Task Completion": "Achèvement de la tâche", "Rewards": "Récompenses", "Task Failure": "Échec de la tâche", "Can be restarted": "Peut être redémarré", "Cannot be restarted": "Ne peut pas être redémarré", "Penalties": "Pénalités", "tasks-page-description": "Découvrez tout ce qu'il faut savoir sur les tâches dans Escape from Tarkov. Découvrez les différents types de tâches disponibles dans le jeu, comment les accomplir et les récompenses que vous pouvez obtenir.", "Hides completed tasks": "Masque les tâches terminées", "Hide locked": "Masquer verrouillé", "Hides locked tasks": "Masque les tâches verrouillées", "Show all tasks": "Montrer toutes les tâches", "Name filter": "Filtre par nom", "filter on task name": "filtrer sur le nom de la tâche", "quests-page-p": "<0>Les commerçants d'Escape from Tarkov ont un certain nombre de tâches que vous pouvez accomplir.<1>En échange de la récupération d'objets, de l'élimination de cibles et de l'exécution d'autres actions lors du raid, vous pouvez augmenter votre réputation auprès des commerçants et gagner des objets de valeur.", "Settings": "Paramètres", "settings-page-description": "Cette page contient les paramètres utilisateur sur Tarkov.dev.", "Language": "Langue", "General": "Général", "Has flea": "Avec le Marché", "Use TarkovTracker": "Utiliser TarkovTracker", "TarkovTracker API Token": "Jeton API TarkovTracker", "API Token": "Jeton API", "Stations": "Stations", "Skills": "Compétences", "Dogtag Barters": "Échanges de plaques d'identité", "Exclude": "Exclure", "Minimum dogtag level": "Niveau de dogtag minimum", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Niveau minimum de dogtag à utiliser pour calculer le coût des échanges de dogtags", "The current estimated average player level is {{avgPlayerLevel}}": "Le niveau de joueur moyen estimé actuel est {{avgPlayerLevel}}", "Miscellaneous": "Divers", "Hide remote control": "Masquer la télécommande", "start-page-description": "Consultez toutes les informations sur les objets, l'artisanat, les échanges, les cartes, les niveaux de butin, les profits des cachettes, les détails des commerçants, une API gratuite et bien plus encore avec tarkov.dev ! Un écosystème gratuit, communautaire et open source d'outils et de guides pour Escape from Tarkov.", "Load More": "Charger plus", "Tools": "Outils", "Ammo chart filter": "Graphique des munitions", "Traders barter profit": "Bénéfices d'échange", "Hideout crafts profit": "Artisanat de planque", "Loot tiers ranking": "Classement des niveaux de butin", "Average wipe length": "Durée de wipe moyenne", "Bitcoin farm profit": "Profit de la ferme à Bitcoin", "Invite Discord bot": "Inviter le bot Discord", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "Tarkov.dev est une boite à outils open source pour Escape de Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "Il est conçu et maintenu par la communauté pour vous aider dans vos quêtes, vos échanges sur les marchés aux puces et pour améliorer votre jeu ! L'API est également disponible gratuitement pour vous permettre de créer vos propres outils et services liés à EFT.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "Vous pouvez ajouter une commande à votre bot StreamElements pour obtenir une vérification des prix dans le chat de votre chaîne Twitch / Youtube", "Make bot - moderator, just type /mod streamelements in your chat": "Make bot - modérateur, tapez simplement / mod StreamElements dans votre chat", "Press the \"Add new command\" button": "Appuyez sur le bouton \"Ajouter une nouvelle commande\"", "Press \"Activate Command\"": "Appuyez sur \"Activer la commande\"", "Player level": "Niveau du joueur", "Reputation": "Réputation", "Commerce": "Commerce", "Trader {{trader}}": "Marchand {{trader}}", "trader-page-description": "Obtenez les dernières informations sur le marchand {{trader}} dans Escape from Tarkov. Découvrez les objets qu'il vend selon votre niveau de fidélité et comment maximiser votre cashback pour augmenter votre niveau de fidélité.", "Items with the best cash back prices for leveling": "Articles avec les meilleurs prix de remise en argent pour la montée de niveau", "Spending": "Dépenses", "Unlocks at Loyalty Level {{level}}": "Débloqué au niveau de fidélité {{level}}", "Tasks given by {{traderName}}": "Tâches données par {{traderName}}", "traders-page-description": "Découvrez tout ce que vous avez besoin de savoir sur les marchands dans Escape from Tarkov. Apprenez à connaître les différents marchands disponibles dans le jeu, leur emplacement et les objets qu'ils vendent.", "About Traders": "À propos des marchands", "traders-page-p": "<0>Les piliers du commerce dans la ville détruite et assiégée de Norvinsk. Dans Escape from Tarkov, chaque marchand se spécialisait dans un type de produit particulier, comme des fournitures médicales, des armes ou du matériel militaire. Bien que leurs prix soient généralement élevés, vous en avez pour votre argent.<1>Plus important encore, vous pouvez développer votre réputation auprès de chaque marchand grâce aux quêtes, ce qui vous permettra de recevoir de meilleures offres et de réduire leur commission (une marge supplémentaire sur les ventes et les achats), entre autres avantages.<2>De plus, les marchands proposent d'autres services comme l'assurance et les réparations (vous permettant de récupérer votre équipement en cas de décès lors d'un raid).", "Patch": "Correctif", "Wipe start": "Début de wipe", "Wipe end": "Fin de wipe", "Ongoing wipe": "Wipe en cours", "{{count}} days_one": "{{count}} jours", "{{count}} days_many": "{{count}} jours", "{{count}} days_other": "{{count}} jours", "{{count}} months_other": "{{count}} mois", "{{count}} years_one": "{{count}} années", "Wipe Length": "Durée des wipe", "wipe-length-description": "Obtenez les dernières informations sur la durée de wipe moyenne dans Escape from Tarkov. Trouvez combien de temps dure un wipe en moyenne et préparez vous pour le prochain wipe.", "Average Wipe Length among last 6 wipes:": "Durée moyenne d'un wipe sur les 6 derniers wipes :", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "cookie-consent": "tarkov.dev utilise des cookies pour améliorer votre expérience. En poursuivant votre navigation sur ce site, vous acceptez l'utilisation de cookies. Ils servent à mémoriser vos paramètres et les fonctionnalités que vous activez.", "I understand": "Je comprends", "Map Icons": "Icônes de carte", "Map marker icons by": "Icônes de marqueur de carte par", "The Official Escape From Tarkov Wiki": "le Wiki officiel Escape From Tarkov", "Rarity": "Rareté", "Currency Converter": "Convertisseur de devises", "Converter": "Convertisseur", "Convert one currency to another": "Convertir une devise en une autre", "Reset": "Réinitialiser", "Only show ammo available from traders on your settings": "Afficher uniquement les munitions disponibles auprès des marchands dans vos paramètres", "Trader Ammo": "Dispo marchands", "control-info-p": "<0>Cette page vous permet de contrôler le site web Tarkov.dev depuis un autre navigateur. L'utilisation typique consiste à ouvrir le site web Tarkov.dev dans un navigateur sur un deuxième écran pendant que vous jouez, et cette page sur votre téléphone ou un autre appareil. Vous pouvez ainsi naviguer entre les différentes pages du site sans avoir à quitter le jeu avec Alt+Tab. Il vous suffit d'ouvrir le site web Tarkov.dev dans le navigateur de votre choix, de cliquer sur le bouton « Cliquer pour se connecter » en bas à gauche*, puis d'utiliser l'identifiant affiché sur cette page sur l'appareil de contrôle et de cliquer sur \"Se connecter\". Une fois connecté, vous pouvez utiliser cette page de contrôle pour ouvrir des pages de cartes ou de munitions spécifiques dans le navigateur contrôlé.<1>*Par défaut, elle apparaît en bas à gauche, mais peut être basculée en bas à droite de l'écran. Elle peut également être masquée via l'option \"Masquer la télécommande\" dans les paramètres.", "Other Options": "Autres options", "This task {{taskStatus}}": "Tâche {{taskStatus}}", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Bot Discord Stash", "More Tools": "Plus d’outils", "Companion app": "Application compagnon", "Discord companion": "Compagnon Discord", "Download latest release": "Télécharger la dernière version", "View on GitHub": "Voir sur GitHub", "Join the community": "Rejoindre la communauté", "Screenshot of TarkovMonitor showing timers and integrations": "Capture d’écran de TarkovMonitor affichant les minuteries et les intégrations", "Visual timers, raid state, and integration health in TarkovMonitor.": "Minuteries visuelles, état de raid et santé des intégrations dans TarkovMonitor.", "Main Features": "Fonctionnalités principales", "tarkov-monitor-page-description": "Apprenez à installer TarkovMonitor, à le connecter à TarkovTracker et à l’utiliser pour piloter les cartes de Tarkov.dev.", "tarkov-monitor-summary": "TarkovMonitor fournit des alertes et des minuteries utiles pour Escape From Tarkov afin de gérer vos raids sans interrompre la partie.", "tarkov-monitor-feature-audio": "Alertes audio pour l’attente, le début de raid, le minuteur runthrough, le temps de recharge scav et les notifications du filtre à air.", "tarkov-monitor-feature-map": "Ouverture automatique de la carte sur Tarkov.dev en fonction de la localisation que vous rejoignez.", "tarkov-monitor-feature-screenshot": "Affichage optionnel de la position déclenché par capture d’écran pour partager rapidement votre localisation.", "tarkov-monitor-feature-quests": "Mises à jour automatiques des quêtes vers TarkovTracker dès qu’une complétion est détectée.", "tarkov-monitor-feature-stats": "Statistiques locales comme les revenus du marché, la durée des files d’attente et la fréquence des cartes.", "tarkov-monitor-feature-timers": "Minuteries visibles du temps en raid et du délai scav pour planifier votre prochaine sortie.", "Download": "Télécharger", "tarkov-monitor-download-1": "Récupérez la dernière archive TarkovMonitor.zip sur GitHub.", "tarkov-monitor-download-2": "Extrayez l’archive où vous voulez sur votre PC.", "tarkov-monitor-download-3": "Lancez TarkovMonitor.exe et gardez-le ouvert pendant que vous jouez.", "Community support": "Support communautaire", "tarkov-monitor-community": "Des questions ou envie d’échanger avec d’autres utilisateurs ? Rejoignez le serveur Discord pour obtenir des conseils, de l’aide et discuter des fonctionnalités.", "Join the Discord": "Rejoindre le Discord", "Security": "Sécurité", "tarkov-monitor-security": "TarkovMonitor n’est pas une triche. Il lit uniquement les journaux d’Escape From Tarkov sur votre PC et ne modifie jamais le jeu ni n’injecte de code.", "stash-page-description": "Invitez le bot Discord Stash, explorez ses commandes et voyez comment il peut aider votre communauté.", "stash-hero": "Stash alimente Discord avec l’intégralité des données de Tarkov.dev pour que votre communauté consulte les prix, les quêtes, les minuteries de planque et plus encore sans quitter le chat.", "Invite Stash": "Inviter Stash", "Report an issue": "Signaler un problème", "Highlights": "Points forts", "Item intelligence": "Analyse des objets", "Instant prices with flea, trader, and craft context.": "Prix instantanés avec contexte marché, marchands et artisanat.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Les recherches craft/échange réutilisent les données de rentabilité de Tarkov.dev.", "Toggle PVE or PMC game modes to match your server rules.": "Passez en mode PVE ou PMC pour adapter les réponses du bot aux règles de votre serveur.", "Progress tracking": "Suivi de progression", "Quest command lists requirements, turn-ins, and rewards.": "La commande de quêtes liste les exigences, dépôts et récompenses.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "La commande progress reflète les améliorations de planque et de marchands sauvegardées sur TarkovTracker.", "Restock and status alerts keep everyone informed between raids.": "Les alertes de réapprovisionnement et d’état informent tout le monde entre deux raids.", "Community tools": "Outils communautaires", "Goons tracker for spotting the Rogue Boss trio.": "Suivi des Goons pour repérer le trio de boss Rogues.", "Roulette mini-game for fun raid modifiers.": "Mini-jeu de roulette pour des modificateurs de raid amusants.", "Slash commands, autocomplete, and localized responses.": "Commandes slash, saisie semi-automatique et réponses localisées.", "Frequently used commands": "Commandes les plus utilisées", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash propose des dizaines de commandes slash. Voici celles sur lesquelles la plupart des serveurs comptent :", "Command": "Commande", "Example": "Exemple", "Support & feedback": "Support & retours", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "Besoin de la politique de confidentialité ou des conditions d’utilisation pour l’audit sécurité de votre serveur ? Elles se trouvent dans le dossier /assets du dépôt et sont mises à jour à chaque version.", "stash-tech-note": "Besoin de guides techniques ou d’instructions d’auto-hébergement ? Consultez le README sur GitHub pour la documentation la plus récente.", "card-tarkov-monitor-desc": "Automatisez le suivi TarkovTracker, capturez les temps d’attente et pilotez les cartes Tarkov.dev avec une seule application Windows.", "card-stash-desc": "Commandes slash pour vérifier les prix, les quêtes, la planque et les réapprovisionnements directement depuis Tarkov.dev.", "Read more": "En savoir plus", "Invite now": "Inviter maintenant", "other-tools-page-description": "Découvrez les applications compagnon créées par l’équipe Tarkov.dev, dont TarkovMonitor et le bot Discord Stash.", "other-tools-body": "<0>Tarkov.dev est plus qu’un site. Ces outils prolongent vos raids, streams et communautés Discord grâce au même jeu de données open source. Explorez chaque outil pour voir captures, guides et liens de support.", "Learn about TarkovMonitor": "Découvrir TarkovMonitor", "Meet the Stash bot": "Rencontrer le bot Stash", "The help command to view all available commands": "Commande d’aide pour afficher tous les commandes disponibles", "View details about the bot": "Voir les détails du bot", "Get a sorted ammo table for a certain ammo type": "Obtenir un tableau de munitions trié pour un calibre précis", "Check barter details for an item": "Vérifier les détails d’échange d’un objet", "Get detailed information about a boss": "Obtenir des informations détaillées sur un boss", "Get the latest game changes from tarkov-changes.com": "Recevoir les derniers changements du jeu depuis tarkov-changes.com", "Check crafting details for an item": "Consulter les détails de fabrication d’un objet", "Set the game mode (regular, PVE) for bot responses": "Définir le mode de jeu (PvP ou PvE) pour les réponses du bot", "Check or report the location of the Goons": "Vérifier ou signaler la position des Goons", "Get a Discord invite link for the bot to join it to another server": "Obtenir un lien d’invitation Discord pour ajouter le bot à un autre serveur", "Report an issue with the bot": "Signaler un problème avec le bot", "Get price, craft, barter, etc. information about an item": "Obtenir des informations de prix, craft, échange, etc. pour un objet", "Get a key's price and maps it is used on": "Connaître le prix d’une clé et les cartes où elle s’utilise", "View a map and some general info about it": "Afficher une carte et des informations générales", "Get the latest official patchnotes for EFT": "Obtenir les dernières notes de mise à jour officielles d’EFT", "Get player profile information": "Obtenir les informations de profil d’un joueur", "Get a detailed output on the price of an item, its price tier, and more!": "Recevoir un rapport détaillé sur le prix d’un objet, son palier et plus encore !", "Manage your customized hideout and trader progress": "Gérer votre progression personnalisée de planque et de marchands", "Get detailed information about a quest": "Obtenir des informations détaillées sur une quête", "Show or set alerts for trader restock timers": "Afficher ou définir des alertes pour les minuteries de réapprovisionnement des marchands", "Play a game of roulette to determine how you play your next raid": "Jouer à la roulette pour déterminer votre prochain raid", "Get the game/server/website status of Escape from Tarkov": "Connaître l’état du jeu/serveur/site d’Escape from Tarkov", "Get information about a in-game stim": "Obtenir des informations sur un stimulant en jeu", "Show the criteria for loot tiers": "Afficher les critères des niveaux de butin", "Get the bot's uptime": "Connaître le temps de fonctionnement du bot", "stash-support": "<0>Stash est maintenu par l’équipe Tarkov.dev. Un bug ou une idée ? Ouvrez un ticket sur <1>GitHub ou discutez avec les développeurs sur le <2>Discord Tarkov.dev. Si vous synchronisez Tarkov.dev et les données du bot, pensez à joindre des captures et des étapes de reproduction.", "Database": "Base de données", "Calculators": "Calculateurs", "Progression": "Progression", "Community": "Communauté", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/it/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Ragazzi subdoli. I cultisti si nascondono nell'ombra in gruppi di 3-5 in attesa che un giocatore si avvicini. Si avvicinano silenziosamente ai nemici e li pugnalano usando normali coltelli o, nel caso dei sacerdoti, il Pugnale cultista avvelenato. Se vengono attaccati, i cultisti rispondono al fuoco con armi da fuoco e granate. Dopo aver attaccato un giocatore con il loro coltello, possono scegliere di spento nel bosco e tornare nell'ombra.", "knight-bio": "", "knight-description": "Il leader dei 'Goons'. Può spawnare in molte mappe diverse.", "glukhar-bio": "Non ci sono informazioni affidabili sulle sue attività passate perché tutti i documenti sono andati persi o sono stati classificati, ma secondo informazioni non verificate, aveva il grado di sottufficiale. Ha partecipato a operazioni di combattimento. Conosceva i fondamenti della tattica e li usava attivamente per rivendicare o difendere vari territori.
    Anche tutto il suo gruppo sembra essere composto da ex militari. Anche se ora il suo gruppo è solo un bandito di fatto che lotta per le risorse e l'influenza a Tarkov. Ha contatti con mercanti in grado di esportare buoni dalla regione di Norvinsk, che gli inviano regolarmente gli ultimi treni funzionanti per il trasporto di merci.", "glukhar-description": "Glukhar e le sue numerose guardie sono estremamente ostili. È molto improbabile che si riesca a combattere in aree aperte. Sono preferibili piccoli corridoi e stanze chiuse. Glukhar e le sue guardie sono molto precisi. Glukhar e le sue guardie rimarranno sempre vicini e le sue guardie lo seguiranno ovunque vada.", "kaban-bio": "Un tempo aveva una piccola attività legale a Tarkov, ma non aveva paura di usare metodi criminali per acquisire denaro. Dopo l'evacuazione generale è rimasto in città e la sua banda è cresciuta.", "kaban-description": "La sua stazza gli permette di sparare con diverse mitragliatrici pesanti senza appoggiare l'arma, ma allo stesso tempo Kaban non può permettersi di essere agile e quindi rimane in posizione o si sposta lentamente da un punto all'altro durante il combattimento. Ha un gran numero di guardie ben armate, alcune delle quali sono ex militari che hanno organizzato una forte difesa per lui. Il boss è stanziato nell'area dell'autofficina di \"Streets of Tarkov\". L'area è pesantemente difesa, gli ingressi sono fortificati con mitragliatrici fisse e AGS, i sentieri sono minati e ci sono cecchini sul tetto del centro di assistenza auto. Kaban utilizza un giubbotto personalizzato per riporre le scatole di mitragliatrici, indossa un'armatura sotto i vestiti e ha un'autorità indiscutibile tra le sue guardie. Gli Scav nelle vicinanze lo aiuteranno a difendersi combattendo per lui.", "killa-bio": "", "killa-description": "Il vero Giga Chad di Tarkov. Killa usa una mitragliatrice leggera o un'altra arma automatica per sopprimere il nemico mentre si apposta da una copertura all'altra avvicinandosi all'obiettivo per la spinta finale. Durante l'assalto si muove a zig-zag, usa granate fumogene e a frammentazione e sopprime senza sosta i nemici con il fuoco automatico. Seguirà il suo bersaglio per grandi distanze al di fuori del suo percorso di pattugliamento, quindi assicurati di correre molto lontano per sfuggirgli se ti ha chiuso.", "kollontay-bio": "He is a former officer of the MVD (Ministry of Internal Affairs), during his service in law enforcement he had a reputation as a vile man, whose behavior was sometimes feared by his coworkers. During his work, he often resorted to his favorite method of interrogation - a rubber baton, as well as other non-statutory pressure on someone who was not to his liking. Thanks to his physical strength and bold temperament, after the events of the TerraGroup scandal, he formed a gang and began to do what he himself was recently supposed to combat - looting and banditry. However, even before the conflict, he often provided protection to local \"businessmen\". For example, his good relations with Kaban are well-known.", "kollontay-description": "Kollontay has a small number of guards, prefers to stay in one position and occasionally patrols his territory. If he feels he has the upper hand, he may switch to his police baton. He lives in the area around Klimov Shopping Mall and the Tarkov Academy of the Ministry of Internal Affairs.", "partisan-bio": "There are few reliable details about his past, but it's known that he once served in Afghanistan, where his radical methods of warfare took root. Referred to by some as 'Partizan', he became notorious for his expertise in setting traps and mines. His reputation for eliminating enemies often came down to catching them off guard, using their overconfidence against them. Partizan's knowledge of guerrilla tactics made him a dangerous adversary, able to turn any location—whether forest or building—into a deadly trap.
    Those who survive long enough to learn his ways may just find themselves in his good graces, but only if they're careful enough to see the traps before it's too late.", "partisan-description": "", "raider-bio": "", "raider-description": "I Scav raider (noti anche come semplicemente 'raider') sono Scav avanzati, molto più forti e tattici dei tipici Scav. Portano con sé armi molto più pericolose e usano munizioni di livello più alto. Inoltre, hanno una mira molto migliore e spesso possono far cadere giocatori ben equipaggiati con pochi proiettili (o ti becchi un testa-occhio). I Banditi scav pattugliano anche in gruppi multipli e di solito si distinguono per l'equipaggiamento, la voce unica e l'aggressività generale. I Scav raider iniziano in modo amichevole con tutti gli altri Scav (compresi i giocatori Scav), ma diventano ostili se ci si avvicina e si ignorano i loro avvertimenti verbali. Diventano ostili anche a tutti gli Scav se uno Scav li fa arrabbiare.", "reshala-bio": "", "reshala-description": "Di solito cerca di rimanere nelle retrovie del combattimento, nascosto alla vista del giocatore. Inoltre, non indossa mai un'armatura. Se sei uno scav giocatore, fai attenzione perché se hai un karma scav basso Reshala o le sue guardie possono spararti senza provocazione o spararti se ti avvicini a Reshala. Le sue guardie sono talvolta note per dare avvertimenti agli scav giocatori con un karma basso prima di diventare ostili.", "rogue-bio": "", "rogue-description": "I Rogue difendono l'impianto di trattamento dell'acqua e le aree circostanti di Lighthouse. Il loro comportamento principale è la pattuglia, ma spesso prendono posizioni difensive sui tetti e usano armi piazzate. Prendono di mira tutti i giocatori che entrano nella loro area, ma sono leggermente più indulgenti nei confronti dei PMC USEC e degli Scav. I Rogue possono anche spawnare dalla zona del faro meridionale (isola). I Rogue sono estremamente pericolose grazie all'elevata precisione del raggio laser sulla salute e all'alta distanza di puntamento. I Rogue corrono anche dietro una copertura e usano i Medicinali se sono ferite.", "sanitar-bio": "Ex medico e scienziato. Ha lavorato per TerraGroup. Ha diretto diversi progetti in laboratorio, tra cui lo sviluppo di nuove sostanze psicoattive. L'area di ricerca si estendeva dall'influenza di varie condizioni sul corpo allo sviluppo di neurostimolanti. Oltre al laboratorio di TerraGroup, aveva un proprio ufficio presso il Resort Azure Coast, dove ha condotto ricerche, soprattutto nelle ultime settimane prima dell'evacuazione completa.
    Spesso si recava in missione nelle zone d'Evacuazione insieme al corpo medico e, dopo aver iniziato a lavorare per la corporazione, ha visitato regolarmente gli uffici africani e altri uffici, supervisionando gli sviluppi. Si è guadagnato un'autorità indiscussa e il rispetto dei colleghi.", "sanitar-description": "Quando è impegnato in un combattimento, combatte a fianco dei suoi compagni Scav e delle sue Guardie, ma può spesso staccarsi per guarire o iniettarsi. Dispone di molti Medicinali, quindi è possibile un impegno prolungato.", "shturman-bio": "", "shturman-description": "Shturman e i suoi seguaci ingaggeranno il giocatore a lunga distanza proteggendo l'area della segheria nella Foresta. Preferiscono tenersi a distanza perché non sono adatti al combattimento ravvicinato.", "tagilla-bio": "", "tagilla-description": "È pazzo da legare e cercherà di abbatterti a colpi di martello. Tuttavia, se ti trovi in una posizione che non può raggiungere, come le travi, userà la sua arma secondaria (di solito un fucile a pompa) per ucciderti da lontano. È attivo immediatamente all'inizio dell'raid. Il boss può tendere imboscate, aprire il fuoco di soppressione e fare irruzione se necessario.", "zryachiy-bio": "Una delle figure più misteriose di Tarkov. Non si sa praticamente nulla del suo passato, tranne che ha un addestramento da cecchino e si dice che sia stato più volte nelle zone calde del Medio Oriente e dell'Africa.
    Molto prima del conflitto, è diventato il fedele cagnolino di Cecchino e ha preso parte attiva nello \"stabilire\" i legami tra Cecchino e tutti coloro con cui ha interagito. È noto per essere amico del gruppo dei Rogue, così come degli uomini incappucciati che disegnano simboli misteriosi dalle zone.
    Zryachiy è molto taciturno, anche se chi lavora con lui di solito lo capisce senza parole. Ci sono molte voci sui suoi occhi, alcuni dicono che si tratta di una peculiarità innata, altri indicano alcuni colliri che gli permettono di migliorare la visione al buio, dando ai suoi occhi questo effetto collaterale di biancore. Nonostante l'aspetto, sembra che si sia guadagnato il suo nome proprio per la sua eccellente vista, il che non sorprende per un ex cecchino militare.", "zryachiy-description": "Guardia cultista del Guardiano della Luce." } ================================================ FILE: src/translations/it/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Interactive", "Landscape": "Orizontale", "View Fullscreen": "View Fullscreen", "Exit Fullscreen": "Exit Fullscreen", "Satellite": "Satellite", "Abstract": "Abstract", "Levels": "Levels", "1st Floor": "1st Floor", "2nd Floor": "2nd Floor", "3rd Floor": "3rd Floor", "4th Floor": "4th Floor", "5th Floor": "5th Floor", "Underground": "Sottoterra", "Garage": "Garage", "Tunnels": "Tunnels", "Bunkers": "Bunkers", "Spawns": "Spawns", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "Sniper Scav", "Boss": "Boss", "Extracts": "Extracts", "Shared": "Shared", "Hazards": "Hazards", "Usable": "Usable", "Locks": "Locks", "Stationary Gun": "Stationary Gun", "Lever": "Lever", "Switch": "Switch", "Door": "Door", "Container": "Container", "Car Door or Trunk": "Car Door or Trunk", "Lock": "Lock", "Activated by": "Activated by", "Activates": "Activates", "Needs power": "Needs power", "Lootable Items": "Lootable Items", "Tasks": "Tasks", "Item": "Item", "Objective": "Objective", "Misc": "Misc", "openworld-name": "Mondo aperto", "openworld-description": "Questa è un'immaginazione di come potrebbe essere la mappa completa di Tarkov. Questa mappa del mondo aperto probabilmente includerebbe tutti i luoghi chiave delle mappe esistenti combinate in un'unica enorme mappa.", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "Use TarkovMonitor to show your position", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/it/properties.json ================================================ { "ambientVolume": "Ambience", "caliber": "Calibro", "damage": "Danno", "distanceModifier": "Distance", "distortion": "Distortion", "projectileCount": "Numero di proiettili", "penetrationPower": "Potere di penetrazione", "armorDamage": "Danno all'armatura", "fragmentationChance": "Probabilità di frammentazione", "ammoType": "Tipo di munizione", "class": "Classe", "material": "Materiale", "zones": "Zone", "defaultPreset": "Preset predefinito", "durability": "Durabilita'", "ergoPenalty": "Penalità all'ergo", "speedPenalty": "Penalità alla velocità", "turnPenalty": "Penalità alla rotazione", "headZones": "Zone della testa", "capacity": "Capacità", "grids": "Griglie", "energy": "Energia", "hydration": "Idratazione", "units": "Unità", "stimEffects": "Effetti dello stim", "blindnessProtection": "Protezione dalla cecità", "fuse": "Fusibile", "maxExplosionDistance": "Distanza massima di esplosione", "fragments": "Frammentazioni", "deafening": "Assordante", "blocksHeadset": "Blocca le cuffie", "ricochetY": "Possibilità di rimbalzo", "uses": "Usa", "malfunctionChance": "Probabilità di malfunzionamento", "ergonomics": "Ergonomia", "recoil": "Rinculo", "loadModifier": "Modificatore di carica", "ammoCheckModifier": "Modificatore del controllo munizioni", "useTime": "Tempo di utilizzo", "cures": "Cure", "hitpoints": "Punti ferita", "maxHealPerUse": "Max cura per ogni uso", "hpCostLightBleeding": "Costo Hp sanguinamento leggero", "hpCostHeavyBleeding": "Costo Hp sanguinamento forte", "painkillerDuration": "Durata dell'antidolorifico", "energyImpact": "Impatto sull'energia", "hydrationImpact": "Impatto sull'idratazione", "recoilVertical": "Rinculo verticale", "recoilHorizontal": "Rinculo orizzontale", "zoomLevels": "Livelli di zoom", "minLimbHealth": "Salute dell'arto min", "maxLimbHealth": "Salute dell'arti max", "effectiveDistance": "Distanza Effettiva", "fireModes": "Modalità di fuoco", "fireRate": "Rateo di fuoco", "sightingRange": "Portata di avvistamento", "defaultWidth": "Larghezza predefinita", "defaultHeight": "Altezza predefinita", "defaultErgonomics": "Ergonomia predefinita", "defaultRecoilVertical": "Rinculo verticale predefinito", "defaultRecoilHorizontal": "Rinculo orizzontale predefinito", "defaultWeight": "Peso predefinito", "recoilModifier": "Modificatore di rinculo", "weight": "Peso", "baseItem": "Oggetto base", "categories": "Categorie", "type": "Tipo", "convergence": "Convergenza", "cameraRecoil": "Rinculo della camera", "recoilAngle": "Angolo del rinculo", "recoilDispersion": "Dispersione del rinculo", "usedOnMaps": "Used on Maps" } ================================================ FILE: src/translations/it/translation.json ================================================ { "No data": "Nessun dato", "Current Average Latency": "Latenza media attuale", "API Latency in milliseconds": "Latenza API in millisecondi", "No barters found for this item": "Nessun baratto trovato per questo oggetto", "LL{{level}}": "LF{{level}}", "Barter at {{trader}}": "Baratto con {{trader}}", "Craft at {{station}}": "Craft at {{station}}", "Barter": "Baratto", "Craft at {{stationName}} {{stationLevel}}": "Craft at {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Provides {{count}} for {{totalCost}}", "Provides {{count}} for {{totalCost}}_many": "Provides {{count}} for {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Provides {{count}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_many": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Reward": "Ricompensa", "Cost": "Costo", "Cost ₽": "Costo ₽", "Estimated savings": "Risparmio stimato", "InstaProfit": "InstaProfit", "N/A": "N/D", "Barter cost": "Costo del Baratto", "No barters available for selected filters": "Non ci sono baratti disponibili per i filtri selezionati", "No barters available for selected filters but some were hidden by ": "Non ci sono baratti disponibili per i filtri selezionati, ma alcuni sono stati nascosti da ", "your settings": "impostazioni", "Some barters hidden by ": "Alcuni baratti nascosti da ", "Can hold:": "Può contenere:", "Can't hold:": "Non può contenere:", "Level": "Livello", "Flea Market": "Mercato Delle Pulci", "Flea banned": "Vietato sul mercato", "Sell price": "Prezzo di vendita", "Flea Market fee": "Tassa per il Mercato Delle Pulci", "Duration": "Durata", "Finishes": "Finiture", "Start now": "Inizia ora", "Flea throughput/h": "Produzione del mercato/h", "Estimated profit": "Profitto stimato", "Estimated profit/h": "Profitto stimato/h", "No crafts available for selected filters": "Non ci sono creazioni disponibili per i filtri selezionati", "No crafts available for selected filters but some were hidden by ": "Non ci sono creazioni disponibili per i filtri selezionati, ma alcuni sono stati nascosti da ", "Some crafts hidden by ": "Creazione di alcuni oggetti nascosta da ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "All options already selected", "Clear selection": "Clear selection", "This item can't be sold on the Flea Market": "Questo oggetto non può essere venduto nel Mercato Delle Pulci", "Not scanned on the Flea Market": "Non è stato scansionato nel Mercato Delle Pulci", "Flea market prices loading": "Caricamento dei prezzi del Mercato Delle Pulci", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>L'intera piattaforma è open source e incentrata sugli sviluppatori. Tutto il codice è disponibile su <1><0> GitHub.", "about-discord-p": "<0>Se tu vuoi chiacchierare, fare domande o richiedere funzionalità, abbiamo un server <1><0> Discord.", "about-x-p": "<0>Follow us on <1><0> X for all the latest updates.", "About": "Chi siamo", "Contributors": "Contribuenti", "Massive thanks to all the people who help build and maintain this project!": "Un enorme ringraziamento a tutte le persone che aiutano a costruire e mantenere questo progetto!", "Made with ❤️ by:": "Realizzato con ❤️ da:", "Supporters": "Sostenitori", "about-support-ukraine-p": "<0>Incoraggiamo tutti coloro che possono a fare una donazione per sostenere il popolo ucraino utilizzando il pulsante qui sotto.", "about-support-collective-p": "<0>Se anche tu vuoi sostenere questo progetto, puoi fare una donazione e/o diventare finanziatore su <1>Open Collective.", "Item Data": "Dati degli oggetti", "Fresh EFT data courtesy of": "Nuovi dati EFT per gentile concessione di", "Additional data courtesy of": "Dati aggiuntivi per gentile concessione di", "Resources": "Risorsa", "Tarkov.dev API": "API di Tarkov.dev", "{{bot}} integration": "Integrazione di {{bot}}", "Discord bot for your Discord": "Discord bot per il tuo Discord", "External resources": "Risorse esterne", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev è un fork dell'ormai chiuso tarkov-tools.com | Un grande ringraziamento a kokarn per tutto il suo lavoro di costruzione di Tarkov Tools e della comunità che lo circonda.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "I contenuti e i materiali del gioco sono marchi e copyright di Battlestate Games e dei suoi licenziatari. Tutti i diritti sono riservati.", "version": "versione", "PMC & Scav Thorax HP": "PMC e Scav Torace HP", "Reshala Thorax HP": "Reshala Torace HP", "Raider Thorax HP": "Raider Torace HP", "Shturman Thorax HP": "Shturman Torace HP", "Cultist Priest Thorax HP": "Prete cultista Torace HP", "Cultist Warrior Thorax HP": "Guerrero cultista Torace HP", "Damage": "Danno", "Class {{tier}}": "Classe {{tier}}", "Penetration": "Penetrazione", "Filter by caliber": "Filtra per calibro", "This item can only be sold to trader": "This item can only be sold to trader", "per slot": "per slot", "Value": "Valore", "Per slot": "Per slot", "Sell to": "Vendi a", "Found In Raid": "Trovato Nel Raid", "Search item...": "Cerca oggetto...", "Search task...": "Cerca missione...", "Tasks": "Missioni", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Items": "Oggetti", "No hideout modules requires this item": "Nessun modulo di rifugio richiede questo oggetto", "No unbuilt hideout modules for selected filters but some were hidden by ": "Non ci sono moduli a scomparsa non costruiti per i filtri selezionati, ma alcuni sono stati nascosti da ", "Hideout Module": "Modulo Rifugio", "Item": "Oggetto", "Amount": "Quantità", "Player level: {{playerLevel}}": "Livello giocatore: {{playerLevel}}", "Reputation: {{reputation}}": "Reputation: {{reputation}}", "Commerce: {{commerce}}": "Commerce: {{commerce}}", "Cheapest Price": "Prezzo più basso", "Task: {{taskName}}": "Missione: {{taskName}}", "Flea Market not available": "Flea Market not available", "No trader offers available": "Non sono disponibili offerte dei mercanti", "Loading...": "Caricamento...", "Ammo": "Munizioni", "Maps": "Mappe", "More": "Di più", "Traders": "Mercanti", "Prapor": "Prapor", "Therapist": "Terapeuta", "Skier": "Sciatore", "Peacekeeper": "Pacificatore", "Mechanic": "Meccanico", "Ragman": "Straccivendolo", "Jaeger": "Jaeger", "Bosses": "I boss", "Barter profit": "Profitto da baratto", "Hideout profit": "Profitto da rifugio", "Loot tiers": "Livelli di Bottino", "Hideout build costs": "Costi di costruzione del rifugio", "Wipe length": "Lunghezza del wipe", "Bitcoin Farm Profit": "Profitto della Bitcoin Farm", "Achievements": "Achievements", "API": "API", "Donate": "Donare", "Become a patron": "Diventa mecenate", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "has alternates", "On Task Completion": "Al completamento della missione", "On Task Start": "All'inizio della missione", "Task": "Missione", "Required items": "Oggetti necessari", "Reward items": "Ricompensa in oggetti", "Required tasks": "Missioni richieste", "loading": "caricamento", "active": "attivo", "succeeded": "riuscito", "complete": "completato", "failed": "fallita", "Minimum level": "Livello minimo", "Minimum trader level": "Livello minimo del mercante", "Reputation rewards": "Ricompensa in reputazione", "Endgame": "Endgame", "Required for Kappa": "Required for Kappa", "Required for Lightkeeper": "Required for Lightkeeper", "No quests found": "Nessuna missione trovata", "Some tasks hidden by filter settings": "Alcune missioni nascoste dalle impostazioni del filtro", "open this page in another browser or window and connect using this id": "aprire questa pagina in un altro browser o in un'altra finestra e connettersi utilizzando questo id", "ID for remote control": "ID per il telecomando", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Andiamo su Tarkov.dev con un altro browser e inseriamo questo ID per controllare questa pagina da lì", "Click to connect": "Fare clic per connettersi", "Sell value": "Valore vendita", "Tarkov server status": "Stato del server di Tarkov", "This item can't be sold to traders": "Questo oggetto non può essere venduto ai mercanti", "Name": "Nome", "Sell to Flea": "Vendi sul Mercato", "Buy on Flea": "Acquista sul Mercato", "Sell to Trader": "Vendi al mercante", "Trader buy": "Compra da mercante", "Buyback ratio": "Rapporto di riacquisto", "The percent recovered if you buy this item and sell it to the trader": "La percentuale recuperata se tu compri questo oggetto e lo vendi al mercante", "Grid": "Griglia", "Slots occupied": "Slot occupati", "Slots inside": "Slot all'interno", "Slots ratio": "Rapporto di slot", "Price per slot": "Prezzo per slot", "Armor class": "Classe dell'armatura", "Zones": "Zone", "Max Durability": "Durabilita' max", "Effective Durability": "Durabilita' effettiva", "Repairability": "Riparabilità", "Weight (kg)": "Peso (kg)", "Stats": "Statistiche", "Mov/Turn/Ergo": "Mov/Giro/Ergo", "Caliber": "Calibro", "Armor damage": "Danno all'armatura", "Fragmentation chance": "Probabilità di frammentazione", "Blindness protection": "Protezione dalla cecità", "Hydration": "Idratazione", "Energy": "Energia", "Hydration Cost": "Costo dell'Idratazione", "Energy Cost": "Costo dell'energia", "Hydration + Energy Value": "Idratazione + Valore energetico", "Sound suppression": "Soppressione dell'audio", "Low": "Basso", "None": "Nessuno", "Blocks earpiece": "Blocca le cuffie", "Yes": "Sì", "No": "No", "Ergonomics": "Ergonomia", "Cost per ergo": "Costo per ergo", "Recoil": "Rinculo", "Distance": "Distance", "No items": "Oggetti", "Not built": "Non costruito", "Locked": "Chiuso", "Crafting": "Creazione", "Hideout Management": "Gestione Rifugio", "Be the first!": "Siate i primi!", "Objective": "Obiettivo", "No objectives": "Nessun obiettivo", "Players": "I giocatori", "By": "Da", "Restock in": "Rifornito in", "Support Ukraine": "Sostenere l'Ucraina", "Cost per unit": "Costo per unità", "About the tarkov.dev project": "Informazioni sul progetto tarkov.dev", "about-page-description": "Per saperne di più su the-hideout e tarkov.dev. L'ecosistema di Escape from Tarkov è gratuito, realizzato dalla comunità e open source! Usa i nostri strumenti per aiutarti a giocare o costruisci i tuoi progetti con le nostre API gratuite.", "Open source": "Open source", "Discussions & feedback": "Discussioni e feedback", "Support": "Supporto", "about-support-more-p": "<0>Tu puoi anche aiutarci a segnalare bug, suggerire o implementare nuove funzioni, migliorare le mappe o qualsiasi altra cosa ti venga in mente per migliorare il sito.", "about-api-p": "<0>Offriamo un'API 100% gratuita e pubblicamente accessibile per tutte le vostre esigenze di sviluppo di Tarkov - <1>API.", "History": "La storia", "about-history-p": "<0>Questo progetto è un fork di <1>tarkov-tools.com. Il creatore originale <3>@kokarn ha deciso di chiudere il sito. Nello spirito dell'open source, un gruppo di sviluppatori si è riunito per ridare vita al sito, al fine di continuare a fornire un ottimo sito web per la comunità di Tarkov e un'API per alimentare ulteriori sviluppi per i creatori. Questo progetto è ora al 100% open source e viene sviluppato in primo luogo dagli sviluppatori. La nostra organizzazione GitHub (<5>the-hideout) contiene tutti i repo che alimentano le API, questo sito web, il bot Discord della comunità, l'infrastruttura del server e molto altro ancora! Siamo appassionati di open source e amiamo le richieste di pull per migliorare il nostro ecosistema per tutti.", "Core Contributors": "Contributori principali", "about-core-contributors-p": "<0>I collaboratori principali di questo progetto (in ordine sparso) sono:", "All Contributors": "Tutti i collaboratori", "about-all-contributors-p": "<0>Un enorme grazie a tutte le persone che hanno contribuito a questo progetto per renderlo possibile! ❤️", "Description": "Description", "Hidden": "Hidden", "Player %": "Player %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "This page includes information on the achievements that can be earned.", "Ammo chart": "Grafico delle munizioni", "ammo-page-description": "Questa pagina contiene un elenco di tutti i tipi di munizioni presenti in Escape from Tarkov. Per filtrare l'elenco completo delle cartucce disponibili, fare clic sul nome di un calibro.", "ammo-page-p": "<0>La natura selvaggia di Tarkov comprende una vasta gamma di munizioni. Per combattere i diversi avversari, sono necessari diversi tipi di munizioni.<1>Questa pagina contiene un elenco di tutti i tipi di munizioni presenti in Escape from Tarkov. Per filtrare l'elenco completo delle cartucce disponibili, fare clic sul nome di un calibro.", "Total damage": "Danno totale", "Use total damage of all projectiles in a round": "Usa il danno totale di tutti i proiettili di un round", "Ignore settings": "Ignora le impostazioni", "Shows all sources of items regardless of your settings": "Mostra tutte le fonti degli oggetti, indipendentemente dalle impostazioni", "Use barters for item sources": "Use barters for item sources", "Use crafts for item sources": "Use crafts for item sources", "Ammo Statistics Table": "Tabella delle statistiche delle munizioni", "API Documentation": "Documentazione API", "api-docs-page-description": "L'API di Escape from Tarkov realizzata dalla comunità e la relativa documentazione. Usa la nostra API GraphQL gratuita e facile da usare per EFT.", "api-about-p": "<0>L'API è scritta in GraphQL e cerchiamo di fare del nostro meglio per seguire le specifiche e non apportare Cambiamenti. Per sapere quali sono le query che tu puoi fare e come è strutturato lo schema, visita il parco giochi e fai clic sulla scheda 'Docs' nella parte destra. Quando tu sei pronto a provare alcune query, puoi anche testarle nell'area di gioco. Per conoscere le query GraphQL in generale, la GraphQL Foundation offre risorse utili.<1><0><0>Parco giochi GraphQL di Tarkov.dev<1><0>Risorse della Fondazione GraphQL<1>Una volta pronti a inviare query API dall'esterno del parco giochi, l'endpoint è: <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Prestazioni attuali dell'API", "api-performance-p": "<0>Per conoscere le metriche e le prestazioni dell'API, consultate la nostra <1>pagina dello stato.", "FAQ": "FAQ", "Is it free?": "È gratuito?", "Is it open source?": "È open source?", "api-faq-open-source-p": "Naturalmente! Il codice sorgente dell'API è disponibile nel suo repo GitHub: <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "C'è un limite alla frequenza?", "api-faq-rate-limit-p": "We occasionally get hit with a lot of traffic from bad actors that requires implementing rate limits. Price data is updated every 5 minutes, so there's really no need to query faster than that. Use common sense, and you should be fine.", "What about caching?": "E la cache?", "api-faq-caching-p": "Poiché i nostri dati vengono aggiornati ogni 5 minuti, anche le query GraphQL vengono memorizzate nella cache per 5 minuti. Questo aiuta a ridurre notevolmente il carico sui nostri server e a velocizzare le vostre richieste!", "Where is the data from?": "Da dove provengono i dati?", "We source data from multiple places to build an API as complete as possible. We use data from:": "I dati provengono da più posti per costruire un'API il più completa possibile. Usiamo i dati di:", "Our network of scanners": "La nostra rete di scanner", "Examples": "Esempi", "example": "esempio", "Contributed by": "Contribuito da", "API Users": "Utenti API", "api-users-page-description": "Questa pagina contiene un elenco di tutti gli utenti di API pubbliche su Tarkov.dev e dei loro progetti.", "api-users-p": "<0>Vuoi essere attivo in questa pagina? Unisciti al <1>Discord e raccontaci le tue creazioni!", "Barter Profits": "Profitti da Baratto", "barters-page-description": "Questa pagina contiene informazioni sui diversi oggetti di scambio con i PNG, sui prezzi di scambio e sui profitti che si possono ottenere dalla vendita degli oggetti.", "Shows all barters regardless of your settings": "Mostra tutti i baratti, indipendentemente dalle impostazioni", "Hide dogtags": "Nascondere piastrine", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "Il vero \"costo\" dei baratti con le piastrine è difficile da stimare, quindi si potrebbe voler escludere i baratti con le piastrine", "Show all barters": "Mostra tutti i baratti", "All": "Tutto", "Item filter": "Filtra per oggetto", "filter on item": "filtra per oggetto", "barters-page-p": "<0>Fatta eccezione per Fence, tutti i commercianti di Escape from Tarkov offrono beni da barattare piuttosto che da acquistare direttamente.<1>In cambio di una varietà di oggetti poco costosi, il giocatore può spesso scambiarli con oggetti di maggior valore che possono essere utilizzati o venduti per un profitto o con equipaggiamenti di livello superiore a livelli di fedeltà più bassi.<3>Assicurati di controllare in corso dopo il reset per le tue transazioni preferite, perché la maggior parte di questi scambi di valore ha limiti rigorosi per il reset del mercante e si esaurisce spesso.", "Num graphic cards": "Num di schede grafiche", "Hours": "Orario", "Bitcoin Farm Calculator": "Calcolatore della Bitcoin Farm", "bitcoin-farm-calculator-page-description": "Questa pagina include uno strumento di calcolo che aiuta a determinare il prezzo della costruzione e del mantenimento di una Bitcoin Farm, in base al numero di GPU, ai costi dell'elettricità e al costo dei bitcoin.", "Graphic cards count": "Numero di schede grafiche", "Use fuel cost: {{price}}/day": "Usa il costo del carburante: {{price}}/giorno", "Use station build costs": "Usa i costi di costruzione delle stazioni", "Purchase cost": "Costo di acquisto", "Remaining days in wipe:": "Giorni rimasti nel wipe:", "Time to produce 1 bitcoin": "Tempo per produrre 1 bitcoin", "BTC/day": "BTC/giorno", "Estimated profit/day": "Profitto stimato al giorno", "Profitable after days": "Redditizio dopo giorni", "Total cost of graphic cards": "Costo totale delle schede grafiche", "Build costs": "Costi di costruzione", "GPU + build costs": "GPU + costi di costruzione", "Remaining profit": "Profitto rimasto", "Map": "Mappa", "Spawn Location": "Luogo di spawn", "Chance": "Probabilità", "Count": "Conteggio", "Spawn chance": "Probabilità di spawn", "Chance that the boss spawns on a given map": "Probabilità che il boss si spawna in una determinata mappa", "Health": "Salute", "Total boss health": "Salute totale del boss", "Patrol": "Pattuglia", "Rush": "Corsa", "Stalker": "Stalker", "Hostile and accurate": "Ostile e preciso", "Patrol and highly armored": "Pattuglia e pesantemete armato", "Group patrol": "Pattuglia del Gruppo", "Frequent healing and stim injections": "Frequenti iniezioni di Curando e di stimolo", "Sniper": "Cecchino", "Batshit insane": "Pazzo furioso", "Behavior": "Comportamento", "The boss's general AI behavior": "Il comportamento generale dell'IA del boss", "Wiki": "Wiki", "Boss Stats": "Statistiche del boss", "Special Boss Loot": "Bottino speciale del boss", "Spawn Locations": "Luoghi di spawn", "boss-spawn-table-description": "<0>Mappa: Il nome della mappa in cui il boss può spawnare<1>Posizione di spawn: La posizione esatta dalla zona della mappa in cui il boss può spawnare<2>Probabilità: Se la \"Probabilità di spawn\" è attivata per la mappa, questa è la probabilità stimata che il boss spawnerà in una determinata zona della mappa", "Boss Escorts": "Scorta boss", "This boss does not have any escorts": "Questo boss non ha nessuna scorta", "boss-page-description": "Questa pagina contiene informazioni sulla zona di {{bossName}}, sul bottino e sulle strategie per sconfiggerlo.", "bosses-page-description": "Questa pagina contiene informazioni su tutti i boss del gioco, la loro zona, il bottino, la scorta e le strategie per sconfiggerli.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "I boss sono nemici temuti e letali con equipaggiamenti e caratteristiche uniche in Escape from Tarkov", "About Bosses": "Informazioni sui boss", "bosses-page-p": "<0>In Escape from Tarkov ci sono molti boss che si aggirano nell'area di Norvinsk assediata.<1>Ogni boss ha comportamenti, caratteristiche e tattiche uniche. I boss di Tarkov sono temuti dai giocatori di ogni livello e spesso rappresentano una minaccia maggiore dei PMC nemici della regione.<2>Tuttavia, ad un alto rischio corrisponde un'alta ricompensa. Molti boss contengono Oggetti per missioni di alto livello o devono essere eliminati per le missioni. Imparare gli schemi, le zone e l'equipaggiamento di un boss è spesso il modo migliore per prepararsi a combattere contro un boss a Tarkov.", "Connect": "Collegare", "Connected to": "Collegato a", "id to control": "id per controllare", "Remote Control": "Controlli a distanza", "remote-control-page-description": "Questa pagina contiene tutti gli strumenti necessari per controllare in remoto un'altra istanza del sito web Tarkov.dev.", "View Map": "Visualizza Mappa", "Go": "Andiamo", "View caliber": "Visualizza Calibro", "Select...": "Seleziona...", "Load tarkov.dev in another browser or window to control it from here": "Caricare tarkov.dev in un altro browser o in un'altra finestra per controllarlo da qui", "Hideout Crafts": "Creazioni nel Rifugio", "crafts-page-description": "Questa pagina contiene informazioni sui diversi oggetti che possono essere creati nel rifugio, sui materiali e le risorse necessarie e sui profitti che si possono ottenere vendendo i prodotti completati.", "Shows all crafts regardless of your settings": "Mostra tutte le creazioni, indipendentemente dalle impostazioni", "Average prices": "Prezzi medi", "Use average prices from the past 24 hours for profit calculations": "Usa i prezzi medi delle ultime 24 ore per calcolare i profitti", "Most profitable craft in each station": "Creazione più redditizia in ogni stazione", "Best": "Milgiori", "Flea Market banned items": "Flea Market banned items", "Empty fuel": "Taniche vuote", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "Imposta il costo delle taniche per le creazione che le richiedono al costo minimo che le pagherebbero i mercanti quandi si usano taniche non-TIR.", "crafts-page-p": "<0>In Escape from Tarkov, le creazioni artigianali consentono a te di creare una serie di oggetti. Si possono utilizzare diversi moduli del rifugio, tra cui il raccoglitore d'acqua, il banco da lavoro, l'infermeria, la lavanderia e l'unità di nutrimento.<1>Lo stato \"Trovato Nel Raid\" viene applicato a ogni oggetto creato nel nascondiglio. L'elenco completo di questi mestieri è mostrato sopra. L'abilità Creazione influisce sul tempo di creazione degli oggetti.<2>Quando l'icona di un oggetto ha un bordo blu, viene utilizzato come strumento ausiliario e, una volta completata la produzione, viene restituito alla scorta.", "Page not found": "Pagina non trovata", "error-page-description": "Questa non è la pagina che tu stai cercando", "Sorry, that page doesn't exist!": "Spiacente, quella pagina non esiste!", "Hideout": "Rifugio", "hideout-page-description": "Questa pagina contiene informazioni sulle diverse stazioni e moduli che possono essere costruiti con i materiali e le risorse necessarie per migliorare il vostro rifugio.", "Show all stations & modules": "Mostra tutte le stazioni e i moduli", "Show built": "Mostra costruiti", "Show already built stations": "Show already built stations", "Show locked": "Show locked", "Show unavailable stations": "Show unavailable stations", "Show all requirements": "Show all requirements", "Show trader and other station level requirements": "Show trader and other station level requirements", "Collected": "Raccogliendo", "Item Tracker": "Tracciamento degli Oggetti", "Only show Found in Raid": "Mostra solo Trovato Nel Raid", "Reset all tracking": "Azzeramento di tutto il tracciamento", "Hide completed": "Nascondere completate", "Hide tasks you've completed": "Nasconde le missioni che hai completato", "Hide dogtag barters": "Nascondere i baratti con le piastrine", "Best price to sell for": "Prezzo migliore per vendere", "Fee": "Tassa", "Profit": "Profitto", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "L'ultimo prezzo basso osservato per questo oggetto nel Mercato Delle Pulci è stato {{lastSeenPrice}}.\nTuttavia, a causa delle modalità di calcolo delle tariffe, è preferibile vendere a {{bestPrice}}.", "Max price to sell for": "Prezzo max da vendere", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "Questo oggetto non è stato osservato al Mercato Delle Pulci.\nIl prezzo massimo profittevole è {{bestPrice}}, ma l'oggetto potrebbe non essere venduto a quel prezzo.\nIl prezzo massimo è influenzato dai livelli di Centro di Intelligence e dall'abilità Gestione Rifugio nelle impostazioni.", "Likely sell price": "Prezzo di vendita probabile", "item-page-description": "Questa pagina contiene informazioni sulle caratteristiche, gli Usa e le strategie di {{itemName}}.", "Sell for": "Vendi per", "Buy for": "Compra per", "Flea price history": "Cronologia dei prezzi del mercato delle pulci", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "Cambiamento rispetto a ieri: {{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "Prezzo più basso scansionato nelle ultime 24 ore: {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Prezzo più alto scansionato nelle ultime 24 ore: {{high24hPrice}}", "Updated: {{val, relativetime}}": "Aggiornato: {{val, relativetime}}", "Items contained in {{itemName}}": "Oggetti contenuti in {{itemName}}", "Barters with {{itemName}}": "Baratto con {{itemName}}", "Crafts with {{itemName}}": "Creazioni con {{itemName}}", "Hideout modules needing {{itemName}}": "Moduli di Rifugio che necessitano di {{itemName}}", "Shows all modules regardless of your settings": "Mostra tutti i moduli, indipendentemente dalle impostazioni", "Quests requiring {{itemName}}": "Requisiti che richiedono {{itemName}}", "Quests rewarding {{itemName}}": "Missioni che ricompensano {{itemName}}", "Armors": "Armature", "armors-page-description": "Questa pagina contiene una tabella ordinabile con informazioni sui diversi tipi di armatura disponibili nel gioco, tra cui il costo di riparazione, la riparabilità, la classe di armatura e altre caratteristiche.", "Class effective durability": "Durabilita' effettiva della classe", "Include rigs": "Includere i gilet tattici", "Max price": "Prezzo max", "max price": "prezzo max", "armors-page-p": "<0>In the video game Escape from Tarkov, armor vests are worn to lessen bullet damage. Helmets are typically used in addition to them.", "Backpacks": "Zaini", "backpacks-page-description": "Questa pagina contiene una tabella ordinabile con informazioni sui diversi tipi di Zaini disponibili nel gioco, compresi prezzo, dimensioni, capacità e altre caratteristiche.", "Net price per slot": "Prezzo netto per slot", "Show price per additional slot of storage gained from the container": "Mostra il prezzo per ogni slot aggiuntivo di stoccaggio ricavato dal contenitore", "backpacks-page-p": "<0>Backpacks in the Escape from Tarkov game are various-sized containers for carrying your hard-earned riches.", "Barter Items": "Oggetti di baratto", "barter-items-page-p": "<0>This table of barter items from Escape from Tarkov will make it simple for you to determine how much each one is worth. It can be challenging to determine which products are valuable enough to take because there are over 150 barter items in the game, and flea market pricing can fluctuate suddenly. You may optimize your loot with the aid of this interactive table.", "bsg-category-description": "Scopri tutto quello che c'è da sapere su {{category}} in Escape from Tarkov.", "Containers": "Contenitori", "containers-page-p": "<0>As their name implies, containers in Escape from Tarkov are items used to hold other things. Some of these items are used to clear up inventory space by acting as storage and taking up less inventory slots however some of them cannot be equipped on the character.", "Glasses": "Occhiali", "glasses-page-description": "Questa pagina contiene una tabella ordinabile con informazioni sui diversi tipi di occhiali disponibili nel gioco, compresi il prezzo, la classe di armatura e altre caratteristiche.", "glasses-page-p": "<0>Eyewear in Escape from Tarkov can be used to decrease the number and quantity of raindrops on the players' screens as well as the length of flashbang effects.", "Grenades": "Granate", "grenades-page-description": "Questa pagina contiene una tabella ordinabile con informazioni sui diversi tipi di granate disponibili nel gioco, inclusi il prezzo, il danno e altre caratteristiche.", "grenades-page-p": "<0>There are only a handful distinct types of grenades that may be thrown or launched in Escape from Tarkov, and each one has a unique effect: flash, smokes, high explosive, and fragmentation.<1>Grenades are situational, but when utilized properly, they can have deadly results. Any advantage from high-tier equipment can be fully negated by a single well-thrown grenade, whether it completely blinds the adversary, kills them instantly, or forces them out of cover and into your gunfire.<3>Five factors to think about while using throwable grenades include the fuse time, explosion radius, fragment damage, fragment count, and even the weight of the grenade. With specific uses arising from each component.", "Guns": "Armi", "guns-page-description": "Questa pagina include una tabella ordinabile con informazioni sui diversi tipi di armi disponibili nel gioco, tra cui il prezzo, il danno, la precisione e altre caratteristiche.", "guns-page-p": "<0>Your main tool for survival is a weapon. Almost all weapons are completely modular, allowing them to be customized for various scenarios. All of the weaponry used in Escape from Tarkov are listed on this page.", "Headsets": "Cuffie", "headsets-page-description": "Questa pagina include una tabella ordinabile con informazioni sui diversi tipi di cuffie disponibili nel gioco, compresi prezzo, disponibilità e altre caratteristiche.", "headsets-page-p": "<0>In Escape from Tarkov, headsets magnify low-frequency noises like footsteps while muzzling impulsive stimuli like gunshots. Different audio profiles are offered by the various models.", "Helmets": "Elmetti", "helmet-page-description": "Questa pagina contiene una tabella ordinabile con informazioni sui diversi tipi di elmetti disponibili nel gioco, inclusi il prezzo, la classe di armatura e altre caratteristiche.", "Show blocking headset": "Mostra quelli che bloccano le cuffie", "Min armor class": "Classe armatura min", "helmets-page-p": "<0>In Escape from Tarkov, headgear serves a variety of functions.<1>There are useful objects, vanity items, and safety headgear. Before entering combat, choosing a helmet that will protect different parts of the head becomes crucial.<3>The impact that different helmets will have on how much sound they suppress is another crucial factor to take into account. Escape from Tarkov's gameplay heavily relies on sound.<5>Modular helmets, which have an assortment of different components, are another aspect of Escape from Tarkov. These helmets may modify the number of segments they protect. Top, Nape, Ears, Eyes, and Jaws are the segments.", "items-page-description": "Questa pagina contiene collegamenti a pagine con informazioni su diverse categorie di oggetti, tra cui armature, zaini, oggetti di scambio, contenitori, occhiali, granate, armi, cuffie, elmetti, chiavi, modifiche per armi, impugnature, provvisioni, gilet tattici, soppressori e altro ancora.", "Keys": "Chiavi", "keys-page-description": "Questa pagina contiene una tabella ordinabile con informazioni sui diversi tipi di chiave disponibili nel gioco, compresi il prezzo, la rarità e altre caratteristiche.", "keys-page-p": "<0>Maps, keys, key cards, and other useful objects are included in intelligence items. These will help you stay one step ahead of the competition—or at the very least, know where you are in Escape from Tarkov.<1>The remaining durability of keys and keycards with a limited number of uses is displayed in the bottom right corner of their icons and on their inspection screens.", "Mods": "Modifiche", "mods-page-description": "Questa pagina include una tabella ordinabile con informazioni sui diversi tipi di modifiche per le armi disponibili nel gioco, inclusi il prezzo, la compatibilità e altre caratteristiche.", "mods-page-p": "<0>In Escape from Tarkov, the performance and functioning of a weapon are controlled by elaborate mechanisms organized into five categories:<1><0>Functional Mods<1>Muzzle devices (Functional Mods)<2>Sights (Functional Mods)<3>Gear Mods<4>Vital parts", "Pistol Grips": "Impugnature", "pistol-page-description": "Questa pagina include una tabella ordinabile con informazioni sui diversi tipi di impugnature disponibili nel gioco, compresi i prezzi, l'ergonomia, la compatibilità e altre caratteristiche.", "Filter by gun": "Filtra per arma", "select a gun": "seleziona un'arma", "pistol-grips-page-p": "<0>In Escape from Tarkov a pistol grips and stocks are vital parts of a weapon.<1>On this page you can sort them buy ergonomics improvement or their cost and see on which weapon they can be mounted.", "Provisions": "Provviste", "provisions-page-description": "Questa pagina contiene una tabella ordinabile con informazioni sui diversi tipi di provviste disponibili nel gioco, tra cui l'idratazione, l'energia, il prezzo più basso e il valore di Mercanti o al Mercato Delle Pulci.", "Total energy cost": "Costo totale dell'energia", "Include the cost of lost hydration in the cost of energy": "Includere il costo della perdita di idratazione nel costo dell'energia", "provisions-page-p": "<0>In Escape from Tarkov, provisions are utilized to replenish energy and hydration.<1>Your Metabolism skill level will determine how effective they are.", "Rigs": "Gilet tattici", "rigs-page-description": "Questa pagina include una tabella ordinabile con informazioni sui diversi tipi di gilet tattici disponibili nel gioco, tra cui il prezzo, le dimensioni interne ed esterne, il peso, la compressione e altre caratteristiche.", "Armored rigs?": "Gilet armati?", "Min slots": "Slot min", "3-slot": "3 slot", "4-slot": "4 slot", "rigs-page-p": "<0>When it comes to carrying and storing ammunition and magazines during your excursions in Escape from Tarkov, chest rigs are crucial. Some even provide you with additional security.", "Suppressors": "Silenziatori", "suppressors-page-description": "Questa pagina include una tabella ordinabile con informazioni sui diversi tipi di Silenziatori disponibili nel gioco, compresa l'ergonomia, il rinculo e il prezzo più basso.", "suppressors-page-p": "<0>In Escape from Tarkov, a suppressor is a muzzle device (a functional mod) and can be installed on a weapon to muffle gunshot sound.<1>On this page you can sort them buy ergonomics penalty, recoil improvement or their cost and see on which weapon they can be directly mounted.", "Barters": "Baratti", "Marked": "Contrassegnato", "Wearables": "Oggetti da indossare", "loot-tiers-page-description": "Impara a conoscere i diversi tipi di bottino disponibili nel gioco, il loro valore, la loro rarità, cosa tenere e cosa cestinare.", "Ranking the most valuable items in the game": "Classifica degli oggetti di valore più preziosi del gioco", "Include Marked": "Includi marcati", "Group by type": "Ragruppa per tipologia", "min value": "valore min", "Only show markers for active tasks": "Only show markers for active tasks", "Map of {{mapName}}": "Map of {{mapName}}", "maps-page-description": "Ottieni le ultime informazioni su tutte le mappe di Escape from Tarkov, compresi i punti di estrazione e le posizioni dei bottini. Scoprite dove trovare i migliori equipaggiamenti e le migliori risorse del gioco", "maps-page-p": "<0>La mappa Escape from Tarkov contiene 11 diversi luoghi, di cui 10 sono stati resi pubblici finora. Anche se alla fine tutte le mappe saranno collegate, attualmente sono tutte separate l'una dall'altra.", "Streets of Tarkov": "Streets of Tarkov", "Ground Zero": "Ground Zero", "Customs": "Personalizzazione", "Factory": "La Fabbrica", "Interchange": "Interscambio", "The Lab": "Il laboratorio", "Lighthouse": "Faro", "Reserve": "Riserva", "Shoreline": "Linea di riva", "Woods": "Foresta", "Openworld": "Mondo aperto", "Tarkov.dev {{bot}} integration": "Integrazione di {{bot}} con Tarkov.dev", "bot-page-description": "Questa pagina contiene tutto il necessario per integrare {{bot}} con Tarkov.dev.", "You can add command to your moobot to get price check in your twitch chat": "Tu puoi aggiungere un comando al tuo moobot per ottenere il controllo dei prezzi nella chat di Twitch", "Instructions": "Istruzioni", "Register at": "Registrati su", "using your twitch account": "usando il tuo account twitch", "Go to Custom commands": "Andiamo ai Comandi personalizzati", "Set what you want the command to be. Common is \"p\" or \"price\"": "Impostare il nome del comando. Il più comune è \"p\" o \"prezzo\"", "Press the \"Create\" button": "Premi il pulsante \"Create\"", "In response choose URL Fetch - Full (plain) response": "In risposta scegli \"URL Fetch - Full (plain) response\"", "and after insert \"Command arguments\"": "e dopo inserisci \"Command arguments\"", "Now press \"Save\" button": "Ora premere il pulsante \"Save\"", "Big thanks to": "Un grande ringraziamento a", "for feedback": "per il feedback", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "Puoi aggiungere un comando al tuo nightbot per ottenere il controllo del prezzo nella chat del tuo canale twitch / youtube", "using your twitch / youtube account": "usando il proprio account twitch / youtube", "Go to dashboard": "Andiamo alla plancia di comando", "Click the \"Join Channel\" button": "Fare clic sul pulsante \"Join Channel\"", "Make bot - moderator, just type /mod nightbot in your chat": "Modifica del bot - moderatore, basta digitare /mod nightbot nella chat", "Go to custom commands": "Andiamo ai comandi personalizzati", "Press the \"Add command\" button": "Premi il pulsante \"Add command\"", "Command: !p or anything you like": "Comando: !p o qualsiasi cosa tu desideri", "Message:": "Messaggio:", "Press \"Submit\"": "Premere \"Submit\"", "Trader Levels": "Livelli del mercante", "Trader Reputation": "Reputazione del mercante", "Prerequisite Tasks": "Missioni preliminari", "Start Requirements": "Requisiti di Partenza", "Attributes": "Attributi", "Contains All": "Contiene Tutti", "Contains Item in Category": "Contiene Oggetti in Categorie", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Avere l'effetto {{effectNames, list}} sul tuo {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondo", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Avere l'effetto {{effectNames, list}} sul tuo {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondi", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Avere l'effetto {{effectNames, list}} sul tuo {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondi", "using extract: {{extractName}}": "usando estrazione: {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Estrarsi con gli stati: {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x any of", "Dogtag level": "Livello delle piastrine", "Max durability": "Durabilita' max", "Min durability": "Durabilita' min", "Kill": "Uccisione", "Shoot": "Sparare", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "Durante orario: {{hourStart}}:00 a {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "Dalla distanza: {{operator}} {{count}} metro", "From distance: {{operator}} {{count}} meters_many": "Dalla distanza: {{operator}} {{count}} metri", "From distance: {{operator}} {{count}} meters_other": "Dalla distanza: {{operator}} {{count}} metri", "While inside: {{zoneList, list(type: disjunction)}}": "Mentre all'interno: {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Colpito: {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Usando armi:", "Using weapon mods:": "Usando mod sull'arma:", "While wearing:": "Indossando:", "Not wearing:": "Non indossando:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Mentre l'effetto {{effectNames, list}} è attivo sulle {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondo", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Mentre l'effetto {{effectNames, list}} è attivo sulle {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondi", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Mentre l'effetto {{effectNames, list}} è attivo sulle {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondi", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "Mentre gli effetti di {{effectNames, list}} sono attivi sulle {{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Mentre il bersaglio subisce l'effetto {{effectNames, list}} sulle sue {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondo", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Mentre il bersaglio subisce l'effetto {{effectNames, list}} sulle sue {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondi", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Mentre il bersaglio subisce l'effetto {{effectNames, list}} sulle sue {{bodyParts, list(type: disjunction)}} per {{operator}} {{count}} secondi", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "Mentre il bersaglio ha l'effetto {{effectNames, list}} sulle sue {{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "Ottenere il livello {{level}} nell'abilità {{skillName}}", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} reputazione", "In area(s): {{areaList, list(type: disjunction)}}": "Nelle aree: {{areaList, list(type: disjunction)}}", "Use any of:": "Usa qualsiasi di:", "Reach level {{playerLevel}}": "Reach level {{playerLevel}}", "optional": "opzionale", "Trader Standing": "Reputazione dei mercanti", "Skill Level": "Livello di abilità", "Trader Offer Unlock": "Sblocco offerte del mercante", "Trader Unlock": "Sblocco mercante", "Craft Unlock": "Craft Unlock", "task-page-description": "Questa pagina contiene informazioni sugli obiettivi, le Ricompense e le strategie per completare la missione {{questName}}. Ottieni consigli su come prepararti e portare a termine con successo la missione.", "TarkovTracker": "TarkovTracker", "Leads to": "Porta a", "(on failure)": "(in caso di fallimento)", "Task Details": "Dettagli della Missione", "Objectives": "Obiettivi", "Fail On": "Fallisce se", "Needed Keys": "Chiavi necessarie", "Task Start": "Task Start", "Task Completion": "Completamento della Missione", "Rewards": "Ricompense", "Task Failure": "Task Failure", "Can be restarted": "Can be restarted", "Cannot be restarted": "Cannot be restarted", "Penalties": "Penalties", "tasks-page-description": "Scopri tutto quello che c'è da sapere sulle missioni in Escape from Tarkov. Scopri i diversi tipi di missioni disponibili nel gioco, come completarle e le ricompense che puoi ottenere.", "Hides completed tasks": "Nasconde le missioni completate", "Hide locked": "Nascondere bloccate", "Hides locked tasks": "Nasconde le missioni bloccate", "Show all tasks": "Mostra tutte le Missioni", "Name filter": "Filtra per nome", "filter on task name": "filtra sul nome della missione", "quests-page-p": "<0>I mercanti in Escape from Tarkov hanno una serie di missioni che tu puoi completare.<1>In cambio del recupero di oggetti, dell'eliminazione di bersagli e di altre azioni nel raid, è possibile aumentare la propria reputazione del mercante e guadagnare oggetti di valore.", "Settings": "Impostazioni", "settings-page-description": "Questa pagina contiene le impostazioni degli utenti su Tarkov.dev.", "Language": "Lingua", "General": "Generale", "Has flea": "Mercato abilitato", "Use TarkovTracker": "Usa TarkovTracker", "TarkovTracker API Token": "Token API di TarkovTracker", "API Token": "Token API", "Stations": "Stazioni", "Skills": "Abilità", "Dogtag Barters": "Baratti con le piastrine", "Exclude": "Escludere", "Minimum dogtag level": "Livello minimo delle piastrine", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Livello minimo di piastrine da usare per calcolare il costo dei baratti con piastrine", "The current estimated average player level is {{avgPlayerLevel}}": "L'attuale livello medio stimato dei giocatori è {{avgPlayerLevel}}", "Miscellaneous": "Varie", "Hide remote control": "Nascondere il telecomando", "start-page-description": "Scopri tutte le informazioni su oggetti, creazioni, baratti, mappe, livelli di bottino, profitti del rifugio, dettagli sui mercanti, un'API gratuita e molto altro con tarkov.dev! Un ecosistema gratuito, creato dalla comunità e open source di strumenti e guide di Escape from Tarkov.", "Load More": "Carica altri", "Tools": "Strumenti", "Ammo chart filter": "Filtro del grafico delle munizioni", "Traders barter profit": "Profitto da baratto con i mercanti", "Hideout crafts profit": "Creazioni redditizie nel rifugio", "Loot tiers ranking": "Classifica dei livelli di Bottino", "Average wipe length": "Lunghezza media del wipe", "Bitcoin farm profit": "Profitto della Bitcoin Farm", "Invite Discord bot": "Invita il bot Discord", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.dev è un kit di strumenti open source per Escape from Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "È progettato e mantenuto dalla comunità per aiutarti nelle missioni, nel commercio al mercato delle pulci e nel miglioramento del gioco! L'API è inoltre liberamente disponibile per consentire a te di creare i tuoi strumenti e servizi legati a EFT.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "Puoi aggiungere un comando al tuo bot StreamElements per ottenere un controllo del prezzo nella chat del tuo canale twitch / youtube", "Make bot - moderator, just type /mod streamelements in your chat": "Modifica del bot - moderatore, basta digitare /mod streamelements nella chat", "Press the \"Add new command\" button": "Premete il pulsante \"Add new command\"", "Press \"Activate Command\"": "Premete \"Activate Command\"", "Player level": "Livello giocatore", "Reputation": "Reputazione", "Commerce": "Commercio", "Trader {{trader}}": "Mercante {{trader}}", "trader-page-description": "Ottieni le ultime informazioni sul commerciante {{trader}} in Escape from Tarkov. Scopri gli oggetti che vende a determinati Livelli di Fedeltà e come massimizzare il cash-back di tuoi soldi per livellare la Fedeltà.", "Items with the best cash back prices for leveling": "Oggetti con i migliori prezzi di cash back per avanzare di livello", "Spending": "Da spendere", "Unlocks at Loyalty Level {{level}}": "Si sblocca al Livello di Fedeltà {{level}}", "Tasks given by {{traderName}}": "Missioni fornite da {{traderName}}", "traders-page-description": "Scopri tutto quello che c'è da sapere sui mercanti in Escape from Tarkov. Scoprite i diversi mercanti disponibili nel gioco, i loro luoghi e gli oggetti che vendono.", "About Traders": "Informazioni sui mercanti", "traders-page-p": "<0>Le colonne portanti del commercio nella Norvinsk distrutta e assediata. In Escape from Tarkov, ogni mercante è specializzato in un particolare tipo di prodotto, come forniture mediche, armi o equipaggiamento militare. Sebbene i loro prezzi siano in genere alti, tu ottieni quello per cui paghi.<1>Altro aspetto importante è che attraverso le missioni dei mercanti si può sviluppare una reputazione che consente di ricevere offerte migliori e di ridurre la commissione che ricevono (una maggiorazione aggiuntiva che si paga sulle vendite e sugli acquisti), oltre ad altri vantaggi.<2>Inoltre, i Mercanti forniscono altri servizi come l'assicurazione e le riparazioni (che permettono di recuperare l'Equipaggiamento in caso di morte durante un'raid).", "Patch": "Patch", "Wipe start": "Inizio wipe", "Wipe end": "Fine wipe", "Ongoing wipe": "Wipe in corso", "{{count}} days_one": "{{count}} giorno", "{{count}} days_many": "{{count}} giorni", "{{count}} days_other": "{{count}} giorni", "{{count}} months_other": "{{count}} months", "{{count}} years_one": "{{count}} year", "Wipe Length": "Lunghezza del wipe", "wipe-length-description": "Ottieni le ultime informazioni sulla durata media dei wipe in Escape from Tarkov. Scoprite quanto durano in genere i wipe e preparatevi per il prossimo wipe.", "Average Wipe Length among last 6 wipes:": "Lunghezza media degli ultimi 6 wipe:", "Trader Ammo": "Trader Ammo", "Only show ammo available from traders on your settings": "Only show ammo available from traders on your settings", "Reset": "Reset", "Convert one currency to another": "Convert one currency to another", "Currency Converter": "Currency Converter", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "control-info-p": "<0>This page allows you to control the Tarkov.dev website using another browser. The typical use case is to have the Tarkov.dev website open in a browser on a second monitor while you play the game and this page open on your phone or another device so that you can navigate to different pages on the Tarkov.dev website without having to alt+tab out of the game. All you have to do is open the Tarkov.dev website in a browser where you want it to be displayed, click the \"Click to connect\" button in the lower left*, and then use the ID shown there on this page on the control device and click the Connect. Once connected, you can use this control page to open specific map or ammo pages in the controlled browser.<1>*It appears on the lower left by default but can be toggled to the lower right side of the screen. It can also be hidden by the \"Hide remote control\" option on the settings page.", "cookie-consent": "tarkov.dev uses cookies to enhance your experience. By continuing to use this site, you agree to the usage of cookies. Cookies are used to remember your settings and features that you enable.", "I understand": "I understand", "Other Options": "Other Options", "This task {{taskStatus}}": "This task {{taskStatus}}", "Slots per kg": "Slots per kg", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Bot Discord Stash", "More Tools": "Altri strumenti", "Companion app": "App companion", "Discord companion": "Companion per Discord", "Download latest release": "Scarica l’ultima release", "View on GitHub": "Vedi su GitHub", "Join the community": "Unisciti alla community", "Screenshot of TarkovMonitor showing timers and integrations": "Screenshot di TarkovMonitor con timer e integrazioni", "Visual timers, raid state, and integration health in TarkovMonitor.": "Timer visivi, stato del raid e salute delle integrazioni in TarkovMonitor.", "Main Features": "Funzionalità principali", "tarkov-monitor-page-description": "Scopri come installare TarkovMonitor, collegarlo a TarkovTracker e usarlo per controllare le mappe di Tarkov.dev.", "tarkov-monitor-summary": "TarkovMonitor fornisce avvisi e timer utili per Escape From Tarkov così puoi gestire i raid senza interrompere la partita.", "tarkov-monitor-feature-audio": "Avvisi audio per matchmaking, inizio raid, timer runthrough, ricarica scav e notifiche del filtro dell’aria.", "tarkov-monitor-feature-map": "Apertura automatica della mappa su Tarkov.dev in base alla posizione che stai entrando.", "tarkov-monitor-feature-screenshot": "Visualizzazione opzionale della posizione attivata dagli screenshot per condividere rapidamente dove ti trovi.", "tarkov-monitor-feature-quests": "Aggiornamenti automatici delle missioni su TarkovTracker quando vengono rilevate completate.", "tarkov-monitor-feature-stats": "Statistiche locali come ricavi dal flea market, durata delle code e frequenza delle mappe.", "tarkov-monitor-feature-timers": "Timer visibili per il tempo in raid e il cooldown dello scav per pianificare la prossima run.", "Download": "Scarica", "tarkov-monitor-download-1": "Scarica l’ultima TarkovMonitor.zip da GitHub.", "tarkov-monitor-download-2": "Estrai l’archivio ovunque sul tuo PC.", "tarkov-monitor-download-3": "Esegui TarkovMonitor.exe e lascialo aperto mentre giochi.", "Community support": "Supporto della community", "tarkov-monitor-community": "Domande o vuoi parlare con altri utenti? Entra nel server Discord per suggerimenti, supporto e discussioni sulle funzionalità.", "Join the Discord": "Unisciti al Discord", "Security": "Sicurezza", "tarkov-monitor-security": "TarkovMonitor non è un cheat. Legge solo i log di Escape From Tarkov salvati sul tuo PC e non modifica mai il gioco né inietta codice.", "stash-page-description": "Invita il bot Discord Stash, esplora i suoi comandi e scopri come può aiutare la tua community.", "stash-hero": "Stash porta l’intero dataset di Tarkov.dev in Discord così la tua community può controllare prezzi, missioni, timer del nascondiglio e altro senza lasciare la chat.", "Invite Stash": "Invita Stash", "Report an issue": "Segnala un problema", "Highlights": "In evidenza", "Item intelligence": "Analisi oggetti", "Instant prices with flea, trader, and craft context.": "Prezzi istantanei con contesto di flea market, commercianti e craft.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Le ricerche di craft/baratto riutilizzano i dati di redditività di Tarkov.dev.", "Toggle PVE or PMC game modes to match your server rules.": "Alterna le modalità PVE o PMC per adattare le risposte del bot alle regole del server.", "Progress tracking": "Monitoraggio dei progressi", "Quest command lists requirements, turn-ins, and rewards.": "Il comando quest elenca requisiti, consegne e ricompense.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "Il comando progress rispecchia i miglioramenti di hideout e trader salvati su TarkovTracker.", "Restock and status alerts keep everyone informed between raids.": "Gli avvisi di restock e di stato tengono tutti informati tra i raid.", "Community tools": "Strumenti per la community", "Goons tracker for spotting the Rogue Boss trio.": "Tracker dei Goons per individuare il trio di boss Rouge.", "Roulette mini-game for fun raid modifiers.": "Mini-gioco roulette per modificatori di raid divertenti.", "Slash commands, autocomplete, and localized responses.": "Comandi slash, autocompletamento e risposte localizzate.", "Frequently used commands": "Comandi più usati", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash offre decine di comandi slash. Eccone alcuni su cui la maggior parte dei server fa affidamento:", "Command": "Comando", "Example": "Esempio", "Support & feedback": "Supporto e feedback", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "Ti servono privacy policy o termini di servizio per la revisione di sicurezza del server? Si trovano nella cartella /assets del repository e vengono aggiornati ad ogni release.", "stash-tech-note": "Hai bisogno di guide tecniche o istruzioni per l’hosting autonomo? Consulta il README su GitHub per la documentazione più recente.", "card-tarkov-monitor-desc": "Automatizza i progressi di TarkovTracker, cattura i tempi di coda e controlla le mappe di Tarkov.dev con una sola app Windows.", "card-stash-desc": "Comandi slash per controllare prezzi, missioni, progressi del nascondiglio e restock direttamente da Tarkov.dev.", "Read more": "Scopri di più", "Invite now": "Invita ora", "other-tools-page-description": "Scopri le app companion create dal team Tarkov.dev, tra cui TarkovMonitor e il bot Discord Stash.", "other-tools-body": "<0>Tarkov.dev è più di un sito. Questi strumenti estendono i tuoi raid, stream e community Discord usando lo stesso dataset open source. Esplora ogni tool per vedere screenshot, guide e link di supporto.", "Learn about TarkovMonitor": "Scopri TarkovMonitor", "Meet the Stash bot": "Conosci il bot Stash", "The help command to view all available commands": "Il comando help per vedere tutti i comandi disponibili", "View details about the bot": "Mostra i dettagli del bot", "Get a sorted ammo table for a certain ammo type": "Ottieni una tabella di munizioni ordinata per un certo tipo", "Check barter details for an item": "Controlla i dettagli di baratto di un oggetto", "Get detailed information about a boss": "Ottieni informazioni dettagliate su un boss", "Get the latest game changes from tarkov-changes.com": "Ricevi gli ultimi cambiamenti del gioco da tarkov-changes.com", "Check crafting details for an item": "Controlla i dettagli di crafting di un oggetto", "Set the game mode (regular, PVE) for bot responses": "Imposta la modalità di gioco (regolare o PVE) per le risposte del bot", "Check or report the location of the Goons": "Controlla o segnala la posizione dei Goons", "Get a Discord invite link for the bot to join it to another server": "Ottieni un link di invito Discord per aggiungere il bot a un altro server", "Report an issue with the bot": "Segnala un problema con il bot", "Get price, craft, barter, etc. information about an item": "Ottieni informazioni di prezzo, craft, baratto, ecc. di un oggetto", "Get a key's price and maps it is used on": "Ottieni il prezzo di una chiave e le mappe in cui si usa", "View a map and some general info about it": "Visualizza una mappa e alcune info generali", "Get the latest official patchnotes for EFT": "Ricevi le ultime patch note ufficiali di EFT", "Get player profile information": "Ottieni informazioni sul profilo di un giocatore", "Get a detailed output on the price of an item, its price tier, and more!": "Ricevi un report dettagliato sul prezzo di un oggetto, il suo tier e altro ancora!", "Manage your customized hideout and trader progress": "Gestisci i progressi personalizzati di nascondiglio e trader", "Get detailed information about a quest": "Ottieni informazioni dettagliate su una missione", "Show or set alerts for trader restock timers": "Mostra o imposta avvisi per i timer di restock dei trader", "Play a game of roulette to determine how you play your next raid": "Gioca alla roulette per decidere come affronterai il prossimo raid", "Get the game/server/website status of Escape from Tarkov": "Ottieni lo stato del gioco/server/sito di Escape from Tarkov", "Get information about a in-game stim": "Ottieni informazioni su uno stim in-game", "Show the criteria for loot tiers": "Mostra i criteri dei tier di bottino", "Get the bot's uptime": "Mostra l’uptime del bot", "stash-support": "<0>Stash è mantenuto dal team di Tarkov.dev. Bug o idee? Apri un issue su <1>GitHub o parla con gli sviluppatori nel <2>Discord Tarkov.dev. Se sincronizzi Tarkov.dev e i dati del bot, includi screenshot e passi per riprodurre.", "Database": "Database", "Calculators": "Calculators", "Progression": "Progression", "Community": "Community", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/ja/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "こそこそボイ。カルチストは3~5人のグループ内で物陰に潜み、プレイヤーが近づいてくるのを待ちます。彼らは静かに敵に近づき、普通のナイフか、カルトの司祭の場合は毒入りカルトナイフで刺します。発砲された場合、カルト教団は銃器やグレネードを用いて応戦する。ナイフでプレイヤーを攻撃した後、彼らは再びWoodsに逃げ込み、影に戻ることを選択することができる。", "knight-bio": "", "knight-description": "The Goons'のリーダー。様々な地図にスポーンすることができる。", "glukhar-bio": "彼の過去の進行中については、すべての文書が紛失または機密扱いのため、信頼できる情報はありませんが、未確認情報によると、彼は下士官という階級を持っていたようです。コンバットオペレーションに参加した。
    彼の仲間もすべて元軍人であるようだ。たった今、彼のグループはタルコフで資源と影響力を争う事実上の盗賊団に過ぎないが。ノルヴィンスク地方から物資を輸出できるトレーダーとコネクションがあり、定期的に貨物輸送のための最終列車を送りつけてくる。", "glukhar-description": "グルカールとそのガードたちは、非常に敵対的です。開けた場所で戦って成功することはまずない。狭い廊下や密室が望ましい。Glukharと彼のガードは非常に正確です。Glukharと彼のガードは常に近くにいて、彼のガードは彼が行くところならどこでもついてくる。", "kaban-bio": "彼は以前タルコフで小規模な合法ビジネスを経営していましたが、金を稼ぐためには犯罪的な手段を使うことも厭いませんでした。一般的な避難の後も彼は街に残り、そのギャングは成長しました。", "kaban-description": "彼の体格は、機関銃を休めることなく撃つことを可能にしますが、同時に移動性に乏しく、戦闘中は一箇所に留まるか、ゆっくりとポイント間を移動します。彼には多数の武装した護衛がおり、その中には彼のために強固な防御を組織した元軍人もいます。ボスは「ストリート・オブ・タルコフ」の自動車修理工場エリアに住んでいます。このエリアは厳重に防御されており、入り口は固定式機関銃や自動擲弾発射器で要塞化され、周囲には地雷が設置され、自動車サービスセンターの屋根には狙撃手が配置されています。カバンは機関銃の弾薬箱を収納するためのカスタムリグを使用し、服の下にボディアーマーを着用し、護衛たちの間で絶対的な権威を持っています。近隣のスカブはボスの防御を手伝い、カバンのために戦闘に参加します。", "killa-bio": "", "killa-description": "Tarkovの真のギガチャド。キラは軽機関銃などの自動小銃で敵を制圧射撃しながら、カバーからカバーへと潜伏し、最後の追い込みのために目標に接近する。アサルト中はジグザグに進入し、スモークや破片グレネードを使用し、自動射撃で執拗に敵を制圧する。パトロールルートから大きく外れて目標を追いかけるので、ロックオンされたらかなり遠くまで走って逃げること。", "kollontay-bio": "彼は内務省(MVD)の元将校で、法執行機関での勤務中には卑劣な男としての評判を持ち、同僚たちから時々恐れられる行動をとっていました。仕事中、彼はしばしば好みでない人物に対して、彼の好みの尋問方法であるゴム警棒やその他の非法的圧力を使いました。彼の身体的な強さと大胆な気質のおかげで、TerraGroupのスキャンダル事件の後、彼はギャングを結成し、最近まで自分が戦うべきだったこと - 略奪と強盗 - を始めました。しかし、その対立以前にも、彼はしばしば地元の「ビジネスマン」に保護を提供していました。たとえば、カバンとの良好な関係はよく知られています。", "kollontay-description": "コロンタイは少数の護衛を持ち、一箇所に留まることを好み、時々自分の領域をパトロールします。彼は優位に立つと感じた場合、警棒に持ち替えることがあります。彼はクリモフショッピングモールと内務省タルコフアカデミー周辺に住んでいます。", "partisan-bio": "There are few reliable details about his past, but it's known that he once served in Afghanistan, where his radical methods of warfare took root. Referred to by some as 'Partizan', he became notorious for his expertise in setting traps and mines. His reputation for eliminating enemies often came down to catching them off guard, using their overconfidence against them. Partizan's knowledge of guerrilla tactics made him a dangerous adversary, able to turn any location—whether forest or building—into a deadly trap.
    Those who survive long enough to learn his ways may just find themselves in his good graces, but only if they're careful enough to see the traps before it's too late.", "partisan-description": "", "raider-bio": "", "raider-description": "レイダーは一般的なScavよりもかなり強く、より戦術的なScavである。彼らはより危険な武器を持ち、より高いレベルの弾薬を使用します。さらに、彼らはより優れた狙いを持ち、装備品の揃ったプレイヤーをわずかな弾丸で落とすこともしばしばあります(あるいは、頭部を狙われるだけです)。また、Scavレイダーは複数のグループ内でパトロールしており、装備品やボイスライン、攻撃性などで見分けることができる。レイダーは最初は他のプレイヤーにもフレンドリーに接しますが、近づいたり警告を無視したりすると敵対的になります。また、Scavsが怒るとすべてのScavsに敵対心を持つようになります。", "reshala-bio": "", "reshala-description": "通常、プレイヤーの視界に入らないよう、戦闘の後方で待機していることが多い。また、アーマーを装着することはない。プレイヤーのカルマレベルが低い場合、Reshalaやそのガードに挑発されずに撃たれたり、Reshalaに近づくと撃たれたりすることがあるので、プレイヤーとして注意すること。また、カルマが低いプレイヤーは敵対する前にガードから警告を受けることがある。", "rogue-bio": "", "rogue-description": "ローグはLighthouseの浄水場とその周辺を守っています。主な行動はパトロールだが、しばしば屋根の上に防御の位置をとり、配置された武器を使用する。彼らは自分たちのエリアに入るすべてのプレイヤーを目標にするが、USEC PMCやScavに対しては若干甘くなる。ローグは南の灯台の場所(島)でもスポーンすることがあります。ローグは体力が高く、レーザービームの精度と目標距離が高いため、非常に危険です。ローグはまた、負傷するとカバーの後ろに逃げ込み、医薬品を使用する。", "sanitar-bio": "元医師、科学者。テラグループ社に勤務。研究所で新しい精神作用物質の開発など、いくつかのプロジェクトを主導した。研究領域は、複数状態が死体に与える影響から神経刺激物質の開発まで多岐にわたった。テラグループの研究所以外にも、アズール海岸のサナトリウムに自分のオフィスを持ち、特に完全避難前の最後の数週間はここで研究を行った。
    医療部隊とともにホットゾーンに派遣されることも多く、入社後はアフリカや他のオフィスを定期的に訪問して開発を監修した。同僚たちから絶大な信頼と尊敬を集めている。", "sanitar-description": "コンバットでは仲間のスカブやガードと一緒に戦うが、治療や注射のために離脱することもしばしばある。医薬品をたくさん持っているので、長時間の戦闘も可能である。", "shturman-bio": "", "shturman-description": "Shturmanとそのプレイヤーは、森の製材所を守るため、遠距離からプレイヤーと交戦することになる。彼らは近接戦闘に向かないため、距離を置くことを好む。", "tagilla-bio": "", "tagilla-description": "彼は狂気じみた性格で、あなたをハンマーで殴り倒そうとします。しかし、もしあなたが垂木のようなパスファインディングできない位置にいる場合、彼はサイド武器(通常はショットガン)を使って遠くからあなたをキルする。レイド開始直後から進行中。ボスは待ち伏せして制圧射撃を行い、必要に応じて侵入することができる。", "zryachiy-bio": "Tarkovの中で最も謎めいた人物の一人である。スナイパーの訓練を受けており、中東やアフリカのホットゾーンに何度も出没したとの噂がある以外は、過去についてほとんど何も知られていない。
    紛争のずっと前からライトキーパーの忠実な愛玩犬となり、ライトキーパーと彼が関わるすべての人々とのつながりを「確立」することに進行中であった。ローググループや、場所に謎のシンボルを描くフードの男たちとも親交がある。
    Zryachiyは非常に寡黙だが、一緒に働く者はたいてい言葉がなくても彼のことを理解している。彼の目については多くの噂があり、先天性の特殊性だと言う人もいれば、暗闇での視力を高めるためのある目薬が、彼の目に白さを与えるという副作用を指摘する人もいる。このような外見とは裏腹に、元軍人スナイパーということもあり、その優れた視力によってその名を知られるようになったようです。", "zryachiy-description": "ライトキーパーの教団員ガード。" } ================================================ FILE: src/translations/ja/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "インタラクティブ", "Landscape": "風景", "View Fullscreen": "全画面表示", "Exit Fullscreen": "全画面表示を終了", "Satellite": "衛星", "Abstract": "抽象", "Levels": "レベル", "1st Floor": "1階", "2nd Floor": "2階", "3rd Floor": "3階", "4th Floor": "4階", "5th Floor": "5階", "Underground": "アンダーグラウンド", "Garage": "ガレージ", "Tunnels": "トンネル", "Bunkers": "バンカー", "Spawns": "スポーン", "PMC": "PMC", "Scav": "スカブ", "Sniper Scav": "スナイパースカブ", "Boss": "ボス", "Extracts": "出口", "Shared": "共有", "Hazards": "危険", "Usable": "使用可能", "Locks": "ロック", "Stationary Gun": "固定銃", "Lever": "レバー", "Switch": "スイッチ", "Door": "ドア", "Container": "コンテナ", "Car Door or Trunk": "車のドアまたはトランク", "Lock": "ロック", "Activated by": "起動による", "Activates": "起動", "Needs power": "電源が必要", "Lootable Items": "略奪可能なアイテム", "Tasks": "タスク", "Item": "アイテム", "Objective": "目標物", "Misc": "Misc", "openworld-name": "オープンワールド", "openworld-description": "これはTarkovのフルマップのイメージを表したものです。このオープンワールドマップは、既存の地図にある鍵の場所をすべて組み合わせて、巨大な1つのマップにすることになるでしょう。", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "Use TarkovMonitor to show your position", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/ja/properties.json ================================================ { "ambientVolume": "環境音", "caliber": "口径", "damage": "ダメージ", "distanceModifier": "距離", "distortion": "歪み", "projectileCount": "投射回数", "penetrationPower": "貫通力", "armorDamage": "アーマーダメージ", "fragmentationChance": "破片チャンス", "ammoType": "弾薬の種類", "class": "クラス", "material": "素材", "zones": "ゾーン", "defaultPreset": "デフォルトプリセット", "durability": "耐久性", "ergoPenalty": "エルゴペナルティ", "speedPenalty": "スピードペナルティ", "turnPenalty": "ターンペナルティ", "headZones": "頭部ゾーン", "capacity": "容量", "grids": "グリッド", "energy": "エネルギー", "hydration": "水分量", "units": "ユニット", "stimEffects": "スティム効果", "blindnessProtection": "失明防止", "fuse": "ヒューズ", "maxExplosionDistance": "最大爆発物距離", "fragments": "破片", "deafening": "耳障りなこと", "blocksHeadset": "ヘッドセットをブロックする", "ricochetY": "跳弾確率", "uses": "用途", "malfunctionChance": "動作不良のチャンス", "ergonomics": "エルゴノミクス", "recoil": "リコイル", "loadModifier": "ロードモディファイアー", "ammoCheckModifier": "残弾確認モディファイ", "useTime": "使用時間", "cures": "治療法", "hitpoints": "ヒットポイント", "maxHealPerUse": "1回の使用で回復した最大値", "hpCostLightBleeding": "Hpコスト 軽量出血", "hpCostHeavyBleeding": "Hpコスト重度出血の場合", "painkillerDuration": "鎮痛剤の持続時間", "energyImpact": "エネルギーインパクト", "hydrationImpact": "水分量による影響", "recoilVertical": "垂直反動", "recoilHorizontal": "水平反動", "zoomLevels": "ズームレベル", "minLimbHealth": "分肢の体力", "maxLimbHealth": "四肢の体力の最大値", "effectiveDistance": "有効射程距離", "fireModes": "発射機構", "fireRate": "連射速度", "sightingRange": "視認範囲", "defaultWidth": "デフォルトの幅", "defaultHeight": "デフォルトの高さ", "defaultErgonomics": "デフォルトのエルゴノミクス", "defaultRecoilVertical": "デフォルトのリコイル垂直反動", "defaultRecoilHorizontal": "デフォルトの水平反動", "defaultWeight": "デフォルトの重量", "recoilModifier": "リコイルモディファイア", "weight": "重量", "baseItem": "ベースアイテム", "categories": "カテゴリ", "type": "の種類", "convergence": "コンバージェンス", "cameraRecoil": "カメラリコイル", "recoilAngle": "リコイルアングル", "recoilDispersion": "リコイルディスパージョン", "usedOnMaps": "地図で使用" } ================================================ FILE: src/translations/ja/translation.json ================================================ { "No data": "データなし", "Current Average Latency": "現在の平均レイテンシー", "API Latency in milliseconds": "APIレイテンシー(ミリ秒単位", "No barters found for this item": "このアイテムに交換用バーターはありません", "LL{{level}}": "LL{{level}}", "Barter at {{trader}}": "でバーター{{trader}}", "Craft at {{station}}": "{{station}}でクラフト", "Barter": "バーター", "Craft at {{stationName}} {{stationLevel}}": "{{stationName}} {{stationLevel}}でクラフト", "Provides {{count}} for {{totalCost}}_other": "{{count}}を{{totalCost}}で提供(その他)", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "{{duration}}内に{{count}}を{{totalCost}}でクラフト(その他)", "Reward": "報酬", "Cost": "コスト", "Cost ₽": "コスト₽", "Estimated savings": "想定される節約額", "InstaProfit": "即売会利益", "N/A": "N/A", "Barter cost": "バーターコスト", "No barters available for selected filters": "選択済のフィルターにバーターはありません", "No barters available for selected filters but some were hidden by ": "選択済フィルターにバーターはありませんが、いくつかのフィルターが非表示になっています ", "your settings": "環境設定", "Some barters hidden by ": "によって隠されたバーターもある ", "Can hold:": "保持できる:", "Can't hold:": "持てない:", "Level": "レベル", "Flea Market": "フリーマーケット", "Flea banned": "蚤の市禁止", "Sell price": "販売価格", "Flea Market fee": "フリーマーケット手数料", "Duration": "期間", "Finishes": "達成", "Start now": "今すぐ始める", "Flea throughput/h": "蚤の市スループット/h", "Estimated profit": "推定利益", "Estimated profit/h": "推定利益/h", "No crafts available for selected filters": "選択済のフィルターに対応したクラフトはありません", "No crafts available for selected filters but some were hidden by ": "選択済フィルターで使用可能なクラフトはありませんが、一部非表示になっていたため ", "Some crafts hidden by ": "で隠されたクラフトもあります ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "All options already selected", "Clear selection": "選択をクリア", "This item can't be sold on the Flea Market": "このアイテムはフリーマーケットで販売することはできません", "Not scanned on the Flea Market": "蚤の市でスキャンされたわけではない", "Flea market prices loading": "フリーマーケットの価格ロード中", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>プラットフォーム全体がオープンソースで、開発者向けにフォーカスされています。すべてのコードは<1><0> GitHub で公開されています。", "about-discord-p": "<0>チャットや質問、機能の要望があれば、<1><0> Discordサーバーを用意しています。", "about-x-p": "<0>最新の情報は<1><0>Xでフォローしてください。", "About": "について", "Contributors": "投稿者", "Massive thanks to all the people who help build and maintain this project!": "このプロジェクトの構築と維持にご協力いただいているすべての方々に、多大なる感謝を申し上げます!", "Made with ❤️ by:": "によって、❤️、作られました:", "Supporters": "サポーターズ", "about-support-ukraine-p": "<0>ウクライナの人々を支援するため、可能な方は下記のボタンから寄付をすることをお勧めします。", "about-support-collective-p": "<0>また、このプロジェクトを支援したい方は、<1>Open Collectiveで寄付やバッカーになることができます。", "Item Data": "アイテムデータ", "Fresh EFT data courtesy of": "の最新 EFT データ提供", "Additional data courtesy of": "追加データ提供", "Resources": "資源", "Tarkov.dev API": "Tarkov.dev API", "{{bot}} integration": "{{bot}} 統合", "Discord bot for your Discord": "あなたのDiscordのためのDiscordボット", "External resources": "外部資源", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.devは、現在閉鎖されているtarkov-tools.comのフォークです | Tarkovツールとその周りのコミュニティを構築してくれたkokarnに大きな感謝を捧げます。", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "ゲームの内容および素材は、Battlestate Gamesおよびそのライセンサーの商標および著作権です。すべての権利はReserveされています。", "version": "バージョン", "PMC & Scav Thorax HP": "PMC & Scavs 胸部 HP", "Reshala Thorax HP": "Reshala 胸部 HP", "Raider Thorax HP": "レイダー胸部 HP", "Shturman Thorax HP": "Shturman 胸部 HP", "Cultist Priest Thorax HP": "カルトの司祭 胸部 HP", "Cultist Warrior Thorax HP": "カルトの戦士 胸部 HP", "Damage": "ダメージ", "Class {{tier}}": "クラス{{tier}}", "Penetration": "貫通", "Filter by caliber": "口径でフィルターする", "This item can only be sold to trader": "このアイテムはトレーダーにのみ売却可能です", "per slot": "スロットあたり", "Value": "価値観", "Per slot": "スロットあたり", "Sell to": "売却品", "Found In Raid": "レイドで発見", "Search item...": "サーチ中アイテム...", "Search task...": "サーチ中...", "Tasks": "タスク", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Items": "アイテム", "No hideout modules requires this item": "ハイドアウトのモジュールにはこのアイテムは必要ない", "No unbuilt hideout modules for selected filters but some were hidden by ": "選択済フィルターに未作成のハイドアウトのモジュールはありませんが、一部は以下の方法で隠されていました ", "Hideout Module": "ハイドアウトのモジュール", "Item": "アイテム", "Amount": "金額", "Player level: {{playerLevel}}": "プレイヤーレベルです:{{playerLevel}}", "Reputation: {{reputation}}": "評判:{{reputation}}", "Commerce: {{commerce}}": "商業:{{commerce}}", "Cheapest Price": "最安価格", "Task: {{taskName}}": "タスクです:{{taskName}}", "Flea Market not available": "フリーマーケットは利用不可", "No trader offers available": "トレーダーオファーなし", "Loading...": "ロード中...", "Ammo": "弾薬", "Maps": "地図", "More": "もっと見る", "Traders": "トレーダー", "Prapor": "Prapor", "Therapist": "Therapist", "Skier": "Skier", "Peacekeeper": "Peacekeeper", "Mechanic": "Mechanic", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "ボス", "Barter profit": "バーター利益", "Hideout profit": "ハイドアウトの利益", "Loot tiers": "戦利品レベル", "Hideout build costs": "ハイドアウトの構築コスト", "Wipe length": "ワイプの長さ", "Bitcoin Farm Profit": "ビットコインファームの儲け話", "Achievements": "Achievements", "API": "API", "Donate": "寄付する", "Become a patron": "パトロンになる", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "has alternates", "On Task Completion": "オンタスクコンプリート", "On Task Start": "オンタスクスタート", "Task": "タスク", "Required items": "条件の良いアイテム", "Reward items": "報酬アイテム", "Required tasks": "条件のタスク", "loading": "ロード中", "active": "進行中", "succeeded": "好評", "complete": "完了", "failed": "へたこいた", "Minimum level": "最低レベル", "Minimum trader level": "トレーダーとしての最低レベル", "Reputation rewards": "親密度報酬", "Endgame": "エンドゲーム", "Required for Kappa": "カッパのために必要", "Required for Lightkeeper": "ライトキーパーのために必要", "No quests found": "クエストが見つからない", "Some tasks hidden by filter settings": "フィルター設定で非表示になるタスクもある", "open this page in another browser or window and connect using this id": "このページを別のブラウザやウィンドウで開き、このIDを使って接続します", "ID for remote control": "リモートコントロール用ID", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "別のブラウザでtarkov.devにアクセスし、このIDを入力すると、そこからこのページをコントロールすることができます", "Click to connect": "クリックで接続", "Sell value": "売却品", "Tarkov server status": "Tarkovサーバーの状況", "This item can't be sold to traders": "このアイテムはトレーダーに販売することはできません", "Name": "名称", "Sell to Flea": "蚤の市への販売", "Buy on Flea": "蚤の市で購入する", "Sell to Trader": "トレーダーへの販売", "Trader buy": "トレーダー購入", "Buyback ratio": "自己株式取得率", "The percent recovered if you buy this item and sell it to the trader": "このアイテムを購入し、トレーダーに売却した場合に回収されるパーセント", "Grid": "グリッド", "Slots occupied": "占有するスロット", "Slots inside": "内スロット", "Slots ratio": "スロット比", "Price per slot": "1スロットあたりの価格", "Armor class": "アーマークラス", "Zones": "ゾーン", "Max Durability": "最大耐久性", "Effective Durability": "効果的な耐久性", "Repairability": "修理の容易さ", "Weight (kg)": "重量(kg)", "Stats": "スタッツ", "Mov/Turn/Ergo": "ムーブ/ターン/エルゴ", "Caliber": "口径", "Armor damage": "アーマーダメージ", "Fragmentation chance": "破片チャンス", "Blindness protection": "失明防止", "Hydration": "水分量", "Energy": "エネルギー", "Hydration Cost": "水分量コスト", "Energy Cost": "エネルギーコスト", "Hydration + Energy Value": "水分量+エネルギー量", "Sound suppression": "音の制圧射撃", "Low": "低い", "None": "なし", "Blocks earpiece": "イヤホンをブロックする", "Yes": "はい", "No": "いいえ", "Ergonomics": "エルゴノミクス", "Cost per ergo": "エルゴあたりのコスト", "Recoil": "リコイル", "Distance": "距離", "No items": "アイテムなし", "Not built": "構築されていない", "Locked": "ロックされた", "Crafting": "クラフティング", "Hideout Management": "ハイドアウトの管理", "Be the first!": "一番になる!", "Objective": "目標物", "No objectives": "目標物なし", "Players": "プレイヤー", "By": "で", "Restock in": "で再入荷", "Support Ukraine": "ウクライナへの支援", "Cost per unit": "1台あたりのコスト", "About the tarkov.dev project": "tarkov.devプロジェクトについて", "about-page-description": "the-hideoutとtarkov.devについてもっと知る。コミュニティが作った無料のオープンソースEscape from Tarkovエコシステムです!私たちのツールを使ってゲームをプレイしたり、無料のAPIを使って自分のプロジェクトを作ったりしてください。", "Open source": "オープンソース", "Discussions & feedback": "ディスカッションとフィードバック", "Support": "サポート", "about-support-more-p": "<0>また、バグの投稿、新機能の提案や実装、マップの改善など、サイトをより良くするために思いつくことで、ご協力いただくことも可能です。", "about-api-p": "<0>Tarkovの開発に関するすべてのニーズに対して、100%無料で一般公開されているAPIをオファーしています -<1>API", "History": "沿革", "about-history-p": "<0>このプロジェクトは、<1>tarkov-tools.comのフォークです。オリジナルの作成者である<3>@kokarnは、サイトを閉鎖することを決定しました。オープンソースの精神に基づき、開発者のグループが集まり、Tarkovコミュニティのための素晴らしいウェブサイトと、クリエイターのためのさらなる開発を後押しするAPIを提供し続けるために、サイトを復活させました。このプロジェクトは現在、100%オープンソースで開発者優先となっています。私たちのGitHub組織(<5>the-hideout)には、API、このウェブサイト、コミュニティDiscordボット、サーバーインフラ、その他多くの機能を提供するすべてのレポがあります!私たちはオープンソースに情熱を持っており、すべての人のために私たちのエコシステムを改善するためのプルリクエストが大好きです。", "Core Contributors": "コアコントリビューター", "about-core-contributors-p": "<0>このプロジェクトの中心的な貢献者(順不同)は以下の通りです:", "All Contributors": "すべての投稿者", "about-all-contributors-p": "<0>このプロジェクトを実現するために貢献してくださったすべての方々に、多大なる感謝を申し上げます!❤️", "Description": "Description", "Hidden": "Hidden", "Player %": "Player %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "This page includes information on the achievements that can be earned.", "Ammo chart": "弾薬チャート", "ammo-page-description": "このページでは、Escape from Tarkovに登場する全弾薬の種類を一覧で紹介しています。使用可能な弾薬の完了リストをフィルタリングするには、口径の名前をクリックします。", "ammo-page-p": "<0>タルコフの荒野には、多様な弾薬が用意されています。さまざまな相手とコンバットするためには、さまざまな種類の弾薬が必要です。<1>このページでは、Escape from Tarkovに登場するすべての弾薬の種類のリストを掲載しています。使用可能な弾薬の完了リストをフィルタリングするには、口径の名前をクリックしてください。", "Total damage": "ダメージ合計", "Use total damage of all projectiles in a round": "弾薬の合計ダメージを使用します", "Ignore settings": "設定を無視する", "Shows all sources of items regardless of your settings": "環境設定に関係なく、すべてのアイテムのソースが表示される", "Use barters for item sources": "アイテムの入手元としてバーターを使用", "Use crafts for item sources": "アイテムの入手元としてクラフトを使用", "Ammo Statistics Table": "弾薬統計表", "API Documentation": "APIドキュメンテーション", "api-docs-page-description": "Escape from Tarkovのコミュニティが作ったAPIとそのドキュメントをご紹介します。EFTのための無料で使いやすいGraphQL APIの詳細については、こちらをご覧ください。", "api-about-p": "<0>APIはGraphQLで書かれており、私たちは仕様に沿い、壊れるような変更をしないように努めています。どのようなクエリが作れるのか、スキーマがどのように構成されているのかについては、プレイグラウンドにアクセスして右側の「Docs」タブをクリックしてみてください。いくつかのクエリーを試す準備ができたら、プレイグラウンドでテストすることもできます。一般的にGraphQLクエリについて学ぶには、GraphQL Foundationが役立つ資源を提供しています。<1><0><0>tarkov.dev GraphQLプレイグラウンド<1><0>GraphQL Foundationの資源<1>プレイグラウンドの外から<1>APIクエリを送信できるようになったら、エンドポイントは<1>https://api.tarkov.dev/graphql", "Current API Performance": "現在のAPI性能", "api-performance-p": "<0>APIの完全な指標とパフォーマンスについては、<1>ステータスページをご確認ください。", "FAQ": "よくあるご質問", "Is it free?": "無料ですか?", "Is it open source?": "オープンソースなのでしょうか?", "api-faq-open-source-p": "もちろんです!APIのソースコードは、<1>github.com/the-hideout/tarkov-apiのGitHubリポジトリで見ることができる。", "Is there a rate limit?": "料金の上限はあるのでしょうか?", "api-faq-rate-limit-p": "We occasionally get hit with a lot of traffic from bad actors that requires implementing rate limits. Price data is updated every 5 minutes, so there's really no need to query faster than that. Use common sense, and you should be fine.", "What about caching?": "キャッシングについてはどうでしょうか?", "api-faq-caching-p": "私たちのデータは5分ごとに更新されるため、すべてのGraphQLクエリも同様に5分間キャッシュされます。これにより、私たちのサーバーのロード中が大幅に削減され、お客様のリクエストがスピーディーになるのです!", "Where is the data from?": "データはどこの国のものですか?", "We source data from multiple places to build an API as complete as possible. We use data from:": "私たちは、できるだけ完全なAPIを構築するために、複数の場所からデータを調達しています。私たちは、以下のところからデータを利用しています:", "Our network of scanners": "スキャナーのネットワーク", "Examples": "例", "example": "例", "Contributed by": "寄稿", "API Users": "APIユーザー", "api-users-page-description": "このページには、Tarkov.devのパブリックAPIの全ユーザーとそのプロジェクトのリストが含まれています。", "api-users-p": "<0>このページに掲載されたいですか?<1>Discordに参加して、あなたの作ったものを教えてください!", "Barter Profits": "バータープロフィッツ", "barters-page-description": "このページでは、NPCベンダーと交換できるさまざまなアイテム、交換用価格、売却品で得られる利益について紹介しています。", "Shows all barters regardless of your settings": "環境設定に関係なく、すべてのバーターを表示します", "Hide dogtags": "ドッグタグを隠す", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "ドッグタグを使用したバーターの本当の「コスト」を見積もるのは難しいので、ドッグタグを使用したバーターは除外するのがよいでしょう", "Show all barters": "バーターをすべて表示する", "All": "すべて", "Item filter": "アイテムフィルター", "filter on item": "アイテムにフィルターをかける", "barters-page-p": "<0>Fenceを除いて、Escape from Tarkovのすべてのトレーダーは、そのまま購入するのではなく、<0>物々交換で商品を提供しています。<1>さまざまな安価なものと引き換えに、プレイヤーは、より価値のある物と頻繁に交換することができます。<3>これらの価値あるトレードの大部分は、トレーダーのリセットと頻繁に売り切れる厳格な上限を持っているのであなたのお気に入りの取引のためにリセット後にチェックバックすることを確認してください。", "Num graphic cards": "グラフィックカード数", "Hours": "時間", "Bitcoin Farm Calculator": "ビットコインファーム計算機", "bitcoin-farm-calculator-page-description": "このページでは、GPUの数、電気代、ビットコインコストから、ビットコインファームの構築・維持にかかる価格を割り出すことができる計算ツールを掲載しています。", "Graphic cards count": "グラフィックカード数", "Use fuel cost: {{price}}/day": "燃料費を使う:{{price}}/日", "Use station build costs": "駅の建設費を使う", "Purchase cost": "購入費用", "Remaining days in wipe:": "ワイプでの残り日数:", "Time to produce 1 bitcoin": "1ビットコインの生産にかかる時間", "BTC/day": "BTC/日", "Estimated profit/day": "推定利益/日", "Profitable after days": "利益までの日数", "Total cost of graphic cards": "グラフィックカードの合計コスト", "Build costs": "ビルドコスト", "GPU + build costs": "GPU+ビルドコスト", "Remaining profit": "残り利益", "Map": "マップ", "Spawn Location": "スポーン場所", "Chance": "チャンス", "Count": "カウント", "Spawn chance": "スポーンチャンス", "Chance that the boss spawns on a given map": "ボスが指定された地図にスポーンするチャンス", "Health": "体力", "Total boss health": "合計ボス体力", "Patrol": "パトロール", "Rush": "ラッシュ", "Stalker": "ストーカー", "Hostile and accurate": "敵対的で正確", "Patrol and highly armored": "パトロールと高装甲化", "Group patrol": "グループ内パトロール", "Frequent healing and stim injections": "治療中や刺激注射の頻度も多い", "Sniper": "スナイパー", "Batshit insane": "バカヤロー", "Behavior": "ビヘイビア", "The boss's general AI behavior": "ボスの一般的なAI行動", "Wiki": "ウィキ", "Boss Stats": "ボスの統計情報", "Special Boss Loot": "スペシャルボスのルーティング", "Spawn Locations": "スポーン設置場所", "boss-spawn-table-description": "<0>マップです:ボスがスポーンできるマップ名<1>スポーンする場所:ボスがスポーンするマップ上の正確な場所です。<2>チャンスマップの「スポーンチャンス」が進行中の場合、そのマップの任意の場所にボスがスポーンする推定確率を示します", "Boss Escorts": "ボスエスコート", "This boss does not have any escorts": "このボスにはエスコートがない", "boss-page-description": "このページでは、{{bossName}} の場所や戦利品を漁る情報、討伐のための戦略などを紹介しています。", "bosses-page-description": "このページでは、ゲームに登場するすべてのボスの場所、戦利品を漁る方法、護衛、倒し方の攻略法などを紹介しています。", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "ボスは、Escape from Tarkovでユニークな装備品と特徴を持つ、恐るべき敵である", "About Bosses": "ボスについて", "bosses-page-p": "<0>Escape from Tarkovでは、包囲されたノルビンスクを徘徊する多くのボスが登場します。<1>それぞれのボスはユニークな行動、特徴、戦術を持っています。タルコフのボスはあらゆるレベルのプレイヤーに恐れられており、この地域の敵PMCよりも大きな脅威となることが多いでしょう。<2>しかし、ハイリスクにはハイ報酬がつきものです。多くのボスは高次元のルーティングアイテムを含んでいたり、クエストのために排除する必要がある。ボスのパターンや場所、特徴的な服装を覚えることが、タルコフのボスとの戦闘を開始する際にプレイヤーができる最善の準備となることが多い。", "Connect": "接続", "Connected to": "に接続されている", "id to control": "制御する側", "Remote Control": "リモートコントロール", "remote-control-page-description": "このページでは、Tarkov.devウェブサイトの別のインスタンスをリモートコントロールするために必要なすべてのツールをコンテナで提供します。", "View Map": "マップを見る", "Go": "逝く", "View caliber": "口径を見る", "Select...": "選択済...", "Load tarkov.dev in another browser or window to control it from here": "tarkov.devを別のブラウザやウィンドウで読み込んで、ここから操作する", "Hideout Crafts": "ハイドアウトのクラフト", "crafts-page-description": "このページでは、ハイドアウトでクラフティングできるさまざまなアイテム、必要な素材や資源、達成品を販売することで得られる利益について紹介しています。", "Shows all crafts regardless of your settings": "環境設定に関係なく、すべてのクラフトを表示します", "Average prices": "平均価格", "Use average prices from the past 24 hours for profit calculations": "利益計算には、過去24時間の平均価格を使う", "Most profitable craft in each station": "各局で最も収益性の高いクラフティング", "Best": "一番", "Flea Market banned items": "フリーマーケット禁止アイテム", "Empty fuel": "空っぽの燃料", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "FIR燃料キャニスターを使用するクラフトの燃料キャニスターの価格を、ベンダーの最低売却価格に設定します。", "crafts-page-p": "<0>Escape from Tarkovでは、クラフトによってさまざまなものを作成することができます。集水器、ワークベンチ、医療ステーション、洗面所、食堂ユニットなど、さまざまなハイドアウトのモジュールを使って実現します。<1>ハイドアウトの中で作成された各アイテムには「レイドで発見」のステータスが適用されます。これらのクラフトの全リストは上に示されている。クラフティングスキルはアイテムの作成時間に影響します。<2>アイテムのアイコンが青い枠で囲まれている場合、補助ツールとして活用され、製造が達成されるとスタッシュに戻されます。", "Page not found": "ページが見つかりません", "error-page-description": "これは、あなたが探しているページではありません", "Sorry, that page doesn't exist!": "申し訳ありませんが、そのページは存在しません!", "Hideout": "ハイドアウトのご案内", "hideout-page-description": "このページでは、ハイドアウトのアップグレードに必要な素材や資源を利用して建築できる、さまざまなステーションやモジュールについて紹介しています。", "Show all stations & modules": "すべてのステーション&モジュールを表示する", "Show built": "構築されたショー", "Show already built stations": "既に建設済みのステーションを表示", "Show locked": "ロックされたものを表示", "Show unavailable stations": "利用不可のステーションを表示", "Show all requirements": "すべての要件を表示", "Show trader and other station level requirements": "トレーダーおよびその他のステーションレベルの要件を表示", "Collected": "稼働中", "Item Tracker": "アイテムトラッカー", "Only show Found in Raid": "レイドで発見されたショーのみ", "Reset all tracking": "すべてのトラッキングをリセットする", "Hide completed": "完了を隠す", "Hide tasks you've completed": "完了したタスクを非表示にする", "Hide dogtag barters": "ドッグタグバーターを隠す", "Best price to sell for": "ベストプライスで販売します", "Fee": "手数料", "Profit": "プロフィット", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "このアイテムのフリーマーケットで最後に観測された最安値は{{lastSeenPrice}} でした。\nしかし、手数料の計算方法の関係で、{{bestPrice}} で売却したほうがよいでしょう。", "Max price to sell for": "最高価格で販売する", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "このアイテムは、フリーマーケットで観測されていません。\n最大収益価格は{{bestPrice}} ですが、その価格で売却品が販売されない場合もあります。\n最高価格は、環境設定のインテルセンターとハイドアウト管理のスキルレベルに影響されます。", "Likely sell price": "売却品と思われる価格", "item-page-description": "このページでは、{{itemName}} の特徴、使い方、攻略法などを紹介しています。", "Sell for": "の販売品です", "Buy for": "のために購入する", "Flea price history": "フリーマーケットの価格履歴", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "昨日との比較で変化: {{changeLast48h}} ₽ /{{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "直近24時間の最安値スキャン価格:{{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "直近24時間のスキャン価格の最高値:{{high24hPrice}}", "Updated: {{val, relativetime}}": "更新しました:{{val, relativetime}}", "Items contained in {{itemName}}": "に含まれるアイテム{{itemName}}", "Barters with {{itemName}}": "とのバーターがあります{{itemName}}", "Crafts with {{itemName}}": "でのクラフティング{{itemName}}", "Hideout modules needing {{itemName}}": "ハイドアウトのモジュールの必要性{{itemName}}", "Shows all modules regardless of your settings": "環境設定に関係なく、すべてのモジュールを表示します", "Quests requiring {{itemName}}": "クエストの必要性{{itemName}}", "Quests rewarding {{itemName}}": "クエスト報酬{{itemName}}", "Armors": "アーマー", "armors-page-description": "このページでは、ゲーム内で使用できるアーマーの種類を、価格や修理の容易さ、アーマークラスなどの特徴を含めて、ソート可能な表で紹介しています。", "Class effective durability": "クラスで有効な耐久性", "Include rigs": "リグを含む", "Max price": "最高価格", "max price": "最高価格", "armors-page-p": "<0>In the video game Escape from Tarkov, armor vests are worn to lessen bullet damage. Helmets are typically used in addition to them.", "Backpacks": "バックパック", "backpacks-page-description": "このページでは、ゲーム内で使用できるバックパックの種類を、価格、サイズ、容量などの特徴別に、ソート可能な表で紹介しています。", "Net price per slot": "1スロットあたりのネット価格", "Show price per additional slot of storage gained from the container": "コンテナ&ケースから得られるストレージの追加スロットあたりの価格を表示します", "backpacks-page-p": "<0>Backpacks in the Escape from Tarkov game are various-sized containers for carrying your hard-earned riches.", "Barter Items": "交換用アイテム", "barter-items-page-p": "<0>This table of barter items from Escape from Tarkov will make it simple for you to determine how much each one is worth. It can be challenging to determine which products are valuable enough to take because there are over 150 barter items in the game, and flea market pricing can fluctuate suddenly. You may optimize your loot with the aid of this interactive table.", "bsg-category-description": "Escape from Tarkovの{{category}} について、必要な情報をすべて確認することができます。", "Containers": "コンテナ", "containers-page-p": "<0>As their name implies, containers in Escape from Tarkov are items used to hold other things. Some of these items are used to clear up inventory space by acting as storage and taking up less inventory slots however some of them cannot be equipped on the character.", "Glasses": "ガラス", "glasses-page-description": "このページでは、ゲーム内で使用できるガラスの種類について、価格やアーマークラスなどの情報をソート可能な表で紹介しています。", "glasses-page-p": "<0>Eyewear in Escape from Tarkov can be used to decrease the number and quantity of raindrops on the players' screens as well as the length of flashbang effects.", "Grenades": "グレネード", "grenades-page-description": "このページでは、ゲーム内で使用できるグレネードの種類について、価格やダメージなどの情報をソート可能な表で紹介しています。", "grenades-page-p": "<0>There are only a handful distinct types of grenades that may be thrown or launched in Escape from Tarkov, and each one has a unique effect: flash, smokes, high explosive, and fragmentation.<1>Grenades are situational, but when utilized properly, they can have deadly results. Any advantage from high-tier equipment can be fully negated by a single well-thrown grenade, whether it completely blinds the adversary, kills them instantly, or forces them out of cover and into your gunfire.<3>Five factors to think about while using throwable grenades include the fuse time, explosion radius, fragment damage, fragment count, and even the weight of the grenade. With specific uses arising from each component.", "Guns": "ガンズ", "guns-page-description": "このページでは、ゲーム内で使用できる銃の種類について、価格、ダメージ、精度などの情報をソート可能な表で紹介しています。", "guns-page-p": "<0>Your main tool for survival is a weapon. Almost all weapons are completely modular, allowing them to be customized for various scenarios. All of the weaponry used in Escape from Tarkov are listed on this page.", "Headsets": "ヘッドセット", "headsets-page-description": "このページでは、ゲーム内で使用できるヘッドセットの種類や価格、在庫状況などの情報を、ソート可能な表にして掲載しています。", "headsets-page-p": "<0>In Escape from Tarkov, headsets magnify low-frequency noises like footsteps while muzzling impulsive stimuli like gunshots. Different audio profiles are offered by the various models.", "Helmets": "ヘルメット", "helmet-page-description": "このページでは、ゲーム内で使用できるヘルメットの種類を、価格やアーマークラスなどの特徴を含めて、ソート可能な表でご紹介しています。", "Show blocking headset": "ショーブロッキングヘッドセット", "Min armor class": "最小アーマークラス", "helmets-page-p": "<0>In Escape from Tarkov, headgear serves a variety of functions.<1>There are useful objects, vanity items, and safety headgear. Before entering combat, choosing a helmet that will protect different parts of the head becomes crucial.<3>The impact that different helmets will have on how much sound they suppress is another crucial factor to take into account. Escape from Tarkov's gameplay heavily relies on sound.<5>Modular helmets, which have an assortment of different components, are another aspect of Escape from Tarkov. These helmets may modify the number of segments they protect. Top, Nape, Ears, Eyes, and Jaws are the segments.", "items-page-description": "このページでは、アーマー、バックパック、交換用アイテム、コンテナ、ガラス、グレネード、銃、ヘッドセット、鍵類、銃改造、ピストルグリップ、プロビジョン、リグ、サプレッサーなど、さまざまなアイテムカテゴリに関する情報を掲載したページへのリンクを紹介しています。", "Keys": "鍵類", "keys-page-description": "このページでは、ゲーム内で使用できる鍵の種類と価格、レア度などの情報をソート可能な表で紹介しています。", "keys-page-p": "<0>Maps, keys, key cards, and other useful objects are included in intelligence items. These will help you stay one step ahead of the competition—or at the very least, know where you are in Escape from Tarkov.<1>The remaining durability of keys and keycards with a limited number of uses is displayed in the bottom right corner of their icons and on their inspection screens.", "Mods": "武器パーツ", "mods-page-description": "このページでは、ゲーム内で使用可能な武器パーツの種類や価格、互換性などの情報をソート可能な表で紹介しています。", "mods-page-p": "<0>In Escape from Tarkov, the performance and functioning of a weapon are controlled by elaborate mechanisms organized into five categories:<1><0>Functional Mods<1>Muzzle devices (Functional Mods)<2>Sights (Functional Mods)<3>Gear Mods<4>Vital parts", "Pistol Grips": "ピストルグリップ", "pistol-page-description": "このページでは、ゲーム内で使用できるピストルグリップの種類を、価格やエルゴノミクス、互換性などの特徴を含めて、ソート可能な表にしています。", "Filter by gun": "銃でフィルターする", "select a gun": "ほうをえらぶ", "pistol-grips-page-p": "<0>In Escape from Tarkov a pistol grips and stocks are vital parts of a weapon.<1>On this page you can sort them buy ergonomics improvement or their cost and see on which weapon they can be mounted.", "Provisions": "食料品", "provisions-page-description": "このページでは、ゲーム内で入手できる食料品の種類(水分量、エネルギー、最安値、トレーダーやフリーマーケットの価格など)に関する情報を、ソート可能な表で紹介しています。", "Total energy cost": "合計エネルギーコスト", "Include the cost of lost hydration in the cost of energy": "失われた水分量のコストをエネルギーコストに含める", "provisions-page-p": "<0>In Escape from Tarkov, provisions are utilized to replenish energy and hydration.<1>Your Metabolism skill level will determine how effective they are.", "Rigs": "リグ", "rigs-page-description": "このページでは、ゲーム内で使用できるリグの種類を、価格、内外装サイズ、重量、圧縮率などの情報を、ソート可能な表で紹介しています。", "Armored rigs?": "アーマーリグ?", "Min slots": "最小スロット", "3-slot": "3スロット", "4-slot": "4スロット", "rigs-page-p": "<0>When it comes to carrying and storing ammunition and magazines during your excursions in Escape from Tarkov, chest rigs are crucial. Some even provide you with additional security.", "Suppressors": "サプレッサー", "suppressors-page-description": "このページでは、ゲーム内で使用できるサプレッサーの種類について、エルゴノミクス、リコイル、最安値などの情報をソート可能な表で紹介しています。", "suppressors-page-p": "<0>In Escape from Tarkov, a suppressor is a muzzle device (a functional mod) and can be installed on a weapon to muffle gunshot sound.<1>On this page you can sort them buy ergonomics penalty, recoil improvement or their cost and see on which weapon they can be directly mounted.", "Barters": "バーター", "Marked": "マーク付き", "Wearables": "ウェアラブル", "loot-tiers-page-description": "ゲーム内で入手できるルーティングの種類、その価値、希少性、そして何を残し、何をゴミにするかについて学ぶことができます。", "Ranking the most valuable items in the game": "ゲーム内で最も貴重なアイテムランキング", "Include Marked": "インクルードマーク付き", "Group by type": "の種類別グループ", "min value": "最小値", "Only show markers for active tasks": "Only show markers for active tasks", "Map of {{mapName}}": "Map of {{mapName}}", "maps-page-description": "脱出地点や戦利品を漁る場所など、Escape from Tarkov全マップの最新情報をお届けします。ゲーム内で最高の装備品や資源が手に入る場所を確認できる", "maps-page-p": "<0>Escape from Tarkovマップには12カ所の場所があり、そのうち9カ所がこれまでに公開されている。最終的にはすべてのマップがつながる予定ですが、現在はすべて離れています。", "Streets of Tarkov": "Streets of Tarkov", "Ground Zero": "Ground Zero", "Customs": "Customs", "Factory": "Factory", "Interchange": "Interchange", "The Lab": "The Lab", "Lighthouse": "Lighthouse", "Reserve": "Reserve", "Shoreline": "Shoreline", "Woods": "Woods", "Openworld": "オープンワールド", "Tarkov.dev {{bot}} integration": "Tarkov.dev {{bot}} の統合", "bot-page-description": "このページには、{{bot}} と Tarkov.dev を統合するために必要なものがすべてコンテナで収められています。", "You can add command to your moobot to get price check in your twitch chat": "Moobotに行動指示を追加することで、Twitchチャットで価格チェックを受けることができます", "Instructions": "使用方法", "Register at": "にてご登録ください", "using your twitch account": "ツイッチアカウントを使用して", "Go to Custom commands": "カスタムコマンドに移動する", "Set what you want the command to be. Common is \"p\" or \"price\"": "行動指示をどうするか設定します。一般的なのは \"p\" または \"price\" です", "Press the \"Create\" button": "作成」ボタンを押す", "In response choose URL Fetch - Full (plain) response": "レスポンスで「URL Fetch - Full (plain) response」を選択します", "and after insert \"Command arguments\"": "と挿入した後に、\"行動指示 \"を挿入する", "Now press \"Save\" button": "ここで「保存」ボタンを押します", "Big thanks to": "に大感謝です", "for feedback": "フィードバック用", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "ナイトボットに行動指示を追加することで、twitch / youtubeチャンネルのチャットで価格チェックを受けることができます", "using your twitch / youtube account": "ツイッチ/ユーチューブアカウントを使用して", "Go to dashboard": "ダッシュボードに移動する", "Click the \"Join Channel\" button": "チャンネルに参加する」ボタンをクリック", "Make bot - moderator, just type /mod nightbot in your chat": "ボット - モデレーターを作るには、チャットに /mod nightbot と入力します", "Go to custom commands": "カスタムコマンドに進む", "Press the \"Add command\" button": "行動指示の追加」ボタンを押す", "Command: !p or anything you like": "行動指示です:!pまたは好きなもの", "Message:": "メッセージです:", "Press \"Submit\"": "\"Submit \"を押す", "Trader Levels": "トレーダーレベル", "Trader Reputation": "トレーダー親密度", "Prerequisite Tasks": "前提条件となるタスク", "Start Requirements": "スタート条件", "Attributes": "アトリビュート", "Contains All": "コンテナ・オール", "Contains Item in Category": "カテゴリにアイテムが含まれています", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "{{effectNames, list}} {{bodyParts, list(type: disjunction)}} {{operator}} {{count}} 秒間、 効果を発揮します", "using extract: {{extractName}}": "エキスを使用しています:{{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "状態(es)で抽出します:{{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "ステータス{{extractStatuses, list(type: disjunction)}}で{{extractCount}}回抽出する", "{{itemCount}}x any of": "{{itemCount}}x any of", "Dogtag level": "ドッグタグレベル", "Max durability": "最大耐久性", "Min durability": "最小耐久性", "Kill": "キル", "Shoot": "シュート", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "営業時間内:{{hourStart}}:00 ~{{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_other": "距離から:{{operator}} {{count}} メートル", "While inside: {{zoneList, list(type: disjunction)}}": "中にいながら:{{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "打つことです:{{bodyPartList, list(type: disjunction)}}", "Using weapon:": "武器を使う:", "Using weapon mods:": "武器改造を使う:", "While wearing:": "装着したまま:", "Not wearing:": "装着していない:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "{{effectNames, list}} {{bodyParts, list(type: disjunction)}} {{operator}} {{count}} 秒間、自分の に効果(複数可)がある間", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "{{effectNames, list}} の効果(複数)を持ちながら、あなたの{{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "の目標が{{effectNames, list}} の効果を持っている間、{{operator}} {{count}} 秒間、{{bodyParts, list(type: disjunction)}} の効果を持っている。", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "の目標が{{effectNames, list}} の効果(複数可)を受けている間。{{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "レベル{{level}} {{skillName}} のスキルを取得する", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} 親密度", "In area(s): {{areaList, list(type: disjunction)}}": "エリア(s)で:{{areaList, list(type: disjunction)}}", "Use any of:": "のいずれかを使用します:", "Reach level {{playerLevel}}": "Reach level {{playerLevel}}", "optional": "任意", "Trader Standing": "トレーダーの評価", "Skill Level": "スキルレベル", "Trader Offer Unlock": "トレーダーオファーアンロック", "Trader Unlock": "トレーダーアンロック", "Craft Unlock": "Craft Unlock", "task-page-description": "このページでは、タスク{{questName}} を完了するための目標物や報酬、攻略法などを紹介しています。ミッションの準備と成功のためのヒントを得ることができます。", "TarkovTracker": "タルコフトラッカー", "Leads to": "につながる", "(on failure)": "(駄目押し)", "Task Details": "タスクの詳細", "Objectives": "目標物", "Fail On": "フェイルオン", "Needed Keys": "必要な鍵類", "Task Start": "Task Start", "Task Completion": "タスクの遂行", "Rewards": "報酬", "Task Failure": "タスク失敗", "Can be restarted": "再開可能", "Cannot be restarted": "再開不可", "Penalties": "ペナルティ", "tasks-page-description": "Escape from Tarkovのタスクについて、必要な情報をすべてご紹介します。ゲーム内で利用できるタスクの種類や完了方法、獲得できる報酬についてご紹介します。", "Hides completed tasks": "任務遂行を隠す", "Hide locked": "ロックされているのを隠す", "Hides locked tasks": "ロックされたタスクを非表示にする", "Show all tasks": "すべてのタスクを表示する", "Name filter": "ネームフィルター", "filter on task name": "タスク名でフィルターする", "quests-page-p": "<0>Escape from Tarkovに登場するトレーダーには、達成できるタスクがいくつもあります。<1>アイテムを回収したり、敵の無力化数を排除したりと、レイドでの行動と引き換えに、トレーダーの評価を上げ、貴重なアイテムを獲得することができるのです。", "Settings": "設定", "settings-page-description": "このページは、Tarkov.devのユーザー設定をまとめたものです。", "Language": "言語", "General": "一般", "Has flea": "蚤の市がある", "Use TarkovTracker": "TarkovTrackerを使う", "TarkovTracker API Token": "TarkovTracker APIトークン", "API Token": "APIトークン", "Stations": "ステーション", "Skills": "スキル", "Dogtag Barters": "ドッグタグバーター", "Exclude": "除く", "Minimum dogtag level": "ドッグタグレベルの最低ライン", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "ドッグタグのバータートレードのコスト算出に使用する最低ドッグタグレベルについて", "The current estimated average player level is {{avgPlayerLevel}}": "現在の推定平均プレイヤーレベルは{{avgPlayerLevel}}", "Miscellaneous": "その他", "Hide remote control": "リモコンを隠す", "start-page-description": "アイテム、クラフト、交換用アイテム、バーター、地図、戦利品レベル、ハイドアウトの利益、トレーダーの詳細、無料のAPIなど、tarkov.devですべての情報をチェックしましょう!Escape from Tarkovのツールやガイドの無料、コミュニティ製、オープンソースのエコシステムです。", "Load More": "ロード中", "Tools": "ツール", "Ammo chart filter": "弾薬チャートフィルター", "Traders barter profit": "トレーダーバーター利益", "Hideout crafts profit": "ハイドアウトのクラフトの利益", "Loot tiers ranking": "ルーティング・ティアランキング", "Average wipe length": "ワイプの平均長さ", "Bitcoin farm profit": "ビットコインファームの利益", "Invite Discord bot": "Discord botを招待する", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.devはEscape from Tarkovのためのオープンソースツールキットです。", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "クエストやフリーマーケットの取引、ゲームの改善などに役立つように、コミュニティによって設計・管理されています!また、APIは自由に利用できるので、EFTに関連するツールやサービスを独自に構築することも可能です。", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "StreamElementsボットに行動指示を追加することで、twitch / youtubeチャンネルのチャットで価格チェックを受けることができます", "Make bot - moderator, just type /mod streamelements in your chat": "ボット - モデレーターを作成し、あなたのチャットで/mod streamelementsを入力するだけです", "Press the \"Add new command\" button": "新しい行動指示を追加する」ボタンを押す", "Press \"Activate Command\"": "\"行動指示 \"を押してください", "Player level": "プレイヤーレベル", "Reputation": "親密度", "Commerce": "取引額", "Trader {{trader}}": "トレーダー{{trader}}", "trader-page-description": "Escape from Tarkovに登場するトレーダー{{trader}} の最新情報をお届けします。彼が特定の信頼度で売却するアイテムや、キャッシュバック金銭を最大限に利用して忠誠度を上げる方法について紹介します。", "Items with the best cash back prices for leveling": "レベリングに最適なキャッシュバック価格が設定されているアイテム", "Spending": "必要取引量", "Unlocks at Loyalty Level {{level}}": "信頼度レベルで解錠済み{{level}}", "Tasks given by {{traderName}}": "で与えられるタスク{{traderName}}", "traders-page-description": "Escape from Tarkovのトレーダーについて、必要な情報をすべてご紹介します。ゲーム内で利用できるトレーダーの種類、場所、売却品についてご紹介します。", "About Traders": "トレーダーについて", "traders-page-p": "<0>破壊され、包囲されたノルヴィンスクの貿易のバックボーン。Escape from Tarkovでは、各商人は医療品や武器、軍用品など、特定の種類の商品に特化していた。その価格は一般的に高いが、払った分だけ得をする。<1>さらに重要なのは、クエストを通じてトレーダーと親密な関係になることで、一般的により良いオファーを受け取れるようになったり、コミッション(販売や購入の際に支払う付加価値)を減らせるなどの利点があることだ。<2>さらに、トレーダーは保険や修理(レイド中に死亡した場合に装備品を回収できる)などのサービスも提供しています。", "Patch": "パッチ", "Wipe start": "ワイプスタート", "Wipe end": "ワイプエンド", "Ongoing wipe": "オンゴーイングワイプ", "{{count}} days_other": "{{count}} 日", "{{count}} months_other": "{{count}} months", "{{count}} years_one": "{{count}} year", "Wipe Length": "ワイプの長さ", "wipe-length-description": "Escape from Tarkovの平均ワイプ時間に関する最新情報を入手できます。一般的なワイプの長さを知り、次のワイプに備えましょう。", "Average Wipe Length among last 6 wipes:": "直近6回のワイプの平均的な長さ:", "Trader Ammo": "Trader Ammo", "Only show ammo available from traders on your settings": "Only show ammo available from traders on your settings", "Reset": "Reset", "Convert one currency to another": "Convert one currency to another", "Currency Converter": "Currency Converter", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "control-info-p": "<0>This page allows you to control the Tarkov.dev website using another browser. The typical use case is to have the Tarkov.dev website open in a browser on a second monitor while you play the game and this page open on your phone or another device so that you can navigate to different pages on the Tarkov.dev website without having to alt+tab out of the game. All you have to do is open the Tarkov.dev website in a browser where you want it to be displayed, click the \"Click to connect\" button in the lower left*, and then use the ID shown there on this page on the control device and click the Connect. Once connected, you can use this control page to open specific map or ammo pages in the controlled browser.<1>*It appears on the lower left by default but can be toggled to the lower right side of the screen. It can also be hidden by the \"Hide remote control\" option on the settings page.", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "{{operator}} {{count}}秒間、あなたの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(単数の場合)", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "{{operator}} {{count}}秒間、あなたの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(少数の場合)", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "{{operator}} {{count}}秒間、あなたの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(多数の場合)", "From distance: {{operator}} {{count}} meters_one": "距離から:{{operator}} {{count}}メートル(単数の場合)", "From distance: {{operator}} {{count}} meters_few": "距離から:{{operator}} {{count}}メートル(少数の場合)", "From distance: {{operator}} {{count}} meters_many": "距離から:{{operator}} {{count}}メートル(多数の場合)", "{{count}} days_one": "{{count}}日(単数の場合)", "{{count}} days_few": "{{count}}日(少数の場合)", "{{count}} days_many": "{{count}}日(多数の場合)", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "{{operator}} {{count}}秒間、あなたの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "{{operator}} {{count}}秒間、あなたの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(少数の場合)", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "{{operator}} {{count}}秒間、あなたの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(多数の場合)", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "対象が{{operator}} {{count}}秒間、彼らの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(単数の場合)", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "対象が{{operator}} {{count}}秒間、彼らの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(少数の場合)", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "対象が{{operator}} {{count}}秒間、彼らの{{bodyParts, list(type: disjunction)}}に{{effectNames, list}}の効果がある間(多数の場合)", "Provides {{count}} for {{totalCost}}_one": "{{count}}を{{totalCost}}で提供", "Provides {{count}} for {{totalCost}}_few": "{{count}}を{{totalCost}}で提供(少数形)", "Provides {{count}} for {{totalCost}}_many": "{{count}}を{{totalCost}}で提供(多数形)", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "{{duration}}内に{{count}}を{{totalCost}}でクラフト", "Crafts {{count}} in {{duration}} for {{totalCost}}_few": "{{duration}}内に{{count}}を{{totalCost}}でクラフト(少数形)", "Crafts {{count}} in {{duration}} for {{totalCost}}_many": "{{duration}}内に{{count}}を{{totalCost}}でクラフト(多数形)", "cookie-consent": "tarkov.dev uses cookies to enhance your experience. By continuing to use this site, you agree to the usage of cookies. Cookies are used to remember your settings and features that you enable.", "I understand": "I understand", "Other Options": "Other Options", "This task {{taskStatus}}": "This task {{taskStatus}}", "Slots per kg": "Slots per kg", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Stash Discord Bot", "More Tools": "その他のツール", "Companion app": "コンパニオンアプリ", "Discord companion": "Discord用コンパニオン", "Download latest release": "最新リリースをダウンロード", "View on GitHub": "GitHubで見る", "Join the community": "コミュニティに参加", "Screenshot of TarkovMonitor showing timers and integrations": "タイマーと連携状況を表示する TarkovMonitor のスクリーンショット", "Visual timers, raid state, and integration health in TarkovMonitor.": "TarkovMonitor でタイマーやレイド状態、連携のヘルスを確認できます。", "Main Features": "主な機能", "tarkov-monitor-page-description": "TarkovMonitor の導入方法、TarkovTracker との連携、Tarkov.dev のマップ連動の使い方を紹介。", "tarkov-monitor-summary": "TarkovMonitor は EFT のレイド管理に役立つアラートとタイマーを提供し、プレイを中断せずに済みます。", "tarkov-monitor-feature-audio": "マッチング、レイド開始、runthrough タイマー、スカブクールダウン、空気清浄フィルター通知の音声アラート。", "tarkov-monitor-feature-map": "参加マップに合わせて Tarkov.dev のマップを自動的に開きます。", "tarkov-monitor-feature-screenshot": "スクリーンショットで位置をトリガーでき、素早く座標を共有。", "tarkov-monitor-feature-quests": "完了を検知すると TarkovTracker にクエストを自動同期。", "tarkov-monitor-feature-stats": "フリマ収益、待機時間、マップ頻度などローカル統計を表示。", "tarkov-monitor-feature-timers": "レイド時間とスカブクールダウンを可視化して次の出撃を計画。", "Download": "ダウンロード", "tarkov-monitor-download-1": "GitHub から最新の TarkovMonitor.zip を取得。", "tarkov-monitor-download-2": "アーカイブを任意の場所に展開します。", "tarkov-monitor-download-3": "TarkovMonitor.exe を起動し、プレイ中は開いたままにします。", "Community support": "コミュニティサポート", "tarkov-monitor-community": "質問や雑談をしたい場合は Discord サーバーに参加してヒントやサポート、機能の議論を行いましょう。", "Join the Discord": "Discord に参加", "Security": "セキュリティ", "tarkov-monitor-security": "TarkovMonitor はチートではありません。PC に保存された EFT のログを読むだけで、ゲームを書き換えたりコードを挿入したりしません。", "stash-page-description": "Stash Discord Bot を招待し、コマンドを確認してコミュニティでの活用方法を知ろう。", "stash-hero": "Stash は Tarkov.dev のデータセットを Discord に届け、チャットを離れずに価格、クエスト進行、隠れ家タイマーなどを確認できます。", "Invite Stash": "Stash を招待", "Report an issue": "問題を報告", "Highlights": "ハイライト", "Item intelligence": "アイテムインテリジェンス", "Instant prices with flea, trader, and craft context.": "フリマ・トレーダー・クラフト情報付きの即時価格。", "Craft/barter lookups reuse Tarkov.dev profitability data.": "クラフト/交換検索は Tarkov.dev の収益データを再利用。", "Toggle PVE or PMC game modes to match your server rules.": "サーバールールに合わせて PVE/PMC モードを切り替え。", "Progress tracking": "進行状況の追跡", "Quest command lists requirements, turn-ins, and rewards.": "クエストコマンドで要件・納品・報酬を一覧表示。", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "progress コマンドは TarkovTracker に保存した隠れ家・商人の進捗を反映。", "Restock and status alerts keep everyone informed between raids.": "補充・ステータス通知でレイド間も全員に情報共有。", "Community tools": "コミュニティツール", "Goons tracker for spotting the Rogue Boss trio.": "ローグ三人組を追跡する Goons トラッカー。", "Roulette mini-game for fun raid modifiers.": "次のレイド条件を決めるルーレットミニゲーム。", "Slash commands, autocomplete, and localized responses.": "スラッシュコマンド、オートコンプリート、ローカライズされた応答。", "Frequently used commands": "よく使われるコマンド", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash には多数のスラッシュコマンドがあります。多くのサーバーが使う代表的なものはこちら:", "Command": "コマンド", "Example": "例", "Support & feedback": "サポートとフィードバック", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "サーバー審査用のプライバシーポリシーや利用規約が必要ですか?リポジトリの /assets フォルダーで常に最新のものが入手できます。", "stash-tech-note": "技術向けガイドやセルフホスト手順が必要なら GitHub の README をご覧ください。", "card-tarkov-monitor-desc": "1 つの Windows アプリで TarkovTracker 進行を自動化し、待機時間を記録し、Tarkov.dev のマップを操作。", "card-stash-desc": "価格チェック、クエスト支援、隠れ家進捗、補充タイマーを行うスラッシュコマンド集(データ元は Tarkov.dev)。", "Read more": "さらに詳しく", "Invite now": "今すぐ招待", "other-tools-page-description": "TarkovMonitor や Stash Discord Bot など、Tarkov.dev チームが作ったコンパニオンアプリを紹介。", "other-tools-body": "<0>Tarkov.dev はサイトだけではありません。同じオープンデータを使ってレイドや配信、Discord コミュニティを拡張するツール群です。各ツールのスクリーンショットやセットアップガイド、サポートリンクをチェックしましょう。", "Learn about TarkovMonitor": "TarkovMonitor を知る", "Meet the Stash bot": "Stash ボットを知る", "The help command to view all available commands": "利用可能なコマンドを表示する help コマンド", "View details about the bot": "ボットの詳細を表示", "Get a sorted ammo table for a certain ammo type": "指定した弾種のソート済みテーブルを取得", "Check barter details for an item": "アイテムの交換詳細を確認", "Get detailed information about a boss": "ボスの詳細情報を取得", "Get the latest game changes from tarkov-changes.com": "tarkov-changes.com から最新のゲーム変更を取得", "Check crafting details for an item": "アイテムのクラフト情報を確認", "Set the game mode (regular, PVE) for bot responses": "ボットの応答用に通常/PVE モードを切り替え", "Check or report the location of the Goons": "Goons の位置を確認または報告", "Get a Discord invite link for the bot to join it to another server": "ボットを別サーバーに招待する Discord リンクを取得", "Report an issue with the bot": "ボットに関する問題を報告", "Get price, craft, barter, etc. information about an item": "アイテムの価格・クラフト・交換などの情報を取得", "Get a key's price and maps it is used on": "キーの価格と使用マップを確認", "View a map and some general info about it": "マップとその概要を表示", "Get the latest official patchnotes for EFT": "EFT の最新公式パッチノートを取得", "Get player profile information": "プレイヤープロフィール情報を取得", "Get a detailed output on the price of an item, its price tier, and more!": "アイテム価格やティアなどの詳細レポートを取得", "Manage your customized hideout and trader progress": "カスタム隠れ家と商人の進捗を管理", "Get detailed information about a quest": "クエストの詳細情報を取得", "Show or set alerts for trader restock timers": "トレーダー補充タイマーの通知を表示または設定", "Play a game of roulette to determine how you play your next raid": "次のレイドの縛りを決めるルーレットで遊ぶ", "Get the game/server/website status of Escape from Tarkov": "Escape from Tarkov のゲーム/サーバー/サイトの状態を確認", "Get information about a in-game stim": "ゲーム内スティムの情報を取得", "Show the criteria for loot tiers": "ルートグレードの基準を表示", "Get the bot's uptime": "ボットの稼働時間を確認", "stash-support": "<0>Stash は Tarkov.dev チームが運用しています。バグやアイデアは <1>GitHub で issue を作成するか、<2>Tarkov.dev Discord で開発者に連絡してください。Tarkov.dev とボットのデータを同期する場合はスクリーンショットと再現手順を添付してください。", "Database": "Database", "Calculators": "Calculators", "Progression": "Progression", "Community": "Community", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/pl/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Podstępne chłopaki. Kultyści czają się w cieniu w grupach po 3-5 osób, czekając aż gracz się zbliży. Po cichu podchodzą do swoich wrogów i dźgają ich zwykłymi nożami lub w przypadku kapłanów zatrutym nożem kultystów. Jeśli zostaną ostrzelani, odpłacą się ogniem z broni palnej i granatów. Po tym jak zaatakują gracza swoim nożem, mogą zdecydować się na ponowną ucieczkę do lasu i powrót do cienia.", "knight-bio": "", "knight-description": "Przywódca 'The Goons'. Może pojawić się na wielu różnych mapach.", "glukhar-bio": "Nie ma wiarygodnych informacji o jego dotychczasowej działalności, bo wszystkie dokumenty zaginęły albo zostały utajnione, ale według niezweryfikowanych informacji miał stopień bosmana. Brał udział w działaniach bojowych. Znał podstawy taktyki i aktywnie wykorzystywał tę wiedzę w zdobywaniu lub obronie różnych terytoriów.
    Również cała jego załoga wydaje się być byłymi służbistami. Choć teraz jego gang jest tylko de facto grupą bandycką walczącą o zasoby i wpływy w Tarkowie. Ma powiązania z handlarzami mogącymi eksportować towary z obwodu norwińskiego, którzy regularnie wysyłają mu ostatnie działające pociągi do przewozu ładunków.", "glukhar-description": "Głuchar i jego liczni strażnicy są niezwykle wrogo nastawieni. Jest bardzo mało prawdopodobne, aby odnieść sukces podczas walki na jakichkolwiek otwartych obszarach. Preferowane są małe korytarze i zamknięte pomieszczenia. Głuchar i jego strażnicy są bardzo celni oraz będą się trzymać blisko siebie przez cały czas, a jego strażnicy będą podążać za nim, gdziekolwiek się uda.", "kaban-bio": "Kiedyś miał mały legalny biznes w Tarkowie, ale nie bał się używać przestępczych metod zdobywania pieniędzy. Po ogólnej ewakuacji pozostał w mieście, a jego gang rozrósł się.", "kaban-description": "Jego rozmiar pozwala mu strzelać z różnych ciężkich karabinów maszynowych bez odpoczynku, ale jednocześnie Kaban nie może pozwolić sobie na mobilność, dlatego podczas walki albo pozostaje w miejscu, albo powoli przemieszcza się z punktu do punktu. Ma dużą liczbę dobrze uzbrojonych strażników, z których niektórzy są byłymi wojskowymi, którzy zorganizowali dla niego silną obronę. Boss mieszka na terenie warsztatu samochodowego na \"Ulicach Tarkowa\". Obszar jest silnie broniony, wejścia są ufortyfikowane stacjonarnymi karabinami maszynowymi i AGS, ścieżki są zaminowane, a na dachu centrum serwisowego znajdują się snajperzy. Kaban używa niestandardowej platformy do przechowywania skrzynek z karabinami maszynowymi, nosi pancerz pod ubraniem i ma niekwestionowany autorytet wśród swoich strażników. Szczawie w pobliżu pomagają bossowi w obronie i angażują się w walkę dla Kabana.", "killa-bio": "", "killa-description": "Prawdziwy Giga Chad z Tarkova. Killa używa ręcznego karabinu maszynowego lub innej broni samoczynnej, by ostrzelać wroga, a jednocześnie chowa się od osłony do osłony, zbliżając się do celu, by wykonać ostateczne natarcie. Podczas szturmu porusza się w układzie zygzakowatym, używa granatów dymnych i odłamkowych oraz bezlitośnie ostrzeliwuje wrogów ogniem automatycznym. Będzie podążał za swoim celem na duże odległości poza trasą patrolu, więc pamiętaj, by uciekać bardzo daleko, jeśli cię namierzy.", "kollontay-bio": "Jest byłym funkcjonariuszem MSW (Ministerstwa Spraw Wewnętrznych), podczas swojej służby w organach ścigania miał reputację podłego człowieka, którego zachowania czasami obawiali się jego współpracownicy. Podczas swojej pracy często uciekał się do swojej ulubionej metody przesłuchań - gumowej pałki, a także innych pozaustawowych środków nacisku na kogoś, kto mu się nie podobał. Dzięki swojej sile fizycznej i zuchwałemu temperamentowi, po wydarzeniach związanych z aferą TerraGroup, założył gang i zaczął robić to, z czym sam niedawno miał walczyć - grabieże i bandytyzm. Jednak nawet przed konfliktem często zapewniał ochronę lokalnym \"biznesmenom\". Znane są na przykład jego dobre stosunki z Kabanem.", "kollontay-description": "Kołontaj ma niewielką liczbę ochroniarzy, woli pozostać w jednej pozycji i od czasu do czasu patroluje swoje terytorium. Jeśli czuje, że ma przewagę, może użyć pałki policyjnej. Mieszka w okolicy centrum handlowego Klimowa i Akademii Ministerstwa Spraw Wewnętrznych w Tarkowie.", "partisan-bio": "There are few reliable details about his past, but it's known that he once served in Afghanistan, where his radical methods of warfare took root. Referred to by some as 'Partizan', he became notorious for his expertise in setting traps and mines. His reputation for eliminating enemies often came down to catching them off guard, using their overconfidence against them. Partizan's knowledge of guerrilla tactics made him a dangerous adversary, able to turn any location—whether forest or building—into a deadly trap.
    Those who survive long enough to learn his ways may just find themselves in his good graces, but only if they're careful enough to see the traps before it's too late.", "partisan-description": "", "raider-bio": "", "raider-description": "Najeźdźcy Scav (znani również jako 'Najeźdźcy') to zaawansowane Scavy, które są znacznie silniejsze i bardziej taktyczne niż typowe Scavy. Noszą znacznie bardziej niebezpieczną broń i używają wyższej klasy amunicji. Dodatkowo mają znacznie lepszy cel i często potrafią powalić dobrze wyekwipowanych graczy kilkoma kulami (lub po prostu trafić w oczy). Najeźdźcy Scav patrolują również w wielu grupach i zazwyczaj można ich rozróżnić po ich ekwipunku, unikalnym głosie i ogólnej agresji. Najeźdźcy Scav są początkowo przyjaźnie nastawieni do wszystkich innych Scavów (w tym graczy), ale staną się wrogo nastawieni, jeśli podejdziesz zbyt blisko i zignorujesz ich słowne ostrzeżenia. Stają się również wrogo nastawieni do wszystkich Scavów, jeśli jakiś Scav ich zdenerwuje.", "reshala-bio": "", "reshala-description": "Zazwyczaj będzie starał się pozostać z tyłu walki i ukryty przed wzrokiem gracza. Dodatkowo nigdy nie nosi zbroi. Uważaj jako Scav, ponieważ jeśli masz niższy poziom karmy, Reshala lub jego strażnicy mogą cię zastrzelić bez prowokacji lub jeśli zbliżysz się do Reshali. Jego strażnicy czasami ostrzegają Scavów z niską karmą, zanim staną się wrogo nastawieni.", "rogue-bio": "", "rogue-description": "Zbuntowani bronią oczyszczalni ścieków i okolicznych terenów na latarni morskiej. Ich głównym zachowaniem jest patrolowanie, ale często zajmują pozycje obronne na dachach i używają rozstawionej broni. Będą atakować wszystkich graczy, którzy wejdą na ich teren, ale są nieco bardziej pobłażliwi dla PMC USEC i Scavów. Zbuntowani mogą również pojawić się w południowej lokalizacji latarni morskiej (wyspa). Zbuntowani są bardzo niebezpieczni ze względu na ich laserową wręcz celność i duży dystans celowania. Uciekają za osłonę i używają leków, jeśli są ranni.", "sanitar-bio": "Były lekarz i naukowiec. Pracował dla TerraGroup. Kierował kilkoma projektami w laboratorium, w tym opracowywaniem nowych substancji psychoaktywnych. Obszar badań rozciągał się od wpływu różnych schorzeń na organizm po opracowywanie neurostymulantów. Oprócz laboratorium TerraGroup miał swoje biuro w Sanatorium Lazurowe Wybrzeże, gdzie również prowadził badania, zwłaszcza w ostatnich tygodniach przed pełną ewakuacją.
    Często wyjeżdżał na dyżury do stref walki wraz z korpusem medycznym, a po rozpoczęciu pracy w korporacji regularnie odwiedzał afrykańskie i inne biura, nadzorując rozwój wydarzeń. Zdobył niekwestionowany autorytet i szacunek wśród kolegów.", "sanitar-description": "Kiedy jest zaangażowany w walkę, walczy razem z innymi Scavami i strażnikami, ale często wyrywa się, by się uleczyć lub zrobić sobie zastrzyk. Ma dużo leków, więc możliwe jest dłuższe starcie.", "shturman-bio": "", "shturman-description": "Nawigator i jego towarzysze będą atakować gracza z dużej odległości, chroniąc obszar tartaku w lesie. Wolą trzymać się na dystans, gdyż nie są przystosowani do walki w zwarciu.", "tagilla-bio": "", "tagilla-description": "Jest szalony i będzie próbował cię zabić młotem. Jeśli jednak znajdujesz się w miejscu, do którego nie może trafić, jak np. na dachach, użyje swojej drugiej broni (zazwyczaj strzelba), aby zabić cię z dystansu. Jest aktywny natychmiast po początku rajdu. Boss może zastawić zasadzki, otworzyć ogień zaporowy i wyważać drzwi w razie potrzeby.", "zryachiy-bio": "Jedna z najbardziej tajemniczych postaci Tarkowa. O jego przeszłości nie wiadomo praktycznie nic, poza tym, że przeszedł szkolenie snajperskie i podobno wielokrotnie przebywał w strefach walki na Bliskim Wschodzie i w Afryce.
    Na długo przed konfliktem stał się wiernym pieskiem Latarnika i brał czynny udział w „ustanawianiu” połączeń między Latarnikiem a wszystkimi, z którymi wchodził w interakcje. Wiadomo, że przyjaźni się z grupą Zbuntowanych, a także z zakapturzonymi mężczyznami, którzy rysują tajemnicze symbole na lokacjach.
    Zriaczij jest bardzo milczący, choć ci, którzy z nim pracują, zazwyczaj rozumieją go bez słów. O jego oczach krąży wiele plotek, niektórzy twierdzą, że to wrodzona osobliwość, inni wskazują na pewne krople do oczu, które pozwalają mu wzmocnić widzenie w ciemności, dając jego oczom ten efekt uboczny w postaci białości. Wbrew pozorom wydaje się, że swoje imię zyskał właśnie dzięki doskonałemu wzrokowi, co nie dziwi w przypadku byłego wojskowego snajpera.", "zryachiy-description": "Strażnik kultysta Latarnika" } ================================================ FILE: src/translations/pl/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Interaktywna", "Landscape": "Krajobraz", "View Fullscreen": "Pełen ekran", "Exit Fullscreen": "Opuść pełen ekran", "Satellite": "Satelita", "Abstract": "Abstrakcyjna", "Levels": "Poziomy", "1st Floor": "1. poziom", "2nd Floor": "2. poziom", "3rd Floor": "3. poziom", "4th Floor": "4. poziom", "5th Floor": "5. poziom", "Underground": "Podziemia", "Garage": "Garaż", "Tunnels": "Tunele", "Bunkers": "Bunkry", "Spawns": "Spawny", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "Snajper Scav", "Boss": "Boss", "Extracts": "Wyjścia", "Shared": "Wspólne", "Hazards": "Zagrożenia", "Usable": "Użyteczne", "Locks": "Zamki", "Stationary Gun": "Broń stacjonarna", "Lever": "Dźwignia", "Switch": "Przełącznik", "Door": "Drzwi", "Container": "Pojemnik", "Car Door or Trunk": "Drzwi samochodu lub bagażnik", "Lock": "Zamek", "Activated by": "Aktywowane przez", "Activates": "Aktywuje", "Needs power": "Potrzebuje zasilania", "Lootable Items": "Łupy", "Tasks": "Zadania", "Item": "Przedmiot", "Objective": "Cel", "Misc": "Różne", "openworld-name": "Otwarty świat", "openworld-description": "To jest wyobrażenie tego, jak wyglądałaby pełna mapa Tarkowa. Ta mapa z otwartym światem prawdopodobnie zawierałaby wszystkie kluczowe lokacje z istniejących map połączone w jedną wielką mapę.", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "Use TarkovMonitor to show your position", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/pl/properties.json ================================================ { "ambientVolume": "Otoczenie", "caliber": "Kaliber", "damage": "Obrażenia", "distanceModifier": "Odległość", "distortion": "Zniekształcenie", "projectileCount": "Ilość pocisków", "penetrationPower": "Siła penetracji", "armorDamage": "Obrażenia pancerza", "fragmentationChance": "Szansa fragmentacji", "ammoType": "Typ amunicji", "class": "Klasa", "material": "Materiał", "zones": "Strefy", "defaultPreset": "Domyślna konfiguracja", "durability": "Wytrzymałość", "ergoPenalty": "Kara ergonomii", "speedPenalty": "Kara szybkości", "turnPenalty": "Kara obracania", "headZones": "Strefy głowy", "capacity": "Pojemność", "grids": "Siatka", "energy": "Energia", "hydration": "Nawodnienie", "units": "Jednostki", "stimEffects": "Efekty stymulanta", "blindnessProtection": "Ochrona przed oślepieniem", "fuse": "Zapalnik", "maxExplosionDistance": "Maks. dystans wybuchu", "fragments": "Odłamki", "deafening": "Ogłusza", "blocksHeadset": "Blokuje słuchawki", "ricochetY": "Szansa na rykoszet", "uses": "Użyć", "malfunctionChance": "Szansa na zacięcie", "ergonomics": "Ergonomia", "recoil": "Odrzut", "loadModifier": "Modyfikator ładowania", "ammoCheckModifier": "Modyfikator sprawdzenia amunicji", "useTime": "Czas użycia", "cures": "Leczy", "hitpoints": "Punkty życia", "maxHealPerUse": "Maks. leczenie na użycie", "hpCostLightBleeding": "Koszt PŻ lekkiego krawienia", "hpCostHeavyBleeding": "Koszt PŻ ciężkiego krawienia", "painkillerDuration": "Czas przeciwbólowy", "energyImpact": "Wpływ na energię", "hydrationImpact": "Wpływ na nawodnienie", "recoilVertical": "Odrzut pionowy", "recoilHorizontal": "Odrzut poziomy", "zoomLevels": "Poziomy przybliżenia", "minLimbHealth": "Minimalne zdrowie kończyn", "maxLimbHealth": "Maksymalne zdrowie kończyn", "effectiveDistance": "Zasięg skuteczny", "fireModes": "Tryby ognia", "fireRate": "Szybkostrzelność", "sightingRange": "Zasięg celowania", "defaultWidth": "Domyślna szerokość", "defaultHeight": "Domyślna wysokość", "defaultErgonomics": "Domyślna ergonomia", "defaultRecoilVertical": "Domyślny odrzut pionowy", "defaultRecoilHorizontal": "Domyślny odrzut poziomy", "defaultWeight": "Domyślna waga", "recoilModifier": "Modyfikator odrzutu", "weight": "Waga", "baseItem": "Podstawowy przedmiot", "categories": "Kategorie", "type": "Typ", "convergence": "Konwergencja", "cameraRecoil": "Odrzut kamery", "recoilAngle": "Kąt odrzutu", "recoilDispersion": "Rozproszenie odrzutu", "usedOnMaps": "Używane na mapach" } ================================================ FILE: src/translations/pl/translation.json ================================================ { "No data": "Brak danych", "Current Average Latency": "Obecne średnie opóźnienie", "API Latency in milliseconds": "Opóźnienie API w milisekundach", "No barters found for this item": "Nie znaleziono barterów dla tego przedmiotu", "LL{{level}}": "PL{{level}}", "Barter at {{trader}}": "Barter u {{trader}}", "Craft at {{station}}": "Wytwarzane w {{station}}", "Barter": "Barter", "Craft at {{stationName}} {{stationLevel}}": "Wytwarzane w {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Dostarcza {{count}} za {{totalCost}}", "Provides {{count}} for {{totalCost}}_few": "Dostarcza {{count}} za {{totalCost}}", "Provides {{count}} for {{totalCost}}_many": "Dostarcza {{count}} za {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Dostarcza {{count}} za {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "Wytwarza {{count}} w {{duration}} za {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_few": "Wytwarza {{count}} w {{duration}} za {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_many": "Wytwarza {{count}} w {{duration}} za {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "Wytwarza {{count}} w {{duration}} za {{totalCost}}", "Reward": "Nagroda", "Cost": "Koszt", "Cost ₽": "Koszt ₽", "Estimated savings": "Szacunkowe oszczędności", "InstaProfit": "InstaZysk", "N/A": "nd.", "Barter cost": "Koszt barteru", "No barters available for selected filters": "Brak dostępnych barterów dla wybranych filtrów", "No barters available for selected filters but some were hidden by ": "Brak dostępnych barterów dla wybranych filtrów, ale niektóre ukryto przez ", "your settings": "twoje ustawienia", "Some barters hidden by ": "Niektóre bartery ukryto przez ", "Can hold:": "Może mieścić:", "Can't hold:": "Nie może mieścić:", "Level": "Poziom", "Flea Market": "Pchli targ", "Flea banned": "Zablokowane z targu", "Sell price": "Cena sprzedaży", "Flea Market fee": "Opłata pchlego targu", "Duration": "Czas", "Finishes": "Koniec", "Start now": "Zacznij teraz", "Flea throughput/h": "Przepustowość targu/h", "Estimated profit": "Szacunkowy zysk", "Estimated profit/h": "Szacunkowy zysk/h", "No crafts available for selected filters": "Brak dostępnych wytworzeń dla wybranych filtrów", "No crafts available for selected filters but some were hidden by ": "Brak dostępnych wytworzeń dla wybranych filtrów, ale niektóre ukryto przez ", "Some crafts hidden by ": "Niektóre wytrworzenia ukryto dla ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "Wszystkie opcje są już wybrane", "Clear selection": "Wyczyść zaznaczenie", "This item can't be sold on the Flea Market": "Ten przedmiot nie może być sprzedany na pchlim targu.", "Not scanned on the Flea Market": "Nie zeskanowano na pchlim targu", "Flea market prices loading": "Wczytywanie cen pchlego marketu", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>Cała platforma jest open source i skupia się wokół deweloperów. Cały kod jest dostępny na <1><0> GitHub.", "about-discord-p": "<0>Jeśli chcesz porozmawiać, zadać pytania lub poprosić o nowe funkcje, mamy serwer <1><0> Discord.", "about-x-p": "<0>Obserwuj nas na <1><0> X'ie dla wszystkich najnowszych aktualizacji.", "About": "O", "Contributors": "Współtwórcy", "Massive thanks to all the people who help build and maintain this project!": "Ogromne podziękowania dla wszystkich ludzi, którzy pomagają budować i utrzymywać ten projekt!", "Made with ❤️ by:": "Zrobione z ❤️ przez:", "Supporters": "Wspierający", "about-support-ukraine-p": "<0>Zachęcamy wszystkich, którzy mogą, do przekazania darowizny na wsparcie ludzi z Ukrainy za pomocą poniższego przycisku.", "about-support-collective-p": "<0>Jeśli chciałbyś wesprzeć ten projekt, możesz przekazać darowiznę i/lub zostać wspierającym na stronie <1>Open Collective.", "Item Data": "Dane przedmiotów", "Fresh EFT data courtesy of": "Świeże dane EFT dzięki uprzejmości", "Additional data courtesy of": "Dodatkowe dane dzięki", "Resources": "Zasoby", "Tarkov.dev API": "API Tarkov.dev", "{{bot}} integration": "Integracja z {{bot}}", "Discord bot for your Discord": "Bot Discorda dla twojego Discorda", "External resources": "Zewnętrzne zasoby", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev jest forkiem zamkniętego już tarkov-tools.com | Wielkie podziękowania dla kokarna za całą jego pracę przy tworzeniu Tarkov Tools i społeczności wokół.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "Zawartość gry i materiały są znakami towarowymi i prawami autorskimi Battlestate Games i ich licencjodawców. Wszelkie prawa zastrzeżone.", "version": "wersja", "PMC & Scav Thorax HP": "PŻ tułowia PMC & Scava", "Reshala Thorax HP": "PŻ tułowia Reshali", "Raider Thorax HP": "PŻ tułowia najeźdźcy", "Shturman Thorax HP": "PŻ tułowia Nawigatora", "Cultist Priest Thorax HP": "PŻ tułowia kultysty kapłana", "Cultist Warrior Thorax HP": "PŻ tułowia kultysty wojownika", "Damage": "Obrażenia", "Class {{tier}}": "Klasa {{tier}}", "Penetration": "Penetracja", "Filter by caliber": "Filtr po kalibrze", "This item can only be sold to trader": "Ten przedmiot można tylko sprzedać handlarzowi", "per slot": "na miejsce", "Value": "Wartość", "Per slot": "Na miejsce", "Sell to": "Sprzedaj do", "Found In Raid": "Znalezione w rajdzie", "Search item...": "Wyszukaj przedmiot...", "Search task...": "Szukaj zadania...", "Tasks": "Zadania", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Items": "Przedmioty", "No hideout modules requires this item": "Żaden z modułów kryjówki nie wymaga tego przedmiotu", "No unbuilt hideout modules for selected filters but some were hidden by ": "Brak niewybudowanych modułów kryjówki dla wybranych filtrów, ale niektóre ukryto przez ", "Hideout Module": "Moduł kryjówki", "Item": "Przedmiot", "Amount": "Ilość", "Player level: {{playerLevel}}": "Poziom gracza: {{playerLevel}}", "Reputation: {{reputation}}": "Reputacja: {{reputation}}", "Commerce: {{commerce}}": "Komercyjność: {{commerce}}", "Cheapest Price": "Najtańsza cena", "Task: {{taskName}}": "Zadanie: {{taskName}}", "Flea Market not available": "Pchli tyarg jest niedostępny", "No trader offers available": "Brak dostępnych ofert handlarza", "Loading...": "Wczytywanie...", "Ammo": "Amunicja", "Maps": "Mapy", "More": "Więcej", "Traders": "Handlarze", "Prapor": "Prapor", "Therapist": "Terapeutka", "Skier": "Narciarz", "Peacekeeper": "Rozjemca", "Mechanic": "Mechanik", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "Bossy", "Barter profit": "Zysk barteru", "Hideout profit": "Zysk kryjówki", "Loot tiers": "Rangi łupów", "Hideout build costs": "Koszt budowy kryjówki", "Wipe length": "Długości resetów", "Bitcoin Farm Profit": "Zysk farmy Bitcoinów", "Achievements": "Osiągnięcia", "API": "API", "Donate": "Darowizna", "Become a patron": "Zostań patronem", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "has alternates", "On Task Completion": "Na ukończeniu zadania", "On Task Start": "Na zaczęciu zadania", "Task": "Zadanie", "Required items": "Wymagane przedmioty", "Reward items": "Przedmioty w nagrodę", "Required tasks": "Wymagane zadania", "loading": "wczytywanie", "active": "aktywne", "succeeded": "powiodło się", "complete": "ukończone", "failed": "nieudane", "Minimum level": "Minimalny poziom", "Minimum trader level": "Minimalny poziom handlarza", "Reputation rewards": "Nagrody za reputację", "Endgame": "Endgame", "Required for Kappa": "Wymagane do Kappy", "Required for Lightkeeper": "Wymagane do Latarnika", "No quests found": "Nie odnaleziono zadań", "Some tasks hidden by filter settings": "Niektóre zadania ukryto ustawieniami filtra", "open this page in another browser or window and connect using this id": "otwórz tę stronę w innej przeglądarce lub oknie i połącz się za pomocą tego identyfikatora", "ID for remote control": "Identyfikator do zdalnego sterowania", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Wejdź na Tarkov.dev z innej przeglądarki i wpisz ten identyfikator, aby kontrolować tę stronę stamtąd", "Click to connect": "Kliknij, by połączyć", "Sell value": "Wartość sprzedaży", "Tarkov server status": "Status serwera Tarkova", "This item can't be sold to traders": "Ten przedmiot nie może być sprzedawany handlarzom.", "Name": "Nazwa", "Sell to Flea": "Sprzedaż na pchlim targu", "Buy on Flea": "Kupno na pchlim targu", "Sell to Trader": "Sprzedaż handlarzowi", "Trader buy": "Kupo u handlarza", "Buyback ratio": "Wskaźnik odkupu", "The percent recovered if you buy this item and sell it to the trader": "Procent odzyskany w przypadku zakupu tego przedmiotu i sprzedaży go handlarzowi", "Grid": "Siatka", "Slots occupied": "Zajmowane miejsca", "Slots inside": "Miejsca w środku", "Slots ratio": "Współczynnik miejsc", "Price per slot": "Cena za miejsce", "Armor class": "Klasa pancerza", "Zones": "Strefy", "Max Durability": "Maksymalna wytrzymałość", "Effective Durability": "Sktuczna wytrzymałość", "Repairability": "Naprawialność", "Weight (kg)": "Waga (kg)", "Stats": "Statystyki", "Mov/Turn/Ergo": "Ruch/Obrót/Ergo", "Caliber": "Kaliber", "Armor damage": "Obrażenia pancerza", "Fragmentation chance": "Szansa na fragmentację", "Blindness protection": "Ochrona przed oślepieniem", "Hydration": "Nawodnienie", "Energy": "Energia", "Hydration Cost": "Koszt nawodnienia", "Energy Cost": "Koszt energii", "Hydration + Energy Value": "Wartość nawodnienia + energii", "Sound suppression": "Tłumienie dźwięku", "Low": "Niskie", "None": "Brak", "Blocks earpiece": "Blokuje słuchawki", "Yes": "Tak", "No": "Nie", "Ergonomics": "Ergonomia", "Cost per ergo": "Koszt za ergonomię", "Recoil": "Odrzut", "Distance": "Dystans", "No items": "Brak przedmiotów", "Not built": "Niezbudowane", "Locked": "Zablokowane", "Crafting": "Wytwarzanie", "Hideout Management": "Zarządzanie kryjówką", "Be the first!": "Bądź pierwszy!", "Objective": "Cel", "No objectives": "Brak celów", "Players": "Gracze", "By": "Przez", "Restock in": "Uzupełnienie za", "Support Ukraine": "Wspieraj Ukrainę", "Cost per unit": "Koszt na jednostkę", "About the tarkov.dev project": "O projekcie Tarkov.dev", "about-page-description": "Dowiedz się więcej o the-hideout i Tarkov.dev. Wolny, stworzony przez społeczność, ekosystem open source Escape from Tarkov! Skorzystaj z naszych narzędzi, które pomogą ci w grze, lub zbuduj swoje własne projekty z naszym darmowym API.", "Open source": "Open source", "Discussions & feedback": "Dyskusje i opinie", "Support": "Wsparcie", "about-support-more-p": "<0>Możesz również pomóc, publikując błędy, sugerując lub wdrażając nowe funkcje, poprawiając mapy lub cokolwiek innego, co mogłoby ulepszyć stronę.", "about-api-p": "<0>Oferujemy w 100% darmowe i publicznie dostępne API dla wszystkich potrzeb rozwoju Tarkov - <1>API.", "History": "Historia", "about-history-p": "<0>Ten projekt to fork <1>tarkov-tools.com. Oryginalny twórca <3>@kokarn postanowił zamknąć stronę. W duchu open source, grupa deweloperów zebrała się, aby ożywić stronę, aby kontynuować dostarczanie wspaniałej strony dla społeczności Tarkov i API, które pozwoli na dalszy rozwój twórców. Ten projekt jest teraz w 100% open source i należy do deweloperów. Nasza organizacja na GitHubie (<5>the-hideout) contains all the repos which power the API, this website, the community Discord bot, server infrastructure, and much more! We are passionate about open source and love pull requests to improve our ecosystem for all.", "Core Contributors": "Główni współtwórcy", "about-core-contributors-p": "<0>Główni współtwórcy tego projektu (w nieszczególnej kolejności) to:", "All Contributors": "Wszyscy twórcy", "about-all-contributors-p": "<0>Ogromne podziękowania dla wszystkich osób, które przyczyniły się do powstania tego projektu! ❤️", "Description": "Opis", "Hidden": "Ukryte", "Player %": "Player %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "Ta strona zawiera informacje na temat osiągnięć, które można zdobyć.", "Ammo chart": "Tabela amunicji", "ammo-page-description": "Ta strona zawiera listę każdego rodzaju amunicji w Escape from Tarkov. Aby przefiltrować pełną listę dostępnych nabojów, kliknij nazwę kalibru.", "ammo-page-p": "<0>Dzicze Tarkowa pełne są zróżnicowanej amunicji. Do walki z różnymi przeciwnikami potrzebne są różne rodzaje amunicji.<1>Ta strona zawiera listę każdego rodzaju amunicji w Escape from Tarkov. Aby przefiltrować pełną listę dostępnych nabojów, kliknij nazwę kalibru.", "Total damage": "Łączne obrażenia", "Use total damage of all projectiles in a round": "Użyj całkowitych obrażeń wszystkich pocisków w naboju", "Ignore settings": "Ignoruj ustawienia", "Shows all sources of items regardless of your settings": "Pokazuje wszystkie źródła przedmiotów niezależnie od ustawień", "Use barters for item sources": "Używanie barterów dla źródeł przedmiotów", "Use crafts for item sources": "Używaj wytwarzania jako źródła przedmiotów", "Ammo Statistics Table": "Tabela statysyk amunicji", "API Documentation": "Dokumentacja API", "api-docs-page-description": "API Escape from Tarkov stworzone przez społeczność i jego dokumentacja. Dowiedz się więcej o naszym darmowym i łatwym w użyciu API GraphQL dla EFT.", "api-about-p": "<0>API jest napisane w GraphQL i staramy się jak najlepiej przestrzegać specyfikacji i nie wprowadzać przełomowych zmian. Aby dowiedzieć się jakie zapytania można wykonać i jak zbudowany jest schemat, wejdź na plac zabaw i kliknij zakładkę 'Dokumentacja' po prawej stronie. Kiedy już będziesz gotowy na kilka zapytań, możesz je przetestować również na placu zabaw. Aby dowiedzieć się o zapytaniach GraphQL ogólnie, Fundacja GraphQL ma pomocne zasoby.<1><0><0>Plac zabaw GraphQL Tarkov.dev<1><0>Zasoby GraphQL Foundation<1>Kiedy już będziesz gotowy do wysyłania zapytań API spoza placu zabaw, punkt końcowy to: <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Obecna wydajność API", "api-performance-p": "<0>Aby zapoznać się z pełną metryką i wydajnością API, sprawdź naszą <1>stronę statusu.", "FAQ": "FAQ", "Is it free?": "Czy to jest darmowe?", "Is it open source?": "Czy to jest open source?", "api-faq-open-source-p": "Oczywiście! Kod źródłowy dla API można znaleźć w jego repozetorium na GitHubie: <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "Czy jest jakiś limit częstotliwości?", "api-faq-rate-limit-p": "We occasionally get hit with a lot of traffic from bad actors that requires implementing rate limits. Price data is updated every 5 minutes, so there's really no need to query faster than that. Use common sense, and you should be fine.", "What about caching?": "Co z cache'owaniem?", "api-faq-caching-p": "Ponieważ nasze dane są aktualizowane co 5 minut, cache'ujemy również wszystkie zapytania GraphQL przez 5 minut.\nPomaga to znacznie zmniejszyć obciążenie naszych serwerów, jednocześnie sprawiając, że twoje żądania są szybkie!", "Where is the data from?": "Skąd pochodzą dane?", "We source data from multiple places to build an API as complete as possible. We use data from:": "Pozyskujemy dane z wielu miejsc, aby zbudować jak najbardziej kompletne API. Wykorzystujemy dane z:", "Our network of scanners": "Naszej sieci skanerów", "Examples": "Przykłady", "example": " - przykład", "Contributed by": "Autorstwa", "API Users": "Użytkownicy API", "api-users-page-description": "Ta strona zawiera listę wszystkich użytkowników publicznego API na Tarkov.dev i ich projektów.", "api-users-p": "<0>Chcesz się znaleźć na tej stronie? Dołącz do <1>Discorda i opowiedz nam o tym, co stworzyłeś!", "Barter Profits": "Zyski z barteru", "barters-page-description": "Ta strona zawiera informacje o różnych przedmiotach, którymi można handlować ze sprzedawcami NPC, cenach wymiany oraz zyskach, jakie można osiągnąć ze sprzedaży przedmiotów.", "Shows all barters regardless of your settings": "Pokazuje wszystkie bartery niezależnie od ustawień", "Hide dogtags": "Ukryj nieśmiertelniki", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "Prawdziwy \"koszt\" barterów z nieśmiertelnikami jest trudny do oszacowania, więc możesz chcieć wykluczyć bartery z nieśmiertelnikami.", "Show all barters": "Pokaż wszystkie bartery", "All": "Wszystko", "Item filter": "Filtr przedmiotu", "filter on item": "filtruj po przedmiocie", "barters-page-p": "<0>Z wyjątkiem Pasera, każdy handlarz w Escape from Tarkov oferuje towary w ramach barteru, a nie do kupienia od razu.<1>W zamian za różne niedrogie rzeczy gracz może je często wymieniać na bardziej wartościowe przedmioty, które może wykorzystać lub sprzedać z zyskiem, albo na wyższy ekwipunek na niższych poziomach lojalności.<3>Pamiętaj, aby sprawdzić po resecie dla swoich ulubionych transakcji, ponieważ większość z tych cennych transakcji ma ścisłe limity na uzupełnienie handlarza i często się wyprzedaje.", "Num graphic cards": "Ilość kart graf.", "Hours": "Godziny", "Bitcoin Farm Calculator": "Kalkulator farmy Bitcoinów", "bitcoin-farm-calculator-page-description": "Ta strona zawiera narzędzie kalkulatora, które pomaga określić cenę budowy i utrzymania farmy Bitcoinów, w oparciu o liczbę jednostek GPU, koszty paliwa i koszt bitcoinów.", "Graphic cards count": "Ilość kart graficznych", "Use fuel cost: {{price}}/day": "Koszt zużycia paliwa: {{price}}/dzień", "Use station build costs": "Użyj koszta budowy stacji", "Purchase cost": "Koszt zakupu", "Remaining days in wipe:": "Pozostałe dni w resecie:", "Time to produce 1 bitcoin": "Czas do produkcji 1 Bitcoina", "BTC/day": "BTC/dzień", "Estimated profit/day": "Szacowany zysk/dzień", "Profitable after days": "Zyskowne po dniach", "Total cost of graphic cards": "Łączny koszt kart graficznych", "Build costs": "Koszt budowy", "GPU + build costs": "Koszt budowy + GPU", "Remaining profit": "Pozostały zysk", "Map": "Mapa", "Spawn Location": "Lokalizacja pojawienia", "Chance": "Szansa", "Count": "Ilość", "Spawn chance": "Szansa pojawienia się", "Chance that the boss spawns on a given map": "Szansa, że boss pojawi się na danej mapie", "Health": "Zdrowie", "Total boss health": "Łączne zdrowie bossa", "Patrol": "Patroluje", "Rush": "Naciera", "Stalker": "Prześladowca", "Hostile and accurate": "Wrogi i celny", "Patrol and highly armored": "Patroluje i ciężko uzbrojony", "Group patrol": "Patroluje w grupie", "Frequent healing and stim injections": "Częste leczenie i zastrzyki stymulujące", "Sniper": "Snajper", "Batshit insane": "Cholernie szalony", "Behavior": "Zachowanie", "The boss's general AI behavior": "Ogólne zachowanie SI bossa", "Wiki": "Wiki", "Boss Stats": "Statystyki bossa", "Special Boss Loot": "Specjalne łupy bossa", "Spawn Locations": "Lokalizacje pojawienia", "boss-spawn-table-description": "<0>Mapa: Nazwa mapy, na której boss może się pojawić<1>Lokalizacja pojawienia: Dokładne miejsce na danej mapie, w którym boss może się pojawić<2>Szansa: Jeśli dla danej mapy aktywna jest opcja \"Szansa pojawienia się\", to jest to szacunkowa szansa, że boss będzie się pojawiał w danym miejscu na tej mapie.", "Boss Escorts": "Eskorty bossa", "This boss does not have any escorts": "Ten boss nie ma żadnej eskorty", "boss-page-description": "Ta strona zawiera informacje o lokalizacji bossa {{bossName}}, łupach i strategiach na jego pokonanie.", "bosses-page-description": "Ta strona zawiera informacje o wszystkich bossach w grze, ich lokalizacji, łupach, eskorcie i strategiach ich pokonania.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Bossy to przerażający i śmiertelni wrogowie z unikalnym ekwipunkiem i cechami w Escape from Tarkov", "About Bosses": "O bossach", "bosses-page-p": "<0>W Escape from Tarkov jest wielu bossów, którzy przemierzają teren oblężonego Norwińska.<1>Każdy boss ma unikalne zachowania, cechy i taktykę. Gracze na każdym poziomie obawiają się Bossów w Tarkowie, którzy często będą stanowić większe zagrożenie niż wrodzy PMC w regionie.<2>Z wysokim ryzykiem wiąże się jednak wysoka nagroda. Wiele bossów zawiera wysokopoziomowe przedmioty lub są wymagani do elimacji dla zadań. Poznanie schematów, miejsc i charakterystycznego stroju bossa jest często najlepsze, co może przygotować gracza do rozpoczęcia walki z bossem w Tarkowie.", "Connect": "Połącz", "Connected to": "Połączone do", "id to control": "id do sterowania", "Remote Control": "Zdalne sterowanie", "remote-control-page-description": "Ta strona zawiera wszystkie niezbędne narzędzia do zdalnej kontroli innej instancji strony Tarkov.dev.", "View Map": "Pokaż mapę", "Go": "Idź", "View caliber": "Pokaż kaliber", "Select...": "Wybierz...", "Load tarkov.dev in another browser or window to control it from here": "Wczytaj Tarkov.dev w innej przeglądarce lub oknie, aby móc kontrolować go z tego miejsca", "Hideout Crafts": "Wytwarzania w kryjówce", "crafts-page-description": "Ta strona zawiera informacje na temat różnych przedmiotów, które można wykonać w kryjówce, wymaganych materiałów i zasobów oraz zysków, które można uzyskać ze sprzedaży gotowych produktów.", "Shows all crafts regardless of your settings": "Pokazuje wszystkie wytwarzania niezależnie od ustawień", "Average prices": "Średnie ceny", "Use average prices from the past 24 hours for profit calculations": "Użyj średnich cen z ostatnich 24 godzin do kalkulacji zysków", "Most profitable craft in each station": "Najbardziej dochodowe wywarzania w każdej stacji", "Best": "Najlepsze", "Flea Market banned items": "Przedmioty zablokowane na pchlim targu", "Empty fuel": "Puste paliwo", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "Ustala koszt kanistra na paliwo dla jednostek, które tego wymagają, na poziomie minimalnej ceny sprzedaży stosowanej przez sprzedawcę w przypadku stosowania kanistrów na paliwo innych niż znalezione w rajdzie.", "crafts-page-p": "<0>W Escape from Tarkov wytwarzanie pozwala na tworzenie różnych rzeczy. Robi się to za pomocą różnych modułów kryjówki, w tym kolektora wody, stołu warsztatowego, stacji medycznej, łazienki i kuchni.<1>Status \"Znalezione w rajdzie\" zostanie zastosowany do każdego przedmiotu stworzonego w kryjówce. Cała lista tych wytwarzań jest pokazana powyżej. Umiejętność wytwarzanie ma wpływ na czas tworzenia przedmiotów.<2>Gdy ikona przedmiotu ma niebieską obwódkę, będzie on używany jako narzędzie pomocnicze, a po zakończeniu produkcji zostanie zwrócony do schowka.", "Page not found": "Nie znaleziono strony", "error-page-description": "To nie jest strona, której szukasz", "Sorry, that page doesn't exist!": "Przepraszamy, ta strona nie istnieje!", "Hideout": "Kryjówka", "hideout-page-description": "Ta strona zawiera informacje o różnych stacjach i modułach, które można zbudować wraz z materiałami i zasobami potrzebnymi do ulepszenia swojej kryjówki.", "Show all stations & modules": "Pokaż wszystkie stacje i moduły", "Show built": "Pokaż wybodwane", "Show already built stations": "Pokaż już wybudowane stacje", "Show locked": "Pokaż zablokowane", "Show unavailable stations": "Pokaż niedostępne stacje", "Show all requirements": "Pokaż wszystkie wymagania", "Show trader and other station level requirements": "Pokaż handlartzy i inne wymagania poziomu stacji", "Collected": "Zebrane", "Item Tracker": "Tracker przedmiotów", "Only show Found in Raid": "Pokaż tylko znalezione w rajdzie", "Reset all tracking": "Wyzeruj wszystkie śledzenia", "Hide completed": "Ukryj ukończone", "Hide tasks you've completed": "Ukryj zadania, które wykonałeś", "Hide dogtag barters": "Ukryj bartery nieśmiertelników", "Best price to sell for": "Najlepsza cena do sprzedania", "Fee": "Opłaty", "Profit": "Zysk", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "Ostatnia zanotowana niska cena dla tego przedmiotu na pchlim targu to {{lastSeenPrice}}.\nJednak ze względu na sposób naliczania opłat, lepiej sprzedać za {{bestPrice}}.", "Max price to sell for": "Maksymalna cena sprzedaży", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "Tego przedmiotu nie zauważono na pchlim targu.\nMaksymalna opłacalna cena to {{bestPrice}}, ale przedmiot może nie sprzedać się za tę cenę.\nNa maksymalną opłacalną cenę wpływa poziom centrum wywiadowczego i umiejętności zarządzanie kryjówką w ustawieniach.", "Likely sell price": "Prawdopodobna cena sprzedaży", "item-page-description": "Ta strona zawiera informacje na temat cech, zastosowań i strategii dla {{itemName}}.", "Sell for": "Sprzedaj za", "Buy for": "Kup za", "Flea price history": "Historia cen na pchlim targu", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "Zmiana w stosunku do wczoraj: {{changeLast48h}} ₽ / {{changeLast48Percent}}%", "Lowest scanned price last 24h: {{low24hPrice}}": "Najniższa zeskanowana cena w ostatnich 24h: {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Najwyższa zeskanowana cena w ostatnich 24h: {{high24hPrice}}", "Updated: {{val, relativetime}}": "Zaktualizowano: {{val, relativetime}}", "Items contained in {{itemName}}": "Przedmioty zawarte w {{itemName}}", "Barters with {{itemName}}": "Bartery z {{itemName}}", "Crafts with {{itemName}}": "Wytwarzania z {{itemName}}", "Hideout modules needing {{itemName}}": "Moduły kyrjówki potrzebujące {{itemName}}", "Shows all modules regardless of your settings": "Pokazuje wszystkie moduły niezależnie od ustawień", "Quests requiring {{itemName}}": "Zadania wymagające {{itemName}}", "Quests rewarding {{itemName}}": "Zadania dające {{itemName}}", "Armors": "Pancerze", "armors-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów pancerzy dostępnych w grze, w tym ich ceny, możliwości naprawy, klasy pancerza i innych cech.", "Class effective durability": "Klasa efektywnej trwałości", "Include rigs": "Uwzględnij kamizelki", "Max price": "Maksymalna cena", "max price": "maks. cena", "armors-page-p": "<0>In the video game Escape from Tarkov, armor vests are worn to lessen bullet damage. Helmets are typically used in addition to them.", "Backpacks": "Plecaki", "backpacks-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów plecaków dostępnych w grze, w tym ich ceny, rozmiaru, pojemności i innych cech.", "Net price per slot": "Cena za miejsce", "Show price per additional slot of storage gained from the container": "Pokaż cenę za dodatkowe miejsce na przechowywanie uzyskany z kontenera", "backpacks-page-p": "<0>Backpacks in the Escape from Tarkov game are various-sized containers for carrying your hard-earned riches.", "Barter Items": "Przedmioty barterowe", "barter-items-page-p": "<0>This table of barter items from Escape from Tarkov will make it simple for you to determine how much each one is worth. It can be challenging to determine which products are valuable enough to take because there are over 150 barter items in the game, and flea market pricing can fluctuate suddenly. You may optimize your loot with the aid of this interactive table.", "bsg-category-description": "Dowiedz się wszystkiego, co musisz wiedzieć o {{category}} w Escape from Tarkov.", "Containers": "Pojemniki", "containers-page-p": "<0>As their name implies, containers in Escape from Tarkov are items used to hold other things. Some of these items are used to clear up inventory space by acting as storage and taking up less inventory slots however some of them cannot be equipped on the character.", "Glasses": "Okulary", "glasses-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów okularów dostępnych w grze, w tym ich ceny, klasy pancerza i innych cech.", "glasses-page-p": "<0>Eyewear in Escape from Tarkov can be used to decrease the number and quantity of raindrops on the players' screens as well as the length of flashbang effects.", "Grenades": "Granaty", "grenades-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów granatów dostępnych w grze, w tym ich cenę, obrażenia i inne cechy.", "grenades-page-p": "<0>There are only a handful distinct types of grenades that may be thrown or launched in Escape from Tarkov, and each one has a unique effect: flash, smokes, high explosive, and fragmentation.<1>Grenades are situational, but when utilized properly, they can have deadly results. Any advantage from high-tier equipment can be fully negated by a single well-thrown grenade, whether it completely blinds the adversary, kills them instantly, or forces them out of cover and into your gunfire.<3>Five factors to think about while using throwable grenades include the fuse time, explosion radius, fragment damage, fragment count, and even the weight of the grenade. With specific uses arising from each component.", "Guns": "Broń palna", "guns-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów broni dostępnych w grze, w tym ich cenę, obrażenia, celność i inne cechy.", "guns-page-p": "<0>Your main tool for survival is a weapon. Almost all weapons are completely modular, allowing them to be customized for various scenarios. All of the weaponry used in Escape from Tarkov are listed on this page.", "Headsets": "Słuchawki", "headsets-page-description": "Ta strona zawiera sortowalną tabelę z informacjami o różnych typach zestawów słuchawkowych dostępnych w grze, w tym o ich cenie, żywotności i innych cechach.", "headsets-page-p": "<0>In Escape from Tarkov, headsets magnify low-frequency noises like footsteps while muzzling impulsive stimuli like gunshots. Different audio profiles are offered by the various models.", "Helmets": "Hełmy", "helmet-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów hełmów dostępnych w grze, w tym ich ceny, klasy pancerza i innych cech.", "Show blocking headset": "Pokaż blokujące słuchawki", "Min armor class": "Minimalna klasa pancerza", "helmets-page-p": "<0>In Escape from Tarkov, headgear serves a variety of functions.<1>There are useful objects, vanity items, and safety headgear. Before entering combat, choosing a helmet that will protect different parts of the head becomes crucial.<3>The impact that different helmets will have on how much sound they suppress is another crucial factor to take into account. Escape from Tarkov's gameplay heavily relies on sound.<5>Modular helmets, which have an assortment of different components, are another aspect of Escape from Tarkov. These helmets may modify the number of segments they protect. Top, Nape, Ears, Eyes, and Jaws are the segments.", "items-page-description": "Ta strona zawiera linki do stron z informacjami na temat różnych kategorii przedmiotów, w tym zbroi, plecaków, przedmiotów barterowych, pojemników, okularów, granatów, pistoletów, zestawów słuchawkowych, hełmów, kluczy, modyfikacji do broni, chwytów pistoletowych, prowiantu, kamizelek, tłumików i innych.", "Keys": "Klucze", "keys-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów kluczy dostępnych w grze, w tym ich ceny, rzadkości i innych cech.", "keys-page-p": "<0>Maps, keys, key cards, and other useful objects are included in intelligence items. These will help you stay one step ahead of the competition—or at the very least, know where you are in Escape from Tarkov.<1>The remaining durability of keys and keycards with a limited number of uses is displayed in the bottom right corner of their icons and on their inspection screens.", "Mods": "Modyfikacje", "mods-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów modów do broni dostępnych w grze, w tym ich ceny, kompatybilności i innych cech.", "mods-page-p": "<0>In Escape from Tarkov, the performance and functioning of a weapon are controlled by elaborate mechanisms organized into five categories:<1><0>Functional Mods<1>Muzzle devices (Functional Mods)<2>Sights (Functional Mods)<3>Gear Mods<4>Vital parts", "Pistol Grips": "Chwyty pistoletowe", "pistol-page-description": "Strona zawiera sortowalną tabelę z informacjami na temat różnych typów chwytów pistoletowych dostępnych w grze, w tym ich ceny, ergonomii, kompatybilności i innych cech.", "Filter by gun": "Filtruj po broni", "select a gun": "wybierz broń", "pistol-grips-page-p": "<0>In Escape from Tarkov a pistol grips and stocks are vital parts of a weapon.<1>On this page you can sort them buy ergonomics improvement or their cost and see on which weapon they can be mounted.", "Provisions": "Prowiant", "provisions-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych rodzajów prowiantu dostępnych w grze, w tym ich nawodnienia, energii, najtańszej ceny oraz wartości dla handlarzy lub pchlim targu.", "Total energy cost": "Łączny koszt energii", "Include the cost of lost hydration in the cost of energy": "Uwzględnij koszt utraty nawodnienia w koszcie energii", "provisions-page-p": "<0>In Escape from Tarkov, provisions are utilized to replenish energy and hydration.<1>Your Metabolism skill level will determine how effective they are.", "Rigs": "Kamizelki", "rigs-page-description": "Ta strona zawiera sortowalną tabelę z informacjami na temat różnych typów kamizelek dostępnych w grze, w tym ich cenę, rozmiar wewnętrzny i zewnętrzny, wagę, kompresję i inne cechy.", "Armored rigs?": "Opancerzone kamizelki?", "Min slots": "Min. miejsca", "3-slot": "3-miejscowe", "4-slot": "4-miejscowe", "rigs-page-p": "<0>When it comes to carrying and storing ammunition and magazines during your excursions in Escape from Tarkov, chest rigs are crucial. Some even provide you with additional security.", "Suppressors": "Tłumiki", "suppressors-page-description": "Na tej stronie znajduje się sortowalna tabela z informacjami na temat różnych typów tłumików dostępnych w grze, w tym ich ergonomii, odrzutu i najtańszej ceny.", "suppressors-page-p": "<0>In Escape from Tarkov, a suppressor is a muzzle device (a functional mod) and can be installed on a weapon to muffle gunshot sound.<1>On this page you can sort them buy ergonomics penalty, recoil improvement or their cost and see on which weapon they can be directly mounted.", "Barters": "Bartery", "Marked": "Oznaczone", "Wearables": "Noszone", "loot-tiers-page-description": "Poznaj różne rodzaje łupów dostępnych w grze, ich wartość, rzadkość oraz co zachować, a co wyrzucić do kosza.", "Ranking the most valuable items in the game": "Ranking najcenniejszych przedmiotów w grze", "Include Marked": "Uwzględnij market", "Group by type": "Grupuj po typie", "min value": "min. wartość", "Only show markers for active tasks": "Only show markers for active tasks", "Map of {{mapName}}": "Map of {{mapName}}", "maps-page-description": "Poznaj najnowsze informacje na temat wszystkich map w Escape from Tarkov, w tym punkty wyjścia i lokalizacje łupów. Dowiedz się, gdzie znaleźć najlepszy sprzęt i zasoby w grze", "maps-page-p": "<0>Na mapie Escape from Tarkov znajduje się 11 różnych lokalizacji, z czego 10 zostało do tej pory publicznie udostępnionych. Chociaż docelowo wszystkie mapy będą połączone, to obecnie wszystkie są od siebie niezależne.", "Streets of Tarkov": "Ulice Tarkowa", "Ground Zero": "Ground Zero", "Customs": "Skład celny", "Factory": "Fabryka", "Interchange": "Węzeł transportowy", "The Lab": "Laboratorium", "Lighthouse": "Latarnia morska", "Reserve": "Rezerwy", "Shoreline": "Wybrzeże", "Woods": "Las", "Openworld": "Otwarty świat", "Tarkov.dev {{bot}} integration": "Integracja {{bot}} Tarkov.dev", "bot-page-description": "Ta strona zawiera wszystko co jest potrzebne do integracji {{bot}} z Tarkov.dev.", "You can add command to your moobot to get price check in your twitch chat": "Możesz dodać polecenie do swojego moobota, aby uzyskać sprawdzenie ceny na czacie Twitch", "Instructions": "Instrukcje", "Register at": "Zarejestruj na", "using your twitch account": "używając twojego konta Twitch", "Go to Custom commands": "Przejdź do własnych poleceń", "Set what you want the command to be. Common is \"p\" or \"price\"": "Ustaw to, czym chcesz by było polecenie. Przeważnie to \"p\" albo \"price\"", "Press the \"Create\" button": "Wciśnij przycisk \"Utwrórz\"", "In response choose URL Fetch - Full (plain) response": "W odpowiedzi wybierz odpowiedź URL Fetch - Full (plain)", "and after insert \"Command arguments\"": "i po tym wklej \"Argumenty polecenia\"", "Now press \"Save\" button": "Teraz wciśnij przycisk \"Zapisz\"", "Big thanks to": "Duże podziękowania dla", "for feedback": "za wsparcie", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "Możesz dodać polecenie do swojego nightbota, aby uzyskać sprawdzenie ceny na czacie swojego kanału Twitch/YouTube", "using your twitch / youtube account": "używając twojego konta Twitch/YouTube", "Go to dashboard": "Idź do kokpitu", "Click the \"Join Channel\" button": "Wciśnij przycisk \"Dołącz do kanału\"", "Make bot - moderator, just type /mod nightbot in your chat": "Stwórz bota - moderatorze, napisz /mod na twoim czacie", "Go to custom commands": "Przejdź do własnych komend", "Press the \"Add command\" button": "Wciśnij przycisk \"Dodaj polecenie\"", "Command: !p or anything you like": "Polecenie: !p albo cokolwiek chcesz", "Message:": "Wiadomość:", "Press \"Submit\"": "Wciśnij \"Prześlij\"", "Trader Levels": "Poziomy handlarzy", "Trader Reputation": "Trader Reputation", "Prerequisite Tasks": "Wymagane wstępnie zadania", "Start Requirements": "Wymogi rozpoczęcia", "Attributes": "Atrybuty", "Contains All": "Zawiera wszystkie", "Contains Item in Category": "Zawiera przedmiot w kategorii", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Posiada {{effectNames, list}} efekt(y) na twojej {{bodyParts, list(type: disjunction)}} przez {{operator}} {{count}} sekundę", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "Posiada {{effectNames, list}} efekt(y) na twojej {{bodyParts, list(type: disjunction)}} przez {{operator}} {{count}} sekundy", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Posiada {{effectNames, list}} efekt(y) na twojej {{bodyParts, list(type: disjunction)}} przez {{operator}} {{count}} sekund", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Posiada {{effectNames, list}} efekt(y) na twojej {{bodyParts, list(type: disjunction)}} przez {{operator}} {{count}} sekundy", "using extract: {{extractName}}": "używając wyjścia: {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Wyjdź ze statusem(-ami): {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x any of", "Dogtag level": "Poziom nieśmiertelnika", "Max durability": "Maksymalna wytrzymałość", "Min durability": "Minimalna wytrzymałość", "Kill": "Zabij", "Shoot": "Zastrzel", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "Podczas godzin: {{hourStart}}:00 to {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "Z odległości: {{operator}} {{count}} metra", "From distance: {{operator}} {{count}} meters_few": "Z odległości: {{operator}} {{count}} metrów", "From distance: {{operator}} {{count}} meters_many": "Z odległości: {{operator}} {{count}} metrów", "From distance: {{operator}} {{count}} meters_other": "Z odległości: {{operator}} {{count}} metra", "While inside: {{zoneList, list(type: disjunction)}}": "Gdy w środku: {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Trafiając: {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Używając broni:", "Using weapon mods:": "Używając modyfikacji broni:", "While wearing:": "Nosząc:", "Not wearing:": "Nie nosząc:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Mając {{effectNames, list}} efekt(-y) na twojej {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekundę", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "Mając {{effectNames, list}} efekt(-y) na twojej {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekundy", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Mając {{effectNames, list}} efekt(-y) na twojej {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekund", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Mając {{effectNames, list}} efekt(-y) na twojej {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekundy", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "Mając {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Gdy cel ma {{effectNames, list}} efekt(-y) na swoim {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekundę", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "Gdy cel ma {{effectNames, list}} efekt(-y) na swoim {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekundy", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Gdy cel ma {{effectNames, list}} efekt(-y) na swoim {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekund", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Gdy cel ma {{effectNames, list}} efekt(-y) na swoim {{bodyParts, list(type: disjunction)}} na {{operator}} {{count}} sekundy", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "Gdy cel ma {{effectNames, list}} efekt(-y) na swoim {{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "Zdobądź poziom {{level}} umiejętności {{skillName}}", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} reputacja", "In area(s): {{areaList, list(type: disjunction)}}": "W obszarze(-ach): {{areaList, list(type: disjunction)}}", "Use any of:": "Użyj dowolnego z:", "Reach level {{playerLevel}}": "Reach level {{playerLevel}}", "optional": "opcjonalne", "Trader Standing": "Lojalność handlarza", "Skill Level": "Poziom umiejętności", "Trader Offer Unlock": "Odblokowuje ofertę handlarza", "Trader Unlock": "Odblokowuje handlarza", "Craft Unlock": "Craft Unlock", "task-page-description": "Ta strona zawiera informacje na temat celów, nagród i strategii wykonania zadania {{questName}}. Poznaj wskazówki, jak przygotować się do misji i odnieść w niej sukces.", "TarkovTracker": "TarkovTracker", "Leads to": "Prowadzi do", "(on failure)": "(przy porażce)", "Task Details": "Szczegóły zadania", "Objectives": "Cele", "Fail On": "Porażka na", "Needed Keys": "Potrzebuje kluczy", "Task Start": "Task Start", "Task Completion": "Ukończenie zadania", "Rewards": "Nagrody", "Task Failure": "Nieudane zadanie", "Can be restarted": "Może być restartowane", "Cannot be restarted": "Nie możę być restartowane", "Penalties": "Kary", "tasks-page-description": "Dowiedz się wszystkiego, co musisz wiedzieć o zadaniach w grze Escape from Tarkov. Poznaj różne rodzaje zadań dostępnych w grze, dowiedz się, jak je wykonać i jakie nagrody możesz zdobyć.", "Hides completed tasks": "Ukryj ukończone zadania", "Hide locked": "Ukryj zablokowane", "Hides locked tasks": "Ukrywa zablokowane zadania", "Show all tasks": "Pokaż wszystkie zadania", "Name filter": "Filtr nazwy", "filter on task name": "filtruj po nazwie zadania", "quests-page-p": "<0>Traders in Escape from Tarkov have a number of tasks you can complete.<1>In exchange for retrieving items, eliminating targets, and performing other actions in raid, you can increase your standing with the traders and earn valuable items.", "Settings": "Ustawienia", "settings-page-description": "Ta strona zawiera ustawienia użytkownika na Tarkov.dev.", "Language": "Język", "General": "Ogólne", "Has flea": "Ma pchli targ", "Use TarkovTracker": "Użyj TarkovTracker", "TarkovTracker API Token": "Token API TarkovTracker", "API Token": "Token API", "Stations": "Stacje", "Skills": "Umiejętności", "Dogtag Barters": "Bartery nieśmiertelników", "Exclude": "Wyklucz", "Minimum dogtag level": "Minimalny poziom nieśmiertelnika", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Minimalny poziom nieśmiertelnika używany do obliczania kosztów transakcji barterowych z nieśmiertelnikami.", "The current estimated average player level is {{avgPlayerLevel}}": "Obecny szacowany średni poziom gracza to {{avgPlayerLevel}}", "Miscellaneous": "Różne", "Hide remote control": "Ukryj zdalne sterowanie", "start-page-description": "Sprawdź wszystkie informacje o przedmiotach, rzemiośle, barterach, mapach, poziomach łupów, zyskach z kryjówek, szczegółach dotyczących handlarzy, darmowym API i wiele więcej dzięki tarkov.dev! Wolny, tworzony przez społeczność i otwarty ekosystem narzędzi i przewodników Escape from Tarkov.", "Load More": "Wczytaj więcej", "Tools": "Narzędzia", "Ammo chart filter": "Filtr wykresu amunicji", "Traders barter profit": "Zysk z barterku handlarzami", "Hideout crafts profit": "Zysk z wytwarzań w kryjówce", "Loot tiers ranking": "Ranking rang łupów", "Average wipe length": "Średnia długość wipe'u", "Bitcoin farm profit": "Zysk z farmy Bitcoinów", "Invite Discord bot": "Zaproś bota Discorda", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "Tarkov.dev to zestaw narzędzi open source do gry Escape from Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "Jest on zaprojektowany i utrzymywany przez społeczność, aby pomóc ci w zadaniach, handlu na pchlim targu i ulepszaniu twojej gry! API jest również dostępne za darmo, abyś mógł zbudować własne narzędzia i usługi związane z EFT.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "Możesz dodać polecenie do swojego bota StreamElements, aby uzyskać kontrolę cen w czacie swojego kanału Twitch/TouTube", "Make bot - moderator, just type /mod streamelements in your chat": "Stwórz bota - moderatorze, napisz /mod na twoim czacie", "Press the \"Add new command\" button": "Wciśnij przycisk \"Dodaj polecenie\"", "Press \"Activate Command\"": "Wciśnij \"Aktywuj polecenie\"", "Player level": "Player level", "Reputation": "Reputation", "Commerce": "Commerce", "Trader {{trader}}": "Handlarz {{trader}}", "trader-page-description": "Zdobądź najnowsze informacje na temat handlarza {{trader}} w Escape from Tarkov. Dowiedz się o przedmiotach, które sprzedaje na danym poziomie lojalności i jak zmaksymalizować swój zwrot gotówki do poziomu lojalności.", "Items with the best cash back prices for leveling": "Przedmioty z najlepszymi cenami zwrotu gotówki do zwiększania poziomu", "Spending": "Wydawanie", "Unlocks at Loyalty Level {{level}}": "Odblokowuje się na poziomie lojalności {{level}}", "Tasks given by {{traderName}}": "Zadania dane przez {{traderName}}", "traders-page-description": "Dowiedz się wszystkiego, co musisz wiedzieć o handlarzach w grze Escape from Tarkov. Poznaj różnych handlarzy dostępnych w grze, ich lokalizacje i przedmioty, które sprzedają.", "About Traders": "O handlarzach", "traders-page-p": "<0>Główny sposób handlu w zniszczonym, oblężonym Norwińsku. W Escape from Tarkov każdy kupiec specjalizował się w konkretnym rodzaju produktów, takich jak środki medyczne, broń czy sprzęt wojskowy. Choć ich ceny są zazwyczaj wysokie, dostajesz to, za co płacisz.<1>Co ważniejsze, dzięki zadaniom możesz wyrobić sobie reputację u każdego handlarza, co pozwoli ci na otrzymanie ogólnie lepszych ofert i zmniejszenie otrzymywanej przez nich prowizji (dodatkowej marży, którą płacisz od sprzedaży i zakupu), łącznie z innymi korzyśćmi.<2>Dodatkowo handlarze świadczą inne usługi, takie jak ubezpieczenia i naprawy (pozwalające odzyskać ekwipunek w przypadku śmierci podczas rajdu).", "Patch": "Wersja", "Wipe start": "Start resetu", "Wipe end": "Koniec resetu", "Ongoing wipe": "Trwający reset", "{{count}} days_one": "{{count}} dzień", "{{count}} days_few": "{{count}} dni", "{{count}} days_many": "{{count}} dni", "{{count}} days_other": "{{count}} dnia", "{{count}} months_other": "{{count}} miesięcy", "{{count}} years_one": "{{count}} rok", "Wipe Length": "Długość resetu", "wipe-length-description": "Uzyskaj najnowsze informacje na temat średniej długości resetów w Escape from Tarkov. Dowiedz się, jak długo zazwyczaj trwają resety i przygotuj się na następny reset.", "Average Wipe Length among last 6 wipes:": "Średnia długość resetu wśród ostatnich 6 resetów:", "Trader Ammo": "Trader Ammo", "Only show ammo available from traders on your settings": "Only show ammo available from traders on your settings", "Reset": "Reset", "Convert one currency to another": "Convert one currency to another", "Currency Converter": "Currency Converter", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "control-info-p": "<0>This page allows you to control the Tarkov.dev website using another browser. The typical use case is to have the Tarkov.dev website open in a browser on a second monitor while you play the game and this page open on your phone or another device so that you can navigate to different pages on the Tarkov.dev website without having to alt+tab out of the game. All you have to do is open the Tarkov.dev website in a browser where you want it to be displayed, click the \"Click to connect\" button in the lower left*, and then use the ID shown there on this page on the control device and click the Connect. Once connected, you can use this control page to open specific map or ammo pages in the controlled browser.<1>*It appears on the lower left by default but can be toggled to the lower right side of the screen. It can also be hidden by the \"Hide remote control\" option on the settings page.", "cookie-consent": "tarkov.dev wykorzystuje pliki cookie w celu poprawy komfortu użytkowania. Kontynuując korzystanie z tej strony, wyrażasz zgodę na wykorzystanie plików cookie. Pliki cookie służą do zapamiętywania twoich ustawień i funkcji, które włączasz.", "I understand": "Rozumiem", "Other Options": "Inne opcje", "This task {{taskStatus}}": "To zadanie {{taskStatus}}", "Slots per kg": "Miejsca na kg", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Bot Discord Stash", "More Tools": "Więcej narzędzi", "Companion app": "Aplikacja pomocnicza", "Discord companion": "Dodatek Discord", "Download latest release": "Pobierz najnowsze wydanie", "View on GitHub": "Zobacz na GitHubie", "Join the community": "Dołącz do społeczności", "Screenshot of TarkovMonitor showing timers and integrations": "Zrzut ekranu TarkovMonitor z timerami i integracjami", "Visual timers, raid state, and integration health in TarkovMonitor.": "Widoczne timery, stan rajdu i kondycja integracji w TarkovMonitor.", "Main Features": "Najważniejsze funkcje", "tarkov-monitor-page-description": "Dowiedz się, jak zainstalować TarkovMonitor, połączyć go z TarkovTracker i sterować mapami Tarkov.dev.", "tarkov-monitor-summary": "TarkovMonitor zapewnia przydatne alerty i timery do Escape From Tarkov, abyś mógł zarządzać rajdami bez przerywania gry.", "tarkov-monitor-feature-audio": "Alerty dźwiękowe dla matchmakingu, startu rajdu, timera runthrough, odnowienia scava i powiadomień o filtrze powietrza.", "tarkov-monitor-feature-map": "Automatyczne otwieranie mapy na Tarkov.dev w zależności od lokalizacji, do której dołączasz.", "tarkov-monitor-feature-screenshot": "Opcjonalne wyświetlanie pozycji aktywowane zrzutem ekranu do szybkiego udostępniania lokalizacji.", "tarkov-monitor-feature-quests": "Automatyczne aktualizacje zadań do TarkovTracker po wykryciu ukończenia.", "tarkov-monitor-feature-stats": "Lokalne statystyki, takie jak zyski z pchlego targu, długość kolejek i częstotliwość map.", "tarkov-monitor-feature-timers": "Widoczne liczniki czasu w rajdzie oraz odnowienia scava, by zaplanować kolejny wypad.", "Download": "Pobierz", "tarkov-monitor-download-1": "Pobierz najnowszy plik TarkovMonitor.zip z GitHuba.", "tarkov-monitor-download-2": "Wypakuj archiwum w dowolnym miejscu na komputerze.", "tarkov-monitor-download-3": "Uruchom TarkovMonitor.exe i pozostaw otwarty podczas gry.", "Community support": "Wsparcie społeczności", "tarkov-monitor-community": "Masz pytania lub chcesz porozmawiać z innymi? Dołącz do serwera Discord po wskazówki, pomoc i dyskusje o funkcjach.", "Join the Discord": "Dołącz do Discorda", "Security": "Bezpieczeństwo", "tarkov-monitor-security": "TarkovMonitor nie jest cheatem. Czyta jedynie logi Escape From Tarkov zapisane na twoim PC i nigdy nie modyfikuje gry ani nie wstrzykuje kodu.", "stash-page-description": "Zaproś bota Discord Stash, poznaj jego komendy i zobacz, jak może pomóc twojej społeczności.", "stash-hero": "Stash przenosi cały zestaw danych Tarkov.dev do Discorda, aby społeczność mogła sprawdzać ceny, zadania, timery kryjówki i więcej bez opuszczania czatu.", "Invite Stash": "Zaproś Stash", "Report an issue": "Zgłoś problem", "Highlights": "Najważniejsze", "Item intelligence": "Informacje o przedmiotach", "Instant prices with flea, trader, and craft context.": "Natychmiastowe ceny z kontekstem pchlego targu, handlarzy i craftingu.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Wyszukiwania craftu/wymiany wykorzystują dane opłacalności z Tarkov.dev.", "Toggle PVE or PMC game modes to match your server rules.": "Przełącz tryb PVE lub PMC, aby dopasować odpowiedzi bota do zasad serwera.", "Progress tracking": "Śledzenie postępów", "Quest command lists requirements, turn-ins, and rewards.": "Komenda quest wypisuje wymagania, oddania i nagrody.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "Komenda progress odzwierciedla ulepszenia kryjówki i handlarzy zapisane na TarkovTracker.", "Restock and status alerts keep everyone informed between raids.": "Alerty o dostawach i statusie informują wszystkich między rajdami.", "Community tools": "Narzędzia społecznościowe", "Goons tracker for spotting the Rogue Boss trio.": "Tracker Goons do namierzania trójki bossów Rogue.", "Roulette mini-game for fun raid modifiers.": "Mini-gra ruletka dla zabawnych modyfikatorów rajdów.", "Slash commands, autocomplete, and localized responses.": "Komendy slash, autouzupełnianie i lokalne odpowiedzi.", "Frequently used commands": "Najczęściej używane komendy", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash udostępnia dziesiątki komend slash. Oto kilka, na których polega większość serwerów:", "Command": "Komenda", "Example": "Przykład", "Support & feedback": "Wsparcie i opinie", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "Potrzebujesz polityki prywatności lub regulaminu do audytu bezpieczeństwa? Znajdziesz je w folderze /assets repozytorium i są aktualizowane przy każdym wydaniu.", "stash-tech-note": "Potrzebujesz poradników technicznych lub instrukcji self-hostingu? Sprawdź README na GitHubie po najświeższą dokumentację.", "card-tarkov-monitor-desc": "Automatyzuj postęp TarkovTracker, zapisuj czasy kolejek i steruj mapami Tarkov.dev w jednej aplikacji Windows.", "card-stash-desc": "Komendy slash do sprawdzania cen, zadań, kryjówki i timerów dostaw bezpośrednio z Tarkov.dev.", "Read more": "Czytaj więcej", "Invite now": "Zaproś teraz", "other-tools-page-description": "Odkryj aplikacje towarzyszące stworzone przez zespół Tarkov.dev, w tym TarkovMonitor i bota Discord Stash.", "other-tools-body": "<0>Tarkov.dev to coś więcej niż strona. Te narzędzia rozszerzają twoje rajdy, streamy i społeczności Discord, korzystając z tych samych otwartych danych. Zajrzyj do każdego narzędzia po screeny, instrukcje i linki wsparcia.", "Learn about TarkovMonitor": "Poznaj TarkovMonitor", "Meet the Stash bot": "Poznaj bota Stash", "The help command to view all available commands": "Komenda help pokazująca wszystkie dostępne polecenia", "View details about the bot": "Zobacz szczegóły bota", "Get a sorted ammo table for a certain ammo type": "Pobierz posortowaną tabelę amunicji dla wybranego typu", "Check barter details for an item": "Sprawdź szczegóły wymiany dla przedmiotu", "Get detailed information about a boss": "Uzyskaj szczegółowe informacje o bosie", "Get the latest game changes from tarkov-changes.com": "Otrzymaj najnowsze zmiany gry z tarkov-changes.com", "Check crafting details for an item": "Sprawdź szczegóły craftingu przedmiotu", "Set the game mode (regular, PVE) for bot responses": "Ustaw tryb gry (regular, PVE) dla odpowiedzi bota", "Check or report the location of the Goons": "Sprawdź lub zgłoś lokalizację Goons", "Get a Discord invite link for the bot to join it to another server": "Uzyskaj link zaproszenia Discord, by dodać bota na inny serwer", "Report an issue with the bot": "Zgłoś problem z botem", "Get price, craft, barter, etc. information about an item": "Uzyskaj informacje o cenie, craftingu, wymianie itp. dla przedmiotu", "Get a key's price and maps it is used on": "Poznaj cenę klucza i mapy, na których go użyjesz", "View a map and some general info about it": "Wyświetl mapę oraz podstawowe informacje", "Get the latest official patchnotes for EFT": "Odbierz najnowsze oficjalne patch notes EFT", "Get player profile information": "Pobierz informacje o profilu gracza", "Get a detailed output on the price of an item, its price tier, and more!": "Uzyskaj szczegółowy raport o cenie przedmiotu, jego tierze i więcej!", "Manage your customized hideout and trader progress": "Zarządzaj swoim spersonalizowanym postępem kryjówki i handlarzy", "Get detailed information about a quest": "Uzyskaj szczegółowe informacje o zadaniu", "Show or set alerts for trader restock timers": "Pokaż lub ustaw alerty dla timerów dostaw handlarzy", "Play a game of roulette to determine how you play your next raid": "Zagraj w ruletkę, aby określić, jak zagrasz kolejny rajd", "Get the game/server/website status of Escape from Tarkov": "Sprawdź status gry/serwera/strony Escape from Tarkov", "Get information about a in-game stim": "Uzyskaj informacje o stimie w grze", "Show the criteria for loot tiers": "Pokaż kryteria poziomów łupów", "Get the bot's uptime": "Sprawdź czas działania bota", "stash-support": "<0>Stash jest utrzymywany przez zespół Tarkov.dev. Masz błąd lub pomysł? Zgłoś issue na <1>GitHubie lub porozmawiaj z devami na <2>Discordzie Tarkov.dev. Jeśli synchronizujesz Tarkov.dev z danymi bota, dołącz zrzuty i kroki reprodukcji.", "Database": "Database", "Calculators": "Calculators", "Progression": "Progression", "Community": "Community", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/pt/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Sorrateiros. Os Cultistas espreitam pelas sombras em grupos de 3 a 5, esperando um jogador se aproximar. Eles silenciosamente se aproximam dos seus inimigos e os esfaqueiam usando facas comuns ou, no caso dos sacerdotes, a faca envenenada Cultista. Quando alvejados, os Cultistas revidarão com armas de fogo e granadas. Após atacarem um jovador com suas facas, eles podem optar por correr de volta para o mato e retornar às sombras.", "knight-bio": "", "knight-description": "O lider dos 'Goons'. Pode aparecer em diversos mapas.", "glukhar-bio": "Não existem informações confiáveis sobre seu passado porque todos os documentos foram perdidos ou são secretos, mas segundo boatos, ele possuia o posto de suboficial. Ele participou em operações de combate. Conhecia os fundamentos táticos e utilizou seu conhecimento ativamente dominando ou defendendo vários territórios.
    Toda a sua equipe também aparenta ter servido. Ainda que o seu bando seja simplesmente um grupo de bandidos lutando por recursos e influência em Tarkov. Ele tem conexões com comerciantes capazes de exportar bens da região de Norvinsk, que regularmente o enviam os trens que restaram funcionando para transportar carga.", "glukhar-description": "Glukhar e seus vários guardas são extremamente hostis. É bastante improvável ganhar dele lutando em áreas abertas. Corredores pequenos e cômodos fechados são preferíveis. Glukhar e seus guardas são bem precisos. Eles ficarão próximos um dos outros o tempo inteiro, e os guardas seguirão Glukhar para qualquer lugar que ele for.", "kaban-bio": "He once had a small legal business in Tarkov, but was not afraid to use criminal methods of money acquisition. After the general evacuation he remained in the city, and his gang has grown. ", "kaban-description": "His size allows him to fire various heavy machine guns without resting the gun, but at the same time Kaban cannot afford to be mobile and therefore either stays in position or moves slowly from point to point during combat. He has a large number of well-armed guards, some of whom are former military men who have organized a strong defense for him. The boss dwells in the area of the car repair shop on \"Streets of Tarkov\". The area is heavily defended, entrances are fortified with stationary machine guns and AGS, the paths are mined, and there are snipers on the roof of the car service center. Kaban uses a custom rig to store machine gun boxes, wears body armor under his clothes, and has unquestionable authority among his guards. Scavs nearby help the boss with defense and will engage in combat for Kaban.", "killa-bio": "", "killa-description": "O verdadeiro Giga Chad de Tarkov. Killa usa uma metralhadora leve ou outra arma automática para suprimir o inimigo enquanto espreita de cobertura em cobertura se aproximando do seu alvo para o avanço final. Durante o ataque ele se move em zigue-zague, usa granadas de fumaça e fragmentação, e incessantemente suprime seus inimigos com rajadas de tiros. Ele seguirá seu alvo por grandes distâncias fora da sua rota de patrulha, então lembre-se de correr bem longe para fugir caso ele esteja focado em você.", "kollontay-bio": "He is a former officer of the MVD (Ministry of Internal Affairs), during his service in law enforcement he had a reputation as a vile man, whose behavior was sometimes feared by his coworkers. During his work, he often resorted to his favorite method of interrogation - a rubber baton, as well as other non-statutory pressure on someone who was not to his liking. Thanks to his physical strength and bold temperament, after the events of the TerraGroup scandal, he formed a gang and began to do what he himself was recently supposed to combat - looting and banditry. However, even before the conflict, he often provided protection to local \"businessmen\". For example, his good relations with Kaban are well-known.", "kollontay-description": "Kollontay has a small number of guards, prefers to stay in one position and occasionally patrols his territory. If he feels he has the upper hand, he may switch to his police baton. He lives in the area around Klimov Shopping Mall and the Tarkov Academy of the Ministry of Internal Affairs.", "partisan-bio": "There are few reliable details about his past, but it's known that he once served in Afghanistan, where his radical methods of warfare took root. Referred to by some as 'Partizan', he became notorious for his expertise in setting traps and mines. His reputation for eliminating enemies often came down to catching them off guard, using their overconfidence against them. Partizan's knowledge of guerrilla tactics made him a dangerous adversary, able to turn any location—whether forest or building—into a deadly trap.
    Those who survive long enough to learn his ways may just find themselves in his good graces, but only if they're careful enough to see the traps before it's too late.", "partisan-description": "", "raider-bio": "", "raider-description": "Scav Raiders(ou somente 'Raiders') são Scavs avançados, consideravelmente mais fortes emais táticos do que os Scavs comuns. Eles portam armas bem mais fortes e usam munição de alto nível. Além disso, eles miram muito melhor e podem frequentemente matar jogadores bem equipados com poucas balas (ou simplesmente te dar 1 tiro nos olhos). Scav Raiderstambém patrulham em múltiplos grupos e são diferenciados pelos seus equipamentos, falas únicas, e agressividade em geral. Eles são inicialmente amigáveis com todos os outros Scavs (inclusive jogadores Scavs), mas se tornarão hostis se você chegar muito perto ou ignorar suas advertências verbais. Eles também ficarão hostis com todos os Scavs se qualquer Scav os incomodar.", "reshala-bio": "", "reshala-description": "Ele normalmente tentará ficar no fundo da luta e escondido da visão do jogador. Além disso, ele nunca usa armadura. Tenha cuidado sendo um jogador Scav se estiver nos níveis mais baixos de karma, porque o Reshala ou seus guardas poderão atirar em você sem provocações ou irão atirar em você se chegar perto do Reshala. Seus guardas são conhecidos por advertir jogadores Scavs com karma baixo antes de se tornarem hostis.", "rogue-bio": "", "rogue-description": "Os Rogues defendem a estação de tratamento de água e as áreas próximas em Lighthouse. O seu comportamento primário é patrulhar, mas eles frequentemente tomarão posições defensivas nas coberturas e usarão armas estacionárias. Eles focarão em qualquer jogadore que entrar na sua área, mas são um pouco mais calmos com PMCs da USEC e Scavs. Os Rogues também podem aparecer ao sul do mapa (na ilha do farol). Eles são extremamente perigosos pela sua saúde alta, precisão de laser e longa distância de ataque. Os Rogues também correrão para se abrigar e usar medicamentos se estiverem feridos.", "sanitar-bio": "Previamente doutor e cientista. Trabalhou para o TerraGroup. Ele encabeçou vários projetos no laboratório, incluindo o desenvolvimento de novas substâncias psicoativas. A sua área de pesquisa se estendeu da influência de várias condições no corpo para o desenvolvimento de neuroestimulantes. Além do laboratório do TerraGroup, ele tinha seu próprio escritório no Sanatório Azure Coast, onde ele também conduzia pesquisas, especialmente nas útlimas semanas antes da evacuação completa.
    Frequentemente saia para missões independentes nas áreas críticas junto às equipes médicas militares, e depois de começar a trabalhar para a corporação, visitou regularmente o escritório africano e em outros locais, supervisionando desenvolvimentos. Ele conquistou uma autoridade incontestada e respeito dentre seus colegas.", "sanitar-description": "Quando em combate ele lutará ao lado dos seus companheiros Scavs e guardas, mas pode frequentemente se destacar para se curar ou usar injetores. Ele tem muitos medicamentos, então um combate prolongado é possível.", "shturman-bio": "", "shturman-description": "Shturman e seus seguidores atacarão o jogador a longas distâncias, protegendo a área da serralheria em Woods. Eles preferem manter a distância já que não são preparados para combate de perto.", "tagilla-bio": "", "tagilla-description": "Ele é completamente insano e vai tentar te matar com uma marreta. Entretanto, se você está numa posição onde ele não consegue chegar, como nas vigas, ele usará sua arma secundária (normalmente uma escopeta) para te matar à distância. Ele está ativo imediatamente no início da raid. O chefe pode armar emboscadas, abrir fogo de supressão, e arrombar portas se necessário.", "zryachiy-bio": "Uma das figuras mais misteriosas de Tarkov. Não se sabe praticamente nada sobre seu passado, além de que ele tem treinamento de atirador de elite, e existem rumores de que ele esteve em zonas críticas no Oriente Médio e África várias vezes.
    Muito antes do conflito, ele se tornou o leal cão de guarda do Lightkeeper e ativamente \"estabeleceu\" conexões entre o Lightkeeper e todos com quem ele interagia. Ele é conhecido por ser amigável com os Rogues, e por ser o homem encapuzado que desenha simbolos misteriosos nos locais.
    Zryachiy é bem taciturno, porém aqueles que trabalham com ele normalmente o entendem sem palavras. Existem vários rumores sobre os seus olhos, alguns dizem que eles têm uma peculiaridade inata, alguns apontam para um certo colírio que o ajuda a melhorar sua visão no escuro, deixando seus olhos esbranquiçados. Fora a aparência, ele parece ter sido nomeado exatamente pela sua visão excelente, o que não é uma surpresa para um antigo atirador de elite militar.", "zryachiy-description": "O guarda cultista do Lightkeeper." } ================================================ FILE: src/translations/pt/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Interactive", "Landscape": "Paisagem", "View Fullscreen": "View Fullscreen", "Exit Fullscreen": "Exit Fullscreen", "Satellite": "Satellite", "Abstract": "Abstract", "Levels": "Levels", "1st Floor": "1st Floor", "2nd Floor": "2nd Floor", "3rd Floor": "3rd Floor", "4th Floor": "4th Floor", "5th Floor": "5th Floor", "Underground": "Subterrâneo", "Garage": "Garage", "Tunnels": "Tunnels", "Bunkers": "Bunkers", "Spawns": "Spawns", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "Sniper Scav", "Boss": "Boss", "Extracts": "Extracts", "Shared": "Shared", "Hazards": "Hazards", "Usable": "Usable", "Locks": "Locks", "Stationary Gun": "Stationary Gun", "Lever": "Lever", "Switch": "Switch", "Door": "Door", "Container": "Container", "Car Door or Trunk": "Car Door or Trunk", "Lock": "Lock", "Activated by": "Activated by", "Activates": "Activates", "Needs power": "Needs power", "Lootable Items": "Lootable Items", "Tasks": "Tarefas", "Item": "Item", "Objective": "Objetivo", "Misc": "Misc", "openworld-name": "Mundo Aberto", "openworld-description": "Essa é uma projeção de como seria o mapa completo de Tarkov. Esse mapa de mundo aberto provavelmente incluiria todas as localizações chave dos mapas existentes combinadas em um gigantesco mapa único.", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "Use TarkovMonitor to show your position", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/pt/properties.json ================================================ { "ambientVolume": "Ambience", "caliber": "Calibre", "damage": "Dano", "distanceModifier": "Distance", "distortion": "Distortion", "projectileCount": "Quantidade de projéteis", "penetrationPower": "Poder de penetração", "armorDamage": "Dano em armadura", "fragmentationChance": "Chance de fragmentação", "ammoType": "Tipo de munição", "class": "Classe", "material": "Material", "zones": "Zonas", "defaultPreset": "Predefinição padrão", "durability": "Durabilidade", "ergoPenalty": "Perda de ergonomia", "speedPenalty": "Perda de velocidade", "turnPenalty": "Perda de guinada", "headZones": "Zonas da cabeça", "capacity": "Capacidade", "grids": "Grids", "energy": "Energia", "hydration": "Hidratação", "units": "Unidades", "stimEffects": "Efeitos estimulantes", "blindnessProtection": "Proteção contra cegueira", "fuse": "Fusível", "maxExplosionDistance": "Distância máxima de explosão", "fragments": "Fragmentos", "deafening": "Ensurdecedor", "blocksHeadset": "Bloqueia headsets", "ricochetY": "Chance de ricochete", "uses": "Usos", "malfunctionChance": "Chance de pane", "ergonomics": "Ergonomia", "recoil": "Recuo", "loadModifier": "Modificador de carga", "ammoCheckModifier": "Modificador de verificação de munição", "useTime": "Tempo de uso", "cures": "Curas", "hitpoints": "Hitpoints", "maxHealPerUse": "Cura máxima por uso", "hpCostLightBleeding": "Custo de HP para hemorragia leve", "hpCostHeavyBleeding": "Custo de HP para hemorragia grave", "painkillerDuration": "Duração do analgésico", "energyImpact": "Impacto na energia", "hydrationImpact": "Impacto na hidratação", "recoilVertical": "Recuo vertical", "recoilHorizontal": "Recuo horizontal", "zoomLevels": "Níveis de zoom", "minLimbHealth": "Saúde mínima do membro", "maxLimbHealth": "Saúde máxima do membro", "effectiveDistance": "Distância efetiva", "fireModes": "Modos de disparo", "fireRate": "Cadência de disparo", "sightingRange": "Distância de visada", "defaultWidth": "Largura padrão", "defaultHeight": "Altura padrão", "defaultErgonomics": "Ergonomia padrão", "defaultRecoilVertical": "Recuo vertical padrão", "defaultRecoilHorizontal": "Recuo horizontal padrão", "defaultWeight": "Peso padrão", "recoilModifier": "Modificador de recuo", "weight": "Peso", "baseItem": "Item base", "categories": "Categorias", "type": "Tipo", "convergence": "Convergência", "cameraRecoil": "Recuo da Câmera", "recoilAngle": "Ângulo de Recuo", "recoilDispersion": "Dispersão do Recuo", "usedOnMaps": "Used on Maps" } ================================================ FILE: src/translations/pt/translation.json ================================================ { "No data": "Sem informações disponíveis", "Current Average Latency": "Latência média atual", "API Latency in milliseconds": "Latência da API em milissegundos", "No barters found for this item": "Nenhuma troca para esse item", "LL{{level}}": "LL{{level}}", "Barter at {{trader}}": "Trocar com {{trader}}", "Craft at {{station}}": "Craft at {{station}}", "Barter": "Troca", "Craft at {{stationName}} {{stationLevel}}": "Craft at {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Provides {{count}} for {{totalCost}}", "Provides {{count}} for {{totalCost}}_many": "Provides {{count}} for {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Provides {{count}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_many": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "Crafts {{count}} in {{duration}} for {{totalCost}}", "Reward": "Recompensa", "Cost": "Preço", "Cost ₽": "Preço ₽", "Estimated savings": "Economia estimada", "InstaProfit": "Lucro imediato", "N/A": "Indisponível", "Barter cost": "Custo da troca", "No barters available for selected filters": "Nenhuma troca disponível para os filtros escolhidos", "No barters available for selected filters but some were hidden by ": "Nenhuma troca disponível para os filtros escolhidos, mas algumas foram escondidas por ", "your settings": "suas configurações", "Some barters hidden by ": "Algumas trocas foram escondidas por ", "Can hold:": "Pode segurar:", "Can't hold:": "Não pode segurar:", "Level": "Nível", "Flea Market": "Mercado", "Flea banned": "Banido do Mercado", "Sell price": "Preço de venda", "Flea Market fee": "Taxa do Mercado", "Duration": "Duração", "Finishes": "Termina em", "Start now": "Começar agora", "Flea throughput/h": "Rendimento por hora do Mercado", "Estimated profit": "Lucro estimado", "Estimated profit/h": "Lucro estimado por hora", "No crafts available for selected filters": "Nenhum fabricável disponível para os filtros escolhidos", "No crafts available for selected filters but some were hidden by ": "Nenhum fabricável disponível para os filtros escolhidos, mas alguns foram escondidos por ", "Some crafts hidden by ": "Alguns fabricáveis foram escondidos por ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "All options already selected", "Clear selection": "Clear selection", "This item can't be sold on the Flea Market": "Esse item não pode ser vendido no Mercado", "Not scanned on the Flea Market": "Não escaneado no Mercado", "Flea market prices loading": "Carregando preços do Mercado", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>A plataforma é inteiramente de código aberto e focada em desenvolvedores. O código está disponível na íntegra no <1><0> GitHub.", "about-discord-p": "<0>Caso queira conversar, fazer perguntas ou pedir novas funcionalidades, nós temos um <1><0> Discord servidor.", "about-x-p": "<0>Follow us on <1><0> X for all the latest updates.", "About": "Sobre", "Contributors": "Contribuidores", "Massive thanks to all the people who help build and maintain this project!": "Enormes agradecimentos a todos que ajudam a construir e manter esse projeto!", "Made with ❤️ by:": "Feito com ❤️ por:", "Supporters": "Apoiadores", "about-support-ukraine-p": "<0>Encorajamos a todos que puderem que doem para apoiar as pessoas da Ucrânia usando o botão abaixo.", "about-support-collective-p": "<0>Se você gostaria de apoiar esse projeto, você pode fazer uma doação e/ou virar um patrocinador em <1>Open Collective.", "Item Data": "Informações sobre o item", "Fresh EFT data courtesy of": "Fresh EFT data courtesy of", "Additional data courtesy of": "Informações adicionais são uma cortesia de", "Resources": "Recursos", "Tarkov.dev API": "API Tarkov.dev", "{{bot}} integration": "Integração com {{bot}}", "Discord bot for your Discord": "Bot do Discord para o seu Discord", "External resources": "Recursos externos", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev é um fork do agora desligado tarkov-tools.com | Nossos mais sinceros agradecimentos a kokarn por todo o seu trabalho construindo Tarkov Tools e a comunidade em seu redor.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "Conteúdo e materiais do jogo são marcas registradas e direitos autorais da Battlestate Games e seus licenciadores. Todos os direitos reservados.", "version": "versão", "PMC & Scav Thorax HP": "HP do Tórax de PMC & Scav", "Reshala Thorax HP": "HP do Tórax de Reshala", "Raider Thorax HP": "HP do Tórax de Raider", "Shturman Thorax HP": "HP do Tórax de Shturman", "Cultist Priest Thorax HP": "HP do Tórax de Cultist Priest", "Cultist Warrior Thorax HP": "HP do Tórax de Cultist Warrior", "Damage": "Dano", "Class {{tier}}": "Classe {{tier}}", "Penetration": "Penetração", "Filter by caliber": "Filtrar por calibre", "This item can only be sold to trader": "This item can only be sold to trader", "per slot": "por espaço", "Value": "Preço", "Per slot": "Por espaço", "Sell to": "Vender para", "Found In Raid": "Encontrado em Incursão", "Search item...": "Procurar item...", "Search task...": "Buscar tarefa...", "Tasks": "Tarefas", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Items": "Itens", "No hideout modules requires this item": "Nenhum módulo de esconderijo requer esse item", "No unbuilt hideout modules for selected filters but some were hidden by ": "Sem módulos de esconderijo não-construídos para os filtros escolhidos, mas alguns foram escondidos por ", "Hideout Module": "Módulo de Esconderijo", "Item": "Item", "Amount": "Quantidade", "Player level: {{playerLevel}}": "Nível do jogador: {{playerLevel}}", "Reputation: {{reputation}}": "Reputation: {{reputation}}", "Commerce: {{commerce}}": "Commerce: {{commerce}}", "Cheapest Price": "Menor preço", "Task: {{taskName}}": "Tarefa: {{taskName}}", "Flea Market not available": "Flea Market not available", "No trader offers available": "Sem ofertas de comerciantes disponíveis", "Loading...": "Carregando...", "Ammo": "Munição", "Maps": "Mapas", "More": "Mais", "Traders": "Comerciantes", "Prapor": "Prapor", "Therapist": "Terapêuta", "Skier": "Skier", "Peacekeeper": "Peacekeeper", "Mechanic": "Mecânico", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "Chefes", "Barter profit": "Lucro de trocas", "Hideout profit": "Lucro de esconderijo", "Loot tiers": "Níveis de loot", "Hideout build costs": "Custos de construção de esconderijos", "Wipe length": "Duração da Wipe", "Bitcoin Farm Profit": "Lucro da fazenda de Bitcoin", "Achievements": "Achievements", "API": "API", "Donate": "Doar", "Become a patron": "Se tornar um patrão", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "has alternates", "On Task Completion": "Ao concluir a tarefa", "On Task Start": "Ao iniciar a tarefa", "Task": "Tarefa", "Required items": "Itens necessários", "Reward items": "Itens de recompensa", "Required tasks": "Tarefas necessárias", "loading": "carregando", "active": "ativo", "succeeded": "sucedido", "complete": "completo", "failed": "falhou", "Minimum level": "Nível mínimo", "Minimum trader level": "Nível mínimo de trocador", "Reputation rewards": "Recompensas de reputação", "Endgame": "Endgame", "Required for Kappa": "Required for Kappa", "Required for Lightkeeper": "Required for Lightkeeper", "No quests found": "Nenhuma missão encontrada", "Some tasks hidden by filter settings": "Algumas tarefas foram escondidas pelas configurações dos filtros", "open this page in another browser or window and connect using this id": "abra essa página em outro navegador ou janela e conecte-se usando essa ID", "ID for remote control": "ID para controle remoto", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Vá para Tarkov.dev em outro navegador e use esta ID para controlar essa página por lá", "Click to connect": "Clique para conectar", "Sell value": "Valor de venda", "Tarkov server status": "Estado do servidor Tarkov", "This item can't be sold to traders": "Esse item não pode ser vendido para os comerciantes", "Name": "Preço", "Sell to Flea": "Vender no Mercado", "Buy on Flea": "Comprar no Mercado", "Sell to Trader": "Vender para Trocador", "Trader buy": "Trocador compra", "Buyback ratio": "Taxa de compras de volta", "The percent recovered if you buy this item and sell it to the trader": "O percentual recuperado caso compre esse item no Mercado e venda para um comerciante", "Grid": "Grid", "Slots occupied": "Espaços ocupados", "Slots inside": "Espaços dentro", "Slots ratio": "Proporção dos espaços", "Price per slot": "Preço por espaço", "Armor class": "Classe da armadura", "Zones": "Zonas", "Max Durability": "Durabilidade máxima", "Effective Durability": "Durability efetiva", "Repairability": "Reparabilidade", "Weight (kg)": "Peso(kg)", "Stats": "Estatísticas", "Mov/Turn/Ergo": "Mov/Giro/Ergo", "Caliber": "Calibre", "Armor damage": "Dano da armadura", "Fragmentation chance": "Chance de fragmentação", "Blindness protection": "Proteção contra cegueira", "Hydration": "Hidratação", "Energy": "Energia", "Hydration Cost": "Custo de hidratação", "Energy Cost": "Custo de energia", "Hydration + Energy Value": "Valor de Hidratação + Energia", "Sound suppression": "Supressão de som", "Low": "Baixo", "None": "Nenhum", "Blocks earpiece": "Bloqueia fones de ouvido", "Yes": "Sim", "No": "Não", "Ergonomics": "Ergonômicos", "Cost per ergo": "Preço por ergo", "Recoil": "Recuo", "Distance": "Distance", "No items": "Sem itens", "Not built": "Não construído", "Locked": "Trancado", "Crafting": "Construindo", "Hideout Management": "Gerenciamento de Esconderijo", "Be the first!": "Seja o primeiro!", "Objective": "Objetivo", "No objectives": "Sem objetivos", "Players": "Jogadores", "By": "Por", "Restock in": "Estoque renova em", "Support Ukraine": "Apoie a Ucrânia", "Cost per unit": "Preço unitário", "About the tarkov.dev project": "Sobre o projeto tarkov.dev", "about-page-description": "Saiba mais sobre the-hideout e tarkov.dev. Um ecossitema livre, de código aberto, feito pela comunidade de Escape from Tarkov! Use nossas ferramentas para te auxiliar com o jogo, ou construa seus próprios projetos com a nossa API gratuita.", "Open source": "Código aberto", "Discussions & feedback": "Discussões e feedback", "Support": "Apoie", "about-support-more-p": "<0>Você também pode ajudar postando bugs, sugerindo ou implementando novas funcionalidades, melhorando mapas ou de qualquer outra maneira de melhorar o site na qual você possa pensar.", "about-api-p": "<0>Oferecemos uma API 100% gratuita e publicamente acessível para todas as suas necessidades de desenvolvimento relacionadas a Tarkov - <1>API.", "History": "História", "about-history-p": "<0>Esse projeto é um fork de <1>tarkov-tools.com. O criador original <3>@kokarn decidiu desligar o site. Com o espírito do código aberto, um grupo de desenvolvedores se uniu para reviver o site com o intuito de continuar a prover um bom website para a comunidade do Tarkov, e uma API para impulsionar futuros desenvolvimentos para criadores. Esse projeto tem o código 100% aberto e é feito para desenvolvedores. Nossa Organização no Github (<5>the-hideout) contém todos os repositórios que cuidam da API, desse website, do bot para comunidades do Discord, da infraestrutura do servidor, e muito mais! Nós somos apaixonados por código aberto e amamos pull requests que melhorem o nosso ecosistema para todos.", "Core Contributors": "Principais contribuidores", "about-core-contributors-p": "<0>Os principais contribuidores para esse projeto (organizados sem seguir uma ordem em específico) são:", "All Contributors": "Todos os contribuidores", "about-all-contributors-p": "<0>Muito obrigado a todos vocês que contribuiram para tornar esse projeto possível! ❤️", "Description": "Description", "Hidden": "Hidden", "Player %": "Player %", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "This page includes information on the achievements that can be earned.", "Ammo chart": "Gráfico de Munições", "ammo-page-description": "Esta página contém uma lista de todos os tipos de munição em Escape from Tarkov. Para filtrar a lista completa de cartuchos, clique no nome de um calibre.", "ammo-page-p": "<0>A fauna de Tarkov inclui uma gama diversa de munições.<1>Essa página contém uma lista de cada tipo de munição em Escape from Tarkov. Para filtrar a lista completa de munições disponíveis, clique no nome de um calibre.", "Total damage": "Dano total", "Use total damage of all projectiles in a round": "Use dano total de todos os projéteis em um round de disparo", "Ignore settings": "Ignorar configurações", "Shows all sources of items regardless of your settings": "Mostra todas as origens dos itens, independenteme de suas configurações", "Use barters for item sources": "Use barters for item sources", "Use crafts for item sources": "Use crafts for item sources", "Ammo Statistics Table": "Tabela de estatísticas de munição", "API Documentation": "Documentação da API", "api-docs-page-description": "A comunidade de Escape from Tarkov fez a API e sua docimentação. Saiba mais sobre a nossa API GraphQL para EFT, é de graça e simples de usar.", "api-about-p": "<0>A API é escrita em GraphQL e nós tentamos o nosso melhor para seguir especificações e não fazer mudanças gigantes. Para aprender sobre quais consultas você pode fazer e como o esquema é estruturado, visite o playground e clique na aba 'Docs' no lado direito. Quando estiver pronto pra tentar algumas consultas, você pode testá-las no playground. Para aprender sobre consultas de GraphQL em geral, a GraphQL Foundation possui recursos úteis.<1><0><0>Tarkov.dev GraphQL playground<1><0>Recursos da GraphQL Foundation<1>Quando estiver pronto para enviar consultas de API fora do playground, o endpoint é: <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Performance atual da API", "api-performance-p": "<0>Para métricas completas da API e performance, veja a nossa <1>página de status.", "FAQ": "FAQ", "Is it free?": "É de graça?", "Is it open source?": "É de código aberto?", "api-faq-open-source-p": "É claro! O código fonte da API pode ser encontrado no repositório no GitHub: <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "Têm limite de uso?", "api-faq-rate-limit-p": "We occasionally get hit with a lot of traffic from bad actors that requires implementing rate limits. Price data is updated every 5 minutes, so there's really no need to query faster than that. Use common sense, and you should be fine.", "What about caching?": "E quanto a caching?", "api-faq-caching-p": "Já que os nosso dados são atualizados a cada 5 minutos, nós também fazemos cache de todas as consultas GraphQL por 5 minutos. Isso ajuda a reduzir muito o trabalho nos nossos servidores, ao mesmo tempo que torna os seus requests bem mais rápidos!", "Where is the data from?": "De onde vem as informações?", "We source data from multiple places to build an API as complete as possible. We use data from:": "Nós usamos dados de várias fontes para construir a API mais completa possível. Nós usamos dados de:", "Our network of scanners": "Nossa rede de escaneadores", "Examples": "Exemplos", "example": "exemplo", "Contributed by": "Contribuição de", "API Users": "Usuários da API", "api-users-page-description": "Essa página contém uma lista de todos os usuários da API públic em Tarkov.dev e seus projetos.", "api-users-p": "<0>Quer fazer parte dessa página? Junte-se ao <1>Discord e nos conte sobre o que você fez!", "Barter Profits": "Lucro de trocas", "barters-page-description": "Essa página inclui informações sobre os diferentes itens que podem ser trocados com vendedores NPC, os preços das trocas e os lucro que pode ser feito ao vender os items.", "Shows all barters regardless of your settings": "Mostra todas as trocas independentemente das suas configurações", "Hide dogtags": "Esconder dogtags", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "O verdadeiro \"preço\" de trocas usando Dogtags é difícil de estimar, por isso você pode querer excluir trocas com dogtag", "Show all barters": "Mostrar todas as trocas", "All": "Todos", "Item filter": "Filtro de itens", "filter on item": "filtrar o item", "barters-page-p": "<0>Com exceção do Fence, todos os comerciantes no Escape from Tarkov oferecem trocas, ao invés de apenas vendas.<1>O jogador pode frequentemente trocar uma variedade de itens baratos por objetos mais valiosos, que podem ser utilizados ou vendidos para lucrar ou conseguir equipamentos melhores em níveis de lealdade mais baixos.<3>Lembre-se de procurar novamente pelas suas trocas favoritas após os resets, porque a maioria dessas trocas valiosas têm curtos limites de troca por estoque e normalmente acabam rápido.", "Num graphic cards": "Número de placas gráficas", "Hours": "Horas", "Bitcoin Farm Calculator": "Calculadora da fazenda de Bitcoin", "bitcoin-farm-calculator-page-description": "Essa página possui uma calculadora que te ajuda a determinar o preço de construir e manter uma fazenda de mineração de Bitcoin, baseado no número de GPUs, gasto com eletricidade e preço do bitcoin.", "Graphic cards count": "Contador de placas gráficas", "Use fuel cost: {{price}}/day": "Consumo de combustível: {{price}} por dia", "Use station build costs": "Usar preço de construção de estação", "Purchase cost": "Preço de compra", "Remaining days in wipe:": "Dias restantes no wipe:", "Time to produce 1 bitcoin": "Tempo pra produzir 1 bitcoin", "BTC/day": "BTC/dia", "Estimated profit/day": "Lucro estimado/dia", "Profitable after days": "Lucrativo após dias", "Total cost of graphic cards": "Custo total das placas gráficas", "Build costs": "Custo de produção", "GPU + build costs": "Custos de GPU + produção", "Remaining profit": "Lucro restante", "Map": "Mapa", "Spawn Location": "Local de aparição", "Chance": "Chance", "Count": "Quantidade", "Spawn chance": "Chance de aparição", "Chance that the boss spawns on a given map": "Chance de o chefe aparecer em um mapa", "Health": "Saúde", "Total boss health": "Saúde total do chefe", "Patrol": "Patrulha", "Rush": "Adentrar", "Stalker": "Perseguidor", "Hostile and accurate": "Hostil e preciso", "Patrol and highly armored": "Patrulha e altamente blindado", "Group patrol": "Patrulha em grupo", "Frequent healing and stim injections": "Cura frequente e injeção de estimulantes", "Sniper": "Sniper", "Batshit insane": "Doido de pedra", "Behavior": "Comportamento", "The boss's general AI behavior": "O comportamento geral da IA do chefe", "Wiki": "Wiki", "Boss Stats": "Status do chefe", "Special Boss Loot": "Loot especial de Chefe", "Spawn Locations": "Locais de Aparição", "boss-spawn-table-description": "<0>Map: The name of the map which the boss can spawn on<1>Spawn Location: The exact location on the given map which the boss can spawn<2>Chance: If the \"Spawn Chance\" is activated for the map, this is the estimated chance that the boss will spawn at a given location on that map", "Boss Escorts": "Escolta do Chefe", "This boss does not have any escorts": "Esse chefe não é escoltado", "boss-page-description": "Essa página possui informações sobre o chefe {{bossName}}, sua localização, loot e estratégias para o derrotá-lo.", "bosses-page-description": "Essa página possui informações sobre todos os chefes do jogo, suas localizações, loot, guardas e estratégias para derrotá-los.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Os chefes são inimigos mortais e temidos com equipamentos e traços distintos em Escape from Tarkov", "About Bosses": "Sobre Chefes", "bosses-page-p": "<0>Em Escape from Tarkov, há vários cheves que circulam pela área da Norvinsk sitiada.<1>Cada chefe tem comportamentos, características e táticas únicas. Os chefes em Tarkov são temidos por jogadores de todos os níveis e costumam ser ameaças maiores do que PMCs inimigos na região.<2>Contanto, grandes riscos trazem grandes recompensas. Vários chefes possuem itens de alto nível ou são alvos de eliminação em tarefas. Aprender os padrões, localizações e as roupas típicas de um chefe é normalmente a melhor forma de se preparar para lutar contra um chefe em Tarkov.", "Connect": "Conectar", "Connected to": "Conectado com", "id to control": "ID para controlar", "Remote Control": "Controle Remoto", "remote-control-page-description": "Essa página contém todas as ferramentas necessárias para controlar remotamente outra instância do site Tarkov.dev.", "View Map": "Ver mapa", "Go": "Ir", "View caliber": "Ver calibre", "Select...": "Selecione...", "Load tarkov.dev in another browser or window to control it from here": "Abra tarkov.dev em outro navegador ou em outra janela para controlá-lo daqui", "Hideout Crafts": "Fabricáveis de Esconderijo", "crafts-page-description": "Essa página possui informações sobre os diferentes itens que podem ser produzidos no esconderijo, seus materiais, recursos necessários, e os lucros na venda dos produtos criados.", "Shows all crafts regardless of your settings": "Mostra todos os fabricáveis, independentemente das suas configurações", "Average prices": "Média de preços", "Use average prices from the past 24 hours for profit calculations": "Use a média de preços das últimas 24 horas para cálculos de lucros", "Most profitable craft in each station": "Fabricável mais lucrativo em cada estação", "Best": "Melhor", "Flea Market banned items": "Flea Market banned items", "Empty fuel": "Sem combustível", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "Configura o custo de galões de combustível no preço mínimo de venda dos comerciantes, quando estiver usando galões não \"Encontrado em Raid\" para criar fabricáveis.", "crafts-page-p": "<0>Em Escape from Tarkov, os fabricáveis te permitem criar uma variedade de itens. Você pode fabricar itens usando uma variedade de módulos do esconderijo, incluindo o coletor de água, mesa de trabalho, estação de medicamentos, lavatório, e unidade de nutrição.<1>Os itens fabricados no esconderijo possuem a situação \"Encontrado em Raid\". A lista de todos esses fabricáveis é exibida acima. A habilidade Fabricação impacta no tempo para fabricar os itens.<2>Quando o ícone de um item tem uma borda azul, ele será utilizado como uma ferramenta auxiliar, e retornará ao seu inventário após a fabricação.", "Page not found": "Página não encontrada", "error-page-description": "Essa não é a página que você está procurando", "Sorry, that page doesn't exist!": "Desculpe, essa página não existe!", "Hideout": "Esconderijo", "hideout-page-description": "Essa página possui informações sobre as diferentes estações e módulos que podem ser construidos com materiais e recursos necessários para aprimorar o seu esconderijo.", "Show all stations & modules": "Mostrar todas as estações e módulos", "Show built": "Mostrar construídos", "Show already built stations": "Show already built stations", "Show locked": "Show locked", "Show unavailable stations": "Show unavailable stations", "Show all requirements": "Show all requirements", "Show trader and other station level requirements": "Show trader and other station level requirements", "Collected": "Coletado", "Item Tracker": "Rastreador de Item", "Only show Found in Raid": "Mostrar apenas os encontrados em Incursões", "Reset all tracking": "Reiniciar todos os rastreamentos", "Hide completed": "Esconder completados", "Hide tasks you've completed": "Esconder tarefas que você concluiu", "Hide dogtag barters": "Esconder trocas com dogtag", "Best price to sell for": "Melhor preço para vender", "Fee": "Taxa", "Profit": "Lucro", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "O último preço mais baixo observado para esse item no Mercado foi {{lastSeenPrice}}.\nPorém, devido ao cálculo das taxas, é melhor vender por {{bestPrice}}.", "Max price to sell for": "Maior preço para vender", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "Esse item ainda não foi vissto no Mercado.\nO preço mais lucrativo é {{bestPrice}}, você pode não conseguir vender nesse valor.\nO preço mais lucrativo é impactado pelo centro de inteligência e pelo nível da habilidade de gerenciamento do esconderijo.", "Likely sell price": "Preço de venda provável", "item-page-description": "Essa página possui informações sobre as características, usos e estratégias para {{itemName}}.", "Sell for": "Vender por", "Buy for": "Comprar por", "Flea price history": "Histórico de preços de Mercado", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "Diferença em comparação a ontem: {{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "Menor preço nas últimas 24 horas: {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Maior preço nas últimas 24 horas: {{high24hPrice}}", "Updated: {{val, relativetime}}": "Atualizado: {{val, relativetime}}", "Items contained in {{itemName}}": "Itens contidos em {{itemName}}", "Barters with {{itemName}}": "Trocas com {{itemName}}", "Crafts with {{itemName}}": "Fabricáveis com {{itemName}}", "Hideout modules needing {{itemName}}": "Módulos de esconderijo que precisam de {{itemName}}", "Shows all modules regardless of your settings": "Mostra todos os módulos, independentemente das suas configurações", "Quests requiring {{itemName}}": "Missões que requerem {{itemName}}", "Quests rewarding {{itemName}}": "Missões que dão {{itemName}} como recompensa", "Armors": "Armaduras", "armors-page-description": "Essa página possui uma tabela ordenável com informação nos diferentes tipos de armaduras disponíveis no jogo, incluindo seus preços, reparabilidade, classes de proteção e outras características.", "Class effective durability": "Durabilidade efetiva da classe", "Include rigs": "Incluir coletes", "Max price": "Preço máximo", "max price": "preço máximo", "armors-page-p": "<0>In the video game Escape from Tarkov, armor vests are worn to lessen bullet damage. Helmets are typically used in addition to them.", "Backpacks": "Mochilas", "backpacks-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de mochilas disponíveis no jogo, inluindo seus preços, tamanhos, capacidade e outras características.", "Net price per slot": "Preço líquido por espaço", "Show price per additional slot of storage gained from the container": "Mostrar preço por espaço de armazenamento adicional obtido pelo container", "backpacks-page-p": "<0>Backpacks in the Escape from Tarkov game are various-sized containers for carrying your hard-earned riches.", "Barter Items": "Trocar itens", "barter-items-page-p": "<0>This table of barter items from Escape from Tarkov will make it simple for you to determine how much each one is worth. It can be challenging to determine which products are valuable enough to take because there are over 150 barter items in the game, and flea market pricing can fluctuate suddenly. You may optimize your loot with the aid of this interactive table.", "bsg-category-description": "Descubra tudo que precisa saber sobre {{category}} em Escape from Tarkov.", "Containers": "Containeres", "containers-page-p": "<0>As their name implies, containers in Escape from Tarkov are items used to hold other things. Some of these items are used to clear up inventory space by acting as storage and taking up less inventory slots however some of them cannot be equipped on the character.", "Glasses": "Óculos", "glasses-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de óculos disponíveis no jogo, incluindo seus preços, classes de proteção e outras características.", "glasses-page-p": "<0>Eyewear in Escape from Tarkov can be used to decrease the number and quantity of raindrops on the players' screens as well as the length of flashbang effects.", "Grenades": "Granadas", "grenades-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de granadas disponíveis no jogo, incluindo seus preços, dano e outras características.", "grenades-page-p": "<0>There are only a handful distinct types of grenades that may be thrown or launched in Escape from Tarkov, and each one has a unique effect: flash, smokes, high explosive, and fragmentation.<1>Grenades are situational, but when utilized properly, they can have deadly results. Any advantage from high-tier equipment can be fully negated by a single well-thrown grenade, whether it completely blinds the adversary, kills them instantly, or forces them out of cover and into your gunfire.<3>Five factors to think about while using throwable grenades include the fuse time, explosion radius, fragment damage, fragment count, and even the weight of the grenade. With specific uses arising from each component.", "Guns": "Armas", "guns-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de armas disponíveis no jogo, incluindo seus preços, dano, precisão e outras características.", "guns-page-p": "<0>Your main tool for survival is a weapon. Almost all weapons are completely modular, allowing them to be customized for various scenarios. All of the weaponry used in Escape from Tarkov are listed on this page.", "Headsets": "Fones de ouvido", "headsets-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de fones de ouvido disponíveis no jogo, incluindo seus preços, disponibilidade e outras características.", "headsets-page-p": "<0>In Escape from Tarkov, headsets magnify low-frequency noises like footsteps while muzzling impulsive stimuli like gunshots. Different audio profiles are offered by the various models.", "Helmets": "Capacetes", "helmet-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de capacetes disponíveis no jogo, incluindo seus preços, classes de proteção e outras características.", "Show blocking headset": "Mostrar fones de ouvido de bloqueio", "Min armor class": "Classe de armadura mínima", "helmets-page-p": "<0>In Escape from Tarkov, headgear serves a variety of functions.<1>There are useful objects, vanity items, and safety headgear. Before entering combat, choosing a helmet that will protect different parts of the head becomes crucial.<3>The impact that different helmets will have on how much sound they suppress is another crucial factor to take into account. Escape from Tarkov's gameplay heavily relies on sound.<5>Modular helmets, which have an assortment of different components, are another aspect of Escape from Tarkov. These helmets may modify the number of segments they protect. Top, Nape, Ears, Eyes, and Jaws are the segments.", "items-page-description": "Essa página possui links para páginas com informações sobre diferentes categorias de itens, incluindo armaduras, armas, cabos de pistolas, caixas, capacetes, chaves, coletes, granadas, headsets, itens de troca, mantimentos, mochilas, peças de armas, supressores, óculos, e mais.", "Keys": "Chaves", "keys-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de chaves disponíveis no jogo, incluindo seus preços, raridade e outras características.", "keys-page-p": "<0>Maps, keys, key cards, and other useful objects are included in intelligence items. These will help you stay one step ahead of the competition—or at the very least, know where you are in Escape from Tarkov.<1>The remaining durability of keys and keycards with a limited number of uses is displayed in the bottom right corner of their icons and on their inspection screens.", "Mods": "Mods", "mods-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de peças de armas disponíveis no jogo, incluindo seus preços, compatibilidade, e outras características.", "mods-page-p": "<0>In Escape from Tarkov, the performance and functioning of a weapon are controlled by elaborate mechanisms organized into five categories:<1><0>Functional Mods<1>Muzzle devices (Functional Mods)<2>Sights (Functional Mods)<3>Gear Mods<4>Vital parts", "Pistol Grips": "Cabos de pistolas", "pistol-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos cabos de pistolas disponíveis no jogo, incluindo seus preços, ergonomia, compatibilidade e outras características.", "Filter by gun": "Filtrar por arma", "select a gun": "selecione uma arma", "pistol-grips-page-p": "<0>In Escape from Tarkov a pistol grips and stocks are vital parts of a weapon.<1>On this page you can sort them buy ergonomics improvement or their cost and see on which weapon they can be mounted.", "Provisions": "Mantimentos", "provisions-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de mantimentos disponíveis no jogo, inluindo sua hidratação, energia, menores preços com comerciantes ou com o mercado.", "Total energy cost": "Custo total de energia", "Include the cost of lost hydration in the cost of energy": "Incluir a perda de hidratação no gasto de energia", "provisions-page-p": "<0>In Escape from Tarkov, provisions are utilized to replenish energy and hydration.<1>Your Metabolism skill level will determine how effective they are.", "Rigs": "Coletes", "rigs-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de coletes disponíveis no jogo, inluindo seus preços, tamanhos interno e externo, peso, compressão e outras características.", "Armored rigs?": "Coletes com armadura?", "Min slots": "Espaço mínimo", "3-slot": "3-espaços", "4-slot": "4-espaços", "rigs-page-p": "<0>When it comes to carrying and storing ammunition and magazines during your excursions in Escape from Tarkov, chest rigs are crucial. Some even provide you with additional security.", "Suppressors": "Supressores", "suppressors-page-description": "Essa página possui uma tabela ordenável com informações sobre os diferentes tipos de supressores disponíveis no jogo, incluindo suas ergonomias, recuo e menor preço.", "suppressors-page-p": "<0>In Escape from Tarkov, a suppressor is a muzzle device (a functional mod) and can be installed on a weapon to muffle gunshot sound.<1>On this page you can sort them buy ergonomics penalty, recoil improvement or their cost and see on which weapon they can be directly mounted.", "Barters": "Trocas", "Marked": "Marcadas", "Wearables": "Vestíveis", "loot-tiers-page-description": "Aprenda sobre os diferentes tipos de loot disponíveis no jogo, seus valores, raridade, o que guardar e o que jogar fora.", "Ranking the most valuable items in the game": "Categorizando os itens mais valiosos do jogo", "Include Marked": "Incluir marcados", "Group by type": "Agrupar por tipo", "min value": "valor mínimo", "Only show markers for active tasks": "Only show markers for active tasks", "Map of {{mapName}}": "Map of {{mapName}}", "maps-page-description": "Obtenha as informações mais recentes sobre todos os mapas de Escape from Tarkov, incluindo pontos de extração e localização de loot. Descubra onde achar os melhores equipamentos e recursos do jogo", "maps-page-p": "<0>Existem 11 locais diferentes no mapa de Escape from Tarkov, dos quais 10 já foram disponibilizados de forma pública até o momento. Eventualmente todos os mapas serão conectados, porém atualmente todos eles estão separados entre si.", "Streets of Tarkov": "Ruas de Tarkov", "Ground Zero": "Ground Zero", "Customs": "Customizáveis", "Factory": "Fábrica", "Interchange": "Intercâmbio", "The Lab": "O laboratório", "Lighthouse": "Farol", "Reserve": "Reserva", "Shoreline": "Litoral", "Woods": "Floresta", "Openworld": "Mundo aberto", "Tarkov.dev {{bot}} integration": "Integração com o Tarkov.dev {{bot}}", "bot-page-description": "Essa página tem tudo que precisa para a integrar {{bot}} com Tarkov.dev.", "You can add command to your moobot to get price check in your twitch chat": "Você pode adicionar comandos para o seu moobot para fazer checagem de preços no seu chat da twitch", "Instructions": "Instruções", "Register at": "Registrar em", "using your twitch account": "usando sua conta da twitch", "Go to Custom commands": "Vá para comandos personalizados", "Set what you want the command to be. Common is \"p\" or \"price\"": "Defina o que você quer que o comando seja. Comum é \"p\" ou \"price\"", "Press the \"Create\" button": "Aperte o botão \"Create\"", "In response choose URL Fetch - Full (plain) response": "Em response escolha URL Fetch - Full (plain) response", "and after insert \"Command arguments\"": "e então insira \"Command arguments\"", "Now press \"Save\" button": "Agora aperte o botão \"Save\"", "Big thanks to": "Grandes agradecimentos para", "for feedback": "pelo feedback", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "Você pode adicionar comandos para o seu nightbot para checar preços no seu chat da twitch ou chat do canal do youtube", "using your twitch / youtube account": "usando sua conta da twitch / youtube", "Go to dashboard": "Vá para página inicial", "Click the \"Join Channel\" button": "Clique no botão \"Join Channel\"", "Make bot - moderator, just type /mod nightbot in your chat": "Crie o bot - moderador, basta digitar /mod nightbot em seu chat", "Go to custom commands": "Vá para comandos personalizados", "Press the \"Add command\" button": "Clicar no botão \"Add command\"", "Command: !p or anything you like": "Comando: !p ou qualquer coisa que você queira", "Message:": "Mensagem:", "Press \"Submit\"": "Aperte \"Submit\"", "Trader Levels": "Nível dos comerciantes", "Trader Reputation": "Reputação com Comerciantes", "Prerequisite Tasks": "Tarefas pré-requisitadas", "Start Requirements": "Exigências para começar", "Attributes": "Atributos", "Contains All": "Contém todos", "Contains Item in Category": "Contém Item da Categoria", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Possui o(s) efeito(s) {{effectNames, list}} em seu {{bodyParts, list(type: disjunction)}} por {{operator}} {{count}} segundos", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Possui o(s) efeito(s) {{effectNames, list}} em seu {{bodyParts, list(type: disjunction)}} por {{operator}} {{count}} segundos", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Possui o(s) efeito(s) {{effectNames, list}} em seu {{bodyParts, list(type: disjunction)}} por {{operator}} {{count}} segundos", "using extract: {{extractName}}": "usando a extração: {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extrair com os status(es): {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x any of", "Dogtag level": "Nível de Dogtag", "Max durability": "Durabilidade máxima", "Min durability": "Durabilidade mínima", "Kill": "Matar", "Shoot": "Atirar", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "Durante as horas: {{hourStart}}:00 a {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "À {{operator}} {{count}} metros de distância", "From distance: {{operator}} {{count}} meters_many": "À {{operator}} {{count}} metros de distância", "From distance: {{operator}} {{count}} meters_other": "À {{operator}} {{count}} metros de distância", "While inside: {{zoneList, list(type: disjunction)}}": "Enquanto dentro: {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Acertando: {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Usando arma:", "Using weapon mods:": "Usando mods de arma:", "While wearing:": "Enquanto vestindo:", "Not wearing:": "Não vestindo:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Enquanto tiver o(s) efeito(s) {{effectNames, list}} no(s) seu(s) {{bodyParts, list(type: disjunction)}} por {{operator}} {{count}} segundos", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Enquanto tiver o(s) efeito(s) {{effectNames, list}} no(s) seu(s) {{bodyParts, list(type: disjunction)}} port {{operator}} {{count}} segundos", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "Enquanto tiver o(s) efeito(s) {{effectNames, list}} no(s) seu(s) {{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Enquanto o alvo tiver o(s) efeito(s) {{effectNames, list}} no(s) seu(s) {{bodyParts, list(type: disjunction)}} por {{operator}} {{count}} segundos", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Enquanto o alvo tiver o(s) efeito(s) {{effectNames, list}} no(s) seu(s) {{bodyParts, list(type: disjunction)}} por {{operator}} {{count}} segundo(s)", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "Enquanto o alvo tiver o(s) efeito(s) {{effectNames, list}} no(s) seu(s) {{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "Obter nível {{level}} na habilidade {{skillName}}", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} reputação", "In area(s): {{areaList, list(type: disjunction)}}": "Na(s) área(s): {{areaList, list(type: disjunction)}}", "Use any of:": "Use qualquer um dos:", "Reach level {{playerLevel}}": "Reach level {{playerLevel}}", "optional": "opcional", "Trader Standing": "Reputação de trocador", "Skill Level": "Nível de habilidade", "Trader Offer Unlock": "Trocador oferece desbloqueio", "Trader Unlock": "Trocador desbloqueia", "Craft Unlock": "Craft Unlock", "task-page-description": "Essa página contém informações sobre objetivos, recompensas e estratégias para completar a tarefa {{questName}}. Veja dicas de como se preparar e obter sucesso em sua missão.", "TarkovTracker": "TarkovTracker", "Leads to": "Leva a", "(on failure)": "(ao falhar)", "Task Details": "Detalhes da tarefa", "Objectives": "Objetivos", "Fail On": "Falhar Ao", "Needed Keys": "Chaves necessárias", "Task Start": "Task Start", "Task Completion": "Conclusão da Tarefa", "Rewards": "Recompensas", "Task Failure": "Task Failure", "Can be restarted": "Can be restarted", "Cannot be restarted": "Cannot be restarted", "Penalties": "Penalties", "tasks-page-description": "Saiba tudo o que precisa sobre tarefas em Escape from Tarkov. Aprenda sobre os diferentes tipos de tarefas disponíveis no jogo, como completá-las e as recompensas que você pode obter.", "Hides completed tasks": "Esconder tarefas completas", "Hide locked": "Esconder bloqueadas", "Hides locked tasks": "Esconder tarefas bloqueadas", "Show all tasks": "Mostrar todas as tarefas", "Name filter": "Filtro de nome", "filter on task name": "filtrar por nome da tarefa", "quests-page-p": "<0>Os comerciantes em Escape from Tarkov tem um número de tarefas que você pode completar.<1>Por obter itens, eliminar alvos e realizar outras ações em raids, você pode aumentar sua posição com os comerciantes e ganhar itens valiosos.", "Settings": "Configurações", "settings-page-description": "Essa página contém configurações do usuário de Tarkov.dev.", "Language": "Língua", "General": "Geral", "Has flea": "Está no mercado", "Use TarkovTracker": "Usar TarkovTracker", "TarkovTracker API Token": "Token da API TarkovTracker", "API Token": "Token da API", "Stations": "Estações", "Skills": "Habilidades", "Dogtag Barters": "Trocas de Dogtag", "Exclude": "Excluir", "Minimum dogtag level": "Nível mínimo de dogtag", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Nível mínimo de dogtag para usar no cálculo de custo de trocas com dogtag", "The current estimated average player level is {{avgPlayerLevel}}": "O nível médio estimado dos jogadores atualmente é {{avgPlayerLevel}}", "Miscellaneous": "Diversos", "Hide remote control": "Esconder controle remoto", "start-page-description": "Confira todas as informações sobre itens, fabricáveis, mapas, trocas, níveis de loot, lucros no esconderijo, detalhes de comerciantes, uma API gratuita e muito mais em tarkov.dev! Um ecossistema com guias e ferramentas, gratuito, de código aberto e feito pela comunidade Escape from Tarkov.", "Load More": "Carregar mais", "Tools": "Ferramentas", "Ammo chart filter": "Filtro do gráfico de munições", "Traders barter profit": "Lucro dos comerciantes", "Hideout crafts profit": "Lucro dos fabricáveis de esconderijo", "Loot tiers ranking": "Ranking de níveis de loot", "Average wipe length": "Duração média de wipes", "Bitcoin farm profit": "Lucro da fazenda de Bitcoins", "Invite Discord bot": "Convidar bot do Discord", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.dev é um kit de ferramentas de código aberto para Escape from Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "Ela é planejada e mantida pela comunidade para te ajudar com as missões, trocas no mercado, e na sua evolução no jogo! A API também está disponível gratuitamente para você construir suas próprias ferramentas e serviços relacionados ao EFT.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "Você pode adicionar comandos ao seu bot de StreamElements para fazer checagem de preços no seu chat da twitch / canal no youtube", "Make bot - moderator, just type /mod streamelements in your chat": "Fazer bot - moderador, basta digitar /mod streamelements no seu chat", "Press the \"Add new command\" button": "Clicar no botão \"Add new command\"", "Press \"Activate Command\"": "Clicar em \"Activate Command\"", "Player level": "Nível de jogador", "Reputation": "Reputação", "Commerce": "Comércio", "Trader {{trader}}": "Comerciante {{trader}}", "trader-page-description": "Obtenha as informações mais recentes sobre o comerciante {{trader}} em Escape from Tarkov. Aprenda sobre os itens que ele vende em cada nível de lealdade (LL) e como maximizar o seu lucro.", "Items with the best cash back prices for leveling": "Itens com o melhor valor de revenda para ganhar níveis", "Spending": "Gastando", "Unlocks at Loyalty Level {{level}}": "Desbloqueia no nível {{level}} de lealdade", "Tasks given by {{traderName}}": "Tarefas dadas por {{traderName}}", "traders-page-description": "Descubra tudo o que você precisa saber sobre comerciantes em Escape from Tarkov. Aprenda sobre os diferentes comerciantes do jogo, suas localizações e os itens que eles vendem.", "About Traders": "Sobre Comerciantes", "traders-page-p": "<0>The backbones of trade in the destroyed, besieged Norvinsk. In Escape from Tarkov, each merchant specialized in a particular kind of products, such as medical supplies, weaponry, or military equipment. Although their prices are typically high, you get what you pay for.<1>More importantly, you can develop a reputation with each trader through Quests, which will enable you to receive better offers generally and reduce the commission they receive (an additional markup you pay on sales and purchases), among other benefits.<2>Additionally, traders provide other services like insurance and repairs (allowing you to recover your gear in case of death during a raid).", "Patch": "Patch", "Wipe start": "Início da Wipe", "Wipe end": "Fim da Wipe", "Ongoing wipe": "Wipe em atividade", "{{count}} days_one": "{{count}} dias", "{{count}} days_many": "{{count}} dias", "{{count}} days_other": "{{count}} dias", "{{count}} months_other": "{{count}} months", "{{count}} years_one": "{{count}} year", "Wipe Length": "Duração da Wipe", "wipe-length-description": "Veja informações atualizadas sobre a duração média das wipes em Escape from Tarkov. Saiba quanto tempo wipes normalmente duram, e prepare-se para a próxima.", "Average Wipe Length among last 6 wipes:": "Duração média das wipes considerando as últimas 6:", "Trader Ammo": "Trader Ammo", "Only show ammo available from traders on your settings": "Only show ammo available from traders on your settings", "Reset": "Reset", "Convert one currency to another": "Convert one currency to another", "Currency Converter": "Currency Converter", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "control-info-p": "<0>This page allows you to control the Tarkov.dev website using another browser. The typical use case is to have the Tarkov.dev website open in a browser on a second monitor while you play the game and this page open on your phone or another device so that you can navigate to different pages on the Tarkov.dev website without having to alt+tab out of the game. All you have to do is open the Tarkov.dev website in a browser where you want it to be displayed, click the \"Click to connect\" button in the lower left*, and then use the ID shown there on this page on the control device and click the Connect. Once connected, you can use this control page to open specific map or ammo pages in the controlled browser.<1>*It appears on the lower left by default but can be toggled to the lower right side of the screen. It can also be hidden by the \"Hide remote control\" option on the settings page.", "cookie-consent": "tarkov.dev uses cookies to enhance your experience. By continuing to use this site, you agree to the usage of cookies. Cookies are used to remember your settings and features that you enable.", "I understand": "I understand", "Other Options": "Other Options", "This task {{taskStatus}}": "This task {{taskStatus}}", "Slots per kg": "Slots per kg", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Bot do Discord Stash", "More Tools": "Mais ferramentas", "Companion app": "Aplicativo complementar", "Discord companion": "Companheiro do Discord", "Download latest release": "Baixar a versão mais recente", "View on GitHub": "Ver no GitHub", "Join the community": "Junte-se à comunidade", "Screenshot of TarkovMonitor showing timers and integrations": "Captura do TarkovMonitor mostrando cronômetros e integrações", "Visual timers, raid state, and integration health in TarkovMonitor.": "Cronômetros visuais, estado da incursão e saúde das integrações no TarkovMonitor.", "Main Features": "Principais recursos", "tarkov-monitor-page-description": "Aprenda a instalar o TarkovMonitor, conectá-lo ao TarkovTracker e usá-lo para controlar os mapas do Tarkov.dev.", "tarkov-monitor-summary": "O TarkovMonitor fornece alertas e cronômetros úteis para Escape From Tarkov para que você gerencie os raids sem interromper o jogo.", "tarkov-monitor-feature-audio": "Alertas sonoros para matchmaking, início do raid, temporizador de runthrough, recarga de scav e notificações do filtro de ar.", "tarkov-monitor-feature-map": "Abertura automática do mapa no Tarkov.dev com base na localização que você está entrando.", "tarkov-monitor-feature-screenshot": "Exibição opcional da posição ativada por captura de tela para compartilhar sua localização rapidamente.", "tarkov-monitor-feature-quests": "Atualizações automáticas de missões para o TarkovTracker quando são detectadas como concluídas.", "tarkov-monitor-feature-stats": "Estatísticas locais como lucro do mercado das pulgas, duração das filas e frequência dos mapas.", "tarkov-monitor-feature-timers": "Cronômetros visíveis do tempo de raid e do cooldown do scav para planejar a próxima partida.", "Download": "Baixar", "tarkov-monitor-download-1": "Baixe o TarkovMonitor.zip mais recente no GitHub.", "tarkov-monitor-download-2": "Extraia o arquivo em qualquer lugar do seu PC.", "tarkov-monitor-download-3": "Execute o TarkovMonitor.exe e mantenha-o aberto enquanto joga.", "Community support": "Suporte da comunidade", "tarkov-monitor-community": "Tem dúvidas ou quer conversar com outros usuários? Entre no servidor do Discord para dicas, suporte e discussões de recursos.", "Join the Discord": "Entrar no Discord", "Security": "Segurança", "tarkov-monitor-security": "TarkovMonitor não é trapaça. Ele apenas lê os logs de Escape From Tarkov armazenados no seu PC e nunca modifica o jogo ou injeta código.", "stash-page-description": "Convide o bot do Discord Stash, explore seus comandos e veja como ele pode ajudar sua comunidade.", "stash-hero": "O Stash leva todo o conjunto de dados do Tarkov.dev para o Discord para que sua comunidade confira preços, progresso de missões, temporizadores do esconderijo e muito mais sem sair do chat.", "Invite Stash": "Convidar Stash", "Report an issue": "Reportar um problema", "Highlights": "Destaques", "Item intelligence": "Inteligência de itens", "Instant prices with flea, trader, and craft context.": "Preços instantâneos com contexto de mercado, traders e fabricação.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Consultas de craft/troca reutilizam os dados de lucratividade do Tarkov.dev.", "Toggle PVE or PMC game modes to match your server rules.": "Alterne entre modos PVE ou PMC para combinar com as regras do seu servidor.", "Progress tracking": "Acompanhamento de progresso", "Quest command lists requirements, turn-ins, and rewards.": "O comando de missões lista requisitos, entregas e recompensas.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "O comando progress reflete as melhorias de esconderijo e traders salvas no TarkovTracker.", "Restock and status alerts keep everyone informed between raids.": "Alertas de reposição e status mantêm todos informados entre os raids.", "Community tools": "Ferramentas da comunidade", "Goons tracker for spotting the Rogue Boss trio.": "Rastreador dos Goons para localizar o trio de chefes Renegades.", "Roulette mini-game for fun raid modifiers.": "Mini game de roleta para modificadores divertidos de raid.", "Slash commands, autocomplete, and localized responses.": "Comandos slash, autocompletar e respostas localizadas.", "Frequently used commands": "Comandos mais usados", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "O Stash oferece dezenas de comandos slash. Estes são alguns dos mais usados pelos servidores:", "Command": "Comando", "Example": "Exemplo", "Support & feedback": "Suporte e feedback", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "Precisa da política de privacidade ou termos de uso para a revisão de segurança do servidor? Eles estão na pasta /assets do repositório e são atualizados a cada release.", "stash-tech-note": "Precisa de guias técnicos ou instruções de auto-hospedagem? Veja o README no GitHub para a documentação mais recente.", "card-tarkov-monitor-desc": "Automatize o progresso do TarkovTracker, capture tempos de fila e controle os mapas do Tarkov.dev com um único app Windows.", "card-stash-desc": "Comandos slash para checar preços, missões, progresso do esconderijo e timers de reposição diretamente do Tarkov.dev.", "Read more": "Saiba mais", "Invite now": "Convidar agora", "other-tools-page-description": "Descubra apps complementares feitas pela equipe Tarkov.dev, incluindo o TarkovMonitor e o bot Discord Stash.", "other-tools-body": "<0>Tarkov.dev é mais do que um site. Essas ferramentas ampliam seus raids, streams e comunidades do Discord usando o mesmo conjunto de dados open source. Explore cada ferramenta para ver capturas, guias e links de suporte.", "Learn about TarkovMonitor": "Conheça o TarkovMonitor", "Meet the Stash bot": "Conheça o bot Stash", "The help command to view all available commands": "O comando de ajuda para ver todos os comandos disponíveis", "View details about the bot": "Ver detalhes sobre o bot", "Get a sorted ammo table for a certain ammo type": "Obter uma tabela de munições ordenada para um certo tipo", "Check barter details for an item": "Checar detalhes de troca de um item", "Get detailed information about a boss": "Obter informações detalhadas sobre um chefe", "Get the latest game changes from tarkov-changes.com": "Receber as últimas mudanças do jogo do tarkov-changes.com", "Check crafting details for an item": "Ver detalhes de craft de um item", "Set the game mode (regular, PVE) for bot responses": "Definir o modo de jogo (regular ou PVE) para as respostas do bot", "Check or report the location of the Goons": "Checar ou reportar a localização dos Goons", "Get a Discord invite link for the bot to join it to another server": "Obter um link de convite do Discord para adicionar o bot a outro servidor", "Report an issue with the bot": "Reportar um problema com o bot", "Get price, craft, barter, etc. information about an item": "Obter informações de preço, craft, troca etc. de um item", "Get a key's price and maps it is used on": "Saber o preço de uma chave e os mapas onde ela é usada", "View a map and some general info about it": "Ver um mapa e algumas informações gerais", "Get the latest official patchnotes for EFT": "Receber as últimas notas oficiais de atualização de EFT", "Get player profile information": "Obter informações do perfil de um jogador", "Get a detailed output on the price of an item, its price tier, and more!": "Receber um relatório detalhado sobre o preço de um item, sua categoria e muito mais!", "Manage your customized hideout and trader progress": "Gerenciar seu progresso personalizado de esconderijo e traders", "Get detailed information about a quest": "Obter informações detalhadas sobre uma missão", "Show or set alerts for trader restock timers": "Mostrar ou definir alertas para os timers de reposição dos traders", "Play a game of roulette to determine how you play your next raid": "Jogar roleta para decidir como será o próximo raid", "Get the game/server/website status of Escape from Tarkov": "Obter o status do jogo/servidor/site de Escape from Tarkov", "Get information about a in-game stim": "Obter informações sobre um estimulante do jogo", "Show the criteria for loot tiers": "Mostrar os critérios dos níveis de loot", "Get the bot's uptime": "Ver o tempo de atividade do bot", "stash-support": "<0>O Stash é mantido pela equipe do Tarkov.dev. Bugs ou ideias? Abra um issue no <1>GitHub ou fale com os devs no <2>Discord Tarkov.dev. Se sincronizar Tarkov.dev e os dados do bot, inclua capturas e passos de reprodução.", "Database": "Database", "Calculators": "Calculators", "Progression": "Progression", "Community": "Community", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/remove_equal_key_value.py ================================================ # This script is used to remove the key value pairs that are equal so that the file can be imported in POEditor import json import os # Translations dir #translations_dir = '../public/translations' translations_dir = './' # List of languages languages = ['de', 'es', 'fr', 'it', 'ja', 'pl', 'pt', 'ru', 'zh'] # Output directory output_dir = 'poeditor' # Check if output directory exists and create it if not if not os.path.exists(output_dir): os.makedirs(output_dir) for en_file_name in os.listdir(os.path.join(translations_dir, 'en')): en_file_path = os.path.join(translations_dir, 'en', en_file_name) # Read JSON data from file with open(en_file_path, encoding='utf-8') as json_en_file: data_en = json.load(json_en_file) for lang in languages: lang_file_path = os.path.join(translations_dir, lang, en_file_name) # If the file doesn't exist in the language folder, copy it from 'en' folder if not os.path.exists(lang_file_path): #copyfile(en_file_path, lang_file_path) #print(f"File '{en_file_name}' copied to '{lang}' folder.") print(f"File '{en_file_name}' is not present in '{lang}' folder.") else: # Read JSON data from file with open(lang_file_path, encoding='utf-8') as json_lang_file: data = json.load(json_lang_file) new_data = {} # remove key where key == value for key in list(data.keys()): # but first check the en version if key in data_en: if data_en[key] == data[key]: # del data[key] continue else: new_data[key] = data[key] elif key == data[key]: # del data[key] continue else: new_data[key] = data[key] # Write the modified data to the output folder with language appended to the file name new_file = lang + '_' + en_file_name with open(os.path.join(output_dir, new_file), 'w', encoding='utf-8') as json_file: json.dump(new_data, json_file, ensure_ascii=False, indent=4) print(f"File '{en_file_name}' cleaned from English values and saved as '{new_file}'.") # Read the destination JSON file or create an empty dictionary all_file_name = 'all_' + lang + '.json' all_file_path = os.path.join(output_dir, all_file_name) if os.path.exists(all_file_path): with open(all_file_path, 'r', encoding='utf-8') as all_json_file: all_data = json.load(all_json_file) else: all_data = {} # Add all entries from the source to the destination all_data.update(new_data) # Write back the updated destination file with open(all_file_path, 'w', encoding='utf-8') as all_json_file: json.dump(all_data, all_json_file, ensure_ascii=False, indent=4) print(f"File '{all_file_name}' updated with '{new_file}'.") ================================================ FILE: src/translations/ru/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "Ловкие мальчишки. Культисты скрываются в тени группами по 3-5 человек, ожидая приближения игрока. Они бесшумно приближаются к врагам и наносят им удары либо обычными ножами, либо отравленным культистским ножом, если речь идет о жреце. Если по ним открывают огонь, культисты открывают ответный огонь, используя огнестрельное оружие и гранаты. После нападения на игрока с ножом они могут убежать в лес и вернуться в тень.", "knight-bio": "", "knight-description": "Лидер \"головорезов\". Может появляться на разных картах.", "glukhar-bio": "Достоверных сведений о его деятельности ранее нет, так как все документы были утеряны или засекречены, но по непроверенной информации имел звание старшины. Участвовал в боевых действиях. Знает основы тактики и активно использует эти знания при штурме или обороне территорий.
    Вся его команда, судя по всему, тоже бывшие военные. Хотя сейчас его банда де факто является просто бандитской группировкой, воюющей за ресурсы и влияние в Таркове. Имеет выходы на торговцев, способных вывозить товар с Норвинской области, которые регулярно присылают ему последние работающие составы для погрузки.", "glukhar-description": "Глухарь и его многочисленные охранники крайне враждебны. Очень маловероятно, что вы добьетесь успеха, сражаясь на открытых пространствах. Предпочтительнее небольшие коридоры и закрытые комнаты. Глухарь и его охранники очень меткие и они будут постоянно находиться рядом друг с другом. Охранники Глухаря будут следовать за ним, куда бы он ни пошел.", "kaban-bio": "Некогда имел небольшой легальный бизнес в Таркове, однако не гнушался применять криминальные методы добычи денег. После всеобщей эвакуации остался в городе, а его банда обросла еще большим количеством криминальных элементов.", "kaban-description": "Его габариты позволяют стрелять из различных тяжелых пулеметов с руки, но одновременно Кабан не может позволить себе быть мобильным и соответственно либо сидит на позиции, либо переходит медленно с точки на точку во время боя. Имеет большое количество хорошо вооруженной свиты, часть из которых – бывшие военные, организовавшие ему мощную оборону. Босс обитает в районе автосервиса на локации \"Улицы Таркова\". Территория охраняется свитой, входы укреплены стационарными пулеметами и АГС, подходы заминированы, а на крышах стоят дозорные снайпера. Кабан использует кастомную разгрузку, чтобы хранить коробы для пулемета, носит бронежилет под одеждой, обладает непререкаемым авторитетом для своей свиты. Дикие боты, находящиеся неподалеку, помогают боссу с обороной и будут вступать в бой за Кабана.", "killa-bio": "", "killa-description": "Настоящий гига-чад из Таркова. Килла использует легкий пулемет или другое автоматическое оружие для подавления противника, скрываясь от укрытия к укрытию, приближаясь к цели для последнего рывка. Во время штурма он движется зигзагообразно, использует дымовые и осколочные гранаты и неустанно подавляет врагов автоматическим огнем. Он будет преследовать свою цель на большом расстоянии от маршрута патрулирования, поэтому убегайте от него очень далеко, если он вас засек.", "kollontay-bio": "Он — бывший сотрудник МВД, во время службы в органах имел репутацию грязного на руку сотрудника, выходок которого порой боялись его сослуживцы. Во время работы он часто прибегал к своему излюбленному методу допроса с помощью резиновой дубинки, а также иного неуставного давления на того, кто был ему не по нраву. Имея крупные габариты и дерзкий нрав, после событий со скандалом в TerraGroup, он сколотил банду и занялся тем, с чем сам недавно должен был бороться — мародерством и бандитизмом. Впрочем, и до этого он часто крышевал местных «бизнесменов», например, известно об его хороших отношениях с Кабаном.", "kollontay-description": "Коллонтай имеет небольшое количество свиты, предпочитает находиться на позиции и изредка патрулирует свою территорию. Если он чувствует свое преимущество, то может перейти на добивание дубинкой. Обитает в районе Торгового Дома Климова и Тарковской академии МВД.", "partisan-bio": "О его прошлом мало достоверной информации, но известно, что он служил в Афганистане, где и выработал свои радикальные методы ведения войны. Известный некоторым как \"Партизан\", он прославился своим мастерством в установке ловушек и мин. Его репутация устраняющего врагов часто сводилась к тому, что он заставлял их терять бдительность, обращая их излишнюю уверенность против них самих. Знания Партизана в области партизанской тактики делают его опасным противником, способным превратить любое место — будь то лес или здание — в смертельную ловушку.
    Те, кто выживет достаточно долго, чтобы изучить его методы, могут заслужить его благосклонность, но только если будут достаточно осторожны, чтобы замечать ловушки, прежде чем станет слишком поздно.", "partisan-description": "", "raider-bio": "", "raider-description": "Дикие-рейдеры (также известные как просто \"рейдеры\") - это усовершенствованные дикие, которые значительно сильнее и тактичнее ваших обычных диких. Они носят гораздо более опасное оружие и используют боеприпасы более высокого уровня. Кроме того, они гораздо лучше целятся и часто могут завалить хорошо подготовленных игроков, получив всего несколько пуль (или просто попав вам в голову). Дикие-рейдеры также патрулируют несколькими группами, и их обычно можно отличить по уникальной экипировке и общей агрессивности. Поначалу дикие-рейдеры дружелюбно относятся ко всем другим диким (включая диких-игроков), но они станут враждебными, если вы подойдете слишком близко и проигнорируете их устные предупреждения. Они также станут враждебными ко всем диким, если какой-нибудь дикий разозлит их.", "reshala-bio": "", "reshala-description": "Обычно он старается держаться в тылу и быть скрытым от глаз игрока. Кроме того, он никогда не носит броню. Будьте осторожны как игрок, так как при низком уровне кармы Решала или его охранники могут выстрелить в вас без провокации или застрелить вас, если вы подойдете к Решале слишком близко. Известно, что его охранники иногда предупреждают игроков-скавенов с низкой кармой, прежде чем начать враждебные действия.", "rogue-bio": "", "rogue-description": "Отступники защищают водоочистную станцию и прилегающие территории на Маяке. Их основное поведение - патрулирование, но они часто занимают оборонительные позиции на крышах и используют установленное оружие. Они нападают на всех игроков, которые заходят на их территорию, но немного снисходительнее относятся к ЧВК USEC и Диким. Отступники также могут появляться на южном маяке (остров). Роуги чрезвычайно опасны из-за высокой точности лазерного луча и большого расстояния прицеливания. Кроме того, при ранении они будут бежать за укрытие и использовать медикаменты.", "sanitar-bio": "Некогда бывший врач и ученый. Работал на TerraGroup. Вел несколько проектов в лаборатории, в том числе по разработке новых психоактивных веществ. Область интересов распространялась от влияния на организм различных условий до нейростимуляторов. Помимо лаборатории TerraGroup имел свой кабинет в Санатории «Лазурный Берег», где также занимался исследованиями, особенно в последние недели перед всеобщей эвакуацией.
    Часто бывал в командировках в горячих точках вместе с медицинской службой, а после начала работы на корпорацию регулярно посещал африканский и другие офисы, курируя разработки. В команде заслужил непререкаемый авторитет и уважение среди коллег.", "sanitar-description": "В бою он будет сражаться вместе со своими товарищами и охранниками, но может часто отрываться, чтобы подлечиться или сделать себе инъекцию. У него много медикаментов, поэтому возможен длительный бой.", "shturman-bio": "", "shturman-description": "Штурман и его последователи будут сражаться с игроком на дальнем расстоянии, защищая лесопилку в лесу. Они предпочитают держаться на расстоянии, так как не приспособлены для ближнего боя.", "tagilla-bio": "", "tagilla-description": "Он безумен и будет пытаться забить вас. Однако если вы находитесь в таком месте, куда он не может добраться, например, на стропилах, он использует свое вторичное оружие (обычно дробовик), чтобы убить вас с расстояния. Он активен сразу в начале рейда. При необходимости босс может устраивать засады, открывать огонь на подавление и прорываться.", "zryachiy-bio": "Одна из самых таинственных личностей Таркова. О прошлом практически ничего неизвестно, кроме того, что он имеет снайперскую подготовку и по отдаленным слухам не раз бывал в горячих точках на Ближнем Востоке и в Африке.
    Задолго до событий стал верным цепным псом Смотрителя Маяка и активно налаживал связи Смотрителя со всеми, с кем он взаимодействовал. Известно его лояльное отношение к группе отступников, а также к людям в капюшонах, которые рисуют различные символы на локациях.
    Зрячий очень немногословен, хотя все, кто с ним работает, обычно понимают его без слов. Ходит много слухов относительно его зрачков, кто-то говорит, что это врожденная особенность, кто-то указывает на какие-то капли для глаз, позволяющие расширить возможности зрения в темное время суток и с таким эффектом белизны. Тем не менее прозвище, судя по всему, он получил как раз за отличное зрение, что не удивительно для бывшего военного снайпера.", "zryachiy-description": "Культист-охранник смотрителя маяка." } ================================================ FILE: src/translations/ru/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "Интерактивная", "Landscape": "Ландшафтная", "View Fullscreen": "Просмотр в полноэкранном режиме", "Exit Fullscreen": "Выйти из полноэкранного режима", "Satellite": "Спутниковая", "Abstract": "Абстрактная", "Levels": "Уровни", "1st Floor": "1-й этаж", "2nd Floor": "2-й этаж", "3rd Floor": "3-й этаж", "4th Floor": "4-й этаж", "5th Floor": "5-й этаж", "Underground": "Подземный", "Garage": "Гараж", "Tunnels": "Туннели", "Bunkers": "Бункеры", "Spawns": "Спавны", "PMC": "ЧВК", "Scav": "Дикий", "Sniper Scav": "Дикий Снайпер", "Boss": "Босс", "Extracts": "Выходы", "Shared": "Общие", "Hazards": "Опасности", "Usable": "Используемые", "Locks": "Замки", "Stationary Gun": "Стационарное орудие", "Lever": "Рычаг", "Switch": "Выключатель", "Door": "Дверь", "Container": "Контейнер", "Car Door or Trunk": "Дверь или багажник автомобиля", "Lock": "Замок", "Activated by": "Активировано через", "Activates": "Активирует", "Needs power": "Требуется электропитание", "Lootable Items": "Лутабельные предметы", "Tasks": "Задания", "Item": "Предмет", "Objective": "Цель", "Misc": "Разное", "openworld-name": "Открытый мир", "openworld-description": "Это иллюстрация того, какой будет полная карта Таркова. Эта карта открытого мира, вероятно, будет включать все ключевые локации из существующих карт, объединенные в огромную единую карту.", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "Transit", "Task, item or container...": "Task, item or container...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Supports multisearch (e.g. 'labs, ledx, bitcoin')", "Only show markers for active tasks": "Only show markers for active tasks", "Don't collapse layers control": "Don't collapse layers control", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "Use TarkovMonitor to show your position", "Required item": "Required item", "BTR Stop": "BTR Stop", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/ru/properties.json ================================================ { "ambientVolume": "Окружающая среда", "caliber": "Калибр", "damage": "Урон", "distanceModifier": "Расстояние", "distortion": "Искажение", "projectileCount": "Количество снарядов", "penetrationPower": "Пробивная способность", "armorDamage": "Урон по броне", "fragmentationChance": "Шанс осколочного поражения", "ammoType": "Тип боеприпаса", "class": "Класс", "material": "Материал", "zones": "Зоны", "defaultPreset": "Сборка по умолчанию", "durability": "Прочность", "ergoPenalty": "Штраф на эргономику", "speedPenalty": "Штраф на скорость", "turnPenalty": "Штраф на поворот", "headZones": "Зоны головы", "capacity": "Вместимость", "grids": "Сетка", "energy": "Энергия", "hydration": "Гидрация", "units": "Единицы", "stimEffects": "Стим-эффекты", "blindnessProtection": "Защита от слепоты", "fuse": "Взрыватель", "maxExplosionDistance": "Максимальное расстояние взрыва", "fragments": "Осколки", "deafening": "Оглушающий", "blocksHeadset": "Блокирует гарнитуру", "ricochetY": "Шанс рикошета", "uses": "Использования", "malfunctionChance": "Возможность неисправности", "ergonomics": "Эргономика", "recoil": "Отдача", "loadModifier": "Модификатор зарядки", "ammoCheckModifier": "Модификатор проверки патронов", "useTime": "Время использования", "cures": "Лечение", "hitpoints": "Хитпоинты", "maxHealPerUse": "Макс. исцеление за использование", "hpCostLightBleeding": "Стоимость HP при легком кровотечении", "hpCostHeavyBleeding": "Стоимость HP при сильном кровотечении", "painkillerDuration": "Длительность обезболивания", "energyImpact": "Влияние на энергию", "hydrationImpact": "Влияние на гидрацию", "recoilVertical": "Вертикальная отдача", "recoilHorizontal": "Горизонтальная отдача", "zoomLevels": "Уровни увеличения", "minLimbHealth": "Мин. здоровье конечности", "maxLimbHealth": "Макс. здоровье конечности", "effectiveDistance": "Эффективная дистанция", "fireModes": "Режимы огня", "fireRate": "Скорострельность", "sightingRange": "Прицельная дальность", "defaultWidth": "Ширина по умолчанию", "defaultHeight": "Высота по умолчанию", "defaultErgonomics": "Эргономика по умолчанию", "defaultRecoilVertical": "Вертикальная отдача по умолчанию", "defaultRecoilHorizontal": "Горизонтальная отдача по умолчанию", "defaultWeight": "Вес по умолчанию", "recoilModifier": "Модификатор отдачи", "weight": "Вес", "baseItem": "Базовый предмет", "categories": "Категории", "type": "Тип", "convergence": "Конвергенция", "cameraRecoil": "Отдача камеры", "recoilAngle": "Угол отдачи", "recoilDispersion": "Рассеивание отдачи", "usedOnMaps": "Используется на картах" } ================================================ FILE: src/translations/ru/translation.json ================================================ { "No data": "Нет данных", "Current Average Latency": "Текущая средняя задержка", "API Latency in milliseconds": "Задержка API в миллисекундах", "No barters found for this item": "Для этого предмета не найдено бартеров", "LL{{level}}": "{{level}}УЛ", "Barter at {{trader}}": "Бартер у {{trader}}", "Craft at {{station}}": "Крафтится на {{station}}", "Barter": "Бартер", "Craft at {{stationName}} {{stationLevel}}": "Крафтиться на {{stationName}} {{stationLevel}}", "Provides {{count}} for {{totalCost}}_one": "Дает {{count}} за {{totalCost}}", "Provides {{count}} for {{totalCost}}_few": "Дает {{count}} за {{totalCost}}", "Provides {{count}} for {{totalCost}}_many": "Дает {{count}} за {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "Дает {{count}} за {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "Крафтит {{count}} за {{duration}} за {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_few": "Крафтит {{count}} за {{duration}} за {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_many": "Крафтит {{count}} за {{duration}} за {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "Крафтит {{count}} за {{duration}} за {{totalCost}}", "Reward": "Награда", "Cost": "Стоимость", "Cost ₽": "Стоимость ₽", "Estimated savings": "Расчетная экономия", "InstaProfit": "Мгнов. Профит", "N/A": "Н/Д", "Barter cost": "Стоимость бартера", "No barters available for selected filters": "Нет доступных бартеров с выбранными фильтрами", "No barters available for selected filters but some were hidden by ": "Нет доступных бартеров с выбранными фильтрами, но некоторые были скрыты ", "your settings": "вашими настройками", "Some barters hidden by ": "Некоторые бартеры скрыты ", "Can hold:": "Может вмещать:", "Can't hold:": "Не может вмещать:", "Level": "Уровень", "Flea Market": "Барахолка", "Flea banned": "Запрещен на барахолке", "Sell price": "Цена продажи", "Flea Market fee": "Комиссия барахолки", "Duration": "Длительность", "Finishes": "Завершится", "Start now": "Начать сейчас", "Flea throughput/h": "Оборот барахолки/ч", "Estimated profit": "Расчетная прибыль", "Estimated profit/h": "Расчетная прибыль/ч", "No crafts available for selected filters": "Нет доступных крафтов с выбранными фильтрами", "No crafts available for selected filters but some were hidden by ": "Нет доступных крафтов с выбранными фильтрами, но некоторые были скрыты ", "Some crafts hidden by ": "Некоторые крафты скрыты ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "Все опции уже выбраны", "Clear selection": "Очистить выбор", "This item can't be sold on the Flea Market": "Этот предмет нельзя продать на Барахолке", "Not scanned on the Flea Market": "Не отсканировано на барахолке", "Flea market prices loading": "Загрузка цен барахолки", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>Вся платформа имеет открытый исходный код и ориентирована на разработчиков. Весь код доступен на <1><0> GitHub.", "about-discord-p": "<0>Если вы хотите пообщаться, задать вопросы или запросить функции, у нас есть <1><0> Discord сервер.", "about-x-p": "<0>Читайте наш <1><0> X для всех последних обновлений.", "About": "О сайте", "Contributors": "Контрибьюторы", "Massive thanks to all the people who help build and maintain this project!": "Огромное спасибо всем людям, которые помогают создавать и поддерживать этот проект!", "Made with ❤️ by:": "Сделано с ❤️ командой:", "Supporters": "Поддерживающие", "about-support-ukraine-p": "<0>Мы призываем всех, кто может сделать пожертвование, чтобы поддержать людей с Украины, используя кнопку ниже.", "about-support-collective-p": "<0>Если вы также хотите поддержать этот проект, вы можете сделать пожертвование и/или стать спонсором <1>Open Collective.", "Item Data": "Данные предметов", "Fresh EFT data courtesy of": "Свежие данные EFT любезно предоставлены", "Additional data courtesy of": "Дополнительные данные любезно предоставлены", "Resources": "Ресурсы", "Tarkov.dev API": "Tarkov.dev API", "{{bot}} integration": "Интеграция {{bot}}", "Discord bot for your Discord": "Discord бот для вашего Discord", "External resources": "Внешние ресурсы", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev является форком уже закрытого tarkov-tools.com | Большое спасибо kokarn за всю его работу по созданию Tarkov Tools и сообщества вокруг него.", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "Игровой контент и материалы являются торговыми марками и авторскими правами Battlestate Games и ее лицензиаров. Все права защищены.", "version": "версия", "PMC & Scav Thorax HP": "ХП в груди у ЧВК и Дикого", "Reshala Thorax HP": "ХП в груди у Решалы", "Raider Thorax HP": "ХП в груди у Рейдера", "Shturman Thorax HP": "ХП в груди у Штурмана", "Cultist Priest Thorax HP": "ХП в груди у Жреца", "Cultist Warrior Thorax HP": "ХП в груди у Культиста-воина", "Damage": "Урон", "Class {{tier}}": "Класс {{tier}}", "Penetration": "Пробивание", "Filter by caliber": "Фильтр по калибру", "This item can only be sold to trader": "Этот предмет можно продать только торговцу", "per slot": "за слот", "Value": "Цена", "Per slot": "За слот", "Sell to": "Продать", "Found In Raid": "Найдено в Рейде", "Search item...": "Поиск предмета...", "Search task...": "Поиск задания...", "Tasks": "Задания", "Task, item or container...": "Задание, предмет или контейнер...", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "Поддерживает множественный поиск (e.g. 'лаборатория, ledx, биткоин')", "Items": "Предметы", "No hideout modules requires this item": "Ни один модуль убежища не требует этого предмета", "No unbuilt hideout modules for selected filters but some were hidden by ": "Нет не построенных модулей убежища для выбранных фильтров, но некоторые были скрыты ", "Hideout Module": "Модуль убежища", "Item": "Предмет", "Amount": "Количество", "Player level: {{playerLevel}}": "Уровень игрока: {{playerLevel}}", "Reputation: {{reputation}}": "Отношение: {{reputation}}", "Commerce: {{commerce}}": "Оборот: {{commerce}}", "Cheapest Price": "Наименьшая цена", "Task: {{taskName}}": "Задание: {{taskName}}", "Flea Market not available": "Барахолка недоступна", "No trader offers available": "Нет предложений от торговцев", "Loading...": "Загрузка...", "Ammo": "Патроны", "Maps": "Карты", "More": "Ещё", "Traders": "Торговцы", "Prapor": "Прапор", "Therapist": "Терапевт", "Skier": "Лыжник", "Peacekeeper": "Миротворец", "Mechanic": "Механик", "Ragman": "Барахольщик", "Jaeger": "Егерь", "Bosses": "Боссы", "Barter profit": "Прибыль бартера", "Hideout profit": "Прибыль убежища", "Loot tiers": "Рейтинг лута", "Hideout build costs": "Стоимость улучшения убежища", "Wipe length": "Длина вайпа", "Bitcoin Farm Profit": "Прибыль биткоин фермы", "Achievements": "Достижения", "API": "API", "Donate": "Пожертвовать", "Become a patron": "Стать патроном", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "имеет альтернативы", "On Task Completion": "Награда за задание", "On Task Start": "Стартовая экипировка", "Task": "Задание", "Required items": "Требуемые предметы", "Reward items": "Награда", "Required tasks": "Требуемые задания", "loading": "загружается", "active": "активно", "succeeded": "пройдено", "complete": "завершено", "failed": "провалено", "Minimum level": "Минимальный уровень", "Minimum trader level": "Минимальный уровень торговца", "Reputation rewards": "Награда репутации", "Endgame": "Endgame", "Required for Kappa": "Требуется для Каппы", "Required for Lightkeeper": "Требуется для Смотрителя мяка", "No quests found": "Задания не найдены", "Some tasks hidden by filter settings": "Некоторые задания скрыты настройками фильтра", "open this page in another browser or window and connect using this id": "откройте эту страницу в другом браузере или окне и подключитесь, используя этот ID", "ID for remote control": "ID для удаленного управления", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "Перейдите на сайт Tarkov.dev через другой браузер и введите этот ID, чтобы управлять этой страницей оттуда", "Click to connect": "Нажмите для подключения", "Sell value": "Цена продажи", "Tarkov server status": "Статус серверов Таркова", "This item can't be sold to traders": "Этот предмет нельзя продать торговцам", "Name": "Название", "Sell to Flea": "Продать на барахолке", "Buy on Flea": "Купить на барахолке", "Sell to Trader": "Продать торговцу", "Trader buy": "Купить у торговца", "Buyback ratio": "Коэффициент выкупа", "The percent recovered if you buy this item and sell it to the trader": "Возмещаемый процент, если вы купите этот товар и продадите торговцу", "Grid": "Сетка", "Slots occupied": "Занимаемые слоты", "Slots inside": "Внутренние слоты", "Slots ratio": "Соотношение слотов", "Price per slot": "Цена за слот", "Armor class": "Класс брони", "Zones": "Зоны", "Max Durability": "Максимальная прочность", "Effective Durability": "Эффективная прочность", "Repairability": "Ремонтопригодность", "Weight (kg)": "Вес (кг)", "Stats": "Статистика", "Mov/Turn/Ergo": "Движение/Поворот/Эрго", "Caliber": "Калибр", "Armor damage": "Урон брони", "Fragmentation chance": "Шанс фрагментации", "Blindness protection": "Защита от слепоты", "Hydration": "Гидрация", "Energy": "Энергия", "Hydration Cost": "Стоимость Гидрации", "Energy Cost": "Стоимость Энергии", "Hydration + Energy Value": "Ценность Гидрация + Энергия", "Sound suppression": "Звукоподавление", "Low": "Низкое", "None": "Отсутствуюет", "Blocks earpiece": "Блокирует наушники", "Yes": "Да", "No": "Нет", "Ergonomics": "Эргономика", "Cost per ergo": "Стоимость за эрго.", "Recoil": "Отдача", "Distance": "Дистанция", "No items": "Нет предметов", "Not built": "Не построено", "Locked": "Заблокирован", "Crafting": "Ручное производство", "Hideout Management": "Управление убежищем", "Be the first!": "Будь первым!", "Objective": "Цель", "No objectives": "Нет целей", "Players": "Игроки", "By": "От", "Restock in": "Пополнится через", "Support Ukraine": "Поддержите Украину", "Cost per unit": "Стоимость за единицу", "About the tarkov.dev project": "О проекте tarkov.dev", "about-page-description": "Узнайте больше о the-hideout и tarkov.dev. Бесплатная экосистема для игры Escape from Tarkov с открытым исходным кодом, созданная сообществом! Используйте наши инструменты, чтобы помочь вам играть в игру, или создавайте свои собственные проекты с помощью нашего бесплатного API.", "Open source": "Открытый исходный код", "Discussions & feedback": "Обсуждения и отзывы", "Support": "Поддержка", "about-support-more-p": "<0>Вы также можете помочь, опубликовав сообщения об ошибках, предложив или внедрив новые функции, улучшив карты или чем-то еще, что, по вашему мнению, может улучшить сайт.", "about-api-p": "<0>Мы предлагаем 100% бесплатный и общедоступный API для всех ваших потребностей в разработке Tarkov - <1>API.", "History": "История", "about-history-p": "<0>Этот проект является форком <1>tarkov-tools.com. Первоначальный создатель <3>@kokarn решил закрыть сайт. В духе открытого исходного кода группа разработчиков собралась вместе, чтобы возродить сайт, чтобы продолжать предоставлять отличный сайт для сообщества Тарков и API для дальнейшего развития создателей. Теперь этот проект на 100% с открытым исходным кодом и в первую очередь для разработчиков. Наша Организация на GitHub (<5>the-hideout) содержит все репозитории, которые обеспечивают работу API, этого сайта, бота сообщества Discord, серверной инфраструктуры и многого другого! Мы страстно любим открытый исходный код и с удовольствием принимаем запросы на исправление ошибок, чтобы улучшить нашу экосистему для всех.", "Core Contributors": "Основные участники", "about-core-contributors-p": "<0>Основными участниками этого проекта (в произвольном порядке) являются:", "All Contributors": "Все участники", "about-all-contributors-p": "<0>Огромное спасибо всем людям, которые внесли свой вклад в этот проект и сделали его возможным! ❤️", "Description": "Описание", "Hidden": "Скрытое", "Player %": "% игроков", "Escape from Tarkov": "Escape from Tarkov", "achievements-page-description": "На этой странице представлена информация о достижениях, которые можно получить.", "Ammo chart": "Таблица патронов", "ammo-page-description": "На этой странице представлен список всех типов патронов в игре Escape from Tarkov. Чтобы отфильтровать полный список доступных патронов, нажмите на название калибра.", "ammo-page-p": "<0>В диких землях Таркова имеется широкий ассортимент боеприпасов. Для борьбы с разными противниками необходимы разные типы боеприпасов.<1>На этой странице представлен список всех типов патронов в игре Escape from Tarkov. Чтобы отфильтровать полный список доступных патронов, нажмите на название калибра.", "Total damage": "Суммарный урон", "Use total damage of all projectiles in a round": "Использует суммарный урон всех снарядов в патроне", "Ignore settings": "Игнорировать настройки", "Shows all sources of items regardless of your settings": "Показывает все источники предметов независимо от ваших настроек", "Use barters for item sources": "Использовать бартеры как источник предметов", "Use crafts for item sources": "Использовать крафты как источник предметов", "Ammo Statistics Table": "Таблица статистики патронов", "API Documentation": "Документация API", "api-docs-page-description": "Созданное сообществом API для Escape from Tarkov и документация к нему. Узнайте больше о нашем бесплатном и простом в использовании GraphQL API для EFT.", "api-about-p": "<0>API написан на GraphQL, и мы изо всех сил стараемся следовать спецификации и не вносить ломающих изменений. Чтобы узнать, какие запросы можно делать и как устроена схема, посетите playground и прочитайте документацию, нажав на значок книги в левом верхнем углу. Когда вы будете готовы попробовать несколько запросов, вы также можете протестировать их в playground. Чтобы узнать о запросах GraphQL в целом, на сайте GraphQL Foundation есть полезные ресурсы.<1><0><0>Tarkov.dev GraphQL playground<1><0>GraphQL Foundation resources<1>Когда вы будете готовы отправлять API-запросы не из playground, endpoint находится по адресу: <1>https://api.tarkov.dev/graphql.", "Current API Performance": "Текущая производительность API", "api-performance-p": "<0>Для получения полной информации о показателях и производительности API, посетите нашу <1>страницу статуса.", "FAQ": "ЧаВо", "Is it free?": "Бесплатно ли это?", "Is it open source?": "Является ли это открытым исходным кодом?", "api-faq-open-source-p": "Конечно! Исходный код API можно найти в его репозитории на GitHub: <1>github.com/the-hideout/tarkov-api.", "Is there a rate limit?": "Есть ли ограничение на частоту запросов?", "api-faq-rate-limit-p": "Периодически на нас обрушивается куча трафика от злоумышленников, что требует использования системы рейт-лимитов. Данные по ценам обновляются раз в 5 минут, поэтому нет особой нужды делать запросы чаще. Пользуйтесь здравым смыслом, и всё будет в порядке.", "What about caching?": "Что насчет кэширования?", "api-faq-caching-p": "Поскольку наши данные обновляются каждые 5 минут, мы также кэшируем все GraphQL-запросы в течение 5 минут. Это позволяет значительно снизить нагрузку на наши серверы и ускорить выполнение ваших запросов!", "Where is the data from?": "Откуда берутся данные?", "We source data from multiple places to build an API as complete as possible. We use data from:": "Мы получаем данные из разных мест, чтобы создать максимально полный API. Мы используем данные из:", "Our network of scanners": "Нашей сети сканеров", "Examples": "Примеры", "example": "пример", "Contributed by": "Предоставленно", "API Users": "Пользователи API", "api-users-page-description": "Эта страница содержит список всех пользователей общедоступного API Tarkov.dev и их проектов.", "api-users-p": "<0>Хотите, чтобы вас включили на эту страницу? Присоединяйтесь к <1>Discord и расскажите нам о том, что вы сделали!", "Barter Profits": "Прибыль бартера", "barters-page-description": "Эта страница содержит информацию о различных предметах, которыми можно торговать с торговцами, ценах бартера и прибыли, которую можно получить от продажи предметов.", "Shows all barters regardless of your settings": "Показывает все бартеры независимо от ваших настроек", "Hide dogtags": "Сктрыть жетоны", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "Истинную \"стоимость\" бартеров с использованием жетонов трудно оценить, поэтому вы можете захотеть исключить бартеры с жетонами", "Show all barters": "Показать все бартеры", "All": "Все", "Item filter": "Фильтр предметов", "filter on item": "фильтр по предмету", "barters-page-p": "<0>За исключением Скупщика, каждый торговец в Escape from Tarkov предлагает товары по бартеру.<1>В обмен на различные недорогие вещи игрок может обменять их на более ценные предметы (которые можно использовать или продать с выгодой), или на экипировку более высокого уровня при более низком Уровне Лояльности.<3>Не забывайте проверять после сброса свои любимые сделки, так как большинство из этих ценных сделок имеют строгие ограничения на пополнение торговцев и часто распродаются.", "Num graphic cards": "Количество видеокарт", "Hours": "Часов", "Bitcoin Farm Calculator": "Калькулятор биткоин фермы", "bitcoin-farm-calculator-page-description": "На этой странице представлен калькулятор, который поможет вам определить стоимость создания и обслуживания биткоин фермы, исходя из количества видеокарт, затрат на электроэнергию и стоимости биткоина.", "Graphic cards count": "Количество видеокарт", "Use fuel cost: {{price}}/day": "Стоимость топлива: {{price}}/день", "Use station build costs": "Учесть стоимость строительства фермы", "Purchase cost": "Стоимость покупки", "Remaining days in wipe:": "Дней до конца вайпа:", "Time to produce 1 bitcoin": "Время добычи 1 биткоина", "BTC/day": "BTC/день", "Estimated profit/day": "Расчетная прибыль/день", "Profitable after days": "Прибыльно через дней", "Total cost of graphic cards": "Общая стоимость видеокарт", "Build costs": "Стоимость строительства", "GPU + build costs": "Стоимость видеокарт + строительства", "Remaining profit": "Осталось выгоды", "Map": "Карта", "Spawn Location": "Место спавна", "Chance": "Шанс", "Count": "Счет", "Spawn chance": "Шанс спавна", "Chance that the boss spawns on a given map": "Шанс того, что босс заспавнится на определенной карте", "Health": "Здоровье", "Total boss health": "Общее здоровье босса", "Patrol": "Патруль", "Rush": "Стремительный", "Stalker": "Сталкер", "Hostile and accurate": "Враждебный и точный", "Patrol and highly armored": "Патруль и высокобронированные", "Group patrol": "Групповой патруль", "Frequent healing and stim injections": "Частые лечебные и стимулирующие инъекции", "Sniper": "Снайпер", "Batshit insane": "Безумный псих", "Behavior": "Поведение", "The boss's general AI behavior": "Общее поведение ИИ босса", "Wiki": "Вики", "Boss Stats": "Статистика босса", "Special Boss Loot": "Особый лут с босса", "Spawn Locations": "Места спавна", "boss-spawn-table-description": "<0>Карта: Название карты, на которой может появиться босс<1>Место появления: Точное место на карте, где может появиться босс.<2>Шанс: Если \"Шанс появления\" активирован для карты, это шанс появления босса в конкретном месте на этой карте.", "Boss Escorts": "Сопровождение босса", "This boss does not have any escorts": "У этого босса нет сопровождения", "boss-page-description": "Эта страница содержит информацию о местоположении {{bossName}}, добыче и стратегии победы над ним.", "bosses-page-description": "На этой странице представлена информация обо всех боссах в игре, их местоположении, добыче, сопровождении и стратегиях победы над ними.", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Боссы - это страшные и смертельно опасные враги с уникальным снаряжением и чертами характера в игре Escape from Tarkov", "About Bosses": "О боссах", "bosses-page-p": "<0>В игре Escape from Tarkov есть множество боссов, которые бродят по территории осажденного Норвинска.<1>Каждый босс обладает уникальным поведением, характеристиками и тактикой. Боссов в Таркове боятся игроки всех уровней, и зачастую они представляют большую угрозу, чем вражеские ЧВК в регионе.<2>Однако высокий риск влечет за собой высокую награду. Многие боссы несут в себе высокоуровневые предметы или требуют устранения для выполнения заданий. Изучение маршрута, местоположения и характерного одеяния босса - это лучшее, к чему может подготовиться игрок, когда начнется бой с боссом в Таркове.", "Connect": "Подключиться", "Connected to": "Подключен к", "id to control": "id для управления", "Remote Control": "Удаленное управление", "remote-control-page-description": "Эта страница содержит все необходимые инструменты для удаленного управления другим экземпляром веб-сайта Tarkov.dev.", "View Map": "Посмотреть карту", "Go": "Перейти", "View caliber": "Посмотреть калибр", "Select...": "Выбрать...", "Load tarkov.dev in another browser or window to control it from here": "Загрузите tarkov.dev в другом браузер или окне, чтобы управлять им отсюда", "Hideout Crafts": "Крафты в убежище", "crafts-page-description": "На этой странице представлена информация о различных предметах, которые можно скрафтить в убежище, о необходимых материалах и ресурсах, а также о прибыли, которую можно получить от продажи предметов.", "Shows all crafts regardless of your settings": "Показывает все крафты независимо от ваших настроек", "Average prices": "Средняя цена", "Use average prices from the past 24 hours for profit calculations": "Использует средние цены за последние 24 часа для расчета прибыли", "Most profitable craft in each station": "Самое прибыльный крафт в каждом модуле", "Best": "Топ", "Flea Market banned items": "Запрещенные на Барахолке предметы", "Empty fuel": "Пустое топливо", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "Устанавливает стоимость бензиновых канистр для рецептов, требующих их, на минимальную цену продажи торговцам при использовании бензиновых канистр, которые не найдены в рейде", "crafts-page-p": "<0>В игре Escape from Tarkov ремесла позволяют создавать различные вещи. Для этого используются различные модули убежища, включая водосборник, верстак, медблок, санузел и пищеблок.<1>Статус \"Найден в рейде\" будет применен к каждому предмету, созданному в убежище. Полный список этих ремесел приведен выше. Навык Ручное производство влияет на время создания предмета.<2> Если иконка предмета имеет синюю рамку, он будет использоваться как вспомогательный инструмент, а по окончании изготовления будет возвращен в схрон.", "Page not found": "Страница не найдена", "error-page-description": "Это не та страница, которую вы ищете", "Sorry, that page doesn't exist!": "Извините, этой страницы не существует!", "Hideout": "Убежище", "hideout-page-description": "Эта страница содержит информацию о различных модулях, которые можно построить с материалами и ресурсами, необходимыми для улучшения вашего убежища.", "Show all stations & modules": "Показать все модули", "Show built": "Показать построенные", "Show already built stations": "Показать построенные модули", "Show locked": "Показать закрытые", "Show unavailable stations": "Показать недоступные модули", "Show all requirements": "Показать все требования", "Show trader and other station level requirements": "Показать требуемые модули и уровни отношения торговцев", "Collected": "Собрано", "Item Tracker": "Отслеживатель предметов", "Only show Found in Raid": "Показать только Найденные в Рейде", "Reset all tracking": "Сбросить весь трекинг", "Hide completed": "Скрыть выполненные", "Hide tasks you've completed": "Скрыть выполненные вами задания", "Hide dogtag barters": "Скрыть бартеры с жетонами", "Best price to sell for": "Лучшая цена для продажи", "Fee": "Комиссия", "Profit": "Прибыль", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "Последняя наблюдаемая низкая цена на этот товар на Барахолке была {{lastSeenPrice}}.\nОднако из-за того, как рассчитывается комиссия, вам лучше продавать за {{bestPrice}}.", "Max price to sell for": "Максимальная цена для продажи", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "Этот предмет не был замечен на Барахолке.\nМаксимальная прибыльная цена составляет {{bestPrice}}, но товар может не продаться по этой цене.\n На максимальную прибыльную цену влияет уровень разведцентра и уровень навыка управления убежищем в ваших настройках.", "Likely sell price": "Вероятная цена продажи", "item-page-description": "Эта страница содержит информацию о характеристиках, использовании и стратегиях для {{itemName}}.", "Sell for": "Продается за", "Buy for": "Покупается за", "Flea price history": "История цен на блошином рынке", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "По сравнению со вчерашним днем: {{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "Наименьшая цена сканированная за последние 24 часа: {{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "Максимальная цена сканированная за последние 24 часа: {{high24hPrice}}", "Updated: {{val, relativetime}}": "Обновлено: {{val, relativetime}}", "Items contained in {{itemName}}": "Предметы, входящие в {{itemName}}", "Barters with {{itemName}}": "Бартеры с {{itemName}}", "Crafts with {{itemName}}": "Крафты с {{itemName}}", "Hideout modules needing {{itemName}}": "Модули убежища, требующие {{itemName}}", "Shows all modules regardless of your settings": "Показывает все модули независимо от ваших настроек", "Quests requiring {{itemName}}": "Задания, требующие {{itemName}}", "Quests rewarding {{itemName}}": "Задания, вознаграждающие {{itemName}}", "Armors": "Бронежилеты", "armors-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах бронежилетов, доступных в игре, включая их цену, ремонтопригодность, класс брони и прочие характеристики.", "Class effective durability": "Эффективная прочность класса", "Include rigs": "Включая разгрузки", "Max price": "Макс. цена", "max price": "макс. цена", "armors-page-p": "<0>В компьютерной игре Escape from Tarkov бронежилеты надевают, чтобы уменьшить урон от пуль. В дополнение к ним обычно используются шлемы.", "Backpacks": "Рюкзаки", "backpacks-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах рюкзаков, доступных в игре, включая их цену, размер, вместимость и прочие характеристики.", "Net price per slot": "Чистая цена за слот", "Show price per additional slot of storage gained from the container": "Показать цену за дополнительный слот хранения, полученный от контейнера", "backpacks-page-p": "<0>Рюкзаки в игре Escape from Tarkov - это различные по размеру контейнеры для переноски с трудом заработанных богатств.", "Barter Items": "Предметы бартера", "barter-items-page-p": "<0>Эта таблица предметов бартера из Escape from Tarkov поможет вам определить, сколько стоит каждый из них. Определить, какие товары достаточно ценны, может быть непросто, ведь в игре более 150 предметов бартера, а цены на барахолке могут неожиданно меняться. Вы можете оптимизировать свой лут с помощью этой интерактивной таблицы.", "bsg-category-description": "Узнайте все, что нужно знать о {{category}} в Escape from Tarkov.", "Containers": "Контейнеры", "containers-page-p": "<0>Как следует из названия, контейнеры в Escape from Tarkov - это предметы, используемые для хранения других предметов. Некоторые из этих предметов используются для освобождения места в инвентаре, выступая в качестве хранилища и занимая меньше слотов в инвентаре, однако некоторые из них не могут быть экипированы на персонаже.", "Glasses": "Очки", "glasses-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах очков, доступных в игре, включая их цену, класс брони и прочие характеристики.", "glasses-page-p": "<0>Очки в игре Escape from Tarkov можно использовать для уменьшения количества капель дождя на экранах игроков, а также для уменьшения продолжительности эффектов вспышек.", "Grenades": "Гранаты", "grenades-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах гранат, доступных в игре, включая их стоимость, урон и прочие характеристики.", "grenades-page-p": "<0>В игре Escape from Tarkov существует всего несколько типов гранат, которые можно бросать или запускать, и каждая из них обладает уникальным эффектом: вспышка, дым, взрывчатка и осколки.<1>Гранаты ситуативны, но при правильном использовании они могут привести к смертельным результатам. Любое преимущество от высококлассного снаряжения может быть полностью сведено на нет одной хорошо брошенной гранатой, будь то полное ослепление противника, мгновенное убийство или вынуждение его выйти из укрытия и попасть под ваш огонь.<3>Пять факторов, о которых следует подумать при использовании метаемых гранат, включают время запала, радиус взрыва, урон от осколков, количество фрагментов и даже вес гранаты. Каждый компонент имеет свое специфическое применение.", "Guns": "Оружие", "guns-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах оружия, доступных в игре, включая их цену, урон, точность и прочие характеристики.", "guns-page-p": "<0>Ваш главный инструмент для выживания - оружие. Почти все оружие является полностью модульным, что позволяет настраивать его под различные сценарии. Все виды оружия, используемые в Escape from Tarkov, перечислены на этой странице.", "Headsets": "Наушники", "headsets-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах наушников, доступных в игре, включая их цену, наличие и прочие характеристики.", "headsets-page-p": "<0>В игре Escape from Tarkov гарнитуры усиливают низкочастотные шумы, такие как шаги, и приглушают импульсные раздражители, такие как выстрелы. Различные модели предлагают разные аудиопрофили.", "Helmets": "Шлемы", "helmet-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах шлемов, доступных в игре, включая их цену, класс брони и прочие характеристики.", "Show blocking headset": "Показать блокирующие наушники", "Min armor class": "Мин. класс брони", "helmets-page-p": "<0>В игре Escape from Tarkov головные уборы выполняют различные функции.<1>Есть полезные предметы, предметы тщеславия и защитные головные уборы. Прежде чем вступить в бой, необходимо выбрать шлем, который защитит разные части головы.<3>Влияние разных шлемов на уровень подавления звуков - еще один важный фактор, который необходимо учитывать. Геймплей Escape from Tarkov в значительной степени зависит от звука.<5>Модульные шлемы, состоящие из множества различных компонентов, - еще один аспект Escape from Tarkov. Эти шлемы могут изменять количество защищаемых сегментов. Это макушка, затылок, уши, глаза и челюсти.", "items-page-description": "На этой странице находятся ссылки на страницы с информацией о различных категориях предметов, включая бронежилеты, рюкзаки, предметы бартера, контейнеры, очки, гранаты, оружие, наушники, шлемы, ключи, оружейные моды, пистолетные рукоятки, провиант, снаряжение, глушители и многое другое.", "Keys": "Ключи", "keys-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах ключей, доступных в игре, включая их цену, редкость и прочие характеристики.", "keys-page-p": "<0>Карты, ключи, ключ-карты и другие полезные предметы входят в состав предметов разведки. Они помогут вам быть на шаг впереди конкурентов - или, по крайней мере, знать, где вы находитесь в Escape from Tarkov.<1>Оставшийся срок службы ключей и карточек-ключей с ограниченным числом использований отображается в правом нижнем углу их иконок и в окне осмотра.", "Mods": "Моды", "mods-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах оружейных модов, доступных в игре, включая их цену, совместимость и прочие характеристики.", "mods-page-p": "<0>В Escape from Tarkov характеристики и функционирование оружия контролируются сложными механизмами, разделенными на пять категорий:<1><0>Функциональные модификации<1>Дульные устройства (Функциональные модификации)<2>Прицелы (Функциональные модификации)<3>Оружейные модификации<4>Жизненно важные части", "Pistol Grips": "Пистолетные рукоятки", "pistol-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах пистолетных рукояток, доступных в игре, включая их цену, эргономику, совместимость и прочие характеристики.", "Filter by gun": "Фильтр по оружию", "select a gun": "выберите оружие", "pistol-grips-page-p": "<0>В Escape from Tarkov пистолетные рукоятки и ложи являются важнейшими частями оружия.<1>На этой странице вы можете отсортировать их по улучшению эргономики или стоимости и посмотреть, на какое оружие они могут быть установлены.", "Provisions": "Провизия", "provisions-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах провизии, доступных в игре, включая их гидратацию, энергию, самую дешевую цену и стоимость у торговцев или на барахолке.", "Total energy cost": "Полная стоимость энергии", "Include the cost of lost hydration in the cost of energy": "Включить стоимость потерянной гидрации в стоимость энергии", "provisions-page-p": "<0>В игре Escape from Tarkov провизия используется для восполнения энергии и гидратации.<1>Ваш уровень навыка \"Метаболизм\" определяет, насколько она эффективна.", "Rigs": "Разгрузки", "rigs-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах разгрузок, доступных в игре, включая их цену, внутренние и внешние размеры, вес и прочие характеристики.", "Armored rigs?": "Разгрузки с бронепластинами?", "Min slots": "Мин. слоты", "3-slot": "3-слота", "4-slot": "4-слота", "rigs-page-p": "<0>Когда речь заходит о переноске и хранении боеприпасов и магазинов во время ваших экскурсий в Escape from Tarkov, разгрузки играют решающую роль. Некоторые из них даже обеспечивают дополнительную безопасность.", "Suppressors": "Глушители", "suppressors-page-description": "На этой странице находится сортируемая таблица с информацией о различных типах гулшителей, доступных в игре, включая их эргономику, отдачу и самую низкую цену.", "suppressors-page-p": "<0>В Escape from Tarkov глушитель - это дульное устройство (функциональный мод), устанавливаемое на оружие для приглушения звука выстрела.<1>На этой странице вы можете отсортировать их по штрафу эргономики, улучшению отдачи или стоимости и посмотреть, на какое оружие они могут быть непосредственно установлены.", "Barters": "Бартеры", "Marked": "Меченый", "Wearables": "Одеваемые", "loot-tiers-page-description": "Узнайте о различных типах лута, доступных в игре, их ценности, редкости, а также о том, что стоит оставить, а что выбросить.", "Ranking the most valuable items in the game": "Рейтинг самых ценных предметов в игре", "Include Marked": "Включая меченые", "Group by type": "Группировать по типу", "min value": "мин. ценность", "Only show markers for active tasks": "Показывать маркеры только для активных задач", "Map of {{mapName}}": "Карта: {{mapName}}", "maps-page-description": "Получите последнюю информацию обо всех картах в Escape from Tarkov, включая точки добычи и места расположения лута. Узнайте, где найти лучшее снаряжение и ресурсы в игре.", "maps-page-p": "<0>На карте Escape from Tarkov 11 различных локаций, из которых 10 были выпущены в свет на данный момент. Хотя со временем все карты будут связаны между собой, в настоящее время все они находятся отдельно друг от друга.", "Streets of Tarkov": "Улицы Таркова", "Ground Zero": "Эпицентр", "Customs": "Таможня", "Factory": "Завод", "Interchange": "Развязка", "The Lab": "Лаборатория", "Lighthouse": "Маяк", "Reserve": "Резерв", "Shoreline": "Берег", "Woods": "Лес", "Openworld": "Открытый мир", "Tarkov.dev {{bot}} integration": "Интеграция Tarkov.dev с {{bot}}", "bot-page-description": "Эта страница содержит все необходимое для интеграции Tarkov.dev с {{bot}}.", "You can add command to your moobot to get price check in your twitch chat": "Вы можете добавить команду своему Moobot, чтобы получить проверку цен в чате twitch", "Instructions": "Инструкции", "Register at": "Регистрация на", "using your twitch account": "используя свой аккаунт twitch", "Go to Custom commands": "Перейдите к пользовательским командам", "Set what you want the command to be. Common is \"p\" or \"price\"": "Установите, какой должна быть команда. Обычно это \"p\" или \"price\"", "Press the \"Create\" button": "Нажмите кнопку \"Создать\"", "In response choose URL Fetch - Full (plain) response": "В ответе выберите URL Fetch - Full (plain) response ", "and after insert \"Command arguments\"": "и после вставьте \"Command arguments\"", "Now press \"Save\" button": "Теперь нажмите кнопку \"Сохранить\"", "Big thanks to": "Большое спасибо", "for feedback": "за отзыв", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "Вы можете добавить команду вашему Nightbot для получения информации о цене в чате вашего канала twitch / youtube", "using your twitch / youtube account": "используя свою учетную запись twitch / youtube", "Go to dashboard": "Перейдите на панель управления", "Click the \"Join Channel\" button": "Нажмите кнопку \"Присоединиться к каналу\"", "Make bot - moderator, just type /mod nightbot in your chat": "Сделайте бота модератором, просто введите /mod nightbot в чате", "Go to custom commands": "Перейдите к пользовательским командам", "Press the \"Add command\" button": "Нажмите кнопку \"Добавить команду\"", "Command: !p or anything you like": "Команда: !p или что угодно", "Message:": "Сообщение:", "Press \"Submit\"": "Нажмите \"Отправить\"", "Trader Levels": "Уровень торговца", "Trader Reputation": "Репутация торговца", "Prerequisite Tasks": "Необходимые задания", "Start Requirements": "Стартовые требования", "Attributes": "Атрибуты", "Contains All": "Содержит в себе все", "Contains Item in Category": "Содержит предмет в категории", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Иметь эффект(ы) {{effectNames, list}} на вашем(их) {{bodyParts, list(type: disjunction)}} на протяжении {{operator}} {{count}} секунды", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "Иметь эффект(ы) {{effectNames, list}} на вашем(их) {{bodyParts, list(type: disjunction)}} на протяжении {{operator}} {{count}} секунд", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Иметь эффект(ы) {{effectNames, list}} на вашем(их) {{bodyParts, list(type: disjunction)}} на протяжении {{operator}} {{count}} секунд", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Иметь эффект(ы) {{effectNames, list}} на вашем(их) {{bodyParts, list(type: disjunction)}} на протяжении {{operator}} {{count}} секунд", "using extract: {{extractName}}": "выходя на: {{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "Выйти со статусом(ами): {{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "Выйти {{extractCount}} раз со статусом(ами): {{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x любых из", "Dogtag level": "Уровень жетона", "Max durability": "Макс. прочность", "Min durability": "Мин. прочность", "Kill": "Убить", "Shoot": "Выстрелить", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "В течение: от {{hourStart}}:00 до {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "На расстоянии: {{operator}} {{count}} метр", "From distance: {{operator}} {{count}} meters_few": "На расстоянии: {{operator}} {{count}} метра", "From distance: {{operator}} {{count}} meters_many": "На расстоянии: {{operator}} {{count}} метров", "From distance: {{operator}} {{count}} meters_other": "На расстоянии: {{operator}} {{count}} метров", "While inside: {{zoneList, list(type: disjunction)}}": "Находясь внутри: {{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "Попадая: {{bodyPartList, list(type: disjunction)}}", "Using weapon:": "Используя оружие:", "Using weapon mods:": "Используя моды на оружие:", "While wearing:": "Одевая:", "Not wearing:": "Не одевая:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Находясь под действием {{effectNames, list}} эффекта(ов) на вашем(их) {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунды", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "Находясь под действием {{effectNames, list}} эффекта(ов) на вашем(их) {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунд", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Находясь под действием {{effectNames, list}} эффекта(ов) на вашем(их) {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунд", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Находясь под действием {{effectNames, list}} эффекта(ов) на вашем(их) {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунд", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "Находясь под действием {{effectNames, list}} эффекта(ов) на ваших {{bodyParts, list(type: disjunction)}}", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "Пока цель находится под действием {{effectNames, list}} эффекта(ов) на своих {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунды", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_few": "Пока цель находится под действием {{effectNames, list}} эффекта(ов) на своих {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунд", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_many": "Пока цель находится под действием {{effectNames, list}} эффекта(ов) на своих {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунд", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "Пока цель находится под действием {{effectNames, list}} эффекта(ов) на своих {{bodyParts, list(type: disjunction)}} в течение {{operator}} {{count}} секунд", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "Пока цель находится под действием {{effectNames, list}} эффекта(ов) на своих {{bodyParts, list(type: disjunction)}}", "Obtain level {{level}} {{skillName}} skill": "Получить уровень {{level}} навыка {{skillName}}", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} отношение", "In area(s): {{areaList, list(type: disjunction)}}": "В области: {{areaList, list(type: disjunction)}}", "Use any of:": "Использовать что-то из:", "Reach level {{playerLevel}}": "Достигните уровня {{playerLevel}}", "optional": "опционально", "Trader Standing": "Отношение с торговцами", "Skill Level": "Уровень навыков", "Trader Offer Unlock": "Разблокирует товар у торговца", "Trader Unlock": "Разблокирует торговца", "Craft Unlock": "Разблокирует крафт", "task-page-description": "Эта страница содержит информацию о целях, наградах и стратегиях выполнения задания {{questName}}. Получите советы о том, как подготовиться и успешно выполнить задание.", "TarkovTracker": "TarkovTracker", "Leads to": "Ведет к", "(on failure)": "(при провале)", "Task Details": "Детали задания", "Objectives": "Цель(и)", "Fail On": "Проваливается при", "Needed Keys": "Необходимые ключи", "Task Start": "Начало задания", "Task Completion": "Завершение задания", "Rewards": "Награды", "Task Failure": "Провал задания", "Can be restarted": "Можно перезапустить", "Cannot be restarted": "Нельзя перезапустить", "Penalties": "Наказания", "tasks-page-description": "Узнайте все, что вам нужно знать о заданиях в игре Escape from Tarkov. Узнайте о различных типах заданий, доступных в игре, о том, как их выполнять, и о наградах, которые вы можете получить.", "Hides completed tasks": "Скрывает завершенные задачи", "Hide locked": "Скрыть заблокированные", "Hides locked tasks": "Скрывает заблокированные задачи", "Show all tasks": "Показать все задачи", "Name filter": "Фильтр по названию", "filter on task name": "фильтр по названию задачи", "quests-page-p": "<0>У торговцев в Escape from Tarkov есть ряд заданий, которые вы можете выполнить.<1>В обмен на доставку предметов, устранение целей и выполнение других действий в рейдах, вы можете повысить свое отношение с торговцами и заработать ценные предметы.", "Settings": "Настройки", "settings-page-description": "Эта страница содержит пользовательские настройки Tarkov.dev.", "Language": "Язык", "General": "Общие", "Has flea": "Есть барахолка", "Use TarkovTracker": "Использовать TarkovTracker", "TarkovTracker API Token": "Токен API TarkovTracker", "API Token": "Токен API", "Stations": "Модули", "Skills": "Навыки", "Dogtag Barters": "Бартеры с жетонами", "Exclude": "Исключить", "Minimum dogtag level": "Минимальный уровень жетона", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "Минимальный уровень жетона, используемый для расчета стоимости бартерных сделок с жетонами", "The current estimated average player level is {{avgPlayerLevel}}": "Текущий предполагаемый средний уровень игрока составляет {{avgPlayerLevel}}", "Miscellaneous": "Разное", "Hide remote control": "Скрыть удаленное управление", "start-page-description": "Узнайте всю информацию о предметах, крафтах, бартерах, картах, уровнях добычи, прибыли от убежища, деталях торговцев, бесплатном API и многом другом с tarkov.dev! Бесплатная, созданная сообществом экосистема инструментов и руководств по Escape from Tarkov с открытым исходным кодом.", "Load More": "Загрузить еще", "Tools": "Инструменты", "Ammo chart filter": "Фильтр таблицы патронов", "Traders barter profit": "Прибыль от бартерных сделок", "Hideout crafts profit": "Прибыль от крафтов в убежище", "Loot tiers ranking": "Рейтинг уровней лута", "Average wipe length": "Средняя длина вайпа", "Bitcoin farm profit": "Прибыль от биткоин фермы", "Invite Discord bot": "Пригласить Discord бота", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.dev является набором инструментов с открытым исходным кодом для игры Escape from Tarkov.", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "Он разработан и поддерживается сообществом, чтобы помочь вам в выполнении заданий, торговле на барахолке и в совершенствовании вашей игры! Кроме того, для вас открыт свободный доступ к API, чтобы вы могли создавать собственные инструменты и сервисы, связанные с EFT.", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "Вы можете добавить команду к вашему боту StreamElements, чтобы получить проверку цен в чате вашего канала twitch / youtube", "Make bot - moderator, just type /mod streamelements in your chat": "Сделайте бота модератором, просто введите /mod streamelements в вашем чате", "Press the \"Add new command\" button": "Нажмите кнопку \"Добавить новую команду\"", "Press \"Activate Command\"": "Нажмите \"Активировать команду\"", "Player level": "Уровень игрока", "Reputation": "Отношение", "Commerce": "Оборот", "Trader {{trader}}": "Торговец {{trader}}", "trader-page-description": "Получите последнюю информацию о торговце {{trader}} в Escape from Tarkov. Узнайте о предметах, которые он продает на определенном Уровне Лояльности, и о том, как максимально использовать свои деньги, чтобы повысить Уровень Лояльности.", "Items with the best cash back prices for leveling": "Предметы с лучшими ценами кэшбэка для прокачки уровня", "Spending": "Продажа", "Unlocks at Loyalty Level {{level}}": "Открывается на {{level}} Уровне Лояльности", "Tasks given by {{traderName}}": "Задания, которые дает {{traderName}}", "traders-page-description": "Узнайте все, что вам нужно знать о торговцах в игре Escape from Tarkov. Узнайте о различных торговцах, доступных в игре, их местоположении и предметах, которые они продают.", "About Traders": "О торговцах", "traders-page-p": "<0>Они стали основой торговли в разрушенном, осажденном Норвинске. В Escape from Tarkov каждый торговец специализируется на определенном виде товаров, таких как медицинские принадлежности, оружие или военное снаряжение. Хотя их цены обычно высоки, вы получаете то, за что платите.<1>Более того, вы можете заработать репутацию с каждым торговцем через задания, что позволит вам получать лучшие предложения в целом и снизить комиссию, которые они получают (дополнительная наценка, которую вы платите при продаже и покупке), среди прочих преимуществ.<2>Кроме того, торговцы предоставляют другие услуги, такие как ремонт и страховка (позволяющая вам вернуть свое снаряжение в случае смерти во время рейда).", "Patch": "Патч", "Wipe start": "Начало вайпа", "Wipe end": "Конец вайпа", "Ongoing wipe": "Текущий вайп", "{{count}} days_one": "{{count}} день", "{{count}} days_few": "{{count}} дня", "{{count}} days_many": "{{count}} дней", "{{count}} days_other": "{{count}} дней", "{{count}} months_other": "{{count}} months", "{{count}} years_one": "{{count}} year", "Wipe Length": "Длина вайпа", "wipe-length-description": "Получите последнюю информацию о средней продолжительности вайпа в Escape from Tarkov. Узнайте, сколько времени обычно длится вайп, и подготовьтесь к следующему вайпу.", "Average Wipe Length among last 6 wipes:": "Средняя продолжительность вайпа за последние 6 вайпов:", "Trader Ammo": "Trader Ammo", "Only show ammo available from traders on your settings": "Only show ammo available from traders on your settings", "Reset": "Reset", "Convert one currency to another": "Convert one currency to another", "Currency Converter": "Currency Converter", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "Most recent reports:", "Switch to {{gameMode}} profile": "Switch to {{gameMode}} profile", "control-info-p": "<0>Эта страница позволяет контролировать веб-сайт Tarkov.dev из другого браузера. Типичное применение: Tarkov.dev открыт в браузере на втором мониторе пока вы играете и эта страница открыта на телефоне или другом устройстве, и вы можете переключаться между страницами сайта не нуждаяясь в alt+tab. Всё, что вам нужно сделать: открыть веб-сайт Tarkov.dev в браузере, где вы хотите его отображать, нажать \"Нажмите для подключения\" слева внизу*, и использовать ID, показанный там на этой странице на управляющем устройстве и нажать \"Подключиться\". Как только вы подключитесь, вы сможете использовать эту страницу чтобы открывать определенные страницы карт/патронов в контролируемом браузере.<1>*По умолчанию она появляется слева снизу, но может быть перемещена вправо вниз. А ещё её можно скрыть опцией \"Спрятать удаленное управление\" в странице настроек.", "cookie-consent": "tarkov.dev использует куки для улучшения вашего опыта. Продолжая использование сайта, вы соглашаетесь с их использованием. Куки позволяют запоминать ваши настройки и функции которые вы включаете.", "I understand": "Я понимаю", "Other Options": "Другие параметры", "This task {{taskStatus}}": "Это задание {{taskStatus}}", "Slots per kg": "Слотов на кг", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Discord-бот Stash", "More Tools": "Больше инструментов", "Companion app": "Приложение-компаньон", "Discord companion": "Компаньон для Discord", "Download latest release": "Скачать последний релиз", "View on GitHub": "Посмотреть на GitHub", "Join the community": "Присоединиться к сообществу", "Screenshot of TarkovMonitor showing timers and integrations": "Скриншот TarkovMonitor с таймерами и интеграциями", "Visual timers, raid state, and integration health in TarkovMonitor.": "Визуальные таймеры, состояние рейда и здоровье интеграций в TarkovMonitor.", "Main Features": "Основные возможности", "tarkov-monitor-page-description": "Узнайте, как установить TarkovMonitor, подключить его к TarkovTracker и управлять картами Tarkov.dev.", "tarkov-monitor-summary": "TarkovMonitor дает полезные оповещения и таймеры для Escape From Tarkov, чтобы вы управляли рейдами без остановки игры.", "tarkov-monitor-feature-audio": "Звуковые оповещения для матчмейкинга, старта рейда, таймера runthrough, отката scava и уведомлений о фильтре воздуха.", "tarkov-monitor-feature-map": "Автоматическое открытие карты на Tarkov.dev в зависимости от выбранной локации.", "tarkov-monitor-feature-screenshot": "Необязательный показ позиции по скриншоту для быстрого обмена местоположением.", "tarkov-monitor-feature-quests": "Автоматическое обновление квестов в TarkovTracker при обнаружении завершения.", "tarkov-monitor-feature-stats": "Локальная статистика: доходы с барахолки, длительность очередей и частота карт.", "tarkov-monitor-feature-timers": "Видимые таймеры времени в рейде и отката scava, чтобы планировать следующий забег.", "Download": "Скачать", "tarkov-monitor-download-1": "Скачайте свежий TarkovMonitor.zip с GitHub.", "tarkov-monitor-download-2": "Распакуйте архив в любое место на ПК.", "tarkov-monitor-download-3": "Запустите TarkovMonitor.exe и держите его открытым во время игры.", "Community support": "Поддержка сообщества", "tarkov-monitor-community": "Есть вопросы или хотите пообщаться? Вступайте на Discord-сервер за советами, поддержкой и обсуждением функций.", "Join the Discord": "Вступить в Discord", "Security": "Безопасность", "tarkov-monitor-security": "TarkovMonitor — не чит. Он только читает логи Escape From Tarkov на вашем ПК и никогда не изменяет игру и не внедряет код.", "stash-page-description": "Пригласите Discord-бота Stash, изучите его команды и узнайте, чем он поможет вашему сообществу.", "stash-hero": "Stash приносит весь набор данных Tarkov.dev в Discord, чтобы ваше сообщество проверяло цены, прогресс квестов, таймеры убежища и другое, не уходя из чата.", "Invite Stash": "Пригласить Stash", "Report an issue": "Сообщить о проблеме", "Highlights": "Особенности", "Item intelligence": "Информация о предметах", "Instant prices with flea, trader, and craft context.": "Мгновенные цены с контекстом барахолки, торговцев и крафта.", "Craft/barter lookups reuse Tarkov.dev profitability data.": "Поиск крафтов/обменов использует данные прибыльности Tarkov.dev.", "Toggle PVE or PMC game modes to match your server rules.": "Переключайте режимы PVE или PMC, чтобы соответствовать правилам сервера.", "Progress tracking": "Отслеживание прогресса", "Quest command lists requirements, turn-ins, and rewards.": "Команда quest перечисляет требования, сдачу и награды.", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "Команда progress отражает улучшения убежища и торговцев, сохраненные на TarkovTracker.", "Restock and status alerts keep everyone informed between raids.": "Оповещения о перезагрузке и статусе информируют всех между рейдами.", "Community tools": "Инструменты сообщества", "Goons tracker for spotting the Rogue Boss trio.": "Трекер Goons для отслеживания троицы Rogue-боссов.", "Roulette mini-game for fun raid modifiers.": "Мини-игра рулетка для веселых модификаторов рейда.", "Slash commands, autocomplete, and localized responses.": "Slash-команды, автодополнение и локализованные ответы.", "Frequently used commands": "Часто используемые команды", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash предоставляет десятки slash-команд. Вот те, на которые чаще всего опираются серверы:", "Command": "Команда", "Example": "Пример", "Support & feedback": "Поддержка и обратная связь", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "Нужна политика конфиденциальности или условия использования для проверки безопасности? Они лежат в папке /assets репозитория и обновляются с каждым релизом.", "stash-tech-note": "Нужны технические гайды или инструкции по self-host? Смотрите README на GitHub для актуальной документации.", "card-tarkov-monitor-desc": "Автоматизируйте прогресс TarkovTracker, фиксируйте время очередей и управляйте картами Tarkov.dev с помощью одного приложения для Windows.", "card-stash-desc": "Slash-команды для проверки цен, помощи с квестами, прогресса убежища и таймеров пополнения прямо из Tarkov.dev.", "Read more": "Подробнее", "Invite now": "Пригласить сейчас", "other-tools-page-description": "Откройте вспомогательные приложения команды Tarkov.dev, включая TarkovMonitor и Discord-бота Stash.", "other-tools-body": "<0>Tarkov.dev — это больше, чем сайт. Эти инструменты расширяют ваши рейды, стримы и Discord-сообщества, используя один и тот же открытый набор данных. Изучайте каждое приложение, чтобы увидеть скриншоты, инструкции и ссылки поддержки.", "Learn about TarkovMonitor": "Узнать о TarkovMonitor", "Meet the Stash bot": "Познакомьтесь с ботом Stash", "The help command to view all available commands": "Команда help для просмотра всех доступных команд", "View details about the bot": "Просмотреть сведения о боте", "Get a sorted ammo table for a certain ammo type": "Получить отсортированную таблицу патронов для выбранного типа", "Check barter details for an item": "Проверить детали обмена для предмета", "Get detailed information about a boss": "Получить подробную информацию о боссе", "Get the latest game changes from tarkov-changes.com": "Получить последние изменения игры с tarkov-changes.com", "Check crafting details for an item": "Проверить детали крафта предмета", "Set the game mode (regular, PVE) for bot responses": "Задать режим игры (обычный или PVE) для ответов бота", "Check or report the location of the Goons": "Проверить или сообщить местоположение Goons", "Get a Discord invite link for the bot to join it to another server": "Получить ссылку приглашения Discord, чтобы добавить бота на другой сервер", "Report an issue with the bot": "Сообщить о проблеме с ботом", "Get price, craft, barter, etc. information about an item": "Получить информацию о цене, крафте, обмене и т.д. для предмета", "Get a key's price and maps it is used on": "Узнать цену ключа и карты, где он используется", "View a map and some general info about it": "Просмотреть карту и основные сведения", "Get the latest official patchnotes for EFT": "Получить последние официальные патчноуты EFT", "Get player profile information": "Получить информацию о профиле игрока", "Get a detailed output on the price of an item, its price tier, and more!": "Получить подробный отчёт о цене предмета, его уровне и многом другом!", "Manage your customized hideout and trader progress": "Управлять своим прогрессом убежища и торговцев", "Get detailed information about a quest": "Получить подробную информацию о задании", "Show or set alerts for trader restock timers": "Показать или настроить оповещения о таймерах перезаполнения торговцев", "Play a game of roulette to determine how you play your next raid": "Сыграть в рулетку, чтобы решить, как проходить следующий рейд", "Get the game/server/website status of Escape from Tarkov": "Узнать статус игры/сервера/сайта Escape from Tarkov", "Get information about a in-game stim": "Получить сведения об игровом стимуляторе", "Show the criteria for loot tiers": "Показать критерии уровней добычи", "Get the bot's uptime": "Посмотреть аптайм бота", "stash-support": "<0>Stash поддерживается командой Tarkov.dev. Ошибки или идеи? Создайте issue на <1>GitHub или пообщайтесь с разработчиками в <2>Discord Tarkov.dev. Если синхронизируете Tarkov.dev и данные бота, прикладывайте скриншоты и шаги воспроизведения.", "Database": "Database", "Calculators": "Calculators", "Progression": "Progression", "Community": "Community", "Prestige":"Prestige", "Gear":"Gear", "Weaponry":"Weaponry", "Equipment & Tools":"Equipment & Tools", "Game mode":"Game mode", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: src/translations/sync_key_value.py ================================================ # This script is used to syncronize key/values of namespaces other that translation from en to all other langs import json import os from shutil import copyfile # Translations dir #translations_dir = '../public/translations' translations_dir = './' # List of languages languages = ['de', 'es', 'fr', 'it', 'ja', 'pl', 'pt', 'ru', 'zh'] for en_file_name in os.listdir(os.path.join(translations_dir, 'en')): en_file_path = os.path.join(translations_dir, 'en', en_file_name) if en_file_name.endswith('translation.json'): continue # Read JSON data from file with open(en_file_path, encoding='utf-8') as json_en_file: data_en = json.load(json_en_file) for lang in languages: lang_file_path = os.path.join(translations_dir, lang, en_file_name) # If the file doesn't exist in the language folder, copy it from 'en' folder if not os.path.exists(lang_file_path): #copyfile(en_file_path, lang_file_path) #print(f"File '{en_file_name}' copied to '{lang}' folder.") print(f"File '{en_file_name}' is not present in '{lang}' folder.") else: # Read JSON data from file with open(lang_file_path, encoding='utf-8') as json_lang_file: data = json.load(json_lang_file) new_data = {} # scan all en keys for key in list(data_en.keys()): # if the key is already translated copy it if key in data: new_data[key] = data[key] # otherwise use new key from en else: new_data[key] = data_en[key] # Write the modified data with open(lang_file_path, 'w', encoding='utf-8') as json_new_lang_file: json.dump(new_data, json_new_lang_file, ensure_ascii=False, indent=4) print(f"File '{en_file_name}' synchronized with '{lang}' folder.") ================================================ FILE: src/translations/zh/bosses.json ================================================ { "cultist-bio": "", "cultist-priest-description": "潜行的家伙。邪教徒以 3-5 人一组潜伏在阴影中,等待玩家靠近。他们会悄无声息地接近敌人,用普通刀具或祭司专用的淬毒邪教匕首进行刺杀。若遭到射击,邪教徒会使用枪支和手榴弹还击。用刀攻击玩家后,他们可能会再次跑进树林,重新隐入阴影。", "knight-bio": "", "knight-description": "“The Goons”的首领。可在多张地图中刷新。", "glukhar-bio": "关于他过往活动的可靠信息无从考证,因为所有文件要么遗失要么被列为机密,但据未经证实的消息,他曾拥有士官军衔。他参与过战斗行动,精通战术基础,并在争夺或保卫各类领土时积极运用这些知识。他的所有队员似乎也都曾是军人。尽管如今他的帮派实质上只是一个为塔科夫资源与影响力而战的土匪团体。他与有能力从诺文斯克地区运出货品的商人有联系,这些商人会定期为他派出最后仍在运营的货运列车。", "glukhar-description": "Glukhar 及其众多守卫极具敌意。在开阔地带与他们交战极难成功。狭窄走廊和封闭房间是更理想的选择。Glukhar 及其守卫枪法极准。他们会始终聚集行动,守卫们会跟随 Glukhar 前往任何地点。", "kaban-bio": "他曾在塔科夫经营合法小生意,但也不惮使用犯罪手段敛财。全面撤离后他留在城内,其帮派规模日益壮大。", "kaban-description": "魁梧体型使他能无需架枪就持续射击各种重机枪,但同时,Kaban 无法灵活移动,因此在战斗中,他要么固守阵地,要么在点位间缓慢移动。其人拥有大量武装护卫,其中不乏前军人,为他组织起了严密防御。该 Boss 驻扎在“塔科夫街区”的汽车修理厂区域。该区域防御森严,入口处配备固定机枪和 AGS 榴弹发射器,通道布有地雷,汽车服务中心屋顶部署有狙击手。Kaban 使用定制装具携带机枪弹药箱,外衣下穿着防弹装甲,在护卫中拥有绝对权威。附近的 Scav 会协助首领防御并为 Kaban 而战。", "killa-bio": "", "killa-description": "塔科夫的终极猛男。Killa 使用轻机枪或其他自动武器压制敌人,同时在掩体间潜行接近目标发动最终突击。进攻时他以之字形移动,运用烟雾弹和破片手榴弹,用自动火力无情压制敌人。他会超出巡逻范围长距离追击目标,若被他锁定只有远遁才能摆脱。", "kollontay-bio": "他曾是内务部军官,在执法部门服役时就以品行恶劣著称,同事有时都畏惧其行径。任职期间他常使用最爱的审讯方式——橡胶警棍,以及其他非常规手段打压不合其意者。凭借强健体魄和大胆性情,在 TerraGroup 丑闻爆发后组建帮派,开始从事自己昔日本该打击的勾当——抢劫与匪帮活动。其实在冲突前他就常为当地“商人”提供保护,例如与 Kaban 的良好关系便广为人知。", "kollontay-description": "Kollontay 护卫数量较少,偏好固守某处,偶尔巡逻领地。若自觉占据上风,可能会切换使用警棍。他活跃在 Klimov 购物中心,以及内务部塔科夫学院周边区域。", "partisan-bio": "其过往可靠细节寥寥,但可知曾在阿富汗服役,其激进的作战方式于此扎根。人称“游击队员”,以布设陷阱与地雷的专长恶名昭彰。他歼灭敌人的声誉常源于利用对方大意攻其不备。游击战术知识使他成为危险对手,能将任何地点——无论森林或建筑——化为致命陷阱。幸存足够久并洞悉其手法者或能赢得他的青睐,但前提是能在为时已晚前识破陷阱。", "partisan-description": "", "raider-bio": "", "raider-description": "Scav 掠夺者(简称“掠夺者”)是进阶版 Scav,比普通 Scav 更具战术性与战斗力。他们配备更危险的武器与高级弹药,同时拥有更精准的枪法,常仅用数发子弹就击倒重装玩家(或直接爆头秒杀)。Scav 掠夺者以小组形式巡逻,通常可通过独特装备、语音与攻击性进行辨识。初始对所有其他 Scav(包括玩家 Scav)友善,但若无视口头警告靠近则会转为敌对。若有 Scav 激怒他们,会对全体 Scav 敌对。", "reshala-bio": "", "reshala-description": "他通常试图待在战斗后方避开玩家视线,且从不穿戴护甲。玩家 Scav 需注意:若 Scav 声望等级较低,Reshala 或其守卫会无端攻击你,或因你过于接近 Reshala 而开火。其守卫有时会对低声望玩家 Scav 发出警告后再转为敌对。", "rogue-bio": "", "rogue-description": "游荡者守卫着灯塔地图的污水处理厂及周边区域。主要行为是巡逻,但常会在屋顶占据防御位置并使用固定武器。他们会攻击所有进入区域的玩家,但对 Scav 和 USEC 阵营的 PMC 稍显宽容。游荡者因高生命值、激光般精准的枪法及超远射程而极度危险。受伤时,他们会跑向掩体并使用医疗物品。", "sanitar-bio": "前医生与科学家,曾为 TerraGroup 工作。他在实验室领导多个项目,包括开发新型精神活性物质。研究领域涵盖各种条件对人体影响至神经刺激素研发。除 TerraGroup 实验室外,他在蔚蓝海岸疗养院设有私人办公室,亦在此进行研究——尤其是在全面撤离前的最后数周。他常随医疗队前往热点地区出差,为企业工作后定期巡视非洲及其他办事处督导研发。在同事中享有毋庸置疑的权威与尊敬。", "sanitar-description": "交战时他会与 Scav 同伴及护卫协同作战,但又常常会脱离战线治疗或注射药物。携带大量医疗物资,可能会导向持久战。", "shturman-bio": "", "shturman-description": "Shturman 及其追随者会在伐木场远距离与玩家交战,偏好保持距离而不擅近距离战斗。", "tagilla-bio": "", "tagilla-description": "完全是个疯子,会试图用锤子砸碎你。但若你处于他无法路径找到的位置(如横梁),他会使用副武器(通常为霰弹枪)远程攻击。他在战局开始时便被会激活。此 Boss 会设置伏击、展开压制火力并在需要时实施突破。", "zryachiy-bio": "塔科夫最神秘人物之一。其过往几乎无人知晓,仅知受过狙击训练,遥传曾多次出入中东与非洲热点地区。早在冲突爆发前,他就成为 Lightkeeper 的忠犬,积极参与建立 Lightkeeper 与所有合作者之间的联系。已知与游荡者团体及在各地绘制神秘符号的兜帽人交好。Zryachiy 沉默寡言,但共事者常能心领神会。关于其眼睛的传闻众多,有人说是先天特征,有人指认是某种增强暗视能力的眼药水导致眼球泛白的副作用。尽管外观如此,他似乎正是因卓越视力得名——这对前军用狙击手而言并不意外。", "zryachiy-description": "Lightkeeper 的邪教护卫。" } ================================================ FILE: src/translations/zh/maps.json ================================================ { "2D": "2D", "3D": "3D", "interactive": "互动地图", "Landscape": "景观地图", "View Fullscreen": "全屏查看", "Exit Fullscreen": "退出全屏", "Satellite": "卫星图", "Abstract": "抽象图", "Levels": "层级", "1st Floor": "1层", "2nd Floor": "2层", "3rd Floor": "3层", "4th Floor": "4层", "5th Floor": "5层", "Underground": "地下", "Garage": "车库", "Tunnels": "隧道", "Bunkers": "地堡", "Spawns": "出生点", "PMC": "PMC", "Scav": "Scav", "Sniper Scav": "狙击手 Scav", "Boss": "Boss", "Extracts": "撤离点", "Shared": "共享", "Hazards": "危险区", "Usable": "可使用", "Locks": "锁", "Stationary Gun": "固定机枪", "Lever": "控制杆", "Switch": "开关", "Door": "门", "Container": "容器", "Car Door or Trunk": "车门或后备箱", "Lock": "锁", "Activated by": "激活条件", "Activates": "激活", "Needs power": "需要电力", "Lootable Items": "可搜刮物品", "Tasks": "任务", "Item": "物品", "Objective": "目标", "Misc": "杂项", "openworld-name": "开放世界", "terminal-name": "终点站", "openworld-description": "这是对塔科夫完整地图样貌的构想。这张开放世界地图可能会将所有现有地图中的关键地点整合到一个巨大的单张地图中。", "transits-name": "Transits", "transits-description": "This is a transit overlay over the official map that shows all current locations and how to reach them via transit and one-way transit connections.", "Transit": "转移点", "Task, item or container...": "任务、物品或容器……", "Supports multisearch (e.g. 'labs, ledx, bitcoin')": "支持多重搜索(例如:'实验室 LEDX, 比特币')", "Only show markers for active tasks": "仅显示当前任务的标记", "Don't collapse layers control": "保持图层控制栏展开", "Don't collapse search control": "Don't collapse search control", "Use TarkovMonitor to show your position": "使用 TarkovMonitor 来显示你的位置", "Required item": "所需物品", "BTR Stop": "BTR 停车点", "Player Position": "Player Position", "Always show snipers": "Always show snipers", "Task Filter": "Task Filter", "Task name": "Task name", "All": "All", "None": "None", "Search": "Search" } ================================================ FILE: src/translations/zh/properties.json ================================================ { "ambientVolume": "环境", "caliber": "口径", "damage": "伤害", "distanceModifier": "距离", "distortion": "失真", "projectileCount": "弹片数量", "penetrationPower": "穿透力", "armorDamage": "护甲伤害", "fragmentationChance": "碎弹概率", "ammoType": "弹药种类", "class": "等级", "material": "材料", "zones": "区域", "defaultPreset": "基础预设", "durability": "耐久度", "ergoPenalty": "人机惩罚", "speedPenalty": "速度惩罚", "turnPenalty": "转向惩罚", "headZones": "头部区域", "capacity": "容量", "grids": "格子", "energy": "能量", "hydration": "水分", "units": "使用单位", "stimEffects": "针剂效果", "blindnessProtection": "失明防护", "fuse": "爆炸延迟", "maxExplosionDistance": "最大爆炸距离", "fragments": "破片数量", "deafening": "听力减弱", "blocksHeadset": "遮挡耳机", "ricochetY": "跳弹概率", "uses": "使用次数", "malfunctionChance": "故障概率", "ergonomics": "人机工效", "recoil": "后坐力", "loadModifier": "装卸速度修正", "ammoCheckModifier": "检查速度修正", "useTime": "使用时间", "cures": "治愈", "hitpoints": "HP回复量", "maxHealPerUse": "单次使用最大回复量", "hpCostLightBleeding": "轻微出血的HP消耗", "hpCostHeavyBleeding": "大出血的HP消耗", "painkillerDuration": "止痛持续时间", "energyImpact": "能量影响", "hydrationImpact": "水分影响", "recoilVertical": "垂直后坐力", "recoilHorizontal": "水平后坐力", "zoomLevels": "缩放等级", "minLimbHealth": "最小肢体生命值", "maxLimbHealth": "最大肢体生命值", "effectiveDistance": "有效射程", "fireModes": "开火模式", "fireRate": "射速", "sightingRange": "瞄具距离", "defaultWidth": "默认宽度", "defaultHeight": "默认高度", "defaultErgonomics": "默认人机工效", "defaultRecoilVertical": "默认垂直后坐力", "defaultRecoilHorizontal": "默认水平后坐力", "defaultWeight": "默认重量", "recoilModifier": "后坐力修正", "weight": "重量", "baseItem": "基础物品", "categories": "分类", "type": "类型", "convergence": "准心恢复速度", "cameraRecoil": "镜头后坐力", "recoilAngle": "后坐力角度", "recoilDispersion": "后坐力散布", "usedOnMaps": "适用地图" } ================================================ FILE: src/translations/zh/translation.json ================================================ { "No data": "无数据", "Current Average Latency": "当前平均延迟", "API Latency in milliseconds": "API 延迟(毫秒)", "No barters found for this item": "未找到此物品的交易", "LL{{level}}": "LL{{level}}", "Barter at {{trader}}": "在 {{trader}} 处交易", "Craft at {{station}}": "在 {{station}} 处制作", "Barter": "交易", "Craft at {{stationName}} {{stationLevel}}": "在 {{stationName}} {{stationLevel}} 处制作", "Provides {{count}} for {{totalCost}}_one": "提供 {{count}} 件,总成本 {{totalCost}}", "Provides {{count}} for {{totalCost}}_other": "提供 {{count}} 件,总成本 {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_one": "在 {{duration}} 内制作 {{count}} 件,总成本 {{totalCost}}", "Crafts {{count}} in {{duration}} for {{totalCost}}_other": "在 {{duration}} 内制作 {{count}} 件,总成本 {{totalCost}}", "Reward": "奖励", "Cost": "成本", "Cost ₽": "成本 ₽", "Estimated savings": "预估节省", "InstaProfit": "即时利润", "N/A": "N/A", "Barter cost": "交易成本", "No barters available for selected filters": "所选筛选条件下无可用交易", "No barters available for selected filters but some were hidden by ": "所选筛选条件下无可用交易,但部分交易已被隐藏 ", "your settings": "你的设置", "Some barters hidden by ": "部分交易已被隐藏 ", "Can hold:": "可容纳:", "Can't hold:": "无法容纳:", "Level": "等级", "Flea Market": "跳蚤市场", "Flea banned": "跳蚤禁售", "Sell price": "售卖价格", "Flea Market fee": "跳蚤市场手续费", "Duration": "持续时间", "Finishes": "完成时间", "Start now": "立即开始", "Flea throughput/h": "跳蚤市场吞吐量/小时", "Estimated profit": "预估利润", "Estimated profit/h": "预估利润/小时", "No crafts available for selected filters": "所选筛选条件下无可用制作", "No crafts available for selected filters but some were hidden by ": "所选筛选条件下无可用制作,但部分制作已被隐藏 ", "Some crafts hidden by ": "部分制作已被隐藏 ", "{{val, datetime}}": "{{val, datetime}}", "All options already selected": "所有选项已选择", "Clear selection": "清除选择", "This item can't be sold on the Flea Market": "此物品无法在跳蚤市场出售", "Not scanned on the Flea Market": "未在跳蚤市场扫描到", "Flea market prices loading": "跳蚤市场价格加载中", "Tarkov.dev": "Tarkov.dev", "about-open-source-p": "<0>整个平台是开源的,并且以开发者为中心。所有代码均可在 <1><0> GitHub 上获取。", "about-discord-p": "<0>如果你想聊天、提问或请求功能,我们有一个 <1><0> Discord 服务器。", "about-x-p": "<0>在 <1><0> X 上关注我们以获取所有最新更新。", "About": "关于", "Contributors": "贡献者", "Massive thanks to all the people who help build and maintain this project!": "衷心感谢所有帮助构建和维护这个项目的人们!", "Made with ❤️ by:": "由以下人员用 ❤️ 制作:", "Supporters": "支持者", "about-support-ukraine-p": "<0>我们鼓励所有有能力的人使用下面的按钮捐款支持乌克兰人民。", "about-support-collective-p": "<0>如果你也想支持此项目,可以在 <1>Open Collective 上进行捐赠或成为支持者。", "Item Data": "物品数据", "Fresh EFT data courtesy of": "最新 EFT 数据由以下方面提供:", "Additional data courtesy of": "额外数据由以下方面提供:", "Resources": "资源", "Tarkov.dev API": "Tarkov.dev API", "{{bot}} integration": "{{bot}} 集成", "Discord bot for your Discord": "用于你 Discord 的 Discord 机器人", "External resources": "外部资源", "Tarkov.dev is a fork of the now shut-down tarkov-tools.com | Big thanks to kokarn for all his work building Tarkov Tools and the community around it.": "Tarkov.dev 是现已关闭的 tarkov-tools.com 的一个分支 | 非常感谢 kokarn 为构建 Tarkov Tools 及其社区所做的所有工作。", "Game content and materials are trademarks and copyrights of Battlestate Games and its licensors. All rights reserved.": "游戏内容和材料是 Battlestate Games 及其许可方的商标和版权。保留所有权利。", "version": "版本", "PMC & Scav Thorax HP": "PMC & Scav 胸部生命值", "Reshala Thorax HP": "Reshala 胸部生命值", "Raider Thorax HP": "掠夺者胸部生命值", "Shturman Thorax HP": "Shturman 胸部生命值", "Cultist Priest Thorax HP": "邪教徒牧师胸部生命值", "Cultist Warrior Thorax HP": "邪教徒战士胸部生命值", "Damage": "伤害", "Class {{tier}}": "等级 {{tier}}", "Penetration": "穿透", "Filter by caliber": "按口径筛选", "This item can only be sold to trader": "此物品只能出售给商人", "per slot": "单格", "Value": "价值", "Per slot": "单格", "Sell to": "出售给", "Found In Raid": "战局中发现物", "Search item...": "搜索物品……", "Search task...": "搜索任务……", "Tasks": "任务", "Items": "物品", "No hideout modules requires this item": "没有藏身处模块需要此物品", "No unbuilt hideout modules for selected filters but some were hidden by ": "所选筛选条件下无未建造的藏身处模块,但部分模块已被隐藏 ", "Hideout Module": "藏身处模块", "Item": "物品", "Amount": "数量", "Player level: {{playerLevel}}": "玩家等级:{{playerLevel}}", "Reputation: {{reputation}}": "声望:{{reputation}}", "Commerce: {{commerce}}": "交易额:{{commerce}}", "Cheapest Price": "最低价格", "Task: {{taskName}}": "任务:{{taskName}}", "Flea Market not available": "跳蚤市场不可用", "No trader offers available": "无商人报价可用", "Loading...": "正在加载……", "Ammo": "弹药", "Maps": "地图", "More": "更多", "Traders": "商人", "Prapor": "Prapor", "Therapist": "Therapist", "Skier": "Skier", "Peacekeeper": "Peacekeeper", "Mechanic": "Mechanic", "Ragman": "Ragman", "Jaeger": "Jaeger", "Bosses": "Boss", "Barter profit": "交易利润", "Hideout profit": "藏身处利润", "Loot tiers": "战利品等级", "Hideout build costs": "藏身处建造成本", "Wipe length": "删档周期长度", "Bitcoin Farm Profit": "比特币矿场利润", "Achievements": "成就", "API": "API", "Donate": "捐赠", "Become a patron": "成为赞助者", "{{val, relativetime}}": "{{val, relativetime}}", "has alternates": "存在替代", "On Task Completion": "任务完成时", "On Task Start": "任务开始时", "Task": "任务", "Required items": "所需物品", "Reward items": "奖励物品", "Required tasks": "所需任务", "loading": "加载中", "active": "进行中", "succeeded": "已成功", "complete": "已完成", "failed": "已失败", "Minimum level": "最低等级", "Minimum trader level": "最低商人等级", "Reputation rewards": "声望奖励", "Endgame": "终局游戏", "Required for Kappa": "Kappa 前置", "Required for Lightkeeper": "Lightkeeper 前置", "Kappa": "Kappa", "Lightkeeper": "Lightkeeper", "No quests found": "未找到任务", "Some tasks hidden by filter settings": "部分任务被筛选设置隐藏", "open this page in another browser or window and connect using this id": "在另一个浏览器或窗口中打开此页面,并使用此 ID 连接", "ID for remote control": "远程控制 ID", "Go to Tarkov.dev with another browser and enter this ID to control this page from there": "使用另一个浏览器访问 Tarkov.dev 并输入此 ID 以从那里控制此页面", "Click to connect": "点击连接", "Sell value": "出售价值", "Tarkov server status": "Tarkov 服务器状态", "This item can't be sold to traders": "此物品无法出售给商人", "Name": "名称", "Sell to Flea": "出售给跳蚤市场", "Buy on Flea": "在跳蚤市场购买", "Sell to Trader": "出售给商人", "Trader buy": "商人收购", "Buyback ratio": "倒卖比率", "The percent recovered if you buy this item and sell it to the trader": "如果购买此物品并出售给商人,可回收成本的百分比", "Grid": "格子", "Slots occupied": "占用格数", "Slots inside": "内部格数", "Slots ratio": "格数比率", "Price per slot": "单格价格", "Armor class": "护甲等级", "Zones": "区域", "Max Durability": "最大耐久度", "Effective Durability": "有效耐久度", "Repairability": "维修性能", "Weight (kg)": "重量(公斤)", "Stats": "属性", "Mov/Turn/Ergo": "移动/转向/人机", "Caliber": "口径", "Armor damage": "护甲伤害", "Fragmentation chance": "碎弹概率", "Blindness protection": "失明防护", "Hydration": "水分", "Energy": "能量", "Hydration Cost": "水分消耗", "Energy Cost": "能量消耗", "Hydration + Energy Value": "水分 + 能量价值", "Sound suppression": "声音抑制", "Low": "低", "None": "无", "Blocks earpiece": "遮挡耳机", "Yes": "是", "No": "否", "Ergonomics": "人机工效", "Cost per ergo": "每点人机成本", "Recoil": "后坐力", "Distance": "听力距离", "No items": "无物品", "Not built": "未建造", "Locked": "未解锁", "Crafting": "工艺", "Hideout Management": "藏身处管理", "Be the first!": "成为首个赞助者!", "Objective": "目标", "No objectives": "无目标", "Players": "玩家", "By": "由", "Restock in": "补货剩余时间", "Support Ukraine": "支持乌克兰", "Cost per unit": "每单位成本", "About the tarkov.dev project": "关于 tarkov.dev 项目", "about-page-description": "了解更多关于 the-hideout 和 tarkov.dev 的信息。一个免费的、社区制作的、开源的《逃离塔科夫》生态系统!使用我们的工具来帮助你玩游戏,或者使用我们免费的 API 构建你自己的项目。", "Open source": "开源", "Discussions & feedback": "讨论与反馈", "Support": "支持", "about-support-more-p": "<0>你还可以通过汇报Bug、提供建议或实现新功能、改进地图或任何其他你可以想到的能改进网站的方式来提供帮助。", "about-api-p": "<0>我们为你所有的 Tarkov 开发需求提供 100% 免费且公开访问的 API - <1>API", "History": "历史", "about-history-p": "<0>此项目是 <1>tarkov-tools.com 的一个分支。原创建者 <3>@kokarn 决定关闭该网站。本着开源的精神,一群开发者聚集在一起复活该网站,以便继续为 Tarkov 社区提供优秀的网站,并为创作者提供 API 以推动进一步开发。该项目现在 100% 开源且以开发者为先。我们的 GitHub 组织 (<5>the-hideout) 包含了所有支持 API、本网站、社区 Discord 机器人、服务器基础设施等的仓库!我们热衷于开源,并欢迎拉取请求以改善我们所有人的生态系统。", "Core Contributors": "核心贡献者", "about-core-contributors-p": "<0>此项目的核心贡献者(排名不分先后)是:", "All Contributors": "所有贡献者", "about-all-contributors-p": "<0>衷心感谢所有为这个项目做出贡献的人们,使其成为可能!❤️", "Description": "描述", "Hidden": "隐藏", "Player %": "玩家 %", "Escape from Tarkov": "《逃离塔科夫》", "achievements-page-description": "此页面包含有关可获得的成就信息。", "Ammo chart": "弹药图表", "ammo-page-description": "此页面包含《逃离塔科夫》中每种弹药类型的列表。要筛选可用弹药筒的完整列表,请单击口径名称。", "ammo-page-p": "<0>塔科夫的荒野包含各种各样的弹药。你需要不同类型的弹药来对抗不同的对手。<1>此页面包含《逃离塔科夫》中每种弹药类型的列表。要筛选可用弹药筒的完整列表,请单击口径名称。", "Total damage": "总伤害", "Use total damage of all projectiles in a round": "使用单次射击所有弹片的总伤害", "Ignore settings": "忽略设置", "Shows all sources of items regardless of your settings": "显示所有物品来源,忽略设置", "Use barters for item sources": "使用交易作为物品来源", "Use crafts for item sources": "使用制作作为物品来源", "Ammo Statistics Table": "弹药统计表", "API Documentation": "API 文档", "api-docs-page-description": "《逃离塔科夫》社区制作的 API 及其文档。了解更多关于我们为 EFT 提供的免费且易于使用的 GraphQL API。", "api-about-p": "<0>该 API 使用 GraphQL 编写,我们尽最大努力遵循规范,不做破坏性更改。要了解你可以进行哪些查询以及模式的结构,请访问 playground 并通过单击左上角的书本图标阅读文档。当准备好尝试一些查询时,你也可以在 playground 中测试它们。要了解一般的 GraphQL 查询,GraphQL 基金会有有用的资源。<1><0><0>Tarkov.dev GraphQL playground<1><0>GraphQL 基金会资源<1>当你准备好从 playground 外部发送 API 查询时,端点是:<1>https://api.tarkov.dev/graphql", "Current API Performance": "当前 API 性能", "api-performance-p": "<0>有关完整的 API 指标和性能,请查看我们的<1>状态页面", "FAQ": "常见问题解答", "Is it free?": "它是免费的吗?", "Is it open source?": "它是开源的吗?", "api-faq-open-source-p": "当然!API 的源代码可以在其 GitHub 仓库中找到:<1>github.com/the-hideout/tarkov-api。", "Is there a rate limit?": "有速率限制吗?", "api-faq-rate-limit-p": "我们偶尔会遇到恶意用户的大量流量攻击,因此需要实施频率限制。价格数据每 5 分钟更新一次,因此真的不需要比这更频繁地查询。保持合理操作就不会有问题。", "What about caching?": "缓存方面呢?", "api-faq-caching-p": "由于数据每 5 分钟更新一次,所有 GraphQL 查询也会缓存 5 分钟。这有助于大大减轻我们服务器的负载,同时使你的请求速度飞快!", "Where is the data from?": "数据来自哪里?", "We source data from multiple places to build an API as complete as possible. We use data from:": "我们从多个地方获取数据,以构建尽可能完整的 API。我们使用的数据来自:", "Our network of scanners": "我们的扫描器网络", "Examples": "示例", "example": "示例", "Contributed by": "贡献者", "API Users": "API 用户", "api-users-page-description": "此页面包含 Tarkov.dev 上公共 API 的所有用户及其项目的列表。", "api-users-p": "<0>想被列入此页面吗?加入<1>Discord并告诉我们你做了什么!", "Barter Profits": "交易利润", "barters-page-description": "此页面包含有关可以与 NPC 供应商交易的不同物品的信息、交易价格以及出售这些物品可以获得的利润。", "Shows all barters regardless of your settings": "显示所有交易,忽略设置", "Hide dogtags": "隐藏狗牌", "The true \"cost\" of barters using Dogtags is difficult to estimate, so you may want to exclude dogtag barters": "使用狗牌交易的真正“成本”难以估计,因此你可能希望排除狗牌交易", "Show all barters": "显示所有交易", "All": "所有", "Item filter": "物品筛选", "filter on item": "按物品筛选", "barters-page-p": "<0>除了 Fence,《逃离塔科夫》中的每个商人都会提供以物易物的商品,而不是直接购买。<1>通过交换各种廉价物品,玩家经常可以交易获得更有价值的物品,这些物品可以被利用或出售以获取利润。这些交易有时允许玩家获得通常只有在更高信任度等级才能购买的装备和物品。<3>请务必在每次交易刷新后回来查看你最喜欢的报价,因为这些有价值的交易大多数在每个商人重置时都有严格的数量限制,并且经常售罄。", "Num graphic cards": "显示卡数量", "Hours": "小时", "Bitcoin Farm Calculator": "比特币矿场计算器", "bitcoin-farm-calculator-page-description": "此页面包含一个计算器工具,可帮助你根据 GPU 数量、电力成本和比特币成本确定建造和维护比特币矿场的价格。", "Graphic cards count": "显示卡数量", "Use fuel cost: {{price}}/day": "计算燃料成本:{{price}}/天", "Use station build costs": "计算站点建造成本", "Purchase cost": "购买成本", "Remaining days in wipe:": "删档剩余天数:", "Time to produce 1 bitcoin": "生产 1 个比特币所需时间", "BTC/day": "比特币/天", "Estimated profit/day": "预估利润/天", "Profitable after days": "盈利所需天数", "Total cost of graphic cards": "显示卡总成本", "Build costs": "建造成本", "GPU + build costs": "GPU + 建造成本", "Remaining profit": "剩余利润", "Map": "地图", "Spawn Location": "刷新地点", "Chance": "概率", "Count": "数量", "Spawn chance": "刷新概率", "Chance that the boss spawns on a given map": "Boss在给定地图上刷新的概率", "Health": "生命值", "Total boss health": "Boss生命值总量", "Patrol": "巡逻", "Rush": "冲锋", "Stalker": "潜行", "Hostile and accurate": "敌对,精准", "Patrol and highly armored": "巡逻,重装甲", "Group patrol": "小组巡逻", "Frequent healing and stim injections": "频繁治疗和注射针剂", "Sniper": "狙击", "Batshit insane": "极度疯狂", "Behavior": "行为", "The boss's general AI behavior": "Boss的常规 AI 行为", "Wiki": "Wiki", "Boss Stats": "Boss 属性", "Special Boss Loot": "Boss 特殊战利品", "Spawn Locations": "刷新地点", "boss-spawn-table-description": "<0>地图:Boss可以刷新的地图名称<1>刷新地点:Boss可以在给定地图上刷新的确切位置<2>概率:如果地图的“刷新概率”已激活,这是Boss在该地图给定位置刷新的估计几率", "Boss Escorts": "Boss 随从", "This boss does not have any escorts": "此 Boss 没有任何随从", "boss-page-description": "此页面包含有关 {{bossName}} 的位置、战利品以及击败他的策略的信息。", "bosses-page-description": "此页面包含有关游戏中所有 Boss 的信息、他们的位置、战利品、随从以及击败他们的策略。", "Bosses are feared and deadly enemies with unique gear and traits in Escape from Tarkov": "Boss 是《逃离塔科夫》中令人恐惧且致命的敌人,拥有独特的装备和特质", "About Bosses": "关于 Boss", "bosses-page-p": "<0>在《逃离塔科夫》中,有许多 Boss 在被围困的诺文斯克地区游荡。<1>每个 Boss 都有独特的行为、特征和战术。塔科夫中的 Boss 被所有等级的玩家所畏惧,并且通常比该地区的敌方 PMC 威胁更大。<2>然而,高风险意味着高回报。许多 Boss 都有着高级战利品,或者是需要消灭的任务目标。了解 Boss 的行为模式、位置和独特装束通常是玩家在与塔科夫中的 Boss 战斗开始时能做的最好准备。", "Connect": "连接", "Connected to": "已连接至", "id to control": "要控制的 ID", "Remote Control": "远程控制", "remote-control-page-description": "此页面包含远程控制另一个 Tarkov.dev 网站实例所需的所有工具。", "View Map": "查看地图", "Go": "前往", "View caliber": "查看口径", "Select...": "选择……", "Load tarkov.dev in another browser or window to control it from here": "在另一个浏览器或窗口中加载 tarkov.dev 以从此处控制它", "Hideout Crafts": "藏身处制作", "crafts-page-description": "此页面包含有关可以在藏身处制作的不同物品的信息、所需的材料和资源,以及出售成品可以获得的利润。", "Shows all crafts regardless of your settings": "显示所有制作,忽略设置", "Average prices": "平均价格", "Use average prices from the past 24 hours for profit calculations": "使用过去 24 小时的平均价格进行利润计算", "Most profitable craft in each station": "每个制作站盈利最高的制作", "Best": "最佳", "Flea Market banned items": "跳蚤市场禁售物品", "Empty fuel": "空燃料桶", "Sets fuel canister cost for crafts requiring them to vendors' minimum sell price when using non-FIR fuel canisters.": "对于需要使用燃料桶的制作,当使用非战局中发现的燃料桶时,将燃料桶成本设置为商人的最低售价。", "crafts-page-p": "<0>《逃离塔科夫》中可以自己制作各种物品。这是通过使用各种藏身处模块来完成的,包括集水器、工作台、医疗站、卫生间和营养部。<1>在藏身处制造的物品为“战局中发现物”状态。这些制作的完整列表如上所示。工艺技能会影响物品制作时间。<2>当物品图标有蓝色边框时,它将被用作辅助工具,在制造完成后将返回仓库。", "Page not found": "页面未找到", "error-page-description": "这不是您要找的页面", "Sorry, that page doesn't exist!": "抱歉,该页面不存在!", "Hideout": "藏身处", "hideout-page-description": "此页面包含有关可以建造的不同站点和模块的信息,以及升级您的藏身处所需的材料和资源。", "Show all stations & modules": "显示所有站点 & 模块", "Show built": "显示已建造", "Show already built stations": "显示已建造的站点", "Show locked": "显示未解锁", "Show unavailable stations": "显示不可用的站点", "Show all requirements": "显示所有需求", "Show trader and other station level requirements": "显示商人和其他站点等级需求", "Collected": "已收集", "Item Tracker": "物品追踪器", "Only show Found in Raid": "仅显示战局中发现物", "Reset all tracking": "重置所有追踪", "Hide completed": "隐藏已完成", "Hide tasks you've completed": "隐藏你已完成的任务", "Hide dogtag barters": "隐藏狗牌交易", "Best price to sell for": "最佳出售价格", "Fee": "手续费", "Profit": "利润", "The last observed low price for this item on the Flea Market was {{lastSeenPrice}}.\nHowever, due to how fees are calculated, you're better off selling for {{bestPrice}}.": "此物品在跳蚤市场上最后检测到的低价是 {{lastSeenPrice}}。\n但是,由于手续费的计算方式,以 {{bestPrice}} 的价格出售会更划算。", "Max price to sell for": "最高出售价格", "This item has not been observed on the Flea Market.\nThe maximum profitable price is {{bestPrice}}, but the item may not sell at that price.\nThe max profitable price is impacted by the intel center and hideout management skill levels in your settings.": "此物品未在跳蚤市场上检测到。\n最高盈利价格是 {{bestPrice}},但物品可能无法以该价格出售。\n最高盈利价格受设置中情报中心和藏身处管理技能等级影响。", "Likely sell price": "可能的出售价格", "item-page-description": "此页面包含有关 {{itemName}} 的特性、用途和策略的信息。", "Sell for": "出售给", "Buy for": "购买自", "Flea price history": "跳蚤市场价格历史", "Change vs yesterday: {{changeLast48h}} ₽ / {{changeLast48Percent}} %": "与昨日相比变化:{{changeLast48h}} ₽ / {{changeLast48Percent}} %", "Lowest scanned price last 24h: {{low24hPrice}}": "过去 24 小时扫描到的最低价格:{{low24hPrice}}", "Highest scanned price last 24h: {{high24hPrice}}": "过去 24 小时扫描到的最高价格:{{high24hPrice}}", "Updated: {{val, relativetime}}": "更新于:{{val, relativetime}}", "Items contained in {{itemName}}": "{{itemName}} 内含物品", "Barters with {{itemName}}": "与 {{itemName}} 相关的交易", "Crafts with {{itemName}}": "与 {{itemName}} 相关的制作", "Hideout modules needing {{itemName}}": "需要 {{itemName}} 的藏身处模块", "Shows all modules regardless of your settings": "显示所有模块,忽略设置", "Quests requiring {{itemName}}": "需要 {{itemName}} 的任务", "Quests rewarding {{itemName}}": "奖励 {{itemName}} 的任务", "Armors": "护甲", "armors-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型护甲的信息,包括它们的价格、维修性能、护甲等级和其他特性。", "Class effective durability": "等级有效耐久度", "Include rigs": "包括胸挂", "Max price": "最高价格", "max price": "最高价格", "armors-page-p": "<0>在《逃离塔科夫》中,穿着防弹背心是为了减少子弹伤害。通常与头盔一起使用。", "Backpacks": "背包", "backpacks-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型背包的信息,包括它们的价格、尺寸、容量和其他特性。", "Net price per slot": "每格净价格", "Show price per additional slot of storage gained from the container": "显示从容器获得的每个额外存储格子(也就是除去容器本身占用的格子)的价格", "backpacks-page-p": "<0>在《逃离塔科夫》中,背包是尺寸各异的容器,用于携带你辛苦赚来的财富。", "Barter Items": "交换用物品", "barter-items-page-p": "<0>此交换用物品表能帮你轻松确定每个物品的价值。由于游戏中有超过 150 种交换用物品,且跳蚤市场价格可能突然波动,确定哪些物品值得拾取可能不是很容易。这个交互式表格可以帮助你优化战利品。", "bsg-category-description": "了解《逃离塔科夫》中 {{category}} 相关的所有必要信息。", "Containers": "容器", "containers-page-p": "<0>顾名思义,《逃离塔科夫》中的容器是用于存放其他物品的物品。其中一些物品通过充当存储空间并占用更少的格子来节省空间,但其中一些无法装备在角色身上。", "Glasses": "眼镜", "glasses-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型眼镜的信息,包括它们的价格、护甲等级和其他特性。", "glasses-page-p": "<0>在《逃离塔科夫》中,眼部装备可用于减少玩家屏幕上雨滴的数量和密度,并缩短闪光弹的效果持续时间。", "Grenades": "手榴弹", "grenades-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型手榴弹的信息,包括它们的价格、伤害和其他特性。", "grenades-page-p": "<0>在《逃离塔科夫》中,可供投掷或发射的手榴弹类型为数不多,且每种都具有独特效果:闪光弹、烟雾弹、高爆手榴弹和破片手榴弹。<1>手榴弹的使用虽需视情境而定,但若运用得当,却能产生致命效果。无论是以强光致盲对手、瞬间击杀,还是逼迫敌人脱离掩体撞上你的枪火,一枚精准投掷的手榴弹都足以让高等级装备的优势荡然无存。<3>使用投掷类手榴弹时需考量五大要素:爆炸延迟、爆炸半径、破片伤害、破片数量乃至手榴弹重量。每个要素都对应着不同的战术用途。", "Guns": "枪支", "guns-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型枪支的信息,包括它们的价格、伤害、精准度和其他特性。", "guns-page-p": "<0>武器是你生存的主要工具。几乎所有武器都是完全模块化的,从而根据各种场景进行改装。此页面列出了《逃离塔科夫》中使用的所有武器。", "Headsets": "耳机", "headsets-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型耳机的信息,包括它们的价格、可用性和其他特性。", "headsets-page-p": "<0>在《逃离塔科夫》中,耳机会放大低频噪音(如脚步声),同时抑制脉冲刺激(如枪声)。不同型号会提供不同的音频配置。", "Helmets": "头盔", "helmet-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型头盔的信息,包括它们的价格、护甲等级和其他特性。", "Show blocking headset": "显示遮挡耳机的头盔", "Min armor class": "最低护甲等级", "helmets-page-p": "<0>在《逃离塔科夫》中,头部装备具有多种功能。<1>有实用装置、装饰物品和安全头盔。在进入战斗前,选择一个能保护头部不同部位的头盔至关重要。<3>另一个需要考虑的关键因素便是不同头盔对声音抑制的影响。《逃离塔科夫》的游戏玩法严重依赖声音。<5>模块化头盔是《逃离塔科夫》的另一个重要部分,它们具有各种不同的组件。可通过改装这些头盔,来改变其保护的部位数量。部位包括:头顶、脖颈、耳部、眼部和下颚。", "items-page-description": "此页面包含指向不同物品类别信息页面的链接,包括护甲、背包、交易物品、容器、眼镜、手榴弹、枪支、耳机、头盔、钥匙、枪械配件、手枪式握把、给养品、胸挂、消音器等。", "Keys": "钥匙", "keys-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型钥匙的信息,包括它们的价格、稀有度和其他特性。", "keys-page-p": "<0>情报物品包括地图、钥匙、钥匙卡和其他有用物品。这些将帮助你领先对手一步——或者至少令你知道自己在《逃离塔科夫》中的什么地方。<1>对于使用次数有限的钥匙和钥匙卡,其剩余耐久度显示在其图标的右下角以及它们的检查屏幕上。", "Mods": "配件", "mods-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型枪械配件的信息,包括它们的价格、兼容物品和其他特性。", "mods-page-p": "<0>在《逃离塔科夫》中,武器的性能和功能由精细的机制控制,这些机制分为五类:<1><0>功能模块<1>枪口装置(功能配件)<2>瞄具(功能模块)<3>装备配件<4>基础配件", "Pistol Grips": "手枪式握把", "pistol-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型手枪式握把的信息,包括它们的价格、人机工效、兼容物品和其他特性。", "Filter by gun": "按枪支筛选", "select a gun": "选择一把枪", "pistol-grips-page-p": "<0>在《逃离塔科夫》中,手枪式握把和枪托是武器的关键部件。<1>在此页面上,你可以按人机工效改进或成本对它们进行排序,并查看它们可以安装在哪把武器上。", "Provisions": "给养品", "provisions-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型给养品的信息,包括它们的水分、能量、最低价格以及商人或跳蚤市场价值。", "Total energy cost": "总能量成本", "Include the cost of lost hydration in the cost of energy": "在能量成本中包含损失水分的成本", "provisions-page-p": "<0>在《逃离塔科夫》中,给养品用于补充能量和水分。<1>你的代谢技能等级会影响它们的效果。", "Rigs": "胸挂", "rigs-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型胸挂的信息,包括它们的价格、内部和外部尺寸、重量、压缩率和其他特性。", "Armored rigs?": "防弹胸挂?", "Min slots": "最小格数", "3-slot": "3格", "4-slot": "4格", "rigs-page-p": "<0>在《逃离塔科夫》中执行任务时,胸挂对于携带和存放弹药弹匣至关重要。有些甚至能为你提供额外的安全保障。", "Suppressors": "消音器", "suppressors-page-description": "此页面包含一个可排序的表格,其中包含游戏中可用的不同类型消音器的信息,包括它们的人机工效、后坐力和最低价格。", "suppressors-page-p": "<0>在《逃离塔科夫》中,消音器是一种枪口装置(功能模块),可以安装在武器上以抑制枪声。<1>在此页面上,你可以按人机工效惩罚、后坐力改进或成本对它们进行排序,并查看它们可以直接安装在哪把武器上。", "Barters": "交换用物品", "Marked": "标记物品", "Wearables": "可穿戴物品", "loot-tiers-page-description": "了解游戏中不同类型的战利品、它们的价值、稀有度,以及该保留什么和该丢弃什么。", "Ranking the most valuable items in the game": "对游戏中最有价值的物品进行排名", "Include Marked": "包括标记物品", "Group by type": "按类型分组", "min value": "最低价值", "Only show markers for active tasks": "仅显示活动任务的标记", "Map of {{mapName}}": "{{mapName}} 地图", "maps-page-description": "获取《逃离塔科夫》中所有地图的最新信息,包括撤离点和战利品位置。了解在游戏中哪里可以找到最好的装备和资源", "maps-page-p": "<0>《逃离塔科夫》地图上有 11 个不同的地点,其中 10 个已公开发布。虽然最终所有地图都将连接起来,但目前它们彼此分开。", "Streets of Tarkov": "塔科夫街区", "Ground Zero": "中心区", "Customs": "海关", "Factory": "工厂", "Interchange": "立交桥", "The Lab": "实验室", "Lighthouse": "灯塔", "Reserve": "储备站", "Shoreline": "海岸线", "Woods": "森林", "Openworld": "开放世界", "Terminal":"终点站", "Tarkov.dev {{bot}} integration": "Tarkov.dev {{bot}} 集成", "bot-page-description": "此页面包含将 {{bot}} 与 Tarkov.dev 集成所需的一切。", "You can add command to your moobot to get price check in your twitch chat": "可在你的 moobot 中添加命令,以在你的 Twitch 聊天中进行价格查询", "Instructions": "说明", "Register at": "在以下位置注册", "using your twitch account": "使用你的 Twitch 账户", "Go to Custom commands": "转到自定义命令", "Set what you want the command to be. Common is \"p\" or \"price\"": "设置想要的命令。常见的是 \"p\" 或 \"price\"", "Press the \"Create\" button": "按下“创建”按钮", "In response choose URL Fetch - Full (plain) response": "在响应中选择 URL Fetch - 完整(纯文本)响应", "and after insert \"Command arguments\"": "然后插入“命令参数”", "Now press \"Save\" button": "现在按下“保存”按钮", "Big thanks to": "非常感谢", "for feedback": "提供反馈", "You can add command to your nightbot to get price check in your twitch / youtube channel chat": "可在你的 Nightbot 中添加命令,以在你的 Twitch / YouTube 频道聊天中进行价格查询", "using your twitch / youtube account": "使用你的 Twitch / YouTube 账户", "Go to dashboard": "转到仪表板", "Click the \"Join Channel\" button": "单击“加入频道”按钮", "Make bot - moderator, just type /mod nightbot in your chat": "使机器人成为版主,只需在聊天中输入 /mod nightbot", "Go to custom commands": "转到自定义命令", "Press the \"Add command\" button": "按下“添加命令”按钮", "Command: !p or anything you like": "命令:!p 或任何你喜欢的", "Message:": "消息:", "Press \"Submit\"": "按下“提交”", "Trader Levels": "商人等级", "Trader Reputation": "商人声望", "Prerequisite Tasks": "前置任务", "Start Requirements": "开始要求", "Attributes": "属性", "Contains All": "包含全部", "Contains Item in Category": "包含类别中的物品", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "在你的 {{bodyParts, list(type: disjunction)}} 存在 {{effectNames, list}} 效果,持续 {{operator}} {{count}} 秒", "Have the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "在你的 {{bodyParts, list(type: disjunction)}} 存在 {{effectNames, list}} 效果,持续 {{operator}} {{count}} 秒", "using extract: {{extractName}}": "使用撤离点:{{extractName}}", "Extract with the status(es): {{extractStatuses, list(type: disjunction)}}": "以状态撤离:{{extractStatuses, list(type: disjunction)}}", "Extract {{extractCount}} times with the status(es): {{extractStatuses, list(type: disjunction)}}": "撤离 {{extractCount}} 次,状态为:{{extractStatuses, list(type: disjunction)}}", "{{itemCount}}x any of": "{{itemCount}}x 任意", "Dogtag level": "狗牌等级", "Max durability": "最高耐久度", "Min durability": "最低耐久度", "Kill": "击杀", "Shoot": "射击", "During hours: {{hourStart}}:00 to {{hourEnd}}:00": "时间段:{{hourStart}}:00 至 {{hourEnd}}:00", "From distance: {{operator}} {{count}} meters_one": "距离:{{operator}} {{count}} 米", "From distance: {{operator}} {{count}} meters_other": "距离:{{operator}} {{count}} 米", "While inside: {{zoneList, list(type: disjunction)}}": "在区域内:{{zoneList, list(type: disjunction)}}", "Hitting: {{bodyPartList, list(type: disjunction)}}": "命中:{{bodyPartList, list(type: disjunction)}}", "Using weapon:": "使用武器:", "Using weapon mods:": "使用武器配件:", "While wearing:": "穿着:", "Not wearing:": "未穿着:", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "当你的 {{bodyParts, list(type: disjunction)}} 存在 {{operator}} {{count}} 秒的 {{effectNames, list}} 效果", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "当你的 {{bodyParts, list(type: disjunction)}} 存在 {{operator}} {{count}} 秒的 {{effectNames, list}} 效果", "While having the {{effectNames, list}} effect(s) on your {{bodyParts, list(type: disjunction)}}": "当你的 {{bodyParts, list(type: disjunction)}} 存在 {{effectNames, list}} 效果", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_one": "当目标的 {{bodyParts, list(type: disjunction)}} 存在 {{operator}} {{count}} 秒的 {{effectNames, list}} 效果", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}} for {{operator}} {{count}} seconds_other": "当目标的 {{bodyParts, list(type: disjunction)}} 存在 {{operator}} {{count}} 秒的 {{effectNames, list}} 效果", "While target has the {{effectNames, list}} effect(s) on their {{bodyParts, list(type: disjunction)}}": "当目标的 {{bodyParts, list(type: disjunction)}} 存在 {{effectNames, list}} 效果", "Obtain level {{level}} {{skillName}} skill": "{{skillName}} 技能达到 {{level}} 级", "{{compareMethod}} {{reputation}} reputation": "{{compareMethod}} {{reputation}} 声望", "In area(s): {{areaList, list(type: disjunction)}}": "在区域:{{areaList, list(type: disjunction)}}", "Use any of:": "使用任意:", "Reach level {{playerLevel}}": "达到等级 {{playerLevel}}", "optional": "可选", "Trader Standing": "商人声望", "Skill Level": "技能等级", "Trader Offer Unlock": "商人交易解锁", "Trader Unlock": "商人解锁", "Craft Unlock": "制作解锁", "task-page-description": "此页面包含有关完成任务 {{questName}} 的目标、奖励和策略的信息。可从这里获取如何准备和成功完成任务的提示。", "TarkovTracker": "TarkovTracker", "Leads to": "后续任务", "(on failure)": "(失败时)", "Task Details": "任务详情", "Objectives": "目标", "Fail On": "失败条件", "Needed Keys": "所需钥匙", "Task Start": "任务开始", "Task Completion": "任务完成", "Rewards": "奖励", "Task Failure": "任务失败", "Can be restarted": "可以重新开始", "Cannot be restarted": "无法重新开始", "Penalties": "惩罚", "tasks-page-description": "了解《逃离塔科夫》中任务相关的所有必要信息。了解游戏中可用的不同类型的任务、如何完成它们以及获得的奖励。", "Hides completed tasks": "隐藏已完成任务", "Hide locked": "隐藏未解锁", "Hides locked tasks": "隐藏未解锁任务", "Show all tasks": "显示所有任务", "Name filter": "名称筛选", "filter on task name": "按任务名称筛选", "quests-page-p": "<0>《逃离塔科夫》中的商人会发布许多任务。<1>通过找回物品、消灭目标以及在战局中执行其他行动,你可以提高与商人的好感度并获得有价值的物品。", "Settings": "设置", "settings-page-description": "此页面包含 Tarkov.dev 上的用户设置。", "Language": "语言", "General": "常规", "Has flea": "拥有跳蚤市场", "Use TarkovTracker": "使用 TarkovTracker", "TarkovTracker API Token": "TarkovTracker API 令牌", "API Token": "API 令牌", "Stations": "设施", "Skills": "技能", "Dogtag Barters": "狗牌交易", "Exclude": "排除", "Minimum dogtag level": "最低狗牌等级", "Minimum dogtag level to use for calculating the cost of dogtag barter trades": "用于计算狗牌交易成本的最低狗牌等级", "The current estimated average player level is {{avgPlayerLevel}}": "当前估计的平均玩家等级是 {{avgPlayerLevel}}", "Miscellaneous": "杂项", "Hide remote control": "隐藏远程控制", "start-page-description": "使用 tarkov.dev 查看物品、制作、交易、地图、战利品等级、藏身处利润、商人详情、免费 API 等的所有信息!一个免费的、社区制作的、开源的《逃离塔科夫》工具和指南生态系统。", "Load More": "加载更多", "Tools": "工具", "Ammo chart filter": "弹药图表筛选器", "Traders barter profit": "商人交易利润", "Hideout crafts profit": "藏身处制作利润", "Loot tiers ranking": "战利品等级排名", "Average wipe length": "平均删档周期长度", "Bitcoin farm profit": "比特币矿场利润", "Invite Discord bot": "邀请 Discord 机器人", "tarkov.dev is an open source tool kit for Escape from Tarkov.": "tarkov.dev 是一个用于《逃离塔科夫》的开源工具箱。", "It is designed and maintained by the community to help you with quests, flea market trading, and improving your game! The API is also freely available for you to build your own tools and services related to EFT.": "它由社区设计和维护,以帮助你完成任务、进行跳蚤市场交易,并提升游戏体验!API 是免费的,供你构建自己与 EFT 相关的工具和服务。", "You can add command to your StreamElements bot to get price check in your twitch / youtube channel chat": "可在你的 StreamElements 机器人中添加命令,以在你的 Twitch / YouTube 频道聊天中进行价格查询", "Make bot - moderator, just type /mod streamelements in your chat": "使机器人成为版主,只需在聊天中输入 /mod streamelements", "Press the \"Add new command\" button": "按下“添加新命令”按钮", "Press \"Activate Command\"": "按下“激活命令”", "Player level": "玩家等级", "Reputation": "声望", "Commerce": "交易额", "Trader {{trader}}": "商人 {{trader}}", "trader-page-description": "获取《逃离塔科夫》中商人 {{trader}} 的最新信息。了解其在特定信任度等级出售的物品,以及如何最经济地提升信任度等级。", "Items with the best cash back prices for leveling": "用于升级的最佳返现价格物品", "Spending": "消费", "Unlocks at Loyalty Level {{level}}": "解锁于信任度等级 {{level}}", "Tasks given by {{traderName}}": "任务发布者:{{traderName}}", "traders-page-description": "了解《逃离塔科夫》中商人相关的所有必要信息。了解游戏中可用的不同商人、他们的位置以及他们出售的物品。", "About Traders": "关于商人", "traders-page-p": "<0>被摧毁、围困的诺文斯克的贸易支柱。在《逃离塔科夫》中,每个商人都拥有特定类型的产品,例如医疗用品、武器或军事装备。虽然他们的价格通常很高,但总归物有所值。<1>更重要的是,你可以通过任务与每个商人建立声誉,这通常能令你获得更好的交易,并减少他们收取的佣金(在交易和购买时支付的额外加价),以及其他好处。<2>此外,商人还提供其他服务,如保险和维修(允许你在战局中死亡后取回装备)。", "Patch": "补丁", "Wipe start": "开始日期", "Wipe end": "结束日期", "Ongoing wipe": "正在进行,未删档", "{{count}} days_one": "{{count}} 天", "{{count}} days_other": "{{count}} 天", "{{count}} months_other": "{{count}} 个月", "{{count}} years_one": "{{count}} 年", "Wipe Length": "删档周期长度", "wipe-length-description": "获取《逃离塔科夫》中平均删档周期长度的最新信息。了解删档通常持续多长时间,并为下一次删档做准备。", "Average Wipe Length among last 6 wipes:": "最近 6 次删档的平均周期长度:", "Trader Ammo": "商人弹药", "Only show ammo available from traders on your settings": "仅显示根据你的设置,可从商人处获得的弹药", "Reset": "重置", "Convert one currency to another": "将一种货币换算为另一种", "Currency Converter": "货币换算", "game_mode_regular": "PVP", "game_mode_pve": "PVE", "game_mode_arena": "Arena", "Most recent reports:": "最新报告:", "Switch to {{gameMode}} profile": "切换至 {{gameMode}} 配置文件", "control-info-p": "<0>此页面允许你使用另一个浏览器控制 Tarkov.dev 网站。典型的使用场景是:在第二个显示器的浏览器中打开 Tarkov.dev 网站,同时在你的手机或其他设备上打开此页面,这样就可以在 Tarkov.dev 网站上导航到不同页面,而无需从游戏中切换出来(Alt+Tab)。你只需要在要显示 Tarkov.dev 网站的浏览器中打开它,单击左下角的“点击连接”按钮*,然后在控制设备上使用此页面上显示的 ID 并单击连接。连接后,你可以使用此控制页面在受控浏览器中打开特定的地图或弹药页面。<1>*它默认出现在左下角,但可以切换到屏幕的右下角。也可以通过设置页面上的“隐藏远程控制”选项来隐藏。", "cookie-consent": "tarkov.dev 使用 cookie 来增强你的体验。继续使用此站点即表示你同意使用 cookie。Cookie 用于记住你的设置和启用的功能。", "I understand": "我已了解", "Other Options": "其他选项", "This task {{taskStatus}}": "此任务 {{taskStatus}}", "Slots per kg": "每公斤格数", "TarkovMonitor": "TarkovMonitor", "Stash Discord Bot": "Stash Discord 机器人", "More Tools": "更多工具", "Companion app": "辅助应用", "Discord companion": "Discord 辅助功能", "Download latest release": "下载最新版本", "View on GitHub": "在 GitHub 查看", "Join the community": "加入社区", "Screenshot of TarkovMonitor showing timers and integrations": "TarkovMonitor 显示计时器和集成状态的截图", "Visual timers, raid state, and integration health in TarkovMonitor.": "在 TarkovMonitor 中可视化计时器、突袭状态和集成健康。", "Main Features": "主要特性", "tarkov-monitor-page-description": "了解如何安装 TarkovMonitor、连接 TarkovTracker,并用它控制 Tarkov.dev 的地图。", "tarkov-monitor-summary": "TarkovMonitor 提供 EFT 的实用提醒和计时器,让你不打断游戏即可管理突袭。", "tarkov-monitor-feature-audio": "匹配、突袭开始、通关计时、Scav 冷却和空气过滤器通知的声音提醒。", "tarkov-monitor-feature-map": "根据你要加入的地点自动打开 Tarkov.dev 地图。", "tarkov-monitor-feature-screenshot": "可选的截图定位显示,方便快速共享位置。", "tarkov-monitor-feature-quests": "检测到完成后自动把任务更新到 TarkovTracker。", "tarkov-monitor-feature-stats": "本地统计,如跳蚤市场收益、排队时长和地图频率。", "tarkov-monitor-feature-timers": "可见的突袭计时和 Scav 冷却,帮助规划下一次行动。", "Download": "下载", "tarkov-monitor-download-1": "从 GitHub 获取最新的 TarkovMonitor.zip。", "tarkov-monitor-download-2": "将压缩包解压到电脑任意位置。", "tarkov-monitor-download-3": "运行 TarkovMonitor.exe,并在游戏时保持打开。", "Community support": "社区支持", "tarkov-monitor-community": "有疑问或想与其他用户聊天?加入 Discord 服务器获取技巧、排障和功能讨论。", "Join the Discord": "加入 Discord", "Security": "安全", "tarkov-monitor-security": "TarkovMonitor 不是作弊工具。它只读取你电脑上保存的 EFT 日志,从不修改游戏或注入代码。", "stash-page-description": "邀请 Stash Discord 机器人,查看它的指令,了解它如何帮助你的社区。", "stash-hero": "Stash 将整套 Tarkov.dev 数据带到 Discord,让你的社区可在聊天中直接查询价格、任务进度、藏身处计时等。", "Invite Stash": "邀请 Stash", "Report an issue": "报告问题", "Highlights": "亮点", "Item intelligence": "物品情报", "Instant prices with flea, trader, and craft context.": "提供带跳蚤、商人和制作上下文的即时价格。", "Craft/barter lookups reuse Tarkov.dev profitability data.": "制作/交换查询会复用 Tarkov.dev 的盈利数据。", "Toggle PVE or PMC game modes to match your server rules.": "在 PVE 和 PMC 模式间切换以匹配服务器规则。", "Progress tracking": "进度跟踪", "Quest command lists requirements, turn-ins, and rewards.": "任务指令列出需求、交付和奖励。", "Progress command mirrors the hideout and trader upgrades you have saved on TarkovTracker.": "progress 指令会同步你在 TarkovTracker 保存的藏身处及商人升级。", "Restock and status alerts keep everyone informed between raids.": "补货与状态提醒可让所有人在突袭间保持消息同步。", "Community tools": "社区工具", "Goons tracker for spotting the Rogue Boss trio.": "追踪流浪 Boss 三人组的 Goons 跟踪器。", "Roulette mini-game for fun raid modifiers.": "有趣的轮盘小游戏,用来决定突袭限制。", "Slash commands, autocomplete, and localized responses.": "斜杠指令、自动补全与本地化响应。", "Frequently used commands": "常用指令", "Stash exposes dozens of slash commands. Here are a few that most servers rely on:": "Stash 提供数十种斜杠指令,下列是大多数服务器会用到的:", "Command": "指令", "Example": "示例", "Support & feedback": "支持与反馈", "Need the privacy policy or terms of service for your server security review? They live inside the /assets folder of the repository and stay up-to-date with every release.": "需要隐私政策或服务条款进行服务器安全审核?它们位于仓库的 /assets 文件夹,并在每次发布时更新。", "stash-tech-note": "需要面向开发者的指南或自建说明?请查看 GitHub 上的 README 以获取最新文档。", "card-tarkov-monitor-desc": "使用单个 Windows 应用即可自动化 TarkovTracker 进度、记录排队时间并驱动 Tarkov.dev 地图。", "card-stash-desc": "基于 Tarkov.dev 数据的斜杠指令,可查询价格、任务、藏身处进度与补货计时。", "Read more": "了解更多", "Invite now": "立即邀请", "other-tools-page-description": "探索 Tarkov.dev 团队打造的伴侣应用,包括 TarkovMonitor 和 Stash Discord 机器人。", "other-tools-body": "<0>Tarkov.dev 不止是一个网站。这些工具使用同一套开源数据扩展你的突袭、直播和 Discord 社群。查看每个工具的截图、安装指南和支持链接。", "Learn about TarkovMonitor": "了解 TarkovMonitor", "Meet the Stash bot": "认识 Stash 机器人", "The help command to view all available commands": "用于查看所有可用指令的帮助命令", "View details about the bot": "查看机器人详细信息", "Get a sorted ammo table for a certain ammo type": "获取指定弹药类型的排序表", "Check barter details for an item": "查看物品的交换详情", "Get detailed information about a boss": "获取 Boss 的详细信息", "Get the latest game changes from tarkov-changes.com": "从 tarkov-changes.com 获取最新游戏改动", "Check crafting details for an item": "查看物品的制作详情", "Set the game mode (regular, PVE) for bot responses": "设置机器人回复所使用的常规或 PVE 模式", "Check or report the location of the Goons": "查询或上报 Goons 的位置", "Get a Discord invite link for the bot to join it to another server": "获取让机器人加入其他服务器的 Discord 邀请链接", "Report an issue with the bot": "报告机器人相关问题", "Get price, craft, barter, etc. information about an item": "获取物品的价格、制作、交换等信息", "Get a key's price and maps it is used on": "了解钥匙价格及其使用的地图", "View a map and some general info about it": "查看地图及其基本信息", "Get the latest official patchnotes for EFT": "获取 EFT 的最新官方更新日志", "Get player profile information": "获取玩家档案信息", "Get a detailed output on the price of an item, its price tier, and more!": "获得物品价格、等级等详细报告", "Manage your customized hideout and trader progress": "管理自定义的藏身处和商人进度", "Get detailed information about a quest": "获取任务的详细信息", "Show or set alerts for trader restock timers": "显示或设置商人补货计时提醒", "Play a game of roulette to determine how you play your next raid": "玩轮盘游戏决定下一次突袭的玩法", "Get the game/server/website status of Escape from Tarkov": "获取 Escape from Tarkov 的游戏/服务器/网站状态", "Get information about a in-game stim": "获取游戏内注射剂信息", "Show the criteria for loot tiers": "显示战利品等级的标准", "Get the bot's uptime": "查看机器人运行时间", "stash-support": "<0>Stash 由 Tarkov.dev 团队维护。遇到 bug 或有想法?请在 <1>GitHub 提 issue,或在 <2>Tarkov.dev Discord 与开发者交流。若同步 Tarkov.dev 与机器人数据,请附上截图和复现步骤。", "Database": "数据库", "Calculators": "计算器", "Progression": "进度", "Community": "社区", "Prestige":"转生", "Gear":"装备", "Weaponry":"武器", "Equipment & Tools":"装备 & 工具", "Game mode":"游戏模式", "Connecting...": "Connecting...", "Killstreak": "Killstreak", "Max Killstreak": "Max Killstreak", "Max Win Streak": "Max Win Streak", "Best ARP": "Best ARP", "Loss Streak": "Loss Streak", "Max Loss Streak": "Max Loss Streak", "Mode": "Mode", "Kills": "Kills", "Deaths": "Deaths", "Round MVP": "Round MVP", "Match MVP": "Match MVP", "Team Fight": "Team Fight", "Last Hero": "Last Hero", "Checkpoint": "Checkpoint", "Blast Gang": "Blast Gang", "Arena Stats": "Arena Stats", "Arena Mode Stats": "Arena Mode Stats", "K:D": "K:D", "PMC Kills": "PMC Kills", "PMC K:D": "PMC K:D", "No hideout stations match filter settings.": "No hideout stations match filter settings." } ================================================ FILE: stylelint.config.mjs ================================================ /** @type {import("stylelint").Config} */ const config = { extends: ["stylelint-config-standard"], rules: { "length-zero-no-unit": null, "alpha-value-notation": "number", "shorthand-property-no-redundant-values": null, "font-family-name-quotes": "always-unless-keyword", "selector-class-pattern": ".+", "no-descending-specificity": null, }, }; export default config; ================================================ FILE: tsconfig.json ================================================ { "compilerOptions": { "target": "ES2020", "lib": ["DOM", "ES2020"], "module": "ESNext", "jsx": "react-jsx", "allowJs": true, "strict": true, "skipLibCheck": true, "isolatedModules": true, "resolveJsonModule": true, "moduleResolution": "bundler", "useDefineForClassFields": true, "rootDir": "./", "outDir": "./dist" }, "include": ["src", "scripts", "additional.d.ts"] } ================================================ FILE: workers-site/.cargo-ok ================================================ ================================================ FILE: workers-site/.gitignore ================================================ node_modules worker ================================================ FILE: workers-site/index-template.js ================================================ /* eslint-env serviceworker */ import { getAssetFromKV, mapRequestToAsset } from "@cloudflare/kv-asset-handler"; const gearRedirects = { "/gear/": "/items/", "/gear/armors": "/items/armors", "/gear/backpacks": "/items/backpacks", "/gear/helmets": "/items/helmets", "/gear/glasses": "/items/glasses", "/gear/rigs": "/items/rigs", "/gear/suppressors": "/items/suppressors", }; // eslint-disable-next-line no-undef const redirects = REDIRECTS_DATA; /** * The DEBUG flag will do two things that help during development: * 1. we will skip caching on the edge, which makes it easier to * debug. * 2. we will return an error message on exception in your Response rather * than the default 404.html page. */ const DEBUG = false; // eslint-disable-next-line no-restricted-globals addEventListener("fetch", (event) => { try { event.respondWith(handleEvent(event)); } catch (e) { if (DEBUG) { return event.respondWith( new Response(e.message || e.toString(), { status: 500, }), ); } event.respondWith(new Response("Internal Error", { status: 500 })); } }); async function handleEvent(event) { const url = new URL(event.request.url); let options = { cacheControl: { browserTTL: 60 * 60 * 24, edgeTTL: 60 * 60 * 24 * 2, }, }; if (redirects[url.pathname]) { return Response.redirect(`https://tarkov.dev${redirects[url.pathname]}`, 301); } if (gearRedirects[url.pathname]) { return Response.redirect(`https://tarkov.dev${gearRedirects[url.pathname]}`, 301); } /** * You can add custom logic to how we fetch your assets * by configuring the function `mapRequestToAsset` */ options.mapRequestToAsset = (req) => { // First let's apply the default handler, which we imported from // '@cloudflare/kv-asset-handler' at the top of the file. We do // this because the default handler already has logic to detect // paths that should map to HTML files, for which it appends // `/index.html` to the path. req = mapRequestToAsset(req); // Now we can detect if the default handler decided to map to // index.html in some specific directory. if (req.url.endsWith("/index.html")) { // Indeed. Let's change it to instead map to the root `/index.html`. // This avoids the need to do a redundant lookup that we know will // fail. options.cacheControl.browserTTL = 0; options.cacheControl.edgeTTL = 60; return new Request(`${new URL(req.url).origin}/index.html`, req); } else { // The default handler decided this is not an HTML page. It's probably // an image, CSS, or JS file. Leave it as-is. return req; } }; try { if (DEBUG) { // customize caching options.cacheControl = { bypassCache: true, }; } return await getAssetFromKV(event, options); } catch (e) { // Fall back to serving `/index.html` on errors. return getAssetFromKV(event, { mapRequestToAsset: (req) => new Request(`${new URL(req.url).origin}/index.html`, req), }); } } /** * Here's one example of how to modify a request to * remove a specific prefix, in this case `/docs` from * the url. This can be useful if you are deploying to a * route on a zone, or if you only want your static content * to exist at a specific path. */ // eslint-disable-next-line no-unused-vars function handlePrefix(prefix) { return (request) => { // compute the default (e.g. / -> index.html) let defaultAssetKey = mapRequestToAsset(request); let url = new URL(defaultAssetKey.url); // strip the prefix from the path for lookup url.pathname = url.pathname.replace(prefix, "/"); // inherit all other props from the default request return new Request(url.toString(), defaultAssetKey); }; } ================================================ FILE: workers-site/package.json ================================================ { "private": true, "name": "worker", "version": "1.0.0", "description": "A template for kick starting a Cloudflare Workers project", "main": "index.js", "author": "Ashley Lewis ", "license": "MIT", "dependencies": { "@cloudflare/kv-asset-handler": "~0.0.11" } } ================================================ FILE: wrangler.toml ================================================ name = "tarkov.dev" type = "webpack" account_id = "424ad63426a1ae47d559873f929eb9fc" workers_dev = false route = "tarkov.dev/*" zone_id = "a17204c79af55fcf05e4975f66e2490e" [site] bucket = "./build" entry-point = "workers-site"