diff --git a/apps/web/i18n.config.json b/apps/web/i18n.config.json index 021978d..b3e8a0d 100644 --- a/apps/web/i18n.config.json +++ b/apps/web/i18n.config.json @@ -1,6 +1,6 @@ { - "sourceLocale": "en", - "locales": ["en", "zh-Hans"], + "sourceLocale": "en-US", + "locales": ["en-US", "zh-Hans"], "catalogPath": "src/locales/{locale}/messages", "catalogSources": [ "@workspace/ui/locales/{locale}", @@ -10,9 +10,14 @@ "@workspace/blocks/media/locales/{locale}", "@workspace/blocks/navigation/locales/{locale}", "@workspace/blocks/notifications/locales/{locale}", - "@workspace/blocks/search/locales/{locale}", + "@workspace/search/locales/{locale}", "@workspace/lexical/locales/{locale}" ], - "include": ["src", "../../packages/blocks/src", "../../packages/ui/src"], + "include": [ + "src", + "../../packages/blocks/src", + "../../packages/search/src", + "../../packages/ui/src" + ], "exclude": ["**/*.test.{ts,tsx}", "**/node_modules/**"] -} +} \ No newline at end of file diff --git a/apps/web/src/i18n/app-i18n-provider.tsx b/apps/web/src/i18n/app-i18n-provider.tsx index 1ecd2ae..5fb5d8f 100644 --- a/apps/web/src/i18n/app-i18n-provider.tsx +++ b/apps/web/src/i18n/app-i18n-provider.tsx @@ -19,7 +19,7 @@ import { I18nProvider as UiI18nProvider, type CalendarLocale, } from "@workspace/ui/components/i18n" -import { calendarLocale as englishCalendarLocale } from "@workspace/ui/locales/en" +import { calendarLocale as englishCalendarLocale } from "@workspace/ui/locales/en-US" import { calendarLocale as simplifiedChineseCalendarLocale } from "@workspace/ui/locales/zh-Hans" import { appLocales, DEFAULT_APP_LOCALE, type AppLocale } from "./app-locales" @@ -27,7 +27,7 @@ import { AppI18nDevtool } from "./app-i18n-devtool" import { setAppLocale as persistAppLocale } from "@/server/app-locale.functions" const appCalendarLocales: Partial> = { - en: englishCalendarLocale, + "en-US": englishCalendarLocale, "zh-Hans": simplifiedChineseCalendarLocale, } diff --git a/apps/web/src/i18n/app-language-switcher.test.tsx b/apps/web/src/i18n/app-language-switcher.test.tsx index 02d52f9..504ae3c 100644 --- a/apps/web/src/i18n/app-language-switcher.test.tsx +++ b/apps/web/src/i18n/app-language-switcher.test.tsx @@ -7,16 +7,11 @@ import { AppLanguageSwitcher } from "./app-language-switcher" vi.mock("./app-i18n-provider", () => ({ useAppLocale: () => ({ - locale: "en", + locale: "en-US", setLocale: vi.fn(), }), })) -vi.mock("country-flag-icons/react/1x1", () => ({ - CN: () => , - US: () => , -})) - beforeAll(() => { vi.stubGlobal( "ResizeObserver", diff --git a/apps/web/src/i18n/app-locales.ts b/apps/web/src/i18n/app-locales.ts index 9f33d04..4d39352 100644 --- a/apps/web/src/i18n/app-locales.ts +++ b/apps/web/src/i18n/app-locales.ts @@ -1,6 +1,6 @@ import type { LocaleDefinition } from "@workspace/i18n" -export type AppLocale = "en" | "zh-Hans" +export type AppLocale = "en-US" | "zh-Hans" export type AppLocaleCountry = "CN" | "US" export interface AppLocaleDefinition extends LocaleDefinition { @@ -16,7 +16,7 @@ export const appLocales = [ direction: "ltr", languageTag: "en-US", label: "English", - locale: "en", + locale: "en-US", }, { country: "CN", diff --git a/apps/web/src/locales/en/messages.po b/apps/web/src/locales/en-US/messages.po similarity index 85% rename from apps/web/src/locales/en/messages.po rename to apps/web/src/locales/en-US/messages.po index 40a1cb6..6ac67e7 100644 --- a/apps/web/src/locales/en/messages.po +++ b/apps/web/src/locales/en-US/messages.po @@ -4,7 +4,7 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: @lingui/cli\n" -"Language: en\n" +"Language: en-US\n" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: \n" @@ -23,6 +23,21 @@ msgstr "Account password" msgid "blocks.appearance.active" msgstr "Active" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:16 +msgid "blocks.chats.actions.addEmoji" +msgstr "Add emoji" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:4 +msgid "blocks.chats.actions.addFiles" +msgstr "Add files" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:8 +msgid "blocks.chats.actions.addImage" +msgstr "Add image" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:276 msgid "app.navigation.system-members-admins" @@ -33,6 +48,11 @@ msgstr "Administrator accounts" msgid "app.navigation.after-sales-center" msgstr "After-sales" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:12 +msgid "blocks.chats.emojiPicker.allEmojis" +msgstr "All emojis" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:91 msgid "blocks.appearance.color.amber" @@ -73,6 +93,11 @@ msgstr "Awaiting payment" msgid "app.navigation.trade-orders-awaiting-shipment" msgstr "Awaiting shipment" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:20 +msgid "blocks.chats.actions.backToConversations" +msgstr "Back to conversations" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:16 msgid "blocks.appearance.baseColor" @@ -124,7 +149,7 @@ msgid "app.navigation.report-channels" msgstr "Channel analysis" #. js-lingui-explicit-id -#: ../../packages/blocks/src/blocks/chats/messages.ts:4 +#: ../../packages/blocks/src/blocks/chats/messages.ts:112 msgid "blocks.chats.title" msgstr "Chats" @@ -133,6 +158,11 @@ msgstr "Chats" msgid "blocks.notifications.error.description" msgstr "Check your network connection and try again." +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:108 +msgid "blocks.chats.selectConversation.description" +msgstr "Choose a conversation from the list to read its messages." + #. js-lingui-explicit-id #: ../../packages/ui/src/components/i18n.tsx:29 msgid "ui.common.close" @@ -158,6 +188,11 @@ msgstr "Completed orders" msgid "app.navigation.content-assets" msgstr "Content" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:24 +msgid "blocks.chats.actions.conversationDetails" +msgstr "Conversation details" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:192 msgid "app.navigation.marketing-coupons" @@ -218,6 +253,11 @@ msgstr "Dark theme" msgid "app.navigation.data-and-finance" msgstr "Data and finance" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:52 +msgid "blocks.chats.messageStatus.delivered" +msgstr "Delivered" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:296 msgid "app.navigation.system-notification-logs" @@ -343,6 +383,11 @@ msgstr "Light theme" msgid "blocks.appearance.color.lime" msgstr "Lime" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:28 +msgid "blocks.chats.actions.loadEarlier" +msgstr "Load earlier messages" + #. js-lingui-explicit-id #: ../../packages/ui/src/components/i18n.tsx:37 msgid "ui.common.loading" @@ -383,6 +428,11 @@ msgstr "Media" msgid "app.navigation.loyalty-center" msgstr "Membership benefits" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:84 +msgid "blocks.chats.emptyMessages.description" +msgstr "Messages in this conversation will appear here." + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:127 msgid "blocks.appearance.color.mist" @@ -433,11 +483,31 @@ msgstr "Next" msgid "ui.carousel.nextSlide" msgstr "Next slide" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:80 +msgid "blocks.chats.emptyConversations.title" +msgstr "No conversations" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:92 +msgid "blocks.chats.emptySearch" +msgstr "No conversations match your search." + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:88 +msgid "blocks.chats.emptyMessages.title" +msgstr "No messages yet" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/notifications/messages.ts:12 msgid "blocks.notifications.empty.title" msgstr "No notifications" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:56 +msgid "blocks.chats.messageStatus.failed" +msgstr "Not sent" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:292 msgid "app.navigation.system-notification-templates" @@ -543,6 +613,11 @@ msgstr "Pink" msgid "app.navigation.loyalty-points" msgstr "Points rules" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:44 +msgid "blocks.chats.actions.sendOnEnter" +msgstr "Press Enter to send" + #. js-lingui-explicit-id #: ../../packages/ui/src/components/i18n.tsx:65 msgid "ui.pagination.previous" @@ -598,11 +673,21 @@ msgstr "Products and inventory" msgid "blocks.appearance.color.purple" msgstr "Purple" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:60 +msgid "blocks.chats.messageStatus.read" +msgstr "Read" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:12 msgid "app.navigation.overview-realtime" msgstr "Real-time monitoring" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:64 +msgid "blocks.chats.emojiPicker.recentEmojis" +msgstr "Recently used" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:256 msgid "app.navigation.finance-reconciliation" @@ -638,6 +723,11 @@ msgstr "Refresh the current page data" msgid "app.navigation.after-sales-refunds" msgstr "Refund review" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:32 +msgid "blocks.chats.actions.removeAttachment" +msgstr "Remove {name}" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:228 msgid "app.navigation.report-center" @@ -668,6 +758,36 @@ msgstr "Rose" msgid "app.navigation.report-sales" msgstr "Sales analysis" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:100 +msgid "blocks.chats.search" +msgstr "Search conversations" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:104 +msgid "blocks.chats.selectConversation" +msgstr "Select conversation {title}" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:40 +msgid "blocks.chats.actions.send" +msgstr "Send" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:72 +msgid "blocks.chats.messageStatus.sending" +msgstr "Sending" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:48 +msgid "blocks.chats.actions.sending" +msgstr "Sending…" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:68 +msgid "blocks.chats.messageStatus.sent" +msgstr "Sent" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:252 msgid "app.navigation.finance-settlements" @@ -698,6 +818,11 @@ msgstr "Sky" msgid "app.navigation.catalog-product-specifications" msgstr "Specification templates" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:76 +msgid "blocks.chats.emptyConversations.description" +msgstr "Start a conversation to see it here." + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:80 msgid "app.navigation.inventory-transfers" @@ -803,6 +928,11 @@ msgstr "Toggle theme" msgid "app.navigation.after-sales-disputes" msgstr "Transaction disputes" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:36 +msgid "blocks.chats.actions.retry" +msgstr "Try again" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/notifications/messages.ts:36 msgid "blocks.notifications.retry" @@ -843,6 +973,11 @@ msgstr "Violet" msgid "app.navigation.system-integration-webhooks" msgstr "Webhook configuration" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:96 +msgid "blocks.chats.messagePlaceholder" +msgstr "Write a message…" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:179 msgid "blocks.appearance.color.yellow" diff --git a/apps/web/src/locales/en/messages.ts b/apps/web/src/locales/en-US/messages.ts similarity index 67% rename from apps/web/src/locales/en/messages.ts rename to apps/web/src/locales/en-US/messages.ts index 623f532..255ad0a 100644 --- a/apps/web/src/locales/en/messages.ts +++ b/apps/web/src/locales/en-US/messages.ts @@ -1 +1 @@ -/*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 +/*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.actions.addEmoji\":[\"Add emoji\"],\"blocks.chats.actions.addFiles\":[\"Add files\"],\"blocks.chats.actions.addImage\":[\"Add image\"],\"blocks.chats.actions.backToConversations\":[\"Back to conversations\"],\"blocks.chats.actions.conversationDetails\":[\"Conversation details\"],\"blocks.chats.actions.loadEarlier\":[\"Load earlier messages\"],\"blocks.chats.actions.removeAttachment\":[\"Remove \",[\"name\"]],\"blocks.chats.actions.retry\":[\"Try again\"],\"blocks.chats.actions.send\":[\"Send\"],\"blocks.chats.actions.sendOnEnter\":[\"Press Enter to send\"],\"blocks.chats.actions.sending\":[\"Sending…\"],\"blocks.chats.emojiPicker.allEmojis\":[\"All emojis\"],\"blocks.chats.emojiPicker.recentEmojis\":[\"Recently used\"],\"blocks.chats.emptyConversations.description\":[\"Start a conversation to see it here.\"],\"blocks.chats.emptyConversations.title\":[\"No conversations\"],\"blocks.chats.emptyMessages.description\":[\"Messages in this conversation will appear here.\"],\"blocks.chats.emptyMessages.title\":[\"No messages yet\"],\"blocks.chats.emptySearch\":[\"No conversations match your search.\"],\"blocks.chats.messagePlaceholder\":[\"Write a message…\"],\"blocks.chats.messageStatus.delivered\":[\"Delivered\"],\"blocks.chats.messageStatus.failed\":[\"Not sent\"],\"blocks.chats.messageStatus.read\":[\"Read\"],\"blocks.chats.messageStatus.sending\":[\"Sending\"],\"blocks.chats.messageStatus.sent\":[\"Sent\"],\"blocks.chats.search\":[\"Search conversations\"],\"blocks.chats.selectConversation\":[\"Select conversation \",[\"title\"]],\"blocks.chats.selectConversation.description\":[\"Choose a conversation from the list to read its messages.\"],\"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 172c922..436d2c7 100644 --- a/apps/web/src/locales/zh-Hans/messages.po +++ b/apps/web/src/locales/zh-Hans/messages.po @@ -23,6 +23,21 @@ msgstr "账号密码" msgid "blocks.appearance.active" msgstr "使用中" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:16 +msgid "blocks.chats.actions.addEmoji" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:4 +msgid "blocks.chats.actions.addFiles" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:8 +msgid "blocks.chats.actions.addImage" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:276 msgid "app.navigation.system-members-admins" @@ -33,6 +48,11 @@ msgstr "管理员账号" msgid "app.navigation.after-sales-center" msgstr "售后中心" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:12 +msgid "blocks.chats.emojiPicker.allEmojis" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:91 msgid "blocks.appearance.color.amber" @@ -73,6 +93,11 @@ msgstr "待付款订单" msgid "app.navigation.trade-orders-awaiting-shipment" msgstr "待发货订单" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:20 +msgid "blocks.chats.actions.backToConversations" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:16 msgid "blocks.appearance.baseColor" @@ -124,7 +149,7 @@ msgid "app.navigation.report-channels" msgstr "渠道分析" #. js-lingui-explicit-id -#: ../../packages/blocks/src/blocks/chats/messages.ts:4 +#: ../../packages/blocks/src/blocks/chats/messages.ts:112 msgid "blocks.chats.title" msgstr "聊天" @@ -133,6 +158,11 @@ msgstr "聊天" msgid "blocks.notifications.error.description" msgstr "请检查网络连接后重试。" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:108 +msgid "blocks.chats.selectConversation.description" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/ui/src/components/i18n.tsx:29 msgid "ui.common.close" @@ -158,6 +188,11 @@ msgstr "已完成订单" msgid "app.navigation.content-assets" msgstr "内容素材" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:24 +msgid "blocks.chats.actions.conversationDetails" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:192 msgid "app.navigation.marketing-coupons" @@ -218,6 +253,11 @@ msgstr "深色主题" msgid "app.navigation.data-and-finance" msgstr "数据与财务" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:52 +msgid "blocks.chats.messageStatus.delivered" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:296 msgid "app.navigation.system-notification-logs" @@ -343,6 +383,11 @@ msgstr "浅色主题" msgid "blocks.appearance.color.lime" msgstr "青柠色" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:28 +msgid "blocks.chats.actions.loadEarlier" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/ui/src/components/i18n.tsx:37 msgid "ui.common.loading" @@ -383,6 +428,11 @@ msgstr "媒体资源" msgid "app.navigation.loyalty-center" msgstr "会员权益" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:84 +msgid "blocks.chats.emptyMessages.description" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:127 msgid "blocks.appearance.color.mist" @@ -433,11 +483,31 @@ msgstr "下一页" msgid "ui.carousel.nextSlide" msgstr "下一张" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:80 +msgid "blocks.chats.emptyConversations.title" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:92 +msgid "blocks.chats.emptySearch" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:88 +msgid "blocks.chats.emptyMessages.title" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/notifications/messages.ts:12 msgid "blocks.notifications.empty.title" msgstr "暂无通知" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:56 +msgid "blocks.chats.messageStatus.failed" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:292 msgid "app.navigation.system-notification-templates" @@ -543,6 +613,11 @@ msgstr "粉色" msgid "app.navigation.loyalty-points" msgstr "积分规则" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:44 +msgid "blocks.chats.actions.sendOnEnter" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/ui/src/components/i18n.tsx:65 msgid "ui.pagination.previous" @@ -598,11 +673,21 @@ msgstr "商品与库存" msgid "blocks.appearance.color.purple" msgstr "紫色" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:60 +msgid "blocks.chats.messageStatus.read" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:12 msgid "app.navigation.overview-realtime" msgstr "实时监控" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:64 +msgid "blocks.chats.emojiPicker.recentEmojis" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:256 msgid "app.navigation.finance-reconciliation" @@ -638,6 +723,11 @@ msgstr "刷新当前页面的数据" msgid "app.navigation.after-sales-refunds" msgstr "退款审核" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:32 +msgid "blocks.chats.actions.removeAttachment" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:228 msgid "app.navigation.report-center" @@ -668,6 +758,36 @@ msgstr "玫红色" msgid "app.navigation.report-sales" msgstr "销售分析" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:100 +msgid "blocks.chats.search" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:104 +msgid "blocks.chats.selectConversation" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:40 +msgid "blocks.chats.actions.send" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:72 +msgid "blocks.chats.messageStatus.sending" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:48 +msgid "blocks.chats.actions.sending" +msgstr "" + +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:68 +msgid "blocks.chats.messageStatus.sent" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:252 msgid "app.navigation.finance-settlements" @@ -698,6 +818,11 @@ msgstr "天蓝色" msgid "app.navigation.catalog-product-specifications" msgstr "规格模板" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:76 +msgid "blocks.chats.emptyConversations.description" +msgstr "" + #. js-lingui-explicit-id #: src/data/navigation-messages.ts:80 msgid "app.navigation.inventory-transfers" @@ -803,6 +928,11 @@ msgstr "切换主题" msgid "app.navigation.after-sales-disputes" msgstr "交易纠纷" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:36 +msgid "blocks.chats.actions.retry" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/notifications/messages.ts:36 msgid "blocks.notifications.retry" @@ -843,6 +973,11 @@ msgstr "紫罗兰色" msgid "app.navigation.system-integration-webhooks" msgstr "Webhook 配置" +#. js-lingui-explicit-id +#: ../../packages/blocks/src/blocks/chats/messages.ts:96 +msgid "blocks.chats.messagePlaceholder" +msgstr "" + #. js-lingui-explicit-id #: ../../packages/blocks/src/blocks/appearance/messages.ts:179 msgid "blocks.appearance.color.yellow" diff --git a/apps/web/src/locales/zh-Hans/messages.ts b/apps/web/src/locales/zh-Hans/messages.ts index d0780cd..043e32e 100644 --- a/apps/web/src/locales/zh-Hans/messages.ts +++ b/apps/web/src/locales/zh-Hans/messages.ts @@ -1 +1 @@ -/*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 +/*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.actions.addEmoji\":[\"Add emoji\"],\"blocks.chats.actions.addFiles\":[\"Add files\"],\"blocks.chats.actions.addImage\":[\"Add image\"],\"blocks.chats.actions.backToConversations\":[\"Back to conversations\"],\"blocks.chats.actions.conversationDetails\":[\"Conversation details\"],\"blocks.chats.actions.loadEarlier\":[\"Load earlier messages\"],\"blocks.chats.actions.removeAttachment\":[\"Remove \",[\"name\"]],\"blocks.chats.actions.retry\":[\"Try again\"],\"blocks.chats.actions.send\":[\"Send\"],\"blocks.chats.actions.sendOnEnter\":[\"Press Enter to send\"],\"blocks.chats.actions.sending\":[\"Sending…\"],\"blocks.chats.emojiPicker.allEmojis\":[\"All emojis\"],\"blocks.chats.emojiPicker.recentEmojis\":[\"Recently used\"],\"blocks.chats.emptyConversations.description\":[\"Start a conversation to see it here.\"],\"blocks.chats.emptyConversations.title\":[\"No conversations\"],\"blocks.chats.emptyMessages.description\":[\"Messages in this conversation will appear here.\"],\"blocks.chats.emptyMessages.title\":[\"No messages yet\"],\"blocks.chats.emptySearch\":[\"No conversations match your search.\"],\"blocks.chats.messagePlaceholder\":[\"Write a message…\"],\"blocks.chats.messageStatus.delivered\":[\"Delivered\"],\"blocks.chats.messageStatus.failed\":[\"Not sent\"],\"blocks.chats.messageStatus.read\":[\"Read\"],\"blocks.chats.messageStatus.sending\":[\"Sending\"],\"blocks.chats.messageStatus.sent\":[\"Sent\"],\"blocks.chats.search\":[\"Search conversations\"],\"blocks.chats.selectConversation\":[\"Select conversation \",[\"title\"]],\"blocks.chats.selectConversation.description\":[\"Choose a conversation from the list to read its messages.\"],\"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/server/app-locale.server.ts b/apps/web/src/server/app-locale.server.ts index 48bdedc..71da5eb 100644 --- a/apps/web/src/server/app-locale.server.ts +++ b/apps/web/src/server/app-locale.server.ts @@ -1,3 +1,4 @@ +// oxlint-disable-next-line import/no-unassigned-import -- Enforces server-only module usage. import "@tanstack/react-start/server-only" import { getCookie, setCookie } from "@tanstack/react-start/server" diff --git a/packages/blocks/src/blocks/appearance/locales/catalogs.test.ts b/packages/blocks/src/blocks/appearance/locales/catalogs.test.ts index 133c8b8..de82289 100644 --- a/packages/blocks/src/blocks/appearance/locales/catalogs.test.ts +++ b/packages/blocks/src/blocks/appearance/locales/catalogs.test.ts @@ -3,27 +3,15 @@ import { describe, it } from "vitest" import { expectCompleteCatalogs } from "../../../i18n/test-catalogs" import { appearanceMessages, themeColorMessages } from "../messages" import { appearanceCatalogLocales } from "./catalogs" -import { messages as de } from "./de" -import { messages as en } from "./en" -import { messages as es } from "./es" -import { messages as fr } from "./fr" -import { messages as ja } from "./ja" -import { messages as ko } from "./ko" +import { messages as enUS } from "./en-US" import { messages as zhHans } from "./zh-Hans" -import { messages as zhHant } from "./zh-Hant" describe("appearance locale catalogs", () => { it("ship every appearance message in every built-in locale", () => { expectCompleteCatalogs({ catalogs: { - de, - en, - es, - fr, - ja, - ko, + "en-US": enUS, "zh-Hans": zhHans, - "zh-Hant": zhHant, }, locales: appearanceCatalogLocales, messageIds: [ diff --git a/packages/blocks/src/blocks/appearance/locales/de.ts b/packages/blocks/src/blocks/appearance/locales/de.ts deleted file mode 100644 index ab2f394..0000000 --- a/packages/blocks/src/blocks/appearance/locales/de.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { AppearanceMessageCatalog } from "./catalogs" - -export const locale = "de" -export const languageTag = "de-DE" - -export const messages = { - "blocks.appearance.active": "Aktiv", - "blocks.appearance.baseColor": "Basisfarbe", - "blocks.appearance.color.amber": "Bernstein", - "blocks.appearance.color.blue": "Blau", - "blocks.appearance.color.cyan": "Cyan", - "blocks.appearance.color.emerald": "Smaragd", - "blocks.appearance.color.fuchsia": "Fuchsia", - "blocks.appearance.color.green": "Grün", - "blocks.appearance.color.indigo": "Indigo", - "blocks.appearance.color.lime": "Limette", - "blocks.appearance.color.mauve": "Malve", - "blocks.appearance.color.mist": "Nebel", - "blocks.appearance.color.neutral": "Neutral", - "blocks.appearance.color.olive": "Oliv", - "blocks.appearance.color.orange": "Orange", - "blocks.appearance.color.pink": "Rosa", - "blocks.appearance.color.purple": "Lila", - "blocks.appearance.color.red": "Rot", - "blocks.appearance.color.rose": "Rose", - "blocks.appearance.color.sky": "Himmelblau", - "blocks.appearance.color.stone": "Stein", - "blocks.appearance.color.taupe": "Taupe", - "blocks.appearance.color.teal": "Blaugrün", - "blocks.appearance.color.violet": "Violett", - "blocks.appearance.color.yellow": "Gelb", - "blocks.appearance.color.zinc": "Zink", - "blocks.appearance.command.description": - "Design- und Layout-Einstellungen öffnen", - "blocks.appearance.compact.description": - "Eine kompakte Breite für den Hauptinhalt verwenden", - "blocks.appearance.compact.title": "Kompaktes Layout", - "blocks.appearance.description": "Design- und Layout-Einstellungen", - "blocks.appearance.mode.dark": "Dunkel", - "blocks.appearance.mode.dark.description": - "Die Oberfläche verwendet immer das dunkle Design", - "blocks.appearance.mode.light": "Hell", - "blocks.appearance.mode.light.description": - "Die Oberfläche verwendet immer das helle Design", - "blocks.appearance.mode.system": "System", - "blocks.appearance.mode.system.description": - "Das Design der Oberfläche folgt der Systemeinstellung", - "blocks.appearance.mode.title": "Darstellungsmodus", - "blocks.appearance.primaryColor": "Primärfarbe", - "blocks.appearance.theme.dark": "Dunkles Design", - "blocks.appearance.theme.dark.description": - "Dieses Design wird im dunklen Systemmodus verwendet", - "blocks.appearance.theme.light": "Helles Design", - "blocks.appearance.theme.light.description": - "Dieses Design wird im hellen Systemmodus verwendet", - "blocks.appearance.title": "Darstellung", - "blocks.appearance.toggleTheme": "Design wechseln", - "blocks.appearance.toggleTheme.description": - "Zwischen hellem und dunklem Design wechseln", -} as const satisfies AppearanceMessageCatalog diff --git a/packages/blocks/src/blocks/appearance/locales/en.ts b/packages/blocks/src/blocks/appearance/locales/en-US.ts similarity index 95% rename from packages/blocks/src/blocks/appearance/locales/en.ts rename to packages/blocks/src/blocks/appearance/locales/en-US.ts index 68f3ce0..e5fec97 100644 --- a/packages/blocks/src/blocks/appearance/locales/en.ts +++ b/packages/blocks/src/blocks/appearance/locales/en-US.ts @@ -3,7 +3,7 @@ import type { MessageDescriptor } from "@workspace/i18n" import { appearanceMessages, themeColorMessages } from "../messages.ts" import type { AppearanceMessageCatalog } from "./catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" function createSourceCatalog( diff --git a/packages/blocks/src/blocks/appearance/locales/es.ts b/packages/blocks/src/blocks/appearance/locales/es.ts deleted file mode 100644 index 2431661..0000000 --- a/packages/blocks/src/blocks/appearance/locales/es.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { AppearanceMessageCatalog } from "./catalogs" - -export const locale = "es" -export const languageTag = "es-ES" - -export const messages = { - "blocks.appearance.active": "Activo", - "blocks.appearance.baseColor": "Color base", - "blocks.appearance.color.amber": "Ámbar", - "blocks.appearance.color.blue": "Azul", - "blocks.appearance.color.cyan": "Cian", - "blocks.appearance.color.emerald": "Esmeralda", - "blocks.appearance.color.fuchsia": "Fucsia", - "blocks.appearance.color.green": "Verde", - "blocks.appearance.color.indigo": "Índigo", - "blocks.appearance.color.lime": "Lima", - "blocks.appearance.color.mauve": "Malva", - "blocks.appearance.color.mist": "Niebla", - "blocks.appearance.color.neutral": "Neutro", - "blocks.appearance.color.olive": "Oliva", - "blocks.appearance.color.orange": "Naranja", - "blocks.appearance.color.pink": "Rosa", - "blocks.appearance.color.purple": "Morado", - "blocks.appearance.color.red": "Rojo", - "blocks.appearance.color.rose": "Rosa intenso", - "blocks.appearance.color.sky": "Celeste", - "blocks.appearance.color.stone": "Piedra", - "blocks.appearance.color.taupe": "Topo", - "blocks.appearance.color.teal": "Verde azulado", - "blocks.appearance.color.violet": "Violeta", - "blocks.appearance.color.yellow": "Amarillo", - "blocks.appearance.color.zinc": "Zinc", - "blocks.appearance.command.description": - "Abrir las preferencias de tema y diseño", - "blocks.appearance.compact.description": - "Usar un ancho compacto para el contenido principal", - "blocks.appearance.compact.title": "Diseño compacto", - "blocks.appearance.description": "Preferencias de tema y diseño", - "blocks.appearance.mode.dark": "Oscuro", - "blocks.appearance.mode.dark.description": - "La interfaz siempre usará el tema oscuro", - "blocks.appearance.mode.light": "Claro", - "blocks.appearance.mode.light.description": - "La interfaz siempre usará el tema claro", - "blocks.appearance.mode.system": "Sistema", - "blocks.appearance.mode.system.description": - "El tema de la interfaz seguirá la apariencia del sistema", - "blocks.appearance.mode.title": "Modo de tema", - "blocks.appearance.primaryColor": "Color principal", - "blocks.appearance.theme.dark": "Tema oscuro", - "blocks.appearance.theme.dark.description": - "Este tema se usa cuando el sistema está en modo oscuro", - "blocks.appearance.theme.light": "Tema claro", - "blocks.appearance.theme.light.description": - "Este tema se usa cuando el sistema está en modo claro", - "blocks.appearance.title": "Apariencia", - "blocks.appearance.toggleTheme": "Cambiar tema", - "blocks.appearance.toggleTheme.description": - "Cambiar entre los temas claro y oscuro", -} as const satisfies AppearanceMessageCatalog diff --git a/packages/blocks/src/blocks/appearance/locales/fr.ts b/packages/blocks/src/blocks/appearance/locales/fr.ts deleted file mode 100644 index eb10517..0000000 --- a/packages/blocks/src/blocks/appearance/locales/fr.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { AppearanceMessageCatalog } from "./catalogs" - -export const locale = "fr" -export const languageTag = "fr-FR" - -export const messages = { - "blocks.appearance.active": "Actif", - "blocks.appearance.baseColor": "Couleur de base", - "blocks.appearance.color.amber": "Ambre", - "blocks.appearance.color.blue": "Bleu", - "blocks.appearance.color.cyan": "Cyan", - "blocks.appearance.color.emerald": "Émeraude", - "blocks.appearance.color.fuchsia": "Fuchsia", - "blocks.appearance.color.green": "Vert", - "blocks.appearance.color.indigo": "Indigo", - "blocks.appearance.color.lime": "Citron vert", - "blocks.appearance.color.mauve": "Mauve", - "blocks.appearance.color.mist": "Brume", - "blocks.appearance.color.neutral": "Neutre", - "blocks.appearance.color.olive": "Olive", - "blocks.appearance.color.orange": "Orange", - "blocks.appearance.color.pink": "Rose", - "blocks.appearance.color.purple": "Pourpre", - "blocks.appearance.color.red": "Rouge", - "blocks.appearance.color.rose": "Rose soutenu", - "blocks.appearance.color.sky": "Bleu ciel", - "blocks.appearance.color.stone": "Pierre", - "blocks.appearance.color.taupe": "Taupe", - "blocks.appearance.color.teal": "Sarcelle", - "blocks.appearance.color.violet": "Violet", - "blocks.appearance.color.yellow": "Jaune", - "blocks.appearance.color.zinc": "Zinc", - "blocks.appearance.command.description": - "Ouvrir les préférences de thème et de mise en page", - "blocks.appearance.compact.description": - "Utiliser une largeur compacte pour le contenu principal", - "blocks.appearance.compact.title": "Mise en page compacte", - "blocks.appearance.description": "Préférences de thème et de mise en page", - "blocks.appearance.mode.dark": "Sombre", - "blocks.appearance.mode.dark.description": - "L’interface utilisera toujours le thème sombre", - "blocks.appearance.mode.light": "Clair", - "blocks.appearance.mode.light.description": - "L’interface utilisera toujours le thème clair", - "blocks.appearance.mode.system": "Système", - "blocks.appearance.mode.system.description": - "Le thème de l’interface suivra l’apparence du système", - "blocks.appearance.mode.title": "Mode du thème", - "blocks.appearance.primaryColor": "Couleur principale", - "blocks.appearance.theme.dark": "Thème sombre", - "blocks.appearance.theme.dark.description": - "Ce thème est utilisé lorsque le système est en mode sombre", - "blocks.appearance.theme.light": "Thème clair", - "blocks.appearance.theme.light.description": - "Ce thème est utilisé lorsque le système est en mode clair", - "blocks.appearance.title": "Apparence", - "blocks.appearance.toggleTheme": "Changer de thème", - "blocks.appearance.toggleTheme.description": - "Basculer entre les thèmes clair et sombre", -} as const satisfies AppearanceMessageCatalog diff --git a/packages/blocks/src/blocks/appearance/locales/ja.ts b/packages/blocks/src/blocks/appearance/locales/ja.ts deleted file mode 100644 index 14f269b..0000000 --- a/packages/blocks/src/blocks/appearance/locales/ja.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { AppearanceMessageCatalog } from "./catalogs" - -export const locale = "ja" -export const languageTag = "ja-JP" - -export const messages = { - "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": - "ライトテーマとダークテーマを切り替えます", -} as const satisfies AppearanceMessageCatalog diff --git a/packages/blocks/src/blocks/appearance/locales/ko.ts b/packages/blocks/src/blocks/appearance/locales/ko.ts deleted file mode 100644 index e35ef3b..0000000 --- a/packages/blocks/src/blocks/appearance/locales/ko.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { AppearanceMessageCatalog } from "./catalogs" - -export const locale = "ko" -export const languageTag = "ko-KR" - -export const messages = { - "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": - "밝은 테마와 어두운 테마 사이를 전환합니다", -} as const satisfies AppearanceMessageCatalog diff --git a/packages/blocks/src/blocks/appearance/locales/zh-Hant.ts b/packages/blocks/src/blocks/appearance/locales/zh-Hant.ts deleted file mode 100644 index 2adabfc..0000000 --- a/packages/blocks/src/blocks/appearance/locales/zh-Hant.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { AppearanceMessageCatalog } from "./catalogs" - -export const locale = "zh-Hant" -export const languageTag = "zh-TW" - -export const messages = { - "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": "在淺色與深色主題之間切換", -} as const satisfies AppearanceMessageCatalog diff --git a/packages/blocks/src/blocks/chats/chat-message-list.test.tsx b/packages/blocks/src/blocks/chats/chat-message-list.test.tsx index baeb752..d9bf4ad 100644 --- a/packages/blocks/src/blocks/chats/chat-message-list.test.tsx +++ b/packages/blocks/src/blocks/chats/chat-message-list.test.tsx @@ -5,7 +5,7 @@ import { I18nProvider } from "@workspace/i18n" import { afterEach, describe, expect, it, vi } from "vitest" import { ChatMessageList } from "./chat-message-list" -import { messages as englishMessages } from "./locales/en" +import { messages as englishMessages } from "./locales/en-US" import type { ChatConversation } from "./types" const conversation: ChatConversation = { @@ -57,7 +57,7 @@ describe("ChatMessageList", () => { ) render( - + + { expect(editor.getAttribute("contenteditable")).toBe("true") rerender( - + ) diff --git a/packages/blocks/src/blocks/chats/locales/catalogs.test.ts b/packages/blocks/src/blocks/chats/locales/catalogs.test.ts index 57875b9..37e9847 100644 --- a/packages/blocks/src/blocks/chats/locales/catalogs.test.ts +++ b/packages/blocks/src/blocks/chats/locales/catalogs.test.ts @@ -3,27 +3,15 @@ import { describe, it } from "vitest" import { expectCompleteCatalogs } from "../../../i18n/test-catalogs" import { chatMessages } from "../messages" import { chatCatalogLocales } from "./catalogs" -import { messages as de } from "./de" -import { messages as en } from "./en" -import { messages as es } from "./es" -import { messages as fr } from "./fr" -import { messages as ja } from "./ja" -import { messages as ko } from "./ko" +import { messages as enUS } from "./en-US" import { messages as zhHans } from "./zh-Hans" -import { messages as zhHant } from "./zh-Hant" describe("chat locale catalogs", () => { it("ship every chat message in every built-in locale", () => { expectCompleteCatalogs({ catalogs: { - de, - en, - es, - fr, - ja, - ko, + "en-US": enUS, "zh-Hans": zhHans, - "zh-Hant": zhHant, }, locales: chatCatalogLocales, messageIds: Object.values(chatMessages).map( diff --git a/packages/blocks/src/blocks/chats/locales/de.ts b/packages/blocks/src/blocks/chats/locales/de.ts deleted file mode 100644 index 941c077..0000000 --- a/packages/blocks/src/blocks/chats/locales/de.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { ChatMessageCatalog } from "./catalogs" - -export const locale = "de" -export const languageTag = "de-DE" -export const messages = { - "blocks.chats.actions.addFiles": "Dateien hinzufügen", - "blocks.chats.actions.addEmoji": "Emoji hinzufügen", - "blocks.chats.actions.addImage": "Bild hinzufügen", - "blocks.chats.actions.backToConversations": "Zurück zu Unterhaltungen", - "blocks.chats.actions.conversationDetails": "Unterhaltungsdetails", - "blocks.chats.actions.loadEarlier": "Frühere Nachrichten laden", - "blocks.chats.actions.removeAttachment": "{name} entfernen", - "blocks.chats.actions.retry": "Erneut versuchen", - "blocks.chats.actions.send": "Senden", - "blocks.chats.actions.sendOnEnter": "Mit Enter senden", - "blocks.chats.actions.sending": "Wird gesendet…", - "blocks.chats.emptyConversations.description": - "Starte eine Unterhaltung, damit sie hier erscheint.", - "blocks.chats.emptyConversations.title": "Keine Unterhaltungen", - "blocks.chats.emptyMessages.description": - "Nachrichten dieser Unterhaltung werden hier angezeigt.", - "blocks.chats.emptyMessages.title": "Noch keine Nachrichten", - "blocks.chats.emptySearch": "Keine Unterhaltungen entsprechen deiner Suche.", - "blocks.chats.emojiPicker.allEmojis": "Alle Emojis", - "blocks.chats.emojiPicker.recentEmojis": "Kürzlich verwendet", - "blocks.chats.messagePlaceholder": "Nachricht schreiben…", - "blocks.chats.messageStatus.delivered": "Zugestellt", - "blocks.chats.messageStatus.failed": "Nicht gesendet", - "blocks.chats.messageStatus.read": "Gelesen", - "blocks.chats.messageStatus.sending": "Wird gesendet", - "blocks.chats.messageStatus.sent": "Gesendet", - "blocks.chats.search": "Unterhaltungen suchen", - "blocks.chats.selectConversation": "Unterhaltung {title} auswählen", - "blocks.chats.selectConversation.description": - "Wähle eine Unterhaltung aus der Liste, um ihre Nachrichten zu lesen.", - "blocks.chats.title": "Chats", -} as const satisfies ChatMessageCatalog diff --git a/packages/blocks/src/blocks/chats/locales/en.ts b/packages/blocks/src/blocks/chats/locales/en-US.ts similarity index 98% rename from packages/blocks/src/blocks/chats/locales/en.ts rename to packages/blocks/src/blocks/chats/locales/en-US.ts index ac4367b..295b6e2 100644 --- a/packages/blocks/src/blocks/chats/locales/en.ts +++ b/packages/blocks/src/blocks/chats/locales/en-US.ts @@ -1,6 +1,6 @@ import type { ChatMessageCatalog } from "./catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" export const messages = { "blocks.chats.actions.addFiles": "Add files", diff --git a/packages/blocks/src/blocks/chats/locales/es.ts b/packages/blocks/src/blocks/chats/locales/es.ts deleted file mode 100644 index 4ed64b8..0000000 --- a/packages/blocks/src/blocks/chats/locales/es.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { ChatMessageCatalog } from "./catalogs" - -export const locale = "es" -export const languageTag = "es-ES" -export const messages = { - "blocks.chats.actions.addFiles": "Añadir archivos", - "blocks.chats.actions.addEmoji": "Añadir emoji", - "blocks.chats.actions.addImage": "Añadir imagen", - "blocks.chats.actions.backToConversations": "Volver a conversaciones", - "blocks.chats.actions.conversationDetails": "Detalles de la conversación", - "blocks.chats.actions.loadEarlier": "Cargar mensajes anteriores", - "blocks.chats.actions.removeAttachment": "Quitar {name}", - "blocks.chats.actions.retry": "Intentar de nuevo", - "blocks.chats.actions.send": "Enviar", - "blocks.chats.actions.sendOnEnter": "Enviar con Intro", - "blocks.chats.actions.sending": "Enviando…", - "blocks.chats.emptyConversations.description": - "Inicia una conversación para verla aquí.", - "blocks.chats.emptyConversations.title": "No hay conversaciones", - "blocks.chats.emptyMessages.description": - "Los mensajes de esta conversación aparecerán aquí.", - "blocks.chats.emptyMessages.title": "Aún no hay mensajes", - "blocks.chats.emptySearch": - "No hay conversaciones que coincidan con tu búsqueda.", - "blocks.chats.emojiPicker.allEmojis": "Todos los emojis", - "blocks.chats.emojiPicker.recentEmojis": "Usados recientemente", - "blocks.chats.messagePlaceholder": "Escribe un mensaje…", - "blocks.chats.messageStatus.delivered": "Entregado", - "blocks.chats.messageStatus.failed": "No enviado", - "blocks.chats.messageStatus.read": "Leído", - "blocks.chats.messageStatus.sending": "Enviando", - "blocks.chats.messageStatus.sent": "Enviado", - "blocks.chats.search": "Buscar conversaciones", - "blocks.chats.selectConversation": "Seleccionar conversación {title}", - "blocks.chats.selectConversation.description": - "Elige una conversación de la lista para leer sus mensajes.", - "blocks.chats.title": "Chats", -} as const satisfies ChatMessageCatalog diff --git a/packages/blocks/src/blocks/chats/locales/fr.ts b/packages/blocks/src/blocks/chats/locales/fr.ts deleted file mode 100644 index 114506a..0000000 --- a/packages/blocks/src/blocks/chats/locales/fr.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { ChatMessageCatalog } from "./catalogs" - -export const locale = "fr" -export const languageTag = "fr-FR" -export const messages = { - "blocks.chats.actions.addFiles": "Ajouter des fichiers", - "blocks.chats.actions.addEmoji": "Ajouter un emoji", - "blocks.chats.actions.addImage": "Ajouter une image", - "blocks.chats.actions.backToConversations": "Retour aux discussions", - "blocks.chats.actions.conversationDetails": "Détails de la discussion", - "blocks.chats.actions.loadEarlier": "Charger les messages précédents", - "blocks.chats.actions.removeAttachment": "Retirer {name}", - "blocks.chats.actions.retry": "Réessayer", - "blocks.chats.actions.send": "Envoyer", - "blocks.chats.actions.sendOnEnter": "Envoyer avec Entrée", - "blocks.chats.actions.sending": "Envoi…", - "blocks.chats.emptyConversations.description": - "Démarrez une discussion pour la voir ici.", - "blocks.chats.emptyConversations.title": "Aucune discussion", - "blocks.chats.emptyMessages.description": - "Les messages de cette discussion apparaîtront ici.", - "blocks.chats.emptyMessages.title": "Pas encore de messages", - "blocks.chats.emptySearch": - "Aucune discussion ne correspond à votre recherche.", - "blocks.chats.emojiPicker.allEmojis": "Tous les emojis", - "blocks.chats.emojiPicker.recentEmojis": "Récemment utilisés", - "blocks.chats.messagePlaceholder": "Écrivez un message…", - "blocks.chats.messageStatus.delivered": "Distribué", - "blocks.chats.messageStatus.failed": "Non envoyé", - "blocks.chats.messageStatus.read": "Lu", - "blocks.chats.messageStatus.sending": "Envoi", - "blocks.chats.messageStatus.sent": "Envoyé", - "blocks.chats.search": "Rechercher des discussions", - "blocks.chats.selectConversation": "Sélectionner la discussion {title}", - "blocks.chats.selectConversation.description": - "Choisissez une discussion dans la liste pour lire ses messages.", - "blocks.chats.title": "Discussions", -} as const satisfies ChatMessageCatalog diff --git a/packages/blocks/src/blocks/chats/locales/ja.ts b/packages/blocks/src/blocks/chats/locales/ja.ts deleted file mode 100644 index eafb39f..0000000 --- a/packages/blocks/src/blocks/chats/locales/ja.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { ChatMessageCatalog } from "./catalogs" - -export const locale = "ja" -export const languageTag = "ja-JP" -export const messages = { - "blocks.chats.actions.addFiles": "ファイルを追加", - "blocks.chats.actions.addEmoji": "絵文字を追加", - "blocks.chats.actions.addImage": "画像を追加", - "blocks.chats.actions.backToConversations": "会話一覧に戻る", - "blocks.chats.actions.conversationDetails": "会話の詳細", - "blocks.chats.actions.loadEarlier": "以前のメッセージを読み込む", - "blocks.chats.actions.removeAttachment": "{name} を削除", - "blocks.chats.actions.retry": "再試行", - "blocks.chats.actions.send": "送信", - "blocks.chats.actions.sendOnEnter": "Enter キーで送信", - "blocks.chats.actions.sending": "送信中…", - "blocks.chats.emptyConversations.description": - "会話を始めると、ここに表示されます。", - "blocks.chats.emptyConversations.title": "会話はありません", - "blocks.chats.emptyMessages.description": - "この会話のメッセージはここに表示されます。", - "blocks.chats.emptyMessages.title": "メッセージはまだありません", - "blocks.chats.emptySearch": "検索に一致する会話はありません。", - "blocks.chats.emojiPicker.allEmojis": "すべての絵文字", - "blocks.chats.emojiPicker.recentEmojis": "最近使用した絵文字", - "blocks.chats.messagePlaceholder": "メッセージを入力…", - "blocks.chats.messageStatus.delivered": "配信済み", - "blocks.chats.messageStatus.failed": "未送信", - "blocks.chats.messageStatus.read": "既読", - "blocks.chats.messageStatus.sending": "送信中", - "blocks.chats.messageStatus.sent": "送信済み", - "blocks.chats.search": "会話を検索", - "blocks.chats.selectConversation": "会話 {title} を選択", - "blocks.chats.selectConversation.description": - "一覧から会話を選択してメッセージを読みます。", - "blocks.chats.title": "チャット", -} as const satisfies ChatMessageCatalog diff --git a/packages/blocks/src/blocks/chats/locales/ko.ts b/packages/blocks/src/blocks/chats/locales/ko.ts deleted file mode 100644 index bb460aa..0000000 --- a/packages/blocks/src/blocks/chats/locales/ko.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { ChatMessageCatalog } from "./catalogs" - -export const locale = "ko" -export const languageTag = "ko-KR" -export const messages = { - "blocks.chats.actions.addFiles": "파일 추가", - "blocks.chats.actions.addEmoji": "이모지 추가", - "blocks.chats.actions.addImage": "이미지 추가", - "blocks.chats.actions.backToConversations": "대화 목록으로 돌아가기", - "blocks.chats.actions.conversationDetails": "대화 세부 정보", - "blocks.chats.actions.loadEarlier": "이전 메시지 불러오기", - "blocks.chats.actions.removeAttachment": "{name} 제거", - "blocks.chats.actions.retry": "다시 시도", - "blocks.chats.actions.send": "보내기", - "blocks.chats.actions.sendOnEnter": "Enter 키로 전송", - "blocks.chats.actions.sending": "보내는 중…", - "blocks.chats.emptyConversations.description": - "대화를 시작하면 여기에 표시됩니다.", - "blocks.chats.emptyConversations.title": "대화가 없습니다", - "blocks.chats.emptyMessages.description": - "이 대화의 메시지가 여기에 표시됩니다.", - "blocks.chats.emptyMessages.title": "아직 메시지가 없습니다", - "blocks.chats.emptySearch": "검색과 일치하는 대화가 없습니다.", - "blocks.chats.emojiPicker.allEmojis": "모든 이모지", - "blocks.chats.emojiPicker.recentEmojis": "최근 사용", - "blocks.chats.messagePlaceholder": "메시지 작성…", - "blocks.chats.messageStatus.delivered": "전달됨", - "blocks.chats.messageStatus.failed": "전송되지 않음", - "blocks.chats.messageStatus.read": "읽음", - "blocks.chats.messageStatus.sending": "보내는 중", - "blocks.chats.messageStatus.sent": "보냄", - "blocks.chats.search": "대화 검색", - "blocks.chats.selectConversation": "대화 {title} 선택", - "blocks.chats.selectConversation.description": - "목록에서 대화를 선택하여 메시지를 읽으세요.", - "blocks.chats.title": "채팅", -} as const satisfies ChatMessageCatalog diff --git a/packages/blocks/src/blocks/chats/locales/zh-Hant.ts b/packages/blocks/src/blocks/chats/locales/zh-Hant.ts deleted file mode 100644 index 0555b8e..0000000 --- a/packages/blocks/src/blocks/chats/locales/zh-Hant.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { ChatMessageCatalog } from "./catalogs" - -export const locale = "zh-Hant" -export const languageTag = "zh-TW" -export const messages = { - "blocks.chats.actions.addFiles": "新增檔案", - "blocks.chats.actions.addEmoji": "新增表情", - "blocks.chats.actions.addImage": "新增圖片", - "blocks.chats.actions.backToConversations": "返回對話列表", - "blocks.chats.actions.conversationDetails": "對話詳細資料", - "blocks.chats.actions.loadEarlier": "載入較早訊息", - "blocks.chats.actions.removeAttachment": "移除 {name}", - "blocks.chats.actions.retry": "再試一次", - "blocks.chats.actions.send": "傳送", - "blocks.chats.actions.sendOnEnter": "按 Enter 傳送", - "blocks.chats.actions.sending": "傳送中…", - "blocks.chats.emptyConversations.description": "開始對話後會顯示在這裡。", - "blocks.chats.emptyConversations.title": "沒有對話", - "blocks.chats.emptyMessages.description": "此對話的訊息會顯示在這裡。", - "blocks.chats.emptyMessages.title": "尚無訊息", - "blocks.chats.emptySearch": "沒有符合搜尋條件的對話。", - "blocks.chats.emojiPicker.allEmojis": "所有表情", - "blocks.chats.emojiPicker.recentEmojis": "最近使用", - "blocks.chats.messagePlaceholder": "輸入訊息…", - "blocks.chats.messageStatus.delivered": "已送達", - "blocks.chats.messageStatus.failed": "未傳送", - "blocks.chats.messageStatus.read": "已讀", - "blocks.chats.messageStatus.sending": "傳送中", - "blocks.chats.messageStatus.sent": "已傳送", - "blocks.chats.search": "搜尋對話", - "blocks.chats.selectConversation": "選取對話 {title}", - "blocks.chats.selectConversation.description": "從列表中選取對話以閱讀訊息。", - "blocks.chats.title": "聊天", -} as const satisfies ChatMessageCatalog diff --git a/packages/blocks/src/blocks/layout/locales/catalogs.test.ts b/packages/blocks/src/blocks/layout/locales/catalogs.test.ts index ecadf8b..c02a410 100644 --- a/packages/blocks/src/blocks/layout/locales/catalogs.test.ts +++ b/packages/blocks/src/blocks/layout/locales/catalogs.test.ts @@ -3,27 +3,15 @@ import { describe, it } from "vitest" import { expectCompleteCatalogs } from "../../../i18n/test-catalogs" import { layoutMessages } from "../messages" import { layoutCatalogLocales } from "./catalogs" -import { messages as de } from "./de" -import { messages as en } from "./en" -import { messages as es } from "./es" -import { messages as fr } from "./fr" -import { messages as ja } from "./ja" -import { messages as ko } from "./ko" +import { messages as enUS } from "./en-US" import { messages as zhHans } from "./zh-Hans" -import { messages as zhHant } from "./zh-Hant" describe("layout locale catalogs", () => { it("ship every layout message in every built-in locale", () => { expectCompleteCatalogs({ catalogs: { - de, - en, - es, - fr, - ja, - ko, + "en-US": enUS, "zh-Hans": zhHans, - "zh-Hant": zhHant, }, locales: layoutCatalogLocales, messageIds: Object.values(layoutMessages).map( diff --git a/packages/blocks/src/blocks/layout/locales/de.ts b/packages/blocks/src/blocks/layout/locales/de.ts deleted file mode 100644 index da0e82b..0000000 --- a/packages/blocks/src/blocks/layout/locales/de.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { LayoutMessageCatalog } from "./catalogs" - -export const locale = "de" -export const languageTag = "de-DE" -export const messages = { - "blocks.breadcrumb.menuLabel": "Breadcrumb-Menü öffnen", - "blocks.refresh.description": "Daten der aktuellen Seite aktualisieren", - "blocks.refresh.label": "Aktuelle Seitendaten aktualisieren", - "blocks.userMenu.accountPassword": "Kontopasswort", - "blocks.userMenu.appearance": "Darstellung", - "blocks.userMenu.keybindings": "Tastenkürzel", - "blocks.userMenu.logout": "Abmelden", - "blocks.userMenu.open": "Benutzermenü öffnen", - "blocks.userMenu.title": "Benutzermenü", -} as const satisfies LayoutMessageCatalog diff --git a/packages/blocks/src/blocks/layout/locales/en.ts b/packages/blocks/src/blocks/layout/locales/en-US.ts similarity index 95% rename from packages/blocks/src/blocks/layout/locales/en.ts rename to packages/blocks/src/blocks/layout/locales/en-US.ts index c2dac5e..7450380 100644 --- a/packages/blocks/src/blocks/layout/locales/en.ts +++ b/packages/blocks/src/blocks/layout/locales/en-US.ts @@ -1,6 +1,6 @@ import type { LayoutMessageCatalog } from "./catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" export const messages = { "blocks.breadcrumb.menuLabel": "Open breadcrumb menu", diff --git a/packages/blocks/src/blocks/layout/locales/es.ts b/packages/blocks/src/blocks/layout/locales/es.ts deleted file mode 100644 index 7730366..0000000 --- a/packages/blocks/src/blocks/layout/locales/es.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { LayoutMessageCatalog } from "./catalogs" - -export const locale = "es" -export const languageTag = "es-ES" -export const messages = { - "blocks.breadcrumb.menuLabel": "Abrir el menú de ruta de navegación", - "blocks.refresh.description": "Actualizar los datos de la página actual", - "blocks.refresh.label": "Actualizar datos de la página actual", - "blocks.userMenu.accountPassword": "Contraseña de la cuenta", - "blocks.userMenu.appearance": "Apariencia", - "blocks.userMenu.keybindings": "Atajos de teclado", - "blocks.userMenu.logout": "Cerrar sesión", - "blocks.userMenu.open": "Abrir menú de usuario", - "blocks.userMenu.title": "Menú de usuario", -} as const satisfies LayoutMessageCatalog diff --git a/packages/blocks/src/blocks/layout/locales/fr.ts b/packages/blocks/src/blocks/layout/locales/fr.ts deleted file mode 100644 index 4a7a1c7..0000000 --- a/packages/blocks/src/blocks/layout/locales/fr.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { LayoutMessageCatalog } from "./catalogs" - -export const locale = "fr" -export const languageTag = "fr-FR" -export const messages = { - "blocks.breadcrumb.menuLabel": "Ouvrir le menu du fil d’Ariane", - "blocks.refresh.description": "Actualiser les données de la page actuelle", - "blocks.refresh.label": "Actualiser les données de la page", - "blocks.userMenu.accountPassword": "Mot de passe du compte", - "blocks.userMenu.appearance": "Apparence", - "blocks.userMenu.keybindings": "Raccourcis clavier", - "blocks.userMenu.logout": "Se déconnecter", - "blocks.userMenu.open": "Ouvrir le menu utilisateur", - "blocks.userMenu.title": "Menu utilisateur", -} as const satisfies LayoutMessageCatalog diff --git a/packages/blocks/src/blocks/layout/locales/ja.ts b/packages/blocks/src/blocks/layout/locales/ja.ts deleted file mode 100644 index 4af6f0a..0000000 --- a/packages/blocks/src/blocks/layout/locales/ja.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { LayoutMessageCatalog } from "./catalogs" - -export const locale = "ja" -export const languageTag = "ja-JP" -export const messages = { - "blocks.breadcrumb.menuLabel": "パンくずメニューを開く", - "blocks.refresh.description": "現在のページのデータを更新します", - "blocks.refresh.label": "現在のページを更新", - "blocks.userMenu.accountPassword": "アカウントのパスワード", - "blocks.userMenu.appearance": "外観", - "blocks.userMenu.keybindings": "キーバインド", - "blocks.userMenu.logout": "ログアウト", - "blocks.userMenu.open": "ユーザーメニューを開く", - "blocks.userMenu.title": "ユーザーメニュー", -} as const satisfies LayoutMessageCatalog diff --git a/packages/blocks/src/blocks/layout/locales/ko.ts b/packages/blocks/src/blocks/layout/locales/ko.ts deleted file mode 100644 index 379e69b..0000000 --- a/packages/blocks/src/blocks/layout/locales/ko.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { LayoutMessageCatalog } from "./catalogs" - -export const locale = "ko" -export const languageTag = "ko-KR" -export const messages = { - "blocks.breadcrumb.menuLabel": "이동 경로 메뉴 열기", - "blocks.refresh.description": "현재 페이지 데이터를 새로 고칩니다", - "blocks.refresh.label": "현재 페이지 데이터 새로 고침", - "blocks.userMenu.accountPassword": "계정 비밀번호", - "blocks.userMenu.appearance": "화면 모양", - "blocks.userMenu.keybindings": "키 바인딩", - "blocks.userMenu.logout": "로그아웃", - "blocks.userMenu.open": "사용자 메뉴 열기", - "blocks.userMenu.title": "사용자 메뉴", -} as const satisfies LayoutMessageCatalog diff --git a/packages/blocks/src/blocks/layout/locales/zh-Hant.ts b/packages/blocks/src/blocks/layout/locales/zh-Hant.ts deleted file mode 100644 index 840b910..0000000 --- a/packages/blocks/src/blocks/layout/locales/zh-Hant.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { LayoutMessageCatalog } from "./catalogs" - -export const locale = "zh-Hant" -export const languageTag = "zh-TW" -export const messages = { - "blocks.breadcrumb.menuLabel": "開啟麵包屑選單", - "blocks.refresh.description": "重新整理目前頁面的資料", - "blocks.refresh.label": "重新整理目前頁面資料", - "blocks.userMenu.accountPassword": "帳號密碼", - "blocks.userMenu.appearance": "介面外觀", - "blocks.userMenu.keybindings": "按鍵綁定", - "blocks.userMenu.logout": "登出", - "blocks.userMenu.open": "開啟使用者選單", - "blocks.userMenu.title": "使用者選單", -} as const satisfies LayoutMessageCatalog diff --git a/packages/blocks/src/blocks/media/locales/catalogs.test.ts b/packages/blocks/src/blocks/media/locales/catalogs.test.ts new file mode 100644 index 0000000..3ffe1a8 --- /dev/null +++ b/packages/blocks/src/blocks/media/locales/catalogs.test.ts @@ -0,0 +1,22 @@ +import { describe, it } from "vitest" + +import { expectCompleteCatalogs } from "../../../i18n/test-catalogs" +import { mediaMessages } from "../messages" +import { mediaCatalogLocales } from "./catalogs" +import { messages as enUS } from "./en-US" +import { messages as zhHans } from "./zh-Hans" + +describe("media locale catalogs", () => { + it("ships every media message in every built-in locale", () => { + expectCompleteCatalogs({ + catalogs: { + "en-US": enUS, + "zh-Hans": zhHans, + }, + locales: mediaCatalogLocales, + messageIds: Object.values(mediaMessages).map( + (descriptor) => descriptor.id + ), + }) + }) +}) diff --git a/packages/blocks/src/blocks/media/locales/catalogs.ts b/packages/blocks/src/blocks/media/locales/catalogs.ts index 84bddbd..0d6c637 100644 --- a/packages/blocks/src/blocks/media/locales/catalogs.ts +++ b/packages/blocks/src/blocks/media/locales/catalogs.ts @@ -1,4 +1,10 @@ import type { mediaMessages } from "../messages" -import type { BlockMessageCatalog } from "../../../i18n/catalogs" +import { + blockCatalogLocales, + type BlockCatalogLocale, + type BlockMessageCatalog, +} from "../../../i18n/catalogs" +export { blockCatalogLocales as mediaCatalogLocales } +export type MediaCatalogLocale = BlockCatalogLocale export type MediaMessageCatalog = BlockMessageCatalog diff --git a/packages/blocks/src/blocks/media/locales/en.ts b/packages/blocks/src/blocks/media/locales/en-US.ts similarity index 78% rename from packages/blocks/src/blocks/media/locales/en.ts rename to packages/blocks/src/blocks/media/locales/en-US.ts index bf03a38..3d3e9ff 100644 --- a/packages/blocks/src/blocks/media/locales/en.ts +++ b/packages/blocks/src/blocks/media/locales/en-US.ts @@ -1,6 +1,6 @@ import type { MediaMessageCatalog } from "./catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" export const messages = { "blocks.media.actions.cancel": "Cancel", @@ -21,10 +21,13 @@ export const messages = { "blocks.media.actions.unfavorite": "Unfavorite", "blocks.media.actions.upload": "Upload", "blocks.media.actions.viewOriginal": "View original", - "blocks.media.copy.failed": "Copy failed. Check browser clipboard permissions.", - "blocks.media.deleteAsset.description": "This media item will no longer appear in the library.", + "blocks.media.copy.failed": + "Copy failed. Check browser clipboard permissions.", + "blocks.media.deleteAsset.description": + "This media item will no longer appear in the library.", "blocks.media.deleteAsset.title": "Delete media", - "blocks.media.deleteFolder.description": "This folder and its child folders will be deleted. Their media items will become unclassified.", + "blocks.media.deleteFolder.description": + "This folder and its child folders will be deleted. Their media items will become unclassified.", "blocks.media.deleteFolder.title": "Delete folder", "blocks.media.details.dimensions": "Dimensions", "blocks.media.details.fileName": "File name", @@ -32,7 +35,8 @@ export const messages = { "blocks.media.details.size": "Size", "blocks.media.details.type": "Type", "blocks.media.details.uploadedAt": "Uploaded", - "blocks.media.empty.description": "Upload images or videos to manage them here.", + "blocks.media.empty.description": + "Upload images or videos to manage them here.", "blocks.media.empty.title": "No media", "blocks.media.emptySearch.description": "No media files match your search.", "blocks.media.filters.all": "All media", @@ -40,7 +44,8 @@ export const messages = { "blocks.media.filters.image": "Images", "blocks.media.filters.unclassified": "Unclassified", "blocks.media.filters.video": "Videos", - "blocks.media.folders.classification": "Folders only organize media in this library and do not change file URLs.", + "blocks.media.folders.classification": + "Folders only organize media in this library and do not change file URLs.", "blocks.media.folders.create": "New folder", "blocks.media.folders.empty": "No folders yet. Create one.", "blocks.media.folders.name": "Folder name", @@ -50,11 +55,13 @@ export const messages = { "blocks.media.folders.title": "Folders", "blocks.media.load.error": "Unable to load media", "blocks.media.loading": "Loading media…", - "blocks.media.picker.description": "Choose an uploaded image or video from the media library.", + "blocks.media.picker.description": + "Choose an uploaded image or video from the media library.", "blocks.media.picker.selectedCount": "{count} selected", "blocks.media.picker.title": "Select media", "blocks.media.picker.useSelected": "Use selected media", - "blocks.media.renameMedia.description": "This changes the display name without changing the file or its URL.", + "blocks.media.renameMedia.description": + "This changes the display name without changing the file or its URL.", "blocks.media.renameMedia.title": "Rename media", "blocks.media.search": "Search media files", "blocks.media.title": "Media library", diff --git a/packages/blocks/src/blocks/media/media.test.tsx b/packages/blocks/src/blocks/media/media.test.tsx index f98bf01..4bc165a 100644 --- a/packages/blocks/src/blocks/media/media.test.tsx +++ b/packages/blocks/src/blocks/media/media.test.tsx @@ -72,7 +72,7 @@ function MediaTestProvider({ children: ReactNode }) { return ( - + {children} ) diff --git a/packages/blocks/src/blocks/navigation/locales/catalogs.test.ts b/packages/blocks/src/blocks/navigation/locales/catalogs.test.ts index 4edb225..cb392e1 100644 --- a/packages/blocks/src/blocks/navigation/locales/catalogs.test.ts +++ b/packages/blocks/src/blocks/navigation/locales/catalogs.test.ts @@ -3,27 +3,15 @@ import { describe, it } from "vitest" import { expectCompleteCatalogs } from "../../../i18n/test-catalogs" import { navigationMessages } from "../messages" import { navigationCatalogLocales } from "./catalogs" -import { messages as de } from "./de" -import { messages as en } from "./en" -import { messages as es } from "./es" -import { messages as fr } from "./fr" -import { messages as ja } from "./ja" -import { messages as ko } from "./ko" +import { messages as enUS } from "./en-US" import { messages as zhHans } from "./zh-Hans" -import { messages as zhHant } from "./zh-Hant" describe("navigation locale catalogs", () => { it("ship every navigation message in every built-in locale", () => { expectCompleteCatalogs({ catalogs: { - de, - en, - es, - fr, - ja, - ko, + "en-US": enUS, "zh-Hans": zhHans, - "zh-Hant": zhHant, }, locales: navigationCatalogLocales, messageIds: Object.values(navigationMessages).map( diff --git a/packages/blocks/src/blocks/navigation/locales/de.ts b/packages/blocks/src/blocks/navigation/locales/de.ts deleted file mode 100644 index affd3a0..0000000 --- a/packages/blocks/src/blocks/navigation/locales/de.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { NavigationMessageCatalog } from "./catalogs" - -export const locale = "de" -export const languageTag = "de-DE" -export const messages = { - "blocks.navigation.description": "Durch die Anwendung navigieren.", - "blocks.navigation.open": "Navigation öffnen", - "blocks.navigation.title": "Navigation", -} as const satisfies NavigationMessageCatalog diff --git a/packages/blocks/src/blocks/navigation/locales/en.ts b/packages/blocks/src/blocks/navigation/locales/en-US.ts similarity index 91% rename from packages/blocks/src/blocks/navigation/locales/en.ts rename to packages/blocks/src/blocks/navigation/locales/en-US.ts index fd5140a..b086c5e 100644 --- a/packages/blocks/src/blocks/navigation/locales/en.ts +++ b/packages/blocks/src/blocks/navigation/locales/en-US.ts @@ -1,6 +1,6 @@ import type { NavigationMessageCatalog } from "./catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" export const messages = { "blocks.navigation.description": "Navigate through the app.", diff --git a/packages/blocks/src/blocks/navigation/locales/es.ts b/packages/blocks/src/blocks/navigation/locales/es.ts deleted file mode 100644 index d355a56..0000000 --- a/packages/blocks/src/blocks/navigation/locales/es.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { NavigationMessageCatalog } from "./catalogs" - -export const locale = "es" -export const languageTag = "es-ES" -export const messages = { - "blocks.navigation.description": "Navega por la aplicación.", - "blocks.navigation.open": "Abrir navegación", - "blocks.navigation.title": "Navegación", -} as const satisfies NavigationMessageCatalog diff --git a/packages/blocks/src/blocks/navigation/locales/fr.ts b/packages/blocks/src/blocks/navigation/locales/fr.ts deleted file mode 100644 index be12a96..0000000 --- a/packages/blocks/src/blocks/navigation/locales/fr.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { NavigationMessageCatalog } from "./catalogs" - -export const locale = "fr" -export const languageTag = "fr-FR" -export const messages = { - "blocks.navigation.description": "Naviguez dans l’application.", - "blocks.navigation.open": "Ouvrir la navigation", - "blocks.navigation.title": "Navigation", -} as const satisfies NavigationMessageCatalog diff --git a/packages/blocks/src/blocks/navigation/locales/ja.ts b/packages/blocks/src/blocks/navigation/locales/ja.ts deleted file mode 100644 index 4255f4d..0000000 --- a/packages/blocks/src/blocks/navigation/locales/ja.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { NavigationMessageCatalog } from "./catalogs" - -export const locale = "ja" -export const languageTag = "ja-JP" -export const messages = { - "blocks.navigation.description": "アプリ内のページを移動します。", - "blocks.navigation.open": "ナビゲーションを開く", - "blocks.navigation.title": "ナビゲーション", -} as const satisfies NavigationMessageCatalog diff --git a/packages/blocks/src/blocks/navigation/locales/ko.ts b/packages/blocks/src/blocks/navigation/locales/ko.ts deleted file mode 100644 index 20462b8..0000000 --- a/packages/blocks/src/blocks/navigation/locales/ko.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { NavigationMessageCatalog } from "./catalogs" - -export const locale = "ko" -export const languageTag = "ko-KR" -export const messages = { - "blocks.navigation.description": "앱의 페이지를 탐색합니다.", - "blocks.navigation.open": "탐색 메뉴 열기", - "blocks.navigation.title": "탐색", -} as const satisfies NavigationMessageCatalog diff --git a/packages/blocks/src/blocks/navigation/locales/zh-Hant.ts b/packages/blocks/src/blocks/navigation/locales/zh-Hant.ts deleted file mode 100644 index f1801ac..0000000 --- a/packages/blocks/src/blocks/navigation/locales/zh-Hant.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { NavigationMessageCatalog } from "./catalogs" - -export const locale = "zh-Hant" -export const languageTag = "zh-TW" -export const messages = { - "blocks.navigation.description": "瀏覽應用程式中的頁面。", - "blocks.navigation.open": "開啟導覽", - "blocks.navigation.title": "導覽", -} as const satisfies NavigationMessageCatalog diff --git a/packages/blocks/src/blocks/notifications/locales/catalogs.test.ts b/packages/blocks/src/blocks/notifications/locales/catalogs.test.ts index be0b10b..52fb342 100644 --- a/packages/blocks/src/blocks/notifications/locales/catalogs.test.ts +++ b/packages/blocks/src/blocks/notifications/locales/catalogs.test.ts @@ -3,27 +3,15 @@ import { describe, it } from "vitest" import { expectCompleteCatalogs } from "../../../i18n/test-catalogs" import { notificationMessages } from "../messages" import { notificationCatalogLocales } from "./catalogs" -import { messages as de } from "./de" -import { messages as en } from "./en" -import { messages as es } from "./es" -import { messages as fr } from "./fr" -import { messages as ja } from "./ja" -import { messages as ko } from "./ko" +import { messages as enUS } from "./en-US" import { messages as zhHans } from "./zh-Hans" -import { messages as zhHant } from "./zh-Hant" describe("notification locale catalogs", () => { it("ship every notification message in every built-in locale", () => { expectCompleteCatalogs({ catalogs: { - de, - en, - es, - fr, - ja, - ko, + "en-US": enUS, "zh-Hans": zhHans, - "zh-Hant": zhHant, }, locales: notificationCatalogLocales, messageIds: Object.values(notificationMessages).map( diff --git a/packages/blocks/src/blocks/notifications/locales/de.ts b/packages/blocks/src/blocks/notifications/locales/de.ts deleted file mode 100644 index 3812578..0000000 --- a/packages/blocks/src/blocks/notifications/locales/de.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { NotificationMessageCatalog } from "./catalogs" - -export const locale = "de" -export const languageTag = "de-DE" -export const messages = { - "blocks.notifications.description": - "Benachrichtigungen anzeigen und verwalten", - "blocks.notifications.empty.description": - "Neue Aktivitäten werden hier angezeigt.", - "blocks.notifications.empty.title": "Keine Benachrichtigungen", - "blocks.notifications.error.description": - "Überprüfen Sie Ihre Netzwerkverbindung und versuchen Sie es erneut.", - "blocks.notifications.error.title": - "Benachrichtigungen konnten nicht geladen werden", - "blocks.notifications.justNow": "gerade eben", - "blocks.notifications.loading": "Benachrichtigungen werden geladen…", - "blocks.notifications.markAllAsRead": "Alle als gelesen markieren", - "blocks.notifications.retry": "Erneut versuchen", - "blocks.notifications.title": "Benachrichtigungen", - "blocks.notifications.viewAll": "Alle anzeigen", -} as const satisfies NotificationMessageCatalog diff --git a/packages/blocks/src/blocks/notifications/locales/en.ts b/packages/blocks/src/blocks/notifications/locales/en-US.ts similarity index 96% rename from packages/blocks/src/blocks/notifications/locales/en.ts rename to packages/blocks/src/blocks/notifications/locales/en-US.ts index 56c10ed..d6df211 100644 --- a/packages/blocks/src/blocks/notifications/locales/en.ts +++ b/packages/blocks/src/blocks/notifications/locales/en-US.ts @@ -1,6 +1,6 @@ import type { NotificationMessageCatalog } from "./catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" export const messages = { "blocks.notifications.description": "View and manage notifications", diff --git a/packages/blocks/src/blocks/notifications/locales/es.ts b/packages/blocks/src/blocks/notifications/locales/es.ts deleted file mode 100644 index a6139bf..0000000 --- a/packages/blocks/src/blocks/notifications/locales/es.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { NotificationMessageCatalog } from "./catalogs" - -export const locale = "es" -export const languageTag = "es-ES" -export const messages = { - "blocks.notifications.description": "Ver y gestionar notificaciones", - "blocks.notifications.empty.description": - "La actividad nueva aparecerá aquí.", - "blocks.notifications.empty.title": "No hay notificaciones", - "blocks.notifications.error.description": - "Comprueba la conexión de red e inténtalo de nuevo.", - "blocks.notifications.error.title": - "No se pudieron cargar las notificaciones", - "blocks.notifications.justNow": "ahora mismo", - "blocks.notifications.loading": "Cargando notificaciones…", - "blocks.notifications.markAllAsRead": "Marcar todo como leído", - "blocks.notifications.retry": "Intentar de nuevo", - "blocks.notifications.title": "Notificaciones", - "blocks.notifications.viewAll": "Ver todo", -} as const satisfies NotificationMessageCatalog diff --git a/packages/blocks/src/blocks/notifications/locales/fr.ts b/packages/blocks/src/blocks/notifications/locales/fr.ts deleted file mode 100644 index be409da..0000000 --- a/packages/blocks/src/blocks/notifications/locales/fr.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { NotificationMessageCatalog } from "./catalogs" - -export const locale = "fr" -export const languageTag = "fr-FR" -export const messages = { - "blocks.notifications.description": "Afficher et gérer les notifications", - "blocks.notifications.empty.description": - "Les nouvelles activités apparaîtront ici.", - "blocks.notifications.empty.title": "Aucune notification", - "blocks.notifications.error.description": - "Vérifiez votre connexion réseau et réessayez.", - "blocks.notifications.error.title": "Impossible de charger les notifications", - "blocks.notifications.justNow": "à l’instant", - "blocks.notifications.loading": "Chargement des notifications…", - "blocks.notifications.markAllAsRead": "Tout marquer comme lu", - "blocks.notifications.retry": "Réessayer", - "blocks.notifications.title": "Notifications", - "blocks.notifications.viewAll": "Tout afficher", -} as const satisfies NotificationMessageCatalog diff --git a/packages/blocks/src/blocks/notifications/locales/ja.ts b/packages/blocks/src/blocks/notifications/locales/ja.ts deleted file mode 100644 index 4806985..0000000 --- a/packages/blocks/src/blocks/notifications/locales/ja.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { NotificationMessageCatalog } from "./catalogs" - -export const locale = "ja" -export const languageTag = "ja-JP" -export const messages = { - "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": "すべて表示", -} as const satisfies NotificationMessageCatalog diff --git a/packages/blocks/src/blocks/notifications/locales/ko.ts b/packages/blocks/src/blocks/notifications/locales/ko.ts deleted file mode 100644 index decc8b9..0000000 --- a/packages/blocks/src/blocks/notifications/locales/ko.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { NotificationMessageCatalog } from "./catalogs" - -export const locale = "ko" -export const languageTag = "ko-KR" -export const messages = { - "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": "모두 보기", -} as const satisfies NotificationMessageCatalog diff --git a/packages/blocks/src/blocks/notifications/locales/zh-Hant.ts b/packages/blocks/src/blocks/notifications/locales/zh-Hant.ts deleted file mode 100644 index 3c7a583..0000000 --- a/packages/blocks/src/blocks/notifications/locales/zh-Hant.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { NotificationMessageCatalog } from "./catalogs" - -export const locale = "zh-Hant" -export const languageTag = "zh-TW" -export const messages = { - "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": "檢視全部", -} as const satisfies NotificationMessageCatalog diff --git a/packages/blocks/src/i18n/catalogs.ts b/packages/blocks/src/i18n/catalogs.ts index 868e882..8e17b83 100644 --- a/packages/blocks/src/i18n/catalogs.ts +++ b/packages/blocks/src/i18n/catalogs.ts @@ -1,13 +1,4 @@ -export const blockCatalogLocales = [ - "de", - "en", - "es", - "fr", - "ja", - "ko", - "zh-Hans", - "zh-Hant", -] as const +export const blockCatalogLocales = ["en-US", "zh-Hans"] as const interface MessageDescriptorMap { readonly [key: string]: { diff --git a/packages/blocks/src/i18n/test-catalogs.ts b/packages/blocks/src/i18n/test-catalogs.ts index 1758d96..0d424a3 100644 --- a/packages/blocks/src/i18n/test-catalogs.ts +++ b/packages/blocks/src/i18n/test-catalogs.ts @@ -11,9 +11,13 @@ export function expectCompleteCatalogs({ }) { expect(Object.keys(catalogs)).toEqual([...locales]) - const expectedIds = [...messageIds].sort() + // ES2022 compatibility: copy before sorting so the input remains immutable. + // oxlint-disable-next-line unicorn/no-array-sort + const expectedIds = Array.from(messageIds).sort() for (const messages of Object.values(catalogs)) { + // Object.keys returns a fresh array. + // oxlint-disable-next-line unicorn/no-array-sort expect(Object.keys(messages).sort()).toEqual(expectedIds) } } diff --git a/packages/i18n/README.md b/packages/i18n/README.md index cb54a11..5ea6584 100644 --- a/packages/i18n/README.md +++ b/packages/i18n/README.md @@ -28,8 +28,8 @@ Create `i18n.config.json` in that application: ```json { - "sourceLocale": "en", - "locales": ["en", "zh-Hans"], + "sourceLocale": "en-US", + "locales": ["en-US", "zh-Hans"], "catalogPath": "src/locales/{locale}/messages", "catalogSources": [ "@workspace/ui/locales/{locale}", @@ -96,7 +96,7 @@ function Root({ + {import.meta.env.DEV && } @@ -205,8 +205,7 @@ Pass a BCP 47 language tag with `locale` to select it explicitly: When `locale` is omitted, the Devtool selects the first supported entry from `navigator.languages` and falls back to English. Built-in control-panel -locales are English, German, Spanish, French, Japanese, Korean, Simplified -Chinese, and Traditional Chinese. +locales are English (`en-US`) and Simplified Chinese (`zh-Hans`). Lower-level `MessagePanel`, `MessageRepositoryProvider`, and repository types remain available from `@workspace/i18n/devtool`. @@ -222,7 +221,6 @@ Run inside the consuming application so the CLI discovers that application's `i18n.config.json`: ```sh -bun run i18n new ja bun run i18n extract bun run i18n compile bun run i18n ui @@ -249,4 +247,4 @@ bun run i18n:compile The application's `i18n.config.json` is the single machine-editable source of truth. Runtime catalog access, Devtool actions, extraction, and compilation all -derive their Lingui configuration from it. +derive their Lingui configuration from it. \ No newline at end of file diff --git a/packages/i18n/src/build/catalog-sources.test.ts b/packages/i18n/src/build/catalog-sources.test.ts index 049af14..4a99e0d 100644 --- a/packages/i18n/src/build/catalog-sources.test.ts +++ b/packages/i18n/src/build/catalog-sources.test.ts @@ -26,33 +26,39 @@ async function createProject() { catalogPath: "app/{locale}/messages", catalogSources: ["./dependency/{locale}.js"], include: ["src"], - locales: ["en", "zh-Hans"], - sourceLocale: "en", + locales: ["en-US", "zh-Hans"], + sourceLocale: "en-US", } temporaryDirectories.push(projectRoot) - for (const locale of project.locales) { - const dependencyDirectory = join(projectRoot, "dependency") - const applicationDirectory = join(projectRoot, "app", locale) + await Promise.all( + project.locales.map(async (locale) => { + const dependencyDirectory = join(projectRoot, "dependency") + const applicationDirectory = join(projectRoot, "app", locale) - await mkdir(dependencyDirectory, { recursive: true }) - await mkdir(applicationDirectory, { recursive: true }) - await writeFile( - join(dependencyDirectory, `${locale}.js`), - `export const messages = ${JSON.stringify({ - dependency: `${locale}: dependency`, - overridden: `${locale}: dependency`, - })}\n` - ) - await writeFile( - join(applicationDirectory, "messages.js"), - `export const messages = ${JSON.stringify({ - application: `${locale}: application`, - overridden: `${locale}: application`, - })}\n` - ) - } + await Promise.all([ + mkdir(dependencyDirectory, { recursive: true }), + mkdir(applicationDirectory, { recursive: true }), + ]) + await Promise.all([ + writeFile( + join(dependencyDirectory, `${locale}.js`), + `export const messages = ${JSON.stringify({ + dependency: `${locale}: dependency`, + overridden: `${locale}: dependency`, + })}\n` + ), + writeFile( + join(applicationDirectory, "messages.js"), + `export const messages = ${JSON.stringify({ + application: `${locale}: application`, + overridden: `${locale}: application`, + })}\n` + ), + ]) + }) + ) return { project, projectRoot } } @@ -63,12 +69,12 @@ describe("production catalog sources", () => { const filenames = await resolveCatalogSourceFilenames( project, projectRoot, - "en" + "en-US" ) expect(filenames).toEqual([ - join(projectRoot, "dependency", "en.js"), - join(projectRoot, "app", "en", "messages.js"), + join(projectRoot, "dependency", "en-US.js"), + join(projectRoot, "app", "en-US", "messages.js"), ]) }) @@ -76,10 +82,10 @@ describe("production catalog sources", () => { const { project, projectRoot } = await createProject() const { catalogs } = await loadProjectCatalogs(project, projectRoot) - expect(catalogs.en).toEqual({ - application: "en: application", - dependency: "en: dependency", - overridden: "en: application", + expect(catalogs["en-US"]).toEqual({ + application: "en-US: application", + dependency: "en-US: dependency", + overridden: "en-US: application", }) expect(catalogs["zh-Hans"]).toEqual({ application: "zh-Hans: application", diff --git a/packages/i18n/src/build/catalog-sources.ts b/packages/i18n/src/build/catalog-sources.ts index af5d38c..c4475c1 100644 --- a/packages/i18n/src/build/catalog-sources.ts +++ b/packages/i18n/src/build/catalog-sources.ts @@ -30,12 +30,10 @@ export async function resolveCompiledCatalogFilename( ? pathname : resolve(projectRoot, pathname) const candidates = [baseFilename, `${baseFilename}.ts`, `${baseFilename}.js`] + const availability = await Promise.all(candidates.map(fileExists)) + const candidate = candidates.find((_, index) => availability[index]) - for (const candidate of candidates) { - if (await fileExists(candidate)) { - return candidate - } - } + if (candidate) return candidate throw new Error( `Compiled i18n catalog not found for ${locale}: ${baseFilename}.{ts,js}. Run the i18n compile command before building.` diff --git a/packages/i18n/src/build/production-catalogs.ts b/packages/i18n/src/build/production-catalogs.ts index beee0d3..70a9b58 100644 --- a/packages/i18n/src/build/production-catalogs.ts +++ b/packages/i18n/src/build/production-catalogs.ts @@ -23,7 +23,8 @@ export function createMessageIdSchema( ): MessageIdSchema { const ids = Array.from( new Set(Object.values(catalogs).flatMap((catalog) => Object.keys(catalog))) - ).sort() + ) + ids.sort() const messages: Record = {} const idsByHash = new Map() diff --git a/packages/i18n/src/cli/api-plugin.ts b/packages/i18n/src/cli/api-plugin.ts index 3314413..22f39f0 100644 --- a/packages/i18n/src/cli/api-plugin.ts +++ b/packages/i18n/src/cli/api-plugin.ts @@ -1,5 +1,5 @@ import type { IncomingMessage, ServerResponse } from "node:http" -import type { ViteDevServer } from "vite" +import type { Connect, ViteDevServer } from "vite" import type { UpdateMessageInput } from "../devtool/types" import { CatalogService } from "./catalog-service.ts" @@ -43,94 +43,93 @@ export function configureI18nApi( server: ViteDevServer, projectFilename: string ) { - server.middlewares.use(async (request, response, next) => { - if (!request.url) { - next() - return - } - - const url = new URL(request.url, "http://localhost") - - if (!url.pathname.startsWith(API_PREFIX)) { - next() - return - } - - try { - if ( - request.method === "GET" && - url.pathname === `${API_PREFIX}/project` - ) { - const project = await readProject(projectFilename) - sendJson(response, 200, project) - return - } - - if ( - request.method === "GET" && - url.pathname === `${API_PREFIX}/messages` - ) { - const locale = url.searchParams.get("locale") - - if (!locale) { - sendJson(response, 400, { error: "locale is required." }) - return - } - - const service = new CatalogService(projectFilename) - sendJson(response, 200, await service.getMessages(locale)) - return - } - - if ( - request.method === "GET" && - url.pathname === `${API_PREFIX}/packages` - ) { - const service = new CatalogService(projectFilename) - sendJson(response, 200, await service.getPackages()) - return - } - - if ( - request.method === "PUT" && - url.pathname === `${API_PREFIX}/messages` - ) { - const input = await readJsonBody(request) - - if (!isUpdateMessageInput(input)) { - sendJson(response, 400, { - error: "The message update payload is invalid.", - }) - return - } - - const service = new CatalogService(projectFilename) - sendJson(response, 200, await service.updateMessage(input)) - return - } - - if ( - request.method === "POST" && - url.pathname.startsWith(`${API_PREFIX}/actions/`) - ) { - const action = url.pathname.slice(`${API_PREFIX}/actions/`.length) - - if (action !== "extract" && action !== "compile") { - sendJson(response, 404, { error: "Unknown action." }) - return - } - - const result = await runProjectLinguiCommand(projectFilename, action) - sendJson(response, 200, result) - return - } - - sendJson(response, 404, { error: "Not found." }) - } catch (error) { - sendJson(response, 500, { - error: - error instanceof Error ? error.message : "An unknown error occurred.", - }) - } + server.middlewares.use((request, response, next) => { + void handleI18nApiRequest(request, response, next, projectFilename).catch( + next + ) }) } + +async function handleI18nApiRequest( + request: IncomingMessage, + response: ServerResponse, + next: Connect.NextFunction, + projectFilename: string +) { + if (!request.url) { + next() + return + } + + const url = new URL(request.url, "http://localhost") + + if (!url.pathname.startsWith(API_PREFIX)) { + next() + return + } + + try { + if (request.method === "GET" && url.pathname === `${API_PREFIX}/project`) { + const project = await readProject(projectFilename) + sendJson(response, 200, project) + return + } + + if (request.method === "GET" && url.pathname === `${API_PREFIX}/messages`) { + const locale = url.searchParams.get("locale") + + if (!locale) { + sendJson(response, 400, { error: "locale is required." }) + return + } + + const service = new CatalogService(projectFilename) + sendJson(response, 200, await service.getMessages(locale)) + return + } + + if (request.method === "GET" && url.pathname === `${API_PREFIX}/packages`) { + const service = new CatalogService(projectFilename) + sendJson(response, 200, await service.getPackages()) + return + } + + if (request.method === "PUT" && url.pathname === `${API_PREFIX}/messages`) { + const input = await readJsonBody(request) + + if (!isUpdateMessageInput(input)) { + sendJson(response, 400, { + error: "The message update payload is invalid.", + }) + return + } + + const service = new CatalogService(projectFilename) + sendJson(response, 200, await service.updateMessage(input)) + return + } + + if ( + request.method === "POST" && + url.pathname.startsWith(`${API_PREFIX}/actions/`) + ) { + const action = url.pathname.slice(`${API_PREFIX}/actions/`.length) + + if (action !== "extract" && action !== "compile") { + sendJson(response, 404, { error: "Unknown action." }) + return + } + + const result = await runProjectLinguiCommand(projectFilename, action) + sendJson(response, 200, result) + return + } + + sendJson(response, 404, { error: "Not found." }) + } catch (error) { + sendJson(response, 500, { + error: + error instanceof Error ? error.message : "An unknown error occurred.", + }) + } +} diff --git a/packages/i18n/src/cli/catalog-service.test.ts b/packages/i18n/src/cli/catalog-service.test.ts index 3ab3661..4021e30 100644 --- a/packages/i18n/src/cli/catalog-service.test.ts +++ b/packages/i18n/src/cli/catalog-service.test.ts @@ -39,8 +39,8 @@ describe("CatalogService", () => { { catalogPath: "locales/{locale}/messages", include: ["src"], - locales: ["en", "zh-Hans"], - sourceLocale: "en", + locales: ["en-US", "zh-Hans"], + sourceLocale: "en-US", }, null, 2 @@ -54,7 +54,7 @@ describe("CatalogService", () => { throw new Error("Expected a Lingui catalog.") } - await catalog.write("en", { + await catalog.write("en-US", { "dashboard.title": { comments: ["Dashboard heading"], message: "Dashboard", @@ -113,7 +113,7 @@ describe("CatalogService", () => { 'msgstr "数据看板"' ) - const sourceMessages = await service.getMessages("en") + const sourceMessages = await service.getMessages("en-US") const applicationMessage = sourceMessages.find( (item) => item.id === "dashboard.title" ) @@ -134,7 +134,7 @@ describe("CatalogService", () => { service.updateMessage({ catalog: applicationMessage?.catalog ?? "messages", id: "dashboard.title", - locale: "en", + locale: "en-US", translation: "Customized dashboard", }) ).rejects.toThrow("must be changed in source code") @@ -142,7 +142,7 @@ describe("CatalogService", () => { const customizedDependency = await service.updateMessage({ catalog: dependencyMessage?.catalog ?? "messages", id: "ui.common.close", - locale: "en", + locale: "en-US", translation: "Dismiss", }) @@ -151,7 +151,7 @@ describe("CatalogService", () => { source: "Close", translation: "Dismiss", }) - expect(await readFile(catalog.getFilename("en"), "utf8")).toContain( + expect(await readFile(catalog.getFilename("en-US"), "utf8")).toContain( 'msgstr "Dismiss"' ) }) diff --git a/packages/i18n/src/cli/catalog-service.ts b/packages/i18n/src/cli/catalog-service.ts index bc0bd0f..b4e6daa 100644 --- a/packages/i18n/src/cli/catalog-service.ts +++ b/packages/i18n/src/cli/catalog-service.ts @@ -37,15 +37,16 @@ class PackageNameResolver { } async resolve(origins: MessageType["origin"] | undefined) { - for (const [filename] of origins ?? []) { - const packageName = await this.#findNearestPackageName( - dirname(resolve(this.#projectRoot, filename)) + const packageNames = await Promise.all( + (origins ?? []).map(([filename]) => + this.#findNearestPackageName( + dirname(resolve(this.#projectRoot, filename)) + ) ) + ) + const packageName = packageNames.find(Boolean) - if (packageName) { - return packageName - } - } + if (packageName) return packageName return this.#projectPackageName } @@ -187,27 +188,28 @@ export class CatalogService { ...Object.keys(targetCatalog), ]) - return Promise.all( - Array.from(ids) - .sort((left, right) => left.localeCompare(right)) - .map(async (id) => { - const sourceEntry = sourceCatalog[id] - const targetEntry = targetCatalog[id] - const packageName = await packageNameResolver.resolve( - sourceEntry?.origin ?? targetEntry?.origin - ) + const sortedIds = Array.from(ids) + sortedIds.sort((left, right) => left.localeCompare(right)) - return toDevtoolMessage({ - applicationPackageName, - catalog: key, - id, - locale, - packageName, - sourceEntry, - sourceLocale: config.sourceLocale, - targetEntry, - }) + return Promise.all( + sortedIds.map(async (id) => { + const sourceEntry = sourceCatalog[id] + const targetEntry = targetCatalog[id] + const packageName = await packageNameResolver.resolve( + sourceEntry?.origin ?? targetEntry?.origin + ) + + return toDevtoolMessage({ + applicationPackageName, + catalog: key, + id, + locale, + packageName, + sourceEntry, + sourceLocale: config.sourceLocale, + targetEntry, }) + }) ) }) ) diff --git a/packages/i18n/src/cli/lingui-command.test.ts b/packages/i18n/src/cli/lingui-command.test.ts index cb07a96..5573c16 100644 --- a/packages/i18n/src/cli/lingui-command.test.ts +++ b/packages/i18n/src/cli/lingui-command.test.ts @@ -30,8 +30,8 @@ describe("runProjectLinguiCommand", () => { { catalogPath: "locales/{locale}/messages", include: ["src"], - locales: ["en"], - sourceLocale: "en", + locales: ["en-US"], + sourceLocale: "en-US", }, null, 2 @@ -45,7 +45,7 @@ describe("runProjectLinguiCommand", () => { throw new Error("Expected a Lingui catalog.") } - await catalog.write("en", { + await catalog.write("en-US", { greeting: { message: "Hello", translation: "Hello", @@ -53,7 +53,7 @@ describe("runProjectLinguiCommand", () => { }) const result = await runProjectLinguiCommand(projectFilename, "compile") - const compiledFilename = join(directory, "locales/en/messages.ts") + const compiledFilename = join(directory, "locales/en-US/messages.ts") const firstModifiedTime = (await stat(compiledFilename)).mtimeMs expect(result.output).toContain("Compiling message catalogs") diff --git a/packages/i18n/src/cli/lingui-command.ts b/packages/i18n/src/cli/lingui-command.ts index 76b1727..7ba525d 100644 --- a/packages/i18n/src/cli/lingui-command.ts +++ b/packages/i18n/src/cli/lingui-command.ts @@ -83,24 +83,26 @@ async function readFileIfPresent(filename: string) { async function publishCompiledCatalogs( catalogs: readonly StagedCompiledCatalog[] ) { - for (const catalog of catalogs) { - const nextContent = await readFile(catalog.stagedOutputFilename, "utf8") - const currentContent = await readFileIfPresent(catalog.outputFilename) + await Promise.all( + catalogs.map(async (catalog) => { + const [nextContent, currentContent] = await Promise.all([ + readFile(catalog.stagedOutputFilename, "utf8"), + readFileIfPresent(catalog.outputFilename), + ]) - if (currentContent === nextContent) { - continue - } + if (currentContent === nextContent) return - await mkdir(dirname(catalog.outputFilename), { recursive: true }) - await writeFile(catalog.outputFilename, nextContent, "utf8") - } + await mkdir(dirname(catalog.outputFilename), { recursive: true }) + await writeFile(catalog.outputFilename, nextContent, "utf8") + }) + ) } async function runLinguiCommand( args: readonly string[], cwd: string ): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolvePromise, reject) => { const child = spawn("node", [LINGUI_BIN, ...args], { cwd, env: process.env, @@ -119,7 +121,7 @@ async function runLinguiCommand( child.on("error", reject) child.on("close", (code) => { if (code === 0) { - resolve({ output }) + resolvePromise({ output }) return } @@ -170,7 +172,7 @@ export async function runProjectLinguiCommand( catalogs: projectConfig.catalogs?.map((catalog) => typeof catalog === "string" ? catalog - : { ...catalog, path: stagedCatalogPath } + : Object.assign({}, catalog, { path: stagedCatalogPath }) ), } : undefined), diff --git a/packages/i18n/src/cli/project.test.ts b/packages/i18n/src/cli/project.test.ts index 480cf7b..76573f9 100644 --- a/packages/i18n/src/cli/project.test.ts +++ b/packages/i18n/src/cli/project.test.ts @@ -62,8 +62,8 @@ describe("readProject", () => { "@workspace/blocks/navigation/locales/{locale}", ], include: ["src"], - locales: ["en", "zh-Hans"], - sourceLocale: "en", + locales: ["en-US", "zh-Hans"], + sourceLocale: "en-US", })}\n` ) diff --git a/packages/i18n/src/cli/project.ts b/packages/i18n/src/cli/project.ts index 316e455..0fdafa9 100644 --- a/packages/i18n/src/cli/project.ts +++ b/packages/i18n/src/cli/project.ts @@ -60,24 +60,16 @@ function validateProjectConfig( } } -async function findInParents(startDirectory: string) { - let directory = resolve(startDirectory) +async function findInParents( + startDirectory: string +): Promise { + const directory = resolve(startDirectory) + const candidate = join(directory, PROJECT_FILENAME) - while (true) { - const candidate = join(directory, PROJECT_FILENAME) + if (await fileExists(candidate)) return candidate - if (await fileExists(candidate)) { - return candidate - } - - const parent = dirname(directory) - - if (parent === directory) { - return undefined - } - - directory = parent - } + const parent = dirname(directory) + return parent === directory ? undefined : findInParents(parent) } export async function resolveProjectFilename( diff --git a/packages/i18n/src/config/lingui-config.test.ts b/packages/i18n/src/config/lingui-config.test.ts index da52493..9a40d39 100644 --- a/packages/i18n/src/config/lingui-config.test.ts +++ b/packages/i18n/src/config/lingui-config.test.ts @@ -13,8 +13,8 @@ describe("createLinguiConfig", () => { catalogSources: ["@workspace/ui/locales/{locale}"], exclude: ["**/*.test.ts"], include: ["src"], - locales: ["en", "zh-Hans"], - sourceLocale: "en", + locales: ["en-US", "zh-Hans"], + sourceLocale: "en-US", }) ).toEqual({ catalogs: [ @@ -24,11 +24,11 @@ describe("createLinguiConfig", () => { path: "/locales/{locale}/messages", }, ], - locales: ["en", "zh-Hans"], + locales: ["en-US", "zh-Hans"], runtimeConfigModule: { Trans: ["@workspace/i18n", "Translate"], }, - sourceLocale: "en", + sourceLocale: "en-US", }) }) @@ -37,8 +37,8 @@ describe("createLinguiConfig", () => { { catalogPath: "locales/{locale}/messages", include: ["src"], - locales: ["en"], - sourceLocale: "en", + locales: ["en-US"], + sourceLocale: "en-US", }, "/workspace/apps/web" ) diff --git a/packages/i18n/src/devtool/ansi-text.test.tsx b/packages/i18n/src/devtool/ansi-text.test.tsx index 6f3c6c0..dedc911 100644 --- a/packages/i18n/src/devtool/ansi-text.test.tsx +++ b/packages/i18n/src/devtool/ansi-text.test.tsx @@ -4,16 +4,16 @@ import { describe, expect, it } from "vitest" import { AnsiText, resolveAnsiComponent } from "./ansi-text" +function TestComponent({ children }: { children?: string }) { + return {children} +} + describe("AnsiText", () => { it("resolves direct, CommonJS, and nested default exports", () => { - const Component = ({ children }: { children?: string }) => ( - {children} - ) - - expect(resolveAnsiComponent(Component)).toBe(Component) - expect(resolveAnsiComponent({ default: Component })).toBe(Component) - expect(resolveAnsiComponent({ default: { default: Component } })).toBe( - Component + expect(resolveAnsiComponent(TestComponent)).toBe(TestComponent) + expect(resolveAnsiComponent({ default: TestComponent })).toBe(TestComponent) + expect(resolveAnsiComponent({ default: { default: TestComponent } })).toBe( + TestComponent ) }) diff --git a/packages/i18n/src/devtool/app/app.tsx b/packages/i18n/src/devtool/app/app.tsx index 21ca8a4..7f7fbcb 100644 --- a/packages/i18n/src/devtool/app/app.tsx +++ b/packages/i18n/src/devtool/app/app.tsx @@ -42,7 +42,7 @@ export function DevtoolApp() { const locale = state.project.locales.find( - (locale) => locale !== state.project.sourceLocale + (candidateLocale) => candidateLocale !== state.project.sourceLocale ) ?? state.project.sourceLocale if (!state.project.locales.includes(locale)) { diff --git a/packages/i18n/src/devtool/app/index.html b/packages/i18n/src/devtool/app/index.html index 14702e5..71158d8 100644 --- a/packages/i18n/src/devtool/app/index.html +++ b/packages/i18n/src/devtool/app/index.html @@ -1,5 +1,5 @@ - + diff --git a/packages/i18n/src/devtool/app/main.tsx b/packages/i18n/src/devtool/app/main.tsx index a408b21..5408f19 100644 --- a/packages/i18n/src/devtool/app/main.tsx +++ b/packages/i18n/src/devtool/app/main.tsx @@ -2,6 +2,7 @@ import { StrictMode } from "react" import { createRoot } from "react-dom/client" import { DevtoolApp } from "./app" +// oxlint-disable-next-line import/no-unassigned-import -- Loads the standalone Devtool stylesheet. import "./styles.css" const root = document.getElementById("root") diff --git a/packages/i18n/src/devtool/devtool-localization.test.ts b/packages/i18n/src/devtool/devtool-localization.test.ts index 43be1c3..b0d5c1c 100644 --- a/packages/i18n/src/devtool/devtool-localization.test.ts +++ b/packages/i18n/src/devtool/devtool-localization.test.ts @@ -5,17 +5,18 @@ import { resolveI18nDevtoolLocale } from "./devtool-localization" describe("resolveI18nDevtoolLocale", () => { it("normalizes common BCP 47 language tags", () => { expect(resolveI18nDevtoolLocale("zh-CN")).toBe("zh-Hans") - expect(resolveI18nDevtoolLocale("zh-TW")).toBe("zh-Hant") - expect(resolveI18nDevtoolLocale("es-419")).toBe("es") + expect(resolveI18nDevtoolLocale("en-GB")).toBe("en-US") }) it("selects the first supported preferred locale", () => { expect( - resolveI18nDevtoolLocale(undefined, ["pt-BR", "fr-CA", "en-US"]) - ).toBe("fr") + resolveI18nDevtoolLocale(undefined, ["pt-BR", "fr-CA", "zh-CN"]) + ).toBe("zh-Hans") }) it("falls back to English", () => { - expect(resolveI18nDevtoolLocale(undefined, ["pt-BR"])).toBe("en") + expect(resolveI18nDevtoolLocale(undefined, ["pt-BR", "zh-TW"])).toBe( + "en-US" + ) }) }) diff --git a/packages/i18n/src/devtool/devtool-localization.tsx b/packages/i18n/src/devtool/devtool-localization.tsx index 9293225..120a9fa 100644 --- a/packages/i18n/src/devtool/devtool-localization.tsx +++ b/packages/i18n/src/devtool/devtool-localization.tsx @@ -1,15 +1,6 @@ import * as React from "react" -export const I18N_DEVTOOL_LOCALES = [ - "en", - "de", - "es", - "fr", - "ja", - "ko", - "zh-Hans", - "zh-Hant", -] as const +export const I18N_DEVTOOL_LOCALES = ["en-US", "zh-Hans"] as const export type I18nDevtoolLocale = (typeof I18N_DEVTOOL_LOCALES)[number] @@ -104,7 +95,7 @@ interface DevtoolMessages { } const messagesByLocale: Record = { - en: { + "en-US": { actions: { compile: "Compile", compileCompleted: "Compilation completed.", @@ -195,460 +186,6 @@ const messagesByLocale: Record = { open: "Open I18n Devtool", }, }, - de: { - actions: { - compile: "Kompilieren", - compileCompleted: "Kompilierung abgeschlossen.", - compileFailed: "Kompilierung fehlgeschlagen.", - compiling: "Wird kompiliert…", - enterFullscreen: "Vollbildmodus aktivieren", - exitFullscreen: "Vollbildmodus beenden", - extract: "Extrahieren", - extractCompleted: "Extraktion abgeschlossen.", - extractFailed: "Extraktion fehlgeschlagen.", - extracting: "Wird extrahiert…", - label: "Aktionen", - }, - commandOutput: { - close: "Befehlsausgabe schließen", - collapse: "Befehlsausgabe einklappen", - expand: "Befehlsausgabe ausklappen", - title: "Befehlsausgabe", - }, - locale: { - controlLabel: "Zielsprache der Nachrichten", - label: "Zielsprache", - noTargetLocales: "Keine Zielsprachen konfiguriert.", - sourceLabel: "Ausgangssprache", - }, - messagePanel: { - additionalSourceLocations: (count) => `${count} weitere Quellorte`, - chooseCopyContent: "Inhalt zum Kopieren auswählen", - collapseNamespace: (path) => `${path} einklappen`, - collapsePackage: (packageName) => `${packageName} einklappen`, - copied: "Kopiert", - copyDescriptor: "Nachrichten-Deskriptor kopieren", - copyFailed: "Kopieren fehlgeschlagen", - copyMessageId: "Nachrichten-ID kopieren", - copySource: "Quelltext kopieren", - copySourceLocation: "Quellort kopieren", - copyTranslation: "Aktuelle Übersetzung kopieren", - couldNotSave: "Speichern fehlgeschlagen", - emptyCatalog: - "Es sind noch keine Nachrichten verfügbar. Extrahieren Sie das Projekt, um diesen Katalog zu füllen.", - emptyPackage: "In diesem Paket wurden keine Nachrichten gefunden.", - expandNamespace: (path) => `${path} ausklappen`, - expandPackage: (packageName) => `${packageName} ausklappen`, - loading: (locale) => `${locale} wird geladen…`, - messageCount: (count) => `${count} Nachrichten`, - messageEditor: "Nachrichteneditor", - messageNavigation: "Nachrichtennavigation", - missingCount: (count) => `${count} fehlen`, - missingOnly: "Nur fehlende", - noMatches: "Keine Nachrichten entsprechen den aktuellen Filtern.", - noMissingMessages: "Alle Nachrichten sind übersetzt.", - noSearchResults: "Keine Nachrichten entsprechen Ihrer Suche.", - reset: "Zurücksetzen", - retry: "Erneut versuchen", - save: "Speichern", - saved: "Gespeichert", - saving: "Wird gespeichert…", - search: "Nachrichten durchsuchen", - selectMessage: - "Wählen Sie eine Nachricht aus, um ihre Übersetzung anzuzeigen und zu bearbeiten.", - source: "Quelle", - sourceLocations: "Quellorte", - translation: "Übersetzung", - translationFor: (id, locale) => `${id}: Übersetzung für ${locale}`, - unknownSourceLocation: "Unbekannter Quellort", - }, - settings: { - auto: "Automatisch", - autoTheme: "Automatisches Design", - center: "Mitte", - dark: "Dunkel", - darkTheme: "Dunkles Design", - interfaceLanguage: "Oberflächensprache", - interfaceLanguageControl: "Oberflächensprache des I18n Devtools", - label: "I18n-Devtool-Einstellungen", - left: "Links", - light: "Hell", - lightTheme: "Helles Design", - open: "I18n-Devtool-Einstellungen öffnen", - panelPosition: "Panelposition", - panelPositionControl: "Position des I18n-Devtool-Panels", - right: "Rechts", - theme: "Design", - themeControl: "I18n-Devtool-Design", - }, - trigger: { - close: "I18n Devtool schließen", - open: "I18n Devtool öffnen", - }, - }, - es: { - actions: { - compile: "Compilar", - compileCompleted: "Compilación completada.", - compileFailed: "Error de compilación.", - compiling: "Compilando…", - enterFullscreen: "Entrar en pantalla completa", - exitFullscreen: "Salir de pantalla completa", - extract: "Extraer", - extractCompleted: "Extracción completada.", - extractFailed: "Error de extracción.", - extracting: "Extrayendo…", - label: "Acciones", - }, - commandOutput: { - close: "Cerrar salida del comando", - collapse: "Contraer salida del comando", - expand: "Expandir salida del comando", - title: "Salida del comando", - }, - locale: { - controlLabel: "Idioma de destino de los mensajes", - label: "Idioma de destino", - noTargetLocales: "No hay idiomas de destino configurados.", - sourceLabel: "Idioma de origen", - }, - messagePanel: { - additionalSourceLocations: (count) => - `${count} ubicaciones de origen adicionales`, - chooseCopyContent: "Elegir contenido para copiar", - collapseNamespace: (path) => `Contraer ${path}`, - collapsePackage: (packageName) => `Contraer ${packageName}`, - copied: "Copiado", - copyDescriptor: "Copiar descriptor del mensaje", - copyFailed: "No se pudo copiar", - copyMessageId: "Copiar ID del mensaje", - copySource: "Copiar texto de origen", - copySourceLocation: "Copiar ubicación de origen", - copyTranslation: "Copiar traducción actual", - couldNotSave: "No se pudo guardar", - emptyCatalog: - "Aún no hay mensajes disponibles. Extraiga el proyecto para completar este catálogo.", - emptyPackage: "No se encontraron mensajes en este paquete.", - expandNamespace: (path) => `Expandir ${path}`, - expandPackage: (packageName) => `Expandir ${packageName}`, - loading: (locale) => `Cargando ${locale}…`, - messageCount: (count) => `${count} mensajes`, - messageEditor: "Editor de mensajes", - messageNavigation: "Navegación de mensajes", - missingCount: (count) => `${count} faltantes`, - missingOnly: "Solo faltantes", - noMatches: "Ningún mensaje coincide con los filtros actuales.", - noMissingMessages: "Todos los mensajes tienen traducción.", - noSearchResults: "Ningún mensaje coincide con la búsqueda.", - reset: "Restablecer", - retry: "Reintentar", - save: "Guardar", - saved: "Guardado", - saving: "Guardando…", - search: "Buscar mensajes", - selectMessage: "Seleccione un mensaje para ver y editar su traducción.", - source: "Origen", - sourceLocations: "Ubicaciones de origen", - translation: "Traducción", - translationFor: (id, locale) => `Traducción de ${id} para ${locale}`, - unknownSourceLocation: "Ubicación de origen desconocida", - }, - settings: { - auto: "Automático", - autoTheme: "Tema automático", - center: "Centro", - dark: "Oscuro", - darkTheme: "Tema oscuro", - interfaceLanguage: "Idioma de la interfaz", - interfaceLanguageControl: "Idioma de la interfaz de I18n Devtool", - label: "Ajustes de I18n Devtool", - left: "Izquierda", - light: "Claro", - lightTheme: "Tema claro", - open: "Abrir ajustes de I18n Devtool", - panelPosition: "Posición del panel", - panelPositionControl: "Posición del panel de I18n Devtool", - right: "Derecha", - theme: "Tema", - themeControl: "Tema de I18n Devtool", - }, - trigger: { - close: "Cerrar I18n Devtool", - open: "Abrir I18n Devtool", - }, - }, - fr: { - actions: { - compile: "Compiler", - compileCompleted: "Compilation terminée.", - compileFailed: "Échec de la compilation.", - compiling: "Compilation…", - enterFullscreen: "Passer en plein écran", - exitFullscreen: "Quitter le plein écran", - extract: "Extraire", - extractCompleted: "Extraction terminée.", - extractFailed: "Échec de l’extraction.", - extracting: "Extraction…", - label: "Actions", - }, - commandOutput: { - close: "Fermer la sortie de commande", - collapse: "Réduire la sortie de commande", - expand: "Développer la sortie de commande", - title: "Sortie de commande", - }, - locale: { - controlLabel: "Langue cible des messages", - label: "Langue cible", - noTargetLocales: "Aucune langue cible n’est configurée.", - sourceLabel: "Langue source", - }, - messagePanel: { - additionalSourceLocations: (count) => - `${count} emplacements source supplémentaires`, - chooseCopyContent: "Choisir le contenu à copier", - collapseNamespace: (path) => `Réduire ${path}`, - collapsePackage: (packageName) => `Réduire ${packageName}`, - copied: "Copié", - copyDescriptor: "Copier le descripteur du message", - copyFailed: "Échec de la copie", - copyMessageId: "Copier l’identifiant du message", - copySource: "Copier le texte source", - copySourceLocation: "Copier l’emplacement source", - copyTranslation: "Copier la traduction actuelle", - couldNotSave: "Échec de l’enregistrement", - emptyCatalog: - "Aucun message n’est encore disponible. Extrayez le projet pour remplir ce catalogue.", - emptyPackage: "Aucun message n’a été trouvé dans ce package.", - expandNamespace: (path) => `Développer ${path}`, - expandPackage: (packageName) => `Développer ${packageName}`, - loading: (locale) => `Chargement de ${locale}…`, - messageCount: (count) => `${count} messages`, - messageEditor: "Éditeur de messages", - messageNavigation: "Navigation des messages", - missingCount: (count) => `${count} manquants`, - missingOnly: "Manquants uniquement", - noMatches: "Aucun message ne correspond aux filtres actuels.", - noMissingMessages: "Tous les messages sont traduits.", - noSearchResults: "Aucun message ne correspond à votre recherche.", - reset: "Réinitialiser", - retry: "Réessayer", - save: "Enregistrer", - saved: "Enregistré", - saving: "Enregistrement…", - search: "Rechercher des messages", - selectMessage: - "Sélectionnez un message pour afficher et modifier sa traduction.", - source: "Source", - sourceLocations: "Emplacements source", - translation: "Traduction", - translationFor: (id, locale) => `Traduction de ${id} pour ${locale}`, - unknownSourceLocation: "Emplacement source inconnu", - }, - settings: { - auto: "Auto", - autoTheme: "Thème automatique", - center: "Centre", - dark: "Sombre", - darkTheme: "Thème sombre", - interfaceLanguage: "Langue de l’interface", - interfaceLanguageControl: "Langue de l’interface de l’outil I18n", - label: "Paramètres de I18n Devtool", - left: "Gauche", - light: "Clair", - lightTheme: "Thème clair", - open: "Ouvrir les paramètres de I18n Devtool", - panelPosition: "Position du panneau", - panelPositionControl: "Position du panneau I18n Devtool", - right: "Droite", - theme: "Thème", - themeControl: "Thème de I18n Devtool", - }, - trigger: { - close: "Fermer I18n Devtool", - open: "Ouvrir I18n Devtool", - }, - }, - ja: { - actions: { - compile: "コンパイル", - compileCompleted: "コンパイルが完了しました。", - compileFailed: "コンパイルに失敗しました。", - compiling: "コンパイル中…", - enterFullscreen: "全画面表示にする", - exitFullscreen: "全画面表示を終了", - extract: "抽出", - extractCompleted: "抽出が完了しました。", - extractFailed: "抽出に失敗しました。", - extracting: "抽出中…", - label: "操作", - }, - commandOutput: { - close: "コマンド出力を閉じる", - collapse: "コマンド出力を折りたたむ", - expand: "コマンド出力を展開する", - title: "コマンド出力", - }, - locale: { - controlLabel: "メッセージの翻訳先言語", - label: "翻訳先言語", - noTargetLocales: "翻訳先言語が設定されていません。", - sourceLabel: "原文言語", - }, - messagePanel: { - additionalSourceLocations: (count) => `他 ${count} 件のソース位置`, - chooseCopyContent: "コピーする内容を選択", - collapseNamespace: (path) => `${path} を折りたたむ`, - collapsePackage: (packageName) => `${packageName} を折りたたむ`, - copied: "コピーしました", - copyDescriptor: "メッセージ記述子をコピー", - copyFailed: "コピーできませんでした", - copyMessageId: "メッセージ ID をコピー", - copySource: "原文をコピー", - copySourceLocation: "ソース位置をコピー", - copyTranslation: "現在の翻訳をコピー", - couldNotSave: "保存できませんでした", - emptyCatalog: - "メッセージはまだありません。プロジェクトを抽出してカタログを作成してください。", - emptyPackage: "このパッケージにはメッセージがありません。", - expandNamespace: (path) => `${path} を展開`, - expandPackage: (packageName) => `${packageName} を展開`, - loading: (locale) => `${locale} を読み込み中…`, - messageCount: (count) => `${count} 件`, - messageEditor: "メッセージエディター", - messageNavigation: "メッセージナビゲーション", - missingCount: (count) => `未翻訳 ${count} 件`, - missingOnly: "未翻訳のみ", - noMatches: "現在のフィルターに一致するメッセージはありません。", - noMissingMessages: "すべてのメッセージが翻訳済みです。", - noSearchResults: "検索に一致するメッセージはありません。", - reset: "リセット", - retry: "再試行", - save: "保存", - saved: "保存済み", - saving: "保存中…", - search: "メッセージを検索", - selectMessage: "翻訳を表示・編集するメッセージを選択してください。", - source: "原文", - sourceLocations: "ソース位置", - translation: "翻訳", - translationFor: (id, locale) => `${id} の ${locale} 翻訳`, - unknownSourceLocation: "ソース位置不明", - }, - settings: { - auto: "自動", - autoTheme: "自動テーマ", - center: "中央", - dark: "ダーク", - darkTheme: "ダークテーマ", - interfaceLanguage: "表示言語", - interfaceLanguageControl: "I18n Devtool の表示言語", - label: "I18n Devtool の設定", - left: "左", - light: "ライト", - lightTheme: "ライトテーマ", - open: "I18n Devtool の設定を開く", - panelPosition: "パネル位置", - panelPositionControl: "I18n Devtool のパネル位置", - right: "右", - theme: "テーマ", - themeControl: "I18n Devtool のテーマ", - }, - trigger: { - close: "I18n Devtool を閉じる", - open: "I18n Devtool を開く", - }, - }, - ko: { - actions: { - compile: "컴파일", - compileCompleted: "컴파일이 완료되었습니다.", - compileFailed: "컴파일에 실패했습니다.", - compiling: "컴파일 중…", - enterFullscreen: "전체 화면으로 전환", - exitFullscreen: "전체 화면 종료", - extract: "추출", - extractCompleted: "추출이 완료되었습니다.", - extractFailed: "추출에 실패했습니다.", - extracting: "추출 중…", - label: "작업", - }, - commandOutput: { - close: "명령 출력을 닫기", - collapse: "명령 출력을 접기", - expand: "명령 출력을 펼치기", - title: "명령 출력", - }, - locale: { - controlLabel: "메시지 대상 언어", - label: "대상 언어", - noTargetLocales: "대상 언어가 설정되지 않았습니다.", - sourceLabel: "원본 언어", - }, - messagePanel: { - additionalSourceLocations: (count) => `추가 소스 위치 ${count}개`, - chooseCopyContent: "복사할 내용 선택", - collapseNamespace: (path) => `${path} 접기`, - collapsePackage: (packageName) => `${packageName} 접기`, - copied: "복사됨", - copyDescriptor: "메시지 설명자 복사", - copyFailed: "복사하지 못했습니다", - copyMessageId: "메시지 ID 복사", - copySource: "원문 복사", - copySourceLocation: "소스 위치 복사", - copyTranslation: "현재 번역 복사", - couldNotSave: "저장하지 못했습니다", - emptyCatalog: - "아직 사용할 수 있는 메시지가 없습니다. 프로젝트에서 메시지를 추출해 카탈로그를 채우세요.", - emptyPackage: "이 패키지에는 메시지가 없습니다.", - expandNamespace: (path) => `${path} 펼치기`, - expandPackage: (packageName) => `${packageName} 펼치기`, - loading: (locale) => `${locale} 불러오는 중…`, - messageCount: (count) => `${count}개 메시지`, - messageEditor: "메시지 편집기", - messageNavigation: "메시지 탐색", - missingCount: (count) => `${count}개 누락`, - missingOnly: "누락된 항목만", - noMatches: "현재 필터와 일치하는 메시지가 없습니다.", - noMissingMessages: "모든 메시지가 번역되었습니다.", - noSearchResults: "검색어와 일치하는 메시지가 없습니다.", - reset: "재설정", - retry: "다시 시도", - save: "저장", - saved: "저장됨", - saving: "저장 중…", - search: "메시지 검색", - selectMessage: "번역을 확인하고 편집할 메시지를 선택하세요.", - source: "원문", - sourceLocations: "소스 위치", - translation: "번역", - translationFor: (id, locale) => `${id}의 ${locale} 번역`, - unknownSourceLocation: "알 수 없는 소스 위치", - }, - settings: { - auto: "자동", - autoTheme: "자동 테마", - center: "가운데", - dark: "다크", - darkTheme: "다크 테마", - interfaceLanguage: "인터페이스 언어", - interfaceLanguageControl: "I18n Devtool 인터페이스 언어", - label: "I18n Devtool 설정", - left: "왼쪽", - light: "라이트", - lightTheme: "라이트 테마", - open: "I18n Devtool 설정 열기", - panelPosition: "패널 위치", - panelPositionControl: "I18n Devtool 패널 위치", - right: "오른쪽", - theme: "테마", - themeControl: "I18n Devtool 테마", - }, - trigger: { - close: "I18n Devtool 닫기", - open: "I18n Devtool 열기", - }, - }, "zh-Hans": { actions: { compile: "编译", @@ -738,103 +275,14 @@ const messagesByLocale: Record = { open: "打开 I18n 开发工具", }, }, - "zh-Hant": { - actions: { - compile: "編譯", - compileCompleted: "編譯完成。", - compileFailed: "編譯失敗。", - compiling: "正在編譯…", - enterFullscreen: "進入全螢幕", - exitFullscreen: "退出全螢幕", - extract: "擷取", - extractCompleted: "擷取完成。", - extractFailed: "擷取失敗。", - extracting: "正在擷取…", - label: "操作", - }, - commandOutput: { - close: "關閉命令輸出", - collapse: "收合命令輸出", - expand: "展開命令輸出", - title: "命令輸出", - }, - locale: { - controlLabel: "訊息目標語言", - label: "目標語言", - noTargetLocales: "尚未設定目標語言。", - sourceLabel: "來源語言", - }, - messagePanel: { - additionalSourceLocations: (count) => `另外 ${count} 個來源位置`, - chooseCopyContent: "選擇要複製的內容", - collapseNamespace: (path) => `收合 ${path}`, - collapsePackage: (packageName) => `收合 ${packageName}`, - copied: "已複製", - copyDescriptor: "複製 Message Descriptor", - copyFailed: "複製失敗", - copyMessageId: "複製 Message ID", - copySource: "複製原文", - copySourceLocation: "複製來源位置", - copyTranslation: "複製目前譯文", - couldNotSave: "儲存失敗", - emptyCatalog: "尚無可用訊息。請先擷取專案訊息以產生目錄。", - emptyPackage: "這個套件中暫無訊息。", - expandNamespace: (path) => `展開 ${path}`, - expandPackage: (packageName) => `展開 ${packageName}`, - loading: (locale) => `正在載入 ${locale}…`, - messageCount: (count) => `共 ${count} 筆`, - messageEditor: "訊息編輯器", - messageNavigation: "訊息導覽", - missingCount: (count) => `缺漏 ${count} 筆`, - missingOnly: "僅顯示缺漏項目", - noMatches: "沒有符合目前篩選條件的訊息。", - noMissingMessages: "所有訊息皆已完成翻譯。", - noSearchResults: "沒有符合搜尋內容的訊息。", - reset: "重設", - retry: "重試", - save: "儲存", - saved: "已儲存", - saving: "正在儲存…", - search: "搜尋訊息", - selectMessage: "請選擇一則訊息以檢視和編輯譯文。", - source: "原文", - sourceLocations: "來源位置", - translation: "譯文", - translationFor: (id, locale) => `${id} 的 ${locale} 翻譯`, - unknownSourceLocation: "未知來源位置", - }, - settings: { - auto: "自動", - autoTheme: "自動主題", - center: "置中", - dark: "深色", - darkTheme: "深色主題", - interfaceLanguage: "介面語言", - interfaceLanguageControl: "I18n 開發工具介面語言", - label: "I18n 開發工具設定", - left: "左側", - light: "淺色", - lightTheme: "淺色主題", - open: "開啟 I18n 開發工具設定", - panelPosition: "面板位置", - panelPositionControl: "I18n 開發工具面板位置", - right: "右側", - theme: "主題", - themeControl: "I18n 開發工具主題", - }, - trigger: { - close: "關閉 I18n 開發工具", - open: "開啟 I18n 開發工具", - }, - }, } const defaultContextValue: { locale: I18nDevtoolLocale messages: DevtoolMessages } = { - locale: "en", - messages: messagesByLocale.en, + locale: "en-US", + messages: messagesByLocale["en-US"], } const DevtoolLocalizationContext = React.createContext(defaultContextValue) @@ -847,30 +295,22 @@ function matchDevtoolLocale(locale: string): I18nDevtoolLocale | undefined { } if ( - normalizedLocale === "zh-hant" || - normalizedLocale.startsWith("zh-hant-") + normalizedLocale === "zh" || + normalizedLocale === "zh-hans" || + normalizedLocale.startsWith("zh-hans-") || + normalizedLocale === "zh-cn" || + normalizedLocale.startsWith("zh-cn-") || + normalizedLocale === "zh-sg" || + normalizedLocale.startsWith("zh-sg-") ) { - return "zh-Hant" - } - - if ( - normalizedLocale === "zh-tw" || - normalizedLocale.startsWith("zh-tw-") || - normalizedLocale === "zh-hk" || - normalizedLocale.startsWith("zh-hk-") || - normalizedLocale === "zh-mo" || - normalizedLocale.startsWith("zh-mo-") - ) { - return "zh-Hant" - } - - if (normalizedLocale === "zh" || normalizedLocale.startsWith("zh-")) { return "zh-Hans" } - const language = normalizedLocale.split("-")[0] + if (normalizedLocale === "en" || normalizedLocale.startsWith("en-")) { + return "en-US" + } - return I18N_DEVTOOL_LOCALES.find((candidate) => candidate === language) + return undefined } function getNavigatorLocales() { @@ -899,7 +339,7 @@ export function resolveI18nDevtoolLocale( } } - return "en" + return "en-US" } export function getI18nDevtoolMessages(locale: I18nDevtoolLocale) { diff --git a/packages/i18n/src/devtool/i18n-devtool.test.tsx b/packages/i18n/src/devtool/i18n-devtool.test.tsx index 8028bb5..3afc3bd 100644 --- a/packages/i18n/src/devtool/i18n-devtool.test.tsx +++ b/packages/i18n/src/devtool/i18n-devtool.test.tsx @@ -24,7 +24,7 @@ afterEach(() => { function renderDevtool(props?: I18nDevtoolProps) { return render( - + ) @@ -87,17 +87,17 @@ describe("I18nDevtool", () => { it("detects the first supported navigator locale", async () => { vi.spyOn(window.navigator, "languages", "get").mockReturnValue([ "pt-BR", - "ja-JP", + "fr-CA", "en-US", ]) renderDevtool() const trigger = await screen.findByRole("button", { - name: "I18n Devtool を開く", + name: "Open I18n Devtool", }) const devtool = trigger.closest('[data-slot="i18n-devtool"]') - expect(devtool?.getAttribute("lang")).toBe("ja") + expect(devtool?.getAttribute("lang")).toBe("en-US") }) it("falls back to English when an explicit locale is unsupported", async () => { @@ -109,7 +109,7 @@ describe("I18nDevtool", () => { }) const devtool = trigger.closest('[data-slot="i18n-devtool"]') - expect(devtool?.getAttribute("lang")).toBe("en") + expect(devtool?.getAttribute("lang")).toBe("en-US") }) it("includes the project source locale as a customization target", async () => { @@ -118,7 +118,7 @@ describe("I18nDevtool", () => { vi.fn(async (input: RequestInfo | URL) => { const url = String(input) const body = url.endsWith("/project") - ? { locales: ["en", "zh-Hans"], sourceLocale: "en" } + ? { locales: ["en-US", "zh-Hans"], sourceLocale: "en-US" } : [] return new Response(JSON.stringify(body), { @@ -130,10 +130,10 @@ describe("I18nDevtool", () => { render( @@ -146,7 +146,7 @@ describe("I18nDevtool", () => { }) await waitFor(() => { - expect(localeSelect).toHaveProperty("value", "en") + expect(localeSelect).toHaveProperty("value", "en-US") }) expect(screen.getByText("Source locale")).toBeTruthy() expect(screen.getByText("English", { selector: "output" })).toBeTruthy() @@ -157,9 +157,9 @@ describe("I18nDevtool", () => { it("tracks the configured document dark-mode class", async () => { render( diff --git a/packages/i18n/src/devtool/message-panel.test.tsx b/packages/i18n/src/devtool/message-panel.test.tsx index 0cff36a..697ec94 100644 --- a/packages/i18n/src/devtool/message-panel.test.tsx +++ b/packages/i18n/src/devtool/message-panel.test.tsx @@ -24,7 +24,7 @@ const message: DevtoolMessage = { origins: [{ file: "src/navigation.tsx", line: 12 }], packageName: "@workspace/ui", source: "Home", - sourceLocale: "en", + sourceLocale: "en-US", translation: "", } @@ -310,10 +310,10 @@ describe("MessagePanel", () => { updateMessage, } - render() + render() const textarea = await screen.findByLabelText( - "navigation.home translation for en" + "navigation.home translation for en-US" ) expect(textarea).toHaveProperty("readOnly", true) diff --git a/packages/i18n/src/runtime/i18n-provider.tsx b/packages/i18n/src/runtime/i18n-provider.tsx index 6a91ad8..bc789a3 100644 --- a/packages/i18n/src/runtime/i18n-provider.tsx +++ b/packages/i18n/src/runtime/i18n-provider.tsx @@ -62,14 +62,13 @@ function normalizeLocales( const definition = typeof input === "string" ? { locale: input } : input const languageTag = definition.languageTag ?? definition.locale - return { - ...definition, + return Object.assign({}, definition, { direction: definition.direction ?? inferLocaleDirection(languageTag), label: definition.label ?? getLocaleDisplayName(languageTag, definition.locale), languageTag, - } + }) }) if (!definitions.some((definition) => definition.locale === locale)) { diff --git a/packages/i18n/src/runtime/runtime.test.tsx b/packages/i18n/src/runtime/runtime.test.tsx index b4dd632..2f0a232 100644 --- a/packages/i18n/src/runtime/runtime.test.tsx +++ b/packages/i18n/src/runtime/runtime.test.tsx @@ -17,7 +17,7 @@ import { LocalizedText } from "./localized-text" import { Translate } from "./translate" const catalogs = { - en: { + "en-US": { greeting: "Hello", }, "zh-Hans": { @@ -39,6 +39,43 @@ function HookProbe() { ) } +function DirectionProbe() { + return {useLocales()[0]?.direction} +} + +function LocaleLabelsProbe() { + return ( + + {useLocales() + .map((locale) => locale.label) + .join("|")} + + ) +} + +function LocaleProbe() { + const locale = useLocaleDefinition() + + return ( + + {locale.locale}|{locale.languageTag} + + ) +} + +function FormatterProbe() { + const formatters = useFormatters() + + return ( + + {formatters.formatNumber(1234.5)}| + {formatters.formatCurrency(1234.5, "USD")}| + {formatters.formatList(["A", "B", "C"])}| + {formatters.formatRelativeTime(-1, "day", { numeric: "auto" })} + + ) +} + describe("i18n runtime", () => { it("provides locale information and reactive translation helpers", () => { render( @@ -46,7 +83,7 @@ describe("i18n runtime", () => { catalogs={catalogs} locale="zh-Hans" locales={[ - { label: "English", locale: "en" }, + { label: "English", locale: "en-US" }, { label: "简体中文", locale: "zh-Hans" }, ]} > @@ -54,7 +91,7 @@ describe("i18n runtime", () => { ) - expect(screen.getByText("zh-Hans|en,zh-Hans|你好|你好")).toBeTruthy() + expect(screen.getByText("zh-Hans|en-US,zh-Hans|你好|你好")).toBeTruthy() }) it("merges package catalogs and lets application catalogs override them", () => { @@ -87,7 +124,7 @@ describe("i18n runtime", () => { it("wraps Lingui Trans without adding a DOM element", () => { const { container } = render( - +

@@ -110,10 +147,6 @@ describe("i18n runtime", () => { }) it("infers right-to-left locale direction", () => { - function DirectionProbe() { - return {useLocales()[0]?.direction} - } - render( @@ -124,36 +157,16 @@ describe("i18n runtime", () => { }) it("uses localized language names when locale labels are omitted", () => { - function LocaleLabelsProbe() { - return ( - - {useLocales() - .map((locale) => locale.label) - .join("|")} - - ) - } - render( - + ) - expect(screen.getByText("English|简体中文")).toBeTruthy() + expect(screen.getByText("American English|简体中文")).toBeTruthy() }) it("keeps catalog locales separate from Intl language tags", () => { - function LocaleProbe() { - const locale = useLocaleDefinition() - - return ( - - {locale.locale}|{locale.languageTag} - - ) - } - render( { }) it("formats standard internationalized values through Intl", () => { - function FormatterProbe() { - const formatters = useFormatters() - - return ( - - {formatters.formatNumber(1234.5)}| - {formatters.formatCurrency(1234.5, "USD")}| - {formatters.formatList(["A", "B", "C"])}| - {formatters.formatRelativeTime(-1, "day", { numeric: "auto" })} - - ) - } - render( diff --git a/packages/i18n/src/vite.ts b/packages/i18n/src/vite.ts index b677ec3..d950c60 100644 --- a/packages/i18n/src/vite.ts +++ b/packages/i18n/src/vite.ts @@ -139,6 +139,8 @@ ${createCatalogLoaderRuntime(`(async () => { function replaceMessageIds(code: string, schema: MessageIdSchema) { let transformedCode = code + // ES2022 compatibility: Object.entries returns a fresh array. + // oxlint-disable-next-line unicorn/no-array-sort for (const [id, compactId] of Object.entries(schema.messages).sort( ([left], [right]) => right.length - left.length )) { diff --git a/packages/lexical/src/locales/catalogs.test.ts b/packages/lexical/src/locales/catalogs.test.ts index 3621e20..8b75094 100644 --- a/packages/lexical/src/locales/catalogs.test.ts +++ b/packages/lexical/src/locales/catalogs.test.ts @@ -1,16 +1,19 @@ import { describe, expect, it } from "vitest" import { lexicalMessages } from "../messages" -import { messages as en } from "./en" +import { messages as enUS } from "./en-US" import { messages as zhHans } from "./zh-Hans" describe("Lexical locale catalogs", () => { it("ships every built-in message in every locale", () => { - const messageIds = Object.values(lexicalMessages) - .map((descriptor) => descriptor.id) - .sort() + const messageIds = Object.values(lexicalMessages).map( + (descriptor) => descriptor.id + ) + messageIds.sort() - for (const messages of [en, zhHans]) { + for (const messages of [enUS, zhHans]) { + // Object.keys returns a fresh array. + // oxlint-disable-next-line unicorn/no-array-sort expect(Object.keys(messages).sort()).toEqual(messageIds) } }) diff --git a/packages/lexical/src/locales/catalogs.ts b/packages/lexical/src/locales/catalogs.ts index b1a13a0..8b3c693 100644 --- a/packages/lexical/src/locales/catalogs.ts +++ b/packages/lexical/src/locales/catalogs.ts @@ -1,6 +1,6 @@ import type { lexicalMessages } from "../messages" -export const lexicalCatalogLocales = ["en", "zh-Hans"] as const +export const lexicalCatalogLocales = ["en-US", "zh-Hans"] as const type LexicalMessageId = (typeof lexicalMessages)[keyof typeof lexicalMessages]["id"] diff --git a/packages/lexical/src/locales/en.ts b/packages/lexical/src/locales/en-US.ts similarity index 99% rename from packages/lexical/src/locales/en.ts rename to packages/lexical/src/locales/en-US.ts index 138f38f..e3bea49 100644 --- a/packages/lexical/src/locales/en.ts +++ b/packages/lexical/src/locales/en-US.ts @@ -1,6 +1,6 @@ import type { LexicalMessageCatalog } from "./catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" export const messages = { diff --git a/packages/lexical/src/root.tsx b/packages/lexical/src/root.tsx index 4b62547..a066f53 100644 --- a/packages/lexical/src/root.tsx +++ b/packages/lexical/src/root.tsx @@ -16,7 +16,7 @@ import { findLexicalActions, } from "./action-declarations" import { LexicalActionsProvider } from "./actions-context" -import { messages as englishMessages } from "./locales/en" +import { messages as englishMessages } from "./locales/en-US" const pluginKeys = new WeakMap() let nextPluginKey = 0 @@ -46,7 +46,7 @@ function LexicalI18nBoundary({ children }: { children: ReactNode }) { if (hasI18nProvider) return children return ( - + {children} ) diff --git a/packages/ui/src/i18n/catalogs.ts b/packages/ui/src/i18n/catalogs.ts index 26c9420..7390ba6 100644 --- a/packages/ui/src/i18n/catalogs.ts +++ b/packages/ui/src/i18n/catalogs.ts @@ -1,13 +1,4 @@ -export const uiCatalogLocales = [ - "de", - "en", - "es", - "fr", - "ja", - "ko", - "zh-Hans", - "zh-Hant", -] as const +export const uiCatalogLocales = ["en-US", "zh-Hans"] as const export const uiMessageIds = [ "ui.breadcrumb.label", diff --git a/packages/ui/src/i18n/locales/de.ts b/packages/ui/src/i18n/locales/de.ts deleted file mode 100644 index 7000158..0000000 --- a/packages/ui/src/i18n/locales/de.ts +++ /dev/null @@ -1,25 +0,0 @@ -export { de as calendarLocale } from "react-day-picker/locale/de" - -import type { UiMessageCatalog } from "../catalogs" - -export const locale = "de" -export const languageTag = "de-DE" - -export const messages = { - "ui.breadcrumb.label": "Breadcrumb-Navigation", - "ui.carousel.nextSlide": "Nächste Folie", - "ui.carousel.previousSlide": "Vorherige Folie", - "ui.common.close": "Schließen", - "ui.common.loading": "Wird geladen", - "ui.common.more": "Mehr", - "ui.pagination.label": "Seitennavigation", - "ui.pagination.more": "Weitere Seiten", - "ui.pagination.next": "Weiter", - "ui.pagination.nextPage": "Zur nächsten Seite", - "ui.pagination.previous": "Zurück", - "ui.pagination.previousPage": "Zur vorherigen Seite", - "ui.sidebar.description": "Zeigt die mobile Seitenleiste an.", - "ui.sidebar.title": "Seitenleiste", - "ui.sidebar.toggle": "Seitenleiste umschalten", - "ui.toast.close": "Benachrichtigung schließen", -} as const satisfies UiMessageCatalog diff --git a/packages/ui/src/i18n/locales/en.ts b/packages/ui/src/i18n/locales/en-US.ts similarity index 96% rename from packages/ui/src/i18n/locales/en.ts rename to packages/ui/src/i18n/locales/en-US.ts index cf3f2dc..2bbf77e 100644 --- a/packages/ui/src/i18n/locales/en.ts +++ b/packages/ui/src/i18n/locales/en-US.ts @@ -2,7 +2,7 @@ export { enUS as calendarLocale } from "react-day-picker/locale/en-US" import type { UiMessageCatalog } from "../catalogs" -export const locale = "en" +export const locale = "en-US" export const languageTag = "en-US" export const messages = { diff --git a/packages/ui/src/i18n/locales/es.ts b/packages/ui/src/i18n/locales/es.ts deleted file mode 100644 index c3d53a7..0000000 --- a/packages/ui/src/i18n/locales/es.ts +++ /dev/null @@ -1,25 +0,0 @@ -export { es as calendarLocale } from "react-day-picker/locale/es" - -import type { UiMessageCatalog } from "../catalogs" - -export const locale = "es" -export const languageTag = "es-ES" - -export const messages = { - "ui.breadcrumb.label": "Ruta de navegación", - "ui.carousel.nextSlide": "Diapositiva siguiente", - "ui.carousel.previousSlide": "Diapositiva anterior", - "ui.common.close": "Cerrar", - "ui.common.loading": "Cargando", - "ui.common.more": "Más", - "ui.pagination.label": "Paginación", - "ui.pagination.more": "Más páginas", - "ui.pagination.next": "Siguiente", - "ui.pagination.nextPage": "Ir a la página siguiente", - "ui.pagination.previous": "Anterior", - "ui.pagination.previousPage": "Ir a la página anterior", - "ui.sidebar.description": "Muestra la barra lateral móvil.", - "ui.sidebar.title": "Barra lateral", - "ui.sidebar.toggle": "Alternar barra lateral", - "ui.toast.close": "Cerrar notificación", -} as const satisfies UiMessageCatalog diff --git a/packages/ui/src/i18n/locales/fr.ts b/packages/ui/src/i18n/locales/fr.ts deleted file mode 100644 index 8f11a08..0000000 --- a/packages/ui/src/i18n/locales/fr.ts +++ /dev/null @@ -1,25 +0,0 @@ -export { fr as calendarLocale } from "react-day-picker/locale/fr" - -import type { UiMessageCatalog } from "../catalogs" - -export const locale = "fr" -export const languageTag = "fr-FR" - -export const messages = { - "ui.breadcrumb.label": "Fil d’Ariane", - "ui.carousel.nextSlide": "Diapositive suivante", - "ui.carousel.previousSlide": "Diapositive précédente", - "ui.common.close": "Fermer", - "ui.common.loading": "Chargement", - "ui.common.more": "Plus", - "ui.pagination.label": "Pagination", - "ui.pagination.more": "Plus de pages", - "ui.pagination.next": "Suivant", - "ui.pagination.nextPage": "Aller à la page suivante", - "ui.pagination.previous": "Précédent", - "ui.pagination.previousPage": "Aller à la page précédente", - "ui.sidebar.description": "Affiche la barre latérale mobile.", - "ui.sidebar.title": "Barre latérale", - "ui.sidebar.toggle": "Afficher ou masquer la barre latérale", - "ui.toast.close": "Fermer la notification", -} as const satisfies UiMessageCatalog diff --git a/packages/ui/src/i18n/locales/ja.ts b/packages/ui/src/i18n/locales/ja.ts deleted file mode 100644 index 365477d..0000000 --- a/packages/ui/src/i18n/locales/ja.ts +++ /dev/null @@ -1,25 +0,0 @@ -export { ja as calendarLocale } from "react-day-picker/locale/ja" - -import type { UiMessageCatalog } from "../catalogs" - -export const locale = "ja" -export const languageTag = "ja-JP" - -export const messages = { - "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 const satisfies UiMessageCatalog diff --git a/packages/ui/src/i18n/locales/ko.ts b/packages/ui/src/i18n/locales/ko.ts deleted file mode 100644 index 1d0a555..0000000 --- a/packages/ui/src/i18n/locales/ko.ts +++ /dev/null @@ -1,25 +0,0 @@ -export { ko as calendarLocale } from "react-day-picker/locale/ko" - -import type { UiMessageCatalog } from "../catalogs" - -export const locale = "ko" -export const languageTag = "ko-KR" - -export const messages = { - "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 const satisfies UiMessageCatalog diff --git a/packages/ui/src/i18n/locales/zh-Hant.ts b/packages/ui/src/i18n/locales/zh-Hant.ts deleted file mode 100644 index 60239ea..0000000 --- a/packages/ui/src/i18n/locales/zh-Hant.ts +++ /dev/null @@ -1,25 +0,0 @@ -export { zhTW as calendarLocale } from "react-day-picker/locale/zh-TW" - -import type { UiMessageCatalog } from "../catalogs" - -export const locale = "zh-Hant" -export const languageTag = "zh-TW" - -export const messages = { - "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 const satisfies UiMessageCatalog