diff --git a/CHANGELOG.md b/CHANGELOG.md index cabb4ad46..b7ef640fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,24 @@ --> +## 12.103.0 (2022/02/02) + +### Improvements +- クライアント: 連合インスタンスページからインスタンス情報再取得を行えるように + +### Bugfixes +- クライアント: 投稿のNSFW画像を表示したあとにリアクションが更新されると画像が非表示になる問題を修正 +- クライアント: 「クリップ」ページが開かない問題を修正 +- クライアント: トレンドウィジェットが動作しないのを修正 +- クライアント: フェデレーションウィジェットが動作しないのを修正 +- クライアント: リアクション設定で絵文字ピッカーが開かないのを修正 +- クライアント: DMページでメンションが含まれる問題を修正 +- クライアント: 投稿フォームのハッシュタグ保持フィールドが動作しない問題を修正 +- クライアント: サイドビューが動かないのを修正 +- クライアント: ensure that specified users does not get duplicates +- Add `img-src` and `media-src` directives to `Content-Security-Policy` for + files and media proxy + ## 12.102.1 (2022/01/27) ### Bugfixes - チャットが表示できない問題を修正 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27f5598a6..662fa709b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ We're glad you're interested in contributing Misskey! In this document you will **ℹ️ Important:** This project uses Japanese as its major language, **but you do not need to translate and write the Issues/PRs in Japanese.** Also, you might receive comments on your Issue/PR in Japanese, but you do not need to reply to them in Japanese as well.\ -The accuracy of translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language. +The accuracy of machine translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language. It will also allow the reader to use the translation tool of their preference if necessary. ## Issues diff --git a/cypress/integration/basic.js b/cypress/integration/basic.js index aca44ef15..7d27b649f 100644 --- a/cypress/integration/basic.js +++ b/cypress/integration/basic.js @@ -176,3 +176,7 @@ describe('After user singed in', () => { cy.contains('Hello, Misskey!'); }); }); + +// TODO: 投稿フォームの公開範囲指定のテスト +// TODO: 投稿フォームのファイル添付のテスト +// TODO: 投稿フォームのハッシュタグ保持フィールドのテスト diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index ed97d539c..02f18cd1e 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -1 +1,510 @@ --- +_lang_: "বাংলা" +headlineMisskey: "নোট ব্যাবহার করে সংযুক্ত নেটওয়ার্ক" +introMisskey: "স্বাগতম! মিসকি একটি ওপেন সোর্স, ডিসেন্ট্রালাইজড মাইক্রোব্লগিং পরিষেবা। \n\"নোট\" তৈরির মাধ্যমে যা ঘটছে তা সবার সাথে শেয়ার করুন 📡\n\"রিঅ্যাকশন\" গুলির মাধ্যমে যেকোনো নোট সম্পর্কে আপনার অনুভূতি ব্যাক্ত করতে পারেন 👍\nএকটি নতুন দুনিয়া ঘুরে দেখুন 🚀\n" +monthAndDay: "{day}/{month}" +search: "খুঁজুন" +notifications: "বিজ্ঞপ্তি" +username: "ব্যবহারকারীর নাম" +password: "পাসওয়ার্ড" +forgotPassword: "পাসওয়ার্ড ভুলে গেছেন" +fetchingAsApObject: "ফেডিভার্স থেকে খবর আনা হচ্ছে..." +ok: "ঠিক" +gotIt: "বুঝেছি" +cancel: "বাতিল" +enterUsername: "ইউজারনেম লিখুন" +renotedBy: "{user} রিনোট করেছেন" +noNotes: "কোন নোট নেই" +noNotifications: "কোনো বিজ্ঞপ্তি নেই" +instance: "ইন্সট্যান্স" +settings: "সেটিংস" +basicSettings: "সাধারণ সেটিংস" +otherSettings: "অন্যান্য সেটিংস" +openInWindow: "নতুন উইন্ডোতে খুলা" +profile: "প্রোফাইল" +timeline: "টাইমলাইন" +noAccountDescription: "এই ব্যাবহারকারীর কোন বায়ো নেই" +login: "প্রবেশ করুন" +loggingIn: "প্রবেশ করা হচ্ছে..." +logout: "লগআউট" +signup: "নিবন্ধন করুন" +uploading: "আপলোড হচ্ছ …" +save: "সংরক্ষণ" +users: "ব্যবহারকারীগণ" +addUser: "ব্যবহারকারী যোগ করুন" +favorite: "পছন্দ" +favorites: "পছন্দগুলি" +unfavorite: "পছন্দ না" +favorited: "পছন্দ করা হয়েছে" +alreadyFavorited: "ইতিমধ্যে পছন্দ করা হয়েছে" +cantFavorite: "পছন্দ করা যায়নি" +pin: "পিন করা" +unpin: "পিন সরান" +copyContent: "বিষয়বস্তু কপি করুন" +copyLink: "লিঙ্ক কপি করুন" +delete: "মুছুন" +deleteAndEdit: "মুছুন এবং সম্পাদনা করুন" +deleteAndEditConfirm: "আপনি কি এই নোটটি মুছে এটি সম্পাদনা করার বিষয়ে নিশ্চিত? আপনি এটির সমস্ত রিঅ্যাকশন, রিনোট এবং জবাব হারাবেন।" +addToList: "লিস্ট এ যোগ করুন" +sendMessage: "একটি বার্তা পাঠান" +copyUsername: "ব্যবহারকারীর নাম কপি করুন" +searchUser: "ব্যবহারকারী খুঁজুন..." +reply: "জবাব" +loadMore: "আরও দেখুন" +showMore: "আরও দেখুন" +youGotNewFollower: "আপনাকে অনুসরণ করছে" +receiveFollowRequest: "অনুসরণ করার জন্য অনুরোধ পাওয়া গেছে" +followRequestAccepted: "অনুসরণ করার অনুরোধ গৃহীত হয়েছে" +mention: "উল্লেখ" +mentions: "উল্লেখসমূহ" +directNotes: "ডাইরেক্ট নোটগুলি" +importAndExport: "আমদানি এবং রপ্তানি" +import: "আমদানি করুণ" +export: "রপ্তানি" +files: "ফাইলগুলি" +download: "ডাউনলোড" +driveFileDeleteConfirm: "আপনি কি নিশ্চিত যে আপনি \"{name}\" ডিলিট করতে চান? যে সকল নোটের সাথে এই ফাইলটি সংযুক্ত সেগুলোও ডিলিট করা হবে।" +unfollowConfirm: "{name} কে আনফলোও করার ব্যাপারে নিশ্চিত?" +exportRequested: "আপনার তথ্যসমূহ রপ্তানির জন্য অনুরোধ করেছেন। এতে কিছু সময় লাগতে পারে। রপ্তানি সম্পন্ন হলে তা আপনার ড্রাইভে সংরক্ষিত হবে।" +importRequested: "আপনার তথ্যসমূহ আমদানির জন্য অনুরোধ করেছেন। এতে কিছু সময় লাগতে পারে। " +lists: "লিস্ট" +noLists: "কোন লিস্ট নেই" +note: "নোট" +notes: "নোটগুলি" +following: "অনুসরণ করা হচ্ছে" +followers: "অনুসরণকারী" +followsYou: "আপনাকে অনুসরণ করে" +createList: "লিস্ট তৈরি করুন" +manageLists: "লিস্ট ব্যাবস্থাপনা" +error: "সমস্যা" +somethingHappened: "একটি ত্রুটি হয়েছে" +retry: "আবার চেষ্টা করুন" +pageLoadError: "পেজ লোড করা যায়নি" +pageLoadErrorDescription: "এটি সাধারনত নেটওয়ার্কের সমস্যার বা ব্রাউজার ক্যাশের কারণে ঘটে থাকে। ব্রাউজার এর ক্যাশ পরিষ্কার করুন এবং একটু পর আবার চেষ্টা করুন। " +serverIsDead: "এই সার্ভার বর্তমানে সাড়া দিচ্ছে না। একটু পরে আবার চেষ্টা করুন।" +youShouldUpgradeClient: "এই পেজ দেখার জন্য আপনার ব্রাউজার রিফ্রেশ করে ক্লায়েন্ট আপডেট করুন। " +enterListName: "লিস্টের নাম লিখুন" +privacy: "গোপনীয়তা" +makeFollowManuallyApprove: "অনুসরণ করার অনুরোধগুলি গৃহীত হওয়ার জন্য আপনার অনুমতি লাগবে" +defaultNoteVisibility: "ডিফল্ট দৃশ্যমান্যতা" +follow: "অনুসরণ" +followRequest: "অনুসরণ করার অনুরোধ" +followRequests: "অনুসরণ করার অনুরোধসমূহ" +unfollow: "অনুসরণ বাতিল" +followRequestPending: "অনুসরণ করার অনুরোধ বিচারাধীন" +enterEmoji: "ইমোজি প্রবেশ করান" +renote: "রিনোট" +unrenote: "রিনোট সরান " +renoted: "রিনোট করা হয়েছে" +cantRenote: "এই নোটটি রিনোট করা যাবে না।" +cantReRenote: "রিনোটকে রিনোট করা যাবে না।" +quote: "উদ্ধৃতি" +pinnedNote: "পিন করা নোট" +pinned: "পিন করা" +you: "আপনি" +clickToShow: "দেখার জন্য ক্লিক করুন" +sensitive: "সংবেদনশীল বিষয়বস্তু" +add: "যুক্ত করুন" +reaction: "প্রতিক্রিয়া" +reactionSetting: "রিঅ্যাকশন পিকারে যেসকল প্রতিক্রিয়া দেখানো হবে" +reactionSettingDescription2: "পুনরায় সাজাতে টেনে আনুন, মুছতে ক্লিক করুন, যোগ করতে + টিপুন।" +rememberNoteVisibility: "নোটের দৃশ্যমান্যতার সেটিংস মনে রাখুন" +attachCancel: "অ্যাটাচমেন্ট সরান " +markAsSensitive: "সংবেদনশীল হিসাবে চিহ্নিত করুন" +unmarkAsSensitive: "সংবেদনশীল চিহ্ন সরান" +enterFileName: "ফাইলের নাম লিখুন" +mute: "মিউট" +unmute: "আনমিউট" +block: "ব্লক" +unblock: "ব্লক সরান" +suspend: "স্থগিত করা" +unsuspend: "অস্থগিত করা" +blockConfirm: "ব্লক করতে চান?" +unblockConfirm: "ব্লক সরাতে চান?" +suspendConfirm: "স্থগিত করতে চান?" +unsuspendConfirm: "অস্থগিত করতে চান?" +selectList: "লিস্ট নির্বাচন করুন" +selectAntenna: "অ্যান্টেনা নির্বাচন করুন" +selectWidget: "উইজেট নির্বাচন করুন" +editWidgets: "উইজেট সম্পাদনা করুন" +editWidgetsExit: "সম্পাদনা শেষ করুন" +customEmojis: "স্বনির্ধারিত ইমোজিগুলি" +emoji: "ইমোজি" +emojis: "ইমোজিগুলি" +emojiName: "ইমোজির নাম" +emojiUrl: "ইমোজির URL" +addEmoji: "ইমোজি যুক্ত করুন" +settingGuide: "সুপারিশকৃত সেটিংস" +cacheRemoteFiles: "রিমোট ফাইলসমুহ ক্যাশ করুন" +cacheRemoteFilesDescription: "যখন এই অপশনটি বন্ধ থাকে তখন রিমোট ফাইল সমূহ সরাসরি রিমোট ইন্সট্যান্স থেকে লোড করা হয়। এই অপশনটি বন্ধ করলে স্টোরেজ এর ব্যাবহার কমবে তবে থাম্বনেইল তৈরি না করার কারণে নেটওয়ার্ক ব্যান্ডউইথ বেশী লাগবে। " +flagAsBot: "বট হিসাবে চিহ্নিত করুন" +flagAsBotDescription: "এই অ্যাকাউন্টটি যদি একটি প্রোগ্রাম দ্বারা পরিচালিত হয়, তাহলে এই অপশনটি চালু করুন। ইন্টারঅ্যাকশান চেইনিং রোধ করতে, মিস্কির সিস্টেম পরিচালনাকে বট-বান্ধব করতে এবং অন্যান্য ডেভেলপারদের সাহায্য করতে আপনার বট এ এই অপশনটি চালু করুন৷" +flagAsCat: "বিড়াল হিসাবে চিহ্নিত করুন" +flagAsCatDescription: "অ্যাকাউন্টটিকে বিড়াল হিসাবে চিহ্নিত করার জন্য অপশনটি চালু করুন।" +autoAcceptFollowed: "আপনি যেসব অ্যাকাউন্ট অনুসরণ করেন, স্বয়ংক্রিয়ভাবে তাদের অনুসরণের অনুরধ স্বীকার করুন" +addAccount: "অ্যাকাউন্ট যোগ করুন" +loginFailed: "প্রবেশ করা যায়নি" +showOnRemote: "রিমোট সার্ভারে দেখুন" +general: "সাধারণ" +wallpaper: "ওয়ালপেপার" +setWallpaper: "ওয়ালপেপার সেট করুন" +removeWallpaper: "ওয়ালপেপার সরান" +searchWith: "খুঁজুন: {q}" +youHaveNoLists: "আপনার কোন লিস্ট নেই" +followConfirm: "{name} কে ফলোও করার ব্যাপারে নিশ্চিত?" +proxyAccount: "প্রক্সি অ্যাকাউন্ট" +proxyAccountDescription: "একটি প্রক্সি অ্যাকাউন্ট এমন একটি অ্যাকাউন্ট যা নির্দিষ্ট শর্তে ব্যবহারকারীদের জন্য রিমোট অনুসরণকারী হিসাবে কাজ করে। উদাহরণস্বরূপ, যখন একজন ব্যবহারকারী একটি রিমোট ব্যবহারকারীকে তালিকাভুক্ত করে, তখন ক্রিয়াকলাপের দৃষ্টান্তে বিতরণ করা হবে না যদি না কেউ তালিকাভুক্ত ব্যবহারকারীকে অনুসরণ করে, তাই প্রক্সি অ্যাকাউন্ট দ্বারা তাকে অনুসরণ করা হবে।" +host: "হোস্ট" +selectUser: "ব্যবহারকারী নির্বাচন করুন" +recipient: "প্রতি" +annotation: "মন্তব্য" +federation: "ফেডিভার্স" +instances: "ইন্সট্যান্স" +registeredAt: "যোগ দিয়েছেন" +latestRequestSentAt: "শেষ রিকুয়েস্ট পাঠানো হয়েছে" +latestRequestReceivedAt: "শেষ রিকুয়েস্ট গৃহীত হয়েছে" +latestStatus: "সর্বশেষ অবস্থা" +storageUsage: "স্টোরেজের ব্যাবহার" +charts: "চার্ট" +perHour: "ঘন্টা প্রতি" +perDay: "দৈনিক" +stopActivityDelivery: "অ্যাক্টিভিটি পাঠানো বন্ধ করুন" +blockThisInstance: "ইন্সট্যান্স ব্লক করুন" +operations: "ক্রিয়াকলাপ" +software: "সফটওয়্যার" +version: "সংস্করণ" +metadata: "মেটাডাটা" +withNFiles: "{n} টি ফাইল" +monitor: "মনিটর" +jobQueue: "জব কিউ" +cpuAndMemory: "সিপিউ এবং মেমরি" +network: "নেটওয়ার্ক" +disk: "ডিস্ক" +instanceInfo: "ইন্সট্যান্সের তথ্য" +statistics: "পরিসংখ্যান" +clearQueue: "কিউ পরিষ্কার করুন" +clearQueueConfirmTitle: "আপনি কি কিউ পরিষ্কার করার ব্যাপারে নিশ্চিত?" +clearQueueConfirmText: "বিতরণ না করা নোট আর বিতরণ করা হবে না। সাধারণত আপনার এটি করার দরকার নেই।" +clearCachedFiles: "ক্যাশ পরিষ্কার করুন" +clearCachedFilesConfirm: "আপনি কি ক্যাশ পরিষ্কার করার ব্যাপারে নিশ্চিত?" +blockedInstances: "ব্লককৃত ইন্সট্যান্সসমুহ" +blockedInstancesDescription: "আপনি যে ইন্সট্যান্সগুলি ব্লক করতে চান তার হোস্টনেমগুলি প্রত্যেকটি আলাদা লাইনে লিখুন। ব্লককৃত ইন্সট্যান্সগুলি এই ইন্সট্যান্সের সাথে যোগাযোগ করতে পারবেনা৷" +muteAndBlock: "মিউট এবং ব্লকগুলি" +mutedUsers: "নিঃশব্দকৃত ব্যবহারকারী" +blockedUsers: "যাদের ব্লক করা হয়েছে" +noUsers: "কোন ব্যাবহারকারী নেই" +editProfile: "প্রোফাইল সম্পাদনা করুন" +noteDeleteConfirm: "আপনি কি নোট ডিলিট করার ব্যাপারে নিশ্চিত?" +pinLimitExceeded: "আপনি আর কোন নোট পিন করতে পারবেন না" +intro: "Misskey এর ইন্সটলেশন সম্পন্ন হয়েছে!দয়া করে অ্যাডমিন ইউজার তৈরি করুন।" +done: "সম্পন্ন" +processing: "প্রক্রিয়াধীন..." +preview: "পূর্বরূপ দেখুন" +default: "পূর্বনির্ধারিত" +noCustomEmojis: "কোন ইমোজি নাই" +noJobs: "কোন জব নাই" +federating: "ফেডারেট করা হচ্ছে" +blocked: "ব্লক করা হয়েছে" +suspended: "স্থগিত করা হয়েছে" +all: "সবগুলো" +subscribing: "সদস্যতা নেয়া হচ্ছে" +publishing: "প্রকাশ করা হচ্ছে" +notResponding: "সাড়া নেই" +instanceFollowing: "ইন্সট্যান্স অনুসরণ করা হচ্ছে" +instanceFollowers: "ইন্সট্যান্স অনুসরণকারী" +instanceUsers: "ইন্সট্যান্স ব্যাবহারকারী" +changePassword: "পাসওয়ার্ড পরিবর্তন করুন" +security: "নিরাপত্তা" +retypedNotMatch: "ইনপুট মেলে না।" +currentPassword: "বর্তমান পাসওয়ার্ড" +newPassword: "নতুন পাসওয়ার্ড" +newPasswordRetype: "নতুন পাসওয়ার্ড (পুনরায় লিখুন)" +attachFile: "ফাইল সংযুক্ত করুন" +more: "আরও!" +featured: "হাইলাইট" +usernameOrUserId: "ব্যাবহারকারীর নাম বা ব্যাবহারকারী ID" +noSuchUser: "কোন ব্যবহারকারী খুঁজে পাওয়া যায়নি" +lookup: "খুঁজে দেখো" +announcements: "ঘোষণা" +imageUrl: "চিত্রের URL" +remove: "মুছুন" +removed: "সরানো হয়েছে" +removeAreYouSure: "আপনি কি \"{x}\" সরানোর ব্যাপারে নিশ্চিত?" +deleteAreYouSure: "আপনি কি \"{x}\" সরানোর ব্যাপারে নিশ্চিত?" +resetAreYouSure: "রিসেট করার ব্যাপারে নিশ্চিত?" +saved: "সংরক্ষিত হয়েছে" +messaging: "চ্যাট" +upload: "আপলোড" +keepOriginalUploading: "আসল ছবি রাখুন" +keepOriginalUploadingDescription: "ছবিটি আপলোড করার সময় আসল সংস্করণটি রাখুন। অপশনটি বন্ধ থাকলে, আপলোডের সময় ওয়েব প্রকাশনার জন্য ছবি ব্রাউজারে তৈরি করা হবে।" +fromDrive: "ড্রাইভ হতে" +fromUrl: "URL হতে" +uploadFromUrl: "URL হতে আপলোড" +uploadFromUrlDescription: "যে ফাইলটি আপলোড করতে চান, সেটির URL" +uploadFromUrlRequested: "আপলোড অনুরোধ করা হয়েছে" +uploadFromUrlMayTakeTime: "URL হতে আপলোড হতে কিছু সময় লাগতে পারে।" +explore: "ঘুরে দেখুন" +messageRead: "পড়া" +noMoreHistory: "আর কোন ইতিহাস নেই" +startMessaging: "চ্যাট শুরু করুন" +nUsersRead: "{n} জন পড়েছেন" +agreeTo: "{0} এর প্রতি আমি সম্মত" +tos: "পরিষেবার শর্তাদি" +start: "শুরু করুন" +home: "মূল পাতা" +remoteUserCaution: "এই ব্যাবহারকারী রিমোট ইন্সট্যান্সের, নিম্নক্ত তথ্য অসম্পূর্ণ হতে পারে।" +activity: "কার্যকলাপ" +images: "ছবি" +birthday: "জন্মদিন" +yearsOld: "{age} বছর" +registeredDate: "যোগদানের তারিখ" +location: "অবস্থান" +theme: "থিম" +themeForLightMode: "লাইট মোডের থিম" +themeForDarkMode: "ডার্ক মোডের থিম" +light: "আলোকিত" +dark: "অন্ধকার" +lightThemes: "আলোকিত থিম" +darkThemes: "অন্ধকার থিম" +syncDeviceDarkMode: "ডিভাইসের সেটিং অনুযায়ী ডার্ক মোড সেট করুন" +drive: "ড্রাইভ" +fileName: "ফাইলের নাম" +selectFile: "ফাইল নির্বাচন করুন" +selectFiles: "ফাইল নির্বাচন করুন" +selectFolder: "ফোল্ডার নির্বাচন করুন" +selectFolders: "ফোল্ডার নির্বাচন করুন" +renameFile: "ফাইল পুনঃনামকরন" +folderName: "ফোল্ডারের নাম" +createFolder: "ফোল্ডার তৈরি করুন" +renameFolder: "ফোল্ডার পুনঃনামকরন" +deleteFolder: "ফোল্ডার মুছুন" +addFile: "ফাইল যোগ করুন" +emptyDrive: "আপনার ড্রাইভ খালি" +emptyFolder: "এই ফোল্ডার খালি" +unableToDelete: "মুছে ফেলা যায়নি" +inputNewFileName: "ফাইলের নতুন নাম লিখুন" +inputNewDescription: "নতুন ক্যাপশন লিখুন" +inputNewFolderName: "ফোল্ডারের নতুন নাম লিখুন" +circularReferenceFolder: "গন্তব্য ফোল্ডারটি আপনি যে ফোল্ডারটি সরাতে চান তার একটি সাবফোল্ডার।" +hasChildFilesOrFolders: "এই ফোল্ডারটি খালি না হওয়ায় ডিলিট করা যায়নি।" +copyUrl: "URL কপি করুন" +rename: "পুনঃনামকরণ" +avatar: "প্রোফাইল ছবি" +banner: "ব্যানার" +nsfw: "সংবেদনশীল বিষয়বস্তু" +whenServerDisconnected: "সার্ভারের সাথে সংযোগ বিচ্ছিন্ন হয়ে গেলে" +disconnectedFromServer: "সার্ভার থেকে সংযোগ বিচ্ছিন্ন হয়েছে" +reload: "আবার লোড করুন" +doNothing: "কিছু করবেন না" +reloadConfirm: "আপনি কি রিলোড করতে চান?" +watch: "দেখুন" +unwatch: "দেখা বন্ধ করুন " +accept: "অনুমোদন" +reject: "প্রত্যাখ্যান" +normal: "স্বাভাবিক" +instanceName: "ইন্সট্যান্সের নাম" +instanceDescription: "ইন্সট্যান্সের বর্ণনা" +maintainerName: "মেইনটেইনার" +maintainerEmail: "মেইনটেইনারের ইমেইল" +tosUrl: "ব্যবহারের শর্তাবলীর URL" +thisYear: "বছর" +thisMonth: "মাস" +today: "আজ" +dayX: "{day}" +monthX: "{month}" +yearX: "{year}" +pages: "পৃষ্ঠা" +integration: "ইন্টিগ্রেশন" +connectService: "সংযুক্ত করুন" +disconnectService: "সংযোগ বিচ্ছিন্ন করুন" +enableLocalTimeline: "স্থানীয় টাইমলাইন চালু করুন" +enableGlobalTimeline: "গ্লোবাল টাইমলাইন চালু করুন" +disablingTimelinesInfo: "আপনি এই টাইমলাইনগুলি বন্ধ করলেও প্রশাসক এবং মডারেটররা এই টাইমলাইনগুলি ব্যাবহার করতে পারবে" +registration: "নিবন্ধন" +enableRegistration: "নতুন ব্যাবহারকারী নিবন্ধন চালু করুন" +invite: "আমন্ত্রণ" +proxyRemoteFiles: "রিমোট ফাইলসমুহ প্রক্সি করুন" +proxyRemoteFilesDescription: "যখন এই সেটিংটি চালু থাকে, তখন অসংরক্ষিত বা অতিরিক্ত ক্ষমতার কারণে দূরবর্তী ফাইলগুলিকে স্থানীয়ভাবে প্রক্সি করা হবে এবং থাম্বনেলগুলিও তৈরি করা হবে৷ সার্ভার স্টোরেজ ব্যাবহার করে না," +driveCapacityPerLocalAccount: "প্রত্যেক স্থানীয় ব্যাবহারকারীর জন্য ড্রাইভের জায়গা" +driveCapacityPerRemoteAccount: "প্রত্যেক রিমোট ব্যাবহারকারীর জন্য ড্রাইভের জায়গা" +inMb: "মেগাবাইটে লিখুন" +iconUrl: "আইকনের URL (ফ্যাভিকন, ইত্যাদি)" +bannerUrl: "ব্যানার ছবির URL" +backgroundImageUrl: "পটভূমির চিত্রের URL" +basicInfo: "আপনার ব্যক্তিগত তথ্য" +pinnedUsers: "পিন করা ব্যাবহারকারীগণ" +pinnedUsersDescription: "আপনি যেসব ব্যবহারকারীদের \"ঘুরে দেখুন\" পৃষ্ঠায় পিন করতে চান তাদের বর্ণনা করুন, প্রত্যেকের বর্ণনা আলাদা লাইনে লিখুন" +pinnedPages: "পিন করা পৃষ্ঠাসুমহ" +pinnedPagesDescription: "আপনি যেসকল পৃষ্ঠাসমূহকে \"ঘুরে দেখুন\" পৃষ্ঠায় পিন করতে চান তাদের বর্ণনা করুন, প্রত্যেকের বর্ণনা আলাদা লাইনে লিখুন" +pinnedClipId: "পিনকৃত ক্লিপের ID" +pinnedNotes: "পিন করা নোট" +hcaptcha: "hCaptcha" +enableHcaptcha: "hCaptcha চালু করুন" +hcaptchaSiteKey: "সাইট কী" +hcaptchaSecretKey: "সিক্রেট কী" +recaptcha: "reCAPTCHA" +enableRecaptcha: "reCAPTCHA চালু করুন" +recaptchaSiteKey: "সাইট কী" +antennas: "অ্যান্টেনা" +manageAntennas: "অ্যান্টেনা ব্যবস্থাপনা" +name: "নাম" +antennaSource: "অ্যান্টেনার উৎস" +antennaKeywords: "যেসব কীওয়ার্ড দেখা হবে" +antennaExcludeKeywords: "যেসব কীওয়ার্ড দেখা হবে না" +antennaKeywordsDescription: "স্পেস দিয়ে আলাদা করলে AND শর্ত তৈরি হবে এবং আলাদা লাইনে লিখলে OR শর্ত তৈরি হবে।" +notifyAntenna: "নতুন নোট সম্পর্কে অবহিত করুন" +withFileAntenna: "শুধুমাত্র ফাইলযুক্ত নোট" +enableServiceworker: "ServiceWorker চালু করুন" +antennaUsersDescription: "প্রত্যেক লাইনে একজন ব্যবহারকারীর নাম লিখুন" +caseSensitive: "ছোট হাতের এবং বড় হাতের অক্ষর নির্দিষ্ট করুন" +withReplies: "জবাবসমুহ যুক্ত করুন" +connectedTo: "আপনি নিম্নলিখিত অ্যাকাউন্টের সাথে সংযুক্ত" +notesAndReplies: "নোটসমূহ এবং জবাবগুলি" +withFiles: "ফাইলগুলি যুক্ত করুন" +silence: "নীরব" +silenceConfirm: "আপনি কি এই ব্যাবহারকারীকের নীরব করতে চান?" +unsilence: "সরব" +unsilenceConfirm: "আপনি কি এই ব্যাবহারকারীকের সরব করতে চান?" +popularUsers: "জনপ্রিয় ব্যবহারকারীগন" +recentlyUpdatedUsers: "সম্প্রতি পোস্ট করা ব্যবহারকারীগন" +recentlyRegisteredUsers: "নতুন যোগ দেওয়া ব্যবহারকারীগন" +recentlyDiscoveredUsers: "নতুন খুঁজে পাওয়া ব্যবহারকারীগন" +exploreUsersCount: "{count} জন ব্যাবহারকারী" +exploreFediverse: "Fediverse ঘুরে দেখুন" +popularTags: "জনপ্রিয় ট্যাগগুলি" +userList: "লিস্ট" +about: "আপনার সম্পর্কে" +aboutMisskey: "Misskey সম্পর্কে" +administrator: "প্রশাসক" +token: "টোকেন" +twoStepAuthentication: "২-ধাপ প্রমাণীকরণ" +moderator: "মডারেটর" +nUsersMentioned: "{n} জনকে উল্লেখ করা হয়েছে" +securityKey: "সিকিউরিটি কী" +securityKeyName: "কী'র নাম" +registerSecurityKey: "সিকিউরিটি কী নিবন্ধন করুন" +lastUsed: "শেষ ব্যাবহার করা হয়েছে" +unregister: "নিবন্ধনমুক্ত হন" +passwordLessLogin: "পাসওয়ার্ড-বিহীন লগইন সেট আপ করুন" +resetPassword: "পাসওয়ার্ড রিসেট করুন" +newPasswordIs: "নতুন পাসওয়ার্ড হচ্ছে \"{password}\"" +reduceUiAnimation: "UI অ্যানিমেশন কমান" +share: "শেয়ার" +notFound: "পাওয়া যায়নি" +notFoundDescription: "এই URL-এর সাথে সম্পর্কিত কোনো পৃষ্ঠা নেই।" +uploadFolder: "আপলোডের জন্য ডিফল্ট ফোল্ডার" +cacheClear: "ক্যাশ পরিষ্কার করুন" +markAsReadAllNotifications: "সমস্ত বিজ্ঞপ্তিগুলি পঠিত হিসাবে চিহ্নিত করুন" +markAsReadAllUnreadNotes: "সমস্ত নোটগুলি পঠিত হিসাবে চিহ্নিত করুন" +invites: "আমন্ত্রণ" +invitations: "আমন্ত্রণ" +useOsNativeEmojis: "অপারেটিং সিস্টেমের নেটিভ ইমোজি ব্যবহার করুন" +disableDrawer: "ড্রয়ার মেনু প্রদর্শন করবেন না" +youHaveNoGroups: "আপনার কোন গ্রুপ নেই " +joinOrCreateGroup: "একটি বিদ্যমান গ্রুপের আমন্ত্রণ পান বা একটি নতুন গ্রুপ তৈরি করুন৷" +noHistory: "কোনো ইতিহাস নেই" +signinHistory: "প্রবেশ করার ইতিহাস" +disableAnimatedMfm: "অ্যানিমেটেড MFM অক্ষম করুন" +doing: "প্রক্রিয়া করছে..." +category: "বিভাগ" +tags: "ট‍্যাগসমূহ" +docSource: "ডকুমেন্টের উৎস" +createAccount: "অ্যাকাউন্ট তৈরি করুন" +existingAccount: "বিদ্যমান অ্যাকাউন্ট" +regenerate: "আবারও তৈরি করুন" +fontSize: "ফন্টের আকার" +noFollowRequests: "আপনার কোন ফলোও রিকুয়েস্ট নেই" +openImageInNewTab: "ছবি নতুন ট্যাবে খুলুন" +dashboard: "ড্যাশবোর্ড" +local: "স্থানীয়" +remote: "রিমোট" +total: "মোট" +weekOverWeekChanges: "গত সপ্তাহে" +dayOverDayChanges: "গতকাল" +appearance: "অবয়ব" +clientSettings: "ক্লায়েন্ট সেটিংস" +accountSettings: "অ্যাকাউন্ট সেটিংস" +promotion: "প্রমোশন" +promote: "প্রচার করুন" +numberOfDays: "দিনের সংখ্যা" +hideThisNote: "নোটটি লুকান" +smtpHost: "হোস্ট" +smtpUser: "ব্যবহারকারীর নাম" +smtpPass: "পাসওয়ার্ড" +clearCache: "ক্যাশ পরিষ্কার করুন" +info: "আপনার সম্পর্কে" +user: "ব্যবহারকারীগণ" +controlPanel: "নিয়ন্ত্রন কেন্দ্র" +_email: + _follow: + title: "আপনাকে অনুসরণ করছে" +_mfm: + mention: "উল্লেখ" + quote: "উদ্ধৃতি" + emoji: "স্বনির্ধারিত ইমোজিগুলি" + search: "খুঁজুন" +_theme: + keys: + mention: "উল্লেখ" + renote: "রিনোট" +_sfx: + note: "নোটগুলি" + notification: "বিজ্ঞপ্তি" + chat: "চ্যাট" +_widgets: + notifications: "বিজ্ঞপ্তি" + timeline: "টাইমলাইন" + activity: "কার্যকলাপ" + federation: "ফেডিভার্স" + jobQueue: "জব কিউ" +_cw: + show: "আরও দেখুন" +_visibility: + home: "মূল পাতা" + followers: "অনুসরণকারী" +_profile: + name: "নাম" + username: "ব্যবহারকারীর নাম" +_exportOrImport: + followingList: "অনুসরণ করা হচ্ছে" + muteList: "মিউট" + blockingList: "ব্লক" + userLists: "লিস্ট" +_timelines: + home: "মূল পাতা" +_pages: + blocks: + image: "ছবি" + script: + categories: + list: "লিস্ট" + blocks: + _join: + arg1: "লিস্ট" + _randomPick: + arg1: "লিস্ট" + _dailyRandomPick: + arg1: "লিস্ট" + _seedRandomPick: + arg2: "লিস্ট" + _pick: + arg1: "লিস্ট" + _listLen: + arg1: "লিস্ট" + types: + array: "লিস্ট" +_notification: + youWereFollowed: "আপনাকে অনুসরণ করছে" + _types: + follow: "অনুসরণ করা হচ্ছে" + mention: "উল্লেখ" + renote: "রিনোট" + quote: "উদ্ধৃতি" + reaction: "প্রতিক্রিয়া" +_deck: + _columns: + notifications: "বিজ্ঞপ্তি" + tl: "টাইমলাইন" + antenna: "অ্যান্টেনা" + list: "লিস্ট" + mentions: "উল্লেখসমূহ" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 2f327a905..05360e170 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -235,6 +235,8 @@ resetAreYouSure: "Wirklich zurücksetzen?" saved: "Gespeichert" messaging: "Chat" upload: "Hochladen" +keepOriginalUploading: "Originalbild speichern" +keepOriginalUploadingDescription: "Speichert das Originalbild so, wie es ist. Ist dies deaktiviert, wird eine Version zum Anzeigen im Internet generiert." fromDrive: "Aus Drive" fromUrl: "Von einer URL" uploadFromUrl: "Von einer URL hochladen" diff --git a/locales/en-US.yml b/locales/en-US.yml index 6bbe84821..9a2b0bf5c 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -235,6 +235,8 @@ resetAreYouSure: "Really reset?" saved: "Saved" messaging: "Chat" upload: "Upload" +keepOriginalUploading: "Keep original image" +keepOriginalUploadingDescription: "Saves the originally uploaded image as-is. If turned off, a version to display on the web will be generated on upload." fromDrive: "From Drive" fromUrl: "From URL" uploadFromUrl: "Upload from a URL" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 58dd000cc..62f85bef8 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -235,6 +235,7 @@ resetAreYouSure: "Voulez-vous réinitialiser ?" saved: "Enregistré" messaging: "Discuter" upload: "Téléverser" +keepOriginalUploading: "Garder l’image d’origine" fromDrive: "Depuis le Drive" fromUrl: "Depuis une URL" uploadFromUrl: "Téléverser via une URL" @@ -743,6 +744,7 @@ notRecommended: "Déconseillé" botProtection: "Protection contre les bots" instanceBlocking: "Instances bloquées" selectAccount: "Sélectionner un compte" +switchAccount: "Changer de compte" enabled: "Activé" disabled: "Désactivé" quickAction: "Actions rapides" @@ -803,6 +805,7 @@ makeReactionsPublic: "Rendre les réactions publiques" makeReactionsPublicDescription: "Ceci rendra la liste de toutes vos réactions données publique." classic: "Classique" muteThread: "Mettre ce thread en sourdine" +unmuteThread: "Ne plus masquer le fil" ffVisibility: "Visibilité des abonnés/abonnements" ffVisibilityDescription: "Permet de configurer qui peut voir les personnes que tu suis et les personnes qui te suivent." continueThread: "Afficher la suite du fil" @@ -1241,6 +1244,7 @@ _exportOrImport: muteList: "Comptes masqués" blockingList: "Comptes bloqués" userLists: "Listes" + excludeMutingUsers: "Exclure les utilisateur·rice·s mis en sourdine" excludeInactiveUsers: "Exclure les utilisateur·rice·s inactifs" _charts: federationInstancesIncDec: "Variation du nombre d'instances fédérées" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b3279d78b..8fd41e533 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -235,6 +235,8 @@ resetAreYouSure: "リセットしますか?" saved: "保存しました" messaging: "チャット" upload: "アップロード" +keepOriginalUploading: "オリジナル画像を保持" +keepOriginalUploadingDescription: "画像をアップロードする時にオリジナル版を保持します。オフにするとアップロード時にブラウザでWeb公開用画像を生成します。" fromDrive: "ドライブから" fromUrl: "URLから" uploadFromUrl: "URLアップロード" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 7451603a6..38a328862 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -106,6 +106,7 @@ clickToShow: "클릭하여 보기" sensitive: "열람주의" add: "추가" reaction: "리액션" +reactionSetting: "선택기에 표시할 리액션" reactionSettingDescription2: "끌어서 순서 변경, 클릭해서 삭제, +를 눌러서 추가할 수 있습니다." rememberNoteVisibility: "공개 범위를 기억하기" attachCancel: "첨부 취소" @@ -234,6 +235,8 @@ resetAreYouSure: "초기화 하시겠습니까?" saved: "저장하였습니다" messaging: "대화" upload: "업로드" +keepOriginalUploading: "원본 이미지를 유지" +keepOriginalUploadingDescription: "이미지를 업로드할 때에 원본을 그대로 유지합니다. 비활성화하면 업로드할 때 브라우저에서 웹 공개용 이미지를 생성합니다." fromDrive: "드라이브에서" fromUrl: "URL로부터" uploadFromUrl: "URL 업로드" @@ -446,6 +449,7 @@ uiLanguage: "UI 표시 언어" groupInvited: "그룹에 초대되었습니다" aboutX: "{x}에 대하여" useOsNativeEmojis: "OS 기본 이모지를 사용" +disableDrawer: "드로어 메뉴를 사용하지 않기" youHaveNoGroups: "그룹이 없습니다" joinOrCreateGroup: "다른 그룹의 초대를 받거나, 직접 새 그룹을 만들어 보세요." noHistory: "기록이 없습니다" @@ -617,8 +621,11 @@ reportAbuse: "신고" reportAbuseOf: "{name}을 신고하기" fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요." abuseReported: "신고를 보냈습니다. 신고해 주셔서 감사합니다." +reporter: "신고자" reporteeOrigin: "피신고자" reporterOrigin: "신고자" +forwardReport: "리모트 인스턴스에도 신고 내용 보내기" +forwardReportIsAnonymous: "리모트 인스턴스에서는 나의 정보를 볼 수 없으며, 익명의 시스템 계정으로 표시됩니다." send: "전송" abuseMarkAsResolved: "해결됨으로 표시" openInNewTab: "새 탭에서 열기" @@ -680,6 +687,7 @@ center: "가운데" wide: "넓게" narrow: "좁게" reloadToApplySetting: "이 설정을 적용하려면 페이지를 새로고침해야 합니다. 바로 새로고침하시겠습니까?" +needReloadToApply: "변경 사항은 새로고침하면 적용됩니다." showTitlebar: "타이틀 바를 표시하기" clearCache: "캐시 비우기" onlineUsersCount: "{n}명이 접속 중" @@ -740,6 +748,7 @@ notRecommended: "추천하지 않음" botProtection: "Bot 방어" instanceBlocking: "인스턴스 차단" selectAccount: "계정 선택" +switchAccount: "계정 바꾸기" enabled: "활성화" disabled: "비활성화" quickAction: "빠른 동작" @@ -808,6 +817,11 @@ deleteAccountConfirm: "계정이 삭제되고 되돌릴 수 없게 됩니다. incorrectPassword: "비밀번호가 올바르지 않습니다." voteConfirm: "\"{choice}\"에 투표하시겠습니까?" hide: "숨기기" +leaveGroup: "그룹 나가기" +leaveGroupConfirm: "\"{name}\"에서 나갈까요?" +useDrawerReactionPickerForMobile: "모바일에서 드로어 메뉴로 표시" +welcomeBackWithName: "환영합니다, {name}님" +clickToFinishEmailVerification: "[{ok}]를 눌러 이메일 인증을 완료하세요." _emailUnavailable: used: "이 메일 주소는 사용중입니다" format: "형식이 올바르지 않습니다" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 5815c92f4..c54e64214 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -235,6 +235,8 @@ resetAreYouSure: "恢复默认设置?" saved: "已保存" messaging: "聊天" upload: "本地上传" +keepOriginalUploading: "保留原图" +keepOriginalUploadingDescription: "上传图片时保留原始图片。关闭时,浏览器会在上传时生成一张用于web发布的图片。" fromDrive: "从网盘中" fromUrl: "从 URL" uploadFromUrl: "从网址上传" @@ -619,8 +621,11 @@ reportAbuse: "举报" reportAbuseOf: "举报{name}" fillAbuseReportDescription: "请填写举报的详细原因。如果有对方发的帖子,请同时填写URL地址。" abuseReported: "内容已发送。感谢您的报告。" +reporter: "报告者" reporteeOrigin: "举报来源" reporterOrigin: "举报者来源" +forwardReport: "将报告转发给远程实例" +forwardReportIsAnonymous: "在远程实例上显示的报告者是匿名的系统账号,而不是您的账号。" send: "发送" abuseMarkAsResolved: "处理完毕" openInNewTab: "在新标签页中打开" diff --git a/package.json b/package.json index d94567298..8243935bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "12.102.1", + "version": "12.103.0", "codename": "indigo", "repository": { "type": "git", diff --git a/packages/backend/package.json b/packages/backend/package.json index 3d3a901f3..3541e803f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -122,7 +122,7 @@ "langmap": "0.0.16", "mfm-js": "0.21.0", "mime-types": "2.1.34", - "misskey-js": "0.0.13", + "misskey-js": "0.0.14", "mocha": "8.4.0", "ms": "3.0.0-canary.1", "multer": "1.4.4", diff --git a/packages/backend/src/server/api/api-handler.ts b/packages/backend/src/server/api/api-handler.ts index faa35d12d..362bbb0f5 100644 --- a/packages/backend/src/server/api/api-handler.ts +++ b/packages/backend/src/server/api/api-handler.ts @@ -32,7 +32,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { // Authentication authenticate(body['i']).then(([user, app]) => { // API invoking - call(endpoint.name, user, app, body, (ctx as any).file).then((res: any) => { + call(endpoint.name, user, app, body, ctx).then((res: any) => { reply(res); }).catch((e: ApiError) => { reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e); diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts index 399ee65bd..5bc7d2f25 100644 --- a/packages/backend/src/server/api/call.ts +++ b/packages/backend/src/server/api/call.ts @@ -1,3 +1,4 @@ +import * as Koa from 'koa'; import { performance } from 'perf_hooks'; import { limiter } from './limiter'; import { User } from '@/models/entities/user'; @@ -12,7 +13,7 @@ const accessDenied = { id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e', }; -export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, file?: any) => { +export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, ctx?: Koa.Context) => { const isSecure = user != null && token == null; const ep = endpoints.find(e => e.name === endpoint); @@ -76,9 +77,20 @@ export default async (endpoint: string, user: User | null | undefined, token: Ac }); } + // Cast non JSON input + if (ep.meta.requireFile && ep.meta.params) { + const body = (ctx!.request as any).body; + for (const k of Object.keys(ep.meta.params)) { + const param = ep.meta.params[k]; + if (['Boolean', 'Number'].includes(param.validator.name) && typeof body[k] === 'string') { + body[k] = JSON.parse(body[k]); + } + } + } + // API invoking const before = performance.now(); - return await ep.exec(data, user, token, file).catch((e: Error) => { + return await ep.exec(data, user, token, ctx!.file).catch((e: Error) => { if (e instanceof ApiError) { throw e; } else { diff --git a/packages/backend/src/server/api/endpoints/drive/files/create.ts b/packages/backend/src/server/api/endpoints/drive/files/create.ts index dd65ab061..877e76677 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/create.ts @@ -39,15 +39,13 @@ export const meta = { }, isSensitive: { - validator: $.optional.either($.bool, $.str), + validator: $.optional.bool, default: false, - transform: (v: any): boolean => v === true || v === 'true', }, force: { - validator: $.optional.either($.bool, $.str), + validator: $.optional.bool, default: false, - transform: (v: any): boolean => v === true || v === 'true', }, }, diff --git a/packages/backend/src/server/file/index.ts b/packages/backend/src/server/file/index.ts index a455acd1c..6fe6110dc 100644 --- a/packages/backend/src/server/file/index.ts +++ b/packages/backend/src/server/file/index.ts @@ -18,7 +18,7 @@ const _dirname = dirname(_filename); const app = new Koa(); app.use(cors()); app.use(async (ctx, next) => { - ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`); + ctx.set('Content-Security-Policy', `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`); await next(); }); diff --git a/packages/backend/src/server/proxy/index.ts b/packages/backend/src/server/proxy/index.ts index b8993f19f..7a3094311 100644 --- a/packages/backend/src/server/proxy/index.ts +++ b/packages/backend/src/server/proxy/index.ts @@ -11,7 +11,7 @@ import { proxyMedia } from './proxy-media'; const app = new Koa(); app.use(cors()); app.use(async (ctx, next) => { - ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`); + ctx.set('Content-Security-Policy', `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`); await next(); }); diff --git a/packages/backend/yarn.lock b/packages/backend/yarn.lock index 99e2e2306..5bf6e05a7 100644 --- a/packages/backend/yarn.lock +++ b/packages/backend/yarn.lock @@ -4967,10 +4967,10 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -misskey-js@0.0.13: - version "0.0.13" - resolved "https://registry.yarnpkg.com/misskey-js/-/misskey-js-0.0.13.tgz#03a4e469186e28752d599dc4093519eb64647970" - integrity sha512-kBdJdfe281gtykzzsrN3IAxWUQIimzPiJGyKWf863ggWJlWYVPmP9hTFlX2z8oPOaypgVBPEPHyw/jNUdc2DbQ== +misskey-js@0.0.14: + version "0.0.14" + resolved "https://registry.yarnpkg.com/misskey-js/-/misskey-js-0.0.14.tgz#1a616bdfbe81c6ee6900219eaf425bb5c714dd4d" + integrity sha512-bvLx6U3OwQwqHfp/WKwIVwdvNYAAPk0+YblXyxmSG3dwlzCgBRRLcB8o6bNruUDyJgh3t73pLDcOz3myxcUmww== dependencies: autobind-decorator "^2.4.0" eventemitter3 "^4.0.7" diff --git a/packages/client/.eslintrc.js b/packages/client/.eslintrc.js index d414f86ed..acbb7c0c6 100644 --- a/packages/client/.eslintrc.js +++ b/packages/client/.eslintrc.js @@ -18,6 +18,7 @@ module.exports = { // data の禁止理由: 抽象的すぎるため // e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため "id-denylist": ["error", "window", "data", "e"], + 'eqeqeq': ['error', 'always', { 'null': 'ignore' }], "vue/attributes-order": ["error", { "alphabetical": false }], diff --git a/packages/client/package.json b/packages/client/package.json index 71dd89bea..b840bafe8 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -69,7 +69,7 @@ "langmap": "0.0.16", "matter-js": "0.18.0", "mfm-js": "0.21.0", - "misskey-js": "0.0.13", + "misskey-js": "0.0.14", "mocha": "8.4.0", "ms": "2.1.3", "nested-property": "4.0.0", diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts index 5a935e1dc..4aeceecca 100644 --- a/packages/client/src/account.ts +++ b/packages/client/src/account.ts @@ -192,31 +192,31 @@ export async function openAccountMenu(opts: { if (opts.withExtraOperation) { popupMenu([...[{ type: 'link', - text: i18n.locale.profile, + text: i18n.ts.profile, to: `/@${ $i.username }`, avatar: $i, }, null, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, { icon: 'fas fa-plus', - text: i18n.locale.addAccount, + text: i18n.ts.addAccount, action: () => { popupMenu([{ - text: i18n.locale.existingAccount, + text: i18n.ts.existingAccount, action: () => { showSigninDialog(); }, }, { - text: i18n.locale.createAccount, + text: i18n.ts.createAccount, action: () => { createAccount(); }, - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); }, }, { type: 'link', icon: 'fas fa-users', - text: i18n.locale.manageAccounts, + text: i18n.ts.manageAccounts, to: `/settings/accounts`, - }]], ev.currentTarget || ev.target, { + }]], ev.currentTarget ?? ev.target, { align: 'left' }); } else { - popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget || ev.target, { + popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget ?? ev.target, { align: 'left' }); } diff --git a/packages/client/src/components/abuse-report-window.vue b/packages/client/src/components/abuse-report-window.vue index cd04f62bc..f2cb36980 100644 --- a/packages/client/src/components/abuse-report-window.vue +++ b/packages/client/src/components/abuse-report-window.vue @@ -2,7 +2,7 @@ diff --git a/packages/client/src/components/channel-preview.vue b/packages/client/src/components/channel-preview.vue index 8d135a192..dd3794a65 100644 --- a/packages/client/src/components/channel-preview.vue +++ b/packages/client/src/components/channel-preview.vue @@ -6,7 +6,7 @@
- + @@ -14,7 +14,7 @@
- + @@ -27,7 +27,7 @@
- {{ i18n.locale.updatedAt }}: + {{ i18n.ts.updatedAt }}:
diff --git a/packages/client/src/components/chart-tooltip.vue b/packages/client/src/components/chart-tooltip.vue new file mode 100644 index 000000000..b080eaf2b --- /dev/null +++ b/packages/client/src/components/chart-tooltip.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/packages/client/src/components/chart.vue b/packages/client/src/components/chart.vue index 1959271f5..3e46c51b4 100644 --- a/packages/client/src/components/chart.vue +++ b/packages/client/src/components/chart.vue @@ -8,7 +8,7 @@ diff --git a/packages/client/src/components/user-online-indicator.vue b/packages/client/src/components/user-online-indicator.vue index a87b0aeff..a4f6f8038 100644 --- a/packages/client/src/components/user-online-indicator.vue +++ b/packages/client/src/components/user-online-indicator.vue @@ -13,10 +13,10 @@ const props = defineProps<{ const text = $computed(() => { switch (props.user.onlineStatus) { - case 'online': return i18n.locale.online; - case 'active': return i18n.locale.active; - case 'offline': return i18n.locale.offline; - case 'unknown': return i18n.locale.unknown; + case 'online': return i18n.ts.online; + case 'active': return i18n.ts.active; + case 'offline': return i18n.ts.offline; + case 'unknown': return i18n.ts.unknown; } }); diff --git a/packages/client/src/directives/tooltip.ts b/packages/client/src/directives/tooltip.ts index fffde1487..dd715227a 100644 --- a/packages/client/src/directives/tooltip.ts +++ b/packages/client/src/directives/tooltip.ts @@ -48,7 +48,7 @@ export default { popup(import('@/components/ui/tooltip.vue'), { showing, text: self.text, - source: el + targetElement: el, }, {}, 'closed'); self._close = () => { @@ -56,8 +56,8 @@ export default { }; }; - el.addEventListener('selectstart', e => { - e.preventDefault(); + el.addEventListener('selectstart', ev => { + ev.preventDefault(); }); el.addEventListener(start, () => { diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts index af70aec70..81e41febd 100644 --- a/packages/client/src/init.ts +++ b/packages/client/src/init.ts @@ -185,7 +185,7 @@ app.config.globalProperties = { $store: defaultStore, $instance: instance, $t: i18n.t, - $ts: i18n.locale, + $ts: i18n.ts, }; app.use(router); @@ -299,8 +299,8 @@ stream.on('_disconnected_', async () => { reloadDialogShowing = true; const { canceled } = await confirm({ type: 'warning', - title: i18n.locale.disconnectedFromServer, - text: i18n.locale.reloadConfirm, + title: i18n.ts.disconnectedFromServer, + text: i18n.ts.reloadConfirm, }); reloadDialogShowing = false; if (!canceled) { @@ -324,7 +324,7 @@ if ($i) { if ($i.isDeleted) { alert({ type: 'warning', - text: i18n.locale.accountDeletionInProgress, + text: i18n.ts.accountDeletionInProgress, }); } diff --git a/packages/client/src/menu.ts b/packages/client/src/menu.ts index 184779f21..ebc789810 100644 --- a/packages/client/src/menu.ts +++ b/packages/client/src/menu.ts @@ -73,12 +73,12 @@ export const menuDef = reactive({ })), null, { type: 'link', to: '/my/lists', - text: i18n.locale.manageLists, + text: i18n.ts.manageLists, icon: 'fas fa-cog', }]; items.value = _items; }); - os.popupMenu(items, ev.currentTarget || ev.target); + os.popupMenu(items, ev.currentTarget ?? ev.target); }, }, groups: { @@ -104,12 +104,12 @@ export const menuDef = reactive({ })), null, { type: 'link', to: '/my/antennas', - text: i18n.locale.manageAntennas, + text: i18n.ts.manageAntennas, icon: 'fas fa-cog', }]; items.value = _items; }); - os.popupMenu(items, ev.currentTarget || ev.target); + os.popupMenu(items, ev.currentTarget ?? ev.target); }, }, mentions: { @@ -173,34 +173,34 @@ export const menuDef = reactive({ icon: 'fas fa-columns', action: (ev) => { os.popupMenu([{ - text: i18n.locale.default, + text: i18n.ts.default, active: ui === 'default' || ui === null, action: () => { localStorage.setItem('ui', 'default'); unisonReload(); } }, { - text: i18n.locale.deck, + text: i18n.ts.deck, active: ui === 'deck', action: () => { localStorage.setItem('ui', 'deck'); unisonReload(); } }, { - text: i18n.locale.classic, + text: i18n.ts.classic, active: ui === 'classic', action: () => { localStorage.setItem('ui', 'classic'); unisonReload(); } }, /*{ - text: i18n.locale.desktop + ' (β)', + text: i18n.ts.desktop + ' (β)', active: ui === 'desktop', action: () => { localStorage.setItem('ui', 'desktop'); unisonReload(); } - }*/], ev.currentTarget || ev.target); + }*/], ev.currentTarget ?? ev.target); }, }, }); diff --git a/packages/client/src/os.ts b/packages/client/src/os.ts index c16ea717a..95b4e87a1 100644 --- a/packages/client/src/os.ts +++ b/packages/client/src/os.ts @@ -7,8 +7,10 @@ import * as Misskey from 'misskey-js'; import { apiUrl, url } from '@/config'; import MkPostFormDialog from '@/components/post-form-dialog.vue'; import MkWaitingDialog from '@/components/waiting-dialog.vue'; +import { MenuItem } from '@/types/menu'; import { resolve } from '@/router'; import { $i } from '@/account'; +import { defaultStore } from '@/store'; export const pendingApiRequestsCount = ref(0); @@ -403,7 +405,7 @@ export async function selectDriveFolder(multiple: boolean) { }); } -export async function pickEmoji(src?: HTMLElement, opts) { +export async function pickEmoji(src: HTMLElement | null, opts) { return new Promise((resolve, reject) => { popup(import('@/components/emoji-picker-dialog.vue'), { src, @@ -470,7 +472,7 @@ export async function openEmojiPicker(src?: HTMLElement, opts, initialTextarea: }); } -export function popupMenu(items: any[] | Ref, src?: HTMLElement, options?: { +export function popupMenu(items: MenuItem[] | Ref, src?: HTMLElement, options?: { align?: string; width?: number; viaKeyboard?: boolean; @@ -494,7 +496,7 @@ export function popupMenu(items: any[] | Ref, src?: HTMLElement, options? }); } -export function contextMenu(items: any[], ev: MouseEvent) { +export function contextMenu(items: MenuItem[] | Ref, ev: MouseEvent) { ev.preventDefault(); return new Promise((resolve, reject) => { let dispose; @@ -541,7 +543,7 @@ export const uploads = ref<{ img: string; }[]>([]); -export function upload(file: File, folder?: any, name?: string): Promise { +export function upload(file: File, folder?: any, name?: string, keepOriginal: boolean = defaultStore.state.keepOriginalUploading): Promise { if (folder && typeof folder == 'object') folder = folder.id; return new Promise((resolve, reject) => { @@ -559,6 +561,8 @@ export function upload(file: File, folder?: any, name?: string): Promise
-

{{ i18n.locale.pageLoadError }}

-

{{ i18n.locale.pageLoadErrorDescription }}

-

{{ i18n.locale.serverIsDead }}

+

{{ i18n.ts.pageLoadError }}

+

{{ i18n.ts.pageLoadErrorDescription }}

+

{{ i18n.ts.serverIsDead }}

-

{{ i18n.locale.troubleshooting }}

+

{{ i18n.ts.troubleshooting }}

ERROR: {{ error }}

@@ -54,7 +54,7 @@ function reload() { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.error, + title: i18n.ts.error, icon: 'fas fa-exclamation-triangle', }, }); diff --git a/packages/client/src/pages/about-misskey.vue b/packages/client/src/pages/about-misskey.vue index f887e29cc..0ffb6b9e1 100644 --- a/packages/client/src/pages/about-misskey.vue +++ b/packages/client/src/pages/about-misskey.vue @@ -10,7 +10,7 @@
- {{ i18n.locale._aboutMisskey.about }}
{{ i18n.locale.learnMore }} + {{ i18n.ts._aboutMisskey.about }}
{{ i18n.ts.learnMore }}
I #Misskey @@ -19,23 +19,23 @@ - + - + - +
{{ patron }}
- +
@@ -194,7 +194,7 @@ onBeforeUnmount(() => { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.aboutMisskey, + title: i18n.ts.aboutMisskey, icon: null, bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/about.vue b/packages/client/src/pages/about.vue index a5984c548..d5bab4baf 100644 --- a/packages/client/src/pages/about.vue +++ b/packages/client/src/pages/about.vue @@ -90,7 +90,7 @@ const initStats = () => os.api('stats', { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.instanceInfo, + title: i18n.ts.instanceInfo, icon: 'fas fa-info-circle', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/admin/emojis.vue b/packages/client/src/pages/admin/emojis.vue index 5b1dfe565..a080ee9c2 100644 --- a/packages/client/src/pages/admin/emojis.vue +++ b/packages/client/src/pages/admin/emojis.vue @@ -118,7 +118,7 @@ const toggleSelect = (emoji) => { }; const add = async (ev: MouseEvent) => { - const files = await selectFiles(ev.currentTarget || ev.target, null); + const files = await selectFiles(ev.currentTarget ?? ev.target, null); const promise = Promise.all(files.map(file => os.api('admin/emoji/add', { fileId: file.id, @@ -157,23 +157,23 @@ const remoteMenu = (emoji, ev: MouseEvent) => { type: 'label', text: ':' + emoji.name + ':', }, { - text: i18n.locale.import, + text: i18n.ts.import, icon: 'fas fa-plus', action: () => { im(emoji) } - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); }; const menu = (ev: MouseEvent) => { os.popupMenu([{ icon: 'fas fa-download', - text: i18n.locale.export, + text: i18n.ts.export, action: async () => { os.api('export-custom-emojis', { }) .then(() => { os.alert({ type: 'info', - text: i18n.locale.exportRequested, + text: i18n.ts.exportRequested, }); }).catch((e) => { os.alert({ @@ -184,16 +184,16 @@ const menu = (ev: MouseEvent) => { } }, { icon: 'fas fa-upload', - text: i18n.locale.import, + text: i18n.ts.import, action: async () => { - const file = await selectFile(ev.currentTarget || ev.target); + const file = await selectFile(ev.currentTarget ?? ev.target); os.api('admin/emoji/import-zip', { fileId: file.id, }) .then(() => { os.alert({ type: 'info', - text: i18n.locale.importRequested, + text: i18n.ts.importRequested, }); }).catch((e) => { os.alert({ @@ -202,7 +202,7 @@ const menu = (ev: MouseEvent) => { }); }); } - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); }; const setCategoryBulk = async () => { @@ -256,7 +256,7 @@ const setTagBulk = async () => { const delBulk = async () => { const { canceled } = await os.confirm({ type: 'warning', - text: i18n.locale.deleteConfirm, + text: i18n.ts.deleteConfirm, }); if (canceled) return; await os.apiWithDialog('admin/emoji/delete-bulk', { @@ -267,13 +267,13 @@ const delBulk = async () => { defineExpose({ [symbols.PAGE_INFO]: computed(() => ({ - title: i18n.locale.customEmojis, + title: i18n.ts.customEmojis, icon: 'fas fa-laugh', bg: 'var(--bg)', actions: [{ asFullButton: true, icon: 'fas fa-plus', - text: i18n.locale.addEmoji, + text: i18n.ts.addEmoji, handler: add, }, { icon: 'fas fa-ellipsis-h', @@ -281,11 +281,11 @@ defineExpose({ }], tabs: [{ active: tab.value === 'local', - title: i18n.locale.local, + title: i18n.ts.local, onClick: () => { tab.value = 'local'; }, }, { active: tab.value === 'remote', - title: i18n.locale.remote, + title: i18n.ts.remote, onClick: () => { tab.value = 'remote'; }, },] })), diff --git a/packages/client/src/pages/admin/index.vue b/packages/client/src/pages/admin/index.vue index 350e7defc..6b11650f4 100644 --- a/packages/client/src/pages/admin/index.vue +++ b/packages/client/src/pages/admin/index.vue @@ -55,7 +55,7 @@ export default defineComponent({ setup(props, context) { const indexInfo = { - title: i18n.locale.controlPanel, + title: i18n.ts.controlPanel, icon: 'fas fa-cog', bg: 'var(--bg)', hideHeader: true, @@ -91,119 +91,119 @@ export default defineComponent({ }); const menuDef = computed(() => [{ - title: i18n.locale.quickAction, + title: i18n.ts.quickAction, items: [{ type: 'button', icon: 'fas fa-search', - text: i18n.locale.lookup, + text: i18n.ts.lookup, action: lookup, }, ...(instance.disableRegistration ? [{ type: 'button', icon: 'fas fa-user', - text: i18n.locale.invite, + text: i18n.ts.invite, action: invite, }] : [])], }, { - title: i18n.locale.administration, + title: i18n.ts.administration, items: [{ icon: 'fas fa-tachometer-alt', - text: i18n.locale.dashboard, + text: i18n.ts.dashboard, to: '/admin/overview', active: page.value === 'overview', }, { icon: 'fas fa-users', - text: i18n.locale.users, + text: i18n.ts.users, to: '/admin/users', active: page.value === 'users', }, { icon: 'fas fa-laugh', - text: i18n.locale.customEmojis, + text: i18n.ts.customEmojis, to: '/admin/emojis', active: page.value === 'emojis', }, { icon: 'fas fa-globe', - text: i18n.locale.federation, + text: i18n.ts.federation, to: '/admin/federation', active: page.value === 'federation', }, { icon: 'fas fa-clipboard-list', - text: i18n.locale.jobQueue, + text: i18n.ts.jobQueue, to: '/admin/queue', active: page.value === 'queue', }, { icon: 'fas fa-cloud', - text: i18n.locale.files, + text: i18n.ts.files, to: '/admin/files', active: page.value === 'files', }, { icon: 'fas fa-broadcast-tower', - text: i18n.locale.announcements, + text: i18n.ts.announcements, to: '/admin/announcements', active: page.value === 'announcements', }, { icon: 'fas fa-audio-description', - text: i18n.locale.ads, + text: i18n.ts.ads, to: '/admin/ads', active: page.value === 'ads', }, { icon: 'fas fa-exclamation-circle', - text: i18n.locale.abuseReports, + text: i18n.ts.abuseReports, to: '/admin/abuses', active: page.value === 'abuses', }], }, { - title: i18n.locale.settings, + title: i18n.ts.settings, items: [{ icon: 'fas fa-cog', - text: i18n.locale.general, + text: i18n.ts.general, to: '/admin/settings', active: page.value === 'settings', }, { icon: 'fas fa-envelope', - text: i18n.locale.emailServer, + text: i18n.ts.emailServer, to: '/admin/email-settings', active: page.value === 'email-settings', }, { icon: 'fas fa-cloud', - text: i18n.locale.objectStorage, + text: i18n.ts.objectStorage, to: '/admin/object-storage', active: page.value === 'object-storage', }, { icon: 'fas fa-lock', - text: i18n.locale.security, + text: i18n.ts.security, to: '/admin/security', active: page.value === 'security', }, { icon: 'fas fa-globe', - text: i18n.locale.relays, + text: i18n.ts.relays, to: '/admin/relays', active: page.value === 'relays', }, { icon: 'fas fa-share-alt', - text: i18n.locale.integration, + text: i18n.ts.integration, to: '/admin/integrations', active: page.value === 'integrations', }, { icon: 'fas fa-ban', - text: i18n.locale.instanceBlocking, + text: i18n.ts.instanceBlocking, to: '/admin/instance-block', active: page.value === 'instance-block', }, { icon: 'fas fa-ghost', - text: i18n.locale.proxyAccount, + text: i18n.ts.proxyAccount, to: '/admin/proxy-account', active: page.value === 'proxy-account', }, { icon: 'fas fa-cogs', - text: i18n.locale.other, + text: i18n.ts.other, to: '/admin/other-settings', active: page.value === 'other-settings', }], }, { - title: i18n.locale.info, + title: i18n.ts.info, items: [{ icon: 'fas fa-database', - text: i18n.locale.database, + text: i18n.ts.database, to: '/admin/database', active: page.value === 'database', }], @@ -275,37 +275,37 @@ export default defineComponent({ const lookup = (ev) => { os.popupMenu([{ - text: i18n.locale.user, + text: i18n.ts.user, icon: 'fas fa-user', action: () => { lookupUser(); } }, { - text: i18n.locale.note, + text: i18n.ts.note, icon: 'fas fa-pencil-alt', action: () => { alert('TODO'); } }, { - text: i18n.locale.file, + text: i18n.ts.file, icon: 'fas fa-cloud', action: () => { alert('TODO'); } }, { - text: i18n.locale.instance, + text: i18n.ts.instance, icon: 'fas fa-globe', action: () => { alert('TODO'); } - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); }; return { [symbols.PAGE_INFO]: INFO, menuDef, header: { - title: i18n.locale.controlPanel, + title: i18n.ts.controlPanel, }, noMaintainerInformation, noBotProtection, diff --git a/packages/client/src/pages/channel-editor.vue b/packages/client/src/pages/channel-editor.vue index 58c644be6..3818c7481 100644 --- a/packages/client/src/pages/channel-editor.vue +++ b/packages/client/src/pages/channel-editor.vue @@ -112,7 +112,7 @@ export default defineComponent({ }, setBannerImage(e) { - selectFile(e.currentTarget || e.target, null).then(file => { + selectFile(e.currentTarget ?? e.target, null).then(file => { this.bannerId = file.id; }); }, diff --git a/packages/client/src/pages/clip.vue b/packages/client/src/pages/clip.vue index 6b49221d3..c999f1bfc 100644 --- a/packages/client/src/pages/clip.vue +++ b/packages/client/src/pages/clip.vue @@ -127,7 +127,7 @@ export default defineComponent({ clipId: this.clip.id, }); } - } : undefined], ev.currentTarget || ev.target); + } : undefined], ev.currentTarget ?? ev.target); } } }); diff --git a/packages/client/src/pages/drive.vue b/packages/client/src/pages/drive.vue index 1e17bea0c..68777bb08 100644 --- a/packages/client/src/pages/drive.vue +++ b/packages/client/src/pages/drive.vue @@ -15,7 +15,7 @@ let folder = $ref(null); defineExpose({ [symbols.PAGE_INFO]: computed(() => ({ - title: folder ? folder.name : i18n.locale.drive, + title: folder ? folder.name : i18n.ts.drive, icon: 'fas fa-cloud', bg: 'var(--bg)', hideHeader: true, diff --git a/packages/client/src/pages/emojis.emoji.vue b/packages/client/src/pages/emojis.emoji.vue index 83539ce7a..b2801694d 100644 --- a/packages/client/src/pages/emojis.emoji.vue +++ b/packages/client/src/pages/emojis.emoji.vue @@ -23,13 +23,13 @@ function menu(ev) { type: 'label', text: ':' + props.emoji.name + ':', }, { - text: i18n.locale.copy, + text: i18n.ts.copy, icon: 'fas fa-copy', action: () => { copyToClipboard(`:${props.emoji.name}:`); os.success(); } - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); } diff --git a/packages/client/src/pages/emojis.vue b/packages/client/src/pages/emojis.vue index 6577f5abd..886b5f711 100644 --- a/packages/client/src/pages/emojis.vue +++ b/packages/client/src/pages/emojis.vue @@ -16,14 +16,14 @@ const tab = ref('category'); function menu(ev) { os.popupMenu([{ icon: 'fas fa-download', - text: i18n.locale.export, + text: i18n.ts.export, action: async () => { os.api('export-custom-emojis', { }) .then(() => { os.alert({ type: 'info', - text: i18n.locale.exportRequested, + text: i18n.ts.exportRequested, }); }).catch((e) => { os.alert({ @@ -32,12 +32,12 @@ function menu(ev) { }); }); } - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); } defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.customEmojis, + title: i18n.ts.customEmojis, icon: 'fas fa-laugh', bg: 'var(--bg)', actions: [{ diff --git a/packages/client/src/pages/favorites.vue b/packages/client/src/pages/favorites.vue index 8965b30d6..b4f6ff35b 100644 --- a/packages/client/src/pages/favorites.vue +++ b/packages/client/src/pages/favorites.vue @@ -34,7 +34,7 @@ const pagingComponent = ref>(); defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.favorites, + title: i18n.ts.favorites, icon: 'fas fa-star', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/featured.vue b/packages/client/src/pages/featured.vue index 725c70f0f..14fe0cb74 100644 --- a/packages/client/src/pages/featured.vue +++ b/packages/client/src/pages/featured.vue @@ -17,7 +17,7 @@ const pagination = { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.featured, + title: i18n.ts.featured, icon: 'fas fa-fire-alt', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/federation.vue b/packages/client/src/pages/federation.vue index 6a4a28b6b..3c5050cdb 100644 --- a/packages/client/src/pages/federation.vue +++ b/packages/client/src/pages/federation.vue @@ -115,7 +115,7 @@ const pagination = { offsetMode: true, params: computed(() => ({ sort: sort, - host: host != '' ? host : null, + host: host !== '' ? host : null, ...( state === 'federating' ? { federating: true } : state === 'subscribing' ? { subscribing: true } : @@ -135,7 +135,7 @@ function getStatus(instance) { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.federation, + title: i18n.ts.federation, icon: 'fas fa-globe', bg: 'var(--bg)', }, @@ -157,11 +157,10 @@ defineExpose({ > .instance { padding: 16px; - border: solid 1px var(--divider); - border-radius: 6px; + background: var(--panel); + border-radius: 8px; &:hover { - border: solid 1px var(--accent); text-decoration: none; } diff --git a/packages/client/src/pages/follow-requests.vue b/packages/client/src/pages/follow-requests.vue index 764daa0d3..6adc1a404 100644 --- a/packages/client/src/pages/follow-requests.vue +++ b/packages/client/src/pages/follow-requests.vue @@ -60,7 +60,7 @@ function reject(user) { defineExpose({ [symbols.PAGE_INFO]: computed(() => ({ - title: i18n.locale.followRequests, + title: i18n.ts.followRequests, icon: 'fas fa-user-clock', bg: 'var(--bg)', })), diff --git a/packages/client/src/pages/gallery/edit.vue b/packages/client/src/pages/gallery/edit.vue index e3fa1a0fc..25ee51318 100644 --- a/packages/client/src/pages/gallery/edit.vue +++ b/packages/client/src/pages/gallery/edit.vue @@ -92,7 +92,7 @@ export default defineComponent({ methods: { selectFile(e) { - selectFiles(e.currentTarget || e.target, null).then(files => { + selectFiles(e.currentTarget ?? e.target, null).then(files => { this.files = this.files.concat(files); }); }, diff --git a/packages/client/src/pages/instance-info.vue b/packages/client/src/pages/instance-info.vue index fa36db065..f19cb9d1a 100644 --- a/packages/client/src/pages/instance-info.vue +++ b/packages/client/src/pages/instance-info.vue @@ -29,6 +29,7 @@ {{ $ts.stopActivityDelivery }} {{ $ts.blockThisInstance }} + Refresh metadata @@ -111,6 +112,7 @@ import MkChart from '@/components/chart.vue'; import MkObjectView from '@/components/object-view.vue'; import FormLink from '@/components/form/link.vue'; import MkLink from '@/components/link.vue'; +import MkButton from '@/components/ui/button.vue'; import FormSection from '@/components/form/section.vue'; import MkKeyValue from '@/components/key-value.vue'; import MkSelect from '@/components/form/select.vue'; @@ -155,6 +157,15 @@ async function toggleSuspend(v) { }); } +function refreshMetadata() { + os.api('admin/federation/refresh-remote-instance-metadata', { + host: instance.host, + }); + os.alert({ + text: 'Refresh requested', + }); +} + fetch(); defineExpose({ diff --git a/packages/client/src/pages/mentions.vue b/packages/client/src/pages/mentions.vue index bda56fc72..9b57c956b 100644 --- a/packages/client/src/pages/mentions.vue +++ b/packages/client/src/pages/mentions.vue @@ -16,7 +16,7 @@ const pagination = { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.mentions, + title: i18n.ts.mentions, icon: 'fas fa-at', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/messages.vue b/packages/client/src/pages/messages.vue index 8efdc5558..9c5fb9b34 100644 --- a/packages/client/src/pages/messages.vue +++ b/packages/client/src/pages/messages.vue @@ -12,14 +12,14 @@ import { i18n } from '@/i18n'; const pagination = { endpoint: 'notes/mentions' as const, limit: 10, - params: () => ({ + params: { visibility: 'specified' - }), + }, }; defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.directNotes, + title: i18n.ts.directNotes, icon: 'fas fa-envelope', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/messaging/index.vue b/packages/client/src/pages/messaging/index.vue index 554ebc4b6..88a1e07af 100644 --- a/packages/client/src/pages/messaging/index.vue +++ b/packages/client/src/pages/messaging/index.vue @@ -128,7 +128,7 @@ export default defineComponent({ text: this.$ts.messagingWithGroup, icon: 'fas fa-users', action: () => { this.startGroup() } - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); }, async startUser() { diff --git a/packages/client/src/pages/messaging/messaging-room.form.vue b/packages/client/src/pages/messaging/messaging-room.form.vue index 1b9421ca9..3863c8f82 100644 --- a/packages/client/src/pages/messaging/messaging-room.form.vue +++ b/packages/client/src/pages/messaging/messaging-room.form.vue @@ -154,7 +154,7 @@ export default defineComponent({ }, chooseFile(e) { - selectFile(e.currentTarget || e.target, this.$ts.selectFile).then(file => { + selectFile(e.currentTarget ?? e.target, this.$ts.selectFile).then(file => { this.file = file; }); }, @@ -214,7 +214,7 @@ export default defineComponent({ }, async insertEmoji(ev) { - os.openEmojiPicker(ev.currentTarget || ev.target, {}, this.$refs.text); + os.openEmojiPicker(ev.currentTarget ?? ev.target, {}, this.$refs.text); } } }); diff --git a/packages/client/src/pages/messaging/messaging-room.vue b/packages/client/src/pages/messaging/messaging-room.vue index 65c44ce11..2ecc68eb5 100644 --- a/packages/client/src/pages/messaging/messaging-room.vue +++ b/packages/client/src/pages/messaging/messaging-room.vue @@ -335,7 +335,7 @@ const Component = defineComponent({ popout(path); this.$router.back(); }, - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); } } }); diff --git a/packages/client/src/pages/my-antennas/create.vue b/packages/client/src/pages/my-antennas/create.vue index 427c9935c..a08bece73 100644 --- a/packages/client/src/pages/my-antennas/create.vue +++ b/packages/client/src/pages/my-antennas/create.vue @@ -31,7 +31,7 @@ function onAntennaCreated() { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.manageAntennas, + title: i18n.ts.manageAntennas, icon: 'fas fa-satellite', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/my-clips/index.vue b/packages/client/src/pages/my-clips/index.vue index 97b563f6f..e287357a4 100644 --- a/packages/client/src/pages/my-clips/index.vue +++ b/packages/client/src/pages/my-clips/index.vue @@ -19,7 +19,7 @@ import MkPagination from '@/components/ui/pagination.vue'; import MkButton from '@/components/ui/button.vue'; import * as os from '@/os'; import * as symbols from '@/symbols'; -import i18n from '@/components/global/i18n'; +import { i18n } from '@/i18n'; const pagination = { endpoint: 'clips/list' as const, @@ -29,20 +29,20 @@ const pagination = { const pagingComponent = $ref>(); async function create() { - const { canceled, result } = await os.form(i18n.locale.createNewClip, { + const { canceled, result } = await os.form(i18n.ts.createNewClip, { name: { type: 'string', - label: i18n.locale.name, + label: i18n.ts.name, }, description: { type: 'string', required: false, multiline: true, - label: i18n.locale.description, + label: i18n.ts.description, }, isPublic: { type: 'boolean', - label: i18n.locale.public, + label: i18n.ts.public, default: false, }, }); @@ -63,7 +63,7 @@ function onClipDeleted() { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.clip, + title: i18n.ts.clip, icon: 'fas fa-paperclip', bg: 'var(--bg)', action: { diff --git a/packages/client/src/pages/my-lists/index.vue b/packages/client/src/pages/my-lists/index.vue index e6fcba1b3..9ed9e2960 100644 --- a/packages/client/src/pages/my-lists/index.vue +++ b/packages/client/src/pages/my-lists/index.vue @@ -31,7 +31,7 @@ const pagination = { async function create() { const { canceled, result: name } = await os.inputText({ - title: i18n.locale.enterListName, + title: i18n.ts.enterListName, }); if (canceled) return; await os.apiWithDialog('users/lists/create', { name: name }); @@ -40,7 +40,7 @@ async function create() { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.manageLists, + title: i18n.ts.manageLists, icon: 'fas fa-list-ul', bg: 'var(--bg)', action: { diff --git a/packages/client/src/pages/not-found.vue b/packages/client/src/pages/not-found.vue index 914fdb929..cdeb54b88 100644 --- a/packages/client/src/pages/not-found.vue +++ b/packages/client/src/pages/not-found.vue @@ -13,7 +13,7 @@ import { i18n } from '@/i18n'; defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.notFound, + title: i18n.ts.notFound, icon: 'fas fa-exclamation-triangle', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/notifications.vue b/packages/client/src/pages/notifications.vue index 090e80f99..36e423e53 100644 --- a/packages/client/src/pages/notifications.vue +++ b/packages/client/src/pages/notifications.vue @@ -27,26 +27,26 @@ function setFilter(ev) { })); const items = includeTypes != null ? [{ icon: 'fas fa-times', - text: i18n.locale.clear, + text: i18n.ts.clear, action: () => { includeTypes = null; } }, null, ...typeItems] : typeItems; - os.popupMenu(items, ev.currentTarget || ev.target); + os.popupMenu(items, ev.currentTarget ?? ev.target); } defineExpose({ [symbols.PAGE_INFO]: computed(() => ({ - title: i18n.locale.notifications, + title: i18n.ts.notifications, icon: 'fas fa-bell', bg: 'var(--bg)', actions: [{ - text: i18n.locale.filter, + text: i18n.ts.filter, icon: 'fas fa-filter', highlighted: includeTypes != null, handler: setFilter, }, { - text: i18n.locale.markAllAsRead, + text: i18n.ts.markAllAsRead, icon: 'fas fa-check', handler: () => { os.apiWithDialog('notifications/mark-all-as-read'); @@ -54,11 +54,11 @@ defineExpose({ }], tabs: [{ active: tab === 'all', - title: i18n.locale.all, + title: i18n.ts.all, onClick: () => { tab = 'all'; }, }, { active: tab === 'unread', - title: i18n.locale.unread, + title: i18n.ts.unread, onClick: () => { tab = 'unread'; }, },] })), diff --git a/packages/client/src/pages/page-editor/page-editor.vue b/packages/client/src/pages/page-editor/page-editor.vue index fe207555f..f302ac4f9 100644 --- a/packages/client/src/pages/page-editor/page-editor.vue +++ b/packages/client/src/pages/page-editor/page-editor.vue @@ -448,7 +448,7 @@ export default defineComponent({ }, setEyeCatchingImage(e) { - selectFile(e.currentTarget || e.target, null).then(file => { + selectFile(e.currentTarget ?? e.target, null).then(file => { this.eyeCatchingImageId = file.id; }); }, diff --git a/packages/client/src/pages/preview.vue b/packages/client/src/pages/preview.vue index 8eb454951..4accac419 100644 --- a/packages/client/src/pages/preview.vue +++ b/packages/client/src/pages/preview.vue @@ -12,7 +12,7 @@ import { i18n } from '@/i18n'; defineExpose({ [symbols.PAGE_INFO]: computed(() => ({ - title: i18n.locale.preview, + title: i18n.ts.preview, icon: 'fas fa-eye', bg: 'var(--bg)', })), diff --git a/packages/client/src/pages/reset-password.vue b/packages/client/src/pages/reset-password.vue index 8ef73858f..7d008ae75 100644 --- a/packages/client/src/pages/reset-password.vue +++ b/packages/client/src/pages/reset-password.vue @@ -3,10 +3,10 @@
- + - {{ i18n.locale.save }} + {{ i18n.ts.save }}
@@ -43,7 +43,7 @@ onMounted(() => { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.resetPassword, + title: i18n.ts.resetPassword, icon: 'fas fa-lock', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/settings/accounts.vue b/packages/client/src/pages/settings/accounts.vue index c795ede8a..a744a031d 100644 --- a/packages/client/src/pages/settings/accounts.vue +++ b/packages/client/src/pages/settings/accounts.vue @@ -64,7 +64,7 @@ export default defineComponent({ icon: 'fas fa-trash-alt', danger: true, action: () => this.removeAccount(account), - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); }, addAccount(ev) { @@ -74,7 +74,7 @@ export default defineComponent({ }, { text: this.$ts.createAccount, action: () => { this.createAccount(); }, - }], ev.currentTarget || ev.target); + }], ev.currentTarget ?? ev.target); }, addExistingAccount() { diff --git a/packages/client/src/pages/settings/drive.vue b/packages/client/src/pages/settings/drive.vue index f1016ebd8..134fa6330 100644 --- a/packages/client/src/pages/settings/drive.vue +++ b/packages/client/src/pages/settings/drive.vue @@ -28,6 +28,7 @@ + {{ $ts.keepOriginalUploading }}
@@ -36,18 +37,21 @@ import { defineComponent } from 'vue'; import * as tinycolor from 'tinycolor2'; import FormLink from '@/components/form/link.vue'; +import FormSwitch from '@/components/form/switch.vue'; import FormSection from '@/components/form/section.vue'; import MkKeyValue from '@/components/key-value.vue'; import FormSplit from '@/components/form/split.vue'; import * as os from '@/os'; import bytes from '@/filters/bytes'; import * as symbols from '@/symbols'; +import { defaultStore } from '@/store'; // TODO: render chart export default defineComponent({ components: { FormLink, + FormSwitch, FormSection, MkKeyValue, FormSplit, @@ -79,7 +83,8 @@ export default defineComponent({ l: 0.5 }) }; - } + }, + keepOriginalUploading: defaultStore.makeGetterSetter('keepOriginalUploading'), }, async created() { diff --git a/packages/client/src/pages/settings/email.vue b/packages/client/src/pages/settings/email.vue index 54557f877..4697fec9b 100644 --- a/packages/client/src/pages/settings/email.vue +++ b/packages/client/src/pages/settings/email.vue @@ -62,7 +62,7 @@ export default defineComponent({ const emailAddress = ref($i.email); const INFO = { - title: i18n.locale.email, + title: i18n.ts.email, icon: 'fas fa-envelope', bg: 'var(--bg)', }; @@ -75,7 +75,7 @@ export default defineComponent({ const saveEmailAddress = () => { os.inputText({ - title: i18n.locale.password, + title: i18n.ts.password, type: 'password' }).then(({ canceled, result: password }) => { if (canceled) return; diff --git a/packages/client/src/pages/settings/import-export.vue b/packages/client/src/pages/settings/import-export.vue index 21031c559..c153b4d28 100644 --- a/packages/client/src/pages/settings/import-export.vue +++ b/packages/client/src/pages/settings/import-export.vue @@ -60,7 +60,7 @@ export default defineComponent({ setup(props, context) { const INFO = { - title: i18n.locale.importAndExport, + title: i18n.ts.importAndExport, icon: 'fas fa-boxes', bg: 'var(--bg)', }; @@ -71,14 +71,14 @@ export default defineComponent({ const onExportSuccess = () => { os.alert({ type: 'info', - text: i18n.locale.exportRequested, + text: i18n.ts.exportRequested, }); }; const onImportSuccess = () => { os.alert({ type: 'info', - text: i18n.locale.importRequested, + text: i18n.ts.importRequested, }); }; @@ -114,22 +114,22 @@ export default defineComponent({ }; const importFollowing = async (ev) => { - const file = await selectFile(ev.currentTarget || ev.target); + const file = await selectFile(ev.currentTarget ?? ev.target); os.api('i/import-following', { fileId: file.id }).then(onImportSuccess).catch(onError); }; const importUserLists = async (ev) => { - const file = await selectFile(ev.currentTarget || ev.target); + const file = await selectFile(ev.currentTarget ?? ev.target); os.api('i/import-user-lists', { fileId: file.id }).then(onImportSuccess).catch(onError); }; const importMuting = async (ev) => { - const file = await selectFile(ev.currentTarget || ev.target); + const file = await selectFile(ev.currentTarget ?? ev.target); os.api('i/import-muting', { fileId: file.id }).then(onImportSuccess).catch(onError); }; const importBlocking = async (ev) => { - const file = await selectFile(ev.currentTarget || ev.target); + const file = await selectFile(ev.currentTarget ?? ev.target); os.api('i/import-blocking', { fileId: file.id }).then(onImportSuccess).catch(onError); }; diff --git a/packages/client/src/pages/settings/index.vue b/packages/client/src/pages/settings/index.vue index 66c8b147b..ac8414ddb 100644 --- a/packages/client/src/pages/settings/index.vue +++ b/packages/client/src/pages/settings/index.vue @@ -49,7 +49,7 @@ export default defineComponent({ setup(props, context) { const indexInfo = { - title: i18n.locale.settings, + title: i18n.ts.settings, icon: 'fas fa-cog', bg: 'var(--bg)', hideHeader: true, @@ -61,96 +61,96 @@ export default defineComponent({ const el = ref(null); const childInfo = ref(null); const menuDef = computed(() => [{ - title: i18n.locale.basicSettings, + title: i18n.ts.basicSettings, items: [{ icon: 'fas fa-user', - text: i18n.locale.profile, + text: i18n.ts.profile, to: '/settings/profile', active: page.value === 'profile', }, { icon: 'fas fa-lock-open', - text: i18n.locale.privacy, + text: i18n.ts.privacy, to: '/settings/privacy', active: page.value === 'privacy', }, { icon: 'fas fa-laugh', - text: i18n.locale.reaction, + text: i18n.ts.reaction, to: '/settings/reaction', active: page.value === 'reaction', }, { icon: 'fas fa-cloud', - text: i18n.locale.drive, + text: i18n.ts.drive, to: '/settings/drive', active: page.value === 'drive', }, { icon: 'fas fa-bell', - text: i18n.locale.notifications, + text: i18n.ts.notifications, to: '/settings/notifications', active: page.value === 'notifications', }, { icon: 'fas fa-envelope', - text: i18n.locale.email, + text: i18n.ts.email, to: '/settings/email', active: page.value === 'email', }, { icon: 'fas fa-share-alt', - text: i18n.locale.integration, + text: i18n.ts.integration, to: '/settings/integration', active: page.value === 'integration', }, { icon: 'fas fa-lock', - text: i18n.locale.security, + text: i18n.ts.security, to: '/settings/security', active: page.value === 'security', }], }, { - title: i18n.locale.clientSettings, + title: i18n.ts.clientSettings, items: [{ icon: 'fas fa-cogs', - text: i18n.locale.general, + text: i18n.ts.general, to: '/settings/general', active: page.value === 'general', }, { icon: 'fas fa-palette', - text: i18n.locale.theme, + text: i18n.ts.theme, to: '/settings/theme', active: page.value === 'theme', }, { icon: 'fas fa-list-ul', - text: i18n.locale.menu, + text: i18n.ts.menu, to: '/settings/menu', active: page.value === 'menu', }, { icon: 'fas fa-music', - text: i18n.locale.sounds, + text: i18n.ts.sounds, to: '/settings/sounds', active: page.value === 'sounds', }, { icon: 'fas fa-plug', - text: i18n.locale.plugins, + text: i18n.ts.plugins, to: '/settings/plugin', active: page.value === 'plugin', }], }, { - title: i18n.locale.otherSettings, + title: i18n.ts.otherSettings, items: [{ icon: 'fas fa-boxes', - text: i18n.locale.importAndExport, + text: i18n.ts.importAndExport, to: '/settings/import-export', active: page.value === 'import-export', }, { icon: 'fas fa-volume-mute', - text: i18n.locale.instanceMute, + text: i18n.ts.instanceMute, to: '/settings/instance-mute', active: page.value === 'instance-mute', }, { icon: 'fas fa-ban', - text: i18n.locale.muteAndBlock, + text: i18n.ts.muteAndBlock, to: '/settings/mute-block', active: page.value === 'mute-block', }, { icon: 'fas fa-comment-slash', - text: i18n.locale.wordMute, + text: i18n.ts.wordMute, to: '/settings/word-mute', active: page.value === 'word-mute', }, { @@ -160,7 +160,7 @@ export default defineComponent({ active: page.value === 'api', }, { icon: 'fas fa-ellipsis-h', - text: i18n.locale.other, + text: i18n.ts.other, to: '/settings/other', active: page.value === 'other', }], @@ -168,7 +168,7 @@ export default defineComponent({ items: [{ type: 'button', icon: 'fas fa-trash', - text: i18n.locale.clearCache, + text: i18n.ts.clearCache, action: () => { localStorage.removeItem('locale'); localStorage.removeItem('theme'); @@ -177,7 +177,7 @@ export default defineComponent({ }, { type: 'button', icon: 'fas fa-sign-in-alt fa-flip-horizontal', - text: i18n.locale.logout, + text: i18n.ts.logout, action: () => { signout(); }, diff --git a/packages/client/src/pages/settings/mute-block.vue b/packages/client/src/pages/settings/mute-block.vue index f4f9ebf8d..28d11809e 100644 --- a/packages/client/src/pages/settings/mute-block.vue +++ b/packages/client/src/pages/settings/mute-block.vue @@ -52,7 +52,7 @@ const blockingPagination = { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.muteAndBlock, + title: i18n.ts.muteAndBlock, icon: 'fas fa-ban', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/settings/privacy.vue b/packages/client/src/pages/settings/privacy.vue index dd13ba4bd..cfae7e9ca 100644 --- a/packages/client/src/pages/settings/privacy.vue +++ b/packages/client/src/pages/settings/privacy.vue @@ -86,7 +86,7 @@ function save() { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.privacy, + title: i18n.ts.privacy, icon: 'fas fa-lock-open', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/settings/profile.vue b/packages/client/src/pages/settings/profile.vue index f875146a2..66b654d87 100644 --- a/packages/client/src/pages/settings/profile.vue +++ b/packages/client/src/pages/settings/profile.vue @@ -3,45 +3,45 @@
- {{ i18n.locale._profile.changeAvatar }} + {{ i18n.ts._profile.changeAvatar }}
- {{ i18n.locale._profile.changeBanner }} + {{ i18n.ts._profile.changeBanner }}
- + - - + + - + - + - + - {{ i18n.locale._profile.metadataEdit }} - + {{ i18n.ts._profile.metadataEdit }} + - {{ i18n.locale.flagAsCat }} + {{ i18n.ts.flagAsCat }} - {{ i18n.locale.flagAsBot }} + {{ i18n.ts.flagAsBot }} - {{ i18n.locale.alwaysMarkSensitive }} + {{ i18n.ts.alwaysMarkSensitive }} @@ -102,7 +102,7 @@ function save() { } function changeAvatar(ev) { - selectFile(ev.currentTarget || ev.target, i18n.locale.avatar).then(async (file) => { + selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar).then(async (file) => { const i = await os.apiWithDialog('i/update', { avatarId: file.id, }); @@ -112,7 +112,7 @@ function changeAvatar(ev) { } function changeBanner(ev) { - selectFile(ev.currentTarget || ev.target, i18n.locale.banner).then(async (file) => { + selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner).then(async (file) => { const i = await os.apiWithDialog('i/update', { bannerId: file.id, }); @@ -122,45 +122,45 @@ function changeBanner(ev) { } async function editMetadata() { - const { canceled, result } = await os.form(i18n.locale._profile.metadata, { + const { canceled, result } = await os.form(i18n.ts._profile.metadata, { fieldName0: { type: 'string', - label: i18n.locale._profile.metadataLabel + ' 1', + label: i18n.ts._profile.metadataLabel + ' 1', default: additionalFields.fieldName0, }, fieldValue0: { type: 'string', - label: i18n.locale._profile.metadataContent + ' 1', + label: i18n.ts._profile.metadataContent + ' 1', default: additionalFields.fieldValue0, }, fieldName1: { type: 'string', - label: i18n.locale._profile.metadataLabel + ' 2', + label: i18n.ts._profile.metadataLabel + ' 2', default: additionalFields.fieldName1, }, fieldValue1: { type: 'string', - label: i18n.locale._profile.metadataContent + ' 2', + label: i18n.ts._profile.metadataContent + ' 2', default: additionalFields.fieldValue1, }, fieldName2: { type: 'string', - label: i18n.locale._profile.metadataLabel + ' 3', + label: i18n.ts._profile.metadataLabel + ' 3', default: additionalFields.fieldName2, }, fieldValue2: { type: 'string', - label: i18n.locale._profile.metadataContent + ' 3', + label: i18n.ts._profile.metadataContent + ' 3', default: additionalFields.fieldValue2, }, fieldName3: { type: 'string', - label: i18n.locale._profile.metadataLabel + ' 4', + label: i18n.ts._profile.metadataLabel + ' 4', default: additionalFields.fieldName3, }, fieldValue3: { type: 'string', - label: i18n.locale._profile.metadataContent + ' 4', + label: i18n.ts._profile.metadataContent + ' 4', default: additionalFields.fieldValue3, }, }); @@ -196,7 +196,7 @@ async function editMetadata() { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.profile, + title: i18n.ts.profile, icon: 'fas fa-user', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/settings/reaction.vue b/packages/client/src/pages/settings/reaction.vue index e5b118994..ae3e1a118 100644 --- a/packages/client/src/pages/settings/reaction.vue +++ b/packages/client/src/pages/settings/reaction.vue @@ -44,8 +44,8 @@ - diff --git a/packages/client/src/pages/settings/theme.install.vue b/packages/client/src/pages/settings/theme.install.vue index e2a3f042b..2d3514342 100644 --- a/packages/client/src/pages/settings/theme.install.vue +++ b/packages/client/src/pages/settings/theme.install.vue @@ -1,12 +1,12 @@ @@ -32,21 +32,21 @@ function parseThemeCode(code: string) { } catch (e) { os.alert({ type: 'error', - text: i18n.locale._theme.invalid + text: i18n.ts._theme.invalid }); return false; } if (!validateTheme(theme)) { os.alert({ type: 'error', - text: i18n.locale._theme.invalid + text: i18n.ts._theme.invalid }); return false; } if (getThemes().some(t => t.id === theme.id)) { os.alert({ type: 'info', - text: i18n.locale._theme.alreadyInstalled + text: i18n.ts._theme.alreadyInstalled }); return false; } @@ -71,7 +71,7 @@ async function install(code: string): Promise { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale._theme.install, + title: i18n.ts._theme.install, icon: 'fas fa-download', bg: 'var(--bg)', }, diff --git a/packages/client/src/pages/settings/theme.vue b/packages/client/src/pages/settings/theme.vue index 658e36ec0..3e4ec1b2a 100644 --- a/packages/client/src/pages/settings/theme.vue +++ b/packages/client/src/pages/settings/theme.vue @@ -116,7 +116,7 @@ export default defineComponent({ setup(props, { emit }) { const INFO = { - title: i18n.locale.theme, + title: i18n.ts.theme, icon: 'fas fa-palette', bg: 'var(--bg)', }; @@ -184,7 +184,7 @@ export default defineComponent({ themesCount, wallpaper, setWallpaper(e) { - selectFile(e.currentTarget || e.target, null).then(file => { + selectFile(e.currentTarget ?? e.target, null).then(file => { wallpaper.value = file.url; }); }, diff --git a/packages/client/src/pages/signup-complete.vue b/packages/client/src/pages/signup-complete.vue index a10af1a4c..344c9195f 100644 --- a/packages/client/src/pages/signup-complete.vue +++ b/packages/client/src/pages/signup-complete.vue @@ -1,6 +1,6 @@ @@ -18,7 +18,7 @@ const props = defineProps<{ onMounted(async () => { await os.alert({ type: 'info', - text: i18n.t('clickToFinishEmailVerification', { ok: i18n.locale.gotIt }), + text: i18n.t('clickToFinishEmailVerification', { ok: i18n.ts.gotIt }), }); const res = await os.apiWithDialog('signup-pending', { code: props.code, @@ -28,7 +28,7 @@ onMounted(async () => { defineExpose({ [symbols.PAGE_INFO]: { - title: i18n.locale.signup, + title: i18n.ts.signup, icon: 'fas fa-user', }, }); diff --git a/packages/client/src/pages/theme-editor.vue b/packages/client/src/pages/theme-editor.vue index 80b8c7806..a53e23c1c 100644 --- a/packages/client/src/pages/theme-editor.vue +++ b/packages/client/src/pages/theme-editor.vue @@ -2,7 +2,7 @@
- +
- {{ pageInfo.title }} + @@ -13,99 +13,89 @@
- diff --git a/packages/client/src/ui/deck.vue b/packages/client/src/ui/deck.vue index 51a4853e9..9accc34a8 100644 --- a/packages/client/src/ui/deck.vue +++ b/packages/client/src/ui/deck.vue @@ -104,7 +104,7 @@ export default defineComponent({ ]; const { canceled, result: column } = await os.select({ - title: i18n.locale._deck.addColumn, + title: i18n.ts._deck.addColumn, items: columns.map(column => ({ value: column, text: i18n.t('_deck._columns.' + column) })) @@ -121,7 +121,7 @@ export default defineComponent({ const onContextmenu = (ev) => { os.contextMenu([{ - text: i18n.locale._deck.addColumn, + text: i18n.ts._deck.addColumn, icon: null, action: addColumn }], ev); diff --git a/packages/client/src/ui/deck/deck-store.ts b/packages/client/src/ui/deck/deck-store.ts index 6b6b02f3f..66db5e83e 100644 --- a/packages/client/src/ui/deck/deck-store.ts +++ b/packages/client/src/ui/deck/deck-store.ts @@ -77,12 +77,12 @@ export const loadDeck = async () => { deckStore.set('columns', [{ id: 'a', type: 'main', - name: i18n.locale._deck._columns.main, + name: i18n.ts._deck._columns.main, width: 350, }, { id: 'b', type: 'notifications', - name: i18n.locale._deck._columns.notifications, + name: i18n.ts._deck._columns.notifications, width: 330, }]); deckStore.set('layout', [['a'], ['b']]); diff --git a/packages/client/src/ui/universal.vue b/packages/client/src/ui/universal.vue index 16cc9a4f0..b0dfc5aad 100644 --- a/packages/client/src/ui/universal.vue +++ b/packages/client/src/ui/universal.vue @@ -20,7 +20,7 @@
- +
@@ -31,9 +31,9 @@
- + - +
@@ -64,155 +64,133 @@
-