diff --git a/docs/configs/settings.md b/docs/configs/settings.md index 035da32cd..a3ab2981d 100644 --- a/docs/configs/settings.md +++ b/docs/configs/settings.md @@ -396,7 +396,9 @@ Set your desired language using: language: fr ``` -Currently supported languages: ca, de, en, es, fr, he, hr, hu, it, nb-NO, nl, pt, ru, sv, vi, zh-CN, zh-Hant +Currently supported languages: ca, de, en, es, fr, he, hr, hu, it, nb-NO, nl, pt, ru, sv, vi, zh-Hans (Simplified), zh-Hant (Traditional) + +`zh-CN` will still work and is automatically mapped to `zh-Hans` for backwards compatibility. You can also specify locales e.g. for the DateTime widget, e.g. en-AU, en-GB, etc. diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json deleted file mode 100644 index d9ab4c628..000000000 --- a/public/locales/zh-CN/common.json +++ /dev/null @@ -1,750 +0,0 @@ -{ - "widget": { - "missing_type": "缺少小部件类型:{{type}}", - "api_error": "API错误", - "status": "状态", - "information": "信息", - "url": "URL", - "raw_error": "原始错误", - "response_data": "返回数据" - }, - "search": { - "placeholder": "搜索…" - }, - "resources": { - "total": "总计", - "free": "空闲", - "used": "已用", - "load": "负载", - "cpu": "处理器", - "mem": "内存", - "temp": "温度", - "max": "最大", - "uptime": "运行时间", - "months": "月", - "days": "天", - "hours": "时", - "minutes": "分" - }, - "docker": { - "rx": "接收", - "tx": "发送", - "mem": "内存", - "cpu": "处理器", - "offline": "离线", - "error": "错误", - "unknown": "未知问题", - "starting": "启动中", - "unhealthy": "不健康的", - "not_found": "未找到", - "running": "运行中", - "exited": "已退出", - "partial": "部分", - "healthy": "健康的" - }, - "emby": { - "playing": "播放中", - "transcoding": "转码", - "bitrate": "比特率", - "no_active": "暂无播放", - "movies": "电影", - "series": "系列", - "episodes": "剧集", - "songs": "歌曲" - }, - "tautulli": { - "playing": "播放中", - "transcoding": "转码", - "bitrate": "比特率", - "no_active": "暂无播放", - "plex_connection_error": "Check Plex Connection" - }, - "rutorrent": { - "active": "活动中", - "upload": "上传", - "download": "下载" - }, - "sonarr": { - "wanted": "想看", - "queued": "排队", - "series": "系列", - "queue": "Queue", - "unknown": "Unknown" - }, - "radarr": { - "wanted": "想看", - "queued": "队列", - "movies": "电影", - "missing": "丢失", - "queue": "Queue", - "unknown": "Unknown" - }, - "readarr": { - "wanted": "订阅", - "queued": "队列", - "books": "书籍" - }, - "ombi": { - "pending": "待办的", - "approved": "已批准", - "available": "可用的" - }, - "jellyseerr": { - "pending": "待办的", - "approved": "得到正式认可的", - "available": "可用的" - }, - "pihole": { - "queries": "查询", - "blocked": "阻止", - "gravity": "重力", - "blocked_percent": "拦截 %" - }, - "speedtest": { - "upload": "上传", - "download": "下载", - "ping": "ping" - }, - "portainer": { - "running": "运行中", - "stopped": "停止", - "total": "总计" - }, - "traefik": { - "routers": "路由器", - "services": "服务", - "middleware": "中间件" - }, - "npm": { - "enabled": "已启用", - "disabled": "禁用", - "total": "全部的" - }, - "weather": { - "current": "当前定位", - "allow": "点击并允许", - "updating": "更新中", - "wait": "请稍候" - }, - "overseerr": { - "pending": "待办", - "approved": "已批准", - "available": "可用", - "processing": "处理中" - }, - "sabnzbd": { - "rate": "速率", - "queue": "队列", - "timeleft": "剩余时间" - }, - "nzbget": { - "rate": "速率", - "remaining": "剩余", - "downloaded": "下载" - }, - "coinmarketcap": { - "configure": "配置一个或多个需要追踪的加密", - "1hour": "1小时", - "1day": "1天", - "7days": "7天", - "30days": "30天" - }, - "gotify": { - "apps": "应用", - "clients": "客户端", - "messages": "信息" - }, - "prowlarr": { - "enableIndexers": "索引器", - "numberOfGrabs": "抓取", - "numberOfQueries": "查询", - "numberOfFailGrabs": "抓取失败", - "numberOfFailQueries": "查询失败" - }, - "transmission": { - "download": "下载", - "upload": "上传", - "leech": "下载中", - "seed": "做种" - }, - "jackett": { - "configured": "已配置", - "errored": "出错了" - }, - "bazarr": { - "missingEpisodes": "缺少的剧集", - "missingMovies": "缺少的电影" - }, - "lidarr": { - "wanted": "订阅", - "queued": "队列", - "artists": "Artists" - }, - "adguard": { - "queries": "查询", - "blocked": "阻止", - "filtered": "过滤", - "latency": "延迟" - }, - "qbittorrent": { - "download": "下载", - "upload": "上传", - "leech": "下载中", - "seed": "做种" - }, - "mastodon": { - "user_count": "用户", - "status_count": "帖子", - "domain_count": "域" - }, - "strelaysrv": { - "numActiveSessions": "会话", - "dataRelayed": "中继", - "numConnections": "连接", - "transferRate": "速度" - }, - "authentik": { - "users": "用户", - "loginsLast24H": "登录 (24h)", - "failedLoginsLast24H": "登录失败 (24h)" - }, - "proxmox": { - "mem": "内存", - "cpu": "处理器", - "lxc": "容器", - "vms": "虚拟机" - }, - "unifi": { - "users": "用户", - "uptime": "系统运行时间", - "days": "天", - "wan": "广域网", - "lan_users": "局域网用户", - "wlan_users": "无线局域网用户", - "up": "向上", - "down": "向下", - "wait": "请稍候", - "lan": "局域网", - "wlan": "无线局域网", - "devices": "设备", - "lan_devices": "局域网设备", - "wlan_devices": "无线局域网设备", - "empty_data": "子系统状态未知" - }, - "plex": { - "streams": "活动流", - "movies": "电影", - "tv": "电视节目", - "albums": "专辑" - }, - "glances": { - "cpu": "处理器", - "wait": "请稍等", - "temp": "温度", - "uptime": "运行时间", - "days": "天", - "hours": "时", - "load": "Load", - "warn": "Warn", - "total": "Total", - "free": "Free", - "used": "Used", - "crit": "Crit", - "read": "Read", - "write": "Write", - "gpu": "GPU", - "mem": "Mem", - "swap": "Swap", - "_temp": "Temp" - }, - "changedetectionio": { - "totalObserved": "观察到的总数", - "diffsDetected": "检测到差异" - }, - "wmo": { - "0-day": "晴天", - "0-night": "晴朗", - "1-day": "主要是晴天", - "3-day": "阴天", - "3-night": "阴天", - "45-day": "有雾", - "48-day": "有雾", - "51-day": "小雨", - "73-night": "中雪", - "75-day": "大雪", - "1-night": "大部晴朗", - "2-day": "多云", - "2-night": "多云", - "45-night": "有雾", - "48-night": "有雾", - "51-night": "小雨", - "53-day": "小雨", - "53-night": "小雨", - "55-day": "毛毛雨", - "55-night": "毛毛雨", - "56-day": "小冻毛雨", - "56-night": "小冻毛雨", - "57-day": "冻毛雨", - "57-night": "冻毛雨", - "61-day": "小雨", - "61-night": "小雨", - "63-day": "雨", - "63-night": "雨", - "65-day": "大雨", - "65-night": "大雨", - "66-day": "冻雨", - "66-night": "冻雨", - "67-day": "冻雨", - "67-night": "冻雨", - "71-day": "小雪", - "71-night": "小雪", - "73-day": "中雪", - "75-night": "大雪", - "77-day": "雪粒", - "77-night": "雪粒", - "80-day": "微阵雨", - "80-night": "微阵雨", - "81-day": "阵雨", - "81-night": "阵雨", - "82-day": "强阵雨", - "82-night": "强阵雨", - "85-day": "阵雪", - "85-night": "阵雪", - "86-day": "阵雪", - "86-night": "阵雪", - "95-day": "雷雨", - "95-night": "雷雨", - "96-day": "雷雨伴随冰雹", - "96-night": "雷雨伴随冰雹", - "99-day": "雷雨伴随冰雹", - "99-night": "雷雨伴随冰雹" - }, - "quicklaunch": { - "bookmark": "书签", - "service": "服务", - "search": "搜索", - "custom": "自定", - "visit": "访问", - "url": "网址" - }, - "homebridge": { - "available_update": "System", - "updates": "更新", - "update_available": "有可用的更新", - "up_to_date": "Up to Date", - "child_bridges": "子网桥", - "child_bridges_status": "{{ok}}/{{total}}", - "up": "Up", - "pending": "待定中", - "down": "Down" - }, - "autobrr": { - "approvedPushes": "已核准", - "rejectedPushes": "拒绝", - "filters": "Filters", - "indexers": "索引器" - }, - "watchtower": { - "containers_scanned": "已扫描", - "containers_updated": "已升级", - "containers_failed": "失败" - }, - "tubearchivist": { - "downloads": "队列", - "videos": "影片", - "channels": "频道", - "playlists": "播放清单" - }, - "truenas": { - "load": "系统负载", - "uptime": "运行时间", - "alerts": "警报", - "time": "{{value, number(style: unit; unitDisplay: long;)}}" - }, - "navidrome": { - "nothing_streaming": "暂无播放", - "please_wait": "请等待" - }, - "pyload": { - "speed": "速度", - "active": "Active", - "queue": "队列", - "total": "Total" - }, - "gluetun": { - "public_ip": "公网 IP", - "region": "区域", - "country": "国家" - }, - "hdhomerun": { - "channels": "频道", - "hd": "HD" - }, - "ping": { - "error": "错误", - "ping": "Ping", - "up": "Up", - "down": "Down" - }, - "scrutiny": { - "passed": "通过", - "failed": "失败", - "unknown": "未知的" - }, - "paperlessngx": { - "inbox": "收件箱", - "total": "Total" - }, - "deluge": { - "download": "下载", - "upload": "上传", - "leech": "下载中", - "seed": "做种" - }, - "flood": { - "leech": "下载中", - "download": "下载", - "upload": "上传", - "seed": "做种" - }, - "tdarr": { - "saved": "已保存", - "queue": "队列", - "processed": "已处理", - "errored": "出错" - }, - "miniflux": { - "read": "已读", - "unread": "未读" - }, - "nextdns": { - "wait": "请稍候", - "no_devices": "没有接收到设备数据" - }, - "common": { - "bibyterate": "{{value, rate(bits: false; binary: true)}}", - "bibitrate": "{{value, rate(bits: true; binary: true)}}" - }, - "omada": { - "connectedAp": "连接中的AP", - "activeUser": "活跃设备", - "alerts": "警报", - "connectedGateway": "已连接网关", - "connectedSwitches": "已连接开关" - }, - "downloadstation": { - "download": "下载", - "upload": "上传", - "leech": "下载中", - "seed": "做种" - }, - "mikrotik": { - "cpuLoad": "处理器", - "memoryUsed": "内存", - "uptime": "运行时间", - "numberOfLeases": "租约" - }, - "xteve": { - "streams_all": "所有播放活动", - "streams_active": "正在播放", - "streams_xepg": "XEPG 频道" - }, - "opnsense": { - "cpu": "处理器", - "memory": "内存", - "wanUpload": "WAN上传", - "wanDownload": "WAN下载" - }, - "moonraker": { - "printer_state": "打印机状态", - "print_status": "打印状态", - "print_progress": "打印进程", - "layers": "层" - }, - "medusa": { - "wanted": "关注中", - "queued": "已加入队列", - "series": "Series" - }, - "octoprint": { - "printer_state": "打印机状态", - "temp_tool": "喷头温度", - "temp_bed": "平台温度", - "job_completion": "完成度" - }, - "cloudflared": { - "origin_ip": "源IP", - "status": "状态" - }, - "proxmoxbackupserver": { - "datastore_usage": "数据存储", - "failed_tasks_24h": "24h失败任务", - "cpu_usage": "处理器", - "memory_usage": "内存" - }, - "immich": { - "users": "使用者", - "photos": "照片", - "videos": "影片", - "storage": "储存空间" - }, - "uptimekuma": { - "up": "在线网站", - "down": "离线网站", - "uptime": "运行时间", - "incident": "严重事件", - "m": "m" - }, - "komga": { - "libraries": "书库", - "series": "系列", - "books": "书刊" - }, - "mylar": { - "series": "系列", - "issues": "问题", - "wanted": "关注中" - }, - "photoprism": { - "albums": "相册", - "photos": "照片", - "videos": "视频", - "people": "人物" - }, - "diskstation": { - "uptime": "运行时间", - "volumeAvailable": "剩余存储", - "days": "天" - }, - "fileflows": { - "queue": "队列", - "processing": "处理中", - "processed": "已处理", - "time": "时间" - }, - "grafana": { - "totalalerts": "警报总数", - "dashboards": "控制面板", - "datasources": "数据来源", - "alertstriggered": "触发的警报" - }, - "nextcloud": { - "cpuload": "处理器", - "memoryusage": "内存", - "freespace": "剩余空间", - "activeusers": "活跃用户", - "numfiles": "Files", - "numshares": "共享项目" - }, - "kopia": { - "status": "状态", - "size": "大小", - "lastrun": "最后运行", - "nextrun": "下次运行", - "failed": "失败" - }, - "unmanic": { - "active_workers": "在线工作节点", - "total_workers": "工作节点总数", - "records_total": "队列长度" - }, - "healthchecks": { - "new": "新建立", - "up": "在线的", - "grace": "延缓中", - "down": "离线", - "paused": "暂停", - "status": "状态", - "last_ping": "上次检查", - "never": "尚未检查" - }, - "pterodactyl": { - "servers": "服务器", - "nodes": "节点" - }, - "prometheus": { - "targets_up": "目标上线", - "targets_down": "目标在线", - "targets_total": "总目标" - }, - "minecraft": { - "players": "玩家", - "version": "版本", - "status": "状态", - "up": "在线的", - "down": "离线" - }, - "ghostfolio": { - "gross_percent_today": "今天", - "gross_percent_1y": "一年", - "gross_percent_max": "所有时间" - }, - "audiobookshelf": { - "podcasts": "播客", - "books": "图书", - "podcastsDuration": "持续时间", - "booksDuration": "持续时间" - }, - "homeassistant": { - "people_home": "房间", - "lights_on": "照明开", - "switches_on": "开关开" - }, - "freshrss": { - "subscriptions": "订阅", - "unread": "未读" - }, - "channelsdvrserver": { - "shows": "节目", - "recordings": "录像", - "scheduled": "已计划的", - "passes": "通行证" - }, - "whatsupdocker": { - "monitoring": "监测中", - "updates": "可更新" - }, - "tailscale": { - "address": "地址", - "expires": "失效", - "never": "从不", - "last_seen": "最后上线", - "days": "{{number}}d", - "hours": "{{number}}h", - "minutes": "{{number}}m", - "seconds": "{{number}}s", - "ago": "{{value}} 以前", - "now": "现在", - "years": "{{number}}年", - "weeks": "{{number}}周" - }, - "qnap": { - "cpuUsage": "处理器", - "memUsage": "内存", - "systemTempC": "系统温度", - "poolUsage": "存储池", - "volumeUsage": "Volume Usage", - "invalid": "Invalid" - }, - "pfsense": { - "load": "平均负载", - "memory": "内存", - "wanStatus": "WAN 状态", - "up": "上传", - "down": "下载", - "temp": "温度", - "disk": "磁盘", - "wanIP": "WAN IP" - }, - "caddy": { - "upstreams": "上游", - "requests": "当前请求", - "requests_failed": "失败请求" - }, - "evcc": { - "pv_power": "正式环境", - "battery_soc": "Battery", - "grid_power": "Grid", - "home_power": "Consumption", - "charge_power": "Charger", - "watt_hour": "Wh" - }, - "pialert": { - "total": "Total", - "connected": "Connected", - "new_devices": "New Devices", - "down_alerts": "Down Alerts" - }, - "jdownloader": { - "downloadCount": "Queue Count", - "downloadSpeed": "Download Speed", - "downloadBytesRemaining": "Remaining", - "downloadTotalBytes": "Size" - }, - "kavita": { - "seriesCount": "系列", - "totalFiles": "文件" - }, - "gamedig": { - "name": "Name", - "map": "Map", - "currentPlayers": "Current players", - "players": "Players", - "maxPlayers": "Max players", - "bots": "Bots", - "ping": "Ping", - "status": "Status", - "online": "Online", - "offline": "Offline" - }, - "azuredevops": { - "canceled": "Canceled", - "inProgress": "In Progress", - "result": "Result", - "status": "Status", - "buildId": "Build ID", - "succeeded": "Succeeded", - "notStarted": "Not Started", - "failed": "Failed", - "totalPrs": "Total PRs", - "myPrs": "My PRs", - "approved": "Approved" - }, - "urbackup": { - "ok": "Ok", - "errored": "Errors", - "noRecent": "Out of Date", - "totalUsed": "Used Storage" - }, - "openmediavault": { - "downloading": "Downloading", - "total": "Total", - "running": "Running", - "stopped": "Stopped", - "passed": "Passed", - "failed": "Failed" - }, - "mealie": { - "recipes": "Recipes", - "users": "Users", - "categories": "Categories", - "tags": "Tags" - }, - "atsumeru": { - "series": "Series", - "archives": "Archives", - "chapters": "Chapters", - "categories": "Categories" - }, - "calibreweb": { - "books": "书籍", - "authors": "作者", - "categories": "分类", - "series": "丛书" - }, - "uptimerobot": { - "status": "Status", - "uptime": "Uptime", - "lastDown": "Last Downtime", - "downDuration": "Downtime Duration", - "sitesUp": "Sites Up", - "sitesDown": "Sites Down", - "paused": "Paused", - "notyetchecked": "Not Yet Checked", - "up": "Up", - "seemsdown": "Seems Down", - "down": "Down", - "unknown": "Unknown" - }, - "opendtu": { - "relativePower": "Power %", - "yieldDay": "Today", - "limit": "Limit", - "absolutePower": "Power" - }, - "calendar": { - "physicalRelease": "Physical release", - "inCinemas": "In cinemas", - "digitalRelease": "Digital release" - } -} diff --git a/src/pages/index.jsx b/src/pages/index.jsx index e66a19d9e..9109b4bd3 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -41,6 +41,17 @@ const Version = dynamic(() => import("components/version"), { const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "openmeteo", "search", "datetime"]; +// Normalize language codes so older config values like zh-CN still point to Crowdin-provided ones +const LANGUAGE_ALIASES = { + "zh-cn": "zh-Hans", +}; + +const normalizeLanguage = (language) => { + if (!language) return "en"; + const alias = LANGUAGE_ALIASES[language.toLowerCase()]; + return alias || language; +}; + export async function getStaticProps() { let logger; try { @@ -50,6 +61,7 @@ export async function getStaticProps() { const services = await servicesResponse(); const bookmarks = await bookmarksResponse(); const widgets = await widgetsResponse(); + const language = normalizeLanguage(settings.language); return { props: { @@ -60,7 +72,7 @@ export async function getStaticProps() { "/api/widgets": widgets, "/api/hash": false, }, - ...(await serverSideTranslations(settings.language ?? "en")), + ...(await serverSideTranslations(language)), }, }; } catch (e) { @@ -218,8 +230,9 @@ function Home({ initialSettings }) { ); useEffect(() => { - if (settings.language) { - i18n.changeLanguage(settings.language); + const language = normalizeLanguage(settings.language); + if (language) { + i18n.changeLanguage(language); } if (settings.theme && theme !== settings.theme) {