mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 17:12:16 +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
@@ -54,7 +54,9 @@ import { FilterList, LAST_24_HOURS_KEY } from "@/types/filter";
|
||||
import { GiSoundWaves } from "react-icons/gi";
|
||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||
import ReviewDetailDialog from "@/components/overlay/detail/ReviewDetailDialog";
|
||||
|
||||
import { useTimelineZoom } from "@/hooks/use-timeline-zoom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
type EventViewProps = {
|
||||
reviewItems?: SegmentedReviewData;
|
||||
@@ -94,6 +96,7 @@ export default function EventView({
|
||||
pullLatestData,
|
||||
updateFilter,
|
||||
}: EventViewProps) {
|
||||
const { t } = useTranslation(["views/events"]);
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const contentRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
@@ -198,8 +201,10 @@ export default function EventView({
|
||||
.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",
|
||||
},
|
||||
);
|
||||
}
|
||||
})
|
||||
@@ -208,12 +213,18 @@ export default function EventView({
|
||||
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",
|
||||
message: errorMessage,
|
||||
}),
|
||||
{
|
||||
position: "top-center",
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
[reviewItems],
|
||||
[reviewItems, t],
|
||||
);
|
||||
|
||||
const [motionOnly, setMotionOnly] = useState(false);
|
||||
@@ -266,7 +277,7 @@ export default function EventView({
|
||||
<ToggleGroupItem
|
||||
className={cn(severityToggle != "alert" && "text-muted-foreground")}
|
||||
value="alert"
|
||||
aria-label="Select alerts"
|
||||
aria-label={t("alerts")}
|
||||
>
|
||||
{isMobileOnly ? (
|
||||
<div
|
||||
@@ -285,7 +296,7 @@ export default function EventView({
|
||||
<>
|
||||
<MdCircle className="size-2 text-severity_alert md:mr-[10px]" />
|
||||
<div className="hidden md:flex md:flex-row md:items-center">
|
||||
Alerts
|
||||
{t("alerts")}
|
||||
{reviewCounts.alert > -1 ? (
|
||||
` ∙ ${reviewCounts.alert}`
|
||||
) : (
|
||||
@@ -300,7 +311,7 @@ export default function EventView({
|
||||
severityToggle != "detection" && "text-muted-foreground",
|
||||
)}
|
||||
value="detection"
|
||||
aria-label="Select detections"
|
||||
aria-label={t("detections")}
|
||||
>
|
||||
{isMobileOnly ? (
|
||||
<div
|
||||
@@ -321,7 +332,7 @@ export default function EventView({
|
||||
<>
|
||||
<MdCircle className="size-2 text-severity_detection md:mr-[10px]" />
|
||||
<div className="hidden md:flex md:flex-row md:items-center">
|
||||
Detections
|
||||
{t("detections")}
|
||||
{reviewCounts.detection > -1 ? (
|
||||
` ∙ ${reviewCounts.detection}`
|
||||
) : (
|
||||
@@ -337,14 +348,14 @@ export default function EventView({
|
||||
severityToggle != "significant_motion" && "text-muted-foreground",
|
||||
)}
|
||||
value="significant_motion"
|
||||
aria-label="Select motion"
|
||||
aria-label={t("motion.label")}
|
||||
>
|
||||
{isMobileOnly ? (
|
||||
<GiSoundWaves className="size-6 rotate-90 text-severity_significant_motion" />
|
||||
) : (
|
||||
<>
|
||||
<MdCircle className="size-2 text-severity_significant_motion md:mr-[10px]" />
|
||||
<div className="hidden md:block">Motion</div>
|
||||
<div className="hidden md:block">{t("motion.label")}</div>
|
||||
</>
|
||||
)}
|
||||
</ToggleGroupItem>
|
||||
@@ -461,6 +472,8 @@ function DetectionReview({
|
||||
setSelectedReviews,
|
||||
pullLatestData,
|
||||
}: DetectionReviewProps) {
|
||||
const { t } = useTranslation(["views/events"]);
|
||||
|
||||
const reviewTimelineRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// detail
|
||||
@@ -712,7 +725,7 @@ function DetectionReview({
|
||||
{!loading && currentItems?.length === 0 && (
|
||||
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center text-center">
|
||||
<LuFolderCheck className="size-16" />
|
||||
There are no {severity.replace(/_/g, " ")}s to review
|
||||
{t("empty." + severity.replace(/_/g, " "))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -779,14 +792,14 @@ function DetectionReview({
|
||||
<div className="col-span-full flex items-center justify-center">
|
||||
<Button
|
||||
className="text-white"
|
||||
aria-label="Mark these items as reviewed"
|
||||
aria-label={t("markTheseItemsAsReviewed")}
|
||||
variant="select"
|
||||
onClick={() => {
|
||||
setSelectedReviews([]);
|
||||
markAllItemsAsReviewed(currentItems ?? []);
|
||||
}}
|
||||
>
|
||||
Mark these items as reviewed
|
||||
{t("markTheseItemsAsReviewed")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
@@ -862,6 +875,7 @@ function MotionReview({
|
||||
motionOnly = false,
|
||||
onOpenRecording,
|
||||
}: MotionReviewProps) {
|
||||
const { t } = useTranslation(["views/events"]);
|
||||
const segmentDuration = 30;
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
@@ -1051,7 +1065,7 @@ function MotionReview({
|
||||
return (
|
||||
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center text-center">
|
||||
<LuFolderX className="size-16" />
|
||||
No motion data found
|
||||
{t("empty.motion")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user