diff --git a/docs/I18N.md b/docs/I18N.md index dc8789e0..e238c7dd 100644 --- a/docs/I18N.md +++ b/docs/I18N.md @@ -1,6 +1,6 @@ # Translations -Liner ships in 11 languages: en, ru, uk, es, de, it, fr, pl, tr, pt, id. English is the +Liner ships in 12 languages: en, ru, uk, es, de, it, fr, pl, tr, pt, id, vi. English is the source and the fallback for every other language. ## How it works @@ -41,7 +41,7 @@ When `count` is a number, the translator first looks for a plural form chosen by | en, de, tr | `_one`, `_other` | | es, it, fr, pt | `_one`, `_other`, and `_many` (used for round millions) | | ru, uk, pl | `_one`, `_few`, `_many`, `_other` | -| id | `_other` | +| id, vi | `_other` | A missing form does not fall back to `_other`: it goes to `_plural` and then the plain key. Provide every form in the table, or add a `_plural` as a catch-all. diff --git a/src/languages/data.ts b/src/languages/data.ts index 44c06817..8b854d3e 100644 --- a/src/languages/data.ts +++ b/src/languages/data.ts @@ -9,6 +9,7 @@ import pl from "./locales/pl.json"; import tr from "./locales/tr.json"; import pt from "./locales/pt.json"; import id from "./locales/id.json"; +import vi from "./locales/vi.json"; import type { Locale } from "./locale"; export const translations: Record> = { @@ -23,4 +24,5 @@ export const translations: Record> = { tr, pt, id, + vi, }; diff --git a/src/languages/locale.test.ts b/src/languages/locale.test.ts index 2c53df73..a8724011 100644 --- a/src/languages/locale.test.ts +++ b/src/languages/locale.test.ts @@ -75,6 +75,7 @@ describe("getBrowserLocale", () => { ["pt-BR", "pt"], ["pt-PT", "pt"], ["en-GB", "en"], + ["vi-VN", "vi"], ])( "returns the matching locale when navigator.language is %s", (language, expected) => { diff --git a/src/languages/locale.ts b/src/languages/locale.ts index 3266d891..a4a019eb 100644 --- a/src/languages/locale.ts +++ b/src/languages/locale.ts @@ -10,6 +10,7 @@ export const SUPPORTED_LOCALES = [ "tr", "pt", "id", + "vi", ] as const; export type Locale = (typeof SUPPORTED_LOCALES)[number]; diff --git a/src/languages/locales/vi.json b/src/languages/locales/vi.json new file mode 100644 index 00000000..952e33e5 --- /dev/null +++ b/src/languages/locales/vi.json @@ -0,0 +1,1126 @@ +{ + "artist": { + "no_biography": "Chưa có tiểu sử", + "followers": "người theo dõi", + "total_listens": "tổng số lượt nghe", + "tracks": "bài hát", + "popular_songs": "Bài hát phổ biến", + "albums": "Album", + "singles": "Đĩa đơn", + "reposts": "Bài đăng lại", + "play": "Phát", + "remove_from_library": "Xóa khỏi thư viện", + "save_to_library": "Lưu vào thư viện", + "add_to_queue": "Thêm vào danh sách chờ phát", + "share": "Chia sẻ", + "no_popular_songs": "Không có bài hát phổ biến nào.", + "no_singles_available": "Không có đĩa đơn nào.", + "artist_not_found": "Không tìm thấy nghệ sĩ", + "added_to_queue": "Đã thêm bài hát của nghệ sĩ vào danh sách chờ phát", + "monthly_audience": "{count} người nghe hằng tháng", + "listeners": "{count} người nghe", + "show_all": "Xem tất cả", + "show_less": "Thu gọn", + "about_artist": "Giới thiệu", + "aka": "Tên gọi khác", + "genius_profile": "Hồ sơ Genius" + }, + "collection": { + "unknown_album": "Không rõ album", + "unknown_artist": "Không rõ nghệ sĩ", + "unknown_playlist": "Không rõ danh sách phát", + "unknown_owner": "Không rõ chủ sở hữu", + "added_to_queue": "Đã thêm vào danh sách chờ phát", + "not_found": "Không tìm thấy", + "playlist": "Danh sách phát", + "album": "Album", + "ep": "EP", + "single": "Đĩa đơn", + "tracks_count": "bài hát", + "hr": "giờ", + "min": "phút", + "sec": "giây" + }, + "common": { + "app": { + "name": "Liner", + "description": "Thêm nhạc hợp gu bạn", + "version": "Phiên bản 0.1.0" + }, + "sidebar": { + "home": "Trang chủ", + "search": "Tìm kiếm", + "library": "Thư viện", + "settings": "Cài đặt" + }, + "minimize": "Thu nhỏ", + "exitFullscreen": "Thoát toàn màn hình", + "restore": "Khôi phục", + "maximize": "Phóng to", + "loading": "Đang tải", + "signed_in": "Đã đăng nhập", + "signed_out": "Đã đăng xuất", + "sign_out": "Đăng xuất", + "on": "Bật", + "off": "Tắt", + "added_to_queue": "Đã thêm vào danh sách chờ phát", + "account": "Tài khoản", + "coming_soon": "Sắp ra mắt", + "play_all": "Phát tất cả", + "add_to_queue": "Thêm vào danh sách chờ phát", + "remove_from_queue": "Xóa khỏi danh sách chờ phát", + "removed_from_queue": "Đã xóa khỏi danh sách chờ phát", + "undo": "Hoàn tác", + "shuffle": "Phát ngẫu nhiên", + "remove_from_library": "Xóa khỏi thư viện", + "save_to_library": "Lưu vào thư viện", + "share": "Chia sẻ", + "back": "Quay lại", + "link_copied": "Đã sao chép liên kết", + "download": "Tải xuống", + "more": "Xem thêm", + "rename": "Đổi tên", + "edit_description": "Chỉnh sửa mô tả", + "add_description": "Thêm mô tả", + "import_sources_hint": "Dán liên kết từ YouTube, SoundCloud, Spotify, Deezer hoặc Apple Music", + "make_public": "Công khai", + "delete": "Xóa", + "create": "Tạo", + "import": "Nhập", + "add": "Thêm", + "remove": "Xóa", + "cancel": "Hủy", + "confirm": "Xác nhận", + "are_you_sure": "Bạn có chắc không?", + "delete_playlist_desc": "Danh sách phát này sẽ bị xóa vĩnh viễn.", + "add_to_library_desc": "Mục này sẽ được thêm vào thư viện của bạn.", + "remove_from_library_desc": "Mục này sẽ bị xóa khỏi thư viện của bạn.", + "remove_track_from_playlist_desc": "Bài hát này sẽ bị xóa khỏi danh sách phát này.", + "close": "Đóng", + "search": "Tìm kiếm", + "from_scratch": "Tạo mới", + "create_empty_playlist": "Tạo danh sách phát trống", + "playlist_name": "Tên danh sách phát", + "import_playlist": "Nhập danh sách phát", + "import_playlist_description": "Nhập danh sách phát từ Spotify hoặc YouTube", + "paste_link_placeholder": "Dán một liên kết…", + "magic_link": "Liên kết thông minh", + "magic_link_description": "Dán liên kết bài hát, album, danh sách phát hoặc nghệ sĩ từ dịch vụ nghe nhạc. Liner sẽ tự động mở hoặc thêm nội dung cho bạn.", + "streaming_link_placeholder": "https://soundcloud.com/whi...", + "streaming_link": "Liên kết phát trực tuyến", + "import_soundcloud_likes": "Nhập bài hát đã thích trên SoundCloud", + "import_soundcloud_description": "Nhập tên người dùng SoundCloud để thêm các bài hát bạn đã thích", + "soundcloud_username_placeholder": "Tên người dùng SoundCloud", + "import_likes": "Nhập bài hát đã thích", + "add_to_library": "Thêm vào thư viện", + "adding": "Đang thêm...", + "removing": "Đang xóa...", + "importing": "Đang nhập...", + "more_options": "Tùy chọn khác", + "reposted_by": "{name} đã đăng lại", + "and": " và ", + "no_results": "Không tìm thấy kết quả nào", + "try_another_search": "Hãy thử cụm từ tìm kiếm khác.", + "recent_searches": "Tìm kiếm gần đây", + "clear_recent": "Xóa", + "all": "Tất cả", + "songs": "Bài hát", + "artists": "Nghệ sĩ", + "albums": "Album", + "playlists": "Danh sách phát", + "tracks": "bài hát", + "track": "bài hát", + "followers": "{count} người theo dõi", + "select_playlist": "Chọn danh sách phát để xóa bài hát:", + "track_not_in_playlist": "Bài hát này không có trong bất kỳ danh sách phát nào của bạn.", + "track_not_found": "Không tìm thấy bài hát trong danh sách phát", + "name_required": "Vui lòng nhập tên", + "paste_link_first": "Vui lòng dán liên kết trước", + "added_to_library": "Đã thêm {type} vào thư viện", + "added_to_library_success": "Đã thêm vào thư viện", + "failed_to_add_library": "Không thêm được vào thư viện", + "removed_from_library": "Đã xóa {type} khỏi thư viện", + "removed_from_library_success": "Đã xóa khỏi thư viện", + "failed_remove_from_library": "Không xóa được khỏi thư viện", + "failed_to_remove_library": "Không xóa được khỏi thư viện", + "failed_to_load_track": "Không tải được bài hát", + "failed_to_resolve_link": "Không xử lý được liên kết", + "unsupported_link": "Liên kết không hợp lệ hoặc chưa được hỗ trợ", + "failed_to_get_playlist": "Không lấy được thông tin danh sách phát", + "track_already_in_playlist": "Bài hát đã có trong danh sách phát này", + "added_to_playlist": "Đã thêm vào danh sách phát", + "removed_from_playlist": "Đã xóa khỏi danh sách phát", + "failed_to_remove_track": "Không xóa được bài hát", + "importing_progress": "Đang nhập {name}: {done} / {total} bài hát", + "playlist_imported": "Đã nhập {name} ({count} bài hát)", + "importing_likes": "Đang nhập bài hát đã thích: {done} / {total} bài hát", + "imported_likes": "Đã nhập {count} bài hát đã thích", + "username_required": "Vui lòng nhập tên người dùng SoundCloud", + "import_failed_check": "Không nhập được bài hát đã thích. Hãy kiểm tra tên người dùng rồi thử lại.", + "failed_import_playlist": "Không nhập được danh sách phát", + "already_in_library": "{type} đã có trong thư viện của bạn", + "failed_get_track": "Không tải được bài hát", + "playlist_created": "Đã tạo danh sách phát", + "failed_create_playlist": "Không tạo được danh sách phát", + "imported_playlist": "Danh sách phát đã nhập", + "liked_songs": "Bài hát đã thích", + "start_radio": "Bắt đầu Radio", + "play_next": "Phát tiếp theo", + "like": "Thích", + "unlike": "Bỏ thích", + "add_to_playlist": "Thêm vào danh sách phát", + "remove_from_playlist": "Xóa khỏi danh sách phát", + "no_items": "Chưa có mục nào", + "your_library_here": "Nội dung bạn thêm sẽ xuất hiện trong thư viện.", + "try_another_search_clear": "Thử từ khóa khác hoặc xóa nội dung tìm kiếm.", + "youtube_thumbnail": "Ảnh thu nhỏ YouTube", + "no_playlists_yet": "Chưa có danh sách phát nào", + "failed_add_playlist": "Không thêm được vào danh sách phát", + "failed_add_track": "Không thêm được bài hát", + "description_placeholder": "Mô tả (tùy chọn)", + "supported_sources": "Các nguồn được hỗ trợ", + "error_network": "Không có kết nối. Hãy kiểm tra Internet của bạn và thử lại.", + "error_network_title": "Lỗi mạng", + "error_server": "Đã xảy ra lỗi ở phía chúng tôi. Hãy thử lại sau.", + "error_server_title": "Lỗi máy chủ", + "error_timeout_title": "Máy chủ hết thời gian chờ", + "error_not_found": "Không tìm thấy. Có thể nó đã bị xóa.", + "error_session_expired": "Phiên đã hết hạn. Vui lòng đăng nhập lại.", + "error_too_many": "Quá nhiều yêu cầu. Đợi một chút và thử lại.", + "error_something_wrong": "Đã xảy ra lỗi. Hãy thử lại.", + "tracks_plural": "{count} bài hát", + "songs_plural": "{count} bài hát", + "env_warning": "Hãy chạy ứng dụng trong Electron để dùng liên kết mở ứng dụng, kiểm tra kết nối và chia sẻ qua giao diện kết nối với máy tính.", + "env_skip": "Bỏ qua" + }, + "home": { + "speedDial": "Truy cập nhanh", + "goodMorning": "Chào buổi sáng", + "goodAfternoon": "Chào buổi chiều", + "goodEvening": "Chào buổi tối", + "goodNight": "Chào buổi đêm", + "trendingBadge": "Đang thịnh hành", + "allTimeBadge": "Nổi bật nhất", + "whatEveryonesOn": "Mọi người đang nghe", + "mostListened": "Được nghe nhiều nhất", + "jumpBackIn": "Nghe tiếp", + "popularAlbums": "Album hàng đầu", + "mostSaved": "Được lưu nhiều nhất", + "popularArtists": "Nghệ sĩ thịnh hành", + "popularPlaylists": "Danh sách phát phổ biến", + "dailyMixes": "Tuyển tập dành cho bạn", + "dailyMixesSubtitle": "Danh sách phát mới dựa trên nghệ sĩ và thể loại bạn yêu thích" + }, + "library": { + "title": "Thư viện", + "liked_songs": "Bài hát đã thích", + "song": "bài hát", + "songs": "bài hát", + "track": "bài hát", + "tracks": "bài hát", + "tab_all": "Tất cả", + "tab_playlists": "Danh sách phát", + "tab_albums": "Album", + "tab_artists": "Nghệ sĩ", + "search_all": "Tìm trong thư viện", + "search_playlists": "Tìm kiếm danh sách phát", + "search_albums": "Tìm kiếm album", + "search_artists": "Tìm kiếm nghệ sĩ", + "sort_by": "Sắp xếp theo", + "sort_recent": "Mới thêm gần đây", + "sort_title": "Theo bảng chữ cái (A-Z)", + "sort_creator": "Theo người tạo / nghệ sĩ", + "view_grid": "Lưới", + "view_list": "Danh sách", + "find_music": "Tìm kiếm", + "create_playlist": "Tạo danh sách phát", + "no_playlists_title": "Chưa có danh sách phát nào", + "no_playlists_desc": "Tạo danh sách phát đầu tiên hoặc nhập nhạc từ dịch vụ khác", + "no_albums_title": "Chưa lưu album nào", + "no_albums_desc": "Lưu album từ kết quả tìm kiếm hoặc đề xuất để dễ tìm lại", + "no_artists_title": "Chưa lưu nghệ sĩ nào", + "no_artists_desc": "Lưu nghệ sĩ để dễ tìm các album và bài hát của họ", + "search_music": "Tìm kiếm nhạc", + "local": { + "title": "Tệp trên máy", + "subtitle": "Các tệp âm thanh của bạn chỉ nằm trên máy tính này và không bao giờ được gửi đến máy chủ YouTube hoặc Liner.", + "add_files": "Thêm tệp", + "importing": "Đang thêm…", + "empty_title": "Chưa có tệp nhạc trên máy", + "empty_subtitle": "Thêm tệp MP3, FLAC, M4A, OGG, OPUS hoặc WAV, hoặc kéo thả tệp vào cửa sổ.", + "drop_title": "Thả để thêm vào Liner", + "drop_subtitle": "Tệp chỉ được sao chép vào thiết bị này", + "drop_count_one": "{count} tệp", + "drop_count_other": "{count} tệp", + "imported_one": "Đã thêm {count} bài hát", + "imported_other": "Đã thêm {count} bài hát", + "skipped_duplicates_one": "{count} tệp đã có sẵn", + "skipped_duplicates_other": "{count} tệp đã có sẵn", + "already_added": "Các tệp này đã được thêm", + "import_failed_one": "Không thêm được {count} tệp", + "import_failed_other": "Không thêm được {count} tệp", + "unsupported": "Các tệp này không thuộc định dạng âm thanh được hỗ trợ", + "remove": "Xóa khỏi thiết bị" + } + }, + "login": { + "welcome_back": "Chào mừng trở lại", + "sign_in_to_account": "Đăng nhập vào tài khoản của bạn", + "auth_title_login": "Âm nhạc của bạn, theo cách của bạn", + "auth_subtitle_login": "Đăng nhập để tiếp tục nghe nhạc.", + "auth_title_register": "Tham gia Liner", + "auth_subtitle_register": "Tạo tài khoản và bắt đầu xây dựng thư viện nhạc của bạn.", + "profile_setup_title": "Thiết lập hồ sơ của bạn", + "profile_setup_subtitle": "Chọn tên người dùng duy nhất và tên hiển thị.", + "btn_continue": "Tiếp tục", + "btn_back": "Quay lại", + "username_hint": "3-30 ký tự viết thường, số hoặc dấu gạch dưới.", + "label_email": "Email", + "label_username": "Tên người dùng (@tên)", + "placeholder_username": "soundwave", + "label_display_name": "Tên hiển thị", + "placeholder_display_name": "Tên hoặc bí danh của bạn", + "label_password": "Mật khẩu", + "label_confirm_password": "Xác nhận mật khẩu", + "placeholder_email": "you@example.com", + "placeholder_password": "Mật khẩu của bạn", + "placeholder_password_new": "Ít nhất 8 ký tự", + "placeholder_confirm": "Nhập lại mật khẩu", + "btn_sign_in": "Đăng nhập", + "btn_signing_in": "Đang đăng nhập…", + "btn_create_account": "Tạo tài khoản", + "btn_creating_account": "Đang tạo tài khoản…", + "separator_or": "hoặc", + "have_account": "Bạn đã có tài khoản?", + "have_account_action": "Đăng nhập", + "legal": "Bằng cách tiếp tục, bạn đồng ý với", + "legal_tos": "Điều khoản dịch vụ", + "legal_and": "và", + "legal_pp": "Chính sách quyền riêng tư", + "sign_in_google": "Đăng nhập vào tài khoản của bạn", + "sign_in_telegram": "Đăng nhập bằng Telegram", + "or": "hoặc", + "handle_placeholder": "Tên người dùng", + "password_placeholder": "Mật khẩu", + "password_min_placeholder": "Mật khẩu (tối thiểu 6 ký tự)", + "confirm_password": "Xác nhận mật khẩu", + "auth_button": "Xác thực", + "continue_button": "Tiếp tục", + "verify_telegram_button": "Xác minh qua Telegram", + "cancel_button": "Hủy", + "agree_terms": "Khi đăng nhập, bạn đồng ý với", + "tos": "Điều khoản dịch vụ", + "privacy_policy": "Chính sách quyền riêng tư", + "create_account": "Tạo tài khoản của bạn", + "choose_password": "Chọn mật khẩu cho", + "verify_account": "Xác minh tài khoản của bạn", + "verify_description": "Bạn cần xác minh qua Telegram. Nhấn nút bên dưới để mở bot và hoàn thành CAPTCHA.", + "waiting_telegram": "Đang chờ xác minh Telegram...", + "tos_agreement": "Khi đăng nhập, bạn đồng ý với", + "tos_link": "Điều khoản dịch vụ", + "privacy_link": "Chính sách quyền riêng tư", + "create_account_title": "Tạo tài khoản của bạn", + "password_min_chars": "Mật khẩu (tối thiểu 6 ký tự)", + "confirm_password_placeholder": "Xác nhận mật khẩu", + "verify_account_title": "Xác minh tài khoản của bạn", + "verify_via_telegram": "Xác minh qua Telegram", + "waiting_verification": "Đang chờ xác minh Telegram...", + "back": "Quay lại", + "cancel": "Hủy", + "error_handle_required": "Vui lòng nhập tên người dùng", + "error_password_required": "Vui lòng nhập mật khẩu", + "error_passwords_no_match": "Mật khẩu không khớp", + "error_wrong_password": "Sai mật khẩu", + "select_language": "Chọn ngôn ngữ", + "show_password": "Hiển thị mật khẩu", + "hide_password": "Ẩn mật khẩu", + "errors": { + "email_invalid": "Nhập địa chỉ email hợp lệ.", + "password_min_8": "Mật khẩu phải chứa ít nhất 8 ký tự.", + "server_unavailable": "Không thể truy cập máy chủ. Vui lòng kiểm tra kết nối của bạn.", + "server_error": "Máy chủ của Liner hiện đang gặp sự cố. Vui lòng thử lại sau vài phút.", + "invalid_credentials": "Email hoặc mật khẩu không đúng.", + "email_already_used": "Email này đã được sử dụng.", + "username_invalid": "Tên người dùng phải có 3-30 chữ cái viết thường, số hoặc dấu gạch dưới.", + "username_taken": "Tên người dùng này đã có người sử dụng. Hãy chọn tên khác.", + "display_name_required": "Vui lòng nhập tên hiển thị.", + "handle_required": "Vui lòng nhập tên người dùng", + "handle_min": "Tên người dùng phải có ít nhất {min} ký tự", + "handle_max": "Tên người dùng không được quá {max} ký tự", + "handle_invalid": "Tên người dùng phải bắt đầu bằng chữ cái hoặc chữ số và chỉ gồm chữ cái, chữ số, dấu gạch dưới và dấu gạch nối", + "password_required": "Vui lòng nhập mật khẩu", + "password_min": "Mật khẩu phải có ít nhất {min} ký tự", + "password_max": "Mật khẩu không được quá {max} ký tự", + "wrong_password": "Sai mật khẩu", + "password_mismatch": "Mật khẩu không khớp.", + "password_required_simple": "Vui lòng nhập mật khẩu", + "verification_timed_out": "Đã hết thời gian xác minh. Hãy thử lại.", + "verification_expired": "Xác minh đã hết hạn. Hãy thử lại.", + "login_denied": "Đăng nhập bị từ chối trong Telegram.", + "already_linked": "Tài khoản Telegram này đã được liên kết với tài khoản khác. Thay vào đó hãy đăng nhập bằng Telegram.", + "account_not_found": "Không tìm thấy tài khoản hoặc phiên đăng nhập đã hết hạn. Hãy thử đăng ký.", + "failed_start_auth": "Không thể khởi động xác thực Telegram", + "registration_failed": "Đăng ký không thành công: {status}", + "verification_canceled": "Đã hủy xác minh." + }, + "toasts": { + "login_successful": "Đăng nhập thành công", + "account_created": "Đã tạo tài khoản", + "logged_in": "Đã đăng nhập" + } + }, + "player": { + "repeat_off": "Tắt lặp lại", + "repeat_all": "Lặp lại tất cả", + "repeat_one": "Lặp lại một bài", + "nothing_playing": "Chưa phát bài hát nào", + "choose_track": "Tìm và chọn một bài hát để nghe", + "queue": "Danh sách chờ phát", + "lyrics": "Lời bài hát", + "volume": "Âm lượng", + "mute": "Tắt tiếng", + "unmute": "Bật tiếng", + "decrease": "Giảm", + "increase": "Tăng", + "previous": "Bài trước", + "open_player": "Mở trình phát", + "next": "Bài tiếp theo", + "repeat": "Lặp lại", + "lyrics_upgraded": "Đã nâng cấp lời bài hát", + "playing_from": "Phát từ", + "autoplay_radio": "Radio tự động", + "clear_queue": "Xóa danh sách chờ phát", + "shuffle_on": "Bật phát ngẫu nhiên", + "shuffle_off": "Tắt phát ngẫu nhiên", + "save": "Lưu", + "home": "Đang phát triển", + "home_subtitle": "Sử dụng tìm kiếm để nghe nhạc", + "queue_empty": "Danh sách chờ phát trống", + "no_lyrics": "Không tìm thấy lời bài hát", + "back": "Quay lại", + "tracks": "bài hát", + "queue_saved": "Đã lưu danh sách chờ phát", + "instrumental": "♪ nhạc không lời", + "no_lyrics_found": "Chưa có lời cho bài hát này.", + "close_fullscreen": "Thoát toàn màn hình", + "failed_load_lyrics": "Không tải được lời bài hát.", + "lyrics_offset": "Độ lệch lời bài hát", + "earlier": "Sớm hơn", + "later": "Muộn hơn", + "reset": "Đặt lại", + "offset_hint": "Giá trị âm hiển thị lời sớm hơn, giá trị dương hiển thị lời muộn hơn", + "track_unavailable": "\"{title}\" không khả dụng, đang bỏ qua...", + "track_unavailable_title": "Bài hát không khả dụng", + "playback_stopped_too_many_errors": "Đã dừng phát vì có quá nhiều bài hát không tải được.", + "youtube_refused_title": "YouTube đang từ chối kết nối này", + "youtube_refused_description": "Mạng này đang chặn âm thanh từ YouTube. Hãy tắt VPN hoặc proxy, hoặc thử kết nối khác.", + "speed_pitch": "Tốc độ và cao độ", + "speed": "Tốc độ", + "pitch": "Cao độ", + "link_speed_pitch": "Liên kết tốc độ với cao độ", + "link_speed_pitch_hint": "Thay đổi tốc độ sẽ đổi cao độ như khi nghe đĩa than hoặc băng cassette", + "key_lock": "Giữ tông", + "key_lock_hint": "Giữ nguyên tông nhạc khi thay đổi tốc độ", + "keep_speed_across_tracks": "Giữ cài đặt khi chuyển bài", + "keep_speed_hint": "Áp dụng cài đặt này cho các bài hát tiếp theo", + "reset_speed": "Đặt lại", + "preset_normal": "1,0× Bình thường", + "preset_speedup": "1,25× Nhanh hơn", + "preset_slowed": "0,8× Chậm hơn", + "preset_nightcore": "1,35× Nightcore", + "reverb": "Độ vang", + "reverb_hint": "Tạo không gian và chiều sâu cho âm thanh", + "reverb_amount": "Độ vang", + "equalizer": "Bộ chỉnh âm", + "equalizer_hint": "Điều chỉnh âm thanh theo từng dải tần", + "eq_tab_enhance": "Cải thiện âm thanh", + "eq_tab_genre": "Thể loại", + "eq_tab_accent": "Điểm nhấn", + "eq_tab_custom": "Đã lưu", + "eq_save_preset": "Lưu cài đặt hiện tại", + "eq_presets_full": "Đã đạt giới hạn số cấu hình", + "eq_custom_empty": "Điều chỉnh các dải tần rồi lưu thành cấu hình để dùng lại", + "eq_preset_name": "Tên cấu hình", + "eq_delete_preset": "Xóa cấu hình", + "eq_preset_hifi": "Hi-Fi", + "eq_preset_hifi_hint": "Âm trầm đầy đặn, âm cao thoáng hơn, giữ nguyên âm trung", + "eq_preset_clarity": "Trong trẻo", + "eq_preset_clarity_hint": "Giảm độ đục ở dải trung trầm, giúp các nhạc cụ rõ hơn", + "eq_preset_warmth": "Ấm áp", + "eq_preset_warmth_hint": "Chất âm analog ấm áp, làm dịu bản thu quá chói", + "eq_preset_spacious": "Rộng mở", + "eq_preset_spacious_hint": "Không gian âm thanh rộng và thoáng hơn", + "eq_preset_headphones": "Tai nghe", + "eq_preset_headphones_hint": "Bù các dải siêu trầm và trung cao thường bị hụt trên tai nghe", + "eq_preset_laptop": "Máy tính xách tay", + "eq_preset_laptop_hint": "Cho loa nhỏ: giảm siêu trầm, tăng độ đầy đặn", + "eq_preset_night": "Nghe ban đêm", + "eq_preset_night_hint": "Giảm âm trầm ù và âm cao chói, giữ giọng hát rõ khi nghe nhỏ", + "eq_preset_pop": "Pop", + "eq_preset_pop_hint": "Làm nổi bật âm trung và giúp âm cao mượt hơn", + "eq_preset_rock": "Rock", + "eq_preset_rock_hint": "Tiếng trống chắc và tiếng guitar sắc nét", + "eq_preset_hiphop": "Hip-Hop", + "eq_preset_hiphop_hint": "Âm trầm 808 mạnh, giọng hát vẫn nổi bật", + "eq_preset_electronic": "Điện tử", + "eq_preset_electronic_hint": "Tiếng kick sâu và âm synth sắc nét", + "eq_preset_jazz": "Jazz", + "eq_preset_jazz_hint": "Tiếng contrabass ấm, tiếng chũm chọe thoáng", + "eq_preset_classical": "Cổ điển", + "eq_preset_classical_hint": "Âm thanh phòng hòa nhạc tự nhiên, mở rộng nhẹ dải trầm và cao", + "eq_preset_acoustic": "Acoustic", + "eq_preset_acoustic_hint": "Làm rõ âm cộng hưởng của thùng đàn và tiếng dây đàn", + "eq_preset_lofi": "Lo-Fi", + "eq_preset_lofi_hint": "Chất âm hoài cổ như băng cassette, giảm bớt dải cao", + "eq_preset_bass": "Âm trầm", + "eq_preset_bass_hint": "Tăng âm trầm", + "eq_preset_deep_bass": "Âm trầm sâu", + "eq_preset_deep_bass_hint": "Tăng tối đa dải siêu trầm", + "eq_preset_less_bass": "Giảm âm trầm", + "eq_preset_less_bass_hint": "Giảm tiếng ù ở bài hát hoặc loa có nhiều âm trầm", + "eq_preset_vocal": "Giọng hát", + "eq_preset_vocal_hint": "Làm nổi bật giọng hát", + "eq_preset_treble": "Âm bổng", + "eq_preset_treble_hint": "Tăng âm cao và độ chi tiết", + "eq_preset_loudness": "Nghe ở âm lượng nhỏ", + "eq_preset_loudness_hint": "Tăng âm trầm và âm cao khi nghe ở âm lượng nhỏ", + "eq_preset_punch": "Mạnh mẽ", + "eq_preset_punch_hint": "Âm thanh gọn hơn với tiếng kick và độ nảy mạnh", + "eq_preset_smooth": "Mượt mà", + "eq_preset_smooth_hint": "Làm dịu âm cao chói để nghe lâu dễ chịu hơn", + "eq_preset_rnb": "R&B", + "eq_preset_rnb_hint": "Giọng hát mượt mà trên âm trầm tròn trịa, ấm áp", + "beta_visuals": { + "label": "Cảnh báo", + "ambient_title": "Nền động đang thử nghiệm", + "ambient_body": "Bài hát này có nền động tùy chỉnh. Tính năng vẫn đang thử nghiệm và có thể làm nặng thiết bị yếu, vì vậy hãy chọn chế độ nhẹ hơn nếu trình phát bị giật.", + "settings_title": "Chất lượng hình ảnh", + "settings_body": "Chọn mức độ hoạt ảnh của trình phát toàn màn hình. Chế độ nhẹ hơn giúp tiết kiệm pin và chạy mượt hơn trên các thiết bị yếu hơn.", + "modes": { + "full": { + "name": "Tất cả hiệu ứng", + "hint": "Bật mọi hiệu ứng, kể cả làm mờ viền lời bài hát" + }, + "balanced": { + "name": "Cân bằng", + "hint": "Nền động, không làm mờ lời bài hát" + }, + "lite": { + "name": "Nhẹ", + "hint": "Ảnh bìa tĩnh, lời bài hát không có hiệu ứng" + } + } + } + }, + "playlist": { + "playlist": "Danh sách phát", + "liked_songs": "Bài hát đã thích", + "untitled_playlist": "Danh sách phát chưa đặt tên", + "play_all": "Phát tất cả", + "add_to_queue": "Thêm danh sách phát vào danh sách chờ phát", + "added_to_queue": "Đã thêm danh sách phát vào danh sách chờ phát", + "import": "Nhập", + "error_loading": "Không tải được danh sách phát", + "not_found": "Không tìm thấy danh sách phát", + "track": "bài hát", + "tracks": "bài hát", + "hr": "giờ", + "min": "phút", + "sec": "giây", + "empty_title": "Danh sách phát này trống", + "empty_subtitle": "Tìm kiếm bài hát để thêm", + "likes_empty": "Chưa có bài hát đã thích" + }, + "search": { + "placeholder": "Tìm kiếm bài hát, nghệ sĩ, album...", + "all": "Tất cả", + "songs": "Bài hát", + "artists": "Nghệ sĩ", + "albums": "Album", + "playlists": "Danh sách phát", + "no_results": "Không tìm thấy kết quả nào", + "type_to_search": "Gõ để tìm kiếm" + }, + "settings": { + "title": "Cài đặt", + "search_placeholder": "Tìm trong cài đặt…", + "subtitle": "Quản lý tùy chọn của bạn", + "reset_defaults": "Đặt lại về mặc định", + "save_preferences": "Lưu tùy chọn", + "groups": { + "preferences": "Tùy chọn", + "player": "Trình phát", + "interface": "Giao diện", + "integrations": "Tích hợp", + "application": "Ứng dụng", + "help": "Trợ giúp" + }, + "docs": "Tài liệu", + "support": "Hỗ trợ", + "manage_account": "Quản lý tài khoản", + "tabs": { + "general": "Chung", + "appearance": "Giao diện", + "storage": "Bộ nhớ đệm và lưu trữ", + "system": "Hệ thống", + "account": "Tài khoản", + "about": "Giới thiệu", + "playback": "Phát nhạc", + "shortcuts": "Phím tắt", + "overlay": "Trình phát nổi", + "discord": "Discord RPC", + "youtube": "YouTube", + "privacy": "Quyền riêng tư" + }, + "playback": { + "description": "Tùy chỉnh danh sách chờ phát, thao tác nhấp chuột và đầu ra âm thanh." + }, + "shortcuts": { + "description": "Tùy chỉnh phím tắt toàn hệ thống và phím tắt của trình phát.", + "global_section": "Phím tắt toàn hệ thống", + "global_desc": "Hoạt động trong mọi ứng dụng trên máy tính, kể cả khi Liner đang thu nhỏ hoặc không được chọn.", + "main_app_section": "Ứng dụng chính", + "main_app_desc": "Hoạt động khi bạn đang sử dụng cửa sổ Liner chính.", + "miniplayer_section": "Chế độ trình phát thu nhỏ", + "miniplayer_desc": "Hoạt động khi bạn đang sử dụng trình phát nổi.", + "toggle_overlay": "Hiện / Ẩn trình phát nổi", + "toggle_overlay_desc": "Hiện hoặc ẩn trình phát nổi từ bất kỳ ứng dụng nào.", + "quick_like_song": "Thích nhanh bài hát hiện tại", + "quick_like_song_desc": "Thích hoặc bỏ thích bài hát đang phát ngay cả khi bạn đang dùng ứng dụng khác.", + "play_pause": "Phát / Tạm dừng", + "play_pause_desc": "Phát hoặc tạm dừng nhạc.", + "next_track": "Bài hát tiếp theo", + "next_track_desc": "Chuyển sang bài hát tiếp theo trong danh sách chờ phát.", + "prev_track": "Bài hát trước", + "prev_track_desc": "Quay lại bài trước hoặc phát lại từ đầu bài.", + "seek_forward": "Tua tới (+5 giây)", + "seek_forward_desc": "Tua tới 5 giây.", + "seek_backward": "Tua lùi (−5 giây)", + "seek_backward_desc": "Tua lùi 5 giây.", + "volume_up": "Tăng âm lượng", + "volume_up_desc": "Tăng âm lượng thêm 5%.", + "volume_down": "Giảm âm lượng", + "volume_down_desc": "Giảm âm lượng đi 5%.", + "toggle_mute": "Tắt tiếng / Bật tiếng", + "toggle_mute_desc": "Tắt hoặc bật tiếng.", + "search": "Tìm kiếm nhạc", + "search_desc": "Mở nhanh hộp thoại tìm kiếm.", + "toggle_queue": "Danh sách chờ phát", + "toggle_queue_desc": "Mở hoặc đóng bảng danh sách chờ phát phát nhạc.", + "toggle_fullscreen": "Toàn màn hình / Trình phát", + "toggle_fullscreen_desc": "Chuyển sang hoặc thoát trình phát toàn màn hình.", + "like_track": "Thích / Bỏ thích", + "like_track_desc": "Thêm bài hát vào hoặc xóa khỏi danh sách yêu thích.", + "focus_main_window": "Chuyển sang cửa sổ chính", + "focus_main_window_desc": "Đưa cửa sổ chính của ứng dụng lên phía trước.", + "reset_all": "Đặt lại tất cả phím tắt", + "reset_all_desc": "Khôi phục phím tắt mặc định cho tất cả các mục.", + "reset_all_button": "Đặt lại mặc định", + "reset_tooltip": "Đặt lại mặc định ({shortcut})", + "conflict_error": "Đã được \"{action}\" sử dụng", + "modifier_required": "Phím tắt chung yêu cầu Ctrl, Alt hoặc Shift", + "recording_hint": "Nhấn phím để gán (Esc để hủy)", + "press_keys": "Nhấn phím...", + "search_placeholder": "Tìm kiếm phím tắt...", + "tab_all": "Tất cả", + "tab_main_app": "Ứng dụng chính", + "tab_overlay": "Trình phát nổi", + "tab_global": "Toàn hệ thống", + "scope_global": "Toàn hệ thống", + "scope_main_app": "Ứng dụng chính", + "scope_overlay": "Trình phát nổi", + "reset_section": "Đặt lại mục này" + }, + "overlay": { + "description": "Tùy chỉnh trình phát nổi, phím tắt toàn hệ thống và vị trí hiển thị.", + "enabled": { + "title": "Bật trình phát nổi", + "description": "Hiển thị trình phát thu nhỏ nổi phía trên các cửa sổ khác." + }, + "position": { + "title": "Vị trí", + "description": "Chọn vị trí trình phát nổi xuất hiện trên màn hình của bạn.", + "top_left": "Trên cùng bên trái", + "top_center": "Trên cùng ở giữa", + "top_right": "Trên cùng bên phải" + }, + "shortcut": { + "title": "Phím tắt toàn hệ thống", + "description": "Hiện hoặc ẩn trình phát nổi từ bất kỳ ứng dụng nào.", + "recording": "Nhấn tổ hợp phím...", + "need_modifier": "Phím tắt phải bao gồm Ctrl, Alt hoặc Shift", + "reset": "Đặt lại về Alt+Shift+O", + "reset_label": "Đặt lại" + }, + "auto_show_on_minimize": { + "title": "Tự động hiển thị khi thu nhỏ", + "description": "Tự động hiển thị trình phát nổi khi Liner được thu nhỏ." + }, + "always_on_top": { + "title": "Luôn ở trên cùng", + "description": "Giữ trình phát nổi nổi phía trên các cửa sổ khác." + } + }, + "youtube": { + "description": "Đăng nhập vào tài khoản YouTube của bạn để tránh lỗi phát nhạc.", + "section_account": "Tài khoản", + "section_playback": "Phát nhạc", + "account_playback": { + "title": "Phát qua tài khoản của bạn", + "description": "Phát nhạc từ YouTube bằng tài khoản đã đăng nhập để tránh bị chặn." + }, + "prompt_sign_in": { + "title": "Yêu cầu đăng nhập", + "description": "Hiển thị thẻ đăng nhập khi YouTube chặn phát nhạc thay vì bỏ qua bài hát." + }, + "sync_library": { + "title": "Đồng bộ thư viện", + "description": "Hiển thị danh sách phát từ tài khoản YouTube của bạn trong thư viện bên cạnh danh sách phát Liner." + }, + "sign_out": "Đăng xuất", + "sign_in": "Đăng nhập", + "signed_out_title": "Chưa đăng nhập", + "signed_out_description": "Đăng nhập để tiếp tục nghe nhạc từ YouTube" + }, + "discord": { + "description": "Hiển thị nội dung bạn đang nghe trên Discord bằng ảnh bìa album, huy hiệu nghệ sĩ và thanh tiến trình.", + "section_display": "Tùy chọn hiển thị", + "section_buttons": "Nút trên hồ sơ", + "enable": { + "title": "Discord Rich Presence", + "description": "Hiển thị bài hát bạn đang nghe trên hồ sơ Discord." + }, + "status_display": { + "title": "Định dạng trạng thái", + "description": "Chọn nội dung xuất hiện trong tiêu đề trạng thái 'Đang nghe...' của Discord.", + "artist": "Nghệ sĩ (Mặc định)", + "song": "Tên bài hát", + "artist_song": "Nghệ sĩ - Bài hát", + "song_artist": "Bài hát - Nghệ sĩ", + "app": "Liner (Tên ứng dụng)" + }, + "show_timeline": { + "title": "Tiến trình phát nhạc", + "description": "Hiển thị thanh tiến trình với thời gian đã phát và còn lại của bài hát." + }, + "show_artwork": { + "title": "Ảnh bìa bài hát", + "description": "Hiển thị ảnh bìa bài hát hoặc album trong thẻ hoạt động trên Discord." + }, + "show_artist_image": { + "title": "Huy hiệu ảnh nghệ sĩ", + "description": "Hiển thị ảnh nghệ sĩ dưới dạng huy hiệu hình tròn nhỏ ở góc dưới cùng." + }, + "show_paused": { + "title": "Hiển thị khi tạm dừng", + "description": "Tiếp tục hiển thị trạng thái trên Discord kèm biểu tượng tạm dừng khi bạn dừng nhạc." + }, + "show_button": { + "title": "Nút 'Nghe trên Liner'", + "description": "Thêm nút tương tác liên kết tới bài hát trên Liner." + }, + "show_download_button": { + "title": "Nút 'Tải xuống Liner'", + "description": "Thêm nút tương tác liên kết tới tryliner.fun để tải ứng dụng." + }, + "status": { + "connected": "Đã kết nối với Discord ({user})", + "disconnected": "Discord chưa được kết nối", + "ready": "Sẵn sàng", + "waiting": "Đang chờ Discord", + "disabled": "Đã tắt", + "via_arrpc": "Đã kết nối qua arRPC" + } + }, + "audio_data": { + "description": "Chất lượng phát trực tuyến, bộ nhớ đệm ngoại tuyến và chẩn đoán kết nối." + }, + "privacy": { + "description": "Thống kê sử dụng ẩn danh và báo cáo sự cố." + }, + "notifications": { + "test_button": "Gửi thông báo thử", + "playback_title": "Phát nhạc", + "playback_sub": "Daft Punk — Instant Crush", + "playback_action": "Tạm dừng", + "release_title": "Nhạc mới từ nghệ sĩ", + "release_sub": "Kendrick Lamar — GNX", + "release_action": "Nghe", + "copy_request_id": "Sao chép ID yêu cầu để được hỗ trợ", + "copied": "Đã sao chép!" + }, + "language": { + "label": "Ngôn ngữ", + "description": "Chọn ngôn ngữ giao diện" + }, + "autoplay_similar": { + "title": "Tự động phát các bài hát tương tự", + "description": "Tự động thêm các bài hát tương tự khi danh sách chờ phát của bạn kết thúc." + }, + "track_double_click": { + "title": "Nhấp đúp vào bài hát", + "description": "Chọn điều gì sẽ xảy ra khi bạn bấm đúp vào thẻ bài hát.", + "play": "Phát ngay", + "queue": "Thêm vào danh sách chờ phát" + }, + "default_playback_context": { + "title": "Khi mở ứng dụng", + "description": "Tiếp tục danh sách chờ phát lần trước hoặc bắt đầu với danh sách trống.", + "resume": "Khôi phục danh sách chờ phát", + "empty": "Bắt đầu với danh sách trống" + }, + "telemetry": { + "title": "Thống kê và chẩn đoán ẩn danh", + "description": "Giúp phát hiện và khắc phục lỗi phát nhạc, gián đoạn khi tải nhạc và sự cố mạng. Không thu thập dữ liệu cá nhân, mã truy cập, mật khẩu hay đường dẫn tệp trên máy.", + "enabled": "Đã bật thống kê ẩn danh", + "disabled": "Đã tắt hoàn toàn thống kê" + }, + "cache": { + "title": "Bộ nhớ đệm và lưu trữ", + "description": "Quản lý dữ liệu ứng dụng để giải phóng dung lượng hoặc giải quyết các sự cố đồng bộ hóa.", + "local_cache": { + "title": "Bộ nhớ đệm cục bộ", + "description": "Xóa dữ liệu tạm, lời bài hát và các mục đã lưu trên máy.", + "button": "Xóa bộ nhớ đệm cục bộ", + "success": "Đã xóa bộ nhớ đệm cục bộ", + "error": "Không xóa được bộ nhớ đệm cục bộ" + }, + "search_cache": { + "title": "Bộ nhớ đệm tìm kiếm", + "description": "Xóa lịch sử tìm kiếm gần đây trong bộ nhớ.", + "button": "Xóa bộ nhớ đệm tìm kiếm", + "success": "Đã xóa bộ nhớ đệm tìm kiếm", + "error": "Không xóa được bộ nhớ đệm tìm kiếm" + }, + "library_cache": { + "title": "Bộ nhớ đệm thư viện", + "description": "Xóa trạng thái giao diện người dùng, thư viện và luồng dữ liệu đang hoạt động.", + "button": "Xóa bộ nhớ đệm thư viện", + "success": "Đã xóa bộ nhớ đệm thư viện" + } + }, + "storage": { + "title": "Bộ nhớ đệm và lưu trữ", + "description": "Xem dung lượng sử dụng cho bộ nhớ đệm và các tệp âm thanh, hình ảnh.", + "usage_title": "Dung lượng đã dùng", + "device_usage": "Liner đang dùng {size} dung lượng trên thiết bị.", + "device_usage_raw": "Liner đang dùng {size} dung lượng trên thiết bị.", + "audio_cache_limit": "Giới hạn bộ nhớ đệm", + "audio_cache_limit_desc": "Tự động xóa các tệp âm thanh, hình ảnh và dữ liệu cũ khi bộ nhớ đệm đầy", + "cache_limit": "Giới hạn bộ nhớ đệm", + "cache_limit_desc": "Tự động xóa các tệp âm thanh, hình ảnh và dữ liệu cũ khi bộ nhớ đệm đầy", + "no_limit": "Không giới hạn", + "recommended": "Đề xuất", + "open_folder": "Mở thư mục bộ nhớ đệm", + "open_folder_description": "Mở thư mục chứa bộ nhớ đệm và các tệp âm thanh, hình ảnh tạm thời", + "clear_button": "Xóa bộ nhớ đệm ({size})", + "clear_selected": "Xóa bộ nhớ đệm đã chọn", + "select_all": "Chọn tất cả", + "deselect_all": "Bỏ chọn tất cả", + "empty_storage": "Bộ nhớ đệm đang trống", + "cloud_disclaimer": "Nhạc và ảnh bìa vẫn được lưu trên đám mây và sẽ tự động tải lại khi phát.", + "clearing_title": "Đang xóa bộ nhớ đệm...", + "clearing_subtitle": "Vui lòng giữ cửa sổ này mở trong khi Liner xóa bộ nhớ đệm.", + "cleared_title": "Đã xóa bộ nhớ đệm", + "cleared_subtitle": "Bộ nhớ đệm đã được xóa. Nội dung mới sẽ tự động được phát trực tuyến và lưu vào bộ nhớ đệm.", + "done_button": "Xong", + "categories": { + "covers": "Ảnh bìa", + "audio": "Âm thanh", + "lyrics": "Lời bài hát", + "metadata": "Danh mục và tìm kiếm" + } + }, + "theme": { + "title": "Giao diện", + "description": "Chọn giao diện tổng thể của ứng dụng.", + "light": "Sáng", + "dark": "Tối", + "system": "Hệ thống" + }, + "branding": { + "title": "Màu logo", + "description": "Chọn màu nhấn cho logo.", + "default": "Mặc định", + "spotify": "Spotify", + "discord": "Discord", + "telegram": "Telegram", + "aurora": "Cực quang", + "sunset": "Hoàng hôn", + "ocean": "Đại dương", + "forest": "Rừng", + "berry": "Đỏ mọng", + "carbon": "Cacbon", + "pixel": "Pixel", + "scanlines": "Đường quét", + "vhs": "Chrome" + }, + "audio": { + "pause_on_device_change": { + "title": "Tạm dừng khi thay đổi thiết bị", + "description": "Tự động tạm dừng phát nhạc khi thiết bị đầu ra âm thanh thay đổi." + }, + "download_current_song": { + "title": "Tải bài hát hiện tại", + "description": "Tải xuống bài hát đang phát dưới dạng tệp MP3." + } + }, + "profile": { + "title": "Hồ sơ", + "signed_in_as": "Đã đăng nhập bằng", + "not_signed_in": "Bạn chưa đăng nhập.", + "sign_in": "Đăng nhập vào Liner", + "sign_out": "Đăng xuất", + "sign_out_confirm": "Bạn có chắc chắn muốn đăng xuất không?", + "edit_profile": "Chỉnh sửa hồ sơ", + "listening_to": "Đang nghe", + "stat_playlists": "Danh sách phát", + "stat_favorites": "Yêu thích", + "stat_status": "Trạng thái", + "stat_active": "Đang hoạt động", + "no_bio": "Chưa có tiểu sử", + "details_section": "Chi tiết hồ sơ", + "details_subtitle": "Tùy chỉnh thông tin hiển thị công khai trên Liner", + "username_label": "Tên người dùng", + "username_hint": "3–30 ký tự gồm chữ thường, chữ số hoặc dấu gạch dưới (a-z, 0-9, _). Không được trùng với người khác.", + "username_invalid": "Tên người dùng phải có 3-30 chữ cái viết thường, số hoặc dấu gạch dưới.", + "username_taken": "Tên người dùng này đã có người sử dụng. Hãy chọn tên khác.", + "display_name_label": "Tên hiển thị", + "display_name_placeholder": "Tên hoặc bí danh của bạn", + "avatar_url_label": "Liên kết ảnh đại diện", + "avatar_url_placeholder": "https://example.com/avatar.jpg", + "bio_label": "Giới thiệu", + "bio_placeholder": "Chia sẻ đôi điều về gu âm nhạc của bạn…", + "save_changes": "Lưu thay đổi", + "saving": "Đang lưu...", + "reset_changes": "Hủy thay đổi", + "saved_success": "Cập nhật hồ sơ thành công", + "save_failed": "Không cập nhật được hồ sơ", + "privacy_section": "Quyền riêng tư và chia sẻ", + "privacy_subtitle": "Chọn những thông tin người khác có thể xem trên Liner", + "public_profile": { + "title": "Hồ sơ công khai", + "description": "Cho phép người khác tìm kiếm hồ sơ của bạn và xem thông tin công khai của bạn." + }, + "show_activity": { + "title": "Chia sẻ hoạt động nghe nhạc", + "description": "Hiển thị bài hát bạn đang nghe trên hồ sơ của mình." + }, + "show_history": { + "title": "Chia sẻ lịch sử nghe", + "description": "Cho phép người khác xem các bài hát bạn nghe gần đây trên hồ sơ." + }, + "show_liked_tracks": { + "title": "Chia sẻ bài hát đã thích", + "description": "Hiển thị các bài hát bạn thích trên hồ sơ công khai của bạn." + }, + "participate_leaderboards": { + "title": "Tham gia bảng xếp hạng", + "description": "Góp mặt trong bảng xếp hạng người nghe của nghệ sĩ và bảng xếp hạng toàn cầu." + }, + "badge_public": "Công khai", + "badge_private": "Riêng tư" + }, + "about": { + "liner": "Liner", + "telegram": "Kênh", + "discord": "Discord", + "github": "GitHub", + "website": "Trang web", + "tagline": "Ứng dụng nghe nhạc trực tuyến trên máy tính với lời bài hát đồng bộ theo từng âm tiết", + "updates_title": "Cập nhật và phiên bản", + "check_updates": "Kiểm tra cập nhật", + "checking_updates": "Đang kiểm tra…", + "up_to_date": "Đã dùng phiên bản mới nhất", + "latest_version_toast": "Bạn đang chạy phiên bản mới nhất (v{version})", + "build_info": "Bản phát hành chính thức · Electron 44 · React 19", + "tech_stack_title": "Công nghệ", + "tech_electron": "Electron 44 & Web Audio", + "tech_electron_desc": "Phát nhạc trực tuyến với độ trễ thấp, cân bằng âm lượng theo cảm nhận và phát nhạc liên tục.", + "tech_react": "React 19 & Tailwind v4", + "tech_react_desc": "Giao diện phản hồi nhanh với hiệu ứng chuyển động mượt mà ở 60 khung hình/giây.", + "tech_wasm": "Rust WebAssembly tích hợp", + "tech_wasm_desc": "Ký số yêu cầu và ảnh bìa ngay trong bộ nhớ, không cần tệp thực thi bên ngoài.", + "tech_lyrics": "Lời bài hát đồng bộ và hiệu ứng hình ảnh", + "tech_lyrics_desc": "Tích hợp bộ phân tích @braccato/core cùng nền WebGL chuyển động theo nội dung.", + "shortcuts_title": "Phím tắt", + "shortcut_play": "Phát / Tạm dừng", + "shortcut_search": "Tìm kiếm nhạc", + "shortcut_lyrics": "Hiện / Ẩn lời bài hát", + "shortcut_mini": "Trình phát thu nhỏ", + "community_title": "Cộng đồng và tài nguyên", + "open_readme": "Tài liệu và kiến trúc", + "open_readme_desc": "Tìm hiểu cấu trúc hệ thống, cách biên dịch và thiết lập môi trường phát triển.", + "report_issue": "Báo cáo sự cố", + "report_issue_desc": "Gửi báo cáo lỗi, đề xuất tính năng hoặc phản hồi trên GitHub.", + "special_thanks": "Lời cảm ơn", + "special_thanks_desc": "@braccato/core, @kawarp/react, Solar Icons và MingCute Icons.", + "license_notice": "Phân phối theo giấy phép Liner Source-Available & Non-Commercial." + }, + "connection": { + "open_folder": "Mở vị trí đã lưu" + } + }, + "toast": { + "playlist_created": "Đã tạo danh sách phát", + "playlist_imported": "Đã nhập {name} ({count} bài hát)", + "importing_playlist": "Đang nhập {name}: {done} / {total} bài hát", + "importing_likes": "Đang nhập bài hát đã thích: {done} / {total} bài hát", + "imported_likes": "Đã nhập {count} bài hát đã thích", + "failed_create_playlist": "Không tạo được danh sách phát", + "failed_import_playlist": "Không nhập được danh sách phát", + "failed_get_playlist": "Không lấy được thông tin danh sách phát", + "failed_add_track": "Không thêm được bài hát", + "failed_load_track": "Không tải được bài hát", + "failed_resolve_link": "Không xử lý được liên kết", + "unsupported_link": "Liên kết không hợp lệ hoặc chưa được hỗ trợ", + "name_required": "Vui lòng nhập tên", + "paste_link": "Vui lòng dán liên kết trước", + "username_required": "Vui lòng nhập tên người dùng SoundCloud", + "import_failed_check": "Không nhập được bài hát đã thích. Hãy kiểm tra tên người dùng rồi thử lại.", + "track_already_in_playlist": "Bài hát đã có trong danh sách phát này", + "added_to_playlist": "Đã thêm vào danh sách phát", + "removed_from_playlist": "Đã xóa khỏi danh sách phát", + "already_in_library": "{type} đã có trong thư viện của bạn", + "failed_remove_track": "Không xóa được bài hát", + "importing_progress": "Đang nhập {name}: {done} / {total} bài hát" + }, + "import": { + "review_title": "Kiểm tra trước khi nhập", + "review_action": "Kiểm tra", + "review_description": "Chọn các bài hát bạn muốn nhập vào danh sách phát.", + "source_track": "Bài hát gốc", + "proposed_match": "Bài hát tương ứng", + "no_candidate": "Không tìm thấy bài hát tương ứng trong kho nhạc", + "no_candidate_description": "Bài hát này sẽ bị bỏ qua trong quá trình nhập", + "reason_auto_matched": "Đã khớp", + "reason_no_catalog_candidates": "Không tìm thấy trong kho nhạc", + "reason_low_confidence_match": "Kết quả chưa chắc chắn", + "reason_ambiguous_match": "Có nhiều bài hát tương tự", + "reason_duration_mismatch": "Thời lượng không khớp", + "reason_catalog_lookup_failed": "Không tìm kiếm được trong kho nhạc", + "match_score": "Khớp {score}%", + "approve": "Thêm", + "deny": "Bỏ qua", + "select_all": "Chọn tất cả", + "deselect_all": "Bỏ chọn tất cả", + "skip_all": "Bỏ qua tất cả", + "skipped": "Đã bỏ qua", + "apply_decisions": "Nhập các bài đã chọn", + "applying": "Đang nhập…", + "status_queued": "Đã đưa tác vụ nhập vào hàng chờ", + "status_queued_sub": "Sẽ bắt đầu xử lý trong giây lát", + "status_searching": "Đang đối chiếu bài hát", + "status_searching_sub": "Đang phân tích danh sách phát…", + "status_running": "Đang đối chiếu bài hát", + "status_running_progress": "Đã tìm được bài tương ứng cho {count}/{total} bài hát", + "status_awaiting_decision": "Cần kiểm tra", + "status_awaiting_sub": "Kiểm tra các bài hát tương ứng trước khi tạo danh sách phát", + "status_finalizing": "Đang tạo danh sách phát…", + "status_finalizing_sub": "Đang lưu bài hát vào thư viện", + "status_completed": "Đã nhập danh sách phát", + "status_completed_sub": "Đã thêm {count} bài hát", + "status_completed_sub_empty": "Danh sách phát đã sẵn sàng để phát", + "status_failed": "Nhập không thành công", + "status_failed_sub": "Đã xảy ra lỗi", + "view_playlist": "Mở danh sách phát", + "no_candidate_found": "Không tìm thấy bài hát tương ứng trong kho nhạc", + "active_import": "Nhập danh sách phát" + }, + "error_screen": { + "title": "Đã xảy ra lỗi", + "subtitle": "Đã xảy ra lỗi không mong muốn trong Liner. Bạn có thể tải lại ứng dụng hoặc thử lại.", + "reload": "Tải lại ứng dụng", + "try_again": "Thử lại", + "go_home": "Về trang chủ", + "copy_details": "Sao chép chi tiết lỗi", + "copied": "Đã sao chép vào bảng nhớ tạm", + "show_details": "Hiển thị chi tiết kỹ thuật", + "hide_details": "Ẩn chi tiết kỹ thuật", + "error_details": "Chi tiết lỗi" + }, + "profile": { + "title": "Hồ sơ", + "edit_profile": "Chỉnh sửa hồ sơ", + "badge_public": "Công khai", + "badge_private": "Riêng tư", + "no_bio": "Chưa có tiểu sử", + "stat_playlists": "Danh sách phát", + "stat_favorites": "Yêu thích", + "stat_status": "Trạng thái", + "stat_active": "Trực tuyến", + "stat_playing": "Đang nghe", + "listening_to": "Đang nghe", + "settings": "Cài đặt", + "sign_out": "Đăng xuất" + }, + "connectivity": { + "wall_title": "Không thể kết nối", + "wall_subtitle": "Liner không thể kết nối với máy chủ. Nhạc và thư viện của bạn vẫn an toàn.", + "wall_title_server": "Máy chủ của Liner đang gặp sự cố", + "wall_subtitle_server": "Kết nối mạng của bạn vẫn hoạt động, nhưng máy chủ đang gặp lỗi. Nhạc và thư viện của bạn vẫn an toàn. Hãy thử lại sau vài phút.", + "steps_title": "Một số cách khắc phục nhanh", + "step_net": "Kiểm tra kết nối Wi-Fi hoặc cáp mạng và thử mở một trang web trong trình duyệt.", + "step_vpn": "Tạm tắt VPN, proxy hoặc bộ lọc DNS — các dịch vụ này có thể chặn ứng dụng.", + "step_firewall": "Cho phép Liner kết nối mạng trong cài đặt tường lửa và phần mềm diệt vi-rút.", + "step_router": "Khởi động lại bộ định tuyến, sau đó nhấn Thử lại bên dưới.", + "retry": "Thử lại", + "retrying": "Đang kiểm tra…", + "checks_title": "Kiểm tra kết nối", + "check_ok_count": "Đạt {ok}/{total} phép kiểm tra", + "never_run": "chưa chạy", + "status_ok": "đạt", + "status_fail": "thất bại", + "status_skip": "bỏ qua", + "check_device": "Thiết bị trực tuyến", + "check_api": "Tình trạng API", + "check_covers": "Truy cập ảnh bìa", + "check_link": "Truy cập liên kết chia sẻ", + "check_dns": "DNS", + "check_tcp": "TCP 443", + "check_tls": "Bắt tay TLS", + "check_control": "Điểm kiểm tra kết nối", + "check_trace": "Dò tuyến mạng", + "check_platform": "Nền tảng", + "check_main": "Kiểm tra trên máy tính", + "support": "Liên hệ hỗ trợ" + }, + "updater": { + "modal_title": "Đã có bản cập nhật mới", + "modal_desc": "Phiên bản mới của Liner (v{version}) đã sẵn sàng để tải xuống.", + "view_changelog": "Nhật ký thay đổi", + "skip_button": "Bỏ qua", + "update_button": "Cập nhật", + "downloading_title": "Đang tải xuống bản cập nhật…", + "downloaded_title": "Đã tải xuống bản cập nhật", + "downloaded_desc": "Khởi động lại Liner để cài đặt phiên bản {version}.", + "install_button": "Cài đặt", + "error_title": "Cập nhật không thành công" + }, + "track_search": { + "placeholder_playlist": "Tìm kiếm trong danh sách phát", + "placeholder_album": "Tìm kiếm trong album", + "count": "{count} trên {total}", + "no_results": "Không có bài hát nào khớp với “{query}”", + "clear": "Xóa tìm kiếm" + }, + "track_sort": { + "label": "Sắp xếp", + "default": "Mặc định", + "added": "Theo ngày thêm", + "title": "Theo tiêu đề (A–Z)", + "duration": "Theo thời lượng", + "popularity": "Theo mức độ phổ biến" + }, + "youtube_auth": { + "title": "Đăng nhập vào YouTube để tiếp tục nghe", + "description": "YouTube chặn luồng âm thanh khi chưa đăng nhập (kiểm tra BotGuard). Đăng nhập bằng tài khoản Google/YouTube để xác nhận bạn là người nghe thật và gỡ bỏ giới hạn.", + "waiting": "Đang chờ đăng nhập…", + "retry": "Thử lại", + "not_now": "Để sau", + "or_enter_code": "hoặc nhập mã tại", + "copy_code": "Sao chép mã", + "connected": "Đã kết nối YouTube", + "qr_label": "Mã QR đăng nhập" + } +} diff --git a/src/languages/options.tsx b/src/languages/options.tsx index d4d2f600..5589ed98 100644 --- a/src/languages/options.tsx +++ b/src/languages/options.tsx @@ -59,4 +59,9 @@ export const LOCALE_OPTIONS: SelectOption[] = [ label: "Bahasa Indonesia", icon: , }, + { + value: "vi", + label: "Tiếng Việt", + icon: , + }, ]; diff --git a/src/languages/translator.test.ts b/src/languages/translator.test.ts index 5d16cd68..5edce2b4 100644 --- a/src/languages/translator.test.ts +++ b/src/languages/translator.test.ts @@ -107,6 +107,12 @@ describe("createTranslatorSync with plurals", () => { expect(tUk("common.tracks", { count: 10 })).toBe("10 треків"); }); + it("translates correctly in Vietnamese", () => { + const tVi = createTranslatorSync("vi"); + expect(tVi("common.sidebar.library")).toBe("Thư viện"); + expect(tVi("common.tracks", { count: 3 })).toBe("3 bài hát"); + }); + it("falls back to English when key is missing in target locale", () => { const tRu = createTranslatorSync("ru"); expect(tRu("common.app.name")).toBe("Liner");