Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
8f31b305
authored
Jul 07, 2026
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(i18n): standardize locale formatting for Intl APIs
parent
5cbb7b0b
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
35 additions
and
7 deletions
+35
-7
web/default/src/components/language-switcher.tsx
+0
-1
web/default/src/features/channels/components/channels-columns.tsx
+3
-2
web/default/src/features/dashboard/components/models/log-stat-cards.tsx
+2
-1
web/default/src/features/system-info/components/system-instances-panel.tsx
+2
-1
web/default/src/features/system-info/components/system-tasks-panel.tsx
+2
-1
web/default/src/i18n/languages.ts
+26
-1
No files found.
web/default/src/components/language-switcher.tsx
View file @
8f31b305
...
@@ -39,7 +39,6 @@ export function LanguageSwitcher() {
...
@@ -39,7 +39,6 @@ export function LanguageSwitcher() {
const
{
i18n
,
t
}
=
useTranslation
()
const
{
i18n
,
t
}
=
useTranslation
()
const
user
=
useAuthStore
((
s
)
=>
s
.
auth
.
user
)
const
user
=
useAuthStore
((
s
)
=>
s
.
auth
.
user
)
const
currentLanguage
=
normalizeInterfaceLanguage
(
i18n
.
language
)
const
currentLanguage
=
normalizeInterfaceLanguage
(
i18n
.
language
)
console
.
log
(
'Current interface language: %s'
,
currentLanguage
)
const
handleChangeLanguage
=
useCallback
(
const
handleChangeLanguage
=
useCallback
(
async
(
code
:
string
)
=>
{
async
(
code
:
string
)
=>
{
await
i18n
.
changeLanguage
(
code
)
await
i18n
.
changeLanguage
(
code
)
...
...
web/default/src/features/channels/components/channels-columns.tsx
View file @
8f31b305
...
@@ -51,6 +51,7 @@ import {
...
@@ -51,6 +51,7 @@ import {
formatQuotaWithCurrency
,
formatQuotaWithCurrency
,
getCurrencyLabel
,
getCurrencyLabel
,
}
from
'@/lib/currency'
}
from
'@/lib/currency'
import
{
toIntlLocale
}
from
'@/i18n/languages'
import
{
formatTimestampToDate
}
from
'@/lib/format'
import
{
formatTimestampToDate
}
from
'@/lib/format'
import
{
truncateText
}
from
'@/lib/utils'
import
{
truncateText
}
from
'@/lib/utils'
...
@@ -310,7 +311,7 @@ function BalanceCell({ channel }: { channel: Channel }) {
...
@@ -310,7 +311,7 @@ function BalanceCell({ channel }: { channel: Channel }) {
const
withSuffix
=
(
value
:
string
)
=>
const
withSuffix
=
(
value
:
string
)
=>
tokenSuffix
&&
value
!==
'-'
?
`
${
value
}${
tokenSuffix
}
`
:
value
tokenSuffix
&&
value
!==
'-'
?
`
${
value
}${
tokenSuffix
}
`
:
value
const
locale
=
i18n
.
resolvedLanguage
||
i18n
.
language
const
locale
=
toIntlLocale
(
i18n
.
resolvedLanguage
||
i18n
.
language
)
const
balanceFormatOptions
=
{
const
balanceFormatOptions
=
{
digitsLarge
:
2
,
digitsLarge
:
2
,
digitsSmall
:
4
,
digitsSmall
:
4
,
...
@@ -519,7 +520,7 @@ export function useChannelsColumns(
...
@@ -519,7 +520,7 @@ export function useChannelsColumns(
const
{
t
,
i18n
}
=
useTranslation
()
const
{
t
,
i18n
}
=
useTranslation
()
const
{
sensitiveVisible
}
=
useChannels
()
const
{
sensitiveVisible
}
=
useChannels
()
const
enableSelection
=
options
.
enableSelection
??
true
const
enableSelection
=
options
.
enableSelection
??
true
const
locale
=
i18n
.
resolvedLanguage
||
i18n
.
language
const
locale
=
toIntlLocale
(
i18n
.
resolvedLanguage
||
i18n
.
language
)
// The column definitions only depend on the translation function, the active
// The column definitions only depend on the translation function, the active
// locale, and sensitive-data visibility. Memoizing keeps the array (and every
// locale, and sensitive-data visibility. Memoizing keeps the array (and every
// cell renderer reference) stable across unrelated re-renders, so react-table
// cell renderer reference) stable across unrelated re-renders, so react-table
...
...
web/default/src/features/dashboard/components/models/log-stat-cards.tsx
View file @
8f31b305
...
@@ -31,6 +31,7 @@ import type {
...
@@ -31,6 +31,7 @@ import type {
QuotaDataItem
,
QuotaDataItem
,
DashboardFilters
,
DashboardFilters
,
}
from
'@/features/dashboard/types'
}
from
'@/features/dashboard/types'
import
{
toIntlLocale
}
from
'@/i18n/languages'
import
{
formatCompactNumber
,
formatNumber
,
formatQuota
}
from
'@/lib/format'
import
{
formatCompactNumber
,
formatNumber
,
formatQuota
}
from
'@/lib/format'
import
{
computeTimeRange
}
from
'@/lib/time'
import
{
computeTimeRange
}
from
'@/lib/time'
import
{
cn
}
from
'@/lib/utils'
import
{
cn
}
from
'@/lib/utils'
...
@@ -121,7 +122,7 @@ export function LogStatCards(props: LogStatCardsProps) {
...
@@ -121,7 +122,7 @@ export function LogStatCards(props: LogStatCardsProps) {
const
items
=
statCardsConfig
.
map
((
config
)
=>
{
const
items
=
statCardsConfig
.
map
((
config
)
=>
{
const
rawValue
=
config
.
getValue
(
adaptedStats
,
timeRangeMinutes
)
const
rawValue
=
config
.
getValue
(
adaptedStats
,
timeRangeMinutes
)
const
locale
=
i18n
.
resolvedLanguage
||
i18n
.
language
const
locale
=
toIntlLocale
(
i18n
.
resolvedLanguage
||
i18n
.
language
)
const
formatted
=
const
formatted
=
config
.
key
===
'quota'
config
.
key
===
'quota'
?
{
?
{
...
...
web/default/src/features/system-info/components/system-instances-panel.tsx
View file @
8f31b305
...
@@ -47,6 +47,7 @@ import {
...
@@ -47,6 +47,7 @@ import {
TooltipProvider
,
TooltipProvider
,
TooltipTrigger
,
TooltipTrigger
,
}
from
'@/components/ui/tooltip'
}
from
'@/components/ui/tooltip'
import
{
toIntlLocale
}
from
'@/i18n/languages'
import
{
formatTimestampRelative
,
formatTimestampToDate
}
from
'@/lib/format'
import
{
formatTimestampRelative
,
formatTimestampToDate
}
from
'@/lib/format'
import
{
cn
}
from
'@/lib/utils'
import
{
cn
}
from
'@/lib/utils'
...
@@ -411,7 +412,7 @@ function SystemInstancesList(props: SystemInstancesTableProps) {
...
@@ -411,7 +412,7 @@ function SystemInstancesList(props: SystemInstancesTableProps) {
{
formatTimestampRelative
(
{
formatTimestampRelative
(
instance
.
last_seen_at
,
instance
.
last_seen_at
,
'seconds'
,
'seconds'
,
i18n
.
language
toIntlLocale
(
i18n
.
language
)
)
}
)
}
</
TableCell
>
</
TableCell
>
</
TableRow
>
</
TableRow
>
...
...
web/default/src/features/system-info/components/system-tasks-panel.tsx
View file @
8f31b305
...
@@ -38,6 +38,7 @@ import type {
...
@@ -38,6 +38,7 @@ import type {
SystemTask
,
SystemTask
,
SystemTaskStatus
,
SystemTaskStatus
,
}
from
'@/features/system-settings/types'
}
from
'@/features/system-settings/types'
import
{
toIntlLocale
}
from
'@/i18n/languages'
import
{
formatTimestampRelative
,
formatTimestampToDate
}
from
'@/lib/format'
import
{
formatTimestampRelative
,
formatTimestampToDate
}
from
'@/lib/format'
import
{
cn
}
from
'@/lib/utils'
import
{
cn
}
from
'@/lib/utils'
...
@@ -185,7 +186,7 @@ function SystemTasksTable(props: SystemTasksTableProps) {
...
@@ -185,7 +186,7 @@ function SystemTasksTable(props: SystemTasksTableProps) {
{
formatTimestampRelative
(
{
formatTimestampRelative
(
task
.
updated_at
,
task
.
updated_at
,
'seconds'
,
'seconds'
,
i18n
.
language
toIntlLocale
(
i18n
.
language
)
)
}
)
}
</
TableCell
>
</
TableCell
>
<
TableCell
<
TableCell
...
...
web/default/src/i18n/languages.ts
View file @
8f31b305
...
@@ -41,8 +41,33 @@ export function normalizeInterfaceLanguage(value?: string | null): string {
...
@@ -41,8 +41,33 @@ export function normalizeInterfaceLanguage(value?: string | null): string {
normalized
=
'zhCN'
normalized
=
'zhCN'
}
}
console
.
log
(
'Normalized interface language: %s -> %s'
,
value
,
normalized
)
return
INTERFACE_LANGUAGE_OPTIONS
.
some
((
lang
)
=>
lang
.
code
===
normalized
)
return
INTERFACE_LANGUAGE_OPTIONS
.
some
((
lang
)
=>
lang
.
code
===
normalized
)
?
normalized
?
normalized
:
'en'
:
'en'
}
}
/**
* Convert an interface language code (the values i18next uses, such as `zhCN` /
* `zhTW`) into a valid BCP-47 locale tag that the `Intl.*` APIs accept.
*
* `new Intl.NumberFormat('zhCN')` throws `RangeError: Invalid language tag`, so
* any locale derived from `i18n.language` / `i18n.resolvedLanguage` MUST be run
* through this before it reaches an `Intl` constructor. Unknown values fall back
* to `undefined`, which makes `Intl` use the runtime default locale.
*/
export
function
toIntlLocale
(
value
?:
string
|
null
):
string
|
undefined
{
if
(
!
value
)
return
undefined
switch
(
value
)
{
case
'zhCN'
:
return
'zh-CN'
case
'zhTW'
:
return
'zh-TW'
default
:
break
}
try
{
return
Intl
.
getCanonicalLocales
(
value
)[
0
]
}
catch
{
return
undefined
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment