## Problem - Some missing translations in the web UI - https://bugzilla.suse.com/show_bug.cgi?id=1250059#c0 ## Details The code at the top level like ``` const message = _("foo") ``` does not work properly because the code is evaluated too early, even before the component is actually displayed and before the translations are loaded from the server. ## Solution There are basically two solutions: 1. Use `N_()` function instead of `_()` at the top level and then use `_()` when using the constant later. 2. Move the constant into a function (or function component) which is called (and evaluated/retranslated) in every rendering of the component. ## Testing - Tested manually. - Because most of the problems were in special storage technologies like iSCSI or DASD I was able to test only the error message in the software. And even that was a bit tricky, to trigger the error I configured an invalid installation repository with the `inst.instal_url=http://example.com` boot parameter. - I also verified the generated POT file after this change to ensure no translation was lost. The generated POT is the very same (except the line numbers in comments) as before the change. ## Additional changes - Enabled eslint check which finds the top level translations to avoid similar problems in the future - Use NodeJS v22 in the CI build, that's the same version as in SLE-16. Moreover v18 is obsolete and out of support for several months. 😮 ## Screenshots Original SLE-16 system without the patch: <img width="1280" height="800" alt="agama-missing-translation-software" src="https://github.com/user-attachments/assets/2244b15e-3c5f-486d-b118-d5c84a7bdb0f" /> Fixed system after applying this patch: <img width="1280" height="800" alt="agama-missing-translation-software-fixed" src="https://github.com/user-attachments/assets/7865c79e-7868-4614-8146-2f8da20f3ffe" /> --------- Co-authored-by: Martin Vidner <mvidner@suse.com>
106 lines
3.1 KiB
JavaScript
106 lines
3.1 KiB
JavaScript
import js from "@eslint/js";
|
|
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
|
|
import neostandard from "neostandard";
|
|
import tsEslint from "typescript-eslint";
|
|
import tsEslintParser from "@typescript-eslint/parser";
|
|
import globals from "globals";
|
|
import agamaI18nEslintPlugin from "@agama-project/eslint-plugin-agama-i18n";
|
|
import i18nextEslintPlugin from "eslint-plugin-i18next";
|
|
import tsEslintPlugin from "@typescript-eslint/eslint-plugin";
|
|
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
|
|
|
const neostandardConfig = neostandard({ semi: true, noStyle: true });
|
|
|
|
export default [
|
|
...neostandardConfig,
|
|
js.configs.recommended,
|
|
...tsEslint.configs.recommended,
|
|
eslintPluginPrettierRecommended,
|
|
{
|
|
languageOptions: {
|
|
ecmaVersion: 7,
|
|
sourceType: "module",
|
|
globals: {
|
|
...globals.browser,
|
|
...globals.commonjs,
|
|
...globals.jest,
|
|
...globals.node,
|
|
msCrypto: true,
|
|
},
|
|
parser: tsEslintParser,
|
|
},
|
|
},
|
|
{
|
|
plugins: {
|
|
"agama-i18n": agamaI18nEslintPlugin,
|
|
i18next: i18nextEslintPlugin,
|
|
"typescript-eslint": tsEslintPlugin,
|
|
"react-hooks": reactHooksPlugin,
|
|
},
|
|
},
|
|
{
|
|
rules: {
|
|
"agama-i18n/string-literals": "error",
|
|
"agama-i18n/top-level-translation": "error",
|
|
"i18next/no-literal-string": "error",
|
|
"no-var": "error",
|
|
"no-multi-str": "off",
|
|
"no-use-before-define": "off",
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"error",
|
|
{
|
|
ignoreRestSiblings: true,
|
|
},
|
|
],
|
|
"@typescript-eslint/no-unsafe-function-type": "off",
|
|
"@typescript-eslint/no-unused-expressions": "off",
|
|
"@typescript-eslint/no-use-before-define": "warn",
|
|
"@typescript-eslint/ban-ts-comment": "off",
|
|
"lines-between-class-members": [
|
|
"error",
|
|
"always",
|
|
{
|
|
exceptAfterSingleLine: true,
|
|
},
|
|
],
|
|
"prefer-promise-reject-errors": [
|
|
"error",
|
|
{
|
|
allowEmptyReject: true,
|
|
},
|
|
],
|
|
"react-hooks/rules-of-hooks": "error",
|
|
"react-hooks/exhaustive-deps": "error",
|
|
camelcase: "off",
|
|
"comma-dangle": "off",
|
|
curly: "off",
|
|
"jsx-quotes": "off",
|
|
"key-spacing": "off",
|
|
"no-console": "off",
|
|
quotes: "off",
|
|
"react/jsx-curly-spacing": "off",
|
|
"react/jsx-indent-props": "off",
|
|
"react/prop-types": "off",
|
|
"space-before-function-paren": "off",
|
|
"n/no-callback-literal": "off",
|
|
},
|
|
},
|
|
{
|
|
files: ["**/*.test.*", "src/test-utils.js"],
|
|
rules: { "i18next/no-literal-string": "off" },
|
|
},
|
|
{
|
|
files: ["src/i18n.test.js"],
|
|
rules: { "agama-i18n/string-literals": "off" },
|
|
},
|
|
{
|
|
// the translation JS files generated from the PO files use some code in the plural form rule,
|
|
// ignore the possible "problems" there (using "==" operator instead of more strict "===" or not
|
|
// using the "n" variable in languages which do not have plural form)
|
|
files: ["src/po/*.js"],
|
|
rules: { eqeqeq: "off", "@typescript-eslint/no-unused-vars": "off" },
|
|
},
|
|
{
|
|
ignores: ["node_modules/*", "src/lib/*", "src/**/test-data/*"],
|
|
},
|
|
];
|