diff --git a/src/backend/src/modules/puterai/AITestModeService.js b/src/backend/src/modules/puterai/AITestModeService.js new file mode 100644 index 000000000..64289acae --- /dev/null +++ b/src/backend/src/modules/puterai/AITestModeService.js @@ -0,0 +1,12 @@ +const BaseService = require("../../services/BaseService"); + +class AITestModeService extends BaseService { + async _init () { + const svc_driver = this.services.get('driver'); + svc_driver.register_test_service('puter-chat-completion', 'openai-completion'); + } +} + +module.exports = { + AITestModeService, +}; diff --git a/src/backend/src/modules/puterai/AWSPollyService.js b/src/backend/src/modules/puterai/AWSPollyService.js index 1c8fd022d..5189e2592 100644 --- a/src/backend/src/modules/puterai/AWSPollyService.js +++ b/src/backend/src/modules/puterai/AWSPollyService.js @@ -12,6 +12,11 @@ class AWSPollyService extends BaseService { } static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-tts' && method_name === 'synthesize'; + } + }, ['puter-tts']: { async list_voices () { const polly_voices = await this.describe_voices(); diff --git a/src/backend/src/modules/puterai/AWSTextractService.js b/src/backend/src/modules/puterai/AWSTextractService.js index 01e605e8d..e216397a5 100644 --- a/src/backend/src/modules/puterai/AWSTextractService.js +++ b/src/backend/src/modules/puterai/AWSTextractService.js @@ -9,6 +9,11 @@ class AWSTextractService extends BaseService { } static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-ocr' && method_name === 'recognize'; + } + }, ['puter-ocr']: { async recognize ({ source, test_mode }) { if ( test_mode ) { diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index 7c170fe31..5c4fc1f07 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -22,6 +22,12 @@ class OpenAICompletionService extends BaseService { } static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-chat-completion' && + method_name === 'complete'; + } + }, ['puter-chat-completion']: { async list () { return [ diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index a1241530f..f5618759c 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -56,6 +56,9 @@ class PuterAIModule extends AdvancedBase { const { FakeChatService } = require('./FakeChatService'); services.registerService('fake-chat', FakeChatService); + + const{ AITestModeService } = require('./AITestModeService'); + services.registerService('ai-test-mode', AITestModeService); } } diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 27b4bb4bd..59d42d919 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -226,6 +226,10 @@ class PermissionService extends BaseService { } async scan (actor, permission_options, _reserved, state) { + if ( ! state ) this.log.info('scan', { + actor: actor.uid, + permission_options, + }); const reading = []; if ( ! state ) { diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 74c180317..c9220b67b 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -37,6 +37,7 @@ class DriverService extends BaseService { _construct () { this.drivers = {}; this.interface_to_implementation = {}; + this.interface_to_test_service = {}; } async ['__on_registry.collections'] () { @@ -77,6 +78,10 @@ class DriverService extends BaseService { register_driver (interface_name, implementation) { this.interface_to_implementation[interface_name] = implementation; } + + register_test_service (interface_name, service_name) { + this.interface_to_test_service[interface_name] = service_name; + } get_interface (interface_name) { const o = {}; @@ -113,7 +118,8 @@ class DriverService extends BaseService { async _call ({ driver, iface, method, args }) { console.log('??', driver, iface, method, args); const processed_args = await this._process_args(iface, method, args); - if ( Context.get('test_mode') ) { + const test_mode = Context.get('test_mode'); + if ( test_mode ) { processed_args.test_mode = true; } @@ -141,18 +147,31 @@ class DriverService extends BaseService { driver = driver ?? iface_to_driver[iface] ?? iface; + let skip_usage = false; + if ( test_mode && this.interface_to_test_service[iface] ) { + driver = this.interface_to_test_service[iface]; + } + const driver_service_exists = (() => { + console.log('CHECKING FOR THIS', driver, iface); return this.services.has(driver) && this.services.get(driver).list_traits() .includes(iface); })(); if ( driver_service_exists ) { const service = this.services.get(driver); + + const caps = service.as('driver-capabilities'); + if ( test_mode && caps && caps.supports_test_mode(iface, method) ) { + skip_usage = true; + } + return await this.call_new_({ actor, service, service_name: driver, iface, method, args: processed_args, + skip_usage, }); } @@ -240,6 +259,7 @@ class DriverService extends BaseService { service, service_name, iface, method, args, + skip_usage, }) { const svc_permission = this.services.get('permission'); const reading = await svc_permission.scan( @@ -324,6 +344,8 @@ class DriverService extends BaseService { { name: 'enforce monthly usage limit', on_call: async args => { + if ( skip_usage ) return args; + // Typo-Tolerance if ( effective_policy?.['monthy-limit'] ) { effective_policy['monthly-limit'] = effective_policy['monthy-limit']; @@ -343,6 +365,8 @@ class DriverService extends BaseService { return args; }, on_return: async result => { + if ( skip_usage ) return result; + console.log('monthly usage is returning'); const svc_monthlyUsage = services.get('monthly-usage'); const extra = { diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index cf292842f..522dfd6cb 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -37,35 +37,35 @@ const bn = { browse: "ব্রাউজ", cancel: "বাতিল করুন", center: "কেন্দ্র", - change_desktop_background: "ডেস্কটপ পৃষ্ঠভূমি পরিবর্তন করুন…", - change_email: "ইমেল পরিবর্তন করুন", + change_desktop_background: "ডেস্কটপ এর ব্যকগ্রাউন্ড পরিবর্তন করুন…", + change_email: "ইমেইল পরিবর্তন করুন", change_language: "ভাষা পরিবর্তন করুন", change_password: "পাসওয়ার্ড পরিবর্তন করুন", - change_ui_colors: "ইউআই রঙ পরিবর্তন করুন", + change_ui_colors: "ইউআই এর রঙ পরিবর্তন করুন", change_username: "ইউজারনেম পরিবর্তন করুন", close: "বন্ধ করুন", close_all_windows: "সমস্ত উইন্ডো বন্ধ করুন", close_all_windows_confirm: "আপনি কি সমস্ত উইন্ডো বন্ধ করতে চান?", - close_all_windows_and_log_out: "উইন্ডো বন্ধ এবং লগ আউট করুন", - change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় এই সাথে খোলার জন্য চান", + close_all_windows_and_log_out: "সমস্ত উইন্ডো বন্ধ এবং লগ আউট করুন", + change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় একটি নির্দিষ্ট এপ্লিকেশনের মাধ্যমে ওপেন করতে চান?", color: "রঙ", - confirm: "অনুমোদন", - confirm_2fa_setup: "আমি আমার অথেন্টিকেশন অ্যাপ্লিকেশনে কোডটি যোগ করেছি", - confirm_2fa_recovery: "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ স্থানে সংরক্ষণ করেছি", - confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি 1 জিবি স্টোরেজ পান। আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবেন।", + confirm: "নিশ্চিতকরণ", + confirm_2fa_setup: "২ ফ্যাক্টর অথেনটিকেশন নিশ্চিত করুন", + confirm_2fa_recovery: "২ ফ্যাক্টর অথেনটিকেশন এর রিকোভারি কী গুলো নিশ্চিত করুন", + confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি ১ জিবি স্টোরেজ পান। আপনার বন্ধুও ১ জিবি ফ্রি স্টোরেজ পাবেন।", confirm_code_generic_incorrect: "ভুল কোড।", - confirm_code_generic_too_many_requests: "অনেক অনুরোধ। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", + confirm_code_generic_too_many_requests: "কোড জেনারেশনের রিকোয়েস্ট অনেকবার এসেছে। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", confirm_code_generic_submit: "কোড জমা দিন", confirm_code_generic_try_again: "আবার চেষ্টা করুন", confirm_code_generic_title: "অনুমোদন কোড প্রবেশ করুন", - confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে 6-ডিজিট কোডটি প্রবেশ করুন।", + confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে ৬-ডিজিট কোডটি প্রবেশ করুন।", confirm_code_2fa_submit_btn: "জমা দিন", confirm_code_2fa_title: "2FA কোড প্রবেশ করুন", - confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে মুছতে চান?", + confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে ডিলিট করে ফেলতে চান?", confirm_delete_single_item: "আপনি কি এই আইটেমটি স্থায়ীভাবে মুছতে চান?", - confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", + confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", confirm_new_password: "নতুন পাসওয়ার্ড নিশ্চিত করুন", - confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? সমস্ত আপনার ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই ক্রিয়াটি ফিরে পাওয়া যাবে না।", + confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? আপনার সমস্ত ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই প্রক্রিয়া শেষে আগের ডেটা আর ফিরে পাওয়া যাবে না।", confirm_delete_user_title: "অ্যাকাউন্ট মুছে ফেলুন?", confirm_session_revoke: "আপনি কি নিশ্চিত যে আপনি এই সেশনটি প্রত্যাহার করতে চান?", confirm_your_email_address: "আপনার ইমেল ঠিকানা নিশ্চিত করুন", @@ -87,33 +87,33 @@ const bn = { clock: "ঘড়ি", clock_visible_hide: "লুকান - সর্বদা লুকিয়ে রাখা", clock_visible_show: "দেখান - সর্বদা দৃশ্যমান", - clock_visible_auto: "অটো - ডিফল্ট, মুখ্যম্বর মোডে শুধুমাত্র দৃশ্যমান।", - close_all: "সমস্ত বন্ধ করুন", + clock_visible_auto: "অটো - ডিফল্ট, অটো মোডে শুধুমাত্র দৃশ্যমান।", + close_all: "সবকিছু বন্ধ করুন", created: "তৈরি করা হয়েছে", - date_modified: "তারিখ পরিবর্তন", + date_modified: "তারিখ পরিবর্তন করা হয়েছে", default: "ডিফল্ট", delete: "মুছে ফেলুন", delete_account: "অ্যাকাউন্ট মুছে ফেলুন", delete_permanently: "চিরকালের জন্য মুছুন", deleting_file: "ফাইল মুছে ফেলা হচ্ছে %%", - deploy_as_app: "অ্যাপ্লিকেশন হিসেবে ডিপ্লয়", + deploy_as_app: "অ্যাপ্লিকেশন হিসেবে ডিপ্লয় করা হয়েছে", descending: "অবতলভাবে", desktop: "ডেস্কটপ", desktop_background_fit: "ফিট", developers: "ডেভেলপারগণ", dir_published_as_website: `%strong% প্রকাশিত হয়েছে:`, - disable_2fa: "2FA অক্ষম করুন", - disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA অক্ষম করতে চান?", - disable_2fa_instructions: "2FA অক্ষম করতে আপনার পাসওয়ার্ড লিখুন।", + disable_2fa: "2FA বন্ধ করুন", + disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA বন্ধ করতে চান?", + disable_2fa_instructions: "2FA বন্ধ করতে আপনার পাসওয়ার্ড লিখুন।", disassociate_dir: "ডিরেক্টরি আনসোসিএট করুন", documents: "ডকুমেন্টস", - dont_allow: "অনুমতি দিন না", + dont_allow: "অনুমতি দিবেন না", download: "ডাউনলোড", download_file: "ফাইল ডাউনলোড করুন", downloading: "ডাউনলোড হচ্ছে", email: "ইমেল", - email_change_confirmation_sent: "নতুন ইমেল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", - email_invalid: "ইমেল অবৈধ।", + email_change_confirmation_sent: "নতুন ইমেল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", + email_invalid: "ইমেলটি বৈধ নয়।", email_or_username: "ইমেল বা ইউজারনেম", email_required: "ইমেল প্রয়োজন।", empty_trash: "খালি ট্র্যাশ", @@ -131,16 +131,16 @@ const bn = { favorites: "প্রিয়", feedback: "প্রতিক্রিয়া", feedback_c2a: "নীচের ফর্মটি ব্যবহার করে আপনার মতামত, মন্তব্য এবং বাগ রিপোর্ট প্রেরণ করুন।", - feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ইমেল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব তাদের থেকে ফিরে পাবেন।", + feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ইমেল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব আপনার কাছে ফিরে আসতে পারবো।", fit: "ফিট", folder: "ফোল্ডার", - force_quit: "প্রবল বন্ধ", + force_quit: "জোর করে বন্ধ করা", forgot_pass_c2a: "পাসওয়ার্ড ভুলে গেছেন?", from: "থেকে", general: "সাধারণ", get_a_copy_of_on_puter: `পিউটার ডটকমে '%%' এর একটি অনুলিপি পান!`, get_copy_link: "কপি লিংক নিন", - hide_all_windows: "সমস্ত উইন্ডো লুকান", + hide_all_windows: "সমস্ত উইন্ডো ঢেকে ফেলুন", home: "হোম", html_document: "এইচটিএমএল ডকুমেন্ট", hue: "হিউ", @@ -148,12 +148,12 @@ const bn = { incorrect_password: "ভুল পাসওয়ার্ড", invite_link: "আমন্ত্রণ লিংক", item: "আইটেম", - items_in_trash_cannot_be_renamed: `এই আইটেমটি নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`, + items_in_trash_cannot_be_renamed: `এই আইটেমটির নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`, jpeg_image: "জেপিইজি ইমেজ", keep_in_taskbar: "টাস্কবারে রাখুন", language: "ভাষা", license: "লাইসেন্স", - lightness: "হালকালোত্ব", + lightness: "হালকার মতো", link_copied: "লিংক কপি করা হয়েছে", loading: "লোড হচ্ছে", log_in: "লগ ইন করুন", @@ -187,26 +187,26 @@ const bn = { ok: "ঠিক আছে", open: "খোলা", open_in_new_tab: "নতুন ট্যাবে খুলুন", - open_in_new_window: "নতুন উইন্ডোয়ে খুলুন", - open_with: "দিয়ে খোলুন", + open_in_new_window: "নতুন উইন্ডোতে খুলুন", + open_with: "দিয়ে খুলুন", original_name: "মৌলিক নাম", original_path: "মূল পথ", oss_code_and_content: "ওপেন সোর্স সফটওয়্যার এবং কন্টেন্ট", password: "পাসওয়ার্ড", password_changed: "পাসওয়ার্ড পরিবর্তন করা হয়েছে।", - password_recovery_rate_limit: "আপনি আমাদের রেকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", + password_recovery_rate_limit: "আপনি আমাদের রিকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", password_recovery_sent: "আপনার পাসওয়ার্ড পুনরুদ্ধারের জন্য নির্দেশানুযায়ী একটি ইমেল পাঠানো হয়েছে।", - password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের বৃহত্তর হতে হবে।", + password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের বড় অক্ষর থাকতে হবে।", password_reset: "পাসওয়ার্ড রিসেট করুন", password_reset_confirmation: "পাসওয়ার্ড সেট করতে নীচের ফর্মটি পূরণ করুন।", password_reset_request_expired: "আপনার পাসওয়ার্ড রিসেট রিকোয়েস্টের মেয়াদ শেষ হয়ে গেছে। দয়া করে পুনরায় চেষ্টা করুন।", - password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", + password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", password_update_success: "পাসওয়ার্ড সফলভাবে আপডেট হয়েছে!", - passwords_do_not_match: "পাসওয়ার্ড মিলে না", + passwords_do_not_match: "পাসওয়ার্ড মিলছে না", paste: "পেস্ট", paste_into_folder: "ফোল্ডারে পেস্ট করুন", path: "পথ", - personalization: "ব্যক্তিগতীকরণ", + personalization: "ব্যক্তিগতকরণ", pick_name_for_website: "আপনার ওয়েবসাইটের জন্য নাম নির্বাচন করুন:", picture: "ছবি", pictures: "চিত্র", @@ -232,17 +232,17 @@ const bn = { recent: "সাম্প্রতিক", recommended: "অনুমোদিত", recover_password: "পাসওয়ার্ড পুনরুদ্ধার করুন", - refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুর প্রতি 1 জিবি পান। আপনার বন্ধুও 1 জিবি পাবে!", - refer_friends_social_media_c2a: `Puter.com এ 1 GB বিনামূল্যের সংরক্ষণ পান!`, + refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুকে রেফার করার জন্য প্রতি রেফারে ১ জিবি পান। আপনার বন্ধুও ১ জিবি পাবে!", + refer_friends_social_media_c2a: `Puter.com এ ১ জিবি বিনামূল্যের সংরক্ষণ পান!`, refresh: "রিফ্রেশ", release_address_confirmation: `আপনি কি নিশ্চিত যে আপনি এই ঠিকানা রিলিজ করতে চান?`, remove_from_taskbar: "টাস্কবার থেকে সরান", rename: "পুনঃনামকরণ", repeat: "পুনরাবৃত্তি", replace: "প্রতিস্থাপন", - replace_all: "সমস্ত প্রতিস্থাপন", + replace_all: "সমস্তকিছু প্রতিস্থাপন করে ফেলুন", resend_confirmation_code: "পুনরায় নিশ্চিতকরণ কোড প্রেরণ করুন", - reset_colors: "রঙ পুনঃনির্ধারণ করুন", + reset_colors: "রঙ আগেরমত করুন", restart_puter_confirm: "আপনি কি নিশ্চিত যে Puter পুনরায় চালু করতে চান?", restore: "পুনরুদ্ধার", save: "সংরক্ষণ করুন", @@ -277,7 +277,7 @@ const bn = { sign_up: "নিবন্ধন করুন", signing_in: "সাইন ইন হচ্ছে...", size: "আকার", - skip: "পার যান", + skip: "এটি বাদ দিন", something_went_wrong: "কিছু সমস্যা হয়েছে।", sort_by: "অনুযায়ী সাজান", start: "শুরু", @@ -295,14 +295,14 @@ const bn = { transparency: "স্বচ্ছতা", trash: "আবর্জনা", two_factor: "দুটি ফ্যাক্টর প্রমাণীকরণ", - two_factor_disabled: "2FA অক্ষম", - two_factor_enabled: "2FA সক্ষম", + two_factor_disabled: "2FA বন্ধ করা হয়েছে", + two_factor_enabled: "2FA চালু করা হয়েছে", type: "ধরণ", type_confirm_to_delete_account: "অ্যাকাউন্ট মোছার জন্য 'অনুমোদন' টাইপ করুন।", ui_colors: "ইউআই রঙ", ui_manage_sessions: "সেশন ম্যানেজার", ui_revoke: "প্রত্যাহার করুন", - undo: "আনডো", + undo: "আনডু করুন", unlimited: "অসীম", unzip: "আনজিপ", upload: "আপলোড", @@ -323,16 +323,16 @@ const bn = { // === 2FA Setup === setup2fa_1_step_heading: "আপনার প্রামাণিকতা অ্যাপ খুলুন", setup2fa_1_instructions: ` - আপনি যেকোনো প্রামাণিকতা অ্যাপ ব্যবহার করতে পারেন যা Time-based One-Time Password (TOTP) প্রোটোকল সমর্থন করে। + আপনি যেকোনো অথেনটিকেশন অ্যাপ ব্যবহার করতে পারেন যা Time-based One-Time Password (TOTP) প্রোটোকল সমর্থন করে। অনেক বিকল্প রয়েছে, তবে যদি আপনি নিশ্চিত না হন Authy একটি ভালো পছন্দ Android এবং iOS এর জন্য। `, setup2fa_2_step_heading: "QR কোড স্ক্যান করুন", - setup2fa_3_step_heading: "6-টি অংকের কোড লিখুন", + setup2fa_3_step_heading: "৬-টি অংকের কোড লিখুন", setup2fa_4_step_heading: "আপনার পুনরুদ্ধার কোড কপি করুন", setup2fa_4_instructions: ` - এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায় যদি আপনি আপনার ফোন হারান বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন। + এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায়। যদি আপনি আপনার ফোন হারিয়ে ফেলেন বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন, তবে নিশ্চিত করুন যে আপনি তাদের একটি নিরাপদ জায়গায় সংরক্ষণ করেছেন। `, setup2fa_5_step_heading: "2FA সেটআপ নিশ্চিত করুন", @@ -342,35 +342,31 @@ const bn = { // === 2FA Login === login2fa_otp_title: "2FA কোড লিখুন", - login2fa_otp_instructions: "আপনার প্রামাণিকতা অ্যাপ থেকে 6-টি অংকের কোড লিখুন।", + login2fa_otp_instructions: "আপনার প্রামাণিকতা অ্যাপ থেকে ৬-টি অংকের কোড লিখুন।", login2fa_recovery_title: "একটি পুনরুদ্ধার কোড লিখুন", login2fa_recovery_instructions: "আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার জন্য আপনার পুনরুদ্ধার কোডগুলির মধ্য থেকে একটি লিখুন।", login2fa_use_recovery_code: "একটি পুনরুদ্ধার কোড ব্যবহার করুন", login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** - "change": "পরিবর্তন করুন", - "clock_visibility": "ঘড়ির দৃশ্যমানতা", - "password_recovery_token_invalid": "এই পাসওয়ার্ড পুনরুদ্ধার টোকেনটি আর সঠিক নয়।", - "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে। অনুগ্রহ করে পরে আবার চেষ্টা করুন।", - "password_required": "পাসওয়ার্ড প্রয়োজন।", - "password_strength_error": "পাসওয়ার্ড কমপক্ষে ৮ সংখার হতে হবে এবং এতে অন্তত একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা, এবং একটি বিশেষ অক্ষর থাকতে হবে।", - "reading": "পড়া হচ্ছে", - "writing": "লেখা হচ্ছে", - "unzipping": "আনজিপ করা হচ্ছে", - "sequencing": "ক্রমানুসারে সাজানো হচ্ছে", - "zipping": "জিপ করা হচ্ছে", - "Editor": "সম্পাদক", - "Viewer": "দর্শক", - "People with access": "যাদের অ্যাক্সেস আছে", - "Share With…": "শেয়ার করুন…", - "Owner": "মালিক", - "You can't share with yourself.": "নিজের সাথে শেয়ার করতে পারবেন না।", - "This user already has access to this item": "এই ব্যবহারকারীর ইতিমধ্যে এটাতে অ্যাক্সেস রয়েছে।" - + "change": "পরিবর্তন করুন", + "clock_visibility": "ঘড়ির দৃশ্যমানতা", + "password_recovery_token_invalid": "এই পাসওয়ার্ড পুনরুদ্ধার টোকেনটি আর সঠিক নয়।", + "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে। অনুগ্রহ করে পরে আবার চেষ্টা করুন।", + "password_required": "পাসওয়ার্ড প্রয়োজন।", + "password_strength_error": "পাসওয়ার্ড কমপক্ষে ৮ সংখার হতে হবে এবং এতে অন্তত একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা, এবং একটি বিশেষ অক্ষর থাকতে হবে।", + "reading": "পড়া হচ্ছে", + "writing": "লেখা হচ্ছে", + "unzipping": "আনজিপ করা হচ্ছে", + "sequencing": "ক্রমানুসারে সাজানো হচ্ছে", + "zipping": "জিপ করা হচ্ছে", + "Editor": "সম্পাদক", + "Viewer": "দর্শক", + "People with access": "যাদের অ্যাক্সেস আছে", + "Share With…": "শেয়ার করুন…", + "Owner": "মালিক", + "You can't share with yourself.": "নিজের সাথে শেয়ার করতে পারবেন না।", + "This user already has access to this item": "এই ব্যবহারকারীর ইতিমধ্যে এটাতে অ্যাক্সেস রয়েছে।" }, };