diff --git a/i18n/locales/ar-EG.json b/i18n/locales/ar-EG.json
index 18682843b5..b072fd4842 100644
--- a/i18n/locales/ar-EG.json
+++ b/i18n/locales/ar-EG.json
@@ -82,7 +82,6 @@
"cancel": "إلغاء",
"save": "حفظ",
"edit": "تعديل",
- "error": "خطأ",
"view_on": {
"gitlab": "عرض على GitLab",
"bitbucket": "عرض على Bitbucket",
@@ -113,7 +112,9 @@
"message": "انضم إليّ على npmx",
"share_button": "دعوة صديق",
"compose_text": "جرّب npmx، المتصفح السريع لحزم npm!"
- }
+ },
+ "likes_error": "تعذّر تحميل الحزم المُعجَب بها.",
+ "likes_empty": "لا توجد حزم مُعجَب بها بعد."
},
"package": {
"size_increase": {
diff --git a/i18n/locales/ar.json b/i18n/locales/ar.json
index 519b623f7e..3e847eae31 100644
--- a/i18n/locales/ar.json
+++ b/i18n/locales/ar.json
@@ -155,7 +155,9 @@
}
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "تعذر تحميل الحزم المفضلة.",
+ "likes_empty": "لا توجد حزم مفضلة بعد."
},
"package": {
"not_found": "لم يتم العثور على الحزمة",
diff --git a/i18n/locales/az-AZ.json b/i18n/locales/az-AZ.json
index 23805f4f0e..26e4befbda 100644
--- a/i18n/locales/az-AZ.json
+++ b/i18n/locales/az-AZ.json
@@ -193,7 +193,6 @@
"cancel": "Ləğv et",
"save": "Saxla",
"edit": "Redaktə et",
- "error": "Xəta",
"view_on": {
"npm": "npm-də bax",
"github": "GitHub-da bax"
@@ -214,7 +213,9 @@
"message": "Deyəsən onlar hələ npmx istifadə etmirlər. Onlara bu barədə demək istəyirsiniz?",
"share_button": "Bluesky-da paylaş",
"compose_text": "Salam {'@'}{handle}! npmx.dev-i yoxlamısan? Bu, npm reyestri üçün sürətli, müasir və açıq mənbəli brauzerdir.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Bəyənilən paketlər yüklənə bilmədi.",
+ "likes_empty": "Hələ bəyənilən paket yoxdur."
},
"package": {
"not_found": "Paket Tapılmadı",
diff --git a/i18n/locales/bg-BG.json b/i18n/locales/bg-BG.json
index c2d1d1701f..a074d30a0c 100644
--- a/i18n/locales/bg-BG.json
+++ b/i18n/locales/bg-BG.json
@@ -156,7 +156,6 @@
"cancel": "Отказ",
"save": "Запазване",
"edit": "Редактиране",
- "error": "Грешка",
"view_on": {
"npm": "преглед в npm",
"github": "Преглед в GitHub"
@@ -177,7 +176,9 @@
"message": "Изглежда, че все още не използват npmx. Искате ли да им кажете за него?",
"share_button": "Споделете в Bluesky",
"compose_text": "Здравей {'@'}{handle}! Проверил ли си npmx.dev? Това е браузър за npm регистъра - бърз, модерен и с отворен код.\\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Неуспешно зареждане на харесани пакети.",
+ "likes_empty": "Все още няма харесани пакети."
},
"package": {
"not_found": "Пакетът не е намерен",
diff --git a/i18n/locales/bn-IN.json b/i18n/locales/bn-IN.json
index da2e2dccd2..950f774f7e 100644
--- a/i18n/locales/bn-IN.json
+++ b/i18n/locales/bn-IN.json
@@ -13,11 +13,11 @@
"trademark_disclaimer": "npm, npm, Inc. এর একটি নিবন্ধিত ট্রেডমার্ক। এই সাইটটি npm, Inc. এর সাথে সংযুক্ত নয়।",
"footer": {
"about": "আমাদের সম্পর্কে",
+ "blog": "ব্লগ",
"docs": "ডকুমেন্টেশন",
"source": "সোর্স",
"social": "সোশ্যাল",
"chat": "চ্যাট",
- "blog": "ব্লগ",
"builders_chat": "নির্মাতাদের চ্যাট",
"keyboard_shortcuts": "কীবোর্ড শর্টকাটস",
"brand": "ব্র্যান্ড",
@@ -331,7 +331,6 @@
"cancel": "বাতিল করুন",
"save": "সংরক্ষণ করুন",
"edit": "সম্পাদনা করুন",
- "error": "ত্রুটি",
"view_on": {
"npm": "npm এ দেখুন",
"github": "GitHub এ দেখুন",
@@ -359,6 +358,8 @@
"website": "ওয়েবসাইট",
"website_placeholder": "https://example.com",
"likes": "পছন্দ",
+ "likes_error": "পছন্দের প্যাকেজগুলি লোড করা যায়নি।",
+ "likes_empty": "এখনও কোনো পছন্দের প্যাকেজ নেই।",
"seo_title": "{handle} - npmx",
"seo_description": "{handle} দ্বারা npmx প্রোফাইল",
"not_found": "প্রোফাইল পাওয়া যায়নি",
@@ -367,6 +368,19 @@
"message": "তারা এখনও npmx ব্যবহার করছে বলে মনে হচ্ছে না। এটা সম্পর্কে তাদের বলতে চান?",
"share_button": "Bluesky এ শেয়ার করুন",
"compose_text": "আরে {'@'}{handle}! আপনি কি এখনও npmx.dev চেক আউট করেছেন? এটি npm রেজিস্ট্রির জন্য একটি ব্রাউজার যা দ্রুত, আধুনিক এবং ওপেন সোর্স।\nhttps://npmx.dev"
+ },
+ "linked_accounts": {
+ "status": {
+ "verified": "যাচাইকৃত",
+ "unverified": "যাচাইকৃত নয়",
+ "stale": "পুরানো",
+ "failed": "ব্যর্থ"
+ },
+ "legend_info_title": "ব্যাজগুলোর অর্থ",
+ "legend_verified": "দাবিটি যাচাই করা হয়েছে এবং অ্যাকাউন্টটি নিশ্চিত করা হয়েছে।",
+ "legend_unverified": "আমরা দাবিটি নিশ্চিত করতে পারিনি — অ্যাকাউন্টটি পুনরায় যাচাই করার চেষ্টা করুন।",
+ "legend_stale": "সর্বশেষ যাচাইটি পুরানো; অবস্থা আপডেট করতে পুনরায় যাচাই করুন।",
+ "legend_failed": "যাচাই ব্যর্থ হয়েছে (বিস্তারিত দেখুন)। অ্যাকাউন্টে \"পুনরায় যাচাই করুন\" ক্লিক করে পুনরায় পরীক্ষা করার চেষ্টা করতে পারেন।"
}
},
"package": {
@@ -462,10 +476,10 @@
"top_rank_link_label": "পছন্দ লিডারবোর্ড দেখুন. এই প্যাকেজটি #{rank} র্যাঙ্ক করা হয়েছে."
},
"docs": {
- "not_available": "ডকুমেন্টেশন উপলব্ধ নেই",
- "not_available_detail": "আমরা এই ভার্সনের জন্য ডকুমেন্টেশন তৈরি করতে পারিনি।",
"contents": "বিষয়বস্তু",
"default_not_available": "এই ভার্সনের জন্য ডকুমেন্টেশন উপলব্ধ নয়।",
+ "not_available": "ডকুমেন্টেশন উপলব্ধ নেই",
+ "not_available_detail": "আমরা এই ভার্সনের জন্য ডকুমেন্টেশন তৈরি করতে পারিনি।",
"page_title": "API ডকুমেন্টেশন - npmx",
"page_title_name": "{name} ডকুমেন্টেশন - npmx",
"page_title_version": "{name} ডকুমেন্টেশন - npmx",
@@ -476,9 +490,9 @@
"title": "শুরু করুন",
"pm_label": "প্যাকেজ ম্যানেজার",
"copy_command": "ইনস্টল কমান্ড কপি করুন",
- "view_types": "{package} দেখুন",
"copy_dev_command": "ডেভ ইনস্টল কমান্ড কপি করুন",
- "dev_dependency_hint": "সাধারণত ডেভ ডিপেনডেন্সি হিসেবে ইনস্টল করা হয়"
+ "dev_dependency_hint": "সাধারণত ডেভ ডিপেনডেন্সি হিসেবে ইনস্টল করা হয়",
+ "view_types": "{package} দেখুন"
},
"create": {
"title": "নতুন প্রকল্প তৈরি করুন",
@@ -492,6 +506,7 @@
"readme": {
"title": "রিডমি",
"no_readme": "README উপলব্ধ নেই।",
+ "toc_title": "আউটলাইন",
"callout": {
"note": "দ্রষ্টব্য",
"tip": "টিপ",
@@ -499,7 +514,6 @@
"warning": "সতর্কতা",
"caution": "সতর্কতা"
},
- "toc_title": "আউটলাইন",
"copy_as_markdown": "মার্কডাউন হিসাবে README কপি করুন",
"error_loading": "README বিশদ লোড করতে ব্যর্থ হয়েছে৷"
},
@@ -528,10 +542,10 @@
"compatibility": "সামঞ্জস্য",
"card": {
"publisher": "প্রকাশক",
+ "published": "প্রকাশিত",
"weekly_downloads": "সাপ্তাহিক ডাউনলোড",
"keywords": "কীওয়ার্ড",
"license": "লাইসেন্স",
- "published": "প্রকাশিত",
"select": "প্যাকেজ নির্বাচন করুন",
"select_maximum": "সর্বোচ্চ {count}টি প্যাকেজ নির্বাচন করা যাবে"
},
@@ -548,10 +562,6 @@
"all_covered": "সব ভার্সন উপরের ট্যাগ দ্বারা আবৃত",
"deprecated_title": "{version} (নিষ্ক্রিয়)",
"view_all": "{count}টি ভার্সন দেখুন | সব {count}টি ভার্সন দেখুন",
- "copy_alt": {
- "per_version_analysis": "{version} ভার্সনটি {downloads} বার ডাউনলোড করা হয়েছে",
- "general_description": "{package_name} প্যাকেজের {versions_count}টি {semver_grouping_mode} ভার্সনের প্রতি-ভার্সন ডাউনলোড দেখানো বার চার্ট, {first_version} ভার্সন থেকে {last_version} ভার্সন পর্যন্ত, {date_range_label} সময়সীমায়। সবচেয়ে বেশি ডাউনলোড হওয়া ভার্সন হলো {max_downloaded_version}, যার ডাউনলোড সংখ্যা {max_version_downloads}। {per_version_analysis}। {watermark}।"
- },
"view_all_versions": "সব ভার্সন দেখুন",
"distribution_title": "Semver গ্রুপ",
"distribution_modal_title": "ভার্সনসমূহ",
@@ -579,10 +589,43 @@
"license_change_warning": "আগের ভার্সনের পর থেকে লাইসেন্স পরিবর্তিত হয়েছে।",
"license_change_record": "এই প্যাকেজের লাইসেন্স \"{from}\" থেকে \"{to}\" তে পরিবর্তিত হয়েছে।",
"no_matches": "এই পরিসরের সাথে কোনো ভার্সন মেলেনি",
+ "copy_alt": {
+ "per_version_analysis": "{version} ভার্সনটি {downloads} বার ডাউনলোড করা হয়েছে",
+ "general_description": "{package_name} প্যাকেজের {versions_count}টি {semver_grouping_mode} ভার্সনের প্রতি-ভার্সন ডাউনলোড দেখানো বার চার্ট, {first_version} ভার্সন থেকে {last_version} ভার্সন পর্যন্ত, {date_range_label} সময়সীমায়। সবচেয়ে বেশি ডাউনলোড হওয়া ভার্সন হলো {max_downloaded_version}, যার ডাউনলোড সংখ্যা {max_version_downloads}। {per_version_analysis}। {watermark}।"
+ },
"page_title": "ভার্সন ইতিহাস",
"current_tags": "বর্তমান ট্যাগসমূহ",
"no_match_filter": "{filter} এর সাথে কোনো ভার্সন মেলেনি"
},
+ "timeline": {
+ "load_more": "আরো লোড করুন",
+ "load_error": "টাইমলাইন লোড করা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।",
+ "size_increase": "ইনস্টল সাইজ {percent}% বৃদ্ধি পেয়েছে ({size})",
+ "size_decrease": "ইনস্টল সাইজ {percent}% কমেছে ({size})",
+ "dep_increase": "{count}টি ডিপেনডেন্সি যোগ হয়েছে",
+ "dep_decrease": "{count}টি ডিপেনডেন্সি সরানো হয়েছে",
+ "license_change": "লাইসেন্স {from} থেকে {to} এ পরিবর্তিত হয়েছে",
+ "esm_added": "মডিউল টাইপ ESM এ পরিবর্তিত হয়েছে",
+ "esm_removed": "মডিউল টাইপ ESM থেকে CJS এ পরিবর্তিত হয়েছে",
+ "types_added": "TypeScript টাইপ যোগ করা হয়েছে",
+ "types_removed": "TypeScript টাইপ সরানো হয়েছে",
+ "trusted_publisher_added": "বিশ্বস্ত প্রকাশনা সক্রিয় করা হয়েছে",
+ "trusted_publisher_removed": "বিশ্বস্ত প্রকাশনা সরানো হয়েছে",
+ "provenance_added": "প্রোভেন্যান্স সক্রিয় করা হয়েছে",
+ "provenance_removed": "প্রোভেন্যান্স সরানো হয়েছে",
+ "chart": {
+ "tab_aria_label": "মেট্রিক নির্বাচন",
+ "base_scale": "y-অক্ষ শূন্য থেকে শুরু করুন",
+ "zoom": "জুম",
+ "reset_minimap": "মিনিম্যাপ রিসেট করুন",
+ "ordered_versions": "শুধুমাত্র স্থিতিশীল",
+ "copy_alt": {
+ "key_changes": "মূল পরিবর্তনসমূহ: {version_events}।",
+ "version_events": "ভার্সন {version}: {events}",
+ "general_description": "{package} প্যাকেজের {metric} প্রদর্শনকারী লাইন চার্ট, {first} ভার্সন থেকে {last} ভার্সন পর্যন্ত। {first} ভার্সনে {metric} এর মান {first_value}, এবং {last} ভার্সনে {last_value} ({overall_progress_percentage}% সামগ্রিক পরিবর্তন)। {key_changes} {watermark}।"
+ }
+ }
+ },
"dependencies": {
"title": "নির্ভরতা ({count})",
"list_label": "প্যাকেজ নির্ভরতা",
@@ -621,6 +664,15 @@
"maintainer_template": "{avatar} {char126}{name}"
},
"trends": {
+ "chart_assistive_text": {
+ "keyboard_navigation_horizontal": "ডেটা পয়েন্টগুলোর মধ্যে যেতে বাম এবং ডান অ্যারো কী ব্যবহার করুন।",
+ "keyboard_navigation_vertical": "ডেটা পয়েন্টগুলোর মধ্যে যেতে উপরে এবং নিচের অ্যারো কী ব্যবহার করুন।",
+ "table_available": "এই চার্টের জন্য একটি ডেটা টেবিল নিচে উপলব্ধ রয়েছে।",
+ "table_caption": "চার্ট ডেটা টেবিল"
+ },
+ "chart_view_toggle": "ভিউ পরিবর্তন করুন",
+ "chart_view_combined": "সমন্বিত ভিউ",
+ "chart_view_split": "বিভক্ত ভিউ",
"granularity": "বিস্তৃতি",
"granularity_daily": "দৈনিক",
"granularity_weekly": "সাপ্তাহিক",
@@ -633,36 +685,6 @@
"date_range_multiline": "{start}\nথেকে {end}",
"download_file": "{fileType} ডাউনলোড করুন",
"toggle_annotator": "অ্যানোটেটর টগল করুন",
- "items": {
- "downloads": "ডাউনলোড",
- "likes": "পছন্দ",
- "contributors": "অবদানকারী"
- },
- "copy_alt": {
- "trend_none": "মূলত সমতল",
- "trend_strong": "শক্তিশালী",
- "trend_weak": "দুর্বল",
- "trend_undefined": "অনির্ধারিত (অপর্যাপ্ত ডেটা)",
- "button_label": "বিকল্প টেক্সট কপি করুন",
- "watermark": "নিচে একটি ওয়াটারমার্কে লেখা আছে \"./npmx a fast, modern browser for the npm registry\"",
- "analysis": "{package_name} এর শুরু {start_value} থেকে এবং শেষ {end_value} এ, যা প্রতি সময়সীমায় {downloads_slope} ডাউনলোডের ঢালসহ একটি {trend} প্রবণতা দেখায়",
- "estimation": "চূড়ান্ত মানটি বর্তমান সময়সীমার আংশিক ডেটার উপর ভিত্তি করে একটি অনুমান।",
- "estimations": "চূড়ান্ত মানগুলো বর্তমান সময়সীমার আংশিক ডেটার উপর ভিত্তি করে অনুমান করা হয়েছে।",
- "compare": "{packages} এর জন্য প্যাকেজ ডাউনলোড তুলনামূলক লাইন চার্ট।",
- "single_package": "{package} প্যাকেজের ডাউনলোড লাইন চার্ট।",
- "general_description": "Y অক্ষ ডাউনলোডের সংখ্যা নির্দেশ করে। X অক্ষ {start_date} থেকে {end_date} পর্যন্ত তারিখের পরিসর নির্দেশ করে, যেখানে সময়কাল হলো {granularity}। {estimation_notice} {packages_analysis}। {watermark}।",
- "facet_bar_general_description": "{packages} এর জন্য অনুভূমিক বার চার্ট, যেখানে {facet} ({description}) তুলনা করা হয়েছে। {facet_analysis} {watermark}।",
- "facet_bar_analysis": "{package_name} এর মান {value}।"
- },
- "chart_assistive_text": {
- "keyboard_navigation_horizontal": "ডেটা পয়েন্টগুলোর মধ্যে যেতে বাম এবং ডান অ্যারো কী ব্যবহার করুন।",
- "keyboard_navigation_vertical": "ডেটা পয়েন্টগুলোর মধ্যে যেতে উপরে এবং নিচের অ্যারো কী ব্যবহার করুন।",
- "table_available": "এই চার্টের জন্য একটি ডেটা টেবিল নিচে উপলব্ধ রয়েছে।",
- "table_caption": "চার্ট ডেটা টেবিল"
- },
- "chart_view_toggle": "ভিউ পরিবর্তন করুন",
- "chart_view_combined": "সমন্বিত ভিউ",
- "chart_view_split": "বিভক্ত ভিউ",
"toggle_stack_mode": "স্ট্যাক মোড পরিবর্তন করুন",
"open_options": "অপশন খুলুন",
"close_options": "অপশন বন্ধ করুন",
@@ -672,6 +694,11 @@
"facet": "বিভাগ",
"title": "প্রবণতা",
"contributors_skip": "Contributors-এ দেখানো হয়নি (GitHub রিপোজিটরি নেই):",
+ "items": {
+ "downloads": "ডাউনলোড",
+ "likes": "পছন্দ",
+ "contributors": "অবদানকারী"
+ },
"data_correction": "ডেটা সংশোধন",
"average_window": "গড় উইন্ডো",
"smoothing": "মসৃণকরণ",
@@ -683,7 +710,23 @@
"known_anomalies_range_named": "{packageName}: {start} থেকে {end}",
"known_anomalies_none": "এই প্যাকেজের জন্য কোনো পরিচিত অস্বাভাবিকতা নেই। | এই প্যাকেজগুলোর জন্য কোনো পরিচিত অস্বাভাবিকতা নেই।",
"known_anomalies_contribute": "অস্বাভাবিকতার ডেটা যোগ করুন",
- "apply_correction": "সংশোধন প্রয়োগ করুন"
+ "apply_correction": "সংশোধন প্রয়োগ করুন",
+ "copy_alt": {
+ "trend_none": "মূলত সমতল",
+ "trend_strong": "শক্তিশালী",
+ "trend_weak": "দুর্বল",
+ "trend_undefined": "অনির্ধারিত (অপর্যাপ্ত ডেটা)",
+ "button_label": "বিকল্প টেক্সট কপি করুন",
+ "watermark": "নিচে একটি ওয়াটারমার্কে লেখা আছে \"./npmx a fast, modern browser for the npm registry\"",
+ "analysis": "{package_name} এর শুরু {start_value} থেকে এবং শেষ {end_value} এ, যা প্রতি সময়সীমায় {downloads_slope} ডাউনলোডের ঢালসহ একটি {trend} প্রবণতা দেখায়",
+ "estimation": "চূড়ান্ত মানটি বর্তমান সময়সীমার আংশিক ডেটার উপর ভিত্তি করে একটি অনুমান।",
+ "estimations": "চূড়ান্ত মানগুলো বর্তমান সময়সীমার আংশিক ডেটার উপর ভিত্তি করে অনুমান করা হয়েছে।",
+ "compare": "{packages} এর জন্য প্যাকেজ ডাউনলোড তুলনামূলক লাইন চার্ট।",
+ "single_package": "{package} প্যাকেজের ডাউনলোড লাইন চার্ট।",
+ "general_description": "Y অক্ষ ডাউনলোডের সংখ্যা নির্দেশ করে। X অক্ষ {start_date} থেকে {end_date} পর্যন্ত তারিখের পরিসর নির্দেশ করে, যেখানে সময়কাল হলো {granularity}। {estimation_notice} {packages_analysis}। {watermark}।",
+ "facet_bar_general_description": "{packages} এর জন্য অনুভূমিক বার চার্ট, যেখানে {facet} ({description}) তুলনা করা হয়েছে। {facet_analysis} {watermark}।",
+ "facet_bar_analysis": "{package_name} এর মান {value}।"
+ }
},
"downloads": {
"title": "সাপ্তাহিক ডাউনলোড",
@@ -705,11 +748,11 @@
"esm": "ES Modules সমর্থন আছে",
"cjs": "CommonJS সমর্থন আছে",
"no_esm": "ES Modules সমর্থন নেই",
+ "wasm": "WebAssembly রয়েছে",
"types_label": "টাইপ",
"types_included": "টাইপ অন্তর্ভুক্ত",
"types_available": "টাইপ {package} এর মাধ্যমে উপলব্ধ",
- "no_types": "TypeScript টাইপ নেই",
- "wasm": "WebAssembly রয়েছে"
+ "no_types": "TypeScript টাইপ নেই"
},
"license": {
"view_spdx": "SPDX এ লাইসেন্স টেক্সট দেখুন",
@@ -771,9 +814,9 @@
},
"sort": {
"downloads": "সবচেয়ে বেশি ডাউনলোডকৃত",
+ "published": "সম্প্রতি প্রকাশিত",
"name_asc": "নাম (A-Z)",
- "name_desc": "নাম (Z-A)",
- "published": "সম্প্রতি প্রকাশিত"
+ "name_desc": "নাম (Z-A)"
},
"size": {
"b": "{size} B",
@@ -783,35 +826,16 @@
"download": {
"button": "ডাউনলোড",
"tarball": ".tar.gz হিসেবে টারবল ডাউনলোড করুন"
- },
- "timeline": {
- "load_more": "আরো লোড করুন",
- "load_error": "টাইমলাইন লোড করা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।",
- "size_increase": "ইনস্টল সাইজ {percent}% বৃদ্ধি পেয়েছে ({size})",
- "size_decrease": "ইনস্টল সাইজ {percent}% কমেছে ({size})",
- "dep_increase": "{count}টি ডিপেনডেন্সি যোগ হয়েছে",
- "dep_decrease": "{count}টি ডিপেনডেন্সি সরানো হয়েছে",
- "license_change": "লাইসেন্স {from} থেকে {to} এ পরিবর্তিত হয়েছে",
- "esm_added": "মডিউল টাইপ ESM এ পরিবর্তিত হয়েছে",
- "esm_removed": "মডিউল টাইপ ESM থেকে CJS এ পরিবর্তিত হয়েছে",
- "types_added": "TypeScript টাইপ যোগ করা হয়েছে",
- "types_removed": "TypeScript টাইপ সরানো হয়েছে",
- "trusted_publisher_added": "বিশ্বস্ত প্রকাশনা সক্রিয় করা হয়েছে",
- "trusted_publisher_removed": "বিশ্বস্ত প্রকাশনা সরানো হয়েছে",
- "provenance_added": "প্রোভেন্যান্স সক্রিয় করা হয়েছে",
- "provenance_removed": "প্রোভেন্যান্স সরানো হয়েছে",
- "chart": {
- "tab_aria_label": "মেট্রিক নির্বাচন",
- "base_scale": "y-অক্ষ শূন্য থেকে শুরু করুন",
- "zoom": "জুম",
- "reset_minimap": "মিনিম্যাপ রিসেট করুন",
- "ordered_versions": "শুধুমাত্র স্থিতিশীল",
- "copy_alt": {
- "key_changes": "মূল পরিবর্তনসমূহ: {version_events}।",
- "version_events": "ভার্সন {version}: {events}",
- "general_description": "{package} প্যাকেজের {metric} প্রদর্শনকারী লাইন চার্ট, {first} ভার্সন থেকে {last} ভার্সন পর্যন্ত। {first} ভার্সনে {metric} এর মান {first_value}, এবং {last} ভার্সনে {last_value} ({overall_progress_percentage}% সামগ্রিক পরিবর্তন)। {key_changes} {watermark}।"
- }
- }
+ }
+ },
+ "leaderboard": {
+ "likes": {
+ "title": "লাইক লিডারবোর্ড",
+ "description": "বর্তমানে npmx-এর সবচেয়ে বেশি লাইক পাওয়া ১০টি প্যাকেজ।",
+ "rank": "র্যাঙ্ক",
+ "likes": "লাইক",
+ "unavailable_title": "এখনও কোনো লাইক লিডারবোর্ড নেই",
+ "unavailable_description": "এই মুহূর্তে দেখানোর মতো কোনো লাইক লিডারবোর্ড নেই।"
}
},
"connector": {
@@ -849,7 +873,9 @@
"otp_placeholder": "OTP কোড দিন...",
"otp_label": "একবার ব্যবহারের পাসওয়ার্ড",
"retry_otp": "OTP দিয়ে আবার চেষ্টা করুন",
+ "retry_web_auth": "ওয়েব অথ দিয়ে আবার চেষ্টা করুন",
"retrying": "আবার চেষ্টা করা হচ্ছে...",
+ "open_web_auth": "ওয়েব অথ লিংক খুলুন",
"approve_operation": "অপারেশন অনুমোদন করুন",
"remove_operation": "অপারেশন সরান",
"approve_all": "সব অনুমোদন করুন",
@@ -857,9 +883,7 @@
"executing": "চালানো হচ্ছে...",
"log": "লগ",
"log_label": "সম্পূর্ণ অপারেশন লগ",
- "remove_from_log": "লগ থেকে সরান",
- "retry_web_auth": "ওয়েব অথ দিয়ে আবার চেষ্টা করুন",
- "open_web_auth": "ওয়েব অথ লিংক খুলুন"
+ "remove_from_log": "লগ থেকে সরান"
}
},
"org": {
@@ -973,6 +997,7 @@
"invalid_name": "অবৈধ প্যাকেজ নাম:",
"available": "এই নামটি উপলব্ধ!",
"taken": "এই নামটি ইতিমধ্যে নেওয়া হয়েছে।",
+ "missing_permission": "আপনার কাছে {'@'}{scope} স্কোপে প্যাকেজ যোগ করার অনুমতি নেই।",
"similar_warning": "সমান প্যাকেজ রয়েছে - npm এই নামটি প্রত্যাখ্যান করতে পারে:",
"related": "সংশ্লিষ্ট প্যাকেজ:",
"scope_warning_title": "পরিবর্তে স্কোপড প্যাকেজ ব্যবহার বিবেচনা করুন",
@@ -985,8 +1010,7 @@
"publishing": "প্রকাশ করা হচ্ছে...",
"checking": "প্রাপ্যতা যাচাই করা হচ্ছে...",
"failed_to_check": "নামের প্রাপ্যতা যাচাই করতে ব্যর্থ",
- "failed_to_claim": "প্যাকেজ দাবি করতে ব্যর্থ",
- "missing_permission": "আপনার কাছে {'@'}{scope} স্কোপে প্যাকেজ যোগ করার অনুমতি নেই।"
+ "failed_to_claim": "প্যাকেজ দাবি করতে ব্যর্থ"
}
},
"code": {
@@ -995,8 +1019,12 @@
"lines": "{count}টি লাইন",
"toggle_tree": "ফাইল ট্রি টগল করুন",
"close_tree": "ফাইল ট্রি বন্ধ করুন",
+ "copy_content": "ফাইল কন্টেন্ট কপি করুন",
"copy_link": "লিঙ্ক কপি করুন",
"view_raw": "রও ফাইল দেখুন",
+ "toggle_container": "কোড কন্টেইনার প্রস্থ টগল করুন",
+ "open_raw_file": "রও ফাইল খুলুন",
+ "open_path_dropdown": "পাথ সেগমেন্টস ড্রপডাউন খুলুন",
"file_too_large": "প্রিভিউ-র জন্য ফাইল খুব বড়",
"file_size_warning": "{size} সিনট্যাক্স হাইলাইটিং-এর জন্য 500KB সীমার চেয়ে বেশি",
"failed_to_load": "ফাইল লোড করতে ব্যর্থ",
@@ -1015,10 +1043,6 @@
"code": "কোড"
},
"file_path": "ফাইল পাথ",
- "copy_content": "ফাইল কন্টেন্ট কপি করুন",
- "toggle_container": "কোড কন্টেইনার প্রস্থ টগল করুন",
- "open_raw_file": "রও ফাইল খুলুন",
- "open_path_dropdown": "পাথ সেগমেন্টস ড্রপডাউন খুলুন",
"binary_file": "বাইনারি ফাইল",
"binary_rendering_warning": "ফাইল টাইপ \"{contentType}\" প্রিভিউয়ের জন্য সমর্থিত নয়."
},
@@ -1082,6 +1106,8 @@
"secure": "সতর্কতা ছাড়া",
"insecure": "সতর্কতা সহ"
},
+ "view_selected": "নির্বাচিত দেখুন",
+ "clear_selected_label": "নির্বাচিত সাফ করুন",
"sort": {
"label": "প্যাকেজগুলি সাজান",
"toggle_direction": "ক্রম দিক টগল করুন",
@@ -1092,8 +1118,8 @@
"downloads_day": "ডাউনলোড/দিন",
"downloads_month": "ডাউনলোড/মাস",
"downloads_year": "ডাউনলোড/বছর",
- "name": "নাম",
- "published": "সর্বশেষ প্রকাশিত"
+ "published": "সর্বশেষ প্রকাশিত",
+ "name": "নাম"
},
"columns": {
"title": "কলাম",
@@ -1104,10 +1130,10 @@
"version": "ভার্সন",
"description": "বর্ণনা",
"downloads": "ডাউনলোড/সপ্তাহ",
+ "published": "সর্বশেষ প্রকাশিত",
"maintainers": "রক্ষণাবেক্ষণকারী",
"keywords": "কীওয়ার্ড",
"security": "নিরাপত্তা",
- "published": "সর্বশেষ প্রকাশিত",
"selection": "প্যাকেজ নির্বাচন করুন"
},
"view_mode": {
@@ -1135,9 +1161,7 @@
"security_warning": "নিরাপত্তা সতর্কতা",
"secure": "নিরাপদ",
"no_packages": "কোনো প্যাকেজ পাওয়া যায়নি"
- },
- "view_selected": "নির্বাচিত দেখুন",
- "clear_selected_label": "নির্বাচিত সাফ করুন"
+ }
},
"about": {
"title": "আমাদের সম্পর্কে",
@@ -1270,11 +1294,11 @@
"section_packages": "প্যাকেজ",
"section_facets": "ফ্যাসেট",
"section_comparison": "তুলনা",
+ "copy_as_markdown": "মার্কডাউন হিসেবে কপি করুন",
"loading": "প্যাকেজ ডেটা লোড হচ্ছে...",
"error": "প্যাকেজ ডেটা লোড করতে ব্যর্থ। অনুগ্রহ করে আবার চেষ্টা করুন।",
"empty_title": "তুলনা করার জন্য প্যাকেজ নির্বাচন করুন",
"empty_description": "তাদের মেট্রিক্স পাশাপাশি তুলনা দেখতে উপরে কমপক্ষে ২টি প্যাকেজ অনুসন্ধান করে যোগ করুন।",
- "copy_as_markdown": "মার্কডাউন হিসেবে কপি করুন",
"table_view": "টেবিল",
"charts_view": "চার্ট",
"no_chartable_data": "নির্বাচিত ফ্যাসেটগুলোর জন্য কোনো চার্টযোগ্য ডেটা উপলব্ধ নেই।",
@@ -1290,6 +1314,17 @@
"packages_selected": "{count}/{max}টি প্যাকেজ নির্বাচিত।",
"add_hint": "তুলনা করার জন্য কমপক্ষে ২টি প্যাকেজ যোগ করুন।"
},
+ "scatter_chart": {
+ "title": "{x} বনাম {y} তুলনা করুন",
+ "freshness_score": "নতুনত্ব স্কোর",
+ "copy_alt": {
+ "analysis": "{package}: {x_name} ({x_value}) এবং {y_name} ({y_value})",
+ "description": "{packages}টি প্যাকেজের জন্য {x_name} বনাম {y_name} এর স্ক্যাটার প্লট চার্ট। {analysis}. {watermark}"
+ },
+ "filename": "{x}-vs-{y}-scatter-chart",
+ "x_axis": "X-অক্ষ ↦",
+ "y_axis": "Y-অক্ষ ↥"
+ },
"no_dependency": {
"label": "(কোনো নির্ভরতা নেই)",
"typeahead_title": "জেমস কী করতেন?",
@@ -1302,9 +1337,14 @@
"facets": {
"all": "সব",
"none": "কিছু না",
+ "select_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন করুন",
+ "deselect_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন বাতিল করুন",
+ "selected_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন করা হয়েছে",
+ "deselected_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন বাতিল করা হয়েছে",
"coming_soon": "শীঘ্রই আসছে",
"select_all": "সব ফ্যাসেট নির্বাচন করুন",
"deselect_all": "সব ফ্যাসেট অনির্বাচিত করুন",
+ "binary_only_tooltip": "এই প্যাকেজটি বাইনারি সরবরাহ করে এবং কোনো এক্সপোর্ট নেই",
"categories": {
"performance": "কর্মক্ষমতা",
"health": "স্বাস্থ্য",
@@ -1390,39 +1430,7 @@
},
"trends": {
"title": "প্রবণতা তুলনা করুন"
- },
- "select_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন করুন",
- "deselect_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন বাতিল করুন",
- "selected_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন করা হয়েছে",
- "deselected_all_category_facets": "{category}-এর সব ফ্যাসেট নির্বাচন বাতিল করা হয়েছে",
- "binary_only_tooltip": "এই প্যাকেজটি বাইনারি সরবরাহ করে এবং কোনো এক্সপোর্ট নেই"
- },
- "version_invalid_url_format": {
- "hint": "অবৈধ তুলনা URL। এই ফরম্যাট ব্যবহার করুন: {0}",
- "from_version": "থেকে",
- "to_version": "পর্যন্ত"
- },
- "file_filter_option": {
- "all": "সব ({count})",
- "added": "যোগ করা হয়েছে ({count})",
- "removed": "মুছে ফেলা হয়েছে ({count})",
- "modified": "পরিবর্তিত ({count})"
- },
- "filter": {
- "added": "যোগ করা",
- "removed": "মুছে ফেলা",
- "modified": "পরিবর্তিত"
- },
- "scatter_chart": {
- "title": "{x} বনাম {y} তুলনা করুন",
- "freshness_score": "নতুনত্ব স্কোর",
- "copy_alt": {
- "analysis": "{package}: {x_name} ({x_value}) এবং {y_name} ({y_value})",
- "description": "{packages}টি প্যাকেজের জন্য {x_name} বনাম {y_name} এর স্ক্যাটার প্লট চার্ট। {analysis}. {watermark}"
- },
- "filename": "{x}-vs-{y}-scatter-chart",
- "x_axis": "X-অক্ষ ↦",
- "y_axis": "Y-অক্ষ ↥"
+ }
},
"file_changes": "ফাইল পরিবর্তন",
"files_count": "{count}টি ফাইল | {count}টি ফাইল",
@@ -1434,6 +1442,11 @@
"comparing_versions_label": "সংস্করণ তুলনা করা হচ্ছে...",
"version_back_to_package": "প্যাকেজে ফিরে যান",
"version_error_message": "সংস্করণ তুলনা ব্যর্থ হয়েছে।",
+ "version_invalid_url_format": {
+ "hint": "অবৈধ তুলনা URL। এই ফরম্যাট ব্যবহার করুন: {0}",
+ "from_version": "থেকে",
+ "to_version": "পর্যন্ত"
+ },
"version_selector_title": "সংস্করণের সাথে তুলনা করুন",
"summary": "সারাংশ",
"deps_count": "{count}টি নির্ভরতা | {count}টি নির্ভরতা",
@@ -1442,10 +1455,21 @@
"peer_dependencies": "পিয়ার নির্ভরতা",
"optional_dependencies": "ঐচ্ছিক নির্ভরতা",
"no_dependency_changes": "কোনো নির্ভরতা পরিবর্তন নেই",
+ "file_filter_option": {
+ "all": "সব ({count})",
+ "added": "যোগ করা হয়েছে ({count})",
+ "removed": "মুছে ফেলা হয়েছে ({count})",
+ "modified": "পরিবর্তিত ({count})"
+ },
"search_files_placeholder": "ফাইল খুঁজুন...",
"no_files_all": "কোনো ফাইল নেই",
"no_files_search": "\"{query}\" এর সাথে মিল থাকা কোনো ফাইল নেই",
"no_files_filtered": "কোনো {filter} ফাইল নেই",
+ "filter": {
+ "added": "যোগ করা",
+ "removed": "মুছে ফেলা",
+ "modified": "পরিবর্তিত"
+ },
"files_button": "ফাইলসমূহ",
"select_file_prompt": "ডিফ দেখতে সাইডবার থেকে একটি ফাইল নির্বাচন করুন",
"close_files_panel": "ফাইল প্যানেল বন্ধ করুন",
@@ -1463,6 +1487,8 @@
"word_wrap": "লাইন মোড়ানো"
},
"pds": {
+ "title": "npmx.social",
+ "meta_description": "npmx কমিউনিটির জন্য অফিসিয়াল AT Protocol Personal Data Server (PDS)।",
"join": {
"title": "কমিউনিটিতে যোগ দিন",
"description": "আপনি অ্যাটমোসফিয়ারে প্রথম অ্যাকাউন্ট তৈরি করছেন বা বিদ্যমান অ্যাকাউন্ট স্থানান্তর করছেন—আপনি এখানে স্বাগতম। আপনি আপনার বর্তমান অ্যাকাউন্ট হ্যান্ডেল, পোস্ট বা ফলোয়ার হারানো ছাড়াই স্থানান্তর করতে পারেন।",
@@ -1486,11 +1512,12 @@
"empty": "দেখানোর মতো কোনো কমিউনিটি সদস্য নেই।",
"view_profile": "{handle}-এর প্রোফাইল দেখুন",
"new_accounts": "...এছাড়া আরও {count}টি নতুন অ্যাকাউন্ট অ্যাটমোসফিয়ারে যুক্ত হয়েছে"
- },
- "title": "npmx.social",
- "meta_description": "npmx কমিউনিটির জন্য অফিসিয়াল AT Protocol Personal Data Server (PDS)।"
+ }
},
"privacy_policy": {
+ "title": "প্রাইভেসি পলিসি",
+ "last_updated": "সর্বশেষ আপডেট: {date}",
+ "welcome": "{app}-এ স্বাগতম। আমরা আপনার গোপনীয়তা রক্ষায় প্রতিশ্রুতিবদ্ধ। এই নীতিতে আমরা কী ডেটা সংগ্রহ করি, কীভাবে ব্যবহার করি এবং আপনার ডেটা সম্পর্কিত অধিকার ব্যাখ্যা করা হয়েছে।",
"cookies": {
"what_are": {
"title": "কুকি কী?",
@@ -1565,12 +1592,12 @@
"changes": {
"title": "এই নীতির পরিবর্তন",
"p1": "আমরা সময়ে সময়ে এই প্রাইভেসি পলিসি আপডেট করতে পারি। যেকোনো পরিবর্তন এই পাতায় আপডেটেড রিভিশন তারিখসহ প্রকাশ করা হবে।"
- },
- "title": "প্রাইভেসি পলিসি",
- "last_updated": "সর্বশেষ আপডেট: {date}",
- "welcome": "{app}-এ স্বাগতম। আমরা আপনার গোপনীয়তা রক্ষায় প্রতিশ্রুতিবদ্ধ। এই নীতিতে আমরা কী ডেটা সংগ্রহ করি, কীভাবে ব্যবহার করি এবং আপনার ডেটা সম্পর্কিত অধিকার ব্যাখ্যা করা হয়েছে।"
+ }
},
"a11y": {
+ "title": "অ্যাক্সেসিবিলিটি",
+ "footer_title": "a11y",
+ "welcome": "আমরা চাই {app} যত বেশি সম্ভব মানুষের জন্য ব্যবহারযোগ্য হোক।",
"approach": {
"title": "আমাদের দৃষ্টিভঙ্গি",
"p1": "আমরা Web Content Accessibility Guidelines (WCAG) 2.2 অনুসরণ করার চেষ্টা করি এবং ফিচার তৈরি করার সময় এটিকে রেফারেন্স হিসেবে ব্যবহার করি। আমরা কোনো WCAG স্তরের পূর্ণ সম্মতি দাবি করি না—অ্যাক্সেসিবিলিটি একটি চলমান প্রক্রিয়া এবং সবসময় উন্নতির সুযোগ থাকে।",
@@ -1595,19 +1622,9 @@
"title": "প্রতিক্রিয়া",
"p1": "{app}-এ যদি আপনি কোনো অ্যাক্সেসিবিলিটি সমস্যা পান, অনুগ্রহ করে আমাদের {link}-এ ইস্যু খুলে জানান। আমরা এসব রিপোর্ট গুরুত্ব সহকারে নেই এবং সমাধানের সর্বোচ্চ চেষ্টা করি।",
"link": "GitHub রিপোজিটরি"
- },
- "title": "অ্যাক্সেসিবিলিটি",
- "footer_title": "a11y",
- "welcome": "আমরা চাই {app} যত বেশি সম্ভব মানুষের জন্য ব্যবহারযোগ্য হোক।"
+ }
},
"translation_status": {
- "table": {
- "file": "ফাইল",
- "status": "অবস্থা",
- "error": "ফাইল তালিকা লোড করার সময় ত্রুটি হয়েছে।",
- "empty": "কোনো ফাইল পাওয়া যায়নি",
- "file_link": "{file} ({lang}) GitHub-এ সম্পাদনা করুন"
- },
"title": "অনুবাদ অবস্থা",
"generated_at": "উৎপাদনের তারিখ: {date}",
"welcome": "{npmx}-কে বিভিন্ন ভাষায় অনুবাদ করতে সাহায্য করতে আগ্রহী হলে আপনি সঠিক জায়গায় এসেছেন! এই স্বয়ংক্রিয়ভাবে আপডেট হওয়া পেজটি বর্তমানে যেসব কনটেন্টে সাহায্য দরকার তা দেখায়।",
@@ -1621,22 +1638,13 @@
"complete_text": "এই অনুবাদ সম্পূর্ণ হয়েছে, দারুণ কাজ!",
"missing_text": "অনুপস্থিত",
"missing_keys": "কোনো অনুবাদ অনুপস্থিত নেই | অনুপস্থিত অনুবাদ | অনুপস্থিত অনুবাদসমূহ",
- "progress_label": "{locale}-এর জন্য অগ্রগতির অবস্থা"
- },
- "action_bar": {
- "title": "অ্যাকশন বার",
- "selection": "০টি নির্বাচিত | ১টি নির্বাচিত | {count}টি নির্বাচিত",
- "shortcut": "\"{key}\" চাপুন অ্যাকশন ফোকাস করতে",
- "button_close_aria_label": "অ্যাকশন বার বন্ধ করুন"
- },
- "leaderboard": {
- "likes": {
- "title": "লাইক লিডারবোর্ড",
- "description": "বর্তমানে npmx-এর সবচেয়ে বেশি লাইক পাওয়া ১০টি প্যাকেজ।",
- "rank": "র্যাঙ্ক",
- "likes": "লাইক",
- "unavailable_title": "এখনও কোনো লাইক লিডারবোর্ড নেই",
- "unavailable_description": "এই মুহূর্তে দেখানোর মতো কোনো লাইক লিডারবোর্ড নেই।"
+ "progress_label": "{locale}-এর জন্য অগ্রগতির অবস্থা",
+ "table": {
+ "file": "ফাইল",
+ "status": "অবস্থা",
+ "error": "ফাইল তালিকা লোড করার সময় ত্রুটি হয়েছে।",
+ "empty": "কোনো ফাইল পাওয়া যায়নি",
+ "file_link": "{file} ({lang}) GitHub-এ সম্পাদনা করুন"
}
},
"vacations": {
@@ -1673,6 +1681,12 @@
}
}
},
+ "action_bar": {
+ "title": "অ্যাকশন বার",
+ "selection": "০টি নির্বাচিত | ১টি নির্বাচিত | {count}টি নির্বাচিত",
+ "shortcut": "\"{key}\" চাপুন অ্যাকশন ফোকাস করতে",
+ "button_close_aria_label": "অ্যাকশন বার বন্ধ করুন"
+ },
"logo_menu": {
"copy_svg": "SVG হিসেবে লোগো কপি করুন",
"copied": "কপি হয়েছে!",
diff --git a/i18n/locales/cs-CZ.json b/i18n/locales/cs-CZ.json
index 7fefeb1a20..94c73276d4 100644
--- a/i18n/locales/cs-CZ.json
+++ b/i18n/locales/cs-CZ.json
@@ -323,7 +323,6 @@
"cancel": "Zrušit",
"save": "Uložit",
"edit": "Upravit",
- "error": "Chyba",
"view_on": {
"npm": "Zobrazit na npm",
"github": "Zobrazit na GitHubu",
@@ -359,7 +358,9 @@
"message": "Zdá se, že ještě nepoužívají npmx. Chcete jim o tom říct?",
"share_button": "Sdílet na Bluesky",
"compose_text": "Ahoj {'@'}{handle}! Viděl jsi už npmx.dev? Je to prohlížeč pro npm registr, který je rychlý, moderní a open-source.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Nepodařilo se načíst oblíbené balíčky.",
+ "likes_empty": "Zatím žádné oblíbené balíčky."
},
"package": {
"not_found": "Balíček nenalezen",
diff --git a/i18n/locales/de-AT.json b/i18n/locales/de-AT.json
index 458cf38f23..34b42e1e03 100644
--- a/i18n/locales/de-AT.json
+++ b/i18n/locales/de-AT.json
@@ -21,5 +21,28 @@
"instant_search_turn_on": "Schnellsuche aktivieren",
"instant_search_turn_off": "Schnellsuche deaktivieren",
"instant_search_advisory": "Die Schnellsuche sendet bei jedem Tastendruck eine Anfrage."
+ },
+ "profile": {
+ "likes_error": "Gelikte Pakete konnten nicht geladen werden.",
+ "likes_empty": "Noch keine gelikten Pakete.",
+ "avatar_alt": "Profilavatar",
+ "unknown_profile": "Unbekanntes Profil",
+ "linked_accounts": {
+ "status": {
+ "verified": "Verifiziert",
+ "unverified": "Nicht verifiziert",
+ "stale": "Veraltet",
+ "failed": "Fehlgeschlagen"
+ },
+ "title": "Verknüpfte Konten",
+ "verified_summary": "Verifizierte Konten",
+ "legend_aria_label": "Legende zum Verifizierungsstatus von Konten",
+ "empty": "Keine verknüpften Konten",
+ "legend_info_title": "Bedeutung der Abzeichen",
+ "legend_verified": "Die Angabe wurde überprüft und das Konto wurde bestätigt.",
+ "legend_unverified": "Die Angabe konnte nicht bestätigt werden – versuche, das Konto erneut zu verifizieren.",
+ "legend_stale": "Die letzte Verifizierung ist veraltet; verifiziere das Konto erneut, um den Status zu aktualisieren.",
+ "legend_failed": "Die Verifizierung ist fehlgeschlagen (siehe Details). Du kannst beim Konto auf „Erneut verifizieren“ klicken, um einen neuen Prüfversuch zu starten."
+ }
}
}
diff --git a/i18n/locales/de-DE.json b/i18n/locales/de-DE.json
index 0618235d76..174330ff11 100644
--- a/i18n/locales/de-DE.json
+++ b/i18n/locales/de-DE.json
@@ -1,3 +1,26 @@
{
- "$schema": "../schema.json"
+ "$schema": "../schema.json",
+ "profile": {
+ "likes_error": "Gelikte Pakete konnten nicht geladen werden.",
+ "likes_empty": "Noch keine gelikten Pakete.",
+ "avatar_alt": "Profilavatar",
+ "unknown_profile": "Unbekanntes Profil",
+ "linked_accounts": {
+ "status": {
+ "verified": "Verifiziert",
+ "unverified": "Nicht verifiziert",
+ "stale": "Veraltet",
+ "failed": "Fehlgeschlagen"
+ },
+ "title": "Verknüpfte Konten",
+ "verified_summary": "Verifizierte Konten",
+ "legend_aria_label": "Legende zum Verifizierungsstatus von Konten",
+ "empty": "Keine verknüpften Konten",
+ "legend_info_title": "Was die Badges bedeuten",
+ "legend_verified": "Der Nachweis wurde geprüft und das Konto bestätigt.",
+ "legend_unverified": "Der Nachweis konnte nicht bestätigt werden — versuche, das Konto erneut zu verifizieren.",
+ "legend_stale": "Die letzte Verifizierung ist veraltet; verifiziere erneut, um den Status zu aktualisieren.",
+ "legend_failed": "Die Verifizierung ist fehlgeschlagen (siehe Details). Du kannst beim Konto auf \"Erneut verifizieren\" klicken, um es erneut zu prüfen."
+ }
+ }
}
diff --git a/i18n/locales/de.json b/i18n/locales/de.json
index e315922ac8..cd9ed21734 100644
--- a/i18n/locales/de.json
+++ b/i18n/locales/de.json
@@ -322,7 +322,6 @@
"cancel": "Abbrechen",
"save": "Speichern",
"edit": "Bearbeiten",
- "error": "Fehler",
"view_on": {
"npm": "Auf npm ansehen",
"github": "Auf GitHub ansehen",
@@ -350,6 +349,8 @@
"website": "Website",
"website_placeholder": "https://beispiel.de",
"likes": "Likes",
+ "likes_error": "Gelikte Pakete konnten nicht geladen werden.",
+ "likes_empty": "Noch keine gelikten Pakete.",
"seo_title": "{handle} - npmx",
"seo_description": "npmx-Profil von {handle}",
"not_found": "Profil nicht gefunden",
@@ -358,6 +359,23 @@
"message": "Es sieht nicht so aus, als ob sie npmx schon benutzen. Möchtest du ihnen davon erzählen?",
"share_button": "Auf Bluesky teilen",
"compose_text": "Hey {'@'}{handle}! Hast du schon npmx.dev ausprobiert? Es ist ein Browser für die npm Registry, der schnell, modern und Open-Source ist.\nhttps://npmx.dev"
+ },
+ "linked_accounts": {
+ "status": {
+ "verified": "Verifiziert",
+ "unverified": "Nicht verifiziert",
+ "stale": "Veraltet",
+ "failed": "Fehlgeschlagen"
+ },
+ "title": "Verknüpfte Konten",
+ "verified_summary": "Verifizierte Konten",
+ "legend_info_title": "Was die Badges bedeuten",
+ "legend_verified": "Der Nachweis wurde geprüft und das Konto bestätigt.",
+ "legend_unverified": "Der Nachweis konnte nicht bestätigt werden — versuche, das Konto erneut zu verifizieren.",
+ "legend_stale": "Die letzte Verifizierung ist veraltet; verifiziere erneut, um den Status zu aktualisieren.",
+ "legend_failed": "Die Verifizierung ist fehlgeschlagen (siehe Details). Du kannst beim Konto auf „\"Erneut verifizieren\" klicken, um es erneut zu prüfen.",
+ "legend_aria_label": "Legende zum Verifizierungsstatus von Konten",
+ "empty": "Keine verknüpften Konten"
}
},
"package": {
@@ -379,6 +397,7 @@
"size": "Installationsgröße um {percent} gestiegen ({size} größer)",
"deps": "{count} zusätzliche Abhängigkeiten"
},
+ "size_decrease": {},
"replacement": {
"title": "Du brauchst diese Abhängigkeit vielleicht nicht.",
"native": "Dies kann durch {replacement} ersetzt werden, verfügbar seit Node {nodeVersion}.",
@@ -556,6 +575,7 @@
"current_tags": "Aktuelle Tags",
"no_match_filter": "Keine Versionen entsprechen {filter}"
},
+ "timeline": {},
"dependencies": {
"title": "Abhängigkeit ({count}) | Abhängigkeiten ({count})",
"list_label": "Paketabhängigkeiten",
@@ -1315,7 +1335,10 @@
"vulnerabilities": {
"label": "Sicherheitslücken",
"description": "Bekannte Sicherheitsrisiken"
- }
+ },
+ "githubStars": {},
+ "githubIssues": {},
+ "createdAt": {}
},
"values": {
"any": "Beliebig",
diff --git a/i18n/locales/en-GB.json b/i18n/locales/en-GB.json
index cd250a7f15..09c69c0e03 100644
--- a/i18n/locales/en-GB.json
+++ b/i18n/locales/en-GB.json
@@ -45,5 +45,9 @@
"error": "Failed to load organisations",
"empty": "No organisations found"
}
+ },
+ "profile": {
+ "likes_error": "Could not load liked packages.",
+ "likes_empty": "No liked packages yet."
}
}
diff --git a/i18n/locales/en.json b/i18n/locales/en.json
index 7b56e0311e..676807e5ef 100644
--- a/i18n/locales/en.json
+++ b/i18n/locales/en.json
@@ -331,7 +331,6 @@
"cancel": "Cancel",
"save": "Save",
"edit": "Edit",
- "error": "Error",
"view_on": {
"npm": "View on npm",
"github": "View on GitHub",
@@ -359,6 +358,8 @@
"website": "Website",
"website_placeholder": "https://example.com",
"likes": "Likes",
+ "likes_error": "Could not load liked packages.",
+ "likes_empty": "No liked packages yet.",
"seo_title": "{handle} - npmx",
"seo_description": "npmx profile by {handle}",
"not_found": "Profile Not Found",
@@ -367,6 +368,23 @@
"message": "It doesn't look like they're using npmx yet. Want to tell them about it?",
"share_button": "Share on Bluesky",
"compose_text": "Hey {'@'}{handle}! Have you checked out npmx.dev yet? It's a browser for the npm registry that's fast, modern, and open-source.\nhttps://npmx.dev"
+ },
+ "linked_accounts": {
+ "status": {
+ "verified": "Verified",
+ "unverified": "Unverified",
+ "stale": "Stale",
+ "failed": "Failed"
+ },
+ "title": "Linked Accounts",
+ "verified_summary": "{verified}/{total} verified",
+ "legend_aria_label": "Account verification status legend",
+ "legend_info_title": "What the badges mean",
+ "legend_verified": "The claim has been checked and the account is confirmed.",
+ "legend_unverified": "We couldn't confirm the claim — try re-verifying the account.",
+ "legend_stale": "The last verification is outdated; re-verify to refresh the status.",
+ "legend_failed": "Verification failed (see details). You can click \"Re-verify\" on the account to attempt a fresh check.",
+ "empty": "No linked accounts"
}
},
"package": {
diff --git a/i18n/locales/es-419.json b/i18n/locales/es-419.json
index aff49a7df8..fce9151ed6 100644
--- a/i18n/locales/es-419.json
+++ b/i18n/locales/es-419.json
@@ -43,7 +43,9 @@
"invite": {
"message": "Parece que aún no usa npmx. ¿Quieres contarle?",
"compose_text": "¡Hola {'@'}{handle}! ¿Has probado ya npmx.dev? Es un navegador para el registro de npm rápido, moderno y de código abierto.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "No se pudieron cargar los paquetes favoritos.",
+ "likes_empty": "Aún no hay paquetes favoritos."
},
"package": {
"readme": {
diff --git a/i18n/locales/es.json b/i18n/locales/es.json
index fff67c83e8..2e60c76ebe 100644
--- a/i18n/locales/es.json
+++ b/i18n/locales/es.json
@@ -331,7 +331,6 @@
"cancel": "Cancelar",
"save": "Guardar",
"edit": "Editar",
- "error": "Error",
"view_on": {
"npm": "ver en npm",
"github": "Ver en GitHub",
@@ -367,7 +366,9 @@
"message": "Parece que aún no usa npmx. ¿Quieres contárselo?",
"share_button": "Compartir en Bluesky",
"compose_text": "¡Hola {'@'}{handle}! ¿Has probado ya npmx.dev? Es un navegador para el registro de npm rápido, moderno y de código abierto.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "No se pudieron cargar los paquetes que te gustan.",
+ "likes_empty": "Aún no hay paquetes que te gusten."
},
"package": {
"not_found": "Paquete no encontrado",
diff --git a/i18n/locales/fr-FR.json b/i18n/locales/fr-FR.json
index a85b4a926b..ad34c44157 100644
--- a/i18n/locales/fr-FR.json
+++ b/i18n/locales/fr-FR.json
@@ -328,7 +328,6 @@
"cancel": "Annuler",
"save": "Enregistrer",
"edit": "Modifier",
- "error": "Erreur",
"view_on": {
"npm": "voir sur npm",
"github": "Voir sur GitHub",
@@ -364,7 +363,9 @@
"message": "Il semblerait qu'ils n'utilisent pas encore npmx. Vous voulez leur en parler ?",
"share_button": "Partager sur Bluesky",
"compose_text": "Salut {'@'}{handle} ! As-tu déjà testé npmx.dev ? C'est un navigateur pour le registre npm : rapide, moderne et open source.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Impossible de charger les paquets aimés.",
+ "likes_empty": "Aucun paquet aimé pour le moment."
},
"package": {
"not_found": "Paquet introuvable",
diff --git a/i18n/locales/hi-IN.json b/i18n/locales/hi-IN.json
index 16ddb8fe46..b279674f6a 100644
--- a/i18n/locales/hi-IN.json
+++ b/i18n/locales/hi-IN.json
@@ -210,7 +210,6 @@
"cancel": "रद्द करें",
"save": "सहेजें",
"edit": "संपादित करें",
- "error": "त्रुटि",
"view_on": {
"npm": "npm पर देखें",
"github": "GitHub पर देखें",
@@ -229,7 +228,9 @@
"expand": "विस्तृत करें"
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "पसंद किए गए पैकेज लोड नहीं हो सके।",
+ "likes_empty": "अभी तक कोई पसंद किए गए पैकेज नहीं।"
},
"package": {
"not_found": "पैकेज नहीं मिला",
diff --git a/i18n/locales/hu-HU.json b/i18n/locales/hu-HU.json
index 5b2f287810..144764df4e 100644
--- a/i18n/locales/hu-HU.json
+++ b/i18n/locales/hu-HU.json
@@ -156,7 +156,6 @@
"cancel": "Mégse",
"save": "Mentés",
"edit": "Szerkesztés",
- "error": "Hiba",
"view_on": {
"npm": "megtekintés npm-en",
"github": "Megtekintés GitHubon"
@@ -177,7 +176,9 @@
"message": "Úgy tűnik, hogy még nem használja az npmx-et. Szeretnéd megtudatni vele?",
"share_button": "Megosztás a Bluesky-on",
"compose_text": "Halló {'@'}{handle}! Már próbáltad az npmx.dev-et? Egy gyors, modern és nyílt forráskódú böngésző az npm regiszterhez.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Nem sikerült betölteni a kedvelt csomagokat.",
+ "likes_empty": "Még nincsenek kedvelt csomagok."
},
"package": {
"not_found": "Csomag Nem Található",
diff --git a/i18n/locales/id-ID.json b/i18n/locales/id-ID.json
index d35c639463..f0a8dacd2f 100644
--- a/i18n/locales/id-ID.json
+++ b/i18n/locales/id-ID.json
@@ -211,7 +211,6 @@
"cancel": "Batal",
"save": "Simpan",
"edit": "Edit",
- "error": "Kesalahan",
"view_on": {
"npm": "lihat di npm",
"github": "Lihat di GitHub",
@@ -244,7 +243,9 @@
"message": "Sepertinya mereka belum menggunakan npmx. Ingin memberi tahu mereka?",
"share_button": "Bagikan di Bluesky",
"compose_text": "Hai {'@'}{handle}! Sudah pernah mencoba npmx.dev? Ini adalah browser untuk npm registry yang cepat, modern, dan open-source.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Gagal memuat paket yang disukai.",
+ "likes_empty": "Belum ada paket yang disukai."
},
"package": {
"not_found": "Paket Tidak Ditemukan",
diff --git a/i18n/locales/it-IT.json b/i18n/locales/it-IT.json
index b19efca8db..da169b7504 100644
--- a/i18n/locales/it-IT.json
+++ b/i18n/locales/it-IT.json
@@ -155,7 +155,9 @@
}
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "Impossibile caricare i pacchetti preferiti.",
+ "likes_empty": "Nessun pacchetto preferito ancora."
},
"package": {
"not_found": "Pacchetto Non Trovato",
diff --git a/i18n/locales/ja-JP.json b/i18n/locales/ja-JP.json
index 4e2cd238c6..d2a70dae2f 100644
--- a/i18n/locales/ja-JP.json
+++ b/i18n/locales/ja-JP.json
@@ -331,7 +331,6 @@
"cancel": "キャンセル",
"save": "保存",
"edit": "編集",
- "error": "エラー",
"view_on": {
"npm": "npmで表示",
"github": "GitHubで表示",
@@ -367,7 +366,9 @@
"message": "まだnpmxを利用していないようです。npmxを紹介しますか?",
"share_button": "Blueskyで共有",
"compose_text": "{'@'}{handle} さん、npmx.devはもうチェックしましたか? 高速でモダンなオープンソースのnpmレジストリブラウザです。\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "いいねしたパッケージを読み込めませんでした。",
+ "likes_empty": "いいねしたパッケージはまだありません。"
},
"package": {
"not_found": "パッケージが見つかりません",
diff --git a/i18n/locales/kn-IN.json b/i18n/locales/kn-IN.json
index 31c0b57196..52f192ed5a 100644
--- a/i18n/locales/kn-IN.json
+++ b/i18n/locales/kn-IN.json
@@ -122,7 +122,9 @@
}
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "ಇಷ್ಟಪಟ್ಟ ಪ್ಯಾಕೇಜುಗಳನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ.",
+ "likes_empty": "ಇನ್ನೂ ಇಷ್ಟಪಟ್ಟ ಪ್ಯಾಕೇಜುಗಳಿಲ್ಲ."
},
"package": {
"not_found": "ಪ್ಯಾಕೇಜ್ ಕಂಡುಬಂದಿಲ್ಲ",
diff --git a/i18n/locales/mr-IN.json b/i18n/locales/mr-IN.json
index 7aa91dcc71..4df475a15e 100644
--- a/i18n/locales/mr-IN.json
+++ b/i18n/locales/mr-IN.json
@@ -194,7 +194,6 @@
"cancel": "रद्द करा",
"save": "जतन करा",
"edit": "संपादित करा",
- "error": "त्रुटी",
"view_on": {
"npm": "npm वर पहा",
"github": "GitHub वर पहा",
@@ -213,7 +212,9 @@
"expand": "विस्तृत करा"
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "आवडलेल्या पॅकेजेस लोड करता आल्या नाहीत.",
+ "likes_empty": "अद्याप आवडलेली कोणतीही पॅकेजेस नाहीत."
},
"package": {
"not_found": "पॅकेज सापडले नाही",
diff --git a/i18n/locales/nb-NO.json b/i18n/locales/nb-NO.json
index 7a9b3c4012..eed0770c85 100644
--- a/i18n/locales/nb-NO.json
+++ b/i18n/locales/nb-NO.json
@@ -328,7 +328,6 @@
"cancel": "Avbryt",
"save": "Lagre",
"edit": "Rediger",
- "error": "Feil",
"view_on": {
"npm": "vis på npm",
"github": "Vis på GitHub",
@@ -364,7 +363,9 @@
"message": "Det ser ikke ut som de bruker npmx ennå. Vil du fortelle dem om det?",
"share_button": "Del på Bluesky",
"compose_text": "Hei {'@'}{handle}! Har du sjekket ut npmx.dev ennå? Det er en leser for npm-registeret som er rask, moderne og åpen kildekode.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Kunne ikke laste likte pakker.",
+ "likes_empty": "Ingen likte pakker ennå."
},
"package": {
"not_found": "Pakke ikke funnet",
diff --git a/i18n/locales/ne-NP.json b/i18n/locales/ne-NP.json
index 60b7dec1f1..d76a7e7235 100644
--- a/i18n/locales/ne-NP.json
+++ b/i18n/locales/ne-NP.json
@@ -122,7 +122,9 @@
}
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "मनपरेका प्याकेजहरू लोड गर्न सकिएन।",
+ "likes_empty": "अहिले सम्म मनपरेका प्याकेजहरू छैनन्।"
},
"package": {
"not_found": "प्याकेज फेला परेन",
diff --git a/i18n/locales/nl.json b/i18n/locales/nl.json
index 9f1282b71a..13db86af5a 100644
--- a/i18n/locales/nl.json
+++ b/i18n/locales/nl.json
@@ -331,7 +331,6 @@
"cancel": "Annuleer",
"save": "Opslaan",
"edit": "Wijzigen",
- "error": "Fout",
"view_on": {
"npm": "Bekijk op npm",
"github": "Bekijk op GitHub",
@@ -367,7 +366,9 @@
"message": "Het lijkt erop dat ze npmx nog niet gebruiken. Wilt u ze hierop wijzen",
"share_button": "Deel op Bluesky",
"compose_text": "Hallo {'@'}{handle}! Hebt u npmx.dev al bekeken? Het is een browser voor het npm-register die snel, modern en open source is.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Kon gelikete pakketten niet laden.",
+ "likes_empty": "Nog geen gelikete pakketten."
},
"package": {
"not_found": "Pakket niet gevonden",
diff --git a/i18n/locales/pl-PL.json b/i18n/locales/pl-PL.json
index 7abdf7e745..63f8f08b92 100644
--- a/i18n/locales/pl-PL.json
+++ b/i18n/locales/pl-PL.json
@@ -193,7 +193,6 @@
"cancel": "Anuluj",
"save": "Zapisz",
"edit": "Edytuj",
- "error": "Błąd",
"view_on": {
"npm": "zobacz na npm",
"github": "Zobacz w GitHub",
@@ -224,7 +223,9 @@
"message": "Wygląda na to, że jeszcze nie korzystają z npmx. Chcesz ich powiadomić?",
"share_button": "Podziel się na Bluesky",
"compose_text": "Hej {'@'}{handle}! Czy znasz już npmx.dev? To szybka, nowoczesna przeglądarka rejestru npm z otwartym kodem źródłowym.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Nie udało się wczytać polubionych pakietów.",
+ "likes_empty": "Brak polubionych pakietów."
},
"package": {
"not_found": "Nie znaleziono pakietu",
diff --git a/i18n/locales/pt-BR.json b/i18n/locales/pt-BR.json
index f7ba0028f0..cafac22b25 100644
--- a/i18n/locales/pt-BR.json
+++ b/i18n/locales/pt-BR.json
@@ -327,7 +327,6 @@
"cancel": "Cancelar",
"save": "Salvar",
"edit": "Editar",
- "error": "Erro",
"view_on": {
"npm": "Ver no npm",
"github": "Ver no GitHub",
@@ -363,7 +362,9 @@
"message": "Parece que eles ainda não estão usando o npmx. Quer contar a eles sobre isso?",
"share_button": "Compartilhar no Bluesky",
"compose_text": "Olá, {'@'}{handle}! Você já conferiu npmx.dev? É um navegador para o registro npm rápido, moderno e de código aberto.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Não foi possível carregar os pacotes curtidos.",
+ "likes_empty": "Nenhum pacote curtido ainda."
},
"package": {
"not_found": "Pacote não encontrado",
diff --git a/i18n/locales/pt-PT.json b/i18n/locales/pt-PT.json
index 683ce28ae6..c4620bb3d3 100644
--- a/i18n/locales/pt-PT.json
+++ b/i18n/locales/pt-PT.json
@@ -328,7 +328,6 @@
"cancel": "Cancelar",
"save": "Guardar",
"edit": "Editar",
- "error": "Erro",
"view_on": {
"npm": "Ver no npm",
"github": "Ver no GitHub",
@@ -364,6 +363,14 @@
"message": "Parece que ainda não estão a usar o npmx. Queres contar-lhes sobre isso?",
"share_button": "Partilhar no Bluesky",
"compose_text": "Olá, {'@'}{handle}! Já conheces o npmx.dev? É um navegador para o registo npm rápido, moderno e de código aberto.\nhttps://npmx.dev"
+ },
+ "linked_accounts": {
+ "status": {},
+ "legend_info_title": "O significado dos distintivos",
+ "legend_verified": "A reivindicação foi verificada e a conta foi confirmada.",
+ "legend_unverified": "Não foi possível confirmar a reivindicação — tente verificar novamente a conta.",
+ "legend_stale": "A última verificação está desatualizada; volte a verificar para atualizar o estado.",
+ "legend_failed": "A verificação falhou (consulte os detalhes). Pode clicar em \"Verificar novamente\" na conta para tentar uma nova verificação."
}
},
"package": {
@@ -591,7 +598,10 @@
"trusted_publisher_added": "Publicação de confiança ativada",
"trusted_publisher_removed": "Publicação de confiança removida",
"provenance_added": "Proveniência ativada",
- "provenance_removed": "Proveniência removida"
+ "provenance_removed": "Proveniência removida",
+ "chart": {
+ "copy_alt": {}
+ }
},
"dependencies": {
"title": "Dependência ({count}) | Dependências ({count})",
@@ -1704,5 +1714,8 @@
"discord_link_text": "chat.npmx.dev"
}
},
- "alt_logo_kawaii": "Uma versão fofa, arredondada e colorida do logótipo do npmx."
+ "alt_logo_kawaii": "Uma versão fofa, arredondada e colorida do logótipo do npmx.",
+ "changelog": {
+ "error": {}
+ }
}
diff --git a/i18n/locales/ro-RO.json b/i18n/locales/ro-RO.json
index 07e880b329..62f29c46f6 100644
--- a/i18n/locales/ro-RO.json
+++ b/i18n/locales/ro-RO.json
@@ -328,7 +328,6 @@
"cancel": "Anulează",
"save": "Salvează",
"edit": "Editează",
- "error": "Eroare",
"view_on": {
"npm": "Vizualizează pe npm",
"github": "Vizualizează pe GitHub",
@@ -364,6 +363,14 @@
"message": "Se pare că încă nu folosesc npmx. Vrei să le spui despre asta?",
"share_button": "Partajează pe Bluesky",
"compose_text": "Salut {'@'}{handle}! Ai vizitat deja npmx.dev? Este un browser pentru registrul npm, rapid, modern și open-source.\nhttps://npmx.dev"
+ },
+ "linked_accounts": {
+ "status": {},
+ "legend_info_title": "Ce înseamnă insignele",
+ "legend_verified": "Declarația a fost verificată, iar contul este confirmat.",
+ "legend_unverified": "Nu am putut confirma declarația — încearcă să reverifici contul.",
+ "legend_stale": "Ultima verificare este învechită; reverifică pentru a actualiza starea.",
+ "legend_failed": "Verificarea a eșuat (vezi detaliile). Poți face clic pe „Reverifică” în cont pentru a încerca o nouă verificare."
}
},
"package": {
diff --git a/i18n/locales/ru-RU.json b/i18n/locales/ru-RU.json
index 3b5ee6174f..de0e3976e8 100644
--- a/i18n/locales/ru-RU.json
+++ b/i18n/locales/ru-RU.json
@@ -331,7 +331,6 @@
"cancel": "Отменить",
"save": "Сохранить",
"edit": "Изменить",
- "error": "Ошибка",
"view_on": {
"npm": "Открыть на npm",
"github": "Открыть на GitHub",
@@ -367,7 +366,9 @@
"message": "Похоже, этот пользователь ещё не пользуется npmx. Хотите рассказать ему о проекте?",
"share_button": "Поделиться в Bluesky",
"compose_text": "Привет, {'@'}{handle}! Уже смотрел npmx.dev? Это быстрый, современный и open-source браузер для реестра npm.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Не удалось загрузить понравившиеся пакеты.",
+ "likes_empty": "Понравившихся пакетов пока нет."
},
"package": {
"not_found": "Пакет не найден",
diff --git a/i18n/locales/sr-Latn-RS.json b/i18n/locales/sr-Latn-RS.json
index e164313a05..fa1b9be906 100644
--- a/i18n/locales/sr-Latn-RS.json
+++ b/i18n/locales/sr-Latn-RS.json
@@ -211,7 +211,6 @@
"cancel": "Otkažite",
"save": "Sačuvajte",
"edit": "Uredite",
- "error": "Greška",
"view_on": {
"npm": "pogledajte na npm-u",
"github": "Pogledajte na GitHub-u",
@@ -244,7 +243,9 @@
"message": "Izgleda da još uvek ne koriste npmx. Želite li da im kažete nešto više o tome?",
"share_button": "Podelite na Bluesky-u",
"compose_text": "Hej {'@'}{handle}! Da li ste već pogledali npmx.dev? To je pretraživač za npm registar koji je brz, moderan i otvorenog koda.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Nije moguće učitati omiljene pakete.",
+ "likes_empty": "Još nema omiljenih paketa."
},
"package": {
"not_found": "Paket nije pronađen",
diff --git a/i18n/locales/ta-IN.json b/i18n/locales/ta-IN.json
index e8b657110c..fd5231ece7 100644
--- a/i18n/locales/ta-IN.json
+++ b/i18n/locales/ta-IN.json
@@ -154,7 +154,9 @@
}
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "விரும்பிய தொகுப்புகளை ஏற்ற முடியவில்லை.",
+ "likes_empty": "இன்னும் விரும்பிய தொகுப்புகள் இல்லை."
},
"package": {
"not_found": "தொகுப்பு கிடைக்கவில்லை",
diff --git a/i18n/locales/te-IN.json b/i18n/locales/te-IN.json
index 7e92347d2e..5686a70a35 100644
--- a/i18n/locales/te-IN.json
+++ b/i18n/locales/te-IN.json
@@ -122,7 +122,9 @@
}
},
"profile": {
- "invite": {}
+ "invite": {},
+ "likes_error": "Could not load liked packages.",
+ "likes_empty": "No liked packages yet."
},
"package": {
"not_found": "ప్యాకేజ్ కనుగొనబడలేదు",
diff --git a/i18n/locales/tr-TR.json b/i18n/locales/tr-TR.json
index 6189f3d8ce..48c67d6a24 100644
--- a/i18n/locales/tr-TR.json
+++ b/i18n/locales/tr-TR.json
@@ -331,7 +331,6 @@
"cancel": "İptal",
"save": "Kaydet",
"edit": "Düzenle",
- "error": "Hata",
"view_on": {
"npm": "npm'de görüntüle",
"github": "GitHub'da görüntüle",
@@ -367,7 +366,9 @@
"message": "npmx'i deneyin - npm için daha iyi bir paket tarayıcısı",
"share_button": "Paylaş",
"compose_text": "npmx'i deneyin - npm için daha iyi bir paket tarayıcısı: {url}"
- }
+ },
+ "likes_error": "Beğenilen paketler yüklenemedi.",
+ "likes_empty": "Henüz beğenilen paket yok."
},
"package": {
"not_found": "Paket Bulunamadı",
diff --git a/i18n/locales/uk-UA.json b/i18n/locales/uk-UA.json
index 4b7a443e46..4bef9f7040 100644
--- a/i18n/locales/uk-UA.json
+++ b/i18n/locales/uk-UA.json
@@ -328,7 +328,6 @@
"cancel": "Скасувати",
"save": "Зберегти",
"edit": "Редагувати",
- "error": "Помилка",
"view_on": {
"npm": "Переглянути на npm",
"github": "Переглянути на GitHub",
@@ -364,7 +363,9 @@
"message": "Схоже, вони ще не користуються npmx. Хочете розповісти їм про нього?",
"share_button": "Поділитися в Bluesky",
"compose_text": "Привіт, {'@'}{handle}! Ти вже перевірив npmx.dev? Це швидкий сучасний браузер для реєстру npm з відкритим кодом.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Не вдалося завантажити вподобані пакети.",
+ "likes_empty": "Вподобаних пакетів поки немає."
},
"package": {
"not_found": "Пакет не знайдено",
diff --git a/i18n/locales/vi-VN.json b/i18n/locales/vi-VN.json
index 4594ee1b87..a07976d200 100644
--- a/i18n/locales/vi-VN.json
+++ b/i18n/locales/vi-VN.json
@@ -211,7 +211,6 @@
"cancel": "Hủy",
"save": "Lưu",
"edit": "Chỉnh sửa",
- "error": "Lỗi",
"view_on": {
"npm": "xem trên npm",
"github": "Xem trên GitHub",
@@ -244,7 +243,9 @@
"message": "Có vẻ họ chưa dùng npmx. Bạn có muốn giới thiệu cho họ không?",
"share_button": "Chia sẻ trên Bluesky",
"compose_text": "Chào {'@'}{handle}! Bạn đã thử npmx.dev chưa? Đây là trình duyệt cho npm registry, nhanh, hiện đại và mã nguồn mở.\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "Không thể tải các package đã thích.",
+ "likes_empty": "Chưa có package nào được thích."
},
"package": {
"not_found": "Không tìm thấy gói",
diff --git a/i18n/locales/zh-CN.json b/i18n/locales/zh-CN.json
index e8f028d69f..e2a6232a55 100644
--- a/i18n/locales/zh-CN.json
+++ b/i18n/locales/zh-CN.json
@@ -328,7 +328,6 @@
"cancel": "取消",
"save": "保存",
"edit": "编辑",
- "error": "加载出错",
"view_on": {
"npm": "在 npm 上查看",
"github": "在 GitHub 上查看",
@@ -364,7 +363,9 @@
"message": "看起来他们还没有使用 npmx,去邀请一下?",
"share_button": "分享到 Bluesky",
"compose_text": "嗨 {'@'}{handle}!您用过 npmx.dev 吗?它是一个快速、现代且开源的 npm registry 浏览器。\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "无法加载喜欢的包。",
+ "likes_empty": "还没有喜欢的包。"
},
"package": {
"not_found": "未找到包",
diff --git a/i18n/locales/zh-TW.json b/i18n/locales/zh-TW.json
index 069716b94d..4b821b92b0 100644
--- a/i18n/locales/zh-TW.json
+++ b/i18n/locales/zh-TW.json
@@ -322,7 +322,6 @@
"cancel": "取消",
"save": "儲存",
"edit": "編輯",
- "error": "錯誤",
"view_on": {
"npm": "在 npm 上檢視",
"github": "在 GitHub 上檢視",
@@ -357,7 +356,9 @@
"message": "看起來對方還沒在用 npmx。要不要跟他們分享一下?",
"share_button": "分享到 Bluesky",
"compose_text": "Hey {'@'}{handle}!你用過 npmx.dev 了嗎?它是 npm Registry 的瀏覽器,快速、現代,而且是開源的。\nhttps://npmx.dev"
- }
+ },
+ "likes_error": "無法載入喜歡的套件。",
+ "likes_empty": "目前尚無喜歡的套件。"
},
"package": {
"not_found": "找不到套件",
diff --git a/i18n/schema.json b/i18n/schema.json
index 8ab3e4a2da..269fdce0f0 100644
--- a/i18n/schema.json
+++ b/i18n/schema.json
@@ -997,9 +997,6 @@
"edit": {
"type": "string"
},
- "error": {
- "type": "string"
- },
"view_on": {
"type": "object",
"properties": {
@@ -1081,6 +1078,12 @@
"likes": {
"type": "string"
},
+ "likes_error": {
+ "type": "string"
+ },
+ "likes_empty": {
+ "type": "string"
+ },
"seo_title": {
"type": "string"
},
@@ -1107,6 +1110,57 @@
}
},
"additionalProperties": false
+ },
+ "linked_accounts": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "object",
+ "properties": {
+ "verified": {
+ "type": "string"
+ },
+ "unverified": {
+ "type": "string"
+ },
+ "stale": {
+ "type": "string"
+ },
+ "failed": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "title": {
+ "type": "string"
+ },
+ "verified_summary": {
+ "type": "string"
+ },
+ "legend_aria_label": {
+ "type": "string"
+ },
+ "legend_info_title": {
+ "type": "string"
+ },
+ "legend_verified": {
+ "type": "string"
+ },
+ "legend_unverified": {
+ "type": "string"
+ },
+ "legend_stale": {
+ "type": "string"
+ },
+ "legend_failed": {
+ "type": "string"
+ },
+ "empty": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
}
},
"additionalProperties": false
diff --git a/package.json b/package.json
index 21e41ec52c..c1eb08c83e 100644
--- a/package.json
+++ b/package.json
@@ -57,6 +57,7 @@
"@iconify-json/svg-spinners": "1.2.4",
"@iconify-json/vscode-icons": "1.2.45",
"@intlify/shared": "11.3.0",
+ "@keytrace/claims": "1.4.0",
"@lunariajs/core": "https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@904b935",
"@napi-rs/canvas": "1.0.0",
"@nuxt/a11y": "1.0.0-alpha.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1d666694a6..4a1707fc66 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -90,6 +90,9 @@ importers:
'@intlify/shared':
specifier: 11.3.0
version: 11.3.0
+ '@keytrace/claims':
+ specifier: 1.4.0
+ version: 1.4.0
'@lunariajs/core':
specifier: https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@904b935
version: https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@904b935
@@ -2262,6 +2265,10 @@ packages:
'@jsr/std__path@1.1.4':
resolution: {integrity: sha512-SK4u9H6NVTfolhPdlvdYXfNFefy1W04AEHWJydryYbk+xqzNiVmr5o7TLJLJFqwHXuwMRhwrn+mcYeUfS0YFaA==, tarball: https://npm.jsr.io/~/11/@jsr/std__path/1.1.4.tgz}
+ '@keytrace/claims@1.4.0':
+ resolution: {integrity: sha512-XeojwXFFnvhPsDI7f99e2KCvk8gDC5ztKxRBplB+Zx5OmfcaBovX+DZJODZsxz3b1r4ZITBDOjZD8gftgpAZyw==}
+ engines: {node: '>=18'}
+
'@kwsites/file-exists@1.1.1':
resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==}
@@ -13497,6 +13504,8 @@ snapshots:
dependencies:
'@jsr/std__internal': 1.0.12
+ '@keytrace/claims@1.4.0': {}
+
'@kwsites/file-exists@1.1.1':
dependencies:
debug: 4.4.3
diff --git a/server/api/keytrace/[domain].ts b/server/api/keytrace/[domain].ts
new file mode 100644
index 0000000000..0ea5c494e2
--- /dev/null
+++ b/server/api/keytrace/[domain].ts
@@ -0,0 +1,178 @@
+import { getClaimsForHandle, type ClaimVerificationResult } from '@keytrace/claims'
+import type { KeytraceProofMethod, KeytraceResponse } from '#shared/types/keytrace'
+import {
+ getOptionalClaimField,
+ mapKeytraceVerificationStatus,
+ mapClaimTypeToPlatform,
+} from '#server/utils/keytrace'
+import { toProxiedImageUrl } from '#server/utils/image-proxy'
+import { getSafeHttpUrl } from '#shared/utils/url'
+
+function domainToDisplayName(domain: string): string {
+ const firstSegment = domain.split('.')[0] || domain
+ return firstSegment.charAt(0).toUpperCase() + firstSegment.slice(1)
+}
+
+function buildDefaultAvatarUrl(domain: string, imageProxySecret: string): string {
+ return buildSeededAvatarUrl(domain, imageProxySecret)
+}
+
+function buildSeededAvatarUrl(seed: string, imageProxySecret: string): string {
+ const rawFallbackAvatar = `https://api.dicebear.com/9.x/initials/svg?seed=${encodeURIComponent(seed)}`
+ return toProxiedImageUrl(rawFallbackAvatar, imageProxySecret)
+}
+
+function toProfileAvatarUrl(
+ rawAvatarUrl: string | undefined,
+ domain: string,
+ imageProxySecret: string,
+): string {
+ const safeAvatarUrl = getSafeHttpUrl(rawAvatarUrl)
+ if (!safeAvatarUrl) {
+ return buildDefaultAvatarUrl(domain, imageProxySecret)
+ }
+
+ return toProxiedImageUrl(safeAvatarUrl, imageProxySecret)
+}
+
+function toAccountAvatarUrl(
+ rawAvatarUrl: string | undefined,
+ imageProxySecret: string,
+ fallbackSeed: string,
+): string {
+ const safeAvatarUrl = getSafeHttpUrl(rawAvatarUrl)
+ if (!safeAvatarUrl) {
+ return buildSeededAvatarUrl(fallbackSeed, imageProxySecret)
+ }
+
+ return toProxiedImageUrl(safeAvatarUrl, imageProxySecret)
+}
+
+function buildFallbackProfile(domain: string, imageProxySecret: string): KeytraceResponse {
+ return {
+ profile: {
+ name: `${domainToDisplayName(domain)} Developer`,
+ avatar: buildDefaultAvatarUrl(domain, imageProxySecret),
+ description: `No Keytrace claims found for ${domain}.`,
+ },
+ accounts: [],
+ }
+}
+
+function buildServiceUnavailableProfile(
+ domain: string,
+ imageProxySecret: string,
+): KeytraceResponse {
+ return {
+ profile: {
+ name: `${domainToDisplayName(domain)} Developer`,
+ avatar: buildDefaultAvatarUrl(domain, imageProxySecret),
+ description: 'Keytrace is temporarily unavailable. Please try again shortly.',
+ },
+ accounts: [],
+ }
+}
+
+const allowedProofMethods = new Set
([
+ 'dns',
+ 'github',
+ 'npm',
+ 'mastodon',
+ 'bluesky',
+ 'pgp',
+ 'other',
+])
+
+function mapProofMethod(type: string): KeytraceProofMethod {
+ const mappedType = mapClaimTypeToPlatform(type)
+ return allowedProofMethods.has(mappedType as KeytraceProofMethod)
+ ? (mappedType as KeytraceProofMethod)
+ : 'other'
+}
+
+// Convert Keytrace claims to our account format
+function mapClaimsToAccounts(
+ claims: ClaimVerificationResult[],
+ imageProxySecret: string,
+): KeytraceResponse['accounts'] {
+ return claims.map(claim => ({
+ platform: mapClaimTypeToPlatform(claim.type),
+ username: claim.identity.subject,
+ displayName: claim.identity.displayName || claim.identity.subject,
+ avatar: toAccountAvatarUrl(claim.identity.avatarUrl, imageProxySecret, claim.identity.subject),
+ url: getSafeHttpUrl(claim.identity.profileUrl) || undefined,
+ status: mapKeytraceVerificationStatus(claim),
+ proofMethod: mapProofMethod(claim.type),
+ addedAt: claim.claim.createdAt,
+ lastCheckedAt:
+ getOptionalClaimField(claim, 'lastVerifiedAt') ||
+ claim.claim.retractedAt ||
+ claim.claim.createdAt,
+ failureReason: claim.error || undefined,
+ }))
+}
+
+type KeytraceFetchResult =
+ | { kind: 'success'; data: KeytraceResponse }
+ | { kind: 'no-claims' }
+ | { kind: 'error'; error: unknown }
+
+// Fetch real Keytrace profile data
+async function fetchKeytraceProfile(
+ domain: string,
+ imageProxySecret: string,
+): Promise {
+ try {
+ const result = await getClaimsForHandle(domain)
+
+ if (!result.claims || result.claims.length === 0) {
+ return { kind: 'no-claims' }
+ }
+
+ // Build profile from first claim's identity (they all belong to the same DID)
+ const firstClaim = result.claims[0]
+ if (!firstClaim) {
+ return { kind: 'no-claims' }
+ }
+
+ return {
+ kind: 'success',
+ data: {
+ profile: {
+ name: firstClaim.identity.displayName || domainToDisplayName(domain),
+ avatar: toProfileAvatarUrl(firstClaim.identity.avatarUrl, domain, imageProxySecret),
+ description: `Identity profile for ${domain}`,
+ },
+ accounts: mapClaimsToAccounts(result.claims, imageProxySecret),
+ },
+ }
+ } catch (error) {
+ console.error('Failed to fetch Keytrace profile:', error)
+ return { kind: 'error', error }
+ }
+}
+
+export default defineEventHandler(async event => {
+ const { imageProxySecret } = useRuntimeConfig(event)
+ const domain = getRouterParam(event, 'domain')?.trim().toLowerCase()
+ if (!domain) {
+ throw createError({
+ statusCode: 400,
+ message: 'Domain is required',
+ })
+ }
+
+ // Try to fetch real Keytrace data
+ const keytraceData = await fetchKeytraceProfile(domain, imageProxySecret)
+
+ if (keytraceData.kind === 'success') {
+ return keytraceData.data
+ }
+
+ if (keytraceData.kind === 'no-claims') {
+ return buildFallbackProfile(domain, imageProxySecret)
+ }
+
+ // If Keytrace is unavailable and mock mode isn't allowed, return a neutral profile.
+ return buildServiceUnavailableProfile(domain, imageProxySecret)
+})
diff --git a/server/api/keytrace/reverify.post.ts b/server/api/keytrace/reverify.post.ts
new file mode 100644
index 0000000000..b46a4fca08
--- /dev/null
+++ b/server/api/keytrace/reverify.post.ts
@@ -0,0 +1,93 @@
+import { getClaimsForHandle, type ClaimVerificationResult } from '@keytrace/claims'
+import type { KeytraceReverifyRequest, KeytraceReverifyResponse } from '#shared/types/keytrace'
+import {
+ getOptionalClaimField,
+ mapPlatformToClaimType,
+ mapKeytraceVerificationStatus,
+} from '#server/utils/keytrace'
+
+function mapReverifyStatus(claim: ClaimVerificationResult): KeytraceReverifyResponse['status'] {
+ return mapKeytraceVerificationStatus(claim)
+}
+
+function getReverifyLastCheckedAt(claim: ClaimVerificationResult): string {
+ return getOptionalClaimField(claim, 'lastVerifiedAt') || claim.claim.createdAt
+}
+
+function matchesAccount(
+ claim: ClaimVerificationResult,
+ claimType: string,
+ username: string,
+ url?: string,
+): boolean {
+ if (claim.type !== claimType) {
+ return false
+ }
+
+ const normalizedSubject = claim.identity.subject.toLowerCase()
+ const normalizedUsername = username.toLowerCase()
+ if (normalizedSubject === normalizedUsername) {
+ return true
+ }
+
+ const profileUrl = (claim.identity.profileUrl || '').toLowerCase()
+ const normalizedUrl = (url || '').toLowerCase()
+ if (normalizedUrl && profileUrl && profileUrl === normalizedUrl) {
+ return true
+ }
+
+ return false
+}
+
+export default defineEventHandler(async event => {
+ const body = await readBody(event)
+
+ const identity = body?.identity?.trim().toLowerCase()
+ const platform = body?.platform?.trim().toLowerCase()
+ const username = body?.username?.trim()
+
+ if (!identity || !platform || !username) {
+ throw createError({
+ statusCode: 400,
+ message: 'identity, platform and username are required',
+ })
+ }
+
+ try {
+ const result = await getClaimsForHandle(identity)
+ const claimType = mapPlatformToClaimType(platform)
+ const matchedClaim = result.claims.find(claim =>
+ matchesAccount(claim, claimType, username, body?.url),
+ )
+
+ if (!matchedClaim) {
+ return {
+ status: 'unverified',
+ lastCheckedAt: new Date().toISOString(),
+ failureReason: 'No matching Keytrace claim found for this account.',
+ }
+ }
+
+ const response: KeytraceReverifyResponse = {
+ status: mapReverifyStatus(matchedClaim),
+ lastCheckedAt: getReverifyLastCheckedAt(matchedClaim),
+ failureReason: matchedClaim.error || undefined,
+ }
+
+ if (matchedClaim.claim.retractedAt) {
+ response.status = 'unverified'
+ response.retractedAt = matchedClaim.claim.retractedAt
+ response.failureReason = response.failureReason || 'Keytrace claim was retracted.'
+ }
+
+ return response
+ } catch (error) {
+ console.error('[keytrace] reverify failed', error)
+
+ return {
+ status: 'unverified',
+ lastCheckedAt: new Date().toISOString(),
+ failureReason: 'Keytrace is temporarily unavailable. Please try again shortly.',
+ }
+ }
+})
diff --git a/server/utils/keytrace.ts b/server/utils/keytrace.ts
new file mode 100644
index 0000000000..4448994538
--- /dev/null
+++ b/server/utils/keytrace.ts
@@ -0,0 +1,93 @@
+import type { ClaimVerificationResult } from '@keytrace/claims'
+import type { KeytraceVerificationStatus } from '#shared/types/keytrace'
+
+const STALE_THRESHOLD_DAYS = 30
+
+const platformToClaimTypeMap: Record = {
+ github: 'github',
+ dns: 'dns',
+ mastodon: 'activitypub',
+ bluesky: 'bsky',
+ npm: 'npm',
+ tangled: 'tangled',
+ pgp: 'pgp',
+ twitter: 'twitter',
+ linkedin: 'linkedin',
+ instagram: 'instagram',
+ reddit: 'reddit',
+ hackernews: 'hackernews',
+ orcid: 'orcid',
+ itchio: 'itchio',
+ discord: 'discord',
+ steam: 'steam',
+}
+
+const claimTypeToPlatformMap: Record = {
+ github: 'github',
+ dns: 'dns',
+ activitypub: 'mastodon',
+ bsky: 'bluesky',
+ npm: 'npm',
+ tangled: 'tangled',
+ pgp: 'pgp',
+ twitter: 'twitter',
+ linkedin: 'linkedin',
+ instagram: 'instagram',
+ reddit: 'reddit',
+ hackernews: 'hackernews',
+ orcid: 'orcid',
+ itchio: 'itchio',
+ discord: 'discord',
+ steam: 'steam',
+}
+
+export function mapPlatformToClaimType(platform: string): string {
+ return platformToClaimTypeMap[platform] || platform
+}
+
+export function mapClaimTypeToPlatform(type: string): string {
+ return claimTypeToPlatformMap[type] || type
+}
+
+export function getOptionalClaimField(
+ claim: ClaimVerificationResult,
+ key: string,
+): string | undefined {
+ const rawClaim = claim.claim as unknown as Record
+ const value = rawClaim[key]
+ return typeof value === 'string' ? value : undefined
+}
+
+export function isStaleIsoDate(isoDate: string | undefined): boolean {
+ if (!isoDate) {
+ return false
+ }
+
+ const timestamp = Date.parse(isoDate)
+ if (Number.isNaN(timestamp)) {
+ return false
+ }
+
+ return Date.now() - timestamp > STALE_THRESHOLD_DAYS * 24 * 60 * 60 * 1000
+}
+
+export function mapKeytraceVerificationStatus(
+ claim: ClaimVerificationResult,
+): KeytraceVerificationStatus {
+ const rawStatus = getOptionalClaimField(claim, 'status')
+ const lastVerifiedAt = getOptionalClaimField(claim, 'lastVerifiedAt')
+
+ if (rawStatus === 'failed' || rawStatus === 'retracted') {
+ return 'failed'
+ }
+
+ if (rawStatus === 'verified' || claim.verified) {
+ return isStaleIsoDate(lastVerifiedAt) ? 'stale' : 'verified'
+ }
+
+ if (claim.error) {
+ return 'failed'
+ }
+
+ return 'unverified'
+}
diff --git a/shared/types/keytrace.ts b/shared/types/keytrace.ts
new file mode 100644
index 0000000000..76d9ede744
--- /dev/null
+++ b/shared/types/keytrace.ts
@@ -0,0 +1,49 @@
+export type KeytraceProfile = {
+ name: string
+ avatar: string
+ banner?: string
+ description: string
+}
+
+export type KeytraceVerificationStatus = 'verified' | 'unverified' | 'stale' | 'failed'
+
+export type KeytraceProofMethod =
+ | 'dns'
+ | 'github'
+ | 'npm'
+ | 'mastodon'
+ | 'pgp'
+ | 'bluesky'
+ | 'other'
+
+export type KeytraceAccount = {
+ platform: string
+ username: string
+ displayName?: string
+ avatar?: string
+ url?: string
+ status: KeytraceVerificationStatus
+ proofMethod: KeytraceProofMethod
+ addedAt: string
+ lastCheckedAt: string
+ failureReason?: string
+}
+
+export type KeytraceResponse = {
+ profile: KeytraceProfile
+ accounts: KeytraceAccount[]
+}
+
+export type KeytraceReverifyRequest = {
+ identity: string
+ platform: string
+ username: string
+ url?: string
+}
+
+export type KeytraceReverifyResponse = {
+ status: KeytraceVerificationStatus
+ lastCheckedAt: string
+ failureReason?: string
+ retractedAt?: string
+}
diff --git a/test/nuxt/a11y.spec.ts b/test/nuxt/a11y.spec.ts
index 69fd4ccfde..a0ee370416 100644
--- a/test/nuxt/a11y.spec.ts
+++ b/test/nuxt/a11y.spec.ts
@@ -279,6 +279,8 @@ import PackageLikeCard from '~/components/Package/LikeCard.vue'
import SizeIncrease from '~/components/Package/SizeIncrease.vue'
import SizeDecrease from '~/components/Package/SizeDecrease.vue'
import Likes from '~/components/Package/Likes.vue'
+import AccountItem from '~/components/AccountItem.vue'
+import LinkedAccounts from '~/components/LinkedAccounts.vue'
import LikesLeaderboardPage from '~/pages/leaderboard/likes.vue'
import type { VueUiXyDatasetItem } from 'vue-data-ui'
@@ -704,7 +706,11 @@ describe('component accessibility audits', () => {
it('should have no accessibility violations as secondary button', async () => {
const component = await mountSuspended(LinkBase, {
- props: { to: 'http://example.com', disabled: true, variant: 'button-secondary' },
+ props: {
+ to: 'http://example.com',
+ disabled: true,
+ variant: 'button-secondary',
+ },
slots: { default: 'Button link content' },
})
const results = await runAxe(component)
@@ -713,7 +719,11 @@ describe('component accessibility audits', () => {
it('should have no accessibility violations as primary button', async () => {
const component = await mountSuspended(LinkBase, {
- props: { to: 'http://example.com', disabled: true, variant: 'button-primary' },
+ props: {
+ to: 'http://example.com',
+ disabled: true,
+ variant: 'button-primary',
+ },
slots: { default: 'Button link content' },
})
const results = await runAxe(component)
@@ -1033,6 +1043,52 @@ describe('component accessibility audits', () => {
})
})
+ describe('LinkedAccounts', () => {
+ it('should have no accessibility violations with account list', async () => {
+ const component = await mountSuspended(LinkedAccounts, {
+ props: {
+ identity: 'npmx.dev',
+ accounts: [
+ {
+ platform: 'github',
+ username: 'npmx-dev',
+ displayName: 'npmx-dev',
+ status: 'verified',
+ proofMethod: 'github',
+ addedAt: '2026-04-01T10:00:00.000Z',
+ lastCheckedAt: '2026-04-21T10:00:00.000Z',
+ url: 'https://github.com/npmx-dev',
+ },
+ ],
+ },
+ })
+ const results = await runAxe(component)
+ expect(results.violations).toEqual([])
+ })
+ })
+
+ describe('AccountItem', () => {
+ it('should have no accessibility violations', async () => {
+ const component = await mountSuspended(AccountItem, {
+ props: {
+ identity: 'npmx.dev',
+ account: {
+ platform: 'github',
+ username: 'npmx-dev',
+ displayName: 'npmx-dev',
+ status: 'verified',
+ proofMethod: 'github',
+ addedAt: '2026-04-01T10:00:00.000Z',
+ lastCheckedAt: '2026-04-21T10:00:00.000Z',
+ url: 'https://github.com/npmx-dev',
+ },
+ },
+ })
+ const results = await runAxe(component)
+ expect(results.violations).toEqual([])
+ })
+ })
+
describe('PackageHeader', () => {
it('should have no accessibility violations', async () => {
const component = await mountSuspended(PackageHeader, {
@@ -3900,7 +3956,14 @@ describe('component accessibility audits', () => {
files: {
added: [{ path: 'new.ts', type: 'added' as const, newSize: 100 }],
removed: [{ path: 'old.ts', type: 'removed' as const, oldSize: 50 }],
- modified: [{ path: 'changed.ts', type: 'modified' as const, oldSize: 200, newSize: 250 }],
+ modified: [
+ {
+ path: 'changed.ts',
+ type: 'modified' as const,
+ oldSize: 200,
+ newSize: 250,
+ },
+ ],
},
dependencyChanges: [
{
@@ -3925,7 +3988,12 @@ describe('component accessibility audits', () => {
const mockAllChanges = [
{ path: 'new.ts', type: 'added' as const, newSize: 100 },
{ path: 'old.ts', type: 'removed' as const, oldSize: 50 },
- { path: 'changed.ts', type: 'modified' as const, oldSize: 200, newSize: 250 },
+ {
+ path: 'changed.ts',
+ type: 'modified' as const,
+ oldSize: 200,
+ newSize: 250,
+ },
]
const mockGroupedDeps = new Map([
@@ -4024,7 +4092,14 @@ describe('component accessibility audits', () => {
files: {
added: [{ path: 'new.ts', type: 'added' as const, newSize: 100 }],
removed: [],
- modified: [{ path: 'changed.ts', type: 'modified' as const, oldSize: 200, newSize: 250 }],
+ modified: [
+ {
+ path: 'changed.ts',
+ type: 'modified' as const,
+ oldSize: 200,
+ newSize: 250,
+ },
+ ],
},
dependencyChanges: [],
stats: {
@@ -4039,7 +4114,12 @@ describe('component accessibility audits', () => {
const mockAllChanges = [
{ path: 'new.ts', type: 'added' as const, newSize: 100 },
- { path: 'changed.ts', type: 'modified' as const, oldSize: 200, newSize: 250 },
+ {
+ path: 'changed.ts',
+ type: 'modified' as const,
+ oldSize: 200,
+ newSize: 250,
+ },
]
it('should have no accessibility violations when closed', async () => {