diff --git a/.github/workflows/lint_prettify.yml b/.github/workflows/lint_prettify.yml index 7cfdc56cbbd..056ecf73760 100644 --- a/.github/workflows/lint_prettify.yml +++ b/.github/workflows/lint_prettify.yml @@ -87,7 +87,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: 1.96.0 components: rustfmt override: true diff --git a/.github/workflows/step_cli_build.yml b/.github/workflows/step_cli_build.yml index 5f50fba0a8c..98dbc299e58 100644 --- a/.github/workflows/step_cli_build.yml +++ b/.github/workflows/step_cli_build.yml @@ -31,7 +31,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: 1.96.0 components: rustfmt override: true target: x86_64-unknown-linux-musl diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 410bb5a7b7a..10f38160b86 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly-2024-08-02 + toolchain: 1.96.0 components: rustfmt override: true diff --git a/devenv.nix b/devenv.nix index 284eeacd181..79067ae98ee 100644 --- a/devenv.nix +++ b/devenv.nix @@ -1,5 +1,18 @@ { pkgs, ... }: +let + rustOverlay = import (builtins.fetchTarball { + url = "https://github.com/oxalica/rust-overlay/archive/107c334f141854f563f8adf1db781dc453d92639.tar.gz"; + sha256 = "138jwq564qji7dc5yav2j2c1c1mr65smqqk00mni9lvqhx0n45w4"; + }); + + pkgs' = pkgs.extend rustOverlay; + + rustStable = pkgs'.rust-bin.stable."1.96.0".default.override { + targets = [ "wasm32-unknown-unknown" "wasm32-wasip1" "wasm32-wasip2" ]; + extensions = [ "rust-src" "rust-analyzer-preview" ]; + }; +in { # https://devenv.sh/basics/ env = { @@ -16,6 +29,9 @@ # https://devenv.sh/packages/ packages = with pkgs; [ + # Binary Rust + rustStable + # AWS (aws-sam-cli.overridePythonAttrs { doCheck = false; }) @@ -83,15 +99,9 @@ export LD_LIBRARY_PATH=${pkgs.openssl.out}/lib:$LD_LIBRARY_PATH export PATH=/workspaces/step/packages/step-cli/rust-local-target/release:$PATH set +a - ''; - # https://devenv.sh/languages/ - languages.rust = { - enable = true; - # https://devenv.sh/reference/options/#languagesrustchannel - channel = "nightly"; - toolchain.rust-src = pkgs.rustPlatform.rustLibSrc; - }; + export RUST_SRC_PATH=${rustStable}/lib/rustlib/src/rust/library + ''; languages.java = { enable = true; diff --git a/packages/Dockerfile.cargo-packages b/packages/Dockerfile.cargo-packages index f4ed59a4b2e..8bb888dc835 100644 --- a/packages/Dockerfile.cargo-packages +++ b/packages/Dockerfile.cargo-packages @@ -7,7 +7,7 @@ # for example packages/windmill/Dockerfile, packages/harvest/Dockerfile, etc. -FROM rustlang/rust:nightly-bookworm-slim +FROM rust:1.96.0-slim-bookworm WORKDIR /app diff --git a/packages/Dockerfile.immudb-init-vstl-dependencies b/packages/Dockerfile.immudb-init-vstl-dependencies index 84cd7f81d7c..fa17e92cbf6 100644 --- a/packages/Dockerfile.immudb-init-vstl-dependencies +++ b/packages/Dockerfile.immudb-init-vstl-dependencies @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0-slim-bookworm +FROM rust:1.96.0-slim-bookworm WORKDIR /app @@ -13,9 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ make \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - # copy projects #TODO: Copy only necessary files WORKDIR /app diff --git a/packages/Dockerfile.immudb-init.prod b/packages/Dockerfile.immudb-init.prod index c51a8f159a8..8d5a9d92b0c 100644 --- a/packages/Dockerfile.immudb-init.prod +++ b/packages/Dockerfile.immudb-init.prod @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.90.0-slim-bookworm as builder +FROM rust:1.96.0-slim-bookworm as builder WORKDIR /app diff --git a/packages/b3/Dockerfile.prod b/packages/b3/Dockerfile.prod index 983076a2954..62e92ce71df 100644 --- a/packages/b3/Dockerfile.prod +++ b/packages/b3/Dockerfile.prod @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rustlang/rust:nightly-bookworm-slim as builder +FROM rust:1.96.0-slim-bookworm as builder WORKDIR /app @@ -13,9 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ make \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - # copy projects #TODO: Copy only necessary files WORKDIR /app diff --git a/packages/b3/Dockerfile.prod-vstl-dependencies b/packages/b3/Dockerfile.prod-vstl-dependencies index c651a91746d..57d57fcfab1 100644 --- a/packages/b3/Dockerfile.prod-vstl-dependencies +++ b/packages/b3/Dockerfile.prod-vstl-dependencies @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0-slim-bookworm +FROM rust:1.96.0-slim-bookworm WORKDIR /app @@ -16,9 +16,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - #TODO: Copy only necessary files COPY ./braid/Cargo.toml ./braid/Cargo.toml COPY ./b3/Cargo.toml ./b3/Cargo.toml diff --git a/packages/braid/Dockerfile b/packages/braid/Dockerfile index f157b184ad3..3ef8fa3ffbb 100644 --- a/packages/braid/Dockerfile +++ b/packages/braid/Dockerfile @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rustlang/rust:nightly-bookworm-slim +FROM rust:1.96.0-slim-bookworm # Copy projects WORKDIR /app @@ -25,10 +25,6 @@ RUN apt-get update \ curl \ && rm -rf /var/lib/apt/lists/* -# Install the specific nightly toolchain -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - ARG VAULT_VERSION=1.15.5 # Install vault diff --git a/packages/braid/Dockerfile.prod b/packages/braid/Dockerfile.prod index 8dcbe354cd2..f69802396ce 100644 --- a/packages/braid/Dockerfile.prod +++ b/packages/braid/Dockerfile.prod @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rustlang/rust:nightly-bookworm-slim as builder +FROM rust:1.96.0-slim-bookworm as builder WORKDIR /app @@ -18,9 +18,6 @@ RUN apt-get update \ curl \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - # copy projects #TODO: Copy only necessary files WORKDIR /app diff --git a/packages/braid/Dockerfile.prod-vstl-dependencies b/packages/braid/Dockerfile.prod-vstl-dependencies index 5e7fbd89006..6ef60e56aa8 100644 --- a/packages/braid/Dockerfile.prod-vstl-dependencies +++ b/packages/braid/Dockerfile.prod-vstl-dependencies @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rustlang/rust:nightly-bookworm-slim as builder +FROM rust:1.96.0-slim-bookworm as builder WORKDIR /app @@ -13,9 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ make \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - # copy projects #TODO: Copy only necessary files WORKDIR /app diff --git a/packages/e2e/src/mock_server/Dockerfile.prod b/packages/e2e/src/mock_server/Dockerfile.prod index ce86fa7fd92..19502c5b7de 100644 --- a/packages/e2e/src/mock_server/Dockerfile.prod +++ b/packages/e2e/src/mock_server/Dockerfile.prod @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0-slim-bookworm AS builder +FROM rust:1.96.0-slim-bookworm AS builder WORKDIR /app @@ -16,9 +16,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - #TODO: Copy only necessary files COPY ./ ./ diff --git a/packages/harvest/Dockerfile b/packages/harvest/Dockerfile index ad263da2318..7f5f4fe0207 100644 --- a/packages/harvest/Dockerfile +++ b/packages/harvest/Dockerfile @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0 +FROM rust:1.96.0-slim-bookworm ENV ROCKET_ADDRESS=0.0.0.0 ENV ROCKET_PORT=8400 @@ -19,7 +19,6 @@ COPY ./wrap-map-err ./wrap-map-err COPY ./velvet ./velvet RUN apt-get update && apt-get install -y chromium protobuf-compiler libprotobuf-dev -RUN rustup default nightly WORKDIR /app/harvest RUN cargo build diff --git a/packages/harvest/Dockerfile.prod b/packages/harvest/Dockerfile.prod index b7f2a2d1279..58001c76234 100644 --- a/packages/harvest/Dockerfile.prod +++ b/packages/harvest/Dockerfile.prod @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0-slim-bookworm as builder +FROM rust:1.96.0-slim-bookworm as builder WORKDIR /app @@ -16,9 +16,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - #TODO: Copy only necessary files COPY ./braid ./braid COPY ./b3 ./b3 diff --git a/packages/harvest/Dockerfile.prod-vstl-dependencies b/packages/harvest/Dockerfile.prod-vstl-dependencies index 5f835475e9d..42f5add2e98 100644 --- a/packages/harvest/Dockerfile.prod-vstl-dependencies +++ b/packages/harvest/Dockerfile.prod-vstl-dependencies @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0-slim-bookworm +FROM rust:1.96.0-slim-bookworm WORKDIR /app @@ -16,9 +16,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - #TODO: Copy only necessary files COPY ./braid/Cargo.toml ./braid/Cargo.toml COPY ./b3/Cargo.toml ./b3/Cargo.toml diff --git a/packages/orare/doc_renderer/Dockerfile b/packages/orare/doc_renderer/Dockerfile index 2e33c5bdf8f..ee8115f9fdc 100644 --- a/packages/orare/doc_renderer/Dockerfile +++ b/packages/orare/doc_renderer/Dockerfile @@ -12,7 +12,7 @@ ARG AWS_S3_MAX_UPLOAD_BYTES="" ARG AWS_S3_UPLOAD_EXPIRATION_SECS="" ARG AWS_S3_FETCH_EXPIRATION_SECS="" -FROM rustlang/rust:nightly AS builder +FROM rust:1.96.0-slim-bookworm AS builder ARG FEATURES RUN apt-get update && \ diff --git a/packages/sequent-core/src/ballot_codec/raw_ballot.rs b/packages/sequent-core/src/ballot_codec/raw_ballot.rs index 7362ffb4221..3f14d7c02d2 100644 --- a/packages/sequent-core/src/ballot_codec/raw_ballot.rs +++ b/packages/sequent-core/src/ballot_codec/raw_ballot.rs @@ -55,9 +55,16 @@ impl RawBallotCodec for Contest { let base_bits = (char_map.base() as f64).log2().ceil() as i32; if remaining_bits > 0 { - Ok(remaining_bits.div_ceil(base_bits)) + // div_ceil: round up for positive numbers + Ok((remaining_bits as u32).div_ceil(base_bits as u32) as i32) } else { - Ok(remaining_bits.div_floor(base_bits)) + // div_floor: round toward negative infinity for negative numbers + Ok((remaining_bits / base_bits) + - if remaining_bits % base_bits != 0 { + 1 + } else { + 0 + }) } } diff --git a/packages/sequent-core/src/lib.rs b/packages/sequent-core/src/lib.rs index a277a88018b..3009c6cac26 100644 --- a/packages/sequent-core/src/lib.rs +++ b/packages/sequent-core/src/lib.rs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2022 Felix Robles // // SPDX-License-Identifier: AGPL-3.0-only -#![feature(int_roundings)] #[macro_use] extern crate quick_error; extern crate cfg_if; diff --git a/packages/ui-core/src/index.tsx b/packages/ui-core/src/index.tsx index 7681a524195..b2f4fdfc61d 100644 --- a/packages/ui-core/src/index.tsx +++ b/packages/ui-core/src/index.tsx @@ -25,7 +25,11 @@ export {isNumber, isString, isArray, isNull, isUndefined} from "./utils/typechec export {downloadBlob, downloadUrl} from "./services/downloadBlob" export {shuffle, splitList, keyBy} from "./utils/array" export {normalizeWriteInText} from "./services/normalizeWriteInText" -export {translate, translateFromPresentation} from "./services/translate" +export { + isTranslatablePresentation, + translate, + translateFromPresentation, +} from "./services/translate" export * from "./types/ElectionEventPresentation" export * from "./services/percentFormatter" export * from "./services/wasm" diff --git a/packages/ui-core/src/services/translate.test.ts b/packages/ui-core/src/services/translate.test.ts new file mode 100644 index 00000000000..4d45d73e946 --- /dev/null +++ b/packages/ui-core/src/services/translate.test.ts @@ -0,0 +1,139 @@ +// SPDX-FileCopyrightText: 2026 Sequent Tech Inc +// +// SPDX-License-Identifier: AGPL-3.0-only + +import {isTranslatablePresentation, translateFromPresentation} from "./translate" + +const presentation = { + i18n: { + en: {alias: "english-alias", name: "Election", description: null}, + fr: {name: "French election"}, + cat: {name: "Catalan election"}, + }, + language_conf: { + default_language_code: "en", + }, +} + +describe("translateFromPresentation", () => { + it("normalizes regional user locales to internal language codes", () => { + expect(translateFromPresentation({presentation}, "name", "en-GB")).toBe("Election") + expect(translateFromPresentation({presentation}, "name", "EN-GB")).toBe("Election") + expect(translateFromPresentation({presentation}, "name", "fr-CA")).toBe("French election") + expect(translateFromPresentation({presentation}, "name", "cat")).toBe("Catalan election") + }) + + it("falls through null, undefined, and empty translations", () => { + const presentationWithMissingValues = { + i18n: { + en: {name: "", description: null, alias: undefined}, + fr: {name: "French fallback", description: "", alias: null}, + }, + } + + expect( + translateFromPresentation(presentationWithMissingValues, "name", "en", { + defaultLanguageCode: "fr", + }) + ).toBe("French fallback") + expect( + translateFromPresentation(presentationWithMissingValues, "description", "en", { + defaultLanguageCode: "fr", + }) + ).toBeUndefined() + expect( + translateFromPresentation(presentationWithMissingValues, "alias", "en", { + defaultLanguageCode: "fr", + }) + ).toBeUndefined() + expect( + translateFromPresentation( + {name: "Legacy fallback", presentation: presentationWithMissingValues}, + "name", + "en" + ) + ).toBe("Legacy fallback") + }) + + it("uses an explicitly requested default language", () => { + expect( + translateFromPresentation({presentation}, "name", "de-DE", { + defaultLanguageCode: "en-GB", + }) + ).toBe("Election") + }) + + it("ignores malformed unrelated translations when the requested value is valid", () => { + const malformedPresentation = { + i18n: { + en: {name: "Election X", sort_hint: 2}, + }, + } as unknown as Parameters[0] + + expect(isTranslatablePresentation(malformedPresentation)).toBe(false) + expect(translateFromPresentation(malformedPresentation, "name", "en")).toBe("Election X") + }) + + it("does not assume that every presentation owns the fallback policy", () => { + expect(translateFromPresentation(presentation, "name", "de-DE")).toBeUndefined() + }) + + it("preserves user-language alias and name ordering", () => { + expect(translateFromPresentation({presentation}, "alias", "fr")).toBeUndefined() + expect(translateFromPresentation({presentation}, "name", "fr")).toBe("French election") + }) + + it("prefers a direct presentation over a nested presentation", () => { + expect( + translateFromPresentation( + { + i18n: {en: {name: "Direct election"}}, + presentation: {i18n: {en: {name: "Nested election"}}}, + }, + "name", + "en" + ) + ).toBe("Direct election") + }) + + it("supports receiving the presentation object directly", () => { + expect( + translateFromPresentation(presentation, "name", "de-DE", { + defaultLanguageCode: "en", + }) + ).toBe("Election") + }) + + it("preserves the entity value fallback used by legacy callers", () => { + expect( + translateFromPresentation({name: "Legacy election", presentation}, "name", "de-DE") + ).toBe("Legacy election") + }) + + it("prefers a default-language translation over an entity legacy value", () => { + expect( + translateFromPresentation({name: "Legacy election", presentation}, "name", "de-DE", { + defaultLanguageCode: "en", + }) + ).toBe("Election") + }) + + it("returns undefined when neither translation nor legacy value exists", () => { + expect( + translateFromPresentation( + { + presentation: { + i18n: {fr: {name: "French election"}}, + }, + }, + "name", + "de-DE", + {defaultLanguageCode: "en"} + ) + ).toBeUndefined() + }) + + it("preserves the legacy value when no presentation translations exist", () => { + expect(translateFromPresentation({name: "Election"}, "name", "en-GB")).toBe("Election") + }) +}) diff --git a/packages/ui-core/src/services/translate.ts b/packages/ui-core/src/services/translate.ts index 1d268aa59fd..16f35e5994b 100644 --- a/packages/ui-core/src/services/translate.ts +++ b/packages/ui-core/src/services/translate.ts @@ -21,17 +21,111 @@ export const translate = ( return input[key] as string } -export const translateFromPresentation = ( - object: any, - key: string, - lang: string +type TranslationValue = string | null | undefined + +interface TranslatablePresentation { + i18n?: Record> +} + +type TranslatableEntity = Partial< + Record +> & { + presentation?: TranslatablePresentation | null +} + +type TranslationInput = + | TranslatablePresentation + | TranslatableEntity + | null + | undefined + +interface TranslateFromPresentationOptions { + defaultLanguageCode?: string +} + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value) + +export const isTranslatablePresentation = (value: unknown): value is TranslatablePresentation => { + if (!isRecord(value)) { + return false + } + + if (value.i18n === undefined) { + return true + } + + if (!isRecord(value.i18n)) { + return false + } + + return Object.values(value.i18n).every( + (translations) => + isRecord(translations) && + Object.values(translations).every( + (translation) => translation == null || typeof translation === "string" + ) + ) +} + +const getPresentation = ( + object: TranslationInput +): TranslatablePresentation | undefined => { + if (!isRecord(object)) { + return undefined + } + + const value = + "i18n" in object && object.i18n + ? object + : "presentation" in object + ? object.presentation + : object + return isRecord(value) ? (value as TranslatablePresentation) : undefined +} + +const getPrimaryLanguageCode = (lang?: string): string | undefined => + lang?.split("-")[0].toLowerCase() + +const getTranslatedValue = ( + presentation: TranslatablePresentation | undefined, + language: string | undefined, + key: string ): string | undefined => { - if (object?.["i18n"]) { - return object["i18n"][lang]?.[key] || undefined + if (!language) { + return undefined } - if (object?.["presentation"]?.["i18n"]) { - return object["presentation"]["i18n"][lang]?.[key] || object[key] || undefined - } else { - return object?.[key] || undefined + + const value = presentation?.i18n?.[language]?.[key] + return typeof value === "string" && value.length > 0 ? value : undefined +} + +export const translateFromPresentation = ( + object: TranslationInput, + key: K, + lang: string, + options: TranslateFromPresentationOptions = {} +): string | undefined => { + const presentation = getPresentation(object) + const userLanguage = getPrimaryLanguageCode(lang) + const defaultLanguage = getPrimaryLanguageCode(options.defaultLanguageCode) + + const translatedValue = + getTranslatedValue(presentation, userLanguage, key) || + getTranslatedValue(presentation, defaultLanguage, key) + + if (translatedValue) { + return translatedValue + } + + if (isRecord(object) && "i18n" in object && Boolean(object.i18n)) { + return undefined + } + + if (!isRecord(object)) { + return undefined } + + const legacyValue = object[key] + return typeof legacyValue === "string" && legacyValue.length ? legacyValue : undefined } diff --git a/packages/voting-portal/src/routes/ElectionSelectionScreen.tsx b/packages/voting-portal/src/routes/ElectionSelectionScreen.tsx index ab30790679b..0407915f728 100644 --- a/packages/voting-portal/src/routes/ElectionSelectionScreen.tsx +++ b/packages/voting-portal/src/routes/ElectionSelectionScreen.tsx @@ -118,6 +118,9 @@ const ElectionWrapper: React.FC = ({ throw new VotingPortalError(VotingPortalErrorType.INTERNAL_ERROR) } + const defaultLanguageCode = + election.presentation?.language_conf?.default_language_code ?? + electionEvent?.presentation?.language_conf?.default_language_code const electionStatus = election?.status as IElectionStatus | null const isVotingOpen = (electionStatus?.voting_status === EVotingStatus.OPEN || @@ -171,7 +174,11 @@ const ElectionWrapper: React.FC = ({ 0} onClickToVote={canVote() ? onClickToVote : undefined} onClickBallotLocator={handleClickBallotLocator} @@ -480,8 +487,8 @@ const ElectionSelectionScreen: React.FC = () => { electionIds: errorMsgElectionIds, }) : alertMsg - ? t(`electionSelectionScreen.alerts.${alertMsg}`) - : ""} + ? t(`electionSelectionScreen.alerts.${alertMsg}`) + : ""} ) : ( { const navigate = useNavigate() useLanguage({ballotStyle}) + const defaultLanguageCode = + election?.presentation?.language_conf?.default_language_code ?? + ballotStyle?.ballot_eml.election_event_presentation?.language_conf?.default_language_code + useEffect(() => { if (!election) { navigate(backLink) @@ -128,12 +132,18 @@ const StartScreen: React.FC = () => { - {translateFromPresentation(election, "name", i18n.language) ?? "-"} + + {translateFromPresentation(election, "name", i18n.language, { + defaultLanguageCode, + }) ?? "-"} + {election.description ? ( {stringToHtml( - translateFromPresentation(election, "description", i18n.language) ?? "-" + translateFromPresentation(election, "description", i18n.language, { + defaultLanguageCode, + }) ?? "-" )} ) : null} diff --git a/packages/voting-portal/src/routes/SupportMaterialsScreen.tsx b/packages/voting-portal/src/routes/SupportMaterialsScreen.tsx index 39044dc9662..03e7cd484c5 100644 --- a/packages/voting-portal/src/routes/SupportMaterialsScreen.tsx +++ b/packages/voting-portal/src/routes/SupportMaterialsScreen.tsx @@ -102,6 +102,7 @@ const SupportMaterialsScreen: React.FC = () => { }, [materials]) const [materialsTitles, setMaterialsTitles] = useState() + const defaultLanguageCode = materialsTitles?.presentation?.language_conf?.default_language_code useEffect(() => { if (electionEvent) { @@ -134,7 +135,8 @@ const SupportMaterialsScreen: React.FC = () => { (translateFromPresentation( materialsTitles, "materialsTitle", - i18n.language + i18n.language, + {defaultLanguageCode} ) ?? "-")} @@ -142,11 +144,12 @@ const SupportMaterialsScreen: React.FC = () => { {stringToHtml( materialsTitles - ? translateFromPresentation( + ? (translateFromPresentation( materialsTitles, "materialsSubtitle", - i18n.language - ) ?? "-" + i18n.language, + {defaultLanguageCode} + ) ?? "-") : "" )} diff --git a/packages/voting-portal/src/routes/VotingScreen.tsx b/packages/voting-portal/src/routes/VotingScreen.tsx index a1145b3bc3f..e0d75986f51 100644 --- a/packages/voting-portal/src/routes/VotingScreen.tsx +++ b/packages/voting-portal/src/routes/VotingScreen.tsx @@ -283,6 +283,9 @@ const VotingScreen: React.FC = () => { } = provideBallotService() const election = useAppSelector(selectElectionById(String(electionId))) const ballotStyle = useAppSelector(selectBallotStyleByElectionId(String(electionId))) + const defaultLanguageCode = + election?.presentation?.language_conf?.default_language_code ?? + ballotStyle?.ballot_eml.election_event_presentation?.language_conf?.default_language_code const selectionState = useAppSelector( selectBallotSelectionByElectionId(ballotStyle?.election_id ?? "") @@ -435,7 +438,9 @@ const VotingScreen: React.FC = () => { - {translateFromPresentation(election, "name", i18n.language) ?? "-"} + {translateFromPresentation(election, "name", i18n.language, { + defaultLanguageCode, + }) ?? "-"} { sx={{color: theme.palette.customGrey.main}} > {stringToHtml( - translateFromPresentation(election, "description", i18n.language) ?? "-" + translateFromPresentation(election, "description", i18n.language, { + defaultLanguageCode, + }) ?? "-" )} ) : null} diff --git a/packages/windmill/Dockerfile b/packages/windmill/Dockerfile index 2445c5b7b3b..dbfa1171714 100644 --- a/packages/windmill/Dockerfile +++ b/packages/windmill/Dockerfile @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0 +FROM rust:1.96.0-slim-bookworm WORKDIR /app COPY ./immu-board ./immu-board @@ -16,9 +16,6 @@ COPY ./velvet ./velvet RUN cp /app/windmill/external-bin/ecies-tool.jar /usr/local/bin/ -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - # Use Docker build arguments to determine the architecture ARG TARGETARCH @@ -57,7 +54,6 @@ RUN case "${TARGETARCH}" in \ && update-alternatives --install /usr/bin/javac javac /usr/local/jdk-${JAVA_VERSION}/bin/javac 1 # java -jar ecies-tool.jar create-keys public.pem private.pem -RUN rustup default nightly WORKDIR /app/windmill RUN cargo build diff --git a/packages/windmill/Dockerfile.prod b/packages/windmill/Dockerfile.prod index eda884f3519..b38346aa0df 100644 --- a/packages/windmill/Dockerfile.prod +++ b/packages/windmill/Dockerfile.prod @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0-slim-bookworm as builder +FROM rust:1.96.0-slim-bookworm as builder WORKDIR /app @@ -16,9 +16,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ && rm -rf /var/lib/apt/lists/* -# Install the specific nightly toolchain -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 COPY ./braid ./braid COPY ./b3 ./b3 COPY ./electoral-log ./electoral-log diff --git a/packages/windmill/Dockerfile.prod-vstl-dependencies b/packages/windmill/Dockerfile.prod-vstl-dependencies index dc832a833eb..518cc10fe73 100644 --- a/packages/windmill/Dockerfile.prod-vstl-dependencies +++ b/packages/windmill/Dockerfile.prod-vstl-dependencies @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-only -FROM rust:1.82.0-slim-bookworm +FROM rust:1.96.0-slim-bookworm WORKDIR /app @@ -16,9 +16,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ && rm -rf /var/lib/apt/lists/* -RUN rustup toolchain install nightly-2024-09-01 \ - && rustup default nightly-2024-09-01 - #TODO: Copy only necessary files COPY ./braid/Cargo.toml ./braid/Cargo.toml COPY ./b3/Cargo.toml ./b3/Cargo.toml diff --git a/packages/windmill/src/bin/beat.rs b/packages/windmill/src/bin/beat.rs index 328b0c3fbb3..4a56cccf5fe 100644 --- a/packages/windmill/src/bin/beat.rs +++ b/packages/windmill/src/bin/beat.rs @@ -1,5 +1,4 @@ #![allow(non_upper_case_globals)] -#![feature(result_flattening)] #![recursion_limit = "256"] // SPDX-FileCopyrightText: 2023 Felix Robles // SPDX-FileCopyrightText: 2023 Eduardo Robles diff --git a/packages/windmill/src/bin/main.rs b/packages/windmill/src/bin/main.rs index d315bfc9c54..a9ef36ead6e 100644 --- a/packages/windmill/src/bin/main.rs +++ b/packages/windmill/src/bin/main.rs @@ -1,5 +1,4 @@ #![allow(non_upper_case_globals)] -#![feature(result_flattening)] #![recursion_limit = "256"] // SPDX-FileCopyrightText: 2023 Felix Robles // SPDX-FileCopyrightText: 2023 Eduardo Robles diff --git a/packages/windmill/src/lib.rs b/packages/windmill/src/lib.rs index 7c543914eb9..92f2ba38746 100644 --- a/packages/windmill/src/lib.rs +++ b/packages/windmill/src/lib.rs @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: AGPL-3.0-only #![recursion_limit = "256"] -#![feature(result_flattening)] #[macro_use] extern crate lazy_static;