ant-go 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/i18n.js ADDED
@@ -0,0 +1,584 @@
1
+ /**
2
+ * i18n.js — Bilingual support: Vietnamese (default) + English
3
+ * Language stored in ~/.ant-go/config.json → lang
4
+ */
5
+
6
+ const { loadConfig } = require('./config');
7
+
8
+ const MESSAGES = {
9
+ // ── auth ────────────────────────────────────────────────────────────────────
10
+ alreadyLoggedIn: {
11
+ vi: (email) => `Bạn đã đăng nhập với tài khoản: ${email}`,
12
+ en: (email) => `Already logged in as: ${email}`,
13
+ },
14
+ logoutHint: {
15
+ vi: 'Chạy `ant auth logout` nếu muốn đăng nhập tài khoản khác.',
16
+ en: 'Run `ant auth logout` to switch accounts.',
17
+ },
18
+ loginTitle: {
19
+ vi: 'Đăng nhập vào ant',
20
+ en: 'Login to ant',
21
+ },
22
+ loginBrowserHint: {
23
+ vi: 'Dùng --browser để đăng nhập với Google',
24
+ en: 'Use --browser to login with Google',
25
+ },
26
+ loginEmailLabel: {
27
+ vi: 'Email:',
28
+ en: 'Email:',
29
+ },
30
+ loginPasswordLabel: {
31
+ vi: 'Mật khẩu:',
32
+ en: 'Password:',
33
+ },
34
+ loginEmailInvalid: {
35
+ vi: 'Email không hợp lệ',
36
+ en: 'Invalid email',
37
+ },
38
+ loginLoading: {
39
+ vi: 'Đang đăng nhập...',
40
+ en: 'Logging in...',
41
+ },
42
+ loginSuccess: {
43
+ vi: 'Đăng nhập thành công!',
44
+ en: 'Logged in successfully!',
45
+ },
46
+ loginFailed: {
47
+ vi: 'Đăng nhập thất bại',
48
+ en: 'Login failed',
49
+ },
50
+ loginNoAccount: {
51
+ vi: 'Chưa có tài khoản?',
52
+ en: "Don't have an account yet?",
53
+ },
54
+ loginRegisterAt: {
55
+ vi: 'Đăng ký tại:',
56
+ en: 'Register at:',
57
+ },
58
+ browserOpening: {
59
+ vi: 'Đang mở browser để đăng nhập với Google...',
60
+ en: 'Opening browser for Google login...',
61
+ },
62
+ browserManual: {
63
+ vi: 'Nếu browser không tự mở:',
64
+ en: 'If browser did not open:',
65
+ },
66
+ browserSuccess: {
67
+ vi: '✓ Đăng nhập thành công!',
68
+ en: '✓ Logged in successfully!',
69
+ },
70
+ browserSuccessClose: {
71
+ vi: 'Bạn có thể đóng tab này và quay lại terminal.',
72
+ en: 'You can close this tab and return to the terminal.',
73
+ },
74
+ browserTimeout: {
75
+ vi: 'Timeout: quá 5 phút không hoàn tất đăng nhập',
76
+ en: 'Timeout: login not completed within 5 minutes',
77
+ },
78
+ notLoggedIn: {
79
+ vi: 'Bạn chưa đăng nhập.',
80
+ en: 'You are not logged in.',
81
+ },
82
+ logoutSuccess: {
83
+ vi: '✓ Đã đăng xuất thành công.',
84
+ en: '✓ Logged out successfully.',
85
+ },
86
+ whoamiTitle: {
87
+ vi: 'Thông tin tài khoản:',
88
+ en: 'Account info:',
89
+ },
90
+ whoamiEmail: {
91
+ vi: 'Email:',
92
+ en: 'Email:',
93
+ },
94
+ whoamiName: {
95
+ vi: 'Tên:',
96
+ en: 'Name:',
97
+ },
98
+ whoamiPlan: {
99
+ vi: 'Plan:',
100
+ en: 'Plan:',
101
+ },
102
+ whoamiCredits: {
103
+ vi: 'Credits:',
104
+ en: 'Credits:',
105
+ },
106
+ whoamiExpired: {
107
+ vi: 'Đã hết hạn — chạy: ant auth login',
108
+ en: 'Expired — run: ant auth login',
109
+ },
110
+ whoamiExpires: {
111
+ vi: 'Hết hạn:',
112
+ en: 'Expires:',
113
+ },
114
+ sessionRenewing: {
115
+ vi: 'Đang gia hạn phiên đăng nhập...',
116
+ en: 'Renewing session...',
117
+ },
118
+ sessionRenewed: {
119
+ vi: 'Phiên đăng nhập đã được gia hạn',
120
+ en: 'Session renewed',
121
+ },
122
+ sessionRenewFailed: {
123
+ vi: 'Không thể gia hạn phiên',
124
+ en: 'Failed to renew session',
125
+ },
126
+ sessionExpired: {
127
+ vi: 'Bạn chưa đăng nhập hoặc phiên đã hết hạn.',
128
+ en: 'You are not logged in or your session has expired.',
129
+ },
130
+ runLoginHint: {
131
+ vi: 'Chạy: ant auth login',
132
+ en: 'Run: ant auth login',
133
+ },
134
+
135
+ // ── build ───────────────────────────────────────────────────────────────────
136
+ buildNoPlatform: {
137
+ vi: 'Thiếu flag --platform',
138
+ en: 'Missing --platform flag',
139
+ },
140
+ buildPlatformSupported: {
141
+ vi: 'Nền tảng hỗ trợ:',
142
+ en: 'Supported platforms:',
143
+ },
144
+ buildPlatformInvalid: {
145
+ vi: (p) => `--platform không hợp lệ: "${p}"`,
146
+ en: (p) => `Invalid --platform: "${p}"`,
147
+ },
148
+ buildPlatformOnly: {
149
+ vi: `Chỉ chấp nhận: ios hoặc android`,
150
+ en: `Only accepted: ios or android`,
151
+ },
152
+ buildExample: {
153
+ vi: '$ ant build --platform ios',
154
+ en: '$ ant build --platform ios',
155
+ },
156
+ buildUsage: {
157
+ vi: 'Cách dùng:',
158
+ en: 'Usage:',
159
+ },
160
+ buildLoadingAccount: {
161
+ vi: 'Đang tải thông tin tài khoản...',
162
+ en: 'Loading account info...',
163
+ },
164
+ buildLoadAccountFailed: {
165
+ vi: 'Không tải được thông tin tài khoản',
166
+ en: 'Failed to load account info',
167
+ },
168
+ buildCreditsRemaining: {
169
+ vi: (plan, credits) => `Plan: ${plan} · Credits còn lại: ${credits}`,
170
+ en: (plan, credits) => `Plan: ${plan} · Credits remaining: ${credits}`,
171
+ },
172
+ buildOutOfCredits: {
173
+ vi: 'Bạn đã hết credit build.',
174
+ en: 'You have run out of build credits.',
175
+ },
176
+ buildOutOfCreditsHint: {
177
+ vi: 'Nâng cấp plan hoặc chờ reset đầu tháng tại: https://antgo.work/account/billing',
178
+ en: 'Upgrade your plan or wait for monthly reset at: https://antgo.work/account/billing',
179
+ },
180
+ buildPastDue: {
181
+ vi: 'Thanh toán thất bại — vui lòng cập nhật thông tin thanh toán.',
182
+ en: 'Payment failed — please update your billing information.',
183
+ },
184
+ buildNoPlatformDir: {
185
+ vi: (dir, root) => `Không tìm thấy thư mục ${dir}/ trong: ${root}`,
186
+ en: (dir, root) => `Could not find ${dir}/ directory in: ${root}`,
187
+ },
188
+ buildAutoSubmitStoreOnly: {
189
+ vi: '--auto-submit chỉ dùng được với distribution: store',
190
+ en: '--auto-submit only works with distribution: store',
191
+ },
192
+ buildAutoSubmitProfileHint: {
193
+ vi: (name, dist) => `Profile "${name}" đang dùng distribution: ${dist}`,
194
+ en: (name, dist) => `Profile "${name}" uses distribution: ${dist}`,
195
+ },
196
+ buildCreatingJob: {
197
+ vi: 'Đang tạo build job...',
198
+ en: 'Creating build job...',
199
+ },
200
+ buildJobCreated: {
201
+ vi: (id, bn) => `Job tạo thành công: ${id} · Build #${bn}`,
202
+ en: (id, bn) => `Job created: ${id} · Build #${bn}`,
203
+ },
204
+ buildAscKeySaved: {
205
+ vi: '✔ ASC API Key đã lưu vào dashboard',
206
+ en: '✔ ASC API Key saved to dashboard',
207
+ },
208
+ buildAscKeyFailed: {
209
+ vi: '⚠ Không lưu được ASC API Key: ',
210
+ en: '⚠ Failed to save ASC API Key: ',
211
+ },
212
+ buildJobFailed: {
213
+ vi: 'Tạo build job thất bại',
214
+ en: 'Failed to create build job',
215
+ },
216
+ buildProjectNotFound: {
217
+ vi: (id) => `Project ID "${id}" không tồn tại trên hệ thống.`,
218
+ en: (id) => `Project ID "${id}" does not exist on the system.`,
219
+ },
220
+ buildProjectNotFoundHint1: {
221
+ vi: 'Hãy kiểm tra lại projectId trong app.json:',
222
+ en: 'Please check the projectId in app.json:',
223
+ },
224
+ buildProjectNotFoundHint2: {
225
+ vi: 'Tạo project tại:',
226
+ en: 'Create a project at:',
227
+ },
228
+ buildProjectNotFoundHint3: {
229
+ vi: 'Sau đó copy Project ID vào app.json.',
230
+ en: 'Then copy the Project ID into app.json.',
231
+ },
232
+ buildPacking: {
233
+ vi: 'Đang nén project...',
234
+ en: 'Packing project...',
235
+ },
236
+ buildPackDone: {
237
+ vi: (mb) => `Project đã nén: ${mb} MB`,
238
+ en: (mb) => `Project packed: ${mb} MB`,
239
+ },
240
+ buildPackFailed: {
241
+ vi: 'Lỗi khi nén project',
242
+ en: 'Failed to pack project',
243
+ },
244
+ buildUploading: {
245
+ vi: (file) => `Đang upload ${file}...`,
246
+ en: (file) => `Uploading ${file}...`,
247
+ },
248
+ buildUploadDone: {
249
+ vi: (file) => `Upload ${file} hoàn tất`,
250
+ en: (file) => `Upload ${file} complete`,
251
+ },
252
+ buildUploadFailed: {
253
+ vi: (file) => `Lỗi khi upload ${file}`,
254
+ en: (file) => `Failed to upload ${file}`,
255
+ },
256
+ buildUploadProgress: {
257
+ vi: (pct, up, total) => `Đang upload... ${pct}% (${up} / ${total} MB)`,
258
+ en: (pct, up, total) => `Uploading... ${pct}% (${up} / ${total} MB)`,
259
+ },
260
+ buildVerifyingFiles: {
261
+ vi: 'Đang kiểm tra files...',
262
+ en: 'Verifying files...',
263
+ },
264
+ buildVerifyDone: {
265
+ vi: 'Đã kiểm tra đầy đủ files',
266
+ en: 'All files verified',
267
+ },
268
+ buildStartFailed: {
269
+ vi: 'Không thể khởi động build',
270
+ en: 'Failed to start build',
271
+ },
272
+ buildSubmitted: {
273
+ vi: 'Build đã được gửi lên server!',
274
+ en: 'Build submitted to server!',
275
+ },
276
+ buildAutoSubmitNote: {
277
+ vi: '✈ Auto Submit: bật — IPA sẽ tự động được gửi lên TestFlight sau khi build xong.',
278
+ en: '✈ Auto Submit: on — IPA will be automatically submitted to TestFlight after build.',
279
+ },
280
+ buildTrackAt: {
281
+ vi: 'Theo dõi tiến trình tại:',
282
+ en: 'Track progress at:',
283
+ },
284
+ buildAppleCredsError: {
285
+ vi: 'Không lấy được Apple credentials: ',
286
+ en: 'Failed to get Apple credentials: ',
287
+ },
288
+ // ant.json
289
+ antJsonCreated: {
290
+ vi: '📄 Đã tạo ant.json với các profile mặc định:',
291
+ en: '📄 Created ant.json with default profiles:',
292
+ },
293
+ antJsonParseFailed: {
294
+ vi: 'Không thể parse ant.json',
295
+ en: 'Failed to parse ant.json',
296
+ },
297
+ antJsonProfileNotFound: {
298
+ vi: (name) => `Profile "${name}" không tồn tại trong ant.json`,
299
+ en: (name) => `Profile "${name}" does not exist in ant.json`,
300
+ },
301
+ antJsonProfilesAvailable: {
302
+ vi: ' Profiles hiện có:',
303
+ en: ' Available profiles:',
304
+ },
305
+ // app.json
306
+ appJsonNotFound: {
307
+ vi: (path) => `Không tìm thấy app.json tại: ${path}`,
308
+ en: (path) => `app.json not found at: ${path}`,
309
+ },
310
+ appJsonParseFailed: {
311
+ vi: 'Không thể parse app.json',
312
+ en: 'Failed to parse app.json',
313
+ },
314
+ appJsonNoProjectId: {
315
+ vi: '⚠ Chưa có projectId trong app.json → expo.extra.ant.projectId',
316
+ en: '⚠ Missing projectId in app.json → expo.extra.ant.projectId',
317
+ },
318
+ appJsonNoProjectIdHint: {
319
+ vi: 'Vào https://antgo.work để lấy Project ID',
320
+ en: 'Go to https://antgo.work to get your Project ID',
321
+ },
322
+ appJsonNoBundleId: {
323
+ vi: 'Thiếu bundleId — thêm expo.extra.ant.bundleId hoặc expo.ios.bundleIdentifier vào app.json',
324
+ en: 'Missing bundleId — add expo.extra.ant.bundleId or expo.ios.bundleIdentifier to app.json',
325
+ },
326
+ // ── apple creds ─────────────────────────────────────────────────────────────
327
+ appleCredsLogin: {
328
+ vi: '🔐 Cần đăng nhập Apple Developer để lấy certificate & provisioning profile',
329
+ en: '🔐 Apple Developer login required to get certificate & provisioning profile',
330
+ },
331
+ appleIdLabel: { vi: 'Apple ID (email):', en: 'Apple ID (email):' },
332
+ applePasswordLabel:{ vi: 'App-Specific Password (appleid.apple.com):', en: 'App-Specific Password (appleid.apple.com):' },
333
+ appleRequired: { vi: 'Bắt buộc', en: 'Required' },
334
+ appleLoggingIn: { vi: 'Đang đăng nhập Apple Developer...', en: 'Logging in to Apple Developer...' },
335
+ apple2FA: { vi: '🔐 Nhập mã 2FA từ iPhone/Mac của bạn:', en: '🔐 Enter 2FA code from your iPhone/Mac:' },
336
+ apple2FACode: { vi: 'Mã 6 chữ số', en: '6-digit code' },
337
+ apple2FAVerifying: { vi: 'Đang xác thực 2FA...', en: 'Verifying 2FA...' },
338
+ appleLoginSuccess: { vi: 'Đăng nhập thành công', en: 'Logged in successfully' },
339
+ appleLoginFailed: { vi: (msg) => `Đăng nhập thất bại: ${msg}`, en: (msg) => `Login failed: ${msg}` },
340
+ appleLoadingTeam: { vi: 'Đang lấy thông tin team...', en: 'Fetching team info...' },
341
+ appleNoTeam: { vi: 'Không tìm thấy Apple Developer team nào', en: 'No Apple Developer team found' },
342
+ appleSelectTeam: { vi: 'Chọn Apple Developer Team:', en: 'Select Apple Developer Team:' },
343
+ appleTeamFailed: { vi: (msg) => `Không lấy được thông tin team: ${msg}`, en: (msg) => `Failed to get team info: ${msg}` },
344
+ appleUseCache: { vi: (label) => `Đăng nhập tài khoản ${label}`, en: (label) => `Login as ${label}` },
345
+ appleLoginOther: { vi: 'Đăng nhập tài khoản khác', en: 'Login with a different account' },
346
+ appleLoginPrompt: { vi: 'Đăng nhập tài khoản Apple Developer', en: 'Apple Developer account' },
347
+ appleDevicesLabel: { vi: '📱 Chọn device để build (Space = chọn/bỏ, Enter = xác nhận):', en: '📱 Select devices for build (Space = select, Enter = confirm):' },
348
+ appleDevicesMustSelect: { vi: 'Phải chọn ít nhất 1 device.', en: 'Select at least 1 device.' },
349
+ appleDevicesAddNew:{ vi: '+ Thêm device mới', en: '+ Add new device' },
350
+ appleDevicesNone: { vi: 'Chưa có device nào — tiến hành đăng ký device mới.', en: 'No devices yet — proceeding to register a new device.' },
351
+ appleDeviceName: { vi: 'Tên device (để nhận ra sau này):', en: 'Device name (to identify later):' },
352
+ appleDeviceDefault:{ vi: 'My iPhone', en: 'My iPhone' },
353
+ appleDeviceSaving: { vi: 'Đang lưu device...', en: 'Saving device...' },
354
+ appleDeviceSaved: { vi: (name) => `Đã lưu: ${name}`, en: (name) => `Saved: ${name}` },
355
+ appleDeviceSaveFailed: { vi: (msg) => `Không lưu được device: ${msg}`, en: (msg) => `Failed to save device: ${msg}` },
356
+ appleDeviceSyncing:{ vi: (n) => `Đang đồng bộ ${n} device(s) lên Apple Developer...`, en: (n) => `Syncing ${n} device(s) to Apple Developer...` },
357
+ appleDeviceSynced: { vi: (n) => `Đã đồng bộ ${n} device(s) lên Apple Developer`, en: (n) => `Synced ${n} device(s) to Apple Developer` },
358
+ appleDeviceSyncFailed: { vi: (msg) => `Lỗi khi đồng bộ devices: ${msg}`, en: (msg) => `Failed to sync devices: ${msg}` },
359
+ enrollNewDevice: { vi: '📱 Đăng ký device mới', en: '📱 Register new device' },
360
+ enrollQRHint: { vi: ' iPhone sẽ tự động gửi UDID khi quét mã QR bên dưới', en: ' iPhone will automatically send UDID when you scan the QR code below' },
361
+ enrollQRScan: { vi: 'Quét QR code bằng Camera app trên iPhone:', en: 'Scan QR code with Camera app on iPhone:' },
362
+ enrollOrOpen: { vi: 'Hoặc mở URL: ', en: 'Or open URL: ' },
363
+ enrollWaiting: { vi: 'Đang chờ iPhone xác nhận...', en: 'Waiting for iPhone confirmation...' },
364
+ enrollConfirmed: { vi: (name, udid) => `Device đã xác nhận: ${name} (${udid})`, en: (name, udid) => `Device confirmed: ${name} (${udid})` },
365
+ enrollExpired: { vi: 'Enrollment đã hết hạn (10 phút)', en: 'Enrollment expired (10 minutes)' },
366
+ enrollPolling: { vi: (min) => `Chờ iPhone quét QR... (còn ${min} phút)`, en: (min) => `Waiting for iPhone to scan QR... (${min} min left)` },
367
+ enrollTimeout: { vi: 'Hết thời gian chờ (10 phút)', en: 'Timed out (10 minutes)' },
368
+ enrollCreateFailed:{ vi: (msg) => `Không tạo được enrollment session: ${msg}`, en: (msg) => `Failed to create enrollment session: ${msg}` },
369
+ ascKeyCreating: { vi: 'Đang tạo App Store Connect API Key...', en: 'Creating App Store Connect API Key...' },
370
+ ascKeyCreated: { vi: (id) => `ASC API Key tạo thành công: ${id}`, en: (id) => `ASC API Key created: ${id}` },
371
+ ascKeyFailed: { vi: (msg) => `Không lấy được ASC API Key: ${msg}`, en: (msg) => `Failed to get ASC API Key: ${msg}` },
372
+ ascKeyNoIssuer: { vi: '⚠ Không tự lấy được Issuer ID.', en: '⚠ Could not auto-fetch Issuer ID.' },
373
+ ascKeyIssuerHint: { vi: ' Tìm tại: https://appstoreconnect.apple.com/access/integrations/api', en: ' Find it at: https://appstoreconnect.apple.com/access/integrations/api' },
374
+ ascKeyIssuerLabel: { vi: 'Issuer ID (UUID):', en: 'Issuer ID (UUID):' },
375
+ ascKeyCached: { vi: (id) => `✔ ASC API Key (cached): ${id}`, en: (id) => `✔ ASC API Key (cached): ${id}` },
376
+ certLoading: { vi: (label) => `Đang lấy ${label} Certificate...`, en: (label) => `Fetching ${label} Certificate...` },
377
+ certReused: { vi: (label, id) => `${label} Certificate (reused): ${id}`, en: (label, id) => `${label} Certificate (reused): ${id}` },
378
+ certNew: { vi: (label, id) => `${label} Certificate (new): ${id}`, en: (label, id) => `${label} Certificate (new): ${id}` },
379
+ certFailed: { vi: (label, msg) => `Lỗi ${label} cert: ${msg}`, en: (label, msg) => `${label} cert error: ${msg}` },
380
+ profileLoading: { vi: (label) => `Đang lấy ${label} Provisioning Profile...`, en: (label) => `Fetching ${label} Provisioning Profile...` },
381
+ profileReusing: { vi: (label) => `Reusing existing ${label} profile...`, en: (label) => `Reusing existing ${label} profile...` },
382
+ profileCertMismatch: { vi: 'Profile không khớp cert → đang tạo lại...', en: 'Profile cert mismatch → recreating...' },
383
+ profileCapChanged: { vi: 'Capabilities thay đổi → đang tạo lại profile...', en: 'Capabilities changed → recreating profile...' },
384
+ profileNewCert: { vi: 'Cert mới → đang tạo lại profile...', en: 'New cert → recreating profile...' },
385
+ profileInvalid: { vi: 'Profile không hợp lệ → đang tạo lại...', en: 'Invalid profile → recreating...' },
386
+ profileOK: { vi: (label) => `${label} Provisioning Profile OK`, en: (label) => `${label} Provisioning Profile OK` },
387
+ profileFailed: { vi: (label, msg) => `Lỗi ${label} profile: ${msg}`, en: (label, msg) => `${label} profile error: ${msg}` },
388
+ profileNoContent: { vi: 'Profile không có nội dung', en: 'Profile has no content' },
389
+ profileNoBundleId: { vi: (id) => `App ID "${id}" không tồn tại trên Apple Developer`, en: (id) => `App ID "${id}" does not exist on Apple Developer` },
390
+ profileRegisteringId: { vi: (id) => `Đang đăng ký App ID "${id}" trên Apple Developer...`, en: (id) => `Registering App ID "${id}" on Apple Developer...` },
391
+ credsCached: { vi: (path) => `✔ Credentials đã cache tại: ${path}`, en: (path) => `✔ Credentials cached at: ${path}` },
392
+
393
+ // ── status ──────────────────────────────────────────────────────────────────
394
+ statusRunning: {
395
+ vi: 'Build đang chạy — đang theo dõi...',
396
+ en: 'Build is running — watching...',
397
+ },
398
+
399
+ // ── configure ───────────────────────────────────────────────────────────────
400
+ configureProjectLabel: {
401
+ vi: 'Project:',
402
+ en: 'Project:',
403
+ },
404
+ configureProjectDefault: {
405
+ vi: '(cwd khi chạy ant build)',
406
+ en: '(current directory when running ant build)',
407
+ },
408
+ configureUsage: {
409
+ vi: 'Dùng:',
410
+ en: 'Use:',
411
+ },
412
+
413
+ // ── update-check ────────────────────────────────────────────────────────────
414
+ updateAvailable: {
415
+ vi: (cur, lat) => ` Có phiên bản mới: ${cur} → ${lat}`,
416
+ en: (cur, lat) => ` Update available: ${cur} → ${lat}`,
417
+ },
418
+ updateRun: {
419
+ vi: ' Chạy: npm install -g ant-go@latest để cập nhật',
420
+ en: ' Run: npm install -g ant-go@latest to upgrade',
421
+ },
422
+
423
+ // ── server error codes ───────────────────────────────────────────────────────
424
+ // Firebase auth error codes
425
+ serverError: {
426
+ EMAIL_NOT_FOUND: { vi: 'Không tìm thấy tài khoản với email này.', en: 'No account found with this email.' },
427
+ INVALID_PASSWORD: { vi: 'Mật khẩu không đúng.', en: 'Incorrect password.' },
428
+ INVALID_EMAIL: { vi: 'Email không hợp lệ.', en: 'Invalid email address.' },
429
+ USER_DISABLED: { vi: 'Tài khoản đã bị vô hiệu hóa.', en: 'This account has been disabled.' },
430
+ TOO_MANY_ATTEMPTS_TRY_LATER: { vi: 'Quá nhiều lần thử. Vui lòng thử lại sau.', en: 'Too many attempts. Please try again later.' },
431
+ INVALID_LOGIN_CREDENTIALS: { vi: 'Email hoặc mật khẩu không đúng.', en: 'Incorrect email or password.' },
432
+ // Auth / token
433
+ 'Chưa đăng nhập. Chạy: ant auth login': { vi: 'Bạn chưa đăng nhập.', en: 'You are not logged in.' },
434
+ 'Chưa đăng nhập. Chạy: ant-go auth login': { vi: 'Bạn chưa đăng nhập.', en: 'You are not logged in.' },
435
+ 'Missing Authorization header': { vi: 'Thiếu Authorization header.', en: 'Missing Authorization header.' },
436
+ 'Token không hợp lệ hoặc đã hết hạn': { vi: 'Token không hợp lệ hoặc đã hết hạn.', en: 'Token is invalid or expired.' },
437
+ 'Token không hợp lệ': { vi: 'Token không hợp lệ.', en: 'Invalid token.' },
438
+ 'Token không tồn tại': { vi: 'Token không tồn tại.', en: 'Token not found.' },
439
+ 'Token đã hết hạn': { vi: 'Token đã hết hạn.', en: 'Token has expired.' },
440
+ 'Phiên đăng nhập đã hết hạn. Vui lòng đăng nhập lại.': { vi: 'Phiên đăng nhập đã hết hạn.', en: 'Session expired. Please login again.' },
441
+ 'Không thể xác thực token': { vi: 'Không thể xác thực token.', en: 'Failed to verify token.' },
442
+ 'Không thể xác thực token mới': { vi: 'Không thể xác thực token mới.', en: 'Failed to verify new token.' },
443
+ 'Email và password là bắt buộc': { vi: 'Email và password là bắt buộc.', en: 'Email and password are required.' },
444
+ 'refreshToken là bắt buộc': { vi: 'refreshToken là bắt buộc.', en: 'refreshToken is required.' },
445
+ 'idToken là bắt buộc': { vi: 'idToken là bắt buộc.', en: 'idToken is required.' },
446
+ // Build
447
+ 'Build job not found': { vi: 'Không tìm thấy build job.', en: 'Build job not found.' },
448
+ 'Build not found': { vi: 'Không tìm thấy build.', en: 'Build not found.' },
449
+ 'Build không tồn tại': { vi: 'Build không tồn tại.', en: 'Build not found.' },
450
+ 'Build ID is required': { vi: 'Thiếu Build ID.', en: 'Build ID is required.' },
451
+ 'Build chưa có IPA': { vi: 'Build chưa có IPA.', en: 'Build has no IPA yet.' },
452
+ 'Build has no userId': { vi: 'Build không có userId.', en: 'Build has no userId.' },
453
+ 'Chỉ có thể submit build đã thành công': { vi: 'Chỉ có thể submit build đã thành công.', en: 'Only successful builds can be submitted.' },
454
+ 'Không thể khởi động upload job': { vi: 'Không thể khởi động upload job.', en: 'Failed to start upload job.' },
455
+ 'buildId là bắt buộc': { vi: 'buildId là bắt buộc.', en: 'buildId is required.' },
456
+ 'ids is required': { vi: 'Thiếu danh sách ids.', en: 'ids is required.' },
457
+ 'Log file not available for this build': { vi: 'Log chưa có cho build này.', en: 'Log file not available for this build.' },
458
+ // Credits / plan
459
+ 'Hết credit. Nâng cấp plan hoặc chờ reset đầu tháng tại antgo.work/account/billing': {
460
+ vi: 'Hết credit. Nâng cấp plan tại antgo.work/account/billing.',
461
+ en: 'Out of credits. Upgrade your plan at antgo.work/account/billing.',
462
+ },
463
+ 'Invalid plan': { vi: 'Plan không hợp lệ.', en: 'Invalid plan.' },
464
+ // App
465
+ 'App not found or forbidden': { vi: 'Không tìm thấy app hoặc không có quyền truy cập.', en: 'App not found or access denied.' },
466
+ 'App not found': { vi: 'Không tìm thấy app.', en: 'App not found.' },
467
+ 'name là bắt buộc': { vi: 'Tên app là bắt buộc.', en: 'App name is required.' },
468
+ 'projectId là bắt buộc': { vi: 'projectId là bắt buộc.', en: 'projectId is required.' },
469
+ // Device
470
+ 'udid là bắt buộc': { vi: 'udid là bắt buộc.', en: 'udid is required.' },
471
+ // ASC key
472
+ 'keyId, issuerId và privateKeyP8 là bắt buộc': { vi: 'keyId, issuerId và privateKeyP8 là bắt buộc.', en: 'keyId, issuerId and privateKeyP8 are required.' },
473
+ 'teamId, keyId, issuerId và privateKeyP8 là bắt buộc': { vi: 'teamId, keyId, issuerId và privateKeyP8 là bắt buộc.', en: 'teamId, keyId, issuerId and privateKeyP8 are required.' },
474
+ 'privateKeyP8 không hợp lệ — phải là nội dung file .p8': { vi: 'privateKeyP8 không hợp lệ — phải là nội dung file .p8.', en: 'privateKeyP8 is invalid — must be the contents of a .p8 file.' },
475
+ 'missing_asc_key': { vi: 'Thiếu App Store Connect API Key.', en: 'Missing App Store Connect API Key.' },
476
+ // General
477
+ 'Unauthorized': { vi: 'Không có quyền truy cập.', en: 'Unauthorized.' },
478
+ 'Forbidden': { vi: 'Bị từ chối truy cập.', en: 'Access forbidden.' },
479
+ 'Không tìm thấy': { vi: 'Không tìm thấy.', en: 'Not found.' },
480
+ 'Invalid JSON body': { vi: 'Body JSON không hợp lệ.', en: 'Invalid JSON body.' },
481
+ 'Invalid signature': { vi: 'Chữ ký không hợp lệ.', en: 'Invalid signature.' },
482
+ 'Missing signature': { vi: 'Thiếu chữ ký.', en: 'Missing signature.' },
483
+ 'Server misconfigured': { vi: 'Lỗi cấu hình server.', en: 'Server misconfigured.' },
484
+ 'No billing account found': { vi: 'Không tìm thấy tài khoản thanh toán.', en: 'No billing account found.' },
485
+ 'durationMs phải là số dương': { vi: 'durationMs phải là số dương.', en: 'durationMs must be a positive number.' },
486
+ 'repoFullName phải có định dạng owner/repo': { vi: 'repoFullName phải có định dạng owner/repo.', en: 'repoFullName must be in the format owner/repo.' },
487
+ 'antgoAppId and repoFullName are required': { vi: 'Thiếu antgoAppId hoặc repoFullName.', en: 'antgoAppId and repoFullName are required.' },
488
+ 'GITHUB_APP_SLUG chưa được cấu hình': { vi: 'GITHUB_APP_SLUG chưa được cấu hình.', en: 'GITHUB_APP_SLUG is not configured.' },
489
+ },
490
+ loginFailedDefault: {
491
+ vi: 'Đăng nhập thất bại. Kiểm tra lại email và mật khẩu.',
492
+ en: 'Login failed. Please check your email and password.',
493
+ },
494
+ langSet: {
495
+ vi: (lang) => `✓ Ngôn ngữ đã đổi sang: ${lang === 'vi' ? 'Tiếng Việt' : 'English'}`,
496
+ en: (lang) => `✓ Language set to: ${lang === 'vi' ? 'Tiếng Việt' : 'English'}`,
497
+ },
498
+ langInvalid: {
499
+ vi: 'Ngôn ngữ không hợp lệ. Dùng: ant set lang vi hoặc ant set lang en',
500
+ en: 'Invalid language. Use: ant set lang vi or ant set lang en',
501
+ },
502
+
503
+ // ── first run ───────────────────────────────────────────────────────────────
504
+ firstRunWelcome: {
505
+ vi: '👋 Chào mừng bạn đến với ant-go CLI!',
506
+ en: '👋 Welcome to ant-go CLI!',
507
+ },
508
+ firstRunGetStarted: {
509
+ vi: 'Bắt đầu bằng cách đăng nhập:',
510
+ en: 'Get started by logging in:',
511
+ },
512
+ firstRunDocs: {
513
+ vi: 'Tài liệu đầy đủ tại:',
514
+ en: 'Full documentation at:',
515
+ },
516
+ firstRunLangHint: {
517
+ vi: '💡 Prefer English? Run: ant set lang en',
518
+ en: '💡 Muốn dùng CLI bằng tiếng Việt? Chạy: ant set lang vi',
519
+ },
520
+
521
+ // ── uninstall ────────────────────────────────────────────────────────────────
522
+ uninstallConfirm: {
523
+ vi: 'Bạn có chắc muốn gỡ cài đặt ant-go CLI không?',
524
+ en: 'Are you sure you want to uninstall ant-go CLI?',
525
+ },
526
+ uninstallCancelled: {
527
+ vi: 'Đã huỷ.',
528
+ en: 'Cancelled.',
529
+ },
530
+ uninstallRunning: {
531
+ vi: 'Đang gỡ cài đặt...',
532
+ en: 'Uninstalling...',
533
+ },
534
+ uninstallDone: {
535
+ vi: 'ant-go CLI đã được gỡ cài đặt.',
536
+ en: 'ant-go CLI has been uninstalled.',
537
+ },
538
+ uninstallFailed: {
539
+ vi: (msg) => `Gỡ cài đặt thất bại: ${msg}`,
540
+ en: (msg) => `Uninstall failed: ${msg}`,
541
+ },
542
+ };
543
+
544
+ function getLang() {
545
+ try {
546
+ const cfg = loadConfig();
547
+ return cfg.lang === 'vi' ? 'vi' : 'en';
548
+ } catch {
549
+ return 'en';
550
+ }
551
+ }
552
+
553
+ function t(key, ...args) {
554
+ const lang = getLang();
555
+ const entry = MESSAGES[key];
556
+ if (!entry) return key;
557
+ const val = entry[lang] ?? entry['vi'];
558
+ return typeof val === 'function' ? val(...args) : val;
559
+ }
560
+
561
+ // Translate server error message — supports Firebase error codes and Vietnamese strings
562
+ function tError(serverMessage) {
563
+ if (!serverMessage) return serverMessage;
564
+ const lang = getLang();
565
+ const errors = MESSAGES.serverError;
566
+
567
+ // 1. Direct key match (Firebase error codes or exact Vietnamese strings)
568
+ if (errors[serverMessage]) {
569
+ return errors[serverMessage][lang] ?? errors[serverMessage]['vi'];
570
+ }
571
+
572
+ // 2. Firebase error code embedded in message (e.g. "INVALID_LOGIN_CREDENTIALS : ...")
573
+ for (const [code, translations] of Object.entries(errors)) {
574
+ if (serverMessage.includes(code)) {
575
+ return translations[lang] ?? translations['vi'];
576
+ }
577
+ }
578
+
579
+ // 3. No match — return raw server message as-is
580
+ return serverMessage;
581
+ }
582
+
583
+ module.exports = { t, tError, getLang, MESSAGES };
584
+
package/src/logger.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * logger.js — Simple timestamped logger with chalk colors
3
+ */
4
+
5
+ const chalk = require('chalk');
6
+
7
+ function log(msg) { console.log(`${chalk.gray('[' + new Date().toLocaleTimeString() + ']')} ${msg}`); }
8
+ function info(msg) { console.log(`${chalk.cyan('ℹ')} ${msg}`); }
9
+ function success(msg) { console.log(`${chalk.green('✓')} ${msg}`); }
10
+ function warn(msg) { console.warn(`${chalk.yellow('⚠')} ${msg}`); }
11
+ function error(msg) { console.error(`${chalk.red('✗')} ${msg}`); }
12
+
13
+ module.exports = { log, info, success, warn, error };
14
+