diff --git a/.github/workflows/weblate-merge-po.yml b/.github/workflows/weblate-merge-po.yml
index 7d13aeae9..8735946f7 100644
--- a/.github/workflows/weblate-merge-po.yml
+++ b/.github/workflows/weblate-merge-po.yml
@@ -92,7 +92,7 @@ jobs:
if: steps.check_changes.outputs.po_updated == 'true'
working-directory: ./agama
run: |
- web/share/update-manifest.py web/src/manifest.json
+ web/share/update-languages.py web/src/languages.json
# use a unique branch to avoid possible conflicts with already existing branches
git checkout -b "po_merge_${GITHUB_RUN_ID}"
git commit -a -m "Update web PO files"$'\n\n'"Agama-weblate commit: `git -C ../agama-weblate rev-parse HEAD`"
diff --git a/web/cspell.json b/web/cspell.json
index 3a2944fcd..5a6b76748 100644
--- a/web/cspell.json
+++ b/web/cspell.json
@@ -3,6 +3,7 @@
"language": "en",
"allowCompoundWords": false,
"ignorePaths": [
+ "src/languages.json",
"src/lib/cockpit.js",
"src/lib/cockpit-po-plugin.js",
"src/manifest.json",
diff --git a/web/share/update-manifest.py b/web/share/update-languages.py
similarity index 86%
rename from web/share/update-manifest.py
rename to web/share/update-languages.py
index 6976a4e3e..a85323ed2 100755
--- a/web/share/update-manifest.py
+++ b/web/share/update-languages.py
@@ -23,10 +23,8 @@
from langtable import language_name
from pathlib import Path
import json
-import re
import subprocess
-
class Locale:
language: str
territory: str
@@ -76,20 +74,16 @@ def language(self):
return self.path.stem
-class Manifest:
- """ This class takes care of updating the manifest file"""
+class Languages:
+ """ This class takes care of generating the supported languages file"""
def __init__(self, path: Path):
self.path = path
- self.__read__()
-
- def __read__(self):
- with open(self.path) as file:
- self.content = json.load(file)
+ self.content = dict()
def update(self, po_files, lang2territory: str, threshold: int):
"""
- Updates the list of locales in the manifest file
+ Generate the list of supported locales
It does not write the changes to file system. Use the write() function
for that.
@@ -124,32 +118,31 @@ def update(self, po_files, lang2territory: str, threshold: int):
supported.append(locale)
languages = [loc.language for loc in supported]
- self.content["locales"] = dict()
for locale in supported:
include_territory = languages.count(locale.language) > 1
- self.content["locales"][locale.code()] = locale.name(
- include_territory)
+ self.content[locale.code()] = locale.name(include_territory)
def write(self):
with open(self.path, "w+") as file:
- json.dump(self.content, file, indent=4, ensure_ascii=False)
+ json.dump(self.content, file, indent=4, ensure_ascii=False,
+ sort_keys=True)
-def update_manifest(args):
+def update_languages(args):
"""Command to update the manifest.json file"""
- manifest = Manifest(Path(args.manifest))
+ languages = Languages(Path(args.file))
paths = [path for path in Path(args.po_directory).glob("*.po")]
with open(args.territories) as file:
lang2territory = json.load(file)
- manifest.update(paths, lang2territory, args.threshold)
- manifest.write()
+ languages.update(paths, lang2territory, args.threshold)
+ languages.write()
if __name__ == "__main__":
- parser = ArgumentParser(prog="locales.py")
- parser.set_defaults(func=update_manifest)
+ parser = ArgumentParser(prog="update-languages.py")
+ parser.set_defaults(func=update_languages)
parser.add_argument(
- "manifest", type=str, help="Path to the manifest file",
+ "file", type=str, help="Path to the output file",
)
parser.add_argument(
"--po-directory", type=str, help="Directory containing the po files",
diff --git a/web/src/components/l10n/InstallerLocaleSwitcher.jsx b/web/src/components/l10n/InstallerLocaleSwitcher.jsx
index ad81c2ad7..ac8054e36 100644
--- a/web/src/components/l10n/InstallerLocaleSwitcher.jsx
+++ b/web/src/components/l10n/InstallerLocaleSwitcher.jsx
@@ -26,12 +26,11 @@ import { FormSelect, FormSelectOption, Popover } from "@patternfly/react-core";
import { Icon } from "../layout";
import { _ } from "~/i18n";
import { useInstallerL10n } from "~/context/installerL10n";
-import cockpit from "~/lib/cockpit";
+import supportedLanguages from "~/languages.json";
export default function InstallerLocaleSwitcher() {
const { language, changeLanguage } = useInstallerL10n();
const [selected, setSelected] = useState(null);
- const languages = cockpit.manifests.agama?.locales || [];
const onChange = useCallback((_event, value) => {
setSelected(value);
@@ -39,8 +38,8 @@ export default function InstallerLocaleSwitcher() {
}, [setSelected, changeLanguage]);
// sort by the language code to maintain consistent order
- const options = Object.keys(languages).sort()
- .map(id => );
+ const options = Object.keys(supportedLanguages).sort()
+ .map(id => );
// TRANSLATORS: help text for the language selector in the sidebar,
// %s will be replaced by the "Localization" page link
diff --git a/web/src/components/l10n/InstallerLocaleSwitcher.test.jsx b/web/src/components/l10n/InstallerLocaleSwitcher.test.jsx
index f51f3bdea..91e35cbbb 100644
--- a/web/src/components/l10n/InstallerLocaleSwitcher.test.jsx
+++ b/web/src/components/l10n/InstallerLocaleSwitcher.test.jsx
@@ -27,17 +27,10 @@ import InstallerLocaleSwitcher from "./InstallerLocaleSwitcher";
const mockLanguage = "es-es";
let mockChangeLanguageFn;
-jest.mock("~/lib/cockpit", () => ({
- gettext: term => term,
- manifests: {
- agama: {
- locales: {
- "de-de": "Deutsch",
- "en-us": "English (US)",
- "es-es": "Español"
- }
- }
- }
+jest.mock("~/languages.json", () => ({
+ "de-de": "Deutsch",
+ "en-us": "English (US)",
+ "es-es": "Español"
}));
jest.mock("~/context/installerL10n", () => ({
diff --git a/web/src/context/installerL10n.jsx b/web/src/context/installerL10n.jsx
index d73353d7e..d035a6c7e 100644
--- a/web/src/context/installerL10n.jsx
+++ b/web/src/context/installerL10n.jsx
@@ -27,6 +27,7 @@ import { useCancellablePromise, locationReload, setLocationSearch } from "~/util
import cockpit from "../lib/cockpit";
import { useInstallerClient } from "./installer";
import agama from "~/agama";
+import supportedLanguages from "~/languages.json";
const L10nContext = React.createContext(null);
@@ -154,7 +155,7 @@ function navigatorLanguages() {
* @return {string|undefined} Undefined if none of the given languages is supported.
*/
function findSupportedLanguage(languages) {
- const supported = Object.keys(cockpit.manifests.agama?.locales || {});
+ const supported = Object.keys(supportedLanguages);
for (const candidate of languages) {
const [language, country] = candidate.split("-");
diff --git a/web/src/context/installerL10n.test.jsx b/web/src/context/installerL10n.test.jsx
index bcf703a51..3361c84b5 100644
--- a/web/src/context/installerL10n.test.jsx
+++ b/web/src/context/installerL10n.test.jsx
@@ -40,18 +40,14 @@ const client = {
onDisconnect: jest.fn()
};
+jest.mock("~/languages.json", () => ({
+ "es-ar": "Español (Argentina)",
+ "cs-cz": "čeština",
+ "en-us": "English (US)",
+ "es-es": "Español"
+}));
+
jest.mock("~/lib/cockpit", () => ({
- gettext: term => term,
- manifests: {
- agama: {
- locales: {
- "es-ar": "Español (Argentina)",
- "cs-cz": "čeština",
- "en-us": "English (US)",
- "es-es": "Español"
- }
- }
- },
spawn: jest.fn().mockResolvedValue()
}));
diff --git a/web/src/languages.json b/web/src/languages.json
new file mode 100644
index 000000000..ead0f2a4a
--- /dev/null
+++ b/web/src/languages.json
@@ -0,0 +1,12 @@
+{
+ "ca-es": "Català",
+ "de-de": "Deutsch",
+ "en-us": "English",
+ "es-es": "Español",
+ "fr-fr": "Français",
+ "id-id": "Indonesia",
+ "ja-jp": "日本語",
+ "nl-nl": "Nederlands",
+ "sv-se": "Svenska",
+ "zh-Hans": "中文"
+}
\ No newline at end of file
diff --git a/web/src/lib/webpack-manifests-handler.js b/web/src/lib/webpack-manifests-handler.js
deleted file mode 100644
index 49be997c2..000000000
--- a/web/src/lib/webpack-manifests-handler.js
+++ /dev/null
@@ -1,48 +0,0 @@
-const fs = require("fs");
-const path = require("path");
-
-const manifestFile = path.join(__dirname, "..", "manifest.json");
-
-// this function is injected as a string into the resulting JS file
-const updateAgamaManifest = (data) => {
- if (typeof cockpit === "object" && cockpit.manifests) {
- cockpit.manifests.agama = data;
- }
-};
-
-// This function processes the webpack HTTP proxy request for manifests.js file.
-//
-// Patching the original JS code is difficult so rather inject code
-// which rewrites the Agama manifest data with new content.
-//
-// @see https://github.com/http-party/node-http-proxy#modify-response
-//
-// @param proxyRes HTTP proxy resource
-// @param req HTTP request
-// @param res HTTP response
-module.exports = function (proxyRes, req, res) {
- // collect parts of the original response
- const body = [];
-
- proxyRes.on("data", function (chunk) {
- body.push(chunk);
- });
-
- proxyRes.on("end", function () {
- // forward the original status code
- res.statusCode = proxyRes.statusCode;
-
- // patch the response only on success otherwise there
- // might be some unexpected content (HTML error page)
- if (proxyRes.statusCode === 200 && fs.existsSync(manifestFile)) {
- const manifest = fs.readFileSync(manifestFile);
- // use an immediately-invoked function expression to inject the new
- // manifest content
- res.end(Buffer.concat(body).toString() + "((" +
- updateAgamaManifest.toString() + ")(" + manifest + "));");
- } else {
- // otherwise just return the original content
- res.end(Buffer.concat(body).toString());
- }
- });
-};
diff --git a/web/src/manifest.json b/web/src/manifest.json
index 9c6a0332a..2e2bd4cff 100644
--- a/web/src/manifest.json
+++ b/web/src/manifest.json
@@ -7,17 +7,5 @@
"index": {
"label": "Agama"
}
- },
- "locales": {
- "en-us": "English",
- "es-es": "Español",
- "id-id": "Indonesia",
- "fr-fr": "Français",
- "sv-se": "Svenska",
- "ca-es": "Català",
- "ja-jp": "日本語",
- "nl-nl": "Nederlands",
- "zh-Hans": "中文",
- "de-de": "Deutsch"
}
-}
\ No newline at end of file
+}
diff --git a/web/tsconfig.json b/web/tsconfig.json
index 3a117e098..bde7ef8c0 100644
--- a/web/tsconfig.json
+++ b/web/tsconfig.json
@@ -5,6 +5,7 @@
"noEmit": true,
"target": "esnext",
"moduleResolution": "node",
+ "resolveJsonModule": true,
"allowJs": true,
"jsx": "react",
"allowSyntheticDefaultImports": true,
diff --git a/web/webpack.config.js b/web/webpack.config.js
index 8fdda134b..8449f0f16 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -15,7 +15,6 @@ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');
const po_handler = require("./src/lib/webpack-po-handler");
-const manifests_handler = require("./src/lib/webpack-manifests-handler");
/* A standard nodejs and webpack pattern */
const production = process.env.NODE_ENV === 'production';
@@ -112,16 +111,6 @@ module.exports = {
// ignore SSL problems (self-signed certificate)
secure: false,
},
- // forward the manifests.js request and patch the response with the
- // current Agama manifest from the ./src/manifest.json file
- "/manifests.js": {
- target: cockpitTarget + "/cockpit/@localhost/",
- // ignore SSL problems (self-signed certificate)
- secure: false,
- // the response is modified by the onProxyRes handler
- selfHandleResponse : true,
- onProxyRes: manifests_handler,
- },
},
// use https so Cockpit uses wss:// when connecting to the backend
server: "https",