Files
zitadel/apps/login/src/components/language-switcher.tsx
T
Elio BischofandGitHub b10455b51f chore: reproducible pipeline with dev containers (#10305)
# Which Problems Are Solved

- The previous monorepo in monorepo structure for the login app and its
related packages was fragmented, complicated and buggy.
- The process for building and testing the login container was
inconsistent between local development and CI.
- Lack of clear documentation as well as easy and reliable ways for
non-frontend developers to reproduce and fix failing PR checks locally.

# How the Problems Are Solved

- Consolidated the login app and its related npm packages by moving the
main package to `apps/login/apps/login` and merging
`apps/login/packages/integration` and `apps/login/packages/acceptance`
into the main `apps/login` package.
- Migrated from Docker Compose-based test setups to dev container-based
setups, adding support for multiple dev container configurations:
  - `.devcontainer/base`
  - `.devcontainer/turbo-lint-unit`
  - `.devcontainer/turbo-lint-unit-debug`
  - `.devcontainer/login-integration`
  - `.devcontainer/login-integration-debug`
- Added npm scripts to run the new dev container setups, enabling exact
reproduction of GitHub PR checks locally, and updated the pipeline to
use these containers.
- Cleaned up Dockerfiles and docker-bake.hcl files to only build the
production image for the login app.
- Cleaned up compose files to focus on dev environments in dev
containers.
- Updated `CONTRIBUTING.md` with guidance on running and debugging PR
checks locally using the new dev container approach.
- Introduced separate Dockerfiles for the login app to distinguish
between using published client packages and building clients from local
protos.
- Ensured the login container is always built in the pipeline for use in
integration and acceptance tests.
- Updated Makefile and GitHub Actions workflows to use
`--frozen-lockfile` for installing pnpm packages, ensuring reproducible
installs.
- Disabled GitHub release creation by the changeset action.
- Refactored the `/build` directory structure for clarity and
maintainability.
- Added a `clean` command to `docks/package.json`.
- Experimentally added `knip` to the `zitadel-client` package for
improved linting of dependencies and exports.

# Additional Changes

- Fixed Makefile commands for consistency and reliability.
- Improved the structure and clarity of the `/build` directory to
support seamless integration of the login build.
- Enhanced documentation and developer experience for running and
debugging CI checks locally.

# Additional Context

- See updated `CONTRIBUTING.md` for new local development and debugging
instructions.
- These changes are a prerequisite for further improvements to the CI
pipeline and local development workflow.
- Closes #10276
2025-07-24 14:22:32 +02:00

75 lines
2.4 KiB
TypeScript

"use client";
import { setLanguageCookie } from "@/lib/cookies";
import { Lang, LANGS } from "@/lib/i18n";
import {
Listbox,
ListboxButton,
ListboxOption,
ListboxOptions,
} from "@headlessui/react";
import { CheckIcon, ChevronDownIcon } from "@heroicons/react/24/outline";
import clsx from "clsx";
import { useLocale } from "next-intl";
import { useRouter } from "next/navigation";
import { useState } from "react";
export function LanguageSwitcher() {
const currentLocale = useLocale();
const [selected, setSelected] = useState(
LANGS.find((l) => l.code === currentLocale) || LANGS[0],
);
const router = useRouter();
const handleChange = async (language: Lang) => {
setSelected(language);
const newLocale = language.code;
await setLanguageCookie(newLocale);
router.refresh();
};
return (
<div className="w-32">
<Listbox value={selected} onChange={handleChange}>
<ListboxButton
className={clsx(
"relative block w-full rounded-lg bg-black/5 py-1.5 pl-3 pr-8 text-left text-sm/6 text-black dark:bg-white/5 dark:text-white",
"focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-white/25",
)}
>
{selected.name}
<ChevronDownIcon
className="group pointer-events-none absolute right-2.5 top-2.5 size-4"
aria-hidden="true"
/>
</ListboxButton>
<ListboxOptions
anchor="bottom"
transition
className={clsx(
"w-[var(--button-width)] rounded-xl border border-black/5 bg-background-light-500 p-1 [--anchor-gap:var(--spacing-1)] focus:outline-none dark:border-white/5 dark:bg-background-dark-500",
"transition duration-100 ease-in data-[leave]:data-[closed]:opacity-0",
)}
>
{LANGS.map((lang) => (
<ListboxOption
key={lang.code}
value={lang}
className="group flex cursor-default select-none items-center gap-2 rounded-lg px-3 py-1.5 data-[focus]:bg-black/10 dark:data-[focus]:bg-white/10"
>
<CheckIcon className="invisible size-4 group-data-[selected]:visible" />
<div className="text-sm/6 text-black dark:text-white">
{lang.name}
</div>
</ListboxOption>
))}
</ListboxOptions>
</Listbox>
</div>
);
}