-
Notifications
You must be signed in to change notification settings - Fork 11.2k
feat: complete Vietnamese localization for new-api #1802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,75 +1,75 @@ | ||
| # 端口号 | ||
| # PORT=3000 | ||
| # 前端基础URL | ||
| # FRONTEND_BASE_URL=https://your-frontend-url.com | ||
| # Port number (Số cổng) | ||
| PORT=3000 | ||
| # Frontend base URL (URL cơ sở giao diện người dùng) | ||
| FRONTEND_BASE_URL=https://your-frontend-url.com | ||
|
|
||
|
|
||
| # 调试相关配置 | ||
| # 启用pprof | ||
| # ENABLE_PPROF=true | ||
| # 启用调试模式 | ||
| # DEBUG=true | ||
| # Debug related configuration (Cấu hình liên quan đến gỡ lỗi) | ||
| # Enable pprof (Bật pprof) | ||
| ENABLE_PPROF=true | ||
| # Enable debug mode (Bật chế độ gỡ lỗi) | ||
| DEBUG=true | ||
|
|
||
| # 数据库相关配置 | ||
| # 数据库连接字符串 | ||
| # SQL_DSN=user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true | ||
| # 日志数据库连接字符串 | ||
| # LOG_SQL_DSN=user:password@tcp(127.0.0.1:3306)/logdb?parseTime=true | ||
| # SQLite数据库路径 | ||
| # SQLITE_PATH=/path/to/sqlite.db | ||
| # 数据库最大空闲连接数 | ||
| # SQL_MAX_IDLE_CONNS=100 | ||
| # 数据库最大打开连接数 | ||
| # SQL_MAX_OPEN_CONNS=1000 | ||
| # 数据库连接最大生命周期(秒) | ||
| # SQL_MAX_LIFETIME=60 | ||
| # # Database related configuration (Cấu hình liên quan đến cơ sở dữ liệu) | ||
| # Database connection string (Chuỗi kết nối cơ sở dữ liệu) | ||
| SQL_DSN=user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true | ||
| # Log database connection string (Chuỗi kết nối cơ sở dữ liệu log) | ||
| LOG_SQL_DSN=user:password@tcp(127.0.0.1:3306)/logdb?parseTime=true | ||
| # SQLite database path (Đường dẫn cơ sở dữ liệu SQLite) | ||
| SQLITE_PATH=/path/to/sqlite.db | ||
| # Database maximum idle connections (Số kết nối rảnh tối đa của cơ sở dữ liệu) | ||
| SQL_MAX_IDLE_CONNS=100 | ||
| # Database maximum open connections (Số kết nối mở tối đa của cơ sở dữ liệu) | ||
| SQL_MAX_OPEN_CONNS=1000 | ||
| # Database connection maximum lifetime in seconds (Thời gian sống tối đa của kết nối cơ sở dữ liệu tính bằng giây) | ||
| SQL_MAX_LIFETIME=60 | ||
|
|
||
|
|
||
| # 缓存相关配置 | ||
| # Redis连接字符串 | ||
| # REDIS_CONN_STRING=redis://user:password@localhost:6379/0 | ||
| # 同步频率(单位:秒) | ||
| # SYNC_FREQUENCY=60 | ||
| # 内存缓存启用 | ||
| # MEMORY_CACHE_ENABLED=true | ||
| # 渠道更新频率(单位:秒) | ||
| # CHANNEL_UPDATE_FREQUENCY=30 | ||
| # 批量更新启用 | ||
| # BATCH_UPDATE_ENABLED=true | ||
| # 批量更新间隔(单位:秒) | ||
| # BATCH_UPDATE_INTERVAL=5 | ||
| # Cache related configuration (Cấu hình liên quan đến bộ nhớ đệm) | ||
| # Redis connection string (Chuỗi kết nối Redis) | ||
| REDIS_CONN_STRING=redis://user:password@localhost:6379/0 | ||
| # Sync frequency in seconds (Tần suất đồng bộ tính bằng giây) | ||
| SYNC_FREQUENCY=60 | ||
| # Memory cache enabled (Bật bộ nhớ đệm) | ||
| MEMORY_CACHE_ENABLED=true | ||
| # Channel update frequency in seconds (Tần suất cập nhật kênh tính bằng giây) | ||
| CHANNEL_UPDATE_FREQUENCY=30 | ||
| # Batch update enabled (Bật cập nhật hàng loạt) | ||
| BATCH_UPDATE_ENABLED=true | ||
| # Batch update interval in seconds (Khoảng thời gian cập nhật hàng loạt tính bằng giây) | ||
| BATCH_UPDATE_INTERVAL=5 | ||
|
|
||
| # 任务和功能配置 | ||
| # 更新任务启用 | ||
| # UPDATE_TASK=true | ||
| # # Task and function configuration (Cấu hình tác vụ và chức năng) | ||
| # Update task enabled (Bật tác vụ cập nhật) | ||
| UPDATE_TASK=true | ||
|
|
||
| # 对话超时设置 | ||
| # 所有请求超时时间,单位秒,默认为0,表示不限制 | ||
| # RELAY_TIMEOUT=0 | ||
| # 流模式无响应超时时间,单位秒,如果出现空补全可以尝试改为更大值 | ||
| # STREAMING_TIMEOUT=120 | ||
| # Conversation timeout settings (Cài đặt thời gian chờ cuộc hội thoại) | ||
| # All request timeout in seconds, default is 0 means no limit (Thời gian chờ tất cả yêu cầu tính bằng giây, mặc định là 0 có nghĩa là không giới hạn) | ||
| RELAY_TIMEOUT=0 | ||
| # Stream mode no response timeout in seconds, try larger value if empty completion occurs (Thời gian chờ không phản hồi trong chế độ stream tính bằng giây, thử giá trị lớn hơn nếu xảy ra hoàn thành trống) | ||
| STREAMING_TIMEOUT=120 | ||
|
|
||
| # Gemini 识别图片 最大图片数量 | ||
| # GEMINI_VISION_MAX_IMAGE_NUM=16 | ||
| # Gemini image recognition maximum image count (Số lượng hình ảnh tối đa cho nhận dạng hình ảnh Gemini) | ||
| GEMINI_VISION_MAX_IMAGE_NUM=16 | ||
|
|
||
| # 会话密钥 | ||
| # SESSION_SECRET=random_string | ||
| # # Session secret (Khóa phiên) | ||
| SESSION_SECRET=random_string | ||
|
|
||
| # 其他配置 | ||
| # 渠道测试频率(单位:秒) | ||
| # CHANNEL_TEST_FREQUENCY=10 | ||
| # 生成默认token | ||
| # GENERATE_DEFAULT_TOKEN=false | ||
| # Cohere 安全设置 | ||
| # COHERE_SAFETY_SETTING=NONE | ||
| # 是否统计图片token | ||
| # GET_MEDIA_TOKEN=true | ||
| # 是否在非流(stream=false)情况下统计图片token | ||
| # GET_MEDIA_TOKEN_NOT_STREAM=true | ||
| # 设置 Dify 渠道是否输出工作流和节点信息到客户端 | ||
| # DIFY_DEBUG=true | ||
| # Other configuration (Cấu hình khác) | ||
| # Channel test frequency in seconds (Tần suất kiểm tra kênh tính bằng giây) | ||
| CHANNEL_TEST_FREQUENCY=10 | ||
| # Generate default token (Tạo token mặc định) | ||
| GENERATE_DEFAULT_TOKEN=false | ||
| # Cohere safety setting (Cài đặt bảo mật Cohere) | ||
| COHERE_SAFETY_SETTING=NONE | ||
| # Whether to count image tokens (Có đếm token hình ảnh hay không) | ||
| GET_MEDIA_TOKEN=true | ||
| # Whether to count image tokens in non-stream mode (stream=false) (Có đếm token hình ảnh trong chế độ không stream (stream=false) hay không) | ||
| GET_MEDIA_TOKEN_NOT_STREAM=true | ||
| # Set whether Dify channel outputs workflow and node information to client (Thiết lập kênh Dify có xuất thông tin quy trình làm việc và nút tới client hay không) | ||
| DIFY_DEBUG=true | ||
|
|
||
|
|
||
| # 节点类型 | ||
| # 如果是主节点则为master | ||
| # NODE_TYPE=master | ||
| # Node type (Loại nút) | ||
| # If master node then set to master (Nếu là nút chính thì đặt thành master) | ||
| NODE_TYPE=master |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ import { useSetTheme, useTheme } from '../../context/Theme/index.js'; | |
| import { useTranslation } from 'react-i18next'; | ||
| import { API, getLogo, getSystemName, showSuccess, stringToColor } from '../../helpers/index.js'; | ||
| import fireworks from 'react-fireworks'; | ||
| import { CN, GB } from 'country-flag-icons/react/3x2'; | ||
| import { CN, GB, VN } from 'country-flag-icons/react/3x2'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainLanguage code ‘vn’ vs. standard ‘vi/vi-VN’ — verify mapping You register/select 'vn'. Confirm i18n initialization maps 'vi'/'vi-VN' detections to 'vn' to prevent fallback misses. Also applies to: 611-617 🏁 Script executed: #!/bin/bash
# Inspect i18n setup and locale files for 'vn' mapping and detection
rg -n "i18n\\.|init\\(|changeLanguage\\(|supportedLngs|fallbackLng|languageDetector" -C3 web/src/i18n
rg -n "\"vn\"|locales/vn\\.json" -n web/src/i18n -C2
rg -n "vi-VN|vi_" -n web/src/i18n -C2Length of output: 858 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== file: web/src/i18n/i18n.js (first 240 lines) ==="
if [ -f web/src/i18n/i18n.js ]; then
nl -ba web/src/i18n/i18n.js | sed -n '1,240p'
else
echo "MISSING: web/src/i18n/i18n.js"
fi
echo
echo "=== rg: i18n config tokens in web/src/i18n ==="
rg -n "supportedLngs|fallbackLng|resources:|LanguageDetector|init\\(|use\\(|nonExplicit|load|lookup|order|caches|whitelist" web/src/i18n -S -n -C3 || true
echo
echo "=== locales listing ==="
ls -la web/src/i18n/locales || true
echo
echo "=== show vn.json and vi.json if present ==="
if [ -f web/src/i18n/locales/vn.json ]; then
echo "--- vn.json ---"
nl -ba web/src/i18n/locales/vn.json | sed -n '1,200p'
else
echo "vn.json not found"
fi
if [ -f web/src/i18n/locales/vi.json ]; then
echo "--- vi.json ---"
nl -ba web/src/i18n/locales/vi.json | sed -n '1,200p'
else
echo "vi.json not found"
fi
echo
echo "=== search repo for 'vi' and 'vn' occurrences ==="
rg -n --hidden --no-ignore -S "\\bvi(-|_)|vi\\b|vi-VN|\\bvn\\b" || true
echo
echo "=== search for language change/usages ==="
rg -n "changeLanguage\\(|i18n\\.changeLanguage|i18n\\.language|LanguageDetector" -S || trueLength of output: 93 Use standard language code 'vi' or add explicit mapping for Vietnamese i18n currently registers "vn" (web/src/i18n/i18n.js imports ./locales/vn.json and resources include vn) while LanguageDetector returns "vi" / "vi-VN", causing fallbacks (fallbackLng: 'zh'). Fix by renaming the locale key/file to "vi" (rename vn.json → vi.json and update imports/resources) or add an explicit alias (assign resources.vi = vnTranslation and set supportedLngs or map detected "vi"/"vi-VN" → "vn"). HeaderBar's flag import (VN) is the ISO country code and can remain. Files to change: web/src/i18n/i18n.js, web/src/i18n/locales/vn.json (or rename), web/src/components/layout/HeaderBar.js:8 (also applies to 611–617). 🤖 Prompt for AI Agents |
||
| import NoticeModal from './NoticeModal.js'; | ||
|
|
||
| import { | ||
|
|
@@ -608,6 +608,13 @@ const HeaderBar = ({ onMobileMenuToggle, drawerOpen }) => { | |
| <GB title="English" className="!w-5 !h-auto" /> | ||
| <span>English</span> | ||
| </Dropdown.Item> | ||
| <Dropdown.Item | ||
| onClick={() => handleLanguageChange('vn')} | ||
| className={`!flex !items-center !gap-2 !px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'vn' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} | ||
| > | ||
| <VN title="Tiếng Việt" className="!w-5 !h-auto" /> | ||
| <span>Tiếng Việt</span> | ||
| </Dropdown.Item> | ||
| </Dropdown.Menu> | ||
| } | ||
| > | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -59,7 +59,7 @@ const DashboardSetting = () => { | |||||||||||||||||||||
| setLoading(true); | ||||||||||||||||||||||
| await getOptions(); | ||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||
| showError('刷新失败'); | ||||||||||||||||||||||
| showError(t('刷新失败')); | ||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix: t is undefined here This file doesn’t import/use i18n; calling t(...) will crash at runtime. Apply: import React, { useEffect, useState, useMemo } from 'react';
import { Card, Spin, Button, Modal } from '@douyinfe/semi-ui';
import { API, showError, showSuccess, toBoolean } from '../../helpers';
+import { useTranslation } from 'react-i18next';
@@
-const DashboardSetting = () => {
+const DashboardSetting = () => {
+ const { t } = useTranslation();📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| console.error(error); | ||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||
| setLoading(false); | ||||||||||||||||||||||
|
|
@@ -86,12 +86,12 @@ const DashboardSetting = () => { | |||||||||||||||||||||
| try { | ||||||||||||||||||||||
| setLoading(true); | ||||||||||||||||||||||
| await API.post('/api/option/migrate_console_setting'); | ||||||||||||||||||||||
| showSuccess('旧配置迁移完成'); | ||||||||||||||||||||||
| showSuccess(t('旧配置迁移完成')); | ||||||||||||||||||||||
| await onRefresh(); | ||||||||||||||||||||||
| setShowMigrateModal(false); | ||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||
| console.error(err); | ||||||||||||||||||||||
| showError('迁移失败: ' + (err.message || '未知错误')); | ||||||||||||||||||||||
| showError(t('迁移失败') + ': ' + (err.message || t('未知错误'))); | ||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||
| setLoading(false); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
@@ -101,22 +101,22 @@ const DashboardSetting = () => { | |||||||||||||||||||||
| <> | ||||||||||||||||||||||
| <Spin spinning={loading} size='large'> | ||||||||||||||||||||||
| {/* 用于迁移检测的旧键模态框,下个版本会删除 */} | ||||||||||||||||||||||
| <Modal | ||||||||||||||||||||||
| title="配置迁移确认" | ||||||||||||||||||||||
| visible={showMigrateModal} | ||||||||||||||||||||||
| onOk={handleMigrate} | ||||||||||||||||||||||
| onCancel={() => setShowMigrateModal(false)} | ||||||||||||||||||||||
| confirmLoading={loading} | ||||||||||||||||||||||
| okText="确认迁移" | ||||||||||||||||||||||
| cancelText="取消" | ||||||||||||||||||||||
| > | ||||||||||||||||||||||
| <p>检测到旧版本的配置数据,是否要迁移到新的配置格式?</p> | ||||||||||||||||||||||
| <p style={{ color: '#f57c00', marginTop: '10px' }}> | ||||||||||||||||||||||
| <strong>注意:</strong>迁移过程中会自动处理数据格式转换,迁移完成后旧配置将被清除,请在迁移前在数据库中备份好旧配置。 | ||||||||||||||||||||||
| </p> | ||||||||||||||||||||||
| </Modal> | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| {/* 数据看板设置 */} | ||||||||||||||||||||||
| <Modal | ||||||||||||||||||||||
| title={t('配置迁移确认')} | ||||||||||||||||||||||
| visible={showMigrateModal} | ||||||||||||||||||||||
| onOk={handleMigrate} | ||||||||||||||||||||||
| onCancel={() => setShowMigrateModal(false)} | ||||||||||||||||||||||
| confirmLoading={loading} | ||||||||||||||||||||||
| okText={t('确认迁移')} | ||||||||||||||||||||||
| cancelText={t('取消')} | ||||||||||||||||||||||
| > | ||||||||||||||||||||||
| <p>{t('检测到旧版本的配置数据,是否要迁移到新的配置格式?')}</p> | ||||||||||||||||||||||
| <p style={{ color: '#f57c00', marginTop: '10px' }}> | ||||||||||||||||||||||
| <strong>{t('注意:')}</strong>{t('迁移过程中会自动处理数据格式转换,迁移完成后旧配置将被清除,请在迁移前在数据库中备份好旧配置。')} | ||||||||||||||||||||||
| </p> | ||||||||||||||||||||||
| </Modal> | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| {/* 数据看板设置 */} | ||||||||||||||||||||||
| <Card style={{ marginTop: '10px' }}> | ||||||||||||||||||||||
| <SettingsDataDashboard options={inputs} refresh={onRefresh} /> | ||||||||||||||||||||||
| </Card> | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Don’t commit plaintext DB creds; use .env and secrets.
Root password and DSN are hard-coded. Parameterize via env and document in .env.example.
Optional: add
env_file: [.env]on the service.Also applies to: 41-47
🤖 Prompt for AI Agents