├── public ├── favicon.png ├── logo-blue.png ├── og-image.png ├── logo-white.png ├── window.svg ├── file.svg └── globe.svg ├── src ├── app │ ├── fonts │ │ ├── GeistVF.woff │ │ └── GeistMonoVF.woff │ ├── layout.tsx │ ├── page.tsx │ ├── globals.css │ └── [lang] │ │ ├── layout.tsx │ │ └── page.tsx ├── lib │ ├── utils.ts │ ├── getDictionary.ts │ ├── openai.ts │ └── json-utils.ts ├── components │ ├── ui │ │ ├── input.tsx │ │ ├── progress.tsx │ │ ├── toaster.tsx │ │ ├── checkbox.tsx │ │ ├── popover.tsx │ │ ├── tabs.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── toast.tsx │ │ └── select.tsx │ ├── Analytics.tsx │ ├── sections │ │ ├── FeaturesSection.tsx │ │ ├── CTASection.tsx │ │ ├── FAQ.tsx │ │ ├── WorkflowSection.tsx │ │ └── HeroSection.tsx │ ├── VirtualizedJson.tsx │ ├── TranslateProvider.tsx │ ├── LanguageSwitcher.tsx │ ├── Footer.tsx │ ├── Navbar.tsx │ └── FileUpload.tsx ├── config │ └── i18n.ts ├── context │ └── TranslateContext.tsx ├── hooks │ └── use-toast.ts └── dictionaries │ ├── zh.json │ ├── zh-TW.json │ ├── ja.json │ ├── ko.json │ ├── ar.json │ ├── th.json │ ├── en.json │ ├── tr.json │ ├── id.json │ ├── it.json │ └── nl.json ├── postcss.config.js ├── postcss.config.mjs.bak ├── next.config.js ├── next.config.ts.bak ├── components.json ├── .gitignore ├── tsconfig.json ├── LICENSE ├── example └── en-example.json ├── package.json ├── tailwind.config.ts.bak ├── tailwind.config.js ├── README.zh.md ├── json-translator-prd.zh.md ├── json-translator-prd.md └── README.md /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ViggoZ/json-translate/HEAD/public/favicon.png -------------------------------------------------------------------------------- /public/logo-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ViggoZ/json-translate/HEAD/public/logo-blue.png -------------------------------------------------------------------------------- /public/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ViggoZ/json-translate/HEAD/public/og-image.png -------------------------------------------------------------------------------- /public/logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ViggoZ/json-translate/HEAD/public/logo-white.png -------------------------------------------------------------------------------- /src/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ViggoZ/json-translate/HEAD/src/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /src/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ViggoZ/json-translate/HEAD/src/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | module.exports = { 3 | plugins: { 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /postcss.config.mjs.bak: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | 3 | export default function RootLayout({ 4 | children, 5 | }: { 6 | children: React.ReactNode 7 | }) { 8 | return children; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | import { defaultLocale } from '@/config/i18n' 3 | 4 | export default function Home() { 5 | redirect(`/${defaultLocale}`) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | experimental: { 5 | scrollRestoration: true 6 | } 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /next.config.ts.bak: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | // 避免不必要的客户端重新渲染 5 | experimental: { 6 | optimizeCss: true, 7 | scrollRestoration: true 8 | } 9 | } 10 | 11 | module.exports = nextConfig -------------------------------------------------------------------------------- /public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | /.pnp 4 | .pnp.js 5 | .yarn/install-state.gz 6 | 7 | # testing 8 | /coverage 9 | 10 | # next.js 11 | /.next/ 12 | /out/ 13 | 14 | # production 15 | /build 16 | 17 | # misc 18 | .DS_Store 19 | *.pem 20 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # local env files 27 | .env*.local 28 | .env 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | # IDE 38 | .idea 39 | .vscode 40 | *.swp 41 | *.swo 42 | 43 | # OS generated files 44 | .DS_Store 45 | .DS_Store? 46 | ._* 47 | .Spotlight-V100 48 | .Trashes 49 | ehthumbs.db 50 | Thumbs.db 51 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /src/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Input = React.forwardRef>( 6 | ({ className, type, ...props }, ref) => { 7 | return ( 8 | 17 | ) 18 | } 19 | ) 20 | Input.displayName = "Input" 21 | 22 | export { Input } 23 | -------------------------------------------------------------------------------- /src/components/ui/progress.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as ProgressPrimitive from "@radix-ui/react-progress" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Progress = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, value, ...props }, ref) => ( 12 | 20 | 24 | 25 | )) 26 | Progress.displayName = ProgressPrimitive.Root.displayName 27 | 28 | export { Progress } 29 | -------------------------------------------------------------------------------- /src/components/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useToast } from "@/hooks/use-toast" 4 | import { 5 | Toast, 6 | ToastClose, 7 | ToastDescription, 8 | ToastProvider, 9 | ToastTitle, 10 | ToastViewport, 11 | } from "@/components/ui/toast" 12 | 13 | export function Toaster() { 14 | const { toasts } = useToast() 15 | 16 | return ( 17 | 18 | {toasts.map(function ({ id, title, description, action, ...props }) { 19 | return ( 20 | 21 |
22 | {title && {title}} 23 | {description && ( 24 | {description} 25 | )} 26 |
27 | {action} 28 | 29 |
30 | ) 31 | })} 32 | 33 |
34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 viggoz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/Analytics.tsx: -------------------------------------------------------------------------------- 1 | import Script from 'next/script' 2 | 3 | export default function Analytics() { 4 | return ( 5 | <> 6 | {/* Google Analytics */} 7 | 19 | 20 | {/* Microsoft Clarity */} 21 | 30 | 31 | ) 32 | } -------------------------------------------------------------------------------- /src/components/ui/checkbox.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox" 5 | import { Check } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const Checkbox = React.forwardRef< 10 | React.ElementRef, 11 | React.ComponentPropsWithoutRef 12 | >(({ className, ...props }, ref) => ( 13 | 21 | 24 | 25 | 26 | 27 | )) 28 | Checkbox.displayName = CheckboxPrimitive.Root.displayName 29 | 30 | export { Checkbox } 31 | -------------------------------------------------------------------------------- /example/en-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "appInfo": { 3 | "name": "JSON Translation Tool", 4 | "version": "1.0.0", 5 | "description": "An AI-powered JSON internationalization translation tool helping developers quickly complete multilingual translation tasks" 6 | }, 7 | "features": { 8 | "core": { 9 | "title": "Core Features", 10 | "fileUpload": { 11 | "title": "File Upload", 12 | "description": "Supports both drag-and-drop and click-to-upload methods, accepts JSON files up to 10MB in size", 13 | "supportedFormats": ["JSON"], 14 | "restrictions": { 15 | "maxSize": "10MB", 16 | "encoding": ["UTF-8", "UTF-16"] 17 | } 18 | }, 19 | "translation": { 20 | "title": "AI Translation", 21 | "description": "Utilizes OpenAI's GPT model for intelligent translation, ensuring accuracy of technical terms and natural expression", 22 | "features": [ 23 | "Maintains JSON structure integrity", 24 | "Supports nested JSON structures", 25 | "Preserves variable placeholders", 26 | "Supports HTML tags and Markdown format" 27 | ] 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/ui/popover.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as PopoverPrimitive from "@radix-ui/react-popover" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Popover = PopoverPrimitive.Root 9 | 10 | const PopoverTrigger = PopoverPrimitive.Trigger 11 | 12 | const PopoverAnchor = PopoverPrimitive.Anchor 13 | 14 | const PopoverContent = React.forwardRef< 15 | React.ElementRef, 16 | React.ComponentPropsWithoutRef 17 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 18 | 19 | 29 | 30 | )) 31 | PopoverContent.displayName = PopoverPrimitive.Content.displayName 32 | 33 | export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-translate", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@headlessui/react": "^2.2.0", 13 | "@radix-ui/react-checkbox": "^1.1.2", 14 | "@radix-ui/react-popover": "^1.1.2", 15 | "@radix-ui/react-progress": "^1.1.0", 16 | "@radix-ui/react-select": "^2.1.2", 17 | "@radix-ui/react-slot": "^1.1.0", 18 | "@radix-ui/react-tabs": "^1.1.1", 19 | "@radix-ui/react-toast": "^1.2.2", 20 | "@types/react-syntax-highlighter": "^15.5.13", 21 | "@types/react-window": "^1.8.8", 22 | "class-variance-authority": "^0.7.0", 23 | "clsx": "^2.1.1", 24 | "jszip": "^3.10.1", 25 | "lucide-react": "^0.456.0", 26 | "next": "14.1.0", 27 | "openai": "^4.71.1", 28 | "react": "18.2.0", 29 | "react-dom": "18.2.0", 30 | "react-syntax-highlighter": "^15.6.1", 31 | "react-window": "^1.8.10", 32 | "tailwind-merge": "^2.5.4", 33 | "tailwindcss-animate": "^1.0.7" 34 | }, 35 | "devDependencies": { 36 | "@tailwindcss/forms": "^0.5.9", 37 | "@types/node": "^20", 38 | "@types/react": "^18", 39 | "@types/react-dom": "^18", 40 | "autoprefixer": "^10.4.20", 41 | "eslint": "8.56.0", 42 | "eslint-config-next": "14.1.0", 43 | "postcss": "^8.4.49", 44 | "tailwindcss": "^3.4.14", 45 | "typescript": "^5" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/components/sections/FeaturesSection.tsx: -------------------------------------------------------------------------------- 1 | import { Code, Languages, Sparkles, Shield } from 'lucide-react' 2 | import { Card, CardContent } from '@/components/ui/card' 3 | 4 | interface FeaturesSectionProps { 5 | dict: { 6 | title: string 7 | items?: { 8 | title: string 9 | description: string 10 | }[] | { 11 | [key: string]: { 12 | title: string 13 | description: string 14 | } 15 | } 16 | } 17 | } 18 | 19 | export function FeaturesSection({ dict }: FeaturesSectionProps) { 20 | const icons = [ 21 | , 22 | , 23 | , 24 | 25 | ] 26 | 27 | const features = Array.isArray(dict.items) 28 | ? dict.items 29 | : Object.values(dict.items || {}) 30 | 31 | return ( 32 |
33 |
34 |

35 | {dict.title} 36 |

37 |
38 | {features.map((feature, index) => ( 39 | 40 | 41 |
42 |
43 | {icons[index]} 44 |
45 |

{feature.title}

46 |

{feature.description}

47 |
48 |
49 |
50 | ))} 51 |
52 |
53 |
54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /tailwind.config.ts.bak: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | darkMode: ["class"], 5 | content: [ 6 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 8 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 9 | ], 10 | theme: { 11 | extend: { 12 | animation: { 13 | 'bounce-slow': 'bounce 3s infinite' 14 | }, 15 | colors: { 16 | background: 'hsl(var(--background))', 17 | foreground: 'hsl(var(--foreground))', 18 | card: { 19 | DEFAULT: 'hsl(var(--card))', 20 | foreground: 'hsl(var(--card-foreground))' 21 | }, 22 | popover: { 23 | DEFAULT: 'hsl(var(--popover))', 24 | foreground: 'hsl(var(--popover-foreground))' 25 | }, 26 | primary: { 27 | DEFAULT: 'hsl(var(--primary))', 28 | foreground: 'hsl(var(--primary-foreground))' 29 | }, 30 | secondary: { 31 | DEFAULT: 'hsl(var(--secondary))', 32 | foreground: 'hsl(var(--secondary-foreground))' 33 | }, 34 | muted: { 35 | DEFAULT: 'hsl(var(--muted))', 36 | foreground: 'hsl(var(--muted-foreground))' 37 | }, 38 | accent: { 39 | DEFAULT: 'hsl(var(--accent))', 40 | foreground: 'hsl(var(--accent-foreground))' 41 | }, 42 | destructive: { 43 | DEFAULT: 'hsl(var(--destructive))', 44 | foreground: 'hsl(var(--destructive-foreground))' 45 | }, 46 | border: 'hsl(var(--border))', 47 | input: 'hsl(var(--input))', 48 | ring: 'hsl(var(--ring))', 49 | chart: { 50 | '1': 'hsl(var(--chart-1))', 51 | '2': 'hsl(var(--chart-2))', 52 | '3': 'hsl(var(--chart-3))', 53 | '4': 'hsl(var(--chart-4))', 54 | '5': 'hsl(var(--chart-5))' 55 | } 56 | }, 57 | borderRadius: { 58 | lg: 'var(--radius)', 59 | md: 'calc(var(--radius) - 2px)', 60 | sm: 'calc(var(--radius) - 4px)' 61 | } 62 | } 63 | }, 64 | plugins: [require("tailwindcss-animate")], 65 | } satisfies Config; 66 | -------------------------------------------------------------------------------- /src/components/VirtualizedJson.tsx: -------------------------------------------------------------------------------- 1 | import { FixedSizeList as List } from 'react-window'; 2 | import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; 3 | import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; 4 | import { memo, useMemo } from 'react'; 5 | 6 | interface VirtualizedJsonProps { 7 | content: string; 8 | height: number; 9 | width: number; 10 | showLineNumbers?: boolean; 11 | } 12 | 13 | const LINE_HEIGHT = 21; 14 | 15 | const VirtualizedJson = memo(({ content, height, width, showLineNumbers = true }: VirtualizedJsonProps) => { 16 | const lines = useMemo(() => content.split('\n'), [content]); 17 | 18 | const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => { 19 | const line = lines[index]; 20 | 21 | return ( 22 |
30 | 45 | {line} 46 | 47 |
48 | ); 49 | }; 50 | 51 | return ( 52 |
53 | 60 | {Row} 61 | 62 |
63 | ); 64 | }); 65 | 66 | VirtualizedJson.displayName = 'VirtualizedJson'; 67 | 68 | export default VirtualizedJson; -------------------------------------------------------------------------------- /src/lib/getDictionary.ts: -------------------------------------------------------------------------------- 1 | const dictionaries = { 2 | en: () => import('@/dictionaries/en.json').then(module => module.default), 3 | zh: () => import('@/dictionaries/zh.json').then(module => module.default), 4 | ja: () => import('@/dictionaries/ja.json').then(module => module.default), 5 | ko: () => import('@/dictionaries/ko.json').then(module => module.default), 6 | fr: () => import('@/dictionaries/fr.json').then(module => module.default), 7 | de: () => import('@/dictionaries/de.json').then(module => module.default), 8 | es: () => import('@/dictionaries/es.json').then(module => module.default), 9 | pt: () => import('@/dictionaries/pt.json').then(module => module.default), 10 | it: () => import('@/dictionaries/it.json').then(module => module.default), 11 | ru: () => import('@/dictionaries/ru.json').then(module => module.default), 12 | ar: () => import('@/dictionaries/ar.json').then(module => module.default), 13 | el: () => import('@/dictionaries/el.json').then(module => module.default), 14 | nl: () => import('@/dictionaries/nl.json').then(module => module.default), 15 | id: () => import('@/dictionaries/id.json').then(module => module.default), 16 | pl: () => import('@/dictionaries/pl.json').then(module => module.default), 17 | th: () => import('@/dictionaries/th.json').then(module => module.default), 18 | tr: () => import('@/dictionaries/tr.json').then(module => module.default), 19 | vi: () => import('@/dictionaries/vi.json').then(module => module.default), 20 | 'zh-TW': () => import('@/dictionaries/zh-TW.json').then(module => module.default), 21 | } 22 | 23 | export const getDictionary = async (locale: string) => { 24 | try { 25 | if (!(locale in dictionaries)) { 26 | console.warn(`Dictionary not found for locale: ${locale}, falling back to English`) 27 | return await dictionaries.en() 28 | } 29 | return await dictionaries[locale as keyof typeof dictionaries]() 30 | } catch (error) { 31 | console.error(`Failed to load dictionary for ${locale}`, error) 32 | return await dictionaries.en() 33 | } 34 | } -------------------------------------------------------------------------------- /src/config/i18n.ts: -------------------------------------------------------------------------------- 1 | export const defaultLocale = 'en' 2 | 3 | export const locales = ['en', 'zh', 'zh-TW', 'ja', 'ko', 'fr', 'de', 'es', 'pt', 'it', 'ru', 'ar', 'el', 'nl', 'id', 'pl', 'th', 'tr', 'vi'] 4 | 5 | export const localeNames = { 6 | en: 'English', 7 | zh: '简体中文', 8 | 'zh-TW': '繁體中文', 9 | ja: '日本語', 10 | ko: '한국어', 11 | fr: 'Français', 12 | de: 'Deutsch', 13 | es: 'Español', 14 | pt: 'Português', 15 | it: 'Italiano', 16 | ru: 'Русский', 17 | ar: 'العربية', 18 | el: 'Ελληνικά', 19 | nl: 'Nederlands', 20 | id: 'Bahasa Indonesia', 21 | pl: 'Polski', 22 | th: 'ไทย', 23 | tr: 'Türkçe', 24 | vi: 'Tiếng Việt' 25 | } 26 | 27 | export const localeConfigs = { 28 | en: { 29 | label: 'English', 30 | dir: 'ltr' 31 | }, 32 | zh: { 33 | label: '简体中文', 34 | dir: 'ltr' 35 | }, 36 | 'zh-TW': { 37 | label: '繁體中文', 38 | dir: 'ltr' 39 | }, 40 | ja: { 41 | label: '日本語', 42 | dir: 'ltr' 43 | }, 44 | ko: { 45 | label: '한국어', 46 | dir: 'ltr' 47 | }, 48 | fr: { 49 | label: 'Français', 50 | dir: 'ltr' 51 | }, 52 | de: { 53 | label: 'Deutsch', 54 | dir: 'ltr' 55 | }, 56 | es: { 57 | label: 'Español', 58 | dir: 'ltr' 59 | }, 60 | pt: { 61 | label: 'Português', 62 | dir: 'ltr' 63 | }, 64 | it: { 65 | label: 'Italiano', 66 | dir: 'ltr' 67 | }, 68 | ru: { 69 | label: 'Русский', 70 | dir: 'ltr' 71 | }, 72 | ar: { 73 | label: 'العربية', 74 | dir: 'rtl' 75 | }, 76 | el: { 77 | label: 'Ελληνικά', 78 | dir: 'ltr' 79 | }, 80 | nl: { 81 | label: 'Nederlands', 82 | dir: 'ltr' 83 | }, 84 | id: { 85 | label: 'Bahasa Indonesia', 86 | dir: 'ltr' 87 | }, 88 | pl: { 89 | label: 'Polski', 90 | dir: 'ltr' 91 | }, 92 | th: { 93 | label: 'ไทย', 94 | dir: 'ltr' 95 | }, 96 | tr: { 97 | label: 'Türkçe', 98 | dir: 'ltr' 99 | }, 100 | vi: { 101 | label: 'Tiếng Việt', 102 | dir: 'ltr' 103 | } 104 | } -------------------------------------------------------------------------------- /src/components/ui/tabs.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as TabsPrimitive from "@radix-ui/react-tabs" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Tabs = TabsPrimitive.Root 9 | 10 | const TabsList = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, ...props }, ref) => ( 14 | 22 | )) 23 | TabsList.displayName = TabsPrimitive.List.displayName 24 | 25 | const TabsTrigger = React.forwardRef< 26 | React.ElementRef, 27 | React.ComponentPropsWithoutRef 28 | >(({ className, ...props }, ref) => ( 29 | 37 | )) 38 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName 39 | 40 | const TabsContent = React.forwardRef< 41 | React.ElementRef, 42 | React.ComponentPropsWithoutRef 43 | >(({ className, ...props }, ref) => ( 44 | 52 | )) 53 | TabsContent.displayName = TabsPrimitive.Content.displayName 54 | 55 | export { Tabs, TabsList, TabsTrigger, TabsContent } 56 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: ["class"], 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | animation: { 12 | 'bounce-slow': 'bounce 3s infinite' 13 | }, 14 | colors: { 15 | background: 'hsl(var(--background))', 16 | foreground: 'hsl(var(--foreground))', 17 | card: { 18 | DEFAULT: 'hsl(var(--card))', 19 | foreground: 'hsl(var(--card-foreground))' 20 | }, 21 | popover: { 22 | DEFAULT: 'hsl(var(--popover))', 23 | foreground: 'hsl(var(--popover-foreground))' 24 | }, 25 | primary: { 26 | DEFAULT: 'hsl(var(--primary))', 27 | foreground: 'hsl(var(--primary-foreground))' 28 | }, 29 | secondary: { 30 | DEFAULT: 'hsl(var(--secondary))', 31 | foreground: 'hsl(var(--secondary-foreground))' 32 | }, 33 | muted: { 34 | DEFAULT: 'hsl(var(--muted))', 35 | foreground: 'hsl(var(--muted-foreground))' 36 | }, 37 | accent: { 38 | DEFAULT: 'hsl(var(--accent))', 39 | foreground: 'hsl(var(--accent-foreground))' 40 | }, 41 | destructive: { 42 | DEFAULT: 'hsl(var(--destructive))', 43 | foreground: 'hsl(var(--destructive-foreground))' 44 | }, 45 | border: 'hsl(var(--border))', 46 | input: 'hsl(var(--input))', 47 | ring: 'hsl(var(--ring))', 48 | chart: { 49 | '1': 'hsl(var(--chart-1))', 50 | '2': 'hsl(var(--chart-2))', 51 | '3': 'hsl(var(--chart-3))', 52 | '4': 'hsl(var(--chart-4))', 53 | '5': 'hsl(var(--chart-5))' 54 | } 55 | }, 56 | borderRadius: { 57 | lg: 'var(--radius)', 58 | md: 'calc(var(--radius) - 2px)', 59 | sm: 'calc(var(--radius) - 4px)' 60 | } 61 | } 62 | }, 63 | plugins: [require("tailwindcss-animate")], 64 | } 65 | -------------------------------------------------------------------------------- /src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90", 14 | destructive: 15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", 16 | outline: 17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", 18 | secondary: 19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", 20 | ghost: "hover:bg-accent hover:text-accent-foreground", 21 | link: "text-primary underline-offset-4 hover:underline", 22 | }, 23 | size: { 24 | default: "h-9 px-4 py-2", 25 | sm: "h-8 rounded-md px-3 text-xs", 26 | lg: "h-10 rounded-md px-8", 27 | icon: "h-9 w-9", 28 | }, 29 | }, 30 | defaultVariants: { 31 | variant: "default", 32 | size: "default", 33 | }, 34 | } 35 | ) 36 | 37 | export interface ButtonProps 38 | extends React.ButtonHTMLAttributes, 39 | VariantProps { 40 | asChild?: boolean 41 | } 42 | 43 | const Button = React.forwardRef( 44 | ({ className, variant, size, asChild = false, ...props }, ref) => { 45 | const Comp = asChild ? Slot : "button" 46 | return ( 47 | 52 | ) 53 | } 54 | ) 55 | Button.displayName = "Button" 56 | 57 | export { Button, buttonVariants } 58 | -------------------------------------------------------------------------------- /src/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Card = React.forwardRef< 6 | HTMLDivElement, 7 | React.HTMLAttributes 8 | >(({ className, ...props }, ref) => ( 9 |
17 | )) 18 | Card.displayName = "Card" 19 | 20 | const CardHeader = React.forwardRef< 21 | HTMLDivElement, 22 | React.HTMLAttributes 23 | >(({ className, ...props }, ref) => ( 24 |
29 | )) 30 | CardHeader.displayName = "CardHeader" 31 | 32 | const CardTitle = React.forwardRef< 33 | HTMLDivElement, 34 | React.HTMLAttributes 35 | >(({ className, ...props }, ref) => ( 36 |
41 | )) 42 | CardTitle.displayName = "CardTitle" 43 | 44 | const CardDescription = React.forwardRef< 45 | HTMLDivElement, 46 | React.HTMLAttributes 47 | >(({ className, ...props }, ref) => ( 48 |
53 | )) 54 | CardDescription.displayName = "CardDescription" 55 | 56 | const CardContent = React.forwardRef< 57 | HTMLDivElement, 58 | React.HTMLAttributes 59 | >(({ className, ...props }, ref) => ( 60 |
61 | )) 62 | CardContent.displayName = "CardContent" 63 | 64 | const CardFooter = React.forwardRef< 65 | HTMLDivElement, 66 | React.HTMLAttributes 67 | >(({ className, ...props }, ref) => ( 68 |
73 | )) 74 | CardFooter.displayName = "CardFooter" 75 | 76 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 77 | -------------------------------------------------------------------------------- /src/components/sections/CTASection.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { Button } from "@/components/ui/button" 3 | import { ArrowRight, Check } from "lucide-react" 4 | 5 | interface CTASectionProps { 6 | dict: { 7 | title: string 8 | description: string 9 | button: string 10 | features: string[] | { [key: string]: string } 11 | } 12 | } 13 | 14 | export function CTASection({ dict }: CTASectionProps) { 15 | const scrollToTop = () => { 16 | window.scrollTo({ top: 0, behavior: 'smooth' }); 17 | }; 18 | 19 | const features = Array.isArray(dict.features) 20 | ? dict.features 21 | : Object.values(dict.features) 22 | 23 | return ( 24 |
25 |
26 |
27 |

28 | {dict.title} 29 |

30 |

31 | {dict.description} 32 |

33 | 34 | 40 | 41 |
42 | {features.map((feature, index) => ( 43 |
47 | 53 | 59 | 60 | {feature} 61 |
62 | ))} 63 |
64 |
65 |
66 |
67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /src/components/sections/FAQ.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useState } from 'react' 4 | import { ChevronDown } from 'lucide-react' 5 | 6 | interface FAQProps { 7 | dict: { 8 | title: string 9 | description: string 10 | items: { 11 | question: string 12 | answer: string 13 | }[] | { 14 | [key: string]: { 15 | question: string 16 | answer: string 17 | } 18 | } 19 | } 20 | } 21 | 22 | export default function FAQ({ dict }: FAQProps) { 23 | const [openIndex, setOpenIndex] = useState(null) 24 | 25 | const faqs = Array.isArray(dict.items) 26 | ? dict.items 27 | : Object.values(dict.items) 28 | 29 | return ( 30 |
31 |
32 |
33 |

34 | {dict.title} 35 |

36 |

37 | {dict.description} 38 |

39 |
40 | 41 |
42 | {faqs.map((faq, index) => ( 43 |
47 | 58 | 59 |
64 |

65 | {faq.answer} 66 |

67 |
68 |
69 | ))} 70 |
71 |
72 |
73 | ) 74 | } -------------------------------------------------------------------------------- /src/components/sections/WorkflowSection.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { Upload, Languages, Sparkles, Download } from 'lucide-react' 3 | 4 | interface WorkflowSectionProps { 5 | dict: { 6 | title: string 7 | description: string 8 | steps: { 9 | [key: string]: { 10 | title: string 11 | description: string 12 | } 13 | } | { 14 | title: string 15 | description: string 16 | }[] 17 | } 18 | } 19 | 20 | export function WorkflowSection({ dict }: WorkflowSectionProps) { 21 | const icons = [ 22 | , 23 | , 24 | , 25 | 26 | ] 27 | 28 | // 处理 steps 可能是对象或数组的情况 29 | const steps = Array.isArray(dict.steps) 30 | ? dict.steps 31 | : Object.values(dict.steps) 32 | 33 | return ( 34 |
35 |
36 |
37 |

38 | {dict.title} 39 |

40 |

41 | {dict.description} 42 |

43 |
44 | 45 |
46 | {steps.map((step, index) => ( 47 |
48 | {index < steps.length - 1 && ( 49 |
50 | )} 51 | 52 |
53 |
54 |
55 | {icons[index]} 56 |
57 | 58 | {String(index + 1).padStart(2, '0')} 59 | 60 |
61 |

62 | {step.title} 63 |

64 |

65 | {step.description} 66 |

67 |
68 |
69 | ))} 70 |
71 |
72 |
73 | ) 74 | } 75 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | font-family: Arial, Helvetica, sans-serif; 7 | } 8 | 9 | @layer base { 10 | :root { 11 | --background: 0 0% 100%; 12 | --foreground: 0 0% 3.9%; 13 | --card: 0 0% 100%; 14 | --card-foreground: 0 0% 3.9%; 15 | --popover: 0 0% 100%; 16 | --popover-foreground: 0 0% 3.9%; 17 | --primary: 0 0% 9%; 18 | --primary-foreground: 0 0% 98%; 19 | --secondary: 0 0% 96.1%; 20 | --secondary-foreground: 0 0% 9%; 21 | --muted: 0 0% 96.1%; 22 | --muted-foreground: 0 0% 45.1%; 23 | --accent: 0 0% 96.1%; 24 | --accent-foreground: 0 0% 9%; 25 | --destructive: 0 84.2% 60.2%; 26 | --destructive-foreground: 0 0% 98%; 27 | --border: 0 0% 89.8%; 28 | --input: 0 0% 89.8%; 29 | --ring: 0 0% 3.9%; 30 | --chart-1: 12 76% 61%; 31 | --chart-2: 173 58% 39%; 32 | --chart-3: 197 37% 24%; 33 | --chart-4: 43 74% 66%; 34 | --chart-5: 27 87% 67%; 35 | --radius: 0.5rem; 36 | } 37 | .dark { 38 | --background: 0 0% 3.9%; 39 | --foreground: 0 0% 98%; 40 | --card: 0 0% 3.9%; 41 | --card-foreground: 0 0% 98%; 42 | --popover: 0 0% 3.9%; 43 | --popover-foreground: 0 0% 98%; 44 | --primary: 0 0% 98%; 45 | --primary-foreground: 0 0% 9%; 46 | --secondary: 0 0% 14.9%; 47 | --secondary-foreground: 0 0% 98%; 48 | --muted: 0 0% 14.9%; 49 | --muted-foreground: 0 0% 63.9%; 50 | --accent: 0 0% 14.9%; 51 | --accent-foreground: 0 0% 98%; 52 | --destructive: 0 62.8% 30.6%; 53 | --destructive-foreground: 0 0% 98%; 54 | --border: 0 0% 14.9%; 55 | --input: 0 0% 14.9%; 56 | --ring: 0 0% 83.1%; 57 | --chart-1: 220 70% 50%; 58 | --chart-2: 160 60% 45%; 59 | --chart-3: 30 80% 55%; 60 | --chart-4: 280 65% 60%; 61 | --chart-5: 340 75% 55%; 62 | } 63 | } 64 | 65 | @layer base { 66 | * { 67 | @apply border-border; 68 | } 69 | body { 70 | @apply bg-background text-foreground; 71 | } 72 | } 73 | 74 | .syntax-highlighter { 75 | background-color: #282c34; 76 | border-radius: 0.375rem; 77 | color: #abb2bf; 78 | } 79 | 80 | /* 通用滚动条样式 */ 81 | ::-webkit-scrollbar { 82 | width: 12px; 83 | height: 12px; 84 | } 85 | 86 | ::-webkit-scrollbar-thumb { 87 | background-color: hsl(var(--muted-foreground) / 0.2); 88 | border-radius: 3px; 89 | } 90 | 91 | ::-webkit-scrollbar-track { 92 | background-color: transparent; 93 | } 94 | 95 | /* 代码编辑器特定的滚动条样式 */ 96 | .syntax-highlighter::-webkit-scrollbar { 97 | width: 12px; 98 | height: 12px; 99 | } 100 | 101 | .syntax-highlighter::-webkit-scrollbar-thumb { 102 | background-color: hsl(var(--muted-foreground) / 0.2); 103 | border-radius: 3px; 104 | } 105 | 106 | .syntax-highlighter::-webkit-scrollbar-track { 107 | background-color: transparent; 108 | } 109 | -------------------------------------------------------------------------------- /src/components/sections/HeroSection.tsx: -------------------------------------------------------------------------------- 1 | import { Sparkles } from 'lucide-react' 2 | 3 | interface HeroSectionProps { 4 | dict: { 5 | badge: string; 6 | title: string; 7 | description: string; 8 | features: { 9 | multilanguage: string; 10 | realtime: string; 11 | } 12 | } 13 | } 14 | 15 | export const HeroSection = ({ dict }: HeroSectionProps) => { 16 | return ( 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | 25 | {dict.badge} 26 | 27 |
28 |

29 | {dict.title} 30 |

31 |

32 | {dict.description} 33 |

34 |
35 |
36 | 37 | 38 | 39 | 40 | {dict.features.multilanguage} 41 |
42 |
43 | 44 | 45 | 46 | {dict.features.realtime} 47 |
48 |
49 |
50 |
51 |
52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /src/components/TranslateProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { createContext, useContext, useState } from 'react' 4 | 5 | type TranslateContextType = { 6 | file: File | null 7 | setFile: (file: File | null) => void 8 | isUploaded: boolean 9 | setIsUploaded: (isUploaded: boolean) => void 10 | fileInfo: { name: string; size: string } | null 11 | setFileInfo: (fileInfo: { name: string; size: string } | null) => void 12 | selectedLangs: string[] 13 | setSelectedLangs: (langs: string[]) => void 14 | translatedResults: { lang: string; content: string }[] 15 | setTranslatedResults: (results: { lang: string; content: string }[]) => void 16 | isTranslating: boolean 17 | setIsTranslating: (isTranslating: boolean) => void 18 | progress: number 19 | setProgress: (progress: number) => void 20 | streamContent: string 21 | setStreamContent: (content: string) => void 22 | currentTranslatingLang: string | null 23 | setCurrentTranslatingLang: (lang: string | null) => void 24 | estimatedTime: number 25 | setEstimatedTime: (time: number) => void 26 | completedChunks: number 27 | setCompletedChunks: (chunks: number) => void 28 | } 29 | 30 | const TranslateContext = createContext(undefined) 31 | 32 | export function TranslateProvider({ children }: { children: React.ReactNode }) { 33 | const [file, setFile] = useState(null) 34 | const [isUploaded, setIsUploaded] = useState(false) 35 | const [fileInfo, setFileInfo] = useState<{ name: string; size: string } | null>(null) 36 | const [selectedLangs, setSelectedLangs] = useState([]) 37 | const [translatedResults, setTranslatedResults] = useState<{ lang: string; content: string }[]>([]) 38 | const [isTranslating, setIsTranslating] = useState(false) 39 | const [progress, setProgress] = useState(0) 40 | const [streamContent, setStreamContent] = useState('') 41 | const [currentTranslatingLang, setCurrentTranslatingLang] = useState(null) 42 | const [estimatedTime, setEstimatedTime] = useState(0) 43 | const [completedChunks, setCompletedChunks] = useState(0) 44 | 45 | return ( 46 | 72 | {children} 73 | 74 | ) 75 | } 76 | 77 | export function useTranslate() { 78 | const context = useContext(TranslateContext) 79 | if (context === undefined) { 80 | throw new Error('useTranslate must be used within a TranslateProvider') 81 | } 82 | return context 83 | } -------------------------------------------------------------------------------- /src/components/LanguageSwitcher.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { usePathname, useRouter } from 'next/navigation' 4 | import { locales, localeNames } from '@/config/i18n' 5 | import { useState, useEffect } from 'react' 6 | import { Button } from '@/components/ui/button' 7 | import { 8 | Popover, 9 | PopoverContent, 10 | PopoverTrigger, 11 | } from '@/components/ui/popover' 12 | import { Check, Globe } from 'lucide-react' 13 | import { cn } from '@/lib/utils' 14 | 15 | export default function LanguageSwitcher() { 16 | const pathname = usePathname() 17 | const router = useRouter() 18 | const [mounted, setMounted] = useState(false) 19 | const [currentLang, setCurrentLang] = useState('') 20 | const [open, setOpen] = useState(false) 21 | const [scrolled, setScrolled] = useState(false) 22 | 23 | useEffect(() => { 24 | setMounted(true) 25 | setCurrentLang(pathname.split('/')[1]) 26 | }, [pathname]) 27 | 28 | useEffect(() => { 29 | const handleScroll = () => { 30 | setScrolled(window.scrollY > 0) 31 | } 32 | 33 | window.addEventListener('scroll', handleScroll) 34 | handleScroll() // 初始检查 35 | 36 | return () => window.removeEventListener('scroll', handleScroll) 37 | }, []) 38 | 39 | const handleChange = (newLocale: string) => { 40 | const newPath = pathname.replace(`/${currentLang}`, `/${newLocale}`) 41 | router.push(newPath) 42 | setOpen(false) 43 | } 44 | 45 | if (!mounted) return null 46 | 47 | return ( 48 | 49 | 50 | 68 | 69 | 73 |
74 | {locales.map((locale) => ( 75 | 89 | ))} 90 |
91 |
92 |
93 | ) 94 | } -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | interface FooterProps { 2 | dict: { 3 | creator: string 4 | twitter: string 5 | coffee: string 6 | } 7 | } 8 | 9 | export default function Footer({ dict }: FooterProps) { 10 | return ( 11 | 73 | ) 74 | } -------------------------------------------------------------------------------- /src/context/TranslateContext.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { createContext, useContext, useState } from 'react' 4 | 5 | interface TranslatedResult { 6 | lang: string 7 | content: string 8 | } 9 | 10 | interface TranslateContextType { 11 | file: File | null 12 | setFile: (file: File | null) => void 13 | sourceLang: string 14 | setSourceLang: (lang: string) => void 15 | apiKey: string 16 | setApiKey: (key: string) => void 17 | isTranslating: boolean 18 | setIsTranslating: (status: boolean) => void 19 | translatedContent: string 20 | setTranslatedContent: (content: string) => void 21 | progress: number 22 | setProgress: (progress: number) => void 23 | cancelTranslation: boolean 24 | setCancelTranslation: (cancel: boolean) => void 25 | streamContent: string 26 | setStreamContent: (content: string) => void 27 | translatedResults: TranslatedResult[] 28 | setTranslatedResults: (results: TranslatedResult[]) => void 29 | selectedLangs: string[] 30 | setSelectedLangs: (langs: string[]) => void 31 | currentTranslatingLang: string | null 32 | setCurrentTranslatingLang: (lang: string | null) => void 33 | totalProgress: number; 34 | setTotalProgress: (progress: number) => void; 35 | estimatedTime: number; 36 | setEstimatedTime: (time: number) => void; 37 | resetTranslation: () => void; 38 | } 39 | 40 | const TranslateContext = createContext(undefined) 41 | 42 | export function TranslateProvider({ children }: { children: React.ReactNode }) { 43 | const [file, setFile] = useState(null) 44 | const [sourceLang, setSourceLang] = useState('en') 45 | const [apiKey, setApiKey] = useState('') 46 | const [isTranslating, setIsTranslating] = useState(false) 47 | const [translatedContent, setTranslatedContent] = useState('') 48 | const [progress, setProgress] = useState(0) 49 | const [cancelTranslation, setCancelTranslation] = useState(false) 50 | const [streamContent, setStreamContent] = useState('') 51 | const [translatedResults, setTranslatedResults] = useState([]) 52 | const [selectedLangs, setSelectedLangs] = useState(['en', 'de', 'ja', 'ru', 'tr', 'pt', 'es', 'fr', 'zh']) 53 | const [currentTranslatingLang, setCurrentTranslatingLang] = useState(null) 54 | const [totalProgress, setTotalProgress] = useState(0) 55 | const [estimatedTime, setEstimatedTime] = useState(0) 56 | 57 | const resetTranslation = () => { 58 | setTranslatedResults([]); 59 | setTranslatedContent(''); 60 | setStreamContent(''); 61 | setProgress(0); 62 | setTotalProgress(0); 63 | setEstimatedTime(0); 64 | setCurrentTranslatingLang(null); 65 | }; 66 | 67 | const value = { 68 | file, 69 | setFile, 70 | sourceLang, 71 | setSourceLang, 72 | apiKey, 73 | setApiKey, 74 | isTranslating, 75 | setIsTranslating, 76 | translatedContent, 77 | setTranslatedContent, 78 | progress, 79 | setProgress, 80 | cancelTranslation, 81 | setCancelTranslation, 82 | streamContent, 83 | setStreamContent, 84 | translatedResults, 85 | setTranslatedResults, 86 | selectedLangs, 87 | setSelectedLangs, 88 | currentTranslatingLang, 89 | setCurrentTranslatingLang, 90 | totalProgress, 91 | setTotalProgress, 92 | estimatedTime, 93 | setEstimatedTime, 94 | resetTranslation, 95 | } 96 | 97 | return ( 98 | 99 | {children} 100 | 101 | ) 102 | } 103 | 104 | export function useTranslate() { 105 | const context = useContext(TranslateContext) 106 | if (context === undefined) { 107 | throw new Error('useTranslate must be used within a TranslateProvider') 108 | } 109 | return context 110 | } -------------------------------------------------------------------------------- /src/lib/openai.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from 'openai' 2 | 3 | export async function translate( 4 | text: string, 5 | targetLang: string, 6 | apiKey: string, 7 | signal?: AbortSignal, 8 | onProgress?: (progress: number) => void, 9 | onStream?: (chunk: string) => void 10 | ) { 11 | if (!apiKey.startsWith('sk-')) { 12 | throw new Error('Invalid API Key format') 13 | } 14 | 15 | const openai = new OpenAI({ 16 | apiKey, 17 | dangerouslyAllowBrowser: true 18 | }) 19 | 20 | try { 21 | const prompt = `Please translate the following JSON content to ${targetLang}, keep the JSON structure unchanged, only translate the value part. 22 | Note: 23 | 1. Keep all keys unchanged 24 | 2. Only translate value parts 25 | 3. Keep JSON format valid 26 | 4. Keep all special characters and formats 27 | 28 | JSON content: 29 | ${text}` 30 | 31 | const response = await openai.chat.completions.create({ 32 | model: "gpt-4o-mini", 33 | messages: [ 34 | { 35 | role: "system", 36 | content: "You are a professional JSON translation assistant. Please return the translated JSON content directly, without adding any markdown tags or other formats." 37 | }, 38 | { 39 | role: "user", 40 | content: prompt 41 | } 42 | ], 43 | temperature: 0.3, 44 | stream: true 45 | }, { 46 | signal 47 | }) 48 | 49 | let fullContent = '' 50 | let tokenCount = 0 51 | const estimatedTokens = text.length / 4 // Estimate total token count 52 | 53 | for await (const chunk of response) { 54 | const content = chunk.choices[0]?.delta?.content || '' 55 | fullContent += content 56 | tokenCount += content.length / 4 57 | 58 | // Calculate current progress 59 | const progress = Math.min(Math.round((tokenCount / estimatedTokens) * 100), 100) 60 | onProgress?.(progress) 61 | 62 | onStream?.(fullContent) 63 | } 64 | 65 | // Validate final JSON format 66 | try { 67 | const parsedJson = JSON.parse(fullContent) 68 | fullContent = JSON.stringify(parsedJson, null, 2) 69 | } catch (e) { 70 | if (signal?.aborted) { 71 | return '' 72 | } 73 | throw new Error(`Invalid translation result format: ${(e as Error).message}`) 74 | } 75 | 76 | return fullContent 77 | 78 | } catch (error: unknown) { 79 | if (signal?.aborted || (error instanceof DOMException && error.name === 'AbortError')) { 80 | return '' 81 | } 82 | 83 | if (error instanceof OpenAI.APIError) { 84 | if (error.status === 401) { 85 | throw new Error('Invalid or expired API Key') 86 | } 87 | 88 | if (error.status === 429) { 89 | throw new Error('API call limit reached') 90 | } 91 | } 92 | 93 | throw error 94 | } 95 | } 96 | 97 | export async function validateApiKey(apiKey: string): Promise { 98 | if (!apiKey.startsWith('sk-')) { 99 | throw new Error('Invalid API Key format') 100 | } 101 | 102 | const openai = new OpenAI({ 103 | apiKey, 104 | dangerouslyAllowBrowser: true 105 | }) 106 | 107 | try { 108 | // Send a minimal request to validate the API key 109 | await openai.chat.completions.create({ 110 | model: "gpt-4o-mini", 111 | messages: [{ role: "user", content: "test" }], 112 | max_tokens: 1 113 | }) 114 | return true 115 | } catch (error) { 116 | if (error instanceof OpenAI.APIError) { 117 | if (error.status === 401) { 118 | throw new Error('Invalid or expired API Key') 119 | } 120 | if (error.status === 429) { 121 | throw new Error('API call limit reached') 122 | } 123 | } 124 | throw error 125 | } 126 | } -------------------------------------------------------------------------------- /src/app/[lang]/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from "next"; 2 | import localFont from "next/font/local"; 3 | import "../globals.css"; 4 | import { Toaster } from "@/components/ui/toaster"; 5 | import Navbar from "@/components/Navbar"; 6 | import { TranslateProvider } from "@/context/TranslateContext"; 7 | import { locales, defaultLocale } from "@/config/i18n"; 8 | import { notFound } from "next/navigation"; 9 | import { cn } from "@/lib/utils"; 10 | import { ReactNode } from "react"; 11 | import Analytics from '@/components/Analytics' 12 | 13 | const geistSans = localFont({ 14 | src: "../fonts/GeistVF.woff", 15 | variable: "--font-geist-sans", 16 | weight: "100 900", 17 | }); 18 | const geistMono = localFont({ 19 | src: "../fonts/GeistMonoVF.woff", 20 | variable: "--font-geist-mono", 21 | weight: "100 900", 22 | }); 23 | 24 | interface LayoutProps { 25 | children: ReactNode; 26 | params: { 27 | lang: string; 28 | }; 29 | } 30 | 31 | export async function generateMetadata( 32 | { params }: Pick 33 | ): Promise { 34 | const lang = params.lang 35 | 36 | // 导入对应语言的字典 37 | const dict = await import(`@/dictionaries/${params.lang}.json`).then( 38 | (module) => module.default 39 | ); 40 | 41 | // 构建语言替代链接对象 42 | const languageAlternates = { 43 | 'en': '/en', 44 | 'zh': '/zh', 45 | 'zh-TW': '/zh-TW', 46 | 'ja': '/ja', 47 | 'ko': '/ko', 48 | 'fr': '/fr', 49 | 'de': '/de', 50 | 'es': '/es', 51 | 'pt': '/pt', 52 | 'it': '/it', 53 | 'ru': '/ru', 54 | 'ar': '/ar', 55 | 'el': '/el', 56 | 'nl': '/nl', 57 | 'id': '/id', 58 | 'pl': '/pl', 59 | 'th': '/th', 60 | 'tr': '/tr', 61 | 'vi': '/vi' 62 | } 63 | 64 | return { 65 | title: dict.metadata.title, 66 | description: dict.metadata.description, 67 | keywords: dict.metadata.keywords, 68 | icons: { 69 | icon: '/favicon.png', 70 | shortcut: '/favicon.png', 71 | apple: '/favicon.png', 72 | }, 73 | openGraph: { 74 | title: dict.metadata.title, 75 | description: dict.metadata.description, 76 | locale: params.lang, 77 | type: 'website', 78 | images: [ 79 | { 80 | url: 'https://json.uiboy.com/og-image.png', 81 | width: 1200, 82 | height: 630, 83 | alt: dict.metadata.title 84 | } 85 | ] 86 | }, 87 | twitter: { 88 | card: 'summary_large_image', 89 | title: dict.metadata.title, 90 | description: dict.metadata.description, 91 | images: ['https://json.uiboy.com/og-image.png'] 92 | }, 93 | alternates: { 94 | languages: languageAlternates 95 | }, 96 | robots: { 97 | index: true, 98 | follow: true, 99 | googleBot: { 100 | index: true, 101 | follow: true, 102 | 'max-video-preview': -1, 103 | 'max-image-preview': 'large', 104 | 'max-snippet': -1, 105 | }, 106 | } 107 | } 108 | } 109 | 110 | export async function generateStaticParams() { 111 | return locales.map((locale) => ({ lang: locale })) 112 | } 113 | 114 | export default async function LocaleLayout(props: LayoutProps) { 115 | const { children, params: { lang } } = props; 116 | 117 | if (!locales.includes(lang)) { 118 | notFound(); 119 | } 120 | 121 | const dict = await import(`@/dictionaries/${lang}.json`).then( 122 | (module) => module.default 123 | ); 124 | 125 | return ( 126 | 127 | 132 | 133 | 134 | 135 | {children} 136 | 137 | 138 | 139 | 140 | ); 141 | } -------------------------------------------------------------------------------- /src/app/[lang]/page.tsx: -------------------------------------------------------------------------------- 1 | import { getDictionary } from '@/lib/getDictionary' 2 | import { HeroSection } from '@/components/sections/HeroSection' 3 | import { JsonPreview } from '@/components/JsonPreview' 4 | import { FileUpload } from '@/components/FileUpload' 5 | import { TranslatePanel } from '@/components/TranslatePanel' 6 | import { FileIcon, Languages } from 'lucide-react' 7 | import { WorkflowSection } from '@/components/sections/WorkflowSection' 8 | import { FeaturesSection } from '@/components/sections/FeaturesSection' 9 | import { CTASection } from '@/components/sections/CTASection' 10 | import FAQ from '@/components/sections/FAQ' 11 | import Footer from '@/components/Footer' 12 | 13 | export default async function Home({ 14 | params, 15 | }: { 16 | params: { lang: string } 17 | }) { 18 | const lang = await params.lang 19 | const dict = await getDictionary(lang) 20 | 21 | return ( 22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 |
30 |

31 | 32 | {dict.uploadSection.title} 33 |

34 | 35 |
36 | 37 |
38 |

39 | 40 | {dict.translateSection.title} 41 |

42 |

43 | {dict.translateSection.description} 44 |

45 | 51 |
52 |
53 | 54 |
55 |
56 | ; 79 | } 80 | }} /> 81 |
82 |
83 |
84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 |
92 |
93 |
94 | ) 95 | } 96 | -------------------------------------------------------------------------------- /src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import Image from "next/image" 4 | import Link from "next/link" 5 | import { useEffect, useState } from "react" 6 | import LanguageSwitcher from '@/components/LanguageSwitcher' 7 | 8 | export default function Navbar() { 9 | const [scrolled, setScrolled] = useState(false) 10 | const [mounted, setMounted] = useState(false) 11 | 12 | useEffect(() => { 13 | const handleScroll = () => { 14 | const isScrolled = window.scrollY > 10 15 | if (isScrolled !== scrolled) { 16 | setScrolled(isScrolled) 17 | } 18 | } 19 | 20 | window.addEventListener('scroll', handleScroll, { passive: true }) 21 | return () => window.removeEventListener('scroll', handleScroll) 22 | }, [scrolled]) 23 | 24 | useEffect(() => { 25 | setMounted(true) 26 | }, []) 27 | 28 | return ( 29 | 97 | ) 98 | } -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # JSON i18n 翻译工具 2 | 3 |

4 | JSON Translate Logo 5 |

6 | 7 |

8 | 🌐 AI驱动的JSON国际化翻译工具 9 |

10 | 11 |

12 | 🔗 json.uiboy.com
13 | 免费在线JSON翻译工具,支持40+种语言,由AI驱动 14 |

15 | 16 |

17 | 18 | 官网 19 | 20 | 21 | License 22 | 23 | 24 | Version 25 | 26 | 27 | Built with Cursor 28 | 29 |

30 | 31 |

32 | English | 33 | 简体中文 34 |

35 | 36 |

37 | 🎯 AI 辅助开发全过程开源 38 |

39 | 40 |

41 | 这个项目展示了一个完整的 AI 辅助开发过程,从产品设计到代码实现 42 |

43 | 44 |

45 | 开源内容包括: 46 |

47 | 48 |

49 | 🔸 产品需求文档 - 完整的 AI 辅助产品需求文档
50 | 🔸 源代码 - 全部项目代码与 AI 功能实现 51 |

52 | 53 | ## ✨ 特性 54 | 55 | - 🤖 基于OpenAI GPT模型的智能翻译 56 | - 🔄 保持JSON结构完整性 57 | - 🌍 支持40+种语言 58 | - 🌐 网站界面支持多语言切换 59 | - ⚡️ 实时翻译预览 60 | - 🛡️ API密钥本地使用,注重安全 61 | - 📦 支持批量导出翻译结果 62 | - 🎯 专业术语准确翻译 63 | - 💻 完全开源,代码透明 64 | 65 | ## 📖 AI驱动的产品设计 66 | 67 | 本项目包含完整的产品需求文档(提供中英文版本): 68 | - [English PRD](./json-translator-prd.md) 69 | - [中文 PRD](./json-translator-prd.zh.md) 70 | 71 | ## 🚀 快速开始 72 | 73 | ### 环境要求 74 | 75 | - Node.js >= 16.0.0 76 | - npm 或 yarn 或 pnpm 77 | - OpenAI API密钥 78 | 79 | ### 安装 80 | 81 | ```bash 82 | git clone https://github.com/ViggoZ/json-translate.git 83 | ``` 84 | 85 | ```bash 86 | cd json-translate 87 | ``` 88 | 89 | ```bash 90 | npm install 91 | ``` 92 | 93 | ### 开发 94 | 95 | ```bash 96 | npm run dev 97 | ``` 98 | 访问 http://localhost:3000 查看开发环境。 99 | 100 | ### 构建 101 | 102 | ```bash 103 | npm run build 104 | ``` 105 | 106 | ```bash 107 | npm run start 108 | ``` 109 | 110 | ## 📖 使用指南 111 | 112 | 1. **准备工作** 113 | - 准备需要翻译的JSON文件 114 | - 获取OpenAI API密钥 (https://platform.openai.com) 115 | 116 | 2. **开始使用** 117 | - 访问网站 118 | - 上传JSON文件 (支持拖拽上传) 119 | - 选择目标语言 120 | - 输入API密钥 121 | - 点击开始翻译 122 | 123 | 3. **功能说明** 124 | - 支持单个JSON文件翻译 125 | - 实时预览翻译结果 126 | - 支持导出JSON格式 127 | 128 | ## 💡 最佳实践 129 | 130 | - 建议将大文件拆分成小文件翻译 131 | - 翻译前检查JSON格式是否正确 132 | - 使用预览功能确认翻译质量 133 | - 定期备份重要的翻译文件 134 | 135 | ## 🛠 技术栈 136 | 137 | - **开发工具**: 138 | - Cursor (AI辅助开发) 139 | - **框架**: Next.js 14 140 | - **UI**: 141 | - React 18 142 | - Tailwind CSS 143 | - Radix UI 144 | - HeadlessUI 145 | - **语言**: TypeScript 146 | - **API**: OpenAI API 147 | - **工具库**: 148 | - JSZip (文件处理) 149 | - React Syntax Highlighter (代码高亮) 150 | - React Window (虚拟列表) 151 | 152 | ## 🤝 贡献指南 153 | 154 | 我欢迎所有形式的贡献,无论是新功能、bug修复还是文档改进。 155 | 156 | 1. Fork 项目 157 | 2. 创建分支 (`git checkout -b feature/YourFeature`) 158 | 3. 提交更改 (`git commit -m 'Add some feature'`) 159 | 4. 推送到分支 (`git push origin feature/YourFeature`) 160 | 5. 提交 Pull Request 161 | 162 | ### 开发指南 163 | - 遵循项目现有的代码风格 164 | - 确保代码通过 `npm run lint` 检查 165 | - 提交前测试功能是否正常工作 166 | 167 | ## 📝 开源协议 168 | 169 | 本项目采用 MIT 协议 - 查看 [LICENSE](LICENSE) 文件了解详情 170 | 171 | ## 🙋 常见问题 172 | 173 | **Q: API密钥安全吗?** 174 | A: 是的。API密钥仅在浏览器中临时使用,不会保存或传输到服务器。 175 | 176 | **Q: 支持哪些语言?** 177 | A: 支持40+种主流语言,包括但不限于: 178 | - 中文(简体/繁体) 179 | - 英语 180 | - 日语 181 | - 韩语 182 | - 法语 183 | - 德语 184 | - 西班牙语 185 | - 俄语 186 | 等 187 | 188 | **Q: 文件大小有限制吗?** 189 | A: 单个文件限制为10MB。 190 | 191 | ## 📞 联系方式 192 | 193 | - 作者:Viggo 194 | - Email:viggo.zw@gmail.com 195 | - Twitter:[@viggo](https://twitter.com/decohack) 196 | 197 | ## 🌟 致谢 198 | 199 | 感谢所有为这个项目提供反馈的用户。特别感谢: 200 | 201 | - OpenAI 团队提供的强大API支持 202 | - Next.js 团队的出色框架 203 | - 所有项目贡献者 204 | 205 | --- 206 | 207 | 如果这个项目对你有帮助,欢迎 star ⭐️ 支持一下! 208 | 209 |

用 ❤️ 制作 by [@viggo](https://twitter.com/decohack)

-------------------------------------------------------------------------------- /json-translator-prd.zh.md: -------------------------------------------------------------------------------- 1 | # 网站PRD文档 2 | 3 | ## 项目背景与痛点分析 4 | 5 | ### 现状问题 6 | 1. **手动翻译效率低** 7 | - 开发者在进行国际化(i18n)时需要手动翻译大量语言文件 8 | - 翻译过程繁琐耗时,特别是需要支持多种语言时 9 | - 人工翻译容易出现疏漏和不一致 10 | 11 | 2. **JSON文件处理难度大** 12 | - 语言文件通常采用复杂的JSON结构(深层嵌套、数组等) 13 | - 手动编辑容易破坏JSON格式 14 | - 缺乏文件结构可视化工具 15 | - 大型JSON文件处理困难 16 | 17 | 3. **翻译质量与成本的矛盾** 18 | - 专业翻译服务成本高昂 19 | - 普通机器翻译质量不稳定 20 | - 缺乏行业术语的统一管理 21 | 22 | 4. **工具链不完整** 23 | - 现有工具功能分散 24 | - 缺乏一站式解决方案 25 | - 协作效率低下 26 | - 版本管理困难 27 | 28 | ### 解决方案价值 29 | 30 | 1. **提升开发效率** 31 | - 自动化翻译流程 32 | - 批量处理能力 33 | - 保持JSON结构完整性 34 | - 可视化编辑界面 35 | 36 | 2. **保证翻译质量** 37 | - 利用OpenAI API提供高质量翻译 38 | - 自定义术语管理 39 | - 多人协作校对 40 | 41 | 3. **降低使用成本** 42 | - 提供免费基础功能 43 | - 按需付费模式 44 | - 减少人工校对成本 45 | 46 | 4. **优化用户体验** 47 | - 简单直观的操作界面 48 | - 实时预览对比 49 | - 进度保存功能 50 | - 完整的错误提示 51 | 52 | ## 目标用户 53 | 54 | 1. **开发者** 55 | - 前端工程师 56 | - 全栈开发者 57 | - 独立开发者 58 | 59 | 2. **企业用户** 60 | - 需要本地化的产品团队 61 | - 跨国企业 62 | - 软件开发公司 63 | 64 | 3. **内容创作者** 65 | - 技术文档作者 66 | - 内容运营团队 67 | - 本地化团队 68 | 69 | ## 核心功能 70 | 71 | 1. **JSON文件上传** 72 | - 用户可以在界面上上传需要翻译的JSON文件。 73 | - 支持拖拽和点击上传。 74 | 75 | 2. **语言选择** 76 | - 提供多种目标语言选项,用户可以选择需要翻译的语言。 77 | 78 | 3. **OpenAI API集成** 79 | - 用户需输入自己的OpenAI API Key。 80 | - 使用GPT模型进行智能翻译。 81 | 82 | 4. **翻译结果预览** 83 | - 翻译完成后,用户可以在界面上预览翻译结果。 84 | - 支持查看原文和译文的对比。 85 | 86 | 5. **下载翻译文件** 87 | - 用户可以下载翻译后的JSON文件。 88 | 89 | 6. **用户界面** 90 | - 简洁易用的界面,支持响应式设计。 91 | - 提供API Key输入入口,确保安全性。 92 | 93 | 7. **JSON文件处理** 94 | - 支持嵌套结构的JSON文件 95 | - 支持数组类型的JSON结构 96 | - 保持原始JSON文件的格式和缩进 97 | - 支持注释的保留(如果有) 98 | - 支持特殊字符和Unicode编码 99 | 100 | 8. **翻译处理** 101 | - 智能识别需要翻译的文本内容 102 | - 保留变量占位符(如 {name}, {year} 等) 103 | - 保持HTML标签和Markdown格式 104 | - 支持批量翻译多个文件 105 | - 支持翻译进度保存和断点续传 106 | 107 | 9. **文件对比功能** 108 | - 提供原文和译文的并排对比视图 109 | - 支持差异高亮显示 110 | - 支持按层级展开/折叠 111 | 112 | ## 技术栈 113 | 114 | - **前端框架**: Next.js 14 115 | - 提供服务端渲染和静态网站生成能力 116 | - App Router架构 117 | - React Server Components 118 | 119 | - **UI组件库**: shadcn/ui 120 | - 基于 Radix UI 的高质量组件库 121 | - 使用 Tailwind CSS 样式系统 122 | - 主要使用组件: 123 | - Button - 用于文件上传和操作按钮 124 | - Input - 用于API Key输入 125 | - Select - 用于语言选择 126 | - Toast - 用于操作反馈 127 | - Card - 用于JSON预览展示 128 | - Tabs - 用于切换不同的翻译设置 129 | - Dialog - 用于显示帮助信息 130 | - Progress - 用于显示翻译进度 131 | 132 | - **样式方案**: 133 | - Tailwind CSS - 原子化CSS框架 134 | - CSS Variables - 主题定制 135 | - New York Style - shadcn/ui视觉风格 136 | 137 | - **部署平台**: Vercel 138 | - 提供无缝的Next.js部署体验 139 | - 自动化的CI/CD流程 140 | 141 | - **域名管理**: Cloudflare 142 | - 负责域名购买、DNS管理和安全防护 143 | 144 | - **API集成**: 145 | - OpenAI API - 提供GPT-4翻译能力 146 | - 支持自定义API Key 147 | 148 | ## 组件结构 149 | 150 | 1. **FileUpload组件** 151 | - 使用shadcn/ui的Button和Input组件 152 | - 支持拖拽上传 153 | - 文件类型验证 154 | - 上传反馈Toast提示 155 | 156 | 2. **TranslatePanel组件** 157 | - 使用Select组件进行语言选择 158 | - 使用Input组件输入API Key 159 | - 使用Progress组件显示翻译进度 160 | - 使用Button组件触发翻译 161 | 162 | 3. **JsonPreview组件** 163 | - 使用Card组件展示JSON内容 164 | - 支持代码高亮 165 | - 支持折叠/展开 166 | - 并排对比视图 167 | 168 | 4. **SettingsDialog组件** 169 | - 使用Dialog组件 170 | - 包含翻译设置选项 171 | - 自定义词典管理 172 | 173 | ## 非功能性需求 174 | 175 | 1. **性能** 176 | - 确保翻译过程高效,响应时间短。 177 | 178 | 2. **安全性** 179 | - 保护用户的API Key和上传文件的隐私。 180 | - 使用HTTPS进行数据传输。 181 | 182 | 3. **可用性** 183 | - 确保网站在高流量情况下的稳定性。 184 | 185 | 4. **可扩展性** 186 | - 未来可以增加更多语言和文件格式支持。 187 | 188 | 5. **兼容性** 189 | - 支持不同编码格式的JSON文件(UTF-8, UTF-16等) 190 | - 支持不同的换行符格式(LF, CRLF) 191 | - 支持大文件处理(>10MB的JSON文件) 192 | 193 | 6. **翻译质量** 194 | - 保持专业术语的一致性 195 | - 支持自定义翻译词典 196 | - 提供机器翻译质量评估 197 | 198 | 7. **错误处理** 199 | - JSON格式校验和错误提示 200 | - 翻译失败的回滚机制 201 | - 自动保存和恢复机制 202 | 203 | ## 用户界面设计 204 | 205 | 1. **主页** 206 | - 简介和使用说明。 207 | - JSON文件上传区域。 208 | - 语言选择下拉菜单。 209 | - OpenAI API Key输入框。 210 | 211 | 2. **翻译结果页面** 212 | - 显示翻译进度。 213 | - 原文和译文对比展示。 214 | - 下载按钮。 215 | 216 | 3. **翻译设置面板** 217 | - 源语言和目标语言选择 218 | - 翻译引擎选择(OpenAI/其他) 219 | - 自定义词典管理 220 | 221 | 4. **高级功能区** 222 | - 批量文件处理 223 | - 项目管理功能 224 | - 统计分析面板 225 | 226 | ## 部署与维护 227 | 228 | - 使用Vercel进行持续集成和部署。 229 | - 定期更新和维护,确保API的正常调用和界面的流畅运行。 230 | 231 | ## 未来计划 232 | 233 | - 增加对其他文件格式的支持,如XML、CSV等。 234 | - 提供用户注册和登录功能,保存用户的API Key和翻译历史。 235 | - 集成更多AI服务,扩展网站功能。 236 | - 支持更多文件格式(YAML, Properties等) 237 | - 添加协同翻译功能 238 | - 提供API接口供其他服务调用 239 | - 集成更多翻译服务商 240 | - 添加自动化测试功能 241 | - 支持自定义翻译规则 -------------------------------------------------------------------------------- /json-translator-prd.md: -------------------------------------------------------------------------------- 1 | # JSON Translator - Product Requirements Document 2 | 3 | ## 1. Project Overview 4 | 5 | ### 1.1 Background 6 | The internationalization (i18n) of applications has become increasingly important in global software development. Developers need to maintain multiple language versions of their applications, which typically involves managing JSON language files. However, the manual translation of these files is time-consuming and error-prone. 7 | 8 | ### 1.2 Pain Points 9 | 1. **Manual Translation Inefficiency** 10 | - Time-consuming manual translation process 11 | - High risk of human error 12 | - Difficulty in maintaining consistency across translations 13 | 14 | 2. **Technical Challenges** 15 | - Complex JSON structure handling 16 | - Risk of breaking JSON format during translation 17 | - Lack of specialized tools for JSON translation 18 | 19 | ### 1.3 Project Goals 20 | - Create an efficient online JSON translation tool 21 | - Leverage AI for accurate translations 22 | - Maintain JSON structure integrity 23 | - Provide a user-friendly interface 24 | - Ensure data security 25 | 26 | ## 2. Product Features 27 | 28 | ### 2.1 Core Features 29 | 30 | #### JSON File Translation 31 | - Support JSON file upload 32 | - Maintain JSON structure during translation 33 | - Support nested JSON objects and arrays 34 | - Real-time translation preview 35 | - Export translated files 36 | 37 | #### Language Support 38 | - Support 40+ languages 39 | - Accurate technical term translation 40 | - Context-aware translation 41 | - Custom terminology support 42 | 43 | #### Security & Privacy 44 | - Client-side processing 45 | - No server storage of files 46 | - Secure API key handling 47 | - Local file processing 48 | 49 | ### 2.2 User Interface 50 | 51 | #### File Management 52 | - Drag & drop file upload 53 | - File format validation 54 | - Large file handling 55 | - Multiple file support 56 | 57 | #### Translation Interface 58 | - Side-by-side preview 59 | - Real-time updates 60 | - Error highlighting 61 | - Progress indication 62 | 63 | #### Export Options 64 | - Multiple format support 65 | - Batch export 66 | - File naming conventions 67 | - Download management 68 | 69 | ## 3. Technical Requirements 70 | 71 | ### 3.1 Performance 72 | - Fast translation processing 73 | - Efficient file handling 74 | - Responsive interface 75 | - Optimized API usage 76 | 77 | ### 3.2 Security 78 | - Secure API key handling 79 | - Local file processing 80 | - No server storage 81 | - Data encryption 82 | 83 | ### 3.3 Compatibility 84 | - Cross-browser support 85 | - Mobile responsiveness 86 | - File size limitations 87 | - API version compatibility 88 | 89 | ## 4. User Experience 90 | 91 | ### 4.1 Target Users 92 | - Frontend Developers 93 | - Product Managers 94 | - Localization Teams 95 | - International Development Teams 96 | 97 | ### 4.2 User Scenarios 98 | 1. **Developer Translation** 99 | - Quick i18n file translation 100 | - Technical term accuracy 101 | - Structure preservation 102 | 103 | 2. **Product Manager Usage** 104 | - Content localization 105 | - Multiple language management 106 | - Quality assurance 107 | 108 | ### 4.3 User Flow 109 | 1. Visit website 110 | 2. Upload JSON file 111 | 3. Select target language 112 | 4. Enter API key 113 | 5. Review translation 114 | 6. Export result 115 | 116 | ## 5. Development Plan 117 | 118 | ### 5.1 Phase 1 - MVP 119 | - Basic file upload 120 | - Single language translation 121 | - Simple interface 122 | - Core functionality 123 | 124 | ### 5.2 Phase 2 - Enhancement 125 | - Multiple language support 126 | - Advanced UI features 127 | - Performance optimization 128 | - User feedback integration 129 | 130 | ### 5.3 Phase 3 - Advanced Features 131 | - Batch processing 132 | - Custom terminology 133 | - API integration 134 | - Advanced export options 135 | 136 | ## 6. Success Metrics 137 | 138 | ### 6.1 Key Metrics 139 | - Translation accuracy 140 | - Processing speed 141 | - User satisfaction 142 | - Error rate 143 | - Usage statistics 144 | 145 | ### 6.2 Quality Standards 146 | - 95%+ translation accuracy 147 | - <2s processing time 148 | - <1% error rate 149 | - 90%+ user satisfaction 150 | 151 | ## 7. Future Considerations 152 | 153 | ### 7.1 Potential Features 154 | - Translation memory 155 | - Collaborative translation 156 | - API endpoints 157 | - Enterprise integration 158 | 159 | ### 7.2 Scalability 160 | - Infrastructure scaling 161 | - Performance optimization 162 | - User base growth 163 | - Feature expansion 164 | 165 | ## 8. Conclusion 166 | This PRD outlines the development of a specialized JSON translation tool that addresses the needs of modern web development teams. The focus is on combining efficiency, accuracy, and security while maintaining a user-friendly experience. -------------------------------------------------------------------------------- /src/hooks/use-toast.ts: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | // Inspired by react-hot-toast library 4 | import * as React from "react" 5 | 6 | import type { 7 | ToastActionElement, 8 | ToastProps, 9 | } from "@/components/ui/toast" 10 | 11 | const TOAST_LIMIT = 1 12 | const TOAST_REMOVE_DELAY = 1000000 13 | 14 | type ToasterToast = ToastProps & { 15 | id: string 16 | title?: React.ReactNode 17 | description?: React.ReactNode 18 | action?: ToastActionElement 19 | } 20 | 21 | const actionTypes = { 22 | ADD_TOAST: "ADD_TOAST", 23 | UPDATE_TOAST: "UPDATE_TOAST", 24 | DISMISS_TOAST: "DISMISS_TOAST", 25 | REMOVE_TOAST: "REMOVE_TOAST", 26 | } as const 27 | 28 | let count = 0 29 | 30 | function genId() { 31 | count = (count + 1) % Number.MAX_SAFE_INTEGER 32 | return count.toString() 33 | } 34 | 35 | type ActionType = typeof actionTypes 36 | 37 | type Action = 38 | | { 39 | type: ActionType["ADD_TOAST"] 40 | toast: ToasterToast 41 | } 42 | | { 43 | type: ActionType["UPDATE_TOAST"] 44 | toast: Partial 45 | } 46 | | { 47 | type: ActionType["DISMISS_TOAST"] 48 | toastId?: ToasterToast["id"] 49 | } 50 | | { 51 | type: ActionType["REMOVE_TOAST"] 52 | toastId?: ToasterToast["id"] 53 | } 54 | 55 | interface State { 56 | toasts: ToasterToast[] 57 | } 58 | 59 | const toastTimeouts = new Map>() 60 | 61 | const addToRemoveQueue = (toastId: string) => { 62 | if (toastTimeouts.has(toastId)) { 63 | return 64 | } 65 | 66 | const timeout = setTimeout(() => { 67 | toastTimeouts.delete(toastId) 68 | dispatch({ 69 | type: "REMOVE_TOAST", 70 | toastId: toastId, 71 | }) 72 | }, TOAST_REMOVE_DELAY) 73 | 74 | toastTimeouts.set(toastId, timeout) 75 | } 76 | 77 | export const reducer = (state: State, action: Action): State => { 78 | switch (action.type) { 79 | case "ADD_TOAST": 80 | return { 81 | ...state, 82 | toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), 83 | } 84 | 85 | case "UPDATE_TOAST": 86 | return { 87 | ...state, 88 | toasts: state.toasts.map((t) => 89 | t.id === action.toast.id ? { ...t, ...action.toast } : t 90 | ), 91 | } 92 | 93 | case "DISMISS_TOAST": { 94 | const { toastId } = action 95 | 96 | // ! Side effects ! - This could be extracted into a dismissToast() action, 97 | // but I'll keep it here for simplicity 98 | if (toastId) { 99 | addToRemoveQueue(toastId) 100 | } else { 101 | state.toasts.forEach((toast) => { 102 | addToRemoveQueue(toast.id) 103 | }) 104 | } 105 | 106 | return { 107 | ...state, 108 | toasts: state.toasts.map((t) => 109 | t.id === toastId || toastId === undefined 110 | ? { 111 | ...t, 112 | open: false, 113 | } 114 | : t 115 | ), 116 | } 117 | } 118 | case "REMOVE_TOAST": 119 | if (action.toastId === undefined) { 120 | return { 121 | ...state, 122 | toasts: [], 123 | } 124 | } 125 | return { 126 | ...state, 127 | toasts: state.toasts.filter((t) => t.id !== action.toastId), 128 | } 129 | } 130 | } 131 | 132 | const listeners: Array<(state: State) => void> = [] 133 | 134 | let memoryState: State = { toasts: [] } 135 | 136 | function dispatch(action: Action) { 137 | memoryState = reducer(memoryState, action) 138 | listeners.forEach((listener) => { 139 | listener(memoryState) 140 | }) 141 | } 142 | 143 | type Toast = Omit 144 | 145 | function toast({ ...props }: Toast) { 146 | const id = genId() 147 | 148 | const update = (props: ToasterToast) => 149 | dispatch({ 150 | type: "UPDATE_TOAST", 151 | toast: { ...props, id }, 152 | }) 153 | const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) 154 | 155 | dispatch({ 156 | type: "ADD_TOAST", 157 | toast: { 158 | ...props, 159 | id, 160 | open: true, 161 | onOpenChange: (open) => { 162 | if (!open) dismiss() 163 | }, 164 | }, 165 | }) 166 | 167 | return { 168 | id: id, 169 | dismiss, 170 | update, 171 | } 172 | } 173 | 174 | function useToast() { 175 | const [state, setState] = React.useState(memoryState) 176 | 177 | React.useEffect(() => { 178 | listeners.push(setState) 179 | return () => { 180 | const index = listeners.indexOf(setState) 181 | if (index > -1) { 182 | listeners.splice(index, 1) 183 | } 184 | } 185 | }, [state]) 186 | 187 | return { 188 | ...state, 189 | toast, 190 | dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), 191 | } 192 | } 193 | 194 | export { useToast, toast } 195 | -------------------------------------------------------------------------------- /src/components/ui/toast.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as ToastPrimitives from "@radix-ui/react-toast" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | import { X } from "lucide-react" 7 | 8 | import { cn } from "@/lib/utils" 9 | 10 | const ToastProvider = ToastPrimitives.Provider 11 | 12 | const ToastViewport = React.forwardRef< 13 | React.ElementRef, 14 | React.ComponentPropsWithoutRef 15 | >(({ className, ...props }, ref) => ( 16 | 24 | )) 25 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName 26 | 27 | const toastVariants = cva( 28 | "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-[1rem] border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", 29 | { 30 | variants: { 31 | variant: { 32 | default: "border bg-background text-foreground", 33 | destructive: 34 | "destructive group border-destructive bg-destructive text-destructive-foreground", 35 | }, 36 | }, 37 | defaultVariants: { 38 | variant: "default", 39 | }, 40 | } 41 | ) 42 | 43 | const Toast = React.forwardRef< 44 | React.ElementRef, 45 | React.ComponentPropsWithoutRef & 46 | VariantProps 47 | >(({ className, variant, ...props }, ref) => { 48 | return ( 49 | 54 | ) 55 | }) 56 | Toast.displayName = ToastPrimitives.Root.displayName 57 | 58 | const ToastAction = React.forwardRef< 59 | React.ElementRef, 60 | React.ComponentPropsWithoutRef 61 | >(({ className, ...props }, ref) => ( 62 | 70 | )) 71 | ToastAction.displayName = ToastPrimitives.Action.displayName 72 | 73 | const ToastClose = React.forwardRef< 74 | React.ElementRef, 75 | React.ComponentPropsWithoutRef 76 | >(({ className, ...props }, ref) => ( 77 | 86 | 87 | 88 | )) 89 | ToastClose.displayName = ToastPrimitives.Close.displayName 90 | 91 | const ToastTitle = React.forwardRef< 92 | React.ElementRef, 93 | React.ComponentPropsWithoutRef 94 | >(({ className, ...props }, ref) => ( 95 | 100 | )) 101 | ToastTitle.displayName = ToastPrimitives.Title.displayName 102 | 103 | const ToastDescription = React.forwardRef< 104 | React.ElementRef, 105 | React.ComponentPropsWithoutRef 106 | >(({ className, ...props }, ref) => ( 107 | 112 | )) 113 | ToastDescription.displayName = ToastPrimitives.Description.displayName 114 | 115 | type ToastProps = React.ComponentPropsWithoutRef 116 | 117 | type ToastActionElement = React.ReactElement 118 | 119 | export { 120 | type ToastProps, 121 | type ToastActionElement, 122 | ToastProvider, 123 | ToastViewport, 124 | Toast, 125 | ToastTitle, 126 | ToastDescription, 127 | ToastClose, 128 | ToastAction, 129 | } 130 | -------------------------------------------------------------------------------- /src/lib/json-utils.ts: -------------------------------------------------------------------------------- 1 | export function parseJson(jsonString: string) { 2 | try { 3 | // Check if the input is empty 4 | if (!jsonString || jsonString.trim() === '') { 5 | return { 6 | success: false, 7 | data: null, 8 | error: 'File content is empty' 9 | } 10 | } 11 | 12 | const cleanJson = jsonString 13 | .replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1') 14 | .trim() 15 | 16 | if (!cleanJson.startsWith('{') && !cleanJson.startsWith('[')) { 17 | return { 18 | success: false, 19 | data: null, 20 | error: 'File content is not a valid JSON format' 21 | } 22 | } 23 | 24 | const parsed = JSON.parse(cleanJson) 25 | return { 26 | success: true, 27 | data: parsed, 28 | error: null 29 | } 30 | } catch (e) { 31 | return { 32 | success: false, 33 | data: null, 34 | error: e instanceof Error ? e.message : 'Error parsing JSON' 35 | } 36 | } 37 | } 38 | 39 | export function stringifyJson(json: unknown, space = 2) { 40 | try { 41 | return { 42 | success: true, 43 | data: JSON.stringify(json, null, space), 44 | error: null 45 | } 46 | } catch (e) { 47 | return { 48 | success: false, 49 | data: null, 50 | error: e instanceof Error ? e.message : 'Error serializing JSON' 51 | } 52 | } 53 | } 54 | 55 | // Validate JSON size 56 | export function validateJsonSize(json: unknown, maxSize = 10 * 1024 * 1024) { 57 | const size = new Blob([JSON.stringify(json)]).size 58 | return size <= maxSize 59 | } 60 | 61 | // Check JSON encoding 62 | export function detectJsonEncoding(buffer: ArrayBuffer): string { 63 | const arr = new Uint8Array(buffer).subarray(0, 4) 64 | let encoding = 'utf-8' 65 | 66 | if (arr[0] === 0xEF && arr[1] === 0xBB && arr[2] === 0xBF) { 67 | encoding = 'utf-8' 68 | } else if (arr[0] === 0xFE && arr[1] === 0xFF) { 69 | encoding = 'utf-16be' 70 | } else if (arr[0] === 0xFF && arr[1] === 0xFE) { 71 | encoding = 'utf-16le' 72 | } 73 | 74 | return encoding 75 | } 76 | 77 | interface ChunkOptions { 78 | maxKeys?: number; // Maximum number of key-value pairs per block 79 | maxSize?: number; // Maximum number of bytes per block 80 | preserveStructure?: boolean; // Whether to preserve object structure 81 | } 82 | 83 | export function chunkJsonObject( 84 | obj: Record, 85 | options: ChunkOptions = {} 86 | ) { 87 | const { 88 | maxKeys = 50, 89 | maxSize = 4000, // Approximately 4KB 90 | preserveStructure = true 91 | } = options; 92 | 93 | const chunks: Array> = []; 94 | let currentChunk: Record = {}; 95 | let currentSize = 0; 96 | let currentKeys = 0; 97 | 98 | // Recursively process nested objects 99 | function processObject(obj: Record, path: string[] = []) { 100 | for (const [key, value] of Object.entries(obj)) { 101 | const currentPath = [...path, key]; 102 | 103 | if (typeof value === 'object' && value !== null && preserveStructure) { 104 | // If it's an object and structure needs to be preserved, recursively process 105 | processObject(value, currentPath); 106 | continue; 107 | } 108 | 109 | // Calculate the size of the current key-value pair 110 | const entrySize = new Blob([JSON.stringify({ [key]: value })]).size; 111 | 112 | // If the current block is full, create a new block 113 | if (currentKeys >= maxKeys || currentSize + entrySize > maxSize) { 114 | if (Object.keys(currentChunk).length > 0) { 115 | chunks.push(currentChunk); 116 | currentChunk = {}; 117 | currentSize = 0; 118 | currentKeys = 0; 119 | } 120 | } 121 | 122 | // Add the key-value pair to the current block 123 | if (path.length === 0) { 124 | currentChunk[key] = value; 125 | } else { 126 | // Process nested paths 127 | let target = currentChunk; 128 | for (let i = 0; i < path.length; i++) { 129 | const pathKey = path[i]; 130 | if (i === path.length - 1) { 131 | target[pathKey] = target[pathKey] || {}; 132 | target[pathKey][key] = value; 133 | } else { 134 | target[pathKey] = target[pathKey] || {}; 135 | target = target[pathKey]; 136 | } 137 | } 138 | } 139 | 140 | currentSize += entrySize; 141 | currentKeys++; 142 | } 143 | } 144 | 145 | processObject(obj); 146 | 147 | // Add the last block 148 | if (Object.keys(currentChunk).length > 0) { 149 | chunks.push(currentChunk); 150 | } 151 | 152 | return chunks; 153 | } 154 | 155 | // Merge translated results while preserving object structure 156 | export function mergeTranslatedChunks(chunks: Record[]) { 157 | return chunks.reduce((acc, chunk) => { 158 | function deepMerge(target: any, source: any) { 159 | for (const key in source) { 160 | if (typeof source[key] === 'object' && source[key] !== null) { 161 | target[key] = target[key] || {}; 162 | deepMerge(target[key], source[key]); 163 | } else { 164 | target[key] = source[key]; 165 | } 166 | } 167 | return target; 168 | } 169 | return deepMerge(acc, chunk); 170 | }, {}); 171 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSON i18n Translation Tool 2 | 3 |

4 | JSON Translate Logo 5 |

6 | 7 |

8 | 🌐 AI-Powered JSON Internationalization Translation Tool 9 |

10 | 11 |

12 | 🔗 json.uiboy.com
13 | Free online JSON translation tool powered by AI, supporting 40+ languages 14 |

15 | 16 |

17 | 18 | Website 19 | 20 | 21 | License 22 | 23 | 24 | Version 25 | 26 | 27 | Built with Cursor 28 | 29 |

30 | 31 |

32 | English | 33 | 简体中文 34 |

35 | 36 |

37 | 🎯 An Open-Source AI Development Journey 38 |

39 | 40 |

41 | This project showcases a complete AI-assisted development process, from product design to implementation 42 |

43 | 44 |

45 | What's Included: 46 |

47 | 48 |

49 | 🔸 Product Requirements Document - Complete PRD created with AI assistance
50 | 🔸 Source Code - Full codebase with AI-powered features 51 |

52 | 53 | ## ✨ Features 54 | 55 | - 🤖 Smart translation powered by OpenAI GPT models 56 | - 🔄 Maintains JSON structure integrity 57 | - 🌍 Supports 40+ languages 58 | - 🌐 Multi-language interface 59 | - ⚡️ Real-time translation preview 60 | - 🛡️ Local API key usage for security 61 | - 📦 Export translation results 62 | - 🎯 Accurate technical term translation 63 | - 💻 Fully open source, transparent code 64 | 65 | ## 📖 AI-Driven Product Design 66 | 67 | This project includes complete Product Requirements Documents in both English and Chinese: 68 | - [English PRD](./json-translator-prd.md) 69 | - [中文 PRD](./json-translator-prd.zh.md) 70 | 71 | ## 🚀 Quick Start 72 | 73 | ### Requirements 74 | 75 | - Node.js >= 16.0.0 76 | - npm or yarn or pnpm 77 | - OpenAI API key 78 | 79 | ### Installation 80 | 81 | ```bash 82 | git clone https://github.com/ViggoZ/json-translate.git 83 | ``` 84 | 85 | ```bash 86 | cd json-translate 87 | ``` 88 | 89 | ```bash 90 | npm install 91 | ``` 92 | 93 | ### Development 94 | 95 | ```bash 96 | npm run dev 97 | ``` 98 | Visit http://localhost:3000 to view the development environment. 99 | 100 | ### Build 101 | 102 | ```bash 103 | npm run build 104 | ``` 105 | 106 | ```bash 107 | npm run start 108 | ``` 109 | 110 | ## 📖 Usage Guide 111 | 112 | 1. **Preparation** 113 | - Prepare your JSON file for translation 114 | - Get your OpenAI API key (https://platform.openai.com) 115 | 116 | 2. **Getting Started** 117 | - Visit the website 118 | - Upload JSON file (drag & drop supported) 119 | - Select target language 120 | - Enter API key 121 | - Start translation 122 | 123 | 3. **Features** 124 | - Single JSON file translation 125 | - Real-time translation preview 126 | - Export in JSON format 127 | 128 | ## 💡 Best Practices 129 | 130 | - Split large files into smaller ones for translation 131 | - Verify JSON format before translation 132 | - Use preview feature to confirm translation quality 133 | - Regularly backup important translation files 134 | 135 | ## 🛠 Tech Stack 136 | 137 | - **Development Tool**: 138 | - Cursor (AI-assisted development) 139 | - **Framework**: Next.js 14 140 | - **UI**: 141 | - React 18 142 | - Tailwind CSS 143 | - Radix UI 144 | - HeadlessUI 145 | - **Language**: TypeScript 146 | - **API**: OpenAI API 147 | - **Libraries**: 148 | - JSZip (file handling) 149 | - React Syntax Highlighter 150 | - React Window (virtual list) 151 | 152 | ## 🤝 Contributing 153 | 154 | I welcome all forms of contributions, whether it's new features, bug fixes, or documentation improvements. 155 | 156 | 1. Fork the project 157 | 2. Create your feature branch (`git checkout -b feature/YourFeature`) 158 | 3. Commit your changes (`git commit -m 'Add some feature'`) 159 | 4. Push to the branch (`git push origin feature/YourFeature`) 160 | 5. Open a Pull Request 161 | 162 | ### Development Guidelines 163 | - Follow existing code style 164 | - Ensure code passes `npm run lint` 165 | - Test functionality before submitting 166 | 167 | ## 📝 License 168 | 169 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 170 | 171 | ## 🙋 FAQ 172 | 173 | **Q: Is the API key secure?** 174 | A: Yes. API keys are only used temporarily in the browser and are never saved or transmitted to servers. 175 | 176 | **Q: Which languages are supported?** 177 | A: 40+ major languages including but not limited to: 178 | - Chinese (Simplified/Traditional) 179 | - English 180 | - Japanese 181 | - Korean 182 | - French 183 | - German 184 | - Spanish 185 | - Russian 186 | etc. 187 | 188 | **Q: Is there a file size limit?** 189 | A: Single files are limited to 10MB. 190 | 191 | ## 📞 Contact 192 | 193 | - Author: Viggo 194 | - Email: viggo.zw@gmail.com 195 | - Twitter: [@viggo](https://twitter.com/decohack) 196 | 197 | ## 🌟 Acknowledgments 198 | 199 | Thanks to all users who provided feedback. Special thanks to: 200 | 201 | - OpenAI team for their powerful API 202 | - Next.js team for the excellent framework 203 | - All project contributors 204 | 205 | --- 206 | 207 | If this project helps you, please give it a star ⭐️! 208 | 209 |

Made with ❤️ by [@viggo](https://twitter.com/decohack)

-------------------------------------------------------------------------------- /src/components/ui/select.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SelectPrimitive from "@radix-ui/react-select" 5 | import { Check, ChevronDown, ChevronUp } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const Select = SelectPrimitive.Root 10 | 11 | const SelectGroup = SelectPrimitive.Group 12 | 13 | const SelectValue = SelectPrimitive.Value 14 | 15 | const SelectTrigger = React.forwardRef< 16 | React.ElementRef, 17 | React.ComponentPropsWithoutRef 18 | >(({ className, children, ...props }, ref) => ( 19 | span]:line-clamp-1", 23 | className 24 | )} 25 | {...props} 26 | > 27 | {children} 28 | 29 | 30 | 31 | 32 | )) 33 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName 34 | 35 | const SelectScrollUpButton = React.forwardRef< 36 | React.ElementRef, 37 | React.ComponentPropsWithoutRef 38 | >(({ className, ...props }, ref) => ( 39 | 47 | 48 | 49 | )) 50 | SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName 51 | 52 | const SelectScrollDownButton = React.forwardRef< 53 | React.ElementRef, 54 | React.ComponentPropsWithoutRef 55 | >(({ className, ...props }, ref) => ( 56 | 64 | 65 | 66 | )) 67 | SelectScrollDownButton.displayName = 68 | SelectPrimitive.ScrollDownButton.displayName 69 | 70 | const SelectContent = React.forwardRef< 71 | React.ElementRef, 72 | React.ComponentPropsWithoutRef 73 | >(({ className, children, position = "popper", ...props }, ref) => ( 74 | 75 | 86 | 87 | 94 | {children} 95 | 96 | 97 | 98 | 99 | )) 100 | SelectContent.displayName = SelectPrimitive.Content.displayName 101 | 102 | const SelectLabel = React.forwardRef< 103 | React.ElementRef, 104 | React.ComponentPropsWithoutRef 105 | >(({ className, ...props }, ref) => ( 106 | 111 | )) 112 | SelectLabel.displayName = SelectPrimitive.Label.displayName 113 | 114 | const SelectItem = React.forwardRef< 115 | React.ElementRef, 116 | React.ComponentPropsWithoutRef 117 | >(({ className, children, ...props }, ref) => ( 118 | 126 | 127 | 128 | 129 | 130 | 131 | {children} 132 | 133 | )) 134 | SelectItem.displayName = SelectPrimitive.Item.displayName 135 | 136 | const SelectSeparator = React.forwardRef< 137 | React.ElementRef, 138 | React.ComponentPropsWithoutRef 139 | >(({ className, ...props }, ref) => ( 140 | 145 | )) 146 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName 147 | 148 | export { 149 | Select, 150 | SelectGroup, 151 | SelectValue, 152 | SelectTrigger, 153 | SelectContent, 154 | SelectLabel, 155 | SelectItem, 156 | SelectSeparator, 157 | SelectScrollUpButton, 158 | SelectScrollDownButton, 159 | } 160 | -------------------------------------------------------------------------------- /src/components/FileUpload.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Input } from "@/components/ui/input" 4 | import { useTranslate } from "@/context/TranslateContext" 5 | import { useToast } from "@/hooks/use-toast" 6 | import { parseJson } from "@/lib/json-utils" 7 | import { UploadIcon, FileJson2Icon, KeyIcon, Languages, FileIcon } from "lucide-react" 8 | import { useState } from "react" 9 | 10 | interface FileUploadProps { 11 | dict: { 12 | title: string; 13 | description: string; 14 | dragText: string; 15 | supportText: string; 16 | apiKeyTip: string; 17 | apiKeyTitle: string; 18 | apiKeyPlaceholder: string; 19 | errorTitle: string; 20 | successTitle: string; 21 | errors?: { 22 | selectFile: string; 23 | jsonExtension: string; 24 | fileSize: string; 25 | jsonFormat: string; 26 | emptyJson: string; 27 | }; 28 | success?: { 29 | uploaded: string; 30 | }; 31 | } 32 | } 33 | 34 | export function FileUpload({ dict }: FileUploadProps) { 35 | const [isUploaded, setIsUploaded] = useState(false) 36 | const [fileInfo, setFileInfo] = useState<{ name: string; size: string } | null>(null) 37 | const { toast } = useToast() 38 | const { setFile, apiKey, setApiKey, resetTranslation } = useTranslate() 39 | 40 | const handleUpload = async (event: React.ChangeEvent) => { 41 | const files = event.target.files 42 | 43 | if (!files || !files[0]) { 44 | toast({ 45 | variant: "destructive", 46 | title: dict.errorTitle || "Error", 47 | description: dict.errors?.selectFile || "Please select a file" 48 | }) 49 | return 50 | } 51 | 52 | const file = files[0] 53 | 54 | if (!file.name.endsWith('.json')) { 55 | toast({ 56 | variant: "destructive", 57 | title: "Error", 58 | description: dict.errors?.jsonExtension || "Please upload a file with a .json extension" 59 | }) 60 | return 61 | } 62 | 63 | if (file.size > 10 * 1024 * 1024) { 64 | toast({ 65 | variant: "destructive", 66 | title: "Error", 67 | description: dict.errors?.fileSize || "File size cannot exceed 10MB" 68 | }) 69 | return 70 | } 71 | 72 | try { 73 | const text = await file.text() 74 | const result = parseJson(text.trim()) 75 | 76 | if (!result.success) { 77 | throw new Error(result.error || dict.errors?.jsonFormat || 'Invalid JSON format') 78 | } 79 | 80 | if (Object.keys(result.data).length === 0) { 81 | throw new Error(dict.errors?.emptyJson || 'JSON file cannot be empty') 82 | } 83 | 84 | setFile(file) 85 | setIsUploaded(true) 86 | setFileInfo({ 87 | name: file.name, 88 | size: formatFileSize(file.size) 89 | }) 90 | resetTranslation() 91 | toast({ 92 | title: dict.successTitle || "Success", 93 | description: dict.success?.uploaded || "File uploaded successfully" 94 | }) 95 | 96 | } catch (err) { 97 | setIsUploaded(false) 98 | setFileInfo(null) 99 | toast({ 100 | variant: "destructive", 101 | title: "JSON Format Error", 102 | description: err instanceof Error ? err.message : dict.errors?.jsonFormat || "Invalid file format" 103 | }) 104 | } 105 | } 106 | 107 | const handleDragOver = (e: React.DragEvent) => { 108 | e.preventDefault() 109 | e.stopPropagation() 110 | } 111 | 112 | const handleDrop = async (e: React.DragEvent) => { 113 | e.preventDefault() 114 | e.stopPropagation() 115 | 116 | const files = e.dataTransfer.files 117 | if (files && files[0]) { 118 | const event = { target: { files } } as React.ChangeEvent 119 | handleUpload(event) 120 | } 121 | } 122 | 123 | const formatFileSize = (bytes: number): string => { 124 | if (bytes === 0) return '0 Bytes' 125 | const k = 1024 126 | const sizes = ['Bytes', 'KB', 'MB', 'GB'] 127 | const i = Math.floor(Math.log(bytes) / Math.log(k)) 128 | return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] 129 | } 130 | 131 | return ( 132 |
133 |
134 | 178 |
179 | 180 |
181 |

182 | 183 | {dict.apiKeyTitle || "OpenAI API Key"} 184 |

185 |

186 | {dict.apiKeyTip || "Tips: OpenAI API Key is required for translation."} 187 |

188 | setApiKey(e.target.value)} 194 | /> 195 |
196 |
197 | ) 198 | } -------------------------------------------------------------------------------- /src/dictionaries/zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "AI 驱动", 4 | "title": "i18n JSON 国际化翻译工具", 5 | "description": "使用 AI 技术快速翻译您的 JSON 语言文件。快速、准确、易用。", 6 | "features": { 7 | "multilanguage": "多语言支持", 8 | "realtime": "实时翻译" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "四个简单步骤完成翻译", 13 | "description": "我们简化了 JSON 文件翻译流程,帮助您快速获得高质量的翻译结果", 14 | "steps": [ 15 | { 16 | "title": "上传 JSON 文件", 17 | "description": "支持拖拽上传或点击选择文件" 18 | }, 19 | { 20 | "title": "选择目标语言", 21 | "description": "选择需要翻译的目标语言" 22 | }, 23 | { 24 | "title": "开始翻译", 25 | "description": "输入 API Key 并开始 AI 翻译" 26 | }, 27 | { 28 | "title": "下载结果", 29 | "description": "下载翻译完成的 JSON 文件" 30 | } 31 | ] 32 | }, 33 | "features": { 34 | "title": "强大的翻译功能", 35 | "items": [ 36 | { 37 | "title": "保持 JSON 结构", 38 | "description": "智能识别并保持原始 JSON 文件的结构、缩进和格式" 39 | }, 40 | { 41 | "title": "多语言支持", 42 | "description": "支持包括英语、中文、日语等多种语言之间的翻译" 43 | }, 44 | { 45 | "title": "AI 驱动翻译", 46 | "description": "使用 OpenAI GPT 模型确保专业术语的准确性和自然表达" 47 | }, 48 | { 49 | "title": "安全可靠", 50 | "description": "API Key 仅在浏览器临时使用,从不保存或传输到服务器" 51 | } 52 | ] 53 | }, 54 | "uploadSection": { 55 | "title": "上传 JSON 文件", 56 | "description": "上传需要翻译的 JSON 文件", 57 | "dragText": "拖拽文件到此处或点击上传", 58 | "supportText": "支持 .json 格式文件,最大 10MB", 59 | "apiKeyTitle": "OpenAI API 密钥", 60 | "apiKeyPlaceholder": "sk-...", 61 | "errors": { 62 | "selectFile": "请选择文件", 63 | "jsonExtension": "请上传 .json 格式的文件", 64 | "fileSize": "文件大小不能超过 10MB", 65 | "jsonFormat": "无效的 JSON 格式,请检查文件内容", 66 | "emptyJson": "JSON 文件不能为空" 67 | }, 68 | "success": { 69 | "uploaded": "文件上传成功" 70 | }, 71 | "errorTitle": "错误", 72 | "successTitle": "成功", 73 | "apiKeyTip": "提示:翻译功能需要 OpenAI API 密钥" 74 | }, 75 | "translateSection": { 76 | "title": "选择目标语言", 77 | "description": "选择需要翻译的目标语言" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "开始翻译", 81 | "translating": "翻译中...", 82 | "cancel": "取消", 83 | "uploadFirst": "请先上传文件", 84 | "enterApiKey": "请输入 API Key", 85 | "foundUnfinished": "发现未完成的翻译", 86 | "continueTranslation": "继续翻译", 87 | "translationCancelled": "翻译已取消", 88 | "invalidApiKey": "无效的 API Key 格式", 89 | "errorTitle": "错误", 90 | "successTitle": "成功", 91 | "translationCompleted": "翻译完成!", 92 | "showMoreLanguages": "显示更多语言", 93 | "hideMoreLanguages": "隐藏更多语言", 94 | "overallProgress": "总体进度", 95 | "completedSegments": "已完成片段", 96 | "translatingLanguage": "正在翻译", 97 | "tip": "提示", 98 | "allLanguagesTranslated": "所有选择的语言已翻译完成", 99 | "pleaseSelectLanguage": "请选择至少一种目标语言", 100 | "pleaseUploadAndEnterKey": "请上传文件并输入 API Key", 101 | "cancelled": "已取消", 102 | "translationFailed": "翻译失败", 103 | "bytes": "字节", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "无效的 API 密钥格式", 109 | "invalidOrExpired": "无效或已过期的 API 密钥", 110 | "rateLimitReached": "API 调用次数已达上限", 111 | "validationFailed": "API 密钥验证失败" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "预览", 116 | "empty": "JSON 预览将显示在这里", 117 | "copied": "已复制到剪贴板", 118 | "originalJson": "原始 JSON", 119 | "translatedJson": "翻译后的 JSON", 120 | "tips": "提示:支持实时预览和格式化 JSON 文件,您可以直接复制内容", 121 | "placeholder": { 122 | "upload": "请上传 JSON 文件", 123 | "translation": "翻译结果将显示在这里" 124 | }, 125 | "actions": { 126 | "copy": "复制", 127 | "download": "下载", 128 | "downloadAll": "下载所有翻译", 129 | "downloadFormat": "下载{lang}翻译" 130 | }, 131 | "toast": { 132 | "copySuccess": "内容已复制到剪贴板", 133 | "copyError": "复制失败,请手动复制", 134 | "downloadSuccess": "{lang}翻译文件已下载", 135 | "downloadAllSuccess": "所有翻译文件已下载", 136 | "downloadError": "下载失败,请重试" 137 | }, 138 | "languages": { 139 | "en": "英语", 140 | "ru": "俄语", 141 | "es": "西班牙语", 142 | "de": "德语", 143 | "tr": "土耳其语", 144 | "fr": "法语", 145 | "ja": "日语", 146 | "pt": "葡萄牙语", 147 | "zh": "简体中文", 148 | "zh-TW": "繁体中文", 149 | "it": "意大利语", 150 | "ar": "阿拉伯语", 151 | "pl": "波兰语", 152 | "el": "希腊语", 153 | "nl": "荷兰语", 154 | "id": "印尼语", 155 | "ko": "韩语", 156 | "th": "泰", 157 | "vi": "越南语", 158 | "fa": "波斯语", 159 | "uk": "乌克兰语", 160 | "he": "希伯来语", 161 | "sv": "瑞典语", 162 | "ro": "罗马尼亚语", 163 | "hu": "匈牙利语", 164 | "da": "丹麦语", 165 | "sk": "斯洛伐克语", 166 | "sr": "塞尔维亚语", 167 | "bg": "保加利亚语", 168 | "fi": "芬兰语", 169 | "hr": "克罗地亚语", 170 | "lt": "立陶宛语", 171 | "nb": "挪威语(书面语)", 172 | "sl": "斯洛文尼亚语", 173 | "lv": "拉脱维亚语", 174 | "et": "爱沙尼亚语", 175 | "cs": "捷克语", 176 | "ca": "加泰罗尼亚语", 177 | "hi": "印地语", 178 | "bn": "孟加拉语", 179 | "ta": "泰米尔语", 180 | "ur": "乌尔都语", 181 | "gu": "古吉拉特语", 182 | "kn": "卡纳达语", 183 | "ml": "马拉雅拉姆语", 184 | "mr": "马拉地语", 185 | "ms": "马来语", 186 | "my": "缅甸语", 187 | "km": "柬埔寨语", 188 | "lo": "老挝语", 189 | "mn": "蒙古语", 190 | "az": "阿塞拜疆语", 191 | "ka": "格鲁吉亚语", 192 | "hy": "亚美尼亚语", 193 | "sw": "斯瓦希里语", 194 | "af": "南非荷兰语", 195 | "am": "阿姆哈拉语" 196 | } 197 | }, 198 | "faq": { 199 | "title": "常见问题", 200 | "description": "关于 JSON 翻译工具的常见问题", 201 | "items": [ 202 | { 203 | "question": "这个工具是做什么的?", 204 | "answer": "这是一个 AI 驱动的 JSON 国际化翻译工具,帮助开发者在保持 JSON 结构完整性的同时快速将 JSON 语言文件翻译成多种语言。" 205 | }, 206 | { 207 | "question": "如何使用这个工具?", 208 | "answer": "1. 上传需要翻译的 JSON 文件\n2. 选择目标语言\n3. 输入 OpenAI API Key\n4. 点击开始翻译\n5. 翻译完成后下载结果" 209 | }, 210 | { 211 | "question": "支持哪些语言?", 212 | "answer": "目前支持包括英语、简体中文、繁体中文、日语、韩语、法语、德、西班牙语、俄语等多种语言。" 213 | }, 214 | { 215 | "question": "我的 API Key 会被保存吗?", 216 | "answer": "不会。您的 API Key 仅在浏览器中临时使用,不会被保存或传输到任何服务器。" 217 | }, 218 | { 219 | "question": "如何保证翻译质量?", 220 | "answer": "我们使用 OpenAI 的 GPT 模型进行翻译,确保专业术语的准确性和语言表达的自然性。我们还支持自定义词典功能来保持特定术语的一致性。" 221 | }, 222 | { 223 | "question": "文件大小有限制吗?", 224 | "answer": "单个 JSON 文件大小限制为 10MB。对于更大的文件,建议分批翻译。" 225 | } 226 | ] 227 | }, 228 | "cta": { 229 | "title": "立即使用 AI 翻译工具", 230 | "description": "快速准确地将您的 JSON 语言文件翻译成多种语言", 231 | "button": "立即尝试", 232 | "features": [ 233 | "无需注册", 234 | "完全免费", 235 | "实时翻译" 236 | ] 237 | }, 238 | "footer": { 239 | "creator": "由 Viggo 用 ❤️ 创建", 240 | "twitter": "@viggo", 241 | "coffee": "请我喝咖啡", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "JSON翻译工具 - AI驱动的多语言翻译解决方案", 246 | "description": "使用AI技术快速准确地将JSON语言文件翻译成多种语言。支持保持JSON结构、变量占位符和HTML标签。", 247 | "keywords": "JSON翻译,AI翻译,国际化,i18n,多语言翻译,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/zh-TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "AI 驅動", 4 | "title": "i18n JSON 翻譯工具", 5 | "description": "使用 AI 技術快速翻譯您的 JSON 語言文件。快速、準確且易於使用。", 6 | "features": { 7 | "multilanguage": "多語言支持", 8 | "realtime": "實時翻譯" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "四個簡單步驟完成翻譯", 13 | "description": "我們簡化了 JSON 文件翻譯過程,幫助您快速獲得高質量的翻譯結果", 14 | "steps": { 15 | "0": { 16 | "title": "上傳 JSON 文件", 17 | "description": "支持拖放或點擊選擇文件" 18 | }, 19 | "1": { 20 | "title": "選擇目標語言", 21 | "description": "選擇翻譯的目標語言" 22 | }, 23 | "2": { 24 | "title": "開始翻譯", 25 | "description": "輸入 API 密鑰並開始 AI 翻譯" 26 | }, 27 | "3": { 28 | "title": "下載結果", 29 | "description": "下載翻譯後的 JSON 文件" 30 | } 31 | } 32 | }, 33 | "features": { 34 | "title": "強大的翻譯功能", 35 | "items": { 36 | "0": { 37 | "title": "保留 JSON 結構", 38 | "description": "智能識別並保持原始 JSON 文件的結構、縮排和格式" 39 | }, 40 | "1": { 41 | "title": "多語言支持", 42 | "description": "支持多種語言之間的翻譯,包括英語、中文、日語等" 43 | }, 44 | "2": { 45 | "title": "AI 驅動的翻譯", 46 | "description": "利用 OpenAI GPT 模型確保技術術語的準確性和自然表達" 47 | }, 48 | "3": { 49 | "title": "安全可靠", 50 | "description": "API 密鑰僅在瀏覽器中暫時使用,從不保存或傳輸到伺服器" 51 | } 52 | } 53 | }, 54 | "uploadSection": { 55 | "title": "上傳 JSON 文件", 56 | "description": "上傳您的 JSON 文件以進行翻譯", 57 | "dragText": "將文件拖到這裡或點擊上傳", 58 | "supportText": "支持 .json 格式文件,最大 10MB", 59 | "apiKeyTip": "提示:翻譯需要 OpenAI API 密鑰", 60 | "errors": { 61 | "selectFile": "請選擇一個文件", 62 | "jsonExtension": "請上傳一個 .json 擴展名的文件", 63 | "fileSize": "文件大小不能超過 10MB", 64 | "jsonFormat": "無效的 JSON 格式,請檢查文件內容", 65 | "emptyJson": "JSON 文件不能為空" 66 | }, 67 | "success": { 68 | "uploaded": "文件上傳成功" 69 | }, 70 | "apiKeyTitle": "OpenAI API 密鑰", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "錯誤", 73 | "successTitle": "成功" 74 | }, 75 | "translateSection": { 76 | "title": "選擇目標語言", 77 | "description": "選擇要翻譯的語言" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "開始翻譯", 81 | "translating": "翻譯中...", 82 | "cancel": "取消", 83 | "uploadFirst": "請先上傳文件", 84 | "enterApiKey": "請輸入 API 密鑰", 85 | "foundUnfinished": "發現未完成的翻譯", 86 | "continueTranslation": "繼續翻譯", 87 | "translationCancelled": "翻譯已取消", 88 | "invalidApiKey": "無效的 API 密鑰格式", 89 | "errorTitle": "錯誤", 90 | "successTitle": "成功", 91 | "translationCompleted": "翻譯完成!", 92 | "showMoreLanguages": "顯示更多語言", 93 | "hideMoreLanguages": "隱藏更多語言", 94 | "overallProgress": "整體進度", 95 | "completedSegments": "已完成段落", 96 | "translatingLanguage": "翻譯中", 97 | "allLanguagesTranslated": "所有選擇的語言已翻譯", 98 | "pleaseUploadAndEnterKey": "請上傳文件並輸入 API 金鑰", 99 | "tip": "提示", 100 | "cancelled": "已取消", 101 | "translationFailed": "翻譯失敗", 102 | "pleaseSelectLanguage": "請至少選擇一種目標語言", 103 | "bytes": "位元組", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "無效的 API 密鑰格式", 109 | "invalidOrExpired": "無效或已過期的 API 密鑰", 110 | "rateLimitReached": "API 調用次數已達上限", 111 | "validationFailed": "API 密鑰驗證失敗" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "預覽", 116 | "empty": "JSON 預覽將顯示在這裡", 117 | "copied": "已複製到剪貼簿", 118 | "originalJson": "原始 JSON", 119 | "translatedJson": "翻譯後的 JSON", 120 | "tips": "提示:支持 JSON 文件的即時預覽和格式化,您可以直接複製內容", 121 | "placeholder": { 122 | "upload": "請上傳一個 JSON 文件", 123 | "translation": "翻譯結果將顯示在這裡" 124 | }, 125 | "actions": { 126 | "copy": "複製", 127 | "download": "下載", 128 | "downloadAll": "下載所有翻譯", 129 | "downloadFormat": "下載 {lang} 翻譯" 130 | }, 131 | "toast": { 132 | "copySuccess": "內容已複製到剪貼簿", 133 | "copyError": "複製失敗,請手動複製", 134 | "downloadSuccess": "{lang} 翻譯文件已下載", 135 | "downloadAllSuccess": "所有翻譯文件已下載", 136 | "downloadError": "下載失敗,請再試一次" 137 | }, 138 | "languages": { 139 | "en": "英語", 140 | "zh": "中文(簡體)", 141 | "zh-TW": "中文(繁體)", 142 | "ja": "日語", 143 | "ko": "韓語", 144 | "fr": "法語", 145 | "de": "德語", 146 | "es": "西班牙語", 147 | "pt": "葡萄牙語", 148 | "it": "意大利語", 149 | "ru": "俄語", 150 | "ar": "阿拉伯語", 151 | "hi": "印地語", 152 | "bn": "孟加拉語", 153 | "th": "泰語", 154 | "vi": "越南語", 155 | "id": "印尼語", 156 | "ms": "馬來語", 157 | "tr": "土耳其語", 158 | "nl": "荷蘭語", 159 | "pl": "波蘭語", 160 | "uk": "烏克蘭語", 161 | "el": "希臘語", 162 | "he": "希伯來語", 163 | "sv": "瑞典語", 164 | "da": "丹麥語", 165 | "fi": "芬蘭語", 166 | "cs": "捷克語", 167 | "ro": "羅馬尼亞語", 168 | "hu": "匈牙利語", 169 | "sk": "斯洛伐克語", 170 | "bg": "保加利亞語", 171 | "hr": "克羅地亞語", 172 | "lt": "立陶宛語", 173 | "sl": "斯洛文尼亞語", 174 | "et": "愛沙尼亞語", 175 | "lv": "拉脫維亞語", 176 | "sr": "塞爾維亞語", 177 | "mt": "馬耳他語", 178 | "fa": "波斯語", 179 | "ur": "烏爾都語", 180 | "ta": "泰米爾語", 181 | "te": "泰盧固語", 182 | "ml": "馬拉雅拉姆語", 183 | "kn": "卡納達語", 184 | "mr": "馬拉地語", 185 | "gu": "古吉拉特語", 186 | "my": "緬甸語", 187 | "km": "高棉語", 188 | "lo": "老撾語", 189 | "mn": "蒙古語", 190 | "ka": "喬治亞語", 191 | "hy": "亞美尼亞語", 192 | "az": "阿塞拜疆語", 193 | "sw": "斯瓦希里語", 194 | "af": "南非荷蘭語", 195 | "am": "阿姆哈拉語" 196 | } 197 | }, 198 | "faq": { 199 | "title": "常見問題", 200 | "description": "有關 JSON 翻譯工具的常見問題", 201 | "items": { 202 | "0": { 203 | "question": "這個工具是做什麼的?", 204 | "answer": "這是一個由 AI 驅動的 JSON 國際化翻譯工具,幫助開發者快速將 JSON 語言文件翻譯成多種語言,同時保持 JSON 結構的完整性。" 205 | }, 206 | "1": { 207 | "question": "如何使用這個工具?", 208 | "answer": "1. 上傳您的 JSON 文件進行翻譯\n2. 選擇目標語言\n3. 輸入您的 OpenAI API 密鑰\n4. 點擊開始翻譯\n5. 翻譯完成後下載結果" 209 | }, 210 | "2": { 211 | "question": "支持哪些語言?", 212 | "answer": "目前支持多種語言,包括英語、中文(簡體)、中文(繁體)、日語、韓語、法語、德語、西班牙語、俄語等。" 213 | }, 214 | "3": { 215 | "question": "我的 API 金鑰會被保存嗎?", 216 | "answer": "不會。您的 API 金鑰僅在瀏覽器中暫時使用,不會被保存或傳輸到任何伺服器。" 217 | }, 218 | "4": { 219 | "question": "如何確保翻譯質量?", 220 | "answer": "我們使用 OpenAI 的 GPT 模型進行翻譯,確保技術術語的準確性和自然語言表達。我們還支持自定義字典功能,以保持特定術語的一致性。" 221 | }, 222 | "5": { 223 | "question": "是否有檔案大小限制?", 224 | "answer": "單個 JSON 檔案大小限制為 10MB。對於較大的檔案,建議將其拆分並分批翻譯。" 225 | } 226 | } 227 | }, 228 | "cta": { 229 | "title": "立即開始使用 AI 翻譯工具", 230 | "description": "快速準確地將您的 JSON 語言檔案翻譯成多種語言", 231 | "button": "立即試用", 232 | "features": { 233 | "0": "無需註冊", 234 | "1": "完全免費", 235 | "2": "即時翻譯" 236 | } 237 | }, 238 | "footer": { 239 | "creator": "由 Viggo ❤️ 創建", 240 | "twitter": "@viggo", 241 | "coffee": "請我喝杯咖啡", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "JSON翻譯工具 - AI驅動的多語言翻譯解決方案", 246 | "description": "使用AI技術快速準確地將JSON語言文件翻譯成多種語言。支持保持JSON結構、變量佔位符和HTML標籤。", 247 | "keywords": "JSON翻譯,AI翻譯,國際化,i18n,多語言翻譯,OpenAI,線上工具" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "AI搭載", 4 | "title": "i18n JSON国際化翻訳ツール", 5 | "description": "AI技術で素早くJSONファイルを翻訳。高速、正確、使いやすい。", 6 | "features": { 7 | "multilanguage": "多言語対応", 8 | "realtime": "リアルタイム翻訳" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "4つの簡単なステップで翻訳完了", 13 | "description": "JSONファイルの翻訳プロセスを簡素化し、高品質な翻訳結果を素早く取得できます", 14 | "steps": [ 15 | { 16 | "title": "JSONファイルをアップロード", 17 | "description": "ドラッグ&ドロップまたはクリックでファイルを選択" 18 | }, 19 | { 20 | "title": "対象言語を選択", 21 | "description": "翻訳したい言語を選択" 22 | }, 23 | { 24 | "title": "翻訳開始", 25 | "description": "APIキーを入力してAI翻訳を開始" 26 | }, 27 | { 28 | "title": "結果をダウンロード", 29 | "description": "翻訳されたJSONファイルをダウンロード" 30 | } 31 | ] 32 | }, 33 | "features": { 34 | "title": "パワフルな翻訳機能", 35 | "items": [ 36 | { 37 | "title": "JSON構造を保持", 38 | "description": "元のJSONファイルの構造、インデント、フォーマットを維持" 39 | }, 40 | { 41 | "title": "多言語対応", 42 | "description": "英語、中国語、日本語など、多数の言語間の翻訳をサポート" 43 | }, 44 | { 45 | "title": "AI駆動の翻訳", 46 | "description": "OpenAI GPTモデルを使用し、専門用語の正確性と自然な表現を確保" 47 | }, 48 | { 49 | "title": "安全性と信頼性", 50 | "description": "APIキーはブラウザで一時的に使用するのみで、保存や送信は行いません" 51 | } 52 | ] 53 | }, 54 | "uploadSection": { 55 | "title": "JSONファイルをアップロード", 56 | "description": "翻訳したいJSONファイルをアップロードしてください", 57 | "dragText": "ファイルをドラッグ&ドロップまたはクリックしてアップロード", 58 | "supportText": ".json形式のファイル(最大10MB)に対応", 59 | "apiKeyTip": "ヒント:翻訳にはOpenAI API Keyが必要です", 60 | "errors": { 61 | "selectFile": "ファイルを選択してください", 62 | "jsonExtension": ".json形式のファイルをアップロードしてください", 63 | "fileSize": "ファイルサイズは10MB以下にしてください", 64 | "jsonFormat": "無効なJSON形式です。ファイルの内容を確認してください", 65 | "emptyJson": "JSONファイルが空です" 66 | }, 67 | "success": { 68 | "uploaded": "ファイルのアップロードが完了しました" 69 | }, 70 | "apiKeyTitle": "OpenAI API Key", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "エラー", 73 | "successTitle": "成功" 74 | }, 75 | "translateSection": { 76 | "title": "対象言語を選択", 77 | "description": "翻訳したい言語を選んでください" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "翻訳開始", 81 | "translating": "翻訳中...", 82 | "cancel": "キャンセル", 83 | "uploadFirst": "ファイルをアップロードしてください", 84 | "enterApiKey": "API Keyを入力してください", 85 | "foundUnfinished": "未完了の翻訳が見つかりました", 86 | "continueTranslation": "翻訳を続ける", 87 | "translationCancelled": "翻訳がキャンセルされました", 88 | "invalidApiKey": "無効なAPI Keyフォーマット", 89 | "errorTitle": "エラー", 90 | "successTitle": "成功", 91 | "translationCompleted": "翻訳が完了しました!", 92 | "showMoreLanguages": "他の言語を表示", 93 | "hideMoreLanguages": "言語を隠す", 94 | "overallProgress": "全体の進捗", 95 | "completedSegments": "完了セグメント", 96 | "translatingLanguage": "翻訳中の言語", 97 | "allLanguagesTranslated": "選択された全ての言語が翻訳済みです", 98 | "pleaseUploadAndEnterKey": "ファイルをアップロードしAPI Keyを入力してください", 99 | "tip": "ヒント", 100 | "cancelled": "キャンセル済み", 101 | "translationFailed": "翻訳に失敗しました", 102 | "pleaseSelectLanguage": "翻訳する言語を1つ以上選択してください", 103 | "bytes": "バイト", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "APIキーの形式が無効です", 109 | "invalidOrExpired": "APIキーが無効または期限切れです", 110 | "rateLimitReached": "APIレート制限に達しました", 111 | "validationFailed": "APIキーの検証に失敗しました" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "プレビュー", 116 | "empty": "JSONプレビューがここに表示されます", 117 | "copied": "クリップボードにコピーしました", 118 | "originalJson": "元のJSON", 119 | "translatedJson": "翻訳されたJSON", 120 | "tips": "ヒント:JSONファイルのリアルタイムプレビューと整形をサポートし、内容を直接コピーできます", 121 | "placeholder": { 122 | "upload": "JSONファイルをアップロードしてください", 123 | "translation": "翻訳結果がここに表示されます" 124 | }, 125 | "actions": { 126 | "copy": "コピー", 127 | "download": "ダウンロード", 128 | "downloadAll": "すべての翻訳をダウンロード", 129 | "downloadFormat": "{lang}の翻訳をダウンロード" 130 | }, 131 | "toast": { 132 | "copySuccess": "内容をクリップボードにコピーしました", 133 | "copyError": "コピーに失敗しました。手動でコピーしてください", 134 | "downloadSuccess": "{lang}の翻訳ファイルをダウンロードしました", 135 | "downloadAllSuccess": "すべての翻訳ファイルをダウンロードしました", 136 | "downloadError": "ダウンロードに失敗しました。もう一度お試しください" 137 | }, 138 | "languages": { 139 | "en": "英語", 140 | "zh": "中国語(簡体字)", 141 | "zh-TW": "中国語(繁体字)", 142 | "ja": "日本語", 143 | "ko": "韓国語", 144 | "fr": "フランス語", 145 | "de": "ドイツ語", 146 | "es": "スペイン語", 147 | "pt": "ポルトガル語", 148 | "it": "イタリア語", 149 | "ru": "ロシア語", 150 | "ar": "アラビア語", 151 | "hi": "ヒンディー語", 152 | "bn": "ベンガル語", 153 | "th": "タイ語", 154 | "vi": "ベトナム語", 155 | "id": "インドネシア語", 156 | "ms": "マレー語", 157 | "tr": "トルコ語", 158 | "nl": "オランダ語", 159 | "pl": "ポーランド語", 160 | "uk": "ウクライナ語", 161 | "el": "ギリシャ語", 162 | "he": "ヘブライ語", 163 | "sv": "スウェーデン語", 164 | "da": "デンマーク語", 165 | "fi": "フィンランド語", 166 | "cs": "チェコ語", 167 | "ro": "ルーマニア語", 168 | "hu": "ハンガリー語", 169 | "sk": "スロバキア語", 170 | "bg": "ブルガリア語", 171 | "hr": "クロアチア語", 172 | "lt": "リトアニア語", 173 | "sl": "スロベニア語", 174 | "et": "エストニア語", 175 | "lv": "ラトビア語", 176 | "sr": "セルビア語", 177 | "mt": "マルタ語", 178 | "fa": "ペルシャ語", 179 | "ur": "ウルドゥー語", 180 | "ta": "タミル語", 181 | "te": "テルグ語", 182 | "ml": "マラヤーラム語", 183 | "kn": "カンナダ語", 184 | "mr": "マラーティー語", 185 | "gu": "グジャラート語", 186 | "my": "ミャンマー語", 187 | "km": "クメール語", 188 | "lo": "ラオス語", 189 | "mn": "モンゴル語", 190 | "ka": "グルジア語", 191 | "hy": "アルメニア語", 192 | "az": "アゼルバイジャン語", 193 | "sw": "スワヒリ語", 194 | "af": "アフリカーンス語", 195 | "am": "アムハラ語" 196 | } 197 | }, 198 | "faq": { 199 | "title": "よくある質問", 200 | "description": "JSON翻訳ツールに関するよくある質問", 201 | "items": [ 202 | { 203 | "question": "このツールは何ができますか?", 204 | "answer": "これはAI搭載のJSON国際化翻訳ツールで、開発者がJSONファイルの構造を維持しながら、複数の言語に素早く翻訳することができます。" 205 | }, 206 | { 207 | "question": "使い方を教えてください", 208 | "answer": "1. 翻訳したいJSONファイルをアップロード\n2. 対象言語を選択\n3. OpenAI APIキーを入力\n4. 翻訳を開始\n5. 翻訳完了後、結果をダウンロード" 209 | }, 210 | { 211 | "question": "対応している言語は?", 212 | "answer": "現在、英語、簡体字中国語、繁体字中国語、日本語、韓国語、フランス語、ドイツ語、スペイン語、ロシア語など、多数の言語に対応しています。" 213 | }, 214 | { 215 | "question": "APIキーは保存されますか?", 216 | "answer": "いいえ。APIキーはブラウザで一時的に使用されるだけで、サーバーに保存や送信されることはありません。" 217 | }, 218 | { 219 | "question": "翻訳品質はどのように保証されていますか?", 220 | "answer": "OpenAIのGPTモデルを使用して翻訳を行い、専門用語の正確性と自然な表現を確保しています。また、特定の用語の一貫性を保つためのカスタム辞書機能もサポートしています。" 221 | }, 222 | { 223 | "question": "ファイルサイズの制限はありますか?", 224 | "answer": "1つのJSONファイルのサイズ制限は10MBです。より大きなファイルの場合は、分割して翻訳することをお勧めします。" 225 | } 226 | ] 227 | }, 228 | "cta": { 229 | "title": "今すぐAI翻訳ツールを使用開始", 230 | "description": "JSONファイルを素早く正確に多言語翻訳", 231 | "button": "今すぐ試す", 232 | "features": [ 233 | "登録不要", 234 | "完全無料", 235 | "リアルタイム翻訳" 236 | ] 237 | }, 238 | "footer": { 239 | "creator": "Viggoが❤️を込めて作成", 240 | "twitter": "@viggo", 241 | "coffee": "コーヒーを奢る", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "JSON翻訳ツール - AI搭載の多言語翻訳ソリューション", 246 | "description": "AI技術で素早く正確にJSONファイルを多言語に翻訳。JSON構造、変数プレースホルダー、HTMLタグをサポート。", 247 | "keywords": "JSON翻訳,AI翻訳,国際化,i18n,多言語翻訳,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "AI 기반", 4 | "title": "i18n JSON 번역 도구", 5 | "description": "AI 기술을 사용하여 JSON 언어 파일을 빠르게 번역하세요. 빠르고 정확하며 사용하기 쉽습니다.", 6 | "features": { 7 | "multilanguage": "다국어 지원", 8 | "realtime": "실시간 번역" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "네 가지 간단한 단계로 완전한 번역", 13 | "description": "JSON 파일 번역 프로세스를 간소화하여 고품질 번역 결과를 신속하게 얻을 수 있도록 도와드립니다.", 14 | "steps": { 15 | "0": { 16 | "title": "JSON 파일 업로드", 17 | "description": "드래그 앤 드롭 또는 클릭하여 파일 선택 지원" 18 | }, 19 | "1": { 20 | "title": "대상 언어 선택", 21 | "description": "번역할 대상 언어를 선택하세요" 22 | }, 23 | "2": { 24 | "title": "번역 시작", 25 | "description": "API 키를 입력하고 AI 번역을 시작하세요" 26 | }, 27 | "3": { 28 | "title": "결과 다운로드", 29 | "description": "번역된 JSON 파일을 다운로드하세요" 30 | } 31 | } 32 | }, 33 | "features": { 34 | "title": "강력한 번역 기능", 35 | "items": { 36 | "0": { 37 | "title": "JSON 구조 유지", 38 | "description": "원본 JSON 파일의 구조, 들여쓰기 및 형식을 지능적으로 인식하고 유지합니다." 39 | }, 40 | "1": { 41 | "title": "다국어 지원", 42 | "description": "영어, 중국어, 일본어 등 여러 언어 간 번역 지원" 43 | }, 44 | "2": { 45 | "title": "AI 기반 번역", 46 | "description": "기술 용어의 정확성과 자연스러운 표현을 보장하기 위해 OpenAI GPT 모델을 활용합니다." 47 | }, 48 | "3": { 49 | "title": "안전하고 신뢰할 수 있음", 50 | "description": "API 키는 브라우저에서만 일시적으로 사용되며 서버에 저장되거나 전송되지 않습니다." 51 | } 52 | } 53 | }, 54 | "uploadSection": { 55 | "title": "JSON 파일 업로드", 56 | "description": "번역을 위해 JSON 파일을 업로드하세요", 57 | "dragText": "여기에 파일을 드래그하거나 클릭하여 업로드", 58 | "supportText": ".json 형식 파일 지원, 최대 10MB", 59 | "apiKeyTip": "팁: 번역을 위해 OpenAI API 키가 필요합니다", 60 | "errors": { 61 | "selectFile": "파일을 선택하세요", 62 | "jsonExtension": ".json 확장자를 가진 파일을 업로드하세요", 63 | "fileSize": "파일 크기는 10MB를 초과할 수 없습니다", 64 | "jsonFormat": "유효하지 않은 JSON 형식입니다. 파일 내용을 확인하세요", 65 | "emptyJson": "JSON 파일은 비어 있을 수 없습니다" 66 | }, 67 | "success": { 68 | "uploaded": "파일이 성공적으로 업로드되었습니다." 69 | }, 70 | "apiKeyTitle": "OpenAI API 키", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "오류", 73 | "successTitle": "성공" 74 | }, 75 | "translateSection": { 76 | "title": "대상 언어 선택", 77 | "description": "번역할 언어를 선택하세요" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "번역 시작", 81 | "translating": "번역 중...", 82 | "cancel": "취소", 83 | "uploadFirst": "먼저 파일을 업로드하세요", 84 | "enterApiKey": "API 키를 입력하세요", 85 | "foundUnfinished": "완료되지 않은 번역이 발견되었습니다", 86 | "continueTranslation": "번역 계속하기", 87 | "translationCancelled": "번역이 취소되었습니다", 88 | "invalidApiKey": "유효하지 않은 API 키 형식", 89 | "errorTitle": "오류", 90 | "successTitle": "성공", 91 | "translationCompleted": "번역이 완료되었습니다!", 92 | "showMoreLanguages": "더 많은 언어 보기", 93 | "hideMoreLanguages": "더 많은 언어 숨기기", 94 | "overallProgress": "전체 진행 상황", 95 | "completedSegments": "완료된 세그먼트", 96 | "translatingLanguage": "번역 중", 97 | "allLanguagesTranslated": "선택한 모든 언어가 번역되었습니다", 98 | "pleaseUploadAndEnterKey": "파일을 업로드하고 API 키를 입력해 주세요", 99 | "tip": "팁", 100 | "cancelled": "취소됨", 101 | "translationFailed": "번역 실패", 102 | "pleaseSelectLanguage": "최소한 하나의 대상 언어를 선택해 주세요", 103 | "bytes": "바이트", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "잘못된 API 키 형식", 109 | "invalidOrExpired": "유효하지 않거나 만료된 API 키", 110 | "rateLimitReached": "API 호출 한도에 도달했습니다", 111 | "validationFailed": "API 키 검증 실패" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "미리보기", 116 | "empty": "여기에 JSON 미리보기가 표시됩니다", 117 | "copied": "클립보드에 복사됨", 118 | "originalJson": "원본 JSON", 119 | "translatedJson": "번역된 JSON", 120 | "tips": "팁: JSON 파일의 실시간 미리보기 및 형식을 지원하며, 내용을 직접 복사할 수 있습니다", 121 | "placeholder": { 122 | "upload": "JSON 파일을 업로드해 주세요", 123 | "translation": "번역 결과가 여기에 표시됩니다" 124 | }, 125 | "actions": { 126 | "copy": "복사", 127 | "download": "다운로드", 128 | "downloadAll": "모든 번역 다운로드", 129 | "downloadFormat": "{lang} 번역 다운로드" 130 | }, 131 | "toast": { 132 | "copySuccess": "내용이 클립보드에 복사되었습니다", 133 | "copyError": "복사 실패, 수동으로 복사해 주세요", 134 | "downloadSuccess": "{lang} 번역 파일이 다운로드되었습니다", 135 | "downloadAllSuccess": "모든 번역 파일이 다운로드되었습니다", 136 | "downloadError": "다운로드 실패, 다시 시도해 주세요" 137 | }, 138 | "languages": { 139 | "en": "영어", 140 | "zh": "중국어 (간체)", 141 | "zh-TW": "중국어 (번체)", 142 | "ja": "일본어", 143 | "ko": "한국어", 144 | "fr": "프랑스어", 145 | "de": "독일어", 146 | "es": "스페인어", 147 | "pt": "포르투갈어", 148 | "it": "이탈리아어", 149 | "ru": "러시아어", 150 | "ar": "아랍어", 151 | "hi": "힌디어", 152 | "bn": "벵골어", 153 | "th": "태국어", 154 | "vi": "베트남어", 155 | "id": "인도네시아어", 156 | "ms": "말레이어", 157 | "tr": "터키어", 158 | "nl": "네덜란드어", 159 | "pl": "폴란드어", 160 | "uk": "우크라이나어", 161 | "el": "그리스어", 162 | "he": "히브리어", 163 | "sv": "스웨덴어", 164 | "da": "덴마크어", 165 | "fi": "핀란드어", 166 | "cs": "체코어", 167 | "ro": "루마니아어", 168 | "hu": "헝가리어", 169 | "sk": "슬로바키아어", 170 | "bg": "불가리아어", 171 | "hr": "크로아티아어", 172 | "lt": "리투아니아어", 173 | "sl": "슬로베니아어", 174 | "et": "에스토니아어", 175 | "lv": "라트비아어", 176 | "sr": "세르비아어", 177 | "mt": "몰타어", 178 | "fa": "페르시아어", 179 | "ur": "우르두어", 180 | "ta": "타밀어", 181 | "te": "텔루구어", 182 | "ml": "말라얄람어", 183 | "kn": "칸나다어", 184 | "mr": "마라티어", 185 | "gu": "구자라티어", 186 | "my": "버마어", 187 | "km": "크메르어", 188 | "lo": "라오어", 189 | "mn": "몽골어", 190 | "ka": "조지아어", 191 | "hy": "아르메니아어", 192 | "az": "아제르바이잔어", 193 | "sw": "스와힐리어", 194 | "af": "아프리칸스어", 195 | "am": "암하라어" 196 | } 197 | }, 198 | "faq": { 199 | "title": "자주 묻는 질문", 200 | "description": "JSON 번역 도구에 대한 일반적인 질문", 201 | "items": { 202 | "0": { 203 | "question": "이 도구는 무엇을 하나요?", 204 | "answer": "이 도구는 개발자가 JSON 구조의 무결성을 유지하면서 JSON 언어 파일을 여러 언어로 신속하게 번역할 수 있도록 돕는 AI 기반 JSON 국제화 번역 도구입니다." 205 | }, 206 | "1": { 207 | "question": "이 도구를 어떻게 사용하나요?", 208 | "answer": "1. 번역할 JSON 파일을 업로드합니다.\n2. 대상 언어를 선택합니다.\n3. OpenAI API 키를 입력합니다.\n4. 번역 시작을 클릭합니다.\n5. 번역이 완료된 후 결과를 다운로드합니다." 209 | }, 210 | "2": { 211 | "question": "어떤 언어가 지원되나요?", 212 | "answer": "현재 영어, 중국어(간체), 중국어(번체), 일본어, 한국어, 프랑스어, 독일어, 스페인어, 러시아어 등 여러 언어를 지원합니다." 213 | }, 214 | "3": { 215 | "question": "내 API 키가 저장되나요?", 216 | "answer": "아니요. 귀하의 API 키는 브라우저에서 임시로만 사용되며 저장되거나 서버로 전송되지 않습니다." 217 | }, 218 | "4": { 219 | "question": "번역 품질은 어떻게 보장되나요?", 220 | "answer": "우리는 번역을 위해 OpenAI의 GPT 모델을 사용하여 기술 용어의 정확성과 자연어 표현을 보장합니다. 또한 특정 용어의 일관성을 유지하기 위해 사용자 정의 사전 기능을 지원합니다." 221 | }, 222 | "5": { 223 | "question": "파일 크기 제한이 있나요?", 224 | "answer": "단일 JSON 파일 크기는 10MB로 제한됩니다. 더 큰 파일의 경우, 파일을 분할하여 배치로 번역하는 것이 권장됩니다." 225 | } 226 | } 227 | }, 228 | "cta": { 229 | "title": "지금 AI 번역 도구 사용 시작하기", 230 | "description": "귀하의 JSON 언어 파일을 여러 언어로 빠르고 정확하게 번역합니다", 231 | "button": "지금 사용해 보기", 232 | "features": { 233 | "0": "등록 필요 없음", 234 | "1": "완전히 무료", 235 | "2": "실시간 번역" 236 | } 237 | }, 238 | "footer": { 239 | "creator": "❤️로 만든 Viggo", 240 | "twitter": "@viggo", 241 | "coffee": "커피 한 잔 사주세요", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "JSON 번역 도구 - AI 기반 다국어 번역 솔루션", 246 | "description": "AI 기술을 사용하여 JSON 언어 파일을 여러 언어로 빠르고 정확하게 번역합니다. JSON 구조, 변수 자리 표시자 및 HTML 태그를 지원합니다.", 247 | "keywords": "JSON번역,AI번역,국제화,i18n,다국어번역,OpenAI,온라인도구" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "مدعوم بالذكاء الاصطناعي", 4 | "title": "i18n أداة ترجمة JSON", 5 | "description": "ترجم ملفات لغة JSON الخاصة بك بسرعة باستخدام تقنية الذكاء الاصطناعي. سريع ودقيق وسهل الاستخدام.", 6 | "features": { 7 | "multilanguage": "دعم متعدد اللغات", 8 | "realtime": "ترجمة في الوقت الحقيقي" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "إكمال الترجمة في أربع خطوات بسيطة", 13 | "description": "لقد قمنا بتبسيط عملية ترجمة ملفات JSON لمساعدتك في الحصول بسرعة على نتائج ترجمة عالية الجودة", 14 | "steps": { 15 | "0": { 16 | "title": "تحميل ملف JSON", 17 | "description": "يدعم السحب والإفلات أو النقر لاختيار الملف" 18 | }, 19 | "1": { 20 | "title": "اختر اللغة المستهدفة", 21 | "description": "اختر اللغة المستهدفة للترجمة" 22 | }, 23 | "2": { 24 | "title": "ابدأ الترجمة", 25 | "description": "أدخل مفتاح API وابدأ الترجمة بالذكاء الاصطناعي" 26 | }, 27 | "3": { 28 | "title": "تحميل النتائج", 29 | "description": "قم بتنزيل ملف JSON المترجم" 30 | } 31 | } 32 | }, 33 | "features": { 34 | "title": "ميزات ترجمة قوية", 35 | "items": { 36 | "0": { 37 | "title": "الحفاظ على بنية JSON", 38 | "description": "التعرف الذكي والحفاظ على البنية والمسافة البادئة والتنسيق لملف JSON الأصلي" 39 | }, 40 | "1": { 41 | "title": "دعم متعدد اللغات", 42 | "description": "دعم الترجمة بين عدة لغات بما في ذلك الإنجليزية والصينية واليابانية والمزيد" 43 | }, 44 | "2": { 45 | "title": "ترجمة مدعومة بالذكاء الاصطناعي", 46 | "description": "استخدام نماذج OpenAI GPT لضمان دقة المصطلحات الفنية والتعبير الطبيعي" 47 | }, 48 | "3": { 49 | "title": "آمن وموثوق", 50 | "description": "تستخدم مفاتيح API مؤقتًا فقط في المتصفح ولا يتم حفظها أو نقلها إلى الخوادم" 51 | } 52 | } 53 | }, 54 | "uploadSection": { 55 | "title": "تحميل ملف JSON", 56 | "description": "قم بتحميل ملف JSON الخاص بك للترجمة", 57 | "dragText": "اسحب الملفات هنا أو انقر لتحميل", 58 | "supportText": "يدعم ملفات بتنسيق .json، حتى 10MB", 59 | "apiKeyTip": "نصائح: مفتاح OpenAI API مطلوب للترجمة", 60 | "errors": { 61 | "selectFile": "يرجى اختيار ملف", 62 | "jsonExtension": "يرجى تحميل ملف بامتداد .json", 63 | "fileSize": "لا يمكن أن يتجاوز حجم الملف 10MB", 64 | "jsonFormat": "تنسيق JSON غير صالح، يرجى التحقق من محتوى الملف", 65 | "emptyJson": "لا يمكن أن يكون ملف JSON فارغًا" 66 | }, 67 | "success": { 68 | "uploaded": "تم تحميل الملف بنجاح" 69 | }, 70 | "apiKeyTitle": "مفتاح OpenAI API", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "خطأ", 73 | "successTitle": "نجاح" 74 | }, 75 | "translateSection": { 76 | "title": "اختر اللغة المستهدفة", 77 | "description": "اختر اللغات للترجمة إليها" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "ابدأ الترجمة", 81 | "translating": "يتم الترجمة...", 82 | "cancel": "إلغاء", 83 | "uploadFirst": "يرجى تحميل ملف أولاً", 84 | "enterApiKey": "يرجى إدخال مفتاح API", 85 | "foundUnfinished": "تم العثور على ترجمة غير مكتملة", 86 | "continueTranslation": "تابع الترمة", 87 | "translationCancelled": "تم إلغاء الترجمة", 88 | "invalidApiKey": "تنسيق مفتاح API غير صالح", 89 | "errorTitle": "خطأ", 90 | "successTitle": "نجاح", 91 | "translationCompleted": "تمت الترجمة!", 92 | "showMoreLanguages": "عرض المزيد من اللغات", 93 | "hideMoreLanguages": "إخفاء المزيد من اللغات", 94 | "overallProgress": "التقدم العام", 95 | "completedSegments": "الأجزاء المكتملة", 96 | "translatingLanguage": "يتم الترجمة", 97 | "allLanguagesTranslated": "تمت ترجمة جميع اللغات المحددة", 98 | "pleaseUploadAndEnterKey": "يرجى تحميل ملف وإدخال مفتاح API", 99 | "tip": "نصيحة", 100 | "cancelled": "ملغى", 101 | "translationFailed": "فشلت الترجمة", 102 | "pleaseSelectLanguage": "يرجى اختيار لغة واحدة على الأقل", 103 | "bytes": "بايت", 104 | "kb": "كيلوبايت", 105 | "mb": "ميغابايت", 106 | "gb": "جيجابايت", 107 | "apiKeyErrors": { 108 | "invalidFormat": "تنسيق مفتاح API غير صالح", 109 | "invalidOrExpired": "مفتاح API غير صالح أو منتهي الصلاحية", 110 | "rateLimitReached": "تم الوصول إلى حد معدل API", 111 | "validationFailed": "فشل التحقق من مفتاح API" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "معاينة", 116 | "empty": "ستظهر معاينة JSON هنا", 117 | "copied": "تم النسخ إلى الحافظة", 118 | "originalJson": "JSON الأصلي", 119 | "translatedJson": "JSON المترجم", 120 | "tips": "نصائح: يدعم المعاينة الفورية وتنسيق ملفات JSON، ويمكنك نسخ المحتوى مباشرة", 121 | "placeholder": { 122 | "upload": "يرجى تحميل ملف JSON", 123 | "translation": "ستظهر نتائج الترجمة هنا" 124 | }, 125 | "actions": { 126 | "copy": "نسخ", 127 | "download": "تحميل", 128 | "downloadAll": "تحميل جميع الترجمات", 129 | "downloadFormat": "تحميل ترجمة {lang}" 130 | }, 131 | "toast": { 132 | "copySuccess": "تم نسخ المحتوى إلى الحافظة", 133 | "copyError": "فشل النسخ، يرجى النسخ يدويًا", 134 | "downloadSuccess": "تم تحميل ملف ترجمة {lang}", 135 | "downloadAllSuccess": "تم تحميل جميع ملفات الترجمة", 136 | "downloadError": "فشل التحميل، يرجى المحاولة مرة أخرى" 137 | }, 138 | "languages": { 139 | "en": "الإنجليزية", 140 | "zh": "الصينية (المبسطة)", 141 | "zh-TW": "الصينية (التقليدية)", 142 | "ja": "اليابانية", 143 | "ko": "الكورية", 144 | "fr": "الفرنسية", 145 | "de": "الألمانية", 146 | "es": "الإسبانية", 147 | "pt": "البرتغالية", 148 | "it": "الإيطالية", 149 | "ru": "الروسية", 150 | "ar": "العربية", 151 | "hi": "الهندية", 152 | "bn": "البنغالية", 153 | "th": "التايلاندية", 154 | "vi": "الفيتنامية", 155 | "id": "الإندونيسية", 156 | "ms": "الملايوية", 157 | "tr": "التركية", 158 | "nl": "الهولندية", 159 | "pl": "البولندية", 160 | "uk": "الأوكرانية", 161 | "el": "اليونانية", 162 | "he": "العبرية", 163 | "sv": "السويدية", 164 | "da": "الدنماركية", 165 | "fi": "الفنلندية", 166 | "cs": "التشيكية", 167 | "ro": "الرومانية", 168 | "hu": "المجرية", 169 | "sk": "السلوفاكية", 170 | "bg": "البلغارية", 171 | "hr": "الكرواتية", 172 | "lt": "الليتوانية", 173 | "sl": "السلوفينية", 174 | "et": "الإستونية", 175 | "lv": "اللاتفية", 176 | "sr": "الصربية", 177 | "mt": "المالطية", 178 | "fa": "الفارسية", 179 | "ur": "الأردية", 180 | "ta": "التاميلية", 181 | "te": "التيلوجو", 182 | "ml": "الملايالامية", 183 | "kn": "الكانادا", 184 | "mr": "الماراثية", 185 | "gu": "الغوجاراتية", 186 | "my": "البورمية", 187 | "km": "الخميرية", 188 | "lo": "اللاوية", 189 | "mn": "المغولية", 190 | "ka": "الجورجية", 191 | "hy": "الأرمنية", 192 | "az": "الأذربيجانية", 193 | "sw": "السواحيلية", 194 | "af": "الأفريقانية", 195 | "am": "الأمهرية" 196 | } 197 | }, 198 | "faq": { 199 | "title": "الأسئلة المتكررة", 200 | "description": "أسئلة شائعة حول أداة ترجمة JSON", 201 | "items": { 202 | "0": { 203 | "question": "ماذا تفعل هذه الأداة؟", 204 | "answer": "هذه أداة ترجمة دولية مدعومة بالذكاء الاصطناعي تساعد المطورين على ترجمة ملفات لغة JSON بسرعة إلى عدة لغات مع الحفاظ على سلامة هيكل JSON." 205 | }, 206 | "1": { 207 | "question": "كيف تستخدم هذه الأداة؟", 208 | "answer": "1. قم بتحميل ملف JSON الخاص بك للترجمة\n2. اختر اللغات المستهدفة\n3. أدخل مفتاح API الخاص بـ OpenAI\n4. انقر على بدء الترجمة\n5. قم بتنزيل النتائج بعد اكتمال الترجمة" 209 | }, 210 | "2": { 211 | "question": "ما هي اللغات المدعومة؟", 212 | "answer": "يدعم حاليًا عدة لغات بما في ذلك الإنجليزية والصينية (المبسطة) والصينية (التقليدية) واليابانية والكورية والفرنسية والألمانية والإسبانية والروسية والمزيد." 213 | }, 214 | "3": { 215 | "question": "هل سيتم حفظ مفتاح API الخاص بي؟", 216 | "answer": "لا. يتم استخدام مفتاح API الخاص بك مؤقتًا فقط في المتصفح ولن يتم حفظه أو نقله إلى أي خوادم." 217 | }, 218 | "4": { 219 | "question": "كيف يتم ضمان جودة الترجمة؟", 220 | "answer": "نستخدم نموذج GPT من OpenAI للترجمة، مما يضمن دقة المصطلحات الفنية والتعبير باللغة الطبيعية. كما ندعم وظيفة القاموس المخصص للحفاظ على اتساق المصطلحات المحددة." 221 | }, 222 | "5": { 223 | "question": "هل هناك حد لحجم الملف؟", 224 | "answer": "حجم ملف JSON الفردي محدود بـ 10 ميغابايت. بالنسبة للملفات الأكبر، يُوصى بتقسيمها وترجمتها على دفعات." 225 | } 226 | } 227 | }, 228 | "cta": { 229 | "title": "ابدأ استخدام أداة ترجمة الذكاء الاصطناعي الآن", 230 | "description": "ترجم بسرعة وبدقة ملفات لغة JSON الخاصة بك إلى عدة لغات", 231 | "button": "جرب الآن", 232 | "features": { 233 | "0": "لا حاجة للتسجيل", 234 | "1": "مجاني تمامًا", 235 | "2": "ترجمة في الوقت الحقيقي" 236 | } 237 | }, 238 | "footer": { 239 | "creator": "تم الإنشاء مع ❤️ بواسطة فيغو", 240 | "twitter": "@viggo", 241 | "coffee": "اشترِ لي قهوة", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "مترجم JSON - حل الترجمة متعدد اللغات المدعوم بالذكاء الاصطناعي", 246 | "description": "ترجم ملفات JSON اللغوية إلى لغات متعددة بسرعة ودقة باستخدام تقنية الذكاء الاصطناعي. يدعم هيكل JSON والمتغيرات وعلامات HTML.", 247 | "keywords": "ترجمة JSON,ترجمة الذكاء الاصطناعي,التدويل,i18n,الترجمة متعددة اللغات,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/th.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "ขับเคลื่อนด้วย AI", 4 | "title": "i18n เครื่องมือแปล JSON", 5 | "description": "แปลไฟล์ภาษา JSON ของคุณอย่างรวดเร็วโดยใช้เทคโนโลยี AI. รวดเร็ว, แม่นยำ, และใช้งานง่าย.", 6 | "features": { 7 | "multilanguage": "การสนับสนุนหลายภาษา", 8 | "realtime": "การแปลแบบเรียลไทม์" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "การแปลที่สมบูรณ์ในสี่ขั้นตอนง่ายๆ", 13 | "description": "เราได้ทำให้กระบวนการแปลไฟล์ JSON ง่ายขึ้นเพื่อช่วยให้คุณได้รับผลการแปลที่มีคุณภาพสูงอย่างรวดเร็ว", 14 | "steps": { 15 | "0": { 16 | "title": "อัปโหลดไฟล์ JSON", 17 | "description": "สนับสนุนการลากและวางหรือคลิกเพื่อเลือกไฟล์" 18 | }, 19 | "1": { 20 | "title": "เลือกภาษาที่ต้องการแปล", 21 | "description": "เลือกภาษาที่ต้องการแปล" 22 | }, 23 | "2": { 24 | "title": "เริ่มการแปล", 25 | "description": "ป้อน API Key และเริ่มการแปลด้วย AI" 26 | }, 27 | "3": { 28 | "title": "ดาวน์โหลดผลลัพธ์", 29 | "description": "ดาวน์โหลดไฟล์ JSON ที่แปลแล้ว" 30 | } 31 | } 32 | }, 33 | "features": { 34 | "title": "คุณสมบัติการแปลที่ทรงพลัง", 35 | "items": { 36 | "0": { 37 | "title": "รักษาโครงสร้าง JSON", 38 | "description": "รู้จักและรักษาโครงสร้าง, การเยื้อง, และรูปแบบของไฟล์ JSON เดิมอย่างชาญฉลาด" 39 | }, 40 | "1": { 41 | "title": "การสนับสนุนหลายภาษา", 42 | "description": "สนับสนุนการแปลระหว่างหลายภาษา รวมถึงภาษาอังกฤษ, จีน, ญี่ปุ่น, และอื่นๆ" 43 | }, 44 | "2": { 45 | "title": "การแปลที่ขับเคลื่อนด้วย AI", 46 | "description": "ใช้โมเดล OpenAI GPT เพื่อให้แน่ใจในความถูกต้องของคำศัพท์ทางเทคนิคและการแสดงออกตามธรรมชาติ" 47 | }, 48 | "3": { 49 | "title": "ปลอดภัยและเชื่อถือได้", 50 | "description": "API keys จะถูกใช้ชั่วคราวในเบราว์เซอร์และจะไม่ถูกบันทึกหรือส่งไปยังเซิร์ฟเวอร์" 51 | } 52 | } 53 | }, 54 | "uploadSection": { 55 | "title": "อัปโหลดไฟล์ JSON", 56 | "description": "อัปโหลดไฟล์ JSON ของคุณเพื่อการแปล", 57 | "dragText": "ลากไฟล์มาที่นี่หรือคลิกเพื่ออัปโหลด", 58 | "supportText": "รองรับไฟล์รูปแบบ .json ขนาดสูงสุด 10MB", 59 | "apiKeyTip": "เคล็ดลับ: ต้องใช้ OpenAI API Key สำหรับการแปล", 60 | "errors": { 61 | "selectFile": "กรุณาเลือกไฟล์", 62 | "jsonExtension": "กรุณาอัปโหลดไฟล์ที่มีนามสกุล .json", 63 | "fileSize": "ขนาดไฟล์ไม่สามารถเกิน 10MB", 64 | "jsonFormat": "รูปแบบ JSON ไม่ถูกต้อง, กรุณาตรวจสอบเนื้อหาไฟล์", 65 | "emptyJson": "ไฟล์ JSON ไม่สามารถว่างเปล่าได้" 66 | }, 67 | "success": { 68 | "uploaded": "อัปโหลดไฟล์สำเร็จ" 69 | }, 70 | "apiKeyTitle": "OpenAI API Key", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "ข้อผิดพลาด", 73 | "successTitle": "สำเร็จ" 74 | }, 75 | "translateSection": { 76 | "title": "เลือกภาษาที่ต้องการแปล", 77 | "description": "เลือกภาษาที่จะแปลเป็น" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "เริ่มการแปล", 81 | "translating": "กำลังแปล...", 82 | "cancel": "ยกเลิก", 83 | "uploadFirst": "กรุณาอัปโหลดไฟล์ก่อน", 84 | "enterApiKey": "กรุณาใส่ API Key", 85 | "foundUnfinished": "พบการแปลที่ยังไม่เสร็จ", 86 | "continueTranslation": "ดำเนินการแปลต่อ", 87 | "translationCancelled": "การแปลถูกยกเลิก", 88 | "invalidApiKey": "รูปแบบ API Key ไม่ถูกต้อง", 89 | "errorTitle": "ข้อผิดพลาด", 90 | "successTitle": "สำเร็จ", 91 | "translationCompleted": "การแปลเสร็จสิ้นแล้ว!", 92 | "showMoreLanguages": "แสดงภาษามากขึ้น", 93 | "hideMoreLanguages": "ซ่อนภาษามากขึ้น", 94 | "overallProgress": "ความก้าวหน้าทั้งหมด", 95 | "completedSegments": "ส่วนที่เสร็จสมบูรณ์", 96 | "translatingLanguage": "กำลังแปล", 97 | "allLanguagesTranslated": "ภาษาที่เลือกทั้งหมดได้รับการแปลแล้ว", 98 | "pleaseUploadAndEnterKey": "กรุณาอัปโหลดไฟล์และป้อน API Key", 99 | "tip": "เคล็ดลับ", 100 | "cancelled": "ยกเลิก", 101 | "translationFailed": "การแปลล้มเหลว", 102 | "pleaseSelectLanguage": "กรุณาเลือกภาษาที่ต้องการอย่างน้อยหนึ่งภาษา", 103 | "bytes": "ไบต์", 104 | "kb": "กิโลไบต์", 105 | "mb": "เมกะไบต์", 106 | "gb": "กิกะไบต์", 107 | "apiKeyErrors": { 108 | "invalidFormat": "รูปแบบคีย์ API ไม่ถูกต้อง", 109 | "invalidOrExpired": "คีย์ API ไม่ถูกต้องหรือหมดอายุ", 110 | "rateLimitReached": "ถึงขีดจำกัดการเรียก API แล้ว", 111 | "validationFailed": "การตรวจสอบคีย์ API ล้มเหลว" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "ตัวอย่าง", 116 | "empty": "ตัวอย่าง JSON จะปรากฏที่นี่", 117 | "copied": "คัดลอกไปยังคลิปบอร์ดแล้ว", 118 | "originalJson": "JSON ดั้งเดิม", 119 | "translatedJson": "JSON ที่แปลแล้ว", 120 | "tips": "เคล็ดลับ: รองรับการแสดงตัวอย่างแบบเรียลไทม์และการจัดรูปแบบไฟล์ JSON และคุณสามารถคัดลอกเนื้อหาได้โดยตรง", 121 | "placeholder": { 122 | "upload": "กรุณาอัปโหลดไฟล์ JSON", 123 | "translation": "ผลการแปลจะแสดงที่นี่" 124 | }, 125 | "actions": { 126 | "copy": "คัดลอก", 127 | "download": "ดาวน์โหลด", 128 | "downloadAll": "ดาวน์โหลดการแปลทั้งหมด", 129 | "downloadFormat": "ดาวน์โหลดการแปล {lang}" 130 | }, 131 | "toast": { 132 | "copySuccess": "เนื้อหาได้ถูกคัดลอกไปยังคลิปบอร์ด", 133 | "copyError": "การคัดลอกล้มเหลว กรุณาคัดลอกด้วยตนเอง", 134 | "downloadSuccess": "ไฟล์การแปล {lang} ได้ถูกดาวน์โหลดแล้ว", 135 | "downloadAllSuccess": "ไฟล์การแปลทั้งหมดได้ถูกดาวน์โหลดแล้ว", 136 | "downloadError": "การดาวน์โหลดล้มเหลว กรุณาลองใหม่อีกครั้ง" 137 | }, 138 | "languages": { 139 | "en": "อังกฤษ", 140 | "zh": "จีน (ตัวย่อ)", 141 | "zh-TW": "จีน (ตัวเต็ม)", 142 | "ja": "ญี่ปุ่น", 143 | "ko": "เกาหลี", 144 | "fr": "ฝรั่งเศส", 145 | "de": "เยอรมัน", 146 | "es": "สเปน", 147 | "pt": "โปรตุเกส", 148 | "it": "อิตาลี", 149 | "ru": "รัสเซีย", 150 | "ar": "อาหรับ", 151 | "hi": "ฮินดี", 152 | "bn": "เบงกาลี", 153 | "th": "ไทย", 154 | "vi": "ภาษาเวียดนาม", 155 | "id": "ภาษาอินโดนีเซีย", 156 | "ms": "ภาษามาเลย์", 157 | "tr": "ภาษาตุรกี", 158 | "nl": "ภาษาดัตช์", 159 | "pl": "ภาษาโปแลนด์", 160 | "uk": "ภาษาอูเครน", 161 | "el": "ภาษาเก่า", 162 | "he": "ภาษาฮีบรู", 163 | "sv": "ภาษาสวีเดน", 164 | "da": "ภาษาดานิช", 165 | "fi": "ภาษาฟินแลนด์", 166 | "cs": "ภาษาเช็ก", 167 | "ro": "ภาษาโรมาเนีย", 168 | "hu": "ภาษาฮังการี", 169 | "sk": "ภาษาสโลวัก", 170 | "bg": "ภาษาบัลแกเรีย", 171 | "hr": "ภาษาโครเอเชีย", 172 | "lt": "ภาษาลิทัวเนีย", 173 | "sl": "ภาษาสโลวีเนีย", 174 | "et": "ภาษาเอสโตเนีย", 175 | "lv": "ภาษาลัตเวีย", 176 | "sr": "ภาษาเซอร์เบีย", 177 | "mt": "ภาษามอลตา", 178 | "fa": "ภาษาเปอร์เซีย", 179 | "ur": "ภาษาอูรดู", 180 | "ta": "ภาษาทมิฬ", 181 | "te": "ภาษาทีลุก", 182 | "ml": "ภาษาไมลายาลัม", 183 | "kn": "ภาษากันนาดา", 184 | "mr": "ภาษามราฐี", 185 | "gu": "ภาษากุจราตี", 186 | "my": "ภาษาพม่า", 187 | "km": "ภาษาเขมร", 188 | "lo": "ภาษาลาว", 189 | "mn": "ภาษามองโกเลีย", 190 | "ka": "ภาษาเกorgia", 191 | "hy": "ภาษาอาร์เมเนีย", 192 | "az": "ภาษาอาเซอร์ไบจาน", 193 | "sw": "ภาษาสวาฮีลี", 194 | "af": "ภาษาแอฟริคานส์", 195 | "am": "ภาษาอัมฮาริก" 196 | } 197 | }, 198 | "faq": { 199 | "title": "คำถามที่พบบ่อย", 200 | "description": "คำถามทั่วไปเกี่ยวกับเครื่องมือแปล JSON", 201 | "items": { 202 | "0": { 203 | "question": "เครื่องมือนี้ทำอะไร?", 204 | "answer": "นี่คือเครื่องมือแปล JSON ที่ใช้ AI ซึ่งช่วยนักพัฒนาซอฟต์แวร์ในการแปลไฟล์ JSON ภาษาไปยังหลายภาษาอย่างรวดเร็วในขณะที่รักษาความสมบูรณ์ของโครงสร้าง JSON." 205 | }, 206 | "1": { 207 | "question": "จะใช้เครื่องมือนี้อย่างไร?", 208 | "answer": "1. อัปโหลดไฟล์ JSON ของคุณสำหรับการแปล\n2. เลือกภาษาที่ต้องการ\n3. ป้อน OpenAI API Key ของคุณ\n4. คลิกเริ่มการแปล\n5. ดาวน์โหลดผลลัพธ์หลังจากการแปลเสร็จสิ้น" 209 | }, 210 | "2": { 211 | "question": "รองรับภาษาอะไรบ้าง?", 212 | "answer": "ขณะนี้รองรับหลายภาษา รวมถึงภาษาอังกฤษ, ภาษาจีน (แบบย่อ), ภาษาจีน (แบบดั้งเดิม), ภาษาญี่ปุ่น, ภาษาเกาหลี, ภาษาฝรั่งเศส, ภาษาเยอรมัน, ภาษาสเปน, ภาษาอังกฤษ, และอื่น ๆ." 213 | }, 214 | "3": { 215 | "question": "คีย์ API ของฉันจะถูกบันทึกหรือไม่?", 216 | "answer": "ไม่ คีย์ API ของคุณจะถูกใช้ชั่วคราวในเบราว์เซอร์และจะไม่ถูกบันทึกหรือส่งไปยังเซิร์ฟเวอร์ใด ๆ." 217 | }, 218 | "4": { 219 | "question": "คุณภาพการแปลได้รับการรับรองอย่างไร?", 220 | "answer": "เราใช้โมเดล GPT ของ OpenAI สำหรับการแปล เพื่อให้แน่ใจว่ามีความถูกต้องของคำศัพท์ทางเทคนิคและการแสดงออกในภาษาธรรมชาติ เรายังสนับสนุนฟังก์ชันพจนานุกรมที่กำหนดเองเพื่อรักษาความสอดคล้องของคำศัพท์เฉพาะ." 221 | }, 222 | "5": { 223 | "question": "มีขนาดไฟล์ที่จำกัดหรือไม่?", 224 | "answer": "ขนาดไฟล์ JSON เดียวถูกจำกัดที่ 10MB สำหรับไฟล์ที่ใหญ่กว่านั้น แนะนำให้แบ่งไฟล์และแปลเป็นชุด." 225 | } 226 | } 227 | }, 228 | "cta": { 229 | "title": "เริ่มใช้เครื่องมือแปล AI ตอนนี้", 230 | "description": "แปลไฟล์ภาษาของคุณเป็นหลายภาษาอย่างรวดเร็วและแม่นยำ", 231 | "button": "ลองตอนนี้", 232 | "features": { 233 | "0": "ไม่ต้องลงทะเบียน", 234 | "1": "ฟรีโดยสมบูรณ์", 235 | "2": "การแปลแบบเรียลไทม์" 236 | } 237 | }, 238 | "footer": { 239 | "creator": "สร้างด้วย ❤️ โดย Viggo", 240 | "twitter": "@viggo", 241 | "coffee": "ซื้อกาแฟให้ฉัน", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "เครื่องมือแปล JSON - โซลูชันการแปลหลายภาษาด้วย AI", 246 | "description": "แปลไฟล์ภาษา JSON เป็นหลายภาษาได้อย่างรวดเร็วและแม่นยำด้วยเทคโนโลยี AI รองรับโครงสร้าง JSON ตัวแปร และแท็ก HTML", 247 | "keywords": "แปล JSON,แปลด้วย AI,การแปลหลายภาษา,i18n,การแปลภาษา,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "AI Powered", 4 | "title": "i18n JSON Translation Tool", 5 | "description": "Translate your JSON language files quickly using AI technology. Fast, accurate, and easy to use.", 6 | "features": { 7 | "multilanguage": "Multilingual Support", 8 | "realtime": "Real-time Translation" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "Complete Translation in Four Simple Steps", 13 | "description": "We've simplified the JSON file translation process to help you quickly obtain high-quality translation results", 14 | "steps": [ 15 | { 16 | "title": "Upload JSON File", 17 | "description": "Support drag and drop or click to select file" 18 | }, 19 | { 20 | "title": "Select Target Language", 21 | "description": "Choose the target language for translation" 22 | }, 23 | { 24 | "title": "Start Translation", 25 | "description": "Enter API Key and start AI translation" 26 | }, 27 | { 28 | "title": "Download Results", 29 | "description": "Download the translated JSON file" 30 | } 31 | ] 32 | }, 33 | "features": { 34 | "title": "Powerful Translation Features", 35 | "items": [ 36 | { 37 | "title": "Preserve JSON Structure", 38 | "description": "Intelligently recognize and maintain the structure, indentation, and format of the original JSON file" 39 | }, 40 | { 41 | "title": "Multi-language Support", 42 | "description": "Support translation between multiple languages including English, Chinese, Japanese, and more" 43 | }, 44 | { 45 | "title": "AI-Powered Translation", 46 | "description": "Utilizing OpenAI GPT models to ensure accuracy of technical terms and natural expression" 47 | }, 48 | { 49 | "title": "Secure & Reliable", 50 | "description": "API keys are only used temporarily in the browser and never saved or transmitted to servers" 51 | } 52 | ] 53 | }, 54 | "uploadSection": { 55 | "title": "Upload JSON File", 56 | "description": "Upload your JSON file for translation", 57 | "dragText": "Drag files here or click to upload", 58 | "supportText": "Supports .json format files, up to 10MB", 59 | "apiKeyTip": "Tips: OpenAI API Key is required for translation", 60 | "errors": { 61 | "selectFile": "Please select a file", 62 | "jsonExtension": "Please upload a file with a .json extension", 63 | "fileSize": "File size cannot exceed 10MB", 64 | "jsonFormat": "Invalid JSON format, please check the file content", 65 | "emptyJson": "JSON file cannot be empty" 66 | }, 67 | "success": { 68 | "uploaded": "File uploaded successfully" 69 | }, 70 | "apiKeyTitle": "OpenAI API Key", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "Error", 73 | "successTitle": "Success" 74 | }, 75 | "translateSection": { 76 | "title": "Select Target Language", 77 | "description": "Choose languages to translate into" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "Start Translation", 81 | "translating": "Translating...", 82 | "cancel": "Cancel", 83 | "uploadFirst": "Please upload a file first", 84 | "enterApiKey": "Please enter API Key", 85 | "foundUnfinished": "Found unfinished translation", 86 | "continueTranslation": "Continue translation", 87 | "translationCancelled": "Translation cancelled", 88 | "invalidApiKey": "Invalid API Key format", 89 | "errorTitle": "Error", 90 | "successTitle": "Success", 91 | "translationCompleted": "Translation completed!", 92 | "showMoreLanguages": "Show more languages", 93 | "hideMoreLanguages": "Hide more languages", 94 | "overallProgress": "Overall Progress", 95 | "completedSegments": "Completed Segments", 96 | "translatingLanguage": "Translating", 97 | "allLanguagesTranslated": "All selected languages are translated", 98 | "pleaseUploadAndEnterKey": "Please upload a file and enter API Key", 99 | "tip": "Tip", 100 | "cancelled": "Cancelled", 101 | "translationFailed": "Translation failed", 102 | "pleaseSelectLanguage": "Please select at least one target language", 103 | "bytes": "Bytes", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "Invalid API key format", 109 | "invalidOrExpired": "Invalid or expired API key", 110 | "rateLimitReached": "API rate limit reached", 111 | "validationFailed": "API key validation failed" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "Preview", 116 | "empty": "JSON preview will appear here", 117 | "copied": "Copied to clipboard", 118 | "originalJson": "Original JSON", 119 | "translatedJson": "Translated JSON", 120 | "tips": "Tips: Supports real-time preview and formatting of JSON files, and you can directly copy the content", 121 | "placeholder": { 122 | "upload": "Please upload a JSON file", 123 | "translation": "Translation results will be displayed here" 124 | }, 125 | "actions": { 126 | "copy": "Copy", 127 | "download": "Download", 128 | "downloadAll": "Download all translations", 129 | "downloadFormat": "Download {lang} translation" 130 | }, 131 | "toast": { 132 | "copySuccess": "Content has been copied to the clipboard", 133 | "copyError": "Copy failed, please copy manually", 134 | "downloadSuccess": "{lang} translation file has been downloaded", 135 | "downloadAllSuccess": "All translation files have been downloaded", 136 | "downloadError": "Download failed, please try again" 137 | }, 138 | "languages": { 139 | "en": "English", 140 | "zh": "Chinese (Simplified)", 141 | "zh-TW": "Chinese (Traditional)", 142 | "ja": "Japanese", 143 | "ko": "Korean", 144 | "fr": "French", 145 | "de": "German", 146 | "es": "Spanish", 147 | "pt": "Portuguese", 148 | "it": "Italian", 149 | "ru": "Russian", 150 | "ar": "Arabic", 151 | "hi": "Hindi", 152 | "bn": "Bengali", 153 | "th": "Thai", 154 | "vi": "Vietnamese", 155 | "id": "Indonesian", 156 | "ms": "Malay", 157 | "tr": "Turkish", 158 | "nl": "Dutch", 159 | "pl": "Polish", 160 | "uk": "Ukrainian", 161 | "el": "Greek", 162 | "he": "Hebrew", 163 | "sv": "Swedish", 164 | "da": "Danish", 165 | "fi": "Finnish", 166 | "cs": "Czech", 167 | "ro": "Romanian", 168 | "hu": "Hungarian", 169 | "sk": "Slovak", 170 | "bg": "Bulgarian", 171 | "hr": "Croatian", 172 | "lt": "Lithuanian", 173 | "sl": "Slovenian", 174 | "et": "Estonian", 175 | "lv": "Latvian", 176 | "sr": "Serbian", 177 | "mt": "Maltese", 178 | "fa": "Persian", 179 | "ur": "Urdu", 180 | "ta": "Tamil", 181 | "te": "Telugu", 182 | "ml": "Malayalam", 183 | "kn": "Kannada", 184 | "mr": "Marathi", 185 | "gu": "Gujarati", 186 | "my": "Burmese", 187 | "km": "Khmer", 188 | "lo": "Lao", 189 | "mn": "Mongolian", 190 | "ka": "Georgian", 191 | "hy": "Armenian", 192 | "az": "Azerbaijani", 193 | "sw": "Swahili", 194 | "af": "Afrikaans", 195 | "am": "Amharic" 196 | } 197 | }, 198 | "faq": { 199 | "title": "Frequently Asked Questions", 200 | "description": "Common questions about the JSON translation tool", 201 | "items": [ 202 | { 203 | "question": "What does this tool do?", 204 | "answer": "This is an AI-powered JSON internationalization translation tool that helps developers quickly translate JSON language files into multiple languages while maintaining JSON structure integrity." 205 | }, 206 | { 207 | "question": "How to use this tool?", 208 | "answer": "1. Upload your JSON file for translation\n2. Select target languages\n3. Enter your OpenAI API Key\n4. Click start translation\n5. Download results after translation is complete" 209 | }, 210 | { 211 | "question": "What languages are supported?", 212 | "answer": "Currently supports multiple languages including English, Chinese (Simplified), Chinese (Traditional), Japanese, Korean, French, German, Spanish, Russian, and more." 213 | }, 214 | { 215 | "question": "Will my API Key be saved?", 216 | "answer": "No. Your API Key is only used temporarily in the browser and will not be saved or transmitted to any servers." 217 | }, 218 | { 219 | "question": "How is translation quality assured?", 220 | "answer": "We use OpenAI's GPT model for translation, ensuring accuracy of technical terms and natural language expression. We also support custom dictionary functionality to maintain consistency of specific terminology." 221 | }, 222 | { 223 | "question": "Is there a file size limit?", 224 | "answer": "Single JSON file size is limited to 10MB. For larger files, it's recommended to split them and translate in batches." 225 | } 226 | ] 227 | }, 228 | "cta": { 229 | "title": "Start Using AI Translation Tool Now", 230 | "description": "Quickly and accurately translate your JSON language files into multiple languages", 231 | "button": "Try Now", 232 | "features": [ 233 | "No Registration Required", 234 | "Completely Free", 235 | "Real-time Translation" 236 | ] 237 | }, 238 | "footer": { 239 | "creator": "Created with ❤️ by Viggo", 240 | "twitter": "@viggo", 241 | "coffee": "Buy Me a Coffee", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "JSON Translator - AI-Powered Multilingual Translation Solution", 246 | "description": "Quickly and accurately translate JSON language files into multiple languages using AI technology. Supports JSON structure, variable placeholders, and HTML tags.", 247 | "keywords": "JSON translation,AI translation,internationalization,i18n,multilingual translation,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "AI Destekli", 4 | "title": "i18n JSON Çeviri Aracı", 5 | "description": "JSON dil dosyalarınızı hızlı bir şekilde AI teknolojisi kullanarak çevirin. Hızlı, doğru ve kullanımı kolay.", 6 | "features": { 7 | "multilanguage": "Çok Dilli Destek", 8 | "realtime": "Gerçek Zamanlı Çeviri" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "Dört Basit Adımda Tam Çeviri", 13 | "description": "JSON dosyası çeviri sürecini basitleştirdik, böylece yüksek kaliteli çeviri sonuçlarını hızlıca elde edebilirsiniz", 14 | "steps": { 15 | "0": { 16 | "title": "JSON Dosyasını Yükle", 17 | "description": "Sürükleyip bırakmayı veya dosyayı seçmek için tıklamayı destekler" 18 | }, 19 | "1": { 20 | "title": "Hedef Dili Seç", 21 | "description": "Çeviri için hedef dili seçin" 22 | }, 23 | "2": { 24 | "title": "Çeviriyi Başlat", 25 | "description": "API Anahtarını girin ve AI çevirisini başlatın" 26 | }, 27 | "3": { 28 | "title": "Sonuçları İndir", 29 | "description": "Çevrilen JSON dosyasını indirin" 30 | } 31 | } 32 | }, 33 | "features": { 34 | "title": "Güçlü Çeviri Özellikleri", 35 | "items": { 36 | "0": { 37 | "title": "JSON Yapısını Koruma", 38 | "description": "Orijinal JSON dosyasının yapısını, girintisini ve formatını akıllıca tanıyıp koruma" 39 | }, 40 | "1": { 41 | "title": "Çok Dilli Destek", 42 | "description": "İngilizce, Çince, Japonca ve daha fazlası dahil olmak üzere birden fazla dil arasında çeviri desteği" 43 | }, 44 | "2": { 45 | "title": "AI Destekli Çeviri", 46 | "description": "Teknik terimlerin doğruluğunu ve doğal ifadeyi sağlamak için OpenAI GPT modellerini kullanma" 47 | }, 48 | "3": { 49 | "title": "Güvenli ve Güvenilir", 50 | "description": "API anahtarları yalnızca tarayıcıda geçici olarak kullanılır ve asla kaydedilmez veya sunuculara iletilmez" 51 | } 52 | } 53 | }, 54 | "uploadSection": { 55 | "title": "JSON Dosyasını Yükle", 56 | "description": "Çeviri için JSON dosyanızı yükleyin", 57 | "dragText": "Dosyaları buraya sürükleyin veya yüklemek için tıklayın", 58 | "supportText": ".json format dosyalarını destekler, en fazla 10MB", 59 | "apiKeyTip": "İpucu: Çeviri için OpenAI API Anahtarı gereklidir", 60 | "errors": { 61 | "selectFile": "Lütfen bir dosya seçin", 62 | "jsonExtension": "Lütfen .json uzantılı bir dosya yükleyin", 63 | "fileSize": "Dosya boyutu 10MB'yi geçemez", 64 | "jsonFormat": "Geçersiz JSON formatı, lütfen dosya içeriğini kontrol edin", 65 | "emptyJson": "JSON dosyası boş olamaz" 66 | }, 67 | "success": { 68 | "uploaded": "Dosya başarıyla yüklendi" 69 | }, 70 | "apiKeyTitle": "OpenAI API Anahtarı", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "Hata", 73 | "successTitle": "Başarılı" 74 | }, 75 | "translateSection": { 76 | "title": "Hedef Dili Seç", 77 | "description": "Çevrilecek dilleri seçin" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "Çeviriyi Başlat", 81 | "translating": "Çeviri yapılıyor...", 82 | "cancel": "İptal", 83 | "uploadFirst": "Lütfen önce bir dosya yükleyin", 84 | "enterApiKey": "Lütfen API Anahtarını girin", 85 | "foundUnfinished": "Tamamlanmamış çeviri bulundu", 86 | "continueTranslation": "Çeviriye devam et", 87 | "translationCancelled": "Çeviri iptal edildi", 88 | "invalidApiKey": "Geçersiz API Anahtarı formatı", 89 | "errorTitle": "Hata", 90 | "successTitle": "Başarı", 91 | "translationCompleted": "Çeviri tamamlandı!", 92 | "showMoreLanguages": "Daha fazla dil göster", 93 | "hideMoreLanguages": "Daha fazla dili gizle", 94 | "overallProgress": "Genel İlerleme", 95 | "completedSegments": "Tamamlanan Segmentler", 96 | "translatingLanguage": "Çeviri yapılıyor", 97 | "allLanguagesTranslated": "Tüm seçilen diller çevrildi", 98 | "pleaseUploadAndEnterKey": "Lütfen bir dosya yükleyin ve API Anahtarını girin", 99 | "tip": "İpucu", 100 | "cancelled": "İptal edildi", 101 | "translationFailed": "Çeviri başarısız oldu", 102 | "pleaseSelectLanguage": "Lütfen en az bir hedef dil seçin", 103 | "bytes": "Bayt", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "Geçersiz API anahtarı formatı", 109 | "invalidOrExpired": "Geçersiz veya süresi dolmuş API anahtarı", 110 | "rateLimitReached": "API çağrı limiti aşıldı", 111 | "validationFailed": "API anahtarı doğrulaması başarısız oldu" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "Önizleme", 116 | "empty": "JSON önizlemesi burada görünecek", 117 | "copied": "Panoya kopyalandı", 118 | "originalJson": "Orijinal JSON", 119 | "translatedJson": "Çevrilmiş JSON", 120 | "tips": "İpuçları: JSON dosyalarının gerçek zamanlı önizlemesini ve biçimlendirmesini destekler ve içeriği doğrudan kopyalayabilirsiniz", 121 | "placeholder": { 122 | "upload": "Lütfen bir JSON dosyası yükleyin", 123 | "translation": "Çeviri sonuçları burada görüntülenecek" 124 | }, 125 | "actions": { 126 | "copy": "Kopyala", 127 | "download": "İndir", 128 | "downloadAll": "Tüm çevirileri indir", 129 | "downloadFormat": "{lang} çevirisini indir" 130 | }, 131 | "toast": { 132 | "copySuccess": "İçerik panoya kopyalandı", 133 | "copyError": "Kopyalama başarısız, lütfen manuel olarak kopyalayın", 134 | "downloadSuccess": "{lang} çeviri dosyası indirildi", 135 | "downloadAllSuccess": "Tüm çeviri dosyaları indirildi", 136 | "downloadError": "İndirme başarısız, lütfen tekrar deneyin" 137 | }, 138 | "languages": { 139 | "en": "İngilizce", 140 | "zh": "Çince (Basitleştirilmiş)", 141 | "zh-TW": "Çince (Geleneksel)", 142 | "ja": "Japonca", 143 | "ko": "Korece", 144 | "fr": "Fransızca", 145 | "de": "Almanca", 146 | "es": "İspanyolca", 147 | "pt": "Portekizce", 148 | "it": "İtalyanca", 149 | "ru": "Rusça", 150 | "ar": "Arapça", 151 | "hi": "Hintçe", 152 | "bn": "Bengalce", 153 | "th": "Tayca", 154 | "vi": "Vietnamese", 155 | "id": "Endonezce", 156 | "ms": "Malayca", 157 | "tr": "Türkçe", 158 | "nl": "Hollandaca", 159 | "pl": "Lehçe", 160 | "uk": "Ukraynaca", 161 | "el": "Yunanca", 162 | "he": "İbranice", 163 | "sv": "İsveççe", 164 | "da": "Danca", 165 | "fi": "Fince", 166 | "cs": "Çekçe", 167 | "ro": "Romence", 168 | "hu": "Macarca", 169 | "sk": "Slovakça", 170 | "bg": "Bulgarca", 171 | "hr": "Hırvatça", 172 | "lt": "Litvanca", 173 | "sl": "Slovence", 174 | "et": "Estonca", 175 | "lv": "Letonca", 176 | "sr": "Sırpça", 177 | "mt": "Maltaca", 178 | "fa": "Farsça", 179 | "ur": "Urduca", 180 | "ta": "Tamilce", 181 | "te": "Telugu", 182 | "ml": "Malayalam", 183 | "kn": "Kannada", 184 | "mr": "Marathi", 185 | "gu": "Gücerati", 186 | "my": "Birmanya", 187 | "km": "Kmer", 188 | "lo": "Lao", 189 | "mn": "Moğolca", 190 | "ka": "Gürcüce", 191 | "hy": "Ermenice", 192 | "az": "Azerice", 193 | "sw": "Svahili", 194 | "af": "Afrikanca", 195 | "am": "Amharca" 196 | } 197 | }, 198 | "faq": { 199 | "title": "Sıkça Sorulan Sorular", 200 | "description": "JSON çeviri aracı hakkında yaygın sorular", 201 | "items": { 202 | "0": { 203 | "question": "Bu araç ne yapar?", 204 | "answer": "Bu, geliştiricilerin JSON dil dosyalarını birden fazla dile hızlı bir şekilde çevirirken JSON yapı bütünlüğünü korumalarına yardımcı olan AI destekli bir JSON uluslararasılaştırma çeviri aracıdır." 205 | }, 206 | "1": { 207 | "question": "Bu aracı nasıl kullanırım?", 208 | "answer": "1. Çeviri için JSON dosyanızı yükleyin\n2. Hedef dilleri seçin\n3. OpenAI API Anahtarınızı girin\n4. Çeviriyi başlatmak için tıklayın\n5. Çeviri tamamlandıktan sonra sonuçları indirin" 209 | }, 210 | "2": { 211 | "question": "Hangi diller destekleniyor?", 212 | "answer": "Şu anda İngilizce, Çince (Basitleştirilmiş), Çince (Geleneksel), Japonca, Korece, Fransızca, Almanca, İspanyolca, Rusça ve daha fazlası dahil olmak üzere birden fazla dili desteklemektedir." 213 | }, 214 | "3": { 215 | "question": "API Anahtarım kaydedilecek mi?", 216 | "answer": "Hayır. API Anahtarınız sadece tarayıcıda geçici olarak kullanılır ve kaydedilmeyecek veya herhangi bir sunucuya iletilmeyecektir." 217 | }, 218 | "4": { 219 | "question": "Çeviri kalitesi nasıl garanti ediliyor?", 220 | "answer": "Çeviri için OpenAI'nin GPT modelini kullanıyoruz, teknik terimlerin doğruluğunu ve doğal dil ifadesini sağlıyoruz. Ayrıca belirli terminolojinin tutarlılığını korumak için özel sözlük işlevselliğini de destekliyoruz." 221 | }, 222 | "5": { 223 | "question": "Bir dosya boyutu limiti var mı?", 224 | "answer": "Tek bir JSON dosyasının boyutu 10MB ile sınırlıdır. Daha büyük dosyalar için, bunları bölüp partiler halinde çevirmeleri önerilir." 225 | } 226 | } 227 | }, 228 | "cta": { 229 | "title": "AI Çeviri Aracını Şimdi Kullanmaya Başlayın", 230 | "description": "JSON dil dosyalarınızı hızlı ve doğru bir şekilde birden fazla dile çevirin", 231 | "button": "Şimdi Deneyin", 232 | "features": { 233 | "0": "Kayıt Gerekmiyor", 234 | "1": "Tamamen Ücretsiz", 235 | "2": "Gerçek Zamanlı Çeviri" 236 | } 237 | }, 238 | "footer": { 239 | "creator": "❤️ ile oluşturuldu Viggo tarafından", 240 | "twitter": "@viggo", 241 | "coffee": "Bana Bir Kahve Al", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "JSON Çevirmen - AI Destekli Çok Dilli Çeviri Çözümü", 246 | "description": "JSON dil dosyalarını AI teknolojisi ile hızlı ve doğru bir şekilde birden çok dile çevirin. JSON yapısını, değişken yer tutucularını ve HTML etiketlerini destekler.", 247 | "keywords": "JSON çeviri,AI çeviri,uluslararasılaştırma,i18n,çok dilli çeviri,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "Didukung AI", 4 | "title": "i18n Alat Terjemahan JSON", 5 | "description": "Terjemahkan berkas bahasa JSON Anda dengan cepat menggunakan teknologi AI. Cepat, akurat, dan mudah digunakan.", 6 | "features": { 7 | "multilanguage": "Dukungan Multibahasa", 8 | "realtime": "Terjemahan Waktu Nyata" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "Selesaikan Terjemahan dalam Empat Langkah Sederhana", 13 | "description": "Kami telah menyederhanakan proses terjemahan berkas JSON untuk membantu Anda dengan cepat mendapatkan hasil terjemahan berkualitas tinggi", 14 | "steps": { 15 | "0": { 16 | "title": "Unggah Berkas JSON", 17 | "description": "Dukungan seret dan lepas atau klik untuk memilih berkas" 18 | }, 19 | "1": { 20 | "title": "Pilih Bahasa Target", 21 | "description": "Pilih bahasa target untuk terjemahan" 22 | }, 23 | "2": { 24 | "title": "Mulai Terjemahan", 25 | "description": "Masukkan Kunci API dan mulai terjemahan AI" 26 | }, 27 | "3": { 28 | "title": "Unduh Hasil", 29 | "description": "Unduh berkas JSON yang telah diterjemahkan" 30 | } 31 | } 32 | }, 33 | "features": { 34 | "title": "Fitur Terjemahan yang Kuat", 35 | "items": { 36 | "0": { 37 | "title": "Pertahankan Struktur JSON", 38 | "description": "Secara cerdas mengenali dan mempertahankan struktur, indentasi, dan format berkas JSON asli" 39 | }, 40 | "1": { 41 | "title": "Dukungan Multi-bahasa", 42 | "description": "Dukungan terjemahan antara beberapa bahasa termasuk Inggris, Mandarin, Jepang, dan lainnya" 43 | }, 44 | "2": { 45 | "title": "Terjemahan Didukung AI", 46 | "description": "Memanfaatkan model OpenAI GPT untuk memastikan akurasi istilah teknis dan ekspresi alami" 47 | }, 48 | "3": { 49 | "title": "Aman & Andal", 50 | "description": "Kunci API hanya digunakan sementara di browser dan tidak pernah disimpan atau dikirim ke server" 51 | } 52 | } 53 | }, 54 | "uploadSection": { 55 | "title": "Unggah Berkas JSON", 56 | "description": "Unggah berkas JSON Anda untuk terjemahan", 57 | "dragText": "Seret berkas ke sini atau klik untuk mengunggah", 58 | "supportText": "Mendukung berkas format .json, hingga 10MB", 59 | "apiKeyTip": "Tips: Kunci API OpenAI diperlukan untuk terjemahan", 60 | "errors": { 61 | "selectFile": "Silakan pilih berkas", 62 | "jsonExtension": "Silakan unggah berkas dengan ekstensi .json", 63 | "fileSize": "Ukuran berkas tidak boleh melebihi 10MB", 64 | "jsonFormat": "Format JSON tidak valid, silakan periksa konten berkas", 65 | "emptyJson": "Berkas JSON tidak boleh kosong" 66 | }, 67 | "success": { 68 | "uploaded": "Berkas berhasil diunggah" 69 | }, 70 | "apiKeyTitle": "Kunci API OpenAI", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "Kesalahan", 73 | "successTitle": "Sukses" 74 | }, 75 | "translateSection": { 76 | "title": "Pilih Bahasa Target", 77 | "description": "Pilih bahasa untuk diterjemahkan" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "Mulai Terjemahan", 81 | "translating": "Sedang Menerjemahkan...", 82 | "cancel": "Batal", 83 | "uploadFirst": "Silakan unggah berkas terlebih dahulu", 84 | "enterApiKey": "Silakan masukkan Kunci API", 85 | "foundUnfinished": "Ditemukan terjemahan yang belum selesai", 86 | "continueTranslation": "Lanjutkan terjemahan", 87 | "translationCancelled": "Terjemahan dibatalkan", 88 | "invalidApiKey": "Format Kunci API tidak valid", 89 | "errorTitle": "Kesalahan", 90 | "successTitle": "Sukses", 91 | "translationCompleted": "Terjemahan selesai!", 92 | "showMoreLanguages": "Tampilkan lebih banyak bahasa", 93 | "hideMoreLanguages": "Sembunyikan lebih banyak bahasa", 94 | "overallProgress": "Kemajuan Keseluruhan", 95 | "completedSegments": "Segmen yang Diselesaikan", 96 | "translatingLanguage": "Menerjemahkan", 97 | "allLanguagesTranslated": "Semua bahasa yang dipilih telah diterjemahkan", 98 | "pleaseUploadAndEnterKey": "Silakan unggah file dan masukkan Kunci API", 99 | "tip": "Tip", 100 | "cancelled": "Dibatalkan", 101 | "translationFailed": "Terjemahan gagal", 102 | "pleaseSelectLanguage": "Silakan pilih setidaknya satu bahasa target", 103 | "bytes": "Byte", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "Format kunci API tidak valid", 109 | "invalidOrExpired": "Kunci API tidak valid atau kedaluwarsa", 110 | "rateLimitReached": "Batas pemanggilan API tercapai", 111 | "validationFailed": "Validasi kunci API gagal" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "Pratampilan", 116 | "empty": "Pratampilan JSON akan muncul di sini", 117 | "copied": "Disalin ke papan klip", 118 | "originalJson": "JSON Asli", 119 | "translatedJson": "JSON Terjemahan", 120 | "tips": "Tips: Mendukung pratampilan waktu nyata dan pemformatan file JSON, dan Anda dapat langsung menyalin kontennya", 121 | "placeholder": { 122 | "upload": "Silakan unggah file JSON", 123 | "translation": "Hasil terjemahan akan ditampilkan di sini" 124 | }, 125 | "actions": { 126 | "copy": "Salin", 127 | "download": "Unduh", 128 | "downloadAll": "Unduh semua terjemahan", 129 | "downloadFormat": "Unduh terjemahan {lang}" 130 | }, 131 | "toast": { 132 | "copySuccess": "Konten telah disalin ke papan klip", 133 | "copyError": "Salin gagal, silakan salin secara manual", 134 | "downloadSuccess": "File terjemahan {lang} telah diunduh", 135 | "downloadAllSuccess": "Semua file terjemahan telah diunduh", 136 | "downloadError": "Unduh gagal, silakan coba lagi" 137 | }, 138 | "languages": { 139 | "en": "Inggris", 140 | "zh": "Cina (Sederhana)", 141 | "zh-TW": "Cina (Tradisional)", 142 | "ja": "Jepang", 143 | "ko": "Korea", 144 | "fr": "Prancis", 145 | "de": "Jerman", 146 | "es": "Spanyol", 147 | "pt": "Portugis", 148 | "it": "Italia", 149 | "ru": "Rusia", 150 | "ar": "Arab", 151 | "hi": "Hindi", 152 | "bn": "Bengali", 153 | "th": "Thai", 154 | "vi": "Vietnamese", 155 | "id": "Bahasa Indonesia", 156 | "ms": "Melayu", 157 | "tr": "Turki", 158 | "nl": "Belanda", 159 | "pl": "Polandia", 160 | "uk": "Ukraina", 161 | "el": "Yunani", 162 | "he": "Ibrani", 163 | "sv": "Swedia", 164 | "da": "Denmark", 165 | "fi": "Finlandia", 166 | "cs": "Ceko", 167 | "ro": "Rumania", 168 | "hu": "Hongaria", 169 | "sk": "Slovakia", 170 | "bg": "Bulgaria", 171 | "hr": "Kroasia", 172 | "lt": "Lituania", 173 | "sl": "Slovenia", 174 | "et": "Estonia", 175 | "lv": "Latvia", 176 | "sr": "Serbia", 177 | "mt": "Malta", 178 | "fa": "Persia", 179 | "ur": "Urdu", 180 | "ta": "Tamil", 181 | "te": "Telugu", 182 | "ml": "Malayalam", 183 | "kn": "Kannada", 184 | "mr": "Marathi", 185 | "gu": "Gujarati", 186 | "my": "Burmese", 187 | "km": "Khmer", 188 | "lo": "Lao", 189 | "mn": "Mongolia", 190 | "ka": "Georgia", 191 | "hy": "Armenia", 192 | "az": "Azerbaijan", 193 | "sw": "Swahili", 194 | "af": "Afrikaans", 195 | "am": "Amharic" 196 | } 197 | }, 198 | "faq": { 199 | "title": "Pertanyaan yang Sering Diajukan", 200 | "description": "Pertanyaan umum tentang alat terjemahan JSON", 201 | "items": { 202 | "0": { 203 | "question": "Apa yang dilakukan alat ini?", 204 | "answer": "Ini adalah alat terjemahan internasionalisasi JSON yang didukung AI yang membantu pengembang dengan cepat menerjemahkan file bahasa JSON ke dalam berbagai bahasa sambil mempertahankan integritas struktur JSON." 205 | }, 206 | "1": { 207 | "question": "Bagaimana cara menggunakan alat ini?", 208 | "answer": "1. Unggah file JSON Anda untuk diterjemahkan\n2. Pilih bahasa target\n3. Masukkan Kunci API OpenAI Anda\n4. Klik mulai terjemahan\n5. Unduh hasil setelah terjemahan selesai" 209 | }, 210 | "2": { 211 | "question": "Bahasa apa saja yang didukung?", 212 | "answer": "Saat ini mendukung berbagai bahasa termasuk Inggris, Mandarin (Sederhana), Mandarin (Tradisional), Jepang, Korea, Prancis, Jerman, Spanyol, Rusia, dan lainnya." 213 | }, 214 | "3": { 215 | "question": "Apakah Kunci API saya akan disimpan?", 216 | "answer": "Tidak. Kunci API Anda hanya digunakan sementara di browser dan tidak akan disimpan atau dikirim ke server mana pun." 217 | }, 218 | "4": { 219 | "question": "Bagaimana kualitas terjemahan dijamin?", 220 | "answer": "Kami menggunakan model GPT dari OpenAI untuk terjemahan, memastikan akurasi istilah teknis dan ekspresi bahasa alami. Kami juga mendukung fungsi kamus kustom untuk menjaga konsistensi terminologi tertentu." 221 | }, 222 | "5": { 223 | "question": "Apakah ada batas ukuran file?", 224 | "answer": "Ukuran file JSON tunggal dibatasi hingga 10MB. Untuk file yang lebih besar, disarankan untuk membaginya dan menerjemahkan dalam batch." 225 | } 226 | } 227 | }, 228 | "cta": { 229 | "title": "Mulai Menggunakan Alat Terjemahan AI Sekarang", 230 | "description": "Terjemahkan file bahasa JSON Anda dengan cepat dan akurat ke dalam beberapa bahasa", 231 | "button": "Coba Sekarang", 232 | "features": { 233 | "0": "Tidak Perlu Registrasi", 234 | "1": "Sepenuhnya Gratis", 235 | "2": "Terjemahan Waktu Nyata" 236 | } 237 | }, 238 | "footer": { 239 | "creator": "Dibuat dengan ❤️ oleh Viggo", 240 | "twitter": "@viggo", 241 | "coffee": "Beli Saya Secangkir Kopi", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "Penerjemah JSON - Solusi Terjemahan Multibahasa Berbasis AI", 246 | "description": "Terjemahkan file bahasa JSON ke berbagai bahasa dengan cepat dan akurat menggunakan teknologi AI. Mendukung struktur JSON, placeholder variabel, dan tag HTML.", 247 | "keywords": "terjemahan JSON,terjemahan AI,internasionalisasi,i18n,terjemahan multibahasa,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "Basato su IA", 4 | "title": "Strumento di Traduzione JSON i18n", 5 | "description": "Traduci rapidamente i tuoi file JSON utilizzando la tecnologia IA. Veloce, accurato e facile da usare.", 6 | "features": { 7 | "multilanguage": "Supporto Multilingue", 8 | "realtime": "Traduzione in Tempo Reale" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "Completa la Traduzione in Quattro Semplici Passaggi", 13 | "description": "Abbiamo semplificato il processo di traduzione dei file JSON per aiutarti a ottenere rapidamente risultati di alta qualità", 14 | "steps": [ 15 | { 16 | "title": "Carica File JSON", 17 | "description": "Supporta il trascinamento o il clic per selezionare il file" 18 | }, 19 | { 20 | "title": "Seleziona Lingua di Destinazione", 21 | "description": "Scegli la lingua di destinazione per la traduzione" 22 | }, 23 | { 24 | "title": "Avvia Traduzione", 25 | "description": "Inserisci la Chiave API e avvia la traduzione IA" 26 | }, 27 | { 28 | "title": "Scarica Risultati", 29 | "description": "Scarica il file JSON tradotto" 30 | } 31 | ] 32 | }, 33 | "features": { 34 | "title": "Potenti Funzionalità di Traduzione", 35 | "items": [ 36 | { 37 | "title": "Preserva Struttura JSON", 38 | "description": "Riconosce e mantiene intelligentemente la struttura, l'indentazione e il formato del file JSON originale" 39 | }, 40 | { 41 | "title": "Supporto Multilingue", 42 | "description": "Supporta la traduzione tra più lingue inclusi inglese, cinese, giapponese e altri" 43 | }, 44 | { 45 | "title": "Traduzione Basata su IA", 46 | "description": "Utilizza i modelli GPT di OpenAI per garantire l'accuratezza dei termini tecnici e l'espressione naturale" 47 | }, 48 | { 49 | "title": "Sicuro e Affidabile", 50 | "description": "Le chiavi API vengono utilizzate solo temporaneamente nel browser e non vengono mai salvate o trasmesse ai server" 51 | } 52 | ] 53 | }, 54 | "uploadSection": { 55 | "title": "Carica File JSON", 56 | "description": "Carica il tuo file JSON per la traduzione", 57 | "dragText": "Trascina i file qui o clicca per caricare", 58 | "supportText": "Supporta file in formato .json, fino a 10MB", 59 | "apiKeyTip": "Suggerimento: È necessaria una chiave API OpenAI per la traduzione", 60 | "errors": { 61 | "selectFile": "Seleziona un file", 62 | "jsonExtension": "Carica un file con estensione .json", 63 | "fileSize": "La dimensione del file non può superare 10MB", 64 | "jsonFormat": "Formato JSON non valido, controlla il contenuto del file", 65 | "emptyJson": "Il file JSON non può essere vuoto" 66 | }, 67 | "success": { 68 | "uploaded": "File caricato con successo" 69 | }, 70 | "apiKeyTitle": "Chiave API OpenAI", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "Errore", 73 | "successTitle": "Successo" 74 | }, 75 | "translateSection": { 76 | "title": "Seleziona Lingua di Destinazione", 77 | "description": "Scegli le lingue in cui tradurre" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "Avvia Traduzione", 81 | "translating": "Traduzione in corso...", 82 | "cancel": "Annulla", 83 | "uploadFirst": "Carica prima un file", 84 | "enterApiKey": "Inserisci la Chiave API", 85 | "foundUnfinished": "Trovata traduzione incompleta", 86 | "continueTranslation": "Continua traduzione", 87 | "translationCancelled": "Traduzione annullata", 88 | "invalidApiKey": "Formato Chiave API non valido", 89 | "errorTitle": "Errore", 90 | "successTitle": "Successo", 91 | "translationCompleted": "Traduzione completata!", 92 | "showMoreLanguages": "Mostra più lingue", 93 | "hideMoreLanguages": "Nascondi più lingue", 94 | "overallProgress": "Progresso Complessivo", 95 | "completedSegments": "Segmenti Completati", 96 | "translatingLanguage": "Traduzione in corso", 97 | "allLanguagesTranslated": "Tutte le lingue selezionate sono state tradotte", 98 | "pleaseUploadAndEnterKey": "Carica un file e inserisci la Chiave API", 99 | "tip": "Suggerimento", 100 | "cancelled": "Annullato", 101 | "translationFailed": "Traduzione fallita", 102 | "pleaseSelectLanguage": "Seleziona almeno una lingua di destinazione", 103 | "bytes": "Byte", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "Formato chiave API non valido", 109 | "invalidOrExpired": "Chiave API non valida o scaduta", 110 | "rateLimitReached": "Limite di chiamate API raggiunto", 111 | "validationFailed": "Validazione chiave API fallita" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "Anteprima", 116 | "empty": "L'anteprima JSON apparirà qui", 117 | "copied": "Copiato negli appunti", 118 | "originalJson": "JSON Originale", 119 | "translatedJson": "JSON Tradotto", 120 | "tips": "Suggerimenti: Supporta l'anteprima in tempo reale e la formattazione dei file JSON, puoi copiare direttamente il contenuto", 121 | "placeholder": { 122 | "upload": "Carica un file JSON", 123 | "translation": "I risultati della traduzione verranno visualizzati qui" 124 | }, 125 | "actions": { 126 | "copy": "Copia", 127 | "download": "Scarica", 128 | "downloadAll": "Scarica tutte le traduzioni", 129 | "downloadFormat": "Scarica traduzione in {lang}" 130 | }, 131 | "toast": { 132 | "copySuccess": "Contenuto copiato negli appunti", 133 | "copyError": "Copia fallita, copia manualmente", 134 | "downloadSuccess": "File di traduzione {lang} scaricato", 135 | "downloadAllSuccess": "Tutti i file di traduzione sono stati scaricati", 136 | "downloadError": "Download fallito, riprova" 137 | }, 138 | "languages": { 139 | "en": "Inglese", 140 | "zh": "Cinese (Semplificato)", 141 | "zh-TW": "Cinese (Tradizionale)", 142 | "ja": "Giapponese", 143 | "ko": "Coreano", 144 | "fr": "Francese", 145 | "de": "Tedesco", 146 | "es": "Spagnolo", 147 | "pt": "Portoghese", 148 | "it": "Italiano", 149 | "ru": "Russo", 150 | "ar": "Arabo", 151 | "hi": "Hindi", 152 | "bn": "Bengalese", 153 | "th": "Tailandese", 154 | "vi": "Vietnamita", 155 | "id": "Indonesiano", 156 | "ms": "Malese", 157 | "tr": "Turco", 158 | "nl": "Olandese", 159 | "pl": "Polacco", 160 | "uk": "Ucraino", 161 | "el": "Greco", 162 | "he": "Ebraico", 163 | "sv": "Svedese", 164 | "da": "Danese", 165 | "fi": "Finlandese", 166 | "cs": "Ceco", 167 | "ro": "Rumeno", 168 | "hu": "Ungherese", 169 | "sk": "Slovacco", 170 | "bg": "Bulgaro", 171 | "hr": "Croato", 172 | "lt": "Lituano", 173 | "sl": "Sloveno", 174 | "et": "Estone", 175 | "lv": "Lettone", 176 | "sr": "Serbo", 177 | "mt": "Maltese", 178 | "fa": "Persiano", 179 | "ur": "Urdu", 180 | "ta": "Tamil", 181 | "te": "Telugu", 182 | "ml": "Malayalam", 183 | "kn": "Kannada", 184 | "mr": "Marathi", 185 | "gu": "Gujarati", 186 | "my": "Birmano", 187 | "km": "Khmer", 188 | "lo": "Lao", 189 | "mn": "Mongolo", 190 | "ka": "Georgiano", 191 | "hy": "Armeno", 192 | "az": "Azero", 193 | "sw": "Swahili", 194 | "af": "Afrikaans", 195 | "am": "Amarico" 196 | } 197 | }, 198 | "faq": { 199 | "title": "Domande Frequenti", 200 | "description": "Domande comuni sullo strumento di traduzione JSON", 201 | "items": [ 202 | { 203 | "question": "Cosa fa questo strumento?", 204 | "answer": "Questo è uno strumento di traduzione JSON basato su IA che aiuta gli sviluppatori a tradurre rapidamente i file di lingua JSON in più lingue mantenendo l'integrità della struttura JSON." 205 | }, 206 | { 207 | "question": "Come si usa questo strumento?", 208 | "answer": "1. Carica il tuo file JSON per la traduzione\n2. Seleziona le lingue di destinazione\n3. Inserisci la tua Chiave API OpenAI\n4. Clicca avvia traduzione\n5. Scarica i risultati dopo il completamento della traduzione" 209 | }, 210 | { 211 | "question": "Quali lingue sono supportate?", 212 | "answer": "Attualmente supporta più lingue tra cui inglese, cinese (semplificato), cinese (tradizionale), giapponese, coreano, francese, tedesco, spagnolo, russo e altre." 213 | }, 214 | { 215 | "question": "La mia Chiave API verrà salvata?", 216 | "answer": "No. La tua Chiave API viene utilizzata solo temporaneamente nel browser e non verrà mai salvata o trasmessa a nessun server." 217 | }, 218 | { 219 | "question": "Come viene garantita la qualità della traduzione?", 220 | "answer": "Utilizziamo il modello GPT di OpenAI per la traduzione, garantendo l'accuratezza dei termini tecnici e l'espressione naturale. Supportiamo anche la funzionalità di dizionario personalizzato per mantenere la coerenza della terminologia specifica." 221 | }, 222 | { 223 | "question": "C'è un limite di dimensione del file?", 224 | "answer": "La dimensione del singolo file JSON è limitata a 10MB. Per file più grandi, si consiglia di dividerli e tradurli in batch." 225 | } 226 | ] 227 | }, 228 | "cta": { 229 | "title": "Inizia a Usare lo Strumento di Traduzione IA Ora", 230 | "description": "Traduci rapidamente e accuratamente i tuoi file di lingua JSON in più lingue", 231 | "button": "Prova Ora", 232 | "features": [ 233 | "Nessuna Registrazione Richiesta", 234 | "Completamente Gratuito", 235 | "Traduzione in Tempo Reale" 236 | ] 237 | }, 238 | "footer": { 239 | "creator": "Creato con ❤️ da Viggo", 240 | "twitter": "@viggo", 241 | "coffee": "Offrimi un Caffè", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "Traduttore JSON - Soluzione di Traduzione Multilingue Basata su IA", 246 | "description": "Traduci rapidamente e accuratamente i file di lingua JSON in più lingue utilizzando la tecnologia IA. Supporta struttura JSON, segnaposto variabili e tag HTML.", 247 | "keywords": "traduzione JSON,traduzione IA,internazionalizzazione,i18n,traduzione multilingue,OpenAI" 248 | } 249 | } -------------------------------------------------------------------------------- /src/dictionaries/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "hero": { 3 | "badge": "AI Aangedreven", 4 | "title": "i18n JSON Vertaaltool", 5 | "description": "Vertaal uw JSON-taalbestanden snel met behulp van AI-technologie. Snel, nauwkeurig en eenvoudig te gebruiken.", 6 | "features": { 7 | "multilanguage": "Meertalige Ondersteuning", 8 | "realtime": "Realtime Vertaling" 9 | } 10 | }, 11 | "workflow": { 12 | "title": "Voltooi Vertaling in Vier Eenvoudige Stappen", 13 | "description": "We hebben het proces van het vertalen van JSON-bestanden vereenvoudigd om u te helpen snel hoogwaardige vertaalresultaten te verkrijgen", 14 | "steps": { 15 | "0": { 16 | "title": "Upload JSON-bestand", 17 | "description": "Ondersteunt slepen en neerzetten of klik om bestand te selecteren" 18 | }, 19 | "1": { 20 | "title": "Selecteer Doeltaal", 21 | "description": "Kies de doeltaal voor vertaling" 22 | }, 23 | "2": { 24 | "title": "Start Vertaling", 25 | "description": "Voer API-sleutel in en start AI-vertaling" 26 | }, 27 | "3": { 28 | "title": "Download Resultaten", 29 | "description": "Download het vertaalde JSON-bestand" 30 | } 31 | } 32 | }, 33 | "features": { 34 | "title": "Krachtige Vertaalfuncties", 35 | "items": { 36 | "0": { 37 | "title": "Behoud JSON-structuur", 38 | "description": "Intelligente herkenning en behoud van de structuur, inspringing en opmaak van het originele JSON-bestand" 39 | }, 40 | "1": { 41 | "title": "Meertalige Ondersteuning", 42 | "description": "Ondersteunt vertaling tussen meerdere talen, waaronder Engels, Chinees, Japans en meer" 43 | }, 44 | "2": { 45 | "title": "AI-Aangedreven Vertaling", 46 | "description": "Gebruikmakend van OpenAI GPT-modellen om de nauwkeurigheid van technische termen en natuurlijke uitdrukkingen te waarborgen" 47 | }, 48 | "3": { 49 | "title": "Veilig & Betrouwbaar", 50 | "description": "API-sleutels worden alleen tijdelijk in de browser gebruikt en nooit opgeslagen of verzonden naar servers" 51 | } 52 | } 53 | }, 54 | "uploadSection": { 55 | "title": "Upload JSON-bestand", 56 | "description": "Upload uw JSON-bestand voor vertaling", 57 | "dragText": "Sleep bestanden hierheen of klik om te uploaden", 58 | "supportText": "Ondersteunt .json-bestandsindelingen, tot 10MB", 59 | "apiKeyTip": "Tips: OpenAI API-sleutel is vereist voor vertaling", 60 | "errors": { 61 | "selectFile": "Selecteer alstublieft een bestand", 62 | "jsonExtension": "Upload alstublieft een bestand met een .json-extensie", 63 | "fileSize": "Bestandsgrootte mag niet groter zijn dan 10MB", 64 | "jsonFormat": "Ongeldig JSON-formaat, controleer alstublieft de bestandsinhoud", 65 | "emptyJson": "JSON-bestand mag niet leeg zijn" 66 | }, 67 | "success": { 68 | "uploaded": "Bestand succesvol geüpload" 69 | }, 70 | "apiKeyTitle": "OpenAI API-sleutel", 71 | "apiKeyPlaceholder": "sk-...", 72 | "errorTitle": "Fout", 73 | "successTitle": "Succes" 74 | }, 75 | "translateSection": { 76 | "title": "Selecteer Doeltaal", 77 | "description": "Kies talen om in te vertalen" 78 | }, 79 | "translatePanel": { 80 | "startTranslate": "Start Vertaling", 81 | "translating": "Bezig met vertalen...", 82 | "cancel": "Annuleren", 83 | "uploadFirst": "Upload eerst een bestand", 84 | "enterApiKey": "Voer alstublieft API-sleutel in", 85 | "foundUnfinished": "Onvoltooide vertaling gevonden", 86 | "continueTranslation": "Vervolg vertaling", 87 | "translationCancelled": "Vertaling geannuleerd", 88 | "invalidApiKey": "Ongeldig API-sleutel formaat", 89 | "errorTitle": "Fout", 90 | "successTitle": "Succes", 91 | "translationCompleted": "Vertaling voltooid!", 92 | "showMoreLanguages": "Toon meer talen", 93 | "hideMoreLanguages": "Verberg meer talen", 94 | "overallProgress": "Algemene voortgang", 95 | "completedSegments": "Voltooide segmenten", 96 | "translatingLanguage": "Vertalen", 97 | "allLanguagesTranslated": "Alle geselecteerde talen zijn vertaald", 98 | "pleaseUploadAndEnterKey": "Upload een bestand en voer de API-sleutel in", 99 | "tip": "Tip", 100 | "cancelled": "Geannuleerd", 101 | "translationFailed": "Vertaling mislukt", 102 | "pleaseSelectLanguage": "Selecteer alstublieft ten minste één doeltaal", 103 | "bytes": "Bytes", 104 | "kb": "KB", 105 | "mb": "MB", 106 | "gb": "GB", 107 | "apiKeyErrors": { 108 | "invalidFormat": "Ongeldig API-sleutelformaat", 109 | "invalidOrExpired": "Ongeldige of verlopen API-sleutel", 110 | "rateLimitReached": "API-aanroeplimiet bereikt", 111 | "validationFailed": "API-sleutelvalidatie mislukt" 112 | } 113 | }, 114 | "jsonPreview": { 115 | "title": "Voorbeeld", 116 | "empty": "JSON-voorbeeld verschijnt hier", 117 | "copied": "Gekopieerd naar klembord", 118 | "originalJson": "Originele JSON", 119 | "translatedJson": "Vertaald JSON", 120 | "tips": "Tips: Ondersteunt realtime voorbeeld en opmaak van JSON-bestanden, en u kunt de inhoud direct kopiëren", 121 | "placeholder": { 122 | "upload": "Upload een JSON-bestand", 123 | "translation": "Vertaalresultaten worden hier weergegeven" 124 | }, 125 | "actions": { 126 | "copy": "Kopiëren", 127 | "download": "Downloaden", 128 | "downloadAll": "Download alle vertalingen", 129 | "downloadFormat": "Download {lang} vertaling" 130 | }, 131 | "toast": { 132 | "copySuccess": "Inhoud is gekopieerd naar het klembord", 133 | "copyError": "Kopiëren mislukt, kopieer handmatig", 134 | "downloadSuccess": "{lang} vertaalbestand is gedownload", 135 | "downloadAllSuccess": "Alle vertaalbestanden zijn gedownload", 136 | "downloadError": "Downloaden mislukt, probeer het opnieuw" 137 | }, 138 | "languages": { 139 | "en": "Engels", 140 | "zh": "Chinees (vereenvoudigd)", 141 | "zh-TW": "Chinees (traditioneel)", 142 | "ja": "Japans", 143 | "ko": "Koreaans", 144 | "fr": "Frans", 145 | "de": "Duits", 146 | "es": "Spaans", 147 | "pt": "Portugees", 148 | "it": "Italiaans", 149 | "ru": "Russisch", 150 | "ar": "Arabisch", 151 | "hi": "Hindi", 152 | "bn": "Bengaals", 153 | "th": "Thais", 154 | "vi": "Vietnamees", 155 | "id": "Indonesisch", 156 | "ms": "Maleis", 157 | "tr": "Turks", 158 | "nl": "Nederlands", 159 | "pl": "Pools", 160 | "uk": "Oekraïens", 161 | "el": "Grieks", 162 | "he": "Hebreeuws", 163 | "sv": "Zweeds", 164 | "da": "Deens", 165 | "fi": "Fins", 166 | "cs": "Tsjechisch", 167 | "ro": "Roemeens", 168 | "hu": "Hongaars", 169 | "sk": "Slowaaks", 170 | "bg": "Bulgaars", 171 | "hr": "Kroatisch", 172 | "lt": "Litouws", 173 | "sl": "Sloveens", 174 | "et": "Ests", 175 | "lv": "Lets", 176 | "sr": "Servisch", 177 | "mt": "Maltees", 178 | "fa": "Perzisch", 179 | "ur": "Urdu", 180 | "ta": "Tamil", 181 | "te": "Telugu", 182 | "ml": "Malayalam", 183 | "kn": "Kannada", 184 | "mr": "Marathi", 185 | "gu": "Gujarati", 186 | "my": "Birmaans", 187 | "km": "Khmer", 188 | "lo": "Laos", 189 | "mn": "Mongools", 190 | "ka": "Georgisch", 191 | "hy": "Armeens", 192 | "az": "Azerbeidzjaans", 193 | "sw": "Swahili", 194 | "af": "Afrikaans", 195 | "am": "Amhaars" 196 | } 197 | }, 198 | "faq": { 199 | "title": "Veelgestelde Vragen", 200 | "description": "Veelvoorkomende vragen over de JSON vertaaltool", 201 | "items": { 202 | "0": { 203 | "question": "Wat doet deze tool?", 204 | "answer": "Dit is een AI-gestuurde JSON internationalisatie vertaaltool die ontwikkelaars helpt om JSON-taalbestanden snel in meerdere talen te vertalen, terwijl de integriteit van de JSON-structuur behouden blijft." 205 | }, 206 | "1": { 207 | "question": "Hoe gebruik je deze tool?", 208 | "answer": "1. Upload je JSON-bestand voor vertaling\n2. Selecteer doeltalen\n3. Voer je OpenAI API-sleutel in\n4. Klik op start vertaling\n5. Download de resultaten nadat de vertaling is voltooid" 209 | }, 210 | "2": { 211 | "question": "Welke talen worden ondersteund?", 212 | "answer": "Momenteel worden meerdere talen ondersteund, waaronder Engels, Chinees (Vereenvoudigd), Chinees (Traditioneel), Japans, Koreaans, Frans, Duits, Spaans, Russisch, en meer." 213 | }, 214 | "3": { 215 | "question": "Zal mijn API-sleutel worden opgeslagen?", 216 | "answer": "Nee. Uw API-sleutel wordt alleen tijdelijk in de browser gebruikt en zal niet worden opgeslagen of naar servers worden verzonden." 217 | }, 218 | "4": { 219 | "question": "Hoe wordt de vertaalkwaliteit gegarandeerd?", 220 | "answer": "We gebruiken het GPT-model van OpenAI voor vertaling, wat de nauwkeurigheid van technische termen en natuurlijke taaluitdrukkingen waarborgt. We ondersteunen ook de functionaliteit van een aangepast woordenboek om de consistentie van specifieke terminologie te behouden." 221 | }, 222 | "5": { 223 | "question": "Is er een limiet voor de bestandsgrootte?", 224 | "answer": "De grootte van een enkel JSON-bestand is beperkt tot 10MB. Voor grotere bestanden is het aan te raden om ze te splitsen en in batches te vertalen." 225 | } 226 | } 227 | }, 228 | "cta": { 229 | "title": "Begin Nu met het Gebruik van de AI Vertaaltool", 230 | "description": "Vertaal snel en nauwkeurig uw JSON-taalbestanden in meerdere talen", 231 | "button": "Probeer Nu", 232 | "features": { 233 | "0": "Geen Registratie Vereist", 234 | "1": "Volledig Gratis", 235 | "2": "Realtime Vertaling" 236 | } 237 | }, 238 | "footer": { 239 | "creator": "Gemaakt met ❤️ door Viggo", 240 | "twitter": "@viggo", 241 | "coffee": "Koop Me een Koffie", 242 | "github": "GitHub" 243 | }, 244 | "metadata": { 245 | "title": "JSON Vertaler - AI-Aangedreven Meertalige Vertaaloplossing", 246 | "description": "Vertaal JSON-taalbestanden snel en nauwkeurig naar meerdere talen met AI-technologie. Ondersteunt JSON-structuur, variabele plaatshouders en HTML-tags.", 247 | "keywords": "JSON vertaling,AI vertaling,internationalisatie,i18n,meertalige vertaling,OpenAI" 248 | } 249 | } --------------------------------------------------------------------------------