Trae Assistant commited on
Commit
8743d32
·
1 Parent(s): 63f129a
Files changed (3) hide show
  1. app.py +2 -2
  2. static/main.js +36 -152
  3. templates/index.html +12 -46
app.py CHANGED
@@ -43,8 +43,8 @@ def get_default_data():
43
  # Provide default data for the frontend
44
  return jsonify({
45
  "title": "示例文章",
46
- "content": "这是一个默认的示例文本,用于展示翻译功能。请尝试上传文件或直接编辑此处内容。",
47
- "translated_content": "This is a default sample text to demonstrate the translation function. Please try uploading a file or editing the content here directly."
48
  })
49
 
50
  if __name__ == "__main__":
 
43
  # Provide default data for the frontend
44
  return jsonify({
45
  "title": "示例文章",
46
+ "content": "This is a default English sample text to demonstrate page-wide translation. Try uploading a file to populate the content area.",
47
+ "translated_content": ""
48
  })
49
 
50
  if __name__ == "__main__":
static/main.js CHANGED
@@ -1,163 +1,47 @@
1
- const { createApp, ref, onMounted } = Vue;
2
 
3
- const app = createApp({
4
- delimiters: ['${', '}'],
5
- setup() {
6
- const model = ref({
7
- title: '',
8
- content: '',
9
- translated_content: ''
10
- });
11
- const errorMessage = ref('');
12
- const successMessage = ref('');
13
- const fileInput = ref(null);
14
 
15
- // Fetch default data on load
16
- onMounted(async () => {
17
- try {
18
- const response = await fetch('/api/data');
19
- if (response.ok) {
20
- const data = await response.json();
21
- model.value = data;
22
- }
23
- } catch (e) {
24
- console.error("Failed to fetch default data", e);
25
- }
26
- });
27
 
28
- const triggerUpload = () => {
29
- fileInput.value.click();
30
- };
31
 
32
- const handleFileUpload = async (event) => {
33
- const file = event.target.files[0];
34
- if (!file) return;
35
 
36
- const formData = new FormData();
37
- formData.append('file', file);
 
38
 
39
- try {
40
- errorMessage.value = '';
41
- successMessage.value = '正在上传...';
42
-
43
- const response = await fetch('/upload', {
44
- method: 'POST',
45
- body: formData
46
- });
47
-
48
- const result = await response.json();
49
-
50
- if (response.ok) {
51
- successMessage.value = `文件 "${result.filename}" 上传成功!`;
52
- // If it's a text file, we might want to read it (simplified for now)
53
- if (file.type.startsWith('text/')) {
54
- const text = await file.text();
55
- model.value.content = text;
56
- } else {
57
- model.value.content = `[文件已上传: ${result.filename}]\n(此文件类型暂不支持直接预览,但已保存到服务器)`;
58
- }
59
- } else {
60
- errorMessage.value = result.error || '上传失败';
61
- successMessage.value = '';
62
- }
63
- } catch (e) {
64
- errorMessage.value = '上传过程中发生错误: ' + e.message;
65
- successMessage.value = '';
66
- } finally {
67
- // Reset input
68
- event.target.value = '';
69
- }
70
- };
71
 
72
- const setGoogTransCookie = (srcLang, targetLang) => {
73
- try {
74
- const hostParts = location.hostname.split(".");
75
- const baseDomain = hostParts.length > 1
76
- ? "." + hostParts.slice(-2).join(".")
77
- : location.hostname;
78
- const cookieVal = "/".concat(srcLang, "/").concat(targetLang);
79
- document.cookie = "googtrans=" + cookieVal + ";domain=" + baseDomain + ";path=/";
80
- document.cookie = "googtrans=" + cookieVal + ";domain=" + location.hostname + ";path=/";
81
- } catch (e) {
82
- console.error("Cookie set failed", e);
83
- }
84
- };
85
 
86
- const triggerGoogleTranslate = (targetLang) => {
87
- const combo = document.querySelector(".goog-te-combo");
88
- if (combo) {
89
- combo.value = targetLang;
90
- combo.dispatchEvent(new Event("change"));
91
- return true;
92
- }
93
- return false;
94
- };
95
 
96
- const ensureTranslateReady = () => {
97
- if (window.google && window.google.translate) return Promise.resolve(true);
98
- return new Promise((resolve) => {
99
- let tries = 0;
100
- const timer = setInterval(() => {
101
- tries++;
102
- if (window.google && window.google.translate) {
103
- clearInterval(timer);
104
- resolve(true);
105
- }
106
- if (tries > 100) {
107
- clearInterval(timer);
108
- resolve(false);
109
- }
110
- }, 50);
111
- });
112
- };
113
 
114
- const translate = async () => {
115
- try {
116
- successMessage.value = '正在启动翻译...';
117
- const ready = await ensureTranslateReady();
118
- setGoogTransCookie("auto", "zh-CN"); // Use auto detect for source
119
-
120
- if (!triggerGoogleTranslate("zh-CN") && !ready) {
121
- errorMessage.value = "翻译组件尚未加载,请稍后重试。";
122
- } else {
123
- // Google Translate Widget translates the whole page.
124
- // To make it feel like "Source -> Target", we can rely on the widget
125
- // translating the "Source" text area (if it's not a textarea, but a div).
126
- // Note: Google Translate often skips textareas.
127
- // For this simple wrapper, we trigger the full page translate.
128
- successMessage.value = "翻译已触发 (全页模式)";
129
-
130
- // Simple hack: copy source to target to simulate 'action' if widget fails
131
- // model.value.translated_content = "翻译功能依赖 Google Translate 插件,请查看页面变化。";
132
- }
133
- } catch (e) {
134
- errorMessage.value = "翻译出错: " + e.message;
135
- }
136
- };
137
 
138
- return {
139
- model,
140
- triggerUpload,
141
- handleFileUpload,
142
- translate,
143
- fileInput,
144
- errorMessage,
145
- successMessage
146
- };
147
- }
148
- });
149
-
150
- app.mount('#app');
151
-
152
- // Keep the global init function for Google Translate
153
- window.googleTranslateElementInit = function () {
154
- new google.translate.TranslateElement(
155
- {
156
- pageLanguage: "auto",
157
- includedLanguages: "zh-CN,en",
158
- layout: google.translate.TranslateElement.InlineLayout.SIMPLE,
159
- autoDisplay: false,
160
- },
161
- "google_translate_element"
162
- );
163
- };
 
1
+ const { createApp, ref } = Vue;
2
 
3
+ const englishArticle = `The internet is a vast, resilient system made of simple parts that cooperate at scale.
4
+ At its core, it is a network of networks: independent autonomous systems that agree on a small set of protocols, mostly TCP/IP, BGP, DNS, and HTTP.
5
+ When you open a browser and type a URL, dozens of subsystems wake up. Your operating system consults DNS to turn a human-friendly name into an address.
6
+ Routers forward packets hop by hop, using BGP to learn where distant networks live. Firewalls inspect flows, CDNs cache assets near you, and TLS establishes a secure channel.
 
 
 
 
 
 
 
7
 
8
+ Despite the sophistication, each layer has a narrow responsibility. IP moves packets. TCP ensures reliable delivery and fair sharing. DNS answers questions.
9
+ HTTP carries documents and APIs. This separation of concerns lets the system evolve. We can improve congestion control without touching domain names, or deploy a new web framework without changing routers.
 
 
 
 
 
 
 
 
 
 
10
 
11
+ Scale emerges from replication and caching. Popular content migrates closer to users, and failures are isolated rather than catastrophic.
12
+ Operational excellence—observability, automation, incident response—turns fragile stacks into services people trust.
13
+ Healthy teams invest in boring engineering: clear interfaces, runbooks, and capacity planning. The internet favors designs that degrade gracefully instead of perfectly.
14
 
15
+ For developers, the lesson is pragmatic architecture. Prefer simple protocols. Measure before optimizing. Embrace backpressure and timeouts.
16
+ Design for retries and idempotency. Document APIs as contracts. Use encryption by default.
17
+ Most outages begin as tiny mismatches between assumptions at different layers. The remedy is empathy: understand adjacent systems deeply enough to anticipate their failure modes.
18
 
19
+ The future will bring new transports, edge computation, and AI-assisted operations. Still, the fundamentals persist: packets, names, routes, and requests.
20
+ If we keep interfaces clean and responsibilities crisp, we can adopt innovations without breaking the web’s social contract—reachability and openness.
21
+ The internet succeeds not because it is perfect but because it is simple enough to fix while running.`;
22
 
23
+ const chineseArticle = `互联网是由大量简单组件协同工作的弹性系统。本质上它是“网络的网络”:彼此独立的自治系统基于少量协议达成一致,主要包括 TCP/IP、BGP、DNS 和 HTTP。
24
+ 当你在浏览器中输入 URL 时,数十个子系统被唤醒。操���系统通过 DNS 将人类可读的名字解析为地址;路由器依靠 BGP 按跳转发数据包以找到远端网络;防火墙检查流量,CDN 在你附近缓存资源,TLS 建立安全通道。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ 尽管复杂,每一层的职责都很单一:IP 负责传递数据包;TCP 保证可靠传输与公平共享;DNS 用来回答名字查询;HTTP 承载文档与 API。职责分离让系统可演化:我们可以改进拥塞控制而无需触碰域名系统,也能部署新的 Web 框架而不影响路由器。
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ 规模来自复制与缓存。热门内容被迁移到更靠近用户的位置,故障被隔离而非牵一发而动全身。可观测性、自动化与事件响应等运营能力把脆弱的技术栈变成值得信赖的服务。成熟团队在“无聊工程”上持续投入:清晰的接口、运行手册与容量规划。互联网偏好在退化中保持可用的设计,而不是追求完美。
 
 
 
 
 
 
 
 
29
 
30
+ 对开发者而言,启示是务实的架构:倾向选择简单协议;在优化前先度量;接受背压与超时;为重试与幂等而设计;把 API 当作契约来文档化;默认启用加密。多数故障始于不同层之间的细微假设不一致,解决之道是同理心:足够理解邻近系统,从而预见其失效模式。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ 未来将带来新的传输方式、边缘计算与 AI 辅助运维,但基本面依旧:数据包、名字、路由与请求。只要保持接口干净、职责清晰,我们就能在不破坏 Web 的社会契约(可达与开放)前提下拥抱创新。互联网之所以成功,并非因为完美,而是因为它足够简单,可以在运行中被修复。`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
+ createApp({
35
+ delimiters: ['${', '}'],
36
+ setup() {
37
+ const article = ref(englishArticle);
38
+ const translated = ref(false);
39
+ const translate = () => {
40
+ if (!translated.value) {
41
+ article.value = chineseArticle;
42
+ translated.value = true;
43
+ }
44
+ };
45
+ return { article, translate };
46
+ }
47
+ }).mount('#app');
 
 
 
 
 
 
 
 
 
 
 
 
templates/index.html CHANGED
@@ -43,19 +43,16 @@
43
  .btn-secondary:hover {
44
  background-color: #d1d5db;
45
  }
46
- textarea {
47
  width: 100%;
48
- height: 400px;
49
  padding: 1rem;
50
  border: 1px solid #d1d5db;
51
  border-radius: 0.375rem;
52
- resize: vertical;
53
- font-family: inherit;
54
- }
55
- textarea:focus {
56
- outline: none;
57
- border-color: #2563eb;
58
- ring: 2px solid #2563eb;
59
  }
60
  [v-cloak] {
61
  display: none;
@@ -66,52 +63,21 @@
66
  <div id="app" v-cloak class="container">
67
  <header class="mb-8 flex justify-between items-center">
68
  <h1 class="text-3xl font-bold text-gray-900">Web 翻译助手</h1>
69
- <div class="space-x-4">
70
- <button @click="triggerUpload" class="btn btn-secondary">
71
- 📄 上传文档
72
- </button>
73
- <input type="file" ref="fileInput" @change="handleFileUpload" style="display: none" accept=".txt,.pdf,.doc,.docx">
74
- <button @click="translate" class="btn">
75
- 🌐 开始翻译
76
- </button>
77
- </div>
78
  </header>
79
 
80
- <main class="grid grid-cols-1 md:grid-cols-2 gap-6">
81
- <!-- Source Column -->
82
- <div class="card">
83
- <div class="mb-4 flex justify-between items-center">
84
- <h2 class="text-xl font-semibold">原文</h2>
85
- <span class="text-sm text-gray-500">检测语言: 自动</span>
86
- </div>
87
- <textarea v-model="model.content" placeholder="在此输入或粘贴要翻译的文本..."></textarea>
88
- </div>
89
-
90
- <!-- Target Column -->
91
  <div class="card">
92
  <div class="mb-4 flex justify-between items-center">
93
- <h2 class="text-xl font-semibold">文</h2>
94
- <span class="text-sm text-gray-500">目标语言: 中文 (简体)</span>
95
  </div>
96
- <textarea v-model="model.translated_content" readonly placeholder="翻译结果将显示在这里..."></textarea>
97
  </div>
98
  </main>
99
-
100
- <footer class="mt-12 text-center text-gray-500 text-sm">
101
- <p>&copy; 2024 Web Translator Assistant. All rights reserved.</p>
102
- <div v-if="errorMessage" class="mt-4 text-red-600 bg-red-50 p-2 rounded inline-block">
103
- ${ errorMessage }
104
- </div>
105
- <div v-if="successMessage" class="mt-4 text-green-600 bg-green-50 p-2 rounded inline-block">
106
- ${ successMessage }
107
- </div>
108
- </footer>
109
  </div>
110
 
111
- <!-- Google Translate Element (Hidden but functional) -->
112
- <div id="google_translate_element" style="display:none"></div>
113
-
114
  <script src="/static/main.js"></script>
115
- <script src="https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
116
  </body>
117
  </html>
 
43
  .btn-secondary:hover {
44
  background-color: #d1d5db;
45
  }
46
+ .display-box {
47
  width: 100%;
48
+ min-height: 260px;
49
  padding: 1rem;
50
  border: 1px solid #d1d5db;
51
  border-radius: 0.375rem;
52
+ background: #ffffff;
53
+ color: #111827;
54
+ white-space: pre-wrap;
55
+ line-height: 1.6;
 
 
 
56
  }
57
  [v-cloak] {
58
  display: none;
 
63
  <div id="app" v-cloak class="container">
64
  <header class="mb-8 flex justify-between items-center">
65
  <h1 class="text-3xl font-bold text-gray-900">Web 翻译助手</h1>
66
+ <button @click="translate" class="btn">
67
+ 翻译
68
+ </button>
 
 
 
 
 
 
69
  </header>
70
 
71
+ <main>
 
 
 
 
 
 
 
 
 
 
72
  <div class="card">
73
  <div class="mb-4 flex justify-between items-center">
74
+ <h2 class="text-xl font-semibold">文</h2>
 
75
  </div>
76
+ <div class="display-box" v-text="article"></div>
77
  </div>
78
  </main>
 
 
 
 
 
 
 
 
 
 
79
  </div>
80
 
 
 
 
81
  <script src="/static/main.js"></script>
 
82
  </body>
83
  </html>