mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
feat: add language switcher (#1337)
## Description Web changes: - Enabled i18n for web - Add option to change language in command menu - Add option to change language in menu-switcher Web and marketing changes: - Stop setting 'en' preference into cookie if the user's language is not supported - Dropped middleware changes - Rotated cookie from 'i18n' to 'language' <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a language switcher in the footer for improved language selection. - Added dynamic language change functionality in the command menu. - Implemented a dropdown menu item for quick access to the language switcher. - **Bug Fixes** - Resolved issues related to language change notifications and state management. - **Translations** - Added new translation entries for improved language support, including "Search languages..." in English and German. - Updated existing translations to enhance clarity and accuracy. - **Chores** - Simplified internationalization handling in middleware. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: github-actions <github-actions@documenso.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import type { HTMLAttributes } from 'react';
|
||||
import { type HTMLAttributes, useState } from 'react';
|
||||
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
@ -9,15 +9,15 @@ import { msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { FaXTwitter } from 'react-icons/fa6';
|
||||
import { LiaDiscord } from 'react-icons/lia';
|
||||
import { LuGithub } from 'react-icons/lu';
|
||||
import { LuGithub, LuLanguages } from 'react-icons/lu';
|
||||
|
||||
import LogoImage from '@documenso/assets/logo.png';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { ThemeSwitcher } from '@documenso/ui/primitives/theme-switcher';
|
||||
|
||||
import { I18nSwitcher } from '~/components/(marketing)/i18n-switcher';
|
||||
|
||||
import { SUPPORTED_LANGUAGES } from '@documenso/lib/constants/i18n';
|
||||
// import { StatusWidgetContainer } from './status-widget-container';
|
||||
import { LanguageSwitcherDialog } from '@documenso/ui/components/common/language-switcher-dialog';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { ThemeSwitcher } from '@documenso/ui/primitives/theme-switcher';
|
||||
|
||||
export type FooterProps = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
@ -44,7 +44,9 @@ const FOOTER_LINKS = [
|
||||
];
|
||||
|
||||
export const Footer = ({ className, ...props }: FooterProps) => {
|
||||
const { _ } = useLingui();
|
||||
const { _, i18n } = useLingui();
|
||||
|
||||
const [languageSwitcherOpen, setLanguageSwitcherOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className={cn('border-t py-12', className)} {...props}>
|
||||
@ -97,13 +99,22 @@ export const Footer = ({ className, ...props }: FooterProps) => {
|
||||
</p>
|
||||
|
||||
<div className="flex flex-row-reverse items-center sm:flex-row">
|
||||
<I18nSwitcher className="text-muted-foreground ml-2 rounded-full font-normal sm:mr-2" />
|
||||
<Button
|
||||
className="text-muted-foreground ml-2 rounded-full font-normal sm:mr-2"
|
||||
variant="ghost"
|
||||
onClick={() => setLanguageSwitcherOpen(true)}
|
||||
>
|
||||
<LuLanguages className="mr-1.5 h-4 w-4" />
|
||||
{SUPPORTED_LANGUAGES[i18n.locale]?.full || i18n.locale}
|
||||
</Button>
|
||||
|
||||
<div className="flex flex-wrap">
|
||||
<ThemeSwitcher />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LanguageSwitcherDialog open={languageSwitcherOpen} setOpen={setLanguageSwitcherOpen} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { CheckIcon } from 'lucide-react';
|
||||
import { LuLanguages } from 'react-icons/lu';
|
||||
|
||||
import { SUPPORTED_LANGUAGES } from '@documenso/lib/constants/i18n';
|
||||
import { switchI18NLanguage } from '@documenso/lib/server-only/i18n/switch-i18n-language';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
CommandDialog,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@documenso/ui/primitives/command';
|
||||
|
||||
type I18nSwitcherProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const I18nSwitcher = ({ className }: I18nSwitcherProps) => {
|
||||
const { i18n, _ } = useLingui();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [value, setValue] = useState(i18n.locale);
|
||||
|
||||
const setLanguage = async (lang: string) => {
|
||||
setValue(lang);
|
||||
setOpen(false);
|
||||
|
||||
await dynamicActivate(i18n, lang);
|
||||
await switchI18NLanguage(lang);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button className={className} variant="ghost" onClick={() => setOpen(true)}>
|
||||
<LuLanguages className="mr-1.5 h-4 w-4" />
|
||||
{SUPPORTED_LANGUAGES[value]?.full || i18n.locale}
|
||||
</Button>
|
||||
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<CommandInput placeholder={_(msg`Search languages...`)} />
|
||||
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
{Object.values(SUPPORTED_LANGUAGES).map((language) => (
|
||||
<CommandItem
|
||||
key={language.short}
|
||||
value={language.full}
|
||||
onSelect={async () => setLanguage(language.short)}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value === language.short ? 'opacity-100' : 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
{SUPPORTED_LANGUAGES[language.short].full}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,39 +0,0 @@
|
||||
import { cookies } from 'next/headers';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
import { extractLocaleData } from '@documenso/lib/utils/i18n';
|
||||
|
||||
export default function middleware(req: NextRequest) {
|
||||
const { lang } = extractLocaleData({
|
||||
headers: req.headers,
|
||||
cookies: cookies(),
|
||||
});
|
||||
|
||||
const response = NextResponse.next();
|
||||
|
||||
response.cookies.set('i18n', lang);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
/*
|
||||
* Match all request paths except for the ones starting with:
|
||||
* - api (API routes)
|
||||
* - _next/static (static files)
|
||||
* - _next/image (image optimization files)
|
||||
* - favicon.ico (favicon file)
|
||||
* - ingest (analytics)
|
||||
* - site.webmanifest
|
||||
*/
|
||||
{
|
||||
source: '/((?!api|_next/static|_next/image|ingest|favicon|site.webmanifest).*)',
|
||||
missing: [
|
||||
{ type: 'header', key: 'next-router-prefetch' },
|
||||
{ type: 'header', key: 'purpose', value: 'prefetch' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -7,10 +7,11 @@ import { useRouter } from 'next/navigation';
|
||||
import type { MessageDescriptor } from '@lingui/core';
|
||||
import { Trans, msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Loader, Monitor, Moon, Sun } from 'lucide-react';
|
||||
import { CheckIcon, Loader, Monitor, Moon, Sun } from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
import { SUPPORTED_LANGUAGES } from '@documenso/lib/constants/i18n';
|
||||
import {
|
||||
DOCUMENTS_PAGE_SHORTCUT,
|
||||
SETTINGS_PAGE_SHORTCUT,
|
||||
@ -20,7 +21,10 @@ import {
|
||||
DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||
SKIP_QUERY_BATCH_META,
|
||||
} from '@documenso/lib/constants/trpc';
|
||||
import { switchI18NLanguage } from '@documenso/lib/server-only/i18n/switch-i18n-language';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
import { trpc as trpcReact } from '@documenso/trpc/react';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import {
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
@ -31,6 +35,7 @@ import {
|
||||
CommandShortcut,
|
||||
} from '@documenso/ui/primitives/command';
|
||||
import { THEMES_TYPE } from '@documenso/ui/primitives/constants';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
const DOCUMENTS_PAGES = [
|
||||
{
|
||||
@ -207,6 +212,9 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) {
|
||||
<Commands push={push} pages={SETTINGS_PAGES} />
|
||||
</CommandGroup>
|
||||
<CommandGroup className="mx-2 p-0 pb-2" heading={_(msg`Preferences`)}>
|
||||
<CommandItem className="-mx-2 -my-1 rounded-lg" onSelect={() => addPage('language')}>
|
||||
Change language
|
||||
</CommandItem>
|
||||
<CommandItem className="-mx-2 -my-1 rounded-lg" onSelect={() => addPage('theme')}>
|
||||
Change theme
|
||||
</CommandItem>
|
||||
@ -218,7 +226,9 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentPage === 'theme' && <ThemeCommands setTheme={setTheme} />}
|
||||
{currentPage === 'language' && <LanguageCommands />}
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
);
|
||||
@ -269,3 +279,46 @@ const ThemeCommands = ({ setTheme }: { setTheme: (_theme: string) => void }) =>
|
||||
</CommandItem>
|
||||
));
|
||||
};
|
||||
|
||||
const LanguageCommands = () => {
|
||||
const { i18n, _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const setLanguage = async (lang: string) => {
|
||||
if (isLoading || lang === i18n.locale) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
await dynamicActivate(i18n, lang);
|
||||
await switchI18NLanguage(lang);
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`An unknown error occurred`),
|
||||
variant: 'destructive',
|
||||
description: _(msg`Unable to change the language at this time. Please try again later.`),
|
||||
});
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
return Object.values(SUPPORTED_LANGUAGES).map((language) => (
|
||||
<CommandItem
|
||||
disabled={isLoading}
|
||||
key={language.full}
|
||||
onSelect={async () => setLanguage(language.short)}
|
||||
className="-my-1 mx-2 rounded-lg first:mt-2 last:mb-2"
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn('mr-2 h-4 w-4', i18n.locale === language.short ? 'opacity-100' : 'opacity-0')}
|
||||
/>
|
||||
|
||||
{language.full}
|
||||
</CommandItem>
|
||||
));
|
||||
};
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
@ -17,6 +19,7 @@ import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
|
||||
import { canExecuteTeamAction } from '@documenso/lib/utils/teams';
|
||||
import type { User } from '@documenso/prisma/client';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { LanguageSwitcherDialog } from '@documenso/ui/components/common/language-switcher-dialog';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { AvatarWithText } from '@documenso/ui/primitives/avatar';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
@ -41,6 +44,8 @@ export const MenuSwitcher = ({ user, teams: initialTeamsData }: MenuSwitcherProp
|
||||
|
||||
const pathname = usePathname();
|
||||
|
||||
const [languageSwitcherOpen, setLanguageSwitcherOpen] = useState(false);
|
||||
|
||||
const isUserAdmin = isAdmin(user);
|
||||
|
||||
const { data: teamsQueryResult } = trpc.team.getTeams.useQuery(undefined, {
|
||||
@ -274,6 +279,13 @@ export const MenuSwitcher = ({ user, teams: initialTeamsData }: MenuSwitcherProp
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
<DropdownMenuItem
|
||||
className="text-muted-foreground px-4 py-2"
|
||||
onClick={() => setLanguageSwitcherOpen(true)}
|
||||
>
|
||||
<Trans>Language</Trans>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
className="text-destructive/90 hover:!text-destructive px-4 py-2"
|
||||
onSelect={async () =>
|
||||
@ -285,6 +297,8 @@ export const MenuSwitcher = ({ user, teams: initialTeamsData }: MenuSwitcherProp
|
||||
<Trans>Sign Out</Trans>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
||||
<LanguageSwitcherDialog open={languageSwitcherOpen} setOpen={setLanguageSwitcherOpen} />
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
@ -5,7 +5,6 @@ import { NextResponse } from 'next/server';
|
||||
import { getToken } from 'next-auth/jwt';
|
||||
|
||||
import { TEAM_URL_ROOT_REGEX } from '@documenso/lib/constants/teams';
|
||||
import { extractLocaleData } from '@documenso/lib/utils/i18n';
|
||||
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
||||
|
||||
async function middleware(req: NextRequest): Promise<NextResponse> {
|
||||
@ -96,12 +95,7 @@ async function middleware(req: NextRequest): Promise<NextResponse> {
|
||||
export default async function middlewareWrapper(req: NextRequest) {
|
||||
const response = await middleware(req);
|
||||
|
||||
const { lang } = extractLocaleData({
|
||||
headers: req.headers,
|
||||
cookies: cookies(),
|
||||
});
|
||||
|
||||
response.cookies.set('i18n', lang);
|
||||
// Can place anything that needs to be set on the response here.
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ export const NEXT_PRIVATE_INTERNAL_WEBAPP_URL = process.env.NEXT_PRIVATE_INTERNA
|
||||
export const IS_APP_MARKETING = process.env.NEXT_PUBLIC_PROJECT === 'marketing';
|
||||
export const IS_APP_WEB = process.env.NEXT_PUBLIC_PROJECT === 'web';
|
||||
export const IS_BILLING_ENABLED = () => env('NEXT_PUBLIC_FEATURE_BILLING_ENABLED') === 'true';
|
||||
export const IS_APP_WEB_I18N_ENABLED = false;
|
||||
export const IS_APP_WEB_I18N_ENABLED = true;
|
||||
|
||||
export const APP_FOLDER = () => (IS_APP_MARKETING ? 'marketing' : 'web');
|
||||
|
||||
|
||||
@ -4,5 +4,5 @@ import { cookies } from 'next/headers';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
export const switchI18NLanguage = async (lang: string) => {
|
||||
cookies().set('i18n', lang);
|
||||
cookies().set('language', lang);
|
||||
};
|
||||
|
||||
@ -522,6 +522,10 @@ msgstr "Speichern"
|
||||
msgid "Save Template"
|
||||
msgstr "Vorlage speichern"
|
||||
|
||||
#: packages/ui/components/common/language-switcher-dialog.tsx:34
|
||||
msgid "Search languages..."
|
||||
msgstr "Sprachen suchen..."
|
||||
|
||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:105
|
||||
msgid "Select"
|
||||
msgstr "Auswählen"
|
||||
|
||||
@ -430,8 +430,8 @@ msgid "Save $60 or $120"
|
||||
msgstr "Sparen Sie $60 oder $120"
|
||||
|
||||
#: apps/marketing/src/components/(marketing)/i18n-switcher.tsx:47
|
||||
msgid "Search languages..."
|
||||
msgstr "Sprachen suchen..."
|
||||
#~ msgid "Search languages..."
|
||||
#~ msgstr "Sprachen suchen..."
|
||||
|
||||
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109
|
||||
msgid "Securely. Our data centers are located in Frankfurt (Germany), giving us the best local privacy laws. We are very aware of the sensitive nature of our data and follow best practices to ensure the security and integrity of the data entrusted to us."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -303,7 +303,7 @@ msgstr "Das Hinzufügen und Entfernen von Sitzplätzen wird Ihre Rechnung entspr
|
||||
msgid "Admin Actions"
|
||||
msgstr "Admin-Aktionen"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:257
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:262
|
||||
msgid "Admin panel"
|
||||
msgstr "Admin-Panel"
|
||||
|
||||
@ -311,7 +311,7 @@ msgstr "Admin-Panel"
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:37
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:42
|
||||
msgid "All documents"
|
||||
msgstr "Alle Dokumente"
|
||||
|
||||
@ -327,7 +327,7 @@ msgstr "Alle eingefügten Unterschriften werden annulliert"
|
||||
msgid "All recipients will be notified"
|
||||
msgstr "Alle Empfänger werden benachrichtigt"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:52
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:57
|
||||
msgid "All templates"
|
||||
msgstr "Alle Vorlagen"
|
||||
|
||||
@ -481,6 +481,7 @@ msgstr "Ein Fehler ist aufgetreten, während dein Dokument hochgeladen wurde."
|
||||
#: apps/web/src/app/(dashboard)/settings/profile/delete-account-dialog.tsx:63
|
||||
#: apps/web/src/app/(signing)/sign/[token]/complete/claim-account.tsx:98
|
||||
#: apps/web/src/app/(teams)/t/[teamUrl]/settings/team-transfer-status.tsx:54
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:301
|
||||
#: apps/web/src/components/(dashboard)/settings/token/delete-token-dialog.tsx:97
|
||||
#: apps/web/src/components/(dashboard)/settings/webhooks/delete-webhook-dialog.tsx:88
|
||||
#: apps/web/src/components/(teams)/dialogs/add-team-email-dialog.tsx:100
|
||||
@ -793,7 +794,7 @@ msgstr "Betrachten abschließen"
|
||||
msgid "Completed"
|
||||
msgstr "Abgeschlossen"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:43
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:48
|
||||
msgid "Completed documents"
|
||||
msgstr "Abgeschlossene Dokumente"
|
||||
|
||||
@ -927,8 +928,8 @@ msgstr "Jetzt erstellen"
|
||||
msgid "Create one automatically"
|
||||
msgstr "Einen automatisch erstellen"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:176
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:246
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:181
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:251
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-dialog.tsx:138
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-dialog.tsx:146
|
||||
msgid "Create team"
|
||||
@ -1006,7 +1007,7 @@ msgstr "Aktueller Plan: {0}"
|
||||
msgid "Daily"
|
||||
msgstr "Täglich"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:255
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:265
|
||||
msgid "Dark Mode"
|
||||
msgstr "Dunkelmodus"
|
||||
|
||||
@ -1316,7 +1317,7 @@ msgstr "Dokument wird dauerhaft gelöscht"
|
||||
#: apps/web/src/app/(dashboard)/documents/documents-page-view.tsx:110
|
||||
#: apps/web/src/app/(profile)/p/[url]/page.tsx:166
|
||||
#: apps/web/src/app/not-found.tsx:21
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:200
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:205
|
||||
#: apps/web/src/components/(dashboard)/layout/desktop-nav.tsx:18
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:35
|
||||
#: apps/web/src/components/ui/user-profile-timur.tsx:60
|
||||
@ -1358,7 +1359,7 @@ msgstr "Zertifikat herunterladen"
|
||||
msgid "Draft"
|
||||
msgstr "Entwurf"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:41
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:46
|
||||
msgid "Draft documents"
|
||||
msgstr "Entwurfdokumente"
|
||||
|
||||
@ -1683,7 +1684,7 @@ msgstr "Wenn Ihre Authenticator-App keine QR-Codes unterstützt, können Sie sta
|
||||
msgid "Inbox"
|
||||
msgstr "Posteingang"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:47
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:52
|
||||
msgid "Inbox documents"
|
||||
msgstr "Posteingang Dokumente"
|
||||
|
||||
@ -1773,6 +1774,10 @@ msgstr "Es scheint, dass kein Token bereitgestellt wurde. Wenn Sie versuchen, Ih
|
||||
msgid "It seems that there is no token provided. Please check your email and try again."
|
||||
msgstr "Es scheint, dass kein Token bereitgestellt wurde. Bitte überprüfen Sie Ihre E-Mail und versuchen Sie es erneut."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:286
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
|
||||
#: apps/web/src/components/(dashboard)/period-selector/period-selector.tsx:61
|
||||
msgid "Last 14 days"
|
||||
msgstr "Die letzten 14 Tage"
|
||||
@ -1810,7 +1815,7 @@ msgstr "Verlassen"
|
||||
msgid "Leave team"
|
||||
msgstr "Team verlassen"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:254
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:264
|
||||
msgid "Light Mode"
|
||||
msgstr "Lichtmodus"
|
||||
|
||||
@ -1900,7 +1905,7 @@ msgstr "Abonnements verwalten"
|
||||
msgid "Manage team subscription."
|
||||
msgstr "Teamabonnement verwalten."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:163
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:168
|
||||
msgid "Manage teams"
|
||||
msgstr "Teams verwalten"
|
||||
|
||||
@ -2054,7 +2059,7 @@ msgstr "Keine aktuellen Aktivitäten"
|
||||
msgid "No recipients"
|
||||
msgstr "Keine Empfänger"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:195
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:200
|
||||
msgid "No results found."
|
||||
msgstr "Keine Ergebnisse gefunden."
|
||||
|
||||
@ -2146,7 +2151,7 @@ msgid "Otherwise, the document will be created as a draft."
|
||||
msgstr "Andernfalls wird das Dokument als Entwurf erstellt."
|
||||
|
||||
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:86
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:76
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:81
|
||||
msgid "Owner"
|
||||
msgstr "Besitzer"
|
||||
|
||||
@ -2191,7 +2196,7 @@ msgstr "Passkeys ermöglichen das Anmelden und die Authentifizierung mit biometr
|
||||
msgid "Passkeys are not supported on this browser"
|
||||
msgstr "Passkeys werden von diesem Browser nicht unterstützt"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:65
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:70
|
||||
#: apps/web/src/components/forms/password.tsx:123
|
||||
#: apps/web/src/components/forms/reset-password.tsx:110
|
||||
#: apps/web/src/components/forms/signin.tsx:344
|
||||
@ -2225,7 +2230,7 @@ msgstr "Zahlung überfällig"
|
||||
msgid "Pending"
|
||||
msgstr "Ausstehend"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:46
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:51
|
||||
msgid "Pending documents"
|
||||
msgstr "Ausstehende Dokumente"
|
||||
|
||||
@ -2241,11 +2246,11 @@ msgstr "Ausstehende Einladungen"
|
||||
msgid "Pending team deleted."
|
||||
msgstr "Ausstehendes Team gelöscht."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:129
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:134
|
||||
msgid "Personal"
|
||||
msgstr "Persönlich"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:72
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:77
|
||||
msgid "Personal Account"
|
||||
msgstr "Persönliches Konto"
|
||||
|
||||
@ -2329,7 +2334,7 @@ msgstr "Bitte versuchen Sie es später noch einmal."
|
||||
msgid "Please type <0>{0}</0> to confirm."
|
||||
msgstr "Bitte geben Sie <0>{0}</0> ein, um zu bestätigen."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:209
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:214
|
||||
msgid "Preferences"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
@ -2347,7 +2352,7 @@ msgid "Private templates can only be modified and viewed by you."
|
||||
msgstr "Private Vorlagen können nur von Ihnen bearbeitet und angezeigt werden."
|
||||
|
||||
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:28
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:64
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:69
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx:36
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx:39
|
||||
msgid "Profile"
|
||||
@ -2666,8 +2671,8 @@ msgid "Set a password"
|
||||
msgstr "Ein Passwort festlegen"
|
||||
|
||||
#: apps/web/src/app/(dashboard)/settings/layout.tsx:20
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:60
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:206
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:65
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:211
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:47
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
@ -2751,7 +2756,7 @@ msgstr "Einloggen"
|
||||
msgid "Sign in to your account"
|
||||
msgstr "Melden Sie sich bei Ihrem Konto an"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:285
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:297
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:84
|
||||
msgid "Sign Out"
|
||||
msgstr "Ausloggen"
|
||||
@ -2957,7 +2962,7 @@ msgstr "Erfolg"
|
||||
msgid "Successfully created passkey"
|
||||
msgstr "Passkey erfolgreich erstellt"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:256
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:266
|
||||
msgid "System Theme"
|
||||
msgstr "Systemthema"
|
||||
|
||||
@ -3042,7 +3047,7 @@ msgstr "Team-Eigentum übertragen!"
|
||||
msgid "Team Public Profile"
|
||||
msgstr "Öffentliches Profil des Teams"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:272
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:277
|
||||
msgid "Team settings"
|
||||
msgstr "Teameinstellungen"
|
||||
|
||||
@ -3068,7 +3073,7 @@ msgid "Team URL"
|
||||
msgstr "Team-URL"
|
||||
|
||||
#: apps/web/src/app/(dashboard)/settings/teams/page.tsx:25
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:157
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:162
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:43
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx:64
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx:67
|
||||
@ -3114,7 +3119,7 @@ msgstr "Template saved"
|
||||
|
||||
#: apps/web/src/app/(dashboard)/templates/[id]/template-page-view.tsx:60
|
||||
#: apps/web/src/app/(dashboard)/templates/templates-page-view.tsx:55
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:203
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:208
|
||||
#: apps/web/src/components/(dashboard)/layout/desktop-nav.tsx:22
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:39
|
||||
msgid "Templates"
|
||||
@ -3522,7 +3527,7 @@ msgstr "Type"
|
||||
msgid "Type 'delete' to confirm"
|
||||
msgstr "Type 'delete' to confirm"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:181
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:186
|
||||
msgid "Type a command or search..."
|
||||
msgstr "Type a command or search..."
|
||||
|
||||
@ -3530,6 +3535,10 @@ msgstr "Type a command or search..."
|
||||
msgid "Uh oh! Looks like you're missing a token"
|
||||
msgstr "Uh oh! Looks like you're missing a token"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:303
|
||||
msgid "Unable to change the language at this time. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
#: apps/web/src/components/forms/2fa/recovery-code-list.tsx:31
|
||||
msgid "Unable to copy recovery code"
|
||||
msgstr "Unable to copy recovery code"
|
||||
@ -3728,7 +3737,7 @@ msgstr "Benutzer-ID"
|
||||
msgid "User profiles are here!"
|
||||
msgstr "Benutzerprofile sind hier!"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:264
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:269
|
||||
msgid "User settings"
|
||||
msgstr "Benutzereinstellungen"
|
||||
|
||||
@ -4360,7 +4369,7 @@ msgstr "Ihr Dokument wurde erfolgreich hochgeladen."
|
||||
msgid "Your document has been uploaded successfully. You will be redirected to the template page."
|
||||
msgstr "Ihr Dokument wurde erfolgreich hochgeladen. Sie werden zur Vorlagenseite weitergeleitet."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:215
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:223
|
||||
msgid "Your documents"
|
||||
msgstr "Ihre Dokumente"
|
||||
|
||||
|
||||
@ -517,6 +517,10 @@ msgstr "Save"
|
||||
msgid "Save Template"
|
||||
msgstr "Save Template"
|
||||
|
||||
#: packages/ui/components/common/language-switcher-dialog.tsx:34
|
||||
msgid "Search languages..."
|
||||
msgstr "Search languages..."
|
||||
|
||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:105
|
||||
msgid "Select"
|
||||
msgstr "Select"
|
||||
|
||||
@ -425,8 +425,8 @@ msgid "Save $60 or $120"
|
||||
msgstr "Save $60 or $120"
|
||||
|
||||
#: apps/marketing/src/components/(marketing)/i18n-switcher.tsx:47
|
||||
msgid "Search languages..."
|
||||
msgstr "Search languages..."
|
||||
#~ msgid "Search languages..."
|
||||
#~ msgstr "Search languages..."
|
||||
|
||||
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109
|
||||
msgid "Securely. Our data centers are located in Frankfurt (Germany), giving us the best local privacy laws. We are very aware of the sensitive nature of our data and follow best practices to ensure the security and integrity of the data entrusted to us."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -298,7 +298,7 @@ msgstr "Adding and removing seats will adjust your invoice accordingly."
|
||||
msgid "Admin Actions"
|
||||
msgstr "Admin Actions"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:257
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:262
|
||||
msgid "Admin panel"
|
||||
msgstr "Admin panel"
|
||||
|
||||
@ -306,7 +306,7 @@ msgstr "Admin panel"
|
||||
msgid "All"
|
||||
msgstr "All"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:37
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:42
|
||||
msgid "All documents"
|
||||
msgstr "All documents"
|
||||
|
||||
@ -322,7 +322,7 @@ msgstr "All inserted signatures will be voided"
|
||||
msgid "All recipients will be notified"
|
||||
msgstr "All recipients will be notified"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:52
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:57
|
||||
msgid "All templates"
|
||||
msgstr "All templates"
|
||||
|
||||
@ -476,6 +476,7 @@ msgstr "An error occurred while uploading your document."
|
||||
#: apps/web/src/app/(dashboard)/settings/profile/delete-account-dialog.tsx:63
|
||||
#: apps/web/src/app/(signing)/sign/[token]/complete/claim-account.tsx:98
|
||||
#: apps/web/src/app/(teams)/t/[teamUrl]/settings/team-transfer-status.tsx:54
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:301
|
||||
#: apps/web/src/components/(dashboard)/settings/token/delete-token-dialog.tsx:97
|
||||
#: apps/web/src/components/(dashboard)/settings/webhooks/delete-webhook-dialog.tsx:88
|
||||
#: apps/web/src/components/(teams)/dialogs/add-team-email-dialog.tsx:100
|
||||
@ -788,7 +789,7 @@ msgstr "Complete Viewing"
|
||||
msgid "Completed"
|
||||
msgstr "Completed"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:43
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:48
|
||||
msgid "Completed documents"
|
||||
msgstr "Completed documents"
|
||||
|
||||
@ -922,8 +923,8 @@ msgstr "Create now"
|
||||
msgid "Create one automatically"
|
||||
msgstr "Create one automatically"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:176
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:246
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:181
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:251
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-dialog.tsx:138
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-dialog.tsx:146
|
||||
msgid "Create team"
|
||||
@ -1003,7 +1004,7 @@ msgstr "Current plan: {0}"
|
||||
msgid "Daily"
|
||||
msgstr "Daily"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:255
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:265
|
||||
msgid "Dark Mode"
|
||||
msgstr "Dark Mode"
|
||||
|
||||
@ -1313,7 +1314,7 @@ msgstr "Document will be permanently deleted"
|
||||
#: apps/web/src/app/(dashboard)/documents/documents-page-view.tsx:110
|
||||
#: apps/web/src/app/(profile)/p/[url]/page.tsx:166
|
||||
#: apps/web/src/app/not-found.tsx:21
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:200
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:205
|
||||
#: apps/web/src/components/(dashboard)/layout/desktop-nav.tsx:18
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:35
|
||||
#: apps/web/src/components/ui/user-profile-timur.tsx:60
|
||||
@ -1355,7 +1356,7 @@ msgstr "Download Certificate"
|
||||
msgid "Draft"
|
||||
msgstr "Draft"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:41
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:46
|
||||
msgid "Draft documents"
|
||||
msgstr "Draft documents"
|
||||
|
||||
@ -1682,7 +1683,7 @@ msgstr "If your authenticator app does not support QR codes, you can use the fol
|
||||
msgid "Inbox"
|
||||
msgstr "Inbox"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:47
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:52
|
||||
msgid "Inbox documents"
|
||||
msgstr "Inbox documents"
|
||||
|
||||
@ -1772,6 +1773,10 @@ msgstr "It seems that there is no token provided, if you are trying to verify yo
|
||||
msgid "It seems that there is no token provided. Please check your email and try again."
|
||||
msgstr "It seems that there is no token provided. Please check your email and try again."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:286
|
||||
msgid "Language"
|
||||
msgstr "Language"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/period-selector/period-selector.tsx:61
|
||||
msgid "Last 14 days"
|
||||
msgstr "Last 14 days"
|
||||
@ -1809,7 +1814,7 @@ msgstr "Leave"
|
||||
msgid "Leave team"
|
||||
msgstr "Leave team"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:254
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:264
|
||||
msgid "Light Mode"
|
||||
msgstr "Light Mode"
|
||||
|
||||
@ -1899,7 +1904,7 @@ msgstr "Manage subscriptions"
|
||||
msgid "Manage team subscription."
|
||||
msgstr "Manage team subscription."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:163
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:168
|
||||
msgid "Manage teams"
|
||||
msgstr "Manage teams"
|
||||
|
||||
@ -2053,7 +2058,7 @@ msgstr "No recent activity"
|
||||
msgid "No recipients"
|
||||
msgstr "No recipients"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:195
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:200
|
||||
msgid "No results found."
|
||||
msgstr "No results found."
|
||||
|
||||
@ -2145,7 +2150,7 @@ msgid "Otherwise, the document will be created as a draft."
|
||||
msgstr "Otherwise, the document will be created as a draft."
|
||||
|
||||
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:86
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:76
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:81
|
||||
msgid "Owner"
|
||||
msgstr "Owner"
|
||||
|
||||
@ -2190,7 +2195,7 @@ msgstr "Passkeys allow you to sign in and authenticate using biometrics, passwor
|
||||
msgid "Passkeys are not supported on this browser"
|
||||
msgstr "Passkeys are not supported on this browser"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:65
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:70
|
||||
#: apps/web/src/components/forms/password.tsx:123
|
||||
#: apps/web/src/components/forms/reset-password.tsx:110
|
||||
#: apps/web/src/components/forms/signin.tsx:344
|
||||
@ -2224,7 +2229,7 @@ msgstr "Payment overdue"
|
||||
msgid "Pending"
|
||||
msgstr "Pending"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:46
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:51
|
||||
msgid "Pending documents"
|
||||
msgstr "Pending documents"
|
||||
|
||||
@ -2240,11 +2245,11 @@ msgstr "Pending invitations"
|
||||
msgid "Pending team deleted."
|
||||
msgstr "Pending team deleted."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:129
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:134
|
||||
msgid "Personal"
|
||||
msgstr "Personal"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:72
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:77
|
||||
msgid "Personal Account"
|
||||
msgstr "Personal Account"
|
||||
|
||||
@ -2328,7 +2333,7 @@ msgstr "Please try again later."
|
||||
msgid "Please type <0>{0}</0> to confirm."
|
||||
msgstr "Please type <0>{0}</0> to confirm."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:209
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:214
|
||||
msgid "Preferences"
|
||||
msgstr "Preferences"
|
||||
|
||||
@ -2346,7 +2351,7 @@ msgid "Private templates can only be modified and viewed by you."
|
||||
msgstr "Private templates can only be modified and viewed by you."
|
||||
|
||||
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:28
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:64
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:69
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx:36
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx:39
|
||||
msgid "Profile"
|
||||
@ -2665,8 +2670,8 @@ msgid "Set a password"
|
||||
msgstr "Set a password"
|
||||
|
||||
#: apps/web/src/app/(dashboard)/settings/layout.tsx:20
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:60
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:206
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:65
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:211
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:47
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
@ -2750,7 +2755,7 @@ msgstr "Sign In"
|
||||
msgid "Sign in to your account"
|
||||
msgstr "Sign in to your account"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:285
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:297
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:84
|
||||
msgid "Sign Out"
|
||||
msgstr "Sign Out"
|
||||
@ -2956,7 +2961,7 @@ msgstr "Success"
|
||||
msgid "Successfully created passkey"
|
||||
msgstr "Successfully created passkey"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:256
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:266
|
||||
msgid "System Theme"
|
||||
msgstr "System Theme"
|
||||
|
||||
@ -3041,7 +3046,7 @@ msgstr "Team ownership transferred!"
|
||||
msgid "Team Public Profile"
|
||||
msgstr "Team Public Profile"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:272
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:277
|
||||
msgid "Team settings"
|
||||
msgstr "Team settings"
|
||||
|
||||
@ -3067,7 +3072,7 @@ msgid "Team URL"
|
||||
msgstr "Team URL"
|
||||
|
||||
#: apps/web/src/app/(dashboard)/settings/teams/page.tsx:25
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:157
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:162
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:43
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx:64
|
||||
#: apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx:67
|
||||
@ -3113,7 +3118,7 @@ msgstr "Template saved"
|
||||
|
||||
#: apps/web/src/app/(dashboard)/templates/[id]/template-page-view.tsx:60
|
||||
#: apps/web/src/app/(dashboard)/templates/templates-page-view.tsx:55
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:203
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:208
|
||||
#: apps/web/src/components/(dashboard)/layout/desktop-nav.tsx:22
|
||||
#: apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx:39
|
||||
msgid "Templates"
|
||||
@ -3521,7 +3526,7 @@ msgstr "Type"
|
||||
msgid "Type 'delete' to confirm"
|
||||
msgstr "Type 'delete' to confirm"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:181
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:186
|
||||
msgid "Type a command or search..."
|
||||
msgstr "Type a command or search..."
|
||||
|
||||
@ -3529,6 +3534,10 @@ msgstr "Type a command or search..."
|
||||
msgid "Uh oh! Looks like you're missing a token"
|
||||
msgstr "Uh oh! Looks like you're missing a token"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:303
|
||||
msgid "Unable to change the language at this time. Please try again later."
|
||||
msgstr "Unable to change the language at this time. Please try again later."
|
||||
|
||||
#: apps/web/src/components/forms/2fa/recovery-code-list.tsx:31
|
||||
msgid "Unable to copy recovery code"
|
||||
msgstr "Unable to copy recovery code"
|
||||
@ -3727,7 +3736,7 @@ msgstr "User ID"
|
||||
msgid "User profiles are here!"
|
||||
msgstr "User profiles are here!"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:264
|
||||
#: apps/web/src/components/(dashboard)/layout/menu-switcher.tsx:269
|
||||
msgid "User settings"
|
||||
msgstr "User settings"
|
||||
|
||||
@ -4359,7 +4368,7 @@ msgstr "Your document has been uploaded successfully."
|
||||
msgid "Your document has been uploaded successfully. You will be redirected to the template page."
|
||||
msgstr "Your document has been uploaded successfully. You will be redirected to the template page."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:215
|
||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:223
|
||||
msgid "Your documents"
|
||||
msgstr "Your documents"
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ const parseLanguageFromLocale = (locale: string): SupportedLanguageCodes | null
|
||||
export const extractLocaleDataFromCookies = (
|
||||
cookies: ReadonlyRequestCookies,
|
||||
): SupportedLanguageCodes | null => {
|
||||
const preferredLocale = cookies.get('i18n')?.value || '';
|
||||
const preferredLocale = cookies.get('language')?.value || '';
|
||||
|
||||
const language = parseLanguageFromLocale(preferredLocale || '');
|
||||
|
||||
|
||||
57
packages/ui/components/common/language-switcher-dialog.tsx
Normal file
57
packages/ui/components/common/language-switcher-dialog.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import { msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { CheckIcon } from 'lucide-react';
|
||||
|
||||
import { SUPPORTED_LANGUAGES } from '@documenso/lib/constants/i18n';
|
||||
import { switchI18NLanguage } from '@documenso/lib/server-only/i18n/switch-i18n-language';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import {
|
||||
CommandDialog,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@documenso/ui/primitives/command';
|
||||
|
||||
type LanguageSwitcherDialogProps = {
|
||||
open: boolean;
|
||||
setOpen: (_open: boolean) => void;
|
||||
};
|
||||
|
||||
export const LanguageSwitcherDialog = ({ open, setOpen }: LanguageSwitcherDialogProps) => {
|
||||
const { i18n, _ } = useLingui();
|
||||
|
||||
const setLanguage = async (lang: string) => {
|
||||
setOpen(false);
|
||||
|
||||
await dynamicActivate(i18n, lang);
|
||||
await switchI18NLanguage(lang);
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<CommandInput placeholder={_(msg`Search languages...`)} />
|
||||
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
{Object.values(SUPPORTED_LANGUAGES).map((language) => (
|
||||
<CommandItem
|
||||
key={language.short}
|
||||
value={language.full}
|
||||
onSelect={async () => setLanguage(language.short)}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
'mr-2 h-4 w-4',
|
||||
i18n.locale === language.short ? 'opacity-100' : 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
{SUPPORTED_LANGUAGES[language.short].full}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user