Files
planka/client/package.json
T
Daniel Hiller 9069b24cfb chore: Add a locale completeness check
An incomplete locale falls back to English at runtime, so a gap breaks nothing
and nobody notices it on their own. 2.2.1 shipped fifty-six user-facing strings
that existed only in English and German, and it took someone looking for
something else to find them. `npm run client:locales:check` compares every
locale against the reference and exits non-zero when one is behind.

It compares `login.js` and `core.js` separately and never merges them.
`login.js` is the embedded bundle and is all that exists until a session is
established, so a key present only in `core.js` is still missing from every
screen shown before login — the two-factor challenge among them. Merging the
two hides exactly that, which is how the six strings of the challenge stayed
English in thirty-three languages.

Keys are compared on their base name, with the CLDR plural category stripped,
because how many categories a language needs is a property of that language:
English has two, Japanese one, Arabic six. Comparing the suffixed names would
have demanded an English `_one` from Japanese, where i18next never reads it.
Each plural key is then checked against the categories the language itself
declares, through the same Intl.PluralRules that i18next resolves with — a
missing category falls back to `_other` silently, and Russian `few` and `many`
are reachable with counts a user really sees.

It is deliberately not part of `lint`: a pull request that adds a string is
expected to leave the other locales behind for a while, and a check that fails
every such request would only be switched off. This one belongs before a
release.
2026-09-08 19:54:27 +02:00

196 lines
5.2 KiB
JSON

{
"name": "planka-client",
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"postinstall": "patch-package",
"lint": "eslint --ext js,jsx src --report-unused-disable-directives",
"locales:check": "node scripts/check-locales.js",
"start": "vite",
"test": "jest",
"test:acceptance": "cucumber-js --import tests/acceptance/cucumber.conf.js --import tests/acceptance/steps/**/*.js --format @cucumber/pretty-formatter tests"
},
"babel": {
"presets": [
"@babel/preset-env"
]
},
"eslintConfig": {
"env": {
"browser": true,
"jest": true
},
"parser": "@babel/eslint-parser",
"parserOptions": {
"babelOptions": {
"presets": [
"airbnb"
]
},
"requireConfigFile": false
},
"plugins": [
"prettier"
],
"extends": [
"airbnb",
"airbnb/hooks",
"plugin:prettier/recommended"
],
"rules": {
"import/no-unresolved": [
"error",
{
"ignore": [
"\\?url$",
"\\.svg\\?react$"
]
}
],
"prettier/prettier": [
"error",
{
"endOfLine": "auto",
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all"
}
]
},
"overrides": [
{
"files": [
"tests/acceptance/**/*.js"
],
"rules": {
"import/extensions": "off"
},
"globals": {
"browser": "readonly",
"context": "readonly",
"page": "readonly"
}
}
]
},
"jest": {
"transform": {
"^.+\\.(js|jsx)$": "babel-jest"
}
},
"overrides": {
"react-mentions": {
"@babel/runtime": "^7.28.6"
},
"linkify-it": "^5.0.2",
"svgo": "^3.3.4",
"uuid": "^11.1.1"
},
"dependencies": {
"@ballerina/highlightjs-ballerina": "^1.0.1",
"@diplodoc/cut-extension": "^1.1.1",
"@diplodoc/transform": "^4.70.2",
"@gravity-ui/components": "^4.18.0",
"@gravity-ui/markdown-editor": "^15.35.1",
"@gravity-ui/uikit": "^7.34.0",
"@juggle/resize-observer": "^3.4.0",
"@vitejs/plugin-react": "^5.2.0",
"browserslist-to-esbuild": "^2.1.1",
"classnames": "^2.5.1",
"date-fns": "^4.1.0",
"dequal": "^2.0.3",
"highlight.js": "^11.11.1",
"highlightjs-4d": "^1.0.6",
"highlightjs-alan": "^0.0.2",
"highlightjs-apex": "^1.5.0",
"highlightjs-blade": "^0.1.0",
"highlightjs-cobol": "^0.3.3",
"highlightjs-cshtml-razor": "^2.2.0",
"highlightjs-gf": "^1.0.1",
"highlightjs-jolie": "^0.1.8",
"highlightjs-lean": "^1.2.0",
"highlightjs-lookml": "^1.0.2",
"highlightjs-macaulay2": "^0.5.0",
"highlightjs-mlir": "^0.0.1",
"highlightjs-qsharp": "^1.0.2",
"highlightjs-redbol": "^2.1.2",
"highlightjs-rpm-specfile": "^1.0.0",
"highlightjs-sap-abap": "^0.3.0",
"highlightjs-solidity": "^2.0.6",
"highlightjs-supercollider": "^1.0.0",
"highlightjs-svelte": "^1.0.6",
"highlightjs-xsharp": "^1.0.0",
"highlightjs-zenscript": "^2.0.0",
"hightlightjs-papyrus": "^0.0.4",
"history": "^5.3.0",
"i18next": "^25.8.18",
"i18next-browser-languagedetector": "^8.2.1",
"javascript-time-ago": "^2.6.4",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
"linkify-react": "^4.3.2",
"linkifyjs": "^4.3.2",
"lodash": "^4.18.1",
"lowlight": "^3.3.0",
"markdown-it": "^13.0.2",
"nanoid": "^5.1.7",
"papaparse": "^5.5.3",
"patch-package": "^8.0.1",
"photoswipe": "^5.4.4",
"prop-types": "^15.8.1",
"qrcode.react": "^4.2.0",
"react": "18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-datepicker": "^9.1.0",
"react-dom": "18.2.0",
"react-dropzone": "^15.0.0",
"react-frame-component": "^5.2.7",
"react-hot-toast": "^2.6.0",
"react-i18next": "^16.5.8",
"react-input-mask": "^2.0.4",
"react-intersection-observer": "^10.0.3",
"react-mentions": "^4.4.10",
"react-photoswipe-gallery": "^4.0.0",
"react-redux": "^9.2.0",
"react-router": "^7.13.1",
"react-textarea-autosize": "^8.5.9",
"react-time-ago": "^7.4.4",
"redux": "^5.0.1",
"redux-logger": "^3.0.6",
"redux-orm": "^0.16.2",
"redux-saga": "^1.4.2",
"reselect": "^5.1.1",
"sails.io.js": "^1.2.1",
"sass-embedded": "^1.98.0",
"semantic-ui-react": "^2.1.5",
"socket.io-client": "^4.8.3",
"validator": "^13.15.26",
"vite": "^7.3.2",
"vite-plugin-commonjs": "^0.10.4",
"vite-plugin-node-polyfills": "^0.25.0",
"vite-plugin-svgr": "^4.5.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@babel/eslint-parser": "^7.28.6",
"@babel/preset-env": "^7.29.0",
"@cucumber/cucumber": "^12.7.0",
"@cucumber/pretty-formatter": "^3.2.0",
"@playwright/test": "^1.58.2",
"babel-jest": "^30.3.0",
"babel-preset-airbnb": "^5.0.0",
"eslint": "^8.57.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^4.6.2",
"jest": "^30.3.0",
"playwright": "^1.58.2",
"prettier": "3.8.1"
}
}