diff --git a/.env.staging b/.env.staging new file mode 100644 index 0000000..bf811ee --- /dev/null +++ b/.env.staging @@ -0,0 +1,15 @@ +# PRODUCTION ENVIRONMENT VARIABLES + +## DO NOT ADD VARS HERE UNLESS THEY ARE PUBLIC OR NOT SENSITIVE +## THIS ENV IS USED FOR PRODUCTION AND IS COMMITED TO THE REPO +## AVOID PLACING SENSITIVE DATA IN THIS FILE. +## PUBLIC KEYS OR CONFIGURATION ARE OKAY TO BE PLACED HERE. + +# SUPABASE +NEXT_PUBLIC_SUPABASE_URL=https://kaldvociniytdbbcxvqk.supabase.co +NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImthbGR2b2Npbml5dGRiYmN4dnFrIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTYzNjQ5OTYsImV4cCI6MjA3MTk0MDk5Nn0.eixihH2KGkJZolY9FiQDicJOo2kxvXrSe6gGUCrkLo0 + +NEXT_PUBLIC_SITE_URL=https://test.medreport.ee + +# MONTONIO +NEXT_PUBLIC_MONTONIO_ACCESS_KEY=7da5d7fa-3383-4997-9435-46aa818f4ead diff --git a/Dockerfile b/Dockerfile index adf4993..589d56d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ COPY packages packages COPY tooling tooling COPY .env .env COPY .env.production .env.production +COPY .env.staging .env.staging # Load env file and echo a specific variable # RUN dotenv -e .env -- printenv | grep 'SUPABASE' || true @@ -20,13 +21,10 @@ COPY . . ENV NODE_ENV=production -# πŸ” Optional: Log key envs for debug -RUN echo "πŸ“„ .env.production contents:" && cat .env.production \ - && echo "πŸ”§ Current ENV available to Next.js build:" && printenv | grep -E 'SUPABASE|STRIPE|NEXT|NODE_ENV' || true - RUN set -a \ && . .env \ && . .env.production \ + && . .env.staging \ && set +a \ && node check-env.js \ && pnpm build @@ -34,18 +32,21 @@ RUN set -a \ # --- Stage 2: Runtime --- FROM node:20-alpine +ARG APP_ENV=production WORKDIR /app COPY --from=builder /app ./ +RUN cp ".env.${APP_ENV}" .env.local + RUN npm install -g pnpm@9 \ && pnpm install --prod --frozen-lockfile ENV NODE_ENV=production # πŸ” Optional: Log key envs for debug -RUN echo "πŸ“„ .env.production contents:" && cat .env.production \ +RUN echo "πŸ“„ .env contents:" && cat .env.local \ && echo "πŸ”§ Current ENV available to Next.js build:" && printenv | grep -E 'SUPABASE|STRIPE|NEXT|NODE_ENV' || true diff --git a/app/(marketing)/_components/site-header-account-section.tsx b/app/(marketing)/_components/site-header-account-section.tsx index b442ab8..c4c388f 100644 --- a/app/(marketing)/_components/site-header-account-section.tsx +++ b/app/(marketing)/_components/site-header-account-section.tsx @@ -69,7 +69,7 @@ function AuthButtons() {
-
{patient.email}
+
+ +
+
+ {capitalize(languageNames.of(patient.preferred_locale ?? 'et'))} +
{ startTransition(async () => { const result = await fetchAction({ @@ -116,6 +121,9 @@ export default function ResultsTable({ + + + @@ -179,6 +187,11 @@ export default function ResultsTable({ }} /> + + {capitalize( + languageNames.of(result?.patient?.preferred_locale ?? 'et'), + )} + ; }) { - const { id: analysisResponseId } = await params; - const analysisResultDetails = await loadResult(Number(analysisResponseId)); + const { id: analysisOrderId } = await params; + const analysisResultDetails = await loadResult(Number(analysisOrderId)); if (!analysisResultDetails) { return null; @@ -28,7 +28,7 @@ async function AnalysisPage({ if (analysisResultDetails) { await createDoctorPageViewLog({ action: DoctorPageViewAction.VIEW_ANALYSIS_RESULTS, - recordKey: analysisResponseId, + recordKey: analysisOrderId, dataOwnerUserId: analysisResultDetails.patient.userId, }); } @@ -50,3 +50,5 @@ async function AnalysisPage({ export default DoctorGuard(AnalysisPage); const loadResult = cache(getAnalysisResultsForDoctor); + + diff --git a/app/home/(user)/(dashboard)/analysis-results/[id]/page.tsx b/app/home/(user)/(dashboard)/analysis-results/[id]/page.tsx new file mode 100644 index 0000000..a568eed --- /dev/null +++ b/app/home/(user)/(dashboard)/analysis-results/[id]/page.tsx @@ -0,0 +1,107 @@ +import Link from 'next/link'; + +import { ButtonTooltip } from '@kit/shared/components/ui/button-tooltip'; +import { pathsConfig } from '@kit/shared/config'; +import { Button } from '@kit/ui/button'; +import { PageBody, PageHeader } from '@kit/ui/page'; +import { Trans } from '@kit/ui/trans'; + +import { loadCurrentUserAccount } from '~/home/(user)/_lib/server/load-user-account'; +import { loadUserAnalysis } from '~/home/(user)/_lib/server/load-user-analysis'; +import { + PageViewAction, + createPageViewLog, +} from '~/lib/services/audit/pageView.service'; + +import Analysis from '../_components/analysis'; + +export default async function AnalysisResultsPage({ + params, +}: { + params: Promise<{ + id: string; + }>; +}) { + const account = await loadCurrentUserAccount(); + + const { id: analysisResponseId } = await params; + + const analysisResponse = await loadUserAnalysis(Number(analysisResponseId)); + + if (!account?.id || !analysisResponse) { + return null; + } + + await createPageViewLog({ + accountId: account.id, + action: PageViewAction.VIEW_ANALYSIS_RESULTS, + }); + + return ( + <> + + +
+
+

+ +

+

+ {analysisResponse?.elements && + analysisResponse.elements?.length > 0 ? ( + + ) : ( + + )} +

+
+ +
+
+

+ +

+
+ + +
+
+ {analysisResponse?.summary?.value && ( +
+ + + +

{analysisResponse.summary.value}

+
+ )} +
+ {analysisResponse.elements ? ( + analysisResponse.elements.map((element, index) => ( + + )) + ) : ( +
+ +
+ )} +
+
+ + ); +} diff --git a/app/home/(user)/(dashboard)/analysis-results/page.tsx b/app/home/(user)/(dashboard)/analysis-results/page.tsx deleted file mode 100644 index 1dd999c..0000000 --- a/app/home/(user)/(dashboard)/analysis-results/page.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import Link from 'next/link'; -import { redirect } from 'next/navigation'; - -import { loadCurrentUserAccount } from '@/app/home/(user)/_lib/server/load-user-account'; -import { createI18nServerInstance } from '@/lib/i18n/i18n.server'; -import { withI18n } from '@/lib/i18n/with-i18n'; - -import { Trans } from '@kit/ui/makerkit/trans'; -import { PageBody } from '@kit/ui/page'; -import { Button } from '@kit/ui/shadcn/button'; - -import { pathsConfig } from '@kit/shared/config'; - -import { getAnalysisElements } from '~/lib/services/analysis-element.service'; -import { - PageViewAction, - createPageViewLog, -} from '~/lib/services/audit/pageView.service'; -import { AnalysisOrder, getAnalysisOrders } from '~/lib/services/order.service'; -import { ButtonTooltip } from '@kit/shared/components/ui/button-tooltip'; - -import { loadUserAnalysis } from '../../_lib/server/load-user-analysis'; -import Analysis from './_components/analysis'; - -export const generateMetadata = async () => { - const i18n = await createI18nServerInstance(); - const title = i18n.t('analysis-results:pageTitle'); - - return { - title, - }; -}; - -async function AnalysisResultsPage() { - const account = await loadCurrentUserAccount(); - if (!account) { - throw new Error('Account not found'); - } - - const analysisResponses = await loadUserAnalysis(); - const analysisResponseElements = analysisResponses?.flatMap( - ({ elements }) => elements, - ); - - const analysisOrders = await getAnalysisOrders().catch(() => null); - - if (!analysisOrders) { - redirect(pathsConfig.auth.signIn); - } - - await createPageViewLog({ - accountId: account.id, - action: PageViewAction.VIEW_ANALYSIS_RESULTS, - }); - - const getAnalysisElementIds = (analysisOrders: AnalysisOrder[]) => [ - ...new Set(analysisOrders?.flatMap((order) => order.analysis_element_ids).filter(Boolean) as number[]), - ]; - - const analysisElementIds = getAnalysisElementIds(analysisOrders); - const analysisElements = await getAnalysisElements({ ids: analysisElementIds }); - - return ( - -
-
-

- -

-

- {analysisResponses && analysisResponses.length > 0 ? ( - - ) : ( - - )} -

-
- -
-
- {analysisOrders.length > 0 && analysisElements.length > 0 ? analysisOrders.map((analysisOrder) => { - const analysisResponse = analysisResponses?.find((response) => response.analysis_order_id === analysisOrder.id); - const analysisElementIds = getAnalysisElementIds([analysisOrder]); - const analysisElementsForOrder = analysisElements.filter((element) => analysisElementIds.includes(element.id)); - return ( -
-

- -

-
- - -
-
- {analysisElementsForOrder.length > 0 ? analysisElementsForOrder.map((analysisElement) => { - const results = analysisResponse?.elements.some((element) => element.analysis_element_original_id === analysisElement.analysis_id_original) - && analysisResponseElements?.find((element) => element.analysis_element_original_id === analysisElement.analysis_id_original); - if (!results) { - return ( - - ); - } - return ( - - ); - }) : ( -
- -
- )} -
-
- ); - }) : ( -
- -
- )} -
-
- ); -} - -export default withI18n(AnalysisResultsPage); diff --git a/app/home/(user)/_components/dashboard-cards.tsx b/app/home/(user)/_components/dashboard-cards.tsx index a24e465..a39e470 100644 --- a/app/home/(user)/_components/dashboard-cards.tsx +++ b/app/home/(user)/_components/dashboard-cards.tsx @@ -1,30 +1,28 @@ -import { Trans } from '@kit/ui/trans'; -import { - Card, - CardHeader, - CardDescription, - CardFooter, -} from '@kit/ui/card'; - import Link from 'next/link'; -import { Button } from '@kit/ui/button'; + import { ChevronRight, HeartPulse } from 'lucide-react'; +import { Button } from '@kit/ui/button'; +import { Card, CardDescription, CardFooter, CardHeader } from '@kit/ui/card'; +import { Trans } from '@kit/ui/trans'; + export default function DashboardCards() { return ( -
+
-
- +
+ @@ -33,10 +31,10 @@ export default function DashboardCards() {
- +
- +
diff --git a/app/home/(user)/_components/dashboard.tsx b/app/home/(user)/_components/dashboard.tsx index b10238c..65e6970 100644 --- a/app/home/(user)/_components/dashboard.tsx +++ b/app/home/(user)/_components/dashboard.tsx @@ -166,7 +166,7 @@ export default function Dashboard({ return ( <> -
+
{cards({ gender: params?.gender, age: params?.age, @@ -233,8 +233,11 @@ export default function Dashboard({ index, ) => { return ( -
-
+
+
{icon}
-
+
{title} @@ -253,16 +256,24 @@ export default function Dashboard({

-
+

{price}

{href ? ( - ) : ( - )} diff --git a/app/home/(user)/_components/home-mobile-navigation.tsx b/app/home/(user)/_components/home-mobile-navigation.tsx index 7ead53a..21de4e0 100644 --- a/app/home/(user)/_components/home-mobile-navigation.tsx +++ b/app/home/(user)/_components/home-mobile-navigation.tsx @@ -1,12 +1,16 @@ 'use client'; +import { useMemo } from 'react'; + import Link from 'next/link'; import { StoreCart } from '@medusajs/types'; -import { LogOut, Menu, ShoppingCart } from 'lucide-react'; +import { Cross, LogOut, Menu, Shield, ShoppingCart } from 'lucide-react'; +import { usePersonalAccountData } from '@kit/accounts/hooks/use-personal-account-data'; +import { ApplicationRoleEnum } from '@kit/accounts/types/accounts'; import { - featureFlagsConfig, + pathsConfig, personalAccountNavigationConfig, } from '@kit/shared/config'; import { useSignOut } from '@kit/supabase/hooks/use-sign-out'; @@ -15,7 +19,6 @@ import { DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, - DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@kit/ui/dropdown-menu'; @@ -23,14 +26,16 @@ import { If } from '@kit/ui/if'; import { Trans } from '@kit/ui/trans'; // home imports -import { HomeAccountSelector } from '../_components/home-account-selector'; import type { UserWorkspace } from '../_lib/server/load-user-workspace'; export function HomeMobileNavigation(props: { workspace: UserWorkspace; cart: StoreCart | null; }) { + const user = props.workspace.user; + const signOut = useSignOut(); + const { data: personalAccountData } = usePersonalAccountData(user.id); const Links = personalAccountNavigationConfig.routes.map((item, index) => { if ('children' in item) { @@ -51,7 +56,29 @@ export function HomeMobileNavigation(props: { } }); - const cartQuantityTotal = props.cart?.items?.reduce((acc, item) => acc + item.quantity, 0) ?? 0; + const hasTotpFactor = useMemo(() => { + const factors = user?.factors ?? []; + return factors.some( + (factor) => factor.factor_type === 'totp' && factor.status === 'verified', + ); + }, [user?.factors]); + + const isSuperAdmin = useMemo(() => { + const hasAdminRole = + personalAccountData?.application_role === ApplicationRoleEnum.SuperAdmin; + + return hasAdminRole && hasTotpFactor; + }, [user, personalAccountData, hasTotpFactor]); + + const isDoctor = useMemo(() => { + const hasDoctorRole = + personalAccountData?.application_role === ApplicationRoleEnum.Doctor; + + return hasDoctorRole && hasTotpFactor; + }, [user, personalAccountData, hasTotpFactor]); + + const cartQuantityTotal = + props.cart?.items?.reduce((acc, item) => acc + item.quantity, 0) ?? 0; const hasCartItems = cartQuantityTotal > 0; return ( @@ -61,22 +88,6 @@ export function HomeMobileNavigation(props: { - - - - - - - - - - - - {Links} + + + + + + + + Super Admin + + + + + + + + + + + + + + + + + signOut.mutateAsync()} /> diff --git a/app/home/(user)/_components/order-analyses-cards.tsx b/app/home/(user)/_components/order-analyses-cards.tsx index 23b88b5..3f2a72e 100644 --- a/app/home/(user)/_components/order-analyses-cards.tsx +++ b/app/home/(user)/_components/order-analyses-cards.tsx @@ -52,7 +52,7 @@ export default function OrderAnalysesCards({ } return ( -
+
{analyses.map(({ title, variant, diff --git a/app/home/(user)/_components/orders/order-items-table.tsx b/app/home/(user)/_components/orders/order-items-table.tsx index 096ad06..b1e4852 100644 --- a/app/home/(user)/_components/orders/order-items-table.tsx +++ b/app/home/(user)/_components/orders/order-items-table.tsx @@ -1,22 +1,32 @@ 'use client'; -import { Trans } from '@kit/ui/trans'; +import { useRouter } from 'next/navigation'; + +import { StoreOrderLineItem } from '@medusajs/types'; +import { formatDate } from 'date-fns'; +import { Eye } from 'lucide-react'; + +import { pathsConfig } from '@kit/shared/config'; +import { Button } from '@kit/ui/button'; import { Table, TableBody, - TableHead, - TableRow, - TableHeader, TableCell, + TableHead, + TableHeader, + TableRow, } from '@kit/ui/table'; -import { StoreOrderLineItem } from "@medusajs/types"; +import { Trans } from '@kit/ui/trans'; + import { AnalysisOrder } from '~/lib/services/order.service'; -import { formatDate } from 'date-fns'; -import { Eye } from 'lucide-react'; -import { useRouter } from 'next/navigation'; + import { logAnalysisResultsNavigateAction } from './actions'; -export default function OrderItemsTable({ items, title, analysisOrder }: { +export default function OrderItemsTable({ + items, + title, + analysisOrder, +}: { items: StoreOrderLineItem[]; title: string; analysisOrder: AnalysisOrder; @@ -29,11 +39,11 @@ export default function OrderItemsTable({ items, title, analysisOrder }: { const openAnalysisResults = async () => { await logAnalysisResultsNavigateAction(analysisOrder.medusa_order_id); - router.push(`/home/analysis-results`); - } + router.push(`${pathsConfig.app.analysisResults}/${analysisOrder.id}`); + }; return ( - +
@@ -45,13 +55,14 @@ export default function OrderItemsTable({ items, title, analysisOrder }: { - - + {items - .sort((a, b) => (a.created_at ?? "") > (b.created_at ?? "") ? -1 : 1) + .sort((a, b) => + (a.created_at ?? '') > (b.created_at ?? '') ? -1 : 1, + ) .map((orderItem) => ( @@ -64,23 +75,18 @@ export default function OrderItemsTable({ items, title, analysisOrder }: { {formatDate(orderItem.created_at, 'dd.MM.yyyy HH:mm')} - + - - - - + + ))}
- ) + ); } diff --git a/app/home/(user)/_lib/server/load-analysis-packages.ts b/app/home/(user)/_lib/server/load-analysis-packages.ts index ddbf14c..ca3fd5b 100644 --- a/app/home/(user)/_lib/server/load-analysis-packages.ts +++ b/app/home/(user)/_lib/server/load-analysis-packages.ts @@ -6,8 +6,8 @@ import { listRegions } from '@lib/data/regions'; import { getAnalysisElementMedusaProductIds } from '@/utils/medusa-product'; import type { StoreProduct } from '@medusajs/types'; import { loadCurrentUserAccount } from './load-user-account'; -import { AnalysisPackageWithVariant } from '~/components/select-analysis-package'; import { AccountWithParams } from '@/packages/features/accounts/src/server/api'; +import { AnalysisPackageWithVariant } from '@kit/shared/components/select-analysis-package'; async function countryCodesLoader() { const countryCodes = await listRegions().then((regions) => @@ -38,8 +38,11 @@ function userSpecificVariantLoader({ if (age >= 18 && age <= 29) { return '18-29'; } - if (age >= 30 && age <= 49) { - return '30-49'; + if (age >= 30 && age <= 39) { + return '30-39'; + } + if (age >= 40 && age <= 49) { + return '40-49'; } if (age >= 50 && age <= 59) { return '50-59'; diff --git a/app/home/(user)/_lib/server/load-user-analyses.ts b/app/home/(user)/_lib/server/load-user-analyses.ts new file mode 100644 index 0000000..388bfec --- /dev/null +++ b/app/home/(user)/_lib/server/load-user-analyses.ts @@ -0,0 +1,22 @@ +import { cache } from 'react'; + +import { createAccountsApi } from '@kit/accounts/api'; +import { UserAnalysis } from '@kit/accounts/types/accounts'; +import { getSupabaseServerClient } from '@kit/supabase/server-client'; + +export type UserAnalyses = Awaited>; + +/** + * @name loadUserAnalyses + * @description + * Load the user's analyses. It's a cached per-request function that fetches the user workspace data. + * It can be used across the server components to load the user workspace data. + */ +export const loadUserAnalyses = cache(analysesLoader); + +async function analysesLoader(): Promise { + const client = getSupabaseServerClient(); + const api = createAccountsApi(client); + + return api.getUserAnalyses(); +} diff --git a/app/home/(user)/_lib/server/load-user-analysis.ts b/app/home/(user)/_lib/server/load-user-analysis.ts index 52cd529..09efd46 100644 --- a/app/home/(user)/_lib/server/load-user-analysis.ts +++ b/app/home/(user)/_lib/server/load-user-analysis.ts @@ -1,7 +1,7 @@ import { cache } from 'react'; import { createAccountsApi } from '@kit/accounts/api'; -import { UserAnalysis } from '@kit/accounts/types/accounts'; +import { AnalysisResultDetails } from '@kit/accounts/types/accounts'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; export type UserAnalyses = Awaited>; @@ -9,14 +9,15 @@ export type UserAnalyses = Awaited>; /** * @name loadUserAnalysis * @description - * Load the user's analyses. It's a cached per-request function that fetches the user workspace data. - * It can be used across the server components to load the user workspace data. + * Load the user's analysis based on id. It's a cached per-request function that fetches the user's analysis data. */ export const loadUserAnalysis = cache(analysisLoader); -async function analysisLoader(): Promise { +async function analysisLoader( + analysisOrderId: number, +): Promise { const client = getSupabaseServerClient(); const api = createAccountsApi(client); - return api.getUserAnalysis(); + return api.getUserAnalysis(analysisOrderId); } diff --git a/lib/services/account.service.ts b/lib/services/account.service.ts index 2bd7350..22d0684 100644 --- a/lib/services/account.service.ts +++ b/lib/services/account.service.ts @@ -41,3 +41,43 @@ export async function getAccountAdmin({ return data as unknown as AccountWithMemberships; } + +export async function getDoctorAccounts() { + const { data } = await getSupabaseServerAdminClient() + .schema('medreport') + .from('accounts') + .select('id, email, name, last_name, preferred_locale') + .eq('is_personal_account', true) + .eq('application_role', 'doctor') + .throwOnError(); + + return data?.map(({ id, email, name, last_name, preferred_locale }) => ({ + id, + email, + name, + lastName: last_name, + preferredLocale: preferred_locale, + })); +} + +export async function getAssignedDoctorAccount(analysisOrderId: number) { + const { data: doctorUser } = await getSupabaseServerAdminClient() + .schema('medreport') + .from('doctor_analysis_feedback') + .select('doctor_user_id') + .eq('analysis_order_id', analysisOrderId) + .throwOnError(); + + const doctorData = doctorUser[0]; + if (!doctorData || !doctorData.doctor_user_id) { + return null; + } + + const { data } = await getSupabaseServerAdminClient() + .schema('medreport') + .from('accounts') + .select('email') + .eq('primary_owner_user_id', doctorData.doctor_user_id); + + return { email: data?.[0]?.email }; +} diff --git a/lib/services/audit/notificationEntries.service.ts b/lib/services/audit/notificationEntries.service.ts index fee0b75..f83a736 100644 --- a/lib/services/audit/notificationEntries.service.ts +++ b/lib/services/audit/notificationEntries.service.ts @@ -1,8 +1,10 @@ import { Database } from '@kit/supabase/database'; -import { getSupabaseServerClient } from '@kit/supabase/server-client'; +import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client'; export enum NotificationAction { DOCTOR_FEEDBACK_RECEIVED = 'DOCTOR_FEEDBACK_RECEIVED', + NEW_JOBS_ALERT = 'NEW_JOBS_ALERT', + PATIENT_RESULTS_RECEIVED_ALERT = 'PATIENT_RESULTS_RECEIVED_ALERT', } export const createNotificationLog = async ({ @@ -17,7 +19,7 @@ export const createNotificationLog = async ({ relatedRecordId?: string | number; }) => { try { - const supabase = getSupabaseServerClient(); + const supabase = getSupabaseServerAdminClient(); await supabase .schema('audit') @@ -30,6 +32,6 @@ export const createNotificationLog = async ({ }) .throwOnError(); } catch (error) { - console.error('Failed to insert doctor page view log', error); + console.error('Failed to insert doctor notification log', error); } }; diff --git a/lib/services/doctor-jobs.service.ts b/lib/services/doctor-jobs.service.ts new file mode 100644 index 0000000..2f61c00 --- /dev/null +++ b/lib/services/doctor-jobs.service.ts @@ -0,0 +1,32 @@ +import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client'; + +async function getAssignedOrderIds() { + const supabase = getSupabaseServerAdminClient(); + + const { data: assignedOrderIds } = await supabase + .schema('medreport') + .from('doctor_analysis_feedback') + .select('analysis_order_id') + .not('doctor_user_id', 'is', null) + .throwOnError(); + + return assignedOrderIds?.map((f) => f.analysis_order_id) || []; +} + +export async function getOpenJobAnalysisResponseIds() { + const supabase = getSupabaseServerAdminClient(); + const assignedIds = await getAssignedOrderIds(); + + let query = supabase + .schema('medreport') + .from('analysis_responses') + .select('id, analysis_order_id') + .order('created_at', { ascending: false }); + + if (assignedIds.length > 0) { + query = query.not('analysis_order_id', 'in', `(${assignedIds.join(',')})`); + } + + const { data: analysisResponses } = await query.throwOnError(); + return analysisResponses?.map(({ id }) => id) || []; +} diff --git a/lib/services/mailer.service.ts b/lib/services/mailer.service.ts index c902bad..b4a7ecc 100644 --- a/lib/services/mailer.service.ts +++ b/lib/services/mailer.service.ts @@ -1,50 +1,41 @@ 'use server'; -import { CompanySubmitData } from '@/lib/types/company'; -import { emailSchema } from '@/lib/validations/email.schema'; +import { toArray } from '@/lib/utils'; -import { renderDoctorSummaryReceivedEmail } from '@kit/email-templates'; import { getMailer } from '@kit/mailers'; import { enhanceAction } from '@kit/next/actions'; import { getLogger } from '@kit/shared/logger'; -export const sendDoctorSummaryCompletedEmail = async ( - language: string, - recipientName: string, - recipientEmail: string, - orderNr: string, - orderId: number, -) => { - const { html, subject } = await renderDoctorSummaryReceivedEmail({ - language, - recipientName, - recipientEmail, - orderNr, - orderId, - }); +import { emailSchema } from '~/lib/validations/email.schema'; - await sendEmail({ - subject, - html, - to: recipientEmail, - }); +type EmailTemplate = { + html: string; + subject: string; }; -export const sendCompanyOfferEmail = async ( - data: CompanySubmitData, - language: string, -) => { - const { renderCompanyOfferEmail } = await import('@kit/email-templates'); - const { html, subject } = await renderCompanyOfferEmail({ - language, - companyData: data, - }); +type EmailRenderer = (params: T) => Promise; - await sendEmail({ - subject, - html, - to: process.env.CONTACT_EMAIL || '', - }); +export const sendEmailFromTemplate = async ( + renderer: EmailRenderer, + templateParams: T, + recipients: string | string[], +) => { + const { html, subject } = await renderer(templateParams); + + const recipientsArray = toArray(recipients); + if (!recipientsArray.length) { + throw new Error('No valid email recipients provided'); + } + + const emailPromises = recipientsArray.map((email) => + sendEmail({ + subject, + html, + to: email, + }), + ); + + await Promise.all(emailPromises); }; export const sendEmail = enhanceAction( @@ -53,7 +44,7 @@ export const sendEmail = enhanceAction( const log = await getLogger(); if (!process.env.EMAIL_USER) { - log.error('Sending email failed, as no sender found in env.') + log.error('Sending email failed, as no sender was found in env.'); throw new Error('No email user configured'); } diff --git a/lib/services/medipost.service.ts b/lib/services/medipost.service.ts index a32b624..6f91e62 100644 --- a/lib/services/medipost.service.ts +++ b/lib/services/medipost.service.ts @@ -97,7 +97,7 @@ export async function getLatestPublicMessageListItem() { Action: MedipostAction.GetPublicMessageList, User: USER, Password: PASSWORD, - Sender: 'syndev', + Sender: RECIPIENT, // LastChecked (date+time) can be used here to get only messages since the last check - add when cron is created // MessageType check only for messages of certain type }, diff --git a/middleware.ts b/middleware.ts index 09aff36..1507e71 100644 --- a/middleware.ts +++ b/middleware.ts @@ -165,6 +165,20 @@ async function doctorMiddleware(request: NextRequest, response: NextResponse) { */ function getPatterns() { return [ + { + pattern: new URLPattern({ pathname: '/' }), + handler: async (req: NextRequest, res: NextResponse) => { + const { + data: { user }, + } = await getUser(req, res); + + if (user) { + return NextResponse.redirect( + new URL(pathsConfig.app.home, req.nextUrl.origin).href, + ); + } + }, + }, { pattern: new URLPattern({ pathname: '/admin/*?' }), handler: adminMiddleware, diff --git a/packages/database-webhooks/src/server/services/database-webhook-router.service.ts b/packages/database-webhooks/src/server/services/database-webhook-router.service.ts index a97d492..5abe3de 100644 --- a/packages/database-webhooks/src/server/services/database-webhook-router.service.ts +++ b/packages/database-webhooks/src/server/services/database-webhook-router.service.ts @@ -1,7 +1,20 @@ import { SupabaseClient } from '@supabase/supabase-js'; +import { + renderAllResultsReceivedEmail, + renderFirstResultsReceivedEmail, +} from '@kit/email-templates'; import { Database } from '@kit/supabase/database'; +import { + getAssignedDoctorAccount, + getDoctorAccounts, +} from '../../../../../lib/services/account.service'; +import { + NotificationAction, + createNotificationLog, +} from '../../../../../lib/services/audit/notificationEntries.service'; +import { sendEmailFromTemplate } from '../../../../../lib/services/mailer.service'; import { RecordChange, Tables } from '../record-change.type'; export function createDatabaseWebhookRouterService( @@ -42,6 +55,12 @@ class DatabaseWebhookRouterService { return this.handleAccountsWebhook(payload); } + case 'analysis_orders': { + const payload = body as RecordChange; + + return this.handleAnalysisOrdersWebhook(payload); + } + default: { return; } @@ -83,4 +102,69 @@ class DatabaseWebhookRouterService { return service.handleAccountDeletedWebhook(body.old_record); } } + + private async handleAnalysisOrdersWebhook( + body: RecordChange<'analysis_orders'>, + ) { + if (body.type === 'UPDATE' && body.record && body.old_record) { + const { record, old_record } = body; + + if (record.status === old_record.status) { + return; + } + + let action; + try { + const data = { + analysisOrderId: record.id, + language: 'et', + }; + + if (record.status === 'PARTIAL_ANALYSIS_RESPONSE') { + action = NotificationAction.NEW_JOBS_ALERT; + + const doctorAccounts = await getDoctorAccounts(); + const doctorEmails: string[] = doctorAccounts + .map(({ email }) => email) + .filter((email): email is string => !!email); + + await sendEmailFromTemplate( + renderFirstResultsReceivedEmail, + data, + doctorEmails, + ); + } else if (record.status === 'FULL_ANALYSIS_RESPONSE') { + action = NotificationAction.PATIENT_RESULTS_RECEIVED_ALERT; + const doctorAccount = await getAssignedDoctorAccount(record.id); + const assignedDoctorEmail = doctorAccount?.email; + + if (!assignedDoctorEmail) { + return; + } + + await sendEmailFromTemplate( + renderAllResultsReceivedEmail, + data, + assignedDoctorEmail, + ); + } + + if (action) { + await createNotificationLog({ + action, + status: 'SUCCESS', + relatedRecordId: record.id, + }); + } + } catch (e: any) { + if (action) + await createNotificationLog({ + action, + status: 'FAIL', + comment: e?.message, + relatedRecordId: record.id, + }); + } + } + } } diff --git a/packages/email-templates/src/emails/all-results-received.email.tsx b/packages/email-templates/src/emails/all-results-received.email.tsx new file mode 100644 index 0000000..0243fc4 --- /dev/null +++ b/packages/email-templates/src/emails/all-results-received.email.tsx @@ -0,0 +1,82 @@ +import { + Body, + Head, + Html, + Preview, + Tailwind, + Text, + render +} from '@react-email/components'; + +import { BodyStyle } from '../components/body-style'; +import CommonFooter from '../components/common-footer'; +import { EmailContent } from '../components/content'; +import { EmailButton } from '../components/email-button'; +import { EmailHeader } from '../components/header'; +import { EmailHeading } from '../components/heading'; +import { EmailWrapper } from '../components/wrapper'; +import { initializeEmailI18n } from '../lib/i18n'; + +export async function renderAllResultsReceivedEmail({ + language, + analysisOrderId, +}: { + language: string; + analysisOrderId: number; +}) { + const namespace = 'all-results-received-email'; + + const { t } = await initializeEmailI18n({ + language, + namespace: [namespace, 'common'], + }); + + const previewText = t(`${namespace}:previewText`); + + const subject = t(`${namespace}:subject`); + + const html = await render( + + + + + + {previewText} + + + + + + {previewText} + + + + + {t(`${namespace}:hello`)} + + + {t(`${namespace}:openOrdersHeading`)} + + + {t(`${namespace}:linkText`)} + + + + {t(`${namespace}:ifLinksDisabled`)}{' '} + {`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/analysis/${analysisOrderId}`} + + + + + + + , + ); + + return { + html, + subject, + }; +} diff --git a/packages/email-templates/src/emails/doctor-summary-received.email.tsx b/packages/email-templates/src/emails/doctor-summary-received.email.tsx index c9e4fae..69ce37e 100644 --- a/packages/email-templates/src/emails/doctor-summary-received.email.tsx +++ b/packages/email-templates/src/emails/doctor-summary-received.email.tsx @@ -19,16 +19,14 @@ import { initializeEmailI18n } from '../lib/i18n'; export async function renderDoctorSummaryReceivedEmail({ language, - recipientEmail, recipientName, orderNr, - orderId, + analysisOrderId, }: { language?: string; recipientName: string; - recipientEmail: string; orderNr: string; - orderId: number; + analysisOrderId: number; }) { const namespace = 'doctor-summary-received-email'; @@ -37,8 +35,6 @@ export async function renderDoctorSummaryReceivedEmail({ namespace: [namespace, 'common'], }); - const to = recipientEmail; - const previewText = t(`${namespace}:previewText`, { orderNr, }); @@ -73,13 +69,13 @@ export async function renderDoctorSummaryReceivedEmail({ {t(`${namespace}:linkText`, { orderNr })} {t(`${namespace}:ifButtonDisabled`)}{' '} - {`${process.env.NEXT_PUBLIC_SITE_URL}/home/order/${orderId}`} + {`${process.env.NEXT_PUBLIC_SITE_URL}/home/analysis-results/${analysisOrderId}`} @@ -92,6 +88,5 @@ export async function renderDoctorSummaryReceivedEmail({ return { html, subject, - to, }; } diff --git a/packages/email-templates/src/emails/first-results-received.email.tsx b/packages/email-templates/src/emails/first-results-received.email.tsx new file mode 100644 index 0000000..4f9f371 --- /dev/null +++ b/packages/email-templates/src/emails/first-results-received.email.tsx @@ -0,0 +1,86 @@ +import { + Body, + Head, + Html, + Preview, + Tailwind, + Text, + render, +} from '@react-email/components'; + +import { BodyStyle } from '../components/body-style'; +import CommonFooter from '../components/common-footer'; +import { EmailContent } from '../components/content'; +import { EmailButton } from '../components/email-button'; +import { EmailHeader } from '../components/header'; +import { EmailHeading } from '../components/heading'; +import { EmailWrapper } from '../components/wrapper'; +import { initializeEmailI18n } from '../lib/i18n'; + +export async function renderFirstResultsReceivedEmail({ + language, + analysisOrderId, +}: { + language: string; + analysisOrderId: number; +}) { + const namespace = 'first-results-received-email'; + + const { t } = await initializeEmailI18n({ + language, + namespace: [namespace, 'common'], + }); + + const previewText = t(`${namespace}:previewText`); + + const subject = t(`${namespace}:subject`); + + const html = await render( + + + + + + {previewText} + + + + + + {previewText} + + + + + {t(`${namespace}:hello`)} + + + {t(`${namespace}:resultsReceivedForOrders`)} + + + {t(`${namespace}:openOrdersHeading`)} + + + + {t(`${namespace}:linkText`)} + + + + {t(`${namespace}:ifLinksDisabled`)}{' '} + {`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/analysis/${analysisOrderId}`} + + + + + + + , + ); + + return { + html, + subject, + }; +} diff --git a/packages/email-templates/src/emails/new-jobs-available.email.tsx b/packages/email-templates/src/emails/new-jobs-available.email.tsx new file mode 100644 index 0000000..23ca3f4 --- /dev/null +++ b/packages/email-templates/src/emails/new-jobs-available.email.tsx @@ -0,0 +1,99 @@ +import { + Body, + Head, + Html, + Link, + Preview, + Tailwind, + Text, + render +} from '@react-email/components'; + +import { BodyStyle } from '../components/body-style'; +import CommonFooter from '../components/common-footer'; +import { EmailContent } from '../components/content'; +import { EmailHeader } from '../components/header'; +import { EmailHeading } from '../components/heading'; +import { EmailWrapper } from '../components/wrapper'; +import { initializeEmailI18n } from '../lib/i18n'; + +export async function renderNewJobsAvailableEmail({ + language, + analysisResponseIds, +}: { + language?: string; + analysisResponseIds: number[]; +}) { + const namespace = 'new-jobs-available-email'; + + const { t } = await initializeEmailI18n({ + language, + namespace: [namespace, 'common'], + }); + + const previewText = t(`${namespace}:previewText`, { + nr: analysisResponseIds.length, + }); + + const subject = t(`${namespace}:subject`, { + nr: analysisResponseIds.length, + }); + + const html = await render( + + + + + + {previewText} + + + + + + {previewText} + + + + + {t(`${namespace}:hello`)} + + + {t(`${namespace}:resultsReceivedForOrders`, { + nr: analysisResponseIds.length, + })} + + + {t(`${namespace}:openOrdersHeading`, { + nr: analysisResponseIds.length, + })} + +
    + {analysisResponseIds.map((analysisResponseId, index) => ( +
  • + + {t(`${namespace}:linkText`, { nr: index + 1 })} + +
  • + ))} +
+ + {t(`${namespace}:ifLinksDisabled`)}{' '} + {`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/open-jobs`} + + +
+
+ +
+ , + ); + + return { + html, + subject, + }; +} diff --git a/packages/email-templates/src/emails/otp.email.tsx b/packages/email-templates/src/emails/otp.email.tsx index ebb6986..ae6db76 100644 --- a/packages/email-templates/src/emails/otp.email.tsx +++ b/packages/email-templates/src/emails/otp.email.tsx @@ -71,7 +71,7 @@ export async function renderOtpEmail(props: Props) {
diff --git a/packages/email-templates/src/emails/synlab.email.tsx b/packages/email-templates/src/emails/synlab.email.tsx index 57f9f36..29ff7d5 100644 --- a/packages/email-templates/src/emails/synlab.email.tsx +++ b/packages/email-templates/src/emails/synlab.email.tsx @@ -9,12 +9,12 @@ import { } from '@react-email/components'; import { BodyStyle } from '../components/body-style'; +import CommonFooter from '../components/common-footer'; import { EmailContent } from '../components/content'; import { EmailHeader } from '../components/header'; import { EmailHeading } from '../components/heading'; import { EmailWrapper } from '../components/wrapper'; import { initializeEmailI18n } from '../lib/i18n'; -import CommonFooter from '../components/common-footer'; interface Props { analysisPackageName: string; @@ -31,7 +31,10 @@ export async function renderSynlabAnalysisPackageEmail(props: Props) { namespace: [namespace, 'common'], }); - const previewText = t(`${namespace}:previewText`); + const previewText = t(`${namespace}:previewText`, { + analysisPackageName: props.analysisPackageName, + }); + const subject = t(`${namespace}:subject`, { analysisPackageName: props.analysisPackageName, }); diff --git a/packages/email-templates/src/index.ts b/packages/email-templates/src/index.ts index 8407d1a..83e3021 100644 --- a/packages/email-templates/src/index.ts +++ b/packages/email-templates/src/index.ts @@ -4,3 +4,6 @@ export * from './emails/otp.email'; export * from './emails/company-offer.email'; export * from './emails/synlab.email'; export * from './emails/doctor-summary-received.email'; +export * from './emails/new-jobs-available.email'; +export * from './emails/first-results-received.email'; +export * from './emails/all-results-received.email'; diff --git a/packages/email-templates/src/locales/en/all-results-received-email.json b/packages/email-templates/src/locales/en/all-results-received-email.json new file mode 100644 index 0000000..c8e7c4b --- /dev/null +++ b/packages/email-templates/src/locales/en/all-results-received-email.json @@ -0,0 +1,8 @@ +{ + "previewText": "All analysis results have been received", + "subject": "All patient analysis results have been received", + "openOrdersHeading": "Review the results and prepare a summary:", + "linkText": "See results", + "ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.", + "hello": "Hello" +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/en/company-offer-email.json b/packages/email-templates/src/locales/en/company-offer-email.json new file mode 100644 index 0000000..b0cd165 --- /dev/null +++ b/packages/email-templates/src/locales/en/company-offer-email.json @@ -0,0 +1,8 @@ +{ + "subject": "New Company Join Request", + "previewText": "The company {{companyName}} is requesting a quote", + "companyName": "Company Name:", + "contactPerson": "Contact Person:", + "email": "Email:", + "phone": "Phone:" +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/en/first-results-received-email.json b/packages/email-templates/src/locales/en/first-results-received-email.json new file mode 100644 index 0000000..03693ff --- /dev/null +++ b/packages/email-templates/src/locales/en/first-results-received-email.json @@ -0,0 +1,9 @@ +{ + "previewText": "First analysis responses received", + "subject": "New job - first analysis responses received", + "resultsReceivedForOrders": "New job available to claim", + "openOrdersHeading": "See here:", + "linkText": "See results", + "ifLinksDisabled": "If the link does not work, you can see available jobs by copying this link into your browser.", + "hello": "Hello," +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/en/new-jobs-available-email.json b/packages/email-templates/src/locales/en/new-jobs-available-email.json new file mode 100644 index 0000000..e187b3c --- /dev/null +++ b/packages/email-templates/src/locales/en/new-jobs-available-email.json @@ -0,0 +1,9 @@ +{ + "previewText": "New jobs available", + "subject": "Please write a summary", + "resultsReceivedForOrders": "Please review the results and write a summary.", + "openOrdersHeading": "See here:", + "linkText": "Open job {{nr}}", + "ifLinksDisabled": "If the links do not work, you can see available jobs by copying this link into your browser.", + "hello": "Hello," +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/et/all-results-received-email.json b/packages/email-templates/src/locales/et/all-results-received-email.json new file mode 100644 index 0000000..a96c137 --- /dev/null +++ b/packages/email-templates/src/locales/et/all-results-received-email.json @@ -0,0 +1,8 @@ +{ + "previewText": "KΓ΅ik analΓΌΓΌside vastused on saabunud", + "subject": "Patsiendi kΓ΅ikide analΓΌΓΌside vastused on saabunud", + "openOrdersHeading": "Vaata tulemusi ja kirjuta kokkuvΓ΅te:", + "linkText": "Vaata tulemusi", + "ifLinksDisabled": "Kui link ei tΓΆΓΆta, nΓ€ed analΓΌΓΌsitulemusi sellelt aadressilt:", + "hello": "Tere" +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/et/first-results-received-email.json b/packages/email-templates/src/locales/et/first-results-received-email.json new file mode 100644 index 0000000..d82aa7d --- /dev/null +++ b/packages/email-templates/src/locales/et/first-results-received-email.json @@ -0,0 +1,9 @@ +{ + "previewText": "Saabusid esimesed analΓΌΓΌside vastused", + "subject": "Uus tΓΆΓΆ - saabusid esimesed analΓΌΓΌside vastused", + "resultsReceivedForOrders": "Patsiendile saabusid esimesed analΓΌΓΌside vastused.", + "openOrdersHeading": "Vaata siit:", + "linkText": "Vaata tulemusi", + "ifLinksDisabled": "Kui link ei tΓΆΓΆta, nΓ€ed analΓΌΓΌsitulemusi sellelt aadressilt:", + "hello": "Tere" +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/et/new-jobs-available-email.json b/packages/email-templates/src/locales/et/new-jobs-available-email.json new file mode 100644 index 0000000..eae44b8 --- /dev/null +++ b/packages/email-templates/src/locales/et/new-jobs-available-email.json @@ -0,0 +1,9 @@ +{ + "previewText": "Palun koosta kokkuvΓ΅te", + "subject": "Palun koosta kokkuvΓ΅te", + "resultsReceivedForOrders": "Palun vaata tulemused ΓΌle ja kirjuta kokkuvΓ΅te.", + "openOrdersHeading": "Vaata siit:", + "linkText": "TΓΆΓΆ {{nr}}", + "ifLinksDisabled": "Kui lingid ei tΓΆΓΆta, nΓ€ed vabasid tΓΆid sellelt aadressilt:", + "hello": "Tere" +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/ru/all-results-received-email.json b/packages/email-templates/src/locales/ru/all-results-received-email.json new file mode 100644 index 0000000..c8e7c4b --- /dev/null +++ b/packages/email-templates/src/locales/ru/all-results-received-email.json @@ -0,0 +1,8 @@ +{ + "previewText": "All analysis results have been received", + "subject": "All patient analysis results have been received", + "openOrdersHeading": "Review the results and prepare a summary:", + "linkText": "See results", + "ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.", + "hello": "Hello" +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/ru/common.json b/packages/email-templates/src/locales/ru/common.json index fc58e08..5e1ae9a 100644 --- a/packages/email-templates/src/locales/ru/common.json +++ b/packages/email-templates/src/locales/ru/common.json @@ -1,8 +1,8 @@ { "footer": { "lines1": "MedReport", - "lines2": "E-mail: info@medreport.ee", - "lines3": "Klienditugi: +372 5887 1517", + "lines2": "ЭлСктронная ΠΏΠΎΡ‡Ρ‚Π°: info@medreport.ee", + "lines3": "Π‘Π»ΡƒΠΆΠ±Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ: +372 5887 1517", "lines4": "www.medreport.ee" } } \ No newline at end of file diff --git a/packages/email-templates/src/locales/ru/company-offer-email.json b/packages/email-templates/src/locales/ru/company-offer-email.json index 3a39792..2678bdb 100644 --- a/packages/email-templates/src/locales/ru/company-offer-email.json +++ b/packages/email-templates/src/locales/ru/company-offer-email.json @@ -1,8 +1,8 @@ { - "subject": "Uus ettevΓ΅tte liitumispΓ€ring", - "previewText": "EttevΓ΅te {{companyName}} soovib pakkumist", - "companyName": "EttevΓ΅tte nimi:", - "contactPerson": "Kontaktisik:", - "email": "E-mail:", - "phone": "Telefon:" -} + "subject": "Новый запрос Π½Π° присоСдинСниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "previewText": "Компания {{companyName}} Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "companyName": "НазваниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ:", + "contactPerson": "ΠšΠΎΠ½Ρ‚Π°ΠΊΡ‚Π½ΠΎΠ΅ Π»ΠΈΡ†ΠΎ:", + "email": "ЭлСктронная ΠΏΠΎΡ‡Ρ‚Π°:", + "phone": "Π’Π΅Π»Π΅Ρ„ΠΎΠ½:" +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/ru/doctor-summary-received-email.json b/packages/email-templates/src/locales/ru/doctor-summary-received-email.json index e7efdc3..09beb43 100644 --- a/packages/email-templates/src/locales/ru/doctor-summary-received-email.json +++ b/packages/email-templates/src/locales/ru/doctor-summary-received-email.json @@ -1,8 +1,8 @@ { - "subject": "Saabus arsti kokkuvΓ΅tte tellimusele {{orderNr}}", - "previewText": "Arst on saatnud kokkuvΓ΅tte sinu analΓΌΓΌsitulemustele.", - "hello": "Tere, {{displayName}}", - "summaryReceivedForOrder": "Arst on koostanud selgitava kokkuvΓ΅tte sinu tellitud analΓΌΓΌsidele.", - "linkText": "Vaata kokkuvΓ΅tet", - "ifButtonDisabled": "Kui nupule vajutamine ei toimi, kopeeri see link oma brauserisse:" + "subject": "ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΎ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π²Ρ€Π°Ρ‡Π° ΠΏΠΎ Π·Π°ΠΊΠ°Π·Ρƒ {{orderNr}}", + "previewText": "Π’Ρ€Π°Ρ‡ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ» Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ вашим Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°ΠΌ Π°Π½Π°Π»ΠΈΠ·Π°.", + "hello": "ЗдравствуйтС, {{displayName}}", + "summaryReceivedForOrder": "Π’Ρ€Π°Ρ‡ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΠ» ΠΏΠΎΡΡΠ½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ Π·Π°ΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΌ Π²Π°ΠΌΠΈ Π°Π½Π°Π»ΠΈΠ·Π°ΠΌ.", + "linkText": "ΠŸΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅", + "ifButtonDisabled": "Если ΠΊΠ½ΠΎΠΏΠΊΠ° Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚, скопируйтС эту ссылку Π² ваш Π±Ρ€Π°ΡƒΠ·Π΅Ρ€:" } \ No newline at end of file diff --git a/packages/email-templates/src/locales/ru/first-results-received-email.json b/packages/email-templates/src/locales/ru/first-results-received-email.json new file mode 100644 index 0000000..6aff2c7 --- /dev/null +++ b/packages/email-templates/src/locales/ru/first-results-received-email.json @@ -0,0 +1,9 @@ +{ + "previewText": "First analysis responses received", + "subject": "New job - first analysis responses received", + "resultsReceivedForOrders": "New job available to claim", + "openOrdersHeading": "See here:", + "linkText": "See results", + "ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.", + "hello": "Hello," +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/ru/new-jobs-available-email.json b/packages/email-templates/src/locales/ru/new-jobs-available-email.json new file mode 100644 index 0000000..e187b3c --- /dev/null +++ b/packages/email-templates/src/locales/ru/new-jobs-available-email.json @@ -0,0 +1,9 @@ +{ + "previewText": "New jobs available", + "subject": "Please write a summary", + "resultsReceivedForOrders": "Please review the results and write a summary.", + "openOrdersHeading": "See here:", + "linkText": "Open job {{nr}}", + "ifLinksDisabled": "If the links do not work, you can see available jobs by copying this link into your browser.", + "hello": "Hello," +} \ No newline at end of file diff --git a/packages/email-templates/src/locales/ru/synlab-email.json b/packages/email-templates/src/locales/ru/synlab-email.json index fa16c20..6373b90 100644 --- a/packages/email-templates/src/locales/ru/synlab-email.json +++ b/packages/email-templates/src/locales/ru/synlab-email.json @@ -1,12 +1,12 @@ { - "subject": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}", - "previewText": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}", - "heading": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}", - "hello": "Tere {{personName}},", - "lines1": "Saatekiri {{analysisPackageName}} analΓΌΓΌsi uuringuteks on saadetud laborisse digitaalselt. Palun mine proove andma: Synlab - {{partnerLocationName}}", - "lines2": "Kui Teil ei ole vΓ΅imalik valitud asukohta minna proove andma, siis vΓ΅ite minna endale sobivasse proovivΓ΅tupunkti - vaata asukohti ja lahtiolekuaegasid.", - "lines3": "Soovituslik on proove anda pigem hommikul (enne 12:00) ning sΓΆΓΆmata ja joomata (vett vΓ΅ib juua).", - "lines4": "ProovivΓ΅tupunktis valige jΓ€rjekorrasΓΌsteemis: saatekirjad alt eriarsti saatekiri.", - "lines5": "Juhul kui tekkis lisakΓΌsimusi, siis vΓ΅tke julgelt ΓΌhendust.", - "lines6": "SYNLAB klienditoe telefon: 17123" + "subject": "Π’Π°Ρˆ Π·Π°ΠΊΠ°Π· Medreport ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ - {{analysisPackageName}}", + "previewText": "Π’Π°Ρˆ Π·Π°ΠΊΠ°Π· Medreport ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ - {{analysisPackageName}}", + "heading": "Π’Π°Ρˆ Π·Π°ΠΊΠ°Π· Medreport ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ - {{analysisPackageName}}", + "hello": "ЗдравствуйтС, {{personName}},", + "lines1": "НаправлСниС Π½Π° исслСдованиС {{analysisPackageName}} Π±Ρ‹Π»ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ Π² Π»Π°Π±ΠΎΡ€Π°Ρ‚ΠΎΡ€ΠΈΡŽ Π² Ρ†ΠΈΡ„Ρ€ΠΎΠ²ΠΎΠΌ Π²ΠΈΠ΄Π΅. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, сдайтС Π°Π½Π°Π»ΠΈΠ·Ρ‹: Synlab - {{partnerLocationName}}", + "lines2": "Если Π²Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΡΠ΅Ρ‚ΠΈΡ‚ΡŒ Π²Ρ‹Π±Ρ€Π°Π½Π½Ρ‹ΠΉ ΠΏΡƒΠ½ΠΊΡ‚ сдачи Π°Π½Π°Π»ΠΈΠ·ΠΎΠ², Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ Π² ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ для вас ΠΏΡƒΠ½ΠΊΡ‚ - ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ адрСса ΠΈ часы Ρ€Π°Π±ΠΎΡ‚Ρ‹.", + "lines3": "РСкомСндуСтся ΡΠ΄Π°Π²Π°Ρ‚ΡŒ Π°Π½Π°Π»ΠΈΠ·Ρ‹ ΡƒΡ‚Ρ€ΠΎΠΌ (Π΄ΠΎ 12:00) Π½Π°Ρ‚ΠΎΡ‰Π°ΠΊ (ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΈΡ‚ΡŒ Π²ΠΎΠ΄Ρƒ).", + "lines4": "Π’ ΠΏΡƒΠ½ΠΊΡ‚Π΅ сдачи Π°Π½Π°Π»ΠΈΠ·ΠΎΠ² Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π² систСмС ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ: направлСния -> Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡ‚ спСциалиста.", + "lines5": "Если Ρƒ вас Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ вопросы, смСло ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с Π½Π°ΠΌΠΈ.", + "lines6": "Π’Π΅Π»Π΅Ρ„ΠΎΠ½ слуТбы ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ SYNLAB: 17123" } \ No newline at end of file diff --git a/packages/features/accounts/src/hooks/use-update-account.ts b/packages/features/accounts/src/hooks/use-update-account.ts index 386efb8..a5c0814 100644 --- a/packages/features/accounts/src/hooks/use-update-account.ts +++ b/packages/features/accounts/src/hooks/use-update-account.ts @@ -5,12 +5,16 @@ import { useSupabase } from '@kit/supabase/hooks/use-supabase'; type UpdateData = Database['medreport']['Tables']['accounts']['Update']; -export function useUpdateAccountData(accountId: string) { +export function useUpdateAccountData(accountId?: string) { const client = useSupabase(); const mutationKey = ['account:data', accountId]; const mutationFn = async (data: UpdateData) => { + if (!accountId) { + return null; + } + const response = await client .schema('medreport') .from('accounts') diff --git a/packages/features/accounts/src/server/api.ts b/packages/features/accounts/src/server/api.ts index 0844138..336797d 100644 --- a/packages/features/accounts/src/server/api.ts +++ b/packages/features/accounts/src/server/api.ts @@ -2,7 +2,11 @@ import { SupabaseClient } from '@supabase/supabase-js'; import { Database } from '@kit/supabase/database'; -import { UserAnalysis } from '../types/accounts'; +import { + AnalysisResultDetails, + UserAnalysis, + UserAnalysisResponse, +} from '../types/accounts'; export type AccountWithParams = Database['medreport']['Tables']['accounts']['Row'] & { @@ -184,7 +188,49 @@ class AccountsApi { return response.data?.customer_id; } - async getUserAnalysis(): Promise { + async getUserAnalysis( + analysisOrderId: number, + ): Promise { + const authUser = await this.client.auth.getUser(); + const { data, error: userError } = authUser; + + if (userError) { + console.error('Failed to get user', userError); + throw userError; + } + + const { user } = data; + + const { data: analysisResponse } = await this.client + .schema('medreport') + .from('analysis_responses') + .select( + `*, + elements:analysis_response_elements(analysis_name,norm_status,response_value,unit,norm_lower_included,norm_upper_included,norm_lower,norm_upper,response_time), + order:analysis_order_id(medusa_order_id, status, created_at), + summary:analysis_order_id(doctor_analysis_feedback(*))`, + ) + .eq('user_id', user.id) + .eq('analysis_order_id', analysisOrderId) + .throwOnError(); + + const responseWithElements = analysisResponse?.[0]; + if (!responseWithElements) { + return null; + } + + const feedback = responseWithElements.summary.doctor_analysis_feedback?.[0]; + + return { + ...responseWithElements, + summary: + feedback?.status === 'COMPLETED' + ? responseWithElements.summary.doctor_analysis_feedback?.[0] + : null, + }; + } + + async getUserAnalyses(): Promise { const authUser = await this.client.auth.getUser(); const { data, error: userError } = authUser; diff --git a/packages/features/accounts/src/types/accounts.ts b/packages/features/accounts/src/types/accounts.ts index 2d54306..86d51f3 100644 --- a/packages/features/accounts/src/types/accounts.ts +++ b/packages/features/accounts/src/types/accounts.ts @@ -1,3 +1,5 @@ +import * as z from 'zod'; + import { Database } from '@kit/supabase/database'; export type UserAnalysisElement = @@ -15,3 +17,51 @@ export enum ApplicationRoleEnum { Doctor = 'doctor', SuperAdmin = 'super_admin', } + +export const ElementSchema = z.object({ + unit: z.string(), + norm_lower: z.number(), + norm_upper: z.number(), + norm_status: z.number(), + analysis_name: z.string(), + response_time: z.string(), + response_value: z.number(), + norm_lower_included: z.boolean(), + norm_upper_included: z.boolean(), +}); +export type Element = z.infer; + +export const OrderSchema = z.object({ + status: z.string(), + medusa_order_id: z.string(), + created_at: z.coerce.date(), +}); +export type Order = z.infer; + +export const SummarySchema = z.object({ + id: z.number(), + value: z.string(), + status: z.string(), + user_id: z.string(), + created_at: z.coerce.date(), + created_by: z.string(), + updated_at: z.coerce.date().nullable(), + updated_by: z.string(), + doctor_user_id: z.string().nullable(), + analysis_order_id: z.number(), +}); +export type Summary = z.infer; + +export const AnalysisResultDetailsSchema = z.object({ + id: z.number(), + analysis_order_id: z.number(), + order_number: z.string(), + order_status: z.string(), + user_id: z.string(), + created_at: z.coerce.date(), + updated_at: z.coerce.date().nullable(), + elements: z.array(ElementSchema), + order: OrderSchema, + summary: SummarySchema.nullable(), +}); +export type AnalysisResultDetails = z.infer; diff --git a/packages/features/auth/src/components/auth-layout.tsx b/packages/features/auth/src/components/auth-layout.tsx index 26289aa..2d83e61 100644 --- a/packages/features/auth/src/components/auth-layout.tsx +++ b/packages/features/auth/src/components/auth-layout.tsx @@ -7,7 +7,7 @@ export function AuthLayoutShell({ return (
; diff --git a/packages/features/doctor/src/lib/server/schema/doctor-analysis.schema.ts b/packages/features/doctor/src/lib/server/schema/doctor-analysis.schema.ts index 8758cbb..329d846 100644 --- a/packages/features/doctor/src/lib/server/schema/doctor-analysis.schema.ts +++ b/packages/features/doctor/src/lib/server/schema/doctor-analysis.schema.ts @@ -80,6 +80,7 @@ export const AccountSchema = z.object({ last_name: z.string().nullable(), id: z.string(), primary_owner_user_id: z.string(), + preferred_locale: z.string().nullable(), }); export type Account = z.infer; diff --git a/packages/features/doctor/src/lib/server/services/doctor-analysis.service.ts b/packages/features/doctor/src/lib/server/services/doctor-analysis.service.ts index 9bc637a..95790ba 100644 --- a/packages/features/doctor/src/lib/server/services/doctor-analysis.service.ts +++ b/packages/features/doctor/src/lib/server/services/doctor-analysis.service.ts @@ -2,10 +2,11 @@ import 'server-only'; import { isBefore } from 'date-fns'; +import { renderDoctorSummaryReceivedEmail } from '@kit/email-templates'; import { getFullName } from '@kit/shared/utils'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; -import { sendDoctorSummaryCompletedEmail } from '../../../../../../../lib/services/mailer.service'; +import { sendEmailFromTemplate } from '../../../../../../../lib/services/mailer.service'; import { AnalysisResultDetails } from '../schema/doctor-analysis-detail-view.schema'; import { AnalysisResponseBase, @@ -54,7 +55,7 @@ async function enrichAnalysisData(analysisResponses?: AnalysisResponseBase[]) { supabase .schema('medreport') .from('accounts') - .select('name, last_name, id, primary_owner_user_id') + .select('name, last_name, id, primary_owner_user_id, preferred_locale') .in('primary_owner_user_id', userIds), ]); @@ -67,7 +68,7 @@ async function enrichAnalysisData(analysisResponses?: AnalysisResponseBase[]) { ? await supabase .schema('medreport') .from('accounts') - .select('name, last_name, id, primary_owner_user_id') + .select('name, last_name, id, primary_owner_user_id, preferred_locale') .in('primary_owner_user_id', doctorUserIds) : { data: [] }; @@ -408,7 +409,7 @@ export async function getAnalysisResultsForDoctor( .schema('medreport') .from('accounts') .select( - `primary_owner_user_id, id, name, last_name, personal_code, phone, email, + `primary_owner_user_id, id, name, last_name, personal_code, phone, email, preferred_locale, account_params(height,weight)`, ) .eq('is_personal_account', true) @@ -472,6 +473,7 @@ export async function getAnalysisResultsForDoctor( personal_code, phone, account_params, + preferred_locale, } = accountWithParams[0]; const analysisResponseElementsWithPreviousData = []; @@ -503,6 +505,7 @@ export async function getAnalysisResultsForDoctor( }, doctorFeedback: doctorFeedback?.[0], patient: { + preferred_locale, userId: primary_owner_user_id, accountId, firstName: name, @@ -638,7 +641,7 @@ export async function submitFeedback( } if (status === 'COMPLETED') { - const [{ data: recipient }, { data: medusaOrderIds }] = await Promise.all([ + const [{ data: recipient }, { data: analysisOrder }] = await Promise.all([ supabase .schema('medreport') .from('accounts') @@ -653,24 +656,33 @@ export async function submitFeedback( .eq('id', analysisOrderId) .limit(1) .throwOnError(), + supabase + .schema('medreport') + .from('analysis_orders') + .update({ status: 'COMPLETED' }) + .eq('id', analysisOrderId) + .throwOnError(), ]); if (!recipient?.[0]?.email) { throw new Error('Could not find user email.'); } - if (!medusaOrderIds?.[0]?.id) { + if (!analysisOrder?.[0]?.id) { throw new Error('Could not retrieve order.'); } const { preferred_locale, name, last_name, email } = recipient[0]; - await sendDoctorSummaryCompletedEmail( - preferred_locale ?? 'et', - getFullName(name, last_name), + await sendEmailFromTemplate( + renderDoctorSummaryReceivedEmail, + { + language: preferred_locale ?? 'et', + recipientName: getFullName(name, last_name), + orderNr: analysisOrder?.[0]?.medusa_order_id ?? '', + analysisOrderId: analysisOrder[0].id, + }, email, - medusaOrderIds?.[0]?.medusa_order_id ?? '', - medusaOrderIds[0].id, ); } diff --git a/packages/shared/src/components/select-analysis-packages.tsx b/packages/shared/src/components/select-analysis-packages.tsx index 2206676..cdfb9e1 100644 --- a/packages/shared/src/components/select-analysis-packages.tsx +++ b/packages/shared/src/components/select-analysis-packages.tsx @@ -1,6 +1,8 @@ import { Trans } from '@kit/ui/trans'; -import SelectAnalysisPackage, { AnalysisPackageWithVariant } from './select-analysis-package'; +import SelectAnalysisPackage, { + AnalysisPackageWithVariant, +} from './select-analysis-package'; export default function SelectAnalysisPackages({ analysisPackages, @@ -10,11 +12,16 @@ export default function SelectAnalysisPackages({ countryCode: string; }) { return ( -
- {analysisPackages.length > 0 ? analysisPackages.map( - (analysisPackage) => ( - - )) : ( +
+ {analysisPackages.length > 0 ? ( + analysisPackages.map((analysisPackage) => ( + + )) + ) : (

diff --git a/packages/shared/src/config/personal-account-navigation.config.tsx b/packages/shared/src/config/personal-account-navigation.config.tsx index 521ba0a..ea5f2da 100644 --- a/packages/shared/src/config/personal-account-navigation.config.tsx +++ b/packages/shared/src/config/personal-account-navigation.config.tsx @@ -35,12 +35,6 @@ const routes = [ Icon: , end: true, }, - { - label: 'common:routes.analysisResults', - path: pathsConfig.app.analysisResults, - Icon: , - end: true, - }, { label: 'common:routes.orderAnalysisPackage', path: pathsConfig.app.orderAnalysisPackage, diff --git a/packages/shared/src/hooks/index.ts b/packages/shared/src/hooks/index.ts index f132daf..95e4bfd 100644 --- a/packages/shared/src/hooks/index.ts +++ b/packages/shared/src/hooks/index.ts @@ -1 +1,2 @@ export * from './use-csrf-token'; +export * from './use-current-locale-language-names'; diff --git a/packages/shared/src/hooks/use-current-locale-language-names.ts b/packages/shared/src/hooks/use-current-locale-language-names.ts new file mode 100644 index 0000000..5016e6f --- /dev/null +++ b/packages/shared/src/hooks/use-current-locale-language-names.ts @@ -0,0 +1,17 @@ +import { useMemo } from 'react'; + +import { useTranslation } from 'react-i18next'; + +function useLanguageName(currentLanguage: string) { + return useMemo(() => { + return new Intl.DisplayNames([currentLanguage], { + type: 'language', + }); + }, [currentLanguage]); +} + +export function useCurrentLocaleLanguageNames() { + const { i18n } = useTranslation(); + const { language: currentLanguage } = i18n; + return useLanguageName(currentLanguage); +} diff --git a/packages/ui/src/makerkit/language-selector.tsx b/packages/ui/src/makerkit/language-selector.tsx index 59f07d0..f7542f0 100644 --- a/packages/ui/src/makerkit/language-selector.tsx +++ b/packages/ui/src/makerkit/language-selector.tsx @@ -40,7 +40,7 @@ export function LanguageSelector({ }, [currentLanguage]); const userId = user?.id; - const updateAccountMutation = useUpdateAccountData(userId!); + const updateAccountMutation = useUpdateAccountData(userId); const revalidateUserDataQuery = useRevalidatePersonalAccountDataQuery(); const updateLanguagePreference = async ( @@ -52,6 +52,10 @@ export function LanguageSelector({ onChange(locale); } + if (!userId) { + return i18n.changeLanguage(locale); + } + const promise = updateAccountMutation .mutateAsync({ preferred_locale: locale, diff --git a/packages/ui/src/makerkit/marketing/header.tsx b/packages/ui/src/makerkit/marketing/header.tsx index 1489ef2..219c636 100644 --- a/packages/ui/src/makerkit/marketing/header.tsx +++ b/packages/ui/src/makerkit/marketing/header.tsx @@ -1,5 +1,7 @@ -import { cn } from '../../lib/utils'; import { LanguageSelector } from '@kit/ui/language-selector'; + +import { cn } from '../../lib/utils'; + interface HeaderProps extends React.HTMLAttributes { logo?: React.ReactNode; navigation?: React.ReactNode; @@ -22,11 +24,16 @@ export const Header: React.FC = function ({ {...props} >
-
-
{logo}
-
{navigation}
- -
{actions}
+
+
{logo}
+
{navigation}
+ +
+
+ +
+ {actions} +
diff --git a/packages/ui/src/makerkit/page.tsx b/packages/ui/src/makerkit/page.tsx index e089171..7a4ee42 100644 --- a/packages/ui/src/makerkit/page.tsx +++ b/packages/ui/src/makerkit/page.tsx @@ -42,7 +42,7 @@ function PageWithSidebar(props: PageProps) { > {MobileNavigation} -
+
{Children}
@@ -58,7 +58,7 @@ export function PageMobileNavigation( return (
diff --git a/public/locales/en/account.json b/public/locales/en/account.json index eab22ac..1a324fc 100644 --- a/public/locales/en/account.json +++ b/public/locales/en/account.json @@ -128,5 +128,6 @@ "updateRoleLoading": "Updating role...", "updatePreferredLocaleSuccess": "Language preference updated", "updatePreferredLocaleError": "Language preference update failed", - "updatePreferredLocaleLoading": "Updating language preference..." + "updatePreferredLocaleLoading": "Updating language preference...", + "doctorAnalysisSummary": "Doctor's summary" } \ No newline at end of file diff --git a/public/locales/en/analysis-results.json b/public/locales/en/analysis-results.json index 9f6a491..571b1fb 100644 --- a/public/locales/en/analysis-results.json +++ b/public/locales/en/analysis-results.json @@ -12,5 +12,6 @@ "normal": "Normal range" } }, - "orderTitle": "Order number {{orderNumber}}" + "orderTitle": "Order number {{orderNumber}}", + "view": "View results" } \ No newline at end of file diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 2e28960..a7084fe 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -116,5 +116,6 @@ "confirm": "Confirm", "previous": "Previous", "next": "Next", - "invalidDataError": "Invalid data submitted" + "invalidDataError": "Invalid data submitted", + "language": "Language" } \ No newline at end of file diff --git a/public/locales/en/doctor.json b/public/locales/en/doctor.json index 4f6b339..8997f4b 100644 --- a/public/locales/en/doctor.json +++ b/public/locales/en/doctor.json @@ -17,6 +17,7 @@ "assignedTo": "Doctor", "resultsStatus": "Analysis results", "waitingForNr": "Waiting for {{nr}}", + "language": "Preferred language", "responsesReceived": "Results complete" }, "otherPatients": "Other patients", diff --git a/public/locales/et/account.json b/public/locales/et/account.json index 7c6e5cd..b268146 100644 --- a/public/locales/et/account.json +++ b/public/locales/et/account.json @@ -151,5 +151,6 @@ "updateRoleLoading": "Rolli uuendatakse...", "updatePreferredLocaleSuccess": "Eelistatud keel uuendatud", "updatePreferredLocaleError": "Eelistatud keele uuendamine ei Γ΅nnestunud", - "updatePreferredLocaleLoading": "Eelistatud keelt uuendatakse..." + "updatePreferredLocaleLoading": "Eelistatud keelt uuendatakse...", + "doctorAnalysisSummary": "Arsti kokkuvΓ΅te analΓΌΓΌsitulemuste kohta" } \ No newline at end of file diff --git a/public/locales/et/analysis-results.json b/public/locales/et/analysis-results.json index 6334d60..9efe9bd 100644 --- a/public/locales/et/analysis-results.json +++ b/public/locales/et/analysis-results.json @@ -12,5 +12,6 @@ "normal": "Normaalne vahemik" } }, - "orderTitle": "Tellimus {{orderNumber}}" + "orderTitle": "Tellimus {{orderNumber}}", + "view": "Vaata tulemusi" } \ No newline at end of file diff --git a/public/locales/et/common.json b/public/locales/et/common.json index 70e6ec6..ed0e02a 100644 --- a/public/locales/et/common.json +++ b/public/locales/et/common.json @@ -136,5 +136,6 @@ "confirm": "Kinnita", "previous": "Eelmine", "next": "JΓ€rgmine", - "invalidDataError": "Vigased andmed" + "invalidDataError": "Vigased andmed", + "language": "Keel" } diff --git a/public/locales/et/doctor.json b/public/locales/et/doctor.json index e307ff8..180194b 100644 --- a/public/locales/et/doctor.json +++ b/public/locales/et/doctor.json @@ -17,6 +17,7 @@ "assignedTo": "Arst", "resultsStatus": "AnalΓΌΓΌsitulemused", "waitingForNr": "Ootel {{nr}}", + "language": "Patsiendi keel", "responsesReceived": "Tulemused koos" }, "otherPatients": "Muud patsiendid", diff --git a/public/locales/ru/account.json b/public/locales/ru/account.json index 11125e1..c26b6f9 100644 --- a/public/locales/ru/account.json +++ b/public/locales/ru/account.json @@ -1,132 +1,155 @@ { - "accountTabLabel": "Account Settings", - "accountTabDescription": "Manage your account settings", - "homePage": "Home", - "billingTab": "Billing", - "settingsTab": "Settings", - "multiFactorAuth": "Multi-Factor Authentication", - "multiFactorAuthDescription": "Set up Multi-Factor Authentication method to further secure your account", - "updateProfileSuccess": "Profile successfully updated", - "updateProfileError": "Encountered an error. Please try again", - "updatePasswordSuccess": "Password update request successful", - "updatePasswordSuccessMessage": "Your password has been successfully updated!", - "updatePasswordError": "Encountered an error. Please try again", - "updatePasswordLoading": "Updating password...", - "updateProfileLoading": "Updating profile...", - "name": "Your Name", - "nameDescription": "Update your name to be displayed on your profile", - "emailLabel": "Email Address", - "accountImage": "Your Profile Picture", - "accountImageDescription": "Please choose a photo to upload as your profile picture.", - "profilePictureHeading": "Upload a Profile Picture", - "profilePictureSubheading": "Choose a photo to upload as your profile picture.", - "updateProfileSubmitLabel": "Update Profile", - "updatePasswordCardTitle": "Update your Password", - "updatePasswordCardDescription": "Update your password to keep your account secure.", - "currentPassword": "Current Password", - "newPassword": "New Password", - "repeatPassword": "Repeat New Password", - "repeatPasswordDescription": "Please repeat your new password to confirm it", - "yourPassword": "Your Password", - "updatePasswordSubmitLabel": "Update Password", - "updateEmailCardTitle": "Update your Email", - "updateEmailCardDescription": "Update your email address you use to login to your account", - "newEmail": "Your New Email", - "repeatEmail": "Repeat Email", - "updateEmailSubmitLabel": "Update Email Address", - "updateEmailSuccess": "Email update request successful", - "updateEmailSuccessMessage": "We sent you an email to confirm your new email address. Please check your inbox and click on the link to confirm your new email address.", - "updateEmailLoading": "Updating your email...", - "updateEmailError": "Email not updated. Please try again", - "passwordNotMatching": "Passwords do not match. Make sure you're using the correct password", - "emailNotMatching": "Emails do not match. Make sure you're using the correct email", - "passwordNotChanged": "Your password has not changed", - "emailsNotMatching": "Emails do not match. Make sure you're using the correct email", - "cannotUpdatePassword": "You cannot update your password because your account is not linked to any.", - "setupMfaButtonLabel": "Setup a new Factor", - "multiFactorSetupErrorHeading": "Setup Failed", - "multiFactorSetupErrorDescription": "Sorry, there was an error while setting up your factor. Please try again.", - "multiFactorAuthHeading": "Secure your account with Multi-Factor Authentication", - "multiFactorModalHeading": "Use your authenticator app to scan the QR code below. Then enter the code generated.", - "factorNameLabel": "A memorable name to identify this factor", - "factorNameHint": "Use an easy-to-remember name to easily identify this factor in the future. Ex. iPhone 14", - "factorNameSubmitLabel": "Set factor name", - "unenrollTooltip": "Unenroll this factor", - "unenrollingFactor": "Unenrolling factor...", - "unenrollFactorSuccess": "Factor successfully unenrolled", - "unenrollFactorError": "Unenrolling factor failed", - "factorsListError": "Error loading factors list", - "factorsListErrorDescription": "Sorry, we couldn't load the factors list. Please try again.", - "factorName": "Factor Name", - "factorType": "Type", - "factorStatus": "Status", - "mfaEnabledSuccessTitle": "Multi-Factor authentication is enabled", - "mfaEnabledSuccessDescription": "Congratulations! You have successfully enrolled in the multi factor authentication process. You will now be able to access your account with a combination of your password and an authentication code sent to your phone number.", - "verificationCode": "Verification Code", - "addEmailAddress": "Add Email address", - "verifyActivationCodeDescription": "Enter the 6-digit code generated by your authenticator app in the field above", - "loadingFactors": "Loading factors...", - "enableMfaFactor": "Enable Factor", - "disableMfaFactor": "Disable Factor", - "qrCodeErrorHeading": "QR Code Error", - "qrCodeErrorDescription": "Sorry, we weren't able to generate the QR code", - "multiFactorSetupSuccess": "Factor successfully enrolled", - "submitVerificationCode": "Submit Verification Code", - "mfaEnabledSuccessAlert": "Multi-Factor authentication is enabled", - "verifyingCode": "Verifying code...", - "invalidVerificationCodeHeading": "Invalid Verification Code", - "invalidVerificationCodeDescription": "The verification code you entered is invalid. Please try again.", - "unenrollFactorModalHeading": "Unenroll Factor", - "unenrollFactorModalDescription": "You're about to unenroll this factor. You will not be able to use it to login to your account.", - "unenrollFactorModalBody": "You're about to unenroll this factor. You will not be able to use it to login to your account.", - "unenrollFactorModalButtonLabel": "Yes, unenroll factor", - "selectFactor": "Choose a factor to verify your identity", - "disableMfa": "Disable Multi-Factor Authentication", - "disableMfaButtonLabel": "Disable MFA", - "confirmDisableMfaButtonLabel": "Yes, disable MFA", - "disablingMfa": "Disabling Multi-Factor Authentication. Please wait...", - "disableMfaSuccess": "Multi-Factor Authentication successfully disabled", - "disableMfaError": "Sorry, we encountered an error. MFA has not been disabled.", - "sendingEmailVerificationLink": "Sending Email...", - "sendEmailVerificationLinkSuccess": "Verification link successfully sent", - "sendEmailVerificationLinkError": "Sorry, we weren't able to send you the email", - "sendVerificationLinkSubmitLabel": "Send Verification Link", - "sendVerificationLinkSuccessLabel": "Email sent! Check your Inbox", - "verifyEmailAlertHeading": "Please verify your email to enable MFA", - "verificationLinkAlertDescription": "Your email is not yet verified. Please verify your email to be able to set up Multi-Factor Authentication.", - "authFactorName": "Factor Name (optional)", - "authFactorNameHint": "Assign a name that helps you remember the phone number used", - "loadingUser": "Loading user details. Please wait...", - "linkPhoneNumber": "Link Phone Number", - "dangerZone": "Danger Zone", - "dangerZoneDescription": "Some actions cannot be undone. Please be careful.", - "deleteAccount": "Delete your Account", - "deletingAccount": "Deleting account. Please wait...", - "deleteAccountDescription": "This will delete your account and the accounts you own. Furthermore, we will immediately cancel any active subscriptions. This action cannot be undone.", - "deleteProfileConfirmationInputLabel": "Type DELETE to confirm", - "deleteAccountErrorHeading": "Sorry, we couldn't delete your account", - "needsReauthentication": "Reauthentication Required", - "needsReauthenticationDescription": "You need to reauthenticate to change your password. Please sign out and sign in again to change your password.", - "language": "Language", - "languageDescription": "Choose your preferred language", - "noTeamsYet": "You don't have any teams yet.", - "createTeam": "Create a team to get started.", - "createTeamButtonLabel": "Create a Team", - "createCompanyAccount": "Create Company Account", - "updateConsentSuccess": "Consent successfully updated", - "updateConsentError": "Encountered an error. Please try again", - "updateConsentLoading": "Updating consent...", + "accountTabLabel": "Настройки Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "accountTabDescription": "УправляйтС настройками вашСго Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "homePage": "Главная", + "billingTab": "ΠžΠΏΠ»Π°Ρ‚Π°", + "settingsTab": "Настройки", + "multiFactorAuth": "ΠœΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½Π°Ρ аутСнтификация", + "multiFactorAuthDescription": "НастройтС ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΌΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½ΠΎΠΉ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ для Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ Π·Π°Ρ‰ΠΈΡ‚Ρ‹ вашСго Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "updateProfileSuccess": "ΠŸΡ€ΠΎΡ„ΠΈΠ»ΡŒ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½", + "updateProfileError": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "updatePasswordSuccess": "Запрос Π½Π° ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ пароля Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ", + "updatePasswordSuccessMessage": "Π’Π°Ρˆ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π±Ρ‹Π» ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½!", + "updatePasswordError": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "updatePasswordLoading": "ОбновлСниС пароля...", + "updateProfileLoading": "ОбновлСниС профиля...", + "name": "Π’Π°ΡˆΠ΅ имя", + "nameDescription": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ вашС имя, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ Π² ΠΏΡ€ΠΎΡ„ΠΈΠ»Π΅", + "emailLabel": "АдрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "accountImage": "Π’Π°ΡˆΠ° фотография профиля", + "accountImageDescription": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ„ΠΎΡ‚ΠΎ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π² качСствС изобраТСния профиля.", + "profilePictureHeading": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Ρ„ΠΎΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΡŽ профиля", + "profilePictureSubheading": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ„ΠΎΡ‚ΠΎ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π² качСствС изобраТСния профиля.", + "updateProfileSubmitLabel": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΡ„ΠΈΠ»ΡŒ", + "updatePasswordCardTitle": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ ваш ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "updatePasswordCardDescription": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ваш Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Π² бСзопасности.", + "currentPassword": "Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "newPassword": "Новый ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "repeatPassword": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚Π΅ Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "repeatPasswordDescription": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚Π΅ Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ для подтвСрТдСния", + "yourPassword": "Π’Π°Ρˆ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "updatePasswordSubmitLabel": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "updateEmailCardTitle": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ Π²Π°ΡˆΡƒ ΠΏΠΎΡ‡Ρ‚Ρƒ", + "updateEmailCardDescription": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ для Π²Ρ…ΠΎΠ΄Π° Π² Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "newEmail": "Новый адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "repeatEmail": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚Π΅ адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "updateEmailSubmitLabel": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "updateEmailSuccess": "Запрос Π½Π° ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΡ‡Ρ‚Ρ‹ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ", + "updateEmailSuccessMessage": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ письмо для подтвСрТдСния Π½ΠΎΠ²ΠΎΠ³ΠΎ адрСса. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ ΠΏΠΎΡ‡Ρ‚Ρƒ ΠΈ ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ ссылкС для подтвСрТдСния.", + "updateEmailLoading": "ОбновлСниС ΠΏΠΎΡ‡Ρ‚Ρ‹...", + "updateEmailError": "ΠŸΠΎΡ‡Ρ‚Π° Π½Π΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "passwordNotMatching": "ΠŸΠ°Ρ€ΠΎΠ»ΠΈ Π½Π΅ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚. Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "emailNotMatching": "АдрСса элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹ Π½Π΅ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚. Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ адрСс", + "passwordNotChanged": "Π’Π°Ρˆ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π½Π΅ Π±Ρ‹Π» ΠΈΠ·ΠΌΠ΅Π½Π΅Π½", + "emailsNotMatching": "АдрСса элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹ Π½Π΅ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚. Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ адрСс", + "cannotUpdatePassword": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ваш Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Π½Π΅ связан Π½ΠΈ с ΠΎΠ΄Π½ΠΈΠΌ.", + "setupMfaButtonLabel": "ΠΠ°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ Ρ„Π°ΠΊΡ‚ΠΎΡ€", + "multiFactorSetupErrorHeading": "Π‘Π±ΠΎΠΉ настройки", + "multiFactorSetupErrorDescription": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ настройкС Ρ„Π°ΠΊΡ‚ΠΎΡ€Π°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "multiFactorAuthHeading": "Π—Π°Ρ‰ΠΈΡ‚ΠΈΡ‚Π΅ ваш Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½ΠΎΠΉ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ", + "multiFactorModalHeading": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅-Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ для сканирования QR-ΠΊΠΎΠ΄Π° Π½ΠΈΠΆΠ΅, Π·Π°Ρ‚Π΅ΠΌ Π²Π²Π΅Π΄ΠΈΡ‚Π΅ сгСнСрированный ΠΊΠΎΠ΄.", + "factorNameLabel": "Π—Π°ΠΏΠΎΠΌΠΈΠ½Π°ΡŽΡ‰Π΅Π΅ΡΡ имя для ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ этого Ρ„Π°ΠΊΡ‚ΠΎΡ€Π°", + "factorNameHint": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ простоС для запоминания имя, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π»Π΅Π³ΠΊΠΎ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ„Π°ΠΊΡ‚ΠΎΡ€ Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ. ΠŸΡ€ΠΈΠΌΠ΅Ρ€: iPhone 14", + "factorNameSubmitLabel": "Π—Π°Π΄Π°Ρ‚ΡŒ имя Ρ„Π°ΠΊΡ‚ΠΎΡ€Π°", + "unenrollTooltip": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Ρ„Π°ΠΊΡ‚ΠΎΡ€", + "unenrollingFactor": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΊΡ‚ΠΎΡ€Π°...", + "unenrollFactorSuccess": "Π€Π°ΠΊΡ‚ΠΎΡ€ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΡƒΠ΄Π°Π»Π΅Π½", + "unenrollFactorError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Ρ„Π°ΠΊΡ‚ΠΎΡ€", + "factorsListError": "Ошибка Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ списка Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΎΠ²", + "factorsListErrorDescription": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ список Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΎΠ². ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "factorName": "Имя Ρ„Π°ΠΊΡ‚ΠΎΡ€Π°", + "factorType": "Π’ΠΈΠΏ", + "factorStatus": "Бтатус", + "mfaEnabledSuccessTitle": "ΠœΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½Π°Ρ аутСнтификация Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π°", + "mfaEnabledSuccessDescription": "ΠŸΠΎΠ·Π΄Ρ€Π°Π²Π»ΡΠ΅ΠΌ! Π’Ρ‹ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΠΈ ΠΌΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½ΡƒΡŽ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡŽ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ смоТСтС Π²Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π² Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΠΈ пароля ΠΈ ΠΊΠΎΠ΄Π° подтвСрТдСния, ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π½ΠΎΠ³ΠΎ Π½Π° ваш Π½ΠΎΠΌΠ΅Ρ€ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π°.", + "verificationCode": "Код подтвСрТдСния", + "addEmailAddress": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "verifyActivationCodeDescription": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ 6-Π·Π½Π°Ρ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, сгСнСрированный вашим ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ-Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΎΠΌ, Π² ΠΏΠΎΠ»Π΅ Π²Ρ‹ΡˆΠ΅", + "loadingFactors": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΎΠ²...", + "enableMfaFactor": "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„Π°ΠΊΡ‚ΠΎΡ€", + "disableMfaFactor": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„Π°ΠΊΡ‚ΠΎΡ€", + "qrCodeErrorHeading": "Ошибка QR-ΠΊΠΎΠ΄Π°", + "qrCodeErrorDescription": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ QR-ΠΊΠΎΠ΄", + "multiFactorSetupSuccess": "Π€Π°ΠΊΡ‚ΠΎΡ€ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½", + "submitVerificationCode": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄ подтвСрТдСния", + "mfaEnabledSuccessAlert": "ΠœΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½Π°Ρ аутСнтификация Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π°", + "verifyingCode": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ΄Π°...", + "invalidVerificationCodeHeading": "НСвСрный ΠΊΠΎΠ΄ подтвСрТдСния", + "invalidVerificationCodeDescription": "Π’Π²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Π²Π°ΠΌΠΈ ΠΊΠΎΠ΄ Π½Π΅Π²Π΅Ρ€Π΅Π½. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "unenrollFactorModalHeading": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΊΡ‚ΠΎΡ€Π°", + "unenrollFactorModalDescription": "Π’Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ этот Ρ„Π°ΠΊΡ‚ΠΎΡ€. Π’Ρ‹ большС Π½Π΅ смоТСтС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ для Π²Ρ…ΠΎΠ΄Π° Π² Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚.", + "unenrollFactorModalBody": "Π’Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ этот Ρ„Π°ΠΊΡ‚ΠΎΡ€. Π’Ρ‹ большС Π½Π΅ смоТСтС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ для Π²Ρ…ΠΎΠ΄Π° Π² Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚.", + "unenrollFactorModalButtonLabel": "Π”Π°, ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Ρ„Π°ΠΊΡ‚ΠΎΡ€", + "selectFactor": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ„Π°ΠΊΡ‚ΠΎΡ€ для подтвСрТдСния личности", + "disableMfa": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠΌΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½ΡƒΡŽ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡŽ", + "disableMfaButtonLabel": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ MFA", + "confirmDisableMfaButtonLabel": "Π”Π°, ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ MFA", + "disablingMfa": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½ΠΎΠΉ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅...", + "disableMfaSuccess": "ΠœΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½Π°Ρ аутСнтификация ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½Π°", + "disableMfaError": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. MFA Π½Π΅ Π±Ρ‹Π»Π° ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½Π°.", + "sendingEmailVerificationLink": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° письма...", + "sendEmailVerificationLinkSuccess": "Бсылка для подтвСрТдСния ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π°", + "sendEmailVerificationLinkError": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ письмо", + "sendVerificationLinkSubmitLabel": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ссылку для подтвСрТдСния", + "sendVerificationLinkSuccessLabel": "Письмо ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ! ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ ΠΏΠΎΡ‡Ρ‚Ρƒ", + "verifyEmailAlertHeading": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ Π²Π°ΡˆΡƒ ΠΏΠΎΡ‡Ρ‚Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ MFA", + "verificationLinkAlertDescription": "Π’Π°ΡˆΠ° ΠΏΠΎΡ‡Ρ‚Π° Π΅Ρ‰Π΅ Π½Π΅ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½Π°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ Π΅Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΌΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½ΡƒΡŽ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡŽ.", + "authFactorName": "Имя Ρ„Π°ΠΊΡ‚ΠΎΡ€Π° (Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ)", + "authFactorNameHint": "ΠŸΡ€ΠΈΡΠ²ΠΎΠΉΡ‚Π΅ имя, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ Π²Π°ΠΌ Π·Π°ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ Π½ΠΎΠΌΠ΅Ρ€ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π°, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ для Π²Ρ…ΠΎΠ΄Π°", + "loadingUser": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅...", + "linkPhoneNumber": "ΠŸΡ€ΠΈΠ²ΡΠ·Π°Ρ‚ΡŒ Π½ΠΎΠΌΠ΅Ρ€ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π°", + "dangerZone": "Опасная Π·ΠΎΠ½Π°", + "dangerZoneDescription": "НСкоторыС дСйствия нСльзя ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ. Π‘ΡƒΠ΄ΡŒΡ‚Π΅ остороТны.", + "deleteAccount": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "deletingAccount": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅...", + "deleteAccountDescription": "Π­Ρ‚ΠΎ ΡƒΠ΄Π°Π»ΠΈΡ‚ ваш Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ ΠΈ связанныС с Π½ΠΈΠΌ ΡƒΡ‡Π΅Ρ‚Π½Ρ‹Π΅ записи. Π’Π°ΠΊΠΆΠ΅ ΠΌΡ‹ Π½Π΅ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΠΌ всС Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ подписки. Π­Ρ‚ΠΎ дСйствиС нСльзя ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ.", + "deleteProfileConfirmationInputLabel": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ DELETE для подтвСрТдСния", + "deleteAccountErrorHeading": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "needsReauthentication": "ВрСбуСтся повторная аутСнтификация", + "needsReauthenticationDescription": "НСобходимо ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ Π²ΠΎΠΉΡ‚ΠΈ Π² систСму, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Ρ‹ΠΉΠ΄ΠΈΡ‚Π΅ ΠΈ Π²ΠΎΠΉΠ΄ΠΈΡ‚Π΅ снова.", + "language": "Π―Π·Ρ‹ΠΊ", + "languageDescription": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹ΠΉ язык", + "noTeamsYet": "Π£ вас ΠΏΠΎΠΊΠ° Π½Π΅Ρ‚ ΠΊΠΎΠΌΠ°Π½Π΄.", + "createTeam": "Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°Ρ‡Π°Ρ‚ΡŒ.", + "createTeamButtonLabel": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ", + "createCompanyAccount": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "requestCompanyAccount": { + "title": "Π”Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "description": "Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅, поТалуйста, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ Π΄Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ, с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π²Ρ‹ ΠΏΠ»Π°Π½ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ MedReport.", + "button": "Π—Π°ΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "successTitle": "Запрос ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½!", + "successDescription": "ΠœΡ‹ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΠΌ Π²Π°ΠΌ ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΉ возмоТности", + "successButton": "Π’Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ Π½Π° Π³Π»Π°Π²Π½ΡƒΡŽ" + }, + "updateAccount": { + "title": "Π›ΠΈΡ‡Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅", + "description": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ свои Π»ΠΈΡ‡Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ для продолТСния", + "button": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ", + "userConsentLabel": "Π― согласСн Π½Π° использованиС ΠΌΠΎΠΈΡ… ΠΏΠ΅Ρ€ΡΠΎΠ½Π°Π»ΡŒΠ½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅", + "userConsentUrlTitle": "ΠŸΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΡƒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΏΠ΅Ρ€ΡΠΎΠ½Π°Π»ΡŒΠ½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…" + }, + "consentModal": { + "title": "ΠŸΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ Π½Π°Ρ‡Π°Ρ‚ΡŒ", + "description": "Π’Ρ‹ Π΄Π°Π΅Ρ‚Π΅ согласиС Π½Π° использованиС Π²Π°ΡˆΠΈΡ… мСдицинских Π΄Π°Π½Π½Ρ‹Ρ… Π² Π°Π½ΠΎΠ½ΠΈΠΌΠ½ΠΎΠΉ Ρ„ΠΎΡ€ΠΌΠ΅ для статистики работодатСля? Π”Π°Π½Π½Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠ±Π΅Π·Π»ΠΈΡ‡Π΅Π½Ρ‹ ΠΈ ΠΏΠΎΠΌΠΎΠ³ΡƒΡ‚ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Π»ΡƒΡ‡ΡˆΠ΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΠ΅ сотрудников.", + "reject": "НС даю согласиС", + "accept": "Π”Π°, даю согласиС" + }, + "updateConsentSuccess": "Богласия ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Ρ‹", + "updateConsentError": "Π§Ρ‚ΠΎ-Ρ‚ΠΎ пошло Π½Π΅ Ρ‚Π°ΠΊ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "updateConsentLoading": "ОбновлСниС согласий...", "consentToAnonymizedCompanyData": { - "label": "Consent to be included in employer statistics", - "description": "Consent to be included in anonymized company statistics" + "label": "БогласСн ΡƒΡ‡Π°ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π² статистикС работодатСля", + "description": "Π― согласСн Π½Π° использованиС ΠΌΠΎΠΈΡ… мСдицинских Π΄Π°Π½Π½Ρ‹Ρ… Π² Π°Π½ΠΎΠ½ΠΈΠΌΠ½ΠΎΠΉ Ρ„ΠΎΡ€ΠΌΠ΅ для статистики работодатСля" }, - "analysisResults": { - "pageTitle": "My analysis results" + "membershipConfirmation": { + "successTitle": "ЗдравствуйтС, {{firstName}} {{lastName}}", + "successDescription": "Π’Π°Ρˆ мСдицинский Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Π½ ΠΈ Π³ΠΎΡ‚ΠΎΠ² ΠΊ использованию!", + "successButton": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ" }, - "updateRoleSuccess": "Role updated", - "updateRoleError": "Something went wrong, please try again", - "updateRoleLoading": "Updating role...", - "updatePreferredLocaleSuccess": "Language preference updated", - "updatePreferredLocaleError": "Language preference update failed", - "updatePreferredLocaleLoading": "Updating language preference..." + "updateRoleSuccess": "Роль ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π°", + "updateRoleError": "Π§Ρ‚ΠΎ-Ρ‚ΠΎ пошло Π½Π΅ Ρ‚Π°ΠΊ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "updateRoleLoading": "ОбновлСниС Ρ€ΠΎΠ»ΠΈ...", + "updatePreferredLocaleSuccess": "ΠŸΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹ΠΉ язык ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½", + "updatePreferredLocaleError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹ΠΉ язык", + "updatePreferredLocaleLoading": "ОбновлСниС ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°Π΅ΠΌΠΎΠ³ΠΎ языка..." } \ No newline at end of file diff --git a/public/locales/ru/analysis-results.json b/public/locales/ru/analysis-results.json new file mode 100644 index 0000000..8a032b3 --- /dev/null +++ b/public/locales/ru/analysis-results.json @@ -0,0 +1,16 @@ +{ + "pageTitle": "Мои Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "description": "ВсС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ² ΠΏΠΎΡΠ²Π»ΡΡŽΡ‚ΡΡ Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ 1-3 Ρ€Π°Π±ΠΎΡ‡ΠΈΡ… Π΄Π½Π΅ΠΉ послС ΠΈΡ… сдачи.", + "descriptionEmpty": "Если Π²Ρ‹ ΡƒΠΆΠ΅ сдали Π°Π½Π°Π»ΠΈΠ·Ρ‹, Ρ‚ΠΎ вскорС здСсь появятся ваши Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹.", + "orderNewAnalysis": "Π—Π°ΠΊΠ°Π·Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ Π°Π½Π°Π»ΠΈΠ·Ρ‹", + "waitingForResults": "ОТиданиС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²", + "noAnalysisElements": "Анализы Π΅Ρ‰Π΅ Π½Π΅ Π·Π°ΠΊΠ°Π·Π°Π½Ρ‹", + "noAnalysisOrders": "Пока Π½Π΅Ρ‚ Π·Π°ΠΊΠ°Π·ΠΎΠ² Π½Π° Π°Π½Π°Π»ΠΈΠ·Ρ‹", + "analysisDate": "Π”Π°Ρ‚Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° Π°Π½Π°Π»ΠΈΠ·Π°", + "results": { + "range": { + "normal": "ΠΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½" + } + }, + "orderTitle": "Π—Π°ΠΊΠ°Π· {{orderNumber}}" +} diff --git a/public/locales/ru/auth.json b/public/locales/ru/auth.json index 7db0925..8634403 100644 --- a/public/locales/ru/auth.json +++ b/public/locales/ru/auth.json @@ -1,90 +1,90 @@ { - "signUpHeading": "Create an account", - "signUp": "Sign Up", - "signUpSubheading": "Fill the form below to create an account.", - "signInHeading": "Sign in to your account", - "signInSubheading": "Welcome back! Please enter your details", - "signIn": "Sign In", - "getStarted": "Get started", - "updatePassword": "Update Password", - "signOut": "Sign out", - "signingIn": "Signing in...", - "signingUp": "Signing up...", - "doNotHaveAccountYet": "Do not have an account yet?", - "alreadyHaveAnAccount": "Already have an account?", - "signUpToAcceptInvite": "Please sign in/up to accept the invite", - "clickToAcceptAs": "Click the button below to accept the invite with as {{email}}", - "acceptInvite": "Accept invite", - "acceptingInvite": "Accepting Invite...", - "acceptInviteSuccess": "Invite successfully accepted", - "acceptInviteError": "Error encountered while accepting invite", - "acceptInviteWithDifferentAccount": "Want to accept the invite with a different account?", - "alreadyHaveAccountStatement": "I already have an account, I want to sign in instead", - "doNotHaveAccountStatement": "I do not have an account, I want to sign up instead", - "signInWithProvider": "Sign in with {{provider}}", - "signInWithPhoneNumber": "Sign in with Phone Number", - "signInWithEmail": "Sign in with Email", - "signUpWithEmail": "Sign up with Email", - "passwordHint": "Ensure it's at least 8 characters", - "repeatPasswordHint": "Type your password again", - "repeatPassword": "Repeat password", - "passwordForgottenQuestion": "Password forgotten?", - "passwordResetLabel": "Reset Password", - "passwordResetSubheading": "Enter your email address below. You will receive a link to reset your password.", - "passwordResetSuccessMessage": "Check your Inbox! We emailed you a link for resetting your Password.", - "passwordRecoveredQuestion": "Password recovered?", - "passwordLengthError": "Please provide a password with at least 6 characters", - "sendEmailLink": "Send Email Link", - "sendingEmailLink": "Sending Email Link...", - "sendLinkSuccessDescription": "Check your email, we just sent you a link. Follow the link to sign in.", - "sendLinkSuccess": "We sent you a link by email", - "sendLinkSuccessToast": "Link successfully sent", - "getNewLink": "Get a new link", - "verifyCodeHeading": "Verify your account", - "verificationCode": "Verification Code", - "verificationCodeHint": "Enter the code we sent you by SMS", - "verificationCodeSubmitButtonLabel": "Submit Verification Code", - "sendingMfaCode": "Sending Verification Code...", - "verifyingMfaCode": "Verifying code...", - "sendMfaCodeError": "Sorry, we couldn't send you a verification code", - "verifyMfaCodeSuccess": "Code verified! Signing you in...", - "verifyMfaCodeError": "Ops! It looks like the code is not correct", - "reauthenticate": "Reauthenticate", - "reauthenticateDescription": "For security reasons, we need you to re-authenticate", - "errorAlertHeading": "Sorry, we could not authenticate you", - "emailConfirmationAlertHeading": "We sent you a confirmation email.", - "emailConfirmationAlertBody": "Welcome! Please check your email and click the link to verify your account.", - "resendLink": "Resend link", - "resendLinkSuccessDescription": "We sent you a new link to your email! Follow the link to sign in.", - "resendLinkSuccess": "Check your email!", - "authenticationErrorAlertHeading": "Authentication Error", - "authenticationErrorAlertBody": "Sorry, we could not authenticate you. Please try again.", - "sendEmailCode": "Get code to your Email", - "sendingEmailCode": "Sending code...", - "resetPasswordError": "Sorry, we could not reset your password. Please try again.", + "signUpHeading": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "signUp": "Π—Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ", + "signUpSubheading": "Π—Π°ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ Ρ„ΠΎΡ€ΠΌΡƒ Π½ΠΈΠΆΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚.", + "signInHeading": "Π’ΠΎΠΉΠ΄ΠΈΡ‚Π΅ Π² свой Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "signInSubheading": "Π‘ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ΠΌ! ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ свои Π΄Π°Π½Π½Ρ‹Π΅", + "signIn": "Π’ΠΎΠΉΡ‚ΠΈ", + "getStarted": "ΠΠ°Ρ‡Π°Ρ‚ΡŒ", + "updatePassword": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "signOut": "Π’Ρ‹ΠΉΡ‚ΠΈ", + "signingIn": "Π’Ρ…ΠΎΠ΄...", + "signingUp": "РСгистрация...", + "doNotHaveAccountYet": "Π•Ρ‰Π΅ Π½Π΅Ρ‚ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°?", + "alreadyHaveAnAccount": "Π£ΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚?", + "signUpToAcceptInvite": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²ΠΎΠΉΠ΄ΠΈΡ‚Π΅ ΠΈΠ»ΠΈ Π·Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΡƒΠΉΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "clickToAcceptAs": "НаТмитС ΠΊΠ½ΠΎΠΏΠΊΡƒ Π½ΠΈΠΆΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ ΠΊΠ°ΠΊ {{email}}", + "acceptInvite": "ΠŸΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "acceptingInvite": "ΠŸΡ€ΠΈΠ½ΡΡ‚ΠΈΠ΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ...", + "acceptInviteSuccess": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ принято", + "acceptInviteError": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ принятии ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ", + "acceptInviteWithDifferentAccount": "Π₯ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ с Π΄Ρ€ΡƒΠ³ΠΈΠΌ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΎΠΌ?", + "alreadyHaveAccountStatement": "Π£ мСня ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚, я Ρ…ΠΎΡ‡Ρƒ Π²ΠΎΠΉΡ‚ΠΈ", + "doNotHaveAccountStatement": "Π£ мСня Π½Π΅Ρ‚ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°, я Ρ…ΠΎΡ‡Ρƒ Π·Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ", + "signInWithProvider": "Π’ΠΎΠΉΡ‚ΠΈ Ρ‡Π΅Ρ€Π΅Π· {{provider}}", + "signInWithPhoneNumber": "Π’ΠΎΠΉΡ‚ΠΈ ΠΏΠΎ Π½ΠΎΠΌΠ΅Ρ€Ρƒ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π°", + "signInWithEmail": "Π’ΠΎΠΉΡ‚ΠΈ ΠΏΠΎ Email", + "signUpWithEmail": "Π—Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΏΠΎ Email", + "passwordHint": "Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ содСрТит Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ 8 символов", + "repeatPasswordHint": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π΅Ρ‰Π΅ Ρ€Π°Π·", + "repeatPassword": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "passwordForgottenQuestion": "Π—Π°Π±Ρ‹Π»ΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ?", + "passwordResetLabel": "Π‘Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "passwordResetSubheading": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ваш email Π½ΠΈΠΆΠ΅. Π’Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ ссылку для сброса пароля.", + "passwordResetSuccessMessage": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ ΠΏΠΎΡ‡Ρ‚Ρƒ! ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ ссылку для сброса пароля.", + "passwordRecoveredQuestion": "Восстановили ΠΏΠ°Ρ€ΠΎΠ»ΡŒ?", + "passwordLengthError": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π΄Π»ΠΈΠ½ΠΎΠΉ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ 6 символов", + "sendEmailLink": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ссылку Π½Π° ΠΏΠΎΡ‡Ρ‚Ρƒ", + "sendingEmailLink": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ссылки...", + "sendLinkSuccessDescription": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ Π²Π°ΡˆΡƒ ΠΏΠΎΡ‡Ρ‚Ρƒ, ΠΌΡ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ ссылку. ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ Π½Π΅ΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΎΠΉΡ‚ΠΈ.", + "sendLinkSuccess": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ ссылку ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅", + "sendLinkSuccessToast": "Бсылка ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π°", + "getNewLink": "ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ссылку", + "verifyCodeHeading": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ ваш Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "verificationCode": "Код подтвСрТдСния", + "verificationCodeHint": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ ΠΏΠΎ SMS", + "verificationCodeSubmitButtonLabel": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄", + "sendingMfaCode": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ΠΊΠΎΠ΄Π° подтвСрТдСния...", + "verifyingMfaCode": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ΄Π°...", + "sendMfaCodeError": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄ подтвСрТдСния", + "verifyMfaCodeSuccess": "Код ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½! Π’Ρ…ΠΎΠ΄ΠΈΠΌ Π² систСму...", + "verifyMfaCodeError": "Упс! ΠŸΠΎΡ…ΠΎΠΆΠ΅, ΠΊΠΎΠ΄ Π½Π΅Π²Π΅Ρ€Π½Ρ‹ΠΉ", + "reauthenticate": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€Π½Π°Ρ аутСнтификация", + "reauthenticateDescription": "Π’ цСлях бСзопасности Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΏΡ€ΠΎΠΉΡ‚ΠΈ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΡƒΡŽ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡŽ", + "errorAlertHeading": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ вас Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "emailConfirmationAlertHeading": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ письмо для подтвСрТдСния.", + "emailConfirmationAlertBody": "Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ! ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ Π²Π°ΡˆΡƒ ΠΏΠΎΡ‡Ρ‚Ρƒ ΠΈ ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ ссылкС, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚.", + "resendLink": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ссылку снова", + "resendLinkSuccessDescription": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π½ΠΎΠ²ΡƒΡŽ ссылку Π½Π° Π²Π°ΡˆΡƒ ΠΏΠΎΡ‡Ρ‚Ρƒ! ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ Π½Π΅ΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΎΠΉΡ‚ΠΈ.", + "resendLinkSuccess": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ Π²Π°ΡˆΡƒ ΠΏΠΎΡ‡Ρ‚Ρƒ!", + "authenticationErrorAlertHeading": "Ошибка Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ", + "authenticationErrorAlertBody": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ вас Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "sendEmailCode": "ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄ Π½Π° Email", + "sendingEmailCode": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ΠΊΠΎΠ΄Π°...", + "resetPasswordError": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡΠ±Ρ€ΠΎΡΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", "emailPlaceholder": "your@email.com", - "inviteAlertHeading": "You have been invited to join a company", - "inviteAlertBody": "Please sign in or sign up to accept the invite and join the company.", - "acceptTermsAndConditions": "I accept the and ", - "termsOfService": "Terms of Service", - "privacyPolicy": "Privacy Policy", - "orContinueWith": "Or continue with", - "redirecting": "You're in! Please wait...", + "inviteAlertHeading": "Вас пригласили ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "inviteAlertBody": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²ΠΎΠΉΠ΄ΠΈΡ‚Π΅ ΠΈΠ»ΠΈ Π·Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΡƒΠΉΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "acceptTermsAndConditions": "Π― ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽ ΠΈ ", + "termsOfService": "Условия использования", + "privacyPolicy": "ΠŸΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° ΠΊΠΎΠ½Ρ„ΠΈΠ΄Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ", + "orContinueWith": "Или ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π·", + "redirecting": "Π’Ρ‹ вошли! ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅...", "errors": { - "Invalid login credentials": "The credentials entered are invalid", - "User already registered": "This credential is already in use. Please try with another one.", - "Email not confirmed": "Please confirm your email address before signing in", - "default": "We have encountered an error. Please ensure you have a working internet connection and try again", - "generic": "Sorry, we weren't able to authenticate you. Please try again.", - "link": "Sorry, we encountered an error while sending your link. Please try again.", - "codeVerifierMismatch": "It looks like you're trying to sign in using a different browser than the one you used to request the sign in link. Please try again using the same browser.", - "minPasswordLength": "Password must be at least 8 characters long", - "passwordsDoNotMatch": "The passwords do not match", - "minPasswordNumbers": "Password must contain at least one number", - "minPasswordSpecialChars": "Password must contain at least one special character", - "uppercasePassword": "Password must contain at least one uppercase letter", - "insufficient_aal": "Please sign-in with your current multi-factor authentication to perform this action", - "otp_expired": "The email link has expired. Please try again.", - "same_password": "The password cannot be the same as the current password" + "Invalid login credentials": "Π’Π²Π΅Π΄Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π½Π΅Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹", + "User already registered": "Π­Ρ‚ΠΈ Π΄Π°Π½Π½Ρ‹Π΅ ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΈΠ΅.", + "Email not confirmed": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ ваш email ΠΏΠ΅Ρ€Π΅Π΄ Π²Ρ…ΠΎΠ΄ΠΎΠΌ", + "default": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ Ρƒ вас Π΅ΡΡ‚ΡŒ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ ΠΈΠ½Ρ‚Π΅Ρ€Π½Π΅Ρ‚Ρƒ, ΠΈ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "generic": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ вас Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "link": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ ссылки. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "codeVerifierMismatch": "ΠŸΠΎΡ…ΠΎΠΆΠ΅, Π²Ρ‹ ΠΏΡ‹Ρ‚Π°Π΅Ρ‚Π΅ΡΡŒ Π²ΠΎΠΉΡ‚ΠΈ Ρ‡Π΅Ρ€Π΅Π· Π΄Ρ€ΡƒΠ³ΠΎΠΉ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€, Ρ‡Π΅ΠΌ Ρ‚ΠΎΡ‚, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π»ΠΈ ссылку для Π²Ρ…ΠΎΠ΄Π°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Ρ‚ΠΎΡ‚ ΠΆΠ΅ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€.", + "minPasswordLength": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ 8 символов", + "passwordsDoNotMatch": "ΠŸΠ°Ρ€ΠΎΠ»ΠΈ Π½Π΅ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚", + "minPasswordNumbers": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ хотя Π±Ρ‹ ΠΎΠ΄Π½Ρƒ Ρ†ΠΈΡ„Ρ€Ρƒ", + "minPasswordSpecialChars": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ хотя Π±Ρ‹ ΠΎΠ΄ΠΈΠ½ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ символ", + "uppercasePassword": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ хотя Π±Ρ‹ ΠΎΠ΄Π½Ρƒ Π·Π°Π³Π»Π°Π²Π½ΡƒΡŽ Π±ΡƒΠΊΠ²Ρƒ", + "insufficient_aal": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²ΠΎΠΉΠ΄ΠΈΡ‚Π΅ с Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΠΌΠ½ΠΎΠ³ΠΎΡ„Π°ΠΊΡ‚ΠΎΡ€Π½ΠΎΠΉ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠ΅ΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ это дСйствиС", + "otp_expired": "Π‘Ρ€ΠΎΠΊ дСйствия ссылки Π½Π° email истСк. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "same_password": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ²ΠΏΠ°Π΄Π°Ρ‚ΡŒ с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ ΠΏΠ°Ρ€ΠΎΠ»Π΅ΠΌ" } -} +} \ No newline at end of file diff --git a/public/locales/ru/billing.json b/public/locales/ru/billing.json index 0f7b472..c40a1cd 100644 --- a/public/locales/ru/billing.json +++ b/public/locales/ru/billing.json @@ -1,123 +1,143 @@ { - "subscriptionTabSubheading": "Manage your Subscription and Billing", - "planCardTitle": "Your Plan", - "planCardDescription": "Below are the details of your current plan. You can change your plan or cancel your subscription at any time.", - "planRenewal": "Renews every {{interval}} at {{price}}", - "planDetails": "Plan Details", - "checkout": "Proceed to Checkout", - "trialEndsOn": "Your trial ends on", - "billingPortalCardButton": "Visit Billing Portal", - "billingPortalCardTitle": "Manage your Billing Details", - "billingPortalCardDescription": "Visit your Billing Portal to manage your subscription and billing. You can update or cancel your plan, or download your invoices.", - "cancelAtPeriodEndDescription": "Your subscription is scheduled to be canceled on {{- endDate }}.", - "renewAtPeriodEndDescription": "Your subscription is scheduled to be renewed on {{- endDate }}", - "noPermissionsAlertHeading": "You don't have permissions to change the billing settings", - "noPermissionsAlertBody": "Please contact your account admin to change the billing settings for your account.", - "checkoutSuccessTitle": "Done! You're all set.", - "checkoutSuccessDescription": "Thank you for subscribing, we have successfully processed your subscription! A confirmation email will be sent to {{ customerEmail }}.", - "checkoutSuccessBackButton": "Proceed to App", - "cannotManageBillingAlertTitle": "You cannot manage billing", - "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account admin.", - "manageTeamPlan": "Manage your Company Plan", - "manageTeamPlanDescription": "Choose a plan that fits your company's needs. You can upgrade or downgrade your plan at any time.", - "basePlan": "Base Plan", + "subscriptionTabSubheading": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ подпиской ΠΈ ΠΎΠΏΠ»Π°Ρ‚ΠΎΠΉ", + "planCardTitle": "Π’Π°Ρˆ Ρ‚Π°Ρ€ΠΈΡ„", + "planCardDescription": "НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Ρ‹ Π΄Π΅Ρ‚Π°Π»ΠΈ вашСго Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ Ρ‚Π°Ρ€ΠΈΡ„Π°. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ‚Π°Ρ€ΠΈΡ„ ΠΈΠ»ΠΈ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ подписку Π² любоС врСмя.", + "planRenewal": "ΠŸΡ€ΠΎΠ΄Π»Π΅Π²Π°Π΅Ρ‚ΡΡ ΠΊΠ°ΠΆΠ΄Ρ‹Π΅ {{interval}} Π·Π° {{price}}", + "planDetails": "Π”Π΅Ρ‚Π°Π»ΠΈ Ρ‚Π°Ρ€ΠΈΡ„Π°", + "checkout": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ ΠΎΠΏΠ»Π°Ρ‚Π΅", + "trialEndsOn": "ΠŸΡ€ΠΎΠ±Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ заканчиваСтся", + "billingPortalCardButton": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π² Π±ΠΈΠ»Π»ΠΈΠ½Π³-ΠΏΠΎΡ€Ρ‚Π°Π»", + "billingPortalCardTitle": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ»Π°Ρ‚Π΅ΠΆΠ½Ρ‹ΠΌΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ", + "billingPortalCardDescription": "ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π² Π±ΠΈΠ»Π»ΠΈΠ½Π³-ΠΏΠΎΡ€Ρ‚Π°Π», Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ подпиской ΠΈ ΠΏΠ»Π°Ρ‚Π΅ΠΆΠ°ΠΌΠΈ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΈΠ»ΠΈ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ‚Π°Ρ€ΠΈΡ„, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΡΠΊΠ°Ρ‡Π°Ρ‚ΡŒ счСта.", + "cancelAtPeriodEndDescription": "Π’Π°ΡˆΠ° подписка Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° {{- endDate }}.", + "renewAtPeriodEndDescription": "Π’Π°ΡˆΠ° подписка Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠ΄Π»Π΅Π½Π° {{- endDate }}", + "noPermissionsAlertHeading": "Π£ вас Π½Π΅Ρ‚ ΠΏΡ€Π°Π² для измСнСния настроСк ΠΎΠΏΠ»Π°Ρ‚Ρ‹", + "noPermissionsAlertBody": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ настройки ΠΎΠΏΠ»Π°Ρ‚Ρ‹.", + "checkoutSuccessTitle": "Π“ΠΎΡ‚ΠΎΠ²ΠΎ! Всё настроСно.", + "checkoutSuccessDescription": "Бпасибо Π·Π° подписку! ΠœΡ‹ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ„ΠΎΡ€ΠΌΠΈΠ»ΠΈ Π²Π°ΡˆΡƒ подписку. ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ Π½Π° {{ customerEmail }}.", + "checkoutSuccessBackButton": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "cannotManageBillingAlertTitle": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΎΠΏΠ»Π°Ρ‚ΠΎΠΉ", + "cannotManageBillingAlertDescription": "Π£ вас Π½Π΅Ρ‚ ΠΏΡ€Π°Π² для управлСния ΠΎΠΏΠ»Π°Ρ‚ΠΎΠΉ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°.", + "manageTeamPlan": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΡ€ΠΏΠΎΡ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌ Ρ‚Π°Ρ€ΠΈΡ„ΠΎΠΌ", + "manageTeamPlanDescription": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ‚Π°Ρ€ΠΈΡ„, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ соотвСтствуСт потрСбностям вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π² любоС врСмя.", + "basePlan": "Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ Ρ‚Π°Ρ€ΠΈΡ„", "billingInterval": { - "label": "Choose your billing interval", - "month": "Billed monthly", - "year": "Billed yearly" + "label": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π» ΠΎΠΏΠ»Π°Ρ‚Ρ‹", + "month": "ΠžΠΏΠ»Π°Ρ‚Π° СТСмСсячно", + "year": "ΠžΠΏΠ»Π°Ρ‚Π° Π΅ΠΆΠ΅Π³ΠΎΠ΄Π½ΠΎ" }, - "perMonth": "month", - "custom": "Custom Plan", - "lifetime": "Lifetime", - "trialPeriod": "{{period}} day trial", - "perPeriod": "per {{period}}", - "redirectingToPayment": "Redirecting to checkout. Please wait...", - "proceedToPayment": "Proceed to Payment", - "startTrial": "Start Trial", - "perTeamMember": "Per company member", - "perUnit": "Per {{unit}} usage", - "teamMembers": "Company Members", - "includedUpTo": "Up to {{upTo}} {{unit}} included in the plan", - "fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}", - "andAbove": "above {{ previousTier }} {{ unit }}", - "startingAtPriceUnit": "Starting at {{price}}/{{unit}}", + "perMonth": "мСсяц", + "custom": "Π˜Π½Π΄ΠΈΠ²ΠΈΠ΄ΡƒΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ‚Π°Ρ€ΠΈΡ„", + "lifetime": "ΠŸΠΎΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ", + "trialPeriod": "ΠŸΡ€ΠΎΠ±Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ {{period}} Π΄Π½Π΅ΠΉ", + "perPeriod": "Π·Π° {{period}}", + "redirectingToPayment": "ΠŸΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° ΠΎΠΏΠ»Π°Ρ‚Ρƒ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅...", + "proceedToPayment": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ ΠΎΠΏΠ»Π°Ρ‚Π΅", + "startTrial": "ΠΠ°Ρ‡Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄", + "perTeamMember": "На ΠΎΠ΄Π½ΠΎΠ³ΠΎ сотрудника", + "perUnit": "Π—Π° использованиС {{unit}}", + "teamMembers": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊΠΈ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "includedUpTo": "Π”ΠΎ {{upTo}} {{unit}} Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ Π² Ρ‚Π°Ρ€ΠΈΡ„", + "fromPreviousTierUpTo": "Π·Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ {{unit}} для ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… {{ upTo }} {{ unit }}", + "andAbove": "ΡΠ²Ρ‹ΡˆΠ΅ {{ previousTier }} {{ unit }}", + "startingAtPriceUnit": "Начиная с {{price}}/{{unit}}", "priceUnit": "{{price}}/{{unit}}", - "forEveryUnit": "for every {{ unit }}", - "setupFee": "plus a {{ setupFee }} setup fee", - "perUnitIncluded": "({{included}} included)", - "featuresLabel": "Features", - "detailsLabel": "Details", - "planPickerLabel": "Pick your preferred plan", - "planCardLabel": "Manage your Plan", - "planPickerAlertErrorTitle": "Error requesting checkout", - "planPickerAlertErrorDescription": "There was an error requesting checkout. Please try again later.", - "subscriptionCancelled": "Subscription Cancelled", - "cancelSubscriptionDate": "Your subscription will be cancelled at the end of the period", - "noPlanChosen": "Please choose a plan", - "noIntervalPlanChosen": "Please choose a billing interval", + "forEveryUnit": "Π·Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ {{ unit }}", + "setupFee": "плюс ΠΏΠ»Π°Ρ‚Π° Π·Π° установку {{ setupFee }}", + "perUnitIncluded": "({{included}} Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ)", + "featuresLabel": "Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ", + "detailsLabel": "ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΡΡ‚ΠΈ", + "planPickerLabel": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ‚Π°Ρ€ΠΈΡ„", + "planCardLabel": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π°Ρ€ΠΈΡ„ΠΎΠΌ", + "planPickerAlertErrorTitle": "Ошибка ΠΏΡ€ΠΈ запросС ΠΎΠΏΠ»Π°Ρ‚Ρ‹", + "planPickerAlertErrorDescription": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ запросС ΠΎΠΏΠ»Π°Ρ‚Ρ‹. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΏΠΎΠ·ΠΆΠ΅.", + "subscriptionCancelled": "Подписка ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π°", + "cancelSubscriptionDate": "Π’Π°ΡˆΠ° подписка Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° Π² ΠΊΠΎΠ½Ρ†Π΅ расчСтного ΠΏΠ΅Ρ€ΠΈΠΎΠ΄Π°", + "noPlanChosen": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ‚Π°Ρ€ΠΈΡ„", + "noIntervalPlanChosen": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π» ΠΎΠΏΠ»Π°Ρ‚Ρ‹", "status": { "free": { - "badge": "Free Plan", - "heading": "You are currently on the Free Plan", - "description": "You're on a free plan. You can upgrade to a paid plan at any time." + "badge": "БСсплатный Ρ‚Π°Ρ€ΠΈΡ„", + "heading": "Π’Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ бСсплатный Ρ‚Π°Ρ€ΠΈΡ„", + "description": "Π’Ρ‹ Π½Π° бСсплатном Ρ‚Π°Ρ€ΠΈΡ„Π΅. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π½Π° ΠΏΠ»Π°Ρ‚Π½Ρ‹ΠΉ Ρ‚Π°Ρ€ΠΈΡ„ Π² любоС врСмя." }, "active": { - "badge": "Active", - "heading": "Your subscription is active", - "description": "Your subscription is active. You can manage your subscription and billing in the Customer Portal." + "badge": "АктивСн", + "heading": "Π’Π°ΡˆΠ° подписка Π°ΠΊΡ‚ΠΈΠ²Π½Π°", + "description": "Π’Π°ΡˆΠ° подписка Π°ΠΊΡ‚ΠΈΠ²Π½Π°. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ подпиской ΠΈ ΠΎΠΏΠ»Π°Ρ‚ΠΎΠΉ Π² клиСнтском ΠΏΠΎΡ€Ρ‚Π°Π»Π΅." }, "trialing": { - "badge": "Trial", - "heading": "You're on a trial", - "description": "You can enjoy the benefits of plan until the trial ends" + "badge": "ΠŸΡ€ΠΎΠ±Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄", + "heading": "Π’Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ ΠΏΡ€ΠΎΠ±Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄", + "description": "Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Ρ‚Π°Ρ€ΠΈΡ„ΠΎΠΌ Π΄ΠΎ окончания ΠΏΡ€ΠΎΠ±Π½ΠΎΠ³ΠΎ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄Π°" }, "past_due": { - "badge": "Past Due", - "heading": "Your invoice is past due", - "description": "Your invoice is past due. Please update your payment method." + "badge": "ΠŸΡ€ΠΎΡΡ€ΠΎΡ‡Π΅Π½ΠΎ", + "heading": "Π’Π°Ρˆ счСт просрочСн", + "description": "Π’Π°Ρˆ счСт просрочСн. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ способ ΠΎΠΏΠ»Π°Ρ‚Ρ‹." }, "canceled": { - "badge": "Canceled", - "heading": "Your subscription is canceled", - "description": "Your subscription is canceled. It is scheduled to end at end of the billing period." + "badge": "ΠžΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ", + "heading": "Π’Π°ΡˆΠ° подписка ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π°", + "description": "Π’Π°ΡˆΠ° подписка ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡΡ Π² ΠΊΠΎΠ½Ρ†Π΅ расчСтного ΠΏΠ΅Ρ€ΠΈΠΎΠ΄Π°." }, "unpaid": { - "badge": "Unpaid", - "heading": "Your invoice is unpaid", - "description": "Your invoice is unpaid. Please update your payment method." + "badge": "НСоплачСно", + "heading": "Π’Π°Ρˆ счСт Π½Π΅ ΠΎΠΏΠ»Π°Ρ‡Π΅Π½", + "description": "Π’Π°Ρˆ счСт Π½Π΅ ΠΎΠΏΠ»Π°Ρ‡Π΅Π½. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ способ ΠΎΠΏΠ»Π°Ρ‚Ρ‹." }, "incomplete": { - "badge": "Incomplete", - "heading": "We're waiting for your payment", - "description": "We're waiting for your payment to go through. Please bear with us." + "badge": "НС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΎ", + "heading": "ΠœΡ‹ ΠΆΠ΄Π΅ΠΌ Π²Π°ΡˆΡƒ ΠΎΠΏΠ»Π°Ρ‚Ρƒ", + "description": "ΠœΡ‹ ΠΆΠ΄Π΅ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ вашСй ΠΎΠΏΠ»Π°Ρ‚Ρ‹. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅." }, "incomplete_expired": { - "badge": "Expired", - "heading": "Your payment has expired", - "description": "Your payment has expired. Please update your payment method." + "badge": "Π˜ΡΡ‚Π΅ΠΊ", + "heading": "Π‘Ρ€ΠΎΠΊ ΠΎΠΏΠ»Π°Ρ‚Ρ‹ истСк", + "description": "Π‘Ρ€ΠΎΠΊ ΠΎΠΏΠ»Π°Ρ‚Ρ‹ истСк. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ способ ΠΎΠΏΠ»Π°Ρ‚Ρ‹." }, "paused": { - "badge": "Paused", - "heading": "Your subscription is paused", - "description": "Your subscription is paused. You can resume it at any time." + "badge": "ΠŸΡ€ΠΈΠΎΡΡ‚Π°Π½ΠΎΠ²Π»Π΅Π½ΠΎ", + "heading": "Π’Π°ΡˆΠ° подписка приостановлСна", + "description": "Π’Π°ΡˆΠ° подписка приостановлСна. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²ΠΎΠ·ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π΅Π΅ Π² любоС врСмя." }, "succeeded": { - "badge": "Succeeded", - "heading": "Your payment was successful", - "description": "Your payment was successful. Thank you for subscribing!" + "badge": "УспСшно", + "heading": "ΠžΠΏΠ»Π°Ρ‚Π° ΠΏΡ€ΠΎΡˆΠ»Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ", + "description": "ΠžΠΏΠ»Π°Ρ‚Π° ΠΏΡ€ΠΎΡˆΠ»Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ. Бпасибо Π·Π° подписку!" }, "pending": { - "badge": "Pending", - "heading": "Your payment is pending", - "description": "Your payment is pending. Please bear with us." + "badge": "Π’ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠΈ", + "heading": "ΠžΠΏΠ»Π°Ρ‚Π° Π² ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠΈ", + "description": "ΠžΠΏΠ»Π°Ρ‚Π° находится Π² ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠΈ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅." }, "failed": { - "badge": "Failed", - "heading": "Your payment failed", - "description": "Your payment failed. Please update your payment method." + "badge": "НСудачно", + "heading": "ΠžΠΏΠ»Π°Ρ‚Π° Π½Π΅ ΠΏΡ€ΠΎΡˆΠ»Π°", + "description": "ΠžΠΏΠ»Π°Ρ‚Π° Π½Π΅ ΠΏΡ€ΠΎΡˆΠ»Π°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ способ ΠΎΠΏΠ»Π°Ρ‚Ρ‹." } }, "cart": { - "label": "Cart ({{ items }})" + "label": "ΠšΠΎΡ€Π·ΠΈΠ½Π° ({{ items }})" + }, + "pageTitle": "Π‘ΡŽΠ΄ΠΆΠ΅Ρ‚ {{companyName}}", + "description": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΡΡ‰ΡƒΡŽ Π΄Π°Ρ‚Ρƒ Π² ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€Π΅ ΠΈ Π·Π°ΠΏΠΈΡˆΠΈΡ‚Π΅ΡΡŒ Π½Π° ΠΏΡ€ΠΈΠ΅ΠΌ.", + "saveChanges": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ измСнСния", + "healthBenefitForm": { + "title": "Π€ΠΎΡ€ΠΌΠ° Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΡ", + "description": "ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° сотрудника ΠΈΠ· ΠΊΠΎΡ€ΠΏΠΎΡ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ Ρ„ΠΎΠ½Π΄Π° Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΡ", + "info": "* К Ρ†Π΅Π½Π°ΠΌ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ государствСнныС Π½Π°Π»ΠΎΠ³ΠΈ" + }, + "occurance": { + "yearly": "Π Π°Π· Π² Π³ΠΎΠ΄", + "quarterly": "Π Π°Π· Π² ΠΊΠ²Π°Ρ€Ρ‚Π°Π»", + "monthly": "Π Π°Π· Π² мСсяц" + }, + "expensesOverview": { + "title": "ΠžΠ±Π·ΠΎΡ€ расходов Π·Π° 2025 Π³ΠΎΠ΄", + "monthly": "Расход Π½Π° ΠΎΠ΄Π½ΠΎΠ³ΠΎ сотрудника Π² мСсяц *", + "yearly": "ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ расход Π½Π° ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‡Π΅Π»ΠΎΠ²Π΅ΠΊΠ° Π² Π³ΠΎΠ΄ *", + "total": "ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ расход Π½Π° {{employeeCount}} сотрудников Π² Π³ΠΎΠ΄ *", + "sum": "Π˜Ρ‚ΠΎΠ³ΠΎ" } } \ No newline at end of file diff --git a/public/locales/ru/booking.json b/public/locales/ru/booking.json index f4ef7c2..042a4b6 100644 --- a/public/locales/ru/booking.json +++ b/public/locales/ru/booking.json @@ -1,8 +1,9 @@ { - "title": "Select service", - "description": "Select the appropriate service or package according to your health needs or goals.", - "analysisPackages": { - "title": "Analysis packages", - "description": "Get to know the personal analysis packages and order" - } -} \ No newline at end of file + "title": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ услугу", + "description": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΡΡ‰ΡƒΡŽ услугу ΠΈΠ»ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚ Π² зависимости ΠΎΡ‚ вашСй ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ со Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΠ΅ΠΌ ΠΈΠ»ΠΈ Ρ†Π΅Π»ΠΈ.", + "analysisPackages": { + "title": "ΠŸΠ°ΠΊΠ΅Ρ‚Ρ‹ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "description": "ΠžΠ·Π½Π°ΠΊΠΎΠΌΡŒΡ‚Π΅ΡΡŒ с ΠΏΠ΅Ρ€ΡΠΎΠ½Π°Π»ΡŒΠ½Ρ‹ΠΌΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π°ΠΌΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ² ΠΈ Π·Π°ΠΊΠ°ΠΆΠΈΡ‚Π΅" + }, + "noCategories": "Бписок услуг Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΏΠΎΠ·ΠΆΠ΅" +} diff --git a/public/locales/ru/cart.json b/public/locales/ru/cart.json new file mode 100644 index 0000000..9aaeb3f --- /dev/null +++ b/public/locales/ru/cart.json @@ -0,0 +1,75 @@ +{ + "title": "ΠšΠΎΡ€Π·ΠΈΠ½Π°", + "description": "ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅ свою ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ", + "emptyCartMessage": "Π’Π°ΡˆΠ° ΠΊΠΎΡ€Π·ΠΈΠ½Π° пуста", + "emptyCartMessageDescription": "Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Ρ‚ΠΎΠ²Π°Ρ€Ρ‹ Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ.", + "subtotal": "ΠŸΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹ΠΉ ΠΈΡ‚ΠΎΠ³", + "total": "Π‘ΡƒΠΌΠΌΠ°", + "table": { + "item": "Π’ΠΎΠ²Π°Ρ€", + "quantity": "ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ", + "price": "Π¦Π΅Π½Π°", + "total": "Π‘ΡƒΠΌΠΌΠ°" + }, + "checkout": { + "goToCheckout": "ΠžΡ„ΠΎΡ€ΠΌΠΈΡ‚ΡŒ Π·Π°ΠΊΠ°Π·", + "goToDashboard": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ", + "error": { + "title": "Π§Ρ‚ΠΎ-Ρ‚ΠΎ пошло Π½Π΅ Ρ‚Π°ΠΊ", + "description": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΏΠΎΠ·ΠΆΠ΅." + }, + "timeLeft": "ΠžΡΡ‚Π°Π»ΠΎΡΡŒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ {{timeLeft}}", + "timeoutTitle": "Π‘Ρ€ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ истСкло", + "timeoutDescription": "Π‘Ρ€ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ‚ΠΎΠ²Π°Ρ€Π° {{productTitle}} Π² ΠΊΠΎΡ€Π·ΠΈΠ½Π΅ истСкло.", + "timeoutAction": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ" + }, + "discountCode": { + "title": "ΠŸΠΎΠ΄Π°Ρ€ΠΎΡ‡Π½Π°Ρ ΠΊΠ°Ρ€Ρ‚Π° ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠΌΠΎΠΊΠΎΠ΄", + "label": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠΌΠΎΠΊΠΎΠ΄", + "apply": "ΠŸΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ", + "subtitle": "Если Ρ…ΠΎΡ‚ΠΈΡ‚Π΅, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠΌΠΎΠΊΠΎΠ΄", + "placeholder": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠΎΠΊΠΎΠ΄" + }, + "items": { + "synlabAnalyses": { + "productColumnLabel": "НазваниС Π°Π½Π°Π»ΠΈΠ·Π°" + }, + "ttoServices": { + "productColumnLabel": "НазваниС услуги" + }, + "delete": { + "success": "Π’ΠΎΠ²Π°Ρ€ ΡƒΠ΄Π°Π»Π΅Π½ ΠΈΠ· ΠΊΠΎΡ€Π·ΠΈΠ½Ρ‹", + "loading": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ Ρ‚ΠΎΠ²Π°Ρ€Π° ΠΈΠ· ΠΊΠΎΡ€Π·ΠΈΠ½Ρ‹", + "error": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Ρ‚ΠΎΠ²Π°Ρ€ ΠΈΠ· ΠΊΠΎΡ€Π·ΠΈΠ½Ρ‹" + }, + "analysisLocation": { + "success": "ΠœΠ΅ΡΡ‚ΠΎΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΎ", + "loading": "ОбновлСниС мСстополоТСния", + "error": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ мСстополоТСниС" + } + }, + "order": { + "title": "Π—Π°ΠΊΠ°Π·" + }, + "orderConfirmed": { + "title": "Π—Π°ΠΊΠ°Π· ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ„ΠΎΡ€ΠΌΠ»Π΅Π½", + "summary": "Услуги", + "subtotal": "ΠŸΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹ΠΉ ΠΈΡ‚ΠΎΠ³", + "taxes": "Налоги", + "giftCard": "ΠŸΠΎΠ΄Π°Ρ€ΠΎΡ‡Π½Π°Ρ ΠΊΠ°Ρ€Ρ‚Π°", + "total": "Π‘ΡƒΠΌΠΌΠ°", + "orderDate": "Π”Π°Ρ‚Π° Π·Π°ΠΊΠ°Π·Π°", + "orderNumber": "НомСр Π·Π°ΠΊΠ°Π·Π°", + "orderStatus": "Бтатус Π·Π°ΠΊΠ°Π·Π°", + "paymentStatus": "Бтатус ΠΎΠΏΠ»Π°Ρ‚Ρ‹" + }, + "montonioCallback": { + "title": "ΠŸΡ€ΠΎΡ†Π΅ΡΡ ΠΎΠΏΠ»Π°Ρ‚Ρ‹ Montonio", + "description": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅, ΠΏΠΎΠΊΠ° ΠΌΡ‹ Π·Π°Π²Π΅Ρ€ΡˆΠΈΠΌ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ вашСго ΠΏΠ»Π°Ρ‚Π΅ΠΆΠ°." + }, + "locations": { + "title": "ΠœΠ΅ΡΡ‚ΠΎΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для сдачи Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "description": "Если Ρƒ вас Π½Π΅Ρ‚ возмоТности ΠΏΡ€ΠΈΠΉΡ‚ΠΈ Π² Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ΅ мСсто для сдачи Π°Π½Π°Π»ΠΈΠ·ΠΎΠ², Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΡΠ΅Ρ‚ΠΈΡ‚ΡŒ любой ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ для вас ΠΏΡƒΠ½ΠΊΡ‚ Π·Π°Π±ΠΎΡ€Π° ΠΊΡ€ΠΎΠ²ΠΈ.", + "locationSelect": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ мСстополоТСниС" + } +} \ No newline at end of file diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index f27aea6..ebf250c 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -1,118 +1,140 @@ { - "homeTabLabel": "Home", - "homeTabDescription": "Welcome to your home page", - "accountMembers": "Company Members", - "membersTabDescription": "Here you can manage the members of your company.", - "billingTabLabel": "Billing", - "billingTabDescription": "Manage your billing and subscription", - "dashboardTabLabel": "Dashboard", - "settingsTabLabel": "Settings", - "profileSettingsTabLabel": "Profile", - "subscriptionSettingsTabLabel": "Subscription", - "dashboardTabDescription": "An overview of your account's activity and performance across all your projects.", - "settingsTabDescription": "Manage your settings and preferences.", - "emailAddress": "Email Address", - "password": "Password", - "modalConfirmationQuestion": "Are you sure you want to continue?", - "imageInputLabel": "Click here to upload an image", - "cancel": "Cancel", - "clear": "Clear", - "close": "Close", - "notFound": "Not Found", - "backToHomePage": "Back to Home Page", - "goBack": "Go Back", - "genericServerError": "Sorry, something went wrong.", - "genericServerErrorHeading": "Sorry, something went wrong while processing your request. Please contact us if the issue persists.", - "pageNotFound": "Sorry, this page does not exist.", - "pageNotFoundSubHeading": "Apologies, the page you were looking for was not found", - "genericError": "Sorry, something went wrong.", - "genericErrorSubHeading": "Apologies, an error occurred while processing your request. Please contact us if the issue persists.", - "anonymousUser": "Anonymous", - "tryAgain": "Try Again", - "theme": "Theme", - "lightTheme": "Light", - "darkTheme": "Dark", - "systemTheme": "System", - "expandSidebar": "Expand Sidebar", - "collapseSidebar": "Collapse Sidebar", - "documentation": "Documentation", - "getStarted": "Get Started", - "getStartedWithPlan": "Get Started with {{plan}}", - "retry": "Retry", - "contactUs": "Contact Us", - "loading": "Loading. Please wait...", - "yourAccounts": "Your Accounts", - "continue": "Continue", - "skip": "Skip", - "signedInAs": "Signed in as", - "pageOfPages": "Page {{page}} of {{total}}", - "noData": "No data available", - "pageNotFoundHeading": "Ouch! :|", - "errorPageHeading": "Ouch! :|", - "notifications": "Notifications", - "noNotifications": "No notifications", - "justNow": "Just now", - "newVersionAvailable": "New version available", - "newVersionAvailableDescription": "A new version of the app is available. It is recommended to refresh the page to get the latest updates and avoid any issues.", - "newVersionSubmitButton": "Reload and Update", - "back": "Back", - "welcome": "Welcome", - "shoppingCart": "Shopping cart", - "search": "Search{{end}}", - "myActions": "My actions", + "homeTabLabel": "Главная", + "homeTabDescription": "Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° Π²Π°ΡˆΡƒ домашнюю страницу", + "accountMembers": "Π§Π»Π΅Π½Ρ‹ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "membersTabDescription": "Π—Π΄Π΅ΡΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Ρ‡Π»Π΅Π½Π°ΠΌΠΈ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "billingTabLabel": "ΠžΠΏΠ»Π°Ρ‚Π°", + "billingTabDescription": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠΏΠ»Π°Ρ‚ΠΎΠΉ ΠΈ подпиской", + "dashboardTabLabel": "ПанСль", + "settingsTabLabel": "Настройки", + "profileSettingsTabLabel": "ΠŸΡ€ΠΎΡ„ΠΈΠ»ΡŒ", + "subscriptionSettingsTabLabel": "Подписка", + "dashboardTabDescription": "ΠžΠ±Π·ΠΎΡ€ активности ΠΈ эффСктивности вашСй ΡƒΡ‡Π΅Ρ‚Π½ΠΎΠΉ записи ΠΏΠΎ всСм ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°ΠΌ.", + "settingsTabDescription": "УправляйтС своими настройками ΠΈ прСдпочтСниями.", + "emailAddress": "ЭлСктронная ΠΏΠΎΡ‡Ρ‚Π°", + "password": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ", + "modalConfirmationQuestion": "Π’Ρ‹ ΡƒΠ²Π΅Ρ€Π΅Π½Ρ‹, Ρ‡Ρ‚ΠΎ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ?", + "imageInputLabel": "НаТмитС здСсь, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅", + "cancel": "ΠžΡ‚ΠΌΠ΅Π½Π°", + "clear": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ", + "close": "Π—Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ", + "notFound": "НС Π½Π°ΠΉΠ΄Π΅Π½ΠΎ", + "backToHomePage": "Π’Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ Π½Π° Π³Π»Π°Π²Π½ΡƒΡŽ", + "goBack": "Назад", + "genericServerError": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ пошло Π½Π΅ Ρ‚Π°ΠΊ.", + "genericServerErrorHeading": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ вашСго запроса. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с Π½Π°ΠΌΠΈ, Ссли ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π½Π΅ исчСзнСт.", + "pageNotFound": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, эта страница Π½Π΅ сущСствуСт.", + "pageNotFoundSubHeading": "К соТалСнию, Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π΅ΠΌΠ°Ρ страница Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Π°", + "genericError": "Π˜Π·Π²ΠΈΠ½ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ пошло Π½Π΅ Ρ‚Π°ΠΊ.", + "genericErrorSubHeading": "К соТалСнию, ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ вашСго запроса. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с Π½Π°ΠΌΠΈ, Ссли ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π½Π΅ исчСзнСт.", + "anonymousUser": "Анонимный ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ", + "tryAgain": "ΠŸΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ снова", + "theme": "Π’Π΅ΠΌΠ°", + "lightTheme": "БвСтлая", + "darkTheme": "Вёмная", + "systemTheme": "БистСмная", + "expandSidebar": "Π Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Π±ΠΎΠΊΠΎΠ²ΠΎΠ΅ мСню", + "collapseSidebar": "Π‘Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Π±ΠΎΠΊΠΎΠ²ΠΎΠ΅ мСню", + "documentation": "ДокумСнтация", + "getStarted": "ΠΠ°Ρ‡Π°Ρ‚ΡŒ!", + "getStartedWithPlan": "ΠΠ°Ρ‡Π°Ρ‚ΡŒ с {{plan}}", + "retry": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚ΡŒ", + "contactUs": "Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с Π½Π°ΠΌΠΈ", + "loading": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅...", + "yourAccounts": "Π’Π°ΡˆΠΈ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Ρ‹", + "continue": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ", + "skip": "ΠŸΡ€ΠΎΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ", + "signedInAs": "Π’Ρ‹ вошли ΠΊΠ°ΠΊ", + "pageOfPages": "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° {{page}} / {{total}}", + "noData": "НСт Π΄Π°Π½Π½Ρ‹Ρ…", + "pageNotFoundHeading": "Упс! :|", + "errorPageHeading": "Упс! :|", + "notifications": "УвСдомлСния", + "noNotifications": "НСт ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ", + "justNow": "ΠŸΡ€ΡΠΌΠΎ сСйчас", + "newVersionAvailable": "Доступна новая вСрсия", + "newVersionAvailableDescription": "Доступна новая вСрсия прилоТСния. РСкомСндуСтся ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ страницу, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ послСдниС обновлСния ΠΈ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹Ρ… ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ.", + "newVersionSubmitButton": "ΠŸΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΈ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "back": "Назад", + "welcome": "Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ", + "shoppingCart": "ΠšΠΎΡ€Π·ΠΈΠ½Π°", + "shoppingCartCount": "ΠšΠΎΡ€Π·ΠΈΠ½Π° ({{count}})", + "search": "Поиск{{end}}", + "myActions": "Мои дСйствия", "healthPackageComparison": { - "label": "Health package comparison", - "description": "AlljΓ€rgnevalt on antud eelinfo (sugu, vanus ja kehamassiindeksi) pΓ΅hjal tehtud personalne terviseauditi valik. Tabelis on vΓ΅imalik soovitatud terviseuuringute paketile lisada ΓΌksikuid uuringuid juurde." + "label": "Π‘Ρ€Π°Π²Π½Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΡ", + "description": "НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ ΠΏΠ΅Ρ€ΡΠΎΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ Π²Ρ‹Π±ΠΎΡ€ ΠΏΠ°ΠΊΠ΅Ρ‚Π° мСдицинского обслСдования Π½Π° основС ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ (ΠΏΠΎΠ», возраст ΠΈ индСкс массы Ρ‚Π΅Π»Π°). Π’ Ρ‚Π°Π±Π»ΠΈΡ†Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΠΎΠΌΡƒ ΠΏΠ°ΠΊΠ΅Ρ‚Ρƒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ исслСдования." }, "routes": { - "home": "Home", - "overview": "Overview", - "booking": "Booking", - "myOrders": "My orders", - "orderAnalysis": "Order analysis", - "orderAnalysisPackage": "Order analysis package", - "orderHealthAnalysis": "Order health analysis", - "account": "Account", - "members": "Members", - "billing": "Billing", - "dashboard": "Dashboard", - "settings": "Settings", - "profile": "Profile", - "application": "Application" + "home": "Главная", + "overview": "ΠžΠ±Π·ΠΎΡ€", + "booking": "Π—Π°Π±Ρ€ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ врСмя", + "myOrders": "Мои Π·Π°ΠΊΠ°Π·Ρ‹", + "analysisResults": "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "orderAnalysisPackage": "Π—Π°ΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "orderAnalysis": "Π—Π°ΠΊΠ°Π·Π°Ρ‚ΡŒ Π°Π½Π°Π»ΠΈΠ·", + "orderHealthAnalysis": "Π—Π°ΠΊΠ°Π·Π°Ρ‚ΡŒ обслСдованиС", + "account": "Аккаунт", + "members": "Участники", + "billing": "ΠžΠΏΠ»Π°Ρ‚Π°", + "dashboard": "ΠžΠ±Π·ΠΎΡ€", + "settings": "Настройки", + "profile": "ΠŸΡ€ΠΎΡ„ΠΈΠ»ΡŒ", + "application": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "pickTime": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ врСмя" }, "roles": { "owner": { - "label": "Admin" + "label": "Администратор" }, "member": { - "label": "Member" + "label": "Участник" } }, "otp": { - "requestVerificationCode": "Request Verification Code", - "requestVerificationCodeDescription": "We must verify your identity to continue with this action. We'll send a verification code to the email address {{email}}.", - "sendingCode": "Sending Code...", - "sendVerificationCode": "Send Verification Code", - "enterVerificationCode": "Enter Verification Code", - "codeSentToEmail": "We've sent a verification code to the email address {{email}}.", - "verificationCode": "Verification Code", - "enterCodeFromEmail": "Enter the 6-digit code we sent to your email.", - "verifying": "Verifying...", - "verifyCode": "Verify Code", - "requestNewCode": "Request New Code", - "errorSendingCode": "Error sending code. Please try again." + "requestVerificationCode": "Π—Π°ΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ ΠΊΠΎΠ΄ подтвСрТдСния", + "requestVerificationCodeDescription": "ΠœΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ Π²Π°ΡˆΡƒ Π»ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ для продолТСния. ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠΌ ΠΊΠΎΠ΄ подтвСрТдСния Π½Π° элСктронный адрСс {{email}}.", + "sendingCode": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ΠΊΠΎΠ΄Π°...", + "sendVerificationCode": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄ подтвСрТдСния", + "enterVerificationCode": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΊΠΎΠ΄ подтвСрТдСния", + "codeSentToEmail": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ ΠΊΠΎΠ΄ подтвСрТдСния Π½Π° элСктронный адрСс {{email}}.", + "verificationCode": "Код подтвСрТдСния", + "enterCodeFromEmail": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ 6-Π·Π½Π°Ρ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π½Π° Π²Π°ΡˆΡƒ ΠΏΠΎΡ‡Ρ‚Ρƒ.", + "verifying": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°...", + "verifyCode": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄", + "requestNewCode": "Π—Π°ΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ ΠΊΠΎΠ΄", + "errorSendingCode": "Ошибка ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ ΠΊΠΎΠ΄Π°. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова." }, "cookieBanner": { - "title": "Hey, we use cookies πŸͺ", - "description": "This website uses cookies to ensure you get the best experience on our website.", - "reject": "Reject", - "accept": "Accept" + "title": "ΠŸΡ€ΠΈΠ²Π΅Ρ‚, ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΠΊΡƒΠΊΠΈ πŸͺ", + "description": "Π­Ρ‚ΠΎΡ‚ сайт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ„Π°ΠΉΠ»Ρ‹ cookie, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ Π²Π°ΠΌ Π½Π°ΠΈΠ»ΡƒΡ‡ΡˆΠΈΠΉ ΠΎΠΏΡ‹Ρ‚.", + "reject": "ΠžΡ‚ΠΊΠ»ΠΎΠ½ΠΈΡ‚ΡŒ", + "accept": "ΠŸΡ€ΠΈΠ½ΡΡ‚ΡŒ" }, - "doctor": "Doctor", - "save": "Save", - "saveAsDraft": "Save as draft", - "confirm": "Confirm", - "previous": "Previous", - "next": "Next", - "invalidDataError": "Invalid data submitted" + "formField": { + "companyName": "НазваниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "contactPerson": "ΠšΠΎΠ½Ρ‚Π°ΠΊΡ‚Π½ΠΎΠ΅ Π»ΠΈΡ†ΠΎ", + "email": "ЭлСктронная ΠΏΠΎΡ‡Ρ‚Π°", + "phone": "Π’Π΅Π»Π΅Ρ„ΠΎΠ½", + "firstName": "Имя", + "lastName": "Ѐамилия", + "personalCode": "Π›ΠΈΡ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ΄", + "city": "Π“ΠΎΡ€ΠΎΠ΄", + "weight": "ВСс", + "height": "Рост", + "occurance": "Частота ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ", + "amount": "Π‘ΡƒΠΌΠΌΠ°", + "selectDate": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π΄Π°Ρ‚Ρƒ" + }, + "wallet": { + "balance": "Баланс вашСго MedReport Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "expiredAt": "Π”Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π΄ΠΎ {{expiredAt}}" + }, + "doctor": "Π’Ρ€Π°Ρ‡", + "save": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ", + "saveAsDraft": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ Ρ‡Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ", + "confirm": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ", + "previous": "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ", + "next": "Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ", + "invalidDataError": "НСкоррСктныС Π΄Π°Π½Π½Ρ‹Π΅" } \ No newline at end of file diff --git a/public/locales/ru/dashboard.json b/public/locales/ru/dashboard.json index 3893ce4..f7505ae 100644 --- a/public/locales/ru/dashboard.json +++ b/public/locales/ru/dashboard.json @@ -1,16 +1,22 @@ { - "recentlyCheckedDescription": "Super, oled kΓ€inud tervist kontrollimas. Siin on sinule olulised nΓ€itajad", - "respondToQuestion": "Respond", - "gender": "Gender", - "male": "Male", - "female": "Female", - "age": "Age", - "height": "Height", - "weight": "Weight", - "bmi": "BMI", - "bloodPressure": "Blood pressure", - "cholesterol": "Cholesterol", - "ldlCholesterol": "LDL Cholesterol", - "smoking": "Smoking", - "recommendedForYou": "Recommended for you" + "recentlyCheckedDescription": "ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎ, Π²Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠ»ΠΈ своё Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΠ΅. Π’ΠΎΡ‚ Π²Π°ΠΆΠ½Ρ‹Π΅ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ для вас", + "respondToQuestion": "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° вопрос", + "gender": "Пол", + "male": "ΠœΡƒΠΆΡ‡ΠΈΠ½Π°", + "female": "Π–Π΅Π½Ρ‰ΠΈΠ½Π°", + "age": "Возраст", + "height": "Рост", + "weight": "ВСс", + "bmi": "ИМВ", + "bloodPressure": "Π”Π°Π²Π»Π΅Π½ΠΈΠ΅", + "cholesterol": "Π₯олСстСрин", + "ldlCholesterol": "Π›ΠŸΠΠŸ холСстСрин", + "smoking": "ΠšΡƒΡ€Π΅Π½ΠΈΠ΅", + "recommendedForYou": "Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°Ρ†ΠΈΠΈ для вас", + "heroCard": { + "orderAnalysis": { + "title": "Π—Π°ΠΊΠ°Π·Π°Ρ‚ΡŒ Π°Π½Π°Π»ΠΈΠ·", + "description": "Π—Π°ΠΊΠ°ΠΆΠΈΡ‚Π΅ подходящий для вас Π°Π½Π°Π»ΠΈΠ·" + } + } } \ No newline at end of file diff --git a/public/locales/ru/doctor.json b/public/locales/ru/doctor.json index 4f6b339..5ab7fde 100644 --- a/public/locales/ru/doctor.json +++ b/public/locales/ru/doctor.json @@ -1,50 +1,51 @@ { "sidebar": { - "dashboard": "Overview", - "openReviews": "Open jobs", - "myReviews": "My jobs", - "completedReviews": "Completed jobs" + "dashboard": "ΠžΠ±Π·ΠΎΡ€", + "openReviews": "Π‘Π²ΠΎΠ±ΠΎΠ΄Π½Ρ‹Π΅ задания", + "myReviews": "Мои задания", + "completedReviews": "Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Π΅ задания" }, - "openReviews": "Open jobs", - "myReviews": "My jobs", - "completedReviews": "Completed jobs", - "otherReviews": "Other jobs", + "openReviews": "Π‘Π²ΠΎΠ±ΠΎΠ΄Π½Ρ‹Π΅ задания", + "myReviews": "Мои задания", + "completedReviews": "Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Π΅ задания", + "otherReviews": "Π”Ρ€ΡƒΠ³ΠΈΠ΅ задания", "resultsTable": { - "patientName": "Patient name", - "serviceName": "Service", - "orderNr": "Order number", - "time": "Time", - "assignedTo": "Doctor", - "resultsStatus": "Analysis results", - "waitingForNr": "Waiting for {{nr}}", - "responsesReceived": "Results complete" + "patientName": "Имя ΠΏΠ°Ρ†ΠΈΠ΅Π½Ρ‚Π°", + "serviceName": "Услуга", + "orderNr": "НомСр Π·Π°ΠΊΠ°Π·Π°", + "time": "ВрСмя", + "assignedTo": "Π’Ρ€Π°Ρ‡", + "resultsStatus": "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "waitingForNr": "Π’ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠΈ {{nr}}", + "language": "ΠŸΡ€Π΅Π΄ΠΏΠΎΡ‡Ρ‚ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ язык", + "responsesReceived": "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π³ΠΎΡ‚ΠΎΠ²Ρ‹" }, - "otherPatients": "Other patients", - "analyses": "Analyses", - "open": "Open", - "name": "Name", - "personalCode": "Personal code", - "dobAndAge": "Date of birth and age", - "bmi": "Body mass index", - "smoking": "Smoking", - "phone": "Phone", - "email": "Email", - "results": "Analysis results", - "feedback": "Summary", - "selectJob": "Select", - "unselectJob": "Unselect", - "previousResults": "Previous results ({{date}})", - "labComment": "Lab comment", + "otherPatients": "Π”Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΠ°Ρ†ΠΈΠ΅Π½Ρ‚Ρ‹", + "analyses": "Анализы", + "open": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ", + "name": "Имя", + "personalCode": "Π›ΠΈΡ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ΄", + "dobAndAge": "Π”Π°Ρ‚Π° роТдСния ΠΈ возраст", + "bmi": "ИндСкс массы Ρ‚Π΅Π»Π°", + "smoking": "ΠšΡƒΡ€Π΅Π½ΠΈΠ΅", + "phone": "Π’Π΅Π»Π΅Ρ„ΠΎΠ½", + "email": "Π­Π». ΠΏΠΎΡ‡Ρ‚Π°", + "results": "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "feedback": "Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅", + "selectJob": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ", + "unselectJob": "ΠžΡ‚ΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ", + "previousResults": "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠ΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ ({{date}})", + "labComment": "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ Π»Π°Π±ΠΎΡ€Π°Ρ‚ΠΎΡ€ΠΈΠΈ", "confirmFeedbackModal": { - "title": "Confirm publishing summary", - "description": "When confirmed, the summary will be published to the patient." + "title": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡŽ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ", + "description": "ПослС подтвСрТдСния Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½ΠΎ для ΠΏΠ°Ρ†ΠΈΠ΅Π½Ρ‚Π°." }, "error": { - "UNKNOWN": "Something went wrong", - "JOB_ASSIGNED": "Job already selected" + "UNKNOWN": "Π§Ρ‚ΠΎ-Ρ‚ΠΎ пошло Π½Π΅ Ρ‚Π°ΠΊ", + "JOB_ASSIGNED": "Π—Π°Π΄Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ занято" }, - "updateFeedbackSuccess": "Summary updated", - "updateFeedbackLoading": "Updating summary...", - "updateFeedbackError": "Failed to update summary", - "feedbackLengthError": "Summary must be at least 10 characters" + "updateFeedbackSuccess": "Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΎ", + "updateFeedbackLoading": "ОбновлСниС Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ...", + "updateFeedbackError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅", + "feedbackLengthError": "Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ 10 символов" } \ No newline at end of file diff --git a/public/locales/ru/marketing.json b/public/locales/ru/marketing.json index aeeb1b4..8fcbcf8 100644 --- a/public/locales/ru/marketing.json +++ b/public/locales/ru/marketing.json @@ -1,41 +1,41 @@ { - "blog": "Blog", - "blogSubtitle": "News and updates about the platform", - "documentation": "Documentation", - "documentationSubtitle": "Tutorials and guide to get started with the platform", + "blog": "Π‘Π»ΠΎΠ³", + "blogSubtitle": "Новости ΠΈ обновлСния ΠΎ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅", + "documentation": "ДокумСнтация", + "documentationSubtitle": "Π£Ρ‡Π΅Π±Π½ΠΈΠΊΠΈ ΠΈ руководство ΠΏΠΎ Π½Π°Ρ‡Π°Π»Ρƒ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠΎΠΉ", "faq": "FAQ", - "faqSubtitle": "Frequently asked questions about the platform", - "pricing": "Pricing", - "pricingSubtitle": "Pricing plans and payment options", - "backToBlog": "Back to blog", - "noPosts": "No posts found", - "blogPaginationNext": "Next Page", - "blogPaginationPrevious": "Previous Page", - "readMore": "Read more", - "contactFaq": "If you have any questions, please contact us", - "contact": "Contact", - "about": "About", - "product": "Product", - "legal": "Legal", - "termsOfService": "Terms of Service", - "termsOfServiceDescription": "Our terms and conditions", - "cookiePolicy": "Cookie Policy", - "cookiePolicyDescription": "Our cookie policy and how we use them", - "privacyPolicy": "Privacy Policy", - "privacyPolicyDescription": "Our privacy policy and how we use your data", - "contactDescription": "Contact us for any questions or feedback", - "contactHeading": "Send us a message", - "contactSubheading": "We will get back to you as soon as possible", - "contactName": "Your Name", - "contactEmail": "Your Email", - "contactMessage": "Your Message", - "sendMessage": "Send Message", - "contactSuccess": "Your message has been sent successfully", - "contactError": "An error occurred while sending your message", - "contactSuccessDescription": "We have received your message and will get back to you as soon as possible", - "contactErrorDescription": "An error occurred while sending your message. Please try again later", - "footerDescription": "Here you can add a description about your company or product", - "copyright": "Β© Copyright {{year}} {{product}}. All Rights Reserved.", - "heroSubtitle": "A simple, convenient, and quick overview of your health condition", - "notInterestedInAudit": "Currently not interested in a health audit" + "faqSubtitle": "Часто Π·Π°Π΄Π°Π²Π°Π΅ΠΌΡ‹Π΅ вопросы ΠΎ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅", + "pricing": "Π¦Π΅Π½Ρ‹", + "pricingSubtitle": "Π’Π°Ρ€ΠΈΡ„Π½Ρ‹Π΅ ΠΏΠ»Π°Π½Ρ‹ ΠΈ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ ΠΎΠΏΠ»Π°Ρ‚Ρ‹", + "backToBlog": "Назад ΠΊ Π±Π»ΠΎΠ³Ρƒ", + "noPosts": "ΠŸΠΎΡΡ‚Ρ‹ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹", + "blogPaginationNext": "Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ страница", + "blogPaginationPrevious": "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π°Ρ страница", + "readMore": "Π§ΠΈΡ‚Π°Ρ‚ΡŒ Π΄Π°Π»Π΅Π΅", + "contactFaq": "Если Ρƒ вас Π΅ΡΡ‚ΡŒ вопросы, поТалуйста, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с Π½Π°ΠΌΠΈ", + "contact": "ΠšΠΎΠ½Ρ‚Π°ΠΊΡ‚Ρ‹", + "about": "О нас", + "product": "ΠŸΡ€ΠΎΠ΄ΡƒΠΊΡ‚", + "legal": "ΠŸΡ€Π°Π²ΠΎΠ²Π°Ρ информация", + "termsOfService": "Условия обслуТивания", + "termsOfServiceDescription": "Наши ΠΏΡ€Π°Π²ΠΈΠ»Π° ΠΈ условия", + "cookiePolicy": "ΠŸΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° использования Ρ„Π°ΠΉΠ»ΠΎΠ² cookie", + "cookiePolicyDescription": "Наша ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° использования cookie ΠΈ ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΈΡ… примСняСм", + "privacyPolicy": "ΠŸΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° ΠΊΠΎΠ½Ρ„ΠΈΠ΄Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ", + "privacyPolicyDescription": "Наша ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° ΠΊΠΎΠ½Ρ„ΠΈΠ΄Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ ΠΈ ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ваши Π΄Π°Π½Π½Ρ‹Π΅", + "contactDescription": "Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с Π½Π°ΠΌΠΈ ΠΏΠΎ Π»ΡŽΠ±Ρ‹ΠΌ вопросам ΠΈΠ»ΠΈ ΠΎΡ‚Π·Ρ‹Π²Π°ΠΌ", + "contactHeading": "ΠžΡ‚ΠΏΡ€Π°Π²ΡŒΡ‚Π΅ Π½Π°ΠΌ сообщСниС", + "contactSubheading": "ΠœΡ‹ свяТСмся с Π²Π°ΠΌΠΈ ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ скорСС", + "contactName": "Π’Π°ΡˆΠ΅ имя", + "contactEmail": "Π’Π°Ρˆ email", + "contactMessage": "Π’Π°ΡˆΠ΅ сообщСниС", + "sendMessage": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ сообщСниС", + "contactSuccess": "Π’Π°ΡˆΠ΅ сообщСниС ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ", + "contactError": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ сообщСния", + "contactSuccessDescription": "ΠœΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ вашС сообщСниС ΠΈ свяТСмся с Π²Π°ΠΌΠΈ Π² блиТайшСС врСмя", + "contactErrorDescription": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ сообщСния. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΏΠΎΠ·ΠΆΠ΅", + "footerDescription": "Π—Π΄Π΅ΡΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ описаниС вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚Π°", + "copyright": "Β© Copyright {{year}} {{product}}. ВсС ΠΏΡ€Π°Π²Π° Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Ρ‹.", + "heroSubtitle": "ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ, ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΠΈ быстрый ΠΎΠ±Π·ΠΎΡ€ вашСго Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΡ", + "notInterestedInAudit": "НС Ρ…ΠΎΡ‡Ρƒ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π°ΡƒΠ΄ΠΈΡ‚ Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΡ Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚" } \ No newline at end of file diff --git a/public/locales/ru/order-analysis-package.json b/public/locales/ru/order-analysis-package.json index 9502bf1..e14d502 100644 --- a/public/locales/ru/order-analysis-package.json +++ b/public/locales/ru/order-analysis-package.json @@ -1,7 +1,9 @@ { - "title": "Select analysis package", - "noPackagesAvailable": "No packages available", - "selectThisPackage": "Select this package", - "selectPackage": "Select package", - "comparePackages": "Compare packages" -} \ No newline at end of file + "title": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "noPackagesAvailable": "Бписок услуг Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΏΠΎΠ·ΠΆΠ΅", + "selectThisPackage": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ этот ΠΏΠ°ΠΊΠ΅Ρ‚", + "selectPackage": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚", + "comparePackages": "Π‘Ρ€Π°Π²Π½ΠΈΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹", + "analysisPackageAddedToCart": "ΠŸΠ°ΠΊΠ΅Ρ‚ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ² Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ", + "analysisPackageAddToCartError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ² Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ" +} diff --git a/public/locales/ru/order-analysis.json b/public/locales/ru/order-analysis.json new file mode 100644 index 0000000..ea36b5c --- /dev/null +++ b/public/locales/ru/order-analysis.json @@ -0,0 +1,7 @@ +{ + "title": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π°Π½Π°Π»ΠΈΠ·", + "description": "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ всСх Π°Π½Π°Π»ΠΈΠ·ΠΎΠ² Π±ΡƒΠ΄ΡƒΡ‚ доступны Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ 1–3 Ρ€Π°Π±ΠΎΡ‡ΠΈΡ… Π΄Π½Π΅ΠΉ послС сдачи ΠΊΡ€ΠΎΠ²ΠΈ.", + "analysisNotAvailable": "Π—Π°ΠΊΠ°Π· Π°Π½Π°Π»ΠΈΠ·Π° Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ нСдоступСн", + "analysisAddedToCart": "Анализ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ", + "analysisAddToCartError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π°Π½Π°Π»ΠΈΠ· Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ" +} \ No newline at end of file diff --git a/public/locales/ru/orders.json b/public/locales/ru/orders.json new file mode 100644 index 0000000..c42a230 --- /dev/null +++ b/public/locales/ru/orders.json @@ -0,0 +1,19 @@ +{ + "title": "Π—Π°ΠΊΠ°Π·Ρ‹", + "description": "ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅ ваши Π·Π°ΠΊΠ°Π·Ρ‹", + "table": { + "analysisPackage": "ΠŸΠ°ΠΊΠ΅Ρ‚ Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", + "otherOrders": "Π—Π°ΠΊΠ°Π·", + "createdAt": "Π”Π°Ρ‚Π° Π·Π°ΠΊΠ°Π·Π°", + "status": "Бтатус" + }, + "status": { + "QUEUED": "ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ", + "PROCESSING": "ΠŸΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ Π² Synlab", + "PARTIAL_ANALYSIS_RESPONSE": "ЧастичныС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹", + "FULL_ANALYSIS_RESPONSE": "ВсС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Ρ‹, оТидаСтся Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π²Ρ€Π°Ρ‡Π°", + "COMPLETED": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΎ", + "REJECTED": "Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½ΠΎ", + "CANCELLED": "ΠžΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ" + } +} \ No newline at end of file diff --git a/public/locales/ru/product.json b/public/locales/ru/product.json index 3a5c425..b8df373 100644 --- a/public/locales/ru/product.json +++ b/public/locales/ru/product.json @@ -1,31 +1,31 @@ { - "nrOfAnalyses": "{{nr}} analyses", + "nrOfAnalyses": "{{nr}} Π°Π½Π°Π»ΠΈΠ·ΠΎΠ²", "clinicalBloodDraw": { - "label": "Kliiniline vereanalΓΌΓΌs", - "description": "Pending" + "label": "ΠšΠ»ΠΈΠ½ΠΈΡ‡Π΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· ΠΊΡ€ΠΎΠ²ΠΈ", + "description": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ" }, "crp": { - "label": "C-reaktiivne valk (CRP)", - "description": "Pending" + "label": "Π‘-Ρ€Π΅Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΉ Π±Π΅Π»ΠΎΠΊ (CRP)", + "description": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ" }, "ferritin": { - "label": "Ferritiin", - "description": "Pending" + "label": "Π€Π΅Ρ€Ρ€ΠΈΡ‚ΠΈΠ½", + "description": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ" }, "vitaminD": { - "label": "D-vitamiin", - "description": "Pending" + "label": "Π’ΠΈΡ‚Π°ΠΌΠΈΠ½ D", + "description": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ" }, "glucose": { - "label": "GlΓΌkoos", - "description": "Pending" + "label": "Π“Π»ΡŽΠΊΠΎΠ·Π°", + "description": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ" }, "alat": { - "label": "Alaniini aminotransferaas", - "description": "Pending" + "label": "АланинаминотрансфСраза", + "description": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ" }, "ast": { - "label": "Aspartaadi aminotransferaas", - "description": "Pending" + "label": "АспартатаминотрансфСраза", + "description": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ" } } \ No newline at end of file diff --git a/public/locales/ru/teams.json b/public/locales/ru/teams.json index 5a63f7e..0b67de1 100644 --- a/public/locales/ru/teams.json +++ b/public/locales/ru/teams.json @@ -1,164 +1,197 @@ { "home": { - "pageTitle": "Home" + "pageTitle": "ΠžΠ±Π·ΠΎΡ€", + "headerTitle": "ΠžΠ±Π·ΠΎΡ€ Tervisekassa {{companyName}}", + "healthDetails": "Π”Π°Π½Π½Ρ‹Π΅ ΠΎ Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "membersSettingsButtonTitle": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ сотрудниками", + "membersSettingsButtonDescription": "ДобавляйтС, Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΈΠ»ΠΈ удаляйтС сотрудников.", + "membersBillingButtonTitle": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π±ΡŽΠ΄ΠΆΠ΅Ρ‚ΠΎΠΌ", + "membersBillingButtonDescription": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅, ΠΊΠ°ΠΊ Ρ€Π°ΡΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ Π±ΡŽΠ΄ΠΆΠ΅Ρ‚ ΠΌΠ΅ΠΆΠ΄Ρƒ сотрудниками." }, "settings": { - "pageTitle": "Settings", - "pageDescription": "Manage your Company details", - "teamLogo": "Company Logo", - "teamLogoDescription": "Update your company's logo to make it easier to identify", - "teamName": "Company Name", - "teamNameDescription": "Update your company's name", - "dangerZone": "Danger Zone", - "dangerZoneDescription": "This section contains actions that are irreversible" + "pageTitle": "Настройки", + "pageDescription": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "teamLogo": "Π›ΠΎΠ³ΠΎΡ‚ΠΈΠΏ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "teamLogoDescription": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ Π»ΠΎΠ³ΠΎΡ‚ΠΈΠΏ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ для упрощСния ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ", + "teamName": "НазваниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "teamNameDescription": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "dangerZone": "Опасная Π·ΠΎΠ½Π°", + "dangerZoneDescription": "Π­Ρ‚ΠΎΡ‚ Ρ€Π°Π·Π΄Π΅Π» содСрТит дСйствия, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ" }, "members": { - "pageTitle": "Members" + "pageTitle": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊΠΈ" }, "billing": { - "pageTitle": "Billing" + "pageTitle": "Π‘ΠΈΠ»Π»ΠΈΠ½Π³" }, - "yourTeams": "Your Companies ({{teamsCount}})", - "createTeam": "Create a Company", - "creatingTeam": "Creating Company...", - "personalAccount": "Personal Account", - "searchAccount": "Search Account...", - "membersTabLabel": "Members", - "memberName": "Name", - "youLabel": "You", - "emailLabel": "Email", - "roleLabel": "Role", - "primaryOwnerLabel": "Primary Admin", - "joinedAtLabel": "Joined at", - "invitedAtLabel": "Invited at", - "inviteMembersPageSubheading": "Invite members to your Company", - "createTeamModalHeading": "Create Company", - "createTeamModalDescription": "Create a new Company to manage your projects and members.", - "teamNameLabel": "Company Name", - "teamNameDescription": "Your company name should be unique and descriptive", - "createTeamSubmitLabel": "Create Company", - "createTeamSuccess": "Company created successfully", - "createTeamError": "Company not created. Please try again.", - "createTeamLoading": "Creating company...", - "settingsPageLabel": "General", - "createTeamDropdownLabel": "New company", - "changeRole": "Change Role", - "removeMember": "Remove from Account", - "inviteMembersSuccess": "Members invited successfully!", - "inviteMembersError": "Sorry, we encountered an error! Please try again", - "inviteMembersLoading": "Inviting members...", - "removeInviteButtonLabel": "Remove invite", - "addAnotherMemberButtonLabel": "Add another one", - "inviteMembersButtonLabel": "Send Invites", - "removeMemberModalHeading": "You are removing this user", - "removeMemberModalDescription": "Remove this member from the company. They will no longer have access to the company.", - "removeMemberSuccessMessage": "Member removed successfully", - "removeMemberErrorMessage": "Sorry, we encountered an error. Please try again", - "removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.", - "removeMemberLoadingMessage": "Removing member...", - "removeMemberSubmitLabel": "Remove User from Company", - "chooseDifferentRoleError": "Role is the same as the current one", - "updateRole": "Update Role", - "updateRoleLoadingMessage": "Updating role...", - "updateRoleSuccessMessage": "Role updated successfully", - "updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.", - "updateMemberRoleModalHeading": "Update Member's Role", - "updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.", - "roleMustBeDifferent": "Role must be different from the current one", - "memberRoleInputLabel": "Member role", - "updateRoleDescription": "Pick a role for this member.", - "updateRoleSubmitLabel": "Update Role", - "transferOwnership": "Transfer Ownership", - "transferOwnershipDescription": "Transfer ownership of the company account to another member.", - "transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.", - "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary admin of the company account.", - "deleteInvitation": "Delete Invitation", - "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the company account.", - "deleteInviteSuccessMessage": "Invite deleted successfully", - "deleteInviteErrorMessage": "Invite not deleted. Please try again.", - "deleteInviteLoadingMessage": "Deleting invite. Please wait...", - "confirmDeletingMemberInvite": "You are deleting the invite to {{ email }}", - "transferOwnershipDisclaimer": "You are transferring ownership of the selected company account to {{ member }}.", - "transferringOwnership": "Transferring ownership...", - "transferOwnershipSuccess": "Ownership successfully transferred", - "transferOwnershipError": "Sorry, we could not transfer ownership to the selected member. Please try again.", - "deleteInviteSubmitLabel": "Delete Invite", - "youBadgeLabel": "You", - "updateTeamLoadingMessage": "Updating Company...", - "updateTeamSuccessMessage": "Company successfully updated", - "updateTeamErrorMessage": "Could not update Company. Please try again.", - "updateLogoErrorMessage": "Could not update Logo. Please try again.", - "teamNameInputLabel": "Company Name", - "teamLogoInputHeading": "Upload your company's Logo", - "teamLogoInputSubheading": "Please choose a photo to upload as your company logo.", - "updateTeamSubmitLabel": "Update Company", - "inviteMembersHeading": "Invite Members to your Company", - "inviteMembersDescription": "Invite member to your company by entering their email and role.", + "benefitStatistics": { + "budget": { + "title": "Баланс Tervisekassa ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "balance": "ΠžΡΡ‚Π°Ρ‚ΠΎΠΊ Π±ΡŽΠ΄ΠΆΠ΅Ρ‚Π° {{balance}}", + "volume": "ОбъСм Π±ΡŽΠ΄ΠΆΠ΅Ρ‚Π° {{volume}}" + }, + "data": { + "reservations": "{{value}} услуги", + "analysis": "Анализы", + "doctorsAndSpecialists": "Π’Ρ€Π°Ρ‡ΠΈ ΠΈ спСциалисты", + "researches": "ИсслСдования", + "healthResearchPlans": "ΠŸΠ°ΠΊΠ΅Ρ‚Ρ‹ мСдицинских исслСдований", + "serviceUsage": "{{value}} использованиС услуг", + "serviceSum": "Π‘ΡƒΠΌΠΌΠ° услуг", + "eclinic": "Π”ΠΈΠ³ΠΈΠΊΠ»ΠΈΠ½ΠΈΠΊΠ°" + } + }, + "healthDetails": { + "women": "Π–Π΅Π½Ρ‰ΠΈΠ½Ρ‹", + "men": "ΠœΡƒΠΆΡ‡ΠΈΠ½Ρ‹", + "avgAge": "Π‘Ρ€Π΅Π΄Π½ΠΈΠΉ возраст", + "bmi": "ИМВ", + "cholesterol": "ΠžΠ±Ρ‰ΠΈΠΉ холСстСрин", + "vitaminD": "Π’ΠΈΡ‚Π°ΠΌΠΈΠ½ D", + "smokers": "ΠšΡƒΡ€ΡΡ‰ΠΈΠ΅" + }, + "yourTeams": "Π’Π°ΡˆΠΈ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ ({{teamsCount}})", + "createTeam": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ компанию", + "creatingTeam": "Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ...", + "personalAccount": "Π›ΠΈΡ‡Π½Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "searchAccount": "Поиск Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°...", + "membersTabLabel": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊΠΈ", + "memberName": "Имя", + "youLabel": "Π’Ρ‹", + "emailLabel": "E-mail", + "roleLabel": "Роль", + "primaryOwnerLabel": "Π“Π»Π°Π²Π½Ρ‹ΠΉ Π°Π΄ΠΌΠΈΠ½", + "joinedAtLabel": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΠ»ΡΡ", + "invitedAtLabel": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½", + "inviteMembersPageSubheading": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚Π΅ сотрудников Π² компанию", + "createTeamModalHeading": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ компанию", + "createTeamModalDescription": "Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π½ΠΎΠ²ΡƒΡŽ компанию для управлСния ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°ΠΌΠΈ ΠΈ сотрудниками.", + "teamNameLabel": "НазваниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "teamNameDescription": "НазваниС вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΌ ΠΈ ΠΎΠΏΠΈΡΠ°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ", + "createTeamSubmitLabel": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ компанию", + "createTeamSuccess": "Компания ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ создана", + "createTeamError": "Компания Π½Π΅ создана. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "createTeamLoading": "Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ...", + "settingsPageLabel": "ОсновноС", + "createTeamDropdownLabel": "Новая компания", + "changeRole": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ€ΠΎΠ»ΡŒ", + "removeMember": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ· Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "inviteMembersSuccess": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½Ρ‹!", + "inviteMembersError": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка! ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "inviteMembersLoading": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ сотрудников...", + "removeInviteButtonLabel": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "addAnotherMemberButtonLabel": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‰Ρ‘ ΠΎΠ΄Π½ΠΎΠ³ΠΎ", + "inviteMembersButtonLabel": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ", + "removeMemberModalHeading": "Π’Ρ‹ удаляСтС этого ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "removeMemberModalDescription": "Π£Π΄Π°Π»ΠΈΡ‚Π΅ этого сотрудника ΠΈΠ· ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. Он большС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ доступ ΠΊ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "removeMemberSuccessMessage": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΡƒΠ΄Π°Π»Π΅Π½", + "removeMemberErrorMessage": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова", + "removeMemberErrorHeading": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ сотрудника.", + "removeMemberLoadingMessage": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ сотрудника...", + "removeMemberSubmitLabel": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈΠ· ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "chooseDifferentRoleError": "Роль совпадаСт с Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ", + "updateRole": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Ρ€ΠΎΠ»ΡŒ", + "updateRoleLoadingMessage": "ОбновлСниС Ρ€ΠΎΠ»ΠΈ...", + "updateRoleSuccessMessage": "Роль ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π°", + "updatingRoleErrorMessage": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "updateMemberRoleModalHeading": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Ρ€ΠΎΠ»ΡŒ сотрудника", + "updateMemberRoleModalDescription": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚Π΅ Ρ€ΠΎΠ»ΡŒ Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ сотрудника. Роль опрСдСляСт Π΅Π³ΠΎ ΠΏΡ€Π°Π²Π°.", + "roleMustBeDifferent": "Роль Π΄ΠΎΠ»ΠΆΠ½Π° ΠΎΡ‚Π»ΠΈΡ‡Π°Ρ‚ΡŒΡΡ ΠΎΡ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ", + "memberRoleInputLabel": "Роль сотрудника", + "updateRoleDescription": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ€ΠΎΠ»ΡŒ для этого сотрудника.", + "updateRoleSubmitLabel": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Ρ€ΠΎΠ»ΡŒ", + "transferOwnership": "ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° собствСнности", + "transferOwnershipDescription": "ΠŸΠ΅Ρ€Π΅Π΄Π°ΠΉΡ‚Π΅ ΠΏΡ€Π°Π²Π° Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π° Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ сотруднику.", + "transferOwnershipInputLabel": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ TRANSFER для подтвСрТдСния ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ собствСнности.", + "transferOwnershipInputDescription": "ΠŸΠ΅Ρ€Π΅Π΄Π°Π² ΠΏΡ€Π°Π²Π° собствСнности, Π²Ρ‹ большС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚Π΅ Π³Π»Π°Π²Π½Ρ‹ΠΌ администратором ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "deleteInvitation": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "deleteInvitationDialogDescription": "Π’Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅. ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ большС Π½Π΅ смоТСт ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Ρƒ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "deleteInviteSuccessMessage": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΡƒΠ΄Π°Π»Π΅Π½ΠΎ", + "deleteInviteErrorMessage": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ Π½Π΅ ΡƒΠ΄Π°Π»Π΅Π½ΠΎ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "deleteInviteLoadingMessage": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ...", + "confirmDeletingMemberInvite": "Π’Ρ‹ удаляСтС ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ для {{ email }}", + "transferOwnershipDisclaimer": "Π’Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚Π΅ ΠΏΡ€Π°Π²Π° собствСнности Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ {{ member }}.", + "transferringOwnership": "ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° собствСнности...", + "transferOwnershipSuccess": "ΠŸΡ€Π°Π²Π° собствСнности ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Ρ‹", + "transferOwnershipError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΏΡ€Π°Π²Π° собствСнности Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠΌΡƒ сотруднику. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "deleteInviteSubmitLabel": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "youBadgeLabel": "Π’Ρ‹", + "updateTeamLoadingMessage": "ОбновлСниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ...", + "updateTeamSuccessMessage": "Компания ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π°", + "updateTeamErrorMessage": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ компанию. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "updateLogoErrorMessage": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π»ΠΎΠ³ΠΎΡ‚ΠΈΠΏ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "teamNameInputLabel": "НазваниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "teamLogoInputHeading": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚Π΅ Π»ΠΎΠ³ΠΎΡ‚ΠΈΠΏ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "teamLogoInputSubheading": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Ρ„ΠΎΡ‚ΠΎ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π² качСствС Π»ΠΎΠ³ΠΎΡ‚ΠΈΠΏΠ° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "updateTeamSubmitLabel": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ компанию", + "inviteMembersHeading": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ сотрудников Π² компанию", + "inviteMembersDescription": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚Π΅ сотрудника Π² компанию, ΡƒΠΊΠ°Π·Π°Π² Π΅Π³ΠΎ email ΠΈ Ρ€ΠΎΠ»ΡŒ.", "emailPlaceholder": "member@email.com", - "membersPageHeading": "Members", - "inviteMembersButton": "Invite Members", - "invitingMembers": "Inviting members...", - "inviteMembersSuccessMessage": "Members invited successfully", - "inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.", - "pendingInvitesHeading": "Pending Invites", - "pendingInvitesDescription": " Here you can manage the pending invitations to your company.", - "noPendingInvites": "No pending invites found", - "loadingMembers": "Loading members...", - "loadMembersError": "Sorry, we couldn't fetch your company's members.", - "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited members.", - "loadingInvitedMembers": "Loading invited members...", - "invitedBadge": "Invited", - "duplicateInviteEmailError": "You have already entered this email address", - "invitingOwnAccountError": "Hey, that's your email!", - "dangerZone": "Danger Zone", - "dangerZoneSubheading": "Delete or leave your company", - "deleteTeam": "Delete Company", - "deleteTeamDescription": "This action cannot be undone. All data associated with this company will be deleted.", - "deletingTeam": "Deleting company", - "deleteTeamModalHeading": "Deleting Company", - "deletingTeamDescription": "You are about to delete the company {{ teamName }}. This action cannot be undone.", - "deleteTeamInputField": "Type the name of the company to confirm", - "leaveTeam": "Leave Company", - "leavingTeamModalHeading": "Leaving Company", - "leavingTeamModalDescription": "You are about to leave this company. You will no longer have access to it.", - "leaveTeamDescription": "Click the button below to leave the company. Remember, you will no longer have access to it and will need to be re-invited to join.", - "deleteTeamDisclaimer": "You are deleting the company {{ teamName }}. This action cannot be undone.", - "leaveTeamDisclaimer": "You are leaving the company {{ teamName }}. You will no longer have access to it.", - "deleteTeamErrorHeading": "Sorry, we couldn't delete your company.", - "leaveTeamErrorHeading": "Sorry, we couldn't leave your company.", - "searchMembersPlaceholder": "Search members", - "createTeamErrorHeading": "Sorry, we couldn't create your company.", - "createTeamErrorMessage": "We encountered an error creating your company. Please try again.", - "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your company account.", - "transferTeamErrorMessage": "We encountered an error transferring ownership of your company account. Please try again.", - "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.", - "updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.", - "searchInvitations": "Search Invitations", - "updateInvitation": "Update Invitation", - "removeInvitation": "Remove Invitation", - "acceptInvitation": "Accept Invitation", - "renewInvitation": "Renew Invitation", - "resendInvitation": "Resend Invitation", - "expiresAtLabel": "Expires at", - "expired": "Expired", - "active": "Active", - "inviteStatus": "Status", - "inviteNotFoundOrExpired": "Invite not found or expired", - "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company admin to renew the invite.", - "backToHome": "Back to Home", - "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the company.", - "renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.", - "renewInvitationErrorDescription": "We encountered an error renewing the invitation. Please try again.", - "signInWithDifferentAccount": "Sign in with a different account", - "signInWithDifferentAccountDescription": "If you wish to accept the invitation with a different account, please sign out and back in with the account you wish to use.", - "acceptInvitationHeading": "Accept Invitation to join {{accountName}}", - "acceptInvitationDescription": "You have been invited to join the company {{accountName}}. If you wish to accept the invitation, please click the button below.", - "continueAs": "Continue as {{email}}", - "joinTeamAccount": "Join Company", - "joiningTeam": "Joining company...", - "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the company.", - "leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.", - "reservedNameError": "This name is reserved. Please choose a different one.", - "specialCharactersError": "This name cannot contain special characters. Please choose a different one.", - "personalCode": "Π›ΠΈΡ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ΄" -} + "membersPageHeading": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊΠΈ", + "inviteMembersButton": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ сотрудников", + "invitingMembers": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ сотрудников...", + "inviteMembersSuccessMessage": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½Ρ‹", + "inviteMembersErrorMessage": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ сотрудников. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "pendingInvitesHeading": "ΠžΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΠ΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ", + "pendingInvitesDescription": "Π—Π΄Π΅ΡΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΠΌΠΈ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡΠΌΠΈ Π² Π²Π°ΡˆΡƒ компанию.", + "noPendingInvites": "НСт ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΡ… ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠΉ", + "loadingMembers": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° сотрудников...", + "loadMembersError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ список сотрудников ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "loadInvitedMembersError": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ список ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΡ‘Π½Π½Ρ‹Ρ… сотрудников ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "loadingInvitedMembers": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΡ‘Π½Π½Ρ‹Ρ… сотрудников...", + "invitedBadge": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΡ‘Π½", + "duplicateInviteEmailError": "Π’Ρ‹ ΡƒΠΆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ этот адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "invitingOwnAccountError": "Π­ΠΉ, это ваш email!", + "dangerZone": "Опасная Π·ΠΎΠ½Π°", + "dangerZoneSubheading": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ»ΠΈ ΠΏΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ компанию", + "deleteTeam": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ компанию", + "deleteTeamDescription": "Π­Ρ‚ΠΎ дСйствиС Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ. ВсС Π΄Π°Π½Π½Ρ‹Π΅, связанныС с этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠ΅ΠΉ, Π±ΡƒΠ΄ΡƒΡ‚ ΡƒΠ΄Π°Π»Π΅Π½Ρ‹.", + "deletingTeam": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ...", + "deleteTeamModalHeading": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "deletingTeamDescription": "Π’Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ компанию {{ teamName }}. Π­Ρ‚ΠΎ дСйствиС Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ.", + "deleteTeamInputField": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ для подтвСрТдСния", + "leaveTeam": "ΠŸΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ компанию", + "leavingTeamModalHeading": "ПокиданиС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "leavingTeamModalDescription": "Π’Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΠΏΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ эту компанию. Π£ вас большС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΊ Π½Π΅ΠΉ доступа.", + "leaveTeamDescription": "НаТмитС ΠΊΠ½ΠΎΠΏΠΊΡƒ Π½ΠΈΠΆΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ компанию. ΠŸΠΎΠΌΠ½ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ Π²Ρ‹ большС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚Π΅ ΠΈΠΌΠ΅Ρ‚ΡŒ ΠΊ Π½Π΅ΠΉ доступа ΠΈ Π²Π°ΠΌ потрСбуСтся ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ для присоСдинСния.", + "deleteTeamDisclaimer": "Π’Ρ‹ удаляСтС компанию {{ teamName }}. Π­Ρ‚ΠΎ дСйствиС Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ.", + "leaveTeamDisclaimer": "Π’Ρ‹ ΠΏΠΎΠΊΠΈΠ΄Π°Π΅Ρ‚Π΅ компанию {{ teamName }}. Π£ вас большС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΊ Π½Π΅ΠΉ доступа.", + "deleteTeamErrorHeading": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Π²Π°ΡˆΡƒ компанию.", + "leaveTeamErrorHeading": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ Π²Π°ΡˆΡƒ компанию.", + "searchMembersPlaceholder": "Поиск сотрудников", + "createTeamErrorHeading": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π²Π°ΡˆΡƒ компанию.", + "createTeamErrorMessage": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ создании ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "transferTeamErrorHeading": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΏΡ€Π°Π²Π° собствСнности Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "transferTeamErrorMessage": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ ΠΏΡ€Π°Π² собствСнности Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "updateRoleErrorHeading": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Ρ€ΠΎΠ»ΡŒ Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ сотрудника.", + "updateRoleErrorMessage": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ Ρ€ΠΎΠ»ΠΈ Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ сотрудника. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "searchInvitations": "Поиск ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠΉ", + "updateInvitation": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "removeInvitation": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "acceptInvitation": "ΠŸΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "renewInvitation": "ΠŸΡ€ΠΎΠ΄Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "resendInvitation": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ", + "expiresAtLabel": "Π˜ΡΡ‚Π΅ΠΊΠ°Π΅Ρ‚", + "expired": "Π˜ΡΡ‚Π΅ΠΊΠ»ΠΎ", + "active": "Активно", + "inviteStatus": "Бтатус", + "inviteNotFoundOrExpired": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ ΠΈΠ»ΠΈ истСкло", + "inviteNotFoundOrExpiredDescription": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π²Ρ‹ ΠΈΡ‰Π΅Ρ‚Π΅, Π»ΠΈΠ±ΠΎ истСкло, Π»ΠΈΠ±ΠΎ Π½Π΅ сущСствуСт. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ для продлСния ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ.", + "backToHome": "Назад Π½Π° Π³Π»Π°Π²Π½ΡƒΡŽ", + "renewInvitationDialogDescription": "Π’Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΠΏΡ€ΠΎΠ΄Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ для {{ email }}. ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ смоТСт ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "renewInvitationErrorTitle": "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΡ€ΠΎΠ΄Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅.", + "renewInvitationErrorDescription": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠΈ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ снова.", + "signInWithDifferentAccount": "Π’ΠΎΠΉΡ‚ΠΈ с Π΄Ρ€ΡƒΠ³ΠΈΠΌ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΎΠΌ", + "signInWithDifferentAccountDescription": "Если Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ с Π΄Ρ€ΡƒΠ³ΠΈΠΌ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΎΠΌ, Π²Ρ‹ΠΉΠ΄ΠΈΡ‚Π΅ ΠΈΠ· систСмы ΠΈ Π²ΠΎΠΉΠ΄ΠΈΡ‚Π΅ с Π½ΡƒΠΆΠ½Ρ‹ΠΌ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΎΠΌ.", + "acceptInvitationHeading": "ΠŸΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅ для присоСдинСния ΠΊ {{accountName}}", + "acceptInvitationDescription": "Вас пригласили ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ {{accountName}}. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅, Π½Π°ΠΆΠΌΠΈΡ‚Π΅ ΠΊΠ½ΠΎΠΏΠΊΡƒ Π½ΠΈΠΆΠ΅.", + "continueAs": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ {{email}}", + "joinTeamAccount": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "joiningTeam": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ ΠΊ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ...", + "leaveTeamInputLabel": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ LEAVE для подтвСрТдСния Π²Ρ‹Ρ…ΠΎΠ΄Π° ΠΈΠ· ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "leaveTeamInputDescription": "ΠŸΡ€ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π΅ ΠΈΠ· ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Ρƒ вас большС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΊ Π½Π΅ΠΉ доступа.", + "reservedNameError": "Π­Ρ‚ΠΎ имя Π·Π°Ρ€Π΅Π·Π΅Ρ€Π²ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΎΠ΅.", + "specialCharactersError": "Π­Ρ‚ΠΎ имя Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ символы. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΎΠ΅.", + "personalCode": "Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄", + "teamOwnerPersonalCodeLabel": "Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°" +} \ No newline at end of file diff --git a/styles/theme.css b/styles/theme.css index 46641c3..e12a584 100644 --- a/styles/theme.css +++ b/styles/theme.css @@ -135,6 +135,7 @@ --animate-accordion-down: accordion-down 0.2s ease-out; --animate-accordion-up: accordion-up 0.2s ease-out; + --breakpoint-2xs: 36rem; --breakpoint-xs: 48rem; --breakpoint-sm: 64rem; --breakpoint-md: 70rem; diff --git a/supabase/migrations-env-specific/setup_send_unassigned_job_emails_cron.sql b/supabase/migrations-env-specific/setup_send_unassigned_job_emails_cron.sql new file mode 100644 index 0000000..042cf1c --- /dev/null +++ b/supabase/migrations-env-specific/setup_send_unassigned_job_emails_cron.sql @@ -0,0 +1,17 @@ +create extension if not exists pg_cron; +create extension if not exists pg_net; + +select + cron.schedule( + 'send emails with new unassigned jobs 4x a day', + '0 4,9,14,18 * * 1-5', -- Run at 07:00, 12:00, 17:00 and 21:00 (GMT +3) on weekdays only + $$ + select + net.http_post( + url := 'https://test.medreport.ee/api/job/send-open-jobs-emails', + headers := jsonb_build_object( + 'x-jobs-api-key', 'fd26ec26-70ed-11f0-9e95-431ac3b15a84' + ) + ) as request_id; + $$ + ); diff --git a/supabase/migrations/20250828110851_add_service_role_doctor_data_privileges.sql b/supabase/migrations/20250828110851_add_service_role_doctor_data_privileges.sql new file mode 100644 index 0000000..d63a947 --- /dev/null +++ b/supabase/migrations/20250828110851_add_service_role_doctor_data_privileges.sql @@ -0,0 +1,8 @@ +grant select on table "medreport"."doctor_analysis_feedback" to "service_role"; + +create policy "service_role_select" +on "medreport"."doctor_analysis_feedback" +as permissive +for select +to service_role +using (true); \ No newline at end of file diff --git a/supabase/migrations/20250829085942_add_notification_triggers_to_results.sql b/supabase/migrations/20250829085942_add_notification_triggers_to_results.sql new file mode 100644 index 0000000..94de326 --- /dev/null +++ b/supabase/migrations/20250829085942_add_notification_triggers_to_results.sql @@ -0,0 +1,10 @@ + +create trigger "trigger_doctor_notification" after update +on "medreport"."analysis_orders" for each row +execute function "supabase_functions"."http_request"( + 'http://host.docker.internal:3000/api/db/webhook', + 'POST', + '{"Content-Type":"application/json", "X-Supabase-Event-Signature":"WEBHOOKSECRET"}', + '{}', + '5000' +); \ No newline at end of file diff --git a/supabase/migrations/20250901072953_add_notification_permissions_to_service_role.sql b/supabase/migrations/20250901072953_add_notification_permissions_to_service_role.sql new file mode 100644 index 0000000..fdfcf64 --- /dev/null +++ b/supabase/migrations/20250901072953_add_notification_permissions_to_service_role.sql @@ -0,0 +1,10 @@ +alter table audit.notification_entries enable row level security; + +create policy "service_role_insert" +on "audit"."notification_entries" +as permissive +for insert +to service_role +with check (true); + +grant insert on table "audit"."notification_entries" to "service_role";