├── .eslintrc.js ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── build.yml │ └── test.yml ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── ASSUMPTIONS.md ├── LICENSE ├── README.md ├── build ├── icon.icns ├── icon.ico └── icon.png ├── lib ├── mod-checker-conflicts-2022.js ├── mod-checker-conflicts.js ├── mod-checker.js ├── translate.js └── util-extract-conflicts-strings.js ├── main.js ├── modChecker.js ├── package.json ├── renderer ├── arrowDbl.png ├── arrowDbl@2x.png ├── conarrow.png ├── conarrow@2x.png ├── debug.html ├── detail.html ├── folder.png ├── folder@2x.png ├── inc │ ├── bootstrap.bundle.min.js │ ├── bootstrap.min.css │ └── sortable.min.js ├── main.html ├── prefs.html ├── preload-debug.js ├── preload-detail.js ├── preload-main.js ├── preload-pref.js ├── repocard.png ├── repocard@2x.png ├── scan.png ├── scan@2x.png ├── splash.html ├── ui-splash.js ├── ui.js ├── version_icon_19.png ├── version_icon_19@2x.png ├── version_icon_22.png ├── version_icon_22@2x.png ├── xml.png └── xml@2x.png ├── screen_shots ├── 001-config.png ├── 002-broken.png ├── 003-missing.png ├── 004-conflict.png ├── 005-explore.png ├── 006-explore-options.png ├── 010-detail.png └── 020-prefs.png ├── test ├── mod-reader-test.js ├── simpleQuery.js └── testRunnerMods │ ├── gameSettings.xml │ └── mods │ ├── EXAMPLE_Bad_ModDesc_CRC.zip │ ├── EXAMPLE_Broken_Zip_File.zip │ ├── EXAMPLE_Fake_Cracked_DLC.zip │ ├── EXAMPLE_Garbage_File.txt │ ├── EXAMPLE_Good_Mod (1).zip │ ├── EXAMPLE_Good_Mod - Copy.zip │ ├── EXAMPLE_Good_Mod.zip │ ├── EXAMPLE_Good_Mod_Folder_Warning │ ├── modDesc.xml │ └── modIcon.dds │ ├── EXAMPLE_Good_Mod_Folder_and_Zip.zip │ ├── EXAMPLE_Good_Mod_Folder_and_Zip │ ├── EXAMPLE_Good_Mod.zip │ ├── modDesc.xml │ └── modIcon.dds │ ├── EXAMPLE_Good_Mod_No_Original - Copy.zip │ ├── EXAMPLE_Icon_Not_Found.zip │ ├── EXAMPLE_Malformed_ModDesc.zip │ ├── EXAMPLE_Missing_ModDesc.zip │ ├── EXAMPLE_No_Icon.zip │ ├── EXAMPLE_No_Version.zip │ ├── EXAMPLE_Old_ModDesc.zip │ └── EXAMPLE_Really_Malformed_ModDesc.zip ├── translations ├── de.json ├── en.json ├── es.json ├── fr.json ├── nl.json └── pl.json ├── yarn-error.log └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'parser' : '@babel/eslint-parser', 3 | 'env' : { 4 | 'browser' : true, 5 | 'commonjs' : true, 6 | 'es2021' : true, 7 | 'node' : true, 8 | }, 9 | 'extends' : 'eslint:recommended', 10 | 'parserOptions' : { 11 | 'ecmaVersion' : 12, 12 | 'requireConfigFile' : false, 13 | }, 14 | 'rules' : { 15 | 'indent' : [ 16 | 'error', 17 | 'tab', 18 | { 19 | 'SwitchCase' : 1, 20 | }, 21 | ], 22 | 'quotes' : [ 23 | 'error', 24 | 'single', 25 | ], 26 | 'semi' : [ 27 | 'error', 28 | 'never', 29 | ], 30 | 'no-unused-vars' : [ 31 | 'error', 32 | { 33 | 'varsIgnorePattern' : '^_', 34 | }, 35 | ], 36 | 'no-trailing-spaces' : [ 37 | 'error', 38 | { 39 | 'skipBlankLines' : true, 40 | 'ignoreComments' : true, 41 | }, 42 | ], 43 | 'dot-notation' : [ 44 | 'error', 45 | ], 46 | 'comma-dangle' : [ 47 | 'error', 48 | { 49 | 'arrays' : 'only-multiline', 50 | 'objects' : 'always-multiline', 51 | 'imports' : 'never', 52 | 'exports' : 'never', 53 | 'functions' : 'never', 54 | } 55 | ], 56 | 'key-spacing' : [ 57 | 'error', 58 | { 59 | 'beforeColon' : true, 60 | 'afterColon' : true, 61 | 'mode' : 'minimum', 62 | }, 63 | ], 64 | 'array-bracket-spacing' : [ 65 | 'error', 66 | 'never' 67 | ], 68 | 'no-await-in-loop' : 'error', 69 | 'no-promise-executor-return' : 'error', 70 | 'no-useless-backreference' : 'error', 71 | 'require-atomic-updates' : 'error', 72 | 'default-case' : 'error', 73 | 'eqeqeq' : 'error', 74 | 'no-else-return' : 'error', 75 | 'no-global-assign' : 'error', 76 | 'no-implicit-globals' : 'error', 77 | 'no-multi-str' : 'error', 78 | 'no-param-reassign' : 'error', 79 | 'no-return-await' : 'error', 80 | 'no-sequences' : 'error', 81 | 'no-unused-expressions' : 'error', 82 | 'comma-spacing' : 'error', 83 | 'func-call-spacing' : 'error', 84 | 'keyword-spacing' : 'error', 85 | 'no-lonely-if' : 'error', 86 | 'no-unneeded-ternary' : 'error', 87 | 'arrow-parens' : 'error', 88 | 'no-var' : 'error', 89 | 'prefer-const' : 'error', 90 | 'prefer-arrow-callback' : 'error', 91 | 'prefer-template' : 'error', 92 | 'no-useless-concat' : 'error', 93 | 94 | 95 | }, 96 | } 97 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. Windows 10] 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build/release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | release: 10 | runs-on: ${{ matrix.os }} 11 | 12 | strategy: 13 | matrix: 14 | os: [macos-latest, windows-latest] 15 | 16 | steps: 17 | - name: Check out Git repository 18 | uses: actions/checkout@v1 19 | 20 | - name: Install Node.js, NPM and Yarn 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: 14 24 | 25 | - name: Build/release Electron app 26 | uses: samuelmeuli/action-electron-builder@v1 27 | with: 28 | # GitHub token, automatically provided to the action 29 | # (No need to define this secret in the repo settings) 30 | github_token: ${{ secrets.github_token }} 31 | 32 | windows_certs: ${{ secrets.windows_certs }} 33 | windows_certs_password: ${{ secrets.windows_certs_password }} 34 | 35 | # If the commit is tagged with a version (e.g. "v1.0.0"), 36 | # release the app after building 37 | release: ${{ startsWith(github.ref, 'refs/tags/v') }} -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Check out Git repository 15 | uses: actions/checkout@v2 16 | 17 | - name: Install Node.js, NPM and Yarn 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: 14 21 | 22 | - name: Install dependencies 23 | run: yarn 24 | 25 | - name: Test code 26 | run: npm test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | lib/out 4 | lib/conflicts.json 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug - Electron Main Process", 6 | "type": "node", 7 | "request": "launch", 8 | "cwd": "${workspaceFolder}", 9 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", 10 | "windows": { 11 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" 12 | }, 13 | "args" : ["."], 14 | "outputCapture": "std" 15 | }, 16 | { 17 | "name": "Debug - CLI Tester", 18 | "program": "${workspaceFolder}/test/mod-reader-test.js", 19 | "cwd": "${workspaceFolder}", 20 | "request": "launch", 21 | "skipFiles": [ 22 | "/**" 23 | ], 24 | "type": "node" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "astragon", 4 | "backreference", 5 | "BOURGAULT", 6 | "builtins", 7 | "Bulbulator", 8 | "careersavegame", 9 | "CLAAS", 10 | "Courseplay", 11 | "DESCVERSION", 12 | "editorconfig", 13 | "farmingsim", 14 | "filesize", 15 | "flashonce", 16 | "flowconfig", 17 | "fsmodchecker", 18 | "fullscreenable", 19 | "gamesettings", 20 | "gitattributes", 21 | "Grimme", 22 | "grle", 23 | "Hant", 24 | "hprof", 25 | "iconfilename", 26 | "jtsage", 27 | "Kverneland", 28 | "maximizable", 29 | "minimizable", 30 | "modder", 31 | "moddesc", 32 | "modfolder", 33 | "MODNAME", 34 | "modsdirectoryoverride", 35 | "modtiny", 36 | "nsis", 37 | "offcanvas", 38 | "pdlc", 39 | "placeables", 40 | "pngjs", 41 | "prefs", 42 | "productid", 43 | "pycache", 44 | "Rottne", 45 | "savegame", 46 | "SCCS", 47 | "storeitem", 48 | "storeitems", 49 | "unzipper", 50 | "Vicon", 51 | "xproj", 52 | "zippack" 53 | ], 54 | "files.exclude": { 55 | "**/out": true 56 | } 57 | } -------------------------------------------------------------------------------- /ASSUMPTIONS.md: -------------------------------------------------------------------------------- 1 | # Assumptions made that a mod is "good" 2 | 3 | ## File Name 4 | 5 | File name must contain only [a-zA-Z0-9_], cannot must begin with [a-zA-Z]. 6 | 7 | We make no assumptions that files are case insensitive, although this is by default true on windows 10 - it's an extra hurdle to make a folder contain case sensitive files. On mac, this is (probably) not the default, but appears to be available. Either way, we don't check for this, and it would be an *excellent* way to shoot yourself in the foot. 8 | 9 | ## Collections 10 | 11 | ZIP files that include the text "unzip" or "extract" (along with some translations of these terms) are *probably* collections that should be extracted 12 | 13 | ## Folders 14 | 15 | Mods that are not zipped cannot be used in multiplayer 16 | 17 | ## Compression 18 | 19 | Only readable ZIP files are valid - however, the Giants engine is more forgiving than most zip libraries - currently, we only warn if it soft-fails. 20 | 21 | ## Mod Contents 22 | 23 | * a modDesc.xml is required, and must be parse-able 24 | * a readable icon file is required 25 | * the moddesc.descversion attribute must appear, and be between 40 and 53 26 | * a mod version string must be present 27 | * the "productid" tag should not be present (probably cracked DLC) 28 | 29 | ## Mod "working" concerns 30 | 31 | There is really no way we can automate the test to see if a mod actually functions in game - this is to weed out the garbage from the high and low quality mods. 32 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 J.T. Sage 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with 4 | or without fee is hereby granted, provided that the above copyright notice and this 5 | permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD 8 | TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN 9 | NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 10 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 11 | IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 12 | CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FS Mod Install Checker 2 | 3 | [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/jtsage/FS19_Mod_Checker) [![Build/release](https://github.com/jtsage/FS19_Mod_Checker/actions/workflows/build.yml/badge.svg)](https://github.com/jtsage/FS19_Mod_Checker/actions/workflows/build.yml) ![GitHub Release Date](https://img.shields.io/github/release-date/jtsage/FS19_Mod_Checker) ![GitHub all releases](https://img.shields.io/github/downloads/jtsage/FS19_Mod_Checker/total) [![Crowdin](https://badges.crowdin.net/fs19-mod-checker/localized.svg)](https://crowdin.com/project/fs19-mod-checker) 4 | 5 | This little program will take a look at your mod install folder and inform you of what it finds. 6 | 7 | ## This program is dead - try the new version https://github.com/FSGModding/FSG_Mod_Assistant 8 | 9 | ## What this does 10 | 11 | This program provides lots of information. 12 | 13 | _Optionally_, it will also allow you to remove mods from your install folder (atomically - that is, one at a time). Moved mods are sent to a "quarantine" folder of your choice. From this quarantine location you can fix files names, unzip mod packs, or delete stuff you just don't want anymore. 14 | 15 | ### Broken Mods 16 | 17 | * If a mod file is named incorrectly and won't load in the game. 18 | * Suggest it might be a copy if the name looks like a copy 19 | * Note if you already have that identical file 20 | * Note if you already have that version, but the files are different 21 | * Note if you don't have a properly named original 22 | * Suggest you extract it if it looks like a collection of mods 23 | 24 | * If a mod is not properly zipped. 25 | * Suggest that you zip it up 26 | * Suggest you move the contents of the folder if it looks like a mod pack 27 | * Suggest you remove the folder if it looks like garbage 28 | 29 | * If a mod is not intended for FS19 or FS22 (configurable!) (i.e. FS17 mods) 30 | * Warn that you can't use it with this version 31 | 32 | * If a file exists that is not a mod at all 33 | * Suggest you remove the file 34 | 35 | ### Conflicts 36 | 37 | * If a you have a mod as both a folder and a zip file, warn that only the zip file will be used 38 | 39 | * If you have a mod that is known to cause issues in specific circumstances, warn you 40 | 41 | ### Missing Mods 42 | 43 | * List all those mods that are active in your save games but don't appear to be installed any more 44 | * Allow you to search for the missing mod on the official mod hub, Google, DuckDuckGo, and Bing. 45 | 46 | ### Explore Mods 47 | 48 | Here you can sort the list of good, installed mods to discover any number of things 49 | 50 | * If a mod is not loaded or used in any of your save games 51 | 52 | * If a mod is loaded but unused in your save games. 53 | 54 | * What mod each save game is using 55 | 56 | * Which mods take up the most space on your disk 57 | 58 | ## Usage 59 | 60 | Download the installer for your platform from the [Releases](https://github.com/jtsage/FS_Mod_Checker/releases) page - the program 61 | will install with 1-click, and auto-run when it's ready. 62 | 63 | ### Download options 64 | 65 | Builds are available for the following: 66 | 67 | * win x64 Installer 68 | * win x64 portable (no need to install) 69 | * mac x64 DMG (disk image) 70 | * mac x64 ZIP (portable) 71 | 72 | Note: the mac builds probably work just fine on the new M1 macs. 73 | 74 | Linux Note: this builds just fine under linux. For the very few folks this would help, I don't wish to eat into my free github actions minutes - build and run it like any other npm / yarn based project - if you were able to get FS running under linux, this shouldn't be much in comparison. 75 | 76 | ### Updating 77 | 78 | Either download the new version and install over top, or, for every version post 1.9.30, it'll auto update (windows only - mac requires a different code signing at $100/year). Woohoo! 79 | 80 | Note: Give the program a second to update after closing (when notified of the new version). If you are too fast, windows will want to remove your shortcut. If you do what I did, and blindly click yes, the install folder is at: 81 | 82 | ```C:\Users\\AppData\Local\Programs\fs19-mod-checker``` 83 | 84 | ### Something didn't work?!? 85 | 86 | Please open an issue and let me know what. If it is specific to a mod, let me know where to get the mod. You can also hit CTRL+ALT+D in the app to bring up the debug log - sending that too might be a good idea. 87 | 88 | ### Usage with dedicated servers (for active/inactive/unused lists) 89 | 90 | It's beyond the scope of this project to tell you which farm / user is using each mod. But, the program also doesn't look at that bit - a mod is either used or not, associated farm ownership is ignored. 91 | 92 | So, if you want to run it against a dedicated server save: 93 | 94 | Option 1 - If you are running the dedicated server locally, just use the scanner on that set of save files / mods. 95 | 96 | Option 2 - Download your savegame folder *and* gameSettings.xml and run it on that. Keep in mind to make sure the server has saved out the file recently before you do this. Then just run it on that set of files like normal. 97 | 98 | Option 3 - Just grab the savegame folder, and replace one of your unused local saves with it. 99 | 100 | I will not be exploring using the server API to check directly - The amount of complexity this would add overshadows the benefits. Nor will I be adding arbitrary save file loading - again, the complexity add is too much. 101 | 102 | ## What it looks like 103 | 104 | ### Configuration Screen, Mods Loaded 105 | 106 |

107 | 108 |

109 | 110 | ### Bad Mods, Unzipped Mods, Extra Files 111 | 112 |

113 | 114 |

115 | 116 | ### Missing Mods 117 | 118 |

119 | 120 |

121 | 122 | ### Possible Conflicts 123 | 124 |

125 | 126 |

127 | 128 | ### Explore Mods 129 | 130 |

131 | 132 |

133 | 134 |

135 | 136 |

137 | 138 | ### Detail Popup 139 | 140 |

141 | 142 |

143 | 144 | ### User Preferences 145 | 146 |

147 | 148 |

149 | 150 | 151 | ## Translation Effort 152 | 153 | Sadly, the primary developer only understands English. If you'd like to contribute a translation, take a look in the translations folder, it's simple json. If you prefer a web interface: [Crowdin Project Page](https://crowdin.com/project/fs19-mod-checker) 154 | 155 | ### Localizations Available 156 | 157 | * Dutch / Nederlands - Thank you Kim | Paint-a-Farm! 158 | * English 159 | * French / Français - Thank you Taco29! 160 | * German / Deutsch - Thank you paraTM! 161 | * Polish / Polski - Thank you Ziuta! 162 | * Spanish / Español - Thank you Vanquish081! 163 | 164 | ## In-Progress Improvements 165 | 166 | * Note some of the more popular mod conflicts and suggest avoiding them: [GitHub Issue #2](https://github.com/jtsage/FS_Mod_Checker/issues/2) 167 | 168 | ## A short note about the EXE 169 | 170 | 2021-07-03 (ish): The EXE is signed now for windows. Sorry, not willing to join the apple developer program just for this. 171 | 172 | 2021-07-02 (late): Seems to be ok with the ~3pm EDT update to defender. At any rate, purchase pending on the signing certificate. 173 | 174 | 2021-07-02: Spoke too soon. The windows download at least is throwing a false virus warning at the moment. Working on it. Looks like sectigo joined the last couple decades and you can no verify without a listed phone number (a.k.a. Only own a cell phone like, ya know, everybody). Looking into this today or tomorrow. 175 | 176 | 2021-06: the electron package should work without any virus warnings, unlike the python version. It *is* unsigned, and probably will remain so for the future - I cannot possibly spend a couple hundred dollars a year on a code signing certificate for one little project - and as far as I know, no company still offers freebies for open source. 177 | 178 | ## For developers 179 | 180 | There is a CLI version in the repository, modChecker.js (you'll need the npm dependencies, but it will run without the dev-dependencies just fine. (dev stuff is only needed for the test suite and to run/build the electron version)) - it shows the basic usage of the mod / save game parser. Someday, the parser might be it's own npm module, maybe. 181 | -------------------------------------------------------------------------------- /build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/build/icon.icns -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/build/icon.ico -------------------------------------------------------------------------------- /build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/build/icon.png -------------------------------------------------------------------------------- /lib/mod-checker-conflicts-2022.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Mod File Parser - Conflict Mods 7 | 8 | // (c) 2021 JTSage. MIT License. 9 | 10 | /* 11 | These are mods that have often reported conflicts and 12 | we want to warn the user of that. 13 | 14 | This is really for the "big" or "common" conflicts. 15 | One-off oddities is a waste of maintainer time. 16 | 17 | 2022 Version. 18 | */ 19 | 20 | module.exports.conflictMods = {} -------------------------------------------------------------------------------- /lib/mod-checker-conflicts.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Mod File Parser - Conflict Mods 7 | 8 | // (c) 2021 JTSage. MIT License. 9 | 10 | /* 11 | These are mods that have often reported conflicts and 12 | we want to warn the user of that. 13 | 14 | This is really for the "big" or "common" conflicts. 15 | One-off oddities is a waste of maintainer time. 16 | 17 | 2019 Version. 18 | */ 19 | 20 | module.exports.conflictMods = { 21 | 'FS19_InfoMenu' : { 22 | confWith : ['FS19_precisionFarming'], 23 | message : { 24 | en : 'Some versions of Info Menu conflict with the Precision Farming DLC', 25 | pl : 'Niektóre wersje "Info Menu" powodują konflikt z "Precision Farming DLC".', 26 | de : 'Manche Versionen des Infomenüs stehen im Konflikt mit dem Precision Farming DLC', 27 | fr : 'Certaines versions du mod Info Menu entrent en conflit avec le DLC Precision Farming', 28 | }, 29 | }, 30 | 'FS19_UnitConvertLite' : { 31 | confWith : ['FS19_precisionFarming'], 32 | message : { 33 | en : 'Some versions of Unit Convert Lite conflict with the Precision Farming DLC', 34 | pl : 'Niektóre wersje "Unit Convert Lite" powodują konflikt z "Precision Farming DLC".', 35 | de : 'Manche Versionen von Unit Convert Lite stehen in Konflikt mit dem Precision Farming DLC', 36 | fr : 'Certaines versions du mod Unit Convert Lite entrent en conflit avec le DLC Precision Farming', 37 | }, 38 | }, 39 | 'FS19_additionalFieldInfo' : { 40 | confWith : ['FS19_precisionFarming'], 41 | message : { 42 | en : 'Versions of Additional Field Info prior to 1.0.2.3 conflict with the Precision Farming DLC', 43 | pl : '"Additional Field Info" do wersji 1.0.2.3 powoduje konflikt z "Precision Farming DLC".', 44 | de : 'Versionen von Additional Field Info vor 1.0.2.3 stehen in Konflikt mit dem Precision Farming DLC', 45 | fr : 'Les versions du mod Additional Field Info antérieures à 1.0.2.3 entrent en conflit avec le DLC Precision Farming', 46 | }, 47 | }, 48 | 'FS19_Variable_Spray_Usage' : { 49 | confWith : ['FS19_precisionFarming'], 50 | message : { 51 | en : 'Variable Spray Usage conflicts with the Precision Farming DLC', 52 | pl : '"Spray Usage" powoduje konflikt z "Precision Farming DLC".', 53 | de : 'Variabler Düngerverbrauch steht in Konflikt mit dem Precision Farming DLC', 54 | fr : 'Le mod Variable Spray Usage entre en conflit avec le DLC Precision Farming', 55 | }, 56 | }, 57 | 'FS19_towBar' : { 58 | confWith : null, 59 | message : { 60 | en : 'Old versions of the Tow Bar have been reported to be game breaking.', 61 | pl : '"Tow Bar" powoduje bardzo dużo konfliktów z innymi modami.', 62 | de : 'Alte Versionen der Abschleppstange haben bekannte Fehler, die FS19 unspielbar machen.', 63 | fr : 'Les anciennes versions du mod TowBar ont été signalées comme pouvant créer des conflits.', 64 | }, 65 | }, 66 | 'FS19PlaceAnywhere' : { 67 | confWith : ['FS19_GlobalCompany'], 68 | message : { 69 | en : 'The Place Anywhere mod can conflict with Global Company if both are loaded (and Global Company\'s extended placeables is used)', 70 | pl : '"Place Anywhere" z powodu braku aktualizacji nie jest zalecany oraz powoduje konflikt z "Global Company" (Global Company posiada tą samą funkcję w ustawieniach).', 71 | de : 'Wenn Überall Platzieren und Global Company (mit Global Companys "erweitertes Platzieren") gleichzeitig geladen werden, kann es Konflikte geben', 72 | fr : 'Le mod PlaceAnywhere peut entrer en conflit avec GlobalCompany si les deux sont chargés (et que le module extended placeables de GlobalCompany est utilisé)', 73 | }, 74 | }, 75 | 'FS19_REA' : { 76 | confWith : null, 77 | message : { 78 | en : 'The Added Realism For Vehicles mod can cause conflicts with improperly prepared vehicle mods. If has also been reported to not work with CoursePlay', 79 | pl : '"Added Realism For Vehicles" powoduje dużo problemów z niepoprawnie zedytowanymi pojazdami oraz powoduje problem z "Courseplay".', 80 | de : 'Der Mod "Added Realism For Vehicles" kann Konflikte mit unsauber vorbereiteten Fahrzeugen bewirken. Außerdem wird berichtet, dass der Mod nicht mit CoursePlay funktioniert', 81 | fr : 'Le mod Added Realism For Vehicles peut provoquer des conflits avec des mods de véhicules mal préparés. Il a également été signalé que ce mod ne fonctionne pas avec CoursePlay', 82 | }, 83 | }, 84 | 'FS19_realMud' : { 85 | confWith : null, 86 | message : { 87 | en : 'The Real Mud mod can cause conflicts with improperly prepared vehicle mods.', 88 | pl : '"Real Mud" poduje problemy z niepoprawnie zedytowanymi pojazdami.', 89 | de : 'Der Mod "Echter Schlamm" kann Konflikte mit unsauber vorbereiteten Fahrzeugen bewirken.', 90 | fr : 'Le mod RealMud peut provoquer des conflits avec des mods de véhicules mal préparés.', 91 | }, 92 | }, 93 | 'FS19_zzzSpeedControl' : { 94 | confWith : ['FS19_Courseplay'], 95 | message : { 96 | en : 'Speed Control has been reported to not work with CoursePlay', 97 | pl : '"Speed Control" powoduje konflikt z "Courseplay".', 98 | de : 'Es wird berichtet, dass SpeedControl nicht mit CoursePlay funktioniert', 99 | fr : 'Il a été signalé que le mod SpeedControl ne fonctionne pas avec CoursePlay', 100 | }, 101 | }, 102 | 'FS19_waitingWorkers' : { 103 | confWith : ['FS19_Courseplay'], 104 | message : { 105 | en : 'Waiting workers has been reported to not work with CoursePlay', 106 | pl : '"Waiting workers" powoduje konflikt z "Courseplay".', 107 | de : 'Es wird berichtet, dass der Mod "Wartende Helfer" nicht mit CoursePlay funktioniert', 108 | fr : 'Il a été signalé que le mod WaitingWorkers ne fonctionne pas avec CoursePlay', 109 | }, 110 | }, 111 | 'FS19_Courseplay' : { 112 | confWith : [ 113 | 'FS19_IMT_5360', 114 | 'FS_19_JohnDeere_540GIII_V1', 115 | 'FS19_MANMilk', 116 | 'FS19_waitingWorkers', 117 | 'FS19_STS_EU_Series', 118 | 'FS19_RealShovel', 119 | 'FS19_zzzSpeedControl', 120 | 'FS19_towBar', 121 | 'FS19_REA', 122 | 'FS19_coverAddon' 123 | ], 124 | message : { 125 | en : 'There are a number of mods that will not function correctly with courseplay. A partial list is available in the pinned issue on the courseplay github.', 126 | pl : 'Jest bardzo dużo modów które nie działają poprawnie z "Courseplay", listę większości z nich znajdziesz w repozytorium Courseplay na GitHub.', 127 | de : 'Es gibt eine Reihe an Mods, die nicht mit CoursePlay funktionieren. Eine (unvollständige) Liste ist als angepinntes Issue im Github von CoursePlay zu finden.', 128 | fr : 'Il existe un certain nombre de mods qui ne fonctionneront pas correctement avec CoursePlay. Une liste partielle est disponible dans la section problèmes épinglés sur le Github de CoursePlay.', 129 | }, 130 | }, 131 | 'FS19_baler_addon' : { 132 | confWith : ['FS19_addon_strawHarvest'], 133 | message : { 134 | en : 'Using the Baler Addon mod with the Straw Harvest addon can cause baler not be filled with netting/yarn and bales cannot be ejected', 135 | pl : '"Baler Addon" powoduje konflikt z "Straw Harvest Addon": Prasa może nie zostać napełniona siatką/sznurkiem oraz nie może zostać wyładowana z niej bela.', 136 | de : 'Das "Baler Addon" kann in Verbindung mit dem Strohberungs-DLC dafür sorgen, dass Pressen nicht mit Garn gefüllt werden und Ballen nicht ausgeworfen werden können', 137 | fr : 'L\'utilisation du mod Baler Addon avec l\'addon Straw Harvest peut faire en sorte que la presse à balles ne charge pas les filets/ficelles et que les balles ne puissent pas être éjectées', 138 | }, 139 | }, 140 | 'FS19_RoundbalerExtension' : { 141 | confWith : ['FS19_addon_strawHarvest'], 142 | message : { 143 | en : 'Versions of the Round Baler Extension below 1.5.0.0 will fail to work with the Straw Harvest Addon', 144 | pl : '"Round Baler Extension" do wersji 1.5.0.0 powoduje konflikt z "Straw Harvest Addon".', 145 | de : 'Die Versionen unter 1.5.0.0 der Rundballen-Erweiterung funktionieren nicht mit dem Strohbergungs-DLC', 146 | fr : 'Les versions du mod Round Baler Extension inférieures à la version 1.5.0.0 ne fonctionneront pas avec l\'addon Straw Harvest', 147 | }, 148 | }, 149 | 'FS19_VariableBaleCapacity' : { 150 | confWith : ['FS19_addon_strawHarvest'], 151 | message : { 152 | en : 'When also using the Straw Harvest Addon, variable bales will not work correctly with the Premos Bale Shredder vehicle', 153 | pl : '"Variable Bale Capacity" powodują konflikt z "Straw Harvest Addon": Problem z Premos Bale Shredder.', 154 | de : 'Wenn das Strohberungs-DLC genutzt wird, funktioniert der Mod "variable Ballenkapazität" nicht mit dem Premos Ballenschredder', 155 | fr : 'Lorsque vous utilisez également l\'addon Straw Harvest, les balles variables ne fonctionneront pas correctement avec la déchiqueteuse de balles Premos', 156 | }, 157 | }, 158 | 'FS19_GlobalCompanyPlaceable_sawmill' : { 159 | confWith : ['FS19_addon_strawHarvest'], 160 | message : { 161 | en : 'The Global Company Sawmill pack will not work correctly with the Straw Harvest Addon', 162 | pl : '"Sawmill" (dodatek do Global Company) powoduje konflikt z "Straw Harvest Addon".', 163 | de : 'Das Global Company Sägewerk-Pack funktioniert nicht richtig mit dem Strohberungs-DLC', 164 | fr : 'Le pack Placeable Sawmill de Global Company ne fonctionnera pas correctement avec l\'addon Straw Harvest', 165 | }, 166 | }, 167 | 'FS19_SeeBales' : { 168 | confWith : ['FS19_addon_strawHarvest'], 169 | message : { 170 | en : 'See Bales used with the Straw Harvest addon will cause pallets to fill to 0l and a game crash when selling pallets', 171 | pl : '"See Bales" powoduje konflikt z "Straw Harvest Addon": Palety mają wypełnienie na poziomie 0l i przy próbie sprzedaży zawiesza się gra.', 172 | de : 'Wenn der Mod "SeeBales" mit dem Strohbergungs-DLC verwendet wird, werden die Paletten mit 0l gefüllt und das Spiel stürzt beim Verkauf ab', 173 | fr : 'Le mod "See bales" utilisé avec l\'addon Straw Harvest provoque un remplissage des palettes à 0L et un plantage du jeu lors de la vente des palettes', 174 | }, 175 | }, 176 | 'FS19_realDirtFix' : { 177 | confWith : ['FS19_addon_strawHarvest'], 178 | message : { 179 | en : 'Real Dirt Fix will not work correctly with the Straw Harvest addon', 180 | pl : '"Real Dirt Fix" powoduje konflikt z "Straw Harvest Addon".', 181 | de : 'Real Dirt Fix funktioniert nicht korrekt mit dem Straw Ernte Addon', 182 | fr : 'Le mod Real Dirt Fix ne fonctionne pas correctement avec l\'addon Straw Harvest', 183 | }, 184 | }, 185 | 'FS19_MoreBunkersilo' : { 186 | confWith : ['FS19_addon_strawHarvest'], 187 | message : { 188 | en : 'More Bunker Silo versions below 1.0.0.2 pallets cannot be sold when running the Straw Harvest addon', 189 | pl : '"More Bunker Silo" do wersji 1.0.0.2 powoduje konflikt z "Straw Harvest Addon": Nie można sprzedać palet.', 190 | de : 'Der Mod "More Bunkersilo" mit Versionen vor 1.0.0.2 sorgt in Kombination mit dem Strohbergungs-DLC dafür, dass Paletten nicht verkauft werden können', 191 | fr : 'Les palettes du mod Bunker Silo en version inférieure à 1.0.0.2 ne peuvent pas être vendues lorsque l\'addon Straw Harvest est utilisé', 192 | }, 193 | }, 194 | 'FS19_BeetHarvest_Addon' : { 195 | confWith : ['FS19_addon_strawHarvest'], 196 | message : { 197 | en : 'The beet harvest addon is incompatible with the Straw Harvest addon, they cannot be used together', 198 | pl : '"Beet Harvest Addon" powoduje konflikt z "Straw Harvest Addon".', 199 | de : 'Das "Addon Zuckerrübenernte" ist nicht kompatibel mit dem Strohbergungs-DLC. Sie können nicht gleichzeitig verwendet werden', 200 | fr : 'L\'addon Beet Harvest est incompatible avec l\'addon Straw Harvest, ils ne peuvent être utilisés ensemble', 201 | }, 202 | }, 203 | 'FS19_AutomaticUnloadForBaleWrapper' : { 204 | confWith : ['FS19_addon_strawHarvest'], 205 | message : { 206 | en : 'Automatic Unload for Bale Wrappers does not work with the Straw Harvest addon', 207 | pl : '"Automatic Unload for Bale Wrappers" powoduje konflikt z "Straw Harvest Addon".', 208 | de : '"Automatic Unload for Bale Wrappers" funktioniert nicht mit dem Strohbergungs-DLC', 209 | fr : 'Le déchargement automatique des enrubanneuses de balles ne fonctionne pas avec l\'addon Straw Harvest', 210 | }, 211 | }, 212 | 'FS19_addon_strawHarvest' : { 213 | confWith : null, 214 | message : { 215 | en : 'Straw harvest has a few notable mod non-specific incompatibilities :
1.) The palletizer will not work with autoloaded (autounloaded) trailers.
2.) Using Straw Harvest with Seasons and Maize Plus CCM will likely result in too many fill types and could convert snow to a pellet variety.
3.) Alfalfa, if on the map, cannot be baled.
4.) Strange behavior may result when using the Alpine DLC (fixed in version 1.2.1.0)
5.) If you mod folder is on OneDrive or Epic Games sync, you may be unable to sell pallets (or other odd behavior)', 216 | pl : 'Inne możliwe konflikty z "Straw Harvest Addon":
1) Paletyzer nie działa z przyczepami z "autoload".
2) Używanie tego modu wraz z Seasons i Maize Plus spowoduje przekroczenie ilości materiałów i może zmienić np. śnieg w pellet.
3) Lucerna nie może być zbelowana (jeśli jest dodana do mapy).
4) Dziwne problemy używając Alpine DLC (prawdopodobnie naprawione w wersji DLC 1.2.1.0).
5) Jeśli masz włączony OneDrive lub synchronizację danych w Epic Games możesz mieć problem ze sprzedażą palet (lub też inne problemy).', 217 | de : 'Das Strohbergungs-DLC hat ein paar bemerkenswerte Inkompatibilitäten:
1.) Der Pallertierer funktioniert nicht mit AutoLoad-Anhängern.
2.) Die Verwendung des Strohbergungs-DLC mit Seasons und Maize Plus CCM sorgt vermutlich für zu viele fillTypes und könnte Schnee zu Paletten machen.
3.) Alfalfa kann nicht zu Ballen gepresst werden (sofern es in der Map verbaut ist).
4.) Seltsames Verhalten mit Alpine-DLC vor Version 1.2.1.0
5.) Wenn der Mod-Ordner auf einem OneDrive oder im EpicSync liegt, kann es vorkommen, dass man keine Paletten verkaufen kann (oder anderes seltsames Verhalten)', 218 | fr : 'Straw harvest présente quelques incompatibilités notables non spécifiques à un mod :
1.) Le palettiseur ne fonctionne pas avec des remorques à chargement et déchargement automatique (autoload).
2.) L\'utilisation de l\'addon Straw Harvest entrerait en conflit avec Seasons et Maize Plus CCM et donnera probablement lieu à trop de types de remplissage et pourrait convertir la neige en une variété de granulés.
3.) Les balles du Silo fermenteur de Lucerne Alfalfa de Global company, si présent sur la map, ne peuvent pas être enrubannérs.
4.) Un comportement étrange peut se produire lors de l\'utilisation du DLC Alpine (corrigé dans la version 1.2.1.0).
5.) Si votre dossier de mods est sur OneDrive ou Epic Games sync, il se peut que vous ne puissiez pas vendre de palettes (ou autre comportement étrange).', 219 | }, 220 | }, 221 | 'FS19_RM_Seasons' : { 222 | confWith : null, 223 | message : { 224 | en : 'Seasons has issues with the following :
1.) Do not load multiple map mods. Only load the map you are using!
2.) Any mod that manipulates the weather, [e.g. Multi overlay hud]
3.) Any mod that manipulates growth
4.) Any mod that changes animals
5.) Any "season manager" type mods
6.) Some animal cleaning mods may not work correctly, especially during the winter', 225 | pl : 'Możliwe konflikty z Seasons:
1) Nie ładuj kilku map. Zostaw w modach tylko tą której używasz!
2) Każdy mod ingerujący w pogodę (np. Multi overlay hud).
3) Każdy mod ingerujący we wzrost upraw.
4) Każdy mod ingerujący w zwierzęta.
5) Każdy "menadżer sezonów".
6) Niektóre mody do oczyszczania zwierząt, mogą nie działać prawidłowo (w szczególności podczas zimy).', 226 | de : 'Seasons hat Probleme mit dem Folgendem:
1.) Nicht mehrere Maps laden. Immer nur die Karte, die genutzt wird!
2.) Alle Mods, die das Wetter beeinflussen (z. B. Multi Overlay HUD)
3.) Alle Mods, die das Wachstum beeinflussen
4.) Alle Mods, die die Tierhaltung verändern
5.) Alle Mods in der Art von "Seasons Manager"
6.) Manche Stall-Reinigungs-Mods könnten nicht fehlerfrei funktionieren - vor allem im Winter', 227 | fr : 'Seasons a des problèmes avec les éléments suivants :
1.) Ne chargez pas plusieurs maps. Ne chargez que la map que vous utilisez !
2.) Tout mod qui manipule la météo, [par exemple Multi overlay hud]
3.) Tout mod qui manipule la croissance des cultures
4.) Tout mod qui manipule les animaux
5.) Tout mode de type "Gestionnaire de saisons"
6.) Certains modes de nettoyage des animaux peuvent ne pas fonctionner correctement, surtout en hiver', 228 | }, 229 | }, 230 | 'FS19_realistic' : { 231 | confWith : null, 232 | message : { 233 | en : 'Realistic Yield and Weight is incompatible with the Alpine DLC pack. Wheels tend to glitch through the ground', 234 | pl : '"Realistic Yield and Weight" powoduje konflikt z "Alpine DLC": Koła dziwnie zachowują się na terenie.', 235 | de : 'Der Mod "Realistischer Ertrag und Ladungsgewichte" ist nicht kompatibel mit dem Apline-DLC. Räder tendieren dazu, durch den Boden zu sinken', 236 | fr : 'Le mod Realistic Yield and Weight (Rendement et masses réalistes) est incompatible avec le pack DLC Alpine. Les roues ont tendance à passer à travers le sol', 237 | }, 238 | }, 239 | 'FS19_simpleIC' : { 240 | confWith : ['FS19_towBar'], 241 | message : { 242 | en : 'Loading towBar with Simple IC will cause SimpleIC functions to cease operating.', 243 | pl : 'Mod "towBar" powoduje konflikt z SimpleIC: zostają zablokowane wszystkie funkcje SimpleIC', 244 | fr : 'En chargeant le mod towBar avec SimpleIC, les fonctions de SimpleIC cessent de fonctionner.', 245 | }, 246 | }, 247 | 'FS19_HofBergmann' : { 248 | confWith : [ 249 | 'FS19_MaizePlus', 250 | 'FS19_MaizePlus_ccmExtension', 251 | 'FS19_MaizePlus_forageExtension', 252 | 'FS19_MoreBunkersilo', 253 | 'FS19_1TidyShop_UsedEquipment', 254 | 'FS19_SeeBales', 255 | 'FS19_BulkBuy', 256 | 'FS19_FillLevelLimiter', 257 | 'FS19_BeetHarvest_Addon', 258 | 'FS19_manualAttach', 259 | 'FS19_MapObjectsHider', 260 | 'FS19_towBar', 261 | 'FS19_parkVehicle', 262 | 'FS19_GlobalCompany', 263 | 'FS19_GlobalCompanyAddOn_FieldLease', 264 | ], 265 | message : { 266 | en : 'This mod is part of a list of mods recognized as incompatible with the Hof Bergmann map, as stated in the PDF file that is attached with the map.', 267 | pl : 'Ten mod jest jednym z listy modów uznanych za niekompatybilne z mapą Hof Bergmann, jak określono w pliku PDF dołączonym do mapy.', 268 | fr : 'Ce mod fait partie d\'une liste de mods reconnus comme incompatibles avec la carte Hof Bergmann, comme stipulé dans le fichier PDF qui est joint avec la carte.', 269 | }, 270 | }, 271 | 'FS19_ProductionsForAnimals' : { 272 | confWith : null, 273 | message : { 274 | en : 'In the absence of a compatible map, this mod is the reason for the lack of access to the animal menu.', 275 | }, 276 | }, 277 | } -------------------------------------------------------------------------------- /lib/translate.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // i18n Translator function (simple string mapping with "en" fallback) 7 | 8 | // (c) 2021 JTSage. MIT License. 9 | 10 | // Giants' Version of Country Codes: 11 | // en=English de=German fr=French es=Spanish ru=Russian pl=Polish it=Italian 12 | // br=Brazilian-Portuguese cs=Chinese(Simplified) ct=Chinese(Traditional) 13 | // cz=Czech nl=Netherlands hu=Hungary jp=Japanese kr=Korean pt=Portuguese 14 | // ro=Romanian tr=Turkish 15 | 16 | const fs = require('fs') 17 | const path = require('path') 18 | 19 | module.exports.getSystemLocale = function () { 20 | const systemLocale = Intl.DateTimeFormat().resolvedOptions().locale 21 | switch ( systemLocale ) { 22 | case 'pt-BR' : 23 | return 'br' 24 | case 'zh-CHT': 25 | case 'zh-Hant': 26 | case 'zh-HK': 27 | case 'zh-MO': 28 | case 'zh-TW': 29 | return 'ct' 30 | case 'zh': 31 | case 'zh-CHS': 32 | case 'zh-Hans': 33 | case 'zh-CN': 34 | case 'zh-SG': 35 | return 'cs' 36 | case 'cs': 37 | return 'cz' 38 | case 'ja': 39 | return 'jp' 40 | case 'ko': 41 | return 'kr' 42 | default : 43 | return systemLocale.slice(0, 2) 44 | } 45 | } 46 | module.exports.translator = class translator { 47 | #currentLocale = null 48 | #translatorStrings = [] 49 | #langPromise = null 50 | mcVersion = null 51 | 52 | constructor(locale = 'en') { 53 | this.#currentLocale = locale 54 | 55 | this.#langPromise = this.loadLanguages() 56 | } 57 | 58 | deferCurrentLocale = () => { return this.#currentLocale } 59 | get currentLocale() { return this.#currentLocale } 60 | set currentLocale(value) { 61 | if ( value in this.#translatorStrings ) { 62 | this.#currentLocale = value 63 | } 64 | } 65 | 66 | async loadLanguages() { 67 | 68 | const langJSON = fs.readdirSync(path.join(__dirname, '..', 'translations')) 69 | 70 | langJSON.forEach( (thisFile) => { 71 | if ( path.extname(thisFile) === '.json' ) { 72 | const thisLang = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'translations', thisFile))) 73 | this.#translatorStrings[thisLang.language_code] = thisLang 74 | } 75 | }) 76 | } 77 | 78 | async getLangList() { 79 | return this.#langPromise.then(() => { 80 | const returnArray = [] 81 | returnArray.push(['en', this.#translatorStrings.en.language_name]) 82 | Object.keys(this.#translatorStrings).forEach((key) => { 83 | if ( key !== 'en' ) { 84 | returnArray.push([key, this.#translatorStrings[key].language_name]) 85 | } 86 | }) 87 | return returnArray 88 | }) 89 | } 90 | 91 | syncStringLookup(stringID) { 92 | // Note: this could fail depending on when it's used. 93 | if ( stringID === null ) { return null } 94 | 95 | const lcStringID = stringID.toLowerCase() 96 | 97 | if ( lcStringID === 'mc_ver_string' ) { return this.mcVersion } 98 | 99 | if ( this.#currentLocale in this.#translatorStrings && lcStringID in this.#translatorStrings[this.#currentLocale] ) { 100 | return this.#translatorStrings[this.#currentLocale][lcStringID] 101 | } 102 | if ( lcStringID in this.#translatorStrings.en ) { 103 | return this.#translatorStrings.en[lcStringID] 104 | } 105 | return lcStringID 106 | } 107 | 108 | async stringLookup(stringID) { 109 | return this.#langPromise.then(() => { 110 | if ( stringID === null ) { return null } 111 | 112 | const lcStringID = stringID.toLowerCase() 113 | 114 | if ( lcStringID === 'mc_ver_string' ) { return this.mcVersion } 115 | 116 | if ( this.#currentLocale in this.#translatorStrings && lcStringID in this.#translatorStrings[this.#currentLocale] ) { 117 | return this.#translatorStrings[this.#currentLocale][lcStringID] 118 | } 119 | if ( lcStringID in this.#translatorStrings.en ) { 120 | return this.#translatorStrings.en[lcStringID] 121 | } 122 | return lcStringID 123 | }) 124 | } 125 | } -------------------------------------------------------------------------------- /lib/util-extract-conflicts-strings.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Extract the translatable strings from the conflict list 7 | 8 | const conflictListData = require('./mod-checker-conflicts') 9 | const fs = require('fs') 10 | 11 | const newData = {} 12 | 13 | for ( const [modName, conflictDetails] of Object.entries(conflictListData.conflictMods)) { 14 | const thisString = conflictDetails.message.en 15 | 16 | newData[modName] = thisString 17 | } 18 | 19 | fs.writeFileSync('conflicts.json', JSON.stringify(newData)) 20 | process.stdout.write('written\n') -------------------------------------------------------------------------------- /modChecker.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // CLI Version - Really just here as an example on how to use the 7 | // reader / parser library - which might get split off to it's own 8 | // project (npm module) eventually 9 | 10 | // (c) 2021 JTSage. MIT License. 11 | 12 | const yargs = require('yargs/yargs') 13 | const { hideBin } = require('yargs/helpers') 14 | 15 | const _homedir = require('os').homedir() 16 | const path = require('path') 17 | const xml2js = require('xml2js') 18 | const fs = require('fs') 19 | 20 | const translator = require('./lib/translate.js') 21 | const { modReader, mcLogger } = require('./lib/mod-checker.js') 22 | 23 | const defaultGameFolder = path.join(_homedir, 'Documents', 'My Games', 'FarmingSimulator2019', 'gameSettings.xml' ) 24 | 25 | const myArgs = yargs(hideBin(process.argv)) 26 | .usage('Usage: $0 [options]') 27 | .option('gameSettings', { 28 | default : defaultGameFolder, 29 | alias : 'g', 30 | type : 'string', 31 | description : 'gameSettings.xml location', 32 | }) 33 | .option('modFolder', { 34 | default : null, 35 | alias : 'm', 36 | type : 'string', 37 | description : 'Mod folder to scan (no save game scan)', 38 | }) 39 | .option('lang', { 40 | default : null, 41 | alias : 'l', 42 | type : 'string', 43 | description : 'Language to use', 44 | }) 45 | .option('verbose', { 46 | default : false, 47 | type : 'boolean', 48 | alias : 'v', 49 | description : 'Show run log at end', 50 | }) 51 | .option('conflicts', { 52 | default : true, 53 | type : 'boolean', 54 | description : 'Show conflict list', 55 | }) 56 | .option('broken', { 57 | default : true, 58 | type : 'boolean', 59 | description : 'Show broken list', 60 | }) 61 | .option('missing', { 62 | default : true, 63 | type : 'boolean', 64 | description : 'Show missing list', 65 | }) 66 | .option('inactive', { 67 | default : true, 68 | type : 'boolean', 69 | description : 'Show in-active list', 70 | }) 71 | .option('unused', { 72 | default : true, 73 | type : 'boolean', 74 | description : 'Show unused list', 75 | }) 76 | .example('$0 --gameSettings "c:\\path\\to\\gameSettings.xml"') 77 | .help('h') 78 | .alias('h', 'help') 79 | .epilog('copyright 2021') 80 | .argv 81 | 82 | 83 | writeLn(' _______ __ ______ __ __ ') 84 | writeLn('| | |.-----.--| | | |--.-----.----.| |--.-----.----.') 85 | writeLn('| || _ | _ | ---| | -__| __|| <| -__| _|') 86 | writeLn('|__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| ') 87 | writeLn(' (c) 2021 JTSage') 88 | 89 | const myTranslator = new translator.translator(myArgs.lang === null ? translator.getSystemLocale() : myArgs.lang) 90 | 91 | const logger = new mcLogger() 92 | 93 | let location_modfolder = null 94 | let location_savegame = null 95 | 96 | if ( myArgs.modFolder === null ) { 97 | /* read gameSettings */ 98 | const XMLOptions = {strict : true, async : false, normalizeTags : true, attrNameProcessors : [function(name) { return name.toUpperCase() }] } 99 | const strictXMLParser = new xml2js.Parser(XMLOptions) 100 | 101 | location_savegame = path.dirname(myArgs.gameSettings) 102 | 103 | strictXMLParser.parseString(fs.readFileSync(myArgs.gameSettings), (xmlErr, xmlTree) => { 104 | if ( xmlErr !== null ) { 105 | /* Could not parse the settings file. */ 106 | location_savegame = null 107 | logger.fatal('loader', `Unable to parse gameSettings.xml : ${xmlErr.toString()}`) 108 | writeLn(logger.toDisplayText) 109 | process.exit(1) 110 | } 111 | 112 | if ( ! ('gamesettings' in xmlTree) ) { 113 | /* Not a valid config */ 114 | location_savegame = null 115 | logger.fatal('loader', 'gameSettings.xml does not contain the root gamesettings tag (not a settings file)') 116 | writeLn(logger.toDisplayText) 117 | process.exit(1) 118 | } 119 | 120 | let overrideAttr = false 121 | 122 | try { 123 | overrideAttr = xmlTree.gamesettings.modsdirectoryoverride[0].$ 124 | } catch { 125 | overrideAttr = false 126 | logger.notice('loader', 'Did not find override directive in gameSettings.xml (recovering)') 127 | } 128 | 129 | if ( overrideAttr !== false && overrideAttr.ACTIVE === 'true' ) { 130 | location_modfolder = overrideAttr.DIRECTORY 131 | } else { 132 | location_modfolder = path.join(location_savegame, 'mods') 133 | } 134 | }) 135 | } else { 136 | location_modfolder = myArgs.modFolder 137 | myArgs.unused = false 138 | myArgs.inactive = false 139 | myArgs.missing = false 140 | } 141 | 142 | 143 | const modList = new modReader(location_savegame, location_modfolder, logger, myTranslator.deferCurrentLocale) 144 | 145 | modList.readAll().then(async () => { 146 | if ( myArgs.broken === true ) { 147 | writeLn('') 148 | sepLine() 149 | writeLn(await myTranslator.stringLookup('tab_broken')) 150 | writeLn('') 151 | writeLn(await myTranslator.stringLookup('broken_blurb')) 152 | sepLine() 153 | 154 | await modList.search({ 155 | columns : ['filenameSlash', 'failedTestList', 'copyName', 'shortName'], 156 | terms : ['didTestingFail'], 157 | }).then(async (searchResults) => { 158 | for ( let i = 0; i < searchResults.length; i++) { 159 | writeLn(searchResults[i][0]) 160 | for ( let j = 0; j < searchResults[i][1].length; j++ ) { 161 | /* eslint-disable no-await-in-loop */ 162 | writeLn(` ${await myTranslator.stringLookup(searchResults[i][1][j])}`) 163 | /* eslint-enable */ 164 | } 165 | writeLn('') 166 | } 167 | }).catch((unknownError) => { 168 | // Shouldn't happen. No idea 169 | logger.notice('reader', `Could not get "broken list" : ${unknownError}`) 170 | }) 171 | } 172 | 173 | if ( myArgs.conflicts === true ) { 174 | writeLn('') 175 | sepLine() 176 | writeLn(await myTranslator.stringLookup('tab_conflict')) 177 | writeLn('') 178 | writeLn(await myTranslator.stringLookup('conflict_blurb')) 179 | sepLine() 180 | 181 | const folderAndZipText = await myTranslator.stringLookup('conflict_error_folder_and_file') 182 | 183 | await modList.conflictList(folderAndZipText).then((searchResults) => { 184 | const output = searchResults.map((record) => { 185 | return ` ${record[0]} (${record[1]}) - ${record[2]}` 186 | }) 187 | writeLn(output.join('\n\n')) 188 | }).catch((unknownError) => { 189 | // Shouldn't happen. No idea 190 | logger.notice('reader', `Could not get "conflict list" : ${unknownError}`) 191 | }) 192 | } 193 | 194 | if ( myArgs.missing === true ) { 195 | writeLn('') 196 | sepLine() 197 | writeLn(await myTranslator.stringLookup('tab_missing')) 198 | writeLn('') 199 | writeLn(await myTranslator.stringLookup('missing_blurb')) 200 | sepLine() 201 | const usedString = await myTranslator.stringLookup('detail_mod_used_games') 202 | 203 | await modList.search({ 204 | columns : ['shortName', 'title', 'activeGames', 'usedGames'], 205 | terms : ['isMissing'], 206 | }).then((searchResults) => { 207 | const output = searchResults.map((record) => { 208 | if ( record[3] !== '' ) { 209 | return ` ${record[0]} (${record[1]}) - ${usedString}: ${record[3]}` 210 | } 211 | return ` ${record[0]} (${record[1]})` 212 | }) 213 | writeLn(output.join('\n')) 214 | }).catch((unknownError) => { 215 | // Shouldn't happen. No idea 216 | logger.notice('reader', `Could not get "missing list" : ${unknownError}`) 217 | }) 218 | } 219 | 220 | if ( myArgs.inactive === true ) { 221 | writeLn('') 222 | sepLine() 223 | writeLn(await myTranslator.stringLookup('explore_options_special_inactive')) 224 | sepLine() 225 | 226 | await modList.search({ 227 | columns : [ 228 | 'shortName', 'title', 'fileSizeMap', 229 | ], 230 | activeGame : -1, 231 | allTerms : true, 232 | terms : ['isNotMissing', 'didTestingPassEnough'], 233 | }).then((searchResults) => { 234 | const output = searchResults.map((record) => { 235 | return ` ${record[0]} (${record[1]}) - ${record[2][0]}` 236 | }) 237 | writeLn(output.join('\n')) 238 | }).catch((unknownError) => { 239 | // Shouldn't happen. No idea 240 | logger.notice('reader', `Could not get "explore list" : ${unknownError}`) 241 | }) 242 | } 243 | 244 | if ( myArgs.unused === true ) { 245 | writeLn('') 246 | sepLine() 247 | writeLn(await myTranslator.stringLookup('explore_options_special_unused')) 248 | sepLine() 249 | 250 | await modList.search({ 251 | columns : [ 252 | 'shortName', 'title', 'fileSizeMap', 253 | ], 254 | activeGame : 0, 255 | usedGame : -1, 256 | allTerms : true, 257 | terms : ['isNotMissing', 'didTestingPassEnough'], 258 | }).then((searchResults) => { 259 | const output = searchResults.map((record) => { 260 | return ` ${record[0]} (${record[1]}) - ${record[2][0]}` 261 | }) 262 | writeLn(output.join('\n')) 263 | }).catch((unknownError) => { 264 | // Shouldn't happen. No idea 265 | logger.notice('reader', `Could not get "explore list" : ${unknownError}`) 266 | }) 267 | } 268 | 269 | if ( myArgs.verbose === true ) { 270 | writeLn('') 271 | sepLine() 272 | writeLn('Debug Log') 273 | sepLine() 274 | writeLn(logger.toDisplayText) 275 | } 276 | 277 | }) 278 | 279 | 280 | function sepLine() { 281 | writeLn(' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-') 282 | } 283 | 284 | function writeLn(text) { process.stdout.write(`${text}\n`) } 285 | 286 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fs19-mod-checker", 3 | "version": "3.1.0", 4 | "description": "FS Mod Folder Checker", 5 | "main": "main.js", 6 | "homepage": "https://github.com/jtsage/FS_Mod_Checker#readme", 7 | "keywords": [], 8 | "author": { 9 | "name": "J.T.Sage", 10 | "email": "jtsage+datebox@gmail.com", 11 | "url": "http://jtsage.dev" 12 | }, 13 | "license": "ISC", 14 | "bugs": { 15 | "url": "https://github.com/jtsage/FS_Mod_Checker/issues" 16 | }, 17 | "repository": "github:jtsage/FS_Mod_Checker", 18 | "scripts": { 19 | "pack": "electron-builder --dir", 20 | "dist": "electron-builder", 21 | "test": "node ./test/mod-reader-test.js" 22 | }, 23 | "devDependencies": { 24 | "@babel/core": "^7.14.3", 25 | "@babel/eslint-parser": "^7.14.3", 26 | "ansi-colors": "^4.1.1", 27 | "diff": "^5.0.0", 28 | "electron": "^17.0", 29 | "electron-builder": "^22.14", 30 | "eslint": "^7.27.0" 31 | }, 32 | "dependencies": { 33 | "decode-dxt": "^1.0.1", 34 | "electron-store": "^8.0.1", 35 | "electron-updater": "^4.6.1", 36 | "glob": "^7.1.7", 37 | "node-stream-zip": "^1.13.4", 38 | "parse-dds": "^1.2.1", 39 | "pngjs": "^6.0.0", 40 | "xml2js": "^0.4.23", 41 | "yargs": "^17.0.1" 42 | }, 43 | "build": { 44 | "appId": "jtsage.fsmodchecker", 45 | "productName": "FSModChecker", 46 | "files": [ 47 | "!/test/*", 48 | "!/screen_shots/*", 49 | "!**/.vscode/*", 50 | "!/dist/*" 51 | ], 52 | "win": { 53 | "target": [ 54 | "nsis", 55 | "portable" 56 | ] 57 | }, 58 | "portable": { 59 | "artifactName": "${productName} Portable ${version}.exe" 60 | }, 61 | "mac": { 62 | "category": "public.app-category.productivity" 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /renderer/arrowDbl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/arrowDbl.png -------------------------------------------------------------------------------- /renderer/arrowDbl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/arrowDbl@2x.png -------------------------------------------------------------------------------- /renderer/conarrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/conarrow.png -------------------------------------------------------------------------------- /renderer/conarrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/conarrow@2x.png -------------------------------------------------------------------------------- /renderer/debug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |

15 |
16 |
17 |
18 | 28 |
29 |
30 |
31 | 32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /renderer/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |

v

16 |
17 |
18 |

19 |
20 | 21 |
22 |
23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |

43 |
44 |
45 |
46 |
47 |
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /renderer/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/folder.png -------------------------------------------------------------------------------- /renderer/folder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/folder@2x.png -------------------------------------------------------------------------------- /renderer/inc/sortable.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sortable 1.0 3 | * 4 | * Makes html tables sortable, ie9+ (update note: nope. 2019+ browsers, ish) 5 | * 6 | * Styling is done in css. 7 | * 8 | * Original Copyleft 2017 Jonas Earendel 9 | * New version mostly resembles Jonas' work. 10 | */ 11 | 12 | document.addEventListener('click', (e) => { 13 | const table_class_name = 'sortable' 14 | const class_up = 'dir-u' 15 | const class_dn = 'dir-d' 16 | const element = e.target 17 | 18 | function getValue(element) { 19 | // If you aren't using data-sort and want to make it just the tiniest bit smaller/faster 20 | // comment this line and uncomment the next one 21 | return element.getAttribute('data-sort') || element.innerText 22 | // return element.innerText 23 | } 24 | 25 | if (element.nodeName === 'TH') { 26 | try { 27 | const table = element.closest('table') 28 | const tr = element.parentNode 29 | 30 | if ( table.classList.contains(table_class_name) ) { 31 | let column_index, newDirection 32 | const nodes = tr.cells 33 | 34 | // Get column index, reset classes on everything else 35 | Array.from(nodes).forEach((item, idx) => { 36 | if ( element === item ) { 37 | column_index = idx 38 | newDirection = element.classList.contains(class_dn) ? class_up : class_dn 39 | } 40 | item.classList.remove(class_dn, class_up) 41 | }) 42 | 43 | element.classList.add(newDirection) 44 | 45 | // extract all table rows, so the sorting can start. 46 | const org_tbody = table.tBodies[0] 47 | 48 | // get the array rows in an array, so we can sort them... 49 | const rows = Array.from(org_tbody.rows) 50 | 51 | const reverse = newDirection === class_up 52 | 53 | // sort them using custom built in array sort. 54 | rows.sort((a, b) => { 55 | const x = getValue((reverse ? a : b).cells[column_index]) 56 | const y = getValue((reverse ? b : a).cells[column_index]) 57 | 58 | return isNaN(x - y) ? x.localeCompare(y) : x - y 59 | }) 60 | 61 | // Make a clone without content 62 | const clone_tbody = org_tbody.cloneNode() 63 | 64 | // Build a sorted table body and replace the old one. 65 | while (rows.length) { 66 | clone_tbody.appendChild(rows.splice(0, 1)[0]) 67 | } 68 | 69 | // And finally insert the end result 70 | table.replaceChild(clone_tbody, org_tbody) 71 | } 72 | } catch (error) { 73 | // Do Nothing. 74 | } 75 | } 76 | }) -------------------------------------------------------------------------------- /renderer/prefs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |

v

16 |
17 |
18 |

19 |
20 | 21 |
22 |
23 |

24 |

25 |
26 | 27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 |
38 |
39 |

40 |

41 |
42 | 43 |
44 | 45 |
46 |
47 |
48 | 49 |
50 | 51 |
52 |
53 |
54 | 55 |
56 | 57 |
58 |
59 | 60 |
61 |
62 |

63 |

64 |
65 | 66 |
67 | 68 |
69 |
70 |
71 | 72 |
73 | 74 |
75 |
76 |
77 | 78 |
79 | 80 |
81 |
82 | 83 |
84 |
85 |

86 |

87 | 88 |
89 | 90 |
91 | 92 |
93 |
94 |
95 | 96 |
97 | 98 |
99 |
100 |
101 | 102 |
103 | 104 |
105 |
106 | 107 |
108 |
109 |

110 |

111 |
112 | 113 |
114 | 115 |
116 |
117 |
118 | 119 |
120 | 121 |
122 |
123 | 124 | 125 |
126 |
127 |
128 | 129 | 130 | -------------------------------------------------------------------------------- /renderer/preload-debug.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Mod File Parser - Electron Preload (Detail Window) 7 | // (IPC and UI triggers that interact with the browser process) 8 | 9 | // (c) 2021 JTSage. MIT License. 10 | 11 | const {contextBridge, ipcRenderer} = require('electron') 12 | const autoUpdateTimeSeconds = 30 13 | 14 | /* 15 | _____ _____ _______ _____ ______ _______ _____ __ _ _______ _______ __ _ _______ 16 | | |_____] | . | | | | ____ | | | | \ | | |______ | \ | | 17 | __|__ | |_____ . |_____ |_____| |_____| |_____ |_____| | \_| | |______ | \_| | 18 | 19 | */ 20 | ipcRenderer.on('update-log', ( event, logContents ) => { 21 | document.getElementById('debug_log').innerHTML = logContents 22 | }) 23 | 24 | 25 | contextBridge.exposeInMainWorld( 26 | 'ipc', 27 | { 28 | getDebugLogContents : () => { ipcRenderer.send('getDebugLogContents') }, 29 | saveDebugLogContents : () => { ipcRenderer.send('saveDebugLogContents') }, 30 | } 31 | ) 32 | 33 | window.addEventListener('DOMContentLoaded', () => { 34 | setInterval(() => { 35 | ipcRenderer.send('getDebugLogContents') 36 | }, (autoUpdateTimeSeconds * 1000)) 37 | }) 38 | 39 | 40 | /* 41 | _____ _____ _______ _______ ______ _______ __ _ _______ _______ _______ _______ 42 | | |_____] | . | |_____/ |_____| | \ | |______ | |_____| | |______ 43 | __|__ | |_____ . | | \_ | | | \_| ______| |_____ | | | |______ 44 | 45 | */ 46 | 47 | ipcRenderer.on('trigger-i18n', () => { 48 | /* Get all i18n items in the UI and translate them */ 49 | const sendSet = new Set() 50 | for (const item of document.getElementsByClassName('i18n')) { 51 | sendSet.add(item.getAttribute('data-i18n')) 52 | } 53 | sendSet.forEach( (thisStringID ) => { 54 | ipcRenderer.send('i18n-translate', thisStringID) 55 | }) 56 | }) 57 | 58 | ipcRenderer.on('i18n-translate-return', (event, dataPoint, newText) => { 59 | /* Receive the translated text of an i18n item, update it everywhere it appears */ 60 | const changeThese = document.querySelectorAll(`[data-i18n='${dataPoint}']`) 61 | changeThese.forEach((changeThis) => { 62 | changeThis.innerHTML = newText 63 | }) 64 | }) 65 | 66 | -------------------------------------------------------------------------------- /renderer/preload-detail.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Mod File Parser - Electron Preload (Detail Window) 7 | // (IPC and UI triggers that interact with the browser process) 8 | 9 | // (c) 2021 JTSage. MIT License. 10 | 11 | const {ipcRenderer} = require('electron') 12 | 13 | const iconCheckMark = ''+ 14 | '' + 15 | '' + 16 | '' 17 | const iconX = '' + 18 | '' + 19 | '' + 20 | '' 21 | const iconGreenCheckMark = `${iconCheckMark}` 22 | const iconRedCheckMark = `${iconCheckMark}` 23 | const iconGreenX = `${iconX}` 24 | const iconRedX = `${iconX}` 25 | 26 | const byId = (domID) => { return document.getElementById(domID) } 27 | 28 | 29 | 30 | 31 | 32 | /* 33 | _____ _____ _______ _______ _____ ______ ______ _______ _______ _______ _____ 34 | | |_____] | . | | | | | | \ | \ |______ | |_____| | | 35 | __|__ | |_____ . | | | |_____| |_____/ |_____/ |______ | | | __|__ |_____ 36 | 37 | */ 38 | ipcRenderer.on('mod-record', ( event, modDetails ) => { 39 | byId('title').innerHTML = modDetails.title 40 | byId('version').innerHTML = modDetails.version 41 | byId('filesize').innerHTML = modDetails.filesize 42 | byId('has_scripts').innerHTML = ((modDetails.has_scripts) ? iconGreenCheckMark : iconRedX) 43 | byId('is_multiplayer').innerHTML = ((modDetails.is_multiplayer) ? iconGreenCheckMark : iconRedX) 44 | byId('is_old_shaders').innerHTML = ((modDetails.is_old_shaders) ? iconRedCheckMark : iconGreenX) 45 | byId('store_items').innerHTML = modDetails.store_items 46 | byId('mod_author').innerHTML = (modDetails.mod_author === null ) ? '' : modDetails.mod_author 47 | byId('description').innerHTML = modDetails.description 48 | byId('extraFiles').innerHTML = modDetails.extraFiles.join('\n') 49 | byId('i3dFiles').innerHTML = modDetails.i3dFiles.join('\n') 50 | byId('file_date').innerHTML = modDetails.date.toISOString().substring(0, 16) 51 | byId('newest_part').innerHTML = modDetails.newestPart.toISOString().substring(0, 16) 52 | 53 | const row_legend = modDetails.total_games.map((thisGame) => { return `${thisGame}`}) 54 | const row_active = modDetails.total_games.map((thisGame) => { return `${(modDetails.active_game[thisGame])?iconGreenCheckMark:iconRedX}`}) 55 | const row_used = modDetails.total_games.map((thisGame) => { return `${(modDetails.used_game[thisGame])?iconGreenCheckMark:iconRedX}`}) 56 | 57 | byId('used_active_table').innerHTML = `${row_legend.join('')}${row_active.join('')}${row_used.join('')}` 58 | 59 | }) 60 | 61 | ipcRenderer.on('mod-icon', (event, pngData) => { 62 | if ( pngData !== null ) { 63 | byId('icon_div').innerHTML = `` 64 | } else { 65 | byId('icon_div').classList.add('d-none') 66 | } 67 | }) 68 | 69 | 70 | 71 | 72 | /* 73 | _____ _____ _______ _______ ______ _______ __ _ _______ _______ _______ _______ 74 | | |_____] | . | |_____/ |_____| | \ | |______ | |_____| | |______ 75 | __|__ | |_____ . | | \_ | | | \_| ______| |_____ | | | |______ 76 | 77 | */ 78 | 79 | ipcRenderer.on('trigger-i18n', () => { 80 | /* Get all i18n items in the UI and translate them */ 81 | const sendSet = new Set() 82 | for (const item of document.getElementsByClassName('i18n')) { 83 | sendSet.add(item.getAttribute('data-i18n')) 84 | } 85 | sendSet.forEach( (thisStringID ) => { 86 | ipcRenderer.send('i18n-translate', thisStringID) 87 | }) 88 | }) 89 | 90 | ipcRenderer.on('i18n-translate-return', (event, dataPoint, newText) => { 91 | /* Receive the translated text of an i18n item, update it everywhere it appears */ 92 | const changeThese = document.querySelectorAll(`[data-i18n='${dataPoint}']`) 93 | changeThese.forEach((changeThis) => { 94 | changeThis.innerHTML = newText 95 | }) 96 | }) 97 | 98 | -------------------------------------------------------------------------------- /renderer/preload-main.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Mod File Parser - Electron Preload 7 | // (IPC and UI triggers that interact with the browser process) 8 | 9 | // (c) 2021 JTSage. MIT License. 10 | 11 | const {contextBridge, ipcRenderer} = require('electron') 12 | 13 | const iconCheckMark = ''+ 14 | '' + 15 | '' + 16 | '' 17 | const iconX = '' + 18 | '' + 19 | '' + 20 | '' 21 | const iconGreenCheckMark = `${iconCheckMark}` 22 | const iconRedCheckMark = `${iconCheckMark}` 23 | const iconGreenX = `${iconX}` 24 | const iconRedX = `${iconX}` 25 | 26 | let dataIsLoaded = false 27 | 28 | const byId = (domID) => { return document.getElementById(domID) } 29 | const domClass = (domID, className, doAdd=true) => { 30 | const domIDs = ( typeof domID === 'string' ) ? [domID] : domID 31 | 32 | domIDs.forEach( (thisDomID) => { 33 | const curElement = document.getElementById(thisDomID) 34 | if ( curElement !== null ) { 35 | curElement.classList[( doAdd===true ? 'add' : 'remove' )](className) 36 | } 37 | }) 38 | } 39 | const classAdd = (domID, className) => { domClass(domID, className, true) } 40 | const classRem = (domID, className) => { domClass(domID, className, false) } 41 | 42 | const buildOpt = (value, text, selected) => { 43 | /* Build an option for a select box */ 44 | return `` 45 | } 46 | 47 | const buildTableRow = (columnValues, colNames = [], idPrefix = null) => { 48 | /* Build a table row for display */ 49 | let thisRow = '' 50 | const thisID = idPrefix + columnValues[0] 51 | 52 | for ( let i = 0; i < columnValues.length; i++ ) { 53 | let sort = null 54 | let text = null 55 | let cssClass = '' 56 | 57 | if ( colNames.length > 0 ) { cssClass = colNames[i] } 58 | switch (typeof columnValues[i]) { 59 | 60 | case 'string' : 61 | sort = columnValues[i].toString().toLowerCase() 62 | text = columnValues[i] 63 | break 64 | case 'boolean' : 65 | sort = ( columnValues[i] ? 1 : 0 ) 66 | if ( colNames[i] === 'col_mod_is_old_shader' || colNames[i] === 'col_mod_is_bulky' ) { 67 | text = ( columnValues[i] ? iconRedCheckMark : iconGreenX ) 68 | } else { 69 | text = ( columnValues[i] ? iconGreenCheckMark : iconRedX ) 70 | } 71 | break 72 | default : // Object or Array 73 | sort = columnValues[i][1] 74 | text = columnValues[i][0] 75 | break 76 | } 77 | 78 | thisRow += `${text}` 79 | } 80 | return `${thisRow}` 81 | } 82 | 83 | const buildBrokenList = (name, path, bullets, copyName, shortName) => { 84 | /* Build the broken list (multi level UL) */ 85 | const onlyFolderClass = ( bullets.length === 1 && bullets[0] === 'INFO_NO_MULTIPLAYER_UNZIPPED' ) ? 'just-folder-error' : '' 86 | const thisID = `broke_${shortName}` 87 | 88 | let thisListItem = '' + 89 | `
  • ` + 90 | '
    ' + 91 | `
    ${name} ${path}
    ` + 92 | '
      ' 93 | 94 | if ( copyName !== null ) { 95 | const existence = ( copyName[1] ) ? 'file_error_copy_exists' : 'file_error_copy_missing' 96 | const identCopy = ( copyName[2] ) ? '' : '' 97 | thisListItem += `
    • ${copyName[0]}.` 98 | thisListItem += ` ${identCopy}` 99 | thisListItem += '
    • ' 100 | } 101 | 102 | bullets.forEach((thisBullet) => { 103 | thisListItem += `
    • ` 104 | }) 105 | 106 | return thisListItem += '
  • ' 107 | } 108 | 109 | const buildConflictList = (name, title, message, path) => { 110 | /* Build the conflict list (multi level UL) */ 111 | const onlyFolderClass = ( typeof message !== 'string' && message.length === 1 && message[0] === 'INFO_NO_MULTIPLAYER_UNZIPPED' ) ? 'just-folder-error' : '' 112 | const thisID = `conf_${name}` 113 | 114 | const thisMessage = ( typeof message === 'string' ) ? 115 | `
  • ${message}
  • ` : 116 | message.map((msgPart) => { return `
  • `} ).join('\n') 117 | 118 | return '' + 119 | `
  • ` + 120 | `
    ${name} ${title}
    ` + 121 | `
      ${thisMessage}
  • ` 122 | } 123 | 124 | 125 | 126 | 127 | /* 128 | _____ _____ _______ _______ ______ _______ __ _ _______ _______ _______ _______ 129 | | |_____] | . | |_____/ |_____| | \ | |______ | |_____| | |______ 130 | __|__ | |_____ . | | \_ | | | \_| ______| |_____ | | | |______ 131 | 132 | */ 133 | ipcRenderer.on('trigger-i18n-select', (event, langList, locale) => { 134 | /* Load language options into language pick list */ 135 | const newOpts = langList.map((x) => { return buildOpt(x[0], x[1], locale) }) 136 | 137 | byId('language_select').innerHTML = newOpts.join('') 138 | }) 139 | 140 | ipcRenderer.on('trigger-i18n-on-data', () => { 141 | if ( dataIsLoaded ) { 142 | ipcRenderer.send('askBrokenList') 143 | ipcRenderer.send('askMissingList') 144 | ipcRenderer.send('askConflictList') 145 | ipcRenderer.send('askExploreList', 0) 146 | ipcRenderer.send('askGamesActive') 147 | classRem(['tab_broken', 'tab_missing', 'tab_conflict', 'tab_explore'], 'disabled') 148 | } 149 | }) 150 | 151 | ipcRenderer.on('trigger-i18n', () => { 152 | /* Get all i18n items in the UI and translate them */ 153 | const sendSet = new Set() 154 | for (const item of document.getElementsByClassName('i18n')) { 155 | sendSet.add(item.getAttribute('data-i18n')) 156 | } 157 | sendSet.forEach( (thisStringID ) => { 158 | ipcRenderer.send('i18n-translate', thisStringID) 159 | }) 160 | }) 161 | 162 | ipcRenderer.on('i18n-translate-return', (event, dataPoint, newText) => { 163 | /* Receive the translated text of an i18n item, update it everywhere it appears */ 164 | const changeThese = document.querySelectorAll(`[data-i18n='${dataPoint}']`) 165 | changeThese.forEach((changeThis) => { 166 | changeThis.innerHTML = newText 167 | }) 168 | }) 169 | 170 | 171 | 172 | /* 173 | _____ _____ _______ _______ _____ ______ _______ _____ _ _ _______ ______ 174 | | |_____] | . | | | | | | \ | | | | | \ / |______ | \ 175 | __|__ | |_____ . | | | |_____| |_____/ | | | |_____| \/ |______ |_____/ 176 | 177 | */ 178 | ipcRenderer.on('did-move-mod', (event, modName) => { 179 | const exploreRow = byId(`exp_${modName}`) 180 | const confRow = byId(`conf_${modName}`) 181 | const brokeRow = byId(`broke_${modName}`) 182 | 183 | if ( exploreRow !== null ) { 184 | exploreRow.querySelectorAll('td').forEach((part) => { 185 | part.classList.add('bg-secondary') 186 | }) 187 | } 188 | 189 | if ( confRow !== null ) { 190 | confRow.classList.add('bg-secondary') 191 | } 192 | 193 | if ( brokeRow !== null ) { 194 | brokeRow.classList.add('bg-secondary') 195 | } 196 | }) 197 | 198 | /* 199 | _____ _____ _______ _______ _____ __ _ _______ _____ ______ 200 | | |_____] | . | | | | \ | |______ | | ____ 201 | __|__ | |_____ . |_____ |_____| | \_| | __|__ |_____| 202 | 203 | */ 204 | ipcRenderer.on('newFileConfig', (event, arg) => { 205 | /* Get notification of loading a new config file */ 206 | if ( arg.error ) { 207 | classRem('load_error', 'd-none') 208 | } else { 209 | classAdd('load_error', 'd-none') 210 | } 211 | 212 | if ( arg.valid ) { 213 | classRem('button_process', 'disabled') 214 | } else { 215 | classAdd('button_process', 'disabled') 216 | } 217 | 218 | byId('location_savegame_folder').innerHTML = arg.saveDir === null ? '--' : arg.saveDir 219 | byId('location_mod_folder').innerHTML = arg.modDir === null ? '--' : arg.modDir 220 | 221 | byId('button_process').focus() 222 | }) 223 | 224 | 225 | /* 226 | _____ _____ _______ _____ ______ _____ _______ _______ _______ _______ 227 | | |_____] | . |_____] |_____/ | | | |______ |______ |______ 228 | __|__ | |_____ . | | \_ |_____| |_____ |______ ______| ______| 229 | 230 | */ 231 | ipcRenderer.on('processModsCounter', (event, values) => { 232 | byId('counter_mods_done').innerHTML = values[0] 233 | byId('counter_mods_total').innerHTML = values[1] 234 | }) 235 | ipcRenderer.on('processModsDone', () => { 236 | classAdd('status-message-working', 'd-none') 237 | classRem('status-message-testing', 'd-none') 238 | classRem(['button_process', 'button_load', 'button_load_folder'], 'disabled') 239 | classRem(['tab_broken', 'tab_missing', 'tab_conflict', 'tab_explore'], 'disabled') 240 | 241 | // Fuzzy logic. Used to request reload of display data when changing l10n setting. 242 | dataIsLoaded = true 243 | 244 | ipcRenderer.send('askBrokenList') 245 | ipcRenderer.send('askMissingList') 246 | ipcRenderer.send('askConflictList') 247 | ipcRenderer.send('askExploreList', 0) 248 | ipcRenderer.send('askGamesActive') 249 | }) 250 | 251 | 252 | 253 | /* 254 | _____ _____ _______ ______ ______ _____ _ _ _______ __ _ 255 | | |_____] | . |_____] |_____/ | | |____/ |______ | \ | 256 | __|__ | |_____ . |_____] | \_ |_____| | \_ |______ | \_| 257 | 258 | */ 259 | ipcRenderer.on('gotBrokenList', (event, list) => { 260 | classAdd(['status-message-testing', 'status-icon-working'], 'd-none') 261 | classRem(['status-message-done', 'status-icon-done'], 'd-none') 262 | setTimeout(() => { 263 | classRem(['loadingModal', 'loading_modal_backdrop'], 'show') 264 | classAdd('loading_modal_backdrop', 'd-none') 265 | classAdd(['tab_broken', 'tab_missing', 'tab_conflict', 'tab_explore'], 'flashonce') 266 | document.getElementById('loadingModal').style.display = null 267 | setTimeout(() => { 268 | classAdd(['status-message-done', 'status-icon-done'], 'd-none') 269 | classRem(['status-message-working', 'status-icon-working'], 'd-none') 270 | }, 1000) 271 | }, 1500) 272 | 273 | if ( list.length === 0 ) { 274 | classRem('no_broken', 'd-none') 275 | } else { 276 | classAdd('no_broken', 'd-none') 277 | } 278 | 279 | const newContent = list.map((x) => { return buildBrokenList(...x) }) 280 | byId('broken_list').innerHTML = newContent.join('') 281 | 282 | const sendSet = new Set() 283 | for (const item of byId('broken_list').getElementsByClassName('i18n')) { 284 | sendSet.add(item.getAttribute('data-i18n')) 285 | } 286 | sendSet.forEach( (thisStringID ) => { 287 | ipcRenderer.send('i18n-translate', thisStringID) 288 | }) 289 | }) 290 | 291 | 292 | 293 | /* 294 | _____ _____ _______ _______ _____ __ _ _______ _____ _______ _______ _______ 295 | | |_____] | . | | | | \ | |______ | | | | |______ 296 | __|__ | |_____ . |_____ |_____| | \_| | |_____ __|__ |_____ | ______| 297 | 298 | */ 299 | ipcRenderer.on('gotConflictList', (event, list) => { 300 | if ( list.length === 0 ) { 301 | classRem('no_conflict', 'd-none') 302 | } else { 303 | classAdd('no_conflict', 'd-none') 304 | } 305 | 306 | const newContent = list.map((x) => { return buildConflictList(...x) }) 307 | byId('conflict_list').innerHTML = newContent.join('') 308 | 309 | const sendSet = new Set() 310 | for (const item of byId('conflict_list').getElementsByClassName('i18n')) { 311 | sendSet.add(item.getAttribute('data-i18n')) 312 | } 313 | sendSet.forEach( (thisStringID ) => { 314 | ipcRenderer.send('i18n-translate', thisStringID) 315 | }) 316 | }) 317 | 318 | 319 | 320 | /* 321 | _____ _____ _______ _______ _____ _______ _______ _____ __ _ ______ 322 | | |_____] | . | | | | |______ |______ | | \ | | ____ 323 | __|__ | |_____ . | | | __|__ ______| ______| __|__ | \_| |_____| 324 | 325 | */ 326 | ipcRenderer.on('gotMissingList', (event, list) => { 327 | const newContent = list.map((x) => { return buildTableRow(x) }) 328 | 329 | if ( list.length === 0 ) { 330 | classRem('no_missing', 'd-none') 331 | } else { 332 | classAdd('no_missing', 'd-none') 333 | } 334 | 335 | byId('table_missing').innerHTML = newContent.join('') 336 | }) 337 | 338 | 339 | /* 340 | _____ _____ _______ _______ _ _ _____ _____ ______ _______ 341 | | |_____] | . |______ \___/ |_____] | | | |_____/ |______ 342 | __|__ | |_____ . |______ _/ \_ | |_____ |_____| | \_ |______ 343 | 344 | */ 345 | ipcRenderer.on('gotExploreList', (event, list) => { 346 | const colNames = [ 347 | 'col_mod_name', 348 | 'col_mod_title', 349 | 'col_mod_version', 350 | 'col_mod_size', 351 | 'col_mod_date', 352 | 'col_mod_is_active', 353 | 'col_mod_active_games', 354 | 'col_mod_is_used', 355 | 'col_mod_used_games', 356 | 'col_mod_full_path', 357 | 'col_mod_has_scripts', 358 | 'col_mod_is_multiplayer', 359 | 'col_mod_is_bulky', 360 | 'col_mod_is_old_shader', 361 | ] 362 | 363 | const newContent = list.map((x) => { return buildTableRow(x, colNames, 'exp_') }) 364 | 365 | byId('table_explore').innerHTML = newContent.join('') 366 | 367 | byId('col_mod_name_switch').dispatchEvent(new Event('change')) 368 | }) 369 | 370 | 371 | 372 | 373 | /* 374 | _____ _____ _______ _______ _______ _______ _____ _ _ _______ 375 | | |_____] | . |_____| | | | \ / |______ 376 | __|__ | |_____ . | | |_____ | __|__ \/ |______ 377 | 378 | */ 379 | ipcRenderer.on('gotGamesActive', (event, list, saveGameText, allText) => { 380 | /* Change explore list based on save game filter */ 381 | let newOptions = buildOpt(0, allText, 0) 382 | 383 | list.forEach((thisGame) => { 384 | newOptions += buildOpt(thisGame, saveGameText + thisGame, 0) 385 | }) 386 | 387 | byId('savegame_select').innerHTML = newOptions 388 | 389 | const sendSet = new Set() 390 | for (const item of byId('savegame_select').getElementsByClassName('i18n')) { 391 | sendSet.add(item.getAttribute('data-i18n')) 392 | } 393 | sendSet.forEach( (thisStringID ) => { 394 | ipcRenderer.send('i18n-translate', thisStringID) 395 | }) 396 | }) 397 | 398 | 399 | /* 400 | _______ _ _ _______ _____ _____ ______ _____ _______ _______ _______ _______ 401 | |_____| | | | | | |_____] |_____/ | | | |______ |______ |______ 402 | | | |_____| | |_____| | | \_ |_____| |_____ |______ ______| ______| 403 | 404 | */ 405 | // Because of earlier choices, it's easiest to fake a click in the renderer so that all the 406 | // events go to the right place. 407 | 408 | ipcRenderer.on('trigger_version', (event, versionNum) => { 409 | if ( versionNum === 19 ) { 410 | classRem(['ver_icon_19'], 'd-none') 411 | classAdd(['ver_icon_22'], 'd-none') 412 | } else { 413 | classAdd(['ver_icon_19'], 'd-none') 414 | classRem(['ver_icon_22'], 'd-none') 415 | } 416 | }) 417 | 418 | ipcRenderer.on('autoProcess', () => { 419 | ipcRenderer.send('processMods') 420 | classRem(['tab_broken', 'tab_missing', 'tab_conflict', 'tab_explore'], 'flashonce') 421 | classAdd(['button_process', 'button_load', 'button_load_folder'], 'disabled') 422 | classRem('loading_modal_backdrop', 'd-none') 423 | classAdd(['loadingModal', 'loading_modal_backdrop'], 'show') 424 | byId('counter_mods_done').innerHTML = 0 425 | byId('counter_mods_total').innerHTML = 0 426 | document.getElementById('loadingModal').style.display = 'block' 427 | }) 428 | 429 | 430 | 431 | /* 432 | _______ _ _ _____ _____ _______ _______ ______ _______ _____ _____ 433 | |______ \___/ |_____] | | |______ |______ | \ |_____| |_____] | 434 | |______ _/ \_ | |_____| ______| |______ |_____/ | | | __|__ 435 | 436 | Functions that are exposed to the UI renderer process 437 | */ 438 | contextBridge.exposeInMainWorld( 439 | 'ipc', 440 | { 441 | changeLangList : () => { 442 | ipcRenderer.send('i18n-change-locale', byId('language_select').value) 443 | }, 444 | openPreferences : () => { 445 | ipcRenderer.send('askOpenPreferencesWindow') 446 | }, 447 | loadButton : () => { 448 | ipcRenderer.send('openConfigFile') 449 | dataIsLoaded = false 450 | }, 451 | loadFolder : () => { 452 | ipcRenderer.send('openOtherFolder') 453 | dataIsLoaded = false 454 | }, 455 | setVer2019 : () => { 456 | ipcRenderer.send('setGameVersion', 19) 457 | classRem(['ver_icon_19'], 'd-none') 458 | classAdd(['ver_icon_22'], 'd-none') 459 | dataIsLoaded = false 460 | }, 461 | setVer2022 : () => { 462 | ipcRenderer.send('setGameVersion', 22) 463 | classAdd(['ver_icon_19'], 'd-none') 464 | classRem(['ver_icon_22'], 'd-none') 465 | dataIsLoaded = false 466 | }, 467 | processButton : () => { 468 | ipcRenderer.send('processMods') 469 | classRem(['tab_broken', 'tab_missing', 'tab_conflict', 'tab_explore'], 'flashonce') 470 | classAdd(['button_process', 'button_load', 'button_load_folder'], 'disabled') 471 | classRem('loading_modal_backdrop', 'd-none') 472 | classAdd(['loadingModal', 'loading_modal_backdrop'], 'show') 473 | byId('counter_mods_done').innerHTML = 0 474 | byId('counter_mods_total').innerHTML = 0 475 | document.getElementById('loadingModal').style.display = 'block' 476 | }, 477 | changeExplore : () => { 478 | ipcRenderer.send('askExploreList', byId('savegame_select').value) 479 | }, 480 | changeExploreActiveUnused : () => { 481 | ipcRenderer.send('askExploreList', 0, -1) 482 | }, 483 | changeExploreInActive : () => { 484 | ipcRenderer.send('askExploreList', -1) 485 | }, 486 | changeExploreScripts : () => { 487 | ipcRenderer.send('askExploreList', 0, 0, 'hasScripts') 488 | byId('col_mod_has_scripts_switch').checked = true 489 | }, 490 | openDebugLogContents : () => { 491 | ipcRenderer.send('openDebugLogContents') 492 | }, 493 | refreshBroken : () => { 494 | ipcRenderer.send('askBrokenList') 495 | }, 496 | refreshMissing : () => { 497 | ipcRenderer.send('askMissingList') 498 | }, 499 | refreshConflict : () => { 500 | ipcRenderer.send('askConflictList') 501 | }, 502 | refreshExplore : () => { 503 | ipcRenderer.send('askExploreList', 0) 504 | }, 505 | 506 | } 507 | ) 508 | 509 | 510 | 511 | /* 512 | _______ _______ __ _ _ _ _______ 513 | | | | |______ | \ | | | |______ 514 | | | | |______ | \_| |_____| ______| 515 | 516 | Listeners on the renderer that need privileged execution (ipc usually) 517 | */ 518 | 519 | window.addEventListener('DOMContentLoaded', () => { 520 | const table_handler = (e, domID) => { 521 | e.preventDefault() 522 | 523 | if ( e.target.matches('td') ) { 524 | const theseHeaders = Array.from( 525 | byId(domID).parentNode.firstElementChild.querySelectorAll('th.i18n'), 526 | (th) => [th.innerText, th.getAttribute('data-i18n')] 527 | ) 528 | const theseValues = Array.from( 529 | e.target.parentNode.childNodes, 530 | (td) => td.innerText 531 | ) 532 | ipcRenderer.send('show-context-menu-table', theseHeaders, theseValues) 533 | } 534 | } 535 | const table_dblclick = (e) => { 536 | e.preventDefault() 537 | 538 | if ( e.target.matches('td') ) { 539 | const thisMod = e.target.parentNode.childNodes[0].innerText 540 | ipcRenderer.send('show-mod-detail', thisMod) 541 | } 542 | } 543 | const list_handler = (e) => { 544 | e.preventDefault() 545 | 546 | const closestEntry = e.target.closest('.mod-record') 547 | 548 | if ( closestEntry !== null ) { 549 | ipcRenderer.send('show-context-menu-list', closestEntry.getAttribute('data-path'), closestEntry.getAttribute('data-name')) 550 | } 551 | } 552 | 553 | byId('broken_list').addEventListener('contextmenu', (e) => { list_handler(e) }) 554 | byId('conflict_list').addEventListener('contextmenu', (e) => {list_handler(e) }) 555 | 556 | byId('table_missing_parent').addEventListener('dblclick', (e) => { table_dblclick(e) }) 557 | byId('table_explore_parent').addEventListener('dblclick', (e) => { table_dblclick(e) }) 558 | 559 | byId('table_missing_parent').addEventListener('contextmenu', (e) => { table_handler(e, 'table_missing') }) 560 | byId('table_explore_parent').addEventListener('contextmenu', (e) => { table_handler(e, 'table_explore') }) 561 | }) -------------------------------------------------------------------------------- /renderer/preload-pref.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Mod File Parser - Electron Preload (Preferences Window) 7 | // (IPC and UI triggers that interact with the browser process) 8 | 9 | // (c) 2021 JTSage. MIT License. 10 | 11 | const {contextBridge, ipcRenderer} = require('electron') 12 | 13 | const byId = (domID) => { return document.getElementById(domID) } 14 | 15 | contextBridge.exposeInMainWorld( 16 | 'ipc', 17 | { 18 | setLockLang : () => { 19 | ipcRenderer.send('setPreference', 'lock_lang', byId('lock_lang').checked ) 20 | }, 21 | setRememberLast : () => { 22 | ipcRenderer.send('setPreference', 'remember_last', byId('remember_last').checked ) 23 | }, 24 | setAutoProcess : () => { 25 | ipcRenderer.send('setPreference', 'auto_process', byId('auto_process').checked) 26 | }, 27 | setMainWindowX : () => { 28 | ipcRenderer.send('setPreference', 'main_window_x', parseInt(byId('main_window_x').value)) 29 | }, 30 | setMainWindowY : () => { 31 | ipcRenderer.send('setPreference', 'main_window_y', parseInt(byId('main_window_y').value)) 32 | }, 33 | setMainWindowMax : () => { 34 | ipcRenderer.send('setPreference', 'main_window_max', byId('main_window_max').checked) 35 | }, 36 | 37 | setDetailWindowX : () => { 38 | ipcRenderer.send('setPreference', 'detail_window_x', parseInt(byId('detail_window_x').value)) 39 | }, 40 | setDetailWindowY : () => { 41 | ipcRenderer.send('setPreference', 'detail_window_y', parseInt(byId('detail_window_y').value)) 42 | }, 43 | setDetailWindowMax : () => { 44 | ipcRenderer.send('setPreference', 'detail_window_max', byId('detail_window_max').checked) 45 | }, 46 | 47 | setUseMove : () => { 48 | // only if turning it off 49 | if ( byId('use_move').checked === false ) { 50 | 51 | ipcRenderer.send('setPreference', 'use_move', false) 52 | ipcRenderer.send('setPreference', 'move_destination', null) 53 | ipcRenderer.send('refreshPreferences') 54 | } else { 55 | ipcRenderer.send('refreshPreferences') 56 | return false 57 | } 58 | }, 59 | 60 | chooseMoveFolder : () => { 61 | ipcRenderer.send('setMoveFolder') 62 | }, 63 | openCleanDir : () => { 64 | ipcRenderer.send('openCleanDir') 65 | }, 66 | 67 | } 68 | ) 69 | 70 | ipcRenderer.on('got-pref-settings', (event, allPrefs, lang) => { 71 | byId('lock_lang').checked = ( 'lock_lang' in allPrefs ) ? allPrefs.lock_lang : false 72 | byId('current_lang').innerHTML = lang 73 | 74 | byId('remember_last').checked = ( 'remember_last' in allPrefs ) ? allPrefs.remember_last : true 75 | byId('current_gamesettings').innerHTML = ( 'gamesettings' in allPrefs ) ? allPrefs.gamesettings : '--' 76 | byId('auto_process').checked = ( 'auto_process' in allPrefs ) ? allPrefs.auto_process : false 77 | 78 | byId('main_window_x').value = ( 'main_window_x' in allPrefs ) ? allPrefs.main_window_x : 1000 79 | byId('main_window_y').value = ( 'main_window_y' in allPrefs ) ? allPrefs.main_window_y : 700 80 | byId('main_window_max').checked = ( 'main_window_max' in allPrefs ) ? allPrefs.main_window_max : false 81 | 82 | byId('detail_window_x').value = ( 'detail_window_x' in allPrefs ) ? allPrefs.detail_window_x : 800 83 | byId('detail_window_y').value = ( 'detail_window_y' in allPrefs ) ? allPrefs.detail_window_y : 500 84 | byId('detail_window_max').checked = ( 'detail_window_max' in allPrefs ) ? allPrefs.detail_window_max : false 85 | 86 | byId('use_move').checked = ( 'use_move' in allPrefs ) ? allPrefs.use_move : false 87 | byId('move_destination').innerHTML = ( 'move_destination' in allPrefs ) ? allPrefs.move_destination : false 88 | }) 89 | 90 | /* 91 | _____ _____ _______ _______ ______ _______ __ _ _______ _______ _______ _______ 92 | | |_____] | . | |_____/ |_____| | \ | |______ | |_____| | |______ 93 | __|__ | |_____ . | | \_ | | | \_| ______| |_____ | | | |______ 94 | 95 | */ 96 | 97 | ipcRenderer.on('trigger-i18n', () => { 98 | /* Get all i18n items in the UI and translate them */ 99 | const sendSet = new Set() 100 | for (const item of document.getElementsByClassName('i18n')) { 101 | sendSet.add(item.getAttribute('data-i18n')) 102 | } 103 | sendSet.forEach( (thisStringID ) => { 104 | ipcRenderer.send('i18n-translate', thisStringID) 105 | }) 106 | }) 107 | 108 | ipcRenderer.on('i18n-translate-return', (event, dataPoint, newText) => { 109 | /* Receive the translated text of an i18n item, update it everywhere it appears */ 110 | const changeThese = document.querySelectorAll(`[data-i18n='${dataPoint}']`) 111 | changeThese.forEach((changeThis) => { 112 | changeThis.innerHTML = newText 113 | }) 114 | }) 115 | 116 | -------------------------------------------------------------------------------- /renderer/repocard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/repocard.png -------------------------------------------------------------------------------- /renderer/repocard@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/repocard@2x.png -------------------------------------------------------------------------------- /renderer/scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/scan.png -------------------------------------------------------------------------------- /renderer/scan@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/scan@2x.png -------------------------------------------------------------------------------- /renderer/splash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 23 | 24 | 25 | 26 | 27 |
    28 | 29 | -------------------------------------------------------------------------------- /renderer/ui-splash.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Mod File Parser - UI Tweaks, Renderer (Splash Screen) 7 | 8 | // (c) 2021 JTSage. MIT License. 9 | window.addEventListener('DOMContentLoaded', () => { 10 | const urlParams = new URLSearchParams(window.location.search) 11 | const version = urlParams.get('version') 12 | document.getElementById('version').innerText = `v${version}` 13 | }) 14 | 15 | -------------------------------------------------------------------------------- /renderer/ui.js: -------------------------------------------------------------------------------- 1 | /* _______ __ ______ __ __ 2 | | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | | || _ | _ | ---| | -__| __|| <| -__| _| 4 | |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| */ 5 | 6 | // Renderer Thread - UI Functions that don't require data from browser process 7 | 8 | // (c) 2021 JTSage. MIT License. 9 | 10 | const byId = function( id ) { return document.getElementById( id ) } 11 | 12 | function toggleHideFolderOnlyError() { 13 | const folderOnly = byId('conflict_list').querySelectorAll('.just-folder-error') 14 | const status = byId('zip_folder_switch').checked 15 | 16 | folderOnly.forEach((thisConflict) => { 17 | if ( status ) { 18 | thisConflict.classList.add('d-none') 19 | } else { 20 | thisConflict.classList.remove('d-none') 21 | } 22 | }) 23 | } 24 | 25 | function toggleExploreColumns () { 26 | const columns = [ 27 | 'mod_name', 28 | 'mod_title', 29 | 'mod_version', 30 | 'mod_size', 31 | 'mod_date', 32 | 'mod_is_active', 33 | 'mod_active_games', 34 | 'mod_is_used', 35 | 'mod_used_games', 36 | 'mod_full_path', 37 | 'mod_has_scripts', 38 | 'mod_is_old_shader', 39 | 'mod_is_bulky', 40 | 'mod_is_multiplayer', 41 | ] 42 | columns.forEach((thisCol) => { 43 | const theseItems = byId('table_explore_parent').querySelectorAll(`.col_${thisCol}`) 44 | const colStatus = byId(`col_${thisCol}_switch`).checked 45 | 46 | theseItems.forEach((thisRow) => { 47 | if ( colStatus === true ) { 48 | thisRow.classList.remove('d-none') 49 | } else { 50 | thisRow.classList.add('d-none') 51 | } 52 | }) 53 | }) 54 | } 55 | 56 | function searchExploreClear() { 57 | byId('explore-search').value = '' 58 | searchExploreTable() 59 | } 60 | function searchExploreTable() { 61 | const exploreTable = byId('table_explore').querySelectorAll('tbody>tr') 62 | const searchTerm = byId('explore-search').value.toLowerCase() 63 | 64 | exploreTable.forEach((thisTD) => { 65 | const testString = (thisTD.childNodes[0].innerText + thisTD.childNodes[1].innerText).toLowerCase() 66 | 67 | if ( testString.indexOf(searchTerm) > -1 ) { 68 | thisTD.classList.remove('d-none') 69 | } else { 70 | thisTD.classList.add('d-none') 71 | } 72 | }) 73 | } 74 | 75 | function resizeWindow() { 76 | setTimeout(() => { 77 | const headerHeight = byId('main-header').offsetHeight 78 | const footerHeight = byId('main-footer').offsetHeight 79 | const newTabHeight = window.innerHeight - headerHeight - footerHeight 80 | byId('mainTabContent').style.height = `${newTabHeight}px` 81 | byId('mainTabContent').style.marginTop = `${headerHeight}px` 82 | }, 500) 83 | } 84 | 85 | window.addEventListener('DOMContentLoaded', () => { 86 | toggleExploreColumns() 87 | toggleHideFolderOnlyError() 88 | searchExploreClear() 89 | resizeWindow() 90 | }) -------------------------------------------------------------------------------- /renderer/version_icon_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/version_icon_19.png -------------------------------------------------------------------------------- /renderer/version_icon_19@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/version_icon_19@2x.png -------------------------------------------------------------------------------- /renderer/version_icon_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/version_icon_22.png -------------------------------------------------------------------------------- /renderer/version_icon_22@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/version_icon_22@2x.png -------------------------------------------------------------------------------- /renderer/xml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/xml.png -------------------------------------------------------------------------------- /renderer/xml@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/renderer/xml@2x.png -------------------------------------------------------------------------------- /screen_shots/001-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/001-config.png -------------------------------------------------------------------------------- /screen_shots/002-broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/002-broken.png -------------------------------------------------------------------------------- /screen_shots/003-missing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/003-missing.png -------------------------------------------------------------------------------- /screen_shots/004-conflict.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/004-conflict.png -------------------------------------------------------------------------------- /screen_shots/005-explore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/005-explore.png -------------------------------------------------------------------------------- /screen_shots/006-explore-options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/006-explore-options.png -------------------------------------------------------------------------------- /screen_shots/010-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/010-detail.png -------------------------------------------------------------------------------- /screen_shots/020-prefs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/screen_shots/020-prefs.png -------------------------------------------------------------------------------- /test/mod-reader-test.js: -------------------------------------------------------------------------------- 1 | // _______ __ ______ __ __ 2 | // | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | // | || _ | _ | ---| | -__| __|| <| -__| _| 4 | // |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| 5 | 6 | // Test to make sure the mod reader is working as expected 7 | 8 | // (c) 2021 JTSage. MIT License. 9 | require('colors') 10 | const path = require('path') 11 | const c = require('ansi-colors') 12 | const Diff = require('diff') 13 | 14 | const gameFolder = path.join(__dirname, 'testRunnerMods') 15 | const fileFolder = path.join(gameFolder, 'mods') 16 | 17 | const { modReader, mcLogger } = require('../lib/mod-checker.js') 18 | const translator = require('../lib/translate.js') 19 | const myTranslator = new translator.translator('en') 20 | 21 | let exitCode = 0 22 | const logger = new mcLogger() 23 | const modList = new modReader(gameFolder, fileFolder, logger, myTranslator.deferCurrentLocale) 24 | 25 | const expectedConflictList = [ 26 | 'EXAMPLE_Fake_Cracked_DLC', 27 | 'EXAMPLE_Good_Mod (1), EXAMPLE_Good_Mod - Copy, EXAMPLE_Good_Mod, EXAMPLE_Good_Mod_Folder_and_Zip, EXAMPLE_Good_Mod_No_Original - Copy, EXAMPLE_Good_Mod_Folder_Warning', 28 | 'EXAMPLE_Good_Mod_Folder_and_Zip', 29 | 'EXAMPLE_Good_Mod_Folder_Warning' 30 | ] 31 | const expectedBrokenList = [ 32 | ['EXAMPLE_Broken_Zip_File', 33 | ['FILE_ERROR_UNREADABLE_ZIP'] 34 | ], 35 | ['EXAMPLE_Garbage_File', 36 | ['FILE_ERROR_NAME_INVALID', 'FILE_ERROR_GARBAGE_FILE'] 37 | ], 38 | ['EXAMPLE_Good_Mod (1)', 39 | ['FILE_ERROR_LIKELY_COPY', 'FILE_ERROR_NAME_INVALID'] 40 | ], 41 | ['EXAMPLE_Good_Mod - Copy', 42 | ['FILE_ERROR_LIKELY_COPY', 'FILE_ERROR_NAME_INVALID'] 43 | ], 44 | ['EXAMPLE_Good_Mod_No_Original - Copy', 45 | ['FILE_ERROR_LIKELY_COPY', 'FILE_ERROR_NAME_INVALID'] 46 | ], 47 | ['EXAMPLE_Icon_Not_Found', 48 | ['MOD_ERROR_NO_MOD_ICON'] 49 | ], 50 | ['EXAMPLE_Malformed_ModDesc', 51 | ['MOD_ERROR_MODDESC_DAMAGED_RECOVERABLE'] 52 | ], 53 | ['EXAMPLE_Missing_ModDesc', 54 | ['NOT_MOD_MODDESC_MISSING'] 55 | ], 56 | ['EXAMPLE_No_Icon', 57 | ['MOD_ERROR_NO_MOD_ICON'] 58 | ], 59 | ['EXAMPLE_No_Version', 60 | ['MOD_ERROR_NO_MOD_VERSION'] 61 | ], 62 | ['EXAMPLE_Old_ModDesc', 63 | ['NOT_MOD_MODDESC_VERSION_OLD_OR_MISSING'] 64 | ], 65 | ['EXAMPLE_Really_Malformed_ModDesc', 66 | ['MOD_ERROR_MODDESC_DAMAGED_RECOVERABLE', 'MOD_ERROR_NO_MOD_ICON'] 67 | ] 68 | ] 69 | const expectedGoodList = [ 70 | ['EXAMPLE_Bad_ModDesc_CRC', 'Bulbulator', '1.0.0.0'], 71 | ['EXAMPLE_Fake_Cracked_DLC', 'Fake Cracked DLC', '1.0.0.0'], 72 | ['EXAMPLE_Good_Mod', 'Totally valid FS19 Mod', '1.0.0.0'], 73 | ['EXAMPLE_Good_Mod_Folder_and_Zip', 'Totally valid FS19 Mod', '1.0.0.0'], 74 | ['EXAMPLE_Good_Mod_Folder_Warning', 'Totally valid FS19 Mod', '1.0.0.0'], 75 | ['EXAMPLE_Malformed_ModDesc', 'Mod with malformed XML', '1.0.0.0'] 76 | ] 77 | 78 | 79 | modList.readAll().then(() => { 80 | writeLn(c.cyan('NOTICE: File Read Done, Testing Proceeding Async - Calling First Search, will return when testing is complete.')) 81 | 82 | /* Check broken list */ 83 | modList.getBrokenList(['shortName', 'failedTestList']).then((results) => { 84 | if (JSON.stringify(expectedBrokenList) === JSON.stringify(results)) { 85 | writeLn(c.green('PASS: Broken list is as expected')) 86 | } else { 87 | exitCode = 1 88 | writeLn(c.red('FAIL: Broken list is not as expected')) 89 | const diff = Diff.diffChars(JSON.stringify(expectedBrokenList), JSON.stringify(results)) 90 | 91 | diff.forEach((part) => { 92 | const color = part.added ? 'green' : 93 | part.removed ? 'red' : 'grey' 94 | process.stderr.write(part.value[color]) 95 | }) 96 | writeLn() 97 | } 98 | }) 99 | 100 | /* Check conflict list */ 101 | modList.conflictList('').then((results) => { 102 | const simpleResults = results.map((x) => { return x[0] }) 103 | if (JSON.stringify(simpleResults) === JSON.stringify(expectedConflictList)) { 104 | writeLn(c.green('PASS: Conflict list is as expected')) 105 | } else { 106 | exitCode = 1 107 | writeLn(c.red('FAIL: Conflict list is not as expected')) 108 | const diff = Diff.diffChars(JSON.stringify(expectedConflictList), JSON.stringify(simpleResults)) 109 | 110 | diff.forEach((part) => { 111 | const color = part.added ? 'green' : 112 | part.removed ? 'red' : 'grey' 113 | process.stderr.write(part.value[color]) 114 | }) 115 | writeLn() 116 | } 117 | }) 118 | 119 | /* Check good list */ 120 | modList.search({ 121 | columns : ['shortName', 'title', 'mod_version'], 122 | allTerms : true, 123 | terms : ['isNotMissing', 'didTestingPassEnough'], 124 | }).then((results) => { 125 | if (JSON.stringify(expectedGoodList) === JSON.stringify(results)) { 126 | writeLn(c.green('PASS: Good list is as expected')) 127 | } else { 128 | exitCode = 1 129 | writeLn(c.red('FAIL: Good list is not as expected')) 130 | const diff = Diff.diffChars(JSON.stringify(expectedGoodList), JSON.stringify(results)) 131 | 132 | diff.forEach((part) => { 133 | const color = part.added ? 'green' : 134 | part.removed ? 'red' : 'grey' 135 | process.stderr.write(part.value[color]) 136 | }) 137 | writeLn() 138 | } 139 | if ( exitCode === 1 ) { 140 | writeLn(logger.toDisplayText) 141 | } 142 | process.exit(exitCode) 143 | }) 144 | }) 145 | 146 | 147 | writeLn(c.cyan('NOTICE: End File Code. There may (should!) still be running async processes')) 148 | 149 | function writeLn(text) { process.stdout.write(`${text}\n`) } -------------------------------------------------------------------------------- /test/simpleQuery.js: -------------------------------------------------------------------------------- 1 | // _______ __ ______ __ __ 2 | // | | |.-----.--| | | |--.-----.----.| |--.-----.----. 3 | // | || _ | _ | ---| | -__| __|| <| -__| _| 4 | // |__|_|__||_____|_____|______|__|__|_____|____||__|__|_____|__| 5 | 6 | // Simple script for live testing in development environments 7 | 8 | // (c) 2021 JTSage. MIT License. 9 | const path = require('path') 10 | 11 | const gameFolder = path.join(__dirname, '..', '..', 'testFolder') 12 | const fileFolder = path.join(gameFolder, 'mods') 13 | 14 | const { modReader, mcLogger } = require('../lib/mod-checker.js') 15 | const translator = require('../lib/translate.js') 16 | const myTranslator = new translator.translator(translator.getSystemLocale()) 17 | 18 | const logger = new mcLogger() 19 | const modList = new modReader(gameFolder, fileFolder, logger, myTranslator.deferCurrentLocale) 20 | 21 | 22 | modList.readAll().then(() => { 23 | writeLn('File Read Done, Testing Proceeding Async - Calling First Search, will return when testing is complete.') 24 | 25 | modList.search({ 26 | columns : [ 27 | 'shortName', 28 | //'isActive', 29 | //'isUsed', 30 | 'isFolder', 31 | 'didTestingPassEnough', 32 | // 'title', 33 | // 'mod_version', 34 | //'fileSizeMap', 35 | //'activeGames', 36 | //'usedGames', 37 | 'howIsModBroken', 38 | // 'fullPath', 39 | ], 40 | //usedGame : -1, 41 | allTerms : true, 42 | terms : ['isModBroken'], 43 | debug : true, 44 | }).then((searchResults) => { 45 | writeLn('test.js results:', searchResults) 46 | //writeLn(modList.log.toDisplayText) 47 | }) 48 | }) 49 | 50 | async function _promiseStatus() { 51 | /* This is *spiffy* - it looks at the status of the testing promises, with a quick delay. 52 | Assuming everything is working correctly, you should see them resolve in parallel. */ 53 | /* eslint-disable no-promise-executor-return */ 54 | writeLn(modList.testPromise) 55 | await new Promise((resolve) => setTimeout(resolve, 150)) 56 | writeLn(modList.testPromise) 57 | await new Promise((resolve) => setTimeout(resolve, 150)) 58 | writeLn(modList.testPromise) 59 | await new Promise((resolve) => setTimeout(resolve, 150)) 60 | writeLn(modList.testPromise) 61 | await new Promise((resolve) => setTimeout(resolve, 150)) 62 | writeLn(modList.testPromise) 63 | await new Promise((resolve) => setTimeout(resolve, 150)) 64 | writeLn(modList.testPromise) 65 | /* eslint-enable no-promise-executor-return */ 66 | } 67 | //_promiseStatus().then(() => { writeLn('blag')}) 68 | 69 | /* Race the parser!! We initialized in "de", changing to "en" to get the list from the search 70 | above in english. As long as this line is run before the search can return, we should see english 71 | This is a deliberate race condition to make sure async is working. */ 72 | myTranslator.currentLocale = 'en' 73 | 74 | myTranslator.getLangList().then((data) => { 75 | writeLn('Languages List (async loading - likely returning before file load is done):', data) 76 | }) 77 | 78 | 79 | writeLn('End File Code. There may (should!) still be running async processes') 80 | 81 | function writeLn(text) { process.stdout.write(`${text}\n`) } -------------------------------------------------------------------------------- /test/testRunnerMods/gameSettings.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 10823 5 | 30 6 | 1800 7 | false 8 | true 9 | true 10 | 1.500000 11 | 1.000000 12 | 6.000000 13 | 0.750000 14 | 2 15 | true 16 | true 17 | 18 | 0 19 | 20 | 0.000000 21 | 0.800000 22 | 0.800000 23 | 0.500000 24 | 0.500000 25 | 26 | 27 | false 28 | true 29 | 30 | 2 31 | false 32 | true 33 | false 34 | 35 | true 36 | true 37 | true 38 | true 39 | false 40 | false 41 | true 42 | 0 43 | 0 44 | false 45 | 3 46 | 2 47 | 65.000000 48 | 0.900000 49 | true 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Bad_ModDesc_CRC.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Bad_ModDesc_CRC.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Broken_Zip_File.zip: -------------------------------------------------------------------------------- 1 | r,gkjberkgiher;oigher;oigh -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Fake_Cracked_DLC.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Fake_Cracked_DLC.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Garbage_File.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Garbage_File.txt -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod (1).zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod (1).zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod - Copy.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod - Copy.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_Warning/modDesc.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | FSModCheck Test 4 | 5 | <en>Totally valid FS19 Mod</en> 6 | 7 | 8 | 9 | 10 | 11 | 1.0.0.0 12 | 13 | 14 | modIcon.dds 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 5th Wheel LockingVerrouillage de la cinquième roueSattelkupplung VerriegelnQuinta ruota di bloccaggioБлокировка пятого колесаFifth Wheel vergrendelingBlokada piątego kołaUzamčení točniceBloqueo de quinta ruedaTravamento da quinta roda 23 | Locking disabledVerrouillage désactivéSperre deaktiviertBlocco disabilitatoБлокировка отключенаVergrendeling uitgeschakeldBlokowanie wyłączoneZamykání deaktivovánoBloqueo desactivadoBloqueio desativado 24 | Gentle lockingVerrouillage douxSchonendes VerriegelnChiusura delicataБережная блокировкаZachte vergrendelingDelikatne blokowanieJemné zamykáníBloqueo suaveTravamento suave 25 | Partial lockingVerrouillage partielTeilverriegelungChiusura parzialeЧастичная блокировкаGedeeltelijke vergrendelingCzęściowe ryglowanieČástečné zajištěníBloqueo parcialBloqueio parcial 26 | Hard LockingVerrouillage durHarte VerriegelungBlocco duroЖесткая блокировкаHarde vergrendelingTwarde blokowaniePevné zamykáníBloqueo duroTravamento rígido 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_Warning/modIcon.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_Warning/modIcon.dds -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_and_Zip.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_and_Zip.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_and_Zip/EXAMPLE_Good_Mod.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_and_Zip/EXAMPLE_Good_Mod.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_and_Zip/modDesc.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | FSModCheck Test 4 | 5 | <en>Totally valid FS19 Mod</en> 6 | 7 | 8 | 9 | 10 | 11 | 1.0.0.0 12 | 13 | 14 | modIcon.dds 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 5th Wheel LockingVerrouillage de la cinquième roueSattelkupplung VerriegelnQuinta ruota di bloccaggioБлокировка пятого колесаFifth Wheel vergrendelingBlokada piątego kołaUzamčení točniceBloqueo de quinta ruedaTravamento da quinta roda 23 | Locking disabledVerrouillage désactivéSperre deaktiviertBlocco disabilitatoБлокировка отключенаVergrendeling uitgeschakeldBlokowanie wyłączoneZamykání deaktivovánoBloqueo desactivadoBloqueio desativado 24 | Gentle lockingVerrouillage douxSchonendes VerriegelnChiusura delicataБережная блокировкаZachte vergrendelingDelikatne blokowanieJemné zamykáníBloqueo suaveTravamento suave 25 | Partial lockingVerrouillage partielTeilverriegelungChiusura parzialeЧастичная блокировкаGedeeltelijke vergrendelingCzęściowe ryglowanieČástečné zajištěníBloqueo parcialBloqueio parcial 26 | Hard LockingVerrouillage durHarte VerriegelungBlocco duroЖесткая блокировкаHarde vergrendelingTwarde blokowaniePevné zamykáníBloqueo duroTravamento rígido 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_and_Zip/modIcon.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod_Folder_and_Zip/modIcon.dds -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Good_Mod_No_Original - Copy.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Good_Mod_No_Original - Copy.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Icon_Not_Found.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Icon_Not_Found.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Malformed_ModDesc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Malformed_ModDesc.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Missing_ModDesc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Missing_ModDesc.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_No_Icon.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_No_Icon.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_No_Version.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_No_Version.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Old_ModDesc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Old_ModDesc.zip -------------------------------------------------------------------------------- /test/testRunnerMods/mods/EXAMPLE_Really_Malformed_ModDesc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsage/FS_Mod_Checker/5f7feb674846cb02974913e89063e84638acc801/test/testRunnerMods/mods/EXAMPLE_Really_Malformed_ModDesc.zip -------------------------------------------------------------------------------- /translations/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "language_code": "de", 3 | "language_name": "Deutsch", 4 | "language_locale": "de_DE", 5 | "title": "Landwirtschafts-Simulator Mod-Ordner-Checker", 6 | "tab_config": "Konfiguration", 7 | "tab_broken": "Defekte Dateien", 8 | "tab_missing": "Fehlende Mods", 9 | "tab_conflict": "Mögliche Konflikte", 10 | "tab_explore": "Mods durchsuchen", 11 | "config_step_1": "Schritt 1", 12 | "config_step_2": "Schritt 2", 13 | "config_step_3": "Schritt 3 (optional)", 14 | "config_blurb": "Dieses kleine Programm schaut sich deinen mods-Ordner an und informiert dich über mögliche Probleme damit.", 15 | "config_load_button_blurb": "Als erstes wähle bitte deine gameSettings.xml oder einen Ordner mit Mods darin aus", 16 | "config_load_button": "Einstellungen laden", 17 | "config_load_folder_button": "Ordner laden", 18 | "config_process_button_blurb": "Dann klicke auf \"Scannen\", um deine Mods und Savegames zu untersuchen. Mit dem Button kann jederzeit erneut gescannt werden.", 19 | "config_process_button": "Mods und Savegames scannen", 20 | "config_quarantine_folder_blurb": "Wenn du mit diesem Programm Mods aus dem Mod-Ordner entfernen können möchtest, gib hier an, wo es die Mods ablegen soll.", 21 | "config_move_folder_button": "Ziel für verschobene Mods", 22 | "latest_version_link_blurb": "Neuste Version hier herunterladen:", 23 | "user_error_open_settings": "Die ausgewählte gameSettings.xml ist ungültig oder unlesbar oder der angegeben Ordner konnte nicht geöffnet werden! Log: Strg+Alt+D", 24 | "location_savegame_folder": "Savegame-Ordner", 25 | "location_mod_folder": "Mod-Ordner", 26 | "location_quarantine_folder": "Ordner für unerwünschte Mods", 27 | "status-processing-title": "Mods werden verarbeitet...", 28 | "config_working_status": "Lesen...", 29 | "config_testing_status": "Testen...", 30 | "config_working_done": "Fertig!", 31 | "button_refresh_tab": "Tab aktualisieren", 32 | "broken_blurb": "Diese Mods wurden als problematisch erkannt. ZIP-Dateien oder Ordner mit Sonderzeichen außer \"_\" werden vom Spiel nicht geladen. Mods, die nicht als ZIP-Datei vorliegen, können im Multiplayer nicht verwendet werden. Außerdem sollten im Mod-Ordner nur Mods liegen, keine sonstigen Dateien. Unten ist eine Liste problematischer Dateien und eine mögliche Lösungen", 33 | "broken_options_hide_unzipped": "Mods ausblenden, die nur die \"Muss für Multiplayer gezippt sein\"-Warnung haben.", 34 | "missing_blurb": "Der Scanner konnte die unten genannten Mods nicht finden, obwohl sie in einem oder mehreren Savegames verwendet werden. Für Mods, die im Spielstand nicht gekauft wurden ist das harmlos. Wurden sie allerdings im Spiel gekauft, verschwinden sie und es geht dem Spieler In-Game-Geld verloren. Um dies zu verhindern, lade die Mods erneut herunter und lege sie im Mods-Ordner ab.", 35 | "conflict_blurb": "Diese Mods wurden in deinem Mod-Ordner erkannt. In bestimmten Fällen können sie Mod-Konflikte verursachen, was dazu führt, dass dein Spiel entweder nicht funktioniert oder sich merkwürdig verhält. Diese Liste dient zur Information und sollte nicht als Vorschlag verstanden werden, diese Mods nicht zu verwenden", 36 | "explore_blurb": "Unten findest du eine Liste aller Mods, die im Mod-Ordner oder den Spielständen erkannt wurden. Verwende die verschiedenen Ansichten, um bestimmte Mods zu erkennen: fehlende Mods, Mods, die in keinem Savegame aktiviert sind, oder Mods, die zwar aktiviert sind, aber nicht im Spiel verwendet werden", 37 | "explore_options_button": "Spalten oder Filter ein-/ausblenden", 38 | "explore_options_title": "Mod-Optionen durchsuchen", 39 | "explore_options_blurb": "Hier kannst du festlegen, was in der Tabelle \"Mods durchsuchen\" angezeigt wird, einschließlich der Spalten und einiger Filter", 40 | "explore_options_column_visibility": "Spaltensichtbarkeit", 41 | "explore_options_savegame_select": "Auf dieses Savegame filtern:", 42 | "explore_options_special_lists": "Spezial-Listen", 43 | "explore_options_special_inactive": "Inaktive Mods", 44 | "explore_options_special_unused": "Aktive, aber ungenutzte Mods", 45 | "explore_options_special_scripts": "Mods, die LUA-Scripts verwenden", 46 | "filter_savegame_all": "Alle Savegames", 47 | "filter_savegame": "Savegame Nr.", 48 | "menu_details": "Mod-Details öffnen", 49 | "menu_open_explorer": "Im Finder/Explorer anzeigen", 50 | "menu_find_on_mod_hub": "Im ModHub nach diesem Mod suchen", 51 | "menu_find_on_google": "Diesen Mod in Google suchen", 52 | "menu_copy_general": "Kopieren: ", 53 | "menu_copy_full_path": "Kopieren: ganzen Dateipfad", 54 | "menu_move_file": "Mod in Quarantäne verschieben", 55 | "move_mod_message": "Sicher, dass dieser Mod in den Quarantäne-Ordner verschoben werden soll:", 56 | "move_mod_cancel": "Nein, abbrechen", 57 | "move_mod_ok": "Ja, verschieben", 58 | "move_mod_worked": "Der Mod wurde verschoben!", 59 | "move_mod_failed": "Der Mod konnte nicht verschoben werden", 60 | "move_mod_no_folder": "Damit das geht, musst du erst einen Zielort festlegen", 61 | "save_log_failed": "Debug-Log konnte nicht gespeichert werden", 62 | "save_log_worked": "Debug-Log wurde gespeichert", 63 | "open_debug_log": "Debug-Log anzeigen", 64 | "header_mod_name": "Name", 65 | "header_mod_title": "Titel", 66 | "header_mod_version": "Version", 67 | "header_mod_size": "Größe", 68 | "header_mod_date": "Datum", 69 | "header_mod_is_active": "Ist aktiv", 70 | "header_mod_active_games": "Aktiv in Savegame", 71 | "header_mod_is_used": "In Benutzung", 72 | "header_mod_used_games": "Genutzt in Savegames", 73 | "header_mod_full_path": "Ganzer Pfad", 74 | "header_mod_has_scripts": "Nutzt Scripts", 75 | "header_mod_store_items": "Shop-Artikel", 76 | "header_mod_author": "Author", 77 | "header_mod_multiplayer": "Multiplayer", 78 | "detail_mod_version": "Version", 79 | "detail_mod_size": "Größe", 80 | "detail_mod_date": "Datum", 81 | "detail_mod_has_scripts": "Nutzt Scripts", 82 | "detail_mod_store_items": "Shop-Artikel", 83 | "detail_mod_author": "Author", 84 | "detail_mod_multiplayer": "Multiplayer", 85 | "filter_mod_name": "Name", 86 | "filter_mod_title": "Titel", 87 | "filter_mod_version": "Version", 88 | "filter_mod_size": "Größe", 89 | "filter_mod_date": "Datum", 90 | "filter_mod_is_active": "Ist aktiv", 91 | "filter_mod_active_games": "Aktiv in Savegame", 92 | "filter_mod_is_used": "In Benutzung", 93 | "filter_mod_used_games": "Genutzt in Savegames", 94 | "filter_mod_full_path": "Ganzer Pfad", 95 | "filter_mod_has_scripts": "Nutzt Scripts", 96 | "filter_mod_store_items": "Shop-Artikel", 97 | "filter_mod_author": "Author", 98 | "filter_mod_multiplayer": "Multiplayer", 99 | "active_used_table_savegame": "Spielstand", 100 | "active_used_table_active": "Aktiv", 101 | "active_used_table_used": "Genutzt", 102 | "file_error_name_starts_digit": "Diese Datei beginnt mit einer Ziffer. FS19 benötigt einen Buchstaben am Anfang.", 103 | "file_error_likely_copy": "Dieser Dateiname legt nahe, dass es sich um eine Kopie eines anderen Mods handelt.", 104 | "file_error_likely_zip_pack": "Diese Datei hat \"unzip\" im Namen, es ist wahrscheinlich ein Mod-Pack, das entpackt werden sollte.", 105 | "file_error_unsupported_archive": "Dieses Archiv kann nicht von FS19 gelesen werden. Es ist wahrscheinlich ein Mod-Pack, das entpackt werden sollte.", 106 | "file_error_name_invalid": "Diese Datei ist falsch benannt. Mods können nur alphanumerische Zeichen und Unterstriche enthalten. ZIP-Dateien müssen mit .zip enden.", 107 | "file_error_garbage_file": "Diese Datei gehört nicht in den Mod-Ordner. Nur Ordner und Zip-Dateien sollten im Mod-Ordner sein. Diese Datei sollte entfernt werden.", 108 | "file_error_unreadable_zip": "Die Zip-Datei für diesen Mod konnte nicht gelesen werden. FS19 wird wahrscheinlich auch nicht in der Lage sein, diesen Mod zu lesen.", 109 | "not_mod_moddesc_missing": "Es wurde keine modDesc.xml für diesen Mod gefunden. Es ist wahrscheinlich kein Mod. Vielleicht ist es ein falsch platzierter Ordner, oder vielleicht ist es ein Mod-Pack.", 110 | "mod_error_moddesc_damaged_recoverable": "Die modDesc.xml ist zwar fehlerhaft, konnte aber trotzdem verarbeitet werden. Wenn das der einzige Fehler zu diesem Mod ist, kann er wahrscheinlich ignoriert werden.", 111 | "not_mod_moddesc_parse_error": "Die modDesc.xml ist so beschädigt, dass der Scanner sie nicht versteht. Wahrscheinlich wird also auch FS19 mit dem Mod nichts anfangen können.", 112 | "not_mod_moddesc_version_old_or_missing": "Die modDesc.xml-Version konnte entweder nicht gelesen werden oder sie ist zu alt für die Verwendung mit FS19.", 113 | "mod_error_no_mod_version": "Diesem Mod fehlt eine lesbare Version. FS19 wird diesen Mod also wahrscheinlich ablehnen oder sich seltsam verhalten.", 114 | "mod_error_no_mod_icon": "Diesem Mod fehlt ein Icon. FS19 lehnt Mods ohne Icon ab.", 115 | "conflict_error_folder_and_file": "Dieser Mod existiert sowohl als Zip-Datei als auch als Ordner. FS19 wird die Zip-Datei beim Laden von Mods bevorzugen. Wenn du also Änderungen an der Ordnerversion vorgenommen hast, werden diese Änderungen ignoriert.", 116 | "info_no_multiplayer_unzipped": "Entpackte Mods können nicht im Multiplayer verwendet werden. Wenn du diesen Mod nicht in einem Multiplayer verwenden möchtest, kannst du diese Nachricht ignorieren.", 117 | "file_error_copy_name": "Diese Datei sollte umbenannt oder entfernt werden. Es ist wohl eine Kopie von:", 118 | "file_error_copy_exists": "Die ursprüngliche Datei existiert bereits.", 119 | "file_error_copy_missing": "Die Originaldatei existiert nicht.", 120 | "file_error_copy_identical": "Die Originaldatei und diese Datei sind identisch.", 121 | "info_might_be_piracy": "Dies scheint eine Raubkopie von einem kostenpflichtigen DLC zu sein. Dieser Test ist simpel, es könnte also ein Fehlalarm sein. Dennoch sei dir bewusst, dass die Nutzung von solchen Raubkopien zum Verlust von Support durch GIANTS und zur Sperrung vom GIANTS Discord server und dem Forum führen kann. Bitte unterstützt die Entwickler!" 122 | } -------------------------------------------------------------------------------- /translations/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "language_code" : "en", 3 | "language_name" : "English", 4 | "language_locale" : "en_US", 5 | "title" : "Farming Simulator Mod Folder Checker", 6 | "tab_config" : "Configuration", 7 | "tab_broken" : "Broken Files", 8 | "tab_missing" : "Missing Mods", 9 | "tab_conflict" : "Possible Conflicts", 10 | "tab_explore" : "Explore Mods", 11 | "config_step_0" : "Farming Simulator Version", 12 | "config_step_1" : "Step 1", 13 | "config_step_2" : "Step 2", 14 | "config_step_3" : "Step 3 (optional)", 15 | "config_blurb" : "This little program will take a look at your mod install folder and inform you of any potential problems that it finds.", 16 | "config_step_0_blurb" : "Choose which version of Farming Simulator you'd like to check", 17 | "config_load_button_blurb" : "First, you need to point Mod Checker to your gameSettings.xml file OR a folder of mods", 18 | "config_load_button" : "Load Settings", 19 | "config_load_folder_button" : "Load Folder", 20 | "config_process_button_blurb" : "Next, click the \"Scan\" button to process your mods and save game files. You can re-scan using this same button. Note: if scanning a folder only, save games are not checked, making the \"Missing Mods\" tab somewhat useless.", 21 | "config_process_button" : "Scan Mods and Save Games", 22 | "latest_version_link_blurb" : "Get the latest version at:", 23 | "user_error_open_settings" : "Your selected game settings file is invalid or unreadable, or the specified folder was unable to be opened! Log: CTRL+ALT+D", 24 | "location_savegame_folder" : "Save Game Files", 25 | "location_mod_folder" : "Mod Files", 26 | "location_quarantine_folder" : "Folder for Unwanted Mods", 27 | "status-processing-title" : "Processing Mods...", 28 | "config_working_status" : "Reading...", 29 | "config_testing_status" : "Testing...", 30 | "config_working_done" : "Done!", 31 | "button_refresh_tab" : "Refresh this Tab", 32 | "broken_blurb" : "These mods have been detected to be a possible problem. ZIP Files or Folders with any non-alphanumeric character other than \"_\" will not be loaded by the game. Mods that are not compressed as a ZIP file cannot be used in multiplayer games. Finally, the mod folder should only contain mods, no other files. Below, there is a list of problem files, and a suggested solution", 33 | "broken_options_hide_unzipped" : "Hide mods that only have multiplayer \"needs zipped\" warning.", 34 | "missing_blurb" : "The scanner failed to find the mods below, however they are referenced in one or more save games. For mods that have not been purchased, this is usually harmless. For mods you have purchased, missing the mod file could cost you in-game money. To correct this, re-download the mod from where you originally got it and place it in the mod folder.", 35 | "conflict_blurb" : "These mods were detected in your mod folder. In some specific cases, they can cause conflicts with other mods, causing your game to either not work or behave strangely. This display is for informational purposes, and should not be taken as a suggestion not to use anything listed here", 36 | "explore_blurb" : "Below, you will find a list of all mods detected in your mod folder or in your save games. Use the provided options to see specific sets of mods including missing mods, mods that are never loaded in a save, or mods that are loaded but not used in a save", 37 | "explore_options_button" : "Change Column Visibility or Filters", 38 | "explore_options_title" : "Explore Mods Options", 39 | "explore_options_blurb" : "Here you can set what is displayed in the \"Explore Mods\" table, including column visibility and some filters", 40 | "explore_options_column_visibility": "Column Visibility", 41 | "explore_options_savegame_select" : "Filter to only savegame:", 42 | "explore_options_special_lists" : "Special Lists", 43 | "explore_options_special_inactive" : "Inactive Mods", 44 | "explore_options_special_unused" : "Active but Unused Mods", 45 | "explore_options_special_scripts" : "Mods that use LUA scripting", 46 | "filter_savegame_all" : "All Save Game Slots", 47 | "filter_savegame" : "Save Game Slot #", 48 | "broken_blurb_none" : "Congratulations, you have no (detected) broken mods installed", 49 | "conflict_blurb_none" : "Congratulations, you have no (detected) conflicting mods installed", 50 | "missing_blurb_none" : "Congratulations, you have no missing mods in your save games - or you only scanned a mod folder.", 51 | 52 | "menu_details" : "Open Mod Detail", 53 | "menu_open_explorer" : "Show in Finder / Explorer", 54 | "menu_find_on_mod_hub" : "Search ModHub for this Mod", 55 | "menu_find_on_google" : "Search Google for this Mod", 56 | "menu_find_on_duck" : "Search DuckDuckGo for this Mod", 57 | "menu_find_on_bing" : "Search Bing for this Mod", 58 | "menu_copy_general" : "Copy : ", 59 | "menu_copy_full_path" : "Copy : Full File Path", 60 | "menu_move_file" : "Move Mod to quarantine", 61 | 62 | "move_mod_message" : "Are you sure you want to move this mod to quarantine :", 63 | "move_mod_cancel" : "No, cancel", 64 | "move_mod_ok" : "Yes, move it", 65 | "move_mod_worked" : "The mod has been moved!", 66 | "move_mod_failed" : "The mod was unable to be moved", 67 | "move_mod_no_folder" : "You must set a move-to location before using this command", 68 | 69 | "save_log_failed" : "Debug log save failed", 70 | "save_log_worked" : "Debug log saved successfully", 71 | "open_debug_log" : "View Debug Log", 72 | 73 | "header_mod_name" : "Name", 74 | "header_mod_title" : "Title", 75 | "header_mod_version" : "Version", 76 | "header_mod_size" : "Size", 77 | "header_mod_date" : "Date", 78 | "header_mod_is_active" : "Is Active", 79 | "header_mod_active_games": "Active In Saves", 80 | "header_mod_is_used" : "Is Used", 81 | "header_mod_used_games" : "Used In Saves", 82 | "header_mod_full_path" : "Full Path", 83 | "header_mod_has_scripts" : "Uses Scripts", 84 | "header_mod_store_items" : "Store Items", 85 | "header_mod_author" : "Author", 86 | "header_mod_multiplayer" : "Multiplayer", 87 | "header_mod_bulky" : "Extra Files", 88 | "header_mod_support" : "Old Shaders", 89 | 90 | "detail_mod_version" : "Version", 91 | "detail_mod_size" : "Size", 92 | "detail_mod_date" : "Date", 93 | "detail_mod_date_recent" : "Most Recent File Date", 94 | "detail_mod_has_scripts" : "Uses Scripts", 95 | "detail_mod_store_items" : "Store Items", 96 | "detail_mod_author" : "Author", 97 | "detail_mod_multiplayer" : "Multiplayer", 98 | "detail_mod_support" : "Previous Version Shaders", 99 | "detail_dev_info" : "Developer Information", 100 | "detail_extra_files" : "Extra files in the mod (per Giants spec)", 101 | "detail_i3d_files" : "i3D files in the mod", 102 | 103 | "filter_mod_name" : "Name", 104 | "filter_mod_title" : "Title", 105 | "filter_mod_version" : "Version", 106 | "filter_mod_size" : "Size", 107 | "filter_mod_date" : "Date", 108 | "filter_mod_is_active" : "Is Active", 109 | "filter_mod_active_games": "Active In Saves", 110 | "filter_mod_is_used" : "Is Used", 111 | "filter_mod_used_games" : "Used In Saves", 112 | "filter_mod_full_path" : "Full Path", 113 | "filter_mod_has_scripts" : "Uses Scripts", 114 | "filter_mod_store_items" : "Store Items", 115 | "filter_mod_author" : "Author", 116 | "filter_mod_old_shader" : "Old Shaders", 117 | "filter_mod_bulky" : "Extra Files", 118 | "filter_mod_multiplayer" : "Multiplayer", 119 | 120 | "active_used_table_savegame" : "Savegame", 121 | "active_used_table_active" : "Active", 122 | "active_used_table_used" : "Used", 123 | 124 | "file_error_name_starts_digit" : "This file starts with a digit. FS requires that mods start with a letter.", 125 | "file_error_likely_copy" : "This file name suggests that it is a duplicate copy of another mod.", 126 | "file_error_likely_zip_pack" : "This file has \"unzip\" in the name, it is probably a mod pack that should be extracted.", 127 | "file_error_unsupported_archive" : "This file is an archive, but not one that FS can read. It is probably a mod pack and should be extracted.", 128 | "file_error_name_invalid" : "This file is named incorrectly. Mods can only contain alpha-numeric characters and underscore. ZIP files must end with .zip.", 129 | "file_error_garbage_file" : "This file does not belong in your mods folder. Only folders and zip files should be in the mods folder. This file should be removed.", 130 | "file_error_unreadable_zip" : "The zip file for this mod was not able to be read. FS will also likely not be able to read this mod.", 131 | "not_mod_moddesc_missing" : "A modDesc.xml was not found for this mod. It probably is not a mod at all. Maybe it's a misplaced folder, or maybe it is a pack of mods.", 132 | "mod_error_moddesc_damaged_recoverable" : "The modDesc.xml has errors, but they were recovered from. If this is the only error that appears for this mod, you can probably ignore this error.", 133 | "not_mod_moddesc_parse_error" : "The modDesc.xml file is damaged beyond a point the scanner could recover from. FS will probably be unable to use this mod.", 134 | "not_mod_moddesc_version_old_or_missing": "The modDesc.xml version could either not be read, or it indicates this mod can not be used with this version of FS.", 135 | "mod_error_no_mod_version" : "This mod lacks a readable version. FS will likely reject this mod or behave inconsistently.", 136 | "mod_error_no_mod_icon" : "This mod does not have an icon file. FS will reject mods without valid icons.", 137 | "conflict_error_folder_and_file" : "This mod exists as both a zip file and a folder. FS will prefer the zip file when loading mods, so if you have made changes to the folder version, those changes will be ignored.", 138 | "info_no_multiplayer_unzipped" : "Unzipped mods cannot be used in multiplayer. If you don't intend to use this mod in a multiplayer game, you can ignore this message.", 139 | "file_error_copy_name" : "This file should be renamed or removed as it appears to be a copy of :", 140 | "file_error_copy_exists" : "The original file exists.", 141 | "file_error_copy_missing" : "The original file DOES NOT exist.", 142 | "file_error_copy_identical" : "The original file and this file are identical.", 143 | "info_might_be_piracy" : "This mod appears to be a cracked / pirated version of a paid DLC. This test is simplistic, so this could be a false positive, however be aware that using cracked DLC will prevent you from receiving help from Giants support, and is grounds for a ban from the official discord and forums. Please support the developers!", 144 | "info_might_be_duplicate" : "Based on their title, these mods might be duplicates of each other. You should compare versions and see if some could be removed.", 145 | 146 | "user_pref_title_main" : "User Preferences", 147 | "user_pref_title_lang" : "Language", 148 | "user_pref_blurb_lang" : "This allows you to override the detected language for Mod Checker. Note: to change, toggle off and on again.", 149 | "user_pref_title_game_settings" : "gameSettings.xml", 150 | "user_pref_blurb_game_settings" : "This allows you to set the default location of gameSettings.xml. Note: to keep your current location always, toggle this off after loading a gameSettings.xml", 151 | "user_pref_setting_auto_process" : "Automatically Process mod folder on startup. You must have a saved gameSettings.xml location.", 152 | "user_pref_title_main_window" : "Main Window", 153 | "user_pref_blurb_main_window" : "This allows you to set the default size of the main window", 154 | "user_pref_title_detail_window" : "Detail Window", 155 | "user_pref_blurb_detail_window" : "This allows you to set the default size of the detail window", 156 | "user_pref_title_move_dest" : "Mod Move Destination", 157 | "user_pref_blurb_move_dest" : "This allows you to set a destination for unwanted mod files, and toggle this functionality to be either active or inactive", 158 | "user_pref_setting_window_x" : "Window Width", 159 | "user_pref_setting_window_y" : "Window Height", 160 | "user_pref_setting_window_max" : "Start Maximized", 161 | "user_pref_setting_use_move" : "Allow Mods to be Moved (requires location set, turn off to forget current location)", 162 | "user_pref_setting_move_dest" : "Destination for Moved Mods", 163 | "user_pref_setting_move_button" : "Set Destination", 164 | "user_pref_setting_move_open_button" : "Open Destination", 165 | "user_pref_setting_current_lang" : "Current Language Setting", 166 | "user_pref_setting_lock_lang" : "Always use the current language (do not detect on start)", 167 | "user_pref_setting_remember_last" : "Use Last loaded gameSettings.xml (off = Always start with below gameSettings.xml)", 168 | "user_pref_setting_current_gamesettings" : "Current remembered gameSettings.xml" 169 | } -------------------------------------------------------------------------------- /translations/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "language_code" : "es", 3 | "language_name" : "Español", 4 | "language_locale" : "es_ES", 5 | "title" : "Farming Simulator Mod Folder Checker", 6 | "tab_config" : "Configuración", 7 | "tab_broken" : "Mods Rotos", 8 | "tab_missing" : "Mods Ausentes", 9 | "tab_conflict" : "Posibles Conflictos", 10 | "tab_explore" : "Explorar Mods", 11 | "config_step_1" : "Paso 1", 12 | "config_step_2" : "Paso 2", 13 | "config_step_3" : "Paso 3 (opcional)", 14 | "config_blurb" : "Este pequeño programa echará un vistazo a la carpeta de mods y le informará de cualquier problema potencial que encuentre.", 15 | "config_load_button_blurb" : "Primero, necesita indicar a Mod Checker el archivo gameSettings.xml o la carpeta de mods.", 16 | "config_load_button" : "Cargar gameSettings.xml", 17 | "config_load_folder_button" : "Indicar Carpeta de Mods", 18 | "config_process_button_blurb" : "Siguiente, haz click en el botón \"Scan\" para procesar tus mods y las partidas guardadas del juego. Puedes reescanear usando el mismo botón.", 19 | "config_process_button" : "Escanear Mods y Partidas Guardadas", 20 | "config_quarantine_folder_blurb" : "Si desea poder quitar mods de su carpeta de mods con este programa, use este botón para establecer dónde desea moverlos.", 21 | "config_move_folder_button" : "Destino para mods movidos.", 22 | "latest_version_link_blurb" : "Obtenga la última versión en:", 23 | "user_error_open_settings" : "El archivo de ajustes del juego seleccionado es inválido, ilegible o la carpeta especificada no se ha podido abrir! Ver Log: CTRL+ALT+D", 24 | "location_savegame_folder" : "Ruta Partidas Guardadas", 25 | "location_mod_folder" : "Ruta Carpeta Mods", 26 | "location_quarantine_folder" : "Ruta Carpeta para Mods no deseados", 27 | "status-processing-title" : "Procesando Mods...", 28 | "config_working_status" : "Leyendo...", 29 | "config_testing_status" : "Testeando...", 30 | "config_working_done" : "¡Hecho!", 31 | "button_refresh_tab" : "Refrescar esta Pestaña", 32 | "broken_blurb" : "Se ha detectado un posible problema en estos mods. Archivos ZIP o Carpetas con caracter no alfanumérico que no sea \"_\" no será cargado por el juego. Los mods que no están comprimidos en formato ZIP no se pueden usar en partidas multiplayer. Finalmente, la carpeta de mods solo debe contener mods, no otros archivos. A continuación, hay una lista de archivos problemáticos y una solución sugerida.", 33 | "broken_options_hide_unzipped" : "Advertencia, Ocultar mods que solo tienen multijugador \"deben estar comprimidos (.zip)\" ", 34 | "missing_blurb" : "El escáner no pudo encontrar los mods a continuación, sin embargo, se hace referencia a algunos mods en una o más partidas guardadas. Para los mods que no se han comprado, esto suele ser inofensivo. Para los mods que ha comprado, perder el archivo del mod podría costarle dinero en el juego. Para corregir esto, vuelva a descargar el mod de donde lo obtuvo originalmente y colóquelo en la carpeta del mod.", 35 | "conflict_blurb" : "Estos mods se detectaron en su carpeta de mods. En casos específicos, pueden causar conflictos con otros mods, haciendo que tu juego no funcione o se comporte de manera extraña. Esta pantalla tiene fines informativos y no debe tomarse al pie de la letra, el no utilizar nada de lo que se enumera aquí.", 36 | "explore_blurb" : "A continuación, encontrará una lista de todas los mods detectados en su carpeta de mods o en sus partidas guardadas. Utilice las opciones proporcionadas para ver conjuntos específicos de mods, incluidas las que faltan, los mods que nunca se cargan en una partida guardada o los mods que se cargan pero no se usan en una partida guardada.", 37 | "explore_options_button" : "Cambiar la visibilidad o los filtros de las columnas", 38 | "explore_options_title" : "Explore las opciones de Mods", 39 | "explore_options_blurb" : "Aquí puede configurar lo que se muestra en la tabla \"Explorar Mods\" , incluida la visibilidad de columnas y algunos filtros", 40 | "explore_options_column_visibility": "Columnas Visibles", 41 | "explore_options_savegame_select" : "Filtrar Partidas:", 42 | "explore_options_special_lists" : "Lista Especial", 43 | "explore_options_special_inactive" : "Mods Inactivos", 44 | "explore_options_special_unused" : "Mods Activos pero en Desuso", 45 | "explore_options_special_scripts" : "Mods que usan script LUA", 46 | "filter_savegame_all" : "Todas las partidas guardadas", 47 | "filter_savegame" : "Partida Slot #", 48 | 49 | "menu_details" : "Abrir Detalle Mod", 50 | "menu_open_explorer" : "Mostrar en Finder / Explorer", 51 | "menu_find_on_mod_hub" : "Buscar ModHub para este Mod", 52 | "menu_find_on_google" : "Buscar Google para este Mod", 53 | "menu_find_on_duck" : "Buscar DuckDuckGo para este Mod", 54 | "menu_find_on_bing" : "Buscar Bing para este Mod", 55 | "menu_copy_general" : "Copiar : ", 56 | "menu_copy_full_path" : "Copiar : Ruta de archivo completa", 57 | "menu_move_file" : "Mover Mod a No Deseados", 58 | 59 | "move_mod_message" : "Esta seguro que quiere mover este mod a No Deseados? :", 60 | "move_mod_cancel" : "No, cancelar", 61 | "move_mod_ok" : "Si, moverlo", 62 | "move_mod_worked" : "¡El mod ha sido movido!", 63 | "move_mod_failed" : "El mod no se pudo mover", 64 | "move_mod_no_folder" : "Debe fijar una carpeta de destino antes de usar este comando", 65 | 66 | "save_log_failed" : "Ha fallado el guardado del Log de Depuración", 67 | "save_log_worked" : "Log de Depuración guardado satisfactoriamente", 68 | "open_debug_log" : "Ver Log Depuración", 69 | 70 | "header_mod_name" : "Nombre", 71 | "header_mod_title" : "Titulo", 72 | "header_mod_version" : "Version", 73 | "header_mod_size" : "Tamaño", 74 | "header_mod_date" : "Fecha", 75 | "header_mod_is_active" : "Está activo", 76 | "header_mod_active_games": "Activo en Partidas", 77 | "header_mod_is_used" : "Se Usa", 78 | "header_mod_used_games" : "Usado en Partidas", 79 | "header_mod_full_path" : "Ruta completa", 80 | "header_mod_has_scripts" : "Usa Scripts", 81 | "header_mod_store_items" : "Articulos en Tienda", 82 | "header_mod_author" : "Autor", 83 | "header_mod_multiplayer" : "Multiplayer", 84 | 85 | "detail_mod_version" : "Version", 86 | "detail_mod_size" : "Tamaño", 87 | "detail_mod_date" : "Fecha", 88 | "detail_mod_has_scripts" : "Usa Scripts", 89 | "detail_mod_store_items" : "Articulos en Tienda", 90 | "detail_mod_author" : "Autor", 91 | "detail_mod_multiplayer" : "Multiplayer", 92 | 93 | "filter_mod_name" : "Nombre", 94 | "filter_mod_title" : "Titulo", 95 | "filter_mod_version" : "Version", 96 | "filter_mod_size" : "Tamaño", 97 | "filter_mod_date" : "Fecha", 98 | "filter_mod_is_active" : "Está activo", 99 | "filter_mod_active_games": "Activo en Partidas", 100 | "filter_mod_is_used" : "Se Usa", 101 | "filter_mod_used_games" : "Usado en Partidas", 102 | "filter_mod_full_path" : "Ruta completa", 103 | "filter_mod_has_scripts" : "Usa Scripts", 104 | "filter_mod_store_items" : "Articulos en Tienda", 105 | "filter_mod_author" : "Autor", 106 | "filter_mod_multiplayer" : "Multiplayer", 107 | 108 | "active_used_table_savegame" : "Partida", 109 | "active_used_table_active" : "Activo", 110 | "active_used_table_used" : "Usado", 111 | 112 | "file_error_name_starts_digit" : "Este mod empieza con un número. FS19 requiere que los mods empiecen con una letra.", 113 | "file_error_likely_copy" : "Este nombre de mo sugiere que es una copia duplicada de otro mod.", 114 | "file_error_likely_zip_pack" : "Este mod tiene \"unzip\" en el nombre, probablemente sea un pack y deba ser descomprimido.", 115 | "file_error_unsupported_archive" : "Este mod es un archivo, pero no uno que FS19 pueda leer. Probablemente sea un pack y deba ser descomprimido.", 116 | "file_error_name_invalid" : "Este mod esta nombrado incorrectamente. Los mods solo pueden contener caracteres alfanuméricos y guión bajo ( _ ) . El archivo ZIP debe terminar en .zip.", 117 | "file_error_garbage_file" : "Este mod no pertenece a su carpeta de mods. Solo las carpetas y los archivos zip deben estar en la carpeta de modificaciones. Este mod debería ser retirado.", 118 | "file_error_unreadable_zip" : "Este archivo zip, este mod, no se pudo leer. FS19 es probable que no pueda leer este mod, posiblemente contenga errores si lo descargaste para FS19.", 119 | "not_mod_moddesc_missing" : "El modDesc.xml no ha sido encontrado en este mod. Probablemente no sea un mod seguramente. Tal vez sea una carpeta perdida, o tal vez sea un paquete de mods.", 120 | "mod_error_moddesc_damaged_recoverable" : "El modDesc.xml tiene errores, pero podría ser procesado. Si ese es el único defecto de este mod, probablemente pueda ignorarse.", 121 | "not_mod_moddesc_parse_error" : "El archivo modDesc.xml esta dañado más de lo que el escaner podría reparar. FS19 probablemente no pueda leer este mod, lo más seguro vaya...", 122 | "not_mod_moddesc_version_old_or_missing": "La versión del modDesc.xml tampoco se pudo leer o es demasiado antiguo para ser usado en FS19.", 123 | "mod_error_no_mod_version" : "Este mod carece de una versión legible. Es probable que FS19 rechace este mod o se comporte de manera incoherente.", 124 | "mod_error_no_mod_icon" : "Este mod no tiene un archivo de icono (normalmente icon.dds). FS19 rechazará mods sin íconos válidos.", 125 | "conflict_error_folder_and_file" : "Este mod existe como un archivo zip y como carpeta. FS19 prefiere cargar los archivos zip cuando carga mods, por lo que si ha realizado cambios en la versión de la carpeta, esos cambios se ignorarán.", 126 | "info_no_multiplayer_unzipped" : "Los mods descomprimidos no se pueden usar en multiplayer. Si no tiene la intención de utilizar este mod en un juego multijugador, puede ignorar este mensaje.", 127 | "file_error_copy_name" : "Este mod debe cambiarse el nombre o eliminarse, ya que parece ser una copia de :", 128 | "file_error_copy_exists" : "El archivo original existe.", 129 | "file_error_copy_missing" : "El archivo original NO existe.", 130 | "file_error_copy_identical" : "El archivo original y este archivo son idénticos.", 131 | "info_might_be_piracy" : "Este mod parece ser una versión pirateada de un DLC de pago. Esta prueba es simple, por lo que podría ser un falso positivo. Sin embargo, tenga en cuenta que el uso de tales copias pirateadas puede provocar la pérdida de soporte de GIANTS y ​​el bloqueo del servidor en Discord de GIANTS y el foro. Apoye a los desarrolladores! Hombre por favor...", 132 | "info_might_be_duplicate" : "Según su título, estos mods pueden ser duplicados entre sí. Debería comparar versiones y ver si se pueden eliminar algunas." 133 | } 134 | -------------------------------------------------------------------------------- /translations/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "language_code": "fr", 3 | "language_name": "Français", 4 | "language_locale": "fr_FR", 5 | "title": "Farming Simulator Mod Folder Checker", 6 | "tab_config": "Configuration", 7 | "tab_broken": "Fichiers endommagés", 8 | "tab_missing": "Mods manquants", 9 | "tab_conflict": "Possibles conflits", 10 | "tab_explore": "Explorer les Mods", 11 | "config_step_1": "Étape 1", 12 | "config_step_2": "Étape 2", 13 | "config_step_3": "Étape 3 (optionnelle)", 14 | "config_blurb": "Ce petit programme examine votre dossier d'installation de mods FS19 et vous informe de tout problème potentiel qu'il trouve.", 15 | "config_load_button_blurb": "Tout d'abord, vous devez pointer Mod Checker vers votre fichier gameSettings.xml ou un dossier de mods", 16 | "config_load_button": "Indiquer le fichier gameSettings.xml", 17 | "config_load_folder_button": "Indiquer le répertoire de Mods", 18 | "config_process_button_blurb": "Ensuite, cliquez sur le bouton \"Scan\" pour traiter vos mods et les fichiers de sauvegarde du jeu. Vous pouvez effectuer un nouveau balayage en utilisant ce même bouton. Remarque : si vous ne scannez qu'un dossier, les sauvegardes ne sont pas prises en compte, ce qui rend l'onglet \"Mods manquants\" quelque peu inutile.", 19 | "config_process_button": "Scanner les Mods et fichiers de sauvegarde", 20 | "latest_version_link_blurb": "Vérifier les mises à jour sur :", 21 | "user_error_open_settings": "Votre fichier de paramètres gameSettings.xml est incorrect ou illisible, ou le répertoire indiqué n'a pas pu être ouvert! Log : CTRL+ALT+D", 22 | "location_savegame_folder": "Fichiers de sauvegardes", 23 | "location_mod_folder": "Fichiers des Mods", 24 | "location_quarantine_folder": "Répertoire des Mods indésirables", 25 | "status-processing-title": "Traitement des Mods...", 26 | "config_working_status": "Lecture...", 27 | "config_testing_status": "Test...", 28 | "config_working_done": "Fait !", 29 | "button_refresh_tab": "Rafraîchir cet onglet", 30 | "broken_blurb": "Ces mods ont été détectés comme étant potentiellement problématiques. Les fichiers ZIP ou dossiers contenant des caractères non alphanumériques autres que \"_\" ne seront pas chargés par le jeu. Les Mods qui ne sont pas compressés au format ZIP ne peuvent pas être utilisés en multijoueur. Au final, le dossier mods ne doit contenir que des mods, aucun autre fichier. Ci-dessous, il y a une liste de fichiers détectés comme problématiques, et une solution suggérée", 31 | "broken_options_hide_unzipped": "Masquez les mods qui n'ont que l'avertissement \"besoin d'être compressé en .zip\" pour le multijoueur.", 32 | "missing_blurb": "Le scanner n'a pas réussi à trouver les mods ci-dessous, mais ils sont référencés dans une ou plusieurs sauvegardes. Pour les mods qui n'ont pas été achetés, c'est généralement inoffensif. Pour les mods que vous avez achetés, l'absence du fichier de mod peut vous coûter de l'argent en jeu. Pour corriger cela, téléchargez à nouveau le mod où vous l'avez obtenu à l'origine et placez-le dans le dossier mod.", 33 | "conflict_blurb": "Ces mods ont été détectés dans votre dossier mods. Dans certains cas spécifiques, ils peuvent provoquer des conflits avec d'autres mods, empêchant votre jeu de fonctionner, ou se comporter de manière étrange. Cet affichage est destiné à des fins d'information et ne doit pas être considéré comme une suggestion de ne pas utiliser les mods répertoriés ici.", 34 | "explore_blurb": "Vous trouverez ci-dessous une liste de tous les mods détectés dans votre dossier de mods ou dans vos sauvegardes. Utilisez les options fournies pour voir des groupes spécifiques de mods, y compris les mods manquants, les mods qui ne sont jamais chargés dans une sauvegarde, ou les mods qui sont chargés mais non utilisés dans une sauvegarde.", 35 | "explore_options_button": "Modifier les colonnes visibles ou les filtres", 36 | "explore_options_title": "Options de l'explorateur de mods", 37 | "explore_options_blurb": "Ici, vous pouvez définir ce qui est affiché dans l'onglet \"Explorer les Mods\", notamment les colonnes visibles ou les filtres", 38 | "explore_options_column_visibility": "Colonnes visibles", 39 | "explore_options_savegame_select": "Filtrer pour une sauvegarde unique:", 40 | "explore_options_special_lists": "Listes spéciales", 41 | "explore_options_special_inactive": "Mods inactifs", 42 | "explore_options_special_unused": "Mods actifs mais non utilisés", 43 | "explore_options_special_scripts": "Mods qui comportent des scripts LUA", 44 | "filter_savegame_all": "Toutes les sauvegardes", 45 | "filter_savegame": "Emplacement sauvegarde #", 46 | "broken_blurb_none": "Félicitations, vous n'avez pas de mods endommagés (détectés) installés", 47 | "conflict_blurb_none": "Félicitations, vous n'avez pas de mods conflictuels (détectés) installés", 48 | "missing_blurb_none": "Félicitations, vous n'avez pas de mods manquants dans vos sauvegardes - ou vous avez seulement analysé un dossier de mods.", 49 | "menu_details": "Ouvrir les détails du mod", 50 | "menu_open_explorer": "Ouvrir dans le Finder ou l'Explorateur", 51 | "menu_find_on_mod_hub": "Rechercher ce mod dans le ModHub", 52 | "menu_find_on_google": "Rechercher ce mod sur Google", 53 | "menu_find_on_duck": "Rechercher ce mod sur DuckDuckGo", 54 | "menu_find_on_bing": "Rechercher ce mod sur Bing", 55 | "menu_copy_general": "Copier : ", 56 | "menu_copy_full_path": "Copier : Chemin complet du fichier", 57 | "menu_move_file": "Déplacer mod en quarantaine", 58 | "move_mod_message": "Êtes-vous sûr de vouloir placer ce mod en quarantaine :", 59 | "move_mod_cancel": "Non, annuler", 60 | "move_mod_ok": "Oui, déplacer", 61 | "move_mod_worked": "Le mod a été déplacé !", 62 | "move_mod_failed": "Le mod n'a pas pu être déplacé", 63 | "move_mod_no_folder": "Vous devez définir un emplacement de déplacement avant d'utiliser cette commande.", 64 | "save_log_failed": "La sauvegarde du log de débogage a échoué", 65 | "save_log_worked": "Log de débogage sauvegardé avec succès", 66 | "open_debug_log": "Voir le log de débogage", 67 | "header_mod_name": "Nom", 68 | "header_mod_title": "Titre", 69 | "header_mod_version": "Version", 70 | "header_mod_size": "Taille", 71 | "header_mod_date": "Date", 72 | "header_mod_is_active": "Est actif", 73 | "header_mod_active_games": "Actif dans les sauvegardes", 74 | "header_mod_is_used": "Est utilisé", 75 | "header_mod_used_games": "Utilisé dans les sauvegardes", 76 | "header_mod_full_path": "Chemin complet", 77 | "header_mod_has_scripts": "Comporte des scripts", 78 | "header_mod_store_items": "Objets en magasin", 79 | "header_mod_author": "Auteur", 80 | "header_mod_multiplayer": "Multijoueur", 81 | "detail_mod_version": "Version", 82 | "detail_mod_size": "Taille", 83 | "detail_mod_date": "Date", 84 | "detail_mod_has_scripts": "Comporte des scripts", 85 | "detail_mod_store_items": "Objets en magasin", 86 | "detail_mod_author": "Auteur", 87 | "detail_mod_multiplayer": "Multijoueur", 88 | "filter_mod_name": "Nom", 89 | "filter_mod_title": "Titre", 90 | "filter_mod_version": "Version", 91 | "filter_mod_size": "Taille", 92 | "filter_mod_date": "Date", 93 | "filter_mod_is_active": "Est actif", 94 | "filter_mod_active_games": "Actif dans les sauvegardes", 95 | "filter_mod_is_used": "Est utilisé", 96 | "filter_mod_used_games": "Utilisé dans les sauvegardes", 97 | "filter_mod_full_path": "Chemin complet", 98 | "filter_mod_has_scripts": "Comporte des scripts", 99 | "filter_mod_store_items": "Objets en magasin", 100 | "filter_mod_author": "Auteur", 101 | "filter_mod_multiplayer": "Multijoueur", 102 | "active_used_table_savegame": "Sauvegarde", 103 | "active_used_table_active": "Actif", 104 | "active_used_table_used": "Utilisé", 105 | "file_error_name_starts_digit": "Le nom de ce fichier commence par un chiffre. FS19 exige que les mods commencent par une lettre.", 106 | "file_error_likely_copy": "Ce nom de fichier suggère qu'il s'agit d'une copie d'un autre mod.", 107 | "file_error_likely_zip_pack": "Ce mod contient \"unzip\" dans son nom, il s'agit probablement d'un pack de mods qu'il faut extraire.", 108 | "file_error_unsupported_archive": "Ce fichier est une archive, mais incompatible avec FS19. Il s'agit probablement d'un pack de mods qu'il faut extraire.", 109 | "file_error_name_invalid": "Le nom de ce fichier est incorrect. Les mods ne peuvent contenir que des caractères alphanumériques et des tirets bas. Les fichiers ZIP doivent se terminer en .zip.", 110 | "file_error_garbage_file": "Ce fichier n'a pas sa place dans votre dossier de mods. Seuls les dossiers et les fichiers zip doivent se trouver dans le dossier des mods. Ce fichier devrait être retiré.", 111 | "file_error_unreadable_zip": "Le fichier zip de ce mod n'a pas pu être lu. FS19 ne sera probablement pas en mesure de lire ce mod.", 112 | "not_mod_moddesc_missing": "Cette archive ne contient pas de fichier modDesc.xml. Ce n'est probablement pas un mod. Il s'agit peut-être d'un dossier mal placé, ou d'un pack de mods.", 113 | "mod_error_moddesc_damaged_recoverable": "Le fichier modDesc.xml comporte des erreurs, mais elles ont été récupérées. Si c'est la seule erreur qui apparaît pour ce mod, vous pouvez probablement l'ignorer.", 114 | "not_mod_moddesc_parse_error": "Le fichier modDesc.xml est endommagé au-delà du point où le scanner peut le récupérer. FS19 sera probablement incapable d'utiliser ce mod.", 115 | "not_mod_moddesc_version_old_or_missing": "La version du modDesc.xml n'a pas pu être lue, ou bien elle est trop ancienne pour être compatible avec FS19.", 116 | "mod_error_no_mod_version": "Ce mod ne dispose pas d'une version lisible. FS19 rejettera probablement ce mod ou se comportera de manière incohérente.", 117 | "mod_error_no_mod_icon": "Ce mod ne possède pas de fichier d'icône. FS19 rejettera les mods sans icônes valides.", 118 | "conflict_error_folder_and_file": "Ce mod existe à la fois sous forme d'un fichier .zip et d'un dossier. FS19 préférera le fichier zip lors du chargement des mods, donc si vous avez apporté des modifications à la version du dossier, ces modifications seront ignorées.", 119 | "info_no_multiplayer_unzipped": "Les mods décompressés ne peuvent pas être utilisés en mode multijoueur. Si vous n'avez pas l'intention d'utiliser ce mod dans une partie multijoueur, vous pouvez ignorer ce message.", 120 | "file_error_copy_name": "Ce fichier devrait être renommé ou supprimé car il semble être une copie de :", 121 | "file_error_copy_exists": "Le fichier original existe.", 122 | "file_error_copy_missing": "Le fichier original n'existe pas.", 123 | "file_error_copy_identical": "Le fichier original et ce fichier sont identiques.", 124 | "info_might_be_piracy": "Ce mod semble être une version craquée / piratée d'un DLC payant. Ce test est sommaire, il peut donc s'agir d'un faux positif, mais sachez que l'utilisation d'un DLC piraté vous empêchera de recevoir de l'aide de l'assistance Giants, et constitue un motif de bannissement du discord et des forums officiels. Soutenez les développeurs !", 125 | "info_might_be_duplicate": "D'après leur titre, ces mods pourraient être des doublons les uns des autres. Vous devriez comparer les versions et voir si certaines pourraient être supprimées.", 126 | "user_pref_title_main": "Préférences utilisateur", 127 | "user_pref_title_lang": "Langue", 128 | "user_pref_blurb_lang": "Ceci vous permet de déterminer la langue à afficher dans Mod Checker. Note : pour l'appliquer, il faut désactiver puis réactiver.", 129 | "user_pref_title_game_settings": "gameSettings.xml", 130 | "user_pref_blurb_game_settings": "Ceci vous permet de définir l'emplacement par défaut de gameSettings.xml. Remarque : pour conserver votre emplacement actuel, désactivez cette option après avoir chargé un gameSettings.xml", 131 | "user_pref_setting_auto_process": "Scanne automatiquement le dossier mod au démarrage. Vous devez avoir un emplacement sauvegardé de gameSettings.xml.", 132 | "user_pref_title_main_window": "Fenêtre principale", 133 | "user_pref_blurb_main_window": "Cela vous permet de définir la taille par défaut de la fenêtre principale", 134 | "user_pref_title_detail_window": "Fenêtre de détail", 135 | "user_pref_blurb_detail_window": "Cela vous permet de définir la taille par défaut de la fenêtre de détail", 136 | "user_pref_title_move_dest": "Destination du déplacement des mods", 137 | "user_pref_blurb_move_dest": "Cela vous permet de définir une destination pour les fichiers de mods indésirables, et de basculer cette fonctionnalité pour qu'elle soit active ou inactive", 138 | "user_pref_setting_window_x": "Largeur de la fenêtre", 139 | "user_pref_setting_window_y": "Hauteur de la fenêtre", 140 | "user_pref_setting_window_max": "Démarrer en taille maximisée", 141 | "user_pref_setting_use_move": "Permettre aux mods d'être déplacés (nécessite un emplacement défini, à désactiver pour oublier l'emplacement actuel)", 142 | "user_pref_setting_move_dest": "Destination pour les mods déplacés", 143 | "user_pref_setting_move_button": "Définir destination", 144 | "user_pref_setting_move_open_button": "Ouvrir ce dossier de destination", 145 | "user_pref_setting_current_lang": "Réglage de la langue actuelle", 146 | "user_pref_setting_lock_lang": "Toujours utiliser la langue courante (ne pas détecter au démarrage)", 147 | "user_pref_setting_remember_last": "Utiliser le dernier gameSettings.xml chargé (off = Toujours commencer avec le gameSettings.xml ci-dessous)", 148 | "user_pref_setting_current_gamesettings": "gameSettings.xml actuellement mémorisé" 149 | } -------------------------------------------------------------------------------- /translations/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "language_code": "nl", 3 | "language_name": "Nederlands", 4 | "language_locale": "nl_NL", 5 | "title": "Farming Simulator Mod Folder Checker", 6 | "tab_config": "Instellingen", 7 | "tab_broken": "Kapotte Bestanden", 8 | "tab_missing": "Ontbrekende Mods", 9 | "tab_conflict": "Mogelijke conflicten", 10 | "tab_explore": "Mods verkennen", 11 | "config_step_1": "Stap 1", 12 | "config_step_2": "Stap 2", 13 | "config_step_3": "Stap 3 (optioneel)", 14 | "config_blurb": "Dit kleine programma zal een kijkje nemen in uw mod installatiemap en je informeren over mogelijke problemen die het vindt.", 15 | "config_load_button_blurb": "Eerst moet je Mod Checker naar je gameSettings.xml bestand of een mods map wijzen", 16 | "config_load_button": "Instellingen Laden", 17 | "config_load_folder_button": "Laad map", 18 | "config_process_button_blurb": "Next, click the \"Scan\" button to process your mods and save game files. You can re-scan using this same button.", 19 | "config_process_button": "Scan Mods and Save Games", 20 | "config_quarantine_folder_blurb": "Als je mods uit je mod map wilt kunnen verplaatsen met dit programma, gebruik dan deze knop om in te stellen waar je ze naartoe wilt verplaatsen.", 21 | "config_move_folder_button": "Bestemming voor Verplaatste Mods", 22 | "latest_version_link_blurb": "Download de laatste versie op:", 23 | "user_error_open_settings": "Het geselecteerde spelinstellingen bestand is ongeldig of onleesbaar, of de opgegeven map kan niet worden geopend! Log: CTRL+ALT+D", 24 | "location_savegame_folder": "Save Game Files", 25 | "location_mod_folder": "Mod Bestanden", 26 | "location_quarantine_folder": "Map voor ongewenste mods", 27 | "status-processing-title": "Mods Verwerken...", 28 | "config_working_status": "Lezen...", 29 | "config_testing_status": "Testen...", 30 | "config_working_done": "Klaar!", 31 | "button_refresh_tab": "Ververs dit tabblad", 32 | "broken_blurb": "Bij deze mods is mogelijk een probleem aangetroffen. ZIP-bestanden of mappen met een ander niet-alfanumeriek teken dan \"_\" zullen niet worden geladen door het spel. Mods die niet zijn gecomprimeerd als een ZIP-bestand kunnen niet worden gebruikt in multiplayerspellen. Tot slot zou de map mod alleen mods moeten bevatten, geen andere bestanden. Hieronder is een lijst met probleembestanden en een voorgestelde oplossing", 33 | "broken_options_hide_unzipped": "Verberg mods die alleen multiplayer \"moeten gezipped zijn\" waarschuwing hebben.", 34 | "missing_blurb": "The scanner failed to find the mods below, however they are referenced in one or more save games. For mods that have not been purchased, this is usually harmless. For mods you have purchased, missing the mod file could cost you in-game money. To correct this, re-download the mod from where you originally got it and place it in the mod folder.", 35 | "conflict_blurb": "Deze mods werden gedetecteerd in je mod map. In sommige specifieke gevallen kunnen ze conflicten veroorzaken met andere mods, waardoor het spel niet werkt of onvoorspelbaar gedrag vertoont. Deze weergave is bedoeld voor informatieve doeleinden en moet niet worden opgevat als suggestie om niets te gebruiken dat hier vermeld staat", 36 | "explore_blurb": "Below, you will find a list of all mods detected in your mod folder or in your save games. Use the provided options to see specific sets of mods including missing mods, mods that are never loaded in a save, or mods that are loaded but not used in a save", 37 | "explore_options_button": "Wijzig kolomzichtbaarheid of filters", 38 | "explore_options_title": "Mods Verkennen Opties", 39 | "explore_options_blurb": "Hier kun je instellen wat wordt weergegeven in de tabel \"Mods Verkennen\" inclusief kolom zichtbaarheid en enkele filters", 40 | "explore_options_column_visibility": "Kolom zichtbaarheid", 41 | "explore_options_savegame_select": "Filter to only savegame:", 42 | "explore_options_special_lists": "Speciale lijsten", 43 | "explore_options_special_inactive": "Inactieve Mods", 44 | "explore_options_special_unused": "Actieve maar ongebruikte Mods", 45 | "explore_options_special_scripts": "Mods die LUA scripting gebruiken", 46 | "filter_savegame_all": "All Save Game Slots", 47 | "filter_savegame": "Save Game Slot #", 48 | "menu_details": "Open Mod Detail", 49 | "menu_open_explorer": "Weergeven in Finder / Verkenner", 50 | "menu_find_on_mod_hub": "Zoek op ModHub naar deze Mod", 51 | "menu_find_on_google": "Zoek op Google naar deze Mod", 52 | "menu_copy_general": "Kopieer : ", 53 | "menu_copy_full_path": "Kopieer : Volledig Bestandspad", 54 | "menu_move_file": "Verplaats Mod naar quarantaine", 55 | "move_mod_message": "Weet je zeker dat je deze mod naar quarantaine wilt verplaatsen:", 56 | "move_mod_cancel": "Nee, annuleer", 57 | "move_mod_ok": "Ja, verplaatsen", 58 | "move_mod_worked": "De mod is verplaatst!", 59 | "move_mod_failed": "De mod kon niet verplaatst worden", 60 | "move_mod_no_folder": "Je moet een bestemming instellen voordat je deze opdracht kunt gebruiken", 61 | "save_log_failed": "Opslaan debug log mislukt", 62 | "save_log_worked": "Debug log succesvol opgeslagen", 63 | "open_debug_log": "Bekijk Debug Log", 64 | "header_mod_name": "Naam", 65 | "header_mod_title": "Titel", 66 | "header_mod_version": "Versie", 67 | "header_mod_size": "Grootte", 68 | "header_mod_is_active": "Is Actief", 69 | "header_mod_active_games": "Active In Saves", 70 | "header_mod_is_used": "Wordt Gebruikt", 71 | "header_mod_used_games": "Used In Saves", 72 | "header_mod_full_path": "Volledig pad", 73 | "header_mod_has_scripts": "Gebruikt Scripts", 74 | "header_mod_store_items": "Store Items", 75 | "header_mod_author": "Auteur", 76 | "header_mod_multiplayer": "Multiplayer", 77 | "active_used_table_savegame": "Savegame", 78 | "active_used_table_active": "Actief", 79 | "active_used_table_used": "Gebruikt", 80 | "file_error_name_starts_digit": "Dit bestand begint met een cijfer. FS19 vereist dat mods beginnen met een letter.", 81 | "file_error_likely_copy": "Deze bestandsnaam suggereert dat het een dubbele kopie van een andere mod is.", 82 | "file_error_likely_zip_pack": "Dit bestand heeft \"unzip\" in de naam, het is waarschijnlijk een mod pack die uitgepakt moet worden.", 83 | "file_error_unsupported_archive": "Dit bestand is een archief, maar niet een die FS19 kan lezen. Het is waarschijnlijk een mod pack en zou moeten worden uitgepakt.", 84 | "file_error_name_invalid": "Deze bestandsnaam is onjuist. Mods kunnen alleen alfa-numerieke tekens en underscores bevatten. ZIP-bestanden moeten eindigen op .zip.", 85 | "file_error_garbage_file": "Dit bestand hoort niet thuis in de mods map. Alleen mappen en zip-bestanden zouden in de mods map moeten staan. Dit bestand zou verwijderd moeten worden.", 86 | "file_error_unreadable_zip": "Het zip-bestand van deze mod kon niet gelezen worden. FS19 zal waarschijnlijk ook niet in staat zijn om deze mod te lezen.", 87 | "not_mod_moddesc_missing": "Een modDesc.xml kon niet worden gevonden voor deze mod. Het is waarschijnlijk helemaal geen mod. Misschien is het een verkeerd geplaatste map, of misschien is het een mod pack.", 88 | "mod_error_moddesc_damaged_recoverable": "De modDesc.xml bevat fouten, maar ze konden worden hersteld. Als dit de enige fout is die voor deze mod verschijnt, kun je deze fout waarschijnlijk negeren.", 89 | "not_mod_moddesc_parse_error": "Het modDesc.xml-bestand is zo beschadigd dat de scanner het niet heeft kunnen herstellen. FS19 kan deze mod waarschijnlijk niet gebruiken.", 90 | "not_mod_moddesc_version_old_or_missing": "De modDesc.xml versie kon niet worden gelezen, of het is te oud om te worden gebruikt met FS19.", 91 | "mod_error_no_mod_version": "Deze mod heeft geen leesbare versie. FS19 zal deze mod waarschijnlijk afwijzen of zich inconsequent gedragen.", 92 | "mod_error_no_mod_icon": "Deze mod heeft geen icoon. FS19 weigert mods zonder geldige iconen.", 93 | "conflict_error_folder_and_file": "Deze mod bestaat zowel als een zip-bestand als een map. FS19 geeft voorrang aan het zip-bestand bij het laden van mods, dus als je wijzigingen hebt aangebracht in de mapversie, worden deze wijzigingen genegeerd.", 94 | "info_no_multiplayer_unzipped": "Uitgepakte mods kunnen niet worden gebruikt in multiplayer. Als je niet van plan bent om deze mod te gebruiken in een multiplayer spel, dan kun je dit bericht negeren.", 95 | "file_error_copy_name": "Dit bestand zou moeten worden hernoemd of verwijderd omdat het een kopie lijkt te zijn van:", 96 | "file_error_copy_exists": "Het oorspronkelijke bestand bestaat al.", 97 | "file_error_copy_missing": "Het oorspronkelijke bestand bestaat NIET.", 98 | "file_error_copy_identical": "Het oorspronkelijke bestand en dit bestand zijn identiek.", 99 | "info_might_be_piracy": "Deze mod lijkt een gekraakte versie van een betaalde DLC te zijn. Deze test is simplistisch, dus dit zou een valse positieve uitslag kunnen zijn. Wees er echter van bewust dat het gebruik van een gekraakte DLC je ervan weerhoudt hulp te ontvangen van Giants en reden is voor een ban van de officiële Discord en fora. Ondersteun de ontwikkelaars!" 100 | } -------------------------------------------------------------------------------- /translations/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "language_code": "pl", 3 | "language_name": "Polski", 4 | "language_locale": "pl_PL", 5 | "title": "Farming Simulator Mod Folder Checker", 6 | "tab_config": "Konfiguracja", 7 | "tab_broken": "Niepoprawne pliki", 8 | "tab_missing": "Brakujące mody", 9 | "tab_conflict": "Możliwe konflikty", 10 | "tab_explore": "Przegląd modów", 11 | "config_step_1": "Krok 1", 12 | "config_step_2": "Krok 2", 13 | "config_step_3": "Krok 3 (opcjonalnie)", 14 | "config_blurb": "Ten mały program przejrzy twój folder z modami i poinformuje Cię o wszelkich potencjalnych problemach, które znalazł.", 15 | "config_load_button_blurb": "Najpierw musisz załadować do Mod Checker Twój plik gameSettings.xml lub folder z modami", 16 | "config_load_button": "Załaduj ustawienia", 17 | "config_load_folder_button": "Załaduj folder", 18 | "config_process_button_blurb": "Następnie, kliknij przycisk \"Skanuj\", aby przetworzyć twoje mody i zapisy z gry. Używając tego samego przycisku ponownie możesz na nowo przeskanować mody i zapisy. Uwaga: Jeśli skanujesz tylko folder, a zapisy z gier nie są zaznaczone to zakładka \"Brakujące modyfikacje\" staje się bezużyteczna.", 19 | "config_process_button": "Skanuj mody i zapisy", 20 | "latest_version_link_blurb": "Najnowszą wersję znajdziesz tutaj:", 21 | "user_error_open_settings": "Wybrany plik ustawień jest niepoprawny lub uszkodzony, albo określony folder nie mógł zostać otwarty! Log: CTRL+ALT+D", 22 | "location_savegame_folder": "Plik z ustawieniami", 23 | "location_mod_folder": "Folder z modami", 24 | "location_quarantine_folder": "Folder dla przeniesionych modów", 25 | "status-processing-title": "Przetwarzanie modów...", 26 | "config_working_status": "Wczytywanie...", 27 | "config_testing_status": "Testowanie...", 28 | "config_working_done": "Gotowe!", 29 | "button_refresh_tab": "Odśwież tą zakładkę", 30 | "broken_blurb": "Te modyfikacje zostały wykryte jako możliwy problem. Pliki ZIP lub foldery z jakimkolwiek znakiem niealfanumerycznym (spacja, nawias, itp.) innym niż \"_\" nie zostaną załadowane przez grę. Modyfikacje, które nie są skompresowane jako plik ZIP nie mogą być używane w grach wieloosobowych. Dodatkowo folder modyfikacji powinien zawierać tylko modyfikacje, żadnych innych plików. Poniżej znajduje się lista błędów i sugerowane rozwiązanie", 31 | "broken_options_hide_unzipped": "Ukryj mody, które mają tylko ostrzeżenie dotyczące gry wieloosobowej (wymaga spakowania).", 32 | "missing_blurb": "Skaner nie mógł znaleźć modów z listy poniżej, jest do nich odwołanie w jednym lub kilku zapisach. W przypadku modów, które nie zostały zakupione, jest to zwykle nieszkodliwe, jednak w przypadku zakupionych modów, brak takiego może narazić Cię na koszty w grze. Aby to naprawić, pobierz ponownie modyfikację z miejsca, w którym ją pierwotnie uzyskałeś i umieść ją w folderze z modami.", 33 | "conflict_blurb": "Te mody zostały wykryte w folderze modów. W niektórych szczególnych przypadkach mogą one powodować konflikty z innymi modami, powodując, że Twoja gra nie działa lub zachowuje się dziwnie. Zazwyczaj usunięcie ich pomagało rozwiązać problem u innych graczy, ale lista ta służy jedynie celom informacyjnym i nie wymusza na tobie usunięcia tych modów", 34 | "explore_blurb": "Poniżej znajdziesz listę wszystkich modów wykrytych w folderze z modami lub w zapisach. Możesz użyć dostępnych opcji, aby sprawdzić posiadane mody, np. brakujące dla któregoś z zapisów lub te, które nigdy nie zostały użyte w żadnym z zapisów, albo te, które są aktywne, ale nie są używane w zapisie", 35 | "explore_options_button": "Zmień widoczność kolumn lub filtry", 36 | "explore_options_title": "Opcje przeglądu modów", 37 | "explore_options_blurb": "Tutaj możesz ustawić co jest wyświetlane w zakładce \"Przegląd modów\", w tym widoczność kolumn i niektóre filtry", 38 | "explore_options_column_visibility": "Widoczność kolumn", 39 | "explore_options_savegame_select": "Filtr tylko dla zapisów:", 40 | "explore_options_special_lists": "Listy specjalne", 41 | "explore_options_special_inactive": "Mody nieaktywne", 42 | "explore_options_special_unused": "Mody aktywne, ale nieużywane", 43 | "explore_options_special_scripts": "Mody używające skryptów LUA", 44 | "filter_savegame_all": "Wszystkie zapisy", 45 | "filter_savegame": "Zapis #", 46 | "broken_blurb_none": "Gratulacje, nie masz (nie wykryto) uszkodzonych modów", 47 | "conflict_blurb_none": "Gratulacje, nie masz (nie wykryto) konfliktów z innymi modami", 48 | "missing_blurb_none": "Gratulacje, nie masz brakujących modów w swoich zapisanych z gry (albo przeskanowałeś tylko folder z modami).", 49 | "menu_details": "Otwórz szczegółowe informacje", 50 | "menu_open_explorer": "Pokaż w eksploratorze plików", 51 | "menu_find_on_mod_hub": "Wyszukaj modu na ModHub", 52 | "menu_find_on_google": "Wyszukaj modu w Google", 53 | "menu_find_on_duck": "Wyszukaj modu w DuckDuckGo", 54 | "menu_find_on_bing": "Wyszukaj modu w Bing", 55 | "menu_copy_general": "Skopiuj: ", 56 | "menu_copy_full_path": "Skopiuj: Pełną ścieżkę pliku", 57 | "menu_move_file": "Przenieś mod do kwarantanny", 58 | "move_mod_message": "Czy na pewno chcesz przenieść ten mod do kwarantanny:", 59 | "move_mod_cancel": "Nie, anuluj", 60 | "move_mod_ok": "Tak, przenieś", 61 | "move_mod_worked": "Mod został przeniesiony!", 62 | "move_mod_failed": "Nie można było przenieś tego modu", 63 | "move_mod_no_folder": "Musisz ustawić lokalizację docelową przed użyciem tej komendy", 64 | "save_log_failed": "Zapisanie LOGa nie powiodło się", 65 | "save_log_worked": "Zapisano LOG poprawnie", 66 | "open_debug_log": "Zobacz LOG", 67 | "header_mod_name": "Nazwa", 68 | "header_mod_title": "Tytuł", 69 | "header_mod_version": "Wersja", 70 | "header_mod_size": "Rozmiar", 71 | "header_mod_date": "Data", 72 | "header_mod_is_active": "Jest aktywny", 73 | "header_mod_active_games": "Jest aktywny w zapisach", 74 | "header_mod_is_used": "Jest używany", 75 | "header_mod_used_games": "Jest używany w zapisach", 76 | "header_mod_full_path": "Pełna ścieżka", 77 | "header_mod_has_scripts": "Używa skryptów", 78 | "header_mod_store_items": "Ilość", 79 | "header_mod_author": "Autor", 80 | "header_mod_multiplayer": "Tryb wieloosobowy", 81 | "detail_mod_version": "Wersja", 82 | "detail_mod_size": "Rozmiar", 83 | "detail_mod_date": "Data", 84 | "detail_mod_has_scripts": "Używa skryptów", 85 | "detail_mod_store_items": "Ilość", 86 | "detail_mod_author": "Autor", 87 | "detail_mod_multiplayer": "Tryb wieloosobowy", 88 | "filter_mod_name": "Nazwa", 89 | "filter_mod_title": "Tytuł", 90 | "filter_mod_version": "Wersja", 91 | "filter_mod_size": "Rozmiar", 92 | "filter_mod_date": "Data", 93 | "filter_mod_is_active": "Jest aktywny", 94 | "filter_mod_active_games": "Jest aktywny w zapisach", 95 | "filter_mod_is_used": "Jest używany", 96 | "filter_mod_used_games": "Jest używany w zapisach", 97 | "filter_mod_full_path": "Pełna ścieżka", 98 | "filter_mod_has_scripts": "Używa skryptów", 99 | "filter_mod_store_items": "Ilość", 100 | "filter_mod_author": "Autor", 101 | "filter_mod_multiplayer": "Tryb wieloosobowy", 102 | "active_used_table_savegame": "Zapis gry", 103 | "active_used_table_active": "Aktywny", 104 | "active_used_table_used": "Używany", 105 | "file_error_name_starts_digit": "Ten plik zaczyna się od cyfry. FS19 wymaga, aby mody zaczynały się literą.", 106 | "file_error_likely_copy": "Ta nazwa pliku sugeruje, że jest to zduplikowana kopia innego modu.", 107 | "file_error_likely_zip_pack": "Ten plik ma \"rozpakować\" w nazwie, prawdopodobnie jest to paczka modów, która powinna zostać rozpakowana.", 108 | "file_error_unsupported_archive": "Ten plik jest archiwum, ale nie jest plikiem, który FS19 może odczytać. Prawdopodobnie jest to paczka modów i powinna zostać wypakowana.", 109 | "file_error_name_invalid": "Ten plik jest niepoprawnie nazwany. Modyfikacje mogą zawierać tylko znaki alfanumeryczne i podkreślenie. Pliki ZIP muszą kończyć się .zip.", 110 | "file_error_garbage_file": "Ten plik nie jest modem. Tylko foldery i pliki zip powinny znajdować się w folderze z modami. Ten plik powinien zostać usunięty.", 111 | "file_error_unreadable_zip": "Nie można wczytać tego pliku ZIP. FS19 może również nie być w stanie wczytać tego modu.", 112 | "not_mod_moddesc_missing": "Plik modDesc.xml nie został znaleziony w tym modzie. Prawdopodobnie nie jest to w ogóle mod lub może jest to przypadkowy folder, albo może jest to paczka modów.", 113 | "mod_error_moddesc_damaged_recoverable": "Plik modDesc.xml zawiera błędy. Jeśli jest to jedyny błąd, który pojawia się przy tym modzie, prawdopodobnie możesz go zignorować.", 114 | "not_mod_moddesc_parse_error": "Plik modDesc.xml jest uszkodzony, ale skaner może go odczytać. FS19 prawdopodobnie nie będzie w stanie załadować tego modu.", 115 | "not_mod_moddesc_version_old_or_missing": "Wersja modDesc.xml nie może być odczytana lub jest zbyt stara, aby mod mógł być używany w FS19.", 116 | "mod_error_no_mod_version": "Ten mod nie posiada czytelnej wersji. FS19 prawdopodobnie nie załaduje go lub spowoduje to błędy.", 117 | "mod_error_no_mod_icon": "Ten mod nie ma pliku \"icon\". FS19 nie załaduje tego modu poprawnie.", 118 | "conflict_error_folder_and_file": "Ten mod istnieje zarówno jako plik ZIP, jak i folder. FS19 preferuje plik ZIP podczas ładowania modów, więc jeśli dokonałeś zmian w folderze, te zmiany zostaną zignorowane.", 119 | "info_no_multiplayer_unzipped": "Rozpakowane mody nie mogą być używane w trybie wieloosobowym. Jeśli nie zamierzasz używać tego modu w grze wieloosobowej, możesz zignorować tę wiadomość.", 120 | "file_error_copy_name": "Ten plik powinien mieć zmienioną nazwę lub zostać usunięty, ponieważ wydaje się być kopią:", 121 | "file_error_copy_exists": "Oryginalny plik istnieje.", 122 | "file_error_copy_missing": "Oryginalny plik NIE istnieje.", 123 | "file_error_copy_identical": "Oryginalny plik i ten plik są identyczne.", 124 | "info_might_be_piracy": "Ten mod wygląda na piracką wersję DLC. Może to być błędne rozpoznanie ze względu na sposób działania programu, ale używanie pirackich wersji DLC uniemożliwi pomoc w problemach z grą od oficjalnego kanału wsparcia Giantsa oraz zostaniesz zbanowany z oficjalnego serwera Discord i oficjalnego forum gry. Wspieraj twórców gier!", 125 | "info_might_be_duplicate": "Na podstawie nazwy modu, mogą one być duplikatami. Powinieneś porównać wersje i sprawdzić, czy niektóre z nich mogą zostać usunięte.", 126 | "user_pref_title_main": "Ustawienia użytkownika", 127 | "user_pref_title_lang": "Język", 128 | "user_pref_blurb_lang": "Pozwala to na zmianę wykrytego języka w Mod Checker. Uwaga: Aby zastosować zmiany, wyłącz i ponownie włącz program.", 129 | "user_pref_title_game_settings": "gameSettings.xml", 130 | "user_pref_blurb_game_settings": "Pozwala to ustawić domyślną lokalizację gameSettings.xml. Uwaga: Aby zawsze zachować aktualną lokalizację, wyłącz to po załadowaniu gameSettings.xml", 131 | "user_pref_setting_auto_process": "Automatycznie przetwarzaj folder z modami przy starcie. Musisz mieć zapisaną lokalizację gameSettings.xml.", 132 | "user_pref_title_main_window": "Okno główne", 133 | "user_pref_blurb_main_window": "Pozwala to ustawić domyślny rozmiar okna głównego", 134 | "user_pref_title_detail_window": "Okno szczegółów", 135 | "user_pref_blurb_detail_window": "Pozwala to ustawić domyślny rozmiar okna szczegółów", 136 | "user_pref_title_move_dest": "Lokalizacja do przenoszonych modów", 137 | "user_pref_blurb_move_dest": "Pozwala ustawić lokalizację dla niechcianych modów i przełącz tę funkcję, aby była aktywna lub nieaktywna", 138 | "user_pref_setting_window_x": "Szerokość okna", 139 | "user_pref_setting_window_y": "Wysokość okna", 140 | "user_pref_setting_window_max": "Uruchom zmaksymalizowane", 141 | "user_pref_setting_use_move": "Pozwól na przenoszenie modów (wymaga ustawienia lokalizacji, wyłącz aby zapomnieć o bieżącej lokalizacji)", 142 | "user_pref_setting_move_dest": "Lokalizacja dla przeniesionych modów", 143 | "user_pref_setting_move_button": "Ustaw lokalizację", 144 | "user_pref_setting_move_open_button": "Otwórz lokalizację", 145 | "user_pref_setting_current_lang": "Aktualny język", 146 | "user_pref_setting_lock_lang": "Zawsze używaj bieżącego języka (nie wykrywaj przy starcie)", 147 | "user_pref_setting_remember_last": "Użyj ostatnio załadowanego gameSettings.xml (wył. = Zawsze zaczynaj z gameSettings.xml poniżej)", 148 | "user_pref_setting_current_gamesettings": "Aktualnie zapamiętany gameSettings.xml" 149 | } --------------------------------------------------------------------------------