refactor(i18n): colocate runtime and locale resources (#42482)

This commit is contained in:
yyh
2026-09-18 04:13:14 +00:00
committed by GitHub
parent 21d5e4e020
commit 3b8fc9c9b6
1155 changed files with 381 additions and 385 deletions

View File

@@ -8,7 +8,8 @@ const headSha = process.env.HEAD_SHA || ''
const files = (process.env.CHANGED_FILES || '').split(/\s+/).filter(Boolean)
const outputPath = process.env.I18N_CHANGES_OUTPUT_PATH || '/tmp/i18n-changes.json'
const englishPath = (fileStem) => path.join(repoRoot, 'web', 'i18n', 'en-US', `${fileStem}.json`)
const englishPath = (fileStem) =>
path.join(repoRoot, 'web', 'i18n', 'locales', 'en-US', `${fileStem}.json`)
const readCurrentJson = (fileStem) => {
const filePath = englishPath(fileStem)
@@ -21,7 +22,7 @@ const readBaseJson = (fileStem) => {
if (!baseSha) return null
try {
const relativePath = `web/i18n/en-US/${fileStem}.json`
const relativePath = `web/i18n/locales/en-US/${fileStem}.json`
const content = execFileSync('git', ['show', `${baseSha}:${relativePath}`], {
encoding: 'utf8',
})

View File

@@ -100,8 +100,8 @@ jobs:
- 'web/app/components/workflow/hooks/use-nodes-sync-draft.ts'
- 'web/app/components/workflow/nodes/_base/**'
- 'web/app/components/workflow/nodes/agent-v2/**'
- 'web/i18n/en-US/agent-v-2.json'
- 'web/i18n/en-US/common.json'
- 'web/i18n/locales/en-US/agent-v-2.json'
- 'web/i18n/locales/en-US/common.json'
- 'web/service/base.ts'
- 'web/service/console/**'
- 'web/service/share.ts'

View File

@@ -69,7 +69,7 @@ jobs:
/supported: true/ && value != \"en-US\" {
printf \"%s \", value
}
" web/i18n-config/languages.ts | sed 's/[[:space:]]*$//')
" web/i18n/languages.ts | sed 's/[[:space:]]*$//')
generate_changes_json() {
node .github/scripts/generate-i18n-changes.mjs
@@ -110,9 +110,9 @@ jobs:
elif [ "$SYNC_MODE" = "incremental" ]; then
BASE_SHA=$(git rev-parse HEAD~1 2>/dev/null || true)
if [ -n "$BASE_SHA" ]; then
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- 'web/i18n/en-US/*.json' 2>/dev/null | sed -n 's@^.*/@@p' | sed 's/\.json$//' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
CHANGED_FILES=$(git diff --name-only --find-renames=100% --diff-filter=AMDT "$BASE_SHA" "$HEAD_SHA" -- 'web/i18n/' 2>/dev/null | sed -n '\@^web/i18n/locales/en-US/[^/]*\.json$@p' | sed -n 's@^.*/@@p' | sed 's/\.json$//' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
else
CHANGED_FILES=$(find web/i18n/en-US -maxdepth 1 -type f -name '*.json' -print | sed -n 's@^.*/@@p' | sed 's/\.json$//' | sort | tr '\n' ' ' | sed 's/[[:space:]]*$//')
CHANGED_FILES=$(find web/i18n/locales/en-US -maxdepth 1 -type f -name '*.json' -print | sed -n 's@^.*/@@p' | sed 's/\.json$//' | sort | tr '\n' ' ' | sed 's/[[:space:]]*$//')
fi
elif [ "$SYNC_MODE" = "full" ]; then
echo "workflow_dispatch full mode requires the files input to stay within CI limits." >&2
@@ -170,12 +170,12 @@ jobs:
show_full_output: ${{ github.event_name == 'workflow_dispatch' }}
prompt: |
You are the i18n sync agent for the Dify repository.
Your job is to keep translations synchronized with the English source files under `${{ github.workspace }}/web/i18n/en-US/`.
Your job is to keep translations synchronized with the English source files under `${{ github.workspace }}/web/i18n/locales/en-US/`.
Use absolute paths at all times:
- Repo root: `${{ github.workspace }}`
- Web directory: `${{ github.workspace }}/web`
- Language config: `${{ github.workspace }}/web/i18n-config/languages.ts`
- Language config: `${{ github.workspace }}/web/i18n/languages.ts`
Inputs:
- Files in scope: `${{ steps.context.outputs.CHANGED_FILES }}`
@@ -198,12 +198,12 @@ jobs:
Required execution plan:
1. Resolve target languages.
- Use the provided `Target languages` value as the source of truth.
- If it is unexpectedly empty, read `${{ github.workspace }}/web/i18n-config/languages.ts` and use every language with `supported: true` except `en-US`.
- If it is unexpectedly empty, read `${{ github.workspace }}/web/i18n/languages.ts` and use every language with `supported: true` except `en-US`.
2. Stay strictly in scope.
- Only process the files listed in `Files in scope`.
- Only process the resolved target languages, never `en-US`.
- Do not touch unrelated i18n files.
- Do not modify `${{ github.workspace }}/web/i18n/en-US/`.
- Do not modify `${{ github.workspace }}/web/i18n/locales/en-US/`.
3. Resolve source changes.
- If `Structured change set available` is `true`, read `/tmp/i18n-changes.json` and use it as the source of truth for file-level and key-level changes.
- For each file entry:
@@ -227,7 +227,7 @@ jobs:
- Match the existing terminology and register used by each locale.
- Prefer one Edit per file when stable, but prioritize correctness over batching.
6. Verify only the edited files.
- Run `vp fmt <repo-relative edited paths such as web/i18n/...>`
- Run `vp fmt <repo-relative edited paths such as web/i18n/locales/...>`
- Run `vp run dify-web#i18n:check ${{ steps.context.outputs.FILE_ARGS }} ${{ steps.context.outputs.LANG_ARGS }}`
- If verification fails, fix the remaining problems before continuing.
7. Stop after the scoped locale files are updated and verification passes.
@@ -241,7 +241,7 @@ jobs:
if: steps.context.outputs.CHANGED_FILES != ''
shell: bash
run: |
if [ -z "$(git -C "${{ github.workspace }}" status --porcelain -- web/i18n/)" ]; then
if [ -z "$(git -C "${{ github.workspace }}" status --porcelain -- web/i18n/locales/)" ]; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
exit 0
fi
@@ -260,7 +260,7 @@ jobs:
shell: bash
run: |
git -C "${{ github.workspace }}" checkout -B "${{ steps.pr_meta.outputs.branch_name }}"
git -C "${{ github.workspace }}" add web/i18n/
git -C "${{ github.workspace }}" add web/i18n/locales/
git -C "${{ github.workspace }}" commit -m "chore(i18n): sync translations with en-US"
- name: Push translation branch
@@ -326,7 +326,7 @@ jobs:
'## Verification',
'',
`- \`vp run dify-web#i18n:check --file ${process.env.FILES_IN_SCOPE} --lang ${process.env.TARGET_LANGS}\``,
`- \`vp fmt <repo-relative edited paths such as web/i18n/...>\``,
`- \`vp fmt <repo-relative edited paths such as web/i18n/locales/...>\``,
'',
'## Notes',
'',

View File

@@ -4,7 +4,7 @@ on:
push:
branches: [main]
paths:
- 'web/i18n/en-US/*.json'
- 'web/i18n/locales/en-US/*.json'
permissions:
contents: write
@@ -36,9 +36,9 @@ jobs:
HEAD_SHA="${{ github.sha }}"
if [ -n "$BASE_SHA" ]; then
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- 'web/i18n/en-US/*.json' 2>/dev/null | sed -n 's@^.*/@@p' | sed 's/\.json$//' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
CHANGED_FILES=$(git diff --name-only --find-renames=100% --diff-filter=AMDT "$BASE_SHA" "$HEAD_SHA" -- 'web/i18n/' 2>/dev/null | sed -n '\@^web/i18n/locales/en-US/[^/]*\.json$@p' | sed -n 's@^.*/@@p' | sed 's/\.json$//' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
else
CHANGED_FILES=$(find web/i18n/en-US -maxdepth 1 -type f -name '*.json' -print | sed -n 's@^.*/@@p' | sed 's/\.json$//' | sort | tr '\n' ' ' | sed 's/[[:space:]]*$//')
CHANGED_FILES=$(find web/i18n/locales/en-US -maxdepth 1 -type f -name '*.json' -print | sed -n 's@^.*/@@p' | sed 's/\.json$//' | sort | tr '\n' ' ' | sed 's/[[:space:]]*$//')
fi
export BASE_SHA HEAD_SHA CHANGED_FILES

View File

@@ -140,7 +140,7 @@ Dify welcomes contributions of all kinds:
- **Code**: Read the [Contribution Guide](CONTRIBUTING.md), then browse [good first issues](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Ideas and feedback**: Start or join a [GitHub Discussion](https://github.com/langgenius/dify/discussions).
- **Translations**: Follow the [internationalization guide](web/i18n-config/README.md) to add or update a locale.
- **Translations**: Follow the [internationalization guide](web/i18n/README.md) to add or update a locale.
- **Community**: Share the apps you build, help other users, and spread the word about Dify.
### Contributors

View File

@@ -129,7 +129,7 @@ docker compose up -d
- **الشفرة البرمجية**: اقرأ [دليل المساهمة](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md)، ثم تصفح [المشكلات المناسبة للمساهمين الجدد](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **الأفكار والملاحظات**: ابدأ أو انضم إلى [مناقشة على GitHub](https://github.com/langgenius/dify/discussions).
- **الترجمات**: اتبع [دليل التدويل](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) لإضافة لغة أو تحديثها.
- **الترجمات**: اتبع [دليل التدويل](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) لإضافة لغة أو تحديثها.
- **المجتمع**: شارك التطبيقات التي تبنيها، وساعد المستخدمين الآخرين، وساهم في نشر Dify.
### المساهمون

View File

@@ -145,7 +145,7 @@ Dify সব ধরনের অবদানকে স্বাগত জান
- **কোড**: [অবদান নির্দেশিকা](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) পড়ুন, তারপর [নতুন অবদানকারীদের উপযোগী সমস্যাগুলো](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) দেখুন।
- **ধারণা ও প্রতিক্রিয়া**: একটি [GitHub আলোচনা](https://github.com/langgenius/dify/discussions) শুরু করুন বা বিদ্যমান আলোচনায় যোগ দিন।
- **অনুবাদ**: কোনো লোকেল যোগ বা হালনাগাদ করতে [আন্তর্জাতিকীকরণ নির্দেশিকা](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) অনুসরণ করুন।
- **অনুবাদ**: কোনো লোকেল যোগ বা হালনাগাদ করতে [আন্তর্জাতিকীকরণ নির্দেশিকা](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) অনুসরণ করুন।
- **কমিউনিটি**: আপনার তৈরি অ্যাপ শেয়ার করুন, অন্য ব্যবহারকারীদের সাহায্য করুন এবং Dify সম্পর্কে সবাইকে জানান।
### অবদানকারীরা

View File

@@ -144,7 +144,7 @@ Dify freut sich über Beiträge jeder Art:
- **Code**: Lesen Sie den [Contribution Guide](./CONTRIBUTING.md) und stöbern Sie anschließend in den [Good First Issues](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Ideen und Feedback**: Starten Sie eine [GitHub-Diskussion](https://github.com/langgenius/dify/discussions) oder beteiligen Sie sich an einer bestehenden.
- **Übersetzungen**: Folgen Sie dem [Internationalisierungsleitfaden](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md), um eine Sprache hinzuzufügen oder zu aktualisieren.
- **Übersetzungen**: Folgen Sie dem [Internationalisierungsleitfaden](https://github.com/langgenius/dify/blob/main/web/i18n/README.md), um eine Sprache hinzuzufügen oder zu aktualisieren.
- **Community**: Teilen Sie Ihre Apps, helfen Sie anderen Nutzern und machen Sie Dify bekannter.
### Mitwirkende

View File

@@ -140,7 +140,7 @@ Dify acepta contribuciones de todo tipo:
- **Código**: Lee la [Guía de contribución](./CONTRIBUTING.md) y consulta las [incidencias para principiantes](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Ideas y comentarios**: Inicia o únete a una [discusión en GitHub](https://github.com/langgenius/dify/discussions).
- **Traducciones**: Sigue la [guía de internacionalización](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) para añadir o actualizar un idioma.
- **Traducciones**: Sigue la [guía de internacionalización](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) para añadir o actualizar un idioma.
- **Comunidad**: Comparte las aplicaciones que crees, ayuda a otros usuarios y da a conocer Dify.
### Contribuidores

View File

@@ -140,7 +140,7 @@ Dify accueille les contributions de toutes sortes :
- **Code** : consultez le [guide de contribution](./CONTRIBUTING.md), puis parcourez les [issues accessibles aux nouveaux contributeurs](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Idées et retours** : lancez ou rejoignez une [discussion GitHub](https://github.com/langgenius/dify/discussions).
- **Traductions** : suivez le [guide d’internationalisation](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) pour ajouter ou mettre à jour une langue.
- **Traductions** : suivez le [guide d’internationalisation](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) pour ajouter ou mettre à jour une langue.
- **Communauté** : partagez les applications que vous créez, aidez les autres utilisateurs et faites connaître Dify.
### Contributeurs

View File

@@ -146,7 +146,7 @@ Dify सभी प्रकार के योगदानों का स्
- **कोड**: [Contribution Guide](./CONTRIBUTING.md) पढ़ें, फिर [नए योगदानकर्ताओं के लिए उपयुक्त issues](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) देखें।
- **विचार और प्रतिक्रिया**: [GitHub Discussion](https://github.com/langgenius/dify/discussions) शुरू करें या किसी मौजूदा चर्चा में शामिल हों।
- **अनुवाद**: किसी locale को जोड़ने या अपडेट करने के लिए [internationalization guide](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) का पालन करें।
- **अनुवाद**: किसी locale को जोड़ने या अपडेट करने के लिए [internationalization guide](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) का पालन करें।
- **समुदाय**: अपने बनाए हुए ऐप साझा करें, अन्य उपयोगकर्ताओं की मदद करें और Dify के बारे में लोगों को बताएं।
### योगदानकर्ता

View File

@@ -144,7 +144,7 @@ Dify accoglie contributi di ogni tipo:
- **Codice**: leggi la [Guida ai contributi](../../CONTRIBUTING.md), quindi consulta le [issue adatte ai nuovi contributori](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Idee e feedback**: avvia o partecipa a una [discussione su GitHub](https://github.com/langgenius/dify/discussions).
- **Traduzioni**: segui la [guida all’internazionalizzazione](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) per aggiungere o aggiornare una lingua.
- **Traduzioni**: segui la [guida all’internazionalizzazione](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) per aggiungere o aggiornare una lingua.
- **Community**: condividi le app che crei, aiuta gli altri utenti e fai conoscere Dify.
### Collaboratori

View File

@@ -141,7 +141,7 @@ Difyでは、あらゆる形の貢献を歓迎しています。
- **コード**:[コントリビューションガイド](./CONTRIBUTING.md)を読み、[good first issue](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)を確認してください。
- **アイデアとフィードバック**:[GitHub Discussions](https://github.com/langgenius/dify/discussions)で新しい議論を始めるか、既存の議論に参加してください。
- **翻訳**:言語の追加や更新については、[国際化ガイド](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md)に従ってください。
- **翻訳**:言語の追加や更新については、[国際化ガイド](https://github.com/langgenius/dify/blob/main/web/i18n/README.md)に従ってください。
- **コミュニティ**:作成したアプリを共有し、他のユーザーを支援し、Difyを広めてください。
### 貢献者

View File

@@ -134,7 +134,7 @@ Dify는 모든 형태의 기여를 환영합니다.
- **코드**: [기여 가이드](./CONTRIBUTING.md)를 읽고 [good first issue](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)를 살펴보세요.
- **아이디어 및 피드백**: [GitHub 토론](https://github.com/langgenius/dify/discussions)을 시작하거나 기존 토론에 참여하세요.
- **번역**: 언어를 추가하거나 업데이트하려면 [국제화 가이드](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md)를 따르세요.
- **번역**: 언어를 추가하거나 업데이트하려면 [국제화 가이드](https://github.com/langgenius/dify/blob/main/web/i18n/README.md)를 따르세요.
- **커뮤니티**: 만든 앱을 공유하고, 다른 사용자를 돕고, Dify를 널리 알려주세요.
### 기여자

View File

@@ -139,7 +139,7 @@ O Dify aceita contribuições de todos os tipos:
- **Código**: leia o [Guia de Contribuição](./CONTRIBUTING.md) e consulte as [issues para iniciantes](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Ideias e feedback**: inicie ou participe de uma [discussão no GitHub](https://github.com/langgenius/dify/discussions).
- **Traduções**: siga o [guia de internacionalização](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) para adicionar ou atualizar um idioma.
- **Traduções**: siga o [guia de internacionalização](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) para adicionar ou atualizar um idioma.
- **Comunidade**: compartilhe os aplicativos que você criar, ajude outros usuários e divulgue o Dify.
### Contribuidores

View File

@@ -141,7 +141,7 @@ Dify pozdravlja vse vrste prispevkov:
- **Koda**: preberite [vodnik za prispevke](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md), nato pa preglejte [naloge za nove sodelavce](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Ideje in povratne informacije**: začnite ali se pridružite [razpravi na GitHubu](https://github.com/langgenius/dify/discussions).
- **Prevodi**: sledite [vodniku za internacionalizacijo](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md), da dodate ali posodobite jezik.
- **Prevodi**: sledite [vodniku za internacionalizacijo](https://github.com/langgenius/dify/blob/main/web/i18n/README.md), da dodate ali posodobite jezik.
- **Skupnost**: delite ustvarjene aplikacije, pomagajte drugim uporabnikom in razširite glas o Difyju.
### Sodelavci

View File

@@ -140,7 +140,7 @@ Dify welcomes contributions of all kinds:
- **Code**: Read the [Contribution Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md), then browse [good first issues](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Ideas and feedback**: Start or join a [GitHub Discussion](https://github.com/langgenius/dify/discussions).
- **Translations**: Follow the [internationalization guide](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) to add or update a locale.
- **Translations**: Follow the [internationalization guide](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) to add or update a locale.
- **Community**: Share the apps you build, help other users, and spread the word about Dify.
### Contributors

View File

@@ -134,7 +134,7 @@ Dify her türlü katkıyı memnuniyetle karşılar:
- **Kod**: [Katkı Kılavuzu'nu](./CONTRIBUTING.md) okuyun, ardından [yeni katkıda bulunanlara uygun sorunlara](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) göz atın.
- **Fikirler ve geri bildirim**: Bir [GitHub tartışması](https://github.com/langgenius/dify/discussions) başlatın veya mevcut bir tartışmaya katılın.
- **Çeviriler**: Bir dil eklemek veya güncellemek için [uluslararasılaştırma kılavuzunu](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) izleyin.
- **Çeviriler**: Bir dil eklemek veya güncellemek için [uluslararasılaştırma kılavuzunu](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) izleyin.
- **Topluluk**: Oluşturduğunuz uygulamaları paylaşın, diğer kullanıcılara yardımcı olun ve Dify'ı duyurun.
### Katkıda bulunanlar

View File

@@ -135,7 +135,7 @@ Dify chào đón mọi hình thức đóng góp:
- **Mã nguồn**: đọc [Hướng dẫn đóng góp](./CONTRIBUTING.md), sau đó xem các [issue phù hợp cho người mới](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22).
- **Ý tưởng và phản hồi**: bắt đầu hoặc tham gia một [thảo luận trên GitHub](https://github.com/langgenius/dify/discussions).
- **Bản dịch**: làm theo [hướng dẫn quốc tế hóa](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md) để thêm hoặc cập nhật một ngôn ngữ.
- **Bản dịch**: làm theo [hướng dẫn quốc tế hóa](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) để thêm hoặc cập nhật một ngôn ngữ.
- **Cộng đồng**: chia sẻ ứng dụng bạn xây dựng, hỗ trợ người dùng khác và giới thiệu Dify đến nhiều người hơn.
### Người đóng góp

View File

@@ -147,7 +147,7 @@ Dify 欢迎各种形式的贡献:
- **代码**:阅读[贡献指南](./CONTRIBUTING.md),然后浏览[适合新手的问题](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)。
- **想法与反馈**:发起或加入 [GitHub Discussions](https://github.com/langgenius/dify/discussions)。
- **翻译**:按照[国际化指南](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md)添加或更新语言。
- **翻译**:按照[国际化指南](https://github.com/langgenius/dify/blob/main/web/i18n/README.md)添加或更新语言。
- **社区**:分享您构建的应用、帮助其他用户,并向更多人介绍 Dify。
### 贡献者

View File

@@ -145,7 +145,7 @@ Dify 歡迎各種形式的貢獻:
- **程式碼**:閱讀[貢獻指南](./CONTRIBUTING.md),再瀏覽[適合新手的議題](https://github.com/langgenius/dify/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)。
- **想法與意見**:發起或加入 [GitHub Discussions](https://github.com/langgenius/dify/discussions)。
- **翻譯**:依照[國際化指南](https://github.com/langgenius/dify/blob/main/web/i18n-config/README.md)新增或更新語言。
- **翻譯**:依照[國際化指南](https://github.com/langgenius/dify/blob/main/web/i18n/README.md)新增或更新語言。
- **社群**:分享您建立的應用程式、協助其他使用者,並向更多人介紹 Dify。
### 貢獻者

View File

@@ -436,7 +436,7 @@ export default defineConfig([
},
},
{
files: ['web/i18n/**/*.json'],
files: ['web/i18n/locales/**/*.json'],
plugins: {
dify,
},

View File

@@ -33,7 +33,7 @@ const config: KnipConfig = {
'!vitest.setup.ts!',
],
ignore: ['public/**'],
ignoreFiles: ['i18n-config/locale-resources/*.ts'],
ignoreFiles: ['i18n/locale-resources/*.ts'],
ignoreDependencies: ['@iconify-json/*', '@storybook/addon-onboarding'],
},
},

View File

@@ -5163,7 +5163,7 @@
"count": 4
}
},
"web/i18n-config/index.ts": {
"web/i18n/index.ts": {
"no-barrel-files/no-barrel-files": {
"count": 1
}

View File

@@ -4,7 +4,7 @@ import { ToastHost } from '@langgenius/dify-ui/toast'
import { withThemeByDataAttribute } from '@storybook/addon-themes'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { I18nClientProvider as I18N } from '../app/components/provider/i18n'
import commonEnUS from '../i18n/en-US/common.json'
import commonEnUS from '../i18n/locales/en-US/common.json'
import '../app/styles/markdown.css'
import './storybook.css'

View File

@@ -10,7 +10,7 @@ Web owns application-specific requirements and consumes shared architecture guid
- For truncated text disclosure and native `title` decisions, follow [Truncated Text Disclosure].
- When adding or changing page layouts, navigation, or landmark elements, follow [Page landmarks] and inspect the composed page, including parent layouts.
- User-facing strings must use `web/i18n/en-US/` keys. When adding or renaming a key, update every supported locale with the correct localized value.
- User-facing strings must use `web/i18n/locales/en-US/` keys. When adding or renaming a key, update every supported locale with the correct localized value.
- For new backend calls and migrated surfaces, use generated `consoleQuery` / `consoleClient` APIs from `@/service/console`. Do not add handwritten REST helpers or DTO mirrors, mock-backed app state, or direct edits to generated contracts.
- Prefer `@langgenius/dify-ui/*` primitives, data attributes, and design tokens. Use the [Dify UI package index] to find a primitive; read the relevant contract directly when it is already known. Preserve a visible focus indicator on the final focusable element.
- Reuse the Web `SearchInput` composite when its search, clear, and IME contract matches the feature; otherwise follow the canonical [Input Group contract].

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
const I18N_DIR = path.join(__dirname, '../i18n')
const I18N_DIR = path.join(__dirname, '../i18n/locales')
const REQUIRED_APP_STAR_KEYS = [
'studio.allApps',

View File

@@ -7,7 +7,7 @@ import fs from 'node:fs'
import path from 'node:path'
// Get all supported locales from the i18n directory
const I18N_DIR = path.join(__dirname, '../i18n')
const I18N_DIR = path.join(__dirname, '../i18n/locales')
const getSupportedLocales = (): string[] => {
return fs
.readdirSync(I18N_DIR)

View File

@@ -1,4 +1,4 @@
import type { Locale } from '@/i18n-config'
import type { Locale } from '@/i18n'
import AppAccessConfigPage from '@/app/components/app/access-config'
export type AccessConfigPageProps = {

View File

@@ -6,8 +6,8 @@ import { generateMetadata as generateNewKnowledgeMetadata } from '../new/create/
vi.mock('server-only', () => ({}))
vi.mock('@/i18n-config/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n-config/server')>()),
vi.mock('@/i18n/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n/server')>()),
getLocaleOnServer: async () => 'en-US',
}))

View File

@@ -6,8 +6,8 @@ vi.mock('@/app/components/integrations', () => ({
default: () => null,
}))
vi.mock('@/i18n-config/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n-config/server')>()),
vi.mock('@/i18n/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n/server')>()),
getLocaleOnServer: async () => 'en-US',
}))

View File

@@ -2,7 +2,7 @@ import type { PropsWithChildren } from 'react'
import type { IntegrationSection } from '@/app/components/integrations/routes'
import type { Metadata } from '@/next'
import { getIntegrationRouteTargetBySlug } from '@/app/components/integrations/routes'
import { getLocaleOnServer, getTranslation } from '@/i18n-config/server'
import { getLocaleOnServer, getTranslation } from '@/i18n/server'
type IntegrationsRouteLayoutProps = PropsWithChildren<{
params: Promise<{

View File

@@ -1,7 +1,7 @@
import { loadCreatorProfile } from '@/app/components/plugins/marketplace/creator-profile/data.server'
import DifyCreatorProfile from '@/app/components/plugins/marketplace/creator-profile/dify-profile'
import MarketplaceInstallPermissionProvider from '@/app/components/plugins/marketplace/marketplace-install-permission-provider'
import { getLocaleOnServer } from '@/i18n-config/server'
import { getLocaleOnServer } from '@/i18n/server'
import { notFound } from '@/next/navigation'
type CreatorPageSearchParams = {

View File

@@ -3,8 +3,8 @@ import { generateMetadata } from '../page'
vi.mock('server-only', () => ({}))
vi.mock('@/i18n-config/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n-config/server')>()),
vi.mock('@/i18n/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n/server')>()),
getLocaleOnServer: async () => 'en-US',
}))

View File

@@ -63,7 +63,7 @@ vi.mock('@/app/components/plugins/marketplace/templates', () => ({
),
}))
vi.mock('@/i18n-config/server', () => ({
vi.mock('@/i18n/server', () => ({
getLocaleOnServer: () => Promise.resolve('en-US'),
}))

View File

@@ -2,7 +2,7 @@ import { MARKETPLACE_CONTAINER_ID } from '@/app/components/plugins/marketplace/c
import { EmbeddedTemplatesMarketplace } from '@/app/components/plugins/marketplace/templates'
import { TemplateDetailRouteProvider } from '@/app/components/plugins/marketplace/templates/template-detail-route'
import { parseTemplatesRoute } from '@/app/components/plugins/marketplace/templates/template-links'
import { getLocaleOnServer } from '@/i18n-config/server'
import { getLocaleOnServer } from '@/i18n/server'
import { redirect } from '@/next/navigation'
type TemplatesPageProps = {

View File

@@ -20,7 +20,7 @@ vi.mock('@/env', async (importOriginal) => {
}
})
vi.mock('@/i18n-config/server', () => ({
vi.mock('@/i18n/server', () => ({
getLocaleOnServer: async () => 'en-US',
}))

View File

@@ -18,8 +18,8 @@ import { generateMetadata as generateSignupSetPasswordMetadata } from '../signup
vi.mock('server-only', () => ({}))
vi.mock('@/i18n-config/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n-config/server')>()),
vi.mock('@/i18n/server', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n/server')>()),
getLocaleOnServer: async () => 'en-US',
}))

View File

@@ -11,7 +11,7 @@ import { useStore } from '@/app/components/app/store'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { userProfileQueryOptions } from '@/features/account-profile/client'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { getAccessControlTemplateLanguage } from '@/i18n-config/language'
import { getAccessControlTemplateLanguage } from '@/i18n/language'
import { RESOURCE_ACCESS_SETTINGS_PAGE_SIZE } from '@/service/access-control/constants'
import {
useAppAccessRules,

View File

@@ -1,9 +1,9 @@
import type { Mock } from 'vite-plus/test'
import type { Locale } from '@/i18n-config'
import type { Locale } from '@/i18n'
import { render, screen } from '@testing-library/react'
import * as React from 'react'
import { useLocale } from '#i18n'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import CSVDownload from '../csv-downloader'
vi.mock('#i18n', async (importOriginal) => ({

View File

@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
import { useCSVDownloader } from 'react-papaparse'
import { useLocale } from '#i18n'
import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
const CSV_TEMPLATE_QA_EN = [
['question', 'answer'],

View File

@@ -1,11 +1,11 @@
import type { ComponentProps } from 'react'
import type { Mock } from 'vite-plus/test'
import type { AnnotationItemBasic } from '../../type'
import type { Locale } from '@/i18n-config'
import type { Locale } from '@/i18n'
import { act, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useLocale } from '#i18n'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { clearAllAnnotations, fetchExportAnnotationList } from '@/service/annotation'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import HeaderOptions from '../index'

View File

@@ -16,7 +16,7 @@ import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { jsonToCSV } from 'react-papaparse'
import { useLocale } from '#i18n'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { clearAllAnnotations, fetchExportAnnotationList } from '@/service/annotation'
import { downloadBlob } from '@/utils/download'
import AddAnnotationModal from '../add-annotation-modal'

View File

@@ -17,7 +17,7 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { consoleQuery } from '@/service/console'
import ModelIcon from '../../header/account-setting/model-provider-page/model-icon'

View File

@@ -28,7 +28,7 @@ import { AuthCategory, PluginAuthInAgent } from '@/app/components/plugins/plugin
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
import { CollectionType } from '@/app/components/tools/types'
import { toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
import { getPluginLanguage } from '@/i18n-config/metadata'
import { getPluginLanguage } from '@/i18n/metadata'
import {
fetchBuiltInToolList,
fetchCustomToolList,

View File

@@ -6,8 +6,8 @@ import GetAutomaticRes from '../get-automatic-res'
vi.mock('react-i18next', async () => {
const { createReactI18nextMock } = await import('@/test/i18n-mock')
const { default: appDebug } = await import('@/i18n/en-US/app-debug.json')
const { default: common } = await import('@/i18n/en-US/common.json')
const { default: appDebug } = await import('@/i18n/locales/en-US/app-debug.json')
const { default: common } = await import('@/i18n/locales/en-US/common.json')
return createReactI18nextMock({ ...appDebug, ...common })
})

View File

@@ -8,16 +8,6 @@ import { render } from '@/test/console/render'
import { RETRIEVE_METHOD } from '@/types/app'
import SelectDataSet from '../index'
vi.mock('@/i18n-config/i18next-config', () => ({
default: {
changeLanguage: vi.fn(),
addResourceBundle: vi.fn(),
use: vi.fn().mockReturnThis(),
init: vi.fn(),
addResource: vi.fn(),
hasResourceBundle: vi.fn().mockReturnValue(true),
},
}))
const mockUseInfiniteScroll = vi.fn()
vi.mock('ahooks', async (importOriginal) => {
const actual = await importOriginal()

View File

@@ -1,6 +1,6 @@
import type { I18nText } from '@/i18n-config/language'
import type { I18nText } from '@/i18n/language'
import type { CodeBasedExtensionItem } from '@/models/common'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { withSelectorKey } from '@/test/i18n-mock'
import {
buildProviders,

View File

@@ -1,7 +1,7 @@
import type { SelectorTranslate } from '@/app/components/app/configuration/utils'
import type { CodeBasedExtensionItem, ExternalDataTool } from '@/models/common'
import { getStringSelectorTranslate } from '@/app/components/app/configuration/utils'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
const systemTypes = ['api'] as const

View File

@@ -16,7 +16,7 @@ import { LoadingPlaceholder } from '@/app/components/base/loading-placeholder'
import { getEnterpriseDocUrl } from '@/context/i18n'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { userProfileQueryOptions } from '@/features/account-profile/client'
import { getDocLanguage } from '@/i18n-config/language'
import { getDocLanguage } from '@/i18n/language'
import dynamic from '@/next/dynamic'
import { AppModeEnum } from '@/types/app'
import { getAppACLCapabilities } from '@/utils/permission'

View File

@@ -44,7 +44,7 @@ import {
pricingQueryParser,
} from '@/app/components/billing/pricing/query-params'
import { deploymentEditionAtom } from '@/features/system-features/state'
import { languages } from '@/i18n-config/language'
import { languages } from '@/i18n/language'
import Link from '@/next/link'
import { consoleQuery } from '@/service/console'
import { AppModeEnum } from '@/types/app'

View File

@@ -24,7 +24,7 @@ vi.mock('@/hooks/use-app-favicon', () => ({
useAppFavicon: vi.fn(),
}))
vi.mock('@/i18n-config/client', () => ({
vi.mock('@/i18n/client', () => ({
changeLanguage: vi.fn().mockResolvedValue(undefined),
}))

View File

@@ -16,7 +16,7 @@ import { getProcessedFilesFromResponse } from '@/app/components/base/file-upload
import { InputVarType } from '@/app/components/workflow/types'
import { useWebAppStore } from '@/context/web-app-context'
import { useAppFavicon } from '@/hooks/use-app-favicon'
import { changeLanguage } from '@/i18n-config/client'
import { changeLanguage } from '@/i18n/client'
import {
AppSourceType,
delConversation,

View File

@@ -1,12 +1,12 @@
import type { ThoughtItem } from '@/app/components/base/chat/chat/type'
import type { ChatItem } from '@/app/components/base/chat/types'
import type { Locale } from '@/i18n-config'
import type { Locale } from '@/i18n'
import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from '@langgenius/dify-ui/collapsible'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FileList } from '@/app/components/base/file-uploader'
import { Markdown } from '@/app/components/base/markdown'
import { getPluginLanguage, renderI18nObject } from '@/i18n-config/metadata'
import { getPluginLanguage, renderI18nObject } from '@/i18n/metadata'
type AgentRosterResponseContentProps = {
item: ChatItem

View File

@@ -1,5 +1,5 @@
import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types'
import type { Locale } from '@/i18n-config/locale'
import type { Locale } from '@/i18n/locale'
import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
import { InputVarType, SupportUploadFileTypes } from '@/app/components/workflow/types'
import { TransferMethod } from '@/types/app'

View File

@@ -2,7 +2,7 @@ import type { ButtonProps } from '@langgenius/dify-ui/button'
import type { HumanInputFieldValue } from './field-renderer'
import type { FileEntity } from '@/app/components/base/file-uploader/types'
import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types'
import type { Locale } from '@/i18n-config'
import type { Locale } from '@/i18n'
import type { HumanInputResolvedValue } from '@/types/workflow'
import dayjs from 'dayjs'
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'

View File

@@ -27,7 +27,7 @@ type InputForm = {
hide?: boolean
}
vi.mock('@/i18n-config/client', () => ({
vi.mock('@/i18n/client', () => ({
changeLanguage: vi.fn().mockResolvedValue(undefined),
}))
@@ -693,7 +693,7 @@ describe('useEmbeddedChatbot', () => {
describe('Language settings', () => {
it('should set language from URL parameters', async () => {
window.history.replaceState({}, '', '/?locale=zh-Hans')
const { changeLanguage } = await import('@/i18n-config/client')
const { changeLanguage } = await import('@/i18n/client')
await renderWithClient(() => useEmbeddedChatbot(AppSourceType.webApp))
@@ -703,7 +703,7 @@ describe('useEmbeddedChatbot', () => {
it('should set language from system variables when URL param is missing', async () => {
mockGetProcessedSystemVariablesFromUrlParams.mockResolvedValue({ locale: 'fr-FR' })
const { changeLanguage } = await import('@/i18n-config/client')
const { changeLanguage } = await import('@/i18n/client')
await renderWithClient(() => useEmbeddedChatbot(AppSourceType.webApp))
@@ -719,7 +719,7 @@ describe('useEmbeddedChatbot', () => {
default_language: 'ja-JP',
},
} as unknown as AppData
const { changeLanguage } = await import('@/i18n-config/client')
const { changeLanguage } = await import('@/i18n/client')
await renderWithClient(() => useEmbeddedChatbot(AppSourceType.webApp))

View File

@@ -1,6 +1,6 @@
import type { ChatConfig, ChatItem, OnFeedback } from '../types'
import type { InputValueTypes } from '@/app/components/share/text-generation/types'
import type { Locale } from '@/i18n-config'
import type { Locale } from '@/i18n'
import type { AppData, ConversationItem } from '@/models/share'
import { toast } from '@langgenius/dify-ui/toast'
import { noop } from 'es-toolkit/function'
@@ -11,7 +11,7 @@ import { useConversationSelection } from '@/app/components/base/chat/storage'
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
import { InputVarType } from '@/app/components/workflow/types'
import { useWebAppStore } from '@/context/web-app-context'
import { changeLanguage } from '@/i18n-config/client'
import { changeLanguage } from '@/i18n/client'
import { AppSourceType, updateFeedback } from '@/service/share'
import {
useInvalidateShareConversations,

View File

@@ -1,4 +1,4 @@
import type { I18nText } from '@/i18n-config/language'
import type { I18nText } from '@/i18n/language'
import type { CodeBasedExtensionForm } from '@/models/common'
import { fireEvent, render, screen } from '@testing-library/react'
import FormGeneration from '../form-generation'

View File

@@ -18,7 +18,7 @@ import {
settingsQueryParser,
} from '@/app/components/header/account-setting/query-params'
import { useDocLink } from '@/context/i18n'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { useCodeBasedExtensions, useModelProviderDetails } from '@/service/use-common'
import FormGeneration from './form-generation'
import ModerationContent from './moderation-content'

View File

@@ -6,7 +6,7 @@ import { TtsAutoPlay } from '@/types/app'
import { FeaturesProvider } from '../../../context'
import TextToSpeech from '../index'
vi.mock('@/i18n-config/language', () => ({
vi.mock('@/i18n/language', () => ({
languages: [
{ value: 'en-US', name: 'English', example: 'Hello world' },
{ value: 'zh-Hans', name: '中文', example: '你好' },

View File

@@ -41,7 +41,7 @@ vi.mock('@/next/navigation', () => ({
useParams: () => ({}),
}))
vi.mock('@/i18n-config/language', () => ({
vi.mock('@/i18n/language', () => ({
get languages() {
return mockLanguages
},

View File

@@ -10,7 +10,7 @@ import FeatureCard from '@/app/components/base/features/new-feature-panel/featur
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
import { FeatureEnum } from '@/app/components/base/features/types'
import { TextToAudio } from '@/app/components/base/icons/src/vender/features'
import { languages } from '@/i18n-config/language'
import { languages } from '@/i18n/language'
import { TtsAutoPlay } from '@/types/app'
type Props = Readonly<{

View File

@@ -20,7 +20,7 @@ import { replace } from 'string-ts'
import { AudioBtn } from '@/app/components/base/audio-btn'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import { Infotip } from '@/app/components/base/infotip'
import { languages } from '@/i18n-config/language'
import { languages } from '@/i18n/language'
import { usePathname } from '@/next/navigation'
import { consoleQuery } from '@/service/console'
import { TtsAutoPlay } from '@/types/app'

View File

@@ -1,6 +1,6 @@
import type { AnyFormApi, FieldValidators } from '@tanstack/react-form'
import type { ForwardedRef, ReactNode } from 'react'
import type { Locale } from '@/i18n-config'
import type { Locale } from '@/i18n'
export type TypeWithI18N<T = string> = {
en_US: T

View File

@@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event'
import { createInstance } from 'i18next'
import { I18nextProvider } from 'react-i18next'
import { beforeEach, describe, expect, it, vi } from 'vite-plus/test'
import appApi from '@/i18n/en-US/app-api.json'
import appApi from '@/i18n/locales/en-US/app-api.json'
import { useParams, usePathname } from '@/next/navigation'
import AudioBtn from '../index'

View File

@@ -6,7 +6,7 @@ import ResizeHandle from '..'
vi.mock('react-i18next', async () => {
const { createReactI18nextMock } = await import('@/test/i18n-mock')
const { default: common } = await import('@/i18n/en-US/common.json')
const { default: common } = await import('@/i18n/locales/en-US/common.json')
return createReactI18nextMock(common)
})

View File

@@ -1,4 +1,4 @@
import type { Locale } from '@/i18n-config/locale'
import type { Locale } from '@/i18n/locale'
import { render, screen } from '@testing-library/react'
import { PricingFooter } from '../footer'

View File

@@ -1,4 +1,4 @@
import type { Locale } from '@/i18n-config/locale'
import type { Locale } from '@/i18n/locale'
import { useTranslation } from 'react-i18next'
import { useLocale } from '#i18n'
import Link from '@/next/link'

View File

@@ -12,7 +12,7 @@ import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { userProfileQueryOptions } from '@/features/account-profile/client'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { getAccessControlTemplateLanguage } from '@/i18n-config/language'
import { getAccessControlTemplateLanguage } from '@/i18n/language'
import { RESOURCE_ACCESS_SETTINGS_PAGE_SIZE } from '@/service/access-control/constants'
import {
useDatasetAccessRules,

View File

@@ -2,7 +2,7 @@ import { useSuspenseQuery } from '@tanstack/react-query'
import { useMemo } from 'react'
import { useLocale } from '#i18n'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { usePipelineTemplateList } from '@/service/use-pipeline'
import CreateCard from './create-card'
import TemplateCard from './template-card'

View File

@@ -31,7 +31,7 @@ vi.mock('@/service/use-common', () => ({
data: { allowed_extensions: ['pdf', 'docx', 'txt'] },
}),
}))
vi.mock('@/i18n-config/language', () => ({
vi.mock('@/i18n/language', () => ({
LanguagesSupported: ['en-US', 'zh-Hans'],
}))

View File

@@ -38,7 +38,7 @@ vi.mock('@/service/use-common', () => ({
useFileUploadConfig: () => ({ data: mockFileUploadConfig }),
useFileSupportTypes: () => ({ data: mockSupportTypes }),
}))
vi.mock('@/i18n-config/language', () => ({
vi.mock('@/i18n/language', () => ({
LanguagesSupported: ['en-US', 'zh-Hans'],
}))

View File

@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'
import { useLocale } from '#i18n'
import { getFileUploadErrorMessage } from '@/app/components/base/file-uploader/utils'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { upload } from '@/service/base'
import { useFileSupportTypes, useFileUploadConfig } from '@/service/use-common'
import { getFileExtension } from '@/utils/format'

View File

@@ -10,7 +10,7 @@ import { useLocale } from '#i18n'
import Divider from '@/app/components/base/divider'
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { DataSourceProvider } from '@/models/common'
import { ChunkingMode, ProcessMode } from '@/models/datasets'
import { useFetchDefaultProcessRule } from '@/service/knowledge/use-create-dataset'

View File

@@ -2,7 +2,7 @@ import type { ILanguageSelectProps } from '../index'
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { languages } from '@/i18n-config/language'
import { languages } from '@/i18n/language'
import LanguageSelect from '../index'
const supportedLanguages = languages.filter((language) => language.supported)

View File

@@ -11,7 +11,7 @@ import {
SelectValue,
} from '@langgenius/dify-ui/select'
import * as React from 'react'
import { languages } from '@/i18n-config/language'
import { languages } from '@/i18n/language'
export type ILanguageSelectProps = {
currentLanguage: string

View File

@@ -36,7 +36,7 @@ vi.mock('@/utils/format', () => ({
},
}))
// Mock i18n config
vi.mock('@/i18n-config/language', () => ({
vi.mock('@/i18n/language', () => ({
LanguagesSupported: ['en-US', 'zh-Hans'],
}))

View File

@@ -1,7 +1,7 @@
import type { ReactNode } from 'react'
import { render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vite-plus/test'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { ChunkingMode } from '@/models/datasets'
import CSVDownload from '../csv-downloader'

View File

@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
import { useCSVDownloader } from 'react-papaparse'
import { useLocale } from '#i18n'
import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general'
import { LanguagesSupported } from '@/i18n-config/language'
import { LanguagesSupported } from '@/i18n/language'
import { ChunkingMode } from '@/models/datasets'
const CSV_TEMPLATE_QA_EN = [

View File

@@ -3,7 +3,7 @@ import type { AppCategory } from '@/models/explore'
import { cn } from '@langgenius/dify-ui/cn'
import { RadioGroup, RadioItem } from '@langgenius/dify-ui/radio-group'
import { useTranslation } from 'react-i18next'
import exploreI18n from '@/i18n/en-US/explore.json'
import exploreI18n from '@/i18n/locales/en-US/explore.json'
type ICategoryProps = {
className?: string

View File

@@ -6,8 +6,8 @@ vi.mock('@/service/marketplace', () => ({
marketplaceQuery: { searchAdvanced: { queryOptions: serviceMocks.queryOptions } },
}))
vi.mock('@/i18n-config/metadata', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n-config/metadata')>()),
vi.mock('@/i18n/metadata', async (importOriginal) => ({
...(await importOriginal<typeof import('@/i18n/metadata')>()),
renderI18nObject: vi.fn((value: Record<string, string> | string, locale: string) =>
typeof value === 'string' ? value : value[locale] || value.en_US || '',
),

View File

@@ -2,7 +2,7 @@ import { registerCommands, unregisterCommands } from '../command-bus'
import { languageCommand } from '../language'
vi.mock('../command-bus')
vi.mock('@/i18n-config/language', () => ({
vi.mock('@/i18n/language', () => ({
languages: [
{ value: 'en-US', name: 'English', supported: true },
{ value: 'zh-Hans', name: '简体中文', supported: true },

View File

@@ -43,7 +43,7 @@ vi.mock('next-themes', () => ({
setTheme: mockSetTheme,
}),
}))
vi.mock('@/i18n-config/client', () => ({
vi.mock('@/i18n/client', () => ({
setLocaleOnClient: mockSetLocale,
}))
vi.mock('@/features/agent-v2/feature-flag', () => ({

View File

@@ -1,7 +1,7 @@
import type { CommandSearchResult } from '../types'
import type { SlashCommandHandler } from './types'
import { getI18n } from 'react-i18next'
import { languages } from '@/i18n-config/language'
import { languages } from '@/i18n/language'
import { registerCommands, unregisterCommands } from './command-bus'
// Language dependency types

View File

@@ -6,7 +6,7 @@ import { ENABLE_FEATURE_PREVIEW } from '@/config'
import { useDocLink } from '@/context/i18n'
import { isCurrentWorkspaceDatasetOperatorAtom } from '@/context/workspace-state'
import { isAgentV2Enabled } from '@/features/agent-v2/feature-flag'
import { setLocaleOnClient } from '@/i18n-config/client'
import { setLocaleOnClient } from '@/i18n/client'
import { accountCommand } from './account'
import { createCommand } from './create'
import { discordCommand } from './discord'

View File

@@ -1,6 +1,6 @@
import type { Plugin } from '../../plugins/types'
import type { ActionItem, PluginSearchResult } from './types'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { marketplaceQuery } from '@/service/marketplace'
import Icon from '../../plugins/card/base/card-icon'
import { getFormattedPlugin } from '../../plugins/marketplace/utils'

View File

@@ -15,7 +15,7 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocale } from '#i18n'
import { getEnterpriseDocUrl } from '@/context/i18n'
import { getDocLanguage } from '@/i18n-config/language'
import { getDocLanguage } from '@/i18n/language'
import PermissionPicker from './permission-picker'
export type PermissionSetModalMode = 'create' | 'edit' | 'view'

View File

@@ -10,7 +10,7 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocale } from '#i18n'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { getAccessControlTemplateLanguage } from '@/i18n-config/language'
import { getAccessControlTemplateLanguage } from '@/i18n/language'
import { consoleQuery } from '@/service/console'
import { hasPermission } from '@/utils/permission'
import AccessRuleSection from './access-rule-section'

View File

@@ -15,7 +15,7 @@ import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { currentWorkspaceAtom, isCurrentWorkspaceOwnerAtom } from '@/context/workspace-state'
import { userProfileQueryOptions } from '@/features/account-profile/client'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { getAccessControlTemplateLanguage, LanguagesSupported } from '@/i18n-config/language'
import { getAccessControlTemplateLanguage, LanguagesSupported } from '@/i18n/language'
import { useUpdateRolesOfMember } from '@/service/access-control/use-member-roles'
import { consoleQuery } from '@/service/console'
import { useMembers } from '@/service/use-common'

View File

@@ -18,7 +18,7 @@ import {
import { useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocale } from '#i18n'
import { getAccessControlTemplateLanguage } from '@/i18n-config/language'
import { getAccessControlTemplateLanguage } from '@/i18n/language'
import { useWorkspaceRoleList } from '@/service/access-control/use-workspace-roles'
type RoleSelectorProps = {

View File

@@ -9,7 +9,7 @@ import { memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocale } from '#i18n'
import { LoadingPlaceholder } from '@/app/components/base/loading-placeholder'
import { getAccessControlTemplateLanguage } from '@/i18n-config/language'
import { getAccessControlTemplateLanguage } from '@/i18n/language'
import { useRolesOfMember } from '@/service/access-control/use-member-roles'
import AssignRolesModal from '../assign-roles-modal'
import PermissionRoleChip from './permission-role-chip'

View File

@@ -22,7 +22,7 @@ import {
} from '@/app/components/plugins/marketplace/hooks'
import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { useModalContextSelector } from '@/context/modal-context'
import { getModelLanguage } from '@/i18n-config/metadata'
import { getModelLanguage } from '@/i18n/metadata'
import { fetchDefaultModal } from '@/service/common'
import { consoleQuery } from '@/service/console'
import { commonQueryKeys, modelProviderDetailsQueryOptions } from '@/service/use-common'

View File

@@ -8,7 +8,7 @@ import type { ModelSelectorProvider } from '../model-selector/types'
import { cn } from '@langgenius/dify-ui/cn'
import { OpenaiYellow } from '@/app/components/base/icons/src/public/llm'
import useTheme from '@/hooks/use-theme'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { Theme } from '@/types/app'
import { useLanguage } from '../hooks'

View File

@@ -1,7 +1,7 @@
import type { FC, PropsWithChildren } from 'react'
import type { ModelSelectorModel } from '../model-selector/types'
import { cn } from '@langgenius/dify-ui/cn'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { useLanguage } from '../hooks'
import ModelBadge from '../model-badge'
import FeatureIcon from '../model-selector/feature-icon'

View File

@@ -18,7 +18,7 @@ import { useCallback, useId, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useModalContext } from '@/context/modal-context'
import { useCredentialPermissions } from '@/hooks/use-credential-permissions'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { consoleQuery } from '@/service/console'
import { ConfigurationMethodEnum, ModelStatusEnum } from '../declarations'
import {

View File

@@ -21,7 +21,7 @@ import useRefreshPluginList from '@/app/components/plugins/install-plugin/hooks/
import useWorkspacePluginInstallPermission from '@/app/components/plugins/install-plugin/hooks/use-workspace-plugin-install-permission'
import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { consoleQuery } from '@/service/console'
import { fetchPluginInfoFromMarketPlace } from '@/service/plugins'
import { useInstallPackageFromMarketPlace } from '@/service/use-plugins'

View File

@@ -12,7 +12,7 @@ import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { useCredentialPermissions } from '@/hooks/use-credential-permissions'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { consoleQuery } from '@/service/console'
import { commonQueryKeys } from '@/service/use-common'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'

View File

@@ -4,7 +4,7 @@ import { cn } from '@langgenius/dify-ui/cn'
import { AnthropicDark, AnthropicLight } from '@/app/components/base/icons/src/public/llm'
import { Openai } from '@/app/components/base/icons/src/vender/other'
import useTheme from '@/hooks/use-theme'
import { renderI18nObject } from '@/i18n-config/metadata'
import { renderI18nObject } from '@/i18n/metadata'
import { Theme } from '@/types/app'
import { useLanguage } from '../hooks'

View File

@@ -9,7 +9,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocale } from '#i18n'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { getAccessControlTemplateLanguage } from '@/i18n-config/language'
import { getAccessControlTemplateLanguage } from '@/i18n/language'
import {
useCreateWorkspaceRole,
useUpdateWorkspaceRole,

Some files were not shown because too many files have changed in this diff Show More