Fix/23066 i18n related commands are broken (#23071)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
crazywoola
2025-07-28 21:25:18 +08:00
committed by GitHub
parent 572a2bbe53
commit 5f550126b3
6 changed files with 8 additions and 204 deletions

View File

@@ -1,175 +0,0 @@
'use client'
import { loadLangResources } from '@/i18n-config/i18next-config'
import { useCallback, useEffect, useState } from 'react'
import cn from '@/utils/classnames'
import { LanguagesSupported } from '@/i18n-config/language'
export default function I18nTest() {
const [langs, setLangs] = useState<Lang[]>([])
const getLangs = useCallback(async () => {
const langs = await genLangs()
setLangs(langs)
}, [])
useEffect(() => {
getLangs()
}, [])
return (
<div
style={{
height: 'calc(100% - 6em)',
overflowY: 'auto',
margin: '1em 1em 5em',
}}
>
<div style={{ minHeight: '75vh' }}>
<h2>Summary</h2>
<table
className={cn('mt-2 min-w-[340px] border-collapse border-0')}
>
<thead className="system-xs-medium-uppercase text-text-tertiary">
<tr>
<td className="w-5 min-w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1">
#
</td>
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3">
lang
</td>
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3">
count
</td>
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3">
missing
</td>
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3">
extra
</td>
</tr>
</thead>
<tbody className="system-sm-regular text-text-secondary">
{langs.map(({ locale, count, missing, extra }, idx) => <tr key={locale}>
<td className="">{idx}</td>
<td className="p-1.5">{locale}</td>
<td>{count}</td>
<td>{missing.length}</td>
<td>{extra.length}</td>
</tr>)}
</tbody>
</table>
</div>
<h2>Details</h2>
<table
className={cn('mt-2 w-full min-w-[340px] border-collapse border-0')}
>
<thead className="system-xs-medium-uppercase text-text-tertiary">
<tr>
<td className="w-5 min-w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1">
#
</td>
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3">
lang
</td>
<td className="w-full whitespace-nowrap bg-background-section-burn py-1.5 pl-3">
missing
</td>
<td className="w-full whitespace-nowrap bg-background-section-burn py-1.5 pl-3">
extra
</td>
</tr>
</thead>
<tbody>
{langs.map(({ locale, missing, extra }, idx) => {
return (<tr key={locale}>
<td className="py-2 align-top">{idx}</td>
<td className="py-2 align-top">{locale}</td>
<td className="py-2 align-top">
<ul>
{missing.map(key => (
<li key={key}>{key}</li>
))}
</ul>
</td>
<td className="py-2 align-top">
<ul>
{extra.map(key => (
<li key={key}>{key}</li>
))}
</ul>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
async function genLangs() {
const langs_: Lang[] = []
let en!: Lang
const resources: Record<string, any> = {}
// Initialize empty resource object
for (const lang of LanguagesSupported)
resources[lang] = await loadLangResources(lang)
for (const [key, value] of Object.entries(resources)) {
const keys = getNestedKeys(value.translation)
const lang: Lang = {
locale: key,
keys: new Set(keys),
count: keys.length,
missing: [],
extra: [],
}
langs_.push(lang)
if (key === 'en-US') en = lang
}
for (const lang of langs_) {
const missing: string[] = []
const extra: string[] = []
for (const key of lang.keys)
if (!en.keys.has(key)) extra.push(key)
for (const key of en.keys)
if (!lang.keys.has(key)) missing.push(key)
lang.missing = missing
lang.extra = extra
}
return langs_
}
function getNestedKeys(translation: Record<string, any>): string[] {
const nestedKeys: string[] = []
const iterateKeys = (obj: Record<string, any>, prefix = '') => {
for (const key in obj) {
const nestedKey = prefix ? `${prefix}.${key}` : key
// nestedKeys.push(nestedKey);
if (typeof obj[key] === 'object') iterateKeys(obj[key], nestedKey)
else if (typeof obj[key] === 'string') nestedKeys.push(nestedKey)
}
}
iterateKeys(translation)
return nestedKeys
}
type Lang = {
locale: string;
keys: Set<string>;
count: number;
missing: string[];
extra: string[];
}

View File

@@ -1,9 +0,0 @@
import type React from 'react'
import { notFound } from 'next/navigation'
export default async function Layout({ children }: React.PropsWithChildren) {
if (process.env.NODE_ENV !== 'development')
notFound()
return children
}

View File

@@ -1,11 +0,0 @@
'use client'
import DemoForm from '../components/base/form/form-scenarios/demo'
export default function Page() {
return (
<div className='flex h-screen w-full items-center justify-center p-20'>
<DemoForm />
</div>
)
}

View File

@@ -8,6 +8,7 @@ const { translate } = bingTranslate
const data = require('./languages.json') const data = require('./languages.json')
const targetLanguage = 'en-US' const targetLanguage = 'en-US'
const i18nFolder = '../i18n' // Path to i18n folder relative to this script
// https://github.com/plainheart/bing-translate-api/blob/master/src/met/lang.json // https://github.com/plainheart/bing-translate-api/blob/master/src/met/lang.json
const languageKeyMap = data.languages.reduce((map, language) => { const languageKeyMap = data.languages.reduce((map, language) => {
if (language.supported) { if (language.supported) {
@@ -52,10 +53,9 @@ async function translateMissingKeyDeeply(sourceObj, targetObject, toLanguage) {
} }
})) }))
} }
async function autoGenTrans(fileName, toGenLanguage) { async function autoGenTrans(fileName, toGenLanguage) {
const fullKeyFilePath = path.join(__dirname, targetLanguage, `${fileName}.ts`) const fullKeyFilePath = path.join(__dirname, i18nFolder, targetLanguage, `${fileName}.ts`)
const toGenLanguageFilePath = path.join(__dirname, toGenLanguage, `${fileName}.ts`) const toGenLanguageFilePath = path.join(__dirname, i18nFolder, toGenLanguage, `${fileName}.ts`)
// eslint-disable-next-line sonarjs/code-eval // eslint-disable-next-line sonarjs/code-eval
const fullKeyContent = eval(transpile(fs.readFileSync(fullKeyFilePath, 'utf8'))) const fullKeyContent = eval(transpile(fs.readFileSync(fullKeyFilePath, 'utf8')))
// if toGenLanguageFilePath is not exist, create it // if toGenLanguageFilePath is not exist, create it
@@ -87,9 +87,8 @@ async function main() {
// Promise.all(Object.keys(languageKeyMap).map(async (toLanguage) => { // Promise.all(Object.keys(languageKeyMap).map(async (toLanguage) => {
// await autoGenTrans(fileName, toLanguage) // await autoGenTrans(fileName, toLanguage)
// })) // }))
const files = fs const files = fs
.readdirSync(path.join(__dirname, targetLanguage)) .readdirSync(path.join(__dirname, i18nFolder, targetLanguage))
.map(file => file.replace(/\.ts/, '')) .map(file => file.replace(/\.ts/, ''))
.filter(f => f !== 'app-debug') // ast parse error in app-debug .filter(f => f !== 'app-debug') // ast parse error in app-debug

View File

@@ -8,7 +8,7 @@ const languages = data.languages.filter(language => language.supported).map(lang
async function getKeysFromLanuage(language) { async function getKeysFromLanuage(language) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const folderPath = path.join(__dirname, language) const folderPath = path.join(__dirname, '../i18n', language)
let allKeys = [] let allKeys = []
fs.readdir(folderPath, (err, files) => { fs.readdir(folderPath, (err, files) => {
if (err) { if (err) {

View File

@@ -30,8 +30,8 @@
"prepare": "cd ../ && node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky ./web/.husky", "prepare": "cd ../ && node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky ./web/.husky",
"gen-icons": "node ./app/components/base/icons/script.mjs", "gen-icons": "node ./app/components/base/icons/script.mjs",
"uglify-embed": "node ./bin/uglify-embed", "uglify-embed": "node ./bin/uglify-embed",
"check-i18n": "node ./i18n/check-i18n.js", "check-i18n": "node ./i18n-config/check-i18n.js",
"auto-gen-i18n": "node ./i18n/auto-gen-i18n.js", "auto-gen-i18n": "node ./i18n-config/auto-gen-i18n.js",
"test": "jest", "test": "jest",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"storybook": "storybook dev -p 6006", "storybook": "storybook dev -p 6006",