feat(web): integrate localized application catalogs

- compose app, UI, and independently imported block catalogs from JSON configuration\n- persist the selected locale on the server and activate it without hydration flicker\n- add a flag-based language switcher and localized navigation descriptors\n- mount the redesigned i18n devtool only in development\n- regenerate English and Simplified Chinese catalogs and add switcher coverage
This commit is contained in:
Maofeng
2026-07-30 14:48:25 +08:00
parent 6af4d7b798
commit 8cf3a1f03a
19 changed files with 2474 additions and 135 deletions
+336
View File
@@ -0,0 +1,336 @@
import type { MessageDescriptor } from "@workspace/i18n"
export const navigationMessages = {
overview: /* i18n */ {
id: "app.navigation.overview",
message: "Overview",
},
"overview-dashboard": /* i18n */ {
id: "app.navigation.overview-dashboard",
message: "Business overview",
},
"overview-realtime": /* i18n */ {
id: "app.navigation.overview-realtime",
message: "Real-time monitoring",
},
"overview-tasks": /* i18n */ {
id: "app.navigation.overview-tasks",
message: "Tasks",
},
"catalog-and-inventory": /* i18n */ {
id: "app.navigation.catalog-and-inventory",
message: "Products and inventory",
},
"catalog-products": /* i18n */ {
id: "app.navigation.catalog-products",
message: "Products",
},
"catalog-products-list": /* i18n */ {
id: "app.navigation.catalog-products-list",
message: "Product list",
},
"catalog-products-drafts": /* i18n */ {
id: "app.navigation.catalog-products-drafts",
message: "Product drafts",
},
"catalog-products-bundles": /* i18n */ {
id: "app.navigation.catalog-products-bundles",
message: "Product bundles",
},
"catalog-products-attributes": /* i18n */ {
id: "app.navigation.catalog-products-attributes",
message: "Product attributes",
},
"catalog-product-specifications": /* i18n */ {
id: "app.navigation.catalog-product-specifications",
message: "Specification templates",
},
"catalog-product-brands": /* i18n */ {
id: "app.navigation.catalog-product-brands",
message: "Brands",
},
"catalog-categories": /* i18n */ {
id: "app.navigation.catalog-categories",
message: "Categories",
},
"catalog-category-tree": /* i18n */ {
id: "app.navigation.catalog-category-tree",
message: "Category tree",
},
"catalog-category-navigation": /* i18n */ {
id: "app.navigation.catalog-category-navigation",
message: "Navigation categories",
},
"inventory-center": /* i18n */ {
id: "app.navigation.inventory-center",
message: "Inventory",
},
"inventory-overview": /* i18n */ {
id: "app.navigation.inventory-overview",
message: "Inventory overview",
},
"inventory-inbound": /* i18n */ {
id: "app.navigation.inventory-inbound",
message: "Inbound orders",
},
"inventory-outbound": /* i18n */ {
id: "app.navigation.inventory-outbound",
message: "Outbound orders",
},
"inventory-transfers": /* i18n */ {
id: "app.navigation.inventory-transfers",
message: "Stock transfers",
},
"inventory-alerts": /* i18n */ {
id: "app.navigation.inventory-alerts",
message: "Inventory alerts",
},
"content-assets": /* i18n */ {
id: "app.navigation.content-assets",
message: "Content",
},
"content-articles": /* i18n */ {
id: "app.navigation.content-articles",
message: "Articles",
},
"content-media": /* i18n */ {
id: "app.navigation.content-media",
message: "Media",
},
"content-pages": /* i18n */ {
id: "app.navigation.content-pages",
message: "Custom pages",
},
"trade-and-fulfillment": /* i18n */ {
id: "app.navigation.trade-and-fulfillment",
message: "Orders and fulfillment",
},
"trade-orders": /* i18n */ {
id: "app.navigation.trade-orders",
message: "Orders",
},
"trade-orders-awaiting-payment": /* i18n */ {
id: "app.navigation.trade-orders-awaiting-payment",
message: "Awaiting payment",
},
"trade-orders-awaiting-shipment": /* i18n */ {
id: "app.navigation.trade-orders-awaiting-shipment",
message: "Awaiting shipment",
},
"trade-orders-shipped": /* i18n */ {
id: "app.navigation.trade-orders-shipped",
message: "In transit",
},
"trade-orders-completed": /* i18n */ {
id: "app.navigation.trade-orders-completed",
message: "Completed orders",
},
"trade-orders-canceled": /* i18n */ {
id: "app.navigation.trade-orders-canceled",
message: "Canceled orders",
},
"fulfillment-center": /* i18n */ {
id: "app.navigation.fulfillment-center",
message: "Fulfillment",
},
"fulfillment-deliveries": /* i18n */ {
id: "app.navigation.fulfillment-deliveries",
message: "Delivery tasks",
},
"fulfillment-pickups": /* i18n */ {
id: "app.navigation.fulfillment-pickups",
message: "Pickup verification",
},
"fulfillment-freight-rules": /* i18n */ {
id: "app.navigation.fulfillment-freight-rules",
message: "Shipping rules",
},
"after-sales-center": /* i18n */ {
id: "app.navigation.after-sales-center",
message: "After-sales",
},
"after-sales-returns": /* i18n */ {
id: "app.navigation.after-sales-returns",
message: "Return requests",
},
"after-sales-refunds": /* i18n */ {
id: "app.navigation.after-sales-refunds",
message: "Refund review",
},
"after-sales-disputes": /* i18n */ {
id: "app.navigation.after-sales-disputes",
message: "Transaction disputes",
},
"customers-and-marketing": /* i18n */ {
id: "app.navigation.customers-and-marketing",
message: "Customers and marketing",
},
"customer-center": /* i18n */ {
id: "app.navigation.customer-center",
message: "Customers",
},
"customer-profiles": /* i18n */ {
id: "app.navigation.customer-profiles",
message: "Customer profiles",
},
"customer-segments": /* i18n */ {
id: "app.navigation.customer-segments",
message: "Customer segments",
},
"customer-tiers": /* i18n */ {
id: "app.navigation.customer-tiers",
message: "Customer tiers",
},
"customer-risk-list": /* i18n */ {
id: "app.navigation.customer-risk-list",
message: "Risk list",
},
"marketing-campaigns": /* i18n */ {
id: "app.navigation.marketing-campaigns",
message: "Marketing campaigns",
},
"marketing-coupons": /* i18n */ {
id: "app.navigation.marketing-coupons",
message: "Coupons",
},
"marketing-flash-sales": /* i18n */ {
id: "app.navigation.marketing-flash-sales",
message: "Flash sales",
},
"marketing-gift-promotions": /* i18n */ {
id: "app.navigation.marketing-gift-promotions",
message: "Gift promotions",
},
"marketing-referrals": /* i18n */ {
id: "app.navigation.marketing-referrals",
message: "Referral rewards",
},
"loyalty-center": /* i18n */ {
id: "app.navigation.loyalty-center",
message: "Membership benefits",
},
"loyalty-points": /* i18n */ {
id: "app.navigation.loyalty-points",
message: "Points rules",
},
"loyalty-stored-value": /* i18n */ {
id: "app.navigation.loyalty-stored-value",
message: "Stored-value accounts",
},
"loyalty-benefits": /* i18n */ {
id: "app.navigation.loyalty-benefits",
message: "Benefits configuration",
},
"data-and-finance": /* i18n */ {
id: "app.navigation.data-and-finance",
message: "Data and finance",
},
"report-center": /* i18n */ {
id: "app.navigation.report-center",
message: "Reports",
},
"report-sales": /* i18n */ {
id: "app.navigation.report-sales",
message: "Sales analysis",
},
"report-products": /* i18n */ {
id: "app.navigation.report-products",
message: "Product analysis",
},
"report-customers": /* i18n */ {
id: "app.navigation.report-customers",
message: "Customer analysis",
},
"report-channels": /* i18n */ {
id: "app.navigation.report-channels",
message: "Channel analysis",
},
"finance-center": /* i18n */ {
id: "app.navigation.finance-center",
message: "Finance",
},
"finance-settlements": /* i18n */ {
id: "app.navigation.finance-settlements",
message: "Settlement statements",
},
"finance-reconciliation": /* i18n */ {
id: "app.navigation.finance-reconciliation",
message: "Reconciliation",
},
"finance-invoices": /* i18n */ {
id: "app.navigation.finance-invoices",
message: "Invoices",
},
"finance-payouts": /* i18n */ {
id: "app.navigation.finance-payouts",
message: "Payout history",
},
"system-management": /* i18n */ {
id: "app.navigation.system-management",
message: "System management",
},
"system-members": /* i18n */ {
id: "app.navigation.system-members",
message: "Organization members",
},
"system-members-admins": /* i18n */ {
id: "app.navigation.system-members-admins",
message: "Administrator accounts",
},
"system-members-roles": /* i18n */ {
id: "app.navigation.system-members-roles",
message: "Roles",
},
"system-members-permissions": /* i18n */ {
id: "app.navigation.system-members-permissions",
message: "Permission policies",
},
"system-notifications": /* i18n */ {
id: "app.navigation.system-notifications",
message: "Notifications",
},
"system-notification-templates": /* i18n */ {
id: "app.navigation.system-notification-templates",
message: "Notification templates",
},
"system-notification-logs": /* i18n */ {
id: "app.navigation.system-notification-logs",
message: "Delivery logs",
},
"system-audit": /* i18n */ {
id: "app.navigation.system-audit",
message: "Audit log",
},
"system-integrations": /* i18n */ {
id: "app.navigation.system-integrations",
message: "Integrations",
},
"system-integration-api-keys": /* i18n */ {
id: "app.navigation.system-integration-api-keys",
message: "API keys",
},
"system-integration-webhooks": /* i18n */ {
id: "app.navigation.system-integration-webhooks",
message: "Webhook configuration",
},
"system-settings": /* i18n */ {
id: "app.navigation.system-settings",
message: "System settings",
},
"system-settings-store": /* i18n */ {
id: "app.navigation.system-settings-store",
message: "Store information",
},
"system-settings-payments": /* i18n */ {
id: "app.navigation.system-settings-payments",
message: "Payment channels",
},
"system-settings-shipping": /* i18n */ {
id: "app.navigation.system-settings-shipping",
message: "Shipping settings",
},
"system-recycle-bin": /* i18n */ {
id: "app.navigation.system-recycle-bin",
message: "Recycle bin",
},
} as const satisfies Record<string, MessageDescriptor>
+85 -83
View File
@@ -60,73 +60,75 @@ import {
import type { NavigationGroup } from "@workspace/blocks/navigation"
import { navigationMessages } from "./navigation-messages"
export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "overview",
label: "概览",
label: navigationMessages["overview"],
items: [
{
id: "overview-dashboard",
to: "/",
label: "经营总览",
label: navigationMessages["overview-dashboard"],
icon: Analytics01Icon,
},
{
id: "overview-realtime",
to: "/analytics/realtime",
label: "实时监控",
label: navigationMessages["overview-realtime"],
icon: AnalyticsUpIcon,
},
{
id: "overview-tasks",
to: "/workspace/tasks",
label: "待办中心",
label: navigationMessages["overview-tasks"],
icon: Task01Icon,
},
],
},
{
id: "catalog-and-inventory",
label: "商品与库存",
label: navigationMessages["catalog-and-inventory"],
items: [
{
id: "catalog-products",
label: "商品中心",
label: navigationMessages["catalog-products"],
icon: ShoppingBag01Icon,
items: [
{
id: "catalog-products-list",
to: "/catalog/products/list",
label: "商品列表",
label: navigationMessages["catalog-products-list"],
icon: ShoppingBag01Icon,
},
{
id: "catalog-products-drafts",
to: "/catalog/products/drafts",
label: "商品草稿",
label: navigationMessages["catalog-products-drafts"],
icon: File01Icon,
},
{
id: "catalog-products-bundles",
to: "/catalog/products/bundles",
label: "组合商品",
label: navigationMessages["catalog-products-bundles"],
icon: Package02Icon,
},
{
id: "catalog-products-attributes",
label: "商品属性",
label: navigationMessages["catalog-products-attributes"],
icon: Settings03Icon,
items: [
{
id: "catalog-product-specifications",
to: "/catalog/products/attributes/specifications",
label: "规格模板",
label: navigationMessages["catalog-product-specifications"],
icon: ClipboardListIcon,
},
{
id: "catalog-product-brands",
to: "/catalog/products/attributes/brands",
label: "品牌资料",
label: navigationMessages["catalog-product-brands"],
icon: StarIcon,
},
],
@@ -136,19 +138,19 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "catalog-categories",
to: "/catalog/categories",
label: "分类目录",
label: navigationMessages["catalog-categories"],
icon: ClipboardListIcon,
items: [
{
id: "catalog-category-tree",
to: "/catalog/categories/tree",
label: "分类树",
label: navigationMessages["catalog-category-tree"],
icon: Structure01Icon,
},
{
id: "catalog-category-navigation",
to: "/catalog/categories/navigation",
label: "导航分类",
label: navigationMessages["catalog-category-navigation"],
icon: Compass01Icon,
},
],
@@ -156,37 +158,37 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "inventory-center",
to: "/inventory",
label: "库存中心",
label: navigationMessages["inventory-center"],
icon: PackageIcon,
items: [
{
id: "inventory-overview",
to: "/inventory/overview",
label: "库存总览",
label: navigationMessages["inventory-overview"],
icon: Chart01Icon,
},
{
id: "inventory-inbound",
to: "/inventory/inbound",
label: "入库单",
label: navigationMessages["inventory-inbound"],
icon: InboxDownloadIcon,
},
{
id: "inventory-outbound",
to: "/inventory/outbound",
label: "出库单",
label: navigationMessages["inventory-outbound"],
icon: InboxUploadIcon,
},
{
id: "inventory-transfers",
to: "/inventory/transfers",
label: "调拨单",
label: navigationMessages["inventory-transfers"],
icon: ArrowDataTransferHorizontalIcon,
},
{
id: "inventory-alerts",
to: "/inventory/alerts",
label: "库存预警",
label: navigationMessages["inventory-alerts"],
icon: Alert02Icon,
},
],
@@ -194,25 +196,25 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "content-assets",
to: "/content",
label: "内容素材",
label: navigationMessages["content-assets"],
icon: File01Icon,
items: [
{
id: "content-articles",
to: "/content/articles",
label: "内容文章",
label: navigationMessages["content-articles"],
icon: File01Icon,
},
{
id: "content-media",
to: "/content/media",
label: "媒体资源",
label: navigationMessages["content-media"],
icon: GalleryHorizontalIcon,
},
{
id: "content-pages",
to: "/content/pages",
label: "自定义页面",
label: navigationMessages["content-pages"],
icon: AppWindowIcon,
},
],
@@ -221,42 +223,42 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
},
{
id: "trade-and-fulfillment",
label: "交易与履约",
label: navigationMessages["trade-and-fulfillment"],
items: [
{
id: "trade-orders",
to: "/trade/orders",
label: "订单中心",
label: navigationMessages["trade-orders"],
icon: ShoppingCart01Icon,
items: [
{
id: "trade-orders-awaiting-payment",
to: "/trade/orders/awaiting-payment",
label: "待付款订单",
label: navigationMessages["trade-orders-awaiting-payment"],
icon: WalletCardsIcon,
},
{
id: "trade-orders-awaiting-shipment",
to: "/trade/orders/awaiting-shipment",
label: "待发货订单",
label: navigationMessages["trade-orders-awaiting-shipment"],
icon: PackageIcon,
},
{
id: "trade-orders-shipped",
to: "/trade/orders/shipped",
label: "配送中订单",
label: navigationMessages["trade-orders-shipped"],
icon: DeliveryTruck01Icon,
},
{
id: "trade-orders-completed",
to: "/trade/orders/completed",
label: "已完成订单",
label: navigationMessages["trade-orders-completed"],
icon: CheckmarkCircle01Icon,
},
{
id: "trade-orders-canceled",
to: "/trade/orders/canceled",
label: "已取消订单",
label: navigationMessages["trade-orders-canceled"],
icon: CancelCircleIcon,
},
],
@@ -264,25 +266,25 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "fulfillment-center",
to: "/fulfillment",
label: "配送履约",
label: navigationMessages["fulfillment-center"],
icon: DeliveryTruck01Icon,
items: [
{
id: "fulfillment-deliveries",
to: "/fulfillment/deliveries",
label: "配送任务",
label: navigationMessages["fulfillment-deliveries"],
icon: Location01Icon,
},
{
id: "fulfillment-pickups",
to: "/fulfillment/pickups",
label: "自提核销",
label: navigationMessages["fulfillment-pickups"],
icon: Store01Icon,
},
{
id: "fulfillment-freight-rules",
to: "/fulfillment/freight-rules",
label: "运费规则",
label: navigationMessages["fulfillment-freight-rules"],
icon: RoadLocation01Icon,
},
],
@@ -290,25 +292,25 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "after-sales-center",
to: "/after-sales",
label: "售后中心",
label: navigationMessages["after-sales-center"],
icon: CallMissed01Icon,
items: [
{
id: "after-sales-returns",
to: "/after-sales/returns",
label: "退货申请",
label: navigationMessages["after-sales-returns"],
icon: Refresh01Icon,
},
{
id: "after-sales-refunds",
to: "/after-sales/refunds",
label: "退款审核",
label: navigationMessages["after-sales-refunds"],
icon: MoneySendSquareIcon,
},
{
id: "after-sales-disputes",
to: "/after-sales/disputes",
label: "交易纠纷",
label: navigationMessages["after-sales-disputes"],
icon: SecurityWarningIcon,
},
],
@@ -317,36 +319,36 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
},
{
id: "customers-and-marketing",
label: "客户与营销",
label: navigationMessages["customers-and-marketing"],
items: [
{
id: "customer-center",
to: "/customers",
label: "客户中心",
label: navigationMessages["customer-center"],
icon: IdentityCardIcon,
items: [
{
id: "customer-profiles",
to: "/customers/profiles",
label: "客户档案",
label: navigationMessages["customer-profiles"],
icon: IdentityCardIcon,
},
{
id: "customer-segments",
to: "/customers/segments",
label: "客户分群",
label: navigationMessages["customer-segments"],
icon: UserGroupIcon,
},
{
id: "customer-tiers",
to: "/customers/tiers",
label: "客户等级",
label: navigationMessages["customer-tiers"],
icon: CrownIcon,
},
{
id: "customer-risk-list",
to: "/customers/risk-list",
label: "风险名单",
label: navigationMessages["customer-risk-list"],
icon: SecurityWarningIcon,
},
],
@@ -354,31 +356,31 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "marketing-campaigns",
to: "/marketing/campaigns",
label: "营销活动",
label: navigationMessages["marketing-campaigns"],
icon: Discount01Icon,
items: [
{
id: "marketing-coupons",
to: "/marketing/coupons",
label: "优惠券管理",
label: navigationMessages["marketing-coupons"],
icon: Ticket01Icon,
},
{
id: "marketing-flash-sales",
to: "/marketing/flash-sales",
label: "限时折扣",
label: navigationMessages["marketing-flash-sales"],
icon: Clock01Icon,
},
{
id: "marketing-gift-promotions",
to: "/marketing/gift-promotions",
label: "满赠活动",
label: navigationMessages["marketing-gift-promotions"],
icon: GiftIcon,
},
{
id: "marketing-referrals",
to: "/marketing/referrals",
label: "邀请有礼",
label: navigationMessages["marketing-referrals"],
icon: Share01Icon,
},
],
@@ -386,25 +388,25 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "loyalty-center",
to: "/loyalty",
label: "会员权益",
label: navigationMessages["loyalty-center"],
icon: Medal01Icon,
items: [
{
id: "loyalty-points",
to: "/loyalty/points",
label: "积分规则",
label: navigationMessages["loyalty-points"],
icon: StarCircleIcon,
},
{
id: "loyalty-stored-value",
to: "/loyalty/stored-value",
label: "储值账户",
label: navigationMessages["loyalty-stored-value"],
icon: Wallet01Icon,
},
{
id: "loyalty-benefits",
to: "/loyalty/benefits",
label: "权益配置",
label: navigationMessages["loyalty-benefits"],
icon: CheckmarkBadge01Icon,
},
],
@@ -413,36 +415,36 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
},
{
id: "data-and-finance",
label: "数据与财务",
label: navigationMessages["data-and-finance"],
items: [
{
id: "report-center",
to: "/reports",
label: "数据报表",
label: navigationMessages["report-center"],
icon: Chart01Icon,
items: [
{
id: "report-sales",
to: "/reports/sales",
label: "销售分析",
label: navigationMessages["report-sales"],
icon: AnalyticsUpIcon,
},
{
id: "report-products",
to: "/reports/products",
label: "商品分析",
label: navigationMessages["report-products"],
icon: ShoppingBag01Icon,
},
{
id: "report-customers",
to: "/reports/customers",
label: "客群分析",
label: navigationMessages["report-customers"],
icon: UserGroupIcon,
},
{
id: "report-channels",
to: "/reports/channels",
label: "渠道分析",
label: navigationMessages["report-channels"],
icon: ChartIncreaseIcon,
},
],
@@ -450,31 +452,31 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "finance-center",
to: "/finance",
label: "财务中心",
label: navigationMessages["finance-center"],
icon: WalletCardsIcon,
items: [
{
id: "finance-settlements",
to: "/finance/settlements",
label: "结算账单",
label: navigationMessages["finance-settlements"],
icon: Invoice03Icon,
},
{
id: "finance-reconciliation",
to: "/finance/reconciliation",
label: "对账管理",
label: navigationMessages["finance-reconciliation"],
icon: Calculator01Icon,
},
{
id: "finance-invoices",
to: "/finance/invoices",
label: "发票管理",
label: navigationMessages["finance-invoices"],
icon: File01Icon,
},
{
id: "finance-payouts",
to: "/finance/payouts",
label: "打款记录",
label: navigationMessages["finance-payouts"],
icon: MoneySendSquareIcon,
},
],
@@ -483,30 +485,30 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
},
{
id: "system-management",
label: "系统管理",
label: navigationMessages["system-management"],
items: [
{
id: "system-members",
to: "/system/members",
label: "组织成员",
label: navigationMessages["system-members"],
icon: UserShield01Icon,
items: [
{
id: "system-members-admins",
to: "/system/members/admins",
label: "管理员账号",
label: navigationMessages["system-members-admins"],
icon: UserShield01Icon,
},
{
id: "system-members-roles",
to: "/system/members/roles",
label: "角色管理",
label: navigationMessages["system-members-roles"],
icon: UserGroupIcon,
},
{
id: "system-members-permissions",
to: "/system/members/permissions",
label: "权限策略",
label: navigationMessages["system-members-permissions"],
icon: LockKeyIcon,
},
],
@@ -514,19 +516,19 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "system-notifications",
to: "/system/notifications",
label: "消息中心",
label: navigationMessages["system-notifications"],
icon: BubbleChatIcon,
items: [
{
id: "system-notification-templates",
to: "/system/notifications/templates",
label: "通知模板",
label: navigationMessages["system-notification-templates"],
icon: File01Icon,
},
{
id: "system-notification-logs",
to: "/system/notifications/logs",
label: "发送记录",
label: navigationMessages["system-notification-logs"],
icon: HistoryIcon,
},
],
@@ -534,25 +536,25 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "system-audit",
to: "/system/audit",
label: "操作审计",
label: navigationMessages["system-audit"],
icon: Note01Icon,
},
{
id: "system-integrations",
to: "/system/integrations",
label: "开放集成",
label: navigationMessages["system-integrations"],
icon: CodeSquareIcon,
items: [
{
id: "system-integration-api-keys",
to: "/system/integrations/api-keys",
label: "API 密钥",
label: navigationMessages["system-integration-api-keys"],
icon: Key01Icon,
},
{
id: "system-integration-webhooks",
to: "/system/integrations/webhooks",
label: "Webhook 配置",
label: navigationMessages["system-integration-webhooks"],
icon: LinkCircleIcon,
},
],
@@ -560,25 +562,25 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "system-settings",
to: "/system-configs",
label: "系统配置",
label: navigationMessages["system-settings"],
icon: Settings01Icon,
items: [
{
id: "system-settings-store",
to: "/system-configs/store",
label: "门店资料",
label: navigationMessages["system-settings-store"],
icon: Store01Icon,
},
{
id: "system-settings-payments",
to: "/system-configs/payments",
label: "支付渠道",
label: navigationMessages["system-settings-payments"],
icon: CreditCardIcon,
},
{
id: "system-settings-shipping",
to: "/system-configs/shipping",
label: "配送设置",
label: navigationMessages["system-settings-shipping"],
icon: DeliveryTruck01Icon,
},
],
@@ -586,7 +588,7 @@ export const primaryNavigationGroups: readonly NavigationGroup[] = [
{
id: "system-recycle-bin",
to: "/system/recycle-bin",
label: "回收站",
label: navigationMessages["system-recycle-bin"],
icon: Delete02Icon,
},
],
+21
View File
@@ -0,0 +1,21 @@
import { lazy, Suspense } from "react"
const LazyI18nDevtool = import.meta.env.DEV
? lazy(() =>
import("@workspace/i18n/devtool").then((module) => ({
default: module.I18nDevtool,
}))
)
: null
export function AppI18nDevtool() {
if (!LazyI18nDevtool) {
return null
}
return (
<Suspense fallback={null}>
<LazyI18nDevtool dark={"ui\\:dark"} />
</Suspense>
)
}
+91 -37
View File
@@ -1,51 +1,105 @@
import { lazy, Suspense, type PropsWithChildren } from "react"
import { I18nProvider, type LocaleDefinition } from "@workspace/i18n"
import {
createContext,
startTransition,
use,
useCallback,
useContext,
useEffect,
useMemo,
useState,
type PropsWithChildren,
} from "react"
import {
I18nProvider,
useLocaleDefinition,
useTranslate,
} from "@workspace/i18n"
import { loadMessageCatalog } from "@workspace/i18n/catalogs"
import {
I18nProvider as UiI18nProvider,
type CalendarLocale,
} from "@workspace/ui/components/i18n"
import { calendarLocale as englishCalendarLocale } from "@workspace/ui/locales/en"
import { calendarLocale as simplifiedChineseCalendarLocale } from "@workspace/ui/locales/zh-Hans"
import { messages as englishMessages } from "@/locales/en/messages"
import { messages as simplifiedChineseMessages } from "@/locales/zh-Hans/messages"
import { appLocales, DEFAULT_APP_LOCALE, type AppLocale } from "./app-locales"
import { AppI18nDevtool } from "./app-i18n-devtool"
import { setAppLocale as persistAppLocale } from "@/server/app-locale.functions"
const I18nDevtool = import.meta.env.DEV
? lazy(() =>
import("@workspace/i18n/devtool").then((module) => ({
default: module.I18nDevtool,
}))
)
: null
export const appLocales = [
{
label: "English",
locale: "en",
},
{
label: "简体中文",
locale: "zh-Hans",
},
] as const satisfies readonly LocaleDefinition[]
export type AppLocale = (typeof appLocales)[number]["locale"]
const appCatalogs = {
en: englishMessages,
"zh-Hans": simplifiedChineseMessages,
const appCalendarLocales: Partial<Record<AppLocale, CalendarLocale>> = {
en: englishCalendarLocale,
"zh-Hans": simplifiedChineseCalendarLocale,
}
export interface AppI18nProviderProps extends PropsWithChildren {
locale?: AppLocale
}
interface AppLocaleContextValue {
locale: AppLocale
setLocale: (locale: AppLocale) => void
}
const AppLocaleContext = createContext<AppLocaleContextValue | null>(null)
export function AppI18nProvider({
children,
locale = "zh-Hans",
locale: initialLocale = DEFAULT_APP_LOCALE,
}: AppI18nProviderProps) {
const [locale, setLocaleState] = useState(initialLocale)
const messages = use(loadMessageCatalog(locale))
const catalogs = useMemo(() => ({ [locale]: messages }), [locale, messages])
const setLocale = useCallback((nextLocale: AppLocale) => {
startTransition(() => {
setLocaleState(nextLocale)
})
void persistAppLocale({ data: nextLocale })
}, [])
const localeContext = useMemo(
() => ({ locale, setLocale }),
[locale, setLocale]
)
useEffect(() => {
const definition = appLocales.find(
(candidate) => candidate.locale === locale
)
document.documentElement.lang = definition?.languageTag ?? locale
document.documentElement.dir = definition?.direction ?? "ltr"
}, [locale])
return (
<I18nProvider catalogs={appCatalogs} locale={locale} locales={appLocales}>
{children}
{I18nDevtool && (
<Suspense fallback={null}>
<I18nDevtool dark={"ui\\:dark"} />
</Suspense>
)}
</I18nProvider>
<AppLocaleContext.Provider value={localeContext}>
<I18nProvider catalogs={catalogs} locale={locale} locales={appLocales}>
<AppUiI18nProvider>{children}</AppUiI18nProvider>
<AppI18nDevtool />
</I18nProvider>
</AppLocaleContext.Provider>
)
}
export function useAppLocale() {
const context = useContext(AppLocaleContext)
if (!context) {
throw new Error("useAppLocale must be used within AppI18nProvider")
}
return context
}
function AppUiI18nProvider({ children }: PropsWithChildren) {
const locale = useLocaleDefinition()
const translate = useTranslate()
return (
<UiI18nProvider
calendarLocale={appCalendarLocales[locale.locale as AppLocale]}
locale={locale.languageTag ?? locale.locale}
t={translate}
>
{children}
</UiI18nProvider>
)
}
@@ -0,0 +1,45 @@
// @vitest-environment jsdom
import { cleanup, fireEvent, render, screen } from "@testing-library/react"
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"
import { AppLanguageSwitcher } from "./app-language-switcher"
vi.mock("./app-i18n-provider", () => ({
useAppLocale: () => ({
locale: "en",
setLocale: vi.fn(),
}),
}))
vi.mock("country-flag-icons/react/1x1", () => ({
CN: () => <svg />,
US: () => <svg />,
}))
beforeAll(() => {
vi.stubGlobal(
"ResizeObserver",
class {
disconnect() {}
observe() {}
unobserve() {}
}
)
})
afterEach(cleanup)
describe("AppLanguageSwitcher", () => {
it("opens its grouped locale choices", async () => {
render(<AppLanguageSwitcher />)
fireEvent.click(
screen.getByRole("button", {
name: "Change language, currently English",
})
)
expect(await screen.findByText("简体中文")).not.toBeNull()
})
})
@@ -0,0 +1,94 @@
import { CN, US } from "country-flag-icons/react/1x1"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@workspace/ui/components/dropdown-menu"
import { cn } from "@workspace/ui/lib/utils"
import { HeaderActionButton } from "@workspace/blocks/layout"
import { appLocales, isAppLocale, type AppLocaleCountry } from "./app-locales"
import { useAppLocale } from "./app-i18n-provider"
const localeFlags = {
CN,
US,
} satisfies Record<AppLocaleCountry, typeof CN>
function LocaleFlag({
country,
className,
}: {
className?: string
country: AppLocaleCountry
}) {
const Flag = localeFlags[country]
return (
<span
aria-hidden="true"
className={cn(
"inline-flex shrink-0 overflow-hidden rounded-full ring-1 ring-foreground/15",
className
)}
>
<Flag className="size-full" />
</span>
)
}
export function AppLanguageSwitcher() {
const { locale, setLocale } = useAppLocale()
const activeLocale =
appLocales.find((definition) => definition.locale === locale) ??
appLocales[0]
const menuLabel = locale === "zh-Hans" ? "语言" : "Language"
const triggerLabel =
locale === "zh-Hans"
? `切换语言,当前为${activeLocale.label}`
: `Change language, currently ${activeLocale.label}`
return (
<DropdownMenu>
<DropdownMenuTrigger
render={
<HeaderActionButton
aria-label={triggerLabel}
className="rounded-full"
/>
}
>
<LocaleFlag country={activeLocale.country} className="size-6" />
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="w-44"
showArrow={{ cornerRadius: "lg", tailSize: "sm" }}
>
<DropdownMenuRadioGroup
value={locale}
onValueChange={(value) => {
if (isAppLocale(value)) {
setLocale(value)
}
}}
>
<DropdownMenuLabel>{menuLabel}</DropdownMenuLabel>
{appLocales.map((definition) => (
<DropdownMenuRadioItem
key={definition.locale}
className="py-2"
value={definition.locale}
>
<LocaleFlag country={definition.country} className="size-5" />
<span lang={definition.languageTag}>{definition.label}</span>
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
+32
View File
@@ -0,0 +1,32 @@
import type { LocaleDefinition } from "@workspace/i18n"
export type AppLocale = "en" | "zh-Hans"
export type AppLocaleCountry = "CN" | "US"
export interface AppLocaleDefinition extends LocaleDefinition {
country: AppLocaleCountry
locale: AppLocale
}
export const DEFAULT_APP_LOCALE: AppLocale = "zh-Hans"
export const appLocales = [
{
country: "US",
direction: "ltr",
languageTag: "en-US",
label: "English",
locale: "en",
},
{
country: "CN",
direction: "ltr",
languageTag: "zh-CN",
label: "简体中文",
locale: "zh-Hans",
},
] as const satisfies readonly AppLocaleDefinition[]
export function isAppLocale(value: unknown): value is AppLocale {
return appLocales.some((definition) => definition.locale === value)
}
+840
View File
@@ -12,3 +12,843 @@ msgstr ""
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:4
msgid "blocks.userMenu.accountPassword"
msgstr "Account password"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:4
msgid "blocks.appearance.active"
msgstr "Active"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:276
msgid "app.navigation.system-members-admins"
msgstr "Administrator accounts"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:148
msgid "app.navigation.after-sales-center"
msgstr "After-sales"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:91
msgid "blocks.appearance.color.amber"
msgstr "Amber"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:308
msgid "app.navigation.system-integration-api-keys"
msgstr "API keys"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:8
msgid "blocks.userMenu.appearance"
msgstr "Appearance"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:8
msgid "blocks.appearance.title"
msgstr "Appearance"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:92
msgid "app.navigation.content-articles"
msgstr "Articles"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:300
msgid "app.navigation.system-audit"
msgstr "Audit log"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:112
msgid "app.navigation.trade-orders-awaiting-payment"
msgstr "Awaiting payment"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:116
msgid "app.navigation.trade-orders-awaiting-shipment"
msgstr "Awaiting shipment"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:16
msgid "blocks.appearance.baseColor"
msgstr "Base color"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:220
msgid "app.navigation.loyalty-benefits"
msgstr "Benefits configuration"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:95
msgid "blocks.appearance.color.blue"
msgstr "Blue"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:48
msgid "app.navigation.catalog-product-brands"
msgstr "Brands"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:25
msgid "ui.breadcrumb.label"
msgstr "Breadcrumb"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:8
msgid "app.navigation.overview-dashboard"
msgstr "Business overview"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:128
msgid "app.navigation.trade-orders-canceled"
msgstr "Canceled orders"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:52
msgid "app.navigation.catalog-categories"
msgstr "Categories"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:56
msgid "app.navigation.catalog-category-tree"
msgstr "Category tree"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:244
msgid "app.navigation.report-channels"
msgstr "Channel analysis"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/chats/messages.ts:4
msgid "blocks.chats.title"
msgstr "Chats"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:16
msgid "blocks.notifications.error.description"
msgstr "Check your network connection and try again."
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:29
msgid "ui.common.close"
msgstr "Close"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:33
msgid "ui.toast.close"
msgstr "Close notification"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:24
msgid "blocks.appearance.compact.title"
msgstr "Compact layout"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:124
msgid "app.navigation.trade-orders-completed"
msgstr "Completed orders"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:88
msgid "app.navigation.content-assets"
msgstr "Content"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:192
msgid "app.navigation.marketing-coupons"
msgstr "Coupons"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:100
msgid "app.navigation.content-pages"
msgstr "Custom pages"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:240
msgid "app.navigation.report-customers"
msgstr "Customer analysis"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:172
msgid "app.navigation.customer-profiles"
msgstr "Customer profiles"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:176
msgid "app.navigation.customer-segments"
msgstr "Customer segments"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:180
msgid "app.navigation.customer-tiers"
msgstr "Customer tiers"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:168
msgid "app.navigation.customer-center"
msgstr "Customers"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:164
msgid "app.navigation.customers-and-marketing"
msgstr "Customers and marketing"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:99
msgid "blocks.appearance.color.cyan"
msgstr "Cyan"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:28
msgid "blocks.appearance.mode.dark"
msgstr "Dark"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:36
msgid "blocks.appearance.theme.dark"
msgstr "Dark theme"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:224
msgid "app.navigation.data-and-finance"
msgstr "Data and finance"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:296
msgid "app.navigation.system-notification-logs"
msgstr "Delivery logs"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:136
msgid "app.navigation.fulfillment-deliveries"
msgstr "Delivery tasks"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:81
msgid "ui.sidebar.description"
msgstr "Displays the mobile sidebar."
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:103
msgid "blocks.appearance.color.emerald"
msgstr "Emerald"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:248
msgid "app.navigation.finance-center"
msgstr "Finance"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:196
msgid "app.navigation.marketing-flash-sales"
msgstr "Flash sales"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:107
msgid "blocks.appearance.color.fuchsia"
msgstr "Fuchsia"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:132
msgid "app.navigation.fulfillment-center"
msgstr "Fulfillment"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:200
msgid "app.navigation.marketing-gift-promotions"
msgstr "Gift promotions"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:53
msgid "ui.pagination.nextPage"
msgstr "Go to next page"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:69
msgid "ui.pagination.previousPage"
msgstr "Go to previous page"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:111
msgid "blocks.appearance.color.green"
msgstr "Green"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:120
msgid "app.navigation.trade-orders-shipped"
msgstr "In transit"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:72
msgid "app.navigation.inventory-inbound"
msgstr "Inbound orders"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:115
msgid "blocks.appearance.color.indigo"
msgstr "Indigo"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:304
msgid "app.navigation.system-integrations"
msgstr "Integrations"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:64
msgid "app.navigation.inventory-center"
msgstr "Inventory"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:84
msgid "app.navigation.inventory-alerts"
msgstr "Inventory alerts"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:68
msgid "app.navigation.inventory-overview"
msgstr "Inventory overview"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:260
msgid "app.navigation.finance-invoices"
msgstr "Invoices"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:24
msgid "blocks.notifications.justNow"
msgstr "just now"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:16
msgid "blocks.userMenu.keybindings"
msgstr "Keybindings"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:52
msgid "blocks.appearance.mode.light"
msgstr "Light"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:60
msgid "blocks.appearance.theme.light"
msgstr "Light theme"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:119
msgid "blocks.appearance.color.lime"
msgstr "Lime"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:37
msgid "ui.common.loading"
msgstr "Loading"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:28
msgid "blocks.notifications.loading"
msgstr "Loading notifications…"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:20
msgid "blocks.userMenu.logout"
msgstr "Log out"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:32
msgid "blocks.notifications.markAllAsRead"
msgstr "Mark all as read"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:188
msgid "app.navigation.marketing-campaigns"
msgstr "Marketing campaigns"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:123
msgid "blocks.appearance.color.mauve"
msgstr "Mauve"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:96
msgid "app.navigation.content-media"
msgstr "Media"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:208
msgid "app.navigation.loyalty-center"
msgstr "Membership benefits"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:127
msgid "blocks.appearance.color.mist"
msgstr "Mist"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:41
msgid "ui.common.more"
msgstr "More"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:45
msgid "ui.pagination.more"
msgstr "More pages"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/navigation/messages.ts:4
msgid "blocks.navigation.description"
msgstr "Navigate through the app."
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/navigation/messages.ts:12
msgid "blocks.navigation.title"
msgstr "Navigation"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:60
msgid "app.navigation.catalog-category-navigation"
msgstr "Navigation categories"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:131
msgid "blocks.appearance.color.neutral"
msgstr "Neutral"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:8
msgid "blocks.notifications.empty.description"
msgstr "New activity will appear here."
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:49
msgid "ui.pagination.next"
msgstr "Next"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:57
msgid "ui.carousel.nextSlide"
msgstr "Next slide"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:12
msgid "blocks.notifications.empty.title"
msgstr "No notifications"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:292
msgid "app.navigation.system-notification-templates"
msgstr "Notification templates"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:40
msgid "blocks.notifications.title"
msgstr "Notifications"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:288
msgid "app.navigation.system-notifications"
msgstr "Notifications"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:135
msgid "blocks.appearance.color.olive"
msgstr "Olive"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:12
msgid "blocks.breadcrumb.menuLabel"
msgstr "Open breadcrumb menu"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/navigation/messages.ts:8
msgid "blocks.navigation.open"
msgstr "Open navigation"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:12
msgid "blocks.appearance.command.description"
msgstr "Open theme and layout preferences"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:24
msgid "blocks.userMenu.open"
msgstr "Open user menu"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:139
msgid "blocks.appearance.color.orange"
msgstr "Orange"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:108
msgid "app.navigation.trade-orders"
msgstr "Orders"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:104
msgid "app.navigation.trade-and-fulfillment"
msgstr "Orders and fulfillment"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:272
msgid "app.navigation.system-members"
msgstr "Organization members"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:76
msgid "app.navigation.inventory-outbound"
msgstr "Outbound orders"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:4
msgid "app.navigation.overview"
msgstr "Overview"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:61
msgid "ui.pagination.label"
msgstr "Pagination"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:324
msgid "app.navigation.system-settings-payments"
msgstr "Payment channels"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:264
msgid "app.navigation.finance-payouts"
msgstr "Payout history"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:284
msgid "app.navigation.system-members-permissions"
msgstr "Permission policies"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:140
msgid "app.navigation.fulfillment-pickups"
msgstr "Pickup verification"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:143
msgid "blocks.appearance.color.pink"
msgstr "Pink"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:212
msgid "app.navigation.loyalty-points"
msgstr "Points rules"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:65
msgid "ui.pagination.previous"
msgstr "Previous"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:73
msgid "ui.carousel.previousSlide"
msgstr "Previous slide"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:68
msgid "blocks.appearance.primaryColor"
msgstr "Primary color"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:236
msgid "app.navigation.report-products"
msgstr "Product analysis"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:40
msgid "app.navigation.catalog-products-attributes"
msgstr "Product attributes"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:36
msgid "app.navigation.catalog-products-bundles"
msgstr "Product bundles"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:32
msgid "app.navigation.catalog-products-drafts"
msgstr "Product drafts"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:28
msgid "app.navigation.catalog-products-list"
msgstr "Product list"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:24
msgid "app.navigation.catalog-products"
msgstr "Products"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:20
msgid "app.navigation.catalog-and-inventory"
msgstr "Products and inventory"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:147
msgid "blocks.appearance.color.purple"
msgstr "Purple"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:12
msgid "app.navigation.overview-realtime"
msgstr "Real-time monitoring"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:256
msgid "app.navigation.finance-reconciliation"
msgstr "Reconciliation"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:332
msgid "app.navigation.system-recycle-bin"
msgstr "Recycle bin"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:151
msgid "blocks.appearance.color.red"
msgstr "Red"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:204
msgid "app.navigation.marketing-referrals"
msgstr "Referral rewards"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:32
msgid "blocks.refresh.label"
msgstr "Refresh current page data"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:28
msgid "blocks.refresh.description"
msgstr "Refresh the current page data"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:156
msgid "app.navigation.after-sales-refunds"
msgstr "Refund review"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:228
msgid "app.navigation.report-center"
msgstr "Reports"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:152
msgid "app.navigation.after-sales-returns"
msgstr "Return requests"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:184
msgid "app.navigation.customer-risk-list"
msgstr "Risk list"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:280
msgid "app.navigation.system-members-roles"
msgstr "Roles"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:155
msgid "blocks.appearance.color.rose"
msgstr "Rose"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:232
msgid "app.navigation.report-sales"
msgstr "Sales analysis"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:252
msgid "app.navigation.finance-settlements"
msgstr "Settlement statements"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:144
msgid "app.navigation.fulfillment-freight-rules"
msgstr "Shipping rules"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:328
msgid "app.navigation.system-settings-shipping"
msgstr "Shipping settings"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:77
msgid "ui.sidebar.title"
msgstr "Sidebar"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:159
msgid "blocks.appearance.color.sky"
msgstr "Sky"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:44
msgid "app.navigation.catalog-product-specifications"
msgstr "Specification templates"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:80
msgid "app.navigation.inventory-transfers"
msgstr "Stock transfers"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:163
msgid "blocks.appearance.color.stone"
msgstr "Stone"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:320
msgid "app.navigation.system-settings-store"
msgstr "Store information"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:216
msgid "app.navigation.loyalty-stored-value"
msgstr "Stored-value accounts"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:84
msgid "blocks.appearance.toggleTheme.description"
msgstr "Switch between light and dark themes"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:44
msgid "blocks.appearance.mode.system"
msgstr "System"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:268
msgid "app.navigation.system-management"
msgstr "System management"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:316
msgid "app.navigation.system-settings"
msgstr "System settings"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:16
msgid "app.navigation.overview-tasks"
msgstr "Tasks"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:167
msgid "blocks.appearance.color.taupe"
msgstr "Taupe"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:171
msgid "blocks.appearance.color.teal"
msgstr "Teal"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:48
msgid "blocks.appearance.mode.system.description"
msgstr "The interface theme will follow the system appearance"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:32
msgid "blocks.appearance.mode.dark.description"
msgstr "The interface will always use the dark theme"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:56
msgid "blocks.appearance.mode.light.description"
msgstr "The interface will always use the light theme"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:72
msgid "blocks.appearance.description"
msgstr "Theme and layout preferences"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:76
msgid "blocks.appearance.mode.title"
msgstr "Theme mode"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:40
msgid "blocks.appearance.theme.dark.description"
msgstr "This theme is used when the system is in dark mode"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:64
msgid "blocks.appearance.theme.light.description"
msgstr "This theme is used when the system is in light mode"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:85
msgid "ui.sidebar.toggle"
msgstr "Toggle sidebar"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:80
msgid "blocks.appearance.toggleTheme"
msgstr "Toggle theme"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:160
msgid "app.navigation.after-sales-disputes"
msgstr "Transaction disputes"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:36
msgid "blocks.notifications.retry"
msgstr "Try again"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:20
msgid "blocks.notifications.error.title"
msgstr "Unable to load notifications"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:20
msgid "blocks.appearance.compact.description"
msgstr "Use a compact width for the main page content"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:36
msgid "blocks.userMenu.title"
msgstr "User menu"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:44
msgid "blocks.notifications.viewAll"
msgstr "View all"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:4
msgid "blocks.notifications.description"
msgstr "View and manage notifications"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:175
msgid "blocks.appearance.color.violet"
msgstr "Violet"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:312
msgid "app.navigation.system-integration-webhooks"
msgstr "Webhook configuration"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:179
msgid "blocks.appearance.color.yellow"
msgstr "Yellow"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:183
msgid "blocks.appearance.color.zinc"
msgstr "Zinc"
File diff suppressed because one or more lines are too long
+840
View File
@@ -12,3 +12,843 @@ msgstr ""
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:4
msgid "blocks.userMenu.accountPassword"
msgstr "账号密码"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:4
msgid "blocks.appearance.active"
msgstr "使用中"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:276
msgid "app.navigation.system-members-admins"
msgstr "管理员账号"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:148
msgid "app.navigation.after-sales-center"
msgstr "售后中心"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:91
msgid "blocks.appearance.color.amber"
msgstr "琥珀色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:308
msgid "app.navigation.system-integration-api-keys"
msgstr "API 密钥"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:8
msgid "blocks.userMenu.appearance"
msgstr "界面外观"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:8
msgid "blocks.appearance.title"
msgstr "界面外观"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:92
msgid "app.navigation.content-articles"
msgstr "内容文章"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:300
msgid "app.navigation.system-audit"
msgstr "操作审计"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:112
msgid "app.navigation.trade-orders-awaiting-payment"
msgstr "待付款订单"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:116
msgid "app.navigation.trade-orders-awaiting-shipment"
msgstr "待发货订单"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:16
msgid "blocks.appearance.baseColor"
msgstr "基础颜色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:220
msgid "app.navigation.loyalty-benefits"
msgstr "权益配置"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:95
msgid "blocks.appearance.color.blue"
msgstr "蓝色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:48
msgid "app.navigation.catalog-product-brands"
msgstr "品牌资料"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:25
msgid "ui.breadcrumb.label"
msgstr "面包屑导航"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:8
msgid "app.navigation.overview-dashboard"
msgstr "经营总览"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:128
msgid "app.navigation.trade-orders-canceled"
msgstr "已取消订单"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:52
msgid "app.navigation.catalog-categories"
msgstr "分类目录"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:56
msgid "app.navigation.catalog-category-tree"
msgstr "分类树"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:244
msgid "app.navigation.report-channels"
msgstr "渠道分析"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/chats/messages.ts:4
msgid "blocks.chats.title"
msgstr "聊天"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:16
msgid "blocks.notifications.error.description"
msgstr "请检查网络连接后重试。"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:29
msgid "ui.common.close"
msgstr "关闭"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:33
msgid "ui.toast.close"
msgstr "关闭通知"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:24
msgid "blocks.appearance.compact.title"
msgstr "紧凑布局"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:124
msgid "app.navigation.trade-orders-completed"
msgstr "已完成订单"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:88
msgid "app.navigation.content-assets"
msgstr "内容素材"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:192
msgid "app.navigation.marketing-coupons"
msgstr "优惠券管理"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:100
msgid "app.navigation.content-pages"
msgstr "自定义页面"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:240
msgid "app.navigation.report-customers"
msgstr "客群分析"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:172
msgid "app.navigation.customer-profiles"
msgstr "客户档案"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:176
msgid "app.navigation.customer-segments"
msgstr "客户分群"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:180
msgid "app.navigation.customer-tiers"
msgstr "客户等级"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:168
msgid "app.navigation.customer-center"
msgstr "客户中心"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:164
msgid "app.navigation.customers-and-marketing"
msgstr "客户与营销"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:99
msgid "blocks.appearance.color.cyan"
msgstr "青色"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:28
msgid "blocks.appearance.mode.dark"
msgstr "深色"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:36
msgid "blocks.appearance.theme.dark"
msgstr "深色主题"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:224
msgid "app.navigation.data-and-finance"
msgstr "数据与财务"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:296
msgid "app.navigation.system-notification-logs"
msgstr "发送记录"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:136
msgid "app.navigation.fulfillment-deliveries"
msgstr "配送任务"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:81
msgid "ui.sidebar.description"
msgstr "显示移动端侧栏。"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:103
msgid "blocks.appearance.color.emerald"
msgstr "翠绿色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:248
msgid "app.navigation.finance-center"
msgstr "财务中心"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:196
msgid "app.navigation.marketing-flash-sales"
msgstr "限时折扣"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:107
msgid "blocks.appearance.color.fuchsia"
msgstr "紫红色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:132
msgid "app.navigation.fulfillment-center"
msgstr "配送履约"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:200
msgid "app.navigation.marketing-gift-promotions"
msgstr "满赠活动"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:53
msgid "ui.pagination.nextPage"
msgstr "前往下一页"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:69
msgid "ui.pagination.previousPage"
msgstr "前往上一页"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:111
msgid "blocks.appearance.color.green"
msgstr "绿色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:120
msgid "app.navigation.trade-orders-shipped"
msgstr "配送中订单"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:72
msgid "app.navigation.inventory-inbound"
msgstr "入库单"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:115
msgid "blocks.appearance.color.indigo"
msgstr "靛蓝色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:304
msgid "app.navigation.system-integrations"
msgstr "开放集成"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:64
msgid "app.navigation.inventory-center"
msgstr "库存中心"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:84
msgid "app.navigation.inventory-alerts"
msgstr "库存预警"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:68
msgid "app.navigation.inventory-overview"
msgstr "库存总览"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:260
msgid "app.navigation.finance-invoices"
msgstr "发票管理"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:24
msgid "blocks.notifications.justNow"
msgstr "刚刚"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:16
msgid "blocks.userMenu.keybindings"
msgstr "按键映射"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:52
msgid "blocks.appearance.mode.light"
msgstr "浅色"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:60
msgid "blocks.appearance.theme.light"
msgstr "浅色主题"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:119
msgid "blocks.appearance.color.lime"
msgstr "青柠色"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:37
msgid "ui.common.loading"
msgstr "正在加载"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:28
msgid "blocks.notifications.loading"
msgstr "正在加载通知…"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:20
msgid "blocks.userMenu.logout"
msgstr "退出登录"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:32
msgid "blocks.notifications.markAllAsRead"
msgstr "全部标记为已读"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:188
msgid "app.navigation.marketing-campaigns"
msgstr "营销活动"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:123
msgid "blocks.appearance.color.mauve"
msgstr "紫灰"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:96
msgid "app.navigation.content-media"
msgstr "媒体资源"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:208
msgid "app.navigation.loyalty-center"
msgstr "会员权益"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:127
msgid "blocks.appearance.color.mist"
msgstr "雾灰"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:41
msgid "ui.common.more"
msgstr "更多"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:45
msgid "ui.pagination.more"
msgstr "更多页面"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/navigation/messages.ts:4
msgid "blocks.navigation.description"
msgstr "浏览应用中的页面。"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/navigation/messages.ts:12
msgid "blocks.navigation.title"
msgstr "导航"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:60
msgid "app.navigation.catalog-category-navigation"
msgstr "导航分类"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:131
msgid "blocks.appearance.color.neutral"
msgstr "中性灰"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:8
msgid "blocks.notifications.empty.description"
msgstr "新的动态会显示在这里。"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:49
msgid "ui.pagination.next"
msgstr "下一页"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:57
msgid "ui.carousel.nextSlide"
msgstr "下一张"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:12
msgid "blocks.notifications.empty.title"
msgstr "暂无通知"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:292
msgid "app.navigation.system-notification-templates"
msgstr "通知模板"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:40
msgid "blocks.notifications.title"
msgstr "通知"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:288
msgid "app.navigation.system-notifications"
msgstr "消息中心"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:135
msgid "blocks.appearance.color.olive"
msgstr "橄榄灰"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:12
msgid "blocks.breadcrumb.menuLabel"
msgstr "打开面包屑菜单"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/navigation/messages.ts:8
msgid "blocks.navigation.open"
msgstr "打开导航"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:12
msgid "blocks.appearance.command.description"
msgstr "打开主题与布局偏好"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:24
msgid "blocks.userMenu.open"
msgstr "打开用户菜单"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:139
msgid "blocks.appearance.color.orange"
msgstr "橙色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:108
msgid "app.navigation.trade-orders"
msgstr "订单中心"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:104
msgid "app.navigation.trade-and-fulfillment"
msgstr "交易与履约"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:272
msgid "app.navigation.system-members"
msgstr "组织成员"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:76
msgid "app.navigation.inventory-outbound"
msgstr "出库单"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:4
msgid "app.navigation.overview"
msgstr "概览"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:61
msgid "ui.pagination.label"
msgstr "分页导航"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:324
msgid "app.navigation.system-settings-payments"
msgstr "支付渠道"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:264
msgid "app.navigation.finance-payouts"
msgstr "打款记录"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:284
msgid "app.navigation.system-members-permissions"
msgstr "权限策略"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:140
msgid "app.navigation.fulfillment-pickups"
msgstr "自提核销"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:143
msgid "blocks.appearance.color.pink"
msgstr "粉色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:212
msgid "app.navigation.loyalty-points"
msgstr "积分规则"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:65
msgid "ui.pagination.previous"
msgstr "上一页"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:73
msgid "ui.carousel.previousSlide"
msgstr "上一张"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:68
msgid "blocks.appearance.primaryColor"
msgstr "主要颜色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:236
msgid "app.navigation.report-products"
msgstr "商品分析"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:40
msgid "app.navigation.catalog-products-attributes"
msgstr "商品属性"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:36
msgid "app.navigation.catalog-products-bundles"
msgstr "组合商品"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:32
msgid "app.navigation.catalog-products-drafts"
msgstr "商品草稿"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:28
msgid "app.navigation.catalog-products-list"
msgstr "商品列表"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:24
msgid "app.navigation.catalog-products"
msgstr "商品中心"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:20
msgid "app.navigation.catalog-and-inventory"
msgstr "商品与库存"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:147
msgid "blocks.appearance.color.purple"
msgstr "紫色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:12
msgid "app.navigation.overview-realtime"
msgstr "实时监控"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:256
msgid "app.navigation.finance-reconciliation"
msgstr "对账管理"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:332
msgid "app.navigation.system-recycle-bin"
msgstr "回收站"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:151
msgid "blocks.appearance.color.red"
msgstr "红色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:204
msgid "app.navigation.marketing-referrals"
msgstr "邀请有礼"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:32
msgid "blocks.refresh.label"
msgstr "刷新当前页面数据"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:28
msgid "blocks.refresh.description"
msgstr "刷新当前页面的数据"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:156
msgid "app.navigation.after-sales-refunds"
msgstr "退款审核"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:228
msgid "app.navigation.report-center"
msgstr "数据报表"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:152
msgid "app.navigation.after-sales-returns"
msgstr "退货申请"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:184
msgid "app.navigation.customer-risk-list"
msgstr "风险名单"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:280
msgid "app.navigation.system-members-roles"
msgstr "角色管理"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:155
msgid "blocks.appearance.color.rose"
msgstr "玫红色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:232
msgid "app.navigation.report-sales"
msgstr "销售分析"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:252
msgid "app.navigation.finance-settlements"
msgstr "结算账单"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:144
msgid "app.navigation.fulfillment-freight-rules"
msgstr "运费规则"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:328
msgid "app.navigation.system-settings-shipping"
msgstr "配送设置"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:77
msgid "ui.sidebar.title"
msgstr "侧栏"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:159
msgid "blocks.appearance.color.sky"
msgstr "天蓝色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:44
msgid "app.navigation.catalog-product-specifications"
msgstr "规格模板"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:80
msgid "app.navigation.inventory-transfers"
msgstr "调拨单"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:163
msgid "blocks.appearance.color.stone"
msgstr "石灰"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:320
msgid "app.navigation.system-settings-store"
msgstr "门店资料"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:216
msgid "app.navigation.loyalty-stored-value"
msgstr "储值账户"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:84
msgid "blocks.appearance.toggleTheme.description"
msgstr "在浅色与深色主题之间切换"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:44
msgid "blocks.appearance.mode.system"
msgstr "系统"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:268
msgid "app.navigation.system-management"
msgstr "系统管理"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:316
msgid "app.navigation.system-settings"
msgstr "系统配置"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:16
msgid "app.navigation.overview-tasks"
msgstr "待办中心"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:167
msgid "blocks.appearance.color.taupe"
msgstr "灰褐"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:171
msgid "blocks.appearance.color.teal"
msgstr "蓝绿色"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:48
msgid "blocks.appearance.mode.system.description"
msgstr "界面主题将跟随系统外观设置"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:32
msgid "blocks.appearance.mode.dark.description"
msgstr "界面将始终使用深色主题"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:56
msgid "blocks.appearance.mode.light.description"
msgstr "界面将始终使用浅色主题"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:72
msgid "blocks.appearance.description"
msgstr "主题与布局偏好"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:76
msgid "blocks.appearance.mode.title"
msgstr "主题模式"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:40
msgid "blocks.appearance.theme.dark.description"
msgstr "当系统设置为深色模式时,将使用此主题"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:64
msgid "blocks.appearance.theme.light.description"
msgstr "当系统设置为浅色模式时,将使用此主题"
#. js-lingui-explicit-id
#: ../../packages/ui/src/components/i18n.tsx:85
msgid "ui.sidebar.toggle"
msgstr "切换侧栏"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:80
msgid "blocks.appearance.toggleTheme"
msgstr "切换主题"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:160
msgid "app.navigation.after-sales-disputes"
msgstr "交易纠纷"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:36
msgid "blocks.notifications.retry"
msgstr "重新加载"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:20
msgid "blocks.notifications.error.title"
msgstr "无法加载通知"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:20
msgid "blocks.appearance.compact.description"
msgstr "启用后,页面主内容将使用紧凑宽度"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/layout/messages.ts:36
msgid "blocks.userMenu.title"
msgstr "用户菜单"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:44
msgid "blocks.notifications.viewAll"
msgstr "查看全部"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/notifications/messages.ts:4
msgid "blocks.notifications.description"
msgstr "查看并处理通知"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:175
msgid "blocks.appearance.color.violet"
msgstr "紫罗兰色"
#. js-lingui-explicit-id
#: src/data/navigation-messages.ts:312
msgid "app.navigation.system-integration-webhooks"
msgstr "Webhook 配置"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:179
msgid "blocks.appearance.color.yellow"
msgstr "黄色"
#. js-lingui-explicit-id
#: ../../packages/blocks/src/blocks/appearance/messages.ts:183
msgid "blocks.appearance.color.zinc"
msgstr "锌灰"
File diff suppressed because one or more lines are too long
+16 -5
View File
@@ -24,10 +24,19 @@ import { HotkeysProvider } from "@tanstack/react-hotkeys"
import { TooltipProvider } from "@workspace/ui/components/tooltip"
import { QueryClientProvider } from "@tanstack/react-query"
import { AppI18nProvider } from "@/i18n/app-i18n-provider"
import { getAppLocale } from "@/server/app-locale.functions"
import type { AppLocale } from "@/i18n/app-locales"
import { queryClient } from "@/lib/query-client"
export const Route = createRootRoute({
loader: () => getUiState(),
loader: async () => {
const [initialState, initialLocale] = await Promise.all([
getUiState(),
getAppLocale(),
])
return { initialLocale, initialState }
},
head: () => ({
meta: [
{ charSet: "utf-8" },
@@ -48,11 +57,11 @@ export const Route = createRootRoute({
})
function RootComponent() {
const initialState = Route.useLoaderData()
const { initialLocale, initialState } = Route.useLoaderData()
return (
<RootDocument initialState={initialState}>
<AppI18nProvider>
<RootDocument initialLocale={initialLocale} initialState={initialState}>
<AppI18nProvider locale={initialLocale}>
<BreakpointReactor />
<UiStateProvider
initialState={initialState}
@@ -94,9 +103,11 @@ function getUiInitializationScript(state: UiState) {
function RootDocument({
children,
initialLocale,
initialState,
}: Readonly<{
children: ReactNode
initialLocale: AppLocale
initialState: UiState
}>) {
const themeMode = initialState["theme-mode"]
@@ -110,7 +121,7 @@ function RootDocument({
return (
<html
lang="zh-CN"
lang={initialLocale === "zh-Hans" ? "zh-CN" : "en-US"}
suppressHydrationWarning
className={className || undefined}
style={themeMode === "system" ? undefined : { colorScheme: themeMode }}
+2
View File
@@ -8,6 +8,7 @@ import {
fetchMockNotifications,
notificationsQueryKey,
} from "@/data/notifications"
import { AppLanguageSwitcher } from "@/i18n/app-language-switcher"
export const Route = createFileRoute("/_app")({
component: ApplicationLayoutRoute,
@@ -17,6 +18,7 @@ function ApplicationLayoutRoute() {
return (
<AppLayout
chatThreads={chatThreads}
headerActions={<AppLanguageSwitcher />}
navigationGroups={primaryNavigationGroups}
notifications={{
queryFn: fetchMockNotifications,
@@ -0,0 +1,20 @@
import { createServerFn } from "@tanstack/react-start"
import { isAppLocale } from "@/i18n/app-locales"
import { readAppLocale, writeAppLocale } from "./app-locale.server"
export const getAppLocale = createServerFn({ method: "GET" }).handler(() => {
return readAppLocale()
})
export const setAppLocale = createServerFn({ method: "POST" })
.validator((value: unknown) => {
if (!isAppLocale(value)) {
throw new Error("Invalid app locale")
}
return value
})
.handler(({ data }) => {
writeAppLocale(data)
})
+25
View File
@@ -0,0 +1,25 @@
import "@tanstack/react-start/server-only"
import { getCookie, setCookie } from "@tanstack/react-start/server"
import {
DEFAULT_APP_LOCALE,
isAppLocale,
type AppLocale,
} from "@/i18n/app-locales"
const APP_LOCALE_COOKIE = "ui-locale"
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365
export function readAppLocale(): AppLocale {
const locale = getCookie(APP_LOCALE_COOKIE)
return isAppLocale(locale) ? locale : DEFAULT_APP_LOCALE
}
export function writeAppLocale(locale: AppLocale) {
setCookie(APP_LOCALE_COOKIE, locale, {
maxAge: COOKIE_MAX_AGE,
path: "/",
sameSite: "lax",
})
}