-
+
-### What is Foo Medical?
+### Co je Moje Ambulance?
-[Foo Medical](https://foomedical.com/) is a **ready to use medical practice sample app** that's open source. It's meant for developers to clone, customize and run.
+[Moje Ambulance](https://foomedical.com/) je **ukázková open-source aplikace pro lékařskou praxi připravená k okamžitému použití**. Je určena pro vývojáře, aby ji mohli klonovat, přizpůsobovat a spouštět.
-### Features
+### Funkce
-- Completely free and open-source
-- Secure and compliant [Medplum](https://www.medplum.com) backend, which is also open source
-- Patient registration and authentication
-- Health records
- - Lab results
- - Medications
- - Vaccines
- - Vitals
-- Patient-provider messaging
-- Care plans
-- Patient scheduling
-- All data represented in [FHIR](https://hl7.org/FHIR/)
+- Zcela zdarma a open-source
+- Bezpečný a vyhovující [Medplum](https://www.medplum.com) backend, který je také open-source
+- Registrace a ověřování pacientů
+- Zdravotní záznamy
+ - Výsledky laboratoře
+ - Léky
+ - Očkování
+ - Vitální funkce
+- Zprávy mezi pacientem a poskytovatelem
+- Plány péče
+- Plánování pacientů
+- Všechna data reprezentovaná ve [FHIR](https://hl7.org/FHIR/)
-Foo Medical is designed to be forked and customized for your business' needs. Register on [foomedical.com](https://foomedical.com/) to see it in action.
+Moje Ambulance je navržena tak, aby ji bylo možné forkovat a přizpůsobit potřebám vašeho podnikání. Zaregistrujte se na [foomedical.com](https://foomedical.com/), abyste ji viděli v akci.
-### Getting Started
+### Začínáme
-First, [fork](https://github.com/medplum/foomedical/fork) and clone the repo.
+Nejprve [forkujte](https://github.com/medplum/foomedical/fork) a naklonujte repozitář.
-Next, install the app from your terminal
+Dále nainstalujte aplikaci z terminálu
```bash
npm install
```
-Then, run the app!
+Poté aplikaci spusťte!
```bash
npm run dev
```
-This app should run on `http://localhost:3000/`
+Tato aplikace by měla běžet na `http://localhost:3000/`
-Log into the app on localhost using the same credentials you created on [foomedical.com](https://foomedical.com/) and you are ready to start customizing.
+Přihlaste se do aplikace na localhostu pomocí stejných přihlašovacích údajů, které jste vytvořili na [foomedical.com](https://foomedical.com/), a jste připraveni začít s přizpůsobením.
-### Deploying your app
+### Nasazení vaší aplikace
-To get started deploying your app we recommend making an account on [Vercel](https://vercel.com/), free accounts are available.
+Pro nasazení vaší aplikace doporučujeme vytvořit si účet na [Vercel](https://vercel.com/), k dispozici jsou bezplatné účty.
-You can deploy this application by [clicking here](https://vercel.com/new/clone?s=https%3A%2F%2Fgithub.com%2Fmedplum%2Ffoomedical&showOptionalTeamCreation=false).
+Tuto aplikaci můžete nasadit [kliknutím sem](https://vercel.com/new/clone?s=https%3A%2F%2Fgithub.com%2Fmedplum%2Ffoomedical&showOptionalTeamCreation=false).
-### Account Setup
+### Nastavení účtu
-By default, your locally running Foo Medical app is pointing to the hosted Medplum service. Foo Medical registers signups to a test project.
+Ve výchozím nastavení vaše lokálně spuštěná aplikace Moje Ambulance ukazuje na hostovanou službu Medplum. Moje Ambulance registruje přihlášení do testovacího projektu.
-To send patients to your own organization you will need to [register a new Project on Medplum](https://www.medplum.com/docs/tutorials/register) and configure your environment variables to point to your own project (see [config.ts](https://github.com/medplum/foomedical/blob/main/src/config.ts) for an example).
+Chcete-li posílat pacienty do své vlastní organizace, budete muset [zaregistrovat nový projekt na Medplum](https://www.medplum.com/docs/tutorials/register) a nakonfigurovat proměnné prostředí tak, aby ukazovaly na váš vlastní projekt (viz [config.ts](https://github.com/medplum/foomedical/blob/main/src/config.ts) jako příklad).
-If you are using the Medplum Hosted service, you can login to your Medplum Instance and add the following identifiers to your [Project Site Settings](https://app.medplum.com/admin/sites)
+Pokud používáte hostovanou službu Medplum, můžete se přihlásit do své instance Medplum a přidat následující identifikátory do [nastavení webu projektu](https://app.medplum.com/admin/sites)
- Google Client Id
- Google Client Secret
- Recaptcha Site Key
- Recaptcha Secret Key
-Contact the medplum team ([support@medplum.com](mailto:support@medplum.com) or [Discord](https://discord.gg/medplum])) with any questions.
+V případě jakýchkoli dotazů kontaktujte tým Medplum ([support@medplum.com](mailto:support@medplum.com) nebo [Discord](https://discord.gg/medplum])).
-### Data Setup
+### Nastavení dat
-When you log into Foo Medical a set of sample FHIR records is created on your behalf. The ability to run automations is part of the Medplum platform using a framework called [Bots](https://www.medplum.com/docs/bots). For reference, Bot that created the records in Foo Medical can be found [here](https://github.com/medplum/medplum-demo-bots/blob/main/src/sample-account-setup.ts).
+Když se přihlásíte do Moje Ambulance, vytvoří se pro vás sada ukázkových záznamů FHIR. Schopnost spouštět automatizace je součástí platformy Medplum pomocí frameworku zvaného [Boti](https://www.medplum.com/docs/bots). Pro informaci, Bota, který vytvořil záznamy v Moje Ambulance, najdete [zde](https://github.com/medplum/medplum-demo-bots/blob/main/src/sample-account-setup.ts).
-### Compliance
+### Soulad
-Medplum backend is HIPAA compliant and SOC 2 certified. Getting an account set up requires registering on [medplum.com](https://www.medplum.com/). Feel free to ask us questions in real time on our [Discord Server](https://discord.gg/medplum).
+Backend Medplum je v souladu s HIPAA a certifikován SOC 2. Založení účtu vyžaduje registraci na [medplum.com](https://www.medplum.com/). Neváhejte se nás zeptat na otázky v reálném čase na našem [Discord serveru](https://discord.gg/medplum).
-### About Medplum
+### O Medplum
-[Medplum](https://www.medplum.com/) is an open-source, API-first EHR. Medplum makes it easy to build healthcare apps quickly with less code.
+[Medplum](https://www.medplum.com/) je open-source, API-first EHR. Medplum usnadňuje rychlé vytváření zdravotnických aplikací s menším množstvím kódu.
-Medplum supports self-hosting and provides a [hosted service](https://app.medplum.com/). [Foo Medical](https://foomedical.com/) uses the hosted service as a backend.
+Medplum podporuje vlastní hosting a poskytuje [hostovanou službu](https://app.medplum.com/). [Moje Ambulance](https://foomedical.com/) používá hostovanou službu jako backend.
-- Read our [documentation](https://www.medplum.com/docs/)
-- Browse our [React component library](https://storybook.medplum.com/)
-- Join our [Discord](https://discord.gg/medplum)
+- Přečtěte si naši [dokumentaci](https://www.medplum.com/docs/)
+- Prohlédněte si naši [knihovnu komponent React](https://storybook.medplum.com/)
+- Připojte se k našemu [Discordu](https://discord.gg/medplum)
diff --git a/index.html b/index.html
index 907a0b7..75c8a31 100644
--- a/index.html
+++ b/index.html
@@ -1,10 +1,10 @@
-
+
- Foo Medical
+ Moje Ambulance
diff --git a/jules-scratch/verification/verify_homepage.py b/jules-scratch/verification/verify_homepage.py
new file mode 100644
index 0000000..e22e7a7
--- /dev/null
+++ b/jules-scratch/verification/verify_homepage.py
@@ -0,0 +1,13 @@
+from playwright.sync_api import sync_playwright
+
+def run(playwright):
+ browser = playwright.chromium.launch(headless=True)
+ context = browser.new_context()
+ page = context.new_page()
+ page.goto("http://localhost:3000/")
+ page.screenshot(path="jules-scratch/verification/verification.png")
+ context.close()
+ browser.close()
+
+with sync_playwright() as playwright:
+ run(playwright)
diff --git a/package.json b/package.json
index 934c40b..e4b4525 100644
--- a/package.json
+++ b/package.json
@@ -60,5 +60,9 @@
"packageManager": "npm@10.9.3",
"engines": {
"node": "^20.19.0 || >=22.12.0"
+ },
+ "dependencies": {
+ "i18next": "^25.6.0",
+ "react-i18next": "^16.1.0"
}
}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index a6bb378..b2003b0 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -6,24 +6,26 @@ import { ResourceAvatar, useMedplumProfile } from '@medplum/react';
import { IconChevronDown, IconLogout, IconSettings, IconUserCircle } from '@tabler/icons-react';
import cx from 'clsx';
import { JSX, useState } from 'react';
+import { useTranslation } from 'react-i18next';
import { Link, useNavigate } from 'react-router';
import classes from './Header.module.css';
import { Logo } from './Logo';
-const navigation = [
- { name: 'Health Record', href: '/health-record' },
- { name: 'Messages', href: '/messages' },
- { name: 'Care Plan', href: '/care-plan' },
- { name: 'Get Care', href: '/get-care' },
-];
-
export function Header(): JSX.Element {
+ const { t } = useTranslation();
const navigate = useNavigate();
const profile = useMedplumProfile();
const theme = useMantineTheme();
const [opened, { toggle }] = useDisclosure(false);
const [userMenuOpened, setUserMenuOpened] = useState(false);
+ const navigation = [
+ { name: t('header.nav.healthrecord'), href: '/health-record' },
+ { name: t('header.nav.messages'), href: '/messages' },
+ { name: t('header.nav.careplan'), href: '/care-plan' },
+ { name: t('header.nav.getcare'), href: '/get-care' },
+ ];
+
return (
@@ -59,19 +61,19 @@ export function Header(): JSX.Element {
leftSection={}
onClick={() => navigate('/account/profile')?.catch(console.error)}
>
- Your profile
+ {t('header.menu.profile')}
}
onClick={() => navigate('/account/profile')?.catch(console.error)}
>
- Settings
+ {t('header.menu.settings')}
}
onClick={() => navigate('/signout')?.catch(console.error)}
>
- Sign out
+ {t('header.menu.signout')}
diff --git a/src/i18n.ts b/src/i18n.ts
new file mode 100644
index 0000000..32cc1f5
--- /dev/null
+++ b/src/i18n.ts
@@ -0,0 +1,28 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+
+import cs from './locales/cs.json';
+
+// the translations
+// (tip move them in a JSON file and import them,
+// or even better, manage them separated from your code: https://react.i18next.com/guides/multiple-translation-files)
+const resources = {
+ cs: {
+ translation: cs,
+ },
+};
+
+i18n
+ .use(initReactI18next) // passes i18n down to react-i18next
+ .init({
+ resources,
+ lng: 'cs', // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
+ // you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
+ // if you're using a language detector, do not define the lng option
+
+ interpolation: {
+ escapeValue: false // react already safes from xss
+ }
+ });
+
+ export default i18n;
diff --git a/src/locales/cs.json b/src/locales/cs.json
new file mode 100644
index 0000000..53db204
--- /dev/null
+++ b/src/locales/cs.json
@@ -0,0 +1,56 @@
+{
+ "welcome": "Vítejte v Moje Ambulance",
+ "home.carousel.welcome.title": "Vítejte v Moje Ambulance",
+ "home.carousel.welcome.description": "Prozkoumejte své zdravotní záznamy, komunikujte se svým lékařem a mnoho dalšího.",
+ "home.carousel.welcome.label": "Screening rizik sociálního zdraví",
+ "home.carousel.intake.title": "Vstupní dotazník pro pacienta",
+ "home.carousel.intake.description": "Vyplňte prosím vstupní dotazník před vaší první návštěvou.",
+ "home.carousel.intake.label": "Spustit formulář",
+ "home.carousel.doctor.title": "Vyberte si lékaře",
+ "home.carousel.doctor.description": "Najděte si lékaře, který vám nejvíce vyhovuje.",
+ "home.carousel.doctor.label": "Vyberte si poskytovatele primární péče",
+ "home.carousel.contact.title": "Nouzový kontakt",
+ "home.carousel.contact.description": "Ujistěte se, že máme aktuální nouzový kontakt pro případ potřeby.",
+ "home.carousel.contact.label": "Přidat nouzový kontakt",
+ "home.linkpages.healthrecord.title": "Zdravotní záznamy",
+ "home.linkpages.prescription.title": "Požádat o obnovení předpisu",
+ "home.linkpages.pharmacy.title": "Preferovaná lékárna",
+ "home.linkpages.pharmacy.description": "Vaše preferovaná lékárna",
+ "home.recommendations.travel.title": "Získejte doporučení pro cestování",
+ "home.recommendations.travel.description": "Zjistěte, jaká očkování a léky potřebujete na cestu.",
+ "home.recommendations.reimbursement.title": "Získejte proplacení z FSA/HSA",
+ "home.recommendations.reimbursement.description": "Požádejte o předpis na volně prodejné položky.",
+ "home.recommendations.records.title": "Požádejte o zdravotní záznamy",
+ "home.recommendations.records.description": "Nechte si zaslat záznamy do nebo z Moje Ambulance.",
+ "home.announcements": "Oznámení se zobrazí zde.",
+ "home.announcements.links": "V případě potřeby vložte odkazy.",
+ "home.hero.title": "Dobrý den <1>{{profileName}}1>, jsme tu, abychom vám pomohli",
+ "home.hero.button": "Získejte péči",
+ "home.calltoaction": "Sem umístěte výzvy k akci",
+ "home.calltoaction.button": "Odeslat zprávu",
+ "home.card.rest.title": "Lepší odpočinek, lepší zdraví",
+ "home.card.rest.button": "Pozvat přátele",
+ "home.card.available.badge": "Nyní k dispozici",
+ "home.card.available.title": "Nadpis",
+ "home.card.provider.title": "Poskytovatel primární péče",
+ "home.card.provider.description": "Mít stálého a důvěryhodného poskytovatele může vést k lepšímu zdraví.",
+ "home.card.provider.button": "Vybrat poskytovatele",
+ "header.nav.healthrecord": "Zdravotní záznamy",
+ "header.nav.messages": "Zprávy",
+ "header.nav.careplan": "Plán péče",
+ "header.nav.getcare": "Získejte péči",
+ "header.menu.profile": "Váš profil",
+ "header.menu.settings": "Nastavení",
+ "header.menu.signout": "Odhlásit se",
+ "account.title": "Účet",
+ "account.menu.profile": "Profil",
+ "account.menu.provider": "Poskytovatel",
+ "account.menu.billing": "Členství a fakturace",
+ "getcare.title": "Získat péči",
+ "getcare.question1": "Otázka 1",
+ "getcare.question2": "Otázka 2",
+ "getcare.question3": "Otázka 3",
+ "signin.title": "Přihlaste se do Moje Ambulance",
+ "signout.title": "Byli jste odhlášeni.",
+ "signout.button": "Zpět na přihlášení"
+}
diff --git a/src/main.tsx b/src/main.tsx
index d67a26a..9373f24 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -11,6 +11,7 @@ import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router';
import { App } from './App';
+import './i18n';
const medplum = new MedplumClient({
// To run FooMedical locally, you can set the baseURL in this constructor
diff --git a/src/pages/GetCarePage.tsx b/src/pages/GetCarePage.tsx
index d0918d4..4918630 100644
--- a/src/pages/GetCarePage.tsx
+++ b/src/pages/GetCarePage.tsx
@@ -3,8 +3,10 @@
import { Schedule } from '@medplum/fhirtypes';
import { Document, Scheduler, useMedplum } from '@medplum/react';
import { JSX } from 'react';
+import { useTranslation } from 'react-i18next';
export function GetCare(): JSX.Element {
+ const { t } = useTranslation();
const medplum = useMedplum();
const schedule = medplum.searchOne('Schedule').read();
@@ -21,19 +23,19 @@ export function GetCare(): JSX.Element {
id: 'id-1',
linkId: 'q1',
type: 'string',
- text: 'Question 1',
+ text: t('getcare.question1'),
},
{
id: 'id-2',
linkId: 'q2',
type: 'string',
- text: 'Question 2',
+ text: t('getcare.question2'),
},
{
id: 'id-3',
linkId: 'q3',
type: 'string',
- text: 'Question 3',
+ text: t('getcare.question3'),
},
],
}}
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
index 4907b99..b0a8ff4 100644
--- a/src/pages/HomePage.tsx
+++ b/src/pages/HomePage.tsx
@@ -23,6 +23,7 @@ import { Patient, Practitioner } from '@medplum/fhirtypes';
import { useMedplumProfile } from '@medplum/react';
import { IconChecklist, IconGift, IconSquareCheck } from '@tabler/icons-react';
import { JSX } from 'react';
+import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router';
import DoctorImage from '../img/homePage/doctor.svg';
import HealthRecordImage from '../img/homePage/health-record.svg';
@@ -31,88 +32,84 @@ import PharmacyImage from '../img/homePage/pharmacy.svg';
import PillImage from '../img/homePage/pill.svg';
import classes from './HomePage.module.css';
-const carouselItems = [
- {
- img: ,
- title: 'Welcome to Foo Medical',
- description:
- 'Lorem ipsum at porta donec ultricies ut, arcu morbi amet arcu ornare, curabitur pharetra magna tempus',
- url: '/screening-questionnaire',
- label: 'AHC HRSN Screening',
- },
- {
- img: ,
- title: 'Patient Intake Questionnaire',
- description:
- 'Lorem ipsum at porta donec ultricies ut, arcu morbi amet arcu ornare, curabitur pharetra magna tempus',
- url: '/patient-intake-questionnaire',
- label: 'Start Form',
- },
- {
- img: ,
- title: 'Select a Doctor',
- description:
- 'Lorem ipsum at porta donec ultricies ut, arcu morbi amet arcu ornare, curabitur pharetra magna tempus',
- url: '/account/provider/choose-a-primary-care-povider',
- label: 'Choose a Primary Care Provider',
- },
- {
- img: ,
- title: 'Emergency Contact',
- description:
- 'Lorem ipsum at porta donec ultricies ut, arcu morbi amet arcu ornare, curabitur pharetra magna tempus',
- url: '/account',
- label: 'Add emergency contact',
- },
-];
-
-const linkPages = [
- {
- img: HealthRecordImage,
- title: 'Health Record',
- description: '',
- href: '/health-record',
- },
- {
- img: PillImage,
- title: 'Request Prescription Renewal',
- description: '',
- href: '/health-record/medications',
- },
- {
- img: PharmacyImage,
- title: 'Preferred Pharmacy',
- description: 'Walgreens D2866 1363 Divisadero St DIVISADERO',
- href: '#',
- },
-];
-
-const recommendations = [
- {
- title: 'Get travel health recommendations',
- description: 'Find out what vaccines and meds you need for your trip.',
- },
- {
- title: 'Get FSA/HSA reimbursement',
- description: 'Request a prescription for over-the-counter items.',
- },
- {
- title: 'Request health record',
- description: 'Get records sent to or from Foo Medical.',
- },
-];
-
export function HomePage(): JSX.Element {
+ const { t } = useTranslation();
const navigate = useNavigate();
const theme = useMantineTheme();
const profile = useMedplumProfile() as Patient | Practitioner;
const profileName = profile.name ? formatHumanName(profile.name[0]) : '';
+ const linkPages = [
+ {
+ img: HealthRecordImage,
+ title: t('home.linkpages.healthrecord.title'),
+ description: '',
+ href: '/health-record',
+ },
+ {
+ img: PillImage,
+ title: t('home.linkpages.prescription.title'),
+ description: '',
+ href: '/health-record/medications',
+ },
+ {
+ img: PharmacyImage,
+ title: t('home.linkpages.pharmacy.title'),
+ description: t('home.linkpages.pharmacy.description'),
+ href: '#',
+ },
+ ];
+ const recommendations = [
+ {
+ title: t('home.recommendations.travel.title'),
+ description: t('home.recommendations.travel.description'),
+ },
+ {
+ title: t('home.recommendations.reimbursement.title'),
+ description: t('home.recommendations.reimbursement.description'),
+ },
+ {
+ title: t('home.recommendations.records.title'),
+ description: t('home.recommendations.records.description'),
+ },
+ ];
+
+ const carouselItems = [
+ {
+ img: ,
+ title: t('home.carousel.welcome.title'),
+ description: t('home.carousel.welcome.description'),
+ url: '/screening-questionnaire',
+ label: t('home.carousel.welcome.label'),
+ },
+ {
+ img: ,
+ title: t('home.carousel.intake.title'),
+ description: t('home.carousel.intake.description'),
+ url: '/patient-intake-questionnaire',
+ label: t('home.carousel.intake.label'),
+ },
+ {
+ img: ,
+ title: t('home.carousel.doctor.title'),
+ description: t('home.carousel.doctor.description'),
+ url: '/account/provider/choose-a-primary-care-povider',
+ label: t('home.carousel.doctor.label'),
+ },
+ {
+ img: ,
+ title: t('home.carousel.contact.title'),
+ description: t('home.carousel.contact.description'),
+ url: '/account',
+ label: t('home.carousel.contact.label'),
+ },
+ ];
+
return (
- Announcements go here. Include links if needed.
+ {t('home.announcements')} {t('home.announcements.links')}
@@ -123,19 +120,19 @@ export function HomePage(): JSX.Element {
/>
- Hi {profileName}, we’re here to help
+ {t('home.hero.title', { profileName })}
-
Put calls to action here
+
{t('home.calltoaction')}
@@ -164,7 +161,7 @@ export function HomePage(): JSX.Element {
- Better rest, better health
+ {t('home.card.rest.title')}
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Maiores impedit perferendis suscipit eaque, iste
@@ -172,7 +169,7 @@ export function HomePage(): JSX.Element {
impedit perferendis suscipit eaque, iste dolor cupiditate blanditiis ratione.
-
+
@@ -184,10 +181,10 @@ export function HomePage(): JSX.Element {
- Now available
+ {t('home.card.available.badge')}
- Title
+ {t('home.card.available.title')}
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Maiores impedit perferendis suscipit eaque,
@@ -223,11 +220,11 @@ export function HomePage(): JSX.Element {
- Primary Care Provider
+ {t('home.card.provider.title')}
- Having a consistent, trusted provider can lead to better health.
+ {t('home.card.provider.description')}
-
+
diff --git a/src/pages/SignInPage.tsx b/src/pages/SignInPage.tsx
index c689122..64554b5 100644
--- a/src/pages/SignInPage.tsx
+++ b/src/pages/SignInPage.tsx
@@ -3,10 +3,12 @@
import { BackgroundImage, Box, SimpleGrid } from '@mantine/core';
import { SignInForm } from '@medplum/react';
import { JSX } from 'react';
+import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router';
import { MEDPLUM_GOOGLE_CLIENT_ID, MEDPLUM_PROJECT_ID } from '../config';
export function SignInPage(): JSX.Element {
+ const { t } = useTranslation();
const navigate = useNavigate();
return (
@@ -16,7 +18,7 @@ export function SignInPage(): JSX.Element {
googleClientId={MEDPLUM_GOOGLE_CLIENT_ID}
onSuccess={() => navigate('/')?.catch(console.error)}
>
-