diff --git a/.github/workflows/auto-i18n.yml b/.github/workflows/auto-i18n.yml new file mode 100644 index 0000000000..5797675347 --- /dev/null +++ b/.github/workflows/auto-i18n.yml @@ -0,0 +1,65 @@ +name: Auto I18N + +env: + API_KEY: ${{ secrets.TRANSLATE_API_KEY}} + MODEL: ${{ vars.MODEL || 'deepseek/deepseek-v3.1'}} + BASE_URL: ${{ vars.BASE_URL || 'https://api.ppinfra.com/openai'}} + +on: + pull_request: + types: [opened, synchronize, reopened] + workflow_dispatch: + +jobs: + auto-i18n: + runs-on: ubuntu-latest + name: Auto I18N + permissions: + contents: write + pull-requests: write + + steps: + - name: 🐈‍⬛ Checkout + uses: actions/checkout@v5 + with: + ref: ${{ github.event.pull_request.head.ref }} + + - name: 📦 Setting Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: 📦 Install dependencies in isolated directory + run: | + # 在临时目录安装依赖 + mkdir -p /tmp/translation-deps + cd /tmp/translation-deps + echo '{"dependencies": {"openai": "^5.12.2", "cli-progress": "^3.12.0", "tsx": "^4.20.3", "prettier": "^3.5.3", "prettier-plugin-sort-json": "^4.1.1"}}' > package.json + npm install --no-package-lock + + # 设置 NODE_PATH 让项目能找到这些依赖 + echo "NODE_PATH=/tmp/translation-deps/node_modules" >> $GITHUB_ENV + + - name: 🏃‍♀️ Translate + run: npx tsx scripts/auto-translate-i18n.ts + + - name: 🔍 Format + run: cd /tmp/translation-deps && npx prettier --write --config /home/runner/work/cherry-studio/cherry-studio/.prettierrc /home/runner/work/cherry-studio/cherry-studio/src/renderer/src/i18n/ + + - name: 🔄 Commit changes + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add . + git reset -- package.json yarn.lock # 不提交 package.json 和 yarn.lock 的更改 + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "fix(i18n): Auto update translations for PR #${{ github.event.pull_request.number }}" + fi + + - name: 🚀 Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ github.event.pull_request.head.ref }} diff --git a/src/main/utils/locales.ts b/src/main/utils/locales.ts index 9e8d9be839..397e69fd96 100644 --- a/src/main/utils/locales.ts +++ b/src/main/utils/locales.ts @@ -1,13 +1,13 @@ import EnUs from '../../renderer/src/i18n/locales/en-us.json' -import JaJP from '../../renderer/src/i18n/locales/ja-jp.json' -import RuRu from '../../renderer/src/i18n/locales/ru-ru.json' import ZhCn from '../../renderer/src/i18n/locales/zh-cn.json' import ZhTw from '../../renderer/src/i18n/locales/zh-tw.json' // Machine translation import elGR from '../../renderer/src/i18n/translate/el-gr.json' import esES from '../../renderer/src/i18n/translate/es-es.json' import frFR from '../../renderer/src/i18n/translate/fr-fr.json' +import JaJP from '../../renderer/src/i18n/translate/ja-jp.json' import ptPT from '../../renderer/src/i18n/translate/pt-pt.json' +import RuRu from '../../renderer/src/i18n/translate/ru-ru.json' const locales = Object.fromEntries( [ diff --git a/src/renderer/src/i18n/index.ts b/src/renderer/src/i18n/index.ts index da6b924af9..8257f36ad9 100644 --- a/src/renderer/src/i18n/index.ts +++ b/src/renderer/src/i18n/index.ts @@ -5,15 +5,15 @@ import { initReactI18next } from 'react-i18next' // Original translation import enUS from './locales/en-us.json' -import jaJP from './locales/ja-jp.json' -import ruRU from './locales/ru-ru.json' import zhCN from './locales/zh-cn.json' import zhTW from './locales/zh-tw.json' // Machine translation import elGR from './translate/el-gr.json' import esES from './translate/es-es.json' import frFR from './translate/fr-fr.json' +import jaJP from './translate/ja-jp.json' import ptPT from './translate/pt-pt.json' +import ruRU from './translate/ru-ru.json' const logger = loggerService.withContext('I18N') diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index bfaa971abd..627f57d9cc 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -4268,4 +4268,4 @@ "show_window": "Show Window", "visualization": "Visualization" } -} \ No newline at end of file +} diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 2bf63b81bd..b460ca1ae3 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -3925,7 +3925,7 @@ "aistudio_access_token": "星河社区访问令牌", "aistudio_url_label": "星河社区", "api_url": "API URL", - "serving_doc_url_label": "PaddleOCR 服务化部署文档", + "serving_doc_url_label": "PaddleOCR 服务化部署文档", "tip": "您可以参考 PaddleOCR 官方文档部署本地服务,或者在飞桨星河社区部署云服务。对于后一种情况,请填写星河社区访问令牌。" }, "system": { diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index ff61d5e29c..3075f4e44b 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -4268,4 +4268,4 @@ "show_window": "顯示視窗", "visualization": "視覺化" } -} \ No newline at end of file +} diff --git a/src/renderer/src/i18n/translate/README.md b/src/renderer/src/i18n/translate/README.md index 60e516f5c9..3e507e6360 100644 --- a/src/renderer/src/i18n/translate/README.md +++ b/src/renderer/src/i18n/translate/README.md @@ -1,2 +1,2 @@ -本目录文件使用`yarn update:i18n`机器翻译生成,请勿手动编辑。 -This directory contains machine translated files generated by `yarn update:i18n`. Please do not edit manually. +本目录文件使用 GitHub Workflow 自动翻译,无需人工维护 +Files in this directory are automatically translated using GitHub Workflow and require no manual maintenance diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index 63e84d7cc8..4513d00461 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -1085,7 +1085,7 @@ "status_preprocess_completed": "Η προεπεξεργασία ολοκληρώθηκε", "status_preprocess_failed": "Η προεπεξεργασία απέτυχε", "status_processing": "Επεξεργασία", - "subtitle_file": "[to be translated]:字幕文件", + "subtitle_file": "Υποτίτλων", "threshold": "Περιθώριο συνάφειας", "threshold_placeholder": "Δεν έχει ρυθμιστεί", "threshold_too_large_or_small": "Το περιθώριο δεν μπορεί να είναι μεγαλύτερο από 1 ή μικρότερο από 0", @@ -1099,7 +1099,7 @@ "url_placeholder": "Εισάγετε τη διεύθυνση, χωρίστε πολλαπλές διευθύνσεις με επιστροφή", "urls": "Διευθύνσεις", "videos": "βίντεο", - "videos_file": "[to be translated]:视频文件" + "videos_file": "Αρχείο βίντεο" }, "languages": { "arabic": "Αραβικά", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index 031e0a3575..f4f37f4bf1 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -1085,7 +1085,7 @@ "status_preprocess_completed": "Preprocesamiento completado", "status_preprocess_failed": "Error en el preprocesamiento", "status_processing": "Procesando", - "subtitle_file": "[to be translated]:字幕文件", + "subtitle_file": "Archivo de subtítulos", "threshold": "Umbral de coincidencia", "threshold_placeholder": "No configurado", "threshold_too_large_or_small": "El umbral no puede ser mayor que 1 o menor que 0", @@ -1099,7 +1099,7 @@ "url_placeholder": "Ingrese la URL, múltiples URLs separadas por enter", "urls": "URLs", "videos": "vídeo", - "videos_file": "[to be translated]:视频文件" + "videos_file": "video file" }, "languages": { "arabic": "Árabe", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index 6c0a6e5272..6e0e785db7 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -1085,7 +1085,7 @@ "status_preprocess_completed": "Prétraitement terminé", "status_preprocess_failed": "Échec du prétraitement", "status_processing": "En cours de traitement", - "subtitle_file": "[to be translated]:字幕文件", + "subtitle_file": "Fichier de sous-titres", "threshold": "Seuil de similarité", "threshold_placeholder": "Non défini", "threshold_too_large_or_small": "Le seuil ne peut pas être supérieur à 1 ou inférieur à 0", @@ -1099,7 +1099,7 @@ "url_placeholder": "Entrez l'URL, plusieurs URLs séparées par des sauts de ligne", "urls": "URLs", "videos": "vidéo", - "videos_file": "[to be translated]:视频文件" + "videos_file": "Fichier vidéo" }, "languages": { "arabic": "Arabe", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/translate/ja-jp.json similarity index 99% rename from src/renderer/src/i18n/locales/ja-jp.json rename to src/renderer/src/i18n/translate/ja-jp.json index 0d5577467a..052077ab9b 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/translate/ja-jp.json @@ -4268,4 +4268,4 @@ "show_window": "ウィンドウを表示", "visualization": "可視化" } -} \ No newline at end of file +} diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index d6a2e84d9e..835a26cc51 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -1085,7 +1085,7 @@ "status_preprocess_completed": "Pré-processamento concluído", "status_preprocess_failed": "Falha no pré-processamento", "status_processing": "Processando", - "subtitle_file": "[to be translated]:字幕文件", + "subtitle_file": "arquivo de legenda", "threshold": "Limite de correspondência", "threshold_placeholder": "Não definido", "threshold_too_large_or_small": "O limite não pode ser maior que 1 ou menor que 0", @@ -1099,7 +1099,7 @@ "url_placeholder": "Digite a URL, várias URLs separadas por enter", "urls": "URLs", "videos": "vídeo", - "videos_file": "[to be translated]:视频文件" + "videos_file": "Arquivo de vídeo" }, "languages": { "arabic": "Árabe", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/translate/ru-ru.json similarity index 99% rename from src/renderer/src/i18n/locales/ru-ru.json rename to src/renderer/src/i18n/translate/ru-ru.json index e8c61dd971..de8305320b 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/translate/ru-ru.json @@ -4268,4 +4268,4 @@ "show_window": "Показать окно", "visualization": "Визуализация" } -} \ No newline at end of file +}