mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
feat(i18n): added japanese and german translations (#1428)
* feat(changelog): added changelog * feat(i18n): added japanese and german translations * reordered --------- Co-authored-by: waleed <waleed>
This commit is contained in:
12
.github/workflows/i18n.yml
vendored
12
.github/workflows/i18n.yml
vendored
@@ -55,7 +55,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.GH_PAT }}
|
token: ${{ secrets.GH_PAT }}
|
||||||
commit-message: "feat(i18n): update translations"
|
commit-message: "feat(i18n): update translations"
|
||||||
title: "🌐 Auto-update translations"
|
title: "feat(i18n): update translations"
|
||||||
body: |
|
body: |
|
||||||
## Summary
|
## Summary
|
||||||
Automated translation updates triggered by changes to documentation.
|
Automated translation updates triggered by changes to documentation.
|
||||||
@@ -76,8 +76,10 @@ jobs:
|
|||||||
## Testing
|
## Testing
|
||||||
This PR includes automated translations for modified English documentation content:
|
This PR includes automated translations for modified English documentation content:
|
||||||
- 🇪🇸 Spanish (es) translations
|
- 🇪🇸 Spanish (es) translations
|
||||||
- 🇫🇷 French (fr) translations
|
- 🇫🇷 French (fr) translations
|
||||||
- 🇨🇳 Chinese (zh) translations
|
- 🇨🇳 Chinese (zh) translations
|
||||||
|
- 🇯🇵 Japanese (ja) translations
|
||||||
|
- 🇩🇪 German (de) translations
|
||||||
|
|
||||||
**What reviewers should focus on:**
|
**What reviewers should focus on:**
|
||||||
- Verify translated content accuracy and context
|
- Verify translated content accuracy and context
|
||||||
@@ -137,15 +139,21 @@ jobs:
|
|||||||
es_count=$(find content/docs/es -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
es_count=$(find content/docs/es -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
||||||
fr_count=$(find content/docs/fr -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
fr_count=$(find content/docs/fr -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
||||||
zh_count=$(find content/docs/zh -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
zh_count=$(find content/docs/zh -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
||||||
|
ja_count=$(find content/docs/ja -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
||||||
|
de_count=$(find content/docs/de -name "*.mdx" 2>/dev/null | wc -l || echo 0)
|
||||||
|
|
||||||
es_percentage=$((es_count * 100 / en_count))
|
es_percentage=$((es_count * 100 / en_count))
|
||||||
fr_percentage=$((fr_count * 100 / en_count))
|
fr_percentage=$((fr_count * 100 / en_count))
|
||||||
zh_percentage=$((zh_count * 100 / en_count))
|
zh_percentage=$((zh_count * 100 / en_count))
|
||||||
|
ja_percentage=$((ja_count * 100 / en_count))
|
||||||
|
de_percentage=$((de_count * 100 / en_count))
|
||||||
|
|
||||||
echo "### Coverage Statistics" >> $GITHUB_STEP_SUMMARY
|
echo "### Coverage Statistics" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "- **🇬🇧 English**: $en_count files (source)" >> $GITHUB_STEP_SUMMARY
|
echo "- **🇬🇧 English**: $en_count files (source)" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "- **🇪🇸 Spanish**: $es_count/$en_count files ($es_percentage%)" >> $GITHUB_STEP_SUMMARY
|
echo "- **🇪🇸 Spanish**: $es_count/$en_count files ($es_percentage%)" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "- **🇫🇷 French**: $fr_count/$en_count files ($fr_percentage%)" >> $GITHUB_STEP_SUMMARY
|
echo "- **🇫🇷 French**: $fr_count/$en_count files ($fr_percentage%)" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "- **🇨🇳 Chinese**: $zh_count/$en_count files ($zh_percentage%)" >> $GITHUB_STEP_SUMMARY
|
echo "- **🇨🇳 Chinese**: $zh_count/$en_count files ($zh_percentage%)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- **🇯🇵 Japanese**: $ja_count/$en_count files ($ja_percentage%)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- **🇩🇪 German**: $de_count/$en_count files ($de_percentage%)" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "🔄 **Auto-translation PR**: Check for new pull request with updated translations" >> $GITHUB_STEP_SUMMARY
|
echo "🔄 **Auto-translation PR**: Check for new pull request with updated translations" >> $GITHUB_STEP_SUMMARY
|
||||||
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Check, ChevronDown } from 'lucide-react'
|
import { Check, ChevronDown } from 'lucide-react'
|
||||||
import { useParams, usePathname } from 'next/navigation'
|
import { useParams, usePathname, useRouter } from 'next/navigation'
|
||||||
|
|
||||||
const languages = {
|
const languages = {
|
||||||
en: { name: 'English', flag: '🇺🇸' },
|
en: { name: 'English', flag: '🇺🇸' },
|
||||||
es: { name: 'Español', flag: '🇪🇸' },
|
es: { name: 'Español', flag: '🇪🇸' },
|
||||||
fr: { name: 'Français', flag: '🇫🇷' },
|
fr: { name: 'Français', flag: '🇫🇷' },
|
||||||
|
de: { name: 'Deutsch', flag: '🇩🇪' },
|
||||||
|
ja: { name: '日本語', flag: '🇯🇵' },
|
||||||
zh: { name: '简体中文', flag: '🇨🇳' },
|
zh: { name: '简体中文', flag: '🇨🇳' },
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,6 +17,7 @@ export function LanguageDropdown() {
|
|||||||
const [isOpen, setIsOpen] = useState(false)
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const [currentLang, setCurrentLang] = useState(() => {
|
const [currentLang, setCurrentLang] = useState(() => {
|
||||||
const langFromParams = params?.lang as string
|
const langFromParams = params?.lang as string
|
||||||
@@ -56,9 +59,18 @@ export function LanguageDropdown() {
|
|||||||
newPath = `/${locale}${segments.length > 0 ? `/${segments.join('/')}` : '/introduction'}`
|
newPath = `/${locale}${segments.length > 0 ? `/${segments.join('/')}` : '/introduction'}`
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.href = newPath
|
router.push(newPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen) return
|
||||||
|
const onKey = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Escape') setIsOpen(false)
|
||||||
|
}
|
||||||
|
window.addEventListener('keydown', onKey)
|
||||||
|
return () => window.removeEventListener('keydown', onKey)
|
||||||
|
}, [isOpen])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<button
|
<button
|
||||||
@@ -67,9 +79,12 @@ export function LanguageDropdown() {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
setIsOpen(!isOpen)
|
setIsOpen(!isOpen)
|
||||||
}}
|
}}
|
||||||
className='flex items-center gap-2 rounded-xl border border-border/20 bg-muted/50 px-3 py-2 text-sm backdrop-blur-sm transition-colors hover:bg-muted'
|
aria-haspopup='listbox'
|
||||||
|
aria-expanded={isOpen}
|
||||||
|
aria-controls='language-menu'
|
||||||
|
className='flex items-center gap-1.5 rounded-lg border border-border/30 bg-muted/40 px-2.5 py-1.5 text-sm shadow-sm backdrop-blur-sm transition-colors hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-ring'
|
||||||
>
|
>
|
||||||
<span className='text-base'>{languages[currentLang as keyof typeof languages]?.flag}</span>
|
<span className='text-sm'>{languages[currentLang as keyof typeof languages]?.flag}</span>
|
||||||
<span className='font-medium text-foreground'>
|
<span className='font-medium text-foreground'>
|
||||||
{languages[currentLang as keyof typeof languages]?.name}
|
{languages[currentLang as keyof typeof languages]?.name}
|
||||||
</span>
|
</span>
|
||||||
@@ -80,8 +95,12 @@ export function LanguageDropdown() {
|
|||||||
|
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<>
|
<>
|
||||||
<div className='fixed inset-0 z-10' onClick={() => setIsOpen(false)} />
|
<div className='fixed inset-0 z-[1000]' aria-hidden onClick={() => setIsOpen(false)} />
|
||||||
<div className='absolute top-full left-0 z-20 mt-1 w-48 rounded-lg border border-border/50 bg-background/95 shadow-xl backdrop-blur-md'>
|
<div
|
||||||
|
id='language-menu'
|
||||||
|
role='listbox'
|
||||||
|
className='absolute top-full left-0 z-[1001] mt-1 max-h-[75vh] w-56 overflow-auto rounded-xl border border-border/50 bg-white shadow-2xl md:w-44 md:bg-background/95 md:backdrop-blur-md dark:bg-neutral-950 md:dark:bg-background/95'
|
||||||
|
>
|
||||||
{Object.entries(languages).map(([code, lang]) => (
|
{Object.entries(languages).map(([code, lang]) => (
|
||||||
<button
|
<button
|
||||||
key={code}
|
key={code}
|
||||||
@@ -90,13 +109,17 @@ export function LanguageDropdown() {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
handleLanguageChange(code)
|
handleLanguageChange(code)
|
||||||
}}
|
}}
|
||||||
className={`flex w-full items-center gap-3 px-3 py-2.5 text-sm transition-colors first:rounded-t-lg last:rounded-b-lg hover:bg-muted/80 ${
|
role='option'
|
||||||
|
aria-selected={currentLang === code}
|
||||||
|
className={`flex w-full items-center gap-3 px-3 py-3 text-base transition-colors first:rounded-t-xl last:rounded-b-xl hover:bg-muted/80 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring md:gap-2 md:px-2.5 md:py-2 md:text-sm ${
|
||||||
currentLang === code ? 'bg-muted/60 font-medium text-primary' : 'text-foreground'
|
currentLang === code ? 'bg-muted/60 font-medium text-primary' : 'text-foreground'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span className='text-base'>{lang.flag}</span>
|
<span className='text-base md:text-sm'>{lang.flag}</span>
|
||||||
<span>{lang.name}</span>
|
<span className='leading-none'>{lang.name}</span>
|
||||||
{currentLang === code && <Check className='ml-auto h-4 w-4 text-primary' />}
|
{currentLang === code && (
|
||||||
|
<Check className='ml-auto h-4 w-4 text-primary md:h-3.5 md:w-3.5' />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": 1.8,
|
"version": 1.8,
|
||||||
"locale": {
|
"locale": {
|
||||||
"source": "en",
|
"source": "en",
|
||||||
"targets": ["es", "fr", "zh"]
|
"targets": ["es", "fr", "zh", "ja", "de"]
|
||||||
},
|
},
|
||||||
"buckets": {
|
"buckets": {
|
||||||
"mdx": {
|
"mdx": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { defineI18n } from 'fumadocs-core/i18n'
|
|||||||
|
|
||||||
export const i18n = defineI18n({
|
export const i18n = defineI18n({
|
||||||
defaultLanguage: 'en',
|
defaultLanguage: 'en',
|
||||||
languages: ['en', 'es', 'fr', 'zh'],
|
languages: ['en', 'es', 'fr', 'de', 'ja', 'zh'],
|
||||||
hideLocale: 'default-locale',
|
hideLocale: 'default-locale',
|
||||||
parser: 'dir',
|
parser: 'dir',
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user