i18n fixes (#17184)

* update PR template

* fix hook

* fix input

* fix hook

* add all audio detector keys

* add frigate+ keys

* fix spelling, formatting, and spacing

* fix labels

* capitalization

* fix timestamp

* fix menu

* fix plus text

* fix download label

* docs

* fix docs build

* fix docs formatting
This commit is contained in:
Josh Hawkins 2025-03-16 12:13:34 -05:00 committed by GitHub
parent d34533981f
commit c724892158
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 685 additions and 227 deletions

View File

@ -35,4 +35,5 @@
- [ ] The code change is tested and works locally.
- [ ] Local tests pass. **Your PR cannot be merged unless tests pass**
- [ ] There is no commented out code in this PR.
- [ ] UI changes including text have used i18n keys and have been added to the `en` locale.
- [ ] The code has been formatted using Ruff (`ruff format frigate`)

View File

@ -72,7 +72,7 @@ COPY --from=rootfs / /
The images for each board will be built for each Frigate release, this is done in the `.github/workflows/ci.yml` file. The board build workflow will need to be added here.
```yml
- name: Build and push board build
- name: Build and push board build
uses: docker/bake-action@v3
with:
push: true

View File

@ -235,3 +235,14 @@ When testing nginx config changes from within the dev container, the following c
```console
sudo cp docker/main/rootfs/usr/local/nginx/conf/* /usr/local/nginx/conf/ && sudo /usr/local/nginx/sbin/nginx -s reload
```
## Contributing translations of the Web UI
If you'd like to contribute translations to Frigate, please follow these steps:
1. Fork the repository and create a new branch specifically for your translation work
2. Locate the localization files in the web/public/locales directory
3. Add or modify the appropriate language JSON files, maintaining the existing key structure while translating only the values
4. Ensure your translations maintain proper formatting, including any placeholder variables (like `{{example}}`)
5. Before submitting, thoroughly review the UI
6. When creating your PR, include a brief description of the languages you've added or updated, and reference any related issues

View File

@ -1,8 +1,430 @@
{
"crying": "Crying",
"laughter": "Laughter",
"scream": "Scream",
"speech": "Speech",
"babbling": "Babbling",
"yell": "Yell",
"fire_alarm": "Fire alarm"
"bellow": "Bellow",
"whoop": "Whoop",
"whispering": "Whispering",
"laughter": "Laughter",
"snicker": "Snicker",
"crying": "Crying",
"sigh": "Sigh",
"singing": "Singing",
"choir": "Choir",
"yodeling": "Yodeling",
"chant": "Chant",
"mantra": "Mantra",
"child_singing": "Child Singing",
"synthetic_singing": "Synthetic Singing",
"rapping": "Rapping",
"humming": "Humming",
"groan": "Groan",
"grunt": "Grunt",
"whistling": "Whistling",
"breathing": "Breathing",
"wheeze": "Wheeze",
"snoring": "Snoring",
"gasp": "Gasp",
"pant": "Pant",
"snort": "Snort",
"cough": "Cough",
"throat_clearing": "Throat Clearing",
"sneeze": "Sneeze",
"sniff": "Sniff",
"run": "Run",
"shuffle": "Shuffle",
"footsteps": "Footsteps",
"chewing": "Chewing",
"biting": "Biting",
"gargling": "Gargling",
"stomach_rumble": "Stomach Rumble",
"burping": "Burping",
"hiccup": "Hiccup",
"fart": "Fart",
"hands": "Hands",
"finger_snapping": "Finger Snapping",
"clapping": "Clapping",
"heartbeat": "Heartbeat",
"heart_murmur": "Heart Murmur",
"cheering": "Cheering",
"applause": "Applause",
"chatter": "Chatter",
"crowd": "Crowd",
"children_playing": "Children Playing",
"animal": "Animal",
"pets": "Pets",
"dog": "Dog",
"bark": "Bark",
"yip": "Yip",
"howl": "Howl",
"bow_wow": "Bow Wow",
"growling": "Growling",
"whimper_dog": "Dog Whimper",
"cat": "Cat",
"purr": "Purr",
"meow": "Meow",
"hiss": "Hiss",
"caterwaul": "Caterwaul",
"livestock": "Livestock",
"horse": "Horse",
"clip_clop": "Clip Clop",
"neigh": "Neigh",
"cattle": "Cattle",
"moo": "Moo",
"cowbell": "Cowbell",
"pig": "Pig",
"oink": "Oink",
"goat": "Goat",
"bleat": "Bleat",
"sheep": "Sheep",
"fowl": "Fowl",
"chicken": "Chicken",
"cluck": "Cluck",
"cock_a_doodle_doo": "Cock-a-Doodle-Doo",
"turkey": "Turkey",
"gobble": "Gobble",
"duck": "Duck",
"quack": "Quack",
"goose": "Goose",
"honk": "Honk",
"wild_animals": "Wild Animals",
"roaring_cats": "Roaring Cats",
"roar": "Roar",
"bird": "Bird",
"chirp": "Chirp",
"squawk": "Squawk",
"pigeon": "Pigeon",
"coo": "Coo",
"crow": "Crow",
"caw": "Caw",
"owl": "Owl",
"hoot": "Hoot",
"flapping_wings": "Flapping Wings",
"dogs": "Dogs",
"rats": "Rats",
"mouse": "Mouse",
"patter": "Patter",
"insect": "Insect",
"cricket": "Cricket",
"mosquito": "Mosquito",
"fly": "Fly",
"buzz": "Buzz",
"frog": "Frog",
"croak": "Croak",
"snake": "Snake",
"rattle": "Rattle",
"whale_vocalization": "Whale Vocalization",
"music": "Music",
"musical_instrument": "Musical Instrument",
"plucked_string_instrument": "Plucked String Instrument",
"guitar": "Guitar",
"electric_guitar": "Electric Guitar",
"bass_guitar": "Bass Guitar",
"acoustic_guitar": "Acoustic Guitar",
"steel_guitar": "Steel Guitar",
"tapping": "Tapping",
"strum": "Strum",
"banjo": "Banjo",
"sitar": "Sitar",
"mandolin": "Mandolin",
"zither": "Zither",
"ukulele": "Ukulele",
"keyboard": "Keyboard",
"piano": "Piano",
"electric_piano": "Electric Piano",
"organ": "Organ",
"electronic_organ": "Electronic Organ",
"hammond_organ": "Hammond Organ",
"synthesizer": "Synthesizer",
"sampler": "Sampler",
"harpsichord": "Harpsichord",
"percussion": "Percussion",
"drum_kit": "Drum Kit",
"drum_machine": "Drum Machine",
"drum": "Drum",
"snare_drum": "Snare Drum",
"rimshot": "Rimshot",
"drum_roll": "Drum Roll",
"bass_drum": "Bass Drum",
"timpani": "Timpani",
"tabla": "Tabla",
"cymbal": "Cymbal",
"hi_hat": "Hi-Hat",
"wood_block": "Wood Block",
"tambourine": "Tambourine",
"rattle": "Rattle",
"maraca": "Maraca",
"gong": "Gong",
"tubular_bells": "Tubular Bells",
"mallet_percussion": "Mallet Percussion",
"marimba": "Marimba",
"glockenspiel": "Glockenspiel",
"vibraphone": "Vibraphone",
"steelpan": "Steelpan",
"orchestra": "Orchestra",
"brass_instrument": "Brass Instrument",
"french_horn": "French Horn",
"trumpet": "Trumpet",
"trombone": "Trombone",
"bowed_string_instrument": "Bowed String Instrument",
"string_section": "String Section",
"violin": "Violin",
"pizzicato": "Pizzicato",
"cello": "Cello",
"double_bass": "Double Bass",
"wind_instrument": "Wind Instrument",
"flute": "Flute",
"saxophone": "Saxophone",
"clarinet": "Clarinet",
"harp": "Harp",
"bell": "Bell",
"church_bell": "Church Bell",
"jingle_bell": "Jingle Bell",
"bicycle_bell": "Bicycle Bell",
"tuning_fork": "Tuning Fork",
"chime": "Chime",
"wind_chime": "Wind Chime",
"harmonica": "Harmonica",
"accordion": "Accordion",
"bagpipes": "Bagpipes",
"didgeridoo": "Didgeridoo",
"theremin": "Theremin",
"singing_bowl": "Singing Bowl",
"scratching": "Scratching",
"pop_music": "Pop Music",
"hip_hop_music": "Hip-Hop Music",
"beatboxing": "Beatboxing",
"rock_music": "Rock Music",
"heavy_metal": "Heavy Metal",
"punk_rock": "Punk Rock",
"grunge": "Grunge",
"progressive_rock": "Progressive Rock",
"rock_and_roll": "Rock and Roll",
"psychedelic_rock": "Psychedelic Rock",
"rhythm_and_blues": "Rhythm and Blues",
"soul_music": "Soul Music",
"reggae": "Reggae",
"country": "Country",
"swing_music": "Swing Music",
"bluegrass": "Bluegrass",
"funk": "Funk",
"folk_music": "Folk Music",
"middle_eastern_music": "Middle Eastern Music",
"jazz": "Jazz",
"disco": "Disco",
"classical_music": "Classical Music",
"opera": "Opera",
"electronic_music": "Electronic Music",
"house_music": "House Music",
"techno": "Techno",
"dubstep": "Dubstep",
"drum_and_bass": "Drum and Bass",
"electronica": "Electronica",
"electronic_dance_music": "Electronic Dance Music",
"ambient_music": "Ambient Music",
"trance_music": "Trance Music",
"music_of_latin_america": "Music of Latin America",
"salsa_music": "Salsa Music",
"flamenco": "Flamenco",
"blues": "Blues",
"music_for_children": "Music for Children",
"new-age_music": "New Age Music",
"vocal_music": "Vocal Music",
"a_capella": "A Capella",
"music_of_africa": "Music of Africa",
"afrobeat": "Afrobeat",
"christian_music": "Christian Music",
"gospel_music": "Gospel Music",
"music_of_asia": "Music of Asia",
"carnatic_music": "Carnatic Music",
"music_of_bollywood": "Music of Bollywood",
"ska": "Ska",
"traditional_music": "Traditional Music",
"independent_music": "Independent Music",
"song": "Song",
"background_music": "Background Music",
"theme_music": "Theme Music",
"jingle": "Jingle",
"soundtrack_music": "Soundtrack Music",
"lullaby": "Lullaby",
"video_game_music": "Video Game Music",
"christmas_music": "Christmas Music",
"dance_music": "Dance Music",
"wedding_music": "Wedding Music",
"happy_music": "Happy Music",
"sad_music": "Sad Music",
"tender_music": "Tender Music",
"exciting_music": "Exciting Music",
"angry_music": "Angry Music",
"scary_music": "Scary Music",
"wind": "Wind",
"rustling_leaves": "Rustling Leaves",
"wind_noise": "Wind Noise",
"thunderstorm": "Thunderstorm",
"thunder": "Thunder",
"water": "Water",
"rain": "Rain",
"raindrop": "Raindrop",
"rain_on_surface": "Rain on Surface",
"stream": "Stream",
"waterfall": "Waterfall",
"ocean": "Ocean",
"waves": "Waves",
"steam": "Steam",
"gurgling": "Gurgling",
"fire": "Fire",
"crackle": "Crackle",
"vehicle": "Vehicle",
"boat": "Boat",
"sailboat": "Sailboat",
"rowboat": "Rowboat",
"motorboat": "Motorboat",
"ship": "Ship",
"motor_vehicle": "Motor Vehicle",
"car": "Car",
"honk": "Honk",
"toot": "Toot",
"car_alarm": "Car Alarm",
"power_windows": "Power Windows",
"skidding": "Skidding",
"tire_squeal": "Tire Squeal",
"car_passing_by": "Car Passing By",
"race_car": "Race Car",
"truck": "Truck",
"air_brake": "Air Brake",
"air_horn": "Air Horn",
"reversing_beeps": "Reversing Beeps",
"ice_cream_truck": "Ice Cream Truck",
"bus": "Bus",
"emergency_vehicle": "Emergency Vehicle",
"police_car": "Police Car",
"ambulance": "Ambulance",
"fire_engine": "Fire Engine",
"motorcycle": "Motorcycle",
"traffic_noise": "Traffic Noise",
"rail_transport": "Rail Transport",
"train": "Train",
"train_whistle": "Train Whistle",
"train_horn": "Train Horn",
"railroad_car": "Railroad Car",
"train_wheels_squealing": "Train Wheels Squealing",
"subway": "Subway",
"aircraft": "Aircraft",
"aircraft_engine": "Aircraft Engine",
"jet_engine": "Jet Engine",
"propeller": "Propeller",
"helicopter": "Helicopter",
"fixed-wing_aircraft": "Fixed-Wing Aircraft",
"bicycle": "Bicycle",
"skateboard": "Skateboard",
"engine": "Engine",
"light_engine": "Light Engine",
"dental_drill's_drill": "Dental Drill",
"lawn_mower": "Lawn Mower",
"chainsaw": "Chainsaw",
"medium_engine": "Medium Engine",
"heavy_engine": "Heavy Engine",
"engine_knocking": "Engine Knocking",
"engine_starting": "Engine Starting",
"idling": "Idling",
"accelerating": "Accelerating",
"door": "Door",
"doorbell": "Doorbell",
"ding-dong": "Ding-Dong",
"sliding_door": "Sliding Door",
"slam": "Slam",
"knock": "Knock",
"tap": "Tap",
"squeak": "Squeak",
"cupboard_open_or_close": "Cupboard Open or Close",
"drawer_open_or_close": "Drawer Open or Close",
"dishes": "Dishes",
"cutlery": "Cutlery",
"chopping": "Chopping",
"frying": "Frying",
"microwave_oven": "Microwave Oven",
"blender": "Blender",
"water_tap": "Water Tap",
"sink": "Sink",
"bathtub": "Bathtub",
"hair_dryer": "Hair Dryer",
"toilet_flush": "Toilet Flush",
"toothbrush": "Toothbrush",
"electric_toothbrush": "Electric Toothbrush",
"vacuum_cleaner": "Vacuum Cleaner",
"zipper": "Zipper",
"keys_jangling": "Keys Jangling",
"coin": "Coin",
"scissors": "Scissors",
"electric_shaver": "Electric Shaver",
"shuffling_cards": "Shuffling Cards",
"typing": "Typing",
"typewriter": "Typewriter",
"computer_keyboard": "Computer Keyboard",
"writing": "Writing",
"alarm": "Alarm",
"telephone": "Telephone",
"telephone_bell_ringing": "Telephone Bell Ringing",
"ringtone": "Ringtone",
"telephone_dialing": "Telephone Dialing",
"dial_tone": "Dial Tone",
"busy_signal": "Busy Signal",
"alarm_clock": "Alarm Clock",
"siren": "Siren",
"civil_defense_siren": "Civil Defense Siren",
"buzzer": "Buzzer",
"smoke_detector": "Smoke Detector",
"fire_alarm": "Fire Alarm",
"foghorn": "Foghorn",
"whistle": "Whistle",
"steam_whistle": "Steam Whistle",
"mechanisms": "Mechanisms",
"ratchet": "Ratchet",
"clock": "Clock",
"tick": "Tick",
"tick-tock": "Tick-Tock",
"gears": "Gears",
"pulleys": "Pulleys",
"sewing_machine": "Sewing Machine",
"mechanical_fan": "Mechanical Fan",
"air_conditioning": "Air Conditioning",
"cash_register": "Cash Register",
"printer": "Printer",
"camera": "Camera",
"single-lens_reflex_camera": "Single-Lens Reflex Camera",
"tools": "Tools",
"hammer": "Hammer",
"jackhammer": "Jackhammer",
"sawing": "Sawing",
"filing": "Filing",
"sanding": "Sanding",
"power_tool": "Power Tool",
"drill": "Drill",
"explosion": "Explosion",
"gunshot": "Gunshot",
"machine_gun": "Machine Gun",
"fusillade": "Fusillade",
"artillery_fire": "Artillery Fire",
"cap_gun": "Cap Gun",
"fireworks": "Fireworks",
"firecracker": "Firecracker",
"burst": "Burst",
"eruption": "Eruption",
"boom": "Boom",
"wood": "Wood",
"chop": "Chop",
"splinter": "Splinter",
"crack": "Crack",
"glass": "Glass",
"chink": "Chink",
"shatter": "Shatter",
"silence": "Silence",
"sound_effect": "Sound Effect",
"environmental_noise": "Environmental Noise",
"static": "Static",
"white_noise": "White Noise",
"pink_noise": "Pink Noise",
"television": "Television",
"radio": "Radio",
"field_recording": "Field Recording"
}

View File

@ -96,8 +96,8 @@
"languages": "Languages",
"language": {
"en": "English",
"zhCN": "简体中文(Simplified Chinese)",
"withSystem.label": "Use the system settings for languag"
"zhCN": "简体中文 (Simplified Chinese)",
"withSystem.label": "Use the system settings for language"
},
"appearance": "Appearance",
"darkMode": {

View File

@ -9,7 +9,7 @@
"rateLimit": "Exceeded rate limit. Try again later.",
"loginFailed": "Login failed",
"unknownError": "Unknown error. Check logs.",
"webUnkownError": "Unknown error. Check console logs."
"webUnknownError": "Unknown error. Check console logs."
}
}
}

View File

@ -1,8 +1,8 @@
{
"group": {
"label": "Camera Groups",
"add": "Add camera groups",
"edit": "Edit camera groups",
"add": "Add Camera Group",
"edit": "Edit Camera Group",
"delete": {
"label": "Delete Camera Group",
"confirm": "Confirm Delete",

View File

@ -19,8 +19,8 @@
"bandwidth.short": "Bandwidth",
"latency": "Latency:",
"latency.short": "Latency",
"latency.value": "{{secounds}} seconds",
"latency.short.value": "{{secounds}} sec",
"latency.value": "{{seconds}} seconds",
"latency.short.value": "{{seconds}} sec",
"totalFrames": "Total Frames:",
"droppedFrames": "Dropped Frames:",
"droppedFrames.short": "Dropped",

View File

@ -99,6 +99,22 @@
"rabbit": "Rabbit",
"raccoon": "Raccoon",
"robot_lawnmower": "Robot Lawnmower",
"waste_bin": "Waste bin",
"on_demand": "On_demand"
"waste_bin": "Waste Bin",
"on_demand": "On Demand",
"face": "Face",
"license_plate": "License Plate",
"package": "Package",
"bbq_grill": "BBQ Grill",
"amazon": "Amazon",
"usps": "USPS",
"ups": "UPS",
"fedex": "FedEx",
"dhl": "DHL",
"an_post": "An Post",
"purolator": "Purolator",
"postnl": "PostNL",
"nzpost": "NZPost",
"postnord": "PostNord",
"gls": "GLS",
"dpd": "DPD"
}

View File

@ -89,8 +89,8 @@
"camera": "Camera",
"unused": "Unused",
"unusedStorageInformation": "Unused Storage Information",
"storageUsed": "Storage Used",
"percentageOfTotalUsed": "Percentage of Total Used",
"storageUsed": "Storage",
"percentageOfTotalUsed": "Percentage of Total",
"bandwidth": "Bandwidth",
"unused.tips": "This value may not accurately represent the free space available to Frigate if you have other files stored on your drive beyond Frigate's recordings. Frigate does not track storage usage outside of its recordings."
}

View File

@ -101,7 +101,7 @@
"systemLogs": "系统日志",
"settings": "设置",
"configurationEditor": "配置编辑器",
"languages": "languages / 语言",
"languages": "Languages / 语言",
"language": {
"en": "English",
"zhCN": "简体中文",

View File

@ -9,7 +9,7 @@
"rateLimit": "超出请求限制,请稍后再试。",
"loginFailed": "登录失败",
"unknownError": "未知错误,请检查日志。",
"webUnkownError": "未知错误,请检查控制台日志。"
"webUnknownError": "未知错误,请检查控制台日志。"
}
}
}

View File

@ -19,8 +19,8 @@
"bandwidth.short": "带宽",
"latency": "延迟:",
"latency.short": "延迟",
"latency.value": "{{secounds}} 秒",
"latency.short.value": "{{secounds}} 秒",
"latency.value": "{{seconds}} 秒",
"latency.short.value": "{{seconds}} 秒",
"totalFrames": "总帧数:",
"droppedFrames": "丢帧数:",
"droppedFrames.short": "丢帧",

View File

@ -77,7 +77,7 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
});
}
} else {
toast.error(t("form.errors.webUnkownError"), {
toast.error(t("form.errors.webUnknownError"), {
position: "top-center",
});
}

View File

@ -74,7 +74,7 @@ export default function InputWithTags({
setSearch,
allSuggestions,
}: InputWithTagsProps) {
const { t } = useTranslation(["views/search"]);
const { t, i18n } = useTranslation(["views/search"]);
const { data: config } = useSWR<FrigateConfig>("config", {
revalidateOnFocus: false,
});
@ -900,12 +900,17 @@ export default function InputWithTags({
className="cursor-pointer"
onSelect={() => handleSuggestionClick(suggestion)}
>
{i18n.language === "en" ? (
suggestion
) : (
<>
{suggestion} {" ("}
{currentFilterType
? formatFilterValues(currentFilterType, suggestion)
: t("filter.label." + suggestion)}
{" ("}
{suggestion}
{")"}
</>
)}
</CommandItem>
))}
</CommandGroup>

View File

@ -104,7 +104,7 @@ export default function SearchResultActions({
download={`${searchResult.camera}_${searchResult.label}.mp4`}
>
<LuDownload className="mr-2 size-4" />
<span>{t("itemMenu.downloadVideo")}</span>
<span>{t("itemMenu.downloadVideo.label")}</span>
</a>
</MenuItem>
)}

View File

@ -570,8 +570,12 @@ export default function ObjectLifecycle({
timezone: config.ui.timezone,
strftime_fmt:
config.ui.time_format == "24hour"
? t("time.formattedTimestamp2.24hour")
: t("time.formattedTimestamp2"),
? t("time.formattedTimestamp2.24hour", {
ns: "common",
})
: t("time.formattedTimestamp2", {
ns: "common",
}),
time_style: "medium",
date_style: "medium",
})}

View File

@ -226,7 +226,7 @@ export default function SearchDetailDialog({
{item == "object_lifecycle" && (
<FaRotate className="size-4" />
)}
<div className="capitalize">{t("type.{item}")}</div>
<div className="capitalize">{t(`type.${item}`)}</div>
</ToggleGroupItem>
))}
</ToggleGroup>
@ -310,8 +310,8 @@ function ObjectDetailsTab({
const formattedDate = useFormattedTimestamp(
search?.start_time ?? 0,
config?.ui.time_format == "24hour"
? t("time.formattedTimestampWithYear.24hour")
: t("time.formattedTimestampWithYear"),
? t("time.formattedTimestampWithYear.24hour", { ns: "common" })
: t("time.formattedTimestampWithYear", { ns: "common" }),
config?.ui.timezone,
);
@ -902,10 +902,10 @@ export function ObjectSnapshotTab({
"text-lg font-semibold leading-none tracking-tight"
}
>
{t("explore.submitToPlus.label")}
{t("explore.plus.submitToPlus.label")}
</div>
<div className="text-sm text-muted-foreground">
{t("explore.submitToPlus.desc")}
{t("explore.plus.submitToPlus.desc")}
</div>
</div>

View File

@ -25,7 +25,7 @@ export function PlayerStats({ stats, minimal }: PlayerStatsProps) {
<span
className={`text-white ${stats.latency > 2 ? "text-danger" : ""}`}
>
{t("stats.latency.value", { secounds: stats.latency.toFixed(2) })}
{t("stats.latency.value", { seconds: stats.latency.toFixed(2) })}
</span>
</p>
)}
@ -73,7 +73,7 @@ export function PlayerStats({ stats, minimal }: PlayerStatsProps) {
className={`text-white ${stats.latency >= 2 ? "text-danger" : ""}`}
>
{t("stats.latency.short.value", {
secounds: stats.latency.toFixed(2),
seconds: stats.latency.toFixed(2),
})}
</span>
</div>

View File

@ -290,14 +290,18 @@ export function CameraStreamingDialog({
</SelectTrigger>
<SelectContent>
<SelectItem value="no-streaming">
{t("group.camera.setting.streamMethod.method.noStreaming")}
{t(
"group.camera.setting.streamMethod.method.noStreaming.label",
)}
</SelectItem>
<SelectItem value="smart">
{t("group.camera.setting.streamMethod.method.smartStreaming")}
{t(
"group.camera.setting.streamMethod.method.smartStreaming.label",
)}
</SelectItem>
<SelectItem value="continuous">
{t(
"group.camera.setting.streamMethod.method.continuousStreaming",
"group.camera.setting.streamMethod.method.continuousStreaming.label",
)}
</SelectItem>
</SelectContent>
@ -344,7 +348,7 @@ export function CameraStreamingDialog({
htmlFor="compatibility"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
{t("group.camera.setting.compatibilityMode")}
{t("group.camera.setting.compatibilityMode.label")}
</Label>
</div>
<div className="flex flex-col gap-2 leading-none">

View File

@ -12,10 +12,7 @@ import {
import { Switch } from "./switch";
import { cn } from "@/lib/utils";
import { LuCheck } from "react-icons/lu";
import { useTranslation } from "react-i18next";
const { t } = useTranslation(["common"]);
import { t } from "i18next";
export interface DateRangePickerProps {
/** Click handler for applying the updates from DateRangePicker. */
@ -433,7 +430,7 @@ export function DateRangePicker({
}
}}
>
{t("button.apply", { ns: "common"})}
{t("button.apply", { ns: "common" })}
</Button>
<Button
onClick={() => {
@ -444,7 +441,7 @@ export function DateRangePicker({
variant="ghost"
aria-label={t("button.reset", { ns: "common" })}
>
{t("button.reset", { ns: "common"})}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</div>

View File

@ -1,11 +1,9 @@
import * as React from "react"
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
import * as React from "react";
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
import { cn } from "@/lib/utils"
import { ButtonProps, buttonVariants } from "@/components/ui/button"
import { useTranslation } from "react-i18next"
const { t } = useTranslation(["common"])
import { cn } from "@/lib/utils";
import { ButtonProps, buttonVariants } from "@/components/ui/button";
import { t } from "i18next";
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
<nav
@ -14,8 +12,8 @@ const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
className={cn("mx-auto flex w-full justify-center", className)}
{...props}
/>
)
Pagination.displayName = "Pagination"
);
Pagination.displayName = "Pagination";
const PaginationContent = React.forwardRef<
HTMLUListElement,
@ -26,21 +24,21 @@ const PaginationContent = React.forwardRef<
className={cn("flex flex-row items-center gap-1", className)}
{...props}
/>
))
PaginationContent.displayName = "PaginationContent"
));
PaginationContent.displayName = "PaginationContent";
const PaginationItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ className, ...props }, ref) => (
<li ref={ref} className={cn("", className)} {...props} />
))
PaginationItem.displayName = "PaginationItem"
));
PaginationItem.displayName = "PaginationItem";
type PaginationLinkProps = {
isActive?: boolean
isActive?: boolean;
} & Pick<ButtonProps, "size"> &
React.ComponentProps<"a">
React.ComponentProps<"a">;
const PaginationLink = ({
className,
@ -55,12 +53,12 @@ const PaginationLink = ({
variant: isActive ? "outline" : "ghost",
size,
}),
className
className,
)}
{...props}
/>
)
PaginationLink.displayName = "PaginationLink"
);
PaginationLink.displayName = "PaginationLink";
const PaginationPrevious = ({
className,
@ -75,8 +73,8 @@ const PaginationPrevious = ({
<ChevronLeft className="h-4 w-4" />
<span>{t("pagination.previous")}</span>
</PaginationLink>
)
PaginationPrevious.displayName = "PaginationPrevious"
);
PaginationPrevious.displayName = "PaginationPrevious";
const PaginationNext = ({
className,
@ -91,8 +89,8 @@ const PaginationNext = ({
<span>{t("pagination.next")}</span>
<ChevronRight className="h-4 w-4" />
</PaginationLink>
)
PaginationNext.displayName = "PaginationNext"
);
PaginationNext.displayName = "PaginationNext";
const PaginationEllipsis = ({
className,
@ -106,8 +104,8 @@ const PaginationEllipsis = ({
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">{t("pagination.more")}</span>
</span>
)
PaginationEllipsis.displayName = "PaginationEllipsis"
);
PaginationEllipsis.displayName = "PaginationEllipsis";
export {
Pagination,
@ -117,4 +115,4 @@ export {
PaginationLink,
PaginationNext,
PaginationPrevious,
}
};