From 8cf3a1f03a7f3f284675fcaf492c8ab46a7b0794 Mon Sep 17 00:00:00 2001 From: Maofeng Date: Thu, 30 Jul 2026 14:48:25 +0800 Subject: [PATCH] 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 --- apps/web/i18n.config.json | 8 + apps/web/lingui.config.ts | 4 - apps/web/src/data/navigation-messages.ts | 336 +++++++ apps/web/src/data/navigation.ts | 168 ++-- apps/web/src/i18n/app-i18n-devtool.tsx | 21 + apps/web/src/i18n/app-i18n-provider.tsx | 128 ++- .../src/i18n/app-language-switcher.test.tsx | 45 + apps/web/src/i18n/app-language-switcher.tsx | 94 ++ apps/web/src/i18n/app-locales.ts | 32 + apps/web/src/locales/en/messages.po | 840 ++++++++++++++++++ apps/web/src/locales/en/messages.ts | 3 +- apps/web/src/locales/zh-Hans/messages.po | 840 ++++++++++++++++++ apps/web/src/locales/zh-Hans/messages.ts | 3 +- apps/web/src/routes/__root.tsx | 21 +- apps/web/src/routes/_app.tsx | 2 + apps/web/src/server/app-locale.functions.ts | 20 + apps/web/src/server/app-locale.server.ts | 25 + apps/web/tsconfig.node.json | 3 +- apps/web/vitest.config.ts | 16 + 19 files changed, 2474 insertions(+), 135 deletions(-) delete mode 100644 apps/web/lingui.config.ts create mode 100644 apps/web/src/data/navigation-messages.ts create mode 100644 apps/web/src/i18n/app-i18n-devtool.tsx create mode 100644 apps/web/src/i18n/app-language-switcher.test.tsx create mode 100644 apps/web/src/i18n/app-language-switcher.tsx create mode 100644 apps/web/src/i18n/app-locales.ts create mode 100644 apps/web/src/server/app-locale.functions.ts create mode 100644 apps/web/src/server/app-locale.server.ts create mode 100644 apps/web/vitest.config.ts diff --git a/apps/web/i18n.config.json b/apps/web/i18n.config.json index cb9d4d1..250c7c6 100644 --- a/apps/web/i18n.config.json +++ b/apps/web/i18n.config.json @@ -2,6 +2,14 @@ "sourceLocale": "en", "locales": ["en", "zh-Hans"], "catalogPath": "src/locales/{locale}/messages", + "catalogSources": [ + "@workspace/ui/locales/{locale}", + "@workspace/blocks/appearance/locales/{locale}", + "@workspace/blocks/chats/locales/{locale}", + "@workspace/blocks/layout/locales/{locale}", + "@workspace/blocks/navigation/locales/{locale}", + "@workspace/blocks/notifications/locales/{locale}" + ], "include": ["src", "../../packages/blocks/src", "../../packages/ui/src"], "exclude": ["**/*.test.{ts,tsx}", "**/node_modules/**"] } diff --git a/apps/web/lingui.config.ts b/apps/web/lingui.config.ts deleted file mode 100644 index 165c993..0000000 --- a/apps/web/lingui.config.ts +++ /dev/null @@ -1,4 +0,0 @@ -import project from "./i18n.config.json" with { type: "json" } -import { createLinguiConfig } from "@workspace/i18n/lingui-config" - -export default createLinguiConfig(project) diff --git a/apps/web/src/data/navigation-messages.ts b/apps/web/src/data/navigation-messages.ts new file mode 100644 index 0000000..e9dcda0 --- /dev/null +++ b/apps/web/src/data/navigation-messages.ts @@ -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 diff --git a/apps/web/src/data/navigation.ts b/apps/web/src/data/navigation.ts index d7f217e..d07ce28 100644 --- a/apps/web/src/data/navigation.ts +++ b/apps/web/src/data/navigation.ts @@ -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, }, ], diff --git a/apps/web/src/i18n/app-i18n-devtool.tsx b/apps/web/src/i18n/app-i18n-devtool.tsx new file mode 100644 index 0000000..edb0124 --- /dev/null +++ b/apps/web/src/i18n/app-i18n-devtool.tsx @@ -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 ( + + + + ) +} diff --git a/apps/web/src/i18n/app-i18n-provider.tsx b/apps/web/src/i18n/app-i18n-provider.tsx index d3f2755..1ecd2ae 100644 --- a/apps/web/src/i18n/app-i18n-provider.tsx +++ b/apps/web/src/i18n/app-i18n-provider.tsx @@ -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> = { + en: englishCalendarLocale, + "zh-Hans": simplifiedChineseCalendarLocale, } export interface AppI18nProviderProps extends PropsWithChildren { locale?: AppLocale } +interface AppLocaleContextValue { + locale: AppLocale + setLocale: (locale: AppLocale) => void +} + +const AppLocaleContext = createContext(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 ( - - {children} - {I18nDevtool && ( - - - - )} - + + + {children} + + + + ) +} + +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 ( + + {children} + ) } diff --git a/apps/web/src/i18n/app-language-switcher.test.tsx b/apps/web/src/i18n/app-language-switcher.test.tsx new file mode 100644 index 0000000..02d52f9 --- /dev/null +++ b/apps/web/src/i18n/app-language-switcher.test.tsx @@ -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: () => , + US: () => , +})) + +beforeAll(() => { + vi.stubGlobal( + "ResizeObserver", + class { + disconnect() {} + observe() {} + unobserve() {} + } + ) +}) + +afterEach(cleanup) + +describe("AppLanguageSwitcher", () => { + it("opens its grouped locale choices", async () => { + render() + + fireEvent.click( + screen.getByRole("button", { + name: "Change language, currently English", + }) + ) + + expect(await screen.findByText("简体中文")).not.toBeNull() + }) +}) diff --git a/apps/web/src/i18n/app-language-switcher.tsx b/apps/web/src/i18n/app-language-switcher.tsx new file mode 100644 index 0000000..6b9caa8 --- /dev/null +++ b/apps/web/src/i18n/app-language-switcher.tsx @@ -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 + +function LocaleFlag({ + country, + className, +}: { + className?: string + country: AppLocaleCountry +}) { + const Flag = localeFlags[country] + + return ( + + ) +} + +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 ( + + + } + > + + + + { + if (isAppLocale(value)) { + setLocale(value) + } + }} + > + {menuLabel} + {appLocales.map((definition) => ( + + + {definition.label} + + ))} + + + + ) +} diff --git a/apps/web/src/i18n/app-locales.ts b/apps/web/src/i18n/app-locales.ts new file mode 100644 index 0000000..9f33d04 --- /dev/null +++ b/apps/web/src/i18n/app-locales.ts @@ -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) +} diff --git a/apps/web/src/locales/en/messages.po b/apps/web/src/locales/en/messages.po index ed86065..40a1cb6 100644 --- a/apps/web/src/locales/en/messages.po +++ b/apps/web/src/locales/en/messages.po @@ -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" diff --git a/apps/web/src/locales/en/messages.ts b/apps/web/src/locales/en/messages.ts index c754d7a..623f532 100644 --- a/apps/web/src/locales/en/messages.ts +++ b/apps/web/src/locales/en/messages.ts @@ -1,2 +1 @@ -/*eslint-disable*/ import type { Messages } from "@lingui/core" -export const messages = JSON.parse("{}") as Messages +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"app.navigation.after-sales-center\":[\"After-sales\"],\"app.navigation.after-sales-disputes\":[\"Transaction disputes\"],\"app.navigation.after-sales-refunds\":[\"Refund review\"],\"app.navigation.after-sales-returns\":[\"Return requests\"],\"app.navigation.catalog-and-inventory\":[\"Products and inventory\"],\"app.navigation.catalog-categories\":[\"Categories\"],\"app.navigation.catalog-category-navigation\":[\"Navigation categories\"],\"app.navigation.catalog-category-tree\":[\"Category tree\"],\"app.navigation.catalog-product-brands\":[\"Brands\"],\"app.navigation.catalog-product-specifications\":[\"Specification templates\"],\"app.navigation.catalog-products\":[\"Products\"],\"app.navigation.catalog-products-attributes\":[\"Product attributes\"],\"app.navigation.catalog-products-bundles\":[\"Product bundles\"],\"app.navigation.catalog-products-drafts\":[\"Product drafts\"],\"app.navigation.catalog-products-list\":[\"Product list\"],\"app.navigation.content-articles\":[\"Articles\"],\"app.navigation.content-assets\":[\"Content\"],\"app.navigation.content-media\":[\"Media\"],\"app.navigation.content-pages\":[\"Custom pages\"],\"app.navigation.customer-center\":[\"Customers\"],\"app.navigation.customer-profiles\":[\"Customer profiles\"],\"app.navigation.customer-risk-list\":[\"Risk list\"],\"app.navigation.customer-segments\":[\"Customer segments\"],\"app.navigation.customer-tiers\":[\"Customer tiers\"],\"app.navigation.customers-and-marketing\":[\"Customers and marketing\"],\"app.navigation.data-and-finance\":[\"Data and finance\"],\"app.navigation.finance-center\":[\"Finance\"],\"app.navigation.finance-invoices\":[\"Invoices\"],\"app.navigation.finance-payouts\":[\"Payout history\"],\"app.navigation.finance-reconciliation\":[\"Reconciliation\"],\"app.navigation.finance-settlements\":[\"Settlement statements\"],\"app.navigation.fulfillment-center\":[\"Fulfillment\"],\"app.navigation.fulfillment-deliveries\":[\"Delivery tasks\"],\"app.navigation.fulfillment-freight-rules\":[\"Shipping rules\"],\"app.navigation.fulfillment-pickups\":[\"Pickup verification\"],\"app.navigation.inventory-alerts\":[\"Inventory alerts\"],\"app.navigation.inventory-center\":[\"Inventory\"],\"app.navigation.inventory-inbound\":[\"Inbound orders\"],\"app.navigation.inventory-outbound\":[\"Outbound orders\"],\"app.navigation.inventory-overview\":[\"Inventory overview\"],\"app.navigation.inventory-transfers\":[\"Stock transfers\"],\"app.navigation.loyalty-benefits\":[\"Benefits configuration\"],\"app.navigation.loyalty-center\":[\"Membership benefits\"],\"app.navigation.loyalty-points\":[\"Points rules\"],\"app.navigation.loyalty-stored-value\":[\"Stored-value accounts\"],\"app.navigation.marketing-campaigns\":[\"Marketing campaigns\"],\"app.navigation.marketing-coupons\":[\"Coupons\"],\"app.navigation.marketing-flash-sales\":[\"Flash sales\"],\"app.navigation.marketing-gift-promotions\":[\"Gift promotions\"],\"app.navigation.marketing-referrals\":[\"Referral rewards\"],\"app.navigation.overview\":[\"Overview\"],\"app.navigation.overview-dashboard\":[\"Business overview\"],\"app.navigation.overview-realtime\":[\"Real-time monitoring\"],\"app.navigation.overview-tasks\":[\"Tasks\"],\"app.navigation.report-center\":[\"Reports\"],\"app.navigation.report-channels\":[\"Channel analysis\"],\"app.navigation.report-customers\":[\"Customer analysis\"],\"app.navigation.report-products\":[\"Product analysis\"],\"app.navigation.report-sales\":[\"Sales analysis\"],\"app.navigation.system-audit\":[\"Audit log\"],\"app.navigation.system-integration-api-keys\":[\"API keys\"],\"app.navigation.system-integration-webhooks\":[\"Webhook configuration\"],\"app.navigation.system-integrations\":[\"Integrations\"],\"app.navigation.system-management\":[\"System management\"],\"app.navigation.system-members\":[\"Organization members\"],\"app.navigation.system-members-admins\":[\"Administrator accounts\"],\"app.navigation.system-members-permissions\":[\"Permission policies\"],\"app.navigation.system-members-roles\":[\"Roles\"],\"app.navigation.system-notification-logs\":[\"Delivery logs\"],\"app.navigation.system-notification-templates\":[\"Notification templates\"],\"app.navigation.system-notifications\":[\"Notifications\"],\"app.navigation.system-recycle-bin\":[\"Recycle bin\"],\"app.navigation.system-settings\":[\"System settings\"],\"app.navigation.system-settings-payments\":[\"Payment channels\"],\"app.navigation.system-settings-shipping\":[\"Shipping settings\"],\"app.navigation.system-settings-store\":[\"Store information\"],\"app.navigation.trade-and-fulfillment\":[\"Orders and fulfillment\"],\"app.navigation.trade-orders\":[\"Orders\"],\"app.navigation.trade-orders-awaiting-payment\":[\"Awaiting payment\"],\"app.navigation.trade-orders-awaiting-shipment\":[\"Awaiting shipment\"],\"app.navigation.trade-orders-canceled\":[\"Canceled orders\"],\"app.navigation.trade-orders-completed\":[\"Completed orders\"],\"app.navigation.trade-orders-shipped\":[\"In transit\"],\"blocks.appearance.active\":[\"Active\"],\"blocks.appearance.baseColor\":[\"Base color\"],\"blocks.appearance.color.amber\":[\"Amber\"],\"blocks.appearance.color.blue\":[\"Blue\"],\"blocks.appearance.color.cyan\":[\"Cyan\"],\"blocks.appearance.color.emerald\":[\"Emerald\"],\"blocks.appearance.color.fuchsia\":[\"Fuchsia\"],\"blocks.appearance.color.green\":[\"Green\"],\"blocks.appearance.color.indigo\":[\"Indigo\"],\"blocks.appearance.color.lime\":[\"Lime\"],\"blocks.appearance.color.mauve\":[\"Mauve\"],\"blocks.appearance.color.mist\":[\"Mist\"],\"blocks.appearance.color.neutral\":[\"Neutral\"],\"blocks.appearance.color.olive\":[\"Olive\"],\"blocks.appearance.color.orange\":[\"Orange\"],\"blocks.appearance.color.pink\":[\"Pink\"],\"blocks.appearance.color.purple\":[\"Purple\"],\"blocks.appearance.color.red\":[\"Red\"],\"blocks.appearance.color.rose\":[\"Rose\"],\"blocks.appearance.color.sky\":[\"Sky\"],\"blocks.appearance.color.stone\":[\"Stone\"],\"blocks.appearance.color.taupe\":[\"Taupe\"],\"blocks.appearance.color.teal\":[\"Teal\"],\"blocks.appearance.color.violet\":[\"Violet\"],\"blocks.appearance.color.yellow\":[\"Yellow\"],\"blocks.appearance.color.zinc\":[\"Zinc\"],\"blocks.appearance.command.description\":[\"Open theme and layout preferences\"],\"blocks.appearance.compact.description\":[\"Use a compact width for the main page content\"],\"blocks.appearance.compact.title\":[\"Compact layout\"],\"blocks.appearance.description\":[\"Theme and layout preferences\"],\"blocks.appearance.mode.dark\":[\"Dark\"],\"blocks.appearance.mode.dark.description\":[\"The interface will always use the dark theme\"],\"blocks.appearance.mode.light\":[\"Light\"],\"blocks.appearance.mode.light.description\":[\"The interface will always use the light theme\"],\"blocks.appearance.mode.system\":[\"System\"],\"blocks.appearance.mode.system.description\":[\"The interface theme will follow the system appearance\"],\"blocks.appearance.mode.title\":[\"Theme mode\"],\"blocks.appearance.primaryColor\":[\"Primary color\"],\"blocks.appearance.theme.dark\":[\"Dark theme\"],\"blocks.appearance.theme.dark.description\":[\"This theme is used when the system is in dark mode\"],\"blocks.appearance.theme.light\":[\"Light theme\"],\"blocks.appearance.theme.light.description\":[\"This theme is used when the system is in light mode\"],\"blocks.appearance.title\":[\"Appearance\"],\"blocks.appearance.toggleTheme\":[\"Toggle theme\"],\"blocks.appearance.toggleTheme.description\":[\"Switch between light and dark themes\"],\"blocks.breadcrumb.menuLabel\":[\"Open breadcrumb menu\"],\"blocks.chats.title\":[\"Chats\"],\"blocks.navigation.description\":[\"Navigate through the app.\"],\"blocks.navigation.open\":[\"Open navigation\"],\"blocks.navigation.title\":[\"Navigation\"],\"blocks.notifications.description\":[\"View and manage notifications\"],\"blocks.notifications.empty.description\":[\"New activity will appear here.\"],\"blocks.notifications.empty.title\":[\"No notifications\"],\"blocks.notifications.error.description\":[\"Check your network connection and try again.\"],\"blocks.notifications.error.title\":[\"Unable to load notifications\"],\"blocks.notifications.justNow\":[\"just now\"],\"blocks.notifications.loading\":[\"Loading notifications…\"],\"blocks.notifications.markAllAsRead\":[\"Mark all as read\"],\"blocks.notifications.retry\":[\"Try again\"],\"blocks.notifications.title\":[\"Notifications\"],\"blocks.notifications.viewAll\":[\"View all\"],\"blocks.refresh.description\":[\"Refresh the current page data\"],\"blocks.refresh.label\":[\"Refresh current page data\"],\"blocks.userMenu.accountPassword\":[\"Account password\"],\"blocks.userMenu.appearance\":[\"Appearance\"],\"blocks.userMenu.keybindings\":[\"Keybindings\"],\"blocks.userMenu.logout\":[\"Log out\"],\"blocks.userMenu.open\":[\"Open user menu\"],\"blocks.userMenu.title\":[\"User menu\"],\"ui.breadcrumb.label\":[\"Breadcrumb\"],\"ui.carousel.nextSlide\":[\"Next slide\"],\"ui.carousel.previousSlide\":[\"Previous slide\"],\"ui.common.close\":[\"Close\"],\"ui.common.loading\":[\"Loading\"],\"ui.common.more\":[\"More\"],\"ui.pagination.label\":[\"Pagination\"],\"ui.pagination.more\":[\"More pages\"],\"ui.pagination.next\":[\"Next\"],\"ui.pagination.nextPage\":[\"Go to next page\"],\"ui.pagination.previous\":[\"Previous\"],\"ui.pagination.previousPage\":[\"Go to previous page\"],\"ui.sidebar.description\":[\"Displays the mobile sidebar.\"],\"ui.sidebar.title\":[\"Sidebar\"],\"ui.sidebar.toggle\":[\"Toggle sidebar\"],\"ui.toast.close\":[\"Close notification\"]}")as Messages; \ No newline at end of file diff --git a/apps/web/src/locales/zh-Hans/messages.po b/apps/web/src/locales/zh-Hans/messages.po index 0e231a8..172c922 100644 --- a/apps/web/src/locales/zh-Hans/messages.po +++ b/apps/web/src/locales/zh-Hans/messages.po @@ -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 "锌灰" diff --git a/apps/web/src/locales/zh-Hans/messages.ts b/apps/web/src/locales/zh-Hans/messages.ts index c754d7a..d0780cd 100644 --- a/apps/web/src/locales/zh-Hans/messages.ts +++ b/apps/web/src/locales/zh-Hans/messages.ts @@ -1,2 +1 @@ -/*eslint-disable*/ import type { Messages } from "@lingui/core" -export const messages = JSON.parse("{}") as Messages +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"app.navigation.after-sales-center\":[\"售后中心\"],\"app.navigation.after-sales-disputes\":[\"交易纠纷\"],\"app.navigation.after-sales-refunds\":[\"退款审核\"],\"app.navigation.after-sales-returns\":[\"退货申请\"],\"app.navigation.catalog-and-inventory\":[\"商品与库存\"],\"app.navigation.catalog-categories\":[\"分类目录\"],\"app.navigation.catalog-category-navigation\":[\"导航分类\"],\"app.navigation.catalog-category-tree\":[\"分类树\"],\"app.navigation.catalog-product-brands\":[\"品牌资料\"],\"app.navigation.catalog-product-specifications\":[\"规格模板\"],\"app.navigation.catalog-products\":[\"商品中心\"],\"app.navigation.catalog-products-attributes\":[\"商品属性\"],\"app.navigation.catalog-products-bundles\":[\"组合商品\"],\"app.navigation.catalog-products-drafts\":[\"商品草稿\"],\"app.navigation.catalog-products-list\":[\"商品列表\"],\"app.navigation.content-articles\":[\"内容文章\"],\"app.navigation.content-assets\":[\"内容素材\"],\"app.navigation.content-media\":[\"媒体资源\"],\"app.navigation.content-pages\":[\"自定义页面\"],\"app.navigation.customer-center\":[\"客户中心\"],\"app.navigation.customer-profiles\":[\"客户档案\"],\"app.navigation.customer-risk-list\":[\"风险名单\"],\"app.navigation.customer-segments\":[\"客户分群\"],\"app.navigation.customer-tiers\":[\"客户等级\"],\"app.navigation.customers-and-marketing\":[\"客户与营销\"],\"app.navigation.data-and-finance\":[\"数据与财务\"],\"app.navigation.finance-center\":[\"财务中心\"],\"app.navigation.finance-invoices\":[\"发票管理\"],\"app.navigation.finance-payouts\":[\"打款记录\"],\"app.navigation.finance-reconciliation\":[\"对账管理\"],\"app.navigation.finance-settlements\":[\"结算账单\"],\"app.navigation.fulfillment-center\":[\"配送履约\"],\"app.navigation.fulfillment-deliveries\":[\"配送任务\"],\"app.navigation.fulfillment-freight-rules\":[\"运费规则\"],\"app.navigation.fulfillment-pickups\":[\"自提核销\"],\"app.navigation.inventory-alerts\":[\"库存预警\"],\"app.navigation.inventory-center\":[\"库存中心\"],\"app.navigation.inventory-inbound\":[\"入库单\"],\"app.navigation.inventory-outbound\":[\"出库单\"],\"app.navigation.inventory-overview\":[\"库存总览\"],\"app.navigation.inventory-transfers\":[\"调拨单\"],\"app.navigation.loyalty-benefits\":[\"权益配置\"],\"app.navigation.loyalty-center\":[\"会员权益\"],\"app.navigation.loyalty-points\":[\"积分规则\"],\"app.navigation.loyalty-stored-value\":[\"储值账户\"],\"app.navigation.marketing-campaigns\":[\"营销活动\"],\"app.navigation.marketing-coupons\":[\"优惠券管理\"],\"app.navigation.marketing-flash-sales\":[\"限时折扣\"],\"app.navigation.marketing-gift-promotions\":[\"满赠活动\"],\"app.navigation.marketing-referrals\":[\"邀请有礼\"],\"app.navigation.overview\":[\"概览\"],\"app.navigation.overview-dashboard\":[\"经营总览\"],\"app.navigation.overview-realtime\":[\"实时监控\"],\"app.navigation.overview-tasks\":[\"待办中心\"],\"app.navigation.report-center\":[\"数据报表\"],\"app.navigation.report-channels\":[\"渠道分析\"],\"app.navigation.report-customers\":[\"客群分析\"],\"app.navigation.report-products\":[\"商品分析\"],\"app.navigation.report-sales\":[\"销售分析\"],\"app.navigation.system-audit\":[\"操作审计\"],\"app.navigation.system-integration-api-keys\":[\"API 密钥\"],\"app.navigation.system-integration-webhooks\":[\"Webhook 配置\"],\"app.navigation.system-integrations\":[\"开放集成\"],\"app.navigation.system-management\":[\"系统管理\"],\"app.navigation.system-members\":[\"组织成员\"],\"app.navigation.system-members-admins\":[\"管理员账号\"],\"app.navigation.system-members-permissions\":[\"权限策略\"],\"app.navigation.system-members-roles\":[\"角色管理\"],\"app.navigation.system-notification-logs\":[\"发送记录\"],\"app.navigation.system-notification-templates\":[\"通知模板\"],\"app.navigation.system-notifications\":[\"消息中心\"],\"app.navigation.system-recycle-bin\":[\"回收站\"],\"app.navigation.system-settings\":[\"系统配置\"],\"app.navigation.system-settings-payments\":[\"支付渠道\"],\"app.navigation.system-settings-shipping\":[\"配送设置\"],\"app.navigation.system-settings-store\":[\"门店资料\"],\"app.navigation.trade-and-fulfillment\":[\"交易与履约\"],\"app.navigation.trade-orders\":[\"订单中心\"],\"app.navigation.trade-orders-awaiting-payment\":[\"待付款订单\"],\"app.navigation.trade-orders-awaiting-shipment\":[\"待发货订单\"],\"app.navigation.trade-orders-canceled\":[\"已取消订单\"],\"app.navigation.trade-orders-completed\":[\"已完成订单\"],\"app.navigation.trade-orders-shipped\":[\"配送中订单\"],\"blocks.appearance.active\":[\"使用中\"],\"blocks.appearance.baseColor\":[\"基础颜色\"],\"blocks.appearance.color.amber\":[\"琥珀色\"],\"blocks.appearance.color.blue\":[\"蓝色\"],\"blocks.appearance.color.cyan\":[\"青色\"],\"blocks.appearance.color.emerald\":[\"翠绿色\"],\"blocks.appearance.color.fuchsia\":[\"紫红色\"],\"blocks.appearance.color.green\":[\"绿色\"],\"blocks.appearance.color.indigo\":[\"靛蓝色\"],\"blocks.appearance.color.lime\":[\"青柠色\"],\"blocks.appearance.color.mauve\":[\"紫灰\"],\"blocks.appearance.color.mist\":[\"雾灰\"],\"blocks.appearance.color.neutral\":[\"中性灰\"],\"blocks.appearance.color.olive\":[\"橄榄灰\"],\"blocks.appearance.color.orange\":[\"橙色\"],\"blocks.appearance.color.pink\":[\"粉色\"],\"blocks.appearance.color.purple\":[\"紫色\"],\"blocks.appearance.color.red\":[\"红色\"],\"blocks.appearance.color.rose\":[\"玫红色\"],\"blocks.appearance.color.sky\":[\"天蓝色\"],\"blocks.appearance.color.stone\":[\"石灰\"],\"blocks.appearance.color.taupe\":[\"灰褐\"],\"blocks.appearance.color.teal\":[\"蓝绿色\"],\"blocks.appearance.color.violet\":[\"紫罗兰色\"],\"blocks.appearance.color.yellow\":[\"黄色\"],\"blocks.appearance.color.zinc\":[\"锌灰\"],\"blocks.appearance.command.description\":[\"打开主题与布局偏好\"],\"blocks.appearance.compact.description\":[\"启用后,页面主内容将使用紧凑宽度\"],\"blocks.appearance.compact.title\":[\"紧凑布局\"],\"blocks.appearance.description\":[\"主题与布局偏好\"],\"blocks.appearance.mode.dark\":[\"深色\"],\"blocks.appearance.mode.dark.description\":[\"界面将始终使用深色主题\"],\"blocks.appearance.mode.light\":[\"浅色\"],\"blocks.appearance.mode.light.description\":[\"界面将始终使用浅色主题\"],\"blocks.appearance.mode.system\":[\"系统\"],\"blocks.appearance.mode.system.description\":[\"界面主题将跟随系统外观设置\"],\"blocks.appearance.mode.title\":[\"主题模式\"],\"blocks.appearance.primaryColor\":[\"主要颜色\"],\"blocks.appearance.theme.dark\":[\"深色主题\"],\"blocks.appearance.theme.dark.description\":[\"当系统设置为深色模式时,将使用此主题\"],\"blocks.appearance.theme.light\":[\"浅色主题\"],\"blocks.appearance.theme.light.description\":[\"当系统设置为浅色模式时,将使用此主题\"],\"blocks.appearance.title\":[\"界面外观\"],\"blocks.appearance.toggleTheme\":[\"切换主题\"],\"blocks.appearance.toggleTheme.description\":[\"在浅色与深色主题之间切换\"],\"blocks.breadcrumb.menuLabel\":[\"打开面包屑菜单\"],\"blocks.chats.title\":[\"聊天\"],\"blocks.navigation.description\":[\"浏览应用中的页面。\"],\"blocks.navigation.open\":[\"打开导航\"],\"blocks.navigation.title\":[\"导航\"],\"blocks.notifications.description\":[\"查看并处理通知\"],\"blocks.notifications.empty.description\":[\"新的动态会显示在这里。\"],\"blocks.notifications.empty.title\":[\"暂无通知\"],\"blocks.notifications.error.description\":[\"请检查网络连接后重试。\"],\"blocks.notifications.error.title\":[\"无法加载通知\"],\"blocks.notifications.justNow\":[\"刚刚\"],\"blocks.notifications.loading\":[\"正在加载通知…\"],\"blocks.notifications.markAllAsRead\":[\"全部标记为已读\"],\"blocks.notifications.retry\":[\"重新加载\"],\"blocks.notifications.title\":[\"通知\"],\"blocks.notifications.viewAll\":[\"查看全部\"],\"blocks.refresh.description\":[\"刷新当前页面的数据\"],\"blocks.refresh.label\":[\"刷新当前页面数据\"],\"blocks.userMenu.accountPassword\":[\"账号密码\"],\"blocks.userMenu.appearance\":[\"界面外观\"],\"blocks.userMenu.keybindings\":[\"按键映射\"],\"blocks.userMenu.logout\":[\"退出登录\"],\"blocks.userMenu.open\":[\"打开用户菜单\"],\"blocks.userMenu.title\":[\"用户菜单\"],\"ui.breadcrumb.label\":[\"面包屑导航\"],\"ui.carousel.nextSlide\":[\"下一张\"],\"ui.carousel.previousSlide\":[\"上一张\"],\"ui.common.close\":[\"关闭\"],\"ui.common.loading\":[\"正在加载\"],\"ui.common.more\":[\"更多\"],\"ui.pagination.label\":[\"分页导航\"],\"ui.pagination.more\":[\"更多页面\"],\"ui.pagination.next\":[\"下一页\"],\"ui.pagination.nextPage\":[\"前往下一页\"],\"ui.pagination.previous\":[\"上一页\"],\"ui.pagination.previousPage\":[\"前往上一页\"],\"ui.sidebar.description\":[\"显示移动端侧栏。\"],\"ui.sidebar.title\":[\"侧栏\"],\"ui.sidebar.toggle\":[\"切换侧栏\"],\"ui.toast.close\":[\"关闭通知\"]}")as Messages; \ No newline at end of file diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index 65b8520..da2d086 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -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 ( - - + + ) { const themeMode = initialState["theme-mode"] @@ -110,7 +121,7 @@ function RootDocument({ return ( } navigationGroups={primaryNavigationGroups} notifications={{ queryFn: fetchMockNotifications, diff --git a/apps/web/src/server/app-locale.functions.ts b/apps/web/src/server/app-locale.functions.ts new file mode 100644 index 0000000..be41200 --- /dev/null +++ b/apps/web/src/server/app-locale.functions.ts @@ -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) + }) diff --git a/apps/web/src/server/app-locale.server.ts b/apps/web/src/server/app-locale.server.ts new file mode 100644 index 0000000..48bdedc --- /dev/null +++ b/apps/web/src/server/app-locale.server.ts @@ -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", + }) +} diff --git a/apps/web/tsconfig.node.json b/apps/web/tsconfig.node.json index 8ea6773..d3c52ea 100644 --- a/apps/web/tsconfig.node.json +++ b/apps/web/tsconfig.node.json @@ -10,7 +10,6 @@ /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, - "resolveJsonModule": true, "verbatimModuleSyntax": true, "moduleDetection": "force", "noEmit": true, @@ -21,5 +20,5 @@ "erasableSyntaxOnly": true, "noFallthroughCasesInSwitch": true }, - "include": ["vite.config.ts", "lingui.config.ts"] + "include": ["vite.config.ts"] } diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts new file mode 100644 index 0000000..e388757 --- /dev/null +++ b/apps/web/vitest.config.ts @@ -0,0 +1,16 @@ +import path from "node:path" +import react from "@vitejs/plugin-react" +import { defineConfig } from "vitest/config" + +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + tsconfigPaths: true, + }, + test: { + environment: "jsdom", + }, +})