feat(i18n): add Vietnamese translations

This commit is contained in:
leeduc
2026-06-28 21:24:26 +07:00
committed by Maurice
parent e34f40b686
commit e4efcf0840
46 changed files with 3147 additions and 1 deletions
+1
View File
@@ -38,6 +38,7 @@ const localeLoaders: Record<SupportedLanguageCode, () => Promise<{ default: Tran
uk: () => import('@trek/shared/i18n/uk'),
gr: () => import('@trek/shared/i18n/gr'),
sv: () => import('@trek/shared/i18n/sv'),
vi: () => import('@trek/shared/i18n/vi'),
}
// Re-export pure helpers that live in shared so downstream consumers can import them
+2 -1
View File
@@ -91,7 +91,7 @@ describe('isRtlLanguage', () => {
describe('SUPPORTED_LANGUAGES', () => {
it('FE-COMP-I18N-009: contains expected entries with value/label shape', () => {
expect(Array.isArray(SUPPORTED_LANGUAGES)).toBe(true)
expect(SUPPORTED_LANGUAGES).toHaveLength(21)
expect(SUPPORTED_LANGUAGES).toHaveLength(22)
expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'en', label: 'English' }))
expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'tr', label: 'Türkçe' }))
expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'ja', label: '日本語' }))
@@ -99,6 +99,7 @@ describe('SUPPORTED_LANGUAGES', () => {
expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'uk', label: 'Українська' }))
expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'sv', label: 'Svenska' }))
expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'ar', label: 'العربية' }))
expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'vi', label: 'Tiếng Việt' }))
})
})
+1
View File
@@ -20,6 +20,7 @@ export const SUPPORTED_LANGUAGES = [
{ value: 'uk', label: 'Українська', locale: 'uk-UA' },
{ value: 'gr', label: 'Ελληνικά', locale: 'el-GR' },
{ value: 'sv', label: 'Svenska', locale: 'sv-SE' },
{ value: 'vi', label: 'Tiếng Việt', locale: 'vi-VN' },
] as const;
export type SupportedLanguageCode = (typeof SUPPORTED_LANGUAGES)[number]['value'];
+352
View File
@@ -0,0 +1,352 @@
import type { TranslationStrings } from '../types';
const admin: TranslationStrings = {
'admin.notifications.title': 'Thông báo',
'admin.notifications.hint': 'Chọn một kênh thông báo. Chỉ có một người có thể hoạt động tại một thời điểm.',
'admin.notifications.none': 'Tàn tật',
'admin.notifications.email': 'Email (SMTP)',
'admin.notifications.webhook': 'Webhook',
'admin.notifications.ntfy': 'Ntfy',
'admin.ntfy.hint':
'Cho phép người dùng định cấu hình chủ đề thú vị của riêng họ cho thông báo đẩy. Đặt máy chủ mặc định bên dưới để điền trước cài đặt người dùng.',
'admin.notifications.save': 'Lưu cài đặt thông báo',
'admin.notifications.saved': 'Đã lưu cài đặt thông báo',
'admin.notifications.testWebhook': 'Gửi webhook thử nghiệm',
'admin.notifications.testWebhookSuccess': 'Kiểm tra webhook đã được gửi thành công',
'admin.notifications.testWebhookFailed': 'Kiểm tra webhook không thành công',
'admin.notifications.testNtfy': 'Gửi bài kiểm tra',
'admin.notifications.testNtfySuccess': 'Kiểm tra ntfy đã được gửi thành công',
'admin.notifications.testNtfyFailed': 'Kiểm tra ntfy không thành công',
'admin.notifications.emailPanel.title': 'Email (SMTP)',
'admin.notifications.webhookPanel.title': 'Webhook',
'admin.notifications.inappPanel.title': 'Trong ứng dụng',
'admin.notifications.inappPanel.hint': 'Thông báo trong ứng dụng luôn hoạt động và không thể tắt trên toàn cầu.',
'admin.notifications.adminWebhookPanel.title': 'Webhook quản trị viên',
'admin.notifications.adminWebhookPanel.hint':
'Webhook này được sử dụng riêng cho thông báo của quản trị viên (ví dụ: cảnh báo phiên bản). Nó tách biệt với webhooks của mỗi người dùng và luôn kích hoạt khi được đặt.',
'admin.notifications.adminWebhookPanel.saved': 'Đã lưu webhook của quản trị viên URL',
'admin.notifications.adminWebhookPanel.testSuccess': 'Kiểm tra webhook đã được gửi thành công',
'admin.notifications.adminWebhookPanel.testFailed': 'Kiểm tra webhook không thành công',
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Webhook quản trị luôn kích hoạt khi URL được định cấu hình',
'admin.notifications.adminNtfyPanel.title': 'Quản trị viên Ntfy',
'admin.notifications.adminNtfyPanel.hint':
'Chủ đề ntfy này được sử dụng riêng cho thông báo của quản trị viên (ví dụ: cảnh báo phiên bản). Nó tách biệt với các chủ đề của mỗi người dùng và luôn kích hoạt khi được định cấu hình.',
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Máy chủ URL',
'admin.notifications.adminNtfyPanel.serverHint':
'Cũng được sử dụng làm máy chủ mặc định cho thông báo ntfy của người dùng. Để trống để mặc định là ntfy.sh. Người dùng có thể ghi đè điều này trong cài đặt của riêng họ.',
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
'admin.notifications.adminNtfyPanel.topicLabel': 'Chủ đề quản trị',
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-cảnh báo',
'admin.notifications.adminNtfyPanel.tokenLabel': 'Mã thông báo truy cập (tùy chọn)',
'admin.notifications.adminNtfyPanel.tokenCleared': 'Đã xóa mã thông báo truy cập của quản trị viên',
'admin.notifications.adminNtfyPanel.saved': 'Đã lưu cài đặt quản trị viên ntfy',
'admin.notifications.adminNtfyPanel.test': 'Gửi bài kiểm tra',
'admin.notifications.adminNtfyPanel.testSuccess': 'Kiểm tra ntfy đã được gửi thành công',
'admin.notifications.adminNtfyPanel.testFailed': 'Kiểm tra ntfy không thành công',
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Quản trị viên ntfy luôn kích hoạt khi chủ đề được định cấu hình',
'admin.notifications.adminNotificationsHint':
'Định cấu hình kênh nào gửi thông báo chỉ dành cho quản trị viên (ví dụ: cảnh báo phiên bản).',
'admin.notifications.tripReminders.title': 'Lời nhắc chuyến đi',
'admin.notifications.tripReminders.hint':
'Gửi thông báo nhắc nhở trước khi chuyến đi bắt đầu (yêu cầu phải đặt ngày nhắc nhở cho chuyến đi).',
'admin.notifications.tripReminders.enabled': 'Đã bật lời nhắc chuyến đi',
'admin.notifications.tripReminders.disabled': 'Đã tắt lời nhắc chuyến đi',
'admin.smtp.title': 'Email & Thông báo',
'admin.smtp.hint': 'Cấu hình SMTP để gửi thông báo qua email.',
'admin.smtp.testButton': 'Gửi email kiểm tra',
'admin.webhook.hint': 'Cho phép người dùng định cấu hình URL webhook của riêng họ để nhận thông báo (Discord, Slack, v.v.).',
'admin.smtp.testSuccess': 'Email kiểm tra đã được gửi thành công',
'admin.smtp.testFailed': 'Email kiểm tra không thành công',
'admin.title': 'Sự quản lý',
'admin.subtitle': 'Quản lý người dùng và cài đặt hệ thống',
'admin.tabs.users': 'Người dùng',
'admin.tabs.categories': 'Thể loại',
'admin.tabs.backup': 'Hỗ trợ',
'admin.tabs.notifications': 'Thông báo',
'admin.tabs.audit': 'Kiểm toán',
'admin.stats.users': 'Người dùng',
'admin.stats.trips': 'Chuyến đi',
'admin.stats.places': 'Địa điểm',
'admin.stats.photos': 'Ảnh',
'admin.stats.files': 'Tập tin',
'admin.table.user': 'người dùng',
'admin.table.email': 'Email',
'admin.table.role': 'Vai trò',
'admin.table.created': 'Tạo',
'admin.table.lastLogin': 'Đăng nhập lần cuối',
'admin.table.actions': 'hành động',
'admin.you': '(Bạn)',
'admin.editUser': 'Chỉnh sửa người dùng',
'admin.newPassword': 'Mật khẩu mới',
'admin.newPasswordHint': 'Để trống để giữ mật khẩu hiện tại',
'admin.deleteUser': 'Xóa người dùng "{name}"? Tất cả các chuyến đi sẽ bị xóa vĩnh viễn.',
'admin.deleteUserTitle': 'Xóa người dùng',
'admin.newPasswordPlaceholder': 'Nhập mật khẩu mới…',
'admin.toast.loadError': 'Không tải được dữ liệu quản trị viên',
'admin.toast.userUpdated': 'Đã cập nhật người dùng',
'admin.toast.updateError': 'Không thể cập nhật',
'admin.toast.userDeleted': 'Người dùng đã xóa',
'admin.toast.deleteError': 'Không thể xóa',
'admin.toast.cannotDeleteSelf': 'Không thể xóa tài khoản của chính bạn',
'admin.toast.userCreated': 'Người dùng đã tạo',
'admin.toast.createError': 'Không tạo được người dùng',
'admin.toast.fieldsRequired': 'Tên người dùng, email và mật khẩu là bắt buộc',
'admin.createUser': 'Tạo người dùng',
'admin.invite.title': 'Mời liên kết',
'admin.invite.subtitle': 'Tạo liên kết đăng ký một lần',
'admin.invite.create': 'Tạo liên kết',
'admin.invite.createAndCopy': 'Tạo & Sao chép',
'admin.invite.empty': 'Chưa có liên kết mời nào được tạo',
'admin.invite.maxUses': 'Tối đa. Công dụng',
'admin.invite.expiry': 'Hết hạn sau',
'admin.invite.uses': 'đã sử dụng',
'admin.invite.expiresAt': 'hết hạn',
'admin.invite.createdBy': 'qua',
'admin.invite.active': 'Tích cực',
'admin.invite.expired': 'Hết hạn',
'admin.invite.usedUp': 'Đã sử dụng hết',
'admin.invite.copied': 'Đã sao chép liên kết lời mời vào bảng nhớ tạm',
'admin.invite.copyLink': 'Sao chép liên kết',
'admin.invite.deleted': 'Đã xóa liên kết mời',
'admin.invite.createError': 'Không tạo được liên kết mời',
'admin.invite.deleteError': 'Không xóa được liên kết mời',
'admin.tabs.settings': 'Cài đặt',
'admin.allowRegistration': 'Cho phép đăng ký',
'admin.allowRegistrationHint': 'Người dùng mới có thể tự đăng ký',
'admin.authMethods': 'Phương thức xác thực',
'admin.passwordLogin': 'Mật khẩu Đăng nhập',
'admin.passwordLoginHint': 'Cho phép người dùng đăng nhập bằng email và mật khẩu',
'admin.passwordRegistration': 'Đăng ký mật khẩu',
'admin.passwordRegistrationHint': 'Cho phép người dùng mới đăng ký bằng email và mật khẩu',
'admin.oidcLogin': 'SSO Đăng nhập',
'admin.oidcLoginHint': 'Cho phép người dùng đăng nhập bằng SSO',
'admin.oidcRegistration': 'SSO Tự động cấp phép',
'admin.oidcRegistrationHint': 'Tự động tạo tài khoản cho người dùng SSO mới',
'admin.envOverrideHint':
'Cài đặt đăng nhập mật khẩu được kiểm soát bởi biến môi trường OIDC_ONLY và không thể thay đổi tại đây.',
'admin.lockoutWarning': 'Ít nhất một phương thức đăng nhập phải được bật',
'admin.requireMfa': 'Yêu cầu xác thực hai yếu tố (2FA)',
'admin.requireMfaHint': 'Người dùng không có 2FA phải hoàn tất thiết lập trong Cài đặt trước khi sử dụng ứng dụng.',
'admin.apiKeys': 'API Chìa khóa',
'admin.apiKeysHint': 'Không bắt buộc. Cho phép dữ liệu địa điểm mở rộng như ảnh và thời tiết.',
'admin.mapsKey': 'Google Maps API Chìa khóa',
'admin.mapsKeyHint': 'Cần thiết cho tìm kiếm địa điểm. Truy cập tại console.cloud.google.com',
'admin.mapsKeyHintLong':
'Nếu không có khóa API, OpenStreetMap sẽ được sử dụng để tìm kiếm địa điểm. Với khóa Google API, bạn cũng có thể tải ảnh, xếp hạng và giờ mở cửa. Nhận một cái tại console.cloud.google.com.',
'admin.recommended': 'Khuyến khích',
'admin.weatherKey': 'OpenWeatherMap API Chìa khóa',
'admin.weatherKeyHint': 'Đối với dữ liệu thời tiết. Miễn phí tại openweathermap.org',
'admin.validateKey': 'Bài kiểm tra',
'admin.keyValid': 'Đã kết nối',
'admin.keyInvalid': 'Không hợp lệ',
'admin.keySaved': 'Đã lưu khóa API',
'admin.oidcTitle': 'Đăng nhập một lần (OIDC)',
'admin.oidcSubtitle': 'Cho phép đăng nhập thông qua các nhà cung cấp bên ngoài như Google, Apple, Authentik hoặc Keycloak.',
'admin.oidcDisplayName': 'Tên hiển thị',
'admin.oidcIssuer': 'Nhà phát hành URL',
'admin.oidcIssuerHint': 'Nhà phát hành kết nối OpenID URL của nhà cung cấp. ví dụ. https://accounts.google.com',
'admin.oidcSaved': 'Đã lưu cấu hình OIDC',
'admin.oidcOnlyMode': 'Vô hiệu hóa xác thực mật khẩu',
'admin.oidcOnlyModeHint':
'Khi được bật, chỉ cho phép đăng nhập SSO. Đăng nhập và đăng ký dựa trên mật khẩu bị chặn.',
'admin.fileTypes': 'Các loại tệp được phép',
'admin.fileTypesHint': 'Định cấu hình loại tệp mà người dùng có thể tải lên.',
'admin.fileTypesFormat': 'Các phần mở rộng được phân tách bằng dấu phẩy (ví dụ: jpg,png,pdf,doc). Sử dụng * để cho phép tất cả các loại.',
'admin.fileTypesSaved': 'Đã lưu cài đặt loại tệp',
'admin.placesPhotos.title': 'Đặt ảnh',
'admin.placesPhotos.subtitle':
'Tìm nạp ảnh từ Google Địa điểm API. Tắt để lưu hạn ngạch API. Hình ảnh của Wikimedia không bị ảnh hưởng.',
'admin.placesAutocomplete.title': 'Đặt Tự động hoàn thành',
'admin.placesAutocomplete.subtitle': 'Sử dụng Google Địa điểm API để có các đề xuất tìm kiếm. Tắt để lưu hạn ngạch API.',
'admin.placesDetails.title': 'Chi tiết địa điểm',
'admin.placesDetails.subtitle':
'Tìm nạp thông tin chi tiết về địa điểm (giờ, xếp hạng, trang web) từ Google Địa điểm API. Tắt để lưu hạn ngạch API.',
'admin.bagTracking.title': 'Theo dõi túi',
'admin.bagTracking.subtitle': 'Cho phép phân bổ trọng lượng và túi để đóng gói các mặt hàng',
'admin.collab.chat.title': 'Trò chuyện',
'admin.collab.chat.subtitle': 'Nhắn tin theo thời gian thực để cộng tác trong chuyến đi',
'admin.collab.notes.title': 'Ghi chú',
'admin.collab.notes.subtitle': 'Ghi chú và tài liệu được chia sẻ',
'admin.collab.polls.title': 'Thăm dò ý kiến',
'admin.collab.polls.subtitle': 'Thăm dò ý kiến ​​​​nhóm và bỏ phiếu',
'admin.collab.whatsnext.title': 'Tiếp theo là gì',
'admin.collab.whatsnext.subtitle': 'Đề xuất hoạt động và các bước tiếp theo',
'admin.tabs.config': 'Cá nhân hóa',
'admin.tabs.defaults': 'Mặc định của người dùng',
'admin.defaultSettings.title': 'Cài đặt người dùng mặc định',
'admin.defaultSettings.description':
'Đặt mặc định cho toàn phiên bản. Người dùng chưa thay đổi cài đặt sẽ thấy các giá trị này. Những thay đổi của riêng họ luôn được ưu tiên.',
'admin.defaultSettings.saved': 'Đã lưu mặc định',
'admin.defaultSettings.reset': 'Đặt lại về mặc định tích hợp',
'admin.defaultSettings.resetToBuiltIn': 'cài lại',
'admin.defaultSettings.mapProvider': 'Công cụ bản đồ',
'admin.defaultSettings.mapProviderHint':
'Bản đồ mặc định cho mọi người trong trường hợp này. Mỗi người dùng vẫn có thể ghi đè nó trong cài đặt của riêng họ.',
'admin.defaultSettings.providerLeaflet': 'Tiêu chuẩn (miễn phí)',
'admin.defaultSettings.providerMapbox': 'Mapbox (3D)',
'admin.defaultSettings.providerMapLibre': 'MapLibre (OpenFreeMap)',
'admin.defaultSettings.mapboxToken': 'Mã thông báo Mapbox được chia sẻ',
'admin.defaultSettings.mapboxTokenHint':
'Được sử dụng cho mọi người dùng chưa nhập mã thông báo của riêng họ — vì vậy toàn bộ phiên bản sẽ nhận được Mapbox mà không chia sẻ khóa riêng lẻ. Được lưu trữ được mã hóa.',
'admin.defaultSettings.mapboxStyle': 'Kiểu bản đồ',
'admin.defaultSettings.mapboxStylePlaceholder': 'Chọn một phong cách…',
'admin.defaultSettings.mapbox3d': 'Tòa nhà và địa hình 3D',
'admin.defaultSettings.mapboxQuality': 'Chế độ chất lượng cao',
'admin.tabs.templates': 'Mẫu đóng gói',
'admin.packingTemplates.title': 'Mẫu đóng gói',
'admin.packingTemplates.subtitle': 'Tạo danh sách đóng gói có thể tái sử dụng cho chuyến đi của bạn',
'admin.packingTemplates.create': 'Mẫu mới',
'admin.packingTemplates.namePlaceholder': 'Tên mẫu (ví dụ: Kỳ nghỉ ở bãi biển)',
'admin.packingTemplates.empty': 'Chưa có mẫu nào được tạo',
'admin.packingTemplates.items': 'mặt hàng',
'admin.packingTemplates.categories': 'Thể loại',
'admin.packingTemplates.itemName': 'Tên mặt hàng',
'admin.packingTemplates.itemCategory': 'Loại',
'admin.packingTemplates.categoryName': 'Tên danh mục (ví dụ: Quần áo)',
'admin.packingTemplates.addCategory': 'Thêm danh mục',
'admin.packingTemplates.created': 'Đã tạo mẫu',
'admin.packingTemplates.deleted': 'Đã xóa mẫu',
'admin.packingTemplates.loadError': 'Không tải được mẫu',
'admin.packingTemplates.createError': 'Không tạo được mẫu',
'admin.packingTemplates.deleteError': 'Không xóa được mẫu',
'admin.packingTemplates.saveError': 'Không lưu được',
'admin.tabs.addons': 'Tiện ích bổ sung',
'admin.addons.title': 'Tiện ích bổ sung',
'admin.addons.subtitle': 'Bật hoặc tắt các tính năng để tùy chỉnh trải nghiệm TREK của bạn.',
'admin.addons.catalog.packing.name': 'Danh sách',
'admin.addons.catalog.packing.description': 'Danh sách đóng gói và nhiệm vụ cần làm cho chuyến đi của bạn',
'admin.addons.catalog.budget.name': 'Ngân sách',
'admin.addons.catalog.budget.description': 'Theo dõi chi phí và lập kế hoạch ngân sách chuyến đi của bạn',
'admin.addons.catalog.documents.name': 'Tài liệu',
'admin.addons.catalog.documents.description': 'Lưu trữ và quản lý tài liệu du lịch',
'admin.addons.catalog.vacay.name': 'Kỳ nghỉ',
'admin.addons.catalog.vacay.description': 'Kế hoạch kỳ nghỉ cá nhân với chế độ xem lịch',
'admin.addons.catalog.atlas.name': 'Bản đồ',
'admin.addons.catalog.atlas.description': 'Bản đồ thế giới với các quốc gia đã ghé thăm và số liệu thống kê du lịch',
'admin.addons.catalog.collab.name': 'Cộng tác',
'admin.addons.catalog.collab.description': 'Ghi chú, thăm dò ý kiến ​​và trò chuyện theo thời gian thực để lập kế hoạch chuyến đi',
'admin.addons.catalog.memories.name': 'Hình ảnh (Immich)',
'admin.addons.catalog.memories.description': 'Chia sẻ ảnh chuyến đi qua phiên bản Immich của bạn',
'admin.addons.catalog.mcp.name': 'MCP',
'admin.addons.catalog.mcp.description': 'Giao thức ngữ cảnh mẫu để tích hợp trợ lý AI',
'admin.addons.subtitleBefore': 'Bật hoặc tắt các tính năng để tùy chỉnh',
'admin.addons.subtitleAfter': 'kinh nghiệm.',
'admin.addons.enabled': 'Đã bật',
'admin.addons.disabled': 'Tàn tật',
'admin.addons.type.trip': 'Chuyến đi',
'admin.addons.type.global': 'Toàn cầu',
'admin.addons.type.integration': 'Tích hợp',
'admin.addons.tripHint': 'Có sẵn dưới dạng một tab trong mỗi chuyến đi',
'admin.addons.globalHint': 'Có sẵn dưới dạng một phần độc lập trong điều hướng chính',
'admin.addons.integrationHint': 'Dịch vụ phụ trợ và tích hợp API không có trang chuyên dụng',
'admin.addons.toast.updated': 'Đã cập nhật tiện ích bổ sung',
'admin.addons.toast.error': 'Không thể cập nhật tiện ích bổ sung',
'admin.addons.noAddons': 'Không có tiện ích bổ sung nào',
'admin.weather.title': 'Dữ liệu thời tiết',
'admin.weather.badge': 'Kể từ ngày 24 tháng 3 năm 2026',
'admin.weather.description':
'TREK sử dụng Open-Meteo làm nguồn dữ liệu thời tiết. Open-Meteo là dịch vụ thời tiết nguồn mở, miễn phí — không yêu cầu khóa API.',
'admin.weather.forecast': 'dự báo 16 ngày',
'admin.weather.forecastDesc': 'Trước đây 5 ngày (OpenWeatherMap)',
'admin.weather.climate': 'Dữ liệu khí hậu lịch sử',
'admin.weather.climateDesc': 'Trung bình từ 85 năm qua cho những ngày vượt quá dự báo 16 ngày',
'admin.weather.requests': '10.000 yêu cầu/ngày',
'admin.weather.requestsDesc': 'Miễn phí, không cần khóa API',
'admin.weather.locationHint':
'Thời tiết dựa trên địa điểm đầu tiên có tọa độ mỗi ngày. Nếu không có địa điểm nào được chỉ định cho một ngày thì bất kỳ địa điểm nào trong danh sách địa điểm đều được sử dụng làm tham chiếu.',
'admin.tabs.mcpTokens': 'MCP Truy cập',
'admin.mcpTokens.title': 'MCP Truy cập',
'admin.mcpTokens.subtitle': 'Quản lý phiên OAuth và mã thông báo API trên tất cả người dùng',
'admin.mcpTokens.sectionTitle': 'API Mã thông báo',
'admin.mcpTokens.owner': 'Người sở hữu',
'admin.mcpTokens.tokenName': 'Tên mã thông báo',
'admin.mcpTokens.created': 'Tạo',
'admin.mcpTokens.lastUsed': 'Được sử dụng lần cuối',
'admin.mcpTokens.never': 'Không bao giờ',
'admin.mcpTokens.empty': 'Chưa có mã thông báo MCP nào được tạo',
'admin.mcpTokens.deleteTitle': 'Xóa mã thông báo',
'admin.mcpTokens.deleteMessage':
'Điều này sẽ thu hồi mã thông báo ngay lập tức. Người dùng sẽ mất quyền truy cập MCP thông qua mã thông báo này.',
'admin.mcpTokens.deleteSuccess': 'Đã xóa mã thông báo',
'admin.mcpTokens.deleteError': 'Không xóa được mã thông báo',
'admin.mcpTokens.loadError': 'Không thể tải mã thông báo',
'admin.oauthSessions.sectionTitle': 'OAuth Phiên',
'admin.oauthSessions.clientName': 'Khách hàng',
'admin.oauthSessions.owner': 'Người sở hữu',
'admin.oauthSessions.scopes': 'Phạm vi',
'admin.oauthSessions.created': 'Tạo',
'admin.oauthSessions.empty': 'Không có phiên OAuth nào hoạt động',
'admin.oauthSessions.revokeTitle': 'Thu hồi phiên',
'admin.oauthSessions.revokeMessage':
'Thao tác này sẽ thu hồi phiên OAuth ngay lập tức. Khách hàng sẽ mất quyền truy cập MCP.',
'admin.oauthSessions.revokeSuccess': 'Phiên bị thu hồi',
'admin.oauthSessions.revokeError': 'Không thể thu hồi phiên',
'admin.oauthSessions.loadError': 'Không tải được OAuth phiên',
'admin.tabs.github': 'GitHub',
'admin.audit.subtitle': 'Các sự kiện quản trị và nhạy cảm về bảo mật (sao lưu, người dùng, MFA, cài đặt).',
'admin.audit.empty': 'Chưa có mục kiểm toán nào.',
'admin.audit.refresh': 'Làm cho khỏe lại',
'admin.audit.loadMore': 'Tải thêm',
'admin.audit.showing': '{count} đã tải · tổng cộng {total}',
'admin.audit.col.time': 'Thời gian',
'admin.audit.col.user': 'người dùng',
'admin.audit.col.action': 'Hoạt động',
'admin.audit.col.resource': 'Tài nguyên',
'admin.audit.col.ip': 'IP',
'admin.audit.col.details': 'Chi tiết',
'admin.github.title': 'Lịch sử phát hành',
'admin.github.subtitle': 'Cập nhật mới nhất từ ​​{repo}',
'admin.github.latest': 'Mới nhất',
'admin.github.prerelease': 'Phát hành trước',
'admin.github.showDetails': 'Hiển thị chi tiết',
'admin.github.hideDetails': 'Ẩn chi tiết',
'admin.github.loadMore': 'Tải thêm',
'admin.github.loading': 'Đang tải...',
'admin.github.error': 'Không tải được bản phát hành',
'admin.github.by': 'qua',
'admin.github.support': 'Giúp tôi tiếp tục xây dựng TREK',
'admin.update.available': 'Đã có bản cập nhật',
'admin.update.text': 'TREK {version} có sẵn. Bạn đang chạy {current}.',
'admin.update.button': 'Xem trên GitHub',
'admin.update.install': 'Cài đặt bản cập nhật',
'admin.update.confirmTitle': 'Cài đặt bản cập nhật?',
'admin.update.confirmText':
'TREK sẽ được cập nhật từ {current} lên {version}. Máy chủ sẽ tự động khởi động lại sau đó.',
'admin.update.dataInfo': 'Tất cả dữ liệu của bạn (chuyến đi, người dùng, khóa API, nội dung tải lên, Vacay, Atlas, ngân sách) sẽ được giữ nguyên.',
'admin.update.warning': 'Ứng dụng sẽ không khả dụng trong thời gian ngắn khi khởi động lại.',
'admin.update.confirm': 'Cập nhật ngay',
'admin.update.installing': 'Đang cập nhật…',
'admin.update.success': 'Đã cài đặt bản cập nhật! Máy chủ đang khởi động lại…',
'admin.update.failed': 'Cập nhật không thành công',
'admin.update.backupHint': 'Chúng tôi khuyên bạn nên tạo bản sao lưu trước khi cập nhật.',
'admin.update.backupLink': 'Đi tới Sao lưu',
'admin.update.howTo': 'Cách cập nhật',
'admin.update.dockerText':
'Phiên bản TREK của bạn chạy trong Docker. Để cập nhật lên {version}, hãy chạy các lệnh sau trên máy chủ của bạn:',
'admin.update.nonDockerText':
'Phiên bản TREK này không chạy trong Docker. Để cập nhật lên {version}, hãy chạy lại phương pháp cài đặt hoặc cập nhật mà bạn đã sử dụng — ví dụ: trên Proxmox Community Script chạy bản cập nhật từ bảng điều khiển LXC:',
'admin.update.wikiLink': 'Mở hướng dẫn cập nhật',
'admin.update.reloadHint': 'Vui lòng tải lại trang sau vài giây.',
'admin.tabs.permissions': 'Quyền',
'admin.addons.catalog.journey.name': 'Hành trình',
'admin.addons.catalog.journey.description':
'Theo dõi chuyến đi & nhật ký du lịch với thông tin đăng ký, ảnh và câu chuyện hàng ngày',
'admin.passkey.title': 'Đăng nhập bằng mật mã',
'admin.passkey.cardHint': 'Cho phép người dùng đăng nhập bằng mật mã (WebAuthn). Tắt theo mặc định.',
'admin.passkey.login': 'Kích hoạt đăng nhập bằng mật mã',
'admin.passkey.loginHint': 'Hiển thị tùy chọn "Đăng nhập bằng mật mã" và cho phép người dùng đăng ký mật mã trong cài đặt của họ.',
'admin.passkey.notConfigured':
'Chưa có miền WebAuthn nào giải quyết được việc triển khai này. Đặt APP_URL hoặc Relying Party ID bên dưới — mật mã sẽ được ẩn cho đến lúc đó.',
'admin.passkey.rpId': 'Đảng dựa vào ID (miền)',
'admin.passkey.rpIdHint':
'Các mật khẩu tên miền trần bị ràng buộc, ví dụ: didau.vn. Để trống để lấy nó từ APP_URL. Việc thay đổi nó sau này sẽ làm mất hiệu lực các mật mã hiện có.',
'admin.passkey.origins': 'Nguồn gốc được phép',
'admin.passkey.originsHint':
'Nguồn gốc đầy đủ được phân tách bằng dấu phẩy, ví dụ: https://didau.vn. Để trống để sử dụng APP_URL.',
'admin.passkey.reset': 'Đặt lại mật khẩu',
'admin.passkey.resetHint':
'Xóa tất cả mật mã của người dùng này (ví dụ: trên thiết bị bị mất). Họ vẫn có thể đăng nhập bằng mật khẩu của mình.',
'admin.passkey.resetConfirm': 'Xóa tất cả mật mã cho {name}?',
'admin.passkey.resetDone': 'Đã xóa {count} mật mã',
};
export default admin;
+6
View File
@@ -0,0 +1,6 @@
import type { TranslationStrings } from '../types';
const airport: TranslationStrings = {
'airport.searchPlaceholder': 'Mã sân bay hoặc thành phố (ví dụ: FRA)',
};
export default airport;
+58
View File
@@ -0,0 +1,58 @@
import type { TranslationStrings } from '../types';
const atlas: TranslationStrings = {
'atlas.subtitle': 'Dấu chân du lịch của bạn trên khắp thế giới',
'atlas.countries': 'Quốc gia',
'atlas.trips': 'Chuyến đi',
'atlas.places': 'Địa điểm',
'atlas.unmark': 'Di dời',
'atlas.confirmMark': 'Đánh dấu quốc gia này là đã ghé thăm?',
'atlas.confirmUnmark': 'Xóa quốc gia này khỏi danh sách bạn đã ghé thăm?',
'atlas.confirmUnmarkRegion': 'Xóa khu vực này khỏi danh sách bạn đã ghé thăm?',
'atlas.markVisited': 'Đánh dấu là đã ghé thăm',
'atlas.markVisitedHint': 'Thêm quốc gia này vào danh sách bạn đã ghé thăm',
'atlas.markRegionVisitedHint': 'Thêm khu vực này vào danh sách bạn đã ghé thăm',
'atlas.addToBucket': 'Thêm vào danh sách nhóm',
'atlas.addPoi': 'Thêm địa điểm',
'atlas.searchCountry': 'Tìm kiếm một quốc gia...',
'atlas.bucketNamePlaceholder': 'Tên (quốc gia, thành phố, địa điểm...)',
'atlas.month': 'Tháng',
'atlas.year': 'Năm',
'atlas.addToBucketHint': 'Lưu làm địa điểm bạn muốn ghé thăm',
'atlas.bucketWhen': 'Khi nào bạn có kế hoạch đến thăm?',
'atlas.statsTab': 'Thống kê',
'atlas.bucketTab': 'Danh sách nhóm',
'atlas.addBucket': 'Thêm vào danh sách nhóm',
'atlas.bucketNotesPlaceholder': 'Ghi chú (tùy chọn)',
'atlas.bucketEmpty': 'Danh sách nhóm của bạn trống',
'atlas.bucketEmptyHint': 'Thêm địa điểm bạn mơ ước được ghé thăm',
'atlas.days': 'Ngày',
'atlas.visitedCountries': 'Các nước đã ghé thăm',
'atlas.cities': 'Thành phố',
'atlas.noData': 'Chưa có dữ liệu du lịch',
'atlas.noDataHint': 'Tạo chuyến đi và thêm địa điểm để xem bản đồ thế giới của bạn',
'atlas.lastTrip': 'Chuyến đi cuối cùng',
'atlas.nextTrip': 'Chuyến đi tiếp theo',
'atlas.daysLeft': 'ngày còn lại',
'atlas.streak': 'Vệt',
'atlas.years': 'năm',
'atlas.yearInRow': 'năm liên tiếp',
'atlas.yearsInRow': 'năm liên tiếp',
'atlas.tripIn': 'chuyến đi vào',
'atlas.tripsIn': 'chuyến đi trong',
'atlas.since': 'từ',
'atlas.europe': 'Châu Âu',
'atlas.asia': 'Châu Á',
'atlas.northAmerica': 'N. Mỹ',
'atlas.southAmerica': 'S. Mỹ',
'atlas.africa': 'Châu phi',
'atlas.oceania': 'Châu Đại Dương',
'atlas.other': 'Khác',
'atlas.firstVisit': 'Chuyến đi đầu tiên',
'atlas.lastVisitLabel': 'Chuyến đi cuối cùng',
'atlas.tripSingular': 'Chuyến đi',
'atlas.tripPlural': 'Chuyến đi',
'atlas.placeVisited': 'Nơi đã ghé thăm',
'atlas.placesVisited': 'Địa điểm đã ghé thăm',
};
export default atlas;
+72
View File
@@ -0,0 +1,72 @@
import type { TranslationStrings } from '../types';
const backup: TranslationStrings = {
'backup.title': 'Sao lưu dữ liệu',
'backup.subtitle': 'Cơ sở dữ liệu và tất cả các tệp được tải lên',
'backup.refresh': 'Làm cho khỏe lại',
'backup.upload': 'Tải lên bản sao lưu',
'backup.uploading': 'Đang tải lên…',
'backup.create': 'Tạo bản sao lưu',
'backup.creating': 'Đang tạo…',
'backup.empty': 'Chưa có bản sao lưu nào',
'backup.createFirst': 'Tạo bản sao lưu đầu tiên',
'backup.download': 'Tải xuống',
'backup.restore': 'Khôi phục',
'backup.confirm.restore': 'Khôi phục bản sao lưu "{name}"?\n\nTất cả dữ liệu hiện tại sẽ được thay thế bằng bản sao lưu.',
'backup.confirm.uploadRestore': 'Tải lên và khôi phục tập tin sao lưu "{name}"?\n\nTất cả dữ liệu hiện tại sẽ bị ghi đè.',
'backup.confirm.delete': 'Xóa bản sao lưu "{name}"?',
'backup.toast.loadError': 'Không tải được bản sao lưu',
'backup.toast.created': 'Sao lưu được tạo thành công',
'backup.toast.createError': 'Không tạo được bản sao lưu',
'backup.toast.restored': 'Đã khôi phục bản sao lưu. Trang sẽ tải lại…',
'backup.toast.restoreError': 'Không thể khôi phục',
'backup.toast.uploadError': 'Không thể tải lên',
'backup.toast.deleted': 'Đã xóa bản sao lưu',
'backup.toast.deleteError': 'Không thể xóa',
'backup.toast.downloadError': 'Tải xuống không thành công',
'backup.toast.settingsSaved': 'Đã lưu cài đặt tự động sao lưu',
'backup.toast.settingsError': 'Không lưu được cài đặt',
'backup.auto.title': 'Tự động sao lưu',
'backup.auto.subtitle': 'Tự động sao lưu theo lịch trình',
'backup.auto.enable': 'Bật tự động sao lưu',
'backup.auto.enableHint': 'Sao lưu sẽ được tạo tự động theo lịch trình đã chọn',
'backup.auto.interval': 'Khoảng thời gian',
'backup.auto.hour': 'Chạy theo giờ',
'backup.auto.hourHint': 'Giờ địa phương của máy chủ (định dạng {format})',
'backup.auto.dayOfWeek': 'Ngày trong tuần',
'backup.auto.dayOfMonth': 'Ngày trong tháng',
'backup.auto.dayOfMonthHint': 'Giới hạn ở 1–28 để tương thích với tất cả các tháng',
'backup.auto.scheduleSummary': 'Lịch trình',
'backup.auto.summaryDaily': 'Hàng ngày lúc {hour}:00',
'backup.auto.summaryWeekly': 'Mỗi {day} lúc {hour}:00',
'backup.auto.summaryMonthly': 'Ngày {day} hàng tháng lúc {hour}:00',
'backup.auto.envLocked': 'Docker',
'backup.auto.envLockedHint':
'Tự động sao lưu được cấu hình thông qua các biến môi trường Docker. Để thay đổi các cài đặt này, hãy cập nhật docker-compose.yml của bạn và khởi động lại vùng chứa.',
'backup.auto.copyEnv': 'Sao chép Docker env vars',
'backup.auto.envCopied': 'Docker env vars được sao chép vào clipboard',
'backup.auto.keepLabel': 'Xóa bản sao lưu cũ sau',
'backup.dow.sunday': 'Chủ nhật',
'backup.dow.monday': 'Thứ hai',
'backup.dow.tuesday': 'thứ ba',
'backup.dow.wednesday': 'Thứ tư',
'backup.dow.thursday': 'Thứ năm',
'backup.dow.friday': 'Thứ Sáu',
'backup.dow.saturday': 'Thứ bảy',
'backup.interval.hourly': 'Hàng giờ',
'backup.interval.daily': 'Hằng ngày',
'backup.interval.weekly': 'hàng tuần',
'backup.interval.monthly': 'hàng tháng',
'backup.keep.1day': '1 ngày',
'backup.keep.3days': '3 ngày',
'backup.keep.7days': '7 ngày',
'backup.keep.14days': '14 ngày',
'backup.keep.30days': '30 ngày',
'backup.keep.forever': 'Giữ mãi mãi',
'backup.restoreConfirmTitle': 'Khôi phục bản sao lưu?',
'backup.restoreWarning':
'Tất cả dữ liệu hiện tại (chuyến đi, địa điểm, người dùng, nội dung tải lên) sẽ được thay thế vĩnh viễn bằng bản sao lưu. Không thể hoàn tác hành động này.',
'backup.restoreTip': 'Mẹo: Tạo bản sao lưu trạng thái hiện tại trước khi khôi phục.',
'backup.restoreConfirm': 'Có, khôi phục',
};
export default backup;
+121
View File
@@ -0,0 +1,121 @@
import type { TranslationStrings } from '../types';
const budget: TranslationStrings = {
'budget.title': 'Ngân sách',
'budget.exportCsv': 'Xuất CSV',
'budget.emptyTitle': 'Chưa có ngân sách nào được tạo',
'budget.emptyText': 'Tạo danh mục và mục để lập kế hoạch ngân sách du lịch của bạn',
'budget.emptyPlaceholder': 'Nhập tên danh mục...',
'budget.createCategory': 'Tạo danh mục',
'budget.category': 'Loại',
'budget.categoryName': 'Tên danh mục',
'budget.table.name': 'Tên',
'budget.table.total': 'Tổng cộng',
'budget.table.persons': 'Người',
'budget.table.days': 'Ngày',
'budget.table.perPerson': 'Mỗi người',
'budget.table.perDay': 'mỗi ngày',
'budget.table.perPersonDay': 'P.p/Ngày',
'budget.table.note': 'Ghi chú',
'budget.table.date': 'Ngày',
'budget.newEntry': 'Mục mới',
'budget.defaultEntry': 'Mục mới',
'budget.defaultCategory': 'Danh mục mới',
'budget.total': 'Tổng cộng',
'budget.totalBudget': 'Tổng ngân sách',
'budget.byCategory': 'Theo danh mục',
'budget.editTooltip': 'Bấm để chỉnh sửa',
'budget.linkedToReservation': 'Đã liên kết với đặt chỗ — chỉnh sửa tên ở đó',
'budget.confirm.deleteCategory': 'Bạn có chắc chắn muốn xóa danh mục "{name}" với các mục nhập {count} không?',
'budget.deleteCategory': 'Xóa danh mục',
'budget.perPerson': 'Mỗi người',
'budget.paid': 'Trả',
'budget.open': 'Mở',
'budget.noMembers': 'Không có thành viên nào được chỉ định',
'budget.settlement': 'thanh toán',
'budget.settlementInfo':
'Nhấp vào hình đại diện của thành viên trên mục ngân sách để đánh dấu màu xanh lục - điều này có nghĩa là họ đã thanh toán. Việc thanh toán sau đó sẽ cho thấy ai nợ ai và bao nhiêu.',
'budget.netBalances': 'Số dư ròng',
'budget.categoriesLabel': 'Thể loại',
'costs.you': 'Bạn',
'costs.youShort': 'B',
'costs.youLower': 'Bạn',
'costs.youOwe': 'Bạn nợ',
'costs.youOweSub': 'Bạn nên trả tiền cho người khác',
'costs.youreOwed': 'Bạn đang nợ',
'costs.youreOwedSub': 'Những người khác sẽ trả tiền cho bạn',
'costs.totalSpend': 'Tổng chi tiêu chuyến đi',
'costs.totalSpendSub': 'Trên tất cả khách du lịch',
'costs.to': 'ĐẾN',
'costs.from': 'Từ',
'costs.allSettled': 'Bạn đã thanh toán xong rồi',
'costs.nothingOwed': 'Không có gì nợ bạn',
'costs.yourShare': 'Chia sẻ của bạn',
'costs.youPaid': 'Bạn đã trả tiền',
'costs.expenses': 'Chi phí',
'costs.entries': '{count} mục',
'costs.searchPlaceholder': 'Chi phí tìm kiếm…',
'costs.filter.all': 'Tất cả',
'costs.filter.mine': 'Do tôi trả tiền',
'costs.filter.owed': 'tôi nợ',
'costs.addExpense': 'Thêm chi phí',
'costs.editExpense': 'Chỉnh sửa chi phí',
'costs.noMatch': 'Không có chi phí phù hợp với tìm kiếm của bạn.',
'costs.emptyText': 'Chưa có chi phí nào. Thêm cái đầu tiên của bạn.',
'costs.spent': '{amount} đã chi tiêu',
'costs.noDate': 'Không có ngày',
'costs.noOnePaid': 'Chưa có ai trả tiền',
'costs.youLent': 'bạn đã cho mượn {amount}',
'costs.youBorrowed': 'bạn đã mượn {amount}',
'costs.settleUp': 'Thanh toán',
'costs.history': 'Lịch sử',
'costs.everyoneSquare': 'Hình vuông của mọi người',
'costs.nothingOutstanding': 'Hiện chưa có khoản nợ nào chưa thanh toán.',
'costs.pay': 'chi trả',
'costs.pays': 'trả tiền',
'costs.settle': 'Thanh toán',
'costs.balances': 'Số dư',
'costs.byCategory': 'Theo danh mục',
'costs.noCategories': 'Chưa có chi phí nào.',
'costs.settleHistory': 'Thanh toán lịch sử',
'costs.noSettlements': 'Chưa có khoản nợ nào được thanh toán.',
'costs.paymentsSettled': '{count} nợ đã được thanh toán',
'costs.paid': 'trả',
'costs.undo': 'Hoàn tác',
'costs.whatFor': 'Nó dùng để làm gì?',
'costs.namePlaceholder': 'ví dụ. Ăn tối, quà lưu niệm, xăng…',
'costs.totalAmount': 'Tổng số tiền',
'costs.currency': 'Tiền tệ',
'costs.day': 'Ngày',
'costs.rateLabel': '1 {from} trong {to}',
'costs.category': 'Loại',
'costs.whoPaid': 'Ai đã trả tiền?',
'costs.splitBetween': 'Chia đều cho',
'costs.pickSomeone': 'Chọn ít nhất một người để chia tay.',
'costs.splitSummary': 'Chia {count} cách · {amount} mỗi cách',
'costs.cat.accommodation': 'Chỗ ở',
'costs.cat.food': 'Thức ăn và đồ uống',
'costs.cat.groceries': 'Cửa hàng tạp hóa',
'costs.cat.transport': 'Chuyên chở',
'costs.cat.flights': 'Chuyến bay',
'costs.cat.activities': 'Các hoạt động',
'costs.cat.sightseeing': 'Tham quan',
'costs.cat.shopping': 'Mua sắm',
'costs.cat.fees': 'Phí & vé',
'costs.cat.health': 'Sức khỏe',
'costs.cat.tips': 'Mẹo',
'costs.cat.other': 'Khác',
'costs.daysCount': '{count} ngày',
'costs.travelers': '{count} du khách',
'costs.liveRate': 'tỷ lệ trực tiếp',
'costs.settleAll': 'Thanh toán tất cả',
'costs.payment': 'Sự chi trả',
'costs.editPayment': 'Chỉnh sửa thanh toán',
'costs.addPayment': 'Thêm thanh toán',
'costs.unfinished': 'Chưa xong',
'costs.unfinishedHint': 'Chỉ tổng cộng - chưa thanh toán',
'costs.tapToInclude': 'Nhấn để bao gồm',
'costs.amount': 'Số lượng',
};
export default budget;
+25
View File
@@ -0,0 +1,25 @@
import type { TranslationStrings } from '../types';
const categories: TranslationStrings = {
'categories.title': 'Thể loại',
'categories.subtitle': 'Quản lý danh mục cho địa điểm',
'categories.new': 'Danh mục mới',
'categories.empty': 'Chưa có danh mục nào',
'categories.namePlaceholder': 'Tên danh mục',
'categories.icon': 'Biểu tượng',
'categories.color': 'Màu sắc',
'categories.customColor': 'Chọn màu tùy chỉnh',
'categories.preview': 'Xem trước',
'categories.defaultName': 'Loại',
'categories.update': 'Cập nhật',
'categories.create': 'Tạo nên',
'categories.confirm.delete': 'Xóa danh mục? Các địa điểm trong danh mục này sẽ không bị xóa.',
'categories.toast.loadError': 'Không thể tải danh mục',
'categories.toast.nameRequired': 'Vui lòng nhập tên',
'categories.toast.updated': 'Đã cập nhật danh mục',
'categories.toast.created': 'Đã tạo danh mục',
'categories.toast.saveError': 'Không lưu được',
'categories.toast.deleted': 'Đã xóa danh mục',
'categories.toast.deleteError': 'Không thể xóa',
};
export default categories;
+75
View File
@@ -0,0 +1,75 @@
import type { TranslationStrings } from '../types';
const collab: TranslationStrings = {
'collab.tabs.chat': 'Trò chuyện',
'collab.tabs.notes': 'Ghi chú',
'collab.tabs.polls': 'Thăm dò ý kiến',
'collab.whatsNext.title': 'Tiếp theo là gì',
'collab.whatsNext.today': 'Hôm nay',
'collab.whatsNext.tomorrow': 'Ngày mai',
'collab.whatsNext.empty': 'Không có hoạt động sắp tới',
'collab.whatsNext.until': 'ĐẾN',
'collab.whatsNext.emptyHint': 'Các hoạt động có thời gian sẽ xuất hiện ở đây',
'collab.chat.send': 'Gửi',
'collab.chat.placeholder': 'Nhập tin nhắn...',
'collab.chat.empty': 'Bắt đầu cuộc trò chuyện',
'collab.chat.emptyHint': 'Tin nhắn được chia sẻ với tất cả các thành viên chuyến đi',
'collab.chat.emptyDesc': 'Chia sẻ ý tưởng, kế hoạch và cập nhật với nhóm du lịch của bạn',
'collab.chat.today': 'Hôm nay',
'collab.chat.yesterday': 'Hôm qua',
'collab.chat.deletedMessage': 'đã xóa một tin nhắn',
'collab.chat.reply': 'Hồi đáp',
'collab.chat.loadMore': 'Tải tin nhắn cũ hơn',
'collab.chat.justNow': 'vừa xong',
'collab.chat.minutesAgo': '{n}phút trước',
'collab.chat.hoursAgo': '{n}h trước',
'collab.notes.title': 'Ghi chú',
'collab.notes.new': 'Ghi chú mới',
'collab.notes.empty': 'Chưa có ghi chú nào',
'collab.notes.emptyHint': 'Bắt đầu nắm bắt ý tưởng và kế hoạch',
'collab.notes.all': 'Tất cả',
'collab.notes.titlePlaceholder': 'tiêu đề ghi chú',
'collab.notes.contentPlaceholder': 'Viết một cái gì đó...',
'collab.notes.categoryPlaceholder': 'Loại',
'collab.notes.newCategory': 'Thể loại mới...',
'collab.notes.category': 'Loại',
'collab.notes.noCategory': 'Không có danh mục',
'collab.notes.color': 'Màu sắc',
'collab.notes.save': 'Lưu',
'collab.notes.cancel': 'Hủy',
'collab.notes.edit': 'Chỉnh sửa',
'collab.notes.delete': 'Xóa bỏ',
'collab.notes.confirmDeleteTitle': 'Xóa ghi chú?',
'collab.notes.confirmDeleteBody': 'Ghi chú này sẽ bị xóa vĩnh viễn.',
'collab.notes.pin': 'Ghim',
'collab.notes.unpin': 'Bỏ ghim',
'collab.notes.daysAgo': '{n} ngày trước',
'collab.notes.categorySettings': 'Quản lý danh mục',
'collab.notes.create': 'Tạo nên',
'collab.notes.website': 'Trang web',
'collab.notes.websitePlaceholder': 'https://...',
'collab.notes.attachFiles': 'Đính kèm tập tin',
'collab.notes.noCategoriesYet': 'Chưa có danh mục nào',
'collab.notes.emptyDesc': 'Tạo ghi chú để bắt đầu',
'collab.polls.title': 'Thăm dò ý kiến',
'collab.polls.new': 'Cuộc thăm dò mới',
'collab.polls.empty': 'Chưa có cuộc thăm dò nào',
'collab.polls.emptyHint': 'Hỏi nhóm và cùng nhau bỏ phiếu',
'collab.polls.question': 'Câu hỏi',
'collab.polls.questionPlaceholder': 'Chúng ta nên làm gì?',
'collab.polls.addOption': '+ Thêm tùy chọn',
'collab.polls.optionPlaceholder': 'Tùy chọn {n}',
'collab.polls.create': 'Tạo cuộc thăm dò ý kiến',
'collab.polls.close': 'Đóng',
'collab.polls.closed': 'Đã đóng',
'collab.polls.votes': '{n} phiếu bầu',
'collab.polls.vote': '{n} bầu chọn',
'collab.polls.multipleChoice': 'Nhiều lựa chọn',
'collab.polls.multiChoice': 'Nhiều lựa chọn',
'collab.polls.deadline': 'Thời hạn',
'collab.polls.option': 'Tùy chọn',
'collab.polls.options': 'Tùy chọn',
'collab.polls.delete': 'Xóa bỏ',
'collab.polls.closedSection': 'Đã đóng',
};
export default collab;
+54
View File
@@ -0,0 +1,54 @@
import type { TranslationStrings } from '../types';
const common: TranslationStrings = {
'common.save': 'Lưu',
'common.showMore': 'Hiển thị thêm',
'common.showLess': 'Hiển thị ít hơn',
'common.cancel': 'Hủy',
'common.clear': 'Xóa',
'common.delete': 'Xóa bỏ',
'common.edit': 'Chỉnh sửa',
'common.add': 'Thêm',
'common.loading': 'Đang tải...',
'common.import': 'Nhập',
'common.select': 'Chọn',
'common.selectAll': 'Chọn tất cả',
'common.deselectAll': 'Bỏ chọn tất cả',
'common.error': 'Lỗi',
'common.unknownError': 'Lỗi không xác định',
'common.tooManyAttempts': 'Quá nhiều nỗ lực. Vui lòng thử lại sau.',
'common.back': 'Quay lại',
'common.all': 'Tất cả',
'common.close': 'Đóng',
'common.open': 'Mở',
'common.upload': 'Tải lên',
'common.search': 'Tìm kiếm',
'common.confirm': 'Xác nhận',
'common.ok': 'OK',
'common.yes': 'Có',
'common.no': 'Không',
'common.or': 'hoặc',
'common.none': 'Không có',
'common.date': 'Ngày',
'common.rename': 'Đổi tên',
'common.discardChanges': 'Hủy thay đổi',
'common.discard': 'Bỏ',
'common.name': 'Tên',
'common.email': 'Email',
'common.password': 'Mật khẩu',
'common.saving': 'Đang lưu...',
'common.justNow': 'vừa xong',
'common.hoursAgo': '{count}h trước',
'common.daysAgo': '{count} ngày trước',
'common.saved': 'Đã lưu',
'common.update': 'Cập nhật',
'common.change': 'Thay đổi',
'common.uploading': 'Đang tải lên…',
'common.backToPlanning': 'Quay lại Kế hoạch',
'common.reset': 'Đặt lại',
'common.expand': 'Mở rộng',
'common.collapse': 'Thu gọn',
'common.copy': 'Sao chép',
'common.copied': 'Đã sao chép',
};
export default common;
+166
View File
@@ -0,0 +1,166 @@
import type { TranslationStrings } from '../types';
const dashboard: TranslationStrings = {
'dashboard.title': 'Chuyến đi',
'dashboard.subtitle.loading': 'Đang tải chuyến đi...',
'dashboard.subtitle.trips': '{count} chuyến đi ({archived} đã lưu trữ)',
'dashboard.subtitle.empty': 'Bắt đầu chuyến đi đầu tiên của bạn',
'dashboard.subtitle.activeOne': '{count} chuyến đi đang hoạt động',
'dashboard.subtitle.activeMany': '{count} chuyến đi đang hoạt động',
'dashboard.subtitle.archivedSuffix': '· {count} đã lưu trữ',
'dashboard.newTrip': 'Chuyến đi mới',
'dashboard.newTripSub': 'Lên kế hoạch cho một chuyến đi mới từ đầu',
'dashboard.gridView': 'Chế độ xem lưới',
'dashboard.listView': 'Chế độ xem danh sách',
'dashboard.currency': 'Tiền tệ',
'dashboard.timezone': 'Múi giờ',
'dashboard.localTime': 'Địa phương',
'dashboard.timezoneCustomTitle': 'Múi giờ tùy chỉnh',
'dashboard.timezoneCustomLabelPlaceholder': 'Nhãn (tùy chọn)',
'dashboard.timezoneCustomTzPlaceholder': 'ví dụ: America/New_York',
'dashboard.timezoneCustomAdd': 'Thêm',
'dashboard.timezoneCustomErrorEmpty': 'Nhập mã định danh múi giờ',
'dashboard.timezoneCustomErrorInvalid': 'Múi giờ không hợp lệ. Sử dụng định dạng như Europe/Berlin',
'dashboard.timezoneCustomErrorDuplicate': 'Đã thêm',
'dashboard.emptyTitle': 'Chưa có chuyến đi nào',
'dashboard.emptyText': 'Tạo chuyến đi đầu tiên của bạn và bắt đầu lập kế hoạch!',
'dashboard.emptyButton': 'Tạo chuyến đi đầu tiên',
'dashboard.nextTrip': 'Chuyến đi tiếp theo',
'dashboard.shared': 'Đã chia sẻ',
'dashboard.sharedBy': 'Được chia sẻ bởi {name}',
'dashboard.days': 'Ngày',
'dashboard.places': 'Địa điểm',
'dashboard.members': 'thành viên',
'dashboard.archive': 'Lưu trữ',
'dashboard.copyTrip': 'Sao chép',
'dashboard.copySuffix': 'sao chép',
'dashboard.restore': 'Khôi phục',
'dashboard.archived': 'Đã lưu trữ',
'dashboard.status.ongoing': 'Đang thực hiện',
'dashboard.status.today': 'Hôm nay',
'dashboard.status.tomorrow': 'Ngày mai',
'dashboard.status.past': 'Quá khứ',
'dashboard.status.daysLeft': '{count} ngày còn lại',
'dashboard.toast.loadError': 'Không tải được chuyến đi',
'dashboard.loadErrorBanner': 'Không thể truy cập máy chủ. Chuyến đi của bạn an toàn — vui lòng thử lại.',
'dashboard.retry': 'Thử lại',
'dashboard.toast.created': 'Chuyến đi được tạo thành công!',
'dashboard.toast.createError': 'Không tạo được chuyến đi',
'dashboard.toast.updated': 'Đã cập nhật chuyến đi!',
'dashboard.toast.updateError': 'Không cập nhật được chuyến đi',
'dashboard.toast.deleted': 'Chuyến đi đã bị xóa',
'dashboard.toast.deleteError': 'Không thể xóa chuyến đi',
'dashboard.toast.archived': 'Đã lưu trữ chuyến đi',
'dashboard.toast.archiveError': 'Không thể lưu trữ chuyến đi',
'dashboard.toast.restored': 'Chuyến đi được khôi phục',
'dashboard.toast.restoreError': 'Không thể khôi phục chuyến đi',
'dashboard.toast.copied': 'Chuyến đi được sao chép!',
'dashboard.toast.copyError': 'Không thể sao chép chuyến đi',
'dashboard.confirm.delete': 'Xóa chuyến đi "{title}"? Tất cả các địa điểm và kế hoạch sẽ bị xóa vĩnh viễn.',
'dashboard.confirm.copy.title': 'Sao chép chuyến đi này?',
'dashboard.confirm.copy.willCopy': 'Sẽ được sao chép',
'dashboard.confirm.copy.will1': 'Ngày, địa điểm và nhiệm vụ trong ngày',
'dashboard.confirm.copy.will2': 'Chỗ ở và đặt chỗ',
'dashboard.confirm.copy.will3': 'Các mục ngân sách và thứ tự danh mục',
'dashboard.confirm.copy.will4': 'Danh sách đóng gói (không được đánh dấu)',
'dashboard.confirm.copy.will5': 'TODO (chưa được chỉ định và chưa được kiểm tra)',
'dashboard.confirm.copy.will6': 'Ghi chú ngày',
'dashboard.confirm.copy.wontCopy': 'Sẽ không được sao chép',
'dashboard.confirm.copy.wont1': 'Cộng tác viên & nhiệm vụ thành viên',
'dashboard.confirm.copy.wont2': 'Cộng tác ghi chú, thăm dò ý kiến ​​và tin nhắn',
'dashboard.confirm.copy.wont3': 'Tệp và ảnh',
'dashboard.confirm.copy.wont4': 'Chia sẻ mã thông báo',
'dashboard.confirm.copy.confirm': 'Sao chép chuyến đi',
'dashboard.editTrip': 'Chỉnh sửa chuyến đi',
'dashboard.createTrip': 'Tạo chuyến đi mới',
'dashboard.tripTitle': 'Tiêu đề',
'dashboard.tripTitlePlaceholder': 'ví dụ. Mùa hè ở Nhật Bản',
'dashboard.tripDescription': 'Miêu tả',
'dashboard.tripDescriptionPlaceholder': 'Chuyến đi này có ý nghĩa gì?',
'dashboard.startDate': 'Ngày bắt đầu',
'dashboard.endDate': 'Ngày kết thúc',
'dashboard.dayCount': 'Số ngày',
'dashboard.dayCountHint': 'Lên kế hoạch cho bao nhiêu ngày khi không có ngày đi du lịch nào được ấn định.',
'dashboard.noDateHint': 'Không có ngày nào được đặt - 7 ngày mặc định sẽ được tạo. Bạn có thể thay đổi điều này bất cứ lúc nào.',
'dashboard.coverImage': 'Ảnh bìa',
'dashboard.addCoverImage': 'Thêm ảnh bìa (hoặc kéo và thả)',
'dashboard.addMembers': 'Bạn đồng hành',
'dashboard.addMember': 'Thêm thành viên',
'dashboard.coverSaved': 'Đã lưu ảnh bìa',
'dashboard.coverUploadError': 'Không thể tải lên',
'dashboard.coverRemoveError': 'Không thể xóa',
'dashboard.titleRequired': 'Tiêu đề là bắt buộc',
'dashboard.endDateError': 'Ngày kết thúc phải sau ngày bắt đầu',
'dashboard.greeting.morning': 'Chào buổi sáng,',
'dashboard.greeting.afternoon': 'Chào buổi chiều,',
'dashboard.greeting.evening': 'Buổi tối vui vẻ,',
'dashboard.mobile.liveNow': 'Đang diễn ra',
'dashboard.mobile.tripProgress': 'Tiến trình chuyến đi',
'dashboard.mobile.daysLeft': '{count} ngày còn lại',
'dashboard.mobile.places': 'Địa điểm',
'dashboard.mobile.buddies': 'thành viên',
'dashboard.mobile.newTrip': 'Chuyến đi mới',
'dashboard.mobile.currency': 'Tiền tệ',
'dashboard.mobile.timezone': 'Múi giờ',
'dashboard.mobile.upcomingTrips': 'Chuyến đi sắp tới',
'dashboard.mobile.yourTrips': 'Chuyến đi của bạn',
'dashboard.mobile.trips': 'chuyến đi',
'dashboard.mobile.starts': 'Bắt đầu',
'dashboard.mobile.duration': 'Khoảng thời gian',
'dashboard.mobile.day': 'ngày',
'dashboard.mobile.days': 'ngày',
'dashboard.mobile.ongoing': 'Đang thực hiện',
'dashboard.mobile.startsToday': 'Bắt đầu hôm nay',
'dashboard.mobile.tomorrow': 'Ngày mai',
'dashboard.mobile.inDays': 'Trong {count} ngày',
'dashboard.mobile.inMonths': 'Trong {count} tháng',
'dashboard.mobile.completed': 'Hoàn thành',
'dashboard.mobile.currencyConverter': 'Chuyển đổi tiền tệ',
'dashboard.filter.planned': 'Đã lên kế hoạch',
'dashboard.hero.badgeLive': 'ĐANG DIỄN RA',
'dashboard.hero.badgeToday': 'BẮT ĐẦU HÔM NAY',
'dashboard.hero.badgeTomorrow': 'NGÀY MAI',
'dashboard.hero.badgeNext': 'SẮP TỚI',
'dashboard.hero.badgeRecent': 'GẦN ĐÂY',
'dashboard.hero.tripDates': 'Ngày chuyến đi',
'dashboard.hero.noDates': 'Ngày mở',
'dashboard.hero.travelerOne': '{count} du khách',
'dashboard.hero.travelerMany': '{count} du khách',
'dashboard.hero.destinationOne': '{count} điểm đến',
'dashboard.hero.destinationMany': '{count} điểm đến',
'dashboard.hero.dayUnitOne': 'ngày',
'dashboard.hero.dayUnitMany': 'ngày',
'dashboard.hero.dayLeft': 'Ngày còn lại',
'dashboard.hero.daysLeft': 'Số ngày còn lại',
'dashboard.hero.lastDay': 'Ngày cuối cùng',
'dashboard.hero.untilStart': 'Cho đến khi bắt đầu',
'dashboard.hero.startsIn': 'Chuyến đi bắt đầu sau',
'dashboard.atlas.countriesVisited': 'Atlas · Các quốc gia đã ghé thăm',
'dashboard.atlas.ofTotal': 'của {total}',
'dashboard.atlas.tripsTotal': 'Tổng số chuyến đi',
'dashboard.atlas.placesMapped': '{count} địa điểm được ánh xạ',
'dashboard.atlas.daysTraveled': 'Số ngày đi du lịch',
'dashboard.atlas.daysUnit': 'ngày',
'dashboard.atlas.acrossAllTrips': 'trong mọi chuyến đi',
'dashboard.atlas.distanceFlown': 'Khoảng cách bay',
'dashboard.atlas.kmUnit': 'km',
'dashboard.atlas.aroundEquator': '≈ {count}× quanh xích đạo',
'dashboard.card.idea': 'Ý tưởng',
'dashboard.card.buddyOne': 'Bạn bè',
'dashboard.fx.from': 'Từ',
'dashboard.fx.to': 'ĐẾN',
'dashboard.fx.unavailable': 'Không có giá',
'dashboard.tz.searchPlaceholder': 'Tìm kiếm múi giờ…',
'dashboard.tz.empty': 'Chưa có múi giờ nào khác — thêm một múi giờ bằng +',
'dashboard.upcoming.title': 'Đặt chỗ sắp tới',
'dashboard.upcoming.empty': 'Chưa có gì được đặt trước.',
'dashboard.aria.toggleView': 'Chuyển đổi chế độ xem',
'dashboard.aria.filter': 'Lọc',
'dashboard.aria.duplicate': 'Nhân bản',
'dashboard.aria.refreshRates': 'Tốc độ làm mới',
'dashboard.aria.swapCurrencies': 'Trao đổi tiền tệ',
'dashboard.aria.addTimezone': 'Thêm múi giờ',
'dashboard.aria.removeTimezone': 'Xóa {city}',
'dashboard.dayCountRequired': 'Số ngày là bắt buộc',
};
export default dashboard;
+25
View File
@@ -0,0 +1,25 @@
import type { TranslationStrings } from '../types';
const day: TranslationStrings = {
'day.precipProb': 'Xác suất mưa',
'day.precipitation': 'Sự kết tủa',
'day.wind': 'Gió',
'day.sunrise': 'Bình minh',
'day.sunset': 'Hoàng hôn',
'day.hourlyForecast': 'Dự báo hàng giờ',
'day.climateHint': 'Trung bình lịch sử — dự báo thực tế có sẵn trong vòng 16 ngày kể từ ngày này.',
'day.noWeather': 'Không có dữ liệu thời tiết. Thêm địa điểm có tọa độ.',
'day.overview': 'Tổng quan hàng ngày',
'day.accommodation': 'Chỗ ở',
'day.addAccommodation': 'Thêm chỗ ở',
'day.hotelDayRange': 'Áp dụng cho ngày',
'day.noPlacesForHotel': 'Thêm địa điểm vào chuyến đi của bạn trước',
'day.allDays': 'Tất cả',
'day.checkIn': 'Đăng ký vào',
'day.checkInUntil': 'Cho đến khi',
'day.checkOut': 'Trả phòng',
'day.confirmation': 'Xác nhận',
'day.editAccommodation': 'Chỉnh sửa chỗ ở',
'day.reservations': 'Đặt chỗ',
};
export default day;
+55
View File
@@ -0,0 +1,55 @@
import type { TranslationStrings } from '../types';
const dayplan: TranslationStrings = {
'dayplan.icsTooltip': 'Xuất lịch (ICS)',
'dayplan.emptyDay': 'Không có địa điểm nào được lên kế hoạch cho ngày này',
'dayplan.cannotReorderTransport': 'Đặt chỗ với thời gian cố định không thể được sắp xếp lại',
'dayplan.confirmRemoveTimeTitle': 'Xóa thời gian?',
'dayplan.confirmRemoveTimeBody':
'Nơi này có thời gian cố định ({time}). Di chuyển nó sẽ loại bỏ thời gian và cho phép sắp xếp miễn phí.',
'dayplan.confirmRemoveTimeAction': 'Xóa thời gian và di chuyển',
'dayplan.confirmDeleteNoteTitle': 'Xóa ghi chú?',
'dayplan.confirmDeleteNoteBody': 'Ghi chú này sẽ bị xóa vĩnh viễn.',
'dayplan.cannotDropOnTimed': 'Các mục không thể được đặt giữa các mục có giới hạn thời gian',
'dayplan.cannotBreakChronology': 'Điều này sẽ phá vỡ thứ tự thời gian của các mục được tính thời gian và đặt chỗ',
'dayplan.addNote': 'Thêm ghi chú',
'dayplan.expandAll': 'Mở rộng tất cả các ngày',
'dayplan.collapseAll': 'Thu gọn tất cả các ngày',
'dayplan.editNote': 'Chỉnh sửa ghi chú',
'dayplan.noteAdd': 'Thêm ghi chú',
'dayplan.noteEdit': 'Chỉnh sửa ghi chú',
'dayplan.noteTitle': 'Ghi chú',
'dayplan.noteSubtitle': 'Ghi chú hàng ngày',
'dayplan.totalCost': 'Tổng chi phí',
'dayplan.days': 'Ngày',
'dayplan.dayN': 'Ngày {n}',
'dayplan.calculating': 'Đang tính...',
'dayplan.route': 'Chỉ đường',
'dayplan.optimize': 'Tối ưu hóa',
'dayplan.optimized': 'Tuyến đường được tối ưu hóa',
'dayplan.routeError': 'Không tính được lộ trình',
'dayplan.toast.needTwoPlaces': 'Cần ít nhất hai địa điểm để tối ưu hóa tuyến đường',
'dayplan.toast.routeOptimized': 'Tuyến đường được tối ưu hóa',
'dayplan.toast.routeOptimizedFromHotel': 'Tuyến đường được tối ưu hóa từ chỗ ở của bạn',
'dayplan.toast.noGeoPlaces': 'Không tìm thấy địa điểm nào có tọa độ để tính toán tuyến đường',
'dayplan.confirmed': 'Đã xác nhận',
'dayplan.pendingRes': 'Chưa giải quyết',
'dayplan.pdf': 'PDF',
'dayplan.pdfTooltip': 'Kế hoạch ngày xuất dưới dạng PDF',
'dayplan.pdfError': 'Không xuất được PDF',
'dayplan.mobile.addPlace': 'Thêm địa điểm',
'dayplan.mobile.searchPlaces': 'Tìm kiếm địa điểm...',
'dayplan.mobile.allAssigned': 'Tất cả các địa điểm được giao',
'dayplan.mobile.noMatch': 'Không có trận đấu',
'dayplan.mobile.createNew': 'Tạo địa điểm mới',
'dayplan.reorderDays': 'Sắp xếp lại ngày',
'dayplan.reorderTitle': 'Sắp xếp lại ngày',
'dayplan.reorderHint': 'Địa điểm, ghi chú và đặt chỗ trong ngày sẽ di chuyển theo nó.',
'dayplan.addDay': 'Thêm ngày',
'dayplan.moveUp': 'Di chuyển lên',
'dayplan.moveDown': 'Di chuyển xuống',
'dayplan.reorderUndo': 'Sắp xếp lại ngày',
'dayplan.reorderError': 'Không thể sắp xếp lại ngày',
'dayplan.addDayError': 'Không thể thêm ngày',
};
export default dayplan;
@@ -0,0 +1,62 @@
import type { NotificationLocale } from '../externalNotifications/types';
const en: NotificationLocale = {
email: {
footer: 'Bạn nhận được thông báo này vì bạn đã bật thông báo trong TREK.',
manage: 'Quản lý tùy chọn trong Cài đặt',
madeWith: 'Được làm bằng',
openTrek: 'Mở TREK',
},
events: {
trip_invite: (p) => ({
title: `Lời mời chuyến đi: "${p.trip}"`,
body: `${p.actor} đã mời ${p.invitee || 'a member'} tham gia chuyến đi "${p.trip}".`,
}),
booking_change: (p) => ({
title: `Đặt chổ mới: ${p.booking}`,
body: `${p.actor} đã thêm mới một ${p.type} "${p.booking}" vào "${p.trip}".`,
}),
trip_reminder: (p) => ({
title: `Nhắc nhở chuyến đi: ${p.trip}`,
body: `Hành trình "${p.trip}" sắp bất đầu!`,
}),
todo_due: (p) => ({
title: `To-do due: ${p.todo}`,
body: `"${p.todo}" trong "${p.trip}" đến hạn vào ngày ${p.due}.`,
}),
vacay_invite: (p) => ({
title: 'Lời mời kết hợp kì nghỉ',
body: `${p.actor} đã mời bạn kết hợp kế hoạch kỳ nghỉ. Mở TREK để chấp nhận hoặc từ chối.`,
}),
photos_shared: (p) => ({
title: `${p.count} đã chia sẻ hình ảnh`,
body: `${p.actor} đã chi sẻ ${p.count} ảnh trong "${p.trip}".`,
}),
collab_message: (p) => ({
title: `Tin nhắn mới trong "${p.trip}"`,
body: `${p.actor}: ${p.preview}`,
}),
packing_tagged: (p) => ({
title: `Đang đóng đồ: ${p.category}`,
body: `${p.actor} đã giao cho bạn đóng "${p.category}" trong "${p.trip}".`,
}),
version_available: (p) => ({
title: 'Đã có phiên bản TREK mới',
body: `TREK ${p.version} có bản mới. Vui lòng truy cập bảng điều khiển quản trị để cập nhật.`,
}),
synology_session_cleared: () => ({
title: 'Đã xóa phiên Synology',
body: 'Tài khoản Synology của bạn hoặc URL đã thay đổi. Bạn đã đăng xuất khỏi Synology Photos.',
}),
},
passwordReset: {
subject: 'Đặt lại mật khẩu của bạn',
greeting: 'CHÀO',
body: 'Chúng tôi đã nhận được yêu cầu đặt lại mật khẩu cho tài khoản TREK của bạn. Nhấp vào nút bên dưới để đặt mật khẩu mới.',
ctaIntro: 'Đặt lại mật khẩu',
expiry: 'Liên kết này sẽ hết hạn sau 60 phút.',
ignore: "Nếu bạn không yêu cầu điều này, bạn có thể bỏ qua email này một cách an toàn — mật khẩu của bạn sẽ không thay đổi.",
},
};
export default en;
+59
View File
@@ -0,0 +1,59 @@
import type { TranslationStrings } from '../types';
const files: TranslationStrings = {
'files.title': 'Tập tin',
'files.pageTitle': 'Tập tin & Tài liệu',
'files.subtitle': '{count} tệp cho {trip}',
'files.download': 'Tải xuống',
'files.openError': 'Không thể mở tập tin',
'files.downloadPdf': 'Tải xuống PDF',
'files.count': '{count} tập tin',
'files.countSingular': '1 tập tin',
'files.uploaded': '{count} đã tải lên',
'files.uploadError': 'Tải lên không thành công',
'files.dropzone': 'Thả tập tin ở đây',
'files.dropzoneHint': 'hoặc bấm vào để duyệt',
'files.allowedTypes': 'Hình ảnh, PDF, DOC, DOCX, XLS, XLSX, TXT, CSV · Tối đa 50 MB',
'files.uploading': 'Đang tải lên...',
'files.filterAll': 'Tất cả',
'files.filterPdf': 'PDF',
'files.filterImages': 'Hình ảnh',
'files.filterDocs': 'Tài liệu',
'files.filterCollab': 'Ghi chú cộng tác',
'files.sourceCollab': 'Từ ghi chú cộng tác',
'files.empty': 'Chưa có tập tin nào',
'files.emptyHint': 'Tải tệp lên để đính kèm vào chuyến đi của bạn',
'files.openTab': 'Mở trong tab mới',
'files.confirm.delete': 'Bạn có chắc chắn muốn xóa tập tin này?',
'files.toast.deleted': 'Đã xóa tệp',
'files.toast.deleteError': 'Không thể xóa tập tin',
'files.sourcePlan': 'Kế hoạch ngày',
'files.sourceBooking': 'Đặt chỗ',
'files.sourceTransport': 'Chuyên chở',
'files.attach': 'Gắn',
'files.pasteHint': 'Bạn cũng có thể dán hình ảnh từ clipboard (Ctrl+V)',
'files.trash': 'Rác',
'files.trashEmpty': 'Thùng rác trống rỗng',
'files.emptyTrash': 'Dọn sạch thùng rác',
'files.restore': 'Khôi phục',
'files.star': 'Ngôi sao',
'files.unstar': 'Bỏ dấu sao',
'files.assign': 'Giao phó',
'files.assignTitle': 'Gán tập tin',
'files.assignPlace': 'Địa điểm',
'files.assignBooking': 'Đặt chỗ',
'files.assignTransport': 'Chuyên chở',
'files.unassigned': 'Chưa được chỉ định',
'files.unlink': 'Xóa liên kết',
'files.toast.trashed': 'Đã chuyển vào thùng rác',
'files.toast.restored': 'Đã khôi phục tệp',
'files.toast.trashEmptied': 'Đã dọn sạch thùng rác',
'files.toast.assigned': 'Tệp được chỉ định',
'files.toast.assignError': 'Bài tập không thành công',
'files.toast.restoreError': 'Khôi phục không thành công',
'files.confirm.permanentDelete': 'Xóa vĩnh viễn tập tin này? Điều này không thể hoàn tác được.',
'files.confirm.emptyTrash': 'Xóa vĩnh viễn tất cả các tập tin vào thùng rác? Điều này không thể hoàn tác được.',
'files.noteLabel': 'Ghi chú',
'files.notePlaceholder': 'Thêm ghi chú...',
};
export default files;
+86
View File
@@ -0,0 +1,86 @@
import admin from './admin';
import airport from './airport';
import atlas from './atlas';
import backup from './backup';
import budget from './budget';
import categories from './categories';
import collab from './collab';
import common from './common';
import dashboard from './dashboard';
import day from './day';
import dayplan from './dayplan';
import files from './files';
import inspector from './inspector';
import journey from './journey';
import login from './login';
import map from './map';
import members from './members';
import memories from './memories';
import nav from './nav';
import notif from './notif';
import notifications from './notifications';
import oauth from './oauth';
import packing from './packing';
import pdf from './pdf';
import perm from './perm';
import photos from './photos';
import places from './places';
import planner from './planner';
import register from './register';
import reservations from './reservations';
import settings from './settings';
import share from './share';
import shared from './shared';
import stats from './stats';
import system_notice from './system_notice';
import todo from './todo';
import transport from './transport';
import trip from './trip';
import trips from './trips';
import undo from './undo';
import vacay from './vacay';
const locale = {
...common,
...trips,
...nav,
...dashboard,
...settings,
...admin,
...dayplan,
...share,
...shared,
...login,
...register,
...vacay,
...atlas,
...trip,
...places,
...inspector,
...reservations,
...airport,
...map,
...budget,
...files,
...packing,
...members,
...categories,
...backup,
...photos,
...pdf,
...planner,
...stats,
...day,
...memories,
...collab,
...perm,
...undo,
...notifications,
...todo,
...notif,
...journey,
...oauth,
...system_notice,
...transport,
};
export default locale;
+22
View File
@@ -0,0 +1,22 @@
import type { TranslationStrings } from '../types';
const inspector: TranslationStrings = {
'inspector.opened': 'Mở',
'inspector.closed': 'Đã đóng',
'inspector.openingHours': 'Giờ mở cửa',
'inspector.showHours': 'Hiển thị giờ mở cửa',
'inspector.files': 'Tập tin',
'inspector.filesCount': '{count} tập tin',
'inspector.remove': 'Di dời',
'inspector.removeFromDay': 'Xóa khỏi ngày',
'inspector.addToDay': 'Thêm vào ngày',
'inspector.confirmedRes': 'Đã xác nhận đặt chỗ',
'inspector.pendingRes': 'Đang chờ đặt chỗ',
'inspector.google': 'Mở trong Google Maps',
'inspector.website': 'Mở trang web',
'inspector.addRes': 'Sự đặt chỗ',
'inspector.editRes': 'Chỉnh sửa đặt chỗ',
'inspector.participants': 'Người tham gia',
'inspector.trackStats': 'Theo dõi số liệu thống kê',
};
export default inspector;
+231
View File
@@ -0,0 +1,231 @@
import type { TranslationStrings } from '../types';
const journey: TranslationStrings = {
'journey.search.placeholder': 'Hành trình tìm kiếm…',
'journey.search.noResults': 'Không có hành trình nào khớp với "{query}"',
'journey.title': 'Hành trình',
'journey.subtitle': 'Theo dõi chuyến đi của bạn khi chúng diễn ra',
'journey.new': 'Hành trình mới',
'journey.create': 'Tạo nên',
'journey.titlePlaceholder': 'Bạn đang đi đâu?',
'journey.empty': 'Chưa có chuyến đi nào',
'journey.emptyHint': 'Bắt đầu ghi lại chuyến đi tiếp theo của bạn',
'journey.deleted': 'Đã xóa hành trình',
'journey.createError': 'Không thể tạo hành trình',
'journey.deleteError': 'Không thể xóa hành trình',
'journey.deleteConfirmTitle': 'Xóa bỏ',
'journey.deleteConfirmMessage': 'Xóa "{title}"? Điều này không thể hoàn tác được.',
'journey.deleteConfirmGeneric': 'Bạn có chắc chắn muốn xóa cái này không?',
'journey.notFound': 'Hành trình không tìm thấy',
'journey.photos': 'Ảnh',
'journey.timelineEmpty': 'Chưa có điểm dừng',
'journey.timelineEmptyHint': 'Thêm thông tin đăng ký hoặc viết nhật ký để bắt đầu',
'journey.status.draft': 'Bản nháp',
'journey.status.active': 'Tích cực',
'journey.status.completed': 'Hoàn thành',
'journey.status.upcoming': 'Sắp tới',
'journey.status.archived': 'Đã lưu trữ',
'journey.checkin.add': 'Đăng ký vào',
'journey.checkin.namePlaceholder': 'Tên địa điểm',
'journey.checkin.notesPlaceholder': 'Ghi chú (tùy chọn)',
'journey.checkin.save': 'Lưu',
'journey.checkin.error': 'Không thể lưu thông tin đăng ký',
'journey.entry.add': 'tạp chí',
'journey.entry.edit': 'Chỉnh sửa mục nhập',
'journey.entry.titlePlaceholder': 'Tiêu đề (tùy chọn)',
'journey.entry.bodyPlaceholder': 'Chuyện gì đã xảy ra hôm nay vậy?',
'journey.entry.save': 'Lưu',
'journey.entry.error': 'Không thể lưu mục nhập',
'journey.photo.add': 'Ảnh',
'journey.photo.uploadError': 'Tải lên không thành công',
'journey.share.share': 'Chia sẻ',
'journey.share.public': 'Công cộng',
'journey.share.linkCopied': 'Đã sao chép liên kết công khai',
'journey.share.disabled': 'Chia sẻ công khai bị vô hiệu hóa',
'journey.editor.titlePlaceholder': 'Hãy đặt tên cho khoảnh khắc này...',
'journey.editor.bodyPlaceholder': 'Kể lại câu chuyện ngày hôm nay...',
'journey.editor.placePlaceholder': 'Vị trí (tùy chọn)',
'journey.editor.tagsPlaceholder': 'Tags: viên ngọc ẩn, bữa ăn ngon nhất, phải xem lại...',
'journey.visibility.private': 'Riêng tư',
'journey.visibility.shared': 'Đã chia sẻ',
'journey.visibility.public': 'Công cộng',
'journey.emptyState.title': 'Câu chuyện của bạn bắt đầu từ đây',
'journey.emptyState.subtitle': 'Đăng ký tại một địa điểm hoặc viết mục nhật ký đầu tiên của bạn',
'journey.frontpage.subtitle': 'Biến chuyến đi của bạn thành những câu chuyện bạn sẽ không bao giờ quên',
'journey.frontpage.createJourney': 'Tạo hành trình',
'journey.frontpage.activeJourney': 'Hành trình đang hoạt động',
'journey.frontpage.allJourneys': 'Tất cả hành trình',
'journey.frontpage.journeys': 'cuộc hành trình',
'journey.frontpage.createNew': 'Tạo một hành trình mới',
'journey.frontpage.createNewSub': 'Chọn chuyến đi, viết truyện, chia sẻ cuộc phiêu lưu của bạn',
'journey.frontpage.live': 'Sống',
'journey.frontpage.synced': 'Đã đồng bộ hóa',
'journey.frontpage.continueWriting': 'Tiếp tục viết',
'journey.frontpage.updated': 'Đã cập nhật {time}',
'journey.frontpage.suggestionLabel': 'Chuyến đi vừa kết thúc',
'journey.frontpage.suggestionText': 'Biến <strong>{title}</strong> thành một cuộc hành trình',
'journey.frontpage.dismiss': 'Miễn nhiệm',
'journey.frontpage.journeyName': 'Tên hành trình',
'journey.frontpage.namePlaceholder': 'ví dụ. Đông Nam Á 2026',
'journey.frontpage.selectTrips': 'Chọn chuyến đi',
'journey.frontpage.tripsSelected': 'chuyến đi đã chọn',
'journey.frontpage.trips': 'chuyến đi',
'journey.frontpage.placesImported': 'địa điểm sẽ được nhập khẩu',
'journey.frontpage.places': 'địa điểm',
'journey.detail.backToJourney': 'Quay lại Hành trình',
'journey.detail.syncedWithTrips': 'Đã đồng bộ hóa với Chuyến đi',
'journey.detail.addEntry': 'Thêm mục nhập',
'journey.detail.newEntry': 'Mục mới',
'journey.detail.editEntry': 'Chỉnh sửa mục nhập',
'journey.detail.noEntries': 'Chưa có mục nào',
'journey.detail.noEntriesHint': 'Thêm một chuyến đi để bắt đầu với các mục bộ xương',
'journey.detail.noPhotos': 'Chưa có ảnh nào',
'journey.detail.noPhotosHint': 'Tải ảnh lên các mục hoặc duyệt thư viện Immich/Synology của bạn',
'journey.detail.journeyTab': 'Hành trình',
'journey.detail.journeyStats': 'Thống kê hành trình',
'journey.detail.syncedTrips': 'Chuyến đi được đồng bộ hóa',
'journey.detail.noTripsLinked': 'Chưa có chuyến đi nào được liên kết',
'journey.detail.contributors': 'Người đóng góp',
'journey.detail.readMore': 'Đọc thêm',
'journey.detail.prosCons': 'Ưu và nhược điểm',
'journey.detail.photos': 'những bức ảnh',
'journey.detail.day': 'Ngày {number}',
'journey.detail.places': 'địa điểm',
'journey.stats.days': 'Ngày',
'journey.stats.cities': 'Thành phố',
'journey.stats.entries': 'Bài dự thi',
'journey.stats.photos': 'Ảnh',
'journey.stats.places': 'Địa điểm',
'journey.skeletons.show': 'Hiển thị đề xuất',
'journey.skeletons.hide': 'Ẩn đề xuất',
'journey.verdict.lovedIt': 'Yêu nó',
'journey.verdict.couldBeBetter': 'Có thể tốt hơn',
'journey.synced.places': 'địa điểm',
'journey.synced.synced': 'đã đồng bộ hóa',
'journey.editor.discardChangesConfirm': 'Bạn có những thay đổi chưa được lưu. Vứt bỏ chúng?',
'journey.editor.uploadFailed': 'Tải ảnh lên không thành công',
'journey.editor.uploadPhotos': 'Tải ảnh lên',
'journey.editor.uploading': 'Đang tải lên...',
'journey.editor.uploadingProgress': 'Đang tải lên {done}/{total}…',
'journey.editor.uploadPartialFailed': '{failed} trong số {total} ảnh không thành công — lưu lại để thử lại',
'journey.editor.fromGallery': 'Từ thư viện',
'journey.editor.allPhotosAdded': 'Tất cả ảnh đã được thêm',
'journey.editor.writeStory': 'Viết câu chuyện của bạn...',
'journey.editor.prosCons': 'Ưu và nhược điểm',
'journey.editor.pros': 'Ưu điểm',
'journey.editor.cons': 'Nhược điểm',
'journey.editor.proPlaceholder': 'Một cái gì đó tuyệt vời...',
'journey.editor.conPlaceholder': 'Không tuyệt lắm...',
'journey.editor.addAnother': 'Thêm cái khác',
'journey.editor.date': 'Ngày',
'journey.editor.location': 'Vị trí',
'journey.editor.searchLocation': 'Tìm kiếm vị trí...',
'journey.editor.mood': 'Tâm trạng',
'journey.editor.weather': 'Thời tiết',
'journey.editor.photoFirst': 'thứ nhất',
'journey.editor.makeFirst': 'làm số 1',
'journey.editor.searching': 'Đang tìm kiếm...',
'journey.mood.amazing': 'Tuyệt vời',
'journey.mood.good': 'Tốt',
'journey.mood.neutral': 'Trung lập',
'journey.mood.rough': 'Thô',
'journey.weather.sunny': 'Nhiều nắng',
'journey.weather.partly': 'Có mây rải rác',
'journey.weather.cloudy': 'Nhiều mây',
'journey.weather.rainy': 'Có mưa',
'journey.weather.stormy': 'Bão tố',
'journey.weather.cold': 'có tuyết',
'journey.trips.linkTrip': 'Chuyến đi liên kết',
'journey.trips.searchTrip': 'Tìm kiếm chuyến đi',
'journey.trips.searchPlaceholder': 'Tên chuyến đi hoặc điểm đến...',
'journey.trips.noTripsAvailable': 'Không có chuyến đi nào',
'journey.trips.link': 'liên kết',
'journey.trips.tripLinked': 'Đã liên kết chuyến đi',
'journey.trips.linkFailed': 'Không thể liên kết chuyến đi',
'journey.trips.addTrip': 'Thêm chuyến đi',
'journey.trips.unlinkTrip': 'Hủy liên kết chuyến đi',
'journey.trips.unlinkMessage':
'Hủy liên kết "{title}"? Tất cả các mục và ảnh đã đồng bộ hóa từ chuyến đi này sẽ bị xóa vĩnh viễn. Điều này không thể hoàn tác được.',
'journey.trips.unlink': 'Hủy liên kết',
'journey.trips.tripUnlinked': 'Đã hủy liên kết chuyến đi',
'journey.trips.unlinkFailed': 'Không thể hủy liên kết chuyến đi',
'journey.trips.noTripsLinkedSettings': 'Không có chuyến đi nào được liên kết',
'journey.contributors.invite': 'Mời cộng tác viên',
'journey.contributors.searchUser': 'Tìm kiếm người dùng',
'journey.contributors.searchPlaceholder': 'Tên người dùng hoặc email...',
'journey.contributors.noUsers': 'Không tìm thấy người dùng nào',
'journey.contributors.role': 'Vai trò',
'journey.contributors.added': 'Đã thêm người đóng góp',
'journey.contributors.addFailed': 'Không thể thêm người đóng góp',
'journey.contributors.remove': 'Xóa người đóng góp',
'journey.contributors.removeConfirm': 'Xóa {username} khỏi hành trình này?',
'journey.contributors.removed': 'Đã xóa người đóng góp',
'journey.contributors.removeFailed': 'Không thể xóa người đóng góp',
'journey.share.publicShare': 'Chia sẻ công khai',
'journey.share.createLink': 'Tạo liên kết chia sẻ',
'journey.share.linkCreated': 'Đã tạo liên kết chia sẻ',
'journey.share.createFailed': 'Không tạo được liên kết',
'journey.share.copy': 'Sao chép',
'journey.share.copied': 'Đã sao chép!',
'journey.share.timeline': 'Dòng thời gian',
'journey.share.gallery': 'Phòng trưng bày',
'journey.share.map': 'Bản đồ',
'journey.share.removeLink': 'Xóa liên kết chia sẻ',
'journey.share.linkDeleted': 'Đã xóa liên kết chia sẻ',
'journey.share.deleteFailed': 'Không thể xóa',
'journey.share.updateFailed': 'Không thể cập nhật',
'journey.invite.role': 'Vai trò',
'journey.invite.viewer': 'Người xem',
'journey.invite.editor': 'Người chỉnh sửa',
'journey.invite.invite': 'Mời',
'journey.invite.inviting': 'Đang mời...',
'journey.settings.title': 'Cài đặt hành trình',
'journey.settings.coverImage': 'Ảnh bìa',
'journey.settings.changeCover': 'Thay đổi bìa',
'journey.settings.addCover': 'Thêm ảnh bìa',
'journey.settings.name': 'Tên',
'journey.settings.subtitle': 'Phụ đề',
'journey.settings.subtitlePlaceholder': 'ví dụ. Thái Lan, Việt Nam và Campuchia',
'journey.settings.endJourney': 'Hành trình lưu trữ',
'journey.settings.reopenJourney': 'Khôi phục hành trình',
'journey.settings.archived': 'Đã lưu trữ hành trình',
'journey.settings.reopened': 'Hành trình đã mở lại',
'journey.settings.endDescription': 'Ẩn huy hiệu Trực tiếp. Bạn có thể mở lại bất cứ lúc nào.',
'journey.settings.delete': 'Xóa bỏ',
'journey.settings.deleteJourney': 'Xóa hành trình',
'journey.settings.deleteMessage': 'Xóa "{title}"? Tất cả các mục và hình ảnh sẽ bị mất.',
'journey.settings.saved': 'Đã lưu cài đặt',
'journey.settings.saveFailed': 'Không lưu được',
'journey.settings.coverUpdated': 'Đã cập nhật bìa',
'journey.settings.coverFailed': 'Tải lên không thành công',
'journey.settings.failedToDelete': 'Không thể xóa',
'journey.entries.deleteTitle': 'Xóa mục nhập',
'journey.photosUploaded': '{count} ảnh đã được tải lên',
'journey.photosUploadFailed': 'Một số ảnh không thể tải lên',
'journey.photosAdded': '{count} đã thêm ảnh',
'journey.public.notFound': 'Không tìm thấy',
'journey.public.notFoundMessage': 'Hành trình này không tồn tại hoặc liên kết đã hết hạn.',
'journey.public.readOnly': 'Chỉ đọc · Hành trình công khai',
'journey.public.tagline': 'Bộ tài nguyên du lịch & khám phá',
'journey.public.sharedVia': 'Được chia sẻ qua',
'journey.public.madeWith': 'Được làm bằng',
'journey.pdf.journeyBook': 'Sách hành trình',
'journey.pdf.madeWith': 'Được làm bằng TREK',
'journey.pdf.day': 'Ngày',
'journey.pdf.theEnd': 'Sự kết thúc',
'journey.pdf.saveAsPdf': 'Lưu dưới dạng PDF',
'journey.pdf.pages': 'trang',
'journey.picker.tripPeriod': 'Thời gian chuyến đi',
'journey.picker.dateRange': 'Phạm vi ngày',
'journey.picker.allPhotos': 'Tất cả ảnh',
'journey.picker.albums': 'Album',
'journey.picker.selected': 'đã chọn',
'journey.picker.addTo': 'Thêm vào',
'journey.picker.newGallery': 'Thư viện mới',
'journey.picker.selectAll': 'Chọn tất cả',
'journey.picker.deselectAll': 'Bỏ chọn tất cả',
'journey.picker.noAlbums': 'Không tìm thấy album nào',
'journey.picker.selectDate': 'Chọn ngày',
'journey.picker.search': 'Tìm kiếm',
};
export default journey;
+89
View File
@@ -0,0 +1,89 @@
import type { TranslationStrings } from '../types';
const login: TranslationStrings = {
'login.error': 'Đăng nhập không thành công. Vui lòng kiểm tra thông tin đăng nhập của bạn.',
'login.tagline': 'Chuyến đi của bạn.\nKế hoạch của bạn.',
'login.description': 'Lập kế hoạch chuyến đi cộng tác với bản đồ tương tác, ngân sách và đồng bộ hóa thời gian thực.',
'login.features.maps': 'Bản đồ tương tác',
'login.features.mapsDesc': 'Google Địa điểm, tuyến đường và phân cụm',
'login.features.realtime': 'Đồng bộ hóa thời gian thực',
'login.features.realtimeDesc': 'Lập kế hoạch cùng nhau thông qua WebSocket',
'login.features.budget': 'Theo dõi ngân sách',
'login.features.budgetDesc': 'Danh mục, biểu đồ và chi phí mỗi người',
'login.features.collab': 'Sự hợp tác',
'login.features.collabDesc': 'Nhiều người dùng với các chuyến đi chung',
'login.features.packing': 'Danh sách đóng gói',
'login.features.packingDesc': 'Danh mục, tiến độ và đề xuất',
'login.features.bookings': 'Đặt chỗ',
'login.features.bookingsDesc': 'Chuyến bay, khách sạn, nhà hàng và hơn thế nữa',
'login.features.files': 'Tài liệu',
'login.features.filesDesc': 'Tải lên và quản lý tài liệu',
'login.features.routes': 'Tuyến đường thông minh',
'login.features.routesDesc': 'Tự động tối ưu hóa & xuất Google Maps',
'login.selfHosted': 'Tự lưu trữ · Mã nguồn mở · Dữ liệu của bạn vẫn là của bạn',
'login.title': 'Đăng nhập',
'login.subtitle': 'Chào mừng trở lại',
'login.signingIn': 'Đang đăng nhập…',
'login.signIn': 'Đăng nhập',
'login.createAdmin': 'Tạo tài khoản quản trị',
'login.createAdminHint': 'Thiết lập tài khoản quản trị đầu tiên cho TREK.',
'login.setNewPassword': 'Đặt mật khẩu mới',
'login.setNewPasswordHint': 'Bạn phải thay đổi mật khẩu trước khi tiếp tục.',
'login.createAccount': 'Tạo tài khoản',
'login.createAccountHint': 'Đăng ký một tài khoản mới.',
'login.creating': 'Đang tạo…',
'login.noAccount': 'Bạn chưa có tài khoản?',
'login.hasAccount': 'Đã có tài khoản?',
'login.register': 'Đăng ký',
'login.emailPlaceholder': 'your@email.com',
'login.username': 'Tên người dùng',
'login.oidc.registrationDisabled': 'Đăng ký bị vô hiệu hóa. Liên hệ với quản trị viên của bạn.',
'login.oidc.noEmail': 'Không nhận được email từ nhà cung cấp.',
'login.oidc.tokenFailed': 'Xác thực không thành công.',
'login.oidc.invalidState': 'Phiên không hợp lệ. Vui lòng thử lại.',
'login.demoFailed': 'Đăng nhập demo không thành công',
'login.oidcSignIn': 'Đăng nhập bằng {name}',
'login.oidcOnly': 'Xác thực mật khẩu bị vô hiệu hóa. Vui lòng đăng nhập bằng nhà cung cấp SSO của bạn.',
'login.oidcLoggedOut': 'Bạn đã đăng xuất. Đăng nhập lại bằng nhà cung cấp SSO của bạn.',
'login.demoHint': 'Hãy thử bản demo - không cần đăng ký',
'login.mfaTitle': 'Xác thực hai yếu tố',
'login.mfaSubtitle': 'Nhập mã gồm 6 chữ số từ ứng dụng xác thực của bạn.',
'login.mfaCodeLabel': 'Mã xác minh',
'login.mfaCodeRequired': 'Nhập mã từ ứng dụng xác thực của bạn.',
'login.mfaHint': 'Mở Google Authenticator, Authy hoặc ứng dụng TOTP khác.',
'login.mfaBack': '← Quay lại đăng nhập',
'login.mfaVerify': 'Xác minh',
'login.invalidInviteLink': 'Liên kết mời không hợp lệ hoặc đã hết hạn',
'login.oidcFailed': 'OIDC đăng nhập không thành công',
'login.usernameRequired': 'Tên người dùng là bắt buộc',
'login.passwordMinLength': 'Mật khẩu phải có ít nhất 8 ký tự',
'login.forgotPassword': 'Quên mật khẩu?',
'login.rememberMe': 'nhớ tôi',
'login.forgotPasswordTitle': 'Đặt lại mật khẩu của bạn',
'login.forgotPasswordBody':
'Nhập địa chỉ email bạn đã đăng ký. Nếu tài khoản tồn tại, chúng tôi sẽ gửi liên kết đặt lại.',
'login.forgotPasswordSubmit': 'Gửi liên kết đặt lại',
'login.forgotPasswordSentTitle': 'Kiểm tra email của bạn',
'login.forgotPasswordSentBody':
'Nếu có tài khoản cho email đó thì liên kết đặt lại sẽ được gửi đến. Nó hết hạn sau 60 phút.',
'login.forgotPasswordSmtpHintOff':
'Lưu ý: quản trị viên của bạn chưa định cấu hình SMTP nên liên kết đặt lại sẽ được ghi vào bảng điều khiển máy chủ thay vì được gửi qua email.',
'login.backToLogin': 'Quay lại để đăng nhập',
'login.newPassword': 'Mật khẩu mới',
'login.confirmPassword': 'Xác nhận mật khẩu mới',
'login.passwordsDontMatch': 'Mật khẩu không khớp',
'login.mfaCode': 'Mã 2FA',
'login.resetPasswordTitle': 'Đặt mật khẩu mới',
'login.resetPasswordBody': 'Chọn một mật khẩu mạnh mà bạn chưa từng sử dụng ở đây trước đây. Tối thiểu 8 ký tự.',
'login.resetPasswordMfaBody': 'Nhập mã 2FA của bạn hoặc mã dự phòng để hoàn tất quá trình đặt lại.',
'login.resetPasswordSubmit': 'Đặt lại mật khẩu',
'login.resetPasswordVerify': 'Xác minh và đặt lại',
'login.resetPasswordSuccessTitle': 'Đã cập nhật mật khẩu',
'login.resetPasswordSuccessBody': 'Bây giờ bạn có thể đăng nhập bằng mật khẩu mới của mình.',
'login.resetPasswordInvalidLink': 'Liên kết đặt lại không hợp lệ',
'login.resetPasswordInvalidLinkBody': 'Liên kết này bị thiếu hoặc bị hỏng. Yêu cầu một cái mới để tiếp tục.',
'login.resetPasswordFailed': 'Đặt lại không thành công. Liên kết có thể đã hết hạn.',
'login.passkey.signIn': 'Đăng nhập bằng mật mã',
'login.passkey.failed': 'Đăng nhập bằng mật mã không thành công. Vui lòng thử lại.',
};
export default login;
+17
View File
@@ -0,0 +1,17 @@
import type { TranslationStrings } from '../types';
const map: TranslationStrings = {
'map.connections': 'Kết nối',
'map.showConnections': 'Hiển thị lộ trình đặt vé',
'map.hideConnections': 'Ẩn lộ trình đặt chỗ',
'poi.searchThisArea': 'Tìm kiếm khu vực này',
'poi.cat.restaurants': 'Nhà hàng',
'poi.cat.cafes': 'Quán cà phê',
'poi.cat.bars': 'Quán bar & cuộc sống về đêm',
'poi.cat.hotels': 'Chỗ ở',
'poi.cat.sights': 'Điểm tham quan',
'poi.cat.museums': 'Bảo tàng & văn hóa',
'poi.cat.nature': 'Thiên nhiên & công viên',
'poi.cat.activities': 'Các hoạt động',
};
export default map;
+24
View File
@@ -0,0 +1,24 @@
import type { TranslationStrings } from '../types';
const members: TranslationStrings = {
'members.shareTrip': 'Chia sẻ chuyến đi',
'members.inviteUser': 'Mời người dùng',
'members.selectUser': 'Chọn người dùng…',
'members.invite': 'Mời',
'members.allHaveAccess': 'Tất cả người dùng đã có quyền truy cập.',
'members.access': 'Truy cập',
'members.person': 'người',
'members.persons': 'người',
'members.you': 'Bạn',
'members.owner': 'Người sở hữu',
'members.leaveTrip': 'Rời khỏi chuyến đi',
'members.removeAccess': 'Xóa quyền truy cập',
'members.confirmLeave': 'Rời khỏi chuyến đi? Bạn sẽ mất quyền truy cập.',
'members.confirmRemove': 'Xóa quyền truy cập của người dùng này?',
'members.loadError': 'Không thể tải thành viên',
'members.added': 'đã thêm',
'members.addError': 'Không thể thêm',
'members.removed': 'Thành viên đã bị xóa',
'members.removeError': 'Không thể xóa',
};
export default members;
+75
View File
@@ -0,0 +1,75 @@
import type { TranslationStrings } from '../types';
const memories: TranslationStrings = {
'memories.title': 'Ảnh',
'memories.notConnected': '{provider_name} không được kết nối',
'memories.notConnectedHint': 'Kết nối phiên bản {provider_name} của bạn trong Cài đặt để có thể thêm ảnh vào chuyến đi này.',
'memories.notConnectedMultipleHint':
'Kết nối bất kỳ nhà cung cấp ảnh nào sau đây: {provider_names} trong Cài đặt để có thể thêm ảnh vào chuyến đi này.',
'memories.noDates': 'Thêm ngày vào chuyến đi của bạn để tải ảnh.',
'memories.noPhotos': 'Không tìm thấy ảnh nào',
'memories.noPhotosHint': 'Không tìm thấy ảnh nào trong {provider_name} cho phạm vi ngày của chuyến đi này.',
'memories.photosFound': 'những bức ảnh',
'memories.fromOthers': 'từ người khác',
'memories.sharePhotos': 'Chia sẻ ảnh',
'memories.sharing': 'Chia sẻ',
'memories.reviewTitle': 'Xem lại ảnh của bạn',
'memories.reviewHint': 'Nhấp vào ảnh để loại trừ chúng khỏi việc chia sẻ.',
'memories.shareCount': 'Chia sẻ ảnh {count}',
'memories.providerUrl': 'Máy chủ URL',
'memories.providerApiKey': 'API Chìa khóa',
'memories.providerUsername': 'Tên người dùng',
'memories.providerPassword': 'Mật khẩu',
'memories.providerOTP': 'Mã MFA (nếu được bật)',
'memories.skipSSLVerification': 'Bỏ qua xác minh chứng chỉ SSL',
'memories.immichAutoUpload': 'Phản chiếu ảnh hành trình tới Immich khi tải lên',
'memories.providerUrlHintSynology': 'Bao gồm đường dẫn ứng dụng Ảnh trong URL, ví dụ: https://nas:5001/photo',
'memories.testConnection': 'Kiểm tra kết nối',
'memories.testShort': 'Bài kiểm tra',
'memories.testFirst': 'Kiểm tra kết nối trước',
'memories.connected': 'Đã kết nối',
'memories.disconnected': 'Không được kết nối',
'memories.connectionSuccess': 'Đã kết nối với {provider_name}',
'memories.connectionError': 'Không thể kết nối với {provider_name}',
'memories.saved': '{provider_name} đã lưu cài đặt',
'memories.providerDisconnectedBanner':
'Kết nối {provider_name} của bạn bị mất. Kết nối lại trong Cài đặt để xem ảnh.',
'memories.saveError': 'Không thể lưu cài đặt {provider_name}',
'memories.addPhotos': 'Thêm ảnh',
'memories.linkAlbum': 'Liên kết anbom',
'memories.selectAlbum': 'Chọn Album {provider_name}',
'memories.selectAlbumMultiple': 'Chọn Anbom',
'memories.noAlbums': 'Không tìm thấy album nào',
'memories.syncAlbum': 'Đồng bộ album',
'memories.unlinkAlbum': 'Hủy liên kết album',
'memories.photos': 'những bức ảnh',
'memories.selectPhotos': 'Chọn ảnh từ {provider_name}',
'memories.selectPhotosMultiple': 'Chọn ảnh',
'memories.selectHint': 'Nhấn vào ảnh để chọn chúng.',
'memories.selected': 'đã chọn',
'memories.addSelected': 'Thêm {count} ảnh',
'memories.alreadyAdded': 'Đã thêm',
'memories.private': 'Riêng tư',
'memories.stopSharing': 'Dừng chia sẻ',
'memories.oldest': 'Cũ nhất đầu tiên',
'memories.newest': 'Mới nhất đầu tiên',
'memories.allLocations': 'Tất cả địa điểm',
'memories.tripDates': 'Ngày chuyến đi',
'memories.allPhotos': 'Tất cả ảnh',
'memories.confirmShareTitle': 'Chia sẻ với các thành viên chuyến đi?',
'memories.confirmShareHint':
'{count} ảnh sẽ hiển thị với tất cả thành viên của chuyến đi này. Bạn có thể đặt từng ảnh riêng tư sau này.',
'memories.confirmShareButton': 'Chia sẻ ảnh',
'memories.error.loadAlbums': 'Không tải được album',
'memories.error.linkAlbum': 'Không liên kết được album',
'memories.error.unlinkAlbum': 'Không thể hủy liên kết album',
'memories.error.syncAlbum': 'Không thể đồng bộ hóa album',
'memories.error.loadPhotos': 'Không tải được ảnh',
'memories.error.addPhotos': 'Không thể thêm ảnh',
'memories.error.removePhoto': 'Không xóa được ảnh',
'memories.error.toggleSharing': 'Không thể cập nhật chia sẻ',
'memories.saveRouteNotConfigured': 'Lưu tuyến không được định cấu hình cho nhà cung cấp này',
'memories.testRouteNotConfigured': 'Tuyến thử nghiệm không được định cấu hình cho nhà cung cấp này',
'memories.fillRequiredFields': 'Vui lòng điền vào tất cả các trường bắt buộc',
};
export default memories;
+20
View File
@@ -0,0 +1,20 @@
import type { TranslationStrings } from '../types';
const nav: TranslationStrings = {
'nav.trip': 'Chuyến đi',
'nav.share': 'Chia sẻ',
'nav.settings': 'Cài đặt',
'nav.admin': 'Quản trị viên',
'nav.logout': 'Đăng xuất',
'nav.lightMode': 'Chế độ ánh sáng',
'nav.darkMode': 'Chế độ tối',
'nav.autoMode': 'Chế độ tự động',
'nav.administrator': 'Quản trị viên',
'nav.myTrips': 'Chuyến đi',
'nav.profile': 'Hồ sơ',
'nav.bottomSettings': 'Cài đặt',
'nav.bottomAdmin': 'Cài đặt quản trị viên',
'nav.bottomLogout': 'Đăng xuất',
'nav.bottomAdminBadge': 'Quản trị viên',
};
export default nav;
+40
View File
@@ -0,0 +1,40 @@
import type { TranslationStrings } from '../types';
const notif: TranslationStrings = {
'notif.test.title': '[Thử nghiệm] Thông báo',
'notif.test.simple.text': 'Đây là một thông báo thử nghiệm đơn giản.',
'notif.test.boolean.text': 'Bạn có chấp nhận thông báo kiểm tra này không?',
'notif.test.navigate.text': 'Nhấp vào bên dưới để điều hướng đến trang tổng quan.',
'notif.trip_invite.title': 'Lời mời chuyến đi',
'notif.trip_invite.text': '{actor} đã mời bạn tham gia {trip}',
'notif.booking_change.title': 'Đã cập nhật đặt chỗ',
'notif.booking_change.text': '{actor} đã cập nhật lượt đặt chỗ trong {trip}',
'notif.trip_reminder.title': 'Nhắc nhở chuyến đi',
'notif.trip_reminder.text': 'Chuyến đi {trip} của bạn sắp diễn ra!',
'notif.todo_due.title': 'Việc cần làm đến hạn',
'notif.todo_due.text': '{todo} trong {trip} đáo hạn vào {due}',
'notif.vacay_invite.title': 'Lời mời kết hợp Vacay',
'notif.vacay_invite.text': '{actor} đã mời bạn lên kế hoạch cho kỳ nghỉ',
'notif.photos_shared.title': 'Ảnh được chia sẻ',
'notif.photos_shared.text': '{actor} đã chia sẻ {count} ảnh trong {trip}',
'notif.collab_message.title': 'Tin nhắn mới',
'notif.collab_message.text': '{actor} đã gửi tin nhắn trong {trip}',
'notif.packing_tagged.title': 'Nhiệm vụ đóng gói',
'notif.packing_tagged.text': '{actor} đã giao cho bạn {category} trong {trip}',
'notif.version_available.title': 'Phiên bản mới có sẵn',
'notif.version_available.text': 'TREK {version} hiện có sẵn',
'notif.action.view_trip': 'Xem chuyến đi',
'notif.action.view_collab': 'Xem tin nhắn',
'notif.action.view_packing': 'Xem đóng gói',
'notif.action.view_photos': 'Xem ảnh',
'notif.action.view_vacay': 'Xem kỳ nghỉ',
'notif.action.view_admin': 'Đi tới quản trị viên',
'notif.action.view': 'Xem',
'notif.action.accept': 'Chấp nhận',
'notif.action.decline': 'Sự suy sụp',
'notif.generic.title': 'Thông báo',
'notif.generic.text': 'Bạn có thông báo mới',
'notif.dev.unknown_event.title': '[DEV] Sự kiện không xác định',
'notif.dev.unknown_event.text': 'Loại sự kiện "{event}" chưa được đăng ký trong EVENT_NOTIFICATION_CONFIG',
};
export default notif;
+36
View File
@@ -0,0 +1,36 @@
import type { TranslationStrings } from '../types';
const notifications: TranslationStrings = {
'notifications.title': 'Thông báo',
'notifications.markAllRead': 'Đánh dấu tất cả đã đọc',
'notifications.deleteAll': 'Xóa tất cả',
'notifications.showAll': 'Hiển thị tất cả thông báo',
'notifications.empty': 'Không có thông báo',
'notifications.emptyDescription': 'Bạn đã bắt kịp tất cả!',
'notifications.all': 'Tất cả',
'notifications.unreadOnly': 'Chưa đọc',
'notifications.markRead': 'Đánh dấu là đã đọc',
'notifications.markUnread': 'Đánh dấu là chưa đọc',
'notifications.delete': 'Xóa bỏ',
'notifications.system': 'Hệ thống',
'notifications.synologySessionCleared.title': 'Synology Ảnh bị ngắt kết nối',
'notifications.synologySessionCleared.text':
'Máy chủ hoặc tài khoản của bạn đã thay đổi — hãy đi tới Cài đặt để kiểm tra lại kết nối của bạn.',
'notifications.versionAvailable.title': 'Cập nhật có sẵn',
'notifications.versionAvailable.text': 'TREK {version} hiện có sẵn.',
'notifications.versionAvailable.button': 'Xem chi tiết',
'notifications.test.title': 'Thông báo kiểm tra từ {actor}',
'notifications.test.text': 'Đây là một thông báo thử nghiệm đơn giản.',
'notifications.test.booleanTitle': '{actor} yêu cầu sự chấp thuận của bạn',
'notifications.test.booleanText': 'Đây là thông báo boolean thử nghiệm. Chọn một hành động dưới đây.',
'notifications.test.accept': 'Chấp thuận',
'notifications.test.decline': 'Sự suy sụp',
'notifications.test.navigateTitle': 'Kiểm tra cái gì đó',
'notifications.test.navigateText': 'Đây là thông báo điều hướng thử nghiệm.',
'notifications.test.goThere': 'Đến đó',
'notifications.test.adminTitle': 'Quản trị viên phát sóng',
'notifications.test.adminText': '{actor} đã gửi thông báo kiểm tra tới tất cả quản trị viên.',
'notifications.test.tripTitle': '{actor} đã đăng trong chuyến đi của bạn',
'notifications.test.tripText': 'Thông báo kiểm tra chuyến đi "{trip}".',
};
export default notifications;
+91
View File
@@ -0,0 +1,91 @@
import type { TranslationStrings } from '../types';
const oauth: TranslationStrings = {
'oauth.scope.group.trips': 'Chuyến đi',
'oauth.scope.group.places': 'Địa điểm',
'oauth.scope.group.atlas': 'Bản đồ',
'oauth.scope.group.packing': 'Đóng gói',
'oauth.scope.group.todos': 'Việc cần làm',
'oauth.scope.group.budget': 'Ngân sách',
'oauth.scope.group.reservations': 'Đặt chỗ',
'oauth.scope.group.collab': 'Sự hợp tác',
'oauth.scope.group.notifications': 'Thông báo',
'oauth.scope.group.vacay': 'Kì nghỉ',
'oauth.scope.group.geo': 'địa lý',
'oauth.scope.group.weather': 'Thời tiết',
'oauth.scope.group.journey': 'Hành trình',
'oauth.scope.trips:read.label': 'Xem chuyến đi & hành trình',
'oauth.scope.trips:read.description': 'Đọc các chuyến đi, ngày, ghi chú trong ngày và các thành viên',
'oauth.scope.trips:write.label': 'Chỉnh sửa chuyến đi và hành trình',
'oauth.scope.trips:write.description': 'Tạo và cập nhật chuyến đi, ngày, ghi chú và quản lý thành viên',
'oauth.scope.trips:delete.label': 'Xóa chuyến đi',
'oauth.scope.trips:delete.description': 'Xóa vĩnh viễn toàn bộ chuyến đi — hành động này không thể thay đổi được',
'oauth.scope.trips:share.label': 'Quản lý liên kết chia sẻ',
'oauth.scope.trips:share.description': 'Tạo, cập nhật và thu hồi liên kết chia sẻ công khai cho các chuyến đi',
'oauth.scope.places:read.label': 'Xem địa điểm và dữ liệu bản đồ',
'oauth.scope.places:read.description': 'Đọc địa điểm, bài tập trong ngày, thẻ và danh mục',
'oauth.scope.places:write.label': 'Quản lý địa điểm',
'oauth.scope.places:write.description': 'Tạo, cập nhật và xóa địa điểm, bài tập và thẻ',
'oauth.scope.atlas:read.label': 'Xem bản đồ',
'oauth.scope.atlas:read.description': 'Đọc các quốc gia, khu vực và danh sách nhóm đã ghé thăm',
'oauth.scope.atlas:write.label': 'Quản lý bản đồ',
'oauth.scope.atlas:write.description': 'Đánh dấu các quốc gia và khu vực đã ghé thăm, quản lý danh sách nhóm',
'oauth.scope.packing:read.label': 'Xem danh sách đóng gói',
'oauth.scope.packing:read.description': 'Đọc các mặt hàng đóng gói, túi xách và người được giao danh mục',
'oauth.scope.packing:write.label': 'Quản lý danh sách đóng gói',
'oauth.scope.packing:write.description': 'Thêm, cập nhật, xóa, chuyển đổi và sắp xếp lại các mặt hàng và túi đóng gói',
'oauth.scope.todos:read.label': 'Xem danh sách việc cần làm',
'oauth.scope.todos:read.description': 'Đọc các mục việc cần làm trong chuyến đi và người được giao danh mục',
'oauth.scope.todos:write.label': 'Quản lý danh sách việc cần làm',
'oauth.scope.todos:write.description': 'Tạo, cập nhật, chuyển đổi, xóa và sắp xếp lại các mục việc cần làm',
'oauth.scope.budget:read.label': 'Xem ngân sách',
'oauth.scope.budget:read.description': 'Đọc các mục ngân sách và phân tích chi phí',
'oauth.scope.budget:write.label': 'Quản lý ngân sách',
'oauth.scope.budget:write.description': 'Tạo, cập nhật và xóa các mục ngân sách',
'oauth.scope.reservations:read.label': 'Xem đặt chỗ',
'oauth.scope.reservations:read.description': 'Đọc thông tin đặt phòng và chỗ ở',
'oauth.scope.reservations:write.label': 'Quản lý đặt chỗ',
'oauth.scope.reservations:write.description': 'Tạo, cập nhật, xóa và sắp xếp lại các đặt chỗ',
'oauth.scope.collab:read.label': 'Xem cộng tác',
'oauth.scope.collab:read.description': 'Đọc ghi chú cộng tác, cuộc thăm dò và tin nhắn',
'oauth.scope.collab:write.label': 'Quản lý cộng tác',
'oauth.scope.collab:write.description': 'Tạo, cập nhật và xóa ghi chú cộng tác, cuộc thăm dò ý kiến ​​và tin nhắn',
'oauth.scope.notifications:read.label': 'Xem thông báo',
'oauth.scope.notifications:read.description': 'Đọc thông báo trong ứng dụng và số lượng chưa đọc',
'oauth.scope.notifications:write.label': 'Quản lý thông báo',
'oauth.scope.notifications:write.description': 'Đánh dấu thông báo là đã đọc và trả lời chúng',
'oauth.scope.vacay:read.label': 'Xem kế hoạch kỳ nghỉ',
'oauth.scope.vacay:read.description': 'Đọc dữ liệu, mục nhập và số liệu thống kê về kế hoạch kỳ nghỉ',
'oauth.scope.vacay:write.label': 'Quản lý kế hoạch kỳ nghỉ',
'oauth.scope.vacay:write.description': 'Tạo và quản lý các mục nghỉ lễ, ngày lễ và kế hoạch nhóm',
'oauth.scope.geo:read.label': 'Bản đồ & mã hóa địa lý',
'oauth.scope.geo:read.description': 'Tìm kiếm vị trí, phân giải URL bản đồ và đảo ngược tọa độ mã địa lý',
'oauth.scope.weather:read.label': 'Dự báo thời tiết',
'oauth.scope.weather:read.description': 'Tìm nạp dự báo thời tiết cho địa điểm và ngày của chuyến đi',
'oauth.scope.journey:read.label': 'Xem hành trình',
'oauth.scope.journey:read.description': 'Đọc hành trình, mục nhập và danh sách người đóng góp',
'oauth.scope.journey:write.label': 'Quản lý hành trình',
'oauth.scope.journey:write.description': 'Tạo, cập nhật và xóa hành trình cũng như các mục nhập của chúng',
'oauth.scope.journey:share.label': 'Quản lý liên kết hành trình',
'oauth.scope.journey:share.description': 'Tạo, cập nhật và thu hồi liên kết chia sẻ công khai cho hành trình',
'oauth.authorize.authorizing': 'Đang ủy quyền…',
'oauth.authorize.loading': 'Đang tải…',
'oauth.authorize.errorTitle': 'Lỗi ủy quyền',
'oauth.authorize.loginTitle': 'Đăng nhập để tiếp tục',
'oauth.authorize.loginDescription': '{client} muốn truy cập vào tài khoản TREK của bạn. Vui lòng đăng nhập trước.',
'oauth.authorize.loginButton': 'Đăng nhập vào TREK',
'oauth.authorize.requestLabel': 'Yêu cầu ủy quyền',
'oauth.authorize.requestDescription': 'Ứng dụng này đang yêu cầu quyền truy cập vào tài khoản TREK của bạn.',
'oauth.authorize.trustNote': 'Chỉ cấp quyền truy cập cho các ứng dụng mà bạn tin tưởng. Dữ liệu của bạn vẫn còn trên máy chủ của bạn.',
'oauth.authorize.selectScope': 'Chọn ít nhất một phạm vi',
'oauth.authorize.approveOneScope': 'Phê duyệt (phạm vi {count})',
'oauth.authorize.approveManyScopes': 'Phê duyệt ({count} phạm vi)',
'oauth.authorize.approveAccess': 'Phê duyệt quyền truy cập',
'oauth.authorize.deny': 'Từ chối',
'oauth.authorize.choosePermissions': 'Chọn quyền nào để cấp',
'oauth.authorize.permissionsRequested': 'Đã yêu cầu quyền',
'oauth.authorize.alwaysIncluded': 'Luôn bao gồm',
'oauth.authorize.alwaysTool.listTrips': 'Liệt kê các chuyến đi của bạn để AI có thể khám phá ID chuyến đi',
'oauth.authorize.alwaysTool.getTripSummary': 'Đọc tổng quan về chuyến đi cần thiết để sử dụng bất kỳ công cụ nào khác',
};
export default oauth;
+184
View File
@@ -0,0 +1,184 @@
import type { TranslationStrings } from '../types';
const packing: TranslationStrings = {
'packing.title': 'Danh sách đóng gói',
'packing.empty': 'Danh sách đóng gói trống',
'packing.import': 'Nhập',
'packing.importTitle': 'Nhập danh sách đóng gói',
'packing.importHint':
'Một mục trên mỗi dòng. Định dạng: Danh mục, Tên, Trọng lượng tính bằng g (tùy chọn), Túi (tùy chọn), đã chọn/bỏ chọn (tùy chọn)',
'packing.importPlaceholder':
'Vệ sinh, Bàn chải đánh răng\nQuần áo, Áo sơ mi, 200\nGiấy tờ, Hộ chiếu, Hành lý xách tay\nĐiện tử, Sạc, 50, Vali, đã kiểm tra',
'packing.importCsv': 'Tải CSV/TXT',
'packing.importAction': 'Nhập {count}',
'packing.importSuccess': '{count} mặt hàng đã được nhập',
'packing.importError': 'Nhập không thành công',
'packing.importEmpty': 'Không có mặt hàng nào để nhập',
'packing.progress': '{packed} trong số {total} được đóng gói ({percent}%)',
'packing.clearChecked': 'Xóa {count} đã chọn',
'packing.clearCheckedShort': 'Xóa {count}',
'packing.suggestions': 'Đề xuất',
'packing.suggestionsTitle': 'Thêm đề xuất',
'packing.allSuggested': 'Đã thêm tất cả đề xuất',
'packing.allPacked': 'Tất cả đã được đóng gói!',
'packing.addPlaceholder': 'Thêm mục mới...',
'packing.categoryPlaceholder': 'Loại...',
'packing.filterAll': 'Tất cả',
'packing.filterOpen': 'Mở',
'packing.filterDone': 'Xong',
'packing.emptyTitle': 'Danh sách đóng gói trống',
'packing.emptyHint': 'Thêm mục hoặc sử dụng các đề xuất',
'packing.emptyFiltered': 'Không có mục nào phù hợp với bộ lọc này',
'packing.menuRename': 'Đổi tên',
'packing.menuCheckAll': 'Kiểm tra tất cả',
'packing.menuUncheckAll': 'Bỏ chọn tất cả',
'packing.menuDeleteCat': 'Xóa danh mục',
'packing.noMembers': 'Không có thành viên chuyến đi',
'packing.addItem': 'Thêm mục',
'packing.addItemPlaceholder': 'Tên mặt hàng...',
'packing.addCategory': 'Thêm danh mục',
'packing.newCategoryPlaceholder': 'Tên danh mục (ví dụ: Quần áo)',
'packing.applyTemplate': 'Áp dụng mẫu',
'packing.template': 'Bản mẫu',
'packing.templateApplied': '{count} mục được thêm từ mẫu',
'packing.templateError': 'Không áp dụng được mẫu',
'packing.saveAsTemplate': 'Lưu dưới dạng mẫu',
'packing.templateName': 'Tên mẫu',
'packing.templateSaved': 'Danh sách đóng gói được lưu dưới dạng mẫu',
'packing.bags': 'Túi xách',
'packing.noBag': 'Chưa được chỉ định',
'packing.totalWeight': 'Tổng trọng lượng',
'packing.bagName': 'Tên túi...',
'packing.addBag': 'Thêm túi',
'packing.changeCategory': 'Thay đổi danh mục',
'packing.confirm.clearChecked': 'Bạn có chắc chắn muốn xóa {count} mục đã chọn không?',
'packing.confirm.deleteCat': 'Bạn có chắc chắn muốn xóa danh mục "{name}" với các mục {count} không?',
'packing.defaultCategory': 'Khác',
'packing.toast.saveError': 'Không lưu được',
'packing.toast.deleteError': 'Không thể xóa',
'packing.toast.renameError': 'Không thể đổi tên',
'packing.toast.addError': 'Không thể thêm',
'packing.suggestions.items': [
{
name: 'Hộ chiếu',
category: 'Tài liệu',
},
{
name: 'Thẻ ID',
category: 'Tài liệu',
},
{
name: 'Bảo hiểm du lịch',
category: 'Tài liệu',
},
{
name: 'Vé máy bay',
category: 'Tài liệu',
},
{
name: 'Thẻ tín dụng',
category: 'Tài chính',
},
{
name: 'Tiền mặt',
category: 'Tài chính',
},
{
name: 'Visa',
category: 'Tài liệu',
},
{
name: 'Áo sơ mi',
category: 'Quần áo',
},
{
name: 'Quần dài',
category: 'Quần áo',
},
{
name: 'Đồ lót',
category: 'Quần áo',
},
{
name: 'Tất',
category: 'Quần áo',
},
{
name: 'Áo khoác',
category: 'Quần áo',
},
{
name: 'Đồ ngủ',
category: 'Quần áo',
},
{
name: 'Đồ bơi',
category: 'Quần áo',
},
{
name: 'Áo mưa',
category: 'Quần áo',
},
{
name: 'Giày thoải mái',
category: 'Quần áo',
},
{
name: 'Bàn chải đánh răng',
category: 'Đồ vệ sinh cá nhân',
},
{
name: 'Kem đánh răng',
category: 'Đồ vệ sinh cá nhân',
},
{
name: 'Dầu gội đầu',
category: 'Đồ vệ sinh cá nhân',
},
{
name: 'Khử mùi',
category: 'Đồ vệ sinh cá nhân',
},
{
name: 'Kem chống nắng',
category: 'Đồ vệ sinh cá nhân',
},
{
name: 'dao cạo',
category: 'Đồ vệ sinh cá nhân',
},
{
name: 'Bộ sạc',
category: 'Điện tử',
},
{
name: 'Ngân hàng điện',
category: 'Điện tử',
},
{
name: 'Tai nghe',
category: 'Điện tử',
},
{
name: 'Bộ chuyển đổi du lịch',
category: 'Điện tử',
},
{
name: 'Máy ảnh',
category: 'Điện tử',
},
{
name: 'Thuốc giảm đau',
category: 'Sức khỏe',
},
{
name: 'Băng cá nhân',
category: 'Sức khỏe',
},
{
name: 'Thuốc khử trùng',
category: 'Sức khỏe',
},
],
};
export default packing;
+10
View File
@@ -0,0 +1,10 @@
import type { TranslationStrings } from '../types';
const pdf: TranslationStrings = {
'pdf.travelPlan': 'Kế hoạch du lịch',
'pdf.planned': 'Đã lên kế hoạch',
'pdf.costLabel': 'Chi phí EUR',
'pdf.preview': 'PDF Xem trước',
'pdf.saveAsPdf': 'Lưu dưới dạng PDF',
};
export default pdf;
+51
View File
@@ -0,0 +1,51 @@
import type { TranslationStrings } from '../types';
const perm: TranslationStrings = {
'perm.title': 'Cài đặt quyền',
'perm.subtitle': 'Kiểm soát ai có thể thực hiện các hành động trên ứng dụng',
'perm.saved': 'Đã lưu cài đặt quyền',
'perm.resetDefaults': 'Đặt lại về mặc định',
'perm.customized': 'tùy chỉnh',
'perm.level.admin': 'Chỉ quản trị viên',
'perm.level.tripOwner': 'Chủ chuyến đi',
'perm.level.tripMember': 'thành viên chuyến đi',
'perm.level.everybody': 'Mọi người',
'perm.cat.trip': 'Quản lý chuyến đi',
'perm.cat.members': 'Quản lý thành viên',
'perm.cat.files': 'Tập tin',
'perm.cat.content': 'Nội dung & Lịch trình',
'perm.cat.extras': 'Ngân sách, Đóng gói & Hợp tác',
'perm.action.trip_create': 'Tạo chuyến đi',
'perm.action.trip_edit': 'Chỉnh sửa chi tiết chuyến đi',
'perm.action.trip_delete': 'Xóa chuyến đi',
'perm.action.trip_archive': 'Lưu trữ/hủy lưu trữ các chuyến đi',
'perm.action.trip_cover_upload': 'Tải ảnh bìa lên',
'perm.action.member_manage': 'Thêm/xóa thành viên',
'perm.action.file_upload': 'Tải tập tin lên',
'perm.action.file_edit': 'Chỉnh sửa siêu dữ liệu tập tin',
'perm.action.file_delete': 'Xóa tập tin',
'perm.action.place_edit': 'Thêm/sửa/xóa địa điểm',
'perm.action.day_edit': 'Chỉnh sửa ngày, ghi chú và bài tập',
'perm.action.reservation_edit': 'Quản lý đặt chỗ',
'perm.action.budget_edit': 'Quản lý ngân sách',
'perm.action.packing_edit': 'Quản lý danh sách đóng gói',
'perm.action.collab_edit': 'Cộng tác (ghi chú, thăm dò ý kiến, trò chuyện)',
'perm.action.share_manage': 'Quản lý liên kết chia sẻ',
'perm.actionHint.trip_create': 'Ai có thể tạo chuyến đi mới',
'perm.actionHint.trip_edit': 'Ai có thể thay đổi tên chuyến đi, ngày tháng, mô tả và đơn vị tiền tệ',
'perm.actionHint.trip_delete': 'Ai có thể xóa vĩnh viễn chuyến đi',
'perm.actionHint.trip_archive': 'Ai có thể lưu trữ hoặc hủy lưu trữ chuyến đi',
'perm.actionHint.trip_cover_upload': 'Ai có thể tải lên hoặc thay đổi ảnh bìa',
'perm.actionHint.member_manage': 'Ai có thể mời hoặc xóa thành viên chuyến đi',
'perm.actionHint.file_upload': 'Ai có thể tải tập tin lên chuyến đi',
'perm.actionHint.file_edit': 'Ai có thể chỉnh sửa mô tả và liên kết tệp',
'perm.actionHint.file_delete': 'Ai có thể chuyển tệp vào thùng rác hoặc xóa chúng vĩnh viễn',
'perm.actionHint.place_edit': 'Ai có thể thêm, chỉnh sửa hoặc xóa địa điểm',
'perm.actionHint.day_edit': 'Ai có thể chỉnh sửa ngày, ghi chú ngày và đặt bài tập',
'perm.actionHint.reservation_edit': 'Ai có thể tạo, chỉnh sửa hoặc xóa đặt chỗ',
'perm.actionHint.budget_edit': 'Ai có thể tạo, chỉnh sửa hoặc xóa các mục ngân sách',
'perm.actionHint.packing_edit': 'Ai có thể quản lý các mặt hàng đóng gói và túi xách',
'perm.actionHint.collab_edit': 'Ai có thể tạo ghi chú, thăm dò ý kiến ​​và gửi tin nhắn',
'perm.actionHint.share_manage': 'Ai có thể tạo hoặc xóa liên kết chia sẻ công khai',
};
export default perm;
+25
View File
@@ -0,0 +1,25 @@
import type { TranslationStrings } from '../types';
const photos: TranslationStrings = {
'photos.title': 'Ảnh',
'photos.subtitle': '{count} ảnh cho {trip}',
'photos.dropHere': 'Thả ảnh vào đây...',
'photos.dropHereActive': 'Thả ảnh vào đây',
'photos.captionForAll': 'Chú thích (cho tất cả)',
'photos.captionPlaceholder': 'Chú thích tùy chọn...',
'photos.addCaption': 'Thêm chú thích...',
'photos.allDays': 'Tất cả các ngày',
'photos.noPhotos': 'Chưa có ảnh nào',
'photos.uploadHint': 'Tải ảnh du lịch của bạn lên',
'photos.clickToSelect': 'hoặc bấm để chọn',
'photos.linkPlace': 'Địa điểm liên kết',
'photos.noPlace': 'Không có nơi nào',
'photos.uploadN': '{n} tải lên ảnh',
'photos.linkDay': 'Ngày liên kết',
'photos.noDay': 'Không có ngày',
'photos.dayLabel': 'Ngày {number}',
'photos.photoSelected': 'Đã chọn ảnh',
'photos.photosSelected': 'Ảnh đã chọn',
'photos.fileTypeHint': 'JPG, PNG, WebP · tối đa. 10 MB · tối đa 30 ảnh',
};
export default photos;
+90
View File
@@ -0,0 +1,90 @@
import type { TranslationStrings } from '../types';
const places: TranslationStrings = {
'places.addPlace': 'Thêm địa điểm/Hoạt động',
'places.importFile': 'Nhập tập tin',
'places.sidebarDrop': 'Thả để nhập',
'places.importFileHint':
'Nhập tệp.gpx,.kml hoặc.kmz từ các công cụ như Google My Maps, Google Earth hoặc trình theo dõi GPS.',
'places.importFileDropHere': 'Bấm chọn file hoặc kéo thả vào đây',
'places.importFileDropActive': 'Thả tập tin để chọn',
'places.importFileUnsupported': 'Loại tệp không được hỗ trợ. Sử dụng.gpx,.kml hoặc.kmz.',
'places.importFileTooLarge': 'Tệp quá lớn. Kích thước tải lên tối đa là {maxMb} MB.',
'places.importFileError': 'Nhập không thành công',
'places.importAllSkipped': 'Tất cả các địa điểm đã có trong chuyến đi.',
'places.gpxImported': '{count} địa điểm được nhập từ GPX',
'places.gpxImportTypes': 'Bạn muốn nhập khẩu gì?',
'places.gpxImportWaypoints': 'Điểm tham chiếu',
'places.gpxImportRoutes': 'Tuyến đường',
'places.gpxImportTracks': 'Đường đi (có hình dạng đường dẫn)',
'places.gpxImportNoneSelected': 'Chọn ít nhất một loại để nhập.',
'places.kmlImportTypes': 'Bạn muốn nhập khẩu gì?',
'places.kmlImportPoints': 'Điểm (Dấu vị trí)',
'places.kmlImportPaths': 'Đường dẫn (LineStrings)',
'places.kmlImportNoneSelected': 'Chọn ít nhất một loại để nhập.',
'places.selectionCount': '{count} đã chọn',
'places.deleteSelected': 'Xóa đã chọn',
'places.kmlKmzImported': '{count} địa điểm được nhập từ KMZ/KML',
'places.urlResolved': 'Địa điểm được nhập từ URL',
'places.importList': 'Nhập danh sách',
'places.kmlKmzSummaryValues': 'Dấu vị trí: {total} • Đã nhập: {created} • Đã bỏ qua: {skipped}',
'places.importGoogleList': 'Danh sách Google',
'places.importNaverList': 'Danh sách Naver',
'places.googleListHint': 'Dán liên kết danh sách Google Maps được chia sẻ để nhập tất cả các địa điểm.',
'places.googleListImported': '{count} địa điểm được nhập từ "{list}"',
'places.googleListError': 'Không thể nhập danh sách Google Maps',
'places.naverListHint': 'Dán liên kết danh sách Naver Maps được chia sẻ để nhập tất cả các địa điểm.',
'places.naverListImported': '{count} địa điểm được nhập từ "{list}"',
'places.naverListError': 'Không thể nhập danh sách Naver Maps',
'places.viewDetails': 'Xem chi tiết',
'places.assignToDay': 'Thêm vào ngày nào?',
'places.all': 'Tất cả',
'places.unplanned': 'Không có kế hoạch',
'places.filterTracks': 'Bài hát',
'places.search': 'Tìm kiếm địa điểm...',
'places.allCategories': 'Tất cả danh mục',
'places.categoriesSelected': 'Thể loại',
'places.clearFilter': 'Xóa bộ lọc',
'places.count': '{count} địa điểm',
'places.countSingular': '1 nơi',
'places.allPlanned': 'Tất cả các địa điểm đều được quy hoạch',
'places.noneFound': 'Không tìm thấy địa điểm nào',
'places.editPlace': 'Chỉnh sửa địa điểm',
'places.formName': 'Tên',
'places.formNamePlaceholder': 'ví dụ. Tháp Eiffel',
'places.formDescription': 'Miêu tả',
'places.formDescriptionPlaceholder': 'Mô tả ngắn...',
'places.formAddress': 'Địa chỉ',
'places.formAddressPlaceholder': 'Đường phố, Thành phố, Quốc gia',
'places.formLat': 'Vĩ độ (ví dụ: 48,8566)',
'places.formLng': 'Kinh độ (ví dụ: 2,3522)',
'places.formCategory': 'Loại',
'places.noCategory': 'Không có danh mục',
'places.categoryNamePlaceholder': 'Tên danh mục',
'places.formTime': 'Thời gian',
'places.startTime': 'Bắt đầu',
'places.endTime': 'Kết thúc',
'places.endTimeBeforeStart': 'Thời gian kết thúc trước thời gian bắt đầu',
'places.timeCollision': 'Thời gian trùng lặp với:',
'places.formWebsite': 'Trang web',
'places.formNotes': 'Ghi chú',
'places.formNotesPlaceholder': 'Ghi chú cá nhân...',
'places.formReservation': 'Sự đặt chỗ',
'places.reservationNotesPlaceholder': 'Phiếu đặt chỗ, số xác nhận...',
'places.mapsSearchPlaceholder': 'Tìm kiếm địa điểm...',
'places.mapsSearchError': 'Tìm kiếm địa điểm không thành công.',
'places.loadingDetails': 'Đang tải chi tiết địa điểm…',
'places.osmHint':
'Sử dụng tìm kiếm OpenStreetMap (không có ảnh, giờ mở cửa hoặc xếp hạng). Thêm khóa Google API trong cài đặt để biết đầy đủ chi tiết.',
'places.osmActive':
'Tìm kiếm qua OpenStreetMap (không có ảnh, xếp hạng hoặc giờ mở cửa). Thêm khóa Google API trong Cài đặt để có dữ liệu nâng cao.',
'places.categoryCreateError': 'Không tạo được danh mục',
'places.nameRequired': 'Vui lòng nhập tên',
'places.saveError': 'Không lưu được',
'places.duplicateExists': '\'{name}\' đã có trong chuyến đi này.',
'places.addAnyway': 'Vẫn thêm',
'places.enrichOnImport': 'Làm phong phú các địa điểm thông qua Google',
'places.enrichOnImportHint':
'Tra cứu từng địa điểm đã nhập để điền ảnh, địa chỉ và thông tin liên hệ. Sử dụng khóa Google Maps của bạn.',
};
export default places;
+66
View File
@@ -0,0 +1,66 @@
import type { TranslationStrings } from '../types';
const planner: TranslationStrings = {
'planner.places': 'Địa điểm',
'planner.bookings': 'Đặt chỗ',
'planner.packingList': 'Danh sách đóng gói',
'planner.documents': 'Tài liệu',
'planner.dayPlan': 'Kế hoạch ngày',
'planner.reservations': 'Đặt chỗ',
'planner.minTwoPlaces': 'Cần ít nhất 2 địa điểm có tọa độ',
'planner.noGeoPlaces': 'Không có địa điểm nào có tọa độ',
'planner.routeCalculated': 'Tuyến đường được tính toán',
'planner.routeCalcFailed': 'Không thể tính toán lộ trình',
'planner.routeError': 'Lỗi tính toán lộ trình',
'planner.icsExportFailed': 'ICS xuất không thành công',
'planner.routeOptimized': 'Tuyến đường được tối ưu hóa',
'planner.reservationUpdated': 'Đã cập nhật đặt chỗ',
'planner.reservationAdded': 'Đã thêm đặt chỗ',
'planner.confirmDeleteReservation': 'Xóa đặt chỗ?',
'planner.reservationDeleted': 'Đã xóa đặt chỗ',
'planner.days': 'Ngày',
'planner.allPlaces': 'Tất cả địa điểm',
'planner.totalPlaces': 'Tổng cộng {n} địa điểm',
'planner.noDaysPlanned': 'Chưa có kế hoạch ngày nào',
'planner.editTrip': 'Chỉnh sửa chuyến đi →',
'planner.placeOne': '1 nơi',
'planner.placeN': '{n} địa điểm',
'planner.addNote': 'Thêm ghi chú',
'planner.noEntries': 'Không có mục nào cho ngày này',
'planner.addPlace': 'Thêm địa điểm/hoạt động',
'planner.addPlaceShort': '+ Thêm địa điểm/hoạt động',
'planner.resPending': 'Đang chờ đặt chỗ ·',
'planner.resConfirmed': 'Đã xác nhận đặt chỗ ·',
'planner.notePlaceholder': 'Ghi chú…',
'planner.noteTimePlaceholder': 'Thời gian (tùy chọn)',
'planner.noteExamplePlaceholder': 'ví dụ. S3 lúc 14:30 từ ga trung tâm, phà từ bến tàu số 7, nghỉ trưa…',
'planner.totalCost': 'Tổng chi phí',
'planner.searchPlaces': 'Tìm kiếm địa điểm…',
'planner.allCategories': 'Tất cả danh mục',
'planner.noPlacesFound': 'Không tìm thấy địa điểm nào',
'planner.addFirstPlace': 'Thêm vị trí đầu tiên',
'planner.noReservations': 'Không đặt trước',
'planner.addFirstReservation': 'Thêm đặt chỗ đầu tiên',
'planner.new': 'Mới',
'planner.addToDay': '+ Ngày',
'planner.calculating': 'Đang tính…',
'planner.route': 'Tuyến đường',
'planner.optimize': 'Tối ưu hóa',
'planner.openGoogleMaps': 'Mở trong Google Maps',
'planner.selectDayHint': 'Chọn một ngày từ danh sách bên trái để xem kế hoạch trong ngày',
'planner.noPlacesForDay': 'Chưa có địa điểm nào cho ngày này',
'planner.addPlacesLink': 'Thêm địa điểm →',
'planner.minTotal': 'phút. tổng cộng',
'planner.noReservation': 'Không đặt trước',
'planner.removeFromDay': 'Xóa khỏi ngày',
'planner.addToThisDay': 'Thêm vào ngày',
'planner.overview': 'Tổng quan',
'planner.noDays': 'Chưa có ngày nào',
'planner.editTripToAddDays': 'Chỉnh sửa chuyến đi để thêm ngày',
'planner.dayCount': '{n} Ngày',
'planner.clickToUnlock': 'Bấm để mở khóa',
'planner.keepPosition': 'Giữ vị trí trong quá trình tối ưu hóa tuyến đường',
'planner.dayDetails': 'Chi tiết ngày',
'planner.dayN': 'Ngày {n}',
};
export default planner;
+25
View File
@@ -0,0 +1,25 @@
import type { TranslationStrings } from '../types';
const register: TranslationStrings = {
'register.passwordMismatch': 'Mật khẩu không khớp',
'register.passwordTooShort': 'Mật khẩu phải có ít nhất 8 ký tự',
'register.failed': 'Đăng ký không thành công',
'register.getStarted': 'Bắt đầu',
'register.subtitle': 'Tạo một tài khoản và bắt đầu lên kế hoạch cho những chuyến đi mơ ước của bạn.',
'register.feature1': 'Kế hoạch chuyến đi không giới hạn',
'register.feature2': 'Chế độ xem bản đồ tương tác',
'register.feature3': 'Quản lý địa điểm và danh mục',
'register.feature4': 'Theo dõi đặt chỗ',
'register.feature5': 'Tạo danh sách đóng gói',
'register.feature6': 'Lưu trữ ảnh và tập tin',
'register.createAccount': 'Tạo tài khoản',
'register.startPlanning': 'Bắt đầu kế hoạch chuyến đi của bạn',
'register.minChars': 'Tối thiểu. 6 ký tự',
'register.confirmPassword': 'Xác nhận mật khẩu',
'register.repeatPassword': 'Lặp lại mật khẩu',
'register.registering': 'Đang đăng ký...',
'register.register': 'Đăng ký',
'register.hasAccount': 'Đã có tài khoản?',
'register.signIn': 'Đăng nhập',
};
export default register;
+165
View File
@@ -0,0 +1,165 @@
import type { TranslationStrings } from '../types';
const reservations: TranslationStrings = {
'reservations.title': 'Đặt chỗ',
'reservations.empty': 'Chưa có đặt chỗ nào',
'reservations.emptyHint': 'Thêm đặt chỗ cho chuyến bay, khách sạn và hơn thế nữa',
'reservations.add': 'Thêm đặt chỗ',
'reservations.addManual': 'Thêm đặt chỗ',
'reservations.placeHint': 'Mẹo: Tốt nhất bạn nên tạo đặt chỗ trực tiếp từ một nơi để liên kết chúng với kế hoạch trong ngày của bạn.',
'reservations.confirmed': 'Đã xác nhận',
'reservations.pending': 'Chưa giải quyết',
'reservations.summary': '{confirmed} đã xác nhận, {pending} đang chờ xử lý',
'reservations.fromPlan': 'Từ kế hoạch',
'reservations.showFiles': 'Hiển thị tệp',
'reservations.editTitle': 'Chỉnh sửa đặt chỗ',
'reservations.status': 'Trạng thái',
'reservations.datetime': 'Ngày & Giờ',
'reservations.startTime': 'Thời gian bắt đầu',
'reservations.endTime': 'Thời gian kết thúc',
'reservations.date': 'Ngày',
'reservations.time': 'Thời gian',
'reservations.timeAlt': 'Thời gian (thay thế, ví dụ: 19:30)',
'reservations.notes': 'Ghi chú',
'reservations.notesPlaceholder': 'Ghi chú bổ sung...',
'reservations.meta.airline': 'Hãng hàng không',
'reservations.meta.flightNumber': 'Chuyến bay số',
'reservations.meta.from': 'Từ',
'reservations.meta.to': 'ĐẾN',
'reservations.layover.route': 'Tuyến đường',
'reservations.layover.stop': 'Dừng lại',
'reservations.layover.addStop': 'Thêm điểm dừng',
'reservations.layover.connection': 'Sự liên quan',
'reservations.layover.layover': 'quá cảnh',
'reservations.needsReview': 'Ôn tập',
'reservations.needsReviewHint': 'Sân bay không thể được khớp tự động - vui lòng xác nhận vị trí.',
'reservations.searchLocation': 'Trạm tìm kiếm, cổng, địa chỉ…',
'reservations.meta.trainNumber': 'Số tàu',
'reservations.meta.platform': 'Sân ga',
'reservations.meta.seat': 'Ghế',
'reservations.meta.checkIn': 'Đăng ký vào',
'reservations.meta.checkInUntil': 'Nhận phòng cho đến khi',
'reservations.meta.checkOut': 'Trả phòng',
'reservations.meta.linkAccommodation': 'Chỗ ở',
'reservations.meta.pickAccommodation': 'Liên kết chỗ ở',
'reservations.meta.noAccommodation': 'Không có',
'reservations.meta.hotelPlace': 'Chỗ ở',
'reservations.meta.pickHotel': 'Chọn chỗ ở',
'reservations.meta.fromDay': 'Từ',
'reservations.meta.toDay': 'ĐẾN',
'reservations.meta.selectDay': 'Chọn ngày',
'reservations.type.flight': 'Chuyến bay',
'reservations.type.hotel': 'Chỗ ở',
'reservations.type.restaurant': 'Nhà hàng',
'reservations.type.train': 'Xe lửa',
'reservations.type.car': 'Xe hơi',
'reservations.type.cruise': 'Du thuyền',
'reservations.type.event': 'Sự kiện',
'reservations.type.tour': 'Chuyến du lịch',
'reservations.type.other': 'Khác',
'reservations.type.bus': 'xe buýt',
'reservations.type.ferry': 'Phà',
'reservations.type.bicycle': 'Xe đạp',
'reservations.type.taxi': 'Taxi',
'reservations.type.transport_other': 'Khác',
'reservations.confirm.delete': 'Bạn có chắc chắn muốn xóa đặt chỗ "{name}" không?',
'reservations.confirm.deleteTitle': 'Xóa đặt chỗ?',
'reservations.confirm.deleteBody': '"{name}" sẽ bị xóa vĩnh viễn.',
'reservations.toast.updated': 'Đã cập nhật đặt chỗ',
'reservations.toast.removed': 'Đã xóa đặt chỗ',
'reservations.toast.fileUploaded': 'Tệp đã được tải lên',
'reservations.toast.uploadError': 'Không thể tải lên',
'reservations.newTitle': 'Đặt chỗ mới',
'reservations.bookingType': 'Loại đặt chỗ',
'reservations.titleLabel': 'Tiêu đề',
'reservations.titlePlaceholder': 'ví dụ. Lufthansa LH123, Khách sạn Adlon,...',
'reservations.locationAddress': 'Vị trí / Địa chỉ',
'reservations.locationPlaceholder': 'Địa chỉ, Sân bay, Khách sạn...',
'reservations.confirmationCode': 'Mã đặt chỗ',
'reservations.confirmationPlaceholder': 'ví dụ. ABC12345',
'reservations.day': 'Ngày',
'reservations.noDay': 'Không có ngày',
'reservations.place': 'Địa điểm',
'reservations.noPlace': 'Không có nơi nào',
'reservations.pendingSave': 'sẽ được cứu…',
'reservations.uploading': 'Đang tải lên...',
'reservations.attachFile': 'Đính kèm tập tin',
'reservations.linkExisting': 'Liên kết tập tin hiện có',
'reservations.toast.saveError': 'Không lưu được',
'reservations.toast.updateError': 'Không thể cập nhật',
'reservations.toast.deleteError': 'Không thể xóa',
'reservations.confirm.remove': 'Xóa phần đặt chỗ cho "{name}"?',
'reservations.linkAssignment': 'Liên kết đến bài tập trong ngày',
'reservations.pickAssignment': 'Chọn một nhiệm vụ từ kế hoạch của bạn...',
'reservations.noAssignment': 'Không có liên kết (độc lập)',
'reservations.price': 'Giá',
'reservations.budgetCategory': 'Hạng mục ngân sách',
'reservations.budgetCategoryPlaceholder': 'ví dụ. Vận chuyển, Chỗ ở',
'reservations.budgetCategoryAuto': 'Tự động (từ loại đặt chỗ)',
'reservations.budgetHint': 'Một mục nhập ngân sách sẽ được tạo tự động khi lưu.',
'reservations.departureDate': 'Khởi hành',
'reservations.arrivalDate': 'Đến',
'reservations.departureTime': 'Thời gian khởi hành',
'reservations.arrivalTime': 'Thời gian hạ cánh',
'reservations.pickupDate': 'Ngày đón',
'reservations.returnDate': 'Ngày trở về',
'reservations.pickupTime': 'Thời gian đón',
'reservations.returnTime': 'Thời gian trở về',
'reservations.endDate': 'Ngày kết thúc',
'reservations.meta.departureTimezone': 'Múi giờ đi',
'reservations.meta.arrivalTimezone': 'Múi giờ đến',
'reservations.span.departure': 'Khởi hành',
'reservations.span.arrival': 'Đến',
'reservations.span.inTransit': 'Đang chuyển tiếp',
'reservations.span.pickup': 'Đón',
'reservations.span.return': 'Trở lại',
'reservations.span.active': 'Tích cực',
'reservations.span.start': 'Bắt đầu',
'reservations.span.end': 'Kết thúc',
'reservations.span.ongoing': 'Đang thực hiện',
'reservations.validation.endBeforeStart': 'Ngày/giờ kết thúc phải sau ngày/giờ bắt đầu',
'reservations.addBooking': 'Thêm đặt chỗ',
'reservations.import.title': 'Nhập xác nhận đặt chỗ',
'reservations.import.cta': 'Nhập từ tập tin',
'reservations.import.dropHere': 'Thả file xác nhận đặt phòng tại đây, hoặc bấm để chọn',
'reservations.import.dropActive': 'Thả tập tin để nhập',
'reservations.import.acceptedFormats': 'Đã chấp nhận: EML, PDF, PKPass, HTML, TXT (tối đa 10 MB mỗi cái, tối đa 5 tệp)',
'reservations.import.parsing': 'Đang phân tích tệp…',
'reservations.import.previewHeading': '{count} đã tìm thấy (các) đặt chỗ',
'reservations.import.previewEmpty': 'Không thể trích xuất đặt chỗ nào từ các tập tin đã tải lên.',
'reservations.import.removeItem': 'Xóa xem xét',
'reservations.import.needsReview': 'Xem xét',
'reservations.import.tryAi': 'Thử phân tích bằng AI',
'reservations.import.aiParsing': 'Đang phân tích bằng AI...',
'reservations.import.confirm': 'Nhập {count} đặt chỗ',
'reservations.import.back': 'Quay lại',
'reservations.import.success': '{count} đặt chỗ đã được nhập',
'reservations.import.partialFailure': '{created} đã được nhập, {failed} không thành công',
'reservations.import.error': 'Phân tích cú pháp không thành công. Hãy chắc chắn rằng tập tin này là một xác nhận đặt phòng hợp lệ.',
'reservations.import.unavailable': 'Nhập đăng ký không có sẵn trên máy chủ này.',
'reservations.import.unsupportedFormat': 'Định dạng tệp không được hỗ trợ. Sử dụng EML, PDF, PKPass, HTML hoặc TXT.',
'reservations.import.fileTooLarge': 'Tệp "{name}" vượt quá giới hạn 10 MB.',
'reservations.airtrail.title': 'Nhập từ AirTrail',
'reservations.airtrail.cta': 'AirTrail',
'reservations.airtrail.synced': 'AirTrail',
'reservations.airtrail.syncedHint': 'Đã đồng bộ hóa từ AirTrail — các chỉnh sửa vẫn được đồng bộ hóa theo cả hai cách.',
'reservations.airtrail.notSynced': 'Chưa được đồng bộ hóa',
'reservations.airtrail.notSyncedHint': 'Chuyến bay này đã bị xóa trong AirTrail và không còn đồng bộ hóa nữa.',
'reservations.airtrail.loadError': 'Không thể tải chuyến bay AirTrail của bạn.',
'reservations.airtrail.imported': '{count} chuyến bay đã nhập',
'reservations.airtrail.skippedDuplicate': '{count} đã tham gia chuyến đi này, đã bỏ qua',
'reservations.airtrail.nothingImported': 'Không có gì để nhập khẩu.',
'reservations.airtrail.importError': 'Nhập không thành công. Vui lòng thử lại.',
'reservations.airtrail.undo': 'Nhập từ AirTrail',
'reservations.airtrail.alreadyImported': 'Đã nhập',
'reservations.airtrail.duringTrip': 'Trong chuyến đi này',
'reservations.airtrail.otherFlights': 'Các chuyến bay khác',
'reservations.airtrail.empty': 'Không tìm thấy chuyến bay nào trong tài khoản AirTrail của bạn.',
'reservations.airtrail.importCta': 'Nhập {count}',
'reservations.costsLabel': 'Chi phí',
'reservations.createExpense': 'Tạo chi phí',
'reservations.createExpenseHint': 'Lưu đặt chỗ, sau đó mở trình chỉnh sửa Chi phí.',
'reservations.linkedExpense': 'Chi phí liên kết',
'reservations.removeExpense': 'Xóa chi phí',
};
export default reservations;
+345
View File
@@ -0,0 +1,345 @@
import type { TranslationStrings } from '../types';
const settings: TranslationStrings = {
'settings.title': 'Cài đặt',
'settings.subtitle': 'Định cấu hình cài đặt cá nhân của bạn',
'settings.tabs.display': 'Hiển thị',
'settings.tabs.map': 'Bản đồ',
'settings.tabs.notifications': 'Thông báo',
'settings.tabs.integrations': 'Tích hợp',
'settings.tabs.account': 'Tài khoản',
'settings.tabs.offline': 'Ngoại tuyến',
'settings.tabs.about': 'Về',
'settings.map': 'Bản đồ',
'settings.mapTemplate': 'Mẫu bản đồ',
'settings.mapTemplatePlaceholder.select': 'Chọn mẫu...',
'settings.mapDefaultHint': 'Để trống cho OpenStreetMap (mặc định)',
'settings.mapTemplatePlaceholder': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'settings.mapHint': 'Mẫu URL cho ô bản đồ',
'settings.mapProvider': 'Nhà cung cấp bản đồ',
'settings.mapProviderHint': 'Ảnh hưởng tới Công cụ lập kế hoạch chuyến đi và bản đồ hành trình. Atlas luôn sử dụng Leaflet.',
'settings.mapLeafletSubtitle': '2D cổ điển, bất kỳ ô raster nào',
'settings.mapMapboxSubtitle': 'Gạch vector, tòa nhà 3D và địa hình',
'settings.mapMapLibreSubtitle': 'OpenFreeMap gạch vector, không có mã thông báo',
'settings.mapExperimental': 'thực nghiệm',
'settings.mapMapboxToken': 'Mapbox Mã thông báo truy cập',
'settings.mapMapboxTokenHint': 'Mã thông báo công khai (pk.*) từ',
'settings.mapMapboxTokenLink': 'mapbox.com → Mã thông báo truy cập',
'settings.mapStyle': 'Kiểu bản đồ',
'settings.mapStylePlaceholder': 'Chọn kiểu Mapbox',
'settings.mapStyleHint': 'Đặt trước hoặc của riêng bạn mapbox://styles/USER/ID URL',
'settings.mapOpenFreeMapStylePlaceholder': 'Chọn kiểu OpenFreeMap',
'settings.mapOpenFreeMapStyleHint': 'Đặt trước hoặc kiểu OpenFreeMap URL. Kiểu OpenFreeMap hoạt động mà không cần mã thông báo.',
'settings.map3dBuildings': 'Tòa nhà & địa hình 3D',
'settings.map3dHint': 'Cao độ + ép đùn tòa nhà 3D thực - hoạt động trên mọi phong cách, bao gồm cả vệ tinh.',
'settings.mapHighQuality': 'Chế độ chất lượng cao',
'settings.mapHighQualityHint': 'Khử răng cưa + chiếu hình ảnh địa cầu cho các cạnh sắc nét hơn và thế giới quan chân thực hơn.',
'settings.mapHighQualityWarning': 'Có thể ảnh hưởng đến hiệu suất trên các thiết bị cấp thấp hơn.',
'settings.mapTipLabel': 'Mẹo:',
'settings.mapTip':
'nhấp chuột phải và kéo để xoay/cao độ bản đồ. Nhấp chuột giữa để thêm địa điểm (nhấp chuột phải được dành riêng cho việc xoay).',
'settings.latitude': 'Vĩ độ',
'settings.longitude': 'Kinh độ',
'settings.saveMap': 'Lưu bản đồ',
'settings.apiKeys': 'API Chìa khóa',
'settings.mapsKey': 'Google Maps API Chìa khóa',
'settings.mapsKeyHint': 'Để tìm kiếm địa điểm. Yêu cầu Địa điểm API (Mới). Truy cập tại console.cloud.google.com',
'settings.weatherKey': 'OpenWeatherMap API Chìa khóa',
'settings.weatherKeyHint': 'Đối với dữ liệu thời tiết. Miễn phí tại openweathermap.org/api',
'settings.keyPlaceholder': 'Nhập khóa...',
'settings.configured': 'Đã định cấu hình',
'settings.saveKeys': 'Lưu chìa khóa',
'settings.display': 'Hiển thị',
'settings.colorMode': 'Chế độ màu',
'settings.light': 'Sáng',
'settings.dark': 'Tối',
'settings.auto': 'Tự động',
'settings.language': 'Ngôn ngữ',
'settings.temperature': 'Đơn vị nhiệt độ',
'settings.distance': 'Đơn vị khoảng cách',
'settings.timeFormat': 'Định dạng thời gian',
'settings.bookingLabels': 'Nhãn lộ trình đặt chỗ',
'settings.bookingLabelsHint': 'Hiển thị tên ga/sân bay trên bản đồ. Khi tắt, chỉ có biểu tượng được hiển thị.',
'settings.mapPoiPill': 'Khám phá các địa điểm trên bản đồ',
'settings.mapPoiPillHint':
'Hiển thị một danh mục trên bản đồ chuyến đi để tìm các nhà hàng, khách sạn lân cận và hơn thế nữa từ OpenStreetMap.',
'settings.blurBookingCodes': 'Mã đặt chỗ mờ',
'settings.optimizeFromAccommodation': 'Tối ưu hóa tuyến đường từ chỗ ở',
'settings.optimizeFromAccommodationHint':
'Khi tối ưu hóa một ngày, hãy bắt đầu lộ trình tại khách sạn nơi bạn thức dậy và kết thúc tại khách sạn bạn nhận phòng vào tối hôm đó.',
'settings.aiAlwaysRetry': 'Luôn thử lại việc nhập đặt chỗ bằng AI.',
'settings.aiAlwaysRetryHint': 'Khi trình phân tích cú pháp tiêu chuẩn không thể đọc được tệp, hãy tự động thử lại bằng AI..',
'settings.notifications': 'Thông báo',
'settings.notifyTripInvite': 'Lời mời chuyến đi',
'settings.notifyBookingChange': 'Thay đổi đặt chỗ',
'settings.notifyTripReminder': 'Lời nhắc chuyến đi',
'settings.notifyTodoDue': 'Việc cần làm sắp đến hạn',
'settings.notifyVacayInvite': 'Lời mời kết hợp Vacay',
'settings.notifyPhotosShared': 'Ảnh được chia sẻ (Immich)',
'settings.notifyCollabMessage': 'Tin nhắn trò chuyện (Cộng tác)',
'settings.notifyPackingTagged': 'Danh sách đóng gói: phân công',
'settings.notifyWebhook': 'Thông báo webhook',
'settings.notifyVersionAvailable': 'Đã có phiên bản mới',
'settings.notificationPreferences.email': 'Email',
'settings.notificationPreferences.webhook': 'Webhook',
'settings.notificationPreferences.inapp': 'Trong ứng dụng',
'settings.notificationPreferences.ntfy': 'Ntfy',
'settings.notificationPreferences.noChannels':
'Không có kênh thông báo nào được cấu hình. Yêu cầu quản trị viên thiết lập thông báo qua email hoặc webhook.',
'settings.webhookUrl.label': 'Webhook URL',
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
'settings.webhookUrl.hint': 'Nhập Discord, Slack hoặc webhook tùy chỉnh URL của bạn để nhận thông báo.',
'settings.webhookUrl.saved': 'Đã lưu Webhook URL',
'settings.webhookUrl.test': 'Bài kiểm tra',
'settings.webhookUrl.testSuccess': 'Kiểm tra webhook đã được gửi thành công',
'settings.webhookUrl.testFailed': 'Kiểm tra webhook không thành công',
'settings.ntfyUrl.topicLabel': 'Ntfy Chủ đề',
'settings.ntfyUrl.topicPlaceholder': 'cảnh báo chuyến đi của tôi',
'settings.ntfyUrl.serverLabel': 'Ntfy Máy chủ URL (tùy chọn)',
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
'settings.ntfyUrl.hint':
'Nhập chủ đề ntfy của bạn để nhận thông báo đẩy. Để trống máy chủ để sử dụng cài đặt mặc định do quản trị viên của bạn định cấu hình.',
'settings.ntfyUrl.tokenLabel': 'Mã thông báo truy cập (tùy chọn)',
'settings.ntfyUrl.tokenHint': 'Cần thiết cho các chủ đề được bảo vệ bằng mật khẩu.',
'settings.ntfyUrl.saved': 'Ntfy đã lưu cài đặt',
'settings.ntfyUrl.test': 'Bài kiểm tra',
'settings.ntfyUrl.testSuccess': 'Kiểm tra thông báo ntfy đã được gửi thành công',
'settings.ntfyUrl.testFailed': 'Kiểm tra thông báo ntfy không thành công',
'settings.ntfyUrl.tokenCleared': 'Đã xóa mã thông báo truy cập',
'settings.notificationsDisabled':
'Thông báo không được cấu hình. Yêu cầu quản trị viên bật thông báo qua email hoặc webhook.',
'settings.notificationsActive': 'Kênh hoạt động',
'settings.notificationsManagedByAdmin': 'Các sự kiện thông báo được quản trị viên của bạn định cấu hình.',
'settings.on': 'Bật',
'settings.off': 'Tắt',
'settings.mcp.title': 'MCP Cấu hình',
'settings.mcp.endpoint': 'MCP Điểm cuối',
'settings.mcp.clientConfig': 'Cấu hình máy khách',
'settings.mcp.clientConfigHint':
'Thay thế <your_token> bằng mã thông báo API từ danh sách bên dưới. Đường dẫn đến npx có thể cần được điều chỉnh cho hệ thống của bạn (ví dụ: C:\\PROGRA~1\\nodejs\\npx.cmd trên Windows).',
'settings.mcp.clientConfigHintOAuth':
'Thay thế <your_client_id> và <your_client_secret> bằng thông tin xác thực được hiển thị trong ứng dụng khách OAuth 2.1 mà bạn đã tạo ở trên. mcp-remote sẽ mở trình duyệt của bạn để hoàn tất việc ủy ​​quyền vào lần đầu tiên bạn kết nối. Đường dẫn đến npx có thể cần được điều chỉnh cho hệ thống của bạn (ví dụ: C:PROGRA~1\nodejs\npx.cmd trên Windows).',
'settings.mcp.copy': 'Sao chép',
'settings.mcp.copied': 'Đã sao chép!',
'settings.mcp.apiTokens': 'API Mã thông báo',
'settings.mcp.createToken': 'Tạo mã thông báo mới',
'settings.mcp.noTokens': 'Chưa có token nào. Tạo một cái để kết nối các máy khách MCP.',
'settings.mcp.tokenCreatedAt': 'Tạo',
'settings.mcp.tokenUsedAt': 'Đã sử dụng',
'settings.mcp.deleteTokenTitle': 'Xóa mã thông báo',
'settings.mcp.deleteTokenMessage':
'Mã thông báo này sẽ ngừng hoạt động ngay lập tức. Bất kỳ khách hàng MCP nào sử dụng nó sẽ mất quyền truy cập.',
'settings.mcp.modal.createTitle': 'Tạo mã thông báo API',
'settings.mcp.modal.tokenName': 'Tên mã thông báo',
'settings.mcp.modal.tokenNamePlaceholder': 'ví dụ. Máy tính để bàn Claude, Máy tính xách tay làm việc',
'settings.mcp.modal.creating': 'Đang tạo…',
'settings.mcp.modal.create': 'Tạo mã thông báo',
'settings.mcp.modal.createdTitle': 'Đã tạo mã thông báo',
'settings.mcp.modal.createdWarning':
'Mã thông báo này sẽ chỉ được hiển thị một lần. Sao chép và lưu trữ ngay bây giờ - không thể phục hồi được.',
'settings.mcp.modal.done': 'Xong',
'settings.mcp.toast.created': 'Đã tạo mã thông báo',
'settings.mcp.toast.createError': 'Không tạo được mã thông báo',
'settings.mcp.toast.deleted': 'Đã xóa mã thông báo',
'settings.mcp.toast.deleteError': 'Không xóa được mã thông báo',
'settings.mcp.apiTokensDeprecated':
'API Mã thông báo không được dùng nữa và sẽ bị xóa trong bản phát hành trong tương lai. Thay vào đó, vui lòng sử dụng Khách hàng OAuth 2.1.',
'settings.oauth.clients': 'OAuth 2.1 Khách hàng',
'settings.oauth.clientsHint':
'Đăng ký ứng dụng khách OAuth 2.1 để cho phép các ứng dụng MCP của bên thứ ba (Claude Web, Cursor, v.v.) kết nối mà không cần mã thông báo tĩnh.',
'settings.oauth.createClient': 'Khách hàng mới',
'settings.oauth.noClients': 'Không có khách hàng OAuth nào được đăng ký.',
'settings.oauth.clientId': 'Khách hàng ID',
'settings.oauth.clientSecret': 'Bí mật khách hàng',
'settings.oauth.deleteClient': 'Xóa khách hàng',
'settings.oauth.deleteClientMessage':
'Ứng dụng khách này và tất cả các phiên hoạt động sẽ bị xóa vĩnh viễn. Bất kỳ ứng dụng nào sử dụng nó sẽ mất quyền truy cập ngay lập tức.',
'settings.oauth.rotateSecret': 'Xoay bí mật',
'settings.oauth.rotateSecretMessage':
'Một bí mật khách hàng mới sẽ được tạo và tất cả các phiên hiện có sẽ bị vô hiệu ngay lập tức. Cập nhật ứng dụng của bạn trước khi đóng hộp thoại này.',
'settings.oauth.rotateSecretConfirm': 'Quay',
'settings.oauth.rotateSecretConfirming': 'Đang quay…',
'settings.oauth.rotateSecretDoneTitle': 'Bí mật mới được tạo',
'settings.oauth.rotateSecretDoneWarning':
'Bí mật này chỉ được hiển thị một lần. Sao chép nó ngay bây giờ và cập nhật ứng dụng của bạn - tất cả các phiên trước đó đã bị vô hiệu.',
'settings.oauth.activeSessions': 'Phiên hoạt động OAuth',
'settings.oauth.sessionScopes': 'Phạm vi',
'settings.oauth.sessionExpires': 'Hết hạn',
'settings.oauth.revoke': 'Thu hồi',
'settings.oauth.revokeSession': 'Thu hồi phiên',
'settings.oauth.revokeSessionMessage': 'Thao tác này sẽ ngay lập tức thu hồi quyền truy cập đối với phiên OAuth này.',
'settings.oauth.modal.createTitle': 'Đăng ký khách hàng OAuth',
'settings.oauth.modal.presets': 'Cài đặt trước nhanh',
'settings.oauth.modal.clientName': 'Tên ứng dụng',
'settings.oauth.modal.clientNamePlaceholder': 'ví dụ. Claude Web, Ứng dụng MCP của tôi',
'settings.oauth.modal.redirectUris': 'URI chuyển hướng',
'settings.oauth.modal.redirectUrisPlaceholder': 'https://your-app.com/callback\nhttps://your-app.com/auth',
'settings.oauth.modal.redirectUrisHint': 'Một URI trên mỗi dòng. Yêu cầu HTTPS (miễn trừ localhost). Đối sánh chính xác được thực thi.',
'settings.oauth.modal.scopes': 'Phạm vi được phép',
'settings.oauth.modal.scopesHint':
'list_trips và get_trip_summary luôn có sẵn — không yêu cầu phạm vi. Họ cho phép AI khám phá ID chuyến đi cần thiết để sử dụng bất kỳ công cụ nào khác.',
'settings.oauth.modal.selectAll': 'Chọn tất cả',
'settings.oauth.modal.deselectAll': 'Bỏ chọn tất cả',
'settings.oauth.modal.creating': 'Đang đăng ký…',
'settings.oauth.modal.create': 'Đăng ký khách hàng',
'settings.oauth.modal.createdTitle': 'Khách hàng đã đăng ký',
'settings.oauth.modal.createdWarning': 'Bí mật của khách hàng chỉ được hiển thị một lần. Sao chép nó ngay bây giờ - nó không thể phục hồi được.',
'settings.oauth.toast.createError': 'Không thể đăng ký ứng dụng khách OAuth',
'settings.oauth.toast.deleted': 'OAuth khách hàng đã bị xóa',
'settings.oauth.toast.deleteError': 'Không xóa được ứng dụng khách OAuth',
'settings.oauth.toast.revoked': 'Phiên bị thu hồi',
'settings.oauth.toast.revokeError': 'Không thể thu hồi phiên',
'settings.oauth.toast.rotateError': 'Không thể xoay bí mật của khách hàng',
'settings.oauth.modal.machineClient': 'Máy khách (không đăng nhập trình duyệt)',
'settings.oauth.modal.machineClientHint':
'Sử dụng cấp client_credentials — không cần URI chuyển hướng. Mã thông báo được phát hành trực tiếp qua client_id + client_secret và hoạt động với tư cách là bạn trong phạm vi đã chọn.',
'settings.oauth.modal.machineClientUsage':
'Nhận mã thông báo: POST /oauth/token với Grant_type=client_credentials, client_id và client_secret. Không có trình duyệt, không có mã thông báo làm mới.',
'settings.oauth.badge.machine': 'máy móc',
'settings.account': 'Tài khoản',
'settings.about': 'Về',
'settings.about.reportBug': 'Báo cáo lỗi',
'settings.about.reportBugHint': 'Tìm thấy một vấn đề? Hãy cho chúng tôi biết',
'settings.about.featureRequest': 'Yêu cầu tính năng',
'settings.about.featureRequestHint': 'Đề xuất tính năng mới',
'settings.about.wikiHint': 'Tài liệu & hướng dẫn',
'settings.about.supporters.badge': 'Người ủng hộ hàng tháng',
'settings.about.supporters.title': 'Bạn đồng hành cho TREK',
'settings.about.supporters.subtitle':
'Trong khi bạn đang lên kế hoạch cho lộ trình tiếp theo của mình, những người này đang giúp lập kế hoạch cho tương lai của TREK. Đóng góp hàng tháng của họ được đổ thẳng vào hoạt động phát triển và số giờ thực tế được sử dụng — vì vậy TREK vẫn là Nguồn mở.',
'settings.about.supporters.since': 'ủng hộ kể từ {date}',
'settings.about.supporters.tierEmpty': 'Hãy là người đầu tiên',
'settings.about.supporter.tier.noReturnTicket': 'Không có vé khứ hồi',
'settings.about.supporter.tier.lostLuggageVip': 'Hành Lý Thất Lạc VIP',
'settings.about.supporter.tier.businessClassDreamer': 'Người mơ mộng hạng thương gia',
'settings.about.supporter.tier.budgetTraveller': 'Khách du lịch tiết kiệm',
'settings.about.supporter.tier.hostelBunkmate': 'Nhà nghỉ bạn cùng phòng',
'settings.about.description':
'TREK là công cụ lập kế hoạch du lịch tự lưu trữ giúp bạn tổ chức các chuyến đi của mình từ ý tưởng đầu tiên đến kỷ niệm cuối cùng. Lập kế hoạch trong ngày, ngân sách, danh sách đóng gói, ảnh và nhiều nội dung khác — tất cả đều ở cùng một nơi, trên máy chủ của riêng bạn.',
'settings.about.madeWith': 'Được làm bằng',
'settings.about.madeBy': 'của Maurice và cộng đồng nguồn mở đang phát triển.',
'settings.username': 'Tên người dùng',
'settings.email': 'Email',
'settings.role': 'Vai trò',
'settings.roleAdmin': 'Quản trị viên',
'settings.oidcLinked': 'Liên kết với',
'settings.changePassword': 'Thay đổi mật khẩu',
'settings.currentPassword': 'Mật khẩu hiện tại',
'settings.currentPasswordRequired': 'Mật khẩu hiện tại là bắt buộc',
'settings.newPassword': 'Mật khẩu mới',
'settings.confirmPassword': 'Xác nhận mật khẩu mới',
'settings.updatePassword': 'Cập nhật mật khẩu',
'settings.passwordRequired': 'Vui lòng nhập mật khẩu hiện tại và mật khẩu mới',
'settings.passwordTooShort': 'Mật khẩu phải có ít nhất 8 ký tự',
'settings.passwordMismatch': 'Mật khẩu không khớp',
'settings.passwordWeak': 'Mật khẩu phải có chữ hoa, chữ thường, số và ký tự đặc biệt',
'settings.passwordChanged': 'Đã thay đổi mật khẩu thành công',
'settings.mustChangePassword':
'Bạn phải thay đổi mật khẩu trước khi có thể tiếp tục. Vui lòng đặt mật khẩu mới bên dưới.',
'settings.deleteAccount': 'Xóa tài khoản',
'settings.deleteAccountTitle': 'Xóa tài khoản của bạn?',
'settings.deleteAccountWarning':
'Tài khoản của bạn và tất cả các chuyến đi, địa điểm và tệp của bạn sẽ bị xóa vĩnh viễn. Không thể hoàn tác hành động này.',
'settings.deleteAccountConfirm': 'Xóa vĩnh viễn',
'settings.deleteBlockedTitle': 'Không thể xóa',
'settings.deleteBlockedMessage':
'Bạn là quản trị viên duy nhất. Thăng cấp người dùng khác lên quản trị viên trước khi xóa tài khoản của bạn.',
'settings.roleUser': 'người dùng',
'settings.saveProfile': 'Lưu hồ sơ',
'settings.toast.mapSaved': 'Đã lưu cài đặt bản đồ',
'settings.toast.keysSaved': 'Đã lưu khóa API',
'settings.toast.displaySaved': 'Đã lưu cài đặt hiển thị',
'settings.toast.profileSaved': 'Đã lưu hồ sơ',
'settings.uploadAvatar': 'Tải ảnh hồ sơ lên',
'settings.removeAvatar': 'Xóa ảnh hồ sơ',
'settings.avatarUploaded': 'Đã cập nhật ảnh hồ sơ',
'settings.avatarRemoved': 'Đã xóa ảnh hồ sơ',
'settings.avatarError': 'Tải lên không thành công',
'settings.mfa.title': 'Xác thực hai yếu tố (2FA)',
'settings.mfa.description':
'Thêm bước thứ hai khi bạn đăng nhập bằng email và mật khẩu. Sử dụng ứng dụng xác thực (Google Authenticator, Authy, v.v.).',
'settings.mfa.requiredByPolicy':
'Quản trị viên của bạn yêu cầu xác thực hai yếu tố. Thiết lập ứng dụng xác thực bên dưới trước khi tiếp tục.',
'settings.mfa.backupTitle': 'Mã dự phòng',
'settings.mfa.backupDescription': 'Sử dụng các mã dự phòng một lần này nếu bạn mất quyền truy cập vào ứng dụng xác thực của mình.',
'settings.mfa.backupWarning': 'Hãy lưu lại những mã này ngay bây giờ. Mỗi mã chỉ có thể được sử dụng một lần.',
'settings.mfa.backupCopy': 'Sao chép mã',
'settings.mfa.backupDownload': 'Tải xuống TXT',
'settings.mfa.backupPrint': 'In / PDF',
'settings.mfa.backupCopied': 'Đã sao chép mã dự phòng',
'settings.mfa.enabled': '2FA được bật trên tài khoản của bạn.',
'settings.mfa.disabled': '2FA chưa được bật.',
'settings.mfa.setup': 'Thiết lập trình xác thực',
'settings.mfa.scanQr': 'Quét mã QR này bằng ứng dụng của bạn hoặc nhập bí mật theo cách thủ công.',
'settings.mfa.secretLabel': 'Khóa bí mật (nhập thủ công)',
'settings.mfa.codePlaceholder': 'mã 6 chữ số',
'settings.mfa.enable': 'Kích hoạt 2FA',
'settings.mfa.cancelSetup': 'Hủy',
'settings.mfa.disableTitle': 'Tắt 2FA',
'settings.mfa.disableHint': 'Nhập mật khẩu tài khoản của bạn và mã hiện tại từ trình xác thực của bạn.',
'settings.mfa.disable': 'Tắt 2FA',
'settings.mfa.toastEnabled': 'Đã bật xác thực hai yếu tố',
'settings.mfa.toastDisabled': 'Xác thực hai yếu tố bị vô hiệu hóa',
'settings.mfa.demoBlocked': 'Không có sẵn ở chế độ demo',
'settings.currency': 'Tiền tệ',
'settings.currencyHint': 'Tất cả số tiền trong Chi phí được chuyển đổi sang và hiển thị bằng loại tiền tệ này.',
'settings.passkey.title': 'Mật mã',
'settings.passkey.description':
'Đăng nhập nhanh hơn và chống lừa đảo bằng mật mã — vân tay, khuôn mặt, PIN hoặc khóa phần cứng của bạn. Mật khẩu của bạn vẫn là bản sao lưu.',
'settings.passkey.notConfigured':
'Mật mã đã được bật nhưng chưa được định cấu hình đầy đủ trên máy chủ này. Hãy yêu cầu quản trị viên của bạn đặt miền WebAuthn.',
'settings.passkey.add': 'Thêm mật mã',
'settings.passkey.addTitle': 'Thêm mật mã',
'settings.passkey.passwordPrompt': 'Xác nhận mật khẩu hiện tại của bạn, sau đó làm theo lời nhắc trên thiết bị của bạn.',
'settings.passkey.passwordRequired': 'Mật khẩu hiện tại của bạn là bắt buộc.',
'settings.passkey.namePlaceholder': 'Tên (tùy chọn, ví dụ: "iPhone")',
'settings.passkey.addedToast': 'Đã thêm mật mã',
'settings.passkey.added': 'Đã thêm',
'settings.passkey.addError': 'Không thể thêm mật mã',
'settings.passkey.cancelled': 'Đã hủy thiết lập mật khẩu',
'settings.passkey.deleted': 'Đã xóa mật khẩu',
'settings.passkey.deleteConfirm': 'Xóa mật mã này? Xác nhận bằng mật khẩu của bạn.',
'settings.passkey.rename': 'Đổi tên',
'settings.passkey.defaultName': 'Mật mã',
'settings.passkey.synced': 'Đã đồng bộ hóa',
'settings.passkey.deviceBound': 'Thiết bị này',
'settings.passkey.lastUsed': 'Lần sử dụng cuối cùng',
'settings.passkey.neverUsed': 'Chưa bao giờ sử dụng',
'settings.airtrail.title': 'AirTrail',
'settings.airtrail.hint':
'Kết nối AirTrail tự lưu trữ của bạn để nhập và đồng bộ hóa các chuyến bay. Tạo khóa API trong AirTrail trong Cài đặt → Bảo mật.',
'settings.airtrail.url': 'Ví dụ URL',
'settings.airtrail.apiKey': 'Phím API',
'settings.airtrail.apiKeyPlaceholder': 'Chìa khóa API mang',
'settings.airtrail.apiKeyHint': 'Được tạo trong AirTrail trong Cài đặt → Bảo mật. Được lưu trữ được mã hóa.',
'settings.airtrail.allowInsecureTls': 'Cho phép chứng chỉ tự ký',
'settings.airtrail.allowInsecureTlsHint': 'Chỉ kích hoạt cho một phiên bản đáng tin cậy trên mạng của riêng bạn.',
'settings.airtrail.writeBack': 'Viết các thay đổi trở lại AirTrail',
'settings.airtrail.writeBackHint':
'Tắt theo mặc định: AirTrail là nguồn sự thật và TREK chỉ đọc từ đó. Bật để đẩy các chỉnh sửa được thực hiện trong TREK trở lại AirTrail.',
'settings.airtrail.connected': 'Đã kết nối',
'settings.airtrail.notConnected': 'Không được kết nối',
'settings.airtrail.toast.saved': 'AirTrail đã lưu kết nối',
'settings.airtrail.toast.saveError': 'Không thể lưu kết nối',
'settings.airtrail.test.button': 'Kiểm tra kết nối',
'settings.airtrail.test.success': 'Đã kết nối — đã tìm thấy {count} chuyến bay',
'settings.airtrail.test.failed': 'Kết nối không thành công',
'settings.aiParsing.title': 'Phân tích bằng AI',
'settings.aiParsing.hint':
'Sử dụng mô hình AI của riêng bạn để trích xuất đặt chỗ từ các tệp đã tải lên. Tùy chọn này chỉ áp dụng khi quản trị viên chưa cấu hình mô hình cho toàn bộ phiên bản.',
'settings.aiParsing.provider': 'Nhà cung cấp',
'settings.aiParsing.providerLocal': 'Cục bộ (Ollama)',
'settings.aiParsing.providerOpenai': 'OpenAI',
'settings.aiParsing.providerAnthropic': 'Anthropic',
'settings.aiParsing.model': 'Mô hình',
'settings.aiParsing.baseUrl': 'URL cơ sở',
'settings.aiParsing.baseUrlHint': 'Nơi mô hình chạy — máy chủ Ollama cục bộ hoặc endpoint tương thích với OpenAI.',
'settings.aiParsing.apiKey': 'Khóa API',
'settings.aiParsing.apiKeyHint': 'Được lưu trữ mã hóa. Để trống để giữ khóa hiện tại.',
'settings.aiParsing.multimodal': 'Gửi tài liệu dưới dạng hình ảnh',
'settings.aiParsing.multimodalHint': 'Dành cho các mô hình hỗ trợ thị giác — gửi PDF gốc thay vì văn bản đã trích xuất.',
'settings.aiParsing.toast.saved': 'Đã lưu cài đặt AI',
'settings.aiParsing.toast.saveError': 'Không thể lưu cài đặt AI',
};
export default settings;
+16
View File
@@ -0,0 +1,16 @@
import type { TranslationStrings } from '../types';
const share: TranslationStrings = {
'share.linkTitle': 'Liên kết công khai',
'share.linkHint':
'Tạo một liên kết mà bất kỳ ai cũng có thể sử dụng để xem chuyến đi này mà không cần đăng nhập. Chỉ đọc — không thể chỉnh sửa.',
'share.createLink': 'Tạo liên kết',
'share.deleteLink': 'Xóa liên kết',
'share.createError': 'Không thể tạo liên kết',
'share.permMap': 'Bản đồ & Kế hoạch',
'share.permBookings': 'Đặt chỗ',
'share.permPacking': 'Đóng gói',
'share.permBudget': 'Ngân sách',
'share.permCollab': 'Trò chuyện',
};
export default share;
+21
View File
@@ -0,0 +1,21 @@
import type { TranslationStrings } from '../types';
const shared: TranslationStrings = {
'shared.expired': 'Liên kết đã hết hạn hoặc không hợp lệ',
'shared.expiredHint': 'Liên kết chuyến đi được chia sẻ này không còn hoạt động.',
'shared.readOnly': 'Chế độ xem chia sẻ chỉ đọc',
'shared.tabPlan': 'Kế hoạch',
'shared.tabBookings': 'Đặt chỗ',
'shared.tabPacking': 'Đóng gói',
'shared.tabBudget': 'Ngân sách',
'shared.tabChat': 'Trò chuyện',
'shared.days': 'ngày',
'shared.places': 'địa điểm',
'shared.other': 'Khác',
'shared.totalBudget': 'Tổng ngân sách',
'shared.messages': 'tin nhắn',
'shared.sharedVia': 'Được chia sẻ qua',
'shared.confirmed': 'Đã xác nhận',
'shared.pending': 'Chưa giải quyết',
};
export default shared;
+13
View File
@@ -0,0 +1,13 @@
import type { TranslationStrings } from '../types';
const stats: TranslationStrings = {
'stats.countries': 'Quốc gia',
'stats.cities': 'Thành phố',
'stats.trips': 'Chuyến đi',
'stats.places': 'Địa điểm',
'stats.worldProgress': 'Tiến bộ thế giới',
'stats.visited': 'đã đến thăm',
'stats.remaining': 'còn lại',
'stats.visitedCountries': 'Các nước đã ghé thăm',
};
export default stats;
+59
View File
@@ -0,0 +1,59 @@
import type { TranslationStrings } from '../types';
const system_notice: TranslationStrings = {
'system_notice.v3_photos.title': 'Ảnh đã chuyển sang 3.0',
'system_notice.v3_photos.body':
'**Ảnh** trong Công cụ lập kế hoạch chuyến đi đã bị xóa. Ảnh của bạn được an toàn — TREK chưa bao giờ sửa đổi thư viện Immich hoặc Synology của bạn.\n\nẢnh hiện có trong tiện ích bổ sung **Journey**. Hành trình là tùy chọn — nếu nó chưa có sẵn, hãy yêu cầu quản trị viên của bạn kích hoạt nó trong Quản trị → Tiện ích bổ sung.',
'system_notice.v3_journey.title': 'Hành Trình Gặp Gỡ - tạp chí du lịch',
'system_notice.v3_journey.body':
'Ghi lại chuyến đi của bạn dưới dạng những câu chuyện du lịch phong phú với dòng thời gian, thư viện ảnh và bản đồ tương tác.',
'system_notice.v3_journey.cta_label': 'Hành trình mở',
'system_notice.v3_journey.highlight_timeline': 'Dòng thời gian và thư viện hàng ngày',
'system_notice.v3_journey.highlight_photos': 'Nhập từ Immich hoặc Synology',
'system_notice.v3_journey.highlight_share': 'Chia sẻ công khai - không cần đăng nhập',
'system_notice.v3_journey.highlight_export': 'Xuất dưới dạng sách ảnh PDF',
'system_notice.v3_features.title': 'Nhiều điểm nổi bật hơn trong 3.0',
'system_notice.v3_features.body': 'Một vài điều đáng biết nữa về phiên bản này.',
'system_notice.v3_features.highlight_dashboard': 'Thiết kế lại bảng điều khiển ưu tiên thiết bị di động',
'system_notice.v3_features.highlight_offline': 'Chế độ ngoại tuyến hoàn toàn dưới dạng PWA',
'system_notice.v3_features.highlight_search': 'Tự động hoàn thành tìm kiếm địa điểm theo thời gian thực',
'system_notice.v3_features.highlight_import': 'Nhập địa điểm từ tệp KMZ/KML',
'system_notice.v3_mcp.title': 'MCP: OAuth nâng cấp 2.1',
'system_notice.v3_mcp.body':
'Tích hợp MCP đã được đại tu hoàn toàn. OAuth 2.1 hiện là phương pháp xác thực được đề xuất. Mã thông báo tĩnh cũ (trek_…) không được dùng nữa và sẽ bị xóa trong bản phát hành trong tương lai.',
'system_notice.v3_mcp.highlight_oauth': 'OAuth Khuyến nghị 2.1 (mcp-remote)',
'system_notice.v3_mcp.highlight_scopes': '24 phạm vi cấp phép chi tiết',
'system_notice.v3_mcp.highlight_deprecated': 'Mã thông báo trek_ tĩnh không được dùng nữa',
'system_notice.v3_mcp.highlight_tools': 'Bộ công cụ và lời nhắc mở rộng',
'system_notice.v3_thankyou.title': 'Một lưu ý cá nhân từ tôi',
'system_notice.v3_thankyou.body':
'Trước khi bạn đi - tôi muốn dành một chút thời gian.\n\nTREK bắt đầu như một dự án phụ mà tôi xây dựng cho những chuyến đi của riêng mình. Tôi chưa bao giờ tưởng tượng nó sẽ phát triển thành thứ mà 4.000 người trong số các bạn hiện đang tin tưởng để lên kế hoạch cho chuyến phiêu lưu của mình. Mọi ngôi sao, mọi số báo, mọi yêu cầu về tính năng - tôi đọc tất cả và chúng khiến tôi phải thức khuya giữa công việc toàn thời gian và trường đại học.\n\nTôi muốn bạn biết: TREK sẽ luôn là nguồn mở, luôn tự lưu trữ, luôn là của bạn. Không theo dõi, không đăng ký, không ràng buộc. Chỉ là một công cụ được xây dựng bởi một người cũng yêu thích du lịch như bạn.\n\nĐặc biệt cảm ơn [jubnl](https://github.com/jubnl) - bạn đã trở thành một cộng tác viên đáng kinh ngạc. Rất nhiều điều tạo nên sự tuyệt vời của 3.0 đều mang dấu ấn của bạn. Cảm ơn bạn đã tin tưởng vào dự án này khi nó vẫn còn nhiều khó khăn.\n\nVà gửi tới từng người trong số các bạn đã phát hiện lỗi, dịch một chuỗi, chia sẻ TREK với bạn bè hoặc đơn giản sử dụng nó để lên kế hoạch cho chuyến đi — **cảm ơn**. Bạn là lý do điều này tồn tại.\n\nĐây là nhiều cuộc phiêu lưu cùng nhau.\n\n— Maurice\n\n---\n\n[Tham gia cộng đồng trên Discord](https://discord.gg/7Q6M6jDwzf)\n\nNếu TREK giúp chuyến du lịch của bạn trở nên thú vị hơn thì một [cà phê nhỏ](https://ko-fi.com/mauriceboe) luôn luôn bật đèn.',
'system_notice.v3014_whitespace_collision.title': 'Hành động bắt buộc: xung đột tài khoản người dùng',
'system_notice.v3014_whitespace_collision.body':
'Bản nâng cấp 3.0.14 đã phát hiện một hoặc nhiều xung đột tên người dùng hoặc email do khoảng trắng ở đầu/cuối trong tài khoản được lưu trữ. Các tài khoản bị ảnh hưởng đã được đổi tên tự động. Kiểm tra nhật ký máy chủ để tìm các dòng bắt đầu bằng **[migration] WHITESPACE COLLISION** để xác định tài khoản nào cần xem xét.',
'system_notice.welcome_v1.title': 'Chào mừng đến với TREK',
'system_notice.welcome_v1.body':
'Công cụ lập kế hoạch du lịch tất cả trong một của bạn. Xây dựng hành trình, chia sẻ chuyến đi với bạn bè và luôn ngăn nắp — trực tuyến hoặc ngoại tuyến.',
'system_notice.welcome_v1.cta_label': 'Lên kế hoạch cho một chuyến đi',
'system_notice.welcome_v1.hero_alt': 'Một điểm đến du lịch tuyệt đẹp với lớp phủ TREK quy hoạch UI',
'system_notice.welcome_v1.highlight_plan': 'Lịch trình hàng ngày cho bất kỳ chuyến đi nào',
'system_notice.welcome_v1.highlight_share': 'Hợp tác với các đối tác du lịch',
'system_notice.welcome_v1.highlight_offline': 'Hoạt động ngoại tuyến trên thiết bị di động',
'system_notice.dev_test_modal.title': '[Dev] Thông báo kiểm tra',
'system_notice.dev_test_modal.body': 'Đây là thông báo kiểm tra chỉ dành cho nhà phát triển.',
// Thank-you + support the project (shown once per install and once per upgrade)
'system_notice.thank_you_support.title': 'Cảm ơn bạn đã sử dụng TREK',
'system_notice.thank_you_support.body':
'Xin gửi lời cảm ơn nhanh chóng đến bạn vì đã cài đặt TREK — nó thực sự có ý nghĩa rất lớn.\n\nTôi là nhà phát triển một mình và tôi xây dựng TREK trong thời gian rảnh rỗi. Nó bắt đầu như một công cụ nhỏ dành riêng cho những chuyến đi của tôi và tôi thực sự rất ngạc nhiên trước sự hỗ trợ và quan tâm từ cộng đồng kể từ đó. TREK được tạo ra bằng cả trái tim của tôi — nhưng cũng nhờ có nhiều cộng tác viên bên ngoài tuyệt vời đã giúp định hình nó.\n\n**TREK là mã nguồn mở và hoàn toàn miễn phí — và nó sẽ mãi mãi như vậy. Không có tầng trả phí, không đăng ký, không bắt được. Tôi hứa.**\n\nNếu TREK hữu ích cho bạn và bạn muốn hỗ trợ sự phát triển của nó, thì một tách cà phê nhỏ thực sự giúp tôi tiếp tục xây dựng — không có chút áp lực nào, nhưng mỗi tách cà phê sẽ giúp bạn tiếp tục những đêm khuya.\n\nCảm ơn bạn đã ở đây.\n\n— Maurice',
'system_notice.thank_you_support.highlight_opensource': 'Nguồn mở 100% trên GitHub',
'system_notice.thank_you_support.highlight_free': 'Miễn phí mãi mãi - không bao giờ có bất kỳ cấp độ trả phí nào',
'system_notice.thank_you_support.highlight_community': 'Được xây dựng cùng với cộng đồng',
'system_notice.thank_you_support.cta_bmc': 'Mua cho tôi một ly cà phê',
'system_notice.thank_you_support.cta_kofi': 'Hỗ trợ trên Ko-fi',
'system_notice.pager.prev': 'Thông báo trước',
'system_notice.pager.next': 'Thông báo tiếp theo',
'system_notice.pager.counter': '{current} / {total}',
'system_notice.pager.goto': 'Vào thông báo {n}',
'system_notice.pager.position': 'Thông báo {current} của {total}',
};
export default system_notice;
+40
View File
@@ -0,0 +1,40 @@
import type { TranslationStrings } from '../types';
const todo: TranslationStrings = {
'todo.subtab.packing': 'Danh sách đóng gói',
'todo.subtab.todo': 'Việc cần làm',
'todo.completed': 'hoàn thành',
'todo.filter.all': 'Tất cả',
'todo.filter.open': 'Mở',
'todo.filter.done': 'Xong',
'todo.uncategorized': 'Chưa được phân loại',
'todo.namePlaceholder': 'Tên nhiệm vụ',
'todo.descriptionPlaceholder': 'Mô tả (tùy chọn)',
'todo.unassigned': 'Chưa được chỉ định',
'todo.noCategory': 'Không có danh mục',
'todo.hasDescription': 'Có mô tả',
'todo.addItem': 'Thêm nhiệm vụ mới',
'todo.sidebar.sortBy': 'Sắp xếp theo',
'todo.priority': 'Sự ưu tiên',
'todo.newCategoryLabel': 'mới',
'todo.newCategory': 'Tên danh mục',
'todo.addCategory': 'Thêm danh mục',
'todo.newItem': 'Nhiệm vụ mới',
'todo.empty': 'Chưa có nhiệm vụ nào. Thêm một nhiệm vụ để bắt đầu!',
'todo.filter.my': 'Nhiệm vụ của tôi',
'todo.filter.overdue': 'Quá hạn',
'todo.sidebar.tasks': 'Nhiệm vụ',
'todo.sidebar.categories': 'Thể loại',
'todo.detail.title': 'Nhiệm vụ',
'todo.detail.description': 'Miêu tả',
'todo.detail.category': 'Loại',
'todo.detail.dueDate': 'Ngày đến hạn',
'todo.detail.assignedTo': 'Được giao cho',
'todo.detail.delete': 'Xóa bỏ',
'todo.detail.save': 'Lưu thay đổi',
'todo.sortByPrio': 'Sự ưu tiên',
'todo.detail.priority': 'Sự ưu tiên',
'todo.detail.noPriority': 'Không có',
'todo.detail.create': 'Tạo nhiệm vụ',
};
export default todo;
+10
View File
@@ -0,0 +1,10 @@
import type { TranslationStrings } from '../types';
const transport: TranslationStrings = {
'transport.addTransport': 'Thêm phương tiện di chuyển',
'transport.modalTitle.create': 'Thêm phương tiện di chuyển',
'transport.modalTitle.edit': 'Chỉnh sửa phương tiện đi lại',
'transport.title': 'Di chuyển',
'transport.addManual': 'Thêm di chuyển',
};
export default transport;
+31
View File
@@ -0,0 +1,31 @@
import type { TranslationStrings } from '../types';
const trip: TranslationStrings = {
'trip.tabs.plan': 'Kế hoạch',
'trip.tabs.transports': 'Di chuyển',
'trip.tabs.reservations': 'Đặt chỗ',
'trip.tabs.reservationsShort': 'Đặt',
'trip.tabs.packing': 'Danh sách đóng gói',
'trip.tabs.packingShort': 'Đóng gói',
'trip.tabs.lists': 'Danh sách',
'trip.tabs.listsShort': 'Danh sách',
'trip.tabs.budget': 'Chi phí',
'trip.tabs.files': 'Tập tin',
'trip.loading': 'Đang tải chuyến đi...',
'trip.loadingPhotos': 'Đang tải ảnh địa điểm...',
'trip.mobilePlan': 'Kế hoạch',
'trip.mobilePlaces': 'Địa điểm',
'trip.toast.placeUpdated': 'Đã cập nhật địa điểm',
'trip.toast.placeAdded': 'Đã thêm địa điểm',
'trip.toast.placeDeleted': 'Địa điểm đã bị xóa',
'trip.toast.selectDay': 'Vui lòng chọn một ngày trước',
'trip.toast.assignedToDay': 'Địa điểm đã được gán vào ngày',
'trip.toast.reorderError': 'Không thể sắp xếp lại',
'trip.toast.reservationUpdated': 'Đã cập nhật đặt chỗ',
'trip.toast.reservationAdded': 'Đã thêm đặt chỗ',
'trip.toast.deleted': 'Đã xóa',
'trip.confirm.deletePlace': 'Bạn có chắc chắn muốn xóa địa điểm này không?',
'trip.confirm.deletePlaces': 'Xóa {count} địa điểm?',
'trip.toast.placesDeleted': '{count} địa điểm đã bị xóa',
};
export default trip;
+16
View File
@@ -0,0 +1,16 @@
import type { TranslationStrings } from '../types';
const trips: TranslationStrings = {
'trips.memberRemoved': '{username} đã bị xóa',
'trips.memberRemoveError': 'Không thể xóa',
'trips.memberAdded': '{username} đã thêm',
'trips.memberAddError': 'Không thể thêm',
'trips.reminder': 'Lời nhắc nhở',
'trips.reminderNone': 'Không có',
'trips.reminderDay': 'ngày',
'trips.reminderDays': 'ngày',
'trips.reminderCustom': 'Tùy chọn',
'trips.reminderDaysBefore': 'ngày trước khi khởi hành',
'trips.reminderDisabledHint': 'Lời nhắc chuyến đi bị tắt. Kích hoạt chúng trong Quản trị > Cài đặt > Thông báo.',
};
export default trips;
+22
View File
@@ -0,0 +1,22 @@
import type { TranslationStrings } from '../types';
const undo: TranslationStrings = {
'undo.button': 'Hoàn tác',
'undo.tooltip': 'Hoàn tác: {action}',
'undo.assignPlace': 'Địa điểm đã được gán vào ngày',
'undo.removeAssignment': 'Địa điểm đã bị xóa khỏi ngày',
'undo.reorder': 'Địa điểm được sắp xếp lại',
'undo.optimize': 'Tuyến đường được tối ưu hóa',
'undo.deletePlace': 'Địa điểm đã bị xóa',
'undo.deletePlaces': 'Địa điểm đã bị xóa',
'undo.moveDay': 'Địa điểm đã chuyển sang ngày khác',
'undo.lock': 'Đã bật khóa địa điểm',
'undo.importGpx': 'GPX nhập khẩu',
'undo.importKeyholeMarkup': 'KMZ/KML nhập khẩu',
'undo.importGoogleList': 'Google Maps nhập khẩu',
'undo.importNaverList': 'Nhập bản đồ Naver',
'undo.importBooking': 'Nhập xác nhận đặt chỗ',
'undo.addPlace': 'Đã thêm địa điểm',
'undo.done': 'Hoàn tác: {action}',
};
export default undo;
+93
View File
@@ -0,0 +1,93 @@
import type { TranslationStrings } from '../types';
const vacay: TranslationStrings = {
'vacay.subtitle': 'Lập kế hoạch và quản lý ngày nghỉ',
'vacay.settings': 'Cài đặt',
'vacay.year': 'Năm',
'vacay.addYear': 'Thêm vào năm tới',
'vacay.addPrevYear': 'Thêm năm trước',
'vacay.removeYear': 'Xóa năm',
'vacay.removeYearConfirm': 'Xóa {year}?',
'vacay.removeYearHint': 'Tất cả các mục nghỉ lễ và ngày nghỉ lễ của công ty trong năm nay sẽ bị xóa vĩnh viễn.',
'vacay.remove': 'Di dời',
'vacay.persons': 'Người',
'vacay.noPersons': 'Không có người nào được thêm vào',
'vacay.addPerson': 'Thêm người',
'vacay.editPerson': 'Chỉnh sửa người',
'vacay.removePerson': 'Xóa người',
'vacay.removePersonConfirm': 'Xóa {name}?',
'vacay.removePersonHint': 'Tất cả các mục nhập kỳ nghỉ cho người này sẽ bị xóa vĩnh viễn.',
'vacay.personName': 'Tên',
'vacay.personNamePlaceholder': 'Nhập tên',
'vacay.color': 'Màu sắc',
'vacay.add': 'Thêm vào',
'vacay.legend': 'Huyền thoại',
'vacay.publicHoliday': 'Ngày nghỉ lễ',
'vacay.companyHoliday': 'Kỳ nghỉ của công ty',
'vacay.weekend': 'Ngày cuối tuần',
'vacay.modeVacation': 'Kì nghỉ',
'vacay.modeCompany': 'Kỳ nghỉ của công ty',
'vacay.entitlement': 'Quyền lợi',
'vacay.entitlementDays': 'Ngày',
'vacay.used': 'Đã dùng',
'vacay.remaining': 'Bên trái',
'vacay.carriedOver': 'từ {year}',
'vacay.blockWeekends': 'Các ngày cuối tuần',
'vacay.blockWeekendsHint': 'Ngăn chặn các mục nghỉ vào những ngày cuối tuần',
'vacay.weekendDays': 'Những ngày cuối tuần',
'vacay.mon': 'Thứ hai',
'vacay.tue': 'thứ ba',
'vacay.wed': 'Thứ tư',
'vacay.thu': 'Thứ năm',
'vacay.fri': 'Thứ Sáu',
'vacay.sat': 'Thứ bảy',
'vacay.sun': 'Chủ nhật',
'vacay.publicHolidays': 'Ngày lễ',
'vacay.publicHolidaysHint': 'Đánh dấu các ngày lễ trong lịch',
'vacay.selectCountry': 'Chọn quốc gia',
'vacay.selectRegion': 'Chọn khu vực (tùy chọn)',
'vacay.addCalendar': 'Thêm lịch',
'vacay.calendarLabel': 'Nhãn (tùy chọn)',
'vacay.calendarColor': 'Màu sắc',
'vacay.noCalendars': 'Chưa có lịch nghỉ lễ nào được thêm vào',
'vacay.companyHolidays': 'Ngày lễ của công ty',
'vacay.companyHolidaysHint': 'Cho phép đánh dấu ngày nghỉ lễ toàn công ty',
'vacay.companyHolidaysNoDeduct': 'Ngày nghỉ của công ty không được tính vào ngày nghỉ.',
'vacay.weekStart': 'Tuần bắt đầu vào',
'vacay.weekStartHint': 'Chọn xem tuần theo lịch bắt đầu vào Thứ Hai hay Chủ Nhật',
'vacay.carryOver': 'Chuyển tiếp',
'vacay.carryOverHint': 'Tự động chuyển số ngày nghỉ phép còn lại sang năm tiếp theo',
'vacay.sharing': 'Chia sẻ',
'vacay.sharingHint': 'Chia sẻ kế hoạch kỳ nghỉ của bạn với những người dùng TREK khác',
'vacay.owner': 'Người sở hữu',
'vacay.shareEmailPlaceholder': 'Email của người dùng TREK',
'vacay.shareSuccess': 'Đã chia sẻ kế hoạch thành công',
'vacay.shareError': 'Không thể chia sẻ kế hoạch',
'vacay.dissolve': 'Hòa tan phản ứng tổng hợp',
'vacay.dissolveHint': 'Tách lịch lại. Các mục của bạn sẽ được lưu giữ.',
'vacay.dissolveAction': 'Hòa tan',
'vacay.dissolved': 'Đã tách lịch',
'vacay.fusedWith': 'Hợp nhất với',
'vacay.you': 'Bạn',
'vacay.noData': 'Không có dữ liệu',
'vacay.changeColor': 'Thay đổi màu sắc',
'vacay.inviteUser': 'Mời người dùng',
'vacay.inviteHint': 'Mời người dùng TREK khác chia sẻ lịch nghỉ lễ tổng hợp.',
'vacay.selectUser': 'Chọn người dùng',
'vacay.sendInvite': 'Gửi lời mời',
'vacay.inviteSent': 'Đã gửi lời mời',
'vacay.inviteError': 'Không thể gửi lời mời',
'vacay.pending': 'chưa giải quyết',
'vacay.noUsersAvailable': 'Không có người dùng nào',
'vacay.accept': 'Chấp nhận',
'vacay.decline': 'Sự suy sụp',
'vacay.acceptFusion': 'Chấp nhận & Cầu chì',
'vacay.inviteTitle': 'Yêu cầu kết hợp',
'vacay.inviteWantsToFuse': 'muốn chia sẻ lịch nghỉ phép với bạn.',
'vacay.fuseInfo1': 'Cả hai bạn sẽ thấy tất cả các mục nhập kỳ nghỉ trong một lịch chung.',
'vacay.fuseInfo2': 'Cả hai bên có thể tạo và chỉnh sửa các mục cho nhau.',
'vacay.fuseInfo3': 'Cả hai bên đều có thể xóa các mục và thay đổi quyền lợi trong kỳ nghỉ.',
'vacay.fuseInfo4': 'Các cài đặt như ngày nghỉ lễ và ngày nghỉ của công ty đều được chia sẻ.',
'vacay.fuseInfo5': 'Sự hợp nhất có thể được giải thể bất cứ lúc nào bởi một trong hai bên. Các mục của bạn sẽ được bảo tồn.',
};
export default vacay;