chore(web): new lint setup (#30020)

Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
Stephen Zhou
2025-12-23 16:58:55 +08:00
committed by GitHub
parent 9701a2994b
commit f2842da397
3356 changed files with 85046 additions and 81278 deletions

View File

@@ -79,7 +79,6 @@ export type I18nText = {
4. Add the new language to the `language.json` file.
```typescript
export const languages = [
{
value: 'en-US',
@@ -172,7 +171,7 @@ export const languages = [
supported: true,
},
// Add your language here 👇
...
// ...
// Add your language here 👆
]
```

View File

@@ -1,11 +1,11 @@
import fs from 'node:fs'
import path from 'node:path'
import vm from 'node:vm'
import { fileURLToPath } from 'node:url'
import { createRequire } from 'node:module'
import { transpile } from 'typescript'
import { parseModule, generateCode, loadFile } from 'magicast'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import vm from 'node:vm'
import { translate } from 'bing-translate-api'
import { generateCode, loadFile, parseModule } from 'magicast'
import { transpile } from 'typescript'
const require = createRequire(import.meta.url)
const __filename = fileURLToPath(import.meta.url)
@@ -42,7 +42,8 @@ function parseArgs(argv) {
let cursor = startIndex + 1
while (cursor < argv.length && !argv[cursor].startsWith('--')) {
const value = argv[cursor].trim()
if (value) values.push(value)
if (value)
values.push(value)
cursor++
}
return { values, nextIndex: cursor - 1 }
@@ -127,7 +128,7 @@ function protectPlaceholders(text) {
const patterns = [
/\{\{[^{}]+\}\}/g, // mustache
/\$\{[^{}]+\}/g, // template expressions
/<[^>]+?>/g, // html-like tags
/<[^>]+>/g, // html-like tags
]
patterns.forEach((pattern) => {
@@ -160,7 +161,7 @@ async function translateText(source, toLanguage) {
const { translation } = await translate(safeText, null, languageKeyMap[toLanguage])
return { value: restore(translation), skipped: false }
}
catch (error) {
catch (error) {
console.error(`❌ Error translating to ${toLanguage}:`, error.message)
return { value: source, skipped: true, error: error.message }
}
@@ -310,7 +311,7 @@ export default translation
}
const { code } = generateCode(mod)
let res = `const translation =${code.replace('export default', '')}
const res = `const translation =${code.replace('export default', '')}
export default translation
`.replace(/,\n\n/g, ',\n').replace('};', '}')
@@ -319,13 +320,13 @@ export default translation
fs.writeFileSync(toGenLanguageFilePath, res)
console.log(`💾 Saved translations to ${toGenLanguageFilePath}`)
}
else {
else {
console.log(`🔍 [DRY RUN] Would save translations to ${toGenLanguageFilePath}`)
}
return result
}
catch (error) {
catch (error) {
console.error(`Error processing file ${fullKeyFilePath}:`, error.message)
throw error
}

View File

@@ -1,12 +1,13 @@
#!/usr/bin/env node
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import lodash from 'lodash'
const { camelCase } = lodash
import ts from 'typescript'
const { camelCase } = lodash
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

View File

@@ -1,8 +1,8 @@
import fs from 'node:fs'
import path from 'node:path'
import vm from 'node:vm'
import { fileURLToPath } from 'node:url'
import { createRequire } from 'node:module'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import vm from 'node:vm'
import { transpile } from 'typescript'
const require = createRequire(import.meta.url)
@@ -11,6 +11,7 @@ const __dirname = path.dirname(__filename)
const targetLanguage = 'en-US'
const data = require('./languages.json')
const languages = data.languages.filter(language => language.supported).map(language => language.value)
function parseArgs(argv) {
@@ -27,7 +28,8 @@ function parseArgs(argv) {
let cursor = startIndex + 1
while (cursor < argv.length && !argv[cursor].startsWith('--')) {
const value = argv[cursor].trim()
if (value) values.push(value)
if (value)
values.push(value)
cursor++
}
return { values, nextIndex: cursor - 1 }
@@ -124,8 +126,7 @@ async function getKeysFromLanguage(language) {
const filePath = path.join(folderPath, file)
const fileName = file.replace(/\.[^/.]+$/, '') // Remove file extension
const camelCaseFileName = fileName.replace(/[-_](.)/g, (_, c) =>
c.toUpperCase(),
) // Convert to camel case
c.toUpperCase()) // Convert to camel case
try {
const content = fs.readFileSync(filePath, 'utf8')
@@ -147,7 +148,7 @@ async function getKeysFromLanguage(language) {
// Extract the translation object
const translationObj = moduleExports.default || moduleExports
if(!translationObj || typeof translationObj !== 'object') {
if (!translationObj || typeof translationObj !== 'object') {
console.error(`Error parsing file: ${filePath}`)
reject(new Error(`Error parsing file: ${filePath}`))
return
@@ -161,7 +162,7 @@ async function getKeysFromLanguage(language) {
// This is an object (but not array), recurse into it but don't add it as a key
iterateKeys(obj[key], nestedKey)
}
else {
else {
// This is a leaf node (string, number, boolean, array, etc.), add it as a key
nestedKeys.push(nestedKey)
}
@@ -173,7 +174,7 @@ async function getKeysFromLanguage(language) {
const fileKeys = nestedKeys.map(key => `${camelCaseFileName}.${key}`)
allKeys.push(...fileKeys)
}
catch (error) {
catch (error) {
console.error(`Error processing file ${filePath}:`, error.message)
reject(error)
}
@@ -193,7 +194,7 @@ function removeKeysFromObject(obj, keysToRemove, prefix = '') {
modified = true
console.log(`🗑️ Removed key: ${fullKey}`)
}
else if (typeof obj[key] === 'object' && obj[key] !== null) {
else if (typeof obj[key] === 'object' && obj[key] !== null) {
const subModified = removeKeysFromObject(obj[key], keysToRemove, fullKey)
modified = modified || subModified
}
@@ -246,7 +247,7 @@ async function removeExtraKeysFromFile(language, fileName, extraKeys) {
}
}
}
else {
else {
// Nested key - need to find the exact path
const currentPath = []
let braceDepth = 0
@@ -256,12 +257,12 @@ async function removeExtraKeysFromFile(language, fileName, extraKeys) {
const trimmedLine = line.trim()
// Track current object path
const keyMatch = trimmedLine.match(/^(\w+)\s*:\s*{/)
const keyMatch = trimmedLine.match(/^(\w+)\s*:\s*\{/)
if (keyMatch) {
currentPath.push(keyMatch[1])
braceDepth++
}
else if (trimmedLine === '},' || trimmedLine === '}') {
else if (trimmedLine === '},' || trimmedLine === '}') {
if (braceDepth > 0) {
braceDepth--
currentPath.pop()
@@ -316,11 +317,12 @@ async function removeExtraKeysFromFile(language, fileName, extraKeys) {
// Check if this line ends the value (ends with quote and comma/no comma)
if ((trimmed.endsWith('\',') || trimmed.endsWith('",') || trimmed.endsWith('`,')
|| trimmed.endsWith('\'') || trimmed.endsWith('"') || trimmed.endsWith('`'))
&& !trimmed.startsWith('//'))
|| trimmed.endsWith('\'') || trimmed.endsWith('"') || trimmed.endsWith('`'))
&& !trimmed.startsWith('//')) {
break
}
}
else {
else {
break
}
@@ -332,7 +334,7 @@ async function removeExtraKeysFromFile(language, fileName, extraKeys) {
console.log(`🗑️ Found key to remove: ${keyToRemove} at line ${targetLineIndex + 1}${linesToRemoveForKey.length > 1 ? ` (multiline, ${linesToRemoveForKey.length} lines)` : ''}`)
modified = true
}
else {
else {
console.log(`⚠️ Could not find key: ${keyToRemove}`)
}
}
@@ -365,7 +367,7 @@ async function removeExtraKeysFromFile(language, fileName, extraKeys) {
return false
}
catch (error) {
catch (error) {
console.error(`Error processing file ${filePath}:`, error.message)
return false
}
@@ -439,7 +441,8 @@ async function main() {
let totalRemoved = 0
for (const fileName of files) {
const removed = await removeExtraKeysFromFile(language, fileName, extraKeys)
if (removed) totalRemoved++
if (removed)
totalRemoved++
}
console.log(`✅ Auto-removal completed for ${language}. Modified ${totalRemoved} files.`)

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env node
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import lodash from 'lodash'
import ts from 'typescript'
@@ -50,8 +50,8 @@ import 'react-i18next'
// Extract types from translation files using typeof import pattern`
// Generate individual type definitions
const typeDefinitions = namespaces.map(namespace => {
const typeName = camelCase(namespace).replace(/^\w/, c => c.toUpperCase()) + 'Messages'
const typeDefinitions = namespaces.map((namespace) => {
const typeName = `${camelCase(namespace).replace(/^\w/, c => c.toUpperCase())}Messages`
return `type ${typeName} = typeof import('../i18n/en-US/${namespace}').default`
}).join('\n')
@@ -59,11 +59,11 @@ import 'react-i18next'
const messagesInterface = `
// Complete type structure that matches i18next-config.ts camelCase conversion
export type Messages = {
${namespaces.map(namespace => {
const camelCased = camelCase(namespace)
const typeName = camelCase(namespace).replace(/^\w/, c => c.toUpperCase()) + 'Messages'
return ` ${camelCased}: ${typeName};`
}).join('\n')}
${namespaces.map((namespace) => {
const camelCased = camelCase(namespace)
const typeName = `${camelCase(namespace).replace(/^\w/, c => c.toUpperCase())}Messages`
return ` ${camelCased}: ${typeName};`
}).join('\n')}
}`
const utilityTypes = `
@@ -133,13 +133,14 @@ function main() {
}
console.log('✅ Type definitions are in sync')
} else {
}
else {
// Generate mode: write file
fs.writeFileSync(outputPath, typeDefinitions)
console.log(`✅ Generated type definitions: ${outputPath}`)
}
} catch (error) {
}
catch (error) {
console.error('❌ Error:', error.message)
process.exit(1)
}

View File

@@ -3,31 +3,31 @@ import i18n from 'i18next'
import { camelCase } from 'lodash-es'
import { initReactI18next } from 'react-i18next'
import app from '../i18n/en-US/app'
// Static imports for en-US (fallback language)
import appAnnotation from '../i18n/en-US/app-annotation'
import appApi from '../i18n/en-US/app-api'
import appDebug from '../i18n/en-US/app-debug'
import appLog from '../i18n/en-US/app-log'
import appOverview from '../i18n/en-US/app-overview'
import app from '../i18n/en-US/app'
import billing from '../i18n/en-US/billing'
import common from '../i18n/en-US/common'
import custom from '../i18n/en-US/custom'
import dataset from '../i18n/en-US/dataset'
import datasetCreation from '../i18n/en-US/dataset-creation'
import datasetDocuments from '../i18n/en-US/dataset-documents'
import datasetHitTesting from '../i18n/en-US/dataset-hit-testing'
import datasetPipeline from '../i18n/en-US/dataset-pipeline'
import datasetSettings from '../i18n/en-US/dataset-settings'
import dataset from '../i18n/en-US/dataset'
import education from '../i18n/en-US/education'
import explore from '../i18n/en-US/explore'
import layout from '../i18n/en-US/layout'
import login from '../i18n/en-US/login'
import oauth from '../i18n/en-US/oauth'
import pipeline from '../i18n/en-US/pipeline'
import plugin from '../i18n/en-US/plugin'
import pluginTags from '../i18n/en-US/plugin-tags'
import pluginTrigger from '../i18n/en-US/plugin-trigger'
import plugin from '../i18n/en-US/plugin'
import register from '../i18n/en-US/register'
import runLog from '../i18n/en-US/run-log'
import share from '../i18n/en-US/share'
@@ -141,7 +141,8 @@ if (!i18n.isInitialized) {
}
export const changeLanguage = async (lng?: string) => {
if (!lng) return
if (!lng)
return
if (!i18n.hasResourceBundle(lng, 'translation')) {
const resource = await loadLangResources(lng)
i18n.addResourceBundle(lng, 'translation', resource, true, true)

View File

@@ -1,7 +1,7 @@
import Cookies from 'js-cookie'
import { changeLanguage } from '@/i18n-config/i18next-config'
import { LOCALE_COOKIE_NAME } from '@/config'
import { changeLanguage } from '@/i18n-config/i18next-config'
import { LanguagesSupported } from '@/i18n-config/language'
export const i18n = {
@@ -23,8 +23,11 @@ export const getLocaleOnClient = (): Locale => {
}
export const renderI18nObject = (obj: Record<string, string>, language: string) => {
if (!obj) return ''
if (obj?.[language]) return obj[language]
if (obj?.en_US) return obj.en_US
if (!obj)
return ''
if (obj?.[language])
return obj[language]
if (obj?.en_US)
return obj.en_US
return Object.values(obj)[0]
}

View File

@@ -1,4 +1,5 @@
import data from './languages.json'
export type Item = {
value: number | string
name: string

View File

@@ -1,12 +1,12 @@
import { cookies, headers } from 'next/headers'
import Negotiator from 'negotiator'
import type { Locale } from '.'
import { match } from '@formatjs/intl-localematcher'
import { createInstance } from 'i18next'
import resourcesToBackend from 'i18next-resources-to-backend'
import Negotiator from 'negotiator'
import { cookies, headers } from 'next/headers'
import { initReactI18next } from 'react-i18next/initReactI18next'
import { i18n } from '.'
import type { Locale } from '.'
// https://locize.com/blog/next-13-app-dir-i18n/
const initI18next = async (lng: Locale, ns: string) => {