Files
RecipesCam/docker/frontend/src/i18n/vi.ts
T

274 lines
12 KiB
TypeScript

// Vietnamese dictionary — the source of truth for key names (`en.ts` is typed
// as `Dict`, so a missing or misspelled key there is a typecheck error).
// Not translated anywhere, in any language: film-sim names, user recipe names,
// user watermark text — they are proper nouns, see WEB_PLAN.md.
export const vi = {
'lang.name': 'Tiếng Việt',
'nav.demo': 'DÙNG THỬ',
'nav.login': 'ĐĂNG NHẬP',
'nav.signup': 'ĐĂNG KÝ',
'nav.logout': 'Đăng xuất',
'nav.account': 'Tài khoản',
'nav.theme': 'Giao diện',
'nav.language': 'Ngôn ngữ',
'nav.back': 'Về trang chủ',
'nav.admin': 'Quản trị',
'nav.photos': 'Ảnh của tôi',
'nav.profile': 'Hồ sơ',
'nav.studio': 'Studio',
'nav.guest': 'Khách',
'act.undo': 'HOÀN TÁC',
'act.redo': 'LÀM LẠI',
'act.reset': 'ĐẶT LẠI',
'act.export': 'XUẤT ẢNH',
'act.exporting': 'Đang xuất…',
'act.cancel': 'Huỷ',
'drop.title': 'Kéo & thả ảnh vào đây',
'drop.hint': 'hoặc bấm để chọn ảnh · dán từ clipboard bằng Ctrl+V',
'drop.replace': 'Đổi ảnh khác',
'drop.peeking': 'ĐANG XEM ẢNH GỐC',
'drop.peekHint': 'Giữ chuột phải hoặc phím \\ để so ảnh gốc',
'drop.compare': 'So với ảnh gốc',
'drop.demoLimit': 'Bản demo: ảnh xuất ra tối đa {px}px và có watermark.',
// The histogram overlay. 'HISTOGRAM' is the word Vietnamese photographers use.
'hist.title': 'HISTOGRAM',
'hist.drag': 'Kéo để di chuyển',
'hist.hide': 'Ẩn histogram',
'tab.presets': 'PRESETS',
'tab.favorited': 'FAVORITED',
'tab.photos': 'ẢNH CỦA TÔI',
'tab.light': 'LIGHT',
'tab.wb': 'WB',
'tab.fx': 'FX',
'tab.hsl': 'HSL',
'hsl.hint': 'BẤM PICK RỒI CHỌN MỘT MÀU TRÊN ẢNH',
'tab.frame': 'FRAME',
'tab.save': 'LƯU GẦN ĐÂY',
'tab.create': 'CREATE RECIPES',
'create.title': 'TẠO CÔNG THỨC',
'create.save': 'LƯU CÔNG THỨC',
'create.export': 'XUẤT TỆP .RECIPE',
'create.guestHint':
'Khách: công thức chỉ nằm trong RECIPES tới khi đóng trang. Đăng nhập để lưu vào tài khoản và xuất tệp.',
'create.userHint':
'Đã lưu vào tài khoản. Xuất tệp .recipe để chia sẻ — tệp được mã hóa đúng như trên app.',
'sec.filmSims': 'PHOTO STYLE',
'sec.recipes': 'RECIPES',
'sec.saved': 'ĐÃ LƯU',
'sec.savedEmpty': 'Chưa lưu công thức nào. Đăng nhập rồi bấm LƯU để đồng bộ.',
'sec.frame': 'KHUNG',
'sec.crop': 'CẮT',
'sec.rotate': 'XOAY',
'sec.watermark': 'WATERMARK',
'sec.gps': 'GPS',
'wb.temp': 'COLOR TEMP',
'frame.none': 'KHÔNG KHUNG',
'frame.polaroid': 'RETRO INSTANT',
'frame.classic': 'VIỀN CLASSIC',
'frame.cinematic': 'ĐIỆN ẢNH',
'frame.wall': 'WALL FRAME PORTRAIT',
'frame.wallLand': 'WALL FRAME LANDSCAPE',
'crop.none': 'KHÔNG CẮT',
'crop.1:1': '1:1',
'crop.2:3': '2:3',
'crop.3:2': '3:2',
'crop.3:4': '3:4',
'crop.4:3': '4:3',
'crop.16:9': '16:9',
'crop.free': 'TỰ DO',
'crop.apply': 'ÁP DỤNG',
'crop.cancel': 'HUỶ',
'rot.0': '0°',
'rot.90': '90°',
'rot.180': '180°',
'rot.270': '270°',
'wm.text': 'CHỮ',
'wm.color': 'MÀU',
'wm.size': 'CỠ',
'wm.gps': 'DẤU GPS',
'wm.place': 'TÊN ĐỊA ĐIỂM',
'wm.placePh': 'VD: HÀ NỘI',
'wm.manual': 'NHẬP TOẠ ĐỘ',
'wm.lat': 'Vĩ độ',
'wm.lng': 'Kinh độ',
'wm.hasExif': 'Đã đọc GPS từ ảnh.',
'wm.noExif': 'Ảnh không có GPS — nhập tay nếu muốn đóng dấu.',
'auth.loginTitle': 'Đăng nhập',
'auth.signupTitle': 'Tạo tài khoản',
'auth.email': 'Email',
'auth.password': 'Mật khẩu',
'auth.passwordHint': 'Ít nhất 8 ký tự',
'auth.noAccount': 'Chưa có tài khoản? Đăng ký',
'auth.haveAccount': 'Đã có tài khoản? Đăng nhập',
'auth.continueDemo': 'Tiếp tục dùng thử',
'auth.busy': 'Đang xử lý…',
'auth.loggedInAs': 'Đã đăng nhập: {email}',
'save.title': 'Lưu công thức',
'save.name': 'Tên công thức',
'save.recent': 'LƯU THAY ĐỔI VÀO RECIPES',
'save.recentHint': 'Lưu look đang đứng trên màn hình — sim, WB, light, FX và frame — thành một recipe riêng của tài khoản này.',
'save.recentEmpty': 'Chưa có recipe nào của riêng bạn.',
'save.delete': 'Xoá recipe này',
'name.photoTitle': 'ĐẶT TÊN ẢNH',
'name.photoLabel': 'Tên lưu trong thư mục ảnh, và là tiêu đề trên khung ảnh ở landing page.',
'name.recipeTitle': 'LƯU VÀO RECIPES',
'name.recipeLabel': 'Tên cho look này, chỉ trong tài khoản của bạn.',
'name.required': 'Đặt tên trước đã.',
'name.duplicate': 'Bạn đã có một recipe mang tên này.',
'name.save': 'LƯU',
'name.cancel': 'HUỶ',
'save.saved': 'Đã lưu "{name}"',
'save.needLogin': 'Đăng nhập để lưu công thức.',
'save.photo': 'LƯU ẢNH {n}/{max}',
'save.photoNeedLogin': 'Đăng nhập để lưu ảnh.',
'save.photoSaved': 'Đã lưu ảnh {n}/{max}.',
'save.photoFull': 'Đã đủ {max} ảnh — xoá bớt trong Ảnh của tôi.',
'save.photoNoSource': 'Chưa có ảnh nào để lưu.',
'save.photoFailed': 'Không lưu được ảnh: {msg}',
'myp.empty': 'CHƯA LƯU ẢNH NÀO.',
'myp.history': 'LỊCH SỬ',
'myp.historyEmpty': 'CHƯA CÓ MỐC LƯU NÀO TRƯỚC ĐÓ.',
'myp.consent': 'Cho phép ảnh này lên landing page',
'myp.remove': 'XOÁ ẢNH',
'del.title': 'XOÁ ẢNH NÀY',
'del.warning': 'Xoá ảnh này sẽ xoá tất cả history đã lưu trước đó ({n} look) và không khôi phục được. Cần tải ảnh về trước khi xoá.',
'del.download': 'TẢI VỀ TRƯỚC',
'del.confirm': 'XOÁ ẢNH',
'del.cancel': 'HUỶ',
'photo.uploading': 'ĐANG TẢI…',
'photos.title': 'Ảnh của tôi',
'photos.hint': 'Mỗi tài khoản giữ tối đa {max} ảnh. Ảnh lưu từ studio nằm ở đây và xuất hiện trên dải phim cộng đồng.',
'photos.count': '{n}/{max} ảnh',
'photos.add': 'THÊM ẢNH',
'photos.empty': 'Chưa có ảnh nào. Mở studio rồi bấm LƯU ẢNH, hoặc thêm ảnh ngay ở đây.',
'photos.full': 'Đã đủ {max} ảnh. Xoá bớt trước khi lưu tiếp.',
'photos.delete': 'XOÁ',
'photos.deleted': 'Đã xoá ảnh.',
'photos.failed': 'Không thực hiện được: {msg}',
'photos.noLabels': 'Chưa có nhãn dải phim',
'adm.title': 'Quản trị dải phim',
'adm.subtitle': 'Ảnh do người dùng đóng góp. Xoá một ảnh để gỡ nó khỏi trang chủ.',
'adm.upload': 'THÊM ẢNH',
'adm.uploads': 'Ảnh đã tải lên',
'adm.sections': 'Mục trên landing',
'adm.albumAll': 'Tất cả ảnh',
'adm.filterName': 'Lọc theo tên người dùng',
'adm.sort': 'Sắp xếp',
'adm.sortNewest': 'Mới nhất trước',
'adm.sortRecipe': 'Công thức A→Z',
'adm.sortRating': 'Xếp hạng cao nhất',
'adm.rating': 'Xếp hạng',
'adm.ratingAll': 'Mọi mức xếp hạng',
'adm.ratingAtLeast': 'Từ {n} sao',
'adm.recipe': 'Công thức',
'adm.bigEmpty': 'Chọn một ảnh để xem.',
'adm.pickStrip': 'Dải phim',
'adm.pickTester': 'Live preset tester',
'adm.pickCreator': 'Custom recipe creator',
'adm.pickQr': 'Thẻ QR',
'adm.noPreset': 'không có look để chia sẻ',
'adm.rowEmpty': 'Chưa có gì ở đây.',
'adm.slotHint': 'Tích vào những mục ảnh sẽ xuất hiện — một ảnh có thể nằm cùng lúc ở nhiều mục, và mỗi mục bốc ngẫu nhiên một ảnh trong nhóm của nó mỗi lần ghé. Bỏ tích hết sẽ gỡ ảnh khỏi landing mà không xoá — chủ ảnh vẫn giữ nó trong MY PHOTOS. Mục QR là mục duy nhất phát công thức: thẻ của nó vẽ một mã tải chính tệp .recipe của ảnh để app trên điện thoại quét vào.',
'adm.signIn': 'Đăng nhập bằng tài khoản quản trị',
'adm.notAdmin': 'Tài khoản này không có quyền quản trị.',
'adm.empty': 'Chưa có ảnh đóng góp nào.',
'adm.total': '{n} ảnh',
'adm.owner': 'Người đăng',
'adm.size': 'Dung lượng',
'adm.uploaded': 'Thời điểm',
'adm.delete': 'XOÁ',
'adm.clearAll': 'XOÁ TẤT CẢ',
'adm.clearConfirm': 'Xoá toàn bộ {n} ảnh đóng góp? Không hoàn tác được.',
'adm.removed': 'Đã xoá {n} ảnh.',
'adm.back': 'Về trang chủ',
'adm.settings': 'CÀI ĐẶT',
'adm.tabPictures': 'Ảnh',
'adm.tabUsers': 'Người dùng',
'adm.tabProfile': 'Hồ sơ',
'adm.close': 'Đóng',
'adm.userPicture': 'Ảnh',
'adm.userName': 'Tên',
'adm.userEmail': 'Email',
'adm.userRole': 'Quyền',
'adm.userPhotos': 'Số ảnh',
'adm.userJoined': 'Ngày tạo',
'adm.roleAdmin': 'Quản trị',
'adm.roleMember': 'Thành viên',
'adm.viewPhotos': 'XEM ẢNH',
'adm.noUsers': 'Chưa có tài khoản nào.',
'adm.profileHint': 'Ảnh đại diện, email và mật khẩu của tài khoản đang đăng nhập. Đổi email hoặc mật khẩu cần mật khẩu hiện tại.',
'adm.changeAvatar': 'ĐỔI ẢNH ĐẠI DIỆN',
'adm.currentPassword': 'Mật khẩu hiện tại',
'adm.newEmail': 'Email mới',
'adm.newPassword': 'Mật khẩu mới',
'adm.save': 'LƯU',
'adm.saved': 'Đã lưu hồ sơ.',
'adm.userActions': 'Thao tác',
'adm.userBlock': 'KHOÁ',
'adm.userUnblock': 'MỞ KHOÁ',
'adm.userRemove': 'GỠ',
'adm.userRestore': 'KHÔI PHỤC',
'adm.userDelete': 'XOÁ HẲN',
'adm.userBlocked': 'Đã khoá',
'adm.userRemoved': 'Đã gỡ',
'adm.userDeleteConfirm': 'Xoá vĩnh viễn tài khoản {email} cùng toàn bộ ảnh và công thức của nó? Không hoàn tác được.',
'adm.selectAll': 'CHỌN TẤT CẢ',
'adm.selectNone': 'BỎ CHỌN',
'adm.deleteSelected': 'XOÁ ĐÃ CHỌN ({n})',
'adm.userDeleteSelectedConfirm': 'Xoá vĩnh viễn {n} tài khoản đã chọn cùng toàn bộ ảnh và công thức của chúng? Không hoàn tác được.',
'adm.tabStats': 'THỐNG KÊ',
// The traffic screen. Bucket names ('/app', a control's data-key, a browser
// version) are machine values and stay as they are.
'stats.days': '{n} NGÀY',
'stats.hint': 'Lưu lượng trong khoảng đã chọn.',
'stats.views': 'LƯỢT XEM',
'stats.clicks': 'LƯỢT NHẤN',
'stats.visitors': 'KHÁCH TRUY CẬP',
'stats.timeline': 'LƯU LƯỢNG THEO NGÀY',
'stats.peak': 'đỉnh',
'stats.pages': 'TRANG ĐƯỢC XEM',
'stats.targets': 'TÍNH NĂNG ĐƯỢC NHẤN',
'stats.countries': 'QUỐC GIA',
'stats.regions': 'VÙNG MIỀN',
'stats.cities': 'THÀNH PHỐ',
'stats.browsers': 'TRÌNH DUYỆT',
'stats.systems': 'HỆ ĐIỀU HÀNH',
'stats.devices': 'THIẾT BỊ',
'stats.empty': 'Chưa có dữ liệu.',
'profile.title': 'Hồ sơ của tôi',
'err.noWebgl':
'Trình duyệt không cấp được WebGL — bản dựng này cần WebGL để xử lý ảnh (chạy CPU chậm gấp hàng nghìn lần).',
'err.decode': 'Không đọc được ảnh này. Thử JPG hoặc PNG khác.',
'err.generic': 'Có lỗi xảy ra: {msg}',
'err.offline': 'Không gọi được máy chủ.',
'meta.exported': 'Đã tải {name} ({kb}KB, 300 ppi)',
} as const;
// `vi` is `as const` so the key set is exact; `Dict` widens the values to
// string, which is what lets `en.ts` hold different text under the same keys
// while a missing or misspelled key stays a typecheck error.
export type Dict = { [K in keyof typeof vi]: string };
export type MsgKey = keyof Dict;