diff --git a/web/public/locales/en/views/search.json b/web/public/locales/en/views/search.json
new file mode 100644
index 000000000..fbb43253e
--- /dev/null
+++ b/web/public/locales/en/views/search.json
@@ -0,0 +1,35 @@
+{
+ "search": "Search",
+ "savedSearches": "Saved Searches",
+ "searchFor": "Search for {{inputValue}}",
+ "button": {
+ "clear": "Clear search",
+ "save": "Save search",
+ "delete": "Delete saved search",
+ "filterInformation": "Filter information",
+ "filterActive": "Filters active"
+ },
+ "filter": {
+ "toast": {
+ "error": {
+ "beforeDateBeLaterAfter": "The 'before' date must be later than the 'after' date.",
+ "afterDatebeEarlierBefore": "The 'after' date must be earlier than the 'before' date.",
+ "minScoreMustBeLessOrEqualMaxScore": "The 'min_score' must be less than or equal to the 'max_score'.",
+ "maxScoreMustBeGreaterOrEqualMinScore": "The 'max_score' must be greater than or equal to the 'min_score'.",
+ "minSpeedMustBeLessOrEqualMaxSpeed": "The 'min_speed' must be less than or equal to the 'max_speed'.",
+ "maxSpeedMustBeGreaterOrEqualMinSpeed": "The 'max_speed' must be greater than or equal to the 'min_speed'."
+ }
+ },
+ "tips": {
+ "title": "How to use text filters",
+ "desc": "Filters help you narrow down your search results. Here's how to use them in the input field:",
+ "desc.step": "
Type a filter name followed by a colon (e.g., \"cameras:\"). Select a value from the suggestions or type your own. Use multiple filters by adding them one after another with a space in between. Date filters (before: and after:) use {{DateFormat}} format. Time range filter uses {{exampleTime}} format. Remove filters by clicking the 'x' next to them. ",
+ "desc.example": "Example: cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM "
+ }
+ },
+ "similaritySearch": {
+ "title": "Similarity Search",
+ "active": "Similarity search active",
+ "clear": "Clear similarity search"
+ }
+}
\ No newline at end of file
diff --git a/web/public/locales/zh-CN/views/search.json b/web/public/locales/zh-CN/views/search.json
new file mode 100644
index 000000000..11e806844
--- /dev/null
+++ b/web/public/locales/zh-CN/views/search.json
@@ -0,0 +1,35 @@
+{
+ "search": "搜索",
+ "savedSearches": "已保存的搜索",
+ "searchFor": "搜索 {{inputValue}}",
+ "button": {
+ "clear": "清除搜索",
+ "save": "保存搜索",
+ "delete": "删除已保存的搜索",
+ "filterInformation": "筛选信息",
+ "filterActive": "筛选器已激活"
+ },
+ "filter": {
+ "toast": {
+ "error": {
+ "beforeDateBeLaterAfter": "“之前”日期必须晚于“之后”日期。",
+ "afterDatebeEarlierBefore": "“之后”日期必须早于“之前”日期。",
+ "minScoreMustBeLessOrEqualMaxScore": "最小分值 必须小于或等于 最大分值。",
+ "maxScoreMustBeGreaterOrEqualMinScore": "最大分值 必须大于或等于 最小分值",
+ "minSpeedMustBeLessOrEqualMaxSpeed": "最低速度 必须小于或等于 最高速度",
+ "maxSpeedMustBeGreaterOrEqualMinSpeed": "最高速度 必须大于或等于 最低速度"
+ }
+ },
+ "tips": {
+ "title": "如何使用文本筛选器(英文)",
+ "desc": "筛选器可帮助您缩小搜索范围。注意,目前还暂不支持中文搜索。以下是在输入字段中使用筛选器的方法:",
+ "desc.step": "输入筛选器名称后跟一个冒号(例如:“cameras:”)。 从建议中选择一个值或输入您自己的值。 使用多个筛选器时,可以在它们之间用空格分隔。 日期筛选器(before: 和 after:)使用 {{DateFormat}} 格式。 时间范围筛选器使用 {{exampleTime}} 格式。 点击筛选器旁边的“x”即可移除筛选条件。 ",
+ "desc.example": "示例:cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM"
+ }
+ },
+ "similaritySearch": {
+ "title": "相似搜索",
+ "active": "相似搜索已激活",
+ "clear": "清除相似搜索"
+ }
+}
diff --git a/web/src/components/input/InputWithTags.tsx b/web/src/components/input/InputWithTags.tsx
index 3ae78e70a..56fc6feb3 100644
--- a/web/src/components/input/InputWithTags.tsx
+++ b/web/src/components/input/InputWithTags.tsx
@@ -51,6 +51,7 @@ import { toast } from "sonner";
import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { MdImageSearch } from "react-icons/md";
+import { Trans, useTranslation } from "react-i18next";
type InputWithTagsProps = {
inputFocused: boolean;
@@ -73,6 +74,7 @@ export default function InputWithTags({
setSearch,
allSuggestions,
}: InputWithTagsProps) {
+ const { t } = useTranslation(["views/search"]);
const { data: config } = useSWR("config", {
revalidateOnFocus: false,
});
@@ -236,12 +238,9 @@ export default function InputWithTags({
filters.after &&
timestamp <= filters.after * 1000
) {
- toast.error(
- "The 'before' date must be later than the 'after' date.",
- {
- position: "top-center",
- },
- );
+ toast.error(t("filter.toast.error.beforeDateBeLaterAfter"), {
+ position: "top-center",
+ });
return;
}
if (
@@ -249,12 +248,9 @@ export default function InputWithTags({
filters.before &&
timestamp >= filters.before * 1000
) {
- toast.error(
- "The 'after' date must be earlier than the 'before' date.",
- {
- position: "top-center",
- },
- );
+ toast.error(t("afterDatebeEarlierBefore"), {
+ position: "top-center",
+ });
return;
}
if (type === "before") {
@@ -274,7 +270,7 @@ export default function InputWithTags({
score > filters.max_score * 100
) {
toast.error(
- "The 'min_score' must be less than or equal to the 'max_score'.",
+ t("filter.toast.error.minScoreMustBeLessOrEqualMaxScore"),
{
position: "top-center",
},
@@ -287,7 +283,7 @@ export default function InputWithTags({
score < filters.min_score * 100
) {
toast.error(
- "The 'max_score' must be greater than or equal to the 'min_score'.",
+ t("filter.toast.error.maxScoreMustBeGreaterOrEqualMinScore"),
{
position: "top-center",
},
@@ -308,7 +304,7 @@ export default function InputWithTags({
speed > filters.max_speed
) {
toast.error(
- "The 'min_speed' must be less than or equal to the 'max_speed'.",
+ t("filter.toast.error.minSpeedMustBeLessOrEqualMaxSpeed"),
{
position: "top-center",
},
@@ -321,7 +317,7 @@ export default function InputWithTags({
speed < filters.min_speed
) {
toast.error(
- "The 'max_speed' must be greater than or equal to the 'min_speed'.",
+ t("filter.toast.error.maxSpeedMustBeGreaterOrEqualMinSpeed"),
{
position: "top-center",
},
@@ -380,7 +376,7 @@ export default function InputWithTags({
setCurrentFilterType(null);
}
},
- [filters, setFilters, allSuggestions],
+ [filters, setFilters, allSuggestions, t],
);
function formatFilterValues(
@@ -408,7 +404,11 @@ export default function InputWithTags({
return Math.round(Number(filterValues) * 100).toString() + "%";
} else if (filterType === "min_speed" || filterType === "max_speed") {
return (
- filterValues + (config?.ui.unit_system == "metric" ? " kph" : " mph")
+ filterValues +
+ " " +
+ (config?.ui.unit_system == "metric"
+ ? t("unit.speed.kph", { ns: "common" })
+ : t("unit.speed.mph", { ns: "common" }))
);
} else if (
filterType === "has_clip" ||
@@ -665,7 +665,7 @@ export default function InputWithTags({
/>
- Clear search
+ {t("button.clear")}
)}
@@ -679,7 +679,7 @@ export default function InputWithTags({
/>
- Save search
+ {t("button.save")}
)}
@@ -688,12 +688,14 @@ export default function InputWithTags({
- Similarity search active
+
+ {t("similaritySearch.active")}
+
)}
@@ -702,10 +704,10 @@ export default function InputWithTags({
0
@@ -717,43 +719,24 @@ export default function InputWithTags({
-
How to use text filters
+
{t("filter.tips.title")}
- Filters help you narrow down your search results. Here's how
- to use them in the input field:
+ {t("filter.tips.desc")}
-
-
- Type a filter name followed by a colon (e.g., "cameras:").
-
-
- Select a value from the suggestions or type your own.
-
-
- Use multiple filters by adding them one after another with
- a space in between.
-
-
- Date filters (before: and after:) use{" "}
- {getIntlDateFormat()} format.
-
-
- Time range filter uses{" "}
-
- {config?.ui.time_format == "24hour"
+
- format.
-
- Remove filters by clicking the 'x' next to them.
-
+ : "3:00PM-4:00PM",
+ }}
+ >
+ filter.tips.desc.step
+
- Example:{" "}
-
- cameras:front_door label:person before:01012024
- time_range:3:00PM-4:00PM
-
+ filter.tips.desc.example
@@ -780,13 +763,13 @@ export default function InputWithTags({
)}
>
{!currentFilterType && inputValue && (
-
+
handleSearch(inputValue)}
>
- Search for "{inputValue}"
+ {t("searchFor", { inputValue })}
)}
@@ -796,11 +779,11 @@ export default function InputWithTags({
{isSimilaritySearch && (
- Similarity Search
+ {t("similaritySearch.title")}
@@ -863,7 +846,7 @@ export default function InputWithTags({
!inputValue &&
searchHistoryLoaded &&
(searchHistory?.length ?? 0) > 0 && (
-
+
{searchHistory?.map((suggestion, index) => (
- Delete saved search
+ {t("button.delete")}
diff --git a/web/src/components/overlay/dialog/SearchFilterDialog.tsx b/web/src/components/overlay/dialog/SearchFilterDialog.tsx
index 2e2ca4475..f84501bca 100644
--- a/web/src/components/overlay/dialog/SearchFilterDialog.tsx
+++ b/web/src/components/overlay/dialog/SearchFilterDialog.tsx
@@ -558,8 +558,8 @@ export function SpeedFilterContent({
{t("estimatedSpeed", {
unit:
config?.ui.unit_system == "metric"
- ? t("unit.speed.kph")
- : t("unit.speed.mph"),
+ ? t("unit.speed.kph", { ns: "common" })
+ : t("unit.speed.mph", { ns: "common" }),
})}