mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 09:02:15 +03:00
feat: add i18n (translation/localization) (#16877)
* Translation module init * Add more i18n keys * fix: fix string wrong * refactor: use namespace translation file * chore: add more translation key * fix: fix some page name error * refactor: change Trans tag for t function * chore: fix some key not work * chore: fix SearchFilterDialog i18n key error Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * chore: fix en i18n file filter missing some keys * chore: add some i18n keys * chore: add more i18n keys again * feat: add search page i18n * feat: add explore model i18n keys * Update web/src/components/menu/GeneralSettings.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/components/menu/GeneralSettings.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/components/menu/GeneralSettings.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * feat: add more live i18n keys * feat: add more search setting i18n keys * fix: remove some comment * fix: fix some setting page url error * Update web/src/views/settings/SearchSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * fix: add system missing keys * fix: update password update i18n keys * chore: remove outdate translation.json file * fix: fix exploreSettings error * chore: add object setting i18n keys * Update web/src/views/recording/RecordingView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/public/locales/en/components/filter.json Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/components/overlay/ExportDialog.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * feat: add more i18n keys * fix: fix motionDetectionTuner html node * feat: add more page i18n keys * fix: cameraStream i18n keys error * feat: add Player i18n keys * feat: add more toast i18n keys * feat: change explore setting name * feat: add more document title i18n keys * feat: add more search i18n keys * fix: fix accessDenied i18n keys error * chore: add objectType i18n * chore: add inputWithTags i18n * chore: add SearchFilterDialog i18n * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * chore: add some missing i18n keys * chore: remove most import { t } from "i18next"; --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
This commit is contained in:
co-authored by
Josh Hawkins
parent
db541abed4
commit
d34533981f
@@ -20,6 +20,8 @@ import axios from "axios";
|
||||
import SaveExportOverlay from "./SaveExportOverlay";
|
||||
import { isIOS, isMobile } from "react-device-detect";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
type DrawerMode = "none" | "select" | "export" | "calendar" | "filter";
|
||||
|
||||
const DRAWER_FEATURES = ["export", "calendar", "filter"] as const;
|
||||
@@ -68,6 +70,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
setMode,
|
||||
setShowExportPreview,
|
||||
}: MobileReviewSettingsDrawerProps) {
|
||||
const { t } = useTranslation(["views/recording"]);
|
||||
const [drawerMode, setDrawerMode] = useState<DrawerMode>("none");
|
||||
|
||||
// exports
|
||||
@@ -75,12 +78,14 @@ export default function MobileReviewSettingsDrawer({
|
||||
const [name, setName] = useState("");
|
||||
const onStartExport = useCallback(() => {
|
||||
if (!range) {
|
||||
toast.error("No valid time range selected", { position: "top-center" });
|
||||
toast.error(t("toast.error.noValidTimeSelected"), {
|
||||
position: "top-center",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (range.before < range.after) {
|
||||
toast.error("End time must be after start time", {
|
||||
toast.error(t("toast.error.endTimeMustAfterStartTime"), {
|
||||
position: "top-center",
|
||||
});
|
||||
return;
|
||||
@@ -97,8 +102,10 @@ export default function MobileReviewSettingsDrawer({
|
||||
.then((response) => {
|
||||
if (response.status == 200) {
|
||||
toast.success(
|
||||
"Successfully started export. View the file in the /exports folder.",
|
||||
{ position: "top-center" },
|
||||
t("export.toast.success", { ns: "components/dialog" }),
|
||||
{
|
||||
position: "top-center",
|
||||
},
|
||||
);
|
||||
setName("");
|
||||
setRange(undefined);
|
||||
@@ -110,11 +117,17 @@ export default function MobileReviewSettingsDrawer({
|
||||
error.response?.data?.message ||
|
||||
error.response?.data?.detail ||
|
||||
"Unknown error";
|
||||
toast.error(`Failed to start export: ${errorMessage}`, {
|
||||
position: "top-center",
|
||||
});
|
||||
toast.error(
|
||||
t("export.toast.error.failed", {
|
||||
ns: "components/dialog",
|
||||
errorMessage,
|
||||
}),
|
||||
{
|
||||
position: "top-center",
|
||||
},
|
||||
);
|
||||
});
|
||||
}, [camera, name, range, setRange, setName, setMode]);
|
||||
}, [camera, name, range, setRange, setName, setMode, t]);
|
||||
|
||||
// filters
|
||||
|
||||
@@ -136,40 +149,40 @@ export default function MobileReviewSettingsDrawer({
|
||||
{features.includes("export") && (
|
||||
<Button
|
||||
className="flex w-full items-center justify-center gap-2"
|
||||
aria-label="Export"
|
||||
aria-label={t("export")}
|
||||
onClick={() => {
|
||||
setDrawerMode("export");
|
||||
setMode("select");
|
||||
}}
|
||||
>
|
||||
<FaArrowDown className="rounded-md bg-secondary-foreground fill-secondary p-1" />
|
||||
Export
|
||||
{t("export")}
|
||||
</Button>
|
||||
)}
|
||||
{features.includes("calendar") && (
|
||||
<Button
|
||||
className="flex w-full items-center justify-center gap-2"
|
||||
aria-label="Calendar"
|
||||
aria-label={t("calendar")}
|
||||
variant={filter?.after ? "select" : "default"}
|
||||
onClick={() => setDrawerMode("calendar")}
|
||||
>
|
||||
<FaCalendarAlt
|
||||
className={`${filter?.after ? "text-selected-foreground" : "text-secondary-foreground"}`}
|
||||
/>
|
||||
Calendar
|
||||
{t("calendar")}
|
||||
</Button>
|
||||
)}
|
||||
{features.includes("filter") && (
|
||||
<Button
|
||||
className="flex w-full items-center justify-center gap-2"
|
||||
aria-label="Filter"
|
||||
aria-label={t("filter")}
|
||||
variant={filter?.labels || filter?.zones ? "select" : "default"}
|
||||
onClick={() => setDrawerMode("filter")}
|
||||
>
|
||||
<FaFilter
|
||||
className={`${filter?.labels || filter?.zones ? "text-selected-foreground" : "text-secondary-foreground"}`}
|
||||
/>
|
||||
Filter
|
||||
{t("filter")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -206,10 +219,10 @@ export default function MobileReviewSettingsDrawer({
|
||||
className="absolute left-0 text-selected"
|
||||
onClick={() => setDrawerMode("select")}
|
||||
>
|
||||
Back
|
||||
{t("button.back", { ns: "common" })}
|
||||
</div>
|
||||
<div className="absolute left-1/2 -translate-x-1/2 text-muted-foreground">
|
||||
Calendar
|
||||
{t("calendar")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full flex-row justify-center">
|
||||
@@ -234,7 +247,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
<SelectSeparator />
|
||||
<div className="flex items-center justify-center p-2">
|
||||
<Button
|
||||
aria-label="Reset"
|
||||
aria-label={t("button.reset", { ns: "common" })}
|
||||
onClick={() => {
|
||||
onUpdateFilter({
|
||||
...filter,
|
||||
@@ -243,7 +256,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
});
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -256,10 +269,10 @@ export default function MobileReviewSettingsDrawer({
|
||||
className="absolute left-0 text-selected"
|
||||
onClick={() => setDrawerMode("select")}
|
||||
>
|
||||
Back
|
||||
{t("button.back", { ns: "common" })}
|
||||
</div>
|
||||
<div className="absolute left-1/2 -translate-x-1/2 text-muted-foreground">
|
||||
Filter
|
||||
{t("filter")}
|
||||
</div>
|
||||
</div>
|
||||
<GeneralFilterContent
|
||||
@@ -313,7 +326,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
<DrawerTrigger asChild>
|
||||
<Button
|
||||
className="rounded-lg capitalize"
|
||||
aria-label="Filters"
|
||||
aria-label={t("filters")}
|
||||
variant={
|
||||
filter?.labels || filter?.after || filter?.zones
|
||||
? "select"
|
||||
|
||||
Reference in New Issue
Block a user