Skip to content

Commit ac89881

Browse files
committed
fixed coderabbit comments
1 parent 95a26ef commit ac89881

File tree

210 files changed

+2379
-1060
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

210 files changed

+2379
-1060
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "next lint",
10-
"sitemap": "node generate-sitemap.mjs"
10+
"sitemap": "node generate-sitemap.mjs",
11+
"validate-translations": "node scripts/validate-translations.js"
1112
},
1213
"browserslist": "defaults, not ie <= 11",
1314
"dependencies": {

scripts/validate-translations.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Build-time validation script for navigation translations
5+
*
6+
* This script validates that all products have complete translations
7+
* for all required locales. It helps prevent maintenance drift by
8+
* ensuring that when navigation structure changes, translations are
9+
* kept in sync.
10+
*
11+
* Usage:
12+
* node scripts/validate-translations.js
13+
* node scripts/validate-translations.js --fail-on-warning
14+
*/
15+
16+
const { products } = require('../src/components/products/index.js')
17+
const {
18+
validateProductTranslations,
19+
extractNavigationKeys,
20+
generateTranslationTemplate
21+
} = require('../src/utils/navigation-localization.js')
22+
23+
const REQUIRED_LOCALES = ['ja', 'ko']
24+
const FAIL_ON_WARNING = process.argv.includes('--fail-on-warning')
25+
const GENERATE_TEMPLATE = process.argv.includes('--generate-template')
26+
27+
console.log('Validating navigation translations...\n')
28+
29+
let hasErrors = false
30+
let hasWarnings = false
31+
const allResults = []
32+
33+
products.forEach(product => {
34+
// Skip products without navigation
35+
if (!product.sections || product.sections.length === 0) {
36+
return
37+
}
38+
39+
const keys = extractNavigationKeys(product)
40+
41+
// Skip products with no navigable content
42+
if (keys.sections.length === 0 && keys.links.length === 0) {
43+
return
44+
}
45+
46+
console.log(`Checking ${product.name}...`)
47+
48+
// Generate template if requested
49+
if (GENERATE_TEMPLATE && (!product.localizedNavigation || Object.keys(product.localizedNavigation).length === 0)) {
50+
console.log(` Template for ${product.name}:`)
51+
REQUIRED_LOCALES.forEach(locale => {
52+
const template = generateTranslationTemplate(product, locale)
53+
console.log(` ${locale}:`, JSON.stringify(template, null, 2))
54+
})
55+
console.log()
56+
return
57+
}
58+
59+
const validation = validateProductTranslations(product, REQUIRED_LOCALES)
60+
allResults.push({ product: product.name, validation })
61+
62+
if (!validation.isValid) {
63+
hasErrors = true
64+
console.log(` ❌ Validation failed`)
65+
validation.errors.forEach(error => {
66+
console.log(` - ${error}`)
67+
})
68+
} else {
69+
console.log(` ✅ All translations complete`)
70+
}
71+
72+
// Show detailed results for each locale
73+
Object.entries(validation.results).forEach(([locale, result]) => {
74+
if (!result.isValid) {
75+
hasWarnings = true
76+
console.log(` Locale ${locale}:`)
77+
if (result.missing.sections.length > 0) {
78+
console.log(` Missing sections: ${result.missing.sections.join(', ')}`)
79+
}
80+
if (result.missing.links.length > 0) {
81+
console.log(` Missing links: ${result.missing.links.join(', ')}`)
82+
}
83+
if (result.missing.headline) {
84+
console.log(` Missing headline`)
85+
}
86+
if (result.missing.description) {
87+
console.log(` Missing description`)
88+
}
89+
}
90+
})
91+
92+
console.log()
93+
})
94+
95+
// Summary
96+
console.log('Summary:')
97+
console.log(` Total products validated: ${allResults.length}`)
98+
console.log(` Products with errors: ${allResults.filter(r => !r.validation.isValid).length}`)
99+
console.log(` Products with warnings: ${allResults.filter(r => Object.values(r.validation.results).some(v => !v.isValid)).length}`)
100+
101+
if (hasErrors || (FAIL_ON_WARNING && hasWarnings)) {
102+
console.log('\n❌ Translation validation failed!')
103+
console.log('Please ensure all navigation items have translations for all required locales.')
104+
process.exit(1)
105+
} else if (hasWarnings) {
106+
console.log('\n⚠️ Some warnings found, but validation passed.')
107+
console.log('Consider adding missing translations for better localization coverage.')
108+
process.exit(0)
109+
} else {
110+
console.log('\n✅ All translations validated successfully!')
111+
process.exit(0)
112+
}

src/components/NavList.jsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,11 @@ import Link from 'next/link'
55
import { SwitcherPopover } from './products/SwitcherPopover'
66
import { productCategories } from './products/index'
77
import { useTranslations, useLocale } from '@/contexts/LocaleContext'
8+
import { getLocalizedHref } from '@/config/languages'
89

910
const NavList = () => {
1011
const t = useTranslations('header')
1112
const { locale } = useLocale()
12-
13-
const getLocalizedHref = (path) => {
14-
if (locale === 'en') return path
15-
return `/${locale}${path}`
16-
}
1713

1814
const getTranslatedCategory = (category) => {
1915
const categoryMap = {
@@ -29,7 +25,7 @@ const NavList = () => {
2925
{productCategories.map((item, index) => {
3026
if (item === 'Aura') {
3127
return (
32-
<Link href={getLocalizedHref("/aura")} key={index}>
28+
<Link href={getLocalizedHref("/aura", locale)} key={index}>
3329
<div className="-mx-4 -my-2 rounded-lg px-4 py-2 text-black dark:text-white">
3430
{getTranslatedCategory(item)}
3531
</div>
@@ -48,7 +44,7 @@ const NavList = () => {
4844
)
4945
})}
5046
<div className="hidden flex-col lg:flex">
51-
<Link href={getLocalizedHref("/guides")}>
47+
<Link href={getLocalizedHref("/guides", locale)}>
5248
<div className="-mx-4 -my-2 rounded-lg px-4 py-2 text-black dark:text-white">
5349
{t('guides', 'Guides')}
5450
</div>

src/components/products/Grid.jsx

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Link from 'next/link';
22
import { IconWithName } from './IconWithName';
33
import { products as allProducts } from './index';
44
import { useLocale } from '@/contexts/LocaleContext';
5+
import { getLocalizedHref } from '@/config/languages';
56

67
export function Grid({
78
onClick,
@@ -17,30 +18,21 @@ export function Grid({
1718

1819
// Localize product headlines and descriptions
1920
const localizeProduct = (product) => {
20-
if (locale === 'en' || !product.localizedNavigation) return product
21+
if (locale === 'en' || !product.localizedNavigation || !product.localizedNavigation[locale]) {
22+
return product
23+
}
2124

2225
const localizedProduct = { ...product }
23-
const productNav = product.localizedNavigation[locale] || product.localizedNavigation['en']
24-
26+
const productNav = product.localizedNavigation[locale]
27+
2528
if (productNav.headline) {
2629
localizedProduct.headline = productNav.headline
2730
}
2831
if (productNav.description) {
2932
localizedProduct.description = productNav.description
3033
}
31-
32-
return localizedProduct
33-
}
3434

35-
const getLocalizedHref = (path) => {
36-
// Handle external URLs - don't add locale prefix
37-
if (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('//')) {
38-
return path
39-
}
40-
41-
// Handle internal paths
42-
if (locale === 'en') return `/${path}`
43-
return `/${locale}/${path}`
35+
return localizedProduct
4436
}
4537

4638
let className = `relative grid sm:grid-cols-2 grid-cols-1`
@@ -52,7 +44,7 @@ export function Grid({
5244
return (
5345
<li key={product.path || product.href}>
5446
<Link
55-
href={getLocalizedHref(product.href || product.path)}
47+
href={getLocalizedHref(product.href || product.path, locale)}
5648
className="block content-start rounded-lg p-3 hover:bg-slate-50 hover:dark:bg-slate-700"
5749
onClick={onClick}
5850
{...(product.target && { target: product.target })}

0 commit comments

Comments
 (0)