jackkuo commited on
Commit
22f238f
·
1 Parent(s): 72a404d

Add language switch on login page with English as default

Browse files
qa_annotate/html/auth.html CHANGED
@@ -3,17 +3,20 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>QA 标注系统 - 登录/注册</title>
7
  <link rel="stylesheet" href="/static/css/auth.css">
8
  </head>
9
  <body>
10
  <div class="container">
11
  <div class="auth-container">
12
  <div class="auth-header">
13
- <h1 data-i18n="auth.loginTitle">QA 标注系统</h1>
 
 
 
14
  <div class="tab-buttons">
15
- <button class="tab-btn active" data-tab="login" data-i18n="auth.login">登录</button>
16
- <button class="tab-btn" data-tab="register" data-i18n="auth.register">注册</button>
17
  </div>
18
  </div>
19
 
@@ -21,7 +24,7 @@
21
  <div class="form-container active" id="login-form">
22
  <form id="loginForm">
23
  <div class="form-group">
24
- <label for="login-username" data-i18n="auth.username">用户名</label>
25
  <input
26
  type="text"
27
  id="login-username"
@@ -31,11 +34,11 @@
31
  maxlength="50"
32
  value="admin"
33
  data-i18n-placeholder="auth.usernamePlaceholder"
34
- placeholder="请输入用户名"
35
  >
36
  </div>
37
  <div class="form-group">
38
- <label for="login-password" data-i18n="auth.password">密码</label>
39
  <div class="password-field">
40
  <input
41
  type="password"
@@ -45,15 +48,15 @@
45
  minlength="6"
46
  value="123456"
47
  data-i18n-placeholder="auth.passwordPlaceholder"
48
- placeholder="请输入密码"
49
  >
50
  <button
51
  type="button"
52
  class="password-toggle"
53
  id="login-password-toggle"
54
  data-i18n-aria-label="auth.showPassword"
55
- aria-label="显示密码"
56
- title="显示密码"
57
  >
58
  <svg class="icon-eye" viewBox="0 0 24 24" aria-hidden="true">
59
  <path d="M12 5C7 5 2.73 8.11 1 12c1.73 3.89 6 7 11 7s9.27-3.11 11-7c-1.73-3.89-6-7-11-7zm0 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8z" fill="currentColor"/>
@@ -65,7 +68,7 @@
65
  </div>
66
  </div>
67
  <div class="form-group">
68
- <button type="submit" class="btn btn-primary"><span data-i18n="auth.login">登录</span></button>
69
  <p class="demo-hint" data-i18n="auth.demoHint">Demo: Default admin credentials are pre-filled. Click Login to get started.</p>
70
  </div>
71
  <div class="message" id="login-message"></div>
@@ -76,7 +79,7 @@
76
  <div class="form-container" id="register-form">
77
  <form id="registerForm">
78
  <div class="form-group">
79
- <label for="register-username" data-i18n="auth.username">用户名</label>
80
  <input
81
  type="text"
82
  id="register-username"
@@ -85,11 +88,11 @@
85
  minlength="3"
86
  maxlength="50"
87
  data-i18n-placeholder="auth.usernamePlaceholderWithHint"
88
- placeholder="请输入用户名(3-50个字符)"
89
  >
90
  </div>
91
  <div class="form-group">
92
- <label for="register-password" data-i18n="auth.password">密码</label>
93
  <input
94
  type="password"
95
  id="register-password"
@@ -97,52 +100,52 @@
97
  required
98
  minlength="6"
99
  data-i18n-placeholder="auth.passwordPlaceholderWithHint"
100
- placeholder="请输入密码(至少6个字符)"
101
  >
102
  </div>
103
  <div class="form-group">
104
- <label for="register-fullname" data-i18n="auth.fullnameOptional">全名(可选)</label>
105
  <input
106
  type="text"
107
  id="register-fullname"
108
  name="full_name"
109
  maxlength="100"
110
  data-i18n-placeholder="auth.fullnamePlaceholder"
111
- placeholder="请输入全名"
112
  >
113
  </div>
114
  <div class="form-group">
115
- <label for="register-organization" data-i18n="auth.organizationOptional">单位(可选)</label>
116
  <select id="register-organization" name="organization">
117
- <option value="" data-i18n="auth.selectOrganization">请选择</option>
118
  <option value="崖州湾实验室">崖州湾实验室</option>
119
  <option value="之江实验室">之江实验室</option>
120
  </select>
121
  </div>
122
  <div class="form-group">
123
- <label for="register-team" data-i18n="auth.teamOptional">团队(可选)</label>
124
  <input
125
  type="text"
126
  id="register-team"
127
  name="team"
128
  maxlength="100"
129
  data-i18n-placeholder="auth.teamPlaceholder"
130
- placeholder="请输入团队"
131
  >
132
  </div>
133
  <div class="form-group">
134
- <label for="register-species" data-i18n="auth.speciesOptional">物种(可选)</label>
135
  <input
136
  type="text"
137
  id="register-species"
138
  name="species"
139
  maxlength="100"
140
  data-i18n-placeholder="auth.speciesPlaceholder"
141
- placeholder="请输入物种"
142
  >
143
  </div>
144
  <div class="form-group">
145
- <button type="submit" class="btn btn-primary"><span data-i18n="auth.register">注册</span></button>
146
  </div>
147
  <div class="message" id="register-message"></div>
148
  </form>
@@ -192,17 +195,39 @@
192
  };
193
 
194
  updatePageLanguage();
 
 
 
 
 
195
  } catch (error) {
196
  console.error('i18next 初始化失败:', error);
197
  }
198
  });
199
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  function updatePageLanguage() {
201
  if (!window.i18next) return;
202
 
203
  const lang = window.i18next.language;
204
  document.documentElement.lang = lang;
205
 
 
 
 
 
 
206
  // 更新所有带有 data-i18n 属性的元素
207
  document.querySelectorAll('[data-i18n]').forEach(element => {
208
  const key = element.getAttribute('data-i18n');
@@ -233,6 +258,14 @@
233
  element.setAttribute('title', window.i18next.t(key));
234
  });
235
 
 
 
 
 
 
 
 
 
236
  // 更新页面标题
237
  document.title = window.i18next.t('auth.loginTitle') + ' - ' + window.i18next.t('auth.login');
238
  }
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>QA Annotation System - Login</title>
7
  <link rel="stylesheet" href="/static/css/auth.css">
8
  </head>
9
  <body>
10
  <div class="container">
11
  <div class="auth-container">
12
  <div class="auth-header">
13
+ <button class="auth-lang-switch" id="languageSwitchBtn" type="button" title="Switch Language">
14
+ <span id="currentLanguage">English</span>
15
+ </button>
16
+ <h1 data-i18n="auth.loginTitle">QA Annotation System</h1>
17
  <div class="tab-buttons">
18
+ <button class="tab-btn active" data-tab="login" data-i18n="auth.login">Login</button>
19
+ <button class="tab-btn" data-tab="register" data-i18n="auth.register">Register</button>
20
  </div>
21
  </div>
22
 
 
24
  <div class="form-container active" id="login-form">
25
  <form id="loginForm">
26
  <div class="form-group">
27
+ <label for="login-username" data-i18n="auth.username">Username</label>
28
  <input
29
  type="text"
30
  id="login-username"
 
34
  maxlength="50"
35
  value="admin"
36
  data-i18n-placeholder="auth.usernamePlaceholder"
37
+ placeholder="Please enter username"
38
  >
39
  </div>
40
  <div class="form-group">
41
+ <label for="login-password" data-i18n="auth.password">Password</label>
42
  <div class="password-field">
43
  <input
44
  type="password"
 
48
  minlength="6"
49
  value="123456"
50
  data-i18n-placeholder="auth.passwordPlaceholder"
51
+ placeholder="Please enter password"
52
  >
53
  <button
54
  type="button"
55
  class="password-toggle"
56
  id="login-password-toggle"
57
  data-i18n-aria-label="auth.showPassword"
58
+ aria-label="Show password"
59
+ title="Show password"
60
  >
61
  <svg class="icon-eye" viewBox="0 0 24 24" aria-hidden="true">
62
  <path d="M12 5C7 5 2.73 8.11 1 12c1.73 3.89 6 7 11 7s9.27-3.11 11-7c-1.73-3.89-6-7-11-7zm0 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8z" fill="currentColor"/>
 
68
  </div>
69
  </div>
70
  <div class="form-group">
71
+ <button type="submit" class="btn btn-primary"><span data-i18n="auth.login">Login</span></button>
72
  <p class="demo-hint" data-i18n="auth.demoHint">Demo: Default admin credentials are pre-filled. Click Login to get started.</p>
73
  </div>
74
  <div class="message" id="login-message"></div>
 
79
  <div class="form-container" id="register-form">
80
  <form id="registerForm">
81
  <div class="form-group">
82
+ <label for="register-username" data-i18n="auth.username">Username</label>
83
  <input
84
  type="text"
85
  id="register-username"
 
88
  minlength="3"
89
  maxlength="50"
90
  data-i18n-placeholder="auth.usernamePlaceholderWithHint"
91
+ placeholder="Please enter username (3-50 characters)"
92
  >
93
  </div>
94
  <div class="form-group">
95
+ <label for="register-password" data-i18n="auth.password">Password</label>
96
  <input
97
  type="password"
98
  id="register-password"
 
100
  required
101
  minlength="6"
102
  data-i18n-placeholder="auth.passwordPlaceholderWithHint"
103
+ placeholder="Please enter password (at least 6 characters)"
104
  >
105
  </div>
106
  <div class="form-group">
107
+ <label for="register-fullname" data-i18n="auth.fullnameOptional">Full Name (optional)</label>
108
  <input
109
  type="text"
110
  id="register-fullname"
111
  name="full_name"
112
  maxlength="100"
113
  data-i18n-placeholder="auth.fullnamePlaceholder"
114
+ placeholder="Please enter full name"
115
  >
116
  </div>
117
  <div class="form-group">
118
+ <label for="register-organization" data-i18n="auth.organizationOptional">Organization (optional)</label>
119
  <select id="register-organization" name="organization">
120
+ <option value="" data-i18n="auth.selectOrganization">Please select</option>
121
  <option value="崖州湾实验室">崖州湾实验室</option>
122
  <option value="之江实验室">之江实验室</option>
123
  </select>
124
  </div>
125
  <div class="form-group">
126
+ <label for="register-team" data-i18n="auth.teamOptional">Team (optional)</label>
127
  <input
128
  type="text"
129
  id="register-team"
130
  name="team"
131
  maxlength="100"
132
  data-i18n-placeholder="auth.teamPlaceholder"
133
+ placeholder="Please enter team"
134
  >
135
  </div>
136
  <div class="form-group">
137
+ <label for="register-species" data-i18n="auth.speciesOptional">Species (optional)</label>
138
  <input
139
  type="text"
140
  id="register-species"
141
  name="species"
142
  maxlength="100"
143
  data-i18n-placeholder="auth.speciesPlaceholder"
144
+ placeholder="Please enter species"
145
  >
146
  </div>
147
  <div class="form-group">
148
+ <button type="submit" class="btn btn-primary"><span data-i18n="auth.register">Register</span></button>
149
  </div>
150
  <div class="message" id="register-message"></div>
151
  </form>
 
195
  };
196
 
197
  updatePageLanguage();
198
+
199
+ const langBtn = document.getElementById('languageSwitchBtn');
200
+ if (langBtn) {
201
+ langBtn.addEventListener('click', toggleLanguage);
202
+ }
203
  } catch (error) {
204
  console.error('i18next 初始化失败:', error);
205
  }
206
  });
207
 
208
+ function toggleLanguage() {
209
+ if (!window.i18next) return;
210
+
211
+ const currentLang = window.i18next.language;
212
+ const newLang = currentLang === 'zh-CN' ? 'en-US' : 'zh-CN';
213
+
214
+ window.i18next.changeLanguage(newLang, () => {
215
+ localStorage.setItem('appLanguage', newLang);
216
+ updatePageLanguage();
217
+ });
218
+ }
219
+
220
  function updatePageLanguage() {
221
  if (!window.i18next) return;
222
 
223
  const lang = window.i18next.language;
224
  document.documentElement.lang = lang;
225
 
226
+ const langBtn = document.getElementById('currentLanguage');
227
+ if (langBtn) {
228
+ langBtn.textContent = lang === 'zh-CN' ? '中文' : 'English';
229
+ }
230
+
231
  // 更新所有带有 data-i18n 属性的元素
232
  document.querySelectorAll('[data-i18n]').forEach(element => {
233
  const key = element.getAttribute('data-i18n');
 
258
  element.setAttribute('title', window.i18next.t(key));
259
  });
260
 
261
+ const loginPassword = document.getElementById('login-password');
262
+ const loginToggle = document.getElementById('login-password-toggle');
263
+ if (loginPassword && loginToggle && loginPassword.type === 'text') {
264
+ const label = window.i18next.t('auth.hidePassword');
265
+ loginToggle.setAttribute('aria-label', label);
266
+ loginToggle.setAttribute('title', label);
267
+ }
268
+
269
  // 更新页面标题
270
  document.title = window.i18next.t('auth.loginTitle') + ' - ' + window.i18next.t('auth.login');
271
  }
qa_annotate/static/css/auth.css CHANGED
@@ -47,6 +47,25 @@ body {
47
  color: white;
48
  padding: 40px 30px 30px;
49
  text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
51
 
52
  .auth-header h1 {
 
47
  color: white;
48
  padding: 40px 30px 30px;
49
  text-align: center;
50
+ position: relative;
51
+ }
52
+
53
+ .auth-lang-switch {
54
+ position: absolute;
55
+ top: 16px;
56
+ right: 16px;
57
+ padding: 6px 12px;
58
+ background: rgba(255, 255, 255, 0.15);
59
+ border: 1px solid rgba(255, 255, 255, 0.25);
60
+ border-radius: 8px;
61
+ color: white;
62
+ font-size: 13px;
63
+ cursor: pointer;
64
+ transition: all 0.3s ease;
65
+ }
66
+
67
+ .auth-lang-switch:hover {
68
+ background: rgba(255, 255, 255, 0.25);
69
  }
70
 
71
  .auth-header h1 {