From 68163e5a98daeba25c6d49ca207c3ed28cf8e1b7 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 21 Nov 2023 00:17:39 +0100 Subject: [PATCH] lint-locales --- .eslintrc.json | 15 ++++++++----- README.md | 9 +++++--- renderer/i18n.ts | 2 ++ scripts/locales/keys.jq | 1 + scripts/locales/locales.sh | 44 ++++++++++++++++++++++++++++++++++++++ scripts/locales/sort.jq | 13 +++++++++++ src/locales/de.json | 3 +++ src/locales/de.ts | 6 ------ src/locales/en.json | 3 +++ src/locales/en.ts | 6 ------ 10 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 scripts/locales/keys.jq create mode 100755 scripts/locales/locales.sh create mode 100644 scripts/locales/sort.jq create mode 100644 src/locales/de.json delete mode 100644 src/locales/de.ts create mode 100644 src/locales/en.json delete mode 100644 src/locales/en.ts diff --git a/.eslintrc.json b/.eslintrc.json index 9e0f38b..9360b68 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,8 +13,7 @@ "plugin:promise/recommended", "plugin:security/recommended", "plugin:vue/vue3-recommended", - "plugin:storybook/recommended", - "plugin:prettier/recommended" + "plugin:storybook/recommended" ], "parserOptions": { "ecmaVersion": "latest", @@ -23,7 +22,6 @@ }, "plugins": [ "@typescript-eslint", - "prettier", "import", "promise", "security", @@ -40,7 +38,6 @@ "no-console": "error", "no-debugger": "error", "camelcase": "error", - "prettier/prettier": "error", "indent": ["error", 2], "linebreak-style": ["error", "unix"], "semi": ["error", "never"], @@ -120,6 +117,14 @@ "promise/no-multiple-resolved": "error" }, "overrides": [ + { + "files": ["!*.json"], + "plugins": ["prettier"], + "extends": ["plugin:prettier/recommended"], + "rules": { + "prettier/prettier": "error" + } + }, { "files": ["*.json"], "plugins": ["json"], @@ -131,7 +136,7 @@ "extends": ["plugin:vuetify/recommended"] }, { - "files": ["**/*.test.[tj]s"], + "files": ["*.[test,spec].[tj]s"], "plugins": ["vitest"], "extends": ["plugin:vitest/all"] }, diff --git a/README.md b/README.md index b9c13f5..f6a4b9a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![nodejs][badge-nodejs-img]][badge-nodejs-href] [![npm][badge-npm-img]][badge-npm-href] [![docker][badge-docker-img]][badge-docker-href] +[![jq][badge-jq-img]][badge-jq-href] [![vue][badge-vue-img]][badge-vue-href] [![vike][badge-vike-img]][badge-vike-href] [![vuetify][badge-vuetify-img]][badge-vuetify-href] @@ -18,7 +19,7 @@ The IT4C Boilerplate for frontends ## Requirements & Technology -To be able to build this project you need `nodejs`, `npm` and optional `docker`. +To be able to build this project you need `nodejs`, `npm` and optional `docker` and `jq`. The project uses `vite` as builder, `vike` to do the SSR. The design framework is `vuetify` which requires the frontend framework `vue3`. For localization `vue-i18n` is used; Session storage is handled with `pinia`. @@ -41,6 +42,7 @@ The following commands are available: | **Test** | | | `npm run test:lint` | Run all linters | | `npm run test:lint:eslint` | Run linter eslint | +| `npm run test:lint:locales`| Run linter locales | | `npm run test:lint:remark` | Run linter remark | | `npm run test:lint:style` | Run linter stylelint | | `npm run test:unit` | Run all unit tests and generate coverage report | @@ -81,9 +83,7 @@ The following endpoints are provided given the right command is executed or all - [ ] figma - [ ] chromatic - [ ] github actions -- [ ] lint locales - [ ] feature zähler -> pinia tore -- [ ] lint style (inline vue) stylelint? ## Known Problems @@ -103,6 +103,9 @@ Currently none [badge-docker-img]: https://img.shields.io/badge/docker-latest-blue [badge-docker-href]: https://www.docker.com/ +[badge-jq-img]: https://img.shields.io/badge/jq-latest-blue +[badge-jq-href]: https://jqlang.github.io/jq/ + [badge-vue-img]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FIT4Change%2Fboilerplate-frontend%2Fmaster%2Fpackage.json&query=dependencies.vue&label=vue&color=green [badge-vue-href]: https://vuejs.org/ diff --git a/renderer/i18n.ts b/renderer/i18n.ts index 27caf35..7e25431 100644 --- a/renderer/i18n.ts +++ b/renderer/i18n.ts @@ -2,8 +2,10 @@ import { createI18n } from 'vue-i18n' // eslint-disable-next-line import/no-relative-parent-imports import de from '../src/locales/de' +// import { de as $vuetify } from 'vuetify/locale' // eslint-disable-next-line import/no-relative-parent-imports import en from '../src/locales/en' +// import { en as $vuetify } from 'vuetify/locale' export default createI18n({ legacy: false, // Vuetify does not support the legacy mode of vue-i18n diff --git a/scripts/locales/keys.jq b/scripts/locales/keys.jq new file mode 100644 index 0000000..d9085e0 --- /dev/null +++ b/scripts/locales/keys.jq @@ -0,0 +1 @@ +path(..)|[.[]|tostring]|join(".") \ No newline at end of file diff --git a/scripts/locales/locales.sh b/scripts/locales/locales.sh new file mode 100755 index 0000000..4392868 --- /dev/null +++ b/scripts/locales/locales.sh @@ -0,0 +1,44 @@ +#!/bin/bash +if [ $# -eq 0 ] +then + echo "You have to supply at least one argument specifying the folder to lint" +fi + +FILES="$1" + +tmp=$(mktemp) +exit_code=0 + +for locale_file in $FILES/*.json +do + jq -f $(dirname "$0")/sort.jq $locale_file > "$tmp" + # check sort order and fix it if required + if [ "$2" == "--fix" ] + then + mv "$tmp" $locale_file + else + if diff -q "$tmp" $locale_file > /dev/null ; + then + : # all good + else + exit_code=$? + echo "$(basename -- $locale_file) is not sorted by keys" + fi + fi + # check keys + if [ -n "$LAST_FILE" ]; then + listPaths="jq -f $(dirname "$0")/keys.jq" + diffString="<( cat $LAST_FILE | $listPaths ) <( cat $locale_file | $listPaths )" + if eval "diff -q $diffString"; + then + : # all good + else + eval "diff -y $diffString | grep '[|<>]'"; + printf "\n$LAST_FILE\" and $locale_file translation keys do not match, see diff above.\n" + exit_code=1 + fi + fi + LAST_FILE=$locale_file +done + +exit $exit_code diff --git a/scripts/locales/sort.jq b/scripts/locales/sort.jq new file mode 100644 index 0000000..9d108f8 --- /dev/null +++ b/scripts/locales/sort.jq @@ -0,0 +1,13 @@ +def walk(f): + . as $in + | if type == "object" then + reduce keys_unsorted[] as $key + ( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f + elif type == "array" then map( walk(f) ) | f + else f + end; + +def keys_sort_by(f): + to_entries | sort_by(.key|f ) | from_entries; + +walk(if type == "object" then keys_sort_by(ascii_upcase) else . end) \ No newline at end of file diff --git a/src/locales/de.json b/src/locales/de.json new file mode 100644 index 0000000..6c7a761 --- /dev/null +++ b/src/locales/de.json @@ -0,0 +1,3 @@ +{ + "counter": "Zähler" +} diff --git a/src/locales/de.ts b/src/locales/de.ts deleted file mode 100644 index 46135f0..0000000 --- a/src/locales/de.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { de as $vuetify } from 'vuetify/locale' - -export default { - counter: 'Zähler', - $vuetify, -} diff --git a/src/locales/en.json b/src/locales/en.json new file mode 100644 index 0000000..99f45b4 --- /dev/null +++ b/src/locales/en.json @@ -0,0 +1,3 @@ +{ + "counter": "Counter" +} diff --git a/src/locales/en.ts b/src/locales/en.ts deleted file mode 100644 index 69dab4c..0000000 --- a/src/locales/en.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { en as $vuetify } from 'vuetify/locale' - -export default { - counter: 'Counter', - $vuetify, -}